Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sead3-i2c-drv.c
Go to the documentation of this file.
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License. See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
7  */
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/delay.h>
12 #include <linux/i2c.h>
13 #include <linux/platform_device.h>
14 
15 #define PIC32_I2CxCON 0x0000
16 #define PIC32_I2CCON_ON (1<<15)
17 #define PIC32_I2CCON_ACKDT (1<<5)
18 #define PIC32_I2CCON_ACKEN (1<<4)
19 #define PIC32_I2CCON_RCEN (1<<3)
20 #define PIC32_I2CCON_PEN (1<<2)
21 #define PIC32_I2CCON_RSEN (1<<1)
22 #define PIC32_I2CCON_SEN (1<<0)
23 #define PIC32_I2CxCONCLR 0x0004
24 #define PIC32_I2CxCONSET 0x0008
25 #define PIC32_I2CxSTAT 0x0010
26 #define PIC32_I2CxSTATCLR 0x0014
27 #define PIC32_I2CSTAT_ACKSTAT (1<<15)
28 #define PIC32_I2CSTAT_TRSTAT (1<<14)
29 #define PIC32_I2CSTAT_BCL (1<<10)
30 #define PIC32_I2CSTAT_IWCOL (1<<7)
31 #define PIC32_I2CSTAT_I2COV (1<<6)
32 #define PIC32_I2CxBRG 0x0040
33 #define PIC32_I2CxTRN 0x0050
34 #define PIC32_I2CxRCV 0x0060
35 
36 static DEFINE_SPINLOCK(pic32_bus_lock);
37 
38 static void __iomem *bus_xfer = (void __iomem *)0xbf000600;
39 static void __iomem *bus_status = (void __iomem *)0xbf000060;
40 
41 #define DELAY() udelay(100)
42 
43 static inline unsigned int ioready(void)
44 {
45  return readl(bus_status) & 1;
46 }
47 
48 static inline void wait_ioready(void)
49 {
50  do { } while (!ioready());
51 }
52 
53 static inline void wait_ioclear(void)
54 {
55  do { } while (ioready());
56 }
57 
58 static inline void check_ioclear(void)
59 {
60  if (ioready()) {
61  do {
62  (void) readl(bus_xfer);
63  DELAY();
64  } while (ioready());
65  }
66 }
67 
68 static u32 pic32_bus_readl(u32 reg)
69 {
70  unsigned long flags;
71  u32 status, val;
72 
73  spin_lock_irqsave(&pic32_bus_lock, flags);
74 
75  check_ioclear();
76  writel((0x01 << 24) | (reg & 0x00ffffff), bus_xfer);
77  DELAY();
78  wait_ioready();
79  status = readl(bus_xfer);
80  DELAY();
81  val = readl(bus_xfer);
82  wait_ioclear();
83 
84  spin_unlock_irqrestore(&pic32_bus_lock, flags);
85 
86  return val;
87 }
88 
89 static void pic32_bus_writel(u32 val, u32 reg)
90 {
91  unsigned long flags;
92  u32 status;
93 
94  spin_lock_irqsave(&pic32_bus_lock, flags);
95 
96  check_ioclear();
97  writel((0x10 << 24) | (reg & 0x00ffffff), bus_xfer);
98  DELAY();
99  writel(val, bus_xfer);
100  DELAY();
101  wait_ioready();
102  status = readl(bus_xfer);
103  wait_ioclear();
104 
105  spin_unlock_irqrestore(&pic32_bus_lock, flags);
106 }
107 
114 };
115 
116 static inline void pic32_i2c_start(struct pic32_i2c_platform_data *adap)
117 {
118  pic32_bus_writel(PIC32_I2CCON_SEN, adap->base + PIC32_I2CxCONSET);
119 }
120 
121 static inline void pic32_i2c_stop(struct pic32_i2c_platform_data *adap)
122 {
123  pic32_bus_writel(PIC32_I2CCON_PEN, adap->base + PIC32_I2CxCONSET);
124 }
125 
126 static inline void pic32_i2c_ack(struct pic32_i2c_platform_data *adap)
127 {
128  pic32_bus_writel(PIC32_I2CCON_ACKDT, adap->base + PIC32_I2CxCONCLR);
129  pic32_bus_writel(PIC32_I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET);
130 }
131 
132 static inline void pic32_i2c_nack(struct pic32_i2c_platform_data *adap)
133 {
134  pic32_bus_writel(PIC32_I2CCON_ACKDT, adap->base + PIC32_I2CxCONSET);
135  pic32_bus_writel(PIC32_I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET);
136 }
137 
138 static inline int pic32_i2c_idle(struct pic32_i2c_platform_data *adap)
139 {
140  int i;
141 
142  for (i = 0; i < adap->ctl_timeout; i++) {
143  if (((pic32_bus_readl(adap->base + PIC32_I2CxCON) &
146  PIC32_I2CCON_SEN)) == 0) &&
147  ((pic32_bus_readl(adap->base + PIC32_I2CxSTAT) &
148  (PIC32_I2CSTAT_TRSTAT)) == 0))
149  return 0;
150  udelay(1);
151  }
152  return -ETIMEDOUT;
153 }
154 
155 static inline u32 pic32_i2c_master_write(struct pic32_i2c_platform_data *adap,
156  u32 byte)
157 {
158  pic32_bus_writel(byte, adap->base + PIC32_I2CxTRN);
159  return pic32_bus_readl(adap->base + PIC32_I2CxSTAT) &
161 }
162 
163 static inline u32 pic32_i2c_master_read(struct pic32_i2c_platform_data *adap)
164 {
165  pic32_bus_writel(PIC32_I2CCON_RCEN, adap->base + PIC32_I2CxCONSET);
166  while (pic32_bus_readl(adap->base + PIC32_I2CxCON) & PIC32_I2CCON_RCEN)
167  ;
168  pic32_bus_writel(PIC32_I2CSTAT_I2COV, adap->base + PIC32_I2CxSTATCLR);
169  return pic32_bus_readl(adap->base + PIC32_I2CxRCV);
170 }
171 
172 static int pic32_i2c_address(struct pic32_i2c_platform_data *adap,
173  unsigned int addr, int rd)
174 {
175  pic32_i2c_idle(adap);
176  pic32_i2c_start(adap);
177  pic32_i2c_idle(adap);
178 
179  addr <<= 1;
180  if (rd)
181  addr |= 1;
182 
183  if (pic32_i2c_master_write(adap, addr))
184  return -EIO;
185  pic32_i2c_idle(adap);
186  if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) &
188  return -EIO;
189  return 0;
190 }
191 
192 static int sead3_i2c_read(struct pic32_i2c_platform_data *adap,
193  unsigned char *buf, unsigned int len)
194 {
195  u32 data;
196  int i;
197 
198  i = 0;
199  while (i < len) {
200  data = pic32_i2c_master_read(adap);
201  buf[i++] = data;
202  if (i < len)
203  pic32_i2c_ack(adap);
204  else
205  pic32_i2c_nack(adap);
206  }
207 
208  pic32_i2c_stop(adap);
209  pic32_i2c_idle(adap);
210  return 0;
211 }
212 
213 static int sead3_i2c_write(struct pic32_i2c_platform_data *adap,
214  unsigned char *buf, unsigned int len)
215 {
216  int i;
217  u32 data;
218 
219  i = 0;
220  while (i < len) {
221  data = buf[i];
222  if (pic32_i2c_master_write(adap, data))
223  return -EIO;
224  pic32_i2c_idle(adap);
225  if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) &
227  return -EIO;
228  i++;
229  }
230 
231  pic32_i2c_stop(adap);
232  pic32_i2c_idle(adap);
233  return 0;
234 }
235 
236 static int sead3_pic32_platform_xfer(struct i2c_adapter *i2c_adap,
237  struct i2c_msg *msgs, int num)
238 {
239  struct pic32_i2c_platform_data *adap = i2c_adap->algo_data;
240  struct i2c_msg *p;
241  int i, err = 0;
242 
243  for (i = 0; i < num; i++) {
244 #define __BUFSIZE 80
245  int ii;
246  static char buf[__BUFSIZE];
247  char *b = buf;
248 
249  p = &msgs[i];
250  b += sprintf(buf, " [%d bytes]", p->len);
251  if ((p->flags & I2C_M_RD) == 0) {
252  for (ii = 0; ii < p->len; ii++) {
253  if (b < &buf[__BUFSIZE-4]) {
254  b += sprintf(b, " %02x", p->buf[ii]);
255  } else {
256  strcat(b, "...");
257  break;
258  }
259  }
260  }
261  }
262 
263  for (i = 0; !err && i < num; i++) {
264  p = &msgs[i];
265  err = pic32_i2c_address(adap, p->addr, p->flags & I2C_M_RD);
266  if (err || !p->len)
267  continue;
268  if (p->flags & I2C_M_RD)
269  err = sead3_i2c_read(adap, p->buf, p->len);
270  else
271  err = sead3_i2c_write(adap, p->buf, p->len);
272  }
273 
274  /* Return the number of messages processed, or the error code. */
275  if (err == 0)
276  err = num;
277 
278  return err;
279 }
280 
281 static u32 sead3_pic32_platform_func(struct i2c_adapter *adap)
282 {
284 }
285 
286 static const struct i2c_algorithm sead3_platform_algo = {
287  .master_xfer = sead3_pic32_platform_xfer,
288  .functionality = sead3_pic32_platform_func,
289 };
290 
291 static void sead3_i2c_platform_setup(struct pic32_i2c_platform_data *priv)
292 {
293  pic32_bus_writel(500, priv->base + PIC32_I2CxBRG);
294  pic32_bus_writel(PIC32_I2CCON_ON, priv->base + PIC32_I2CxCONCLR);
295  pic32_bus_writel(PIC32_I2CCON_ON, priv->base + PIC32_I2CxCONSET);
296  pic32_bus_writel(PIC32_I2CSTAT_BCL | PIC32_I2CSTAT_IWCOL,
297  priv->base + PIC32_I2CxSTATCLR);
298 }
299 
300 static int __devinit sead3_i2c_platform_probe(struct platform_device *pdev)
301 {
303  struct resource *r;
304  int ret;
305 
307  if (!r) {
308  ret = -ENODEV;
309  goto out;
310  }
311 
312  priv = kzalloc(sizeof(struct pic32_i2c_platform_data), GFP_KERNEL);
313  if (!priv) {
314  ret = -ENOMEM;
315  goto out;
316  }
317 
318  priv->base = r->start;
319  if (!priv->base) {
320  ret = -EBUSY;
321  goto out_mem;
322  }
323 
324  priv->xfer_timeout = 200;
325  priv->ack_timeout = 200;
326  priv->ctl_timeout = 200;
327 
328  priv->adap.nr = pdev->id;
329  priv->adap.algo = &sead3_platform_algo;
330  priv->adap.algo_data = priv;
331  priv->adap.dev.parent = &pdev->dev;
332  strlcpy(priv->adap.name, "SEAD3 PIC32", sizeof(priv->adap.name));
333 
334  sead3_i2c_platform_setup(priv);
335 
336  ret = i2c_add_numbered_adapter(&priv->adap);
337  if (ret == 0) {
338  platform_set_drvdata(pdev, priv);
339  return 0;
340  }
341 
342 out_mem:
343  kfree(priv);
344 out:
345  return ret;
346 }
347 
348 static int __devexit sead3_i2c_platform_remove(struct platform_device *pdev)
349 {
350  struct pic32_i2c_platform_data *priv = platform_get_drvdata(pdev);
351 
352  platform_set_drvdata(pdev, NULL);
353  i2c_del_adapter(&priv->adap);
354  kfree(priv);
355  return 0;
356 }
357 
358 #ifdef CONFIG_PM
359 static int sead3_i2c_platform_suspend(struct platform_device *pdev,
361 {
362  dev_dbg(&pdev->dev, "i2c_platform_disable\n");
363  return 0;
364 }
365 
366 static int sead3_i2c_platform_resume(struct platform_device *pdev)
367 {
368  struct pic32_i2c_platform_data *priv = platform_get_drvdata(pdev);
369 
370  dev_dbg(&pdev->dev, "sead3_i2c_platform_setup\n");
371  sead3_i2c_platform_setup(priv);
372 
373  return 0;
374 }
375 #else
376 #define sead3_i2c_platform_suspend NULL
377 #define sead3_i2c_platform_resume NULL
378 #endif
379 
380 static struct platform_driver sead3_i2c_platform_driver = {
381  .driver = {
382  .name = "sead3-i2c",
383  .owner = THIS_MODULE,
384  },
385  .probe = sead3_i2c_platform_probe,
386  .remove = __devexit_p(sead3_i2c_platform_remove),
387  .suspend = sead3_i2c_platform_suspend,
388  .resume = sead3_i2c_platform_resume,
389 };
390 
391 static int __init sead3_i2c_platform_init(void)
392 {
393  return platform_driver_register(&sead3_i2c_platform_driver);
394 }
395 module_init(sead3_i2c_platform_init);
396 
397 static void __exit sead3_i2c_platform_exit(void)
398 {
399  platform_driver_unregister(&sead3_i2c_platform_driver);
400 }
401 module_exit(sead3_i2c_platform_exit);
402 
403 MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC.");
404 MODULE_DESCRIPTION("SEAD3 PIC32 I2C driver");
405 MODULE_LICENSE("GPL");