--- linux-4.9.37/drivers/i2c/busses/i2c-goke.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-4.9.y/drivers/i2c/busses/i2c-goke.c 2021-06-07 13:01:33.000000000 +0300 @@ -0,0 +1,967 @@ +/* + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * I2C Registers offsets + */ +#define GOKE_I2C_GLB 0x0 +#define GOKE_I2C_SCL_H 0x4 +#define GOKE_I2C_SCL_L 0x8 +#define GOKE_I2C_DATA1 0x10 +#define GOKE_I2C_TXF 0x20 +#define GOKE_I2C_RXF 0x24 +#define GOKE_I2C_CMD_BASE 0x30 +#define GOKE_I2C_LOOP1 0xb0 +#define GOKE_I2C_DST1 0xb4 +#define GOKE_I2C_TX_WATER 0xc8 +#define GOKE_I2C_RX_WATER 0xcc +#define GOKE_I2C_CTRL1 0xd0 +#define GOKE_I2C_CTRL2 0xd4 +#define GOKE_I2C_STAT 0xd8 +#define GOKE_I2C_INTR_RAW 0xe0 +#define GOKE_I2C_INTR_EN 0xe4 +#define GOKE_I2C_INTR_STAT 0xe8 + +/* + * I2C Global Config Register -- GOKE_I2C_GLB + */ +#define GLB_EN_MASK BIT(0) +#define GLB_SDA_HOLD_MASK GENMASK(23, 8) +#define GLB_SDA_HOLD_SHIFT (8) + +/* + * I2C Timing CMD Register -- GOKE_I2C_CMD_BASE + n * 4 (n = 0, 1, 2, ... 31) + */ +#define CMD_EXIT 0x0 +#define CMD_TX_S 0x1 +#define CMD_TX_D1_2 0x4 +#define CMD_TX_D1_1 0x5 +#define CMD_TX_FIFO 0x9 +#define CMD_RX_FIFO 0x12 +#define CMD_RX_ACK 0x13 +#define CMD_IGN_ACK 0x15 +#define CMD_TX_ACK 0x16 +#define CMD_TX_NACK 0x17 +#define CMD_JMP1 0x18 +#define CMD_UP_TXF 0x1d +#define CMD_TX_RS 0x1e +#define CMD_TX_P 0x1f + +/* + * I2C Control Register 1 -- GOKE_I2C_CTRL1 + */ +#define CTRL1_CMD_START_MASK BIT(0) +#define CTRL1_DMA_OP_MASK (0x3 << 8) +#define CTRL1_DMA_R (0x3 << 8) +#define CTRL1_DMA_W (0x2 << 8) + +/* + * I2C Status Register -- GOKE_I2C_STAT + */ +#define STAT_RXF_NOE_MASK BIT(16) /* RX FIFO not empty flag */ +#define STAT_TXF_NOF_MASK BIT(19) /* TX FIFO not full flag */ + + +/* + * I2C Interrupt status and mask Register -- + * GOKE_I2C_INTR_RAW, GOKE_I2C_STAT, GOKE_I2C_INTR_STAT + */ +#define INTR_ABORT_MASK (BIT(0) | BIT(11)) +#define INTR_RX_MASK BIT(2) +#define INTR_TX_MASK BIT(4) +#define INTR_CMD_DONE_MASK BIT(12) +#define INTR_USE_MASK (INTR_ABORT_MASK \ + |INTR_RX_MASK \ + | INTR_TX_MASK \ + | INTR_CMD_DONE_MASK) +#define INTR_ALL_MASK GENMASK(31, 0) + +#define I2C_DEFAULT_FREQUENCY 100000 +#define I2C_TXF_DEPTH 64 +#define I2C_RXF_DEPTH 64 +#define I2C_TXF_WATER 32 +#define I2C_RXF_WATER 32 +#define I2C_WAIT_TIMEOUT 0x400 +#define I2C_IRQ_TIMEOUT (msecs_to_jiffies(1000)) + + +struct goke_i2c_dev { + struct device *dev; + struct i2c_adapter adap; + resource_size_t phybase; + void __iomem *base; + struct clk *clk; + int irq; + + unsigned int freq; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_idx; + unsigned int msg_buf_ptr; + struct completion msg_complete; + + spinlock_t lock; + int status; +}; +static inline void goke_i2c_disable(struct goke_i2c_dev *i2c); +static inline void goke_i2c_cfg_irq(struct goke_i2c_dev *i2c, + unsigned int flag); +static inline unsigned int goke_i2c_clr_irq(struct goke_i2c_dev *i2c); +static inline void goke_i2c_enable(struct goke_i2c_dev *i2c); + +#define CHECK_SDA_IN_SHIFT (16) +#define GPIO_MODE_SHIFT (8) +#define FORCE_SCL_OEN_SHIFT (4) +#define FORCE_SDA_OEN_SHIFT (0) + +static void goke_i2c_rescue(struct goke_i2c_dev *i2c) +{ + unsigned int val; + unsigned int time_cnt; + int index; + + goke_i2c_disable(i2c); + goke_i2c_cfg_irq(i2c, 0); + goke_i2c_clr_irq(i2c); + + val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); + writel(val, i2c->base + GOKE_I2C_CTRL2); + + time_cnt = 0; + do { + for (index = 0; index < 9; index++) { + val = (0x1 << GPIO_MODE_SHIFT) | 0x1; + writel(val, i2c->base + GOKE_I2C_CTRL2); + + udelay(5); + + val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); + writel(val, i2c->base + GOKE_I2C_CTRL2); + + udelay(5); + } + + time_cnt++; + if (time_cnt > I2C_WAIT_TIMEOUT) { + dev_err(i2c->dev, "wait Timeout!\n"); + goto disable_rescue; + } + + val = readl(i2c->base + GOKE_I2C_CTRL2); + } while(!(val & (0x1 << CHECK_SDA_IN_SHIFT))); + + + val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); + writel(val, i2c->base + GOKE_I2C_CTRL2); + + val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT); + writel(val, i2c->base + GOKE_I2C_CTRL2); + + udelay(10); + + val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) | (0x1 << FORCE_SDA_OEN_SHIFT); + writel(val, i2c->base + GOKE_I2C_CTRL2); + +disable_rescue: + val = (0x1 << FORCE_SCL_OEN_SHIFT) | 0x1; + writel(val, i2c->base + GOKE_I2C_CTRL2); +} + +static inline void goke_i2c_disable(struct goke_i2c_dev *i2c) +{ + unsigned int val; + + val = readl(i2c->base + GOKE_I2C_GLB); + val &= ~GLB_EN_MASK; + writel(val, i2c->base + GOKE_I2C_GLB); +} + +static inline void goke_i2c_enable(struct goke_i2c_dev *i2c) +{ + unsigned int val; + + val = readl(i2c->base + GOKE_I2C_GLB); + val |= GLB_EN_MASK; + writel(val, i2c->base + GOKE_I2C_GLB); +} + +static inline void goke_i2c_cfg_irq(struct goke_i2c_dev *i2c, + unsigned int flag) +{ + writel(flag, i2c->base + GOKE_I2C_INTR_EN); +} + +static inline void goke_i2c_disable_irq(struct goke_i2c_dev *i2c, + unsigned int flag) +{ + unsigned int val; + + val = readl(i2c->base + GOKE_I2C_INTR_EN); + val &= ~flag; + writel(val, i2c->base + GOKE_I2C_INTR_EN); +} + +static inline unsigned int goke_i2c_clr_irq(struct goke_i2c_dev *i2c) +{ + unsigned int val; + + val = readl(i2c->base + GOKE_I2C_INTR_STAT); + writel(INTR_ALL_MASK, i2c->base + GOKE_I2C_INTR_RAW); + + return val; +} + +static inline void goke_i2c_cmdreg_set(struct goke_i2c_dev *i2c, + unsigned int cmd, unsigned int *offset) +{ + dev_dbg(i2c->dev, "i2c reg: offset=0x%x, cmd=0x%x...\n", + *offset * 4, cmd); + writel(cmd, i2c->base + GOKE_I2C_CMD_BASE + *offset * 4); + (*offset)++; +} + +/* + * config i2c slave addr + */ +static inline void goke_i2c_set_addr(struct goke_i2c_dev *i2c) +{ + struct i2c_msg *msg = i2c->msg; + u16 addr; + + if (msg->flags & I2C_M_TEN) { + /* First byte is 11110XX0 where XX is upper 2 bits */ + addr = ((msg->addr & 0x300) << 1) | 0xf000; + if (msg->flags & I2C_M_RD) { + addr |= 1 << 8; + } + + /* Second byte is the remaining 8 bits */ + addr |= msg->addr & 0xff; + } else { + addr = (msg->addr & 0x7f) << 1; + if (msg->flags & I2C_M_RD) { + addr |= 1; + } + } + + writel(addr, i2c->base + GOKE_I2C_DATA1); +} + +/* + * Start command sequence + */ +static inline void goke_i2c_start_cmd(struct goke_i2c_dev *i2c) +{ + unsigned int val; + + val = readl(i2c->base + GOKE_I2C_CTRL1); + val |= CTRL1_CMD_START_MASK; + writel(val, i2c->base + GOKE_I2C_CTRL1); +} + +static int goke_i2c_wait_rx_noempty(struct goke_i2c_dev *i2c) +{ + unsigned int time_cnt = 0; + unsigned int val; + + do { + val = readl(i2c->base + GOKE_I2C_STAT); + if (val & STAT_RXF_NOE_MASK) { + return 0; + } + + udelay(50); + } while (time_cnt++ < I2C_WAIT_TIMEOUT); + + goke_i2c_rescue(i2c); + + dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n", + readl(i2c->base + GOKE_I2C_INTR_RAW), val); + return -EIO; +} + +static int goke_i2c_wait_tx_nofull(struct goke_i2c_dev *i2c) +{ + unsigned int time_cnt = 0; + unsigned int val; + + do { + val = readl(i2c->base + GOKE_I2C_STAT); + if (val & STAT_TXF_NOF_MASK) { + return 0; + } + + udelay(50); + } while (time_cnt++ < I2C_WAIT_TIMEOUT); + + goke_i2c_rescue(i2c); + + dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n", + readl(i2c->base + GOKE_I2C_INTR_RAW), val); + return -EIO; +} + +static int goke_i2c_wait_idle(struct goke_i2c_dev *i2c) +{ + unsigned int time_cnt = 0; + unsigned int val; + + do { + val = readl(i2c->base + GOKE_I2C_INTR_RAW); + if (val & (INTR_ABORT_MASK)) { + dev_err(i2c->dev, "wait idle abort!, RIS: 0x%x\n", + val); + return -EIO; + } + + if (val & INTR_CMD_DONE_MASK) { + return 0; + } + + udelay(50); + } while (time_cnt++ < I2C_WAIT_TIMEOUT); + + goke_i2c_rescue(i2c); + + dev_err(i2c->dev, "wait idle timeout, RIS: 0x%x, SR: 0x%x\n", + val, readl(i2c->base + GOKE_I2C_STAT)); + + return -EIO; +} + +static void goke_i2c_set_freq(struct goke_i2c_dev *i2c) +{ + unsigned int max_freq, freq; + unsigned int clk_rate; + unsigned int val; + + freq = i2c->freq; + clk_rate = clk_get_rate(i2c->clk); + max_freq = clk_rate >> 1; + + if (freq > max_freq) { + i2c->freq = max_freq; + freq = i2c->freq; + } + + if (!freq) { + pr_err("goke_i2c_set_freq:freq can't be zero!"); + return; + } + + if (freq <= 100000) { + /* in normal mode F_scl: freq + i2c_scl_hcnt = (F_i2c / F_scl) * 0.5 + i2c_scl_hcnt = (F_i2c / F_scl) * 0.5 + */ + val = clk_rate / (freq * 2); + writel(val, i2c->base + GOKE_I2C_SCL_H); + writel(val, i2c->base + GOKE_I2C_SCL_L); + } else { + /* in fast mode F_scl: freq + i2c_scl_hcnt = (F_i2c / F_scl) * 0.36 + i2c_scl_hcnt = (F_i2c / F_scl) * 0.64 + */ + val = ((clk_rate / 100) * 36) / freq; + writel(val, i2c->base + GOKE_I2C_SCL_H); + val = ((clk_rate / 100) * 64) / freq; + writel(val, i2c->base + GOKE_I2C_SCL_L); + } + + val = readl(i2c->base + GOKE_I2C_GLB); + val &= ~GLB_SDA_HOLD_MASK; + val |= ((0xa << GLB_SDA_HOLD_SHIFT) & GLB_SDA_HOLD_MASK); + writel(val, i2c->base + GOKE_I2C_GLB); +} + +/* + * set i2c controller TX and RX FIFO water + */ +static inline void goke_i2c_set_water(struct goke_i2c_dev *i2c) +{ + writel(I2C_TXF_WATER, i2c->base + GOKE_I2C_TX_WATER); + writel(I2C_RXF_WATER, i2c->base + GOKE_I2C_RX_WATER); +} + +/* + * initialise the controller, set i2c bus interface freq + */ +static void goke_i2c_hw_init(struct goke_i2c_dev *i2c) +{ + goke_i2c_disable(i2c); + goke_i2c_disable_irq(i2c, INTR_ALL_MASK); + goke_i2c_set_freq(i2c); + goke_i2c_set_water(i2c); +} + +/* + * goke_i2c_cfg_cmd - config i2c controller command sequence + * + * After all the timing command is configured, + * and then start the command, you can i2c communication, + * and then only need to read and write i2c fifo. + */ +static void goke_i2c_cfg_cmd(struct goke_i2c_dev *i2c) +{ + struct i2c_msg *msg = i2c->msg; + int offset = 0; + + if (i2c->msg_idx == 0) { + goke_i2c_cmdreg_set(i2c, CMD_TX_S, &offset); + } else { + goke_i2c_cmdreg_set(i2c, CMD_TX_RS, &offset); + } + + if (msg->flags & I2C_M_TEN) { + if (i2c->msg_idx == 0) { + goke_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset); + goke_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset); + } else { + goke_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset); + } + } else { + goke_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset); + } + + if (msg->flags & I2C_M_IGNORE_NAK) { + goke_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset); + } else { + goke_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset); + } + + if (msg->flags & I2C_M_RD) { + if (msg->len >= 2) { + writel(offset, i2c->base + GOKE_I2C_DST1); + writel(msg->len - 2, i2c->base + GOKE_I2C_LOOP1); + goke_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset); + goke_i2c_cmdreg_set(i2c, CMD_TX_ACK, &offset); + goke_i2c_cmdreg_set(i2c, CMD_JMP1, &offset); + } + goke_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset); + goke_i2c_cmdreg_set(i2c, CMD_TX_NACK, &offset); + } else { + writel(offset, i2c->base + GOKE_I2C_DST1); + writel(msg->len - 1, i2c->base + GOKE_I2C_LOOP1); + goke_i2c_cmdreg_set(i2c, CMD_UP_TXF, &offset); + goke_i2c_cmdreg_set(i2c, CMD_TX_FIFO, &offset); + + if (msg->flags & I2C_M_IGNORE_NAK) { + goke_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset); + } else { + goke_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset); + } + + goke_i2c_cmdreg_set(i2c, CMD_JMP1, &offset); + } + + if ((i2c->msg_idx == (i2c->msg_num - 1)) || (msg->flags & I2C_M_STOP)) { + dev_dbg(i2c->dev, "run to %s %d...TX STOP\n", + __func__, __LINE__); + goke_i2c_cmdreg_set(i2c, CMD_TX_P, &offset); + } + + goke_i2c_cmdreg_set(i2c, CMD_EXIT, &offset); +} + +static int goke_i2c_polling_xfer_one_msg(struct goke_i2c_dev *i2c) +{ + int status; + unsigned int val; + struct i2c_msg *msg = i2c->msg; + + dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n", + __func__, __LINE__, msg->flags, msg->len); + + goke_i2c_enable(i2c); + goke_i2c_clr_irq(i2c); + goke_i2c_set_addr(i2c); + goke_i2c_cfg_cmd(i2c); + goke_i2c_start_cmd(i2c); + + i2c->msg_buf_ptr = 0; + + if (msg->flags & I2C_M_RD) { + while (i2c->msg_buf_ptr < msg->len) { + status = goke_i2c_wait_rx_noempty(i2c); + if (status) { + goto end; + } + + val = readl(i2c->base + GOKE_I2C_RXF); + msg->buf[i2c->msg_buf_ptr] = val; + i2c->msg_buf_ptr++; + + } + } else { + while (i2c->msg_buf_ptr < msg->len) { + status = goke_i2c_wait_tx_nofull(i2c); + if (status) { + goto end; + } + + val = msg->buf[i2c->msg_buf_ptr]; + writel(val, i2c->base + GOKE_I2C_TXF); + i2c->msg_buf_ptr++; + } + } + + status = goke_i2c_wait_idle(i2c); +end: + goke_i2c_disable(i2c); + + return status; +} + +static irqreturn_t goke_i2c_isr(int irq, void *dev_id) +{ + struct goke_i2c_dev *i2c = dev_id; + unsigned int irq_status; + struct i2c_msg *msg = i2c->msg; + + spin_lock(&i2c->lock); + + irq_status = goke_i2c_clr_irq(i2c); + dev_dbg(i2c->dev, "%s RIS: 0x%x\n", __func__, irq_status); + + if (!irq_status) { + dev_dbg(i2c->dev, "no irq\n"); + goto end; + } + + if (irq_status & INTR_ABORT_MASK) { + dev_err(i2c->dev, "irq handle abort, RIS: 0x%x\n", + irq_status); + i2c->status = -EIO; + goke_i2c_disable_irq(i2c, INTR_ALL_MASK); + + complete(&i2c->msg_complete); + goto end; + } + + if (msg->flags & I2C_M_RD) { + while ((readl(i2c->base + GOKE_I2C_STAT) & STAT_RXF_NOE_MASK) + && (i2c->msg_buf_ptr < msg->len)) { + msg->buf[i2c->msg_buf_ptr] = + readl(i2c->base + GOKE_I2C_RXF); + i2c->msg_buf_ptr++; + } + } else { + while ((readl(i2c->base + GOKE_I2C_STAT) & STAT_TXF_NOF_MASK) + && (i2c->msg_buf_ptr < msg->len)) { + writel(msg->buf[i2c->msg_buf_ptr], + i2c->base + GOKE_I2C_TXF); + i2c->msg_buf_ptr++; + } + } + + if (i2c->msg_buf_ptr >= msg->len) { + goke_i2c_disable_irq(i2c, INTR_TX_MASK | INTR_RX_MASK); + } + + if (irq_status & INTR_CMD_DONE_MASK) { + dev_dbg(i2c->dev, "cmd done\n"); + i2c->status = 0; + goke_i2c_disable_irq(i2c, INTR_ALL_MASK); + + complete(&i2c->msg_complete); + } + +end: + spin_unlock(&i2c->lock); + + return IRQ_HANDLED; +} + +static int goke_i2c_interrupt_xfer_one_msg(struct goke_i2c_dev *i2c) +{ + int status; + struct i2c_msg *msg = i2c->msg; + unsigned long timeout; + unsigned long flags; + + dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n", + __func__, __LINE__, msg->flags, msg->len); + + reinit_completion(&i2c->msg_complete); + i2c->msg_buf_ptr = 0; + i2c->status = -EIO; + + spin_lock_irqsave(&i2c->lock, flags); + goke_i2c_enable(i2c); + goke_i2c_clr_irq(i2c); + if (msg->flags & I2C_M_RD) { + goke_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_TX_MASK); + } else { + goke_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_RX_MASK); + } + + goke_i2c_set_addr(i2c); + goke_i2c_cfg_cmd(i2c); + goke_i2c_start_cmd(i2c); + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->msg_complete, + I2C_IRQ_TIMEOUT); + + spin_lock_irqsave(&i2c->lock, flags); + if (timeout == 0) { + goke_i2c_disable_irq(i2c, INTR_ALL_MASK); + status = -EIO; + dev_err(i2c->dev, "%s timeout\n", + msg->flags & I2C_M_RD ? "rx" : "tx"); + } else { + status = i2c->status; + } + + goke_i2c_disable(i2c); + + spin_unlock_irqrestore(&i2c->lock, flags); + return status; +} + +/* + * Master transfer function + */ +static int goke_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct goke_i2c_dev *i2c = i2c_get_adapdata(adap); + int status = -EINVAL; + unsigned long flags; + + if (!msgs || (num <= 0)) { + dev_err(i2c->dev, "msgs == NULL || num <= 0, Invalid argument!\n"); + return -EINVAL; + } + + spin_lock_irqsave(&i2c->lock, flags); + + i2c->msg = msgs; + i2c->msg_num = num; + i2c->msg_idx = 0; + + /* FIXME: The wait_for_completion_timeout in goke_i2c_interrupt_xfer_one_msg + * function can not be locked by spin_lock_irqsave. And actually I2C interrupt + * tranfer is rarely used, so we ignore the irq setting to limit the interrupt + * way. But we keep these codes below, reserve for future modifications */ + + while (i2c->msg_idx < i2c->msg_num) { + if (i2c->irq >= 0) { + spin_unlock_irqrestore(&i2c->lock, flags); + status = goke_i2c_interrupt_xfer_one_msg(i2c); + spin_lock_irqsave(&i2c->lock, flags); + if (status) { + break; + } + } else { + status = goke_i2c_polling_xfer_one_msg(i2c); + if (status) { + break; + } + } + i2c->msg++; + i2c->msg_idx++; + } + + if (!status || i2c->msg_idx > 0) { + status = i2c->msg_idx; + } + + spin_unlock_irqrestore(&i2c->lock, flags); + return status; +} + +/* goke_i2c_break_polling_xfer + * + * I2c polling independent branch, Shielding interrupt interface + */ +static int goke_i2c_break_polling_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct goke_i2c_dev *i2c = i2c_get_adapdata(adap); + int status = -EINVAL; + unsigned long flags; + if (!msgs || (num <= 0)) { + dev_err(i2c->dev, "msgs == NULL || num <= 0, Invalid argument!\n"); + return -EINVAL; + } + spin_lock_irqsave(&i2c->lock, flags); + i2c->msg = msgs; + i2c->msg_num = num; + i2c->msg_idx = 0; + while (i2c->msg_idx < i2c->msg_num) { + status = goke_i2c_polling_xfer_one_msg(i2c); + if (status) { + break; + } + i2c->msg++; + i2c->msg_idx++; + } + if (!status || i2c->msg_idx > 0) { + status = i2c->msg_idx; + } + spin_unlock_irqrestore(&i2c->lock, flags); + return status; +} +/* + * bsp_i2c_master_recv - issue a single I2C message in master receive mode + * @client: Handle to slave device + * @buf: Where to store data read from slave + * @count: How many bytes to read, must be less than 64k since msg.len is u16 + * + * Returns negative errno, or else the number of bytes read. + */ +int gk_i2c_master_recv(const struct i2c_client *client, char *buf, + int count) +{ + printk("Wrong interface call." + "bsp_i2c_transfer is the only interface to i2c read!!!\n"); + + return -EIO; +} +EXPORT_SYMBOL(gk_i2c_master_recv); + +/*I2C WRITE* + * bsp_i2c_master_send - issue a single I2C message in master transmit mode + * @client: Handle to slave device + * @buf: Data that will be written to the slave + * @count: How many bytes to write, must be less than 64k since msg.len is u16 + * + * Returns negative errno, or else the number of bytes written. + */ +int gk_i2c_master_send(const struct i2c_client *client, + const char *buf, int count) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + int msgs_count; + + if ((client->addr > 0x3ff) + || (((client->flags & I2C_M_TEN) == 0) && (client->addr > 0x7f))) { + printk(KERN_ERR "dev address out of range\n"); + return -EINVAL; + } + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = count; + + if ((!buf)||(count < 0)) { + printk(KERN_ERR "buf == NULL || count < 0, Invalid argument!\n"); + return -EINVAL; + } + msg.buf = (__u8 *)buf; + + msgs_count = goke_i2c_break_polling_xfer(adap, &msg, 1); + + return (msgs_count == 1) ? count : -EIO; +} +EXPORT_SYMBOL(gk_i2c_master_send); + +/** + * bsp_i2c_transfer - execute a single or combined I2C message + * @adap: Handle to I2C bus + * @msgs: One or more messages to execute before STOP is issued to + * terminate the operation; each message begins with a START. + * @num: Number of messages to be executed. + * + * Returns negative errno, else the number of messages executed. + * + * Note that there is no requirement that each message be sent to + * the same slave address, although that is the most common model. + */ +int gk_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int msgs_count; + + if((!adap)||(!msgs)) { + printk(KERN_ERR "adap == NULL || msgs == NULL, Invalid argument!\n"); + return -EINVAL; + } + + if ((msgs[0].addr > 0x3ff) + || (((msgs[0].flags & I2C_M_TEN) == 0) && (msgs[0].addr > 0x7f))) { + printk(KERN_ERR "msgs[0] dev address out of range\n"); + return -EINVAL; + } + + if ((msgs[1].addr > 0x3ff) + || (((msgs[1].flags & I2C_M_TEN) == 0) && (msgs[1].addr > 0x7f))) { + printk(KERN_ERR "msgs[1] dev address out of range\n"); + return -EINVAL; + } + + msgs_count = goke_i2c_xfer(adap, msgs, num); + + return msgs_count; +} +EXPORT_SYMBOL(gk_i2c_transfer); + +static u32 goke_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR + | I2C_FUNC_PROTOCOL_MANGLING + | I2C_FUNC_SMBUS_WORD_DATA + | I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_BYTE + | I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm goke_i2c_algo = { + .master_xfer = goke_i2c_xfer, + .functionality = goke_i2c_func, +}; + +static int goke_i2c_probe(struct platform_device *pdev) +{ + int status; + struct goke_i2c_dev *i2c = NULL; + struct i2c_adapter *adap = NULL; + struct resource *res = NULL; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + return -ENOMEM; + } + + platform_set_drvdata(pdev, i2c); + i2c->dev = &pdev->dev; + spin_lock_init(&i2c->lock); + init_completion(&i2c->msg_complete); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(i2c->dev, "Invalid mem resource./n"); + return -ENODEV; + } + + i2c->phybase = res->start; + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) { + dev_err(i2c->dev, "cannot ioremap resource\n"); + return -ENOMEM; + } + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(i2c->dev, "cannot get clock\n"); + return -ENOENT; + } + clk_prepare_enable(i2c->clk); + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->freq)) { + dev_warn(i2c->dev, "setting default clock-frequency@%dHz\n", + I2C_DEFAULT_FREQUENCY); + i2c->freq = I2C_DEFAULT_FREQUENCY; + } + + /* i2c controller initialization, disable interrupt */ + goke_i2c_hw_init(i2c); + + i2c->irq = platform_get_irq(pdev, 0); + status = devm_request_irq(&pdev->dev, i2c->irq, goke_i2c_isr, + IRQF_SHARED, dev_name(&pdev->dev), i2c); + if (status) { + dev_dbg(i2c->dev, "falling back to polling mode"); + i2c->irq = -1; + } + + adap = &i2c->adap; + i2c_set_adapdata(adap, i2c); + adap->owner = THIS_MODULE; + strlcpy(adap->name, "goke-i2c", sizeof(adap->name)); + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + adap->algo = &goke_i2c_algo; + + /* Add the i2c adapter */ + status = i2c_add_adapter(adap); + if (status) { + dev_err(i2c->dev, "failed to add bus to i2c core\n"); + goto err_add_adapter; + } + + dev_info(i2c->dev, "%s%d@%dhz registered\n", + adap->name, adap->nr, i2c->freq); + + return 0; + +err_add_adapter: + clk_disable_unprepare(i2c->clk); + return status; +} + +static int goke_i2c_remove(struct platform_device *pdev) +{ + struct goke_i2c_dev *i2c = platform_get_drvdata(pdev); + if (i2c == NULL){ + printk("i2c remove err!!!\n"); + return 0; + } + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adap); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int goke_i2c_suspend(struct device *dev) +{ + struct goke_i2c_dev *i2c = dev_get_drvdata(dev); + + i2c_lock_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + i2c_unlock_adapter(&i2c->adap); + + return 0; +} + +static int goke_i2c_resume(struct device *dev) +{ + struct goke_i2c_dev *i2c = dev_get_drvdata(dev); + + i2c_lock_adapter(&i2c->adap); + clk_prepare_enable(i2c->clk); + goke_i2c_hw_init(i2c); + i2c_unlock_adapter(&i2c->adap); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(goke_i2c_dev_pm, goke_i2c_suspend, + goke_i2c_resume); + +static const struct of_device_id goke_i2c_match[] = { + { .compatible = "goke,goke-i2c"}, + {}, +}; +MODULE_DEVICE_TABLE(of, goke_i2c_match); + +static struct platform_driver goke_i2c_driver = { + .driver = { + .name = "goke-i2c", + .of_match_table = goke_i2c_match, + .pm = &goke_i2c_dev_pm, + }, + .probe = goke_i2c_probe, + .remove = goke_i2c_remove, +}; + +module_platform_driver(goke_i2c_driver); + +MODULE_AUTHOR("Goke"); +MODULE_DESCRIPTION("GOKE I2C Bus driver"); +MODULE_LICENSE("GPL v2");