aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRay Jui <rjui@broadcom.com>2015-02-08 00:25:24 -0500
committerWolfram Sang <wsa@the-dreams.de>2015-02-17 10:44:13 -0500
commite6e5dd3566e092459a11083e5c0775d01df8682f (patch)
tree51f0c92d80b178fbe2352ae8acd2da3de3a25c86
parenta93ac5786d26851fd5df42338e26593cb8d58725 (diff)
i2c: iproc: Add Broadcom iProc I2C Driver
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs. The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz) Signed-off-by: Ray Jui <rjui@broadcom.com> Reviewed-by: Scott Branden <sbranden@broadcom.com> Reviewed-by: Kevin Cernekee <cernekee@chromium.org> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt37
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c461
4 files changed, 509 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
new file mode 100644
index 000000000000..81f982ccca31
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
@@ -0,0 +1,37 @@
1Broadcom iProc I2C controller
2
3Required properties:
4
5- compatible:
6 Must be "brcm,iproc-i2c"
7
8- reg:
9 Define the base and range of the I/O address space that contain the iProc
10 I2C controller registers
11
12- interrupts:
13 Should contain the I2C interrupt
14
15- clock-frequency:
16 This is the I2C bus clock. Need to be either 100000 or 400000
17
18- #address-cells:
19 Always 1 (for I2C addresses)
20
21- #size-cells:
22 Always 0
23
24Example:
25 i2c0: i2c@18008000 {
26 compatible = "brcm,iproc-i2c";
27 reg = <0x18008000 0x100>;
28 #address-cells = <1>;
29 #size-cells = <0>;
30 interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
31 clock-frequency = <100000>;
32
33 codec: wm8750@1a {
34 compatible = "wlf,wm8750";
35 reg = <0x1a>;
36 };
37 };
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d4a5c2e5788b..3de426e2263a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -372,6 +372,16 @@ config I2C_BCM2835
372 This support is also available as a module. If so, the module 372 This support is also available as a module. If so, the module
373 will be called i2c-bcm2835. 373 will be called i2c-bcm2835.
374 374
375config I2C_BCM_IPROC
376 tristate "Broadcom iProc I2C controller"
377 depends on ARCH_BCM_IPROC || COMPILE_TEST
378 default ARCH_BCM_IPROC
379 help
380 If you say yes to this option, support will be included for the
381 Broadcom iProc I2C controller.
382
383 If you don't know what to do here, say N.
384
375config I2C_BCM_KONA 385config I2C_BCM_KONA
376 tristate "BCM Kona I2C adapter" 386 tristate "BCM Kona I2C adapter"
377 depends on ARCH_BCM_MOBILE 387 depends on ARCH_BCM_MOBILE
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a04f9726596d..3638feb6677e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o
33obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o 33obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
34obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o 34obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
35obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o 35obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
36obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o
36obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o 37obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
37obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o 38obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
38obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o 39obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
new file mode 100644
index 000000000000..d3c89157b337
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -0,0 +1,461 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/delay.h>
15#include <linux/i2c.h>
16#include <linux/interrupt.h>
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22
23#define CFG_OFFSET 0x00
24#define CFG_RESET_SHIFT 31
25#define CFG_EN_SHIFT 30
26#define CFG_M_RETRY_CNT_SHIFT 16
27#define CFG_M_RETRY_CNT_MASK 0x0f
28
29#define TIM_CFG_OFFSET 0x04
30#define TIM_CFG_MODE_400_SHIFT 31
31
32#define M_FIFO_CTRL_OFFSET 0x0c
33#define M_FIFO_RX_FLUSH_SHIFT 31
34#define M_FIFO_TX_FLUSH_SHIFT 30
35#define M_FIFO_RX_CNT_SHIFT 16
36#define M_FIFO_RX_CNT_MASK 0x7f
37#define M_FIFO_RX_THLD_SHIFT 8
38#define M_FIFO_RX_THLD_MASK 0x3f
39
40#define M_CMD_OFFSET 0x30
41#define M_CMD_START_BUSY_SHIFT 31
42#define M_CMD_STATUS_SHIFT 25
43#define M_CMD_STATUS_MASK 0x07
44#define M_CMD_STATUS_SUCCESS 0x0
45#define M_CMD_STATUS_LOST_ARB 0x1
46#define M_CMD_STATUS_NACK_ADDR 0x2
47#define M_CMD_STATUS_NACK_DATA 0x3
48#define M_CMD_STATUS_TIMEOUT 0x4
49#define M_CMD_PROTOCOL_SHIFT 9
50#define M_CMD_PROTOCOL_MASK 0xf
51#define M_CMD_PROTOCOL_BLK_WR 0x7
52#define M_CMD_PROTOCOL_BLK_RD 0x8
53#define M_CMD_PEC_SHIFT 8
54#define M_CMD_RD_CNT_SHIFT 0
55#define M_CMD_RD_CNT_MASK 0xff
56
57#define IE_OFFSET 0x38
58#define IE_M_RX_FIFO_FULL_SHIFT 31
59#define IE_M_RX_THLD_SHIFT 30
60#define IE_M_START_BUSY_SHIFT 28
61
62#define IS_OFFSET 0x3c
63#define IS_M_RX_FIFO_FULL_SHIFT 31
64#define IS_M_RX_THLD_SHIFT 30
65#define IS_M_START_BUSY_SHIFT 28
66
67#define M_TX_OFFSET 0x40
68#define M_TX_WR_STATUS_SHIFT 31
69#define M_TX_DATA_SHIFT 0
70#define M_TX_DATA_MASK 0xff
71
72#define M_RX_OFFSET 0x44
73#define M_RX_STATUS_SHIFT 30
74#define M_RX_STATUS_MASK 0x03
75#define M_RX_PEC_ERR_SHIFT 29
76#define M_RX_DATA_SHIFT 0
77#define M_RX_DATA_MASK 0xff
78
79#define I2C_TIMEOUT_MESC 100
80#define M_TX_RX_FIFO_SIZE 64
81
82enum bus_speed_index {
83 I2C_SPD_100K = 0,
84 I2C_SPD_400K,
85};
86
87struct bcm_iproc_i2c_dev {
88 struct device *device;
89 int irq;
90
91 void __iomem *base;
92
93 struct i2c_adapter adapter;
94
95 struct completion done;
96 int xfer_is_done;
97};
98
99/*
100 * Can be expanded in the future if more interrupt status bits are utilized
101 */
102#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT)
103
104static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
105{
106 struct bcm_iproc_i2c_dev *iproc_i2c = data;
107 u32 status = readl(iproc_i2c->base + IS_OFFSET);
108
109 status &= ISR_MASK;
110
111 if (!status)
112 return IRQ_NONE;
113
114 writel(status, iproc_i2c->base + IS_OFFSET);
115 iproc_i2c->xfer_is_done = 1;
116 complete_all(&iproc_i2c->done);
117
118 return IRQ_HANDLED;
119}
120
121static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
122 struct i2c_msg *msg)
123{
124 u32 val;
125
126 val = readl(iproc_i2c->base + M_CMD_OFFSET);
127 val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
128
129 switch (val) {
130 case M_CMD_STATUS_SUCCESS:
131 return 0;
132
133 case M_CMD_STATUS_LOST_ARB:
134 dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
135 return -EAGAIN;
136
137 case M_CMD_STATUS_NACK_ADDR:
138 dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
139 return -ENXIO;
140
141 case M_CMD_STATUS_NACK_DATA:
142 dev_dbg(iproc_i2c->device, "NAK data\n");
143 return -ENXIO;
144
145 case M_CMD_STATUS_TIMEOUT:
146 dev_dbg(iproc_i2c->device, "bus timeout\n");
147 return -ETIMEDOUT;
148
149 default:
150 dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
151 return -EIO;
152 }
153}
154
155static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
156 struct i2c_msg *msg)
157{
158 int ret, i;
159 u8 addr;
160 u32 val;
161 unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
162
163 /* need to reserve one byte in the FIFO for the slave address */
164 if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
165 dev_err(iproc_i2c->device,
166 "only support data length up to %u bytes\n",
167 M_TX_RX_FIFO_SIZE - 1);
168 return -EOPNOTSUPP;
169 }
170
171 /* check if bus is busy */
172 if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
173 BIT(M_CMD_START_BUSY_SHIFT))) {
174 dev_warn(iproc_i2c->device, "bus is busy\n");
175 return -EBUSY;
176 }
177
178 /* format and load slave address into the TX FIFO */
179 addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
180 writel(addr, iproc_i2c->base + M_TX_OFFSET);
181
182 /* for a write transaction, load data into the TX FIFO */
183 if (!(msg->flags & I2C_M_RD)) {
184 for (i = 0; i < msg->len; i++) {
185 val = msg->buf[i];
186
187 /* mark the last byte */
188 if (i == msg->len - 1)
189 val |= 1 << M_TX_WR_STATUS_SHIFT;
190
191 writel(val, iproc_i2c->base + M_TX_OFFSET);
192 }
193 }
194
195 /* mark as incomplete before starting the transaction */
196 reinit_completion(&iproc_i2c->done);
197 iproc_i2c->xfer_is_done = 0;
198
199 /*
200 * Enable the "start busy" interrupt, which will be triggered after the
201 * transaction is done, i.e., the internal start_busy bit, transitions
202 * from 1 to 0.
203 */
204 writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET);
205
206 /*
207 * Now we can activate the transfer. For a read operation, specify the
208 * number of bytes to read
209 */
210 val = 1 << M_CMD_START_BUSY_SHIFT;
211 if (msg->flags & I2C_M_RD) {
212 val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
213 (msg->len << M_CMD_RD_CNT_SHIFT);
214 } else {
215 val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
216 }
217 writel(val, iproc_i2c->base + M_CMD_OFFSET);
218
219 time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
220
221 /* disable all interrupts */
222 writel(0, iproc_i2c->base + IE_OFFSET);
223 /* read it back to flush the write */
224 readl(iproc_i2c->base + IE_OFFSET);
225
226 /* make sure the interrupt handler isn't running */
227 synchronize_irq(iproc_i2c->irq);
228
229 if (!time_left && !iproc_i2c->xfer_is_done) {
230 dev_err(iproc_i2c->device, "transaction timed out\n");
231
232 /* flush FIFOs */
233 val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
234 (1 << M_FIFO_TX_FLUSH_SHIFT);
235 writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
236 return -ETIMEDOUT;
237 }
238
239 ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
240 if (ret) {
241 /* flush both TX/RX FIFOs */
242 val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
243 (1 << M_FIFO_TX_FLUSH_SHIFT);
244 writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
245 return ret;
246 }
247
248 /*
249 * For a read operation, we now need to load the data from FIFO
250 * into the memory buffer
251 */
252 if (msg->flags & I2C_M_RD) {
253 for (i = 0; i < msg->len; i++) {
254 msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
255 M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
256 }
257 }
258
259 return 0;
260}
261
262static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
263 struct i2c_msg msgs[], int num)
264{
265 struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
266 int ret, i;
267
268 /* go through all messages */
269 for (i = 0; i < num; i++) {
270 ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
271 if (ret) {
272 dev_dbg(iproc_i2c->device, "xfer failed\n");
273 return ret;
274 }
275 }
276
277 return num;
278}
279
280static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
281{
282 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
283}
284
285static const struct i2c_algorithm bcm_iproc_algo = {
286 .master_xfer = bcm_iproc_i2c_xfer,
287 .functionality = bcm_iproc_i2c_functionality,
288};
289
290static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
291{
292 unsigned int bus_speed;
293 u32 val;
294 int ret = of_property_read_u32(iproc_i2c->device->of_node,
295 "clock-frequency", &bus_speed);
296 if (ret < 0) {
297 dev_info(iproc_i2c->device,
298 "unable to interpret clock-frequency DT property\n");
299 bus_speed = 100000;
300 }
301
302 if (bus_speed < 100000) {
303 dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
304 bus_speed);
305 dev_err(iproc_i2c->device,
306 "valid speeds are 100khz and 400khz\n");
307 return -EINVAL;
308 } else if (bus_speed < 400000) {
309 bus_speed = 100000;
310 } else {
311 bus_speed = 400000;
312 }
313
314 val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
315 val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
316 val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
317 writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
318
319 dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
320
321 return 0;
322}
323
324static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
325{
326 u32 val;
327
328 /* put controller in reset */
329 val = readl(iproc_i2c->base + CFG_OFFSET);
330 val |= 1 << CFG_RESET_SHIFT;
331 val &= ~(1 << CFG_EN_SHIFT);
332 writel(val, iproc_i2c->base + CFG_OFFSET);
333
334 /* wait 100 usec per spec */
335 udelay(100);
336
337 /* bring controller out of reset */
338 val &= ~(1 << CFG_RESET_SHIFT);
339 writel(val, iproc_i2c->base + CFG_OFFSET);
340
341 /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
342 val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
343 writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
344
345 /* disable all interrupts */
346 writel(0, iproc_i2c->base + IE_OFFSET);
347
348 /* clear all pending interrupts */
349 writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
350
351 return 0;
352}
353
354static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
355 bool enable)
356{
357 u32 val;
358
359 val = readl(iproc_i2c->base + CFG_OFFSET);
360 if (enable)
361 val |= BIT(CFG_EN_SHIFT);
362 else
363 val &= ~BIT(CFG_EN_SHIFT);
364 writel(val, iproc_i2c->base + CFG_OFFSET);
365}
366
367static int bcm_iproc_i2c_probe(struct platform_device *pdev)
368{
369 int irq, ret = 0;
370 struct bcm_iproc_i2c_dev *iproc_i2c;
371 struct i2c_adapter *adap;
372 struct resource *res;
373
374 iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
375 GFP_KERNEL);
376 if (!iproc_i2c)
377 return -ENOMEM;
378
379 platform_set_drvdata(pdev, iproc_i2c);
380 iproc_i2c->device = &pdev->dev;
381 init_completion(&iproc_i2c->done);
382
383 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
384 iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
385 if (IS_ERR(iproc_i2c->base))
386 return PTR_ERR(iproc_i2c->base);
387
388 ret = bcm_iproc_i2c_init(iproc_i2c);
389 if (ret)
390 return ret;
391
392 ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
393 if (ret)
394 return ret;
395
396 irq = platform_get_irq(pdev, 0);
397 if (irq <= 0) {
398 dev_err(iproc_i2c->device, "no irq resource\n");
399 return irq;
400 }
401 iproc_i2c->irq = irq;
402
403 ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
404 pdev->name, iproc_i2c);
405 if (ret < 0) {
406 dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
407 return ret;
408 }
409
410 bcm_iproc_i2c_enable_disable(iproc_i2c, true);
411
412 adap = &iproc_i2c->adapter;
413 i2c_set_adapdata(adap, iproc_i2c);
414 strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
415 adap->algo = &bcm_iproc_algo;
416 adap->dev.parent = &pdev->dev;
417 adap->dev.of_node = pdev->dev.of_node;
418
419 ret = i2c_add_adapter(adap);
420 if (ret) {
421 dev_err(iproc_i2c->device, "failed to add adapter\n");
422 return ret;
423 }
424
425 return 0;
426}
427
428static int bcm_iproc_i2c_remove(struct platform_device *pdev)
429{
430 struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
431
432 /* make sure there's no pending interrupt when we remove the adapter */
433 writel(0, iproc_i2c->base + IE_OFFSET);
434 readl(iproc_i2c->base + IE_OFFSET);
435 synchronize_irq(iproc_i2c->irq);
436
437 i2c_del_adapter(&iproc_i2c->adapter);
438 bcm_iproc_i2c_enable_disable(iproc_i2c, false);
439
440 return 0;
441}
442
443static const struct of_device_id bcm_iproc_i2c_of_match[] = {
444 { .compatible = "brcm,iproc-i2c" },
445 { /* sentinel */ }
446};
447MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
448
449static struct platform_driver bcm_iproc_i2c_driver = {
450 .driver = {
451 .name = "bcm-iproc-i2c",
452 .of_match_table = bcm_iproc_i2c_of_match,
453 },
454 .probe = bcm_iproc_i2c_probe,
455 .remove = bcm_iproc_i2c_remove,
456};
457module_platform_driver(bcm_iproc_i2c_driver);
458
459MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
460MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
461MODULE_LICENSE("GPL v2");