1 From e5d89837a365a810b3cc5ce58d273a7c49029f36 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sun, 5 Sep 2010 03:19:10 +0200
4 Subject: [PATCH] i2c: Add i2c driver for JZ47XX SoCs
6 This patch adds a driver for the i2c controller found in Ingenic JZ47XX based
9 Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
11 drivers/i2c/busses/Kconfig | 10 +
12 drivers/i2c/busses/Makefile | 1 +
13 drivers/i2c/busses/i2c-jz47xx.c | 424 +++++++++++++++++++++++++++++++++++++++
14 3 files changed, 435 insertions(+), 0 deletions(-)
15 create mode 100644 drivers/i2c/busses/i2c-jz47xx.c
17 --- a/drivers/i2c/busses/Kconfig
18 +++ b/drivers/i2c/busses/Kconfig
19 @@ -420,6 +420,16 @@ config I2C_IXP2000
20 This driver is deprecated and will be dropped soon. Use i2c-gpio
24 + tristate "JZ4740 I2C Interface"
25 + depends on MACH_JZ4740
27 + Say Y here if you want support for the I2C controller found on Ingenic
30 + This driver can also be built as a module. If so, the module will be
34 tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
36 --- a/drivers/i2c/busses/Makefile
37 +++ b/drivers/i2c/busses/Makefile
38 @@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic
39 obj-$(CONFIG_I2C_IMX) += i2c-imx.o
40 obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
41 obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
42 +obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o
43 obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
44 obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
45 obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
47 +++ b/drivers/i2c/busses/i2c-jz47xx.c
50 +#include <linux/init.h>
51 +#include <linux/kernel.h>
52 +#include <linux/module.h>
53 +#include <linux/err.h>
54 +#include <linux/clk.h>
55 +#include <linux/platform_device.h>
56 +#include <linux/i2c.h>
57 +#include <linux/slab.h>
58 +#include <linux/interrupt.h>
60 +#include <linux/gpio.h>
61 +#include <linux/delay.h>
63 +#define JZ47XX_REG_I2C_DATA 0x00
64 +#define JZ47XX_REG_I2C_CTRL 0x04
65 +#define JZ47XX_REG_I2C_STATUS 0x08
66 +#define JZ47XX_REG_I2C_CLOCK 0x0C
68 +#define JZ47XX_I2C_STATUS_FIFO_FULL BIT(4)
69 +#define JZ47XX_I2C_STATUS_BUSY BIT(3)
70 +#define JZ47XX_I2C_STATUS_TEND BIT(2)
71 +#define JZ47XX_I2C_STATUS_DATA_VALID BIT(1)
72 +#define JZ47XX_I2C_STATUS_NACK BIT(0)
74 +#define JZ47XX_I2C_CTRL_IRQ_ENABLE BIT(4)
75 +#define JZ47XX_I2C_CTRL_START BIT(3)
76 +#define JZ47XX_I2C_CTRL_STOP BIT(2)
77 +#define JZ47XX_I2C_CTRL_NACK BIT(1)
78 +#define JZ47XX_I2C_CTRL_ENABLE BIT(0)
81 + struct resource *mem;
86 + struct i2c_adapter adapter;
88 + wait_queue_head_t wait_queue;
91 +static inline struct jz47xx_i2c *adapter_to_jz47xx_i2c(struct i2c_adapter *adap)
93 + return container_of(adap, struct jz47xx_i2c, adapter);
96 +static inline void jz47xx_i2c_set_ctrl(struct jz47xx_i2c *jz47xx_i2c,
97 + uint8_t mask, uint8_t value)
100 + ctrl = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
103 + printk("ctrl: %x\n", ctrl);
104 + writeb(ctrl, jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
107 +static irqreturn_t jz47xx_i2c_irq_handler(int irq, void *devid)
109 + struct jz47xx_i2c *jz47xx_i2c = devid;
113 + wake_up(&jz47xx_i2c->wait_queue);
115 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE, 0);
117 + return IRQ_HANDLED;
120 +static inline void jz47xx_i2c_set_data_valid(struct jz47xx_i2c *jz47xx_i2c,
124 + val = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
126 + val |= JZ47XX_I2C_STATUS_DATA_VALID;
128 + val &= ~JZ47XX_I2C_STATUS_DATA_VALID;
129 + writeb(val, jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
132 +static int jz47xx_i2c_test_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t mask, uint8_t value)
136 + mask |= JZ47XX_I2C_STATUS_NACK;
137 + value |= JZ47XX_I2C_STATUS_NACK;
139 + status = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
140 + printk("status: %x %x %x %x\n", status, mask, value, (status & mask) ^
142 + if (((status & mask) ^ value) == mask) {
143 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE,
144 + JZ47XX_I2C_CTRL_IRQ_ENABLE);
150 +static int jz47xx_i2c_wait_event_or_nack(struct jz47xx_i2c *jz47xx_i2c, uint8_t
151 +mask, uint8_t value)
155 + ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
156 + jz47xx_i2c_test_event(jz47xx_i2c, mask, value), 30 * HZ);
158 +/* while (!jz47xx_i2c_test_event(jz47xx_i2c, mask, value));
162 + printk("wait event or nack: %d %x\n", ret, readb(jz47xx_i2c->base +
163 + JZ47XX_REG_I2C_STATUS));
168 + if (readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS) & JZ47XX_I2C_STATUS_NACK)
177 +static int jz47xx_i2c_wait_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t event)
181 + ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
182 + jz47xx_i2c_test_event(jz47xx_i2c, event, event), 30 * HZ);
193 +static int jz47xx_i2c_write_msg(struct jz47xx_i2c *jz47xx_i2c,
194 + struct i2c_msg *msg)
199 + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
200 + for (i = 0; i < msg->len; ++i) {
201 + writeb(msg->buf[i], jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
202 + jz47xx_i2c_set_data_valid(jz47xx_i2c, true);
203 + ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
204 + JZ47XX_I2C_STATUS_DATA_VALID, 0);
208 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
209 + JZ47XX_I2C_CTRL_STOP);
212 + ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c, JZ47XX_I2C_STATUS_TEND,
213 + JZ47XX_I2C_STATUS_TEND);
218 +static int jz47xx_i2c_read_msg(struct jz47xx_i2c *jz47xx_i2c,
219 + struct i2c_msg *msg)
223 + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
225 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
226 + msg->len == 1 ? JZ47XX_I2C_CTRL_NACK : 0);
228 + for (i = 0; i < msg->len; ++i) {
229 + ret = jz47xx_i2c_wait_event(jz47xx_i2c, JZ47XX_I2C_STATUS_DATA_VALID);
231 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
232 + JZ47XX_I2C_CTRL_NACK);
236 + if (i == msg->len - 2) {
237 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
238 + JZ47XX_I2C_CTRL_NACK);
241 + msg->buf[i] = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
242 + printk("read: %x\n", msg->buf[i]);
243 + jz47xx_i2c_set_data_valid(jz47xx_i2c, false);
246 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
247 + JZ47XX_I2C_CTRL_STOP);
252 +static int jz47xx_i2c_xfer_msg(struct jz47xx_i2c *jz47xx_i2c,
253 + struct i2c_msg *msg)
258 + addr = msg->addr << 1;
259 + if (msg->flags & I2C_M_RD)
262 + jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_START,
263 + JZ47XX_I2C_CTRL_START);
264 + writeb(addr, jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
265 + jz47xx_i2c_set_data_valid(jz47xx_i2c, true);
267 + if (msg->flags & I2C_M_RD) {
268 + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
269 + ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
270 + JZ47XX_I2C_STATUS_TEND, JZ47XX_I2C_STATUS_TEND);
272 + ret = jz47xx_i2c_read_msg(jz47xx_i2c, msg);
274 + printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
275 + ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
276 + JZ47XX_I2C_STATUS_DATA_VALID, 0);
278 + ret = jz47xx_i2c_write_msg(jz47xx_i2c, msg);
284 +static int jz47xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int
287 + struct jz47xx_i2c *jz47xx_i2c = adapter_to_jz47xx_i2c(adap);
290 + int mask = JZ47XX_I2C_CTRL_ENABLE;
292 + printk("xfer: %d %x\n", num, readb(jz47xx_i2c->base +
293 + JZ47XX_REG_I2C_STATUS));
295 + clk_enable(jz47xx_i2c->clk);
296 + jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, mask);
298 + for (i = 0; i < num; ++i) {
299 + ret = jz47xx_i2c_xfer_msg(jz47xx_i2c, &msgs[i]);
304 + jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, 0);
305 + clk_disable(jz47xx_i2c->clk);
307 + printk("xfer ret: %d\n", ret);
312 +static u32 jz47xx_i2c_functionality(struct i2c_adapter *adap)
314 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
317 +static const struct i2c_algorithm jz47xx_i2c_algorithm = {
318 + .master_xfer = jz47xx_i2c_xfer,
319 + .functionality = jz47xx_i2c_functionality,
322 +const static struct jz_gpio_bulk_request jz47xx_i2c_pins[] = {
323 + JZ_GPIO_BULK_PIN(I2C_SDA),
324 + JZ_GPIO_BULK_PIN(I2C_SCK),
327 +static int __devinit jz47xx_i2c_probe(struct platform_device *pdev)
329 + struct jz47xx_i2c *jz47xx_i2c;
330 + struct resource *mem;
331 + void __iomem *base;
336 + irq = platform_get_irq(pdev, 0);
338 + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
342 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
344 + dev_err(&pdev->dev, "Failed to get iomem region\n");
348 + mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
350 + dev_err(&pdev->dev, "Failed to request iomem region\n");
354 + base = ioremap(mem->start, resource_size(mem));
356 + dev_err(&pdev->dev, "Failed to ioremap iomem\n");
358 + goto err_release_mem_region;
361 + clk = clk_get(&pdev->dev, "i2c");
363 + ret = PTR_ERR(clk);
367 + jz47xx_i2c = kzalloc(sizeof(*jz47xx_i2c), GFP_KERNEL);
373 + jz47xx_i2c->adapter.owner = THIS_MODULE;
374 + jz47xx_i2c->adapter.algo = &jz47xx_i2c_algorithm;
375 + jz47xx_i2c->adapter.dev.parent = &pdev->dev;
376 + jz47xx_i2c->adapter.nr = pdev->id < 0 ?: 0;
377 + strcpy(jz47xx_i2c->adapter.name, pdev->name);
379 + jz47xx_i2c->mem = mem;
380 + jz47xx_i2c->base = base;
381 + jz47xx_i2c->clk = clk;
382 + jz47xx_i2c->irq = irq;
384 + init_waitqueue_head(&jz47xx_i2c->wait_queue);
386 + ret = request_irq(irq, jz47xx_i2c_irq_handler, 0, pdev->name, jz47xx_i2c);
388 + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
392 + ret = jz_gpio_bulk_request(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
394 + dev_err(&pdev->dev, "Failed to request i2c pins: %d\n", ret);
398 + writew(0x10, jz47xx_i2c->base + JZ47XX_REG_I2C_CLOCK);
400 + ret = i2c_add_numbered_adapter(&jz47xx_i2c->adapter);
402 + dev_err(&pdev->dev, "Failed to add i2c adapter: %d\n", ret);
403 + goto err_free_gpios;
406 + platform_set_drvdata(pdev, jz47xx_i2c);
408 + printk("JZ4740 I2C\n");
413 + jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
415 + free_irq(irq, jz47xx_i2c);
422 +err_release_mem_region:
423 + release_mem_region(mem->start, resource_size(mem));
427 +static int __devexit jz47xx_i2c_remove(struct platform_device *pdev)
429 + struct jz47xx_i2c *jz47xx_i2c = platform_get_drvdata(pdev);
431 + platform_set_drvdata(pdev, NULL);
432 + i2c_del_adapter(&jz47xx_i2c->adapter);
434 + jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
436 + free_irq(jz47xx_i2c->irq, jz47xx_i2c);
437 + clk_put(jz47xx_i2c->clk);
439 + iounmap(jz47xx_i2c->base);
440 + release_mem_region(jz47xx_i2c->mem->start, resource_size(jz47xx_i2c->mem));
447 +static struct platform_driver jz47xx_i2c_driver = {
448 + .probe = jz47xx_i2c_probe,
449 + .remove = jz47xx_i2c_remove,
451 + .name = "jz47xx-i2c",
452 + .owner = THIS_MODULE,
456 +static int __init jz47xx_i2c_init(void)
458 + return platform_driver_register(&jz47xx_i2c_driver);
460 +module_init(jz47xx_i2c_init);
462 +static void jz47xx_i2c_exit(void)
464 + platform_driver_unregister(&jz47xx_i2c_driver);
466 +module_exit(jz47xx_i2c_exit);
468 +MODULE_LICENSE("GPL");
469 +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
470 +MODULE_DESCRIPTION("I2C adapter driver for JZ47XX SoCs");
471 +MODULE_ALIAS("platform:jz47xx-i2c");