blob: 63bdb7e1bf3ef9996a17750b6fd943bbaaaca8fa [file] [log] [blame]
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
#include <autoconf.h>
#include <platsupport/gen_config.h>
#include <platsupport/i2c.h>
#include <platsupport/mux.h>
#include <platsupport/plat/mux.h>
#include <utils/util.h>
#include "../../services.h"
/*********************
*** SoC specifics ***
*********************/
#if defined(CONFIG_PLAT_EXYNOS4)
/* IRQS */
#define EXYNOS_I2C0_IRQ 90
#define EXYNOS_I2C1_IRQ 91
#define EXYNOS_I2C2_IRQ 92
#define EXYNOS_I2C3_IRQ 93
#define EXYNOS_I2C4_IRQ 94
#define EXYNOS_I2C5_IRQ 95
#define EXYNOS_I2C6_IRQ 96
#define EXYNOS_I2C7_IRQ 97
#define EXYNOS_I2C8_IRQ 0
#define EXYNOS_I2C9_IRQ 0
#define EXYNOS_I2C10_IRQ 0
#define EXYNOS_I2C11_IRQ 0
/* Physical addresses */
#define EXYNOS_I2C0_PADDR 0x13860000
#define EXYNOS_I2C1_PADDR 0x13870000
#define EXYNOS_I2C2_PADDR 0x13880000
#define EXYNOS_I2C3_PADDR 0x13890000
#define EXYNOS_I2C4_PADDR 0x138A0000
#define EXYNOS_I2C5_PADDR 0x138B0000
#define EXYNOS_I2C6_PADDR 0x138C0000
#define EXYNOS_I2C7_PADDR 0x138D0000
#define EXYNOS_I2C8_PADDR 0x138E0000
#define EXYNOS_I2C9_PADDR 0xDEADBEEF
#define EXYNOS_I2C10_PADDR 0xDEADBEEF
#define EXYNOS_I2C11_PADDR 0xDEADBEEF
#elif defined(CONFIG_PLAT_EXYNOS5)
/* IRQS */
#define EXYNOS_I2C0_IRQ 88
#define EXYNOS_I2C1_IRQ 89
#define EXYNOS_I2C2_IRQ 90
#define EXYNOS_I2C3_IRQ 91
#define EXYNOS_I2C4_IRQ 92
#define EXYNOS_I2C5_IRQ 93
#define EXYNOS_I2C6_IRQ 94
#define EXYNOS_I2C7_IRQ 95
#define EXYNOS_I2C8_IRQ 96
#define EXYNOS_I2C9_IRQ 0
#define EXYNOS_I2C10_IRQ 0
#define EXYNOS_I2C11_IRQ 0
/* Physical addresses */
#define EXYNOS_I2C0_PADDR 0x12C60000
#define EXYNOS_I2C1_PADDR 0x12C70000
#define EXYNOS_I2C2_PADDR 0x12C80000
#define EXYNOS_I2C3_PADDR 0x12C90000
#define EXYNOS_I2C4_PADDR 0x12CA0000
#define EXYNOS_I2C5_PADDR 0x12CB0000
#define EXYNOS_I2C6_PADDR 0x12CC0000
#define EXYNOS_I2C7_PADDR 0x12CD0000
#define EXYNOS_I2C8_PADDR 0x12CE0000
#define EXYNOS_I2C9_PADDR 0x13130000
#define EXYNOS_I2C10_PADDR 0x13140000
#define EXYNOS_I2C11_PADDR 0x121D0000
#else /* EXYNOS? */
#error Unknown Exynos based platform
#endif /* EXYNOSX */
/* Sizes */
#define EXYNOS_I2CX_SIZE 0x1000
#define EXYNOS_I2C0_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C1_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C2_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C3_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C4_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C5_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C6_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C7_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C8_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C9_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C10_SIZE EXYNOS_I2CX_SIZE
#define EXYNOS_I2C11_SIZE EXYNOS_I2CX_SIZE
/************************
*** Register bitmaps ***
************************/
/* control */
#define I2CCON_ACK_EN BIT(7)
#define I2CCON_CLK_SRC BIT(6)
#define I2CCON_IRQ_EN BIT(5)
#define I2CCON_IRQ_PEND BIT(4)
#define I2CCON_PRESCALE(x) (((x) & 0xf) * BIT(0))
#define I2CCON_PRESCALE_MASK I2CCON_PRESCALE(0xf)
/* status */
#define I2CSTAT_MODE(x) (((x) & 0x3) * BIT(6))
#define I2CSTAT_MODE_SRX I2CSTAT_MODE(0x0)
#define I2CSTAT_MODE_STX I2CSTAT_MODE(0x1)
#define I2CSTAT_MODE_MRX I2CSTAT_MODE(0x2)
#define I2CSTAT_MODE_MTX I2CSTAT_MODE(0x3)
#define I2CSTAT_MODE_MASK I2CSTAT_MODE(0x3)
#define I2CSTAT_BUSY BIT(5)
#define I2CSTAT_ENABLE BIT(4)
#define I2CSTAT_ARB_FAIL BIT(3)
#define I2CSTAT_ADDR_SLAVE BIT(2)
#define I2CSTAT_ADDR_ZERO BIT(1)
#define I2CSTAT_ACK BIT(0)
/* address */
#define I2CADDR(x) (((x) & 0xff) * BIT(0))
#define I2CADDR_MASK I2CADDR(0xff)
/* data */
#define I2CDATA(x) (((x) & 0xff) * BIT(0))
#define I2CDATA_MASK I2CDATA(0xff)
#define I2CDATA_READ(addr) I2CDATA(((addr) & 0xfe) | 1)
#define I2CDATA_WRITE(addr) I2CDATA(((addr) & 0xfe) | 0)
/* Line control */
#define I2CLC_FILT_EN BIT(2)
#define I2CLC_SDA_DELAY(x) (((x) & 0x3) * BIT(0))
#define I2CLC_SDA_DELAY0CLK I2CLC_SDA_DELAY(0x0)
#define I2CLC_SDA_DELAY5CLK I2CLC_SDA_DELAY(0x1)
#define I2CLC_SDA_DELAY10CLK I2CLC_SDA_DELAY(0x2)
#define I2CLC_SDA_DELAY15CLK I2CLC_SDA_DELAY(0x3)
#define I2CLC_SDA_DELAY_MASK I2CLC_SDA_DELAY(0x3)
struct exynos_i2c_regs {
uint32_t control; /* 0x0000 control register 0x0X */
uint32_t status; /* 0x0004 control/status register 0x00 */
uint32_t address; /* 0x0008 address register 0xXX */
uint32_t data; /* 0x000C tx/rx data shift register 0xXX */
uint32_t line_control; /* 0x0010 multi-master line control register */
};
struct i2c_bus_priv {
volatile struct exynos_i2c_regs* regs;
const char* tx_buf;
int tx_len;
int tx_count;
char* rx_buf;
int rx_len;
int rx_count;
enum mux_feature mux;
};
static struct i2c_bus_priv _i2c[NI2C] = {
{ .regs = NULL, .mux = MUX_I2C0 },
{ .regs = NULL, .mux = MUX_I2C1 },
{ .regs = NULL, .mux = MUX_I2C2 },
{ .regs = NULL, .mux = MUX_I2C3 },
{ .regs = NULL, .mux = MUX_I2C4 },
{ .regs = NULL, .mux = MUX_I2C5 },
{ .regs = NULL, .mux = MUX_I2C6 },
{ .regs = NULL, .mux = MUX_I2C7 },
#if defined(CONFIG_PLAT_EXYNOS4)
#elif defined(CONFIG_PLAT_EXYNOS5)
{ .regs = NULL, .mux = MUX_I2C8 },
{ .regs = NULL, .mux = MUX_I2C9 },
{ .regs = NULL, .mux = MUX_I2C10 },
{ .regs = NULL, .mux = MUX_I2C11 }
#else /* EXYNOS? */
#error Unknown Exynos based platform
#endif /* EXYNOSX */
};
static inline struct i2c_bus_priv*
i2c_bus_get_priv(i2c_bus_t* i2c_bus) {
return (struct i2c_bus_priv*)i2c_bus->priv;
}
static inline int
irq_pending(struct i2c_bus_priv* dev)
{
return !!(dev->regs->control & I2CCON_IRQ_PEND);
}
static inline void
clear_pending(struct i2c_bus_priv* dev)
{
uint32_t v = dev->regs->control;
v &= ~(I2CCON_IRQ_PEND);
dev->regs->control = v;
}
static inline int
addressed_as_slave(struct i2c_bus_priv* dev)
{
return !!(dev->regs->status & I2CSTAT_ADDR_SLAVE);
}
static inline int
busy(struct i2c_bus_priv* dev)
{
return !!(dev->regs->status & I2CSTAT_BUSY);
}
static inline int
acked(struct i2c_bus_priv* dev)
{
return !(dev->regs->status & I2CSTAT_ACK);
}
static inline int
enabled(struct i2c_bus_priv* dev)
{
return !!(dev->regs->status & I2CSTAT_ENABLE);
}
static void
master_txstart(struct i2c_bus_priv* dev, int slave)
{
dev->regs->control |= I2CCON_ACK_EN;
/** Configure Master Tx mode **/
dev->regs->status = I2CSTAT_MODE_MTX | I2CSTAT_ENABLE;
/* Write slave address */
dev->regs->data = I2CDATA_WRITE(slave);
/* Write 0xF0 (M/T Start) to I2CSTAT */
clear_pending(dev);
dev->regs->status |= I2CSTAT_BUSY;
}
static void
master_rxstart(struct i2c_bus_priv* dev, int slave)
{
dev->regs->control |= I2CCON_ACK_EN;
/** Configure Master Rx mode **/
dev->regs->status = I2CSTAT_ENABLE | I2CSTAT_MODE_MRX;
/* Write slave address */
dev->regs->data = I2CDATA_READ(slave);
/* Write 0xB0 (M/R Start) to I2CSTAT */
dev->regs->status |= I2CSTAT_BUSY;
}
static void
slave_init(struct i2c_bus_priv* dev, char addr)
{
dev->regs->address = addr;
/** Configure Master Rx mode **/
dev->regs->status = I2CSTAT_ENABLE | I2CSTAT_MODE_SRX;
}
int
exynos_i2c_read(i2c_bus_t* i2c_bus, void* vdata, size_t len,
UNUSED bool send_stop,
i2c_callback_fn cb, void* token)
{
struct i2c_bus_priv* dev = i2c_bus_get_priv(i2c_bus);
dev->rx_buf = (char*)vdata;
dev->rx_len = len;
dev->rx_count = 0;
i2c_bus->cb = cb;
i2c_bus->token = token;
ZF_LOGD("Reading %d bytes as slave 0x%x", len, dev->regs->address);
dev->regs->control |= I2CCON_ACK_EN;
if (cb == NULL) {
/* Read bytes */
while (dev->rx_count < dev->rx_len && busy(dev)) {
i2c_handle_irq(i2c_bus);
}
ZF_LOGD("read %d bytes", dev->rx_count);
return dev->rx_count;
} else {
/* Let the ISR handle it */
return 0;
}
}
static int
exynos_i2c_write(i2c_bus_t* i2c_bus, const void* vdata, size_t len,
UNUSED bool send_stop,
i2c_callback_fn cb, void* token)
{
struct i2c_bus_priv* dev = i2c_bus_get_priv(i2c_bus);
dev->tx_buf = (char*)vdata;
dev->tx_len = len;
dev->tx_count = 0;
i2c_bus->cb = cb;
i2c_bus->token = token;
ZF_LOGD("Writing %d bytes as slave 0x%x", len, dev->regs->address);
dev->regs->control |= I2CCON_ACK_EN;
if (cb == NULL) {
while (dev->tx_count < dev->tx_len && busy(dev)) {
i2c_handle_irq(i2c_bus);
}
ZF_LOGD("wrote %d bytes", dev->tx_count);
return dev->tx_count;
} else {
/* Let the ISR handle it */
return 0;
}
}
static int
exynos_i2c_master_stop(i2c_bus_t* i2c_bus)
{
assert(!"Not implemented");
return -1;
}
/* Exynos4 manual Figure 14-6 p14-9 */
static int
exynos_i2c_start_read(i2c_slave_t* sl, void* vdata, size_t len,
UNUSED bool end_with_repeat_start,
i2c_callback_fn cb, void* token)
{
struct i2c_bus_priv* dev;
assert(sl != NULL && sl->bus != NULL);
dev = i2c_bus_get_priv(sl->bus);
ZF_LOGD("Reading %d bytes from slave@0x%02x", len, sl->address);
master_rxstart(dev, sl->address);
/* Setup the RX descriptor */
dev->rx_buf = (char*)vdata;
dev->rx_len = len;
dev->rx_count = -1;
sl->bus->cb = cb;
sl->bus->token = token;
/* Wait for completion */
if (cb == NULL) {
while (busy(dev)) {
i2c_handle_irq(sl->bus);
}
} else {
clear_pending(dev); // Clears any interrupts
return dev->rx_len;
}
return dev->rx_count;
}
/* Exynos4 manual Figure 14-6 p14-8 */
static int
exynos_i2c_start_write(i2c_slave_t* sl, const void* vdata, size_t len,
UNUSED bool end_with_repeat_start,
i2c_callback_fn cb, void* token)
{
struct i2c_bus_priv* dev;
assert(sl != NULL && sl->bus != NULL);
dev = i2c_bus_get_priv(sl->bus);
ZF_LOGD("Writing %d bytes to slave@0x%02x", len, sl->address);
master_txstart(dev, sl->address);
dev->tx_count = -1;
dev->tx_len = len;
dev->tx_buf = (const char*)vdata;
sl->bus->cb = cb;
sl->bus->token = token;
if (cb == NULL) {
while (busy(dev)) {
i2c_handle_irq(sl->bus);
}
} else {
clear_pending(dev); // Clears any interrupts
return dev->tx_len;
}
return dev->tx_count;
}
static void
exynos_i2c_send_stop(i2c_bus_t* i2c_bus, enum i2c_stat status)
{
struct i2c_bus_priv *dev = i2c_bus_get_priv(i2c_bus);
dev->regs->status &= ~(I2CSTAT_BUSY);
clear_pending(dev);
if (i2c_bus->cb) {
i2c_bus->cb(i2c_bus, status, dev->tx_count, i2c_bus->token);
}
}
static enum i2c_mode
exynos_i2c_probe_aas(i2c_bus_t* i2c_bus)
{
struct i2c_bus_priv* dev;
enum i2c_mode mode = I2CMODE_IDLE;
dev = i2c_bus_get_priv(i2c_bus);
if (addressed_as_slave(dev)) {
if ((dev->regs->status & I2CSTAT_MODE_MASK) == I2CSTAT_MODE_STX) {
mode = I2CMODE_TX;
} else {
mode = I2CMODE_RX;
}
ZF_LOGD("Addressed as slave for %s transfer.",
(mode == I2CMODE_RX) ? "READ" : "WRITE");
/* Call out to the handler if one was registered */
if (i2c_bus->aas_cb) {
/* Is there a transfer in flight? */
if (i2c_bus->cb && (dev->tx_len || dev->rx_len)) {
size_t bytes;
if (mode == I2CMODE_TX) {
bytes = dev->tx_count;
} else {
bytes = dev->rx_count;
}
i2c_bus->cb(i2c_bus, I2CSTAT_INCOMPLETE, bytes, i2c_bus->token);
}
i2c_bus->aas_cb(i2c_bus, mode, i2c_bus->aas_token);
}
/* In read mode, must we perform a dummy read of the received address */
if (mode == I2CMODE_RX) {
(void)dev->regs->data;
clear_pending(dev);
}
}
return mode;
}
static void
exynos_i2c_handle_irq(i2c_bus_t* i2c_bus)
{
struct i2c_bus_priv* dev;
uint32_t v;
dev = i2c_bus_get_priv(i2c_bus);
/* AddressedAsSlave seems to be read_to_clear so process the event immediately */
i2c_probe_aas(i2c_bus);
/* Anything to do? */
if (!enabled(dev) || !irq_pending(dev)) {
return;
}
/* Handle transfer */
switch (dev->regs->status & I2CSTAT_MODE_MASK) {
case I2CSTAT_MODE_MRX:
if (dev->rx_count < 0) {
if (acked(dev)) {
/* slave responded to the address */
dev->rx_count = 0;
} else {
/* No response: Abort */
exynos_i2c_send_stop(i2c_bus, I2CSTAT_ERROR);
}
} else if (dev->regs->control & I2CCON_ACK_EN) {
/* Read from slave */
v = dev->regs->data;
*dev->rx_buf++ = v;
dev->rx_count++;
/* Don't ACK the last byte */
if (dev->rx_count == dev->rx_len) {
dev->regs->control &= ~(I2CCON_ACK_EN);
}
} else {
/* Finally, send stop */
exynos_i2c_send_stop(i2c_bus, I2CSTAT_COMPLETE);
}
break;
case I2CSTAT_MODE_MTX:
if (acked(dev)) {
/* Start pumping out data */
v = *dev->tx_buf++;
dev->regs->data = v;
dev->tx_count++;
if (dev->tx_count == dev->tx_len) {
/* Write 0xD0 (M/T Stop) to I2CSTAT */
exynos_i2c_send_stop(i2c_bus, I2CSTAT_COMPLETE);
}
} else {
/* No response: Abort */
exynos_i2c_send_stop(i2c_bus, I2CSTAT_ERROR);
}
break;
case I2CSTAT_MODE_SRX:
/* Read in the data */
if (dev->rx_buf) {
*dev->rx_buf++ = dev->regs->data;
} else {
(void)dev->regs->data;
}
dev->rx_count++;
/* Last chance for user to supply another buffer */
if (i2c_bus->cb && (dev->rx_count == dev->rx_len)) {
i2c_bus->cb(i2c_bus, I2CSTAT_LASTBYTE, dev->rx_count, i2c_bus->token);
}
/* If this is STILL the last byte, finish up */
if (dev->rx_count == dev->rx_len) {
dev->rx_len = 0;
if (i2c_bus->cb) {
i2c_bus->cb(i2c_bus, I2CSTAT_COMPLETE, dev->rx_count, i2c_bus->token);
}
}
break;
case I2CSTAT_MODE_STX:
/* Last byte? */
if (!acked(dev)) {
enum i2c_stat stat;
if (dev->tx_len == dev->tx_count) {
stat = I2CSTAT_COMPLETE;
} else {
stat = I2CSTAT_INCOMPLETE;
}
/* Now we need to handle the stop. For some reason, we need to prime
* the data register first, but this byte will not actually be sent. */
dev->regs->data = 0xff;
dev->tx_len = 0;
/* Signal the application */
if (i2c_bus->cb) {
i2c_bus->cb(i2c_bus, stat, dev->tx_count, i2c_bus->token);
}
} else if (dev->tx_count == dev->tx_len) {
dev->tx_len = 0;
if (i2c_bus->cb) {
i2c_bus->cb(i2c_bus, I2CSTAT_COMPLETE, dev->tx_count, i2c_bus->token);
}
} else if (dev->tx_count < dev->tx_len) {
/* Call out to user before sending the last byte. We could call out AFTER
* sending the last byte, but it is nice to be consitant with RX behaviour */
if (i2c_bus->cb && (dev->tx_count + 1 < dev->tx_len)) {
i2c_bus->cb(i2c_bus, I2CSTAT_LASTBYTE, dev->tx_count, i2c_bus->token);
}
if (dev->tx_buf) {
dev->regs->data = *dev->tx_buf++;
} else {
dev->regs->data = 0x00;
}
dev->tx_count++;
}
break;
default:
assert(!"Unknown I2C mode");
}
clear_pending(dev);
}
static long
exynos_i2c_set_speed(i2c_bus_t* i2c_bus, UNUSED enum i2c_slave_speed speed)
{
ZF_LOGF("Not implemented");
return -1;
}
static int
exynos_i2c_set_self_slave_address(i2c_bus_t* i2c_bus, int addr)
{
struct i2c_bus_priv* dev;
dev = i2c_bus_get_priv(i2c_bus);
slave_init(dev, addr);
dev->regs->line_control = BIT(2) | 0x3 ;
return 0;
}
static void
exynos_i2c_register_slave_event_handler(i2c_bus_t *bus,
i2c_aas_callback_fn cb, void *token)
{
assert(bus != NULL);
bus->aas_cb = cb;
bus->aas_token = token;
}
static int
exynos_i2c_slave_init(i2c_bus_t* i2c_bus, int address,
enum i2c_slave_address_size address_size,
enum i2c_slave_speed max_speed,
uint32_t flags,
i2c_slave_t* sl)
{
assert(sl != NULL);
if (address_size == I2C_SLAVE_ADDR_7BIT) {
address = i2c_extract_address(address);
}
sl->address = address;
sl->address_size = address_size;
sl->max_speed = max_speed;
sl->i2c_opts = flags;
sl->bus = i2c_bus;
sl->slave_read = exynos_i2c_start_read;
sl->slave_write = exynos_i2c_start_write;
return 0;
}
static int
i2c_init_common(mux_sys_t* mux, i2c_bus_t* i2c, struct i2c_bus_priv* dev)
{
/* Check that our memory was mapped */
if (dev->regs == NULL) {
return -2;
}
ZF_LOGD("Memory for regs mapped");
/* Configure MUX */
if (mux_sys_valid(mux) && mux_feature_enable(mux, dev->mux, MUX_DIR_NOT_A_GPIO)) {
ZF_LOGD("Warning: failed to configure MUX");
}
/* I2C setup */
dev->regs->control = I2CCON_ACK_EN | 0 * I2CCON_CLK_SRC
| I2CCON_PRESCALE(7) | I2CCON_IRQ_EN;
dev->regs->line_control = I2CLC_SDA_DELAY15CLK | I2CLC_FILT_EN;
dev->regs->address = 0x54;
i2c->slave_init = exynos_i2c_slave_init;
i2c->read = exynos_i2c_read;
i2c->write = exynos_i2c_write;
i2c->set_speed = exynos_i2c_set_speed;
i2c->set_self_slave_address = exynos_i2c_set_self_slave_address;
i2c->register_slave_event_handler = exynos_i2c_register_slave_event_handler;
i2c->probe_aas = exynos_i2c_probe_aas;
i2c->master_stop = exynos_i2c_master_stop;
i2c->handle_irq = exynos_i2c_handle_irq;
i2c->priv = (void*)dev;
i2c->cb = NULL;
i2c->token = NULL;
i2c->aas_cb = NULL;
i2c->aas_token = NULL;
return 0;
}
int
exynos_i2c_init(enum i2c_id id, void* base, mux_sys_t* mux, i2c_bus_t* i2c)
{
struct i2c_bus_priv* dev = _i2c + id;
ZF_LOGD("Mapping i2c %d", id);
dev->regs = base;
return i2c_init_common(mux, i2c, dev);
}
int
i2c_init(enum i2c_id id, ps_io_ops_t* io_ops, i2c_bus_t* i2c)
{
struct i2c_bus_priv* dev = _i2c + id;
mux_sys_t* mux = &io_ops->mux_sys;
/* Map memory */
ZF_LOGD("Mapping i2c %d", id);
switch (id) {
case I2C0:
MAP_IF_NULL(io_ops, EXYNOS_I2C0, dev->regs);
break;
case I2C1:
MAP_IF_NULL(io_ops, EXYNOS_I2C1, dev->regs);
break;
case I2C2:
MAP_IF_NULL(io_ops, EXYNOS_I2C2, dev->regs);
break;
case I2C3:
MAP_IF_NULL(io_ops, EXYNOS_I2C3, dev->regs);
break;
case I2C4:
MAP_IF_NULL(io_ops, EXYNOS_I2C4, dev->regs);
break;
case I2C5:
MAP_IF_NULL(io_ops, EXYNOS_I2C5, dev->regs);
break;
case I2C6:
MAP_IF_NULL(io_ops, EXYNOS_I2C6, dev->regs);
break;
case I2C7:
MAP_IF_NULL(io_ops, EXYNOS_I2C7, dev->regs);
break;
#if defined(CONFIG_PLAT_EXYNOS4)
#elif defined(CONFIG_PLAT_EXYNOS5)
case I2C8:
MAP_IF_NULL(io_ops, EXYNOS_I2C8, dev->regs);
break;
case I2C9:
MAP_IF_NULL(io_ops, EXYNOS_I2C9, dev->regs);
break;
case I2C10:
MAP_IF_NULL(io_ops, EXYNOS_I2C10, dev->regs);
break;
case I2C11:
MAP_IF_NULL(io_ops, EXYNOS_I2C11, dev->regs);
break;
#else /* EXYNOS? */
#error Unknown Exynos based platform
#endif /* EXYNOSX */
default :
return -1;
}
return i2c_init_common(mux, i2c, dev);
}