12bbd681bSSubhendu Sekhar Behera /* 22bbd681bSSubhendu Sekhar Behera * Copyright (c) 2003-2015 Broadcom Corporation 32bbd681bSSubhendu Sekhar Behera * 42bbd681bSSubhendu Sekhar Behera * This file is licensed under the terms of the GNU General Public 52bbd681bSSubhendu Sekhar Behera * License version 2. This program is licensed "as is" without any 62bbd681bSSubhendu Sekhar Behera * warranty of any kind, whether express or implied. 72bbd681bSSubhendu Sekhar Behera */ 82bbd681bSSubhendu Sekhar Behera 9748c0bbbSTanmay Jagdale #include <linux/acpi.h> 10c347b8fcSJayachandran C #include <linux/clk.h> 112bbd681bSSubhendu Sekhar Behera #include <linux/completion.h> 122bbd681bSSubhendu Sekhar Behera #include <linux/i2c.h> 132bbd681bSSubhendu Sekhar Behera #include <linux/init.h> 142bbd681bSSubhendu Sekhar Behera #include <linux/interrupt.h> 152bbd681bSSubhendu Sekhar Behera #include <linux/io.h> 162bbd681bSSubhendu Sekhar Behera #include <linux/kernel.h> 172bbd681bSSubhendu Sekhar Behera #include <linux/module.h> 182bbd681bSSubhendu Sekhar Behera #include <linux/platform_device.h> 192bbd681bSSubhendu Sekhar Behera 202bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_DIV 0x0 212bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL 0x1 222bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD 0x2 232bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_STATUS 0x3 242bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MTXFIFO 0x4 252bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MRXFIFO 0x5 262bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MFIFOCTRL 0x6 272bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_STXFIFO 0x7 282bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_SRXFIFO 0x8 292bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_SFIFOCTRL 0x9 302bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_SLAVEADDR 0xA 312bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_OWNADDR 0xB 322bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_FIFOWCNT 0xC 332bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN 0xD 342bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTST 0xE 352bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_WAITCNT 0xF 362bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_TIMEOUT 0X10 372bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_GENCALLADDR 0x11 382bbd681bSSubhendu Sekhar Behera 392bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD_START BIT(7) 402bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD_STOP BIT(6) 412bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD_READ BIT(5) 422bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD_WRITE BIT(4) 432bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CMD_ACK BIT(3) 442bbd681bSSubhendu Sekhar Behera 452bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16 462bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000 472bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_RST BIT(8) 482bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_EN BIT(6) 492bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_MASTER BIT(4) 502bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_FIFORD BIT(1) 512bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_CTRL_ADDMODE BIT(0) 522bbd681bSSubhendu Sekhar Behera 532bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_NACKADDR BIT(25) 542bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_SADDR BIT(13) 552bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_DATADONE BIT(12) 562bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_ARLOST BIT(11) 572bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4) 582bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3) 592bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_MFIFOHI BIT(2) 602bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_INTEN_BUSERR BIT(0) 612bbd681bSSubhendu Sekhar Behera 622bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8 632bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0 642bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_MFIFOCTRL_RST BIT(16) 652bbd681bSSubhendu Sekhar Behera 662bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_SLAVEADDR_RW BIT(0) 672bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1 682bbd681bSSubhendu Sekhar Behera 692bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_IP_CLK_FREQ 133000000UL 702bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_DEFAULT_FREQ 100000 712bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_HIGH_FREQ 400000 722bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_FIFO_SIZE 0x80U 732bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_TIMEOUT_MS 1000 742bbd681bSSubhendu Sekhar Behera 752bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_FIFO_WCNT_MASK 0xff 762bbd681bSSubhendu Sekhar Behera #define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \ 772bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR) 782bbd681bSSubhendu Sekhar Behera 792bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev { 802bbd681bSSubhendu Sekhar Behera struct device *dev; 812bbd681bSSubhendu Sekhar Behera struct i2c_adapter adapter; 822bbd681bSSubhendu Sekhar Behera struct completion msg_complete; 832bbd681bSSubhendu Sekhar Behera int irq; 842bbd681bSSubhendu Sekhar Behera bool msg_read; 852bbd681bSSubhendu Sekhar Behera u32 __iomem *base; 862bbd681bSSubhendu Sekhar Behera u32 msg_buf_remaining; 872bbd681bSSubhendu Sekhar Behera u32 msg_len; 88c347b8fcSJayachandran C u32 ip_clk_hz; 892bbd681bSSubhendu Sekhar Behera u32 clk_hz; 902bbd681bSSubhendu Sekhar Behera u32 msg_err; 912bbd681bSSubhendu Sekhar Behera u8 *msg_buf; 922bbd681bSSubhendu Sekhar Behera }; 932bbd681bSSubhendu Sekhar Behera 942bbd681bSSubhendu Sekhar Behera static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv, 952bbd681bSSubhendu Sekhar Behera unsigned long reg, u32 val) 962bbd681bSSubhendu Sekhar Behera { 972bbd681bSSubhendu Sekhar Behera writel(val, priv->base + reg); 982bbd681bSSubhendu Sekhar Behera } 992bbd681bSSubhendu Sekhar Behera 1002bbd681bSSubhendu Sekhar Behera static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv, 1012bbd681bSSubhendu Sekhar Behera unsigned long reg) 1022bbd681bSSubhendu Sekhar Behera { 1032bbd681bSSubhendu Sekhar Behera return readl(priv->base + reg); 1042bbd681bSSubhendu Sekhar Behera } 1052bbd681bSSubhendu Sekhar Behera 1062bbd681bSSubhendu Sekhar Behera static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) 1072bbd681bSSubhendu Sekhar Behera { 1082bbd681bSSubhendu Sekhar Behera u32 inten; 1092bbd681bSSubhendu Sekhar Behera 1102bbd681bSSubhendu Sekhar Behera inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask; 1112bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); 1122bbd681bSSubhendu Sekhar Behera } 1132bbd681bSSubhendu Sekhar Behera 1142bbd681bSSubhendu Sekhar Behera static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) 1152bbd681bSSubhendu Sekhar Behera { 1162bbd681bSSubhendu Sekhar Behera u32 inten; 1172bbd681bSSubhendu Sekhar Behera 1182bbd681bSSubhendu Sekhar Behera inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask; 1192bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); 1202bbd681bSSubhendu Sekhar Behera } 1212bbd681bSSubhendu Sekhar Behera 1222bbd681bSSubhendu Sekhar Behera static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv) 1232bbd681bSSubhendu Sekhar Behera { 1242bbd681bSSubhendu Sekhar Behera u32 thres; 1252bbd681bSSubhendu Sekhar Behera 1262bbd681bSSubhendu Sekhar Behera thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); 1272bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, 1282bbd681bSSubhendu Sekhar Behera thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT); 1292bbd681bSSubhendu Sekhar Behera } 1302bbd681bSSubhendu Sekhar Behera 1312bbd681bSSubhendu Sekhar Behera static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) 1322bbd681bSSubhendu Sekhar Behera { 1332bbd681bSSubhendu Sekhar Behera u32 len, i; 1342bbd681bSSubhendu Sekhar Behera u8 *buf = priv->msg_buf; 1352bbd681bSSubhendu Sekhar Behera 1362bbd681bSSubhendu Sekhar Behera len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); 1372bbd681bSSubhendu Sekhar Behera for (i = 0; i < len; i++) 1382bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]); 1392bbd681bSSubhendu Sekhar Behera priv->msg_buf_remaining -= len; 1402bbd681bSSubhendu Sekhar Behera priv->msg_buf += len; 1412bbd681bSSubhendu Sekhar Behera } 1422bbd681bSSubhendu Sekhar Behera 1432bbd681bSSubhendu Sekhar Behera static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) 1442bbd681bSSubhendu Sekhar Behera { 1452bbd681bSSubhendu Sekhar Behera u32 len, i; 1462bbd681bSSubhendu Sekhar Behera u8 *buf = priv->msg_buf; 1472bbd681bSSubhendu Sekhar Behera 1482bbd681bSSubhendu Sekhar Behera len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & 1492bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_FIFO_WCNT_MASK; 1502bbd681bSSubhendu Sekhar Behera len = min(priv->msg_buf_remaining, len); 1512bbd681bSSubhendu Sekhar Behera for (i = 0; i < len; i++, buf++) 1522bbd681bSSubhendu Sekhar Behera *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); 1532bbd681bSSubhendu Sekhar Behera 1542bbd681bSSubhendu Sekhar Behera priv->msg_buf_remaining -= len; 1552bbd681bSSubhendu Sekhar Behera priv->msg_buf = buf; 1562bbd681bSSubhendu Sekhar Behera 1572bbd681bSSubhendu Sekhar Behera if (priv->msg_buf_remaining) 1582bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_update_rx_fifo_thres(priv); 1592bbd681bSSubhendu Sekhar Behera } 1602bbd681bSSubhendu Sekhar Behera 1612bbd681bSSubhendu Sekhar Behera static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id) 1622bbd681bSSubhendu Sekhar Behera { 1632bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev *priv = dev_id; 1642bbd681bSSubhendu Sekhar Behera u32 status; 1652bbd681bSSubhendu Sekhar Behera 1662bbd681bSSubhendu Sekhar Behera status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST); 1672bbd681bSSubhendu Sekhar Behera if (status == 0) 1682bbd681bSSubhendu Sekhar Behera return IRQ_NONE; 1692bbd681bSSubhendu Sekhar Behera 1702bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status); 1712bbd681bSSubhendu Sekhar Behera if (status & XLP9XX_I2C_STATUS_ERRMASK) { 1722bbd681bSSubhendu Sekhar Behera priv->msg_err = status; 1732bbd681bSSubhendu Sekhar Behera goto xfer_done; 1742bbd681bSSubhendu Sekhar Behera } 1752bbd681bSSubhendu Sekhar Behera 1762bbd681bSSubhendu Sekhar Behera /* SADDR ACK for SMBUS_QUICK */ 1772bbd681bSSubhendu Sekhar Behera if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0)) 1782bbd681bSSubhendu Sekhar Behera goto xfer_done; 1792bbd681bSSubhendu Sekhar Behera 1802bbd681bSSubhendu Sekhar Behera if (!priv->msg_read) { 1812bbd681bSSubhendu Sekhar Behera if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) { 1822bbd681bSSubhendu Sekhar Behera /* TX FIFO got empty, fill it up again */ 1832bbd681bSSubhendu Sekhar Behera if (priv->msg_buf_remaining) 1842bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_fill_tx_fifo(priv); 1852bbd681bSSubhendu Sekhar Behera else 1862bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_mask_irq(priv, 1872bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_INTEN_MFIFOEMTY); 1882bbd681bSSubhendu Sekhar Behera } 1892bbd681bSSubhendu Sekhar Behera } else { 1902bbd681bSSubhendu Sekhar Behera if (status & (XLP9XX_I2C_INTEN_DATADONE | 1912bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_INTEN_MFIFOHI)) { 1922bbd681bSSubhendu Sekhar Behera /* data is in FIFO, read it */ 1932bbd681bSSubhendu Sekhar Behera if (priv->msg_buf_remaining) 1942bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_drain_rx_fifo(priv); 1952bbd681bSSubhendu Sekhar Behera } 1962bbd681bSSubhendu Sekhar Behera } 1972bbd681bSSubhendu Sekhar Behera 1982bbd681bSSubhendu Sekhar Behera /* Transfer complete */ 1992bbd681bSSubhendu Sekhar Behera if (status & XLP9XX_I2C_INTEN_DATADONE) 2002bbd681bSSubhendu Sekhar Behera goto xfer_done; 2012bbd681bSSubhendu Sekhar Behera 2022bbd681bSSubhendu Sekhar Behera return IRQ_HANDLED; 2032bbd681bSSubhendu Sekhar Behera 2042bbd681bSSubhendu Sekhar Behera xfer_done: 2052bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); 2062bbd681bSSubhendu Sekhar Behera complete(&priv->msg_complete); 2072bbd681bSSubhendu Sekhar Behera return IRQ_HANDLED; 2082bbd681bSSubhendu Sekhar Behera } 2092bbd681bSSubhendu Sekhar Behera 2102bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) 2112bbd681bSSubhendu Sekhar Behera { 2122bbd681bSSubhendu Sekhar Behera u32 prescale; 2132bbd681bSSubhendu Sekhar Behera 2142bbd681bSSubhendu Sekhar Behera /* 2152bbd681bSSubhendu Sekhar Behera * The controller uses 5 * SCL clock internally. 2162bbd681bSSubhendu Sekhar Behera * So prescale value should be divided by 5. 2172bbd681bSSubhendu Sekhar Behera */ 218c347b8fcSJayachandran C prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz); 2192bbd681bSSubhendu Sekhar Behera prescale = ((prescale - 8) / 5) - 1; 2202bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); 2212bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | 2222bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_CTRL_MASTER); 2232bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale); 2242bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); 2252bbd681bSSubhendu Sekhar Behera 2262bbd681bSSubhendu Sekhar Behera return 0; 2272bbd681bSSubhendu Sekhar Behera } 2282bbd681bSSubhendu Sekhar Behera 2292bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, 2302bbd681bSSubhendu Sekhar Behera int last_msg) 2312bbd681bSSubhendu Sekhar Behera { 2322bbd681bSSubhendu Sekhar Behera unsigned long timeleft; 2332bbd681bSSubhendu Sekhar Behera u32 intr_mask, cmd, val; 2342bbd681bSSubhendu Sekhar Behera 2352bbd681bSSubhendu Sekhar Behera priv->msg_buf = msg->buf; 2362bbd681bSSubhendu Sekhar Behera priv->msg_buf_remaining = priv->msg_len = msg->len; 2372bbd681bSSubhendu Sekhar Behera priv->msg_err = 0; 2382bbd681bSSubhendu Sekhar Behera priv->msg_read = (msg->flags & I2C_M_RD); 2392bbd681bSSubhendu Sekhar Behera reinit_completion(&priv->msg_complete); 2402bbd681bSSubhendu Sekhar Behera 2412bbd681bSSubhendu Sekhar Behera /* Reset FIFO */ 2422bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, 2432bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_MFIFOCTRL_RST); 2442bbd681bSSubhendu Sekhar Behera 2452bbd681bSSubhendu Sekhar Behera /* set FIFO threshold if reading */ 2462bbd681bSSubhendu Sekhar Behera if (priv->msg_read) 2472bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_update_rx_fifo_thres(priv); 2482bbd681bSSubhendu Sekhar Behera 2492bbd681bSSubhendu Sekhar Behera /* set slave addr */ 2502bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, 2512bbd681bSSubhendu Sekhar Behera (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | 2522bbd681bSSubhendu Sekhar Behera (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0)); 2532bbd681bSSubhendu Sekhar Behera 2542bbd681bSSubhendu Sekhar Behera /* Build control word for transfer */ 2552bbd681bSSubhendu Sekhar Behera val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); 2562bbd681bSSubhendu Sekhar Behera if (!priv->msg_read) 2572bbd681bSSubhendu Sekhar Behera val &= ~XLP9XX_I2C_CTRL_FIFORD; 2582bbd681bSSubhendu Sekhar Behera else 2592bbd681bSSubhendu Sekhar Behera val |= XLP9XX_I2C_CTRL_FIFORD; /* read */ 2602bbd681bSSubhendu Sekhar Behera 2612bbd681bSSubhendu Sekhar Behera if (msg->flags & I2C_M_TEN) 2622bbd681bSSubhendu Sekhar Behera val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ 2632bbd681bSSubhendu Sekhar Behera else 2642bbd681bSSubhendu Sekhar Behera val &= ~XLP9XX_I2C_CTRL_ADDMODE; 2652bbd681bSSubhendu Sekhar Behera 2662bbd681bSSubhendu Sekhar Behera /* set data length to be transferred */ 2672bbd681bSSubhendu Sekhar Behera val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | 2682bbd681bSSubhendu Sekhar Behera (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); 2692bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); 2702bbd681bSSubhendu Sekhar Behera 2712bbd681bSSubhendu Sekhar Behera /* fill fifo during tx */ 2722bbd681bSSubhendu Sekhar Behera if (!priv->msg_read) 2732bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_fill_tx_fifo(priv); 2742bbd681bSSubhendu Sekhar Behera 2752bbd681bSSubhendu Sekhar Behera /* set interrupt mask */ 2762bbd681bSSubhendu Sekhar Behera intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR | 2772bbd681bSSubhendu Sekhar Behera XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE); 2782bbd681bSSubhendu Sekhar Behera 2792bbd681bSSubhendu Sekhar Behera if (priv->msg_read) { 2802bbd681bSSubhendu Sekhar Behera intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI; 2812bbd681bSSubhendu Sekhar Behera if (msg->len == 0) 2822bbd681bSSubhendu Sekhar Behera intr_mask |= XLP9XX_I2C_INTEN_SADDR; 2832bbd681bSSubhendu Sekhar Behera } else { 2842bbd681bSSubhendu Sekhar Behera if (msg->len == 0) 2852bbd681bSSubhendu Sekhar Behera intr_mask |= XLP9XX_I2C_INTEN_SADDR; 2862bbd681bSSubhendu Sekhar Behera else 2872bbd681bSSubhendu Sekhar Behera intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY; 2882bbd681bSSubhendu Sekhar Behera } 2892bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_unmask_irq(priv, intr_mask); 2902bbd681bSSubhendu Sekhar Behera 2912bbd681bSSubhendu Sekhar Behera /* set cmd reg */ 2922bbd681bSSubhendu Sekhar Behera cmd = XLP9XX_I2C_CMD_START; 2932bbd681bSSubhendu Sekhar Behera cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); 2942bbd681bSSubhendu Sekhar Behera if (last_msg) 2952bbd681bSSubhendu Sekhar Behera cmd |= XLP9XX_I2C_CMD_STOP; 2962bbd681bSSubhendu Sekhar Behera 2972bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd); 2982bbd681bSSubhendu Sekhar Behera 2992bbd681bSSubhendu Sekhar Behera timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); 3002bbd681bSSubhendu Sekhar Behera timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); 3012bbd681bSSubhendu Sekhar Behera 3022bbd681bSSubhendu Sekhar Behera if (priv->msg_err) { 3032bbd681bSSubhendu Sekhar Behera dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); 3042bbd681bSSubhendu Sekhar Behera if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) 3052bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_init(priv); 3062bbd681bSSubhendu Sekhar Behera return -EIO; 3072bbd681bSSubhendu Sekhar Behera } 3082bbd681bSSubhendu Sekhar Behera 3092bbd681bSSubhendu Sekhar Behera if (timeleft == 0) { 3102bbd681bSSubhendu Sekhar Behera dev_dbg(priv->dev, "i2c transfer timed out!\n"); 3112bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_init(priv); 3122bbd681bSSubhendu Sekhar Behera return -ETIMEDOUT; 3132bbd681bSSubhendu Sekhar Behera } 3142bbd681bSSubhendu Sekhar Behera 3152bbd681bSSubhendu Sekhar Behera return 0; 3162bbd681bSSubhendu Sekhar Behera } 3172bbd681bSSubhendu Sekhar Behera 3182bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 3192bbd681bSSubhendu Sekhar Behera int num) 3202bbd681bSSubhendu Sekhar Behera { 3212bbd681bSSubhendu Sekhar Behera int i, ret; 3222bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap); 3232bbd681bSSubhendu Sekhar Behera 3242bbd681bSSubhendu Sekhar Behera for (i = 0; i < num; i++) { 3252bbd681bSSubhendu Sekhar Behera ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); 3262bbd681bSSubhendu Sekhar Behera if (ret != 0) 3272bbd681bSSubhendu Sekhar Behera return ret; 3282bbd681bSSubhendu Sekhar Behera } 3292bbd681bSSubhendu Sekhar Behera 3302bbd681bSSubhendu Sekhar Behera return num; 3312bbd681bSSubhendu Sekhar Behera } 3322bbd681bSSubhendu Sekhar Behera 3332bbd681bSSubhendu Sekhar Behera static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) 3342bbd681bSSubhendu Sekhar Behera { 3352bbd681bSSubhendu Sekhar Behera return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | 3362bbd681bSSubhendu Sekhar Behera I2C_FUNC_10BIT_ADDR; 3372bbd681bSSubhendu Sekhar Behera } 3382bbd681bSSubhendu Sekhar Behera 33992d9d0dfSBhumika Goyal static const struct i2c_algorithm xlp9xx_i2c_algo = { 3402bbd681bSSubhendu Sekhar Behera .master_xfer = xlp9xx_i2c_xfer, 3412bbd681bSSubhendu Sekhar Behera .functionality = xlp9xx_i2c_functionality, 3422bbd681bSSubhendu Sekhar Behera }; 3432bbd681bSSubhendu Sekhar Behera 3442bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, 3452bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev *priv) 3462bbd681bSSubhendu Sekhar Behera { 347c347b8fcSJayachandran C struct clk *clk; 3482bbd681bSSubhendu Sekhar Behera u32 freq; 3492bbd681bSSubhendu Sekhar Behera int err; 3502bbd681bSSubhendu Sekhar Behera 351c347b8fcSJayachandran C clk = devm_clk_get(&pdev->dev, NULL); 352c347b8fcSJayachandran C if (IS_ERR(clk)) { 353c347b8fcSJayachandran C priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ; 354c347b8fcSJayachandran C dev_dbg(&pdev->dev, "using default input frequency %u\n", 355c347b8fcSJayachandran C priv->ip_clk_hz); 356c347b8fcSJayachandran C } else { 357c347b8fcSJayachandran C priv->ip_clk_hz = clk_get_rate(clk); 358c347b8fcSJayachandran C } 359c347b8fcSJayachandran C 360748c0bbbSTanmay Jagdale err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); 3612bbd681bSSubhendu Sekhar Behera if (err) { 3622bbd681bSSubhendu Sekhar Behera freq = XLP9XX_I2C_DEFAULT_FREQ; 3632bbd681bSSubhendu Sekhar Behera dev_dbg(&pdev->dev, "using default frequency %u\n", freq); 3642bbd681bSSubhendu Sekhar Behera } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) { 3652bbd681bSSubhendu Sekhar Behera dev_warn(&pdev->dev, "invalid frequency %u, using default\n", 3662bbd681bSSubhendu Sekhar Behera freq); 3672bbd681bSSubhendu Sekhar Behera freq = XLP9XX_I2C_DEFAULT_FREQ; 3682bbd681bSSubhendu Sekhar Behera } 3692bbd681bSSubhendu Sekhar Behera priv->clk_hz = freq; 3702bbd681bSSubhendu Sekhar Behera 3712bbd681bSSubhendu Sekhar Behera return 0; 3722bbd681bSSubhendu Sekhar Behera } 3732bbd681bSSubhendu Sekhar Behera 3742bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_probe(struct platform_device *pdev) 3752bbd681bSSubhendu Sekhar Behera { 3762bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev *priv; 3772bbd681bSSubhendu Sekhar Behera struct resource *res; 3782bbd681bSSubhendu Sekhar Behera int err = 0; 3792bbd681bSSubhendu Sekhar Behera 3802bbd681bSSubhendu Sekhar Behera priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 3812bbd681bSSubhendu Sekhar Behera if (!priv) 3822bbd681bSSubhendu Sekhar Behera return -ENOMEM; 3832bbd681bSSubhendu Sekhar Behera 3842bbd681bSSubhendu Sekhar Behera res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3852bbd681bSSubhendu Sekhar Behera priv->base = devm_ioremap_resource(&pdev->dev, res); 3862bbd681bSSubhendu Sekhar Behera if (IS_ERR(priv->base)) 3872bbd681bSSubhendu Sekhar Behera return PTR_ERR(priv->base); 3882bbd681bSSubhendu Sekhar Behera 3892bbd681bSSubhendu Sekhar Behera priv->irq = platform_get_irq(pdev, 0); 3902bbd681bSSubhendu Sekhar Behera if (priv->irq <= 0) { 3912bbd681bSSubhendu Sekhar Behera dev_err(&pdev->dev, "invalid irq!\n"); 3922bbd681bSSubhendu Sekhar Behera return priv->irq; 3932bbd681bSSubhendu Sekhar Behera } 3942bbd681bSSubhendu Sekhar Behera 3952bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_get_frequency(pdev, priv); 3962bbd681bSSubhendu Sekhar Behera xlp9xx_i2c_init(priv); 3972bbd681bSSubhendu Sekhar Behera 3982bbd681bSSubhendu Sekhar Behera err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, 3992bbd681bSSubhendu Sekhar Behera pdev->name, priv); 4002bbd681bSSubhendu Sekhar Behera if (err) { 4012bbd681bSSubhendu Sekhar Behera dev_err(&pdev->dev, "IRQ request failed!\n"); 4022bbd681bSSubhendu Sekhar Behera return err; 4032bbd681bSSubhendu Sekhar Behera } 4042bbd681bSSubhendu Sekhar Behera 4052bbd681bSSubhendu Sekhar Behera init_completion(&priv->msg_complete); 4062bbd681bSSubhendu Sekhar Behera priv->adapter.dev.parent = &pdev->dev; 4072bbd681bSSubhendu Sekhar Behera priv->adapter.algo = &xlp9xx_i2c_algo; 408227855b9SGeorge Cherian priv->adapter.class = I2C_CLASS_HWMON; 409254df038STanmay Jagdale ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); 4102bbd681bSSubhendu Sekhar Behera priv->adapter.dev.of_node = pdev->dev.of_node; 4112bbd681bSSubhendu Sekhar Behera priv->dev = &pdev->dev; 4122bbd681bSSubhendu Sekhar Behera 4132bbd681bSSubhendu Sekhar Behera snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c"); 4142bbd681bSSubhendu Sekhar Behera i2c_set_adapdata(&priv->adapter, priv); 4152bbd681bSSubhendu Sekhar Behera 4162bbd681bSSubhendu Sekhar Behera err = i2c_add_adapter(&priv->adapter); 417ea734404SWolfram Sang if (err) 4182bbd681bSSubhendu Sekhar Behera return err; 4192bbd681bSSubhendu Sekhar Behera 4202bbd681bSSubhendu Sekhar Behera platform_set_drvdata(pdev, priv); 4212bbd681bSSubhendu Sekhar Behera dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); 4222bbd681bSSubhendu Sekhar Behera 4232bbd681bSSubhendu Sekhar Behera return 0; 4242bbd681bSSubhendu Sekhar Behera } 4252bbd681bSSubhendu Sekhar Behera 4262bbd681bSSubhendu Sekhar Behera static int xlp9xx_i2c_remove(struct platform_device *pdev) 4272bbd681bSSubhendu Sekhar Behera { 4282bbd681bSSubhendu Sekhar Behera struct xlp9xx_i2c_dev *priv; 4292bbd681bSSubhendu Sekhar Behera 4302bbd681bSSubhendu Sekhar Behera priv = platform_get_drvdata(pdev); 4312bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); 4322bbd681bSSubhendu Sekhar Behera synchronize_irq(priv->irq); 4332bbd681bSSubhendu Sekhar Behera i2c_del_adapter(&priv->adapter); 4342bbd681bSSubhendu Sekhar Behera xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0); 4352bbd681bSSubhendu Sekhar Behera 4362bbd681bSSubhendu Sekhar Behera return 0; 4372bbd681bSSubhendu Sekhar Behera } 4382bbd681bSSubhendu Sekhar Behera 4392bbd681bSSubhendu Sekhar Behera static const struct of_device_id xlp9xx_i2c_of_match[] = { 4402bbd681bSSubhendu Sekhar Behera { .compatible = "netlogic,xlp980-i2c", }, 4412bbd681bSSubhendu Sekhar Behera { /* sentinel */ }, 4422bbd681bSSubhendu Sekhar Behera }; 44306e7b10aSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); 4442bbd681bSSubhendu Sekhar Behera 445748c0bbbSTanmay Jagdale #ifdef CONFIG_ACPI 446748c0bbbSTanmay Jagdale static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { 447748c0bbbSTanmay Jagdale {"BRCM9007", 0}, 4484165bd4bSJayachandran C {"CAV9007", 0}, 449748c0bbbSTanmay Jagdale {} 450748c0bbbSTanmay Jagdale }; 451748c0bbbSTanmay Jagdale MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); 452748c0bbbSTanmay Jagdale #endif 453748c0bbbSTanmay Jagdale 4542bbd681bSSubhendu Sekhar Behera static struct platform_driver xlp9xx_i2c_driver = { 4552bbd681bSSubhendu Sekhar Behera .probe = xlp9xx_i2c_probe, 4562bbd681bSSubhendu Sekhar Behera .remove = xlp9xx_i2c_remove, 4572bbd681bSSubhendu Sekhar Behera .driver = { 4582bbd681bSSubhendu Sekhar Behera .name = "xlp9xx-i2c", 4592bbd681bSSubhendu Sekhar Behera .of_match_table = xlp9xx_i2c_of_match, 460748c0bbbSTanmay Jagdale .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), 4612bbd681bSSubhendu Sekhar Behera }, 4622bbd681bSSubhendu Sekhar Behera }; 4632bbd681bSSubhendu Sekhar Behera 4642bbd681bSSubhendu Sekhar Behera module_platform_driver(xlp9xx_i2c_driver); 4652bbd681bSSubhendu Sekhar Behera 4662bbd681bSSubhendu Sekhar Behera MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>"); 4672bbd681bSSubhendu Sekhar Behera MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver"); 4682bbd681bSSubhendu Sekhar Behera MODULE_LICENSE("GPL v2"); 469