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
6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
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>
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
36 static DEFINE_SPINLOCK(pic32_bus_lock
);
38 static void __iomem
*bus_xfer
= (void __iomem
*)0xbf000600;
39 static void __iomem
*bus_status
= (void __iomem
*)0xbf000060;
41 #define DELAY() udelay(100)
43 static inline unsigned int ioready(void)
45 return readl(bus_status
) & 1;
48 static inline void wait_ioready(void)
50 do { } while (!ioready());
53 static inline void wait_ioclear(void)
55 do { } while (ioready());
58 static inline void check_ioclear(void)
62 (void) readl(bus_xfer
);
68 static u32
pic32_bus_readl(u32 reg
)
73 spin_lock_irqsave(&pic32_bus_lock
, flags
);
76 writel((0x01 << 24) | (reg
& 0x00ffffff), bus_xfer
);
79 status
= readl(bus_xfer
);
81 val
= readl(bus_xfer
);
84 spin_unlock_irqrestore(&pic32_bus_lock
, flags
);
89 static void pic32_bus_writel(u32 val
, u32 reg
)
94 spin_lock_irqsave(&pic32_bus_lock
, flags
);
97 writel((0x10 << 24) | (reg
& 0x00ffffff), bus_xfer
);
99 writel(val
, bus_xfer
);
102 status
= readl(bus_xfer
);
105 spin_unlock_irqrestore(&pic32_bus_lock
, flags
);
108 struct pic32_i2c_platform_data
{
110 struct i2c_adapter adap
;
116 static inline void pic32_i2c_start(struct pic32_i2c_platform_data
*adap
)
118 pic32_bus_writel(PIC32_I2CCON_SEN
, adap
->base
+ PIC32_I2CxCONSET
);
121 static inline void pic32_i2c_stop(struct pic32_i2c_platform_data
*adap
)
123 pic32_bus_writel(PIC32_I2CCON_PEN
, adap
->base
+ PIC32_I2CxCONSET
);
126 static inline void pic32_i2c_ack(struct pic32_i2c_platform_data
*adap
)
128 pic32_bus_writel(PIC32_I2CCON_ACKDT
, adap
->base
+ PIC32_I2CxCONCLR
);
129 pic32_bus_writel(PIC32_I2CCON_ACKEN
, adap
->base
+ PIC32_I2CxCONSET
);
132 static inline void pic32_i2c_nack(struct pic32_i2c_platform_data
*adap
)
134 pic32_bus_writel(PIC32_I2CCON_ACKDT
, adap
->base
+ PIC32_I2CxCONSET
);
135 pic32_bus_writel(PIC32_I2CCON_ACKEN
, adap
->base
+ PIC32_I2CxCONSET
);
138 static inline int pic32_i2c_idle(struct pic32_i2c_platform_data
*adap
)
142 for (i
= 0; i
< adap
->ctl_timeout
; i
++) {
143 if (((pic32_bus_readl(adap
->base
+ PIC32_I2CxCON
) &
144 (PIC32_I2CCON_ACKEN
| PIC32_I2CCON_RCEN
|
145 PIC32_I2CCON_PEN
| PIC32_I2CCON_RSEN
|
146 PIC32_I2CCON_SEN
)) == 0) &&
147 ((pic32_bus_readl(adap
->base
+ PIC32_I2CxSTAT
) &
148 (PIC32_I2CSTAT_TRSTAT
)) == 0))
155 static inline u32
pic32_i2c_master_write(struct pic32_i2c_platform_data
*adap
,
158 pic32_bus_writel(byte
, adap
->base
+ PIC32_I2CxTRN
);
159 return pic32_bus_readl(adap
->base
+ PIC32_I2CxSTAT
) &
163 static inline u32
pic32_i2c_master_read(struct pic32_i2c_platform_data
*adap
)
165 pic32_bus_writel(PIC32_I2CCON_RCEN
, adap
->base
+ PIC32_I2CxCONSET
);
166 while (pic32_bus_readl(adap
->base
+ PIC32_I2CxCON
) & PIC32_I2CCON_RCEN
)
168 pic32_bus_writel(PIC32_I2CSTAT_I2COV
, adap
->base
+ PIC32_I2CxSTATCLR
);
169 return pic32_bus_readl(adap
->base
+ PIC32_I2CxRCV
);
172 static int pic32_i2c_address(struct pic32_i2c_platform_data
*adap
,
173 unsigned int addr
, int rd
)
175 pic32_i2c_idle(adap
);
176 pic32_i2c_start(adap
);
177 pic32_i2c_idle(adap
);
183 if (pic32_i2c_master_write(adap
, addr
))
185 pic32_i2c_idle(adap
);
186 if (pic32_bus_readl(adap
->base
+ PIC32_I2CxSTAT
) &
187 PIC32_I2CSTAT_ACKSTAT
)
192 static int sead3_i2c_read(struct pic32_i2c_platform_data
*adap
,
193 unsigned char *buf
, unsigned int len
)
200 data
= pic32_i2c_master_read(adap
);
205 pic32_i2c_nack(adap
);
208 pic32_i2c_stop(adap
);
209 pic32_i2c_idle(adap
);
213 static int sead3_i2c_write(struct pic32_i2c_platform_data
*adap
,
214 unsigned char *buf
, unsigned int len
)
222 if (pic32_i2c_master_write(adap
, data
))
224 pic32_i2c_idle(adap
);
225 if (pic32_bus_readl(adap
->base
+ PIC32_I2CxSTAT
) &
226 PIC32_I2CSTAT_ACKSTAT
)
231 pic32_i2c_stop(adap
);
232 pic32_i2c_idle(adap
);
236 static int sead3_pic32_platform_xfer(struct i2c_adapter
*i2c_adap
,
237 struct i2c_msg
*msgs
, int num
)
239 struct pic32_i2c_platform_data
*adap
= i2c_adap
->algo_data
;
243 for (i
= 0; i
< num
; i
++) {
246 static char buf
[__BUFSIZE
];
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
]);
263 for (i
= 0; !err
&& i
< num
; i
++) {
265 err
= pic32_i2c_address(adap
, p
->addr
, p
->flags
& I2C_M_RD
);
268 if (p
->flags
& I2C_M_RD
)
269 err
= sead3_i2c_read(adap
, p
->buf
, p
->len
);
271 err
= sead3_i2c_write(adap
, p
->buf
, p
->len
);
274 /* Return the number of messages processed, or the error code. */
281 static u32
sead3_pic32_platform_func(struct i2c_adapter
*adap
)
283 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
286 static const struct i2c_algorithm sead3_platform_algo
= {
287 .master_xfer
= sead3_pic32_platform_xfer
,
288 .functionality
= sead3_pic32_platform_func
,
291 static void sead3_i2c_platform_setup(struct pic32_i2c_platform_data
*priv
)
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
);
300 static int sead3_i2c_platform_probe(struct platform_device
*pdev
)
302 struct pic32_i2c_platform_data
*priv
;
306 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
312 priv
= kzalloc(sizeof(struct pic32_i2c_platform_data
), GFP_KERNEL
);
318 priv
->base
= r
->start
;
324 priv
->xfer_timeout
= 200;
325 priv
->ack_timeout
= 200;
326 priv
->ctl_timeout
= 200;
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
));
334 sead3_i2c_platform_setup(priv
);
336 ret
= i2c_add_numbered_adapter(&priv
->adap
);
338 platform_set_drvdata(pdev
, priv
);
348 static int sead3_i2c_platform_remove(struct platform_device
*pdev
)
350 struct pic32_i2c_platform_data
*priv
= platform_get_drvdata(pdev
);
352 platform_set_drvdata(pdev
, NULL
);
353 i2c_del_adapter(&priv
->adap
);
359 static int sead3_i2c_platform_suspend(struct platform_device
*pdev
,
362 dev_dbg(&pdev
->dev
, "i2c_platform_disable\n");
366 static int sead3_i2c_platform_resume(struct platform_device
*pdev
)
368 struct pic32_i2c_platform_data
*priv
= platform_get_drvdata(pdev
);
370 dev_dbg(&pdev
->dev
, "sead3_i2c_platform_setup\n");
371 sead3_i2c_platform_setup(priv
);
376 #define sead3_i2c_platform_suspend NULL
377 #define sead3_i2c_platform_resume NULL
380 static struct platform_driver sead3_i2c_platform_driver
= {
383 .owner
= THIS_MODULE
,
385 .probe
= sead3_i2c_platform_probe
,
386 .remove
= sead3_i2c_platform_remove
,
387 .suspend
= sead3_i2c_platform_suspend
,
388 .resume
= sead3_i2c_platform_resume
,
391 static int __init
sead3_i2c_platform_init(void)
393 return platform_driver_register(&sead3_i2c_platform_driver
);
395 module_init(sead3_i2c_platform_init
);
397 static void __exit
sead3_i2c_platform_exit(void)
399 platform_driver_unregister(&sead3_i2c_platform_driver
);
401 module_exit(sead3_i2c_platform_exit
);
403 MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC.");
404 MODULE_DESCRIPTION("SEAD3 PIC32 I2C driver");
405 MODULE_LICENSE("GPL");