2 * I2C driver for Marvell 88PM860x
4 * Copyright (C) 2009 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/i2c.h>
15 #include <linux/err.h>
16 #include <linux/regmap.h>
17 #include <linux/mfd/88pm860x.h>
18 #include <linux/slab.h>
20 int pm860x_reg_read(struct i2c_client
*i2c
, int reg
)
22 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
23 struct regmap
*map
= (i2c
== chip
->client
) ? chip
->regmap
24 : chip
->regmap_companion
;
28 ret
= regmap_read(map
, reg
, &data
);
34 EXPORT_SYMBOL(pm860x_reg_read
);
36 int pm860x_reg_write(struct i2c_client
*i2c
, int reg
,
39 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
40 struct regmap
*map
= (i2c
== chip
->client
) ? chip
->regmap
41 : chip
->regmap_companion
;
44 ret
= regmap_write(map
, reg
, data
);
47 EXPORT_SYMBOL(pm860x_reg_write
);
49 int pm860x_bulk_read(struct i2c_client
*i2c
, int reg
,
50 int count
, unsigned char *buf
)
52 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
53 struct regmap
*map
= (i2c
== chip
->client
) ? chip
->regmap
54 : chip
->regmap_companion
;
57 ret
= regmap_raw_read(map
, reg
, buf
, count
);
60 EXPORT_SYMBOL(pm860x_bulk_read
);
62 int pm860x_bulk_write(struct i2c_client
*i2c
, int reg
,
63 int count
, unsigned char *buf
)
65 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
66 struct regmap
*map
= (i2c
== chip
->client
) ? chip
->regmap
67 : chip
->regmap_companion
;
70 ret
= regmap_raw_write(map
, reg
, buf
, count
);
73 EXPORT_SYMBOL(pm860x_bulk_write
);
75 int pm860x_set_bits(struct i2c_client
*i2c
, int reg
,
76 unsigned char mask
, unsigned char data
)
78 struct pm860x_chip
*chip
= i2c_get_clientdata(i2c
);
79 struct regmap
*map
= (i2c
== chip
->client
) ? chip
->regmap
80 : chip
->regmap_companion
;
83 ret
= regmap_update_bits(map
, reg
, mask
, data
);
86 EXPORT_SYMBOL(pm860x_set_bits
);
88 static int read_device(struct i2c_client
*i2c
, int reg
,
89 int bytes
, void *dest
)
91 unsigned char msgbuf0
[I2C_SMBUS_BLOCK_MAX
+ 3];
92 unsigned char msgbuf1
[I2C_SMBUS_BLOCK_MAX
+ 2];
93 struct i2c_adapter
*adap
= i2c
->adapter
;
94 struct i2c_msg msg
[2] = {{i2c
->addr
, 0, 1, msgbuf0
},
95 {i2c
->addr
, I2C_M_RD
, 0, msgbuf1
},
101 msgbuf0
[0] = (unsigned char)reg
; /* command */
104 /* if data needs to read back, num should be 2 */
107 ret
= adap
->algo
->master_xfer(adap
, msg
, num
);
108 memcpy(dest
, msgbuf1
, bytes
);
114 static int write_device(struct i2c_client
*i2c
, int reg
,
115 int bytes
, void *src
)
117 unsigned char buf
[bytes
+ 1];
118 struct i2c_adapter
*adap
= i2c
->adapter
;
122 buf
[0] = (unsigned char)reg
;
123 memcpy(&buf
[1], src
, bytes
);
124 msg
.addr
= i2c
->addr
;
129 ret
= adap
->algo
->master_xfer(adap
, &msg
, 1);
135 int pm860x_page_reg_read(struct i2c_client
*i2c
, int reg
)
137 unsigned char zero
= 0;
141 i2c_lock_adapter(i2c
->adapter
);
142 read_device(i2c
, 0xFA, 0, &zero
);
143 read_device(i2c
, 0xFB, 0, &zero
);
144 read_device(i2c
, 0xFF, 0, &zero
);
145 ret
= read_device(i2c
, reg
, 1, &data
);
148 read_device(i2c
, 0xFE, 0, &zero
);
149 read_device(i2c
, 0xFC, 0, &zero
);
150 i2c_unlock_adapter(i2c
->adapter
);
153 EXPORT_SYMBOL(pm860x_page_reg_read
);
155 int pm860x_page_reg_write(struct i2c_client
*i2c
, int reg
,
161 i2c_lock_adapter(i2c
->adapter
);
162 read_device(i2c
, 0xFA, 0, &zero
);
163 read_device(i2c
, 0xFB, 0, &zero
);
164 read_device(i2c
, 0xFF, 0, &zero
);
165 ret
= write_device(i2c
, reg
, 1, &data
);
166 read_device(i2c
, 0xFE, 0, &zero
);
167 read_device(i2c
, 0xFC, 0, &zero
);
168 i2c_unlock_adapter(i2c
->adapter
);
171 EXPORT_SYMBOL(pm860x_page_reg_write
);
173 int pm860x_page_bulk_read(struct i2c_client
*i2c
, int reg
,
174 int count
, unsigned char *buf
)
176 unsigned char zero
= 0;
179 i2c_lock_adapter(i2c
->adapter
);
180 read_device(i2c
, 0xfa, 0, &zero
);
181 read_device(i2c
, 0xfb, 0, &zero
);
182 read_device(i2c
, 0xff, 0, &zero
);
183 ret
= read_device(i2c
, reg
, count
, buf
);
184 read_device(i2c
, 0xFE, 0, &zero
);
185 read_device(i2c
, 0xFC, 0, &zero
);
186 i2c_unlock_adapter(i2c
->adapter
);
189 EXPORT_SYMBOL(pm860x_page_bulk_read
);
191 int pm860x_page_bulk_write(struct i2c_client
*i2c
, int reg
,
192 int count
, unsigned char *buf
)
194 unsigned char zero
= 0;
197 i2c_lock_adapter(i2c
->adapter
);
198 read_device(i2c
, 0xFA, 0, &zero
);
199 read_device(i2c
, 0xFB, 0, &zero
);
200 read_device(i2c
, 0xFF, 0, &zero
);
201 ret
= write_device(i2c
, reg
, count
, buf
);
202 read_device(i2c
, 0xFE, 0, &zero
);
203 read_device(i2c
, 0xFC, 0, &zero
);
204 i2c_unlock_adapter(i2c
->adapter
);
205 i2c_unlock_adapter(i2c
->adapter
);
208 EXPORT_SYMBOL(pm860x_page_bulk_write
);
210 int pm860x_page_set_bits(struct i2c_client
*i2c
, int reg
,
211 unsigned char mask
, unsigned char data
)
217 i2c_lock_adapter(i2c
->adapter
);
218 read_device(i2c
, 0xFA, 0, &zero
);
219 read_device(i2c
, 0xFB, 0, &zero
);
220 read_device(i2c
, 0xFF, 0, &zero
);
221 ret
= read_device(i2c
, reg
, 1, &value
);
226 ret
= write_device(i2c
, reg
, 1, &value
);
228 read_device(i2c
, 0xFE, 0, &zero
);
229 read_device(i2c
, 0xFC, 0, &zero
);
230 i2c_unlock_adapter(i2c
->adapter
);
233 EXPORT_SYMBOL(pm860x_page_set_bits
);
235 static const struct i2c_device_id pm860x_id_table
[] = {
239 MODULE_DEVICE_TABLE(i2c
, pm860x_id_table
);
241 static int verify_addr(struct i2c_client
*i2c
)
243 unsigned short addr_8607
[] = {0x30, 0x34};
244 unsigned short addr_8606
[] = {0x10, 0x11};
249 size
= ARRAY_SIZE(addr_8606
);
250 for (i
= 0; i
< size
; i
++) {
251 if (i2c
->addr
== *(addr_8606
+ i
))
254 size
= ARRAY_SIZE(addr_8607
);
255 for (i
= 0; i
< size
; i
++) {
256 if (i2c
->addr
== *(addr_8607
+ i
))
262 static struct regmap_config pm860x_regmap_config
= {
267 static int __devinit
pm860x_probe(struct i2c_client
*client
,
268 const struct i2c_device_id
*id
)
270 struct pm860x_platform_data
*pdata
= client
->dev
.platform_data
;
271 struct pm860x_chip
*chip
;
275 pr_info("No platform data in %s!\n", __func__
);
279 chip
= kzalloc(sizeof(struct pm860x_chip
), GFP_KERNEL
);
283 chip
->id
= verify_addr(client
);
284 chip
->regmap
= regmap_init_i2c(client
, &pm860x_regmap_config
);
285 if (IS_ERR(chip
->regmap
)) {
286 ret
= PTR_ERR(chip
->regmap
);
287 dev_err(&client
->dev
, "Failed to allocate register map: %d\n",
292 chip
->client
= client
;
293 i2c_set_clientdata(client
, chip
);
294 chip
->dev
= &client
->dev
;
295 dev_set_drvdata(chip
->dev
, chip
);
298 * Both client and companion client shares same platform driver.
299 * Driver distinguishes them by pdata->companion_addr.
300 * pdata->companion_addr is only assigned if companion chip exists.
301 * At the same time, the companion_addr shouldn't equal to client
304 if (pdata
->companion_addr
&& (pdata
->companion_addr
!= client
->addr
)) {
305 chip
->companion_addr
= pdata
->companion_addr
;
306 chip
->companion
= i2c_new_dummy(chip
->client
->adapter
,
307 chip
->companion_addr
);
308 chip
->regmap_companion
= regmap_init_i2c(chip
->companion
,
309 &pm860x_regmap_config
);
310 if (IS_ERR(chip
->regmap_companion
)) {
311 ret
= PTR_ERR(chip
->regmap_companion
);
312 dev_err(&chip
->companion
->dev
,
313 "Failed to allocate register map: %d\n", ret
);
316 i2c_set_clientdata(chip
->companion
, chip
);
319 pm860x_device_init(chip
, pdata
);
323 static int __devexit
pm860x_remove(struct i2c_client
*client
)
325 struct pm860x_chip
*chip
= i2c_get_clientdata(client
);
327 pm860x_device_exit(chip
);
328 if (chip
->companion
) {
329 regmap_exit(chip
->regmap_companion
);
330 i2c_unregister_device(chip
->companion
);
332 regmap_exit(chip
->regmap
);
337 static struct i2c_driver pm860x_driver
= {
340 .owner
= THIS_MODULE
,
342 .probe
= pm860x_probe
,
343 .remove
= __devexit_p(pm860x_remove
),
344 .id_table
= pm860x_id_table
,
347 static int __init
pm860x_i2c_init(void)
350 ret
= i2c_add_driver(&pm860x_driver
);
352 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret
);
355 subsys_initcall(pm860x_i2c_init
);
357 static void __exit
pm860x_i2c_exit(void)
359 i2c_del_driver(&pm860x_driver
);
361 module_exit(pm860x_i2c_exit
);
363 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
364 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
365 MODULE_LICENSE("GPL");