diff options
| -rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt | 22 | ||||
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-xlp9xx.c | 445 |
4 files changed, 478 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt new file mode 100644 index 000000000000..f818ef507ab7 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | Device tree configuration for the I2C controller on the XLP9xx/5xx SoC | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : should be "netlogic,xlp980-i2c" | ||
| 5 | - reg : bus address start and address range size of device | ||
| 6 | - interrupts : interrupt number | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | - clock-frequency : frequency of bus clock in Hz | ||
| 10 | Defaults to 100 KHz when the property is not specified | ||
| 11 | |||
| 12 | Example: | ||
| 13 | |||
| 14 | i2c0: i2c@113100 { | ||
| 15 | compatible = "netlogic,xlp980-i2c"; | ||
| 16 | #address-cells = <1>; | ||
| 17 | #size-cells = <0>; | ||
| 18 | reg = <0 0x113100 0x100>; | ||
| 19 | clock-frequency = <400000>; | ||
| 20 | interrupts = <30>; | ||
| 21 | interrupt-parent = <&pic>; | ||
| 22 | }; | ||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0b0ca7dd5d1f..2255af23b9c7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
| @@ -916,6 +916,16 @@ config I2C_XLR | |||
| 916 | This driver can also be built as a module. If so, the module | 916 | This driver can also be built as a module. If so, the module |
| 917 | will be called i2c-xlr. | 917 | will be called i2c-xlr. |
| 918 | 918 | ||
| 919 | config I2C_XLP9XX | ||
| 920 | tristate "XLP9XX I2C support" | ||
| 921 | depends on CPU_XLP || COMPILE_TEST | ||
| 922 | help | ||
| 923 | This driver enables support for the on-chip I2C interface of | ||
| 924 | the Broadcom XLP9xx/XLP5xx MIPS processors. | ||
| 925 | |||
| 926 | This driver can also be built as a module. If so, the module will | ||
| 927 | be called i2c-xlp9xx. | ||
| 928 | |||
| 919 | config I2C_RCAR | 929 | config I2C_RCAR |
| 920 | tristate "Renesas R-Car I2C Controller" | 930 | tristate "Renesas R-Car I2C Controller" |
| 921 | depends on ARCH_SHMOBILE || COMPILE_TEST | 931 | depends on ARCH_SHMOBILE || COMPILE_TEST |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ab6a0a67aca1..cdf941da91c6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
| @@ -89,6 +89,7 @@ obj-$(CONFIG_I2C_WMT) += i2c-wmt.o | |||
| 89 | obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o | 89 | obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o |
| 90 | obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o | 90 | obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o |
| 91 | obj-$(CONFIG_I2C_XLR) += i2c-xlr.o | 91 | obj-$(CONFIG_I2C_XLR) += i2c-xlr.o |
| 92 | obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o | ||
| 92 | obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o | 93 | obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o |
| 93 | 94 | ||
| 94 | # External I2C/SMBus adapter drivers | 95 | # External I2C/SMBus adapter drivers |
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c new file mode 100644 index 000000000000..c941418f06f5 --- /dev/null +++ b/drivers/i2c/busses/i2c-xlp9xx.c | |||
| @@ -0,0 +1,445 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2003-2015 Broadcom Corporation | ||
| 3 | * | ||
| 4 | * This file is licensed under the terms of the GNU General Public | ||
| 5 | * License version 2. This program is licensed "as is" without any | ||
| 6 | * warranty of any kind, whether express or implied. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/completion.h> | ||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/interrupt.h> | ||
| 13 | #include <linux/io.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #define XLP9XX_I2C_DIV 0x0 | ||
| 19 | #define XLP9XX_I2C_CTRL 0x1 | ||
| 20 | #define XLP9XX_I2C_CMD 0x2 | ||
| 21 | #define XLP9XX_I2C_STATUS 0x3 | ||
| 22 | #define XLP9XX_I2C_MTXFIFO 0x4 | ||
| 23 | #define XLP9XX_I2C_MRXFIFO 0x5 | ||
| 24 | #define XLP9XX_I2C_MFIFOCTRL 0x6 | ||
| 25 | #define XLP9XX_I2C_STXFIFO 0x7 | ||
| 26 | #define XLP9XX_I2C_SRXFIFO 0x8 | ||
| 27 | #define XLP9XX_I2C_SFIFOCTRL 0x9 | ||
| 28 | #define XLP9XX_I2C_SLAVEADDR 0xA | ||
| 29 | #define XLP9XX_I2C_OWNADDR 0xB | ||
| 30 | #define XLP9XX_I2C_FIFOWCNT 0xC | ||
| 31 | #define XLP9XX_I2C_INTEN 0xD | ||
| 32 | #define XLP9XX_I2C_INTST 0xE | ||
| 33 | #define XLP9XX_I2C_WAITCNT 0xF | ||
| 34 | #define XLP9XX_I2C_TIMEOUT 0X10 | ||
| 35 | #define XLP9XX_I2C_GENCALLADDR 0x11 | ||
| 36 | |||
| 37 | #define XLP9XX_I2C_CMD_START BIT(7) | ||
| 38 | #define XLP9XX_I2C_CMD_STOP BIT(6) | ||
| 39 | #define XLP9XX_I2C_CMD_READ BIT(5) | ||
| 40 | #define XLP9XX_I2C_CMD_WRITE BIT(4) | ||
| 41 | #define XLP9XX_I2C_CMD_ACK BIT(3) | ||
| 42 | |||
| 43 | #define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16 | ||
| 44 | #define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000 | ||
| 45 | #define XLP9XX_I2C_CTRL_RST BIT(8) | ||
| 46 | #define XLP9XX_I2C_CTRL_EN BIT(6) | ||
| 47 | #define XLP9XX_I2C_CTRL_MASTER BIT(4) | ||
| 48 | #define XLP9XX_I2C_CTRL_FIFORD BIT(1) | ||
| 49 | #define XLP9XX_I2C_CTRL_ADDMODE BIT(0) | ||
| 50 | |||
| 51 | #define XLP9XX_I2C_INTEN_NACKADDR BIT(25) | ||
| 52 | #define XLP9XX_I2C_INTEN_SADDR BIT(13) | ||
| 53 | #define XLP9XX_I2C_INTEN_DATADONE BIT(12) | ||
| 54 | #define XLP9XX_I2C_INTEN_ARLOST BIT(11) | ||
| 55 | #define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4) | ||
| 56 | #define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3) | ||
| 57 | #define XLP9XX_I2C_INTEN_MFIFOHI BIT(2) | ||
| 58 | #define XLP9XX_I2C_INTEN_BUSERR BIT(0) | ||
| 59 | |||
| 60 | #define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8 | ||
| 61 | #define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0 | ||
| 62 | #define XLP9XX_I2C_MFIFOCTRL_RST BIT(16) | ||
| 63 | |||
| 64 | #define XLP9XX_I2C_SLAVEADDR_RW BIT(0) | ||
| 65 | #define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1 | ||
| 66 | |||
| 67 | #define XLP9XX_I2C_IP_CLK_FREQ 133000000UL | ||
| 68 | #define XLP9XX_I2C_DEFAULT_FREQ 100000 | ||
| 69 | #define XLP9XX_I2C_HIGH_FREQ 400000 | ||
| 70 | #define XLP9XX_I2C_FIFO_SIZE 0x80U | ||
| 71 | #define XLP9XX_I2C_TIMEOUT_MS 1000 | ||
| 72 | |||
| 73 | #define XLP9XX_I2C_FIFO_WCNT_MASK 0xff | ||
| 74 | #define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \ | ||
| 75 | XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR) | ||
| 76 | |||
| 77 | struct xlp9xx_i2c_dev { | ||
| 78 | struct device *dev; | ||
| 79 | struct i2c_adapter adapter; | ||
| 80 | struct completion msg_complete; | ||
| 81 | int irq; | ||
| 82 | bool msg_read; | ||
| 83 | u32 __iomem *base; | ||
| 84 | u32 msg_buf_remaining; | ||
| 85 | u32 msg_len; | ||
| 86 | u32 clk_hz; | ||
| 87 | u32 msg_err; | ||
| 88 | u8 *msg_buf; | ||
| 89 | }; | ||
| 90 | |||
| 91 | static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv, | ||
| 92 | unsigned long reg, u32 val) | ||
| 93 | { | ||
| 94 | writel(val, priv->base + reg); | ||
| 95 | } | ||
| 96 | |||
| 97 | static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv, | ||
| 98 | unsigned long reg) | ||
| 99 | { | ||
| 100 | return readl(priv->base + reg); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) | ||
| 104 | { | ||
| 105 | u32 inten; | ||
| 106 | |||
| 107 | inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask; | ||
| 108 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); | ||
| 109 | } | ||
| 110 | |||
| 111 | static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) | ||
| 112 | { | ||
| 113 | u32 inten; | ||
| 114 | |||
| 115 | inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask; | ||
| 116 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv) | ||
| 120 | { | ||
| 121 | u32 thres; | ||
| 122 | |||
| 123 | thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); | ||
| 124 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, | ||
| 125 | thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT); | ||
| 126 | } | ||
| 127 | |||
| 128 | static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) | ||
| 129 | { | ||
| 130 | u32 len, i; | ||
| 131 | u8 *buf = priv->msg_buf; | ||
| 132 | |||
| 133 | len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); | ||
| 134 | for (i = 0; i < len; i++) | ||
| 135 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]); | ||
| 136 | priv->msg_buf_remaining -= len; | ||
| 137 | priv->msg_buf += len; | ||
| 138 | } | ||
| 139 | |||
| 140 | static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) | ||
| 141 | { | ||
| 142 | u32 len, i; | ||
| 143 | u8 *buf = priv->msg_buf; | ||
| 144 | |||
| 145 | len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & | ||
| 146 | XLP9XX_I2C_FIFO_WCNT_MASK; | ||
| 147 | len = min(priv->msg_buf_remaining, len); | ||
| 148 | for (i = 0; i < len; i++, buf++) | ||
| 149 | *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); | ||
| 150 | |||
| 151 | priv->msg_buf_remaining -= len; | ||
| 152 | priv->msg_buf = buf; | ||
| 153 | |||
| 154 | if (priv->msg_buf_remaining) | ||
| 155 | xlp9xx_i2c_update_rx_fifo_thres(priv); | ||
| 156 | } | ||
| 157 | |||
| 158 | static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id) | ||
| 159 | { | ||
| 160 | struct xlp9xx_i2c_dev *priv = dev_id; | ||
| 161 | u32 status; | ||
| 162 | |||
| 163 | status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST); | ||
| 164 | if (status == 0) | ||
| 165 | return IRQ_NONE; | ||
| 166 | |||
| 167 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status); | ||
| 168 | if (status & XLP9XX_I2C_STATUS_ERRMASK) { | ||
| 169 | priv->msg_err = status; | ||
| 170 | goto xfer_done; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* SADDR ACK for SMBUS_QUICK */ | ||
| 174 | if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0)) | ||
| 175 | goto xfer_done; | ||
| 176 | |||
| 177 | if (!priv->msg_read) { | ||
| 178 | if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) { | ||
| 179 | /* TX FIFO got empty, fill it up again */ | ||
| 180 | if (priv->msg_buf_remaining) | ||
| 181 | xlp9xx_i2c_fill_tx_fifo(priv); | ||
| 182 | else | ||
| 183 | xlp9xx_i2c_mask_irq(priv, | ||
| 184 | XLP9XX_I2C_INTEN_MFIFOEMTY); | ||
| 185 | } | ||
| 186 | } else { | ||
| 187 | if (status & (XLP9XX_I2C_INTEN_DATADONE | | ||
| 188 | XLP9XX_I2C_INTEN_MFIFOHI)) { | ||
| 189 | /* data is in FIFO, read it */ | ||
| 190 | if (priv->msg_buf_remaining) | ||
| 191 | xlp9xx_i2c_drain_rx_fifo(priv); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Transfer complete */ | ||
| 196 | if (status & XLP9XX_I2C_INTEN_DATADONE) | ||
| 197 | goto xfer_done; | ||
| 198 | |||
| 199 | return IRQ_HANDLED; | ||
| 200 | |||
| 201 | xfer_done: | ||
| 202 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); | ||
| 203 | complete(&priv->msg_complete); | ||
| 204 | return IRQ_HANDLED; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) | ||
| 208 | { | ||
| 209 | u32 prescale; | ||
| 210 | |||
| 211 | /* | ||
| 212 | * The controller uses 5 * SCL clock internally. | ||
| 213 | * So prescale value should be divided by 5. | ||
| 214 | */ | ||
| 215 | prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); | ||
| 216 | prescale = ((prescale - 8) / 5) - 1; | ||
| 217 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); | ||
| 218 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | | ||
| 219 | XLP9XX_I2C_CTRL_MASTER); | ||
| 220 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale); | ||
| 221 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, | ||
| 227 | int last_msg) | ||
| 228 | { | ||
| 229 | unsigned long timeleft; | ||
| 230 | u32 intr_mask, cmd, val; | ||
| 231 | |||
| 232 | priv->msg_buf = msg->buf; | ||
| 233 | priv->msg_buf_remaining = priv->msg_len = msg->len; | ||
| 234 | priv->msg_err = 0; | ||
| 235 | priv->msg_read = (msg->flags & I2C_M_RD); | ||
| 236 | reinit_completion(&priv->msg_complete); | ||
| 237 | |||
| 238 | /* Reset FIFO */ | ||
| 239 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, | ||
| 240 | XLP9XX_I2C_MFIFOCTRL_RST); | ||
| 241 | |||
| 242 | /* set FIFO threshold if reading */ | ||
| 243 | if (priv->msg_read) | ||
| 244 | xlp9xx_i2c_update_rx_fifo_thres(priv); | ||
| 245 | |||
| 246 | /* set slave addr */ | ||
| 247 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, | ||
| 248 | (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | | ||
| 249 | (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0)); | ||
| 250 | |||
| 251 | /* Build control word for transfer */ | ||
| 252 | val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); | ||
| 253 | if (!priv->msg_read) | ||
| 254 | val &= ~XLP9XX_I2C_CTRL_FIFORD; | ||
| 255 | else | ||
| 256 | val |= XLP9XX_I2C_CTRL_FIFORD; /* read */ | ||
| 257 | |||
| 258 | if (msg->flags & I2C_M_TEN) | ||
| 259 | val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ | ||
| 260 | else | ||
| 261 | val &= ~XLP9XX_I2C_CTRL_ADDMODE; | ||
| 262 | |||
| 263 | /* set data length to be transferred */ | ||
| 264 | val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | | ||
| 265 | (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); | ||
| 266 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); | ||
| 267 | |||
| 268 | /* fill fifo during tx */ | ||
| 269 | if (!priv->msg_read) | ||
| 270 | xlp9xx_i2c_fill_tx_fifo(priv); | ||
| 271 | |||
| 272 | /* set interrupt mask */ | ||
| 273 | intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR | | ||
| 274 | XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE); | ||
| 275 | |||
| 276 | if (priv->msg_read) { | ||
| 277 | intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI; | ||
| 278 | if (msg->len == 0) | ||
| 279 | intr_mask |= XLP9XX_I2C_INTEN_SADDR; | ||
| 280 | } else { | ||
| 281 | if (msg->len == 0) | ||
| 282 | intr_mask |= XLP9XX_I2C_INTEN_SADDR; | ||
| 283 | else | ||
| 284 | intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY; | ||
| 285 | } | ||
| 286 | xlp9xx_i2c_unmask_irq(priv, intr_mask); | ||
| 287 | |||
| 288 | /* set cmd reg */ | ||
| 289 | cmd = XLP9XX_I2C_CMD_START; | ||
| 290 | cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); | ||
| 291 | if (last_msg) | ||
| 292 | cmd |= XLP9XX_I2C_CMD_STOP; | ||
| 293 | |||
| 294 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd); | ||
| 295 | |||
| 296 | timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); | ||
| 297 | timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); | ||
| 298 | |||
| 299 | if (priv->msg_err) { | ||
| 300 | dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); | ||
| 301 | if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) | ||
| 302 | xlp9xx_i2c_init(priv); | ||
| 303 | return -EIO; | ||
| 304 | } | ||
| 305 | |||
| 306 | if (timeleft == 0) { | ||
| 307 | dev_dbg(priv->dev, "i2c transfer timed out!\n"); | ||
| 308 | xlp9xx_i2c_init(priv); | ||
| 309 | return -ETIMEDOUT; | ||
| 310 | } | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||
| 316 | int num) | ||
| 317 | { | ||
| 318 | int i, ret; | ||
| 319 | struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap); | ||
| 320 | |||
| 321 | for (i = 0; i < num; i++) { | ||
| 322 | ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); | ||
| 323 | if (ret != 0) | ||
| 324 | return ret; | ||
| 325 | } | ||
| 326 | |||
| 327 | return num; | ||
| 328 | } | ||
| 329 | |||
| 330 | static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) | ||
| 331 | { | ||
| 332 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | | ||
| 333 | I2C_FUNC_10BIT_ADDR; | ||
| 334 | } | ||
| 335 | |||
| 336 | static struct i2c_algorithm xlp9xx_i2c_algo = { | ||
| 337 | .master_xfer = xlp9xx_i2c_xfer, | ||
| 338 | .functionality = xlp9xx_i2c_functionality, | ||
| 339 | }; | ||
| 340 | |||
| 341 | static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, | ||
| 342 | struct xlp9xx_i2c_dev *priv) | ||
| 343 | { | ||
| 344 | struct device_node *np = pdev->dev.of_node; | ||
| 345 | u32 freq; | ||
| 346 | int err; | ||
| 347 | |||
| 348 | err = of_property_read_u32(np, "clock-frequency", &freq); | ||
| 349 | if (err) { | ||
| 350 | freq = XLP9XX_I2C_DEFAULT_FREQ; | ||
| 351 | dev_dbg(&pdev->dev, "using default frequency %u\n", freq); | ||
| 352 | } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) { | ||
| 353 | dev_warn(&pdev->dev, "invalid frequency %u, using default\n", | ||
| 354 | freq); | ||
| 355 | freq = XLP9XX_I2C_DEFAULT_FREQ; | ||
| 356 | } | ||
| 357 | priv->clk_hz = freq; | ||
| 358 | |||
| 359 | return 0; | ||
| 360 | } | ||
| 361 | |||
| 362 | static int xlp9xx_i2c_probe(struct platform_device *pdev) | ||
| 363 | { | ||
| 364 | struct xlp9xx_i2c_dev *priv; | ||
| 365 | struct resource *res; | ||
| 366 | int err = 0; | ||
| 367 | |||
| 368 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
| 369 | if (!priv) | ||
| 370 | return -ENOMEM; | ||
| 371 | |||
| 372 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 373 | priv->base = devm_ioremap_resource(&pdev->dev, res); | ||
| 374 | if (IS_ERR(priv->base)) | ||
| 375 | return PTR_ERR(priv->base); | ||
| 376 | |||
| 377 | priv->irq = platform_get_irq(pdev, 0); | ||
| 378 | if (priv->irq <= 0) { | ||
| 379 | dev_err(&pdev->dev, "invalid irq!\n"); | ||
| 380 | return priv->irq; | ||
| 381 | } | ||
| 382 | |||
| 383 | xlp9xx_i2c_get_frequency(pdev, priv); | ||
| 384 | xlp9xx_i2c_init(priv); | ||
| 385 | |||
| 386 | err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, | ||
| 387 | pdev->name, priv); | ||
| 388 | if (err) { | ||
| 389 | dev_err(&pdev->dev, "IRQ request failed!\n"); | ||
| 390 | return err; | ||
| 391 | } | ||
| 392 | |||
| 393 | init_completion(&priv->msg_complete); | ||
| 394 | priv->adapter.dev.parent = &pdev->dev; | ||
| 395 | priv->adapter.algo = &xlp9xx_i2c_algo; | ||
| 396 | priv->adapter.dev.of_node = pdev->dev.of_node; | ||
| 397 | priv->dev = &pdev->dev; | ||
| 398 | |||
| 399 | snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c"); | ||
| 400 | i2c_set_adapdata(&priv->adapter, priv); | ||
| 401 | |||
| 402 | err = i2c_add_adapter(&priv->adapter); | ||
| 403 | if (err) { | ||
| 404 | dev_err(&pdev->dev, "failed to add I2C adapter!\n"); | ||
| 405 | return err; | ||
| 406 | } | ||
| 407 | |||
| 408 | platform_set_drvdata(pdev, priv); | ||
| 409 | dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | static int xlp9xx_i2c_remove(struct platform_device *pdev) | ||
| 415 | { | ||
| 416 | struct xlp9xx_i2c_dev *priv; | ||
| 417 | |||
| 418 | priv = platform_get_drvdata(pdev); | ||
| 419 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); | ||
| 420 | synchronize_irq(priv->irq); | ||
| 421 | i2c_del_adapter(&priv->adapter); | ||
| 422 | xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0); | ||
| 423 | |||
| 424 | return 0; | ||
| 425 | } | ||
| 426 | |||
| 427 | static const struct of_device_id xlp9xx_i2c_of_match[] = { | ||
| 428 | { .compatible = "netlogic,xlp980-i2c", }, | ||
| 429 | { /* sentinel */ }, | ||
| 430 | }; | ||
| 431 | |||
| 432 | static struct platform_driver xlp9xx_i2c_driver = { | ||
| 433 | .probe = xlp9xx_i2c_probe, | ||
| 434 | .remove = xlp9xx_i2c_remove, | ||
| 435 | .driver = { | ||
| 436 | .name = "xlp9xx-i2c", | ||
| 437 | .of_match_table = xlp9xx_i2c_of_match, | ||
| 438 | }, | ||
| 439 | }; | ||
| 440 | |||
| 441 | module_platform_driver(xlp9xx_i2c_driver); | ||
| 442 | |||
| 443 | MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>"); | ||
| 444 | MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver"); | ||
| 445 | MODULE_LICENSE("GPL v2"); | ||
