2 * I2C driver for PKUnity-v3 SoC
3 * Code specific to PKUnity SoC and UniCore ISA
5 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
6 * Copyright (C) 2001-2010 Guan Xuetao
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/err.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <linux/delay.h>
19 #include <linux/i2c.h>
20 #include <linux/init.h>
21 #include <linux/clk.h>
22 #include <linux/platform_device.h>
24 #include <mach/hardware.h>
27 * Poll the i2c status register until the specified bit is set.
28 * Returns 0 if timed out (100 msec).
30 static short poll_status(unsigned long bit
)
34 if (bit
& I2C_STATUS_TFNF
) {
37 } while (!(readl(I2C_STATUS
) & bit
) && (--loop_cntr
> 0));
41 if (readl(I2C_TAR
) == I2C_TAR_EEPROM
)
45 } while (!(readl(I2C_RXFLR
) & 0xf) && (--loop_cntr
> 0));
48 return (loop_cntr
> 0);
51 static int xfer_read(struct i2c_adapter
*adap
, unsigned char *buf
, int length
)
57 if (!poll_status(I2C_STATUS_TFNF
)) {
58 dev_dbg(&adap
->dev
, "Tx FIFO Not Full timeout\n");
63 writel(i2c_reg
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
65 /* get ready to next write */
69 writel(I2C_DATACMD_READ
, I2C_DATACMD
);
71 /* wait until the Rx FIFO have available */
72 if (!poll_status(I2C_STATUS_RFNE
)) {
73 dev_dbg(&adap
->dev
, "RXRDY timeout\n");
77 /* read the data to buf */
78 *buf
= (readl(I2C_DATACMD
) & I2C_DATACMD_DAT_MASK
);
85 static int xfer_write(struct i2c_adapter
*adap
, unsigned char *buf
, int length
)
89 /* Do nothing but storing the reg_num to a static variable */
91 printk(KERN_WARNING
"Error i2c reg\n");
102 writel(i2c_reg
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
105 writel(*buf
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
107 /* wait until the Rx FIFO have available */
110 /* read the data to buf */
119 * Generic i2c master transfer entrypoint.
122 static int puv3_i2c_xfer(struct i2c_adapter
*adap
, struct i2c_msg
*pmsg
,
129 writel(I2C_ENABLE_DISABLE
, I2C_ENABLE
);
131 /* Set the work mode and speed*/
132 writel(I2C_CON_MASTER
| I2C_CON_SPEED_STD
| I2C_CON_SLAVEDISABLE
, I2C_CON
);
134 writel(pmsg
->addr
, I2C_TAR
);
137 writel(I2C_ENABLE_ENABLE
, I2C_ENABLE
);
139 dev_dbg(&adap
->dev
, "puv3_i2c_xfer: processing %d messages:\n", num
);
141 for (i
= 0; i
< num
; i
++) {
142 dev_dbg(&adap
->dev
, " #%d: %sing %d byte%s %s 0x%02x\n", i
,
143 pmsg
->flags
& I2C_M_RD
? "read" : "writ",
144 pmsg
->len
, pmsg
->len
> 1 ? "s" : "",
145 pmsg
->flags
& I2C_M_RD
? "from" : "to", pmsg
->addr
);
147 if (pmsg
->len
&& pmsg
->buf
) { /* sanity check */
148 if (pmsg
->flags
& I2C_M_RD
)
149 ret
= xfer_read(adap
, pmsg
->buf
, pmsg
->len
);
151 ret
= xfer_write(adap
, pmsg
->buf
, pmsg
->len
);
157 dev_dbg(&adap
->dev
, "transfer complete\n");
158 pmsg
++; /* next message */
161 /* XXX: fixup be16_to_cpu in bq27x00_battery.c */
162 if (pmsg
->addr
== I2C_TAR_PWIC
) {
164 pmsg
->buf
[0] = pmsg
->buf
[1];
172 * Return list of supported functionality.
174 static u32
puv3_i2c_func(struct i2c_adapter
*adapter
)
176 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
179 static struct i2c_algorithm puv3_i2c_algorithm
= {
180 .master_xfer
= puv3_i2c_xfer
,
181 .functionality
= puv3_i2c_func
,
185 * Main initialization routine.
187 static int __devinit
puv3_i2c_probe(struct platform_device
*pdev
)
189 struct i2c_adapter
*adapter
;
190 struct resource
*mem
;
193 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
197 if (!request_mem_region(mem
->start
, resource_size(mem
), "puv3_i2c"))
200 adapter
= kzalloc(sizeof(struct i2c_adapter
), GFP_KERNEL
);
201 if (adapter
== NULL
) {
202 dev_err(&pdev
->dev
, "can't allocate inteface!\n");
206 snprintf(adapter
->name
, sizeof(adapter
->name
), "PUV3-I2C at 0x%08x",
208 adapter
->algo
= &puv3_i2c_algorithm
;
209 adapter
->class = I2C_CLASS_HWMON
;
210 adapter
->dev
.parent
= &pdev
->dev
;
212 platform_set_drvdata(pdev
, adapter
);
214 adapter
->nr
= pdev
->id
;
215 rc
= i2c_add_numbered_adapter(adapter
);
217 dev_err(&pdev
->dev
, "Adapter '%s' registration failed\n",
219 goto fail_add_adapter
;
222 dev_info(&pdev
->dev
, "PKUnity v3 i2c bus adapter.\n");
226 platform_set_drvdata(pdev
, NULL
);
229 release_mem_region(mem
->start
, resource_size(mem
));
234 static int __devexit
puv3_i2c_remove(struct platform_device
*pdev
)
236 struct i2c_adapter
*adapter
= platform_get_drvdata(pdev
);
237 struct resource
*mem
;
240 rc
= i2c_del_adapter(adapter
);
242 dev_err(&pdev
->dev
, "Adapter '%s' delete fail\n",
247 put_device(&pdev
->dev
);
248 platform_set_drvdata(pdev
, NULL
);
250 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
251 release_mem_region(mem
->start
, resource_size(mem
));
257 static int puv3_i2c_suspend(struct platform_device
*dev
, pm_message_t state
)
260 /* Disable the IIC */
261 writel(I2C_ENABLE_DISABLE
, I2C_ENABLE
);
262 for (poll_count
= 0; poll_count
< 50; poll_count
++) {
263 if (readl(I2C_ENSTATUS
) & I2C_ENSTATUS_ENABLE
)
270 static int puv3_i2c_resume(struct platform_device
*dev
)
275 #define puv3_i2c_suspend NULL
276 #define puv3_i2c_resume NULL
279 MODULE_ALIAS("platform:puv3_i2c");
281 static struct platform_driver puv3_i2c_driver
= {
282 .probe
= puv3_i2c_probe
,
283 .remove
= __devexit_p(puv3_i2c_remove
),
284 .suspend
= puv3_i2c_suspend
,
285 .resume
= puv3_i2c_resume
,
287 .name
= "PKUnity-v3-I2C",
288 .owner
= THIS_MODULE
,
292 static int __init
puv3_i2c_init(void)
294 return platform_driver_register(&puv3_i2c_driver
);
297 static void __exit
puv3_i2c_exit(void)
299 platform_driver_unregister(&puv3_i2c_driver
);
302 module_init(puv3_i2c_init
);
303 module_exit(puv3_i2c_exit
);
305 MODULE_DESCRIPTION("PKUnity v3 I2C driver");
306 MODULE_LICENSE("GPL v2");