mfd: twl-core: regulator configuration for twl6030 V1V8, V2V1 SMPS
[linux-2.6.git] / drivers / mfd / 88pm860x-i2c.c
1 /*
2  * I2C driver for Marvell 88PM860x
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  *      Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
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.
10  */
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>
19
20 int pm860x_reg_read(struct i2c_client *i2c, int reg)
21 {
22         struct pm860x_chip *chip = i2c_get_clientdata(i2c);
23         struct regmap *map = (i2c == chip->client) ? chip->regmap
24                                 : chip->regmap_companion;
25         unsigned int data;
26         int ret;
27
28         ret = regmap_read(map, reg, &data);
29         if (ret < 0)
30                 return ret;
31         else
32                 return (int)data;
33 }
34 EXPORT_SYMBOL(pm860x_reg_read);
35
36 int pm860x_reg_write(struct i2c_client *i2c, int reg,
37                      unsigned char data)
38 {
39         struct pm860x_chip *chip = i2c_get_clientdata(i2c);
40         struct regmap *map = (i2c == chip->client) ? chip->regmap
41                                 : chip->regmap_companion;
42         int ret;
43
44         ret = regmap_write(map, reg, data);
45         return ret;
46 }
47 EXPORT_SYMBOL(pm860x_reg_write);
48
49 int pm860x_bulk_read(struct i2c_client *i2c, int reg,
50                      int count, unsigned char *buf)
51 {
52         struct pm860x_chip *chip = i2c_get_clientdata(i2c);
53         struct regmap *map = (i2c == chip->client) ? chip->regmap
54                                 : chip->regmap_companion;
55         int ret;
56
57         ret = regmap_raw_read(map, reg, buf, count);
58         return ret;
59 }
60 EXPORT_SYMBOL(pm860x_bulk_read);
61
62 int pm860x_bulk_write(struct i2c_client *i2c, int reg,
63                       int count, unsigned char *buf)
64 {
65         struct pm860x_chip *chip = i2c_get_clientdata(i2c);
66         struct regmap *map = (i2c == chip->client) ? chip->regmap
67                                 : chip->regmap_companion;
68         int ret;
69
70         ret = regmap_raw_write(map, reg, buf, count);
71         return ret;
72 }
73 EXPORT_SYMBOL(pm860x_bulk_write);
74
75 int pm860x_set_bits(struct i2c_client *i2c, int reg,
76                     unsigned char mask, unsigned char data)
77 {
78         struct pm860x_chip *chip = i2c_get_clientdata(i2c);
79         struct regmap *map = (i2c == chip->client) ? chip->regmap
80                                 : chip->regmap_companion;
81         int ret;
82
83         ret = regmap_update_bits(map, reg, mask, data);
84         return ret;
85 }
86 EXPORT_SYMBOL(pm860x_set_bits);
87
88 static int read_device(struct i2c_client *i2c, int reg,
89                        int bytes, void *dest)
90 {
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},
96                                 };
97         int num = 1, ret = 0;
98
99         if (dest == NULL)
100                 return -EINVAL;
101         msgbuf0[0] = (unsigned char)reg;        /* command */
102         msg[1].len = bytes;
103
104         /* if data needs to read back, num should be 2 */
105         if (bytes > 0)
106                 num = 2;
107         ret = adap->algo->master_xfer(adap, msg, num);
108         memcpy(dest, msgbuf1, bytes);
109         if (ret < 0)
110                 return ret;
111         return 0;
112 }
113
114 static int write_device(struct i2c_client *i2c, int reg,
115                         int bytes, void *src)
116 {
117         unsigned char buf[bytes + 1];
118         struct i2c_adapter *adap = i2c->adapter;
119         struct i2c_msg msg;
120         int ret;
121
122         buf[0] = (unsigned char)reg;
123         memcpy(&buf[1], src, bytes);
124         msg.addr = i2c->addr;
125         msg.flags = 0;
126         msg.len = bytes + 1;
127         msg.buf = buf;
128
129         ret = adap->algo->master_xfer(adap, &msg, 1);
130         if (ret < 0)
131                 return ret;
132         return 0;
133 }
134
135 int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
136 {
137         unsigned char zero = 0;
138         unsigned char data;
139         int ret;
140
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);
146         if (ret >= 0)
147                 ret = (int)data;
148         read_device(i2c, 0xFE, 0, &zero);
149         read_device(i2c, 0xFC, 0, &zero);
150         i2c_unlock_adapter(i2c->adapter);
151         return ret;
152 }
153 EXPORT_SYMBOL(pm860x_page_reg_read);
154
155 int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
156                           unsigned char data)
157 {
158         unsigned char zero;
159         int ret;
160
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);
169         return ret;
170 }
171 EXPORT_SYMBOL(pm860x_page_reg_write);
172
173 int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
174                           int count, unsigned char *buf)
175 {
176         unsigned char zero = 0;
177         int ret;
178
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);
187         return ret;
188 }
189 EXPORT_SYMBOL(pm860x_page_bulk_read);
190
191 int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
192                            int count, unsigned char *buf)
193 {
194         unsigned char zero = 0;
195         int ret;
196
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);
206         return ret;
207 }
208 EXPORT_SYMBOL(pm860x_page_bulk_write);
209
210 int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
211                          unsigned char mask, unsigned char data)
212 {
213         unsigned char zero;
214         unsigned char value;
215         int ret;
216
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);
222         if (ret < 0)
223                 goto out;
224         value &= ~mask;
225         value |= data;
226         ret = write_device(i2c, reg, 1, &value);
227 out:
228         read_device(i2c, 0xFE, 0, &zero);
229         read_device(i2c, 0xFC, 0, &zero);
230         i2c_unlock_adapter(i2c->adapter);
231         return ret;
232 }
233 EXPORT_SYMBOL(pm860x_page_set_bits);
234
235 static const struct i2c_device_id pm860x_id_table[] = {
236         { "88PM860x", 0 },
237         {}
238 };
239 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
240
241 static int verify_addr(struct i2c_client *i2c)
242 {
243         unsigned short addr_8607[] = {0x30, 0x34};
244         unsigned short addr_8606[] = {0x10, 0x11};
245         int size, i;
246
247         if (i2c == NULL)
248                 return 0;
249         size = ARRAY_SIZE(addr_8606);
250         for (i = 0; i < size; i++) {
251                 if (i2c->addr == *(addr_8606 + i))
252                         return CHIP_PM8606;
253         }
254         size = ARRAY_SIZE(addr_8607);
255         for (i = 0; i < size; i++) {
256                 if (i2c->addr == *(addr_8607 + i))
257                         return CHIP_PM8607;
258         }
259         return 0;
260 }
261
262 static struct regmap_config pm860x_regmap_config = {
263         .reg_bits = 8,
264         .val_bits = 8,
265 };
266
267 static int __devinit pm860x_probe(struct i2c_client *client,
268                                   const struct i2c_device_id *id)
269 {
270         struct pm860x_platform_data *pdata = client->dev.platform_data;
271         struct pm860x_chip *chip;
272         int ret;
273
274         if (!pdata) {
275                 pr_info("No platform data in %s!\n", __func__);
276                 return -EINVAL;
277         }
278
279         chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
280         if (chip == NULL)
281                 return -ENOMEM;
282
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",
288                                 ret);
289                 kfree(chip);
290                 return ret;
291         }
292         chip->client = client;
293         i2c_set_clientdata(client, chip);
294         chip->dev = &client->dev;
295         dev_set_drvdata(chip->dev, chip);
296
297         /*
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
302          * address.
303          */
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);
314                         return ret;
315                 }
316                 i2c_set_clientdata(chip->companion, chip);
317         }
318
319         pm860x_device_init(chip, pdata);
320         return 0;
321 }
322
323 static int __devexit pm860x_remove(struct i2c_client *client)
324 {
325         struct pm860x_chip *chip = i2c_get_clientdata(client);
326
327         pm860x_device_exit(chip);
328         if (chip->companion) {
329                 regmap_exit(chip->regmap_companion);
330                 i2c_unregister_device(chip->companion);
331         }
332         regmap_exit(chip->regmap);
333         kfree(chip);
334         return 0;
335 }
336
337 static struct i2c_driver pm860x_driver = {
338         .driver = {
339                 .name   = "88PM860x",
340                 .owner  = THIS_MODULE,
341         },
342         .probe          = pm860x_probe,
343         .remove         = __devexit_p(pm860x_remove),
344         .id_table       = pm860x_id_table,
345 };
346
347 static int __init pm860x_i2c_init(void)
348 {
349         int ret;
350         ret = i2c_add_driver(&pm860x_driver);
351         if (ret != 0)
352                 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
353         return ret;
354 }
355 subsys_initcall(pm860x_i2c_init);
356
357 static void __exit pm860x_i2c_exit(void)
358 {
359         i2c_del_driver(&pm860x_driver);
360 }
361 module_exit(pm860x_i2c_exit);
362
363 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
364 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
365 MODULE_LICENSE("GPL");