Root/target/linux/xburst/patches-2.6.36/050-i2c.patch

1From e5d89837a365a810b3cc5ce58d273a7c49029f36 Mon Sep 17 00:00:00 2001
2From: Lars-Peter Clausen <lars@metafoo.de>
3Date: Sun, 5 Sep 2010 03:19:10 +0200
4Subject: [PATCH] i2c: Add i2c driver for JZ47XX SoCs
5
6This patch adds a driver for the i2c controller found in Ingenic JZ47XX based
7SoCs.
8
9Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
10---
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
16
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
21       instead.
22 
23+config I2C_JZ47XX
24+ tristate "JZ4740 I2C Interface"
25+ depends on MACH_JZ4740
26+ help
27+ Say Y here if you want support for the I2C controller found on Ingenic
28+ JZ47XX based SoCs.
29+
30+ This driver can also be built as a module. If so, the module will be
31+ called i2c-jz47xx.
32+
33 config I2C_MPC
34     tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
35     depends on PPC32
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
46--- /dev/null
47+++ b/drivers/i2c/busses/i2c-jz47xx.c
48@@ -0,0 +1,424 @@
49+
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>
59+
60+#include <linux/gpio.h>
61+#include <linux/delay.h>
62+
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
67+
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)
73+
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)
79+
80+struct jz47xx_i2c {
81+ struct resource *mem;
82+ void __iomem *base;
83+ int irq;
84+ struct clk *clk;
85+
86+ struct i2c_adapter adapter;
87+
88+ wait_queue_head_t wait_queue;
89+};
90+
91+static inline struct jz47xx_i2c *adapter_to_jz47xx_i2c(struct i2c_adapter *adap)
92+{
93+ return container_of(adap, struct jz47xx_i2c, adapter);
94+}
95+
96+static inline void jz47xx_i2c_set_ctrl(struct jz47xx_i2c *jz47xx_i2c,
97+ uint8_t mask, uint8_t value)
98+{
99+ uint8_t ctrl;
100+ ctrl = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
101+ ctrl &= ~mask;
102+ ctrl |= value;
103+ printk("ctrl: %x\n", ctrl);
104+ writeb(ctrl, jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
105+}
106+
107+static irqreturn_t jz47xx_i2c_irq_handler(int irq, void *devid)
108+{
109+ struct jz47xx_i2c *jz47xx_i2c = devid;
110+
111+ printk("IRQ\n");
112+
113+ wake_up(&jz47xx_i2c->wait_queue);
114+
115+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE, 0);
116+
117+ return IRQ_HANDLED;
118+}
119+
120+static inline void jz47xx_i2c_set_data_valid(struct jz47xx_i2c *jz47xx_i2c,
121+ bool valid)
122+{
123+ uint8_t val;
124+ val = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
125+ if (valid)
126+ val |= JZ47XX_I2C_STATUS_DATA_VALID;
127+ else
128+ val &= ~JZ47XX_I2C_STATUS_DATA_VALID;
129+ writeb(val, jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
130+}
131+
132+static int jz47xx_i2c_test_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t mask, uint8_t value)
133+{
134+ uint8_t status;
135+
136+ mask |= JZ47XX_I2C_STATUS_NACK;
137+ value |= JZ47XX_I2C_STATUS_NACK;
138+
139+ status = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
140+ printk("status: %x %x %x %x\n", status, mask, value, (status & mask) ^
141+ value);
142+ if (((status & mask) ^ value) == mask) {
143+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE,
144+ JZ47XX_I2C_CTRL_IRQ_ENABLE);
145+ return 0;
146+ }
147+ return 1;
148+}
149+
150+static int jz47xx_i2c_wait_event_or_nack(struct jz47xx_i2c *jz47xx_i2c, uint8_t
151+mask, uint8_t value)
152+{
153+ int ret;
154+
155+ ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
156+ jz47xx_i2c_test_event(jz47xx_i2c, mask, value), 30 * HZ);
157+
158+/* while (!jz47xx_i2c_test_event(jz47xx_i2c, mask, value));
159+
160+ ret = 1;*/
161+
162+ printk("wait event or nack: %d %x\n", ret, readb(jz47xx_i2c->base +
163+ JZ47XX_REG_I2C_STATUS));
164+
165+ if (ret == 0)
166+ ret = -ETIMEDOUT;
167+ else if(ret > 0) {
168+ if (readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS) & JZ47XX_I2C_STATUS_NACK)
169+ ret = -EIO;
170+ else
171+ ret = 0;
172+ }
173+
174+ return ret;
175+}
176+
177+static int jz47xx_i2c_wait_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t event)
178+{
179+ int ret;
180+
181+ ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
182+ jz47xx_i2c_test_event(jz47xx_i2c, event, event), 30 * HZ);
183+
184+ if (ret == 0)
185+ ret = -ETIMEDOUT;
186+ else if(ret > 0)
187+ ret = 0;
188+
189+ return ret;
190+}
191+
192+
193+static int jz47xx_i2c_write_msg(struct jz47xx_i2c *jz47xx_i2c,
194+ struct i2c_msg *msg)
195+{
196+ int ret;
197+ int i;
198+
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);
205+ if (ret)
206+ break;
207+ }
208+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
209+ JZ47XX_I2C_CTRL_STOP);
210+
211+ if (!ret)
212+ ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c, JZ47XX_I2C_STATUS_TEND,
213+ JZ47XX_I2C_STATUS_TEND);
214+
215+ return ret;
216+}
217+
218+static int jz47xx_i2c_read_msg(struct jz47xx_i2c *jz47xx_i2c,
219+ struct i2c_msg *msg)
220+{
221+ int i;
222+ int ret;
223+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
224+
225+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
226+ msg->len == 1 ? JZ47XX_I2C_CTRL_NACK : 0);
227+
228+ for (i = 0; i < msg->len; ++i) {
229+ ret = jz47xx_i2c_wait_event(jz47xx_i2c, JZ47XX_I2C_STATUS_DATA_VALID);
230+ if (ret) {
231+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
232+ JZ47XX_I2C_CTRL_NACK);
233+ break;
234+ }
235+
236+ if (i == msg->len - 2) {
237+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
238+ JZ47XX_I2C_CTRL_NACK);
239+ }
240+
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);
244+ }
245+
246+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
247+ JZ47XX_I2C_CTRL_STOP);
248+
249+ return ret;
250+}
251+
252+static int jz47xx_i2c_xfer_msg(struct jz47xx_i2c *jz47xx_i2c,
253+ struct i2c_msg *msg)
254+{
255+ uint8_t addr;
256+ int ret;
257+
258+ addr = msg->addr << 1;
259+ if (msg->flags & I2C_M_RD)
260+ addr |= 1;
261+
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);
266+
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);
271+ if (!ret)
272+ ret = jz47xx_i2c_read_msg(jz47xx_i2c, msg);
273+ } else {
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);
277+ if (!ret)
278+ ret = jz47xx_i2c_write_msg(jz47xx_i2c, msg);
279+ }
280+
281+ return ret;
282+}
283+
284+static int jz47xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int
285+num)
286+{
287+ struct jz47xx_i2c *jz47xx_i2c = adapter_to_jz47xx_i2c(adap);
288+ int ret = 0;
289+ int i;
290+ int mask = JZ47XX_I2C_CTRL_ENABLE;
291+
292+ printk("xfer: %d %x\n", num, readb(jz47xx_i2c->base +
293+ JZ47XX_REG_I2C_STATUS));
294+
295+ clk_enable(jz47xx_i2c->clk);
296+ jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, mask);
297+
298+ for (i = 0; i < num; ++i) {
299+ ret = jz47xx_i2c_xfer_msg(jz47xx_i2c, &msgs[i]);
300+ if (ret)
301+ break;
302+ }
303+
304+ jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, 0);
305+ clk_disable(jz47xx_i2c->clk);
306+
307+ printk("xfer ret: %d\n", ret);
308+
309+ return ret;
310+}
311+
312+static u32 jz47xx_i2c_functionality(struct i2c_adapter *adap)
313+{
314+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
315+}
316+
317+static const struct i2c_algorithm jz47xx_i2c_algorithm = {
318+ .master_xfer = jz47xx_i2c_xfer,
319+ .functionality = jz47xx_i2c_functionality,
320+};
321+
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),
325+};
326+
327+static int __devinit jz47xx_i2c_probe(struct platform_device *pdev)
328+{
329+ struct jz47xx_i2c *jz47xx_i2c;
330+ struct resource *mem;
331+ void __iomem *base;
332+ struct clk *clk;
333+ int irq;
334+ int ret;
335+
336+ irq = platform_get_irq(pdev, 0);
337+ if (!irq) {
338+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
339+ return irq;
340+ }
341+
342+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
343+ if (!mem) {
344+ dev_err(&pdev->dev, "Failed to get iomem region\n");
345+ return -ENXIO;
346+ }
347+
348+ mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
349+ if (!mem) {
350+ dev_err(&pdev->dev, "Failed to request iomem region\n");
351+ return -EBUSY;
352+ }
353+
354+ base = ioremap(mem->start, resource_size(mem));
355+ if (!base) {
356+ dev_err(&pdev->dev, "Failed to ioremap iomem\n");
357+ ret = -EBUSY;
358+ goto err_release_mem_region;
359+ }
360+
361+ clk = clk_get(&pdev->dev, "i2c");
362+ if (IS_ERR(clk)) {
363+ ret = PTR_ERR(clk);
364+ goto err_iounmap;
365+ }
366+
367+ jz47xx_i2c = kzalloc(sizeof(*jz47xx_i2c), GFP_KERNEL);
368+ if (!jz47xx_i2c) {
369+ ret = -ENOMEM;
370+ goto err_clk_put;
371+ }
372+
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);
378+
379+ jz47xx_i2c->mem = mem;
380+ jz47xx_i2c->base = base;
381+ jz47xx_i2c->clk = clk;
382+ jz47xx_i2c->irq = irq;
383+
384+ init_waitqueue_head(&jz47xx_i2c->wait_queue);
385+
386+ ret = request_irq(irq, jz47xx_i2c_irq_handler, 0, pdev->name, jz47xx_i2c);
387+ if (ret) {
388+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
389+ goto err_free;
390+ }
391+
392+ ret = jz_gpio_bulk_request(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
393+ if (ret) {
394+ dev_err(&pdev->dev, "Failed to request i2c pins: %d\n", ret);
395+ goto err_free_irq;
396+ }
397+
398+ writew(0x10, jz47xx_i2c->base + JZ47XX_REG_I2C_CLOCK);
399+
400+ ret = i2c_add_numbered_adapter(&jz47xx_i2c->adapter);
401+ if (ret) {
402+ dev_err(&pdev->dev, "Failed to add i2c adapter: %d\n", ret);
403+ goto err_free_gpios;
404+ }
405+
406+ platform_set_drvdata(pdev, jz47xx_i2c);
407+
408+ printk("JZ4740 I2C\n");
409+
410+ return 0;
411+
412+err_free_gpios:
413+ jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
414+err_free_irq:
415+ free_irq(irq, jz47xx_i2c);
416+err_free:
417+ kfree(jz47xx_i2c);
418+err_clk_put:
419+ clk_put(clk);
420+err_iounmap:
421+ iounmap(base);
422+err_release_mem_region:
423+ release_mem_region(mem->start, resource_size(mem));
424+ return ret;
425+}
426+
427+static int __devexit jz47xx_i2c_remove(struct platform_device *pdev)
428+{
429+ struct jz47xx_i2c *jz47xx_i2c = platform_get_drvdata(pdev);
430+
431+ platform_set_drvdata(pdev, NULL);
432+ i2c_del_adapter(&jz47xx_i2c->adapter);
433+
434+ jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
435+
436+ free_irq(jz47xx_i2c->irq, jz47xx_i2c);
437+ clk_put(jz47xx_i2c->clk);
438+
439+ iounmap(jz47xx_i2c->base);
440+ release_mem_region(jz47xx_i2c->mem->start, resource_size(jz47xx_i2c->mem));
441+
442+ kfree(jz47xx_i2c);
443+
444+ return 0;
445+}
446+
447+static struct platform_driver jz47xx_i2c_driver = {
448+ .probe = jz47xx_i2c_probe,
449+ .remove = jz47xx_i2c_remove,
450+ .driver = {
451+ .name = "jz47xx-i2c",
452+ .owner = THIS_MODULE,
453+ },
454+};
455+
456+static int __init jz47xx_i2c_init(void)
457+{
458+ return platform_driver_register(&jz47xx_i2c_driver);
459+}
460+module_init(jz47xx_i2c_init);
461+
462+static void jz47xx_i2c_exit(void)
463+{
464+ platform_driver_unregister(&jz47xx_i2c_driver);
465+}
466+module_exit(jz47xx_i2c_exit);
467+
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");
472+
473

Archive Download this file



interactive