aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2008-04-22 16:16:46 -0400
committerJean Delvare <khali@hyperion.delvare>2008-04-22 16:16:46 -0400
commit244fbbb81c46eefcc5f3a9cc37c4668f9d8ff801 (patch)
treed405d23b51388bb15efeeb4de3e5826cf0954e85 /drivers
parentc01b0831057381c7f6e0bfb3634bac8c5f7fb256 (diff)
i2c: Add platform driver on top of the new pca-algorithm
Tested on a blackfin. Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/Kconfig15
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c298
3 files changed, 312 insertions, 2 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index b04c99580d0d..51de2ccc1519 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -632,8 +632,8 @@ config I2C_PCA_ISA
632 select I2C_ALGOPCA 632 select I2C_ALGOPCA
633 default n 633 default n
634 help 634 help
635 This driver supports ISA boards using the Philips PCA 9564 635 This driver supports ISA boards using the Philips PCA9564
636 Parallel bus to I2C bus controller 636 parallel bus to I2C bus controller.
637 637
638 This driver can also be built as a module. If so, the module 638 This driver can also be built as a module. If so, the module
639 will be called i2c-pca-isa. 639 will be called i2c-pca-isa.
@@ -643,6 +643,17 @@ config I2C_PCA_ISA
643 delays when I2C/SMBus chip drivers are loaded (e.g. at boot 643 delays when I2C/SMBus chip drivers are loaded (e.g. at boot
644 time). If unsure, say N. 644 time). If unsure, say N.
645 645
646config I2C_PCA_PLATFORM
647 tristate "PCA9564 as platform device"
648 select I2C_ALGOPCA
649 default n
650 help
651 This driver supports a memory mapped Philips PCA9564
652 parallel bus to I2C bus controller.
653
654 This driver can also be built as a module. If so, the module
655 will be called i2c-pca-platform.
656
646config I2C_MV64XXX 657config I2C_MV64XXX
647 tristate "Marvell mv64xxx I2C Controller" 658 tristate "Marvell mv64xxx I2C Controller"
648 depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL 659 depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ea7068f1eb6b..378d5c07e048 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
30obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o 30obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
31obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o 31obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
32obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o 32obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
33obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
33obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o 34obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
34obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o 35obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
35obj-$(CONFIG_I2C_PNX) += i2c-pnx.o 36obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
new file mode 100644
index 000000000000..9d75f51e8f0e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -0,0 +1,298 @@
1/*
2 * i2c_pca_platform.c
3 *
4 * Platform driver for the PCA9564 I2C controller.
5 *
6 * Copyright (C) 2008 Pengutronix
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11
12 */
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/delay.h>
18#include <linux/errno.h>
19#include <linux/i2c.h>
20#include <linux/interrupt.h>
21#include <linux/platform_device.h>
22#include <linux/i2c-algo-pca.h>
23#include <linux/i2c-pca-platform.h>
24#include <linux/gpio.h>
25
26#include <asm/irq.h>
27#include <asm/io.h>
28
29#define res_len(r) ((r)->end - (r)->start + 1)
30
31struct i2c_pca_pf_data {
32 void __iomem *reg_base;
33 int irq; /* if 0, use polling */
34 int gpio;
35 wait_queue_head_t wait;
36 struct i2c_adapter adap;
37 struct i2c_algo_pca_data algo_data;
38 unsigned long io_base;
39 unsigned long io_size;
40};
41
42/* Read/Write functions for different register alignments */
43
44static int i2c_pca_pf_readbyte8(void *pd, int reg)
45{
46 struct i2c_pca_pf_data *i2c = pd;
47 return ioread8(i2c->reg_base + reg);
48}
49
50static int i2c_pca_pf_readbyte16(void *pd, int reg)
51{
52 struct i2c_pca_pf_data *i2c = pd;
53 return ioread8(i2c->reg_base + reg * 2);
54}
55
56static int i2c_pca_pf_readbyte32(void *pd, int reg)
57{
58 struct i2c_pca_pf_data *i2c = pd;
59 return ioread8(i2c->reg_base + reg * 4);
60}
61
62static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
63{
64 struct i2c_pca_pf_data *i2c = pd;
65 iowrite8(val, i2c->reg_base + reg);
66}
67
68static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
69{
70 struct i2c_pca_pf_data *i2c = pd;
71 iowrite8(val, i2c->reg_base + reg * 2);
72}
73
74static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
75{
76 struct i2c_pca_pf_data *i2c = pd;
77 iowrite8(val, i2c->reg_base + reg * 4);
78}
79
80
81static int i2c_pca_pf_waitforcompletion(void *pd)
82{
83 struct i2c_pca_pf_data *i2c = pd;
84 int ret = 0;
85
86 if (i2c->irq) {
87 ret = wait_event_interruptible(i2c->wait,
88 i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
89 & I2C_PCA_CON_SI);
90 } else {
91 /*
92 * Do polling...
93 * XXX: Could get stuck in extreme cases!
94 * Maybe add timeout, but using irqs is preferred anyhow.
95 */
96 while ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
97 & I2C_PCA_CON_SI) == 0)
98 udelay(100);
99 }
100
101 return ret;
102}
103
104static void i2c_pca_pf_dummyreset(void *pd)
105{
106 struct i2c_pca_pf_data *i2c = pd;
107 printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",
108 i2c->adap.name);
109}
110
111static void i2c_pca_pf_resetchip(void *pd)
112{
113 struct i2c_pca_pf_data *i2c = pd;
114
115 gpio_set_value(i2c->gpio, 0);
116 ndelay(100);
117 gpio_set_value(i2c->gpio, 1);
118}
119
120static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
121{
122 struct i2c_pca_pf_data *i2c = dev_id;
123
124 if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
125 return IRQ_NONE;
126
127 wake_up_interruptible(&i2c->wait);
128
129 return IRQ_HANDLED;
130}
131
132
133static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
134{
135 struct i2c_pca_pf_data *i2c;
136 struct resource *res;
137 struct i2c_pca9564_pf_platform_data *platform_data =
138 pdev->dev.platform_data;
139 int ret = 0;
140 int irq;
141
142 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
143 irq = platform_get_irq(pdev, 0);
144 /* If irq is 0, we do polling. */
145
146 if (res == NULL) {
147 ret = -ENODEV;
148 goto e_print;
149 }
150
151 if (!request_mem_region(res->start, res_len(res), res->name)) {
152 ret = -ENOMEM;
153 goto e_print;
154 }
155
156 i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);
157 if (!i2c) {
158 ret = -ENOMEM;
159 goto e_alloc;
160 }
161
162 init_waitqueue_head(&i2c->wait);
163
164 i2c->reg_base = ioremap(res->start, res_len(res));
165 if (!i2c->reg_base) {
166 ret = -EIO;
167 goto e_remap;
168 }
169 i2c->io_base = res->start;
170 i2c->io_size = res_len(res);
171 i2c->irq = irq;
172
173 i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
174 i2c->adap.owner = THIS_MODULE;
175 snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx",
176 (unsigned long) res->start);
177 i2c->adap.algo_data = &i2c->algo_data;
178 i2c->adap.dev.parent = &pdev->dev;
179 i2c->adap.timeout = platform_data->timeout;
180
181 i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
182 i2c->algo_data.data = i2c;
183
184 switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
185 case IORESOURCE_MEM_32BIT:
186 i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
187 i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
188 break;
189 case IORESOURCE_MEM_16BIT:
190 i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
191 i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
192 break;
193 case IORESOURCE_MEM_8BIT:
194 default:
195 i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
196 i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
197 break;
198 }
199
200 i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
201
202 i2c->gpio = platform_data->gpio;
203 i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
204
205 /* Use gpio_is_valid() when in mainline */
206 if (i2c->gpio > -1) {
207 ret = gpio_request(i2c->gpio, i2c->adap.name);
208 if (ret == 0) {
209 gpio_direction_output(i2c->gpio, 1);
210 i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
211 } else {
212 printk(KERN_WARNING "%s: Registering gpio failed!\n",
213 i2c->adap.name);
214 i2c->gpio = ret;
215 }
216 }
217
218 if (irq) {
219 ret = request_irq(irq, i2c_pca_pf_handler,
220 IRQF_TRIGGER_FALLING, i2c->adap.name, i2c);
221 if (ret)
222 goto e_reqirq;
223 }
224
225 if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {
226 ret = -ENODEV;
227 goto e_adapt;
228 }
229
230 platform_set_drvdata(pdev, i2c);
231
232 printk(KERN_INFO "%s registered.\n", i2c->adap.name);
233
234 return 0;
235
236e_adapt:
237 if (irq)
238 free_irq(irq, i2c);
239e_reqirq:
240 if (i2c->gpio > -1)
241 gpio_free(i2c->gpio);
242
243 iounmap(i2c->reg_base);
244e_remap:
245 kfree(i2c);
246e_alloc:
247 release_mem_region(res->start, res_len(res));
248e_print:
249 printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret);
250 return ret;
251}
252
253static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
254{
255 struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
256 platform_set_drvdata(pdev, NULL);
257
258 i2c_del_adapter(&i2c->adap);
259
260 if (i2c->irq)
261 free_irq(i2c->irq, i2c);
262
263 if (i2c->gpio > -1)
264 gpio_free(i2c->gpio);
265
266 iounmap(i2c->reg_base);
267 release_mem_region(i2c->io_base, i2c->io_size);
268 kfree(i2c);
269
270 return 0;
271}
272
273static struct platform_driver i2c_pca_pf_driver = {
274 .probe = i2c_pca_pf_probe,
275 .remove = __devexit_p(i2c_pca_pf_remove),
276 .driver = {
277 .name = "i2c-pca-platform",
278 .owner = THIS_MODULE,
279 },
280};
281
282static int __init i2c_pca_pf_init(void)
283{
284 return platform_driver_register(&i2c_pca_pf_driver);
285}
286
287static void __exit i2c_pca_pf_exit(void)
288{
289 platform_driver_unregister(&i2c_pca_pf_driver);
290}
291
292MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
293MODULE_DESCRIPTION("I2C-PCA9564 platform driver");
294MODULE_LICENSE("GPL");
295
296module_init(i2c_pca_pf_init);
297module_exit(i2c_pca_pf_exit);
298