1 // SPDX-License-Identifier: GPL-2.0-only
3 * I2C driver for PKUnity-v3 SoC
4 * Code specific to PKUnity SoC and UniCore ISA
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/err.h>
13 #include <linux/slab.h>
14 #include <linux/types.h>
15 #include <linux/delay.h>
16 #include <linux/i2c.h>
17 #include <linux/clk.h>
18 #include <linux/platform_device.h>
20 #include <mach/hardware.h>
23 * Poll the i2c status register until the specified bit is set.
24 * Returns 0 if timed out (100 msec).
26 static short poll_status(unsigned long bit
)
30 if (bit
& I2C_STATUS_TFNF
) {
33 } while (!(readl(I2C_STATUS
) & bit
) && (--loop_cntr
> 0));
37 if (readl(I2C_TAR
) == I2C_TAR_EEPROM
)
41 } while (!(readl(I2C_RXFLR
) & 0xf) && (--loop_cntr
> 0));
44 return (loop_cntr
> 0);
47 static int xfer_read(struct i2c_adapter
*adap
, unsigned char *buf
, int length
)
53 if (!poll_status(I2C_STATUS_TFNF
)) {
54 dev_dbg(&adap
->dev
, "Tx FIFO Not Full timeout\n");
59 writel(i2c_reg
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
61 /* get ready to next write */
65 writel(I2C_DATACMD_READ
, I2C_DATACMD
);
67 /* wait until the Rx FIFO have available */
68 if (!poll_status(I2C_STATUS_RFNE
)) {
69 dev_dbg(&adap
->dev
, "RXRDY timeout\n");
73 /* read the data to buf */
74 *buf
= (readl(I2C_DATACMD
) & I2C_DATACMD_DAT_MASK
);
81 static int xfer_write(struct i2c_adapter
*adap
, unsigned char *buf
, int length
)
85 /* Do nothing but storing the reg_num to a static variable */
87 printk(KERN_WARNING
"Error i2c reg\n");
98 writel(i2c_reg
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
101 writel(*buf
| I2C_DATACMD_WRITE
, I2C_DATACMD
);
103 /* wait until the Rx FIFO have available */
106 /* read the data to buf */
115 * Generic i2c master transfer entrypoint.
118 static int puv3_i2c_xfer(struct i2c_adapter
*adap
, struct i2c_msg
*pmsg
,
125 writel(I2C_ENABLE_DISABLE
, I2C_ENABLE
);
127 /* Set the work mode and speed*/
128 writel(I2C_CON_MASTER
| I2C_CON_SPEED_STD
| I2C_CON_SLAVEDISABLE
, I2C_CON
);
130 writel(pmsg
->addr
, I2C_TAR
);
133 writel(I2C_ENABLE_ENABLE
, I2C_ENABLE
);
135 dev_dbg(&adap
->dev
, "puv3_i2c_xfer: processing %d messages:\n", num
);
137 for (i
= 0; i
< num
; i
++) {
138 dev_dbg(&adap
->dev
, " #%d: %sing %d byte%s %s 0x%02x\n", i
,
139 pmsg
->flags
& I2C_M_RD
? "read" : "writ",
140 pmsg
->len
, pmsg
->len
> 1 ? "s" : "",
141 pmsg
->flags
& I2C_M_RD
? "from" : "to", pmsg
->addr
);
143 if (pmsg
->len
&& pmsg
->buf
) { /* sanity check */
144 if (pmsg
->flags
& I2C_M_RD
)
145 ret
= xfer_read(adap
, pmsg
->buf
, pmsg
->len
);
147 ret
= xfer_write(adap
, pmsg
->buf
, pmsg
->len
);
153 dev_dbg(&adap
->dev
, "transfer complete\n");
154 pmsg
++; /* next message */
157 /* XXX: fixup be16_to_cpu in bq27x00_battery.c */
158 if (pmsg
->addr
== I2C_TAR_PWIC
) {
160 pmsg
->buf
[0] = pmsg
->buf
[1];
168 * Return list of supported functionality.
170 static u32
puv3_i2c_func(struct i2c_adapter
*adapter
)
172 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
175 static const struct i2c_algorithm puv3_i2c_algorithm
= {
176 .master_xfer
= puv3_i2c_xfer
,
177 .functionality
= puv3_i2c_func
,
181 * Main initialization routine.
183 static int puv3_i2c_probe(struct platform_device
*pdev
)
185 struct i2c_adapter
*adapter
;
186 struct resource
*mem
;
189 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
193 if (!request_mem_region(mem
->start
, resource_size(mem
), "puv3_i2c"))
196 adapter
= kzalloc(sizeof(struct i2c_adapter
), GFP_KERNEL
);
197 if (adapter
== NULL
) {
198 dev_err(&pdev
->dev
, "can't allocate interface!\n");
202 snprintf(adapter
->name
, sizeof(adapter
->name
), "PUV3-I2C at 0x%08x",
204 adapter
->algo
= &puv3_i2c_algorithm
;
205 adapter
->class = I2C_CLASS_HWMON
;
206 adapter
->dev
.parent
= &pdev
->dev
;
208 platform_set_drvdata(pdev
, adapter
);
210 adapter
->nr
= pdev
->id
;
211 rc
= i2c_add_numbered_adapter(adapter
);
213 goto fail_add_adapter
;
215 dev_info(&pdev
->dev
, "PKUnity v3 i2c bus adapter.\n");
221 release_mem_region(mem
->start
, resource_size(mem
));
226 static int puv3_i2c_remove(struct platform_device
*pdev
)
228 struct i2c_adapter
*adapter
= platform_get_drvdata(pdev
);
229 struct resource
*mem
;
231 i2c_del_adapter(adapter
);
233 put_device(&pdev
->dev
);
235 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
236 release_mem_region(mem
->start
, resource_size(mem
));
241 #ifdef CONFIG_PM_SLEEP
242 static int puv3_i2c_suspend(struct device
*dev
)
245 /* Disable the IIC */
246 writel(I2C_ENABLE_DISABLE
, I2C_ENABLE
);
247 for (poll_count
= 0; poll_count
< 50; poll_count
++) {
248 if (readl(I2C_ENSTATUS
) & I2C_ENSTATUS_ENABLE
)
255 static SIMPLE_DEV_PM_OPS(puv3_i2c_pm
, puv3_i2c_suspend
, NULL
);
256 #define PUV3_I2C_PM (&puv3_i2c_pm)
259 #define PUV3_I2C_PM NULL
262 static struct platform_driver puv3_i2c_driver
= {
263 .probe
= puv3_i2c_probe
,
264 .remove
= puv3_i2c_remove
,
266 .name
= "PKUnity-v3-I2C",
271 module_platform_driver(puv3_i2c_driver
);
273 MODULE_DESCRIPTION("PKUnity v3 I2C driver");
274 MODULE_LICENSE("GPL v2");
275 MODULE_ALIAS("platform:puv3_i2c");