026af8a7d933cd80f6c39030cf83ba2c848894b5
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 015-bcm2708-i2c-driver.patch
1 --- /dev/null
2 +++ b/drivers/i2c/busses/i2c-bcm2708.c
3 @@ -0,0 +1,408 @@
4 +/*
5 + * Driver for Broadcom BCM2708 BSC Controllers
6 + *
7 + * Copyright (C) 2012 Chris Boot & Frank Buss
8 + *
9 + * This driver is inspired by:
10 + * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
11 + *
12 + * This program is free software; you can redistribute it and/or modify
13 + * it under the terms of the GNU General Public License as published by
14 + * the Free Software Foundation; either version 2 of the License, or
15 + * (at your option) any later version.
16 + *
17 + * This program is distributed in the hope that it will be useful,
18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 + * GNU General Public License for more details.
21 + *
22 + * You should have received a copy of the GNU General Public License
23 + * along with this program; if not, write to the Free Software
24 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 + */
26 +
27 +#include <linux/kernel.h>
28 +#include <linux/module.h>
29 +#include <linux/spinlock.h>
30 +#include <linux/clk.h>
31 +#include <linux/err.h>
32 +#include <linux/platform_device.h>
33 +#include <linux/io.h>
34 +#include <linux/slab.h>
35 +#include <linux/i2c.h>
36 +#include <linux/interrupt.h>
37 +#include <linux/sched.h>
38 +#include <linux/wait.h>
39 +
40 +/* BSC register offsets */
41 +#define BSC_C 0x00
42 +#define BSC_S 0x04
43 +#define BSC_DLEN 0x08
44 +#define BSC_A 0x0c
45 +#define BSC_FIFO 0x10
46 +#define BSC_DIV 0x14
47 +#define BSC_DEL 0x18
48 +#define BSC_CLKT 0x1c
49 +
50 +/* Bitfields in BSC_C */
51 +#define BSC_C_I2CEN 0x00008000
52 +#define BSC_C_INTR 0x00000400
53 +#define BSC_C_INTT 0x00000200
54 +#define BSC_C_INTD 0x00000100
55 +#define BSC_C_ST 0x00000080
56 +#define BSC_C_CLEAR_1 0x00000020
57 +#define BSC_C_CLEAR_2 0x00000010
58 +#define BSC_C_READ 0x00000001
59 +
60 +/* Bitfields in BSC_S */
61 +#define BSC_S_CLKT 0x00000200
62 +#define BSC_S_ERR 0x00000100
63 +#define BSC_S_RXF 0x00000080
64 +#define BSC_S_TXE 0x00000040
65 +#define BSC_S_RXD 0x00000020
66 +#define BSC_S_TXD 0x00000010
67 +#define BSC_S_RXR 0x00000008
68 +#define BSC_S_TXW 0x00000004
69 +#define BSC_S_DONE 0x00000002
70 +#define BSC_S_TA 0x00000001
71 +
72 +#define I2C_TIMEOUT_MS 150
73 +
74 +#define DRV_NAME "bcm2708_i2c"
75 +
76 +static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
77 +module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
78 +MODULE_PARM_DESC(baudrate, "The I2C baudrate");
79 +
80 +
81 +struct bcm2708_i2c {
82 + struct i2c_adapter adapter;
83 +
84 + spinlock_t lock;
85 + void __iomem *base;
86 + int irq;
87 + struct clk *clk;
88 +
89 + struct completion done;
90 +
91 + struct i2c_msg *msg;
92 + int pos;
93 + int nmsgs;
94 + bool error;
95 +};
96 +
97 +/*
98 + * This function sets the ALT mode on the I2C pins so that we can use them with
99 + * the BSC hardware.
100 + *
101 + * FIXME: This is a hack. Use pinmux / pinctrl.
102 + */
103 +static void bcm2708_i2c_init_pinmode(int id)
104 +{
105 +#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
106 +#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
107 +
108 + int pin;
109 + u32 *gpio = ioremap(0x20200000, SZ_16K);
110 +
111 + BUG_ON(id != 0 && id != 1);
112 + /* BSC0 is on GPIO 0 & 1, BSC1 is on GPIO 2 & 3 */
113 + for (pin = id*2+0; pin <= id*2+1; pin++) {
114 +printk("bcm2708_i2c_init_pinmode(%d,%d)\n", id, pin);
115 + INP_GPIO(pin); /* set mode to GPIO input first */
116 + SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
117 + }
118 +
119 + iounmap(gpio);
120 +
121 +#undef INP_GPIO
122 +#undef SET_GPIO_ALT
123 +}
124 +
125 +static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
126 +{
127 + return readl(bi->base + reg);
128 +}
129 +
130 +static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
131 +{
132 + writel(val, bi->base + reg);
133 +}
134 +
135 +static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
136 +{
137 + bcm2708_wr(bi, BSC_C, 0);
138 + bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
139 +}
140 +
141 +static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
142 +{
143 + while ((bcm2708_rd(bi, BSC_S) & BSC_S_RXD) && (bi->pos < bi->msg->len))
144 + bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
145 +}
146 +
147 +static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
148 +{
149 + while ((bcm2708_rd(bi, BSC_S) & BSC_S_TXD) && (bi->pos < bi->msg->len))
150 + bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
151 +}
152 +
153 +static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
154 +{
155 + unsigned long bus_hz;
156 + u32 cdiv;
157 + u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
158 +
159 + bus_hz = clk_get_rate(bi->clk);
160 + cdiv = bus_hz / baudrate;
161 +
162 + if (bi->msg->flags & I2C_M_RD)
163 + c |= BSC_C_INTR | BSC_C_READ;
164 + else
165 + c |= BSC_C_INTT;
166 +
167 + bcm2708_wr(bi, BSC_DIV, cdiv);
168 + bcm2708_wr(bi, BSC_A, bi->msg->addr);
169 + bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
170 + bcm2708_wr(bi, BSC_C, c);
171 +}
172 +
173 +static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
174 +{
175 + struct bcm2708_i2c *bi = dev_id;
176 + bool handled = true;
177 + u32 s;
178 +
179 + spin_lock(&bi->lock);
180 +
181 + /* we may see camera interrupts on the "other" I2C channel
182 + Just return if we've not sent anything */
183 + if (!bi->nmsgs || !bi->msg )
184 + goto early_exit;
185 +
186 + s = bcm2708_rd(bi, BSC_S);
187 +
188 + if (s & (BSC_S_CLKT | BSC_S_ERR)) {
189 + bcm2708_bsc_reset(bi);
190 + bi->error = true;
191 +
192 + /* wake up our bh */
193 + complete(&bi->done);
194 + } else if (s & BSC_S_DONE) {
195 + bi->nmsgs--;
196 +
197 + if (bi->msg->flags & I2C_M_RD)
198 + bcm2708_bsc_fifo_drain(bi);
199 +
200 + bcm2708_bsc_reset(bi);
201 +
202 + if (bi->nmsgs) {
203 + /* advance to next message */
204 + bi->msg++;
205 + bi->pos = 0;
206 + bcm2708_bsc_setup(bi);
207 + } else {
208 + /* wake up our bh */
209 + complete(&bi->done);
210 + }
211 + } else if (s & BSC_S_TXW) {
212 + bcm2708_bsc_fifo_fill(bi);
213 + } else if (s & BSC_S_RXR) {
214 + bcm2708_bsc_fifo_drain(bi);
215 + } else {
216 + handled = false;
217 + }
218 +
219 +early_exit:
220 + spin_unlock(&bi->lock);
221 +
222 + return handled ? IRQ_HANDLED : IRQ_NONE;
223 +}
224 +
225 +static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
226 + struct i2c_msg *msgs, int num)
227 +{
228 + struct bcm2708_i2c *bi = adap->algo_data;
229 + unsigned long flags;
230 + int ret;
231 +
232 + spin_lock_irqsave(&bi->lock, flags);
233 +
234 + INIT_COMPLETION(bi->done);
235 + bi->msg = msgs;
236 + bi->pos = 0;
237 + bi->nmsgs = num;
238 + bi->error = false;
239 +
240 + spin_unlock_irqrestore(&bi->lock, flags);
241 +
242 + bcm2708_bsc_setup(bi);
243 +
244 + ret = wait_for_completion_timeout(&bi->done,
245 + msecs_to_jiffies(I2C_TIMEOUT_MS));
246 + if (ret == 0) {
247 + dev_err(&adap->dev, "transfer timed out\n");
248 + spin_lock_irqsave(&bi->lock, flags);
249 + bcm2708_bsc_reset(bi);
250 + spin_unlock_irqrestore(&bi->lock, flags);
251 + return -ETIMEDOUT;
252 + }
253 +
254 + return bi->error ? -EIO : num;
255 +}
256 +
257 +static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
258 +{
259 + return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
260 +}
261 +
262 +static struct i2c_algorithm bcm2708_i2c_algorithm = {
263 + .master_xfer = bcm2708_i2c_master_xfer,
264 + .functionality = bcm2708_i2c_functionality,
265 +};
266 +
267 +static int bcm2708_i2c_probe(struct platform_device *pdev)
268 +{
269 + struct resource *regs;
270 + int irq, err = -ENOMEM;
271 + struct clk *clk;
272 + struct bcm2708_i2c *bi;
273 + struct i2c_adapter *adap;
274 +
275 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
276 + if (!regs) {
277 + dev_err(&pdev->dev, "could not get IO memory\n");
278 + return -ENXIO;
279 + }
280 +
281 + irq = platform_get_irq(pdev, 0);
282 + if (irq < 0) {
283 + dev_err(&pdev->dev, "could not get IRQ\n");
284 + return irq;
285 + }
286 +
287 + clk = clk_get(&pdev->dev, NULL);
288 + if (IS_ERR(clk)) {
289 + dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
290 + return PTR_ERR(clk);
291 + }
292 +
293 + bcm2708_i2c_init_pinmode(pdev->id);
294 +
295 + bi = kzalloc(sizeof(*bi), GFP_KERNEL);
296 + if (!bi)
297 + goto out_clk_put;
298 +
299 + platform_set_drvdata(pdev, bi);
300 +
301 + adap = &bi->adapter;
302 + adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
303 + adap->algo = &bcm2708_i2c_algorithm;
304 + adap->algo_data = bi;
305 + adap->dev.parent = &pdev->dev;
306 + adap->nr = pdev->id;
307 + strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
308 +
309 + switch (pdev->id) {
310 + case 0:
311 + adap->class = I2C_CLASS_HWMON;
312 + break;
313 + case 1:
314 + adap->class = I2C_CLASS_DDC;
315 + break;
316 + default:
317 + dev_err(&pdev->dev, "can only bind to BSC 0 or 1\n");
318 + err = -ENXIO;
319 + goto out_free_bi;
320 + }
321 +
322 + spin_lock_init(&bi->lock);
323 + init_completion(&bi->done);
324 +
325 + bi->base = ioremap(regs->start, resource_size(regs));
326 + if (!bi->base) {
327 + dev_err(&pdev->dev, "could not remap memory\n");
328 + goto out_free_bi;
329 + }
330 +
331 + bi->irq = irq;
332 + bi->clk = clk;
333 +
334 + err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
335 + dev_name(&pdev->dev), bi);
336 + if (err) {
337 + dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
338 + goto out_iounmap;
339 + }
340 +
341 + bcm2708_bsc_reset(bi);
342 +
343 + err = i2c_add_numbered_adapter(adap);
344 + if (err < 0) {
345 + dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
346 + goto out_free_irq;
347 + }
348 +
349 + dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %dk)\n",
350 + pdev->id, (unsigned long)regs->start, irq, baudrate/1000);
351 +
352 + return 0;
353 +
354 +out_free_irq:
355 + free_irq(bi->irq, bi);
356 +out_iounmap:
357 + iounmap(bi->base);
358 +out_free_bi:
359 + kfree(bi);
360 +out_clk_put:
361 + clk_put(clk);
362 + return err;
363 +}
364 +
365 +static int bcm2708_i2c_remove(struct platform_device *pdev)
366 +{
367 + struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
368 +
369 + platform_set_drvdata(pdev, NULL);
370 +
371 + i2c_del_adapter(&bi->adapter);
372 + free_irq(bi->irq, bi);
373 + iounmap(bi->base);
374 + clk_disable(bi->clk);
375 + clk_put(bi->clk);
376 + kfree(bi);
377 +
378 + return 0;
379 +}
380 +
381 +static struct platform_driver bcm2708_i2c_driver = {
382 + .driver = {
383 + .name = DRV_NAME,
384 + .owner = THIS_MODULE,
385 + },
386 + .probe = bcm2708_i2c_probe,
387 + .remove = bcm2708_i2c_remove,
388 +};
389 +
390 +// module_platform_driver(bcm2708_i2c_driver);
391 +
392 +
393 +static int __init bcm2708_i2c_init(void)
394 +{
395 + return platform_driver_register(&bcm2708_i2c_driver);
396 +}
397 +
398 +static void __exit bcm2708_i2c_exit(void)
399 +{
400 + platform_driver_unregister(&bcm2708_i2c_driver);
401 +}
402 +
403 +module_init(bcm2708_i2c_init);
404 +module_exit(bcm2708_i2c_exit);
405 +
406 +
407 +
408 +MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
409 +MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
410 +MODULE_LICENSE("GPL v2");
411 +MODULE_ALIAS("platform:" DRV_NAME);
412 --- a/drivers/i2c/busses/Kconfig
413 +++ b/drivers/i2c/busses/Kconfig
414 @@ -344,6 +344,25 @@ config I2C_BCM2835
415 This support is also available as a module. If so, the module
416 will be called i2c-bcm2835.
417
418 +config I2C_BCM2708
419 + tristate "BCM2708 BSC"
420 + depends on MACH_BCM2708
421 + help
422 + Enabling this option will add BSC (Broadcom Serial Controller)
423 + support for the BCM2708. BSC is a Broadcom proprietary bus compatible
424 + with I2C/TWI/SMBus.
425 +
426 +config I2C_BCM2708_BAUDRATE
427 + prompt "BCM2708 I2C baudrate"
428 + depends on I2C_BCM2708
429 + int
430 + default 100000
431 + help
432 + Set the I2C baudrate. This will alter the default value. A
433 + different baudrate can be set by using a module parameter as well. If
434 + no parameter is provided when loading, this is the value that will be
435 + used.
436 +
437 config I2C_BLACKFIN_TWI
438 tristate "Blackfin TWI I2C support"
439 depends on BLACKFIN
440 --- a/drivers/i2c/busses/Makefile
441 +++ b/drivers/i2c/busses/Makefile
442 @@ -32,6 +32,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powerm
443 obj-$(CONFIG_I2C_AT91) += i2c-at91.o
444 obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
445 obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
446 +obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
447 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
448 obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
449 obj-$(CONFIG_I2C_CPM) += i2c-cpm.o