1d211e62aSManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0-or-later 2d211e62aSManivannan Sadhasivam /* 3d211e62aSManivannan Sadhasivam * Actions Semiconductor Owl SoC's I2C driver 4d211e62aSManivannan Sadhasivam * 5d211e62aSManivannan Sadhasivam * Copyright (c) 2014 Actions Semi Inc. 6d211e62aSManivannan Sadhasivam * Author: David Liu <liuwei@actions-semi.com> 7d211e62aSManivannan Sadhasivam * 8d211e62aSManivannan Sadhasivam * Copyright (c) 2018 Linaro Ltd. 9d211e62aSManivannan Sadhasivam * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 10d211e62aSManivannan Sadhasivam */ 11d211e62aSManivannan Sadhasivam 12d211e62aSManivannan Sadhasivam #include <linux/clk.h> 13d211e62aSManivannan Sadhasivam #include <linux/delay.h> 14d211e62aSManivannan Sadhasivam #include <linux/i2c.h> 15d211e62aSManivannan Sadhasivam #include <linux/interrupt.h> 16d211e62aSManivannan Sadhasivam #include <linux/io.h> 17b8be24ecSCristian Ciocaltea #include <linux/iopoll.h> 18d211e62aSManivannan Sadhasivam #include <linux/module.h> 19d211e62aSManivannan Sadhasivam #include <linux/of_device.h> 20d211e62aSManivannan Sadhasivam 21d211e62aSManivannan Sadhasivam /* I2C registers */ 22d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CTL 0x0000 23d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CLKDIV 0x0004 24d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_STAT 0x0008 25d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_ADDR 0x000C 26d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_TXDAT 0x0010 27d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_RXDAT 0x0014 28d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_CMD 0x0018 29d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_FIFOCTL 0x001C 30d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_FIFOSTAT 0x0020 31d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_DATCNT 0x0024 32d211e62aSManivannan Sadhasivam #define OWL_I2C_REG_RCNT 0x0028 33d211e62aSManivannan Sadhasivam 34d211e62aSManivannan Sadhasivam /* I2Cx_CTL Bit Mask */ 35d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_RB BIT(1) 36d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC(x) (((x) & 0x3) << 2) 37d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC_NONE OWL_I2C_CTL_GBCC(0) 38d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC_START OWL_I2C_CTL_GBCC(1) 39d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC_STOP OWL_I2C_CTL_GBCC(2) 40d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_GBCC_RSTART OWL_I2C_CTL_GBCC(3) 41d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_IRQE BIT(5) 42d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_EN BIT(7) 43d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_AE BIT(8) 44d211e62aSManivannan Sadhasivam #define OWL_I2C_CTL_SHSM BIT(10) 45d211e62aSManivannan Sadhasivam 46d211e62aSManivannan Sadhasivam #define OWL_I2C_DIV_FACTOR(x) ((x) & 0xff) 47d211e62aSManivannan Sadhasivam 48d211e62aSManivannan Sadhasivam /* I2Cx_STAT Bit Mask */ 49d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_RACK BIT(0) 50d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_BEB BIT(1) 51d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_IRQP BIT(2) 52d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_LAB BIT(3) 53d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_STPD BIT(4) 54d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_STAD BIT(5) 55d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_BBB BIT(6) 56d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_TCB BIT(7) 57d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_LBST BIT(8) 58d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_SAMB BIT(9) 59d211e62aSManivannan Sadhasivam #define OWL_I2C_STAT_SRGC BIT(10) 60d211e62aSManivannan Sadhasivam 61d211e62aSManivannan Sadhasivam /* I2Cx_CMD Bit Mask */ 62d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SBE BIT(0) 63d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_RBE BIT(4) 64d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_DE BIT(8) 65d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_NS BIT(9) 66d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SE BIT(10) 67d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_MSS BIT(11) 68d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_WRS BIT(12) 69d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SECL BIT(15) 70d211e62aSManivannan Sadhasivam 71d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_AS(x) (((x) & 0x7) << 1) 72d211e62aSManivannan Sadhasivam #define OWL_I2C_CMD_SAS(x) (((x) & 0x7) << 5) 73d211e62aSManivannan Sadhasivam 74d211e62aSManivannan Sadhasivam /* I2Cx_FIFOCTL Bit Mask */ 75d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_NIB BIT(0) 76d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_RFR BIT(1) 77d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOCTL_TFR BIT(2) 78d211e62aSManivannan Sadhasivam 79d211e62aSManivannan Sadhasivam /* I2Cc_FIFOSTAT Bit Mask */ 80b8be24ecSCristian Ciocaltea #define OWL_I2C_FIFOSTAT_CECB BIT(0) 81d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RNB BIT(1) 82d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RFE BIT(2) 83d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_TFF BIT(5) 84d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_TFD GENMASK(23, 16) 85d211e62aSManivannan Sadhasivam #define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8) 86d211e62aSManivannan Sadhasivam 87d211e62aSManivannan Sadhasivam /* I2C bus timeout */ 88b8be24ecSCristian Ciocaltea #define OWL_I2C_TIMEOUT_MS (4 * 1000) 89b8be24ecSCristian Ciocaltea #define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS) 90d211e62aSManivannan Sadhasivam 91d211e62aSManivannan Sadhasivam #define OWL_I2C_MAX_RETRIES 50 92d211e62aSManivannan Sadhasivam 93d211e62aSManivannan Sadhasivam struct owl_i2c_dev { 94d211e62aSManivannan Sadhasivam struct i2c_adapter adap; 95d211e62aSManivannan Sadhasivam struct i2c_msg *msg; 96d211e62aSManivannan Sadhasivam struct completion msg_complete; 97d211e62aSManivannan Sadhasivam struct clk *clk; 98d211e62aSManivannan Sadhasivam spinlock_t lock; 99d211e62aSManivannan Sadhasivam void __iomem *base; 100d211e62aSManivannan Sadhasivam unsigned long clk_rate; 101d211e62aSManivannan Sadhasivam u32 bus_freq; 102d211e62aSManivannan Sadhasivam u32 msg_ptr; 103d211e62aSManivannan Sadhasivam int err; 104d211e62aSManivannan Sadhasivam }; 105d211e62aSManivannan Sadhasivam 106d211e62aSManivannan Sadhasivam static void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state) 107d211e62aSManivannan Sadhasivam { 108d211e62aSManivannan Sadhasivam unsigned int regval; 109d211e62aSManivannan Sadhasivam 110d211e62aSManivannan Sadhasivam regval = readl(reg); 111d211e62aSManivannan Sadhasivam 112d211e62aSManivannan Sadhasivam if (state) 113d211e62aSManivannan Sadhasivam regval |= val; 114d211e62aSManivannan Sadhasivam else 115d211e62aSManivannan Sadhasivam regval &= ~val; 116d211e62aSManivannan Sadhasivam 117d211e62aSManivannan Sadhasivam writel(regval, reg); 118d211e62aSManivannan Sadhasivam } 119d211e62aSManivannan Sadhasivam 120d211e62aSManivannan Sadhasivam static void owl_i2c_reset(struct owl_i2c_dev *i2c_dev) 121d211e62aSManivannan Sadhasivam { 122d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 123d211e62aSManivannan Sadhasivam OWL_I2C_CTL_EN, false); 124d211e62aSManivannan Sadhasivam mdelay(1); 125d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 126d211e62aSManivannan Sadhasivam OWL_I2C_CTL_EN, true); 127d211e62aSManivannan Sadhasivam 128d211e62aSManivannan Sadhasivam /* Clear status registers */ 129d211e62aSManivannan Sadhasivam writel(0, i2c_dev->base + OWL_I2C_REG_STAT); 130d211e62aSManivannan Sadhasivam } 131d211e62aSManivannan Sadhasivam 132d211e62aSManivannan Sadhasivam static int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev) 133d211e62aSManivannan Sadhasivam { 134d211e62aSManivannan Sadhasivam unsigned int val, timeout = 0; 135d211e62aSManivannan Sadhasivam 136d211e62aSManivannan Sadhasivam /* Reset FIFO */ 137d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 138d211e62aSManivannan Sadhasivam OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR, 139d211e62aSManivannan Sadhasivam true); 140d211e62aSManivannan Sadhasivam 141d211e62aSManivannan Sadhasivam /* Wait 50ms for FIFO reset complete */ 142d211e62aSManivannan Sadhasivam do { 143d211e62aSManivannan Sadhasivam val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL); 144d211e62aSManivannan Sadhasivam if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR))) 145d211e62aSManivannan Sadhasivam break; 146d211e62aSManivannan Sadhasivam usleep_range(500, 1000); 147d211e62aSManivannan Sadhasivam } while (timeout++ < OWL_I2C_MAX_RETRIES); 148d211e62aSManivannan Sadhasivam 149d211e62aSManivannan Sadhasivam if (timeout > OWL_I2C_MAX_RETRIES) { 150d211e62aSManivannan Sadhasivam dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n"); 151d211e62aSManivannan Sadhasivam return -ETIMEDOUT; 152d211e62aSManivannan Sadhasivam } 153d211e62aSManivannan Sadhasivam 154d211e62aSManivannan Sadhasivam return 0; 155d211e62aSManivannan Sadhasivam } 156d211e62aSManivannan Sadhasivam 157d211e62aSManivannan Sadhasivam static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev) 158d211e62aSManivannan Sadhasivam { 159d211e62aSManivannan Sadhasivam unsigned int val; 160d211e62aSManivannan Sadhasivam 161d211e62aSManivannan Sadhasivam val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16); 162d211e62aSManivannan Sadhasivam 163d211e62aSManivannan Sadhasivam /* Set clock divider factor */ 164d211e62aSManivannan Sadhasivam writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV); 165d211e62aSManivannan Sadhasivam } 166d211e62aSManivannan Sadhasivam 167b8be24ecSCristian Ciocaltea static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev) 168d211e62aSManivannan Sadhasivam { 169d211e62aSManivannan Sadhasivam struct i2c_msg *msg = i2c_dev->msg; 170d211e62aSManivannan Sadhasivam unsigned int stat, fifostat; 171d211e62aSManivannan Sadhasivam 172d211e62aSManivannan Sadhasivam i2c_dev->err = 0; 173d211e62aSManivannan Sadhasivam 174d211e62aSManivannan Sadhasivam /* Handle NACK from slave */ 175d211e62aSManivannan Sadhasivam fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT); 176d211e62aSManivannan Sadhasivam if (fifostat & OWL_I2C_FIFOSTAT_RNB) { 177d211e62aSManivannan Sadhasivam i2c_dev->err = -ENXIO; 178f5b3f433SCristian Ciocaltea /* Clear NACK error bit by writing "1" */ 179f5b3f433SCristian Ciocaltea owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, 180f5b3f433SCristian Ciocaltea OWL_I2C_FIFOSTAT_RNB, true); 181b8be24ecSCristian Ciocaltea return; 182d211e62aSManivannan Sadhasivam } 183d211e62aSManivannan Sadhasivam 184d211e62aSManivannan Sadhasivam /* Handle bus error */ 185d211e62aSManivannan Sadhasivam stat = readl(i2c_dev->base + OWL_I2C_REG_STAT); 186d211e62aSManivannan Sadhasivam if (stat & OWL_I2C_STAT_BEB) { 187d211e62aSManivannan Sadhasivam i2c_dev->err = -EIO; 188f5b3f433SCristian Ciocaltea /* Clear BUS error bit by writing "1" */ 189f5b3f433SCristian Ciocaltea owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, 190f5b3f433SCristian Ciocaltea OWL_I2C_STAT_BEB, true); 191b8be24ecSCristian Ciocaltea return; 192d211e62aSManivannan Sadhasivam } 193d211e62aSManivannan Sadhasivam 194d211e62aSManivannan Sadhasivam /* Handle FIFO read */ 195d211e62aSManivannan Sadhasivam if (msg->flags & I2C_M_RD) { 196d211e62aSManivannan Sadhasivam while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 197d211e62aSManivannan Sadhasivam OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) { 198d211e62aSManivannan Sadhasivam msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base + 199d211e62aSManivannan Sadhasivam OWL_I2C_REG_RXDAT); 200d211e62aSManivannan Sadhasivam } 201d211e62aSManivannan Sadhasivam } else { 202d211e62aSManivannan Sadhasivam /* Handle the remaining bytes which were not sent */ 203d211e62aSManivannan Sadhasivam while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 204d211e62aSManivannan Sadhasivam OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) { 205d211e62aSManivannan Sadhasivam writel(msg->buf[i2c_dev->msg_ptr++], 206d211e62aSManivannan Sadhasivam i2c_dev->base + OWL_I2C_REG_TXDAT); 207d211e62aSManivannan Sadhasivam } 208d211e62aSManivannan Sadhasivam } 209b8be24ecSCristian Ciocaltea } 210d211e62aSManivannan Sadhasivam 211b8be24ecSCristian Ciocaltea static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) 212b8be24ecSCristian Ciocaltea { 213b8be24ecSCristian Ciocaltea struct owl_i2c_dev *i2c_dev = _dev; 214b8be24ecSCristian Ciocaltea 215b8be24ecSCristian Ciocaltea spin_lock(&i2c_dev->lock); 216b8be24ecSCristian Ciocaltea 217b8be24ecSCristian Ciocaltea owl_i2c_xfer_data(i2c_dev); 218b8be24ecSCristian Ciocaltea 219d211e62aSManivannan Sadhasivam /* Clear pending interrupts */ 220d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, 221d211e62aSManivannan Sadhasivam OWL_I2C_STAT_IRQP, true); 222d211e62aSManivannan Sadhasivam 223d211e62aSManivannan Sadhasivam complete_all(&i2c_dev->msg_complete); 22406856269SBarry Song spin_unlock(&i2c_dev->lock); 225d211e62aSManivannan Sadhasivam 226d211e62aSManivannan Sadhasivam return IRQ_HANDLED; 227d211e62aSManivannan Sadhasivam } 228d211e62aSManivannan Sadhasivam 229d211e62aSManivannan Sadhasivam static u32 owl_i2c_func(struct i2c_adapter *adap) 230d211e62aSManivannan Sadhasivam { 231d211e62aSManivannan Sadhasivam return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 232d211e62aSManivannan Sadhasivam } 233d211e62aSManivannan Sadhasivam 234d211e62aSManivannan Sadhasivam static int owl_i2c_check_bus_busy(struct i2c_adapter *adap) 235d211e62aSManivannan Sadhasivam { 236d211e62aSManivannan Sadhasivam struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); 237d211e62aSManivannan Sadhasivam unsigned long timeout; 238d211e62aSManivannan Sadhasivam 239d211e62aSManivannan Sadhasivam /* Check for Bus busy */ 240d211e62aSManivannan Sadhasivam timeout = jiffies + OWL_I2C_TIMEOUT; 241d211e62aSManivannan Sadhasivam while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) { 242d211e62aSManivannan Sadhasivam if (time_after(jiffies, timeout)) { 243d211e62aSManivannan Sadhasivam dev_err(&adap->dev, "Bus busy timeout\n"); 244d211e62aSManivannan Sadhasivam return -ETIMEDOUT; 245d211e62aSManivannan Sadhasivam } 246d211e62aSManivannan Sadhasivam } 247d211e62aSManivannan Sadhasivam 248d211e62aSManivannan Sadhasivam return 0; 249d211e62aSManivannan Sadhasivam } 250d211e62aSManivannan Sadhasivam 251b8be24ecSCristian Ciocaltea static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, 252b8be24ecSCristian Ciocaltea int num, bool atomic) 253d211e62aSManivannan Sadhasivam { 254d211e62aSManivannan Sadhasivam struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); 255d211e62aSManivannan Sadhasivam struct i2c_msg *msg; 256d211e62aSManivannan Sadhasivam unsigned long time_left, flags; 257d211e62aSManivannan Sadhasivam unsigned int i2c_cmd, val; 258d211e62aSManivannan Sadhasivam unsigned int addr; 259d211e62aSManivannan Sadhasivam int ret, idx; 260d211e62aSManivannan Sadhasivam 261d211e62aSManivannan Sadhasivam spin_lock_irqsave(&i2c_dev->lock, flags); 262d211e62aSManivannan Sadhasivam 263d211e62aSManivannan Sadhasivam /* Reset I2C controller */ 264d211e62aSManivannan Sadhasivam owl_i2c_reset(i2c_dev); 265d211e62aSManivannan Sadhasivam 266d211e62aSManivannan Sadhasivam /* Set bus frequency */ 267d211e62aSManivannan Sadhasivam owl_i2c_set_freq(i2c_dev); 268d211e62aSManivannan Sadhasivam 269d211e62aSManivannan Sadhasivam /* 270d211e62aSManivannan Sadhasivam * Spinlock should be released before calling reset FIFO and 271d211e62aSManivannan Sadhasivam * bus busy check since those functions may sleep 272d211e62aSManivannan Sadhasivam */ 273d211e62aSManivannan Sadhasivam spin_unlock_irqrestore(&i2c_dev->lock, flags); 274d211e62aSManivannan Sadhasivam 275d211e62aSManivannan Sadhasivam /* Reset FIFO */ 276d211e62aSManivannan Sadhasivam ret = owl_i2c_reset_fifo(i2c_dev); 277d211e62aSManivannan Sadhasivam if (ret) 278d211e62aSManivannan Sadhasivam goto unlocked_err_exit; 279d211e62aSManivannan Sadhasivam 280d211e62aSManivannan Sadhasivam /* Check for bus busy */ 281d211e62aSManivannan Sadhasivam ret = owl_i2c_check_bus_busy(adap); 282d211e62aSManivannan Sadhasivam if (ret) 283d211e62aSManivannan Sadhasivam goto unlocked_err_exit; 284d211e62aSManivannan Sadhasivam 285d211e62aSManivannan Sadhasivam spin_lock_irqsave(&i2c_dev->lock, flags); 286d211e62aSManivannan Sadhasivam 287d211e62aSManivannan Sadhasivam /* Check for Arbitration lost */ 288d211e62aSManivannan Sadhasivam val = readl(i2c_dev->base + OWL_I2C_REG_STAT); 289d211e62aSManivannan Sadhasivam if (val & OWL_I2C_STAT_LAB) { 290d211e62aSManivannan Sadhasivam val &= ~OWL_I2C_STAT_LAB; 291d211e62aSManivannan Sadhasivam writel(val, i2c_dev->base + OWL_I2C_REG_STAT); 292d211e62aSManivannan Sadhasivam ret = -EAGAIN; 293d211e62aSManivannan Sadhasivam goto err_exit; 294d211e62aSManivannan Sadhasivam } 295d211e62aSManivannan Sadhasivam 296b8be24ecSCristian Ciocaltea if (!atomic) 297d211e62aSManivannan Sadhasivam reinit_completion(&i2c_dev->msg_complete); 298d211e62aSManivannan Sadhasivam 299b8be24ecSCristian Ciocaltea /* Enable/disable I2C controller interrupt */ 300d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 301b8be24ecSCristian Ciocaltea OWL_I2C_CTL_IRQE, !atomic); 302d211e62aSManivannan Sadhasivam 303d211e62aSManivannan Sadhasivam /* 304d211e62aSManivannan Sadhasivam * Select: FIFO enable, Master mode, Stop enable, Data count enable, 305d211e62aSManivannan Sadhasivam * Send start bit 306d211e62aSManivannan Sadhasivam */ 307d211e62aSManivannan Sadhasivam i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE | 308d211e62aSManivannan Sadhasivam OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE; 309d211e62aSManivannan Sadhasivam 310d211e62aSManivannan Sadhasivam /* Handle repeated start condition */ 311d211e62aSManivannan Sadhasivam if (num > 1) { 312d211e62aSManivannan Sadhasivam /* Set internal address length and enable repeated start */ 313d211e62aSManivannan Sadhasivam i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) | 314d211e62aSManivannan Sadhasivam OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE; 315d211e62aSManivannan Sadhasivam 316d211e62aSManivannan Sadhasivam /* Write slave address */ 317d211e62aSManivannan Sadhasivam addr = i2c_8bit_addr_from_msg(&msgs[0]); 318d211e62aSManivannan Sadhasivam writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); 319d211e62aSManivannan Sadhasivam 320d211e62aSManivannan Sadhasivam /* Write internal register address */ 321d211e62aSManivannan Sadhasivam for (idx = 0; idx < msgs[0].len; idx++) 322d211e62aSManivannan Sadhasivam writel(msgs[0].buf[idx], 323d211e62aSManivannan Sadhasivam i2c_dev->base + OWL_I2C_REG_TXDAT); 324d211e62aSManivannan Sadhasivam 325d211e62aSManivannan Sadhasivam msg = &msgs[1]; 326d211e62aSManivannan Sadhasivam } else { 327d211e62aSManivannan Sadhasivam /* Set address length */ 328d211e62aSManivannan Sadhasivam i2c_cmd |= OWL_I2C_CMD_AS(1); 329d211e62aSManivannan Sadhasivam msg = &msgs[0]; 330d211e62aSManivannan Sadhasivam } 331d211e62aSManivannan Sadhasivam 332d211e62aSManivannan Sadhasivam i2c_dev->msg = msg; 333d211e62aSManivannan Sadhasivam i2c_dev->msg_ptr = 0; 334d211e62aSManivannan Sadhasivam 335d211e62aSManivannan Sadhasivam /* Set data count for the message */ 336d211e62aSManivannan Sadhasivam writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT); 337d211e62aSManivannan Sadhasivam 338d211e62aSManivannan Sadhasivam addr = i2c_8bit_addr_from_msg(msg); 339d211e62aSManivannan Sadhasivam writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); 340d211e62aSManivannan Sadhasivam 341d211e62aSManivannan Sadhasivam if (!(msg->flags & I2C_M_RD)) { 342d211e62aSManivannan Sadhasivam /* Write data to FIFO */ 343d211e62aSManivannan Sadhasivam for (idx = 0; idx < msg->len; idx++) { 344d211e62aSManivannan Sadhasivam /* Check for FIFO full */ 345d211e62aSManivannan Sadhasivam if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 346d211e62aSManivannan Sadhasivam OWL_I2C_FIFOSTAT_TFF) 347d211e62aSManivannan Sadhasivam break; 348d211e62aSManivannan Sadhasivam 349d211e62aSManivannan Sadhasivam writel(msg->buf[idx], 350d211e62aSManivannan Sadhasivam i2c_dev->base + OWL_I2C_REG_TXDAT); 351d211e62aSManivannan Sadhasivam } 352d211e62aSManivannan Sadhasivam 353d211e62aSManivannan Sadhasivam i2c_dev->msg_ptr = idx; 354d211e62aSManivannan Sadhasivam } 355d211e62aSManivannan Sadhasivam 356d211e62aSManivannan Sadhasivam /* Ignore the NACK if needed */ 357d211e62aSManivannan Sadhasivam if (msg->flags & I2C_M_IGNORE_NAK) 358d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 359d211e62aSManivannan Sadhasivam OWL_I2C_FIFOCTL_NIB, true); 360d211e62aSManivannan Sadhasivam else 361d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 362d211e62aSManivannan Sadhasivam OWL_I2C_FIFOCTL_NIB, false); 363d211e62aSManivannan Sadhasivam 364d211e62aSManivannan Sadhasivam /* Start the transfer */ 365d211e62aSManivannan Sadhasivam writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD); 366d211e62aSManivannan Sadhasivam 367d211e62aSManivannan Sadhasivam spin_unlock_irqrestore(&i2c_dev->lock, flags); 368d211e62aSManivannan Sadhasivam 369b8be24ecSCristian Ciocaltea if (atomic) { 370b8be24ecSCristian Ciocaltea /* Wait for Command Execute Completed or NACK Error bits */ 371b8be24ecSCristian Ciocaltea ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, 372b8be24ecSCristian Ciocaltea val, val & (OWL_I2C_FIFOSTAT_CECB | 373b8be24ecSCristian Ciocaltea OWL_I2C_FIFOSTAT_RNB), 374b8be24ecSCristian Ciocaltea 10, OWL_I2C_TIMEOUT_MS * 1000); 375b8be24ecSCristian Ciocaltea } else { 376d211e62aSManivannan Sadhasivam time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, 377d211e62aSManivannan Sadhasivam adap->timeout); 378b8be24ecSCristian Ciocaltea if (!time_left) 379b8be24ecSCristian Ciocaltea ret = -ETIMEDOUT; 380b8be24ecSCristian Ciocaltea } 381d211e62aSManivannan Sadhasivam 382d211e62aSManivannan Sadhasivam spin_lock_irqsave(&i2c_dev->lock, flags); 383b8be24ecSCristian Ciocaltea 384b8be24ecSCristian Ciocaltea if (ret) { 385d211e62aSManivannan Sadhasivam dev_err(&adap->dev, "Transaction timed out\n"); 386d211e62aSManivannan Sadhasivam /* Send stop condition and release the bus */ 387d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 388d211e62aSManivannan Sadhasivam OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB, 389d211e62aSManivannan Sadhasivam true); 390d211e62aSManivannan Sadhasivam goto err_exit; 391d211e62aSManivannan Sadhasivam } 392d211e62aSManivannan Sadhasivam 393b8be24ecSCristian Ciocaltea if (atomic) 394b8be24ecSCristian Ciocaltea owl_i2c_xfer_data(i2c_dev); 395b8be24ecSCristian Ciocaltea 396d211e62aSManivannan Sadhasivam ret = i2c_dev->err < 0 ? i2c_dev->err : num; 397d211e62aSManivannan Sadhasivam 398d211e62aSManivannan Sadhasivam err_exit: 399d211e62aSManivannan Sadhasivam spin_unlock_irqrestore(&i2c_dev->lock, flags); 400d211e62aSManivannan Sadhasivam 401d211e62aSManivannan Sadhasivam unlocked_err_exit: 402d211e62aSManivannan Sadhasivam /* Disable I2C controller */ 403d211e62aSManivannan Sadhasivam owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 404d211e62aSManivannan Sadhasivam OWL_I2C_CTL_EN, false); 405d211e62aSManivannan Sadhasivam 406d211e62aSManivannan Sadhasivam return ret; 407d211e62aSManivannan Sadhasivam } 408d211e62aSManivannan Sadhasivam 409b8be24ecSCristian Ciocaltea static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 410b8be24ecSCristian Ciocaltea int num) 411b8be24ecSCristian Ciocaltea { 412b8be24ecSCristian Ciocaltea return owl_i2c_xfer_common(adap, msgs, num, false); 413b8be24ecSCristian Ciocaltea } 414b8be24ecSCristian Ciocaltea 415b8be24ecSCristian Ciocaltea static int owl_i2c_xfer_atomic(struct i2c_adapter *adap, 416b8be24ecSCristian Ciocaltea struct i2c_msg *msgs, int num) 417b8be24ecSCristian Ciocaltea { 418b8be24ecSCristian Ciocaltea return owl_i2c_xfer_common(adap, msgs, num, true); 419b8be24ecSCristian Ciocaltea } 420b8be24ecSCristian Ciocaltea 421d211e62aSManivannan Sadhasivam static const struct i2c_algorithm owl_i2c_algorithm = { 422b8be24ecSCristian Ciocaltea .master_xfer = owl_i2c_xfer, 423b8be24ecSCristian Ciocaltea .master_xfer_atomic = owl_i2c_xfer_atomic, 424d211e62aSManivannan Sadhasivam .functionality = owl_i2c_func, 425d211e62aSManivannan Sadhasivam }; 426d211e62aSManivannan Sadhasivam 427d211e62aSManivannan Sadhasivam static const struct i2c_adapter_quirks owl_i2c_quirks = { 428d211e62aSManivannan Sadhasivam .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST, 429d211e62aSManivannan Sadhasivam .max_read_len = 240, 430d211e62aSManivannan Sadhasivam .max_write_len = 240, 431d211e62aSManivannan Sadhasivam .max_comb_1st_msg_len = 6, 432d211e62aSManivannan Sadhasivam .max_comb_2nd_msg_len = 240, 433d211e62aSManivannan Sadhasivam }; 434d211e62aSManivannan Sadhasivam 435d211e62aSManivannan Sadhasivam static int owl_i2c_probe(struct platform_device *pdev) 436d211e62aSManivannan Sadhasivam { 437d211e62aSManivannan Sadhasivam struct device *dev = &pdev->dev; 438d211e62aSManivannan Sadhasivam struct owl_i2c_dev *i2c_dev; 439d211e62aSManivannan Sadhasivam int ret, irq; 440d211e62aSManivannan Sadhasivam 441d211e62aSManivannan Sadhasivam i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL); 442d211e62aSManivannan Sadhasivam if (!i2c_dev) 443d211e62aSManivannan Sadhasivam return -ENOMEM; 444d211e62aSManivannan Sadhasivam 445e0442d76SDejin Zheng i2c_dev->base = devm_platform_ioremap_resource(pdev, 0); 446d211e62aSManivannan Sadhasivam if (IS_ERR(i2c_dev->base)) 447d211e62aSManivannan Sadhasivam return PTR_ERR(i2c_dev->base); 448d211e62aSManivannan Sadhasivam 449d211e62aSManivannan Sadhasivam irq = platform_get_irq(pdev, 0); 450e42688edSDejin Zheng if (irq < 0) 451d211e62aSManivannan Sadhasivam return irq; 452d211e62aSManivannan Sadhasivam 453d211e62aSManivannan Sadhasivam if (of_property_read_u32(dev->of_node, "clock-frequency", 454d211e62aSManivannan Sadhasivam &i2c_dev->bus_freq)) 45590224e64SAndy Shevchenko i2c_dev->bus_freq = I2C_MAX_STANDARD_MODE_FREQ; 456d211e62aSManivannan Sadhasivam 457d211e62aSManivannan Sadhasivam /* We support only frequencies of 100k and 400k for now */ 45890224e64SAndy Shevchenko if (i2c_dev->bus_freq != I2C_MAX_STANDARD_MODE_FREQ && 45990224e64SAndy Shevchenko i2c_dev->bus_freq != I2C_MAX_FAST_MODE_FREQ) { 460d211e62aSManivannan Sadhasivam dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq); 461d211e62aSManivannan Sadhasivam return -EINVAL; 462d211e62aSManivannan Sadhasivam } 463d211e62aSManivannan Sadhasivam 464d211e62aSManivannan Sadhasivam i2c_dev->clk = devm_clk_get(dev, NULL); 465d211e62aSManivannan Sadhasivam if (IS_ERR(i2c_dev->clk)) { 466d211e62aSManivannan Sadhasivam dev_err(dev, "failed to get clock\n"); 467d211e62aSManivannan Sadhasivam return PTR_ERR(i2c_dev->clk); 468d211e62aSManivannan Sadhasivam } 469d211e62aSManivannan Sadhasivam 470d211e62aSManivannan Sadhasivam ret = clk_prepare_enable(i2c_dev->clk); 471d211e62aSManivannan Sadhasivam if (ret) 472d211e62aSManivannan Sadhasivam return ret; 473d211e62aSManivannan Sadhasivam 474d211e62aSManivannan Sadhasivam i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk); 475d211e62aSManivannan Sadhasivam if (!i2c_dev->clk_rate) { 476d211e62aSManivannan Sadhasivam dev_err(dev, "input clock rate should not be zero\n"); 477d211e62aSManivannan Sadhasivam ret = -EINVAL; 478d211e62aSManivannan Sadhasivam goto disable_clk; 479d211e62aSManivannan Sadhasivam } 480d211e62aSManivannan Sadhasivam 481d211e62aSManivannan Sadhasivam init_completion(&i2c_dev->msg_complete); 482d211e62aSManivannan Sadhasivam spin_lock_init(&i2c_dev->lock); 483d211e62aSManivannan Sadhasivam i2c_dev->adap.owner = THIS_MODULE; 484d211e62aSManivannan Sadhasivam i2c_dev->adap.algo = &owl_i2c_algorithm; 485d211e62aSManivannan Sadhasivam i2c_dev->adap.timeout = OWL_I2C_TIMEOUT; 486d211e62aSManivannan Sadhasivam i2c_dev->adap.quirks = &owl_i2c_quirks; 487d211e62aSManivannan Sadhasivam i2c_dev->adap.dev.parent = dev; 488d211e62aSManivannan Sadhasivam i2c_dev->adap.dev.of_node = dev->of_node; 489d211e62aSManivannan Sadhasivam snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), 490d211e62aSManivannan Sadhasivam "%s", "OWL I2C adapter"); 491d211e62aSManivannan Sadhasivam i2c_set_adapdata(&i2c_dev->adap, i2c_dev); 492d211e62aSManivannan Sadhasivam 493d211e62aSManivannan Sadhasivam platform_set_drvdata(pdev, i2c_dev); 494d211e62aSManivannan Sadhasivam 495d211e62aSManivannan Sadhasivam ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name, 496d211e62aSManivannan Sadhasivam i2c_dev); 497d211e62aSManivannan Sadhasivam if (ret) { 498d211e62aSManivannan Sadhasivam dev_err(dev, "failed to request irq %d\n", irq); 499d211e62aSManivannan Sadhasivam goto disable_clk; 500d211e62aSManivannan Sadhasivam } 501d211e62aSManivannan Sadhasivam 502d211e62aSManivannan Sadhasivam return i2c_add_adapter(&i2c_dev->adap); 503d211e62aSManivannan Sadhasivam 504d211e62aSManivannan Sadhasivam disable_clk: 505d211e62aSManivannan Sadhasivam clk_disable_unprepare(i2c_dev->clk); 506d211e62aSManivannan Sadhasivam 507d211e62aSManivannan Sadhasivam return ret; 508d211e62aSManivannan Sadhasivam } 509d211e62aSManivannan Sadhasivam 510d211e62aSManivannan Sadhasivam static const struct of_device_id owl_i2c_of_match[] = { 51104fd6f0aSCristian Ciocaltea { .compatible = "actions,s500-i2c" }, 51281482d13SParthiban Nallathambi { .compatible = "actions,s700-i2c" }, 513d211e62aSManivannan Sadhasivam { .compatible = "actions,s900-i2c" }, 514d211e62aSManivannan Sadhasivam { /* sentinel */ } 515d211e62aSManivannan Sadhasivam }; 516d211e62aSManivannan Sadhasivam MODULE_DEVICE_TABLE(of, owl_i2c_of_match); 517d211e62aSManivannan Sadhasivam 518d211e62aSManivannan Sadhasivam static struct platform_driver owl_i2c_driver = { 519d211e62aSManivannan Sadhasivam .probe = owl_i2c_probe, 520d211e62aSManivannan Sadhasivam .driver = { 521d211e62aSManivannan Sadhasivam .name = "owl-i2c", 522*8759500cSKrzysztof Kozlowski .of_match_table = owl_i2c_of_match, 52346f8bfebSCristian Ciocaltea .probe_type = PROBE_PREFER_ASYNCHRONOUS, 524d211e62aSManivannan Sadhasivam }, 525d211e62aSManivannan Sadhasivam }; 526d211e62aSManivannan Sadhasivam module_platform_driver(owl_i2c_driver); 527d211e62aSManivannan Sadhasivam 528d211e62aSManivannan Sadhasivam MODULE_AUTHOR("David Liu <liuwei@actions-semi.com>"); 529d211e62aSManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 530d211e62aSManivannan Sadhasivam MODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver"); 531d211e62aSManivannan Sadhasivam MODULE_LICENSE("GPL"); 532