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