Root/target/linux/xburst/patches-3.0/0008-i2c-Add-i2c-driver-for-JZ47XX-SoCs.patch

1From 5e219770079a61b8c8e59abe5510678361c94696 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 08/32] 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
17diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
18index 646068e..5b76fcf 100644
19--- a/drivers/i2c/busses/Kconfig
20+++ b/drivers/i2c/busses/Kconfig
21@@ -434,6 +434,16 @@ config I2C_IXP2000
22       This driver is deprecated and will be dropped soon. Use i2c-gpio
23       instead.
24 
25+config I2C_JZ47XX
26+ tristate "JZ4740 I2C Interface"
27+ depends on ARCH_JZ4740
28+ help
29+ Say Y here if you want support for the I2C controller found on Ingenic
30+ JZ47XX based SoCs.
31+
32+ This driver can also be built as a module. If so, the module will be
33+ called i2c-jz47xx.
34+
35 config I2C_MPC
36     tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
37     depends on PPC
38diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
39index e6cf294..07be071 100644
40--- a/drivers/i2c/busses/Makefile
41+++ b/drivers/i2c/busses/Makefile
42@@ -41,6 +41,7 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o
43 obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
44 obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
45 obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
46+obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o
47 obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
48 obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
49 obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
50diff --git a/drivers/i2c/busses/i2c-jz47xx.c b/drivers/i2c/busses/i2c-jz47xx.c
51new file mode 100644
52index 0000000..492d350
53--- /dev/null
54+++ b/drivers/i2c/busses/i2c-jz47xx.c
55@@ -0,0 +1,424 @@
56+
57+#include <linux/init.h>
58+#include <linux/kernel.h>
59+#include <linux/module.h>
60+#include <linux/err.h>
61+#include <linux/clk.h>
62+#include <linux/platform_device.h>
63+#include <linux/i2c.h>
64+#include <linux/slab.h>
65+#include <linux/interrupt.h>
66+
67+#include <linux/gpio.h>
68+#include <linux/delay.h>
69+
70+#define JZ47XX_REG_I2C_DATA 0x00
71+#define JZ47XX_REG_I2C_CTRL 0x04
72+#define JZ47XX_REG_I2C_STATUS 0x08
73+#define JZ47XX_REG_I2C_CLOCK 0x0C
74+
75+#define JZ47XX_I2C_STATUS_FIFO_FULL BIT(4)
76+#define JZ47XX_I2C_STATUS_BUSY BIT(3)
77+#define JZ47XX_I2C_STATUS_TEND BIT(2)
78+#define JZ47XX_I2C_STATUS_DATA_VALID BIT(1)
79+#define JZ47XX_I2C_STATUS_NACK BIT(0)
80+
81+#define JZ47XX_I2C_CTRL_IRQ_ENABLE BIT(4)
82+#define JZ47XX_I2C_CTRL_START BIT(3)
83+#define JZ47XX_I2C_CTRL_STOP BIT(2)
84+#define JZ47XX_I2C_CTRL_NACK BIT(1)
85+#define JZ47XX_I2C_CTRL_ENABLE BIT(0)
86+
87+struct jz47xx_i2c {
88+ struct resource *mem;
89+ void __iomem *base;
90+ int irq;
91+ struct clk *clk;
92+
93+ struct i2c_adapter adapter;
94+
95+ wait_queue_head_t wait_queue;
96+};
97+
98+static inline struct jz47xx_i2c *adapter_to_jz47xx_i2c(struct i2c_adapter *adap)
99+{
100+ return container_of(adap, struct jz47xx_i2c, adapter);
101+}
102+
103+static inline void jz47xx_i2c_set_ctrl(struct jz47xx_i2c *jz47xx_i2c,
104+ uint8_t mask, uint8_t value)
105+{
106+ uint8_t ctrl;
107+ ctrl = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
108+ ctrl &= ~mask;
109+ ctrl |= value;
110+ printk("ctrl: %x\n", ctrl);
111+ writeb(ctrl, jz47xx_i2c->base + JZ47XX_REG_I2C_CTRL);
112+}
113+
114+static irqreturn_t jz47xx_i2c_irq_handler(int irq, void *devid)
115+{
116+ struct jz47xx_i2c *jz47xx_i2c = devid;
117+
118+ printk("IRQ\n");
119+
120+ wake_up(&jz47xx_i2c->wait_queue);
121+
122+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE, 0);
123+
124+ return IRQ_HANDLED;
125+}
126+
127+static inline void jz47xx_i2c_set_data_valid(struct jz47xx_i2c *jz47xx_i2c,
128+ bool valid)
129+{
130+ uint8_t val;
131+ val = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
132+ if (valid)
133+ val |= JZ47XX_I2C_STATUS_DATA_VALID;
134+ else
135+ val &= ~JZ47XX_I2C_STATUS_DATA_VALID;
136+ writeb(val, jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
137+}
138+
139+static int jz47xx_i2c_test_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t mask, uint8_t value)
140+{
141+ uint8_t status;
142+
143+ mask |= JZ47XX_I2C_STATUS_NACK;
144+ value |= JZ47XX_I2C_STATUS_NACK;
145+
146+ status = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS);
147+ printk("status: %x %x %x %x\n", status, mask, value, (status & mask) ^
148+ value);
149+ if (((status & mask) ^ value) == mask) {
150+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_IRQ_ENABLE,
151+ JZ47XX_I2C_CTRL_IRQ_ENABLE);
152+ return 0;
153+ }
154+ return 1;
155+}
156+
157+static int jz47xx_i2c_wait_event_or_nack(struct jz47xx_i2c *jz47xx_i2c, uint8_t
158+mask, uint8_t value)
159+{
160+ int ret;
161+
162+ ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
163+ jz47xx_i2c_test_event(jz47xx_i2c, mask, value), 30 * HZ);
164+
165+/* while (!jz47xx_i2c_test_event(jz47xx_i2c, mask, value));
166+
167+ ret = 1;*/
168+
169+ printk("wait event or nack: %d %x\n", ret, readb(jz47xx_i2c->base +
170+ JZ47XX_REG_I2C_STATUS));
171+
172+ if (ret == 0)
173+ ret = -ETIMEDOUT;
174+ else if(ret > 0) {
175+ if (readb(jz47xx_i2c->base + JZ47XX_REG_I2C_STATUS) & JZ47XX_I2C_STATUS_NACK)
176+ ret = -EIO;
177+ else
178+ ret = 0;
179+ }
180+
181+ return ret;
182+}
183+
184+static int jz47xx_i2c_wait_event(struct jz47xx_i2c *jz47xx_i2c, uint8_t event)
185+{
186+ int ret;
187+
188+ ret = wait_event_interruptible_timeout(jz47xx_i2c->wait_queue,
189+ jz47xx_i2c_test_event(jz47xx_i2c, event, event), 30 * HZ);
190+
191+ if (ret == 0)
192+ ret = -ETIMEDOUT;
193+ else if(ret > 0)
194+ ret = 0;
195+
196+ return ret;
197+}
198+
199+
200+static int jz47xx_i2c_write_msg(struct jz47xx_i2c *jz47xx_i2c,
201+ struct i2c_msg *msg)
202+{
203+ int ret;
204+ int i;
205+
206+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
207+ for (i = 0; i < msg->len; ++i) {
208+ writeb(msg->buf[i], jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
209+ jz47xx_i2c_set_data_valid(jz47xx_i2c, true);
210+ ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
211+ JZ47XX_I2C_STATUS_DATA_VALID, 0);
212+ if (ret)
213+ break;
214+ }
215+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
216+ JZ47XX_I2C_CTRL_STOP);
217+
218+ if (!ret)
219+ ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c, JZ47XX_I2C_STATUS_TEND,
220+ JZ47XX_I2C_STATUS_TEND);
221+
222+ return ret;
223+}
224+
225+static int jz47xx_i2c_read_msg(struct jz47xx_i2c *jz47xx_i2c,
226+ struct i2c_msg *msg)
227+{
228+ int i;
229+ int ret;
230+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
231+
232+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
233+ msg->len == 1 ? JZ47XX_I2C_CTRL_NACK : 0);
234+
235+ for (i = 0; i < msg->len; ++i) {
236+ ret = jz47xx_i2c_wait_event(jz47xx_i2c, JZ47XX_I2C_STATUS_DATA_VALID);
237+ if (ret) {
238+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
239+ JZ47XX_I2C_CTRL_NACK);
240+ break;
241+ }
242+
243+ if (i == msg->len - 2) {
244+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_NACK,
245+ JZ47XX_I2C_CTRL_NACK);
246+ }
247+
248+ msg->buf[i] = readb(jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
249+ printk("read: %x\n", msg->buf[i]);
250+ jz47xx_i2c_set_data_valid(jz47xx_i2c, false);
251+ }
252+
253+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_STOP,
254+ JZ47XX_I2C_CTRL_STOP);
255+
256+ return ret;
257+}
258+
259+static int jz47xx_i2c_xfer_msg(struct jz47xx_i2c *jz47xx_i2c,
260+ struct i2c_msg *msg)
261+{
262+ uint8_t addr;
263+ int ret;
264+
265+ addr = msg->addr << 1;
266+ if (msg->flags & I2C_M_RD)
267+ addr |= 1;
268+
269+ jz47xx_i2c_set_ctrl(jz47xx_i2c, JZ47XX_I2C_CTRL_START,
270+ JZ47XX_I2C_CTRL_START);
271+ writeb(addr, jz47xx_i2c->base + JZ47XX_REG_I2C_DATA);
272+ jz47xx_i2c_set_data_valid(jz47xx_i2c, true);
273+
274+ if (msg->flags & I2C_M_RD) {
275+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
276+ ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
277+ JZ47XX_I2C_STATUS_TEND, JZ47XX_I2C_STATUS_TEND);
278+ if (!ret)
279+ ret = jz47xx_i2c_read_msg(jz47xx_i2c, msg);
280+ } else {
281+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
282+ ret = jz47xx_i2c_wait_event_or_nack(jz47xx_i2c,
283+ JZ47XX_I2C_STATUS_DATA_VALID, 0);
284+ if (!ret)
285+ ret = jz47xx_i2c_write_msg(jz47xx_i2c, msg);
286+ }
287+
288+ return ret;
289+}
290+
291+static int jz47xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int
292+num)
293+{
294+ struct jz47xx_i2c *jz47xx_i2c = adapter_to_jz47xx_i2c(adap);
295+ int ret = 0;
296+ int i;
297+ int mask = JZ47XX_I2C_CTRL_ENABLE;
298+
299+ printk("xfer: %d %x\n", num, readb(jz47xx_i2c->base +
300+ JZ47XX_REG_I2C_STATUS));
301+
302+ clk_enable(jz47xx_i2c->clk);
303+ jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, mask);
304+
305+ for (i = 0; i < num; ++i) {
306+ ret = jz47xx_i2c_xfer_msg(jz47xx_i2c, &msgs[i]);
307+ if (ret)
308+ break;
309+ }
310+
311+ jz47xx_i2c_set_ctrl(jz47xx_i2c, mask, 0);
312+ clk_disable(jz47xx_i2c->clk);
313+
314+ printk("xfer ret: %d\n", ret);
315+
316+ return ret;
317+}
318+
319+static u32 jz47xx_i2c_functionality(struct i2c_adapter *adap)
320+{
321+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
322+}
323+
324+static const struct i2c_algorithm jz47xx_i2c_algorithm = {
325+ .master_xfer = jz47xx_i2c_xfer,
326+ .functionality = jz47xx_i2c_functionality,
327+};
328+
329+const static struct jz_gpio_bulk_request jz47xx_i2c_pins[] = {
330+ JZ_GPIO_BULK_PIN(I2C_SDA),
331+ JZ_GPIO_BULK_PIN(I2C_SCK),
332+};
333+
334+static int __devinit jz47xx_i2c_probe(struct platform_device *pdev)
335+{
336+ struct jz47xx_i2c *jz47xx_i2c;
337+ struct resource *mem;
338+ void __iomem *base;
339+ struct clk *clk;
340+ int irq;
341+ int ret;
342+
343+ irq = platform_get_irq(pdev, 0);
344+ if (!irq) {
345+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
346+ return irq;
347+ }
348+
349+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
350+ if (!mem) {
351+ dev_err(&pdev->dev, "Failed to get iomem region\n");
352+ return -ENXIO;
353+ }
354+
355+ mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
356+ if (!mem) {
357+ dev_err(&pdev->dev, "Failed to request iomem region\n");
358+ return -EBUSY;
359+ }
360+
361+ base = ioremap(mem->start, resource_size(mem));
362+ if (!base) {
363+ dev_err(&pdev->dev, "Failed to ioremap iomem\n");
364+ ret = -EBUSY;
365+ goto err_release_mem_region;
366+ }
367+
368+ clk = clk_get(&pdev->dev, "i2c");
369+ if (IS_ERR(clk)) {
370+ ret = PTR_ERR(clk);
371+ goto err_iounmap;
372+ }
373+
374+ jz47xx_i2c = kzalloc(sizeof(*jz47xx_i2c), GFP_KERNEL);
375+ if (!jz47xx_i2c) {
376+ ret = -ENOMEM;
377+ goto err_clk_put;
378+ }
379+
380+ jz47xx_i2c->adapter.owner = THIS_MODULE;
381+ jz47xx_i2c->adapter.algo = &jz47xx_i2c_algorithm;
382+ jz47xx_i2c->adapter.dev.parent = &pdev->dev;
383+ jz47xx_i2c->adapter.nr = pdev->id < 0 ?: 0;
384+ strcpy(jz47xx_i2c->adapter.name, pdev->name);
385+
386+ jz47xx_i2c->mem = mem;
387+ jz47xx_i2c->base = base;
388+ jz47xx_i2c->clk = clk;
389+ jz47xx_i2c->irq = irq;
390+
391+ init_waitqueue_head(&jz47xx_i2c->wait_queue);
392+
393+ ret = request_irq(irq, jz47xx_i2c_irq_handler, 0, pdev->name, jz47xx_i2c);
394+ if (ret) {
395+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
396+ goto err_free;
397+ }
398+
399+ ret = jz_gpio_bulk_request(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
400+ if (ret) {
401+ dev_err(&pdev->dev, "Failed to request i2c pins: %d\n", ret);
402+ goto err_free_irq;
403+ }
404+
405+ writew(0x10, jz47xx_i2c->base + JZ47XX_REG_I2C_CLOCK);
406+
407+ ret = i2c_add_numbered_adapter(&jz47xx_i2c->adapter);
408+ if (ret) {
409+ dev_err(&pdev->dev, "Failed to add i2c adapter: %d\n", ret);
410+ goto err_free_gpios;
411+ }
412+
413+ platform_set_drvdata(pdev, jz47xx_i2c);
414+
415+ printk("JZ4740 I2C\n");
416+
417+ return 0;
418+
419+err_free_gpios:
420+ jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
421+err_free_irq:
422+ free_irq(irq, jz47xx_i2c);
423+err_free:
424+ kfree(jz47xx_i2c);
425+err_clk_put:
426+ clk_put(clk);
427+err_iounmap:
428+ iounmap(base);
429+err_release_mem_region:
430+ release_mem_region(mem->start, resource_size(mem));
431+ return ret;
432+}
433+
434+static int __devexit jz47xx_i2c_remove(struct platform_device *pdev)
435+{
436+ struct jz47xx_i2c *jz47xx_i2c = platform_get_drvdata(pdev);
437+
438+ platform_set_drvdata(pdev, NULL);
439+ i2c_del_adapter(&jz47xx_i2c->adapter);
440+
441+ jz_gpio_bulk_free(jz47xx_i2c_pins, ARRAY_SIZE(jz47xx_i2c_pins));
442+
443+ free_irq(jz47xx_i2c->irq, jz47xx_i2c);
444+ clk_put(jz47xx_i2c->clk);
445+
446+ iounmap(jz47xx_i2c->base);
447+ release_mem_region(jz47xx_i2c->mem->start, resource_size(jz47xx_i2c->mem));
448+
449+ kfree(jz47xx_i2c);
450+
451+ return 0;
452+}
453+
454+static struct platform_driver jz47xx_i2c_driver = {
455+ .probe = jz47xx_i2c_probe,
456+ .remove = jz47xx_i2c_remove,
457+ .driver = {
458+ .name = "jz47xx-i2c",
459+ .owner = THIS_MODULE,
460+ },
461+};
462+
463+static int __init jz47xx_i2c_init(void)
464+{
465+ return platform_driver_register(&jz47xx_i2c_driver);
466+}
467+module_init(jz47xx_i2c_init);
468+
469+static void jz47xx_i2c_exit(void)
470+{
471+ platform_driver_unregister(&jz47xx_i2c_driver);
472+}
473+module_exit(jz47xx_i2c_exit);
474+
475+MODULE_LICENSE("GPL");
476+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
477+MODULE_DESCRIPTION("I2C adapter driver for JZ47XX SoCs");
478+MODULE_ALIAS("platform:jz47xx-i2c");
479+
480--
4811.7.4.1
482
483

Archive Download this file



interactive