6f5b8cf2f652b8edf6accf9db107d8f63ea72c23
[pandora-kernel.git] / drivers / mfd / tps65910.c
1 /*
2  * tps65910.c  --  TI TPS6591x
3  *
4  * Copyright 2010 Texas Instruments Inc.
5  *
6  * Author: Graeme Gregory <gg@slimlogic.co.uk>
7  * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
8  *
9  *  This program is free software; you can redistribute it and/or modify it
10  *  under  the terms of the GNU General  Public License as published by the
11  *  Free Software Foundation;  either version 2 of the License, or (at your
12  *  option) any later version.
13  *
14  */
15
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 #include <linux/init.h>
19 #include <linux/slab.h>
20 #include <linux/i2c.h>
21 #include <linux/gpio.h>
22 #include <linux/mfd/core.h>
23 #include <linux/mfd/tps65910.h>
24
25 static struct mfd_cell tps65910s[] = {
26         {
27                 .name = "tps65910-pmic",
28         },
29         {
30                 .name = "tps65910-rtc",
31         },
32         {
33                 .name = "tps65910-power",
34         },
35 };
36
37
38 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
39                                   int bytes, void *dest)
40 {
41         struct i2c_client *i2c = tps65910->i2c_client;
42         struct i2c_msg xfer[2];
43         int ret;
44
45         /* Write register */
46         xfer[0].addr = i2c->addr;
47         xfer[0].flags = 0;
48         xfer[0].len = 1;
49         xfer[0].buf = &reg;
50
51         /* Read data */
52         xfer[1].addr = i2c->addr;
53         xfer[1].flags = I2C_M_RD;
54         xfer[1].len = bytes;
55         xfer[1].buf = dest;
56
57         ret = i2c_transfer(i2c->adapter, xfer, 2);
58         if (ret == 2)
59                 ret = 0;
60         else if (ret >= 0)
61                 ret = -EIO;
62
63         return ret;
64 }
65
66 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
67                                    int bytes, void *src)
68 {
69         struct i2c_client *i2c = tps65910->i2c_client;
70         /* we add 1 byte for device register */
71         u8 msg[TPS65910_MAX_REGISTER + 1];
72         int ret;
73
74         if (bytes > TPS65910_MAX_REGISTER)
75                 return -EINVAL;
76
77         msg[0] = reg;
78         memcpy(&msg[1], src, bytes);
79
80         ret = i2c_master_send(i2c, msg, bytes + 1);
81         if (ret < 0)
82                 return ret;
83         if (ret != bytes + 1)
84                 return -EIO;
85         return 0;
86 }
87
88 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
89 {
90         u8 data;
91         int err;
92
93         mutex_lock(&tps65910->io_mutex);
94         err = tps65910_i2c_read(tps65910, reg, 1, &data);
95         if (err) {
96                 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
97                 goto out;
98         }
99
100         data |= mask;
101         err = tps65910_i2c_write(tps65910, reg, 1, &data);
102         if (err)
103                 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
104
105 out:
106         mutex_unlock(&tps65910->io_mutex);
107         return err;
108 }
109 EXPORT_SYMBOL_GPL(tps65910_set_bits);
110
111 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
112 {
113         u8 data;
114         int err;
115
116         mutex_lock(&tps65910->io_mutex);
117         err = tps65910_i2c_read(tps65910, reg, 1, &data);
118         if (err) {
119                 dev_err(tps65910->dev, "read from reg %x failed\n", reg);
120                 goto out;
121         }
122
123         data &= mask;
124         err = tps65910_i2c_write(tps65910, reg, 1, &data);
125         if (err)
126                 dev_err(tps65910->dev, "write to reg %x failed\n", reg);
127
128 out:
129         mutex_unlock(&tps65910->io_mutex);
130         return err;
131 }
132 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
133
134 static int tps65910_i2c_probe(struct i2c_client *i2c,
135                             const struct i2c_device_id *id)
136 {
137         struct tps65910 *tps65910;
138         struct tps65910_board *pmic_plat_data;
139         struct tps65910_platform_data *init_data;
140         int ret = 0;
141
142         pmic_plat_data = dev_get_platdata(&i2c->dev);
143         if (!pmic_plat_data)
144                 return -EINVAL;
145
146         init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL);
147         if (init_data == NULL)
148                 return -ENOMEM;
149
150         tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
151         if (tps65910 == NULL) {
152                 kfree(init_data);
153                 return -ENOMEM;
154         }
155
156         i2c_set_clientdata(i2c, tps65910);
157         tps65910->dev = &i2c->dev;
158         tps65910->i2c_client = i2c;
159         tps65910->id = id->driver_data;
160         tps65910->read = tps65910_i2c_read;
161         tps65910->write = tps65910_i2c_write;
162         mutex_init(&tps65910->io_mutex);
163
164         ret = mfd_add_devices(tps65910->dev, -1,
165                               tps65910s, ARRAY_SIZE(tps65910s),
166                               NULL, 0);
167         if (ret < 0)
168                 goto err;
169
170         init_data->irq = pmic_plat_data->irq;
171         init_data->irq_base = pmic_plat_data->irq;
172
173         tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
174
175         ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
176         if (ret < 0)
177                 goto err;
178
179         kfree(init_data);
180         return ret;
181
182 err:
183         mfd_remove_devices(tps65910->dev);
184         kfree(tps65910);
185         kfree(init_data);
186         return ret;
187 }
188
189 static int tps65910_i2c_remove(struct i2c_client *i2c)
190 {
191         struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
192
193         mfd_remove_devices(tps65910->dev);
194         tps65910_irq_exit(tps65910);
195         kfree(tps65910);
196
197         return 0;
198 }
199
200 static const struct i2c_device_id tps65910_i2c_id[] = {
201        { "tps65910", TPS65910 },
202        { "tps65911", TPS65911 },
203        { }
204 };
205 MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
206
207
208 static struct i2c_driver tps65910_i2c_driver = {
209         .driver = {
210                    .name = "tps65910",
211                    .owner = THIS_MODULE,
212         },
213         .probe = tps65910_i2c_probe,
214         .remove = tps65910_i2c_remove,
215         .id_table = tps65910_i2c_id,
216 };
217
218 static int __init tps65910_i2c_init(void)
219 {
220         return i2c_add_driver(&tps65910_i2c_driver);
221 }
222 /* init early so consumer devices can complete system boot */
223 subsys_initcall(tps65910_i2c_init);
224
225 static void __exit tps65910_i2c_exit(void)
226 {
227         i2c_del_driver(&tps65910_i2c_driver);
228 }
229 module_exit(tps65910_i2c_exit);
230
231 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
232 MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
233 MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
234 MODULE_LICENSE("GPL");