162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Actions Semiconductor Owl SoC's I2C driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014 Actions Semi Inc. 662306a36Sopenharmony_ci * Author: David Liu <liuwei@actions-semi.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2018 Linaro Ltd. 962306a36Sopenharmony_ci * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/iopoll.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/of.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* I2C registers */ 2362306a36Sopenharmony_ci#define OWL_I2C_REG_CTL 0x0000 2462306a36Sopenharmony_ci#define OWL_I2C_REG_CLKDIV 0x0004 2562306a36Sopenharmony_ci#define OWL_I2C_REG_STAT 0x0008 2662306a36Sopenharmony_ci#define OWL_I2C_REG_ADDR 0x000C 2762306a36Sopenharmony_ci#define OWL_I2C_REG_TXDAT 0x0010 2862306a36Sopenharmony_ci#define OWL_I2C_REG_RXDAT 0x0014 2962306a36Sopenharmony_ci#define OWL_I2C_REG_CMD 0x0018 3062306a36Sopenharmony_ci#define OWL_I2C_REG_FIFOCTL 0x001C 3162306a36Sopenharmony_ci#define OWL_I2C_REG_FIFOSTAT 0x0020 3262306a36Sopenharmony_ci#define OWL_I2C_REG_DATCNT 0x0024 3362306a36Sopenharmony_ci#define OWL_I2C_REG_RCNT 0x0028 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* I2Cx_CTL Bit Mask */ 3662306a36Sopenharmony_ci#define OWL_I2C_CTL_RB BIT(1) 3762306a36Sopenharmony_ci#define OWL_I2C_CTL_GBCC(x) (((x) & 0x3) << 2) 3862306a36Sopenharmony_ci#define OWL_I2C_CTL_GBCC_NONE OWL_I2C_CTL_GBCC(0) 3962306a36Sopenharmony_ci#define OWL_I2C_CTL_GBCC_START OWL_I2C_CTL_GBCC(1) 4062306a36Sopenharmony_ci#define OWL_I2C_CTL_GBCC_STOP OWL_I2C_CTL_GBCC(2) 4162306a36Sopenharmony_ci#define OWL_I2C_CTL_GBCC_RSTART OWL_I2C_CTL_GBCC(3) 4262306a36Sopenharmony_ci#define OWL_I2C_CTL_IRQE BIT(5) 4362306a36Sopenharmony_ci#define OWL_I2C_CTL_EN BIT(7) 4462306a36Sopenharmony_ci#define OWL_I2C_CTL_AE BIT(8) 4562306a36Sopenharmony_ci#define OWL_I2C_CTL_SHSM BIT(10) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define OWL_I2C_DIV_FACTOR(x) ((x) & 0xff) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* I2Cx_STAT Bit Mask */ 5062306a36Sopenharmony_ci#define OWL_I2C_STAT_RACK BIT(0) 5162306a36Sopenharmony_ci#define OWL_I2C_STAT_BEB BIT(1) 5262306a36Sopenharmony_ci#define OWL_I2C_STAT_IRQP BIT(2) 5362306a36Sopenharmony_ci#define OWL_I2C_STAT_LAB BIT(3) 5462306a36Sopenharmony_ci#define OWL_I2C_STAT_STPD BIT(4) 5562306a36Sopenharmony_ci#define OWL_I2C_STAT_STAD BIT(5) 5662306a36Sopenharmony_ci#define OWL_I2C_STAT_BBB BIT(6) 5762306a36Sopenharmony_ci#define OWL_I2C_STAT_TCB BIT(7) 5862306a36Sopenharmony_ci#define OWL_I2C_STAT_LBST BIT(8) 5962306a36Sopenharmony_ci#define OWL_I2C_STAT_SAMB BIT(9) 6062306a36Sopenharmony_ci#define OWL_I2C_STAT_SRGC BIT(10) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* I2Cx_CMD Bit Mask */ 6362306a36Sopenharmony_ci#define OWL_I2C_CMD_SBE BIT(0) 6462306a36Sopenharmony_ci#define OWL_I2C_CMD_RBE BIT(4) 6562306a36Sopenharmony_ci#define OWL_I2C_CMD_DE BIT(8) 6662306a36Sopenharmony_ci#define OWL_I2C_CMD_NS BIT(9) 6762306a36Sopenharmony_ci#define OWL_I2C_CMD_SE BIT(10) 6862306a36Sopenharmony_ci#define OWL_I2C_CMD_MSS BIT(11) 6962306a36Sopenharmony_ci#define OWL_I2C_CMD_WRS BIT(12) 7062306a36Sopenharmony_ci#define OWL_I2C_CMD_SECL BIT(15) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define OWL_I2C_CMD_AS(x) (((x) & 0x7) << 1) 7362306a36Sopenharmony_ci#define OWL_I2C_CMD_SAS(x) (((x) & 0x7) << 5) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* I2Cx_FIFOCTL Bit Mask */ 7662306a36Sopenharmony_ci#define OWL_I2C_FIFOCTL_NIB BIT(0) 7762306a36Sopenharmony_ci#define OWL_I2C_FIFOCTL_RFR BIT(1) 7862306a36Sopenharmony_ci#define OWL_I2C_FIFOCTL_TFR BIT(2) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* I2Cc_FIFOSTAT Bit Mask */ 8162306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_CECB BIT(0) 8262306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_RNB BIT(1) 8362306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_RFE BIT(2) 8462306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_TFF BIT(5) 8562306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_TFD GENMASK(23, 16) 8662306a36Sopenharmony_ci#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* I2C bus timeout */ 8962306a36Sopenharmony_ci#define OWL_I2C_TIMEOUT_MS (4 * 1000) 9062306a36Sopenharmony_ci#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define OWL_I2C_MAX_RETRIES 50 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct owl_i2c_dev { 9562306a36Sopenharmony_ci struct i2c_adapter adap; 9662306a36Sopenharmony_ci struct i2c_msg *msg; 9762306a36Sopenharmony_ci struct completion msg_complete; 9862306a36Sopenharmony_ci struct clk *clk; 9962306a36Sopenharmony_ci spinlock_t lock; 10062306a36Sopenharmony_ci void __iomem *base; 10162306a36Sopenharmony_ci unsigned long clk_rate; 10262306a36Sopenharmony_ci u32 bus_freq; 10362306a36Sopenharmony_ci u32 msg_ptr; 10462306a36Sopenharmony_ci int err; 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci unsigned int regval; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci regval = readl(reg); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (state) 11462306a36Sopenharmony_ci regval |= val; 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci regval &= ~val; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci writel(regval, reg); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void owl_i2c_reset(struct owl_i2c_dev *i2c_dev) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 12462306a36Sopenharmony_ci OWL_I2C_CTL_EN, false); 12562306a36Sopenharmony_ci mdelay(1); 12662306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 12762306a36Sopenharmony_ci OWL_I2C_CTL_EN, true); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Clear status registers */ 13062306a36Sopenharmony_ci writel(0, i2c_dev->base + OWL_I2C_REG_STAT); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci unsigned int val, timeout = 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Reset FIFO */ 13862306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 13962306a36Sopenharmony_ci OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR, 14062306a36Sopenharmony_ci true); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Wait 50ms for FIFO reset complete */ 14362306a36Sopenharmony_ci do { 14462306a36Sopenharmony_ci val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL); 14562306a36Sopenharmony_ci if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR))) 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci usleep_range(500, 1000); 14862306a36Sopenharmony_ci } while (timeout++ < OWL_I2C_MAX_RETRIES); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (timeout > OWL_I2C_MAX_RETRIES) { 15162306a36Sopenharmony_ci dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n"); 15262306a36Sopenharmony_ci return -ETIMEDOUT; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci unsigned int val; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Set clock divider factor */ 16562306a36Sopenharmony_ci writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct i2c_msg *msg = i2c_dev->msg; 17162306a36Sopenharmony_ci unsigned int stat, fifostat; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci i2c_dev->err = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Handle NACK from slave */ 17662306a36Sopenharmony_ci fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT); 17762306a36Sopenharmony_ci if (fifostat & OWL_I2C_FIFOSTAT_RNB) { 17862306a36Sopenharmony_ci i2c_dev->err = -ENXIO; 17962306a36Sopenharmony_ci /* Clear NACK error bit by writing "1" */ 18062306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, 18162306a36Sopenharmony_ci OWL_I2C_FIFOSTAT_RNB, true); 18262306a36Sopenharmony_ci return; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Handle bus error */ 18662306a36Sopenharmony_ci stat = readl(i2c_dev->base + OWL_I2C_REG_STAT); 18762306a36Sopenharmony_ci if (stat & OWL_I2C_STAT_BEB) { 18862306a36Sopenharmony_ci i2c_dev->err = -EIO; 18962306a36Sopenharmony_ci /* Clear BUS error bit by writing "1" */ 19062306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, 19162306a36Sopenharmony_ci OWL_I2C_STAT_BEB, true); 19262306a36Sopenharmony_ci return; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Handle FIFO read */ 19662306a36Sopenharmony_ci if (msg->flags & I2C_M_RD) { 19762306a36Sopenharmony_ci while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 19862306a36Sopenharmony_ci OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) { 19962306a36Sopenharmony_ci msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base + 20062306a36Sopenharmony_ci OWL_I2C_REG_RXDAT); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } else { 20362306a36Sopenharmony_ci /* Handle the remaining bytes which were not sent */ 20462306a36Sopenharmony_ci while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 20562306a36Sopenharmony_ci OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) { 20662306a36Sopenharmony_ci writel(msg->buf[i2c_dev->msg_ptr++], 20762306a36Sopenharmony_ci i2c_dev->base + OWL_I2C_REG_TXDAT); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic irqreturn_t owl_i2c_interrupt(int irq, void *_dev) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct owl_i2c_dev *i2c_dev = _dev; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci spin_lock(&i2c_dev->lock); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci owl_i2c_xfer_data(i2c_dev); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* Clear pending interrupts */ 22162306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, 22262306a36Sopenharmony_ci OWL_I2C_STAT_IRQP, true); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci complete_all(&i2c_dev->msg_complete); 22562306a36Sopenharmony_ci spin_unlock(&i2c_dev->lock); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return IRQ_HANDLED; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic u32 owl_i2c_func(struct i2c_adapter *adap) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int owl_i2c_check_bus_busy(struct i2c_adapter *adap) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); 23862306a36Sopenharmony_ci unsigned long timeout; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Check for Bus busy */ 24162306a36Sopenharmony_ci timeout = jiffies + OWL_I2C_TIMEOUT; 24262306a36Sopenharmony_ci while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) { 24362306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 24462306a36Sopenharmony_ci dev_err(&adap->dev, "Bus busy timeout\n"); 24562306a36Sopenharmony_ci return -ETIMEDOUT; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, 25362306a36Sopenharmony_ci int num, bool atomic) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); 25662306a36Sopenharmony_ci struct i2c_msg *msg; 25762306a36Sopenharmony_ci unsigned long time_left, flags; 25862306a36Sopenharmony_ci unsigned int i2c_cmd, val; 25962306a36Sopenharmony_ci unsigned int addr; 26062306a36Sopenharmony_ci int ret, idx; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci spin_lock_irqsave(&i2c_dev->lock, flags); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Reset I2C controller */ 26562306a36Sopenharmony_ci owl_i2c_reset(i2c_dev); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Set bus frequency */ 26862306a36Sopenharmony_ci owl_i2c_set_freq(i2c_dev); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * Spinlock should be released before calling reset FIFO and 27262306a36Sopenharmony_ci * bus busy check since those functions may sleep 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_dev->lock, flags); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Reset FIFO */ 27762306a36Sopenharmony_ci ret = owl_i2c_reset_fifo(i2c_dev); 27862306a36Sopenharmony_ci if (ret) 27962306a36Sopenharmony_ci goto unlocked_err_exit; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Check for bus busy */ 28262306a36Sopenharmony_ci ret = owl_i2c_check_bus_busy(adap); 28362306a36Sopenharmony_ci if (ret) 28462306a36Sopenharmony_ci goto unlocked_err_exit; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci spin_lock_irqsave(&i2c_dev->lock, flags); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Check for Arbitration lost */ 28962306a36Sopenharmony_ci val = readl(i2c_dev->base + OWL_I2C_REG_STAT); 29062306a36Sopenharmony_ci if (val & OWL_I2C_STAT_LAB) { 29162306a36Sopenharmony_ci val &= ~OWL_I2C_STAT_LAB; 29262306a36Sopenharmony_ci writel(val, i2c_dev->base + OWL_I2C_REG_STAT); 29362306a36Sopenharmony_ci ret = -EAGAIN; 29462306a36Sopenharmony_ci goto err_exit; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!atomic) 29862306a36Sopenharmony_ci reinit_completion(&i2c_dev->msg_complete); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Enable/disable I2C controller interrupt */ 30162306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 30262306a36Sopenharmony_ci OWL_I2C_CTL_IRQE, !atomic); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * Select: FIFO enable, Master mode, Stop enable, Data count enable, 30662306a36Sopenharmony_ci * Send start bit 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE | 30962306a36Sopenharmony_ci OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Handle repeated start condition */ 31262306a36Sopenharmony_ci if (num > 1) { 31362306a36Sopenharmony_ci /* Set internal address length and enable repeated start */ 31462306a36Sopenharmony_ci i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) | 31562306a36Sopenharmony_ci OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Write slave address */ 31862306a36Sopenharmony_ci addr = i2c_8bit_addr_from_msg(&msgs[0]); 31962306a36Sopenharmony_ci writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Write internal register address */ 32262306a36Sopenharmony_ci for (idx = 0; idx < msgs[0].len; idx++) 32362306a36Sopenharmony_ci writel(msgs[0].buf[idx], 32462306a36Sopenharmony_ci i2c_dev->base + OWL_I2C_REG_TXDAT); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci msg = &msgs[1]; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci /* Set address length */ 32962306a36Sopenharmony_ci i2c_cmd |= OWL_I2C_CMD_AS(1); 33062306a36Sopenharmony_ci msg = &msgs[0]; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci i2c_dev->msg = msg; 33462306a36Sopenharmony_ci i2c_dev->msg_ptr = 0; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Set data count for the message */ 33762306a36Sopenharmony_ci writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci addr = i2c_8bit_addr_from_msg(msg); 34062306a36Sopenharmony_ci writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!(msg->flags & I2C_M_RD)) { 34362306a36Sopenharmony_ci /* Write data to FIFO */ 34462306a36Sopenharmony_ci for (idx = 0; idx < msg->len; idx++) { 34562306a36Sopenharmony_ci /* Check for FIFO full */ 34662306a36Sopenharmony_ci if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & 34762306a36Sopenharmony_ci OWL_I2C_FIFOSTAT_TFF) 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci writel(msg->buf[idx], 35162306a36Sopenharmony_ci i2c_dev->base + OWL_I2C_REG_TXDAT); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci i2c_dev->msg_ptr = idx; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Ignore the NACK if needed */ 35862306a36Sopenharmony_ci if (msg->flags & I2C_M_IGNORE_NAK) 35962306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 36062306a36Sopenharmony_ci OWL_I2C_FIFOCTL_NIB, true); 36162306a36Sopenharmony_ci else 36262306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, 36362306a36Sopenharmony_ci OWL_I2C_FIFOCTL_NIB, false); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Start the transfer */ 36662306a36Sopenharmony_ci writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_dev->lock, flags); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (atomic) { 37162306a36Sopenharmony_ci /* Wait for Command Execute Completed or NACK Error bits */ 37262306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT, 37362306a36Sopenharmony_ci val, val & (OWL_I2C_FIFOSTAT_CECB | 37462306a36Sopenharmony_ci OWL_I2C_FIFOSTAT_RNB), 37562306a36Sopenharmony_ci 10, OWL_I2C_TIMEOUT_MS * 1000); 37662306a36Sopenharmony_ci } else { 37762306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, 37862306a36Sopenharmony_ci adap->timeout); 37962306a36Sopenharmony_ci if (!time_left) 38062306a36Sopenharmony_ci ret = -ETIMEDOUT; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_lock_irqsave(&i2c_dev->lock, flags); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (ret) { 38662306a36Sopenharmony_ci dev_err(&adap->dev, "Transaction timed out\n"); 38762306a36Sopenharmony_ci /* Send stop condition and release the bus */ 38862306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 38962306a36Sopenharmony_ci OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB, 39062306a36Sopenharmony_ci true); 39162306a36Sopenharmony_ci goto err_exit; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (atomic) 39562306a36Sopenharmony_ci owl_i2c_xfer_data(i2c_dev); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = i2c_dev->err < 0 ? i2c_dev->err : num; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cierr_exit: 40062306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_dev->lock, flags); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciunlocked_err_exit: 40362306a36Sopenharmony_ci /* Disable I2C controller */ 40462306a36Sopenharmony_ci owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, 40562306a36Sopenharmony_ci OWL_I2C_CTL_EN, false); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 41162306a36Sopenharmony_ci int num) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci return owl_i2c_xfer_common(adap, msgs, num, false); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int owl_i2c_xfer_atomic(struct i2c_adapter *adap, 41762306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci return owl_i2c_xfer_common(adap, msgs, num, true); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic const struct i2c_algorithm owl_i2c_algorithm = { 42362306a36Sopenharmony_ci .master_xfer = owl_i2c_xfer, 42462306a36Sopenharmony_ci .master_xfer_atomic = owl_i2c_xfer_atomic, 42562306a36Sopenharmony_ci .functionality = owl_i2c_func, 42662306a36Sopenharmony_ci}; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const struct i2c_adapter_quirks owl_i2c_quirks = { 42962306a36Sopenharmony_ci .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST, 43062306a36Sopenharmony_ci .max_read_len = 240, 43162306a36Sopenharmony_ci .max_write_len = 240, 43262306a36Sopenharmony_ci .max_comb_1st_msg_len = 6, 43362306a36Sopenharmony_ci .max_comb_2nd_msg_len = 240, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int owl_i2c_probe(struct platform_device *pdev) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 43962306a36Sopenharmony_ci struct owl_i2c_dev *i2c_dev; 44062306a36Sopenharmony_ci int ret, irq; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL); 44362306a36Sopenharmony_ci if (!i2c_dev) 44462306a36Sopenharmony_ci return -ENOMEM; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci i2c_dev->base = devm_platform_ioremap_resource(pdev, 0); 44762306a36Sopenharmony_ci if (IS_ERR(i2c_dev->base)) 44862306a36Sopenharmony_ci return PTR_ERR(i2c_dev->base); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 45162306a36Sopenharmony_ci if (irq < 0) 45262306a36Sopenharmony_ci return irq; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (of_property_read_u32(dev->of_node, "clock-frequency", 45562306a36Sopenharmony_ci &i2c_dev->bus_freq)) 45662306a36Sopenharmony_ci i2c_dev->bus_freq = I2C_MAX_STANDARD_MODE_FREQ; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* We support only frequencies of 100k and 400k for now */ 45962306a36Sopenharmony_ci if (i2c_dev->bus_freq != I2C_MAX_STANDARD_MODE_FREQ && 46062306a36Sopenharmony_ci i2c_dev->bus_freq != I2C_MAX_FAST_MODE_FREQ) { 46162306a36Sopenharmony_ci dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq); 46262306a36Sopenharmony_ci return -EINVAL; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci i2c_dev->clk = devm_clk_get_enabled(dev, NULL); 46662306a36Sopenharmony_ci if (IS_ERR(i2c_dev->clk)) { 46762306a36Sopenharmony_ci dev_err(dev, "failed to enable clock\n"); 46862306a36Sopenharmony_ci return PTR_ERR(i2c_dev->clk); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk); 47262306a36Sopenharmony_ci if (!i2c_dev->clk_rate) { 47362306a36Sopenharmony_ci dev_err(dev, "input clock rate should not be zero\n"); 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci init_completion(&i2c_dev->msg_complete); 47862306a36Sopenharmony_ci spin_lock_init(&i2c_dev->lock); 47962306a36Sopenharmony_ci i2c_dev->adap.owner = THIS_MODULE; 48062306a36Sopenharmony_ci i2c_dev->adap.algo = &owl_i2c_algorithm; 48162306a36Sopenharmony_ci i2c_dev->adap.timeout = OWL_I2C_TIMEOUT; 48262306a36Sopenharmony_ci i2c_dev->adap.quirks = &owl_i2c_quirks; 48362306a36Sopenharmony_ci i2c_dev->adap.dev.parent = dev; 48462306a36Sopenharmony_ci i2c_dev->adap.dev.of_node = dev->of_node; 48562306a36Sopenharmony_ci snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), 48662306a36Sopenharmony_ci "%s", "OWL I2C adapter"); 48762306a36Sopenharmony_ci i2c_set_adapdata(&i2c_dev->adap, i2c_dev); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci platform_set_drvdata(pdev, i2c_dev); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name, 49262306a36Sopenharmony_ci i2c_dev); 49362306a36Sopenharmony_ci if (ret) { 49462306a36Sopenharmony_ci dev_err(dev, "failed to request irq %d\n", irq); 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return i2c_add_adapter(&i2c_dev->adap); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic const struct of_device_id owl_i2c_of_match[] = { 50262306a36Sopenharmony_ci { .compatible = "actions,s500-i2c" }, 50362306a36Sopenharmony_ci { .compatible = "actions,s700-i2c" }, 50462306a36Sopenharmony_ci { .compatible = "actions,s900-i2c" }, 50562306a36Sopenharmony_ci { /* sentinel */ } 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, owl_i2c_of_match); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic struct platform_driver owl_i2c_driver = { 51062306a36Sopenharmony_ci .probe = owl_i2c_probe, 51162306a36Sopenharmony_ci .driver = { 51262306a36Sopenharmony_ci .name = "owl-i2c", 51362306a36Sopenharmony_ci .of_match_table = owl_i2c_of_match, 51462306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 51562306a36Sopenharmony_ci }, 51662306a36Sopenharmony_ci}; 51762306a36Sopenharmony_cimodule_platform_driver(owl_i2c_driver); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ciMODULE_AUTHOR("David Liu <liuwei@actions-semi.com>"); 52062306a36Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 52162306a36Sopenharmony_ciMODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver"); 52262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 523