CAPI: Clean up capi_open/release
[safe/jmp/linux-2.6] / drivers / mfd / 88pm8607.c
1 /*
2  * Base driver for Marvell 88PM8607
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
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/interrupt.h>
15 #include <linux/platform_device.h>
16 #include <linux/i2c.h>
17 #include <linux/mfd/core.h>
18 #include <linux/mfd/88pm8607.h>
19
20
21 #define PM8607_REG_RESOURCE(_start, _end)               \
22 {                                                       \
23         .start  = PM8607_##_start,                      \
24         .end    = PM8607_##_end,                        \
25         .flags  = IORESOURCE_IO,                        \
26 }
27
28 static struct resource pm8607_regulator_resources[] = {
29         PM8607_REG_RESOURCE(BUCK1, BUCK1),
30         PM8607_REG_RESOURCE(BUCK2, BUCK2),
31         PM8607_REG_RESOURCE(BUCK3, BUCK3),
32         PM8607_REG_RESOURCE(LDO1,  LDO1),
33         PM8607_REG_RESOURCE(LDO2,  LDO2),
34         PM8607_REG_RESOURCE(LDO3,  LDO3),
35         PM8607_REG_RESOURCE(LDO4,  LDO4),
36         PM8607_REG_RESOURCE(LDO5,  LDO5),
37         PM8607_REG_RESOURCE(LDO6,  LDO6),
38         PM8607_REG_RESOURCE(LDO7,  LDO7),
39         PM8607_REG_RESOURCE(LDO8,  LDO8),
40         PM8607_REG_RESOURCE(LDO9,  LDO9),
41         PM8607_REG_RESOURCE(LDO10, LDO10),
42         PM8607_REG_RESOURCE(LDO12, LDO12),
43         PM8607_REG_RESOURCE(LDO14, LDO14),
44 };
45
46 #define PM8607_REG_DEVS(_name, _id)                                     \
47 {                                                                       \
48         .name           = "88pm8607-" #_name,                           \
49         .num_resources  = 1,                                            \
50         .resources      = &pm8607_regulator_resources[PM8607_ID_##_id], \
51 }
52
53 static struct mfd_cell pm8607_devs[] = {
54         PM8607_REG_DEVS(buck1, BUCK1),
55         PM8607_REG_DEVS(buck2, BUCK2),
56         PM8607_REG_DEVS(buck3, BUCK3),
57         PM8607_REG_DEVS(ldo1,  LDO1),
58         PM8607_REG_DEVS(ldo2,  LDO2),
59         PM8607_REG_DEVS(ldo3,  LDO3),
60         PM8607_REG_DEVS(ldo4,  LDO4),
61         PM8607_REG_DEVS(ldo5,  LDO5),
62         PM8607_REG_DEVS(ldo6,  LDO6),
63         PM8607_REG_DEVS(ldo7,  LDO7),
64         PM8607_REG_DEVS(ldo8,  LDO8),
65         PM8607_REG_DEVS(ldo9,  LDO9),
66         PM8607_REG_DEVS(ldo10, LDO10),
67         PM8607_REG_DEVS(ldo12, LDO12),
68         PM8607_REG_DEVS(ldo14, LDO14),
69 };
70
71 static inline int pm8607_read_device(struct pm8607_chip *chip,
72                                      int reg, int bytes, void *dest)
73 {
74         struct i2c_client *i2c = chip->client;
75         unsigned char data;
76         int ret;
77
78         data = (unsigned char)reg;
79         ret = i2c_master_send(i2c, &data, 1);
80         if (ret < 0)
81                 return ret;
82
83         ret = i2c_master_recv(i2c, dest, bytes);
84         if (ret < 0)
85                 return ret;
86         return 0;
87 }
88
89 static inline int pm8607_write_device(struct pm8607_chip *chip,
90                                       int reg, int bytes, void *src)
91 {
92         struct i2c_client *i2c = chip->client;
93         unsigned char buf[bytes + 1];
94         int ret;
95
96         buf[0] = (unsigned char)reg;
97         memcpy(&buf[1], src, bytes);
98
99         ret = i2c_master_send(i2c, buf, bytes + 1);
100         if (ret < 0)
101                 return ret;
102         return 0;
103 }
104
105 int pm8607_reg_read(struct pm8607_chip *chip, int reg)
106 {
107         unsigned char data;
108         int ret;
109
110         mutex_lock(&chip->io_lock);
111         ret = chip->read(chip, reg, 1, &data);
112         mutex_unlock(&chip->io_lock);
113
114         if (ret < 0)
115                 return ret;
116         else
117                 return (int)data;
118 }
119 EXPORT_SYMBOL(pm8607_reg_read);
120
121 int pm8607_reg_write(struct pm8607_chip *chip, int reg,
122                      unsigned char data)
123 {
124         int ret;
125
126         mutex_lock(&chip->io_lock);
127         ret = chip->write(chip, reg, 1, &data);
128         mutex_unlock(&chip->io_lock);
129
130         return ret;
131 }
132 EXPORT_SYMBOL(pm8607_reg_write);
133
134 int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
135                      int count, unsigned char *buf)
136 {
137         int ret;
138
139         mutex_lock(&chip->io_lock);
140         ret = chip->read(chip, reg, count, buf);
141         mutex_unlock(&chip->io_lock);
142
143         return ret;
144 }
145 EXPORT_SYMBOL(pm8607_bulk_read);
146
147 int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
148                       int count, unsigned char *buf)
149 {
150         int ret;
151
152         mutex_lock(&chip->io_lock);
153         ret = chip->write(chip, reg, count, buf);
154         mutex_unlock(&chip->io_lock);
155
156         return ret;
157 }
158 EXPORT_SYMBOL(pm8607_bulk_write);
159
160 int pm8607_set_bits(struct pm8607_chip *chip, int reg,
161                     unsigned char mask, unsigned char data)
162 {
163         unsigned char value;
164         int ret;
165
166         mutex_lock(&chip->io_lock);
167         ret = chip->read(chip, reg, 1, &value);
168         if (ret < 0)
169                 goto out;
170         value &= ~mask;
171         value |= data;
172         ret = chip->write(chip, reg, 1, &value);
173 out:
174         mutex_unlock(&chip->io_lock);
175         return ret;
176 }
177 EXPORT_SYMBOL(pm8607_set_bits);
178
179
180 static const struct i2c_device_id pm8607_id_table[] = {
181         { "88PM8607", 0 },
182         {}
183 };
184 MODULE_DEVICE_TABLE(i2c, pm8607_id_table);
185
186
187 static int __devinit pm8607_probe(struct i2c_client *client,
188                                   const struct i2c_device_id *id)
189 {
190         struct pm8607_platform_data *pdata = client->dev.platform_data;
191         struct pm8607_chip *chip;
192         int i, count;
193         int ret;
194
195         chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
196         if (chip == NULL)
197                 return -ENOMEM;
198
199         chip->client = client;
200         chip->dev = &client->dev;
201         chip->read = pm8607_read_device;
202         chip->write = pm8607_write_device;
203         i2c_set_clientdata(client, chip);
204
205         mutex_init(&chip->io_lock);
206         dev_set_drvdata(chip->dev, chip);
207
208         ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
209         if (ret < 0) {
210                 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
211                 goto out;
212         }
213         if ((ret & CHIP_ID_MASK) == CHIP_ID)
214                 dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
215                          ret);
216         else {
217                 dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
218                         "Chip ID: %02x\n", ret);
219                 goto out;
220         }
221         chip->chip_id = ret;
222
223         ret = pm8607_reg_read(chip, PM8607_BUCK3);
224         if (ret < 0) {
225                 dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
226                 goto out;
227         }
228         if (ret & PM8607_BUCK3_DOUBLE)
229                 chip->buck3_double = 1;
230
231         ret = pm8607_reg_read(chip, PM8607_MISC1);
232         if (ret < 0) {
233                 dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
234                 goto out;
235         }
236         if (pdata->i2c_port == PI2C_PORT)
237                 ret |= PM8607_MISC1_PI2C;
238         else
239                 ret &= ~PM8607_MISC1_PI2C;
240         ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
241         if (ret < 0) {
242                 dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
243                 goto out;
244         }
245
246
247         count = ARRAY_SIZE(pm8607_devs);
248         for (i = 0; i < count; i++) {
249                 ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
250                                       1, NULL, 0);
251                 if (ret != 0) {
252                         dev_err(chip->dev, "Failed to add subdevs\n");
253                         goto out;
254                 }
255         }
256
257         return 0;
258
259 out:
260         i2c_set_clientdata(client, NULL);
261         kfree(chip);
262         return ret;
263 }
264
265 static int __devexit pm8607_remove(struct i2c_client *client)
266 {
267         struct pm8607_chip *chip = i2c_get_clientdata(client);
268
269         mfd_remove_devices(chip->dev);
270         kfree(chip);
271         return 0;
272 }
273
274 static struct i2c_driver pm8607_driver = {
275         .driver = {
276                 .name   = "88PM8607",
277                 .owner  = THIS_MODULE,
278         },
279         .probe          = pm8607_probe,
280         .remove         = __devexit_p(pm8607_remove),
281         .id_table       = pm8607_id_table,
282 };
283
284 static int __init pm8607_init(void)
285 {
286         int ret;
287         ret = i2c_add_driver(&pm8607_driver);
288         if (ret != 0)
289                 pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret);
290         return ret;
291 }
292 subsys_initcall(pm8607_init);
293
294 static void __exit pm8607_exit(void)
295 {
296         i2c_del_driver(&pm8607_driver);
297 }
298 module_exit(pm8607_exit);
299
300 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
301 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
302 MODULE_LICENSE("GPL");