• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/mti-sead3/
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15 */
16
17#include <linux/delay.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/spinlock.h>
21#include <linux/platform_device.h>
22#include <linux/init.h>
23#include <linux/errno.h>
24#include <linux/i2c.h>
25#include <linux/slab.h>
26
27#define PIC32_I2CxCON		0x0000
28#define PIC32_I2CxCONCLR	0x0004
29#define PIC32_I2CxCONSET	0x0008
30#define PIC32_I2CxCONINV	0x000C
31#define  I2CCON_ON		(1<<15)
32#define  I2CCON_FRZ		(1<<14)
33#define  I2CCON_SIDL		(1<<13)
34#define  I2CCON_SCLREL		(1<<12)
35#define  I2CCON_STRICT		(1<<11)
36#define  I2CCON_A10M		(1<<10)
37#define  I2CCON_DISSLW		(1<<9)
38#define  I2CCON_SMEN		(1<<8)
39#define  I2CCON_GCEN		(1<<7)
40#define  I2CCON_STREN		(1<<6)
41#define  I2CCON_ACKDT		(1<<5)
42#define  I2CCON_ACKEN		(1<<4)
43#define  I2CCON_RCEN		(1<<3)
44#define  I2CCON_PEN		(1<<2)
45#define  I2CCON_RSEN		(1<<1)
46#define  I2CCON_SEN		(1<<0)
47
48#define PIC32_I2CxSTAT		0x0010
49#define PIC32_I2CxSTATCLR	0x0014
50#define PIC32_I2CxSTATSET	0x0018
51#define PIC32_I2CxSTATINV	0x001C
52#define  I2CSTAT_ACKSTAT	(1<<15)
53#define  I2CSTAT_TRSTAT		(1<<14)
54#define  I2CSTAT_BCL		(1<<10)
55#define  I2CSTAT_GCSTAT		(1<<9)
56#define  I2CSTAT_ADD10		(1<<8)
57#define  I2CSTAT_IWCOL		(1<<7)
58#define  I2CSTAT_I2COV		(1<<6)
59#define  I2CSTAT_DA		(1<<5)
60#define  I2CSTAT_P		(1<<4)
61#define  I2CSTAT_S		(1<<3)
62#define  I2CSTAT_RW		(1<<2)
63#define  I2CSTAT_RBF		(1<<1)
64#define  I2CSTAT_TBF		(1<<0)
65
66#define PIC32_I2CxADD		0x0020
67#define PIC32_I2CxADDCLR	0x0024
68#define PIC32_I2CxADDSET	0x0028
69#define PIC32_I2CxADDINV	0x002C
70#define PIC32_I2CxMSK		0x0030
71#define PIC32_I2CxMSKCLR	0x0034
72#define PIC32_I2CxMSKSET	0x0038
73#define PIC32_I2CxMSKINV	0x003C
74#define PIC32_I2CxBRG		0x0040
75#define PIC32_I2CxBRGCLR	0x0044
76#define PIC32_I2CxBRGSET	0x0048
77#define PIC32_I2CxBRGINV	0x004C
78#define PIC32_I2CxTRN		0x0050
79#define PIC32_I2CxTRNCLR	0x0054
80#define PIC32_I2CxTRNSET	0x0058
81#define PIC32_I2CxTRNINV	0x005C
82#define PIC32_I2CxRCV		0x0060
83
84struct i2c_platform_data {
85	u32	base;
86	struct i2c_adapter adap;
87	u32	xfer_timeout;
88	u32	ack_timeout;
89	u32	ctl_timeout;
90};
91
92extern u32 pic32_bus_readl(u32 reg);
93extern void pic32_bus_writel(u32 val, u32 reg);
94
95static inline void
96StartI2C(struct i2c_platform_data *adap)
97{
98	pr_debug("StartI2C\n");
99	pic32_bus_writel(I2CCON_SEN, adap->base + PIC32_I2CxCONSET);
100}
101
102static inline void
103StopI2C(struct i2c_platform_data *adap)
104{
105	pr_debug("StopI2C\n");
106	pic32_bus_writel(I2CCON_PEN, adap->base + PIC32_I2CxCONSET);
107}
108
109static inline void
110AckI2C(struct i2c_platform_data *adap)
111{
112	pr_debug("AckI2C\n");
113	pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONCLR);
114	pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET);
115}
116
117static inline void
118NotAckI2C(struct i2c_platform_data *adap)
119{
120	pr_debug("NakI2C\n");
121	pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONSET);
122	pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET);
123}
124
125static inline int
126IdleI2C(struct i2c_platform_data *adap)
127{
128	int i;
129
130	pr_debug("IdleI2C\n");
131	for (i = 0; i < adap->ctl_timeout; i++) {
132		if (((pic32_bus_readl(adap->base + PIC32_I2CxCON) &
133		      (I2CCON_ACKEN|I2CCON_RCEN|I2CCON_PEN|I2CCON_RSEN|I2CCON_SEN)) == 0) &&
134		    ((pic32_bus_readl(adap->base + PIC32_I2CxSTAT) &
135		      (I2CSTAT_TRSTAT)) == 0))
136			return 0;
137		udelay(1);
138	}
139	return -ETIMEDOUT;
140}
141
142static inline u32
143MasterWriteI2C(struct i2c_platform_data *adap, u32 byte)
144{
145	pr_debug("MasterWriteI2C\n");
146
147	pic32_bus_writel(byte, adap->base + PIC32_I2CxTRN);
148
149	return pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_IWCOL;
150}
151
152static inline u32
153MasterReadI2C(struct i2c_platform_data *adap)
154{
155	pr_debug("MasterReadI2C\n");
156
157	pic32_bus_writel(I2CCON_RCEN, adap->base + PIC32_I2CxCONSET);
158
159	while (pic32_bus_readl(adap->base + PIC32_I2CxCON) & I2CCON_RCEN)
160		;
161
162	pic32_bus_writel(I2CSTAT_I2COV, adap->base + PIC32_I2CxSTATCLR);
163
164	return pic32_bus_readl(adap->base + PIC32_I2CxRCV);
165}
166
167static int
168do_address(struct i2c_platform_data *adap, unsigned int addr, int rd)
169{
170	pr_debug("doaddress\n");
171
172	IdleI2C(adap);
173	StartI2C(adap);
174	IdleI2C(adap);
175
176	addr <<= 1;
177	if (rd)
178		addr |= 1;
179
180	if (MasterWriteI2C(adap, addr))
181		return -EIO;
182	IdleI2C(adap);
183	if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_ACKSTAT)
184		return -EIO;
185	return 0;
186}
187
188static int
189i2c_read(struct i2c_platform_data *adap, unsigned char *buf,
190		    unsigned int len)
191{
192	int	i;
193	u32	data;
194
195	pr_debug("i2c_read\n");
196
197	i = 0;
198	while (i < len) {
199		data = MasterReadI2C(adap);
200		buf[i++] = data;
201		if (i < len)
202			AckI2C(adap);
203		else
204			NotAckI2C(adap);
205	}
206
207	StopI2C(adap);
208	IdleI2C(adap);
209	return 0;
210}
211
212static int
213i2c_write(struct i2c_platform_data *adap, unsigned char *buf,
214		     unsigned int len)
215{
216	int	i;
217	u32	data;
218
219	pr_debug("i2c_write\n");
220
221	i = 0;
222	while (i < len) {
223		data = buf[i];
224		if (MasterWriteI2C(adap, data))
225			return -EIO;
226		IdleI2C(adap);
227		if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_ACKSTAT)
228			return -EIO;
229		i++;
230	}
231
232	StopI2C(adap);
233	IdleI2C(adap);
234	return 0;
235}
236
237static int
238platform_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
239{
240	struct i2c_platform_data *adap = i2c_adap->algo_data;
241	struct i2c_msg *p;
242	int i, err = 0;
243
244	pr_debug("platform_xfer\n");
245	for (i = 0; i < num; i++) {
246#define __BUFSIZE 80
247		int ii;
248		static char buf[__BUFSIZE];
249		char *b = buf;
250
251		p = &msgs[i];
252		b += sprintf(buf, " [%d bytes]", p->len);
253		if ((p->flags & I2C_M_RD) == 0) {
254			for (ii = 0; ii < p->len; ii++) {
255				if (b < &buf[__BUFSIZE-4]) {
256					b += sprintf(b, " %02x", p->buf[ii]);
257				} else {
258					strcat(b, "...");
259					break;
260				}
261			}
262		}
263		pr_debug("xfer%d: DevAddr: %04x Op:%s Data:%s\n", i, p->addr,
264			 (p->flags & I2C_M_RD) ? "Rd" : "Wr", buf);
265	}
266
267
268	for (i = 0; !err && i < num; i++) {
269		p = &msgs[i];
270		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
271		if (err || !p->len)
272			continue;
273		if (p->flags & I2C_M_RD)
274			err = i2c_read(adap, p->buf, p->len);
275		else
276			err = i2c_write(adap, p->buf, p->len);
277	}
278
279	/* Return the number of messages processed, or the error code. */
280	if (err == 0)
281		err = num;
282
283	return err;
284}
285
286static u32
287platform_func(struct i2c_adapter *adap)
288{
289	pr_debug("platform_algo\n");
290	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
291}
292
293static const struct i2c_algorithm platform_algo = {
294	.master_xfer	= platform_xfer,
295	.functionality	= platform_func,
296};
297
298static void i2c_platform_setup(struct i2c_platform_data *priv)
299{
300	pr_debug("i2c_platform_setup\n");
301
302	pic32_bus_writel(500, priv->base + PIC32_I2CxBRG);
303	pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONCLR);
304	pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONSET);
305	pic32_bus_writel(I2CSTAT_BCL|I2CSTAT_IWCOL, priv->base + PIC32_I2CxSTATCLR);
306}
307
308static void i2c_platform_disable(struct i2c_platform_data *priv)
309{
310	pr_debug("i2c_platform_disable\n");
311}
312
313static int __devinit
314i2c_platform_probe(struct platform_device *pdev)
315{
316	struct i2c_platform_data *priv;
317	struct resource *r;
318	int ret;
319
320	pr_debug("i2c_platform_probe\n");
321	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
322	if (!r) {
323		ret = -ENODEV;
324		goto out;
325	}
326
327	priv = kzalloc(sizeof(struct i2c_platform_data), GFP_KERNEL);
328	if (!priv) {
329		ret = -ENOMEM;
330		goto out;
331	}
332
333	priv->base = r->start;
334	if (!priv->base) {
335		ret = -EBUSY;
336		goto out_mem;
337	}
338
339	priv->xfer_timeout = 200;
340	priv->ack_timeout = 200;
341	priv->ctl_timeout = 200;
342
343	priv->adap.nr = pdev->id;
344	priv->adap.algo = &platform_algo;
345	priv->adap.algo_data = priv;
346	priv->adap.dev.parent = &pdev->dev;
347	strlcpy(priv->adap.name, "PIC32 I2C", sizeof(priv->adap.name));
348
349	i2c_platform_setup(priv);
350
351	ret = i2c_add_numbered_adapter(&priv->adap);
352	if (ret == 0) {
353		platform_set_drvdata(pdev, priv);
354		return 0;
355	}
356
357	i2c_platform_disable(priv);
358
359out_mem:
360	kfree(priv);
361out:
362	return ret;
363}
364
365static int __devexit
366i2c_platform_remove(struct platform_device *pdev)
367{
368	struct i2c_platform_data *priv = platform_get_drvdata(pdev);
369
370	pr_debug("i2c_platform_remove\n");
371	platform_set_drvdata(pdev, NULL);
372	i2c_del_adapter(&priv->adap);
373	i2c_platform_disable(priv);
374	kfree(priv);
375	return 0;
376}
377
378#ifdef CONFIG_PM
379static int
380i2c_platform_suspend(struct platform_device *pdev, pm_message_t state)
381{
382	struct i2c_platform_data *priv = platform_get_drvdata(pdev);
383
384	dev_dbg(&pdev->dev, "i2c_platform_disable\n");
385	i2c_platform_disable(priv);
386
387	return 0;
388}
389
390static int
391i2c_platform_resume(struct platform_device *pdev)
392{
393	struct i2c_platform_data *priv = platform_get_drvdata(pdev);
394
395	dev_dbg(&pdev->dev, "i2c_platform_setup\n");
396	i2c_platform_setup(priv);
397
398	return 0;
399}
400#else
401#define i2c_platform_suspend	NULL
402#define i2c_platform_resume	NULL
403#endif
404
405static struct platform_driver i2c_platform_driver = {
406	.driver = {
407		.name	= "i2c_pic32",
408		.owner	= THIS_MODULE,
409	},
410	.probe		= i2c_platform_probe,
411	.remove		= __devexit_p(i2c_platform_remove),
412	.suspend	= i2c_platform_suspend,
413	.resume		= i2c_platform_resume,
414};
415
416static int __init
417i2c_platform_init(void)
418{
419	pr_debug("i2c_platform_init\n");
420	return platform_driver_register(&i2c_platform_driver);
421}
422
423static void __exit
424i2c_platform_exit(void)
425{
426	pr_debug("i2c_platform_exit\n");
427	platform_driver_unregister(&i2c_platform_driver);
428}
429
430MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC.");
431MODULE_DESCRIPTION("PIC32 I2C driver");
432MODULE_LICENSE("GPL");
433
434module_init(i2c_platform_init);
435module_exit(i2c_platform_exit);
436