PageRenderTime 35ms CodeModel.GetById 13ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/drivers/i2c/busses/i2c-bcm2708.c

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