ti-st: do not free skb in st_send_frame if receive call returns error
[linux-2.6.git] / drivers / power / smb349-charger.c
1 /*
2  * drivers/power/smb349-charger.c
3  *
4  * Battery charger driver for smb349 from summit microelectronics
5  *
6  * Copyright (c) 2012, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation;
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/platform_device.h>
25 #include <linux/mutex.h>
26 #include <linux/err.h>
27 #include <linux/i2c.h>
28 #include <linux/delay.h>
29 #include <linux/power_supply.h>
30 #include <linux/platform_device.h>
31 #include <linux/regulator/driver.h>
32 #include <linux/regulator/machine.h>
33 #include <linux/smb349-charger.h>
34 #include <linux/slab.h>
35 #include <linux/gpio.h>
36 #include <linux/interrupt.h>
37 #include <linux/irq.h>
38
39 #define SMB349_CHARGE           0x00
40 #define SMB349_CHRG_CRNTS       0x01
41 #define SMB349_VRS_FUNC         0x02
42 #define SMB349_FLOAT_VLTG       0x03
43 #define SMB349_CHRG_CTRL        0x04
44 #define SMB349_STAT_TIME_CTRL   0x05
45 #define SMB349_PIN_CTRL         0x06
46 #define SMB349_THERM_CTRL       0x07
47 #define SMB349_CTRL_REG         0x09
48
49 #define SMB349_OTG_TLIM_REG     0x0A
50 #define SMB349_HRD_SFT_TEMP     0x0B
51 #define SMB349_FAULT_INTR       0x0C
52 #define SMB349_STS_INTR_1       0x0D
53 #define SMB349_SYSOK_USB3       0x0E
54 #define SMB349_IN_CLTG_DET      0x10
55 #define SMB349_STS_INTR_2       0x11
56
57 #define SMB349_CMD_REG          0x30
58 #define SMB349_CMD_REG_B        0x31
59 #define SMB349_CMD_REG_c        0x33
60
61 #define SMB349_INTR_STS_A       0x35
62 #define SMB349_INTR_STS_B       0x36
63 #define SMB349_INTR_STS_C       0x37
64 #define SMB349_INTR_STS_D       0x38
65 #define SMB349_INTR_STS_E       0x39
66 #define SMB349_INTR_STS_F       0x3A
67
68 #define SMB349_STS_REG_A        0x3B
69 #define SMB349_STS_REG_B        0x3C
70 #define SMB349_STS_REG_C        0x3D
71 #define SMB349_STS_REG_D        0x3E
72 #define SMB349_STS_REG_E        0x3F
73
74 #define SMB349_ENABLE_WRITE     1
75 #define SMB349_DISABLE_WRITE    0
76 #define ENABLE_WRT_ACCESS       0x80
77 #define THERM_CTRL              0x10
78 #define BATTERY_MISSING         0x10
79 #define CHARGING                0x06
80 #define DEDICATED_CHARGER       0x04
81 #define CHRG_DOWNSTRM_PORT      0x08
82 #define ENABLE_CHARGE           0x02
83
84 static struct smb349_charger *charger;
85
86 static int smb349_read(struct i2c_client *client, int reg)
87 {
88         int ret;
89
90         ret = i2c_smbus_read_byte_data(client, reg);
91
92         if (ret < 0)
93                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
94
95         return ret;
96 }
97
98 static int smb349_write(struct i2c_client *client, int reg, u8 value)
99 {
100         int ret;
101
102         ret = i2c_smbus_write_byte_data(client, reg, value);
103
104         if (ret < 0)
105                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
106
107         return ret;
108 }
109
110 static int smb349_update_reg(struct i2c_client *client, int reg, u8 value)
111 {
112         int ret, retval;
113
114         retval = smb349_read(client, reg);
115         if (retval < 0) {
116                 dev_err(&client->dev, "%s: err %d\n", __func__, retval);
117                 return retval;
118         }
119
120         ret = smb349_write(client, reg, retval | value);
121         if (ret < 0) {
122                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
123                 return ret;
124         }
125
126         return ret;
127 }
128
129 int smb349_volatile_writes(struct i2c_client *client, uint8_t value)
130 {
131         int ret = 0;
132
133         if (value == SMB349_ENABLE_WRITE) {
134                 /* Enable volatile write to config registers */
135                 ret = smb349_update_reg(client, SMB349_CMD_REG,
136                                                 ENABLE_WRT_ACCESS);
137                 if (ret < 0) {
138                         dev_err(&client->dev, "%s(): Failed in writing"
139                                 "register 0x%02x\n", __func__, SMB349_CMD_REG);
140                         return ret;
141                 }
142         } else {
143                 ret = smb349_read(client, SMB349_CMD_REG);
144                 if (ret < 0) {
145                         dev_err(&client->dev, "%s: err %d\n", __func__, ret);
146                         return ret;
147                 }
148
149                 ret = smb349_write(client, SMB349_CMD_REG, ret & (~(1<<7)));
150                 if (ret < 0) {
151                         dev_err(&client->dev, "%s: err %d\n", __func__, ret);
152                         return ret;
153                 }
154         }
155         return ret;
156 }
157
158 static void smb349_clear_interrupts(struct i2c_client *client)
159 {
160         uint8_t val, buf[6];
161
162         val = i2c_smbus_read_i2c_block_data(client, SMB349_INTR_STS_A, 6, buf);
163         if (val < 0)
164                 dev_err(&client->dev, "%s(): Failed in clearing interrupts\n",
165                                                                 __func__);
166 }
167
168 static int smb349_configure_charger(struct i2c_client *client)
169 {
170         int ret = 0;
171
172         /* Enable volatile writes to registers */
173         ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE);
174         if (ret < 0) {
175                 dev_err(&client->dev, "%s() error in configuring charger..\n",
176                                                                 __func__);
177                 goto error;
178         }
179
180          /* Enable charging */
181         ret = smb349_update_reg(client, SMB349_CMD_REG, ENABLE_CHARGE);
182         if (ret < 0) {
183                 dev_err(&client->dev, "%s(): Failed in writing register"
184                                 "0x%02x\n", __func__, SMB349_CMD_REG);
185                 goto error;
186         }
187
188         /* Configure THERM ctrl */
189         ret = smb349_update_reg(client, SMB349_THERM_CTRL, THERM_CTRL);
190         if (ret < 0) {
191                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
192                 goto error;
193         }
194
195         /* Disable volatile writes to registers */
196         ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE);
197         if (ret < 0) {
198                 dev_err(&client->dev, "%s() error in configuring charger..\n",
199                                                                 __func__);
200                 goto error;
201         }
202 error:
203         return ret;
204 }
205
206 static irqreturn_t smb349_status_isr(int irq, void *dev_id)
207 {
208         struct i2c_client *client = charger->client;
209         int ret, val;
210
211         val =  smb349_read(client, SMB349_STS_REG_D);
212         if (val < 0) {
213                 dev_err(&client->dev, "%s(): Failed in reading register"
214                                 "0x%02x\n", __func__, SMB349_STS_REG_D);
215                 goto irq_error;
216         } else if (val != 0) {
217
218                 if (val & DEDICATED_CHARGER)
219                         charger->chrg_type = AC;
220                 else if (val & CHRG_DOWNSTRM_PORT)
221                         charger->chrg_type = USB;
222
223                 /* configure charger */
224                 ret = smb349_configure_charger(client);
225                 if (ret < 0) {
226                         dev_err(&client->dev, "%s() error in configuring"
227                                 "charger..\n", __func__);
228                         goto irq_error;
229                 }
230
231                 charger->state = progress;
232         } else {
233                 charger->state = stopped;
234
235                 ret = smb349_read(client, SMB349_CMD_REG);
236                 if (ret < 0) {
237                         dev_err(&client->dev, "%s: err %d\n", __func__, ret);
238                         goto irq_error;
239                 }
240
241                 ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<1))));
242                 if (ret < 0) {
243                         dev_err(&client->dev, "%s: err %d\n", __func__, ret);
244                         goto irq_error;
245                 }
246         }
247
248         if (charger->charger_cb)
249                 charger->charger_cb(charger->state, charger->chrg_type,
250                                                 charger->charger_cb_data);
251 irq_error:
252         smb349_clear_interrupts(client);
253         return IRQ_HANDLED;
254 }
255
256 int register_callback(charging_callback_t cb, void *args)
257 {
258         struct smb349_charger *charger_data = charger;
259         if (!charger_data)
260                 return -ENODEV;
261
262         charger_data->charger_cb = cb;
263         charger_data->charger_cb_data = args;
264         return 0;
265 }
266 EXPORT_SYMBOL_GPL(register_callback);
267
268 int smb349_battery_online(void)
269 {
270         int val;
271         struct i2c_client *client = charger->client;
272
273         val = smb349_read(charger->client, SMB349_INTR_STS_B);
274         if (val < 0) {
275                 dev_err(&client->dev, "%s(): Failed in reading register"
276                                 "0x%02x\n", __func__, SMB349_INTR_STS_B);
277                 return val;
278         }
279         if (val & BATTERY_MISSING)
280                 return 0;
281         else
282                 return 1;
283 }
284
285 static int smb349_configure_interrupts(struct i2c_client *client)
286 {
287         int ret = 0;
288
289         /* Enable volatile writes to registers */
290         ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE);
291         if (ret < 0) {
292                 dev_err(&client->dev, "%s() error in configuring charger..\n",
293                                                                 __func__);
294                 goto error;
295         }
296
297         ret = smb349_update_reg(client, SMB349_FAULT_INTR, 0xff);
298         if (ret < 0) {
299                 dev_err(&client->dev, "%s(): Failed in writing register"
300                                 "0x%02x\n", __func__, SMB349_CMD_REG);
301                 goto error;
302         }
303
304         ret = smb349_update_reg(client, SMB349_STS_INTR_1, 0xff);
305         if (ret < 0) {
306                 dev_err(&client->dev, "%s: err %d\n", __func__, ret);
307                 goto error;
308         }
309
310          /* Disable volatile writes to registers */
311         ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE);
312         if (ret < 0) {
313                 dev_err(&client->dev, "%s() error in configuring charger..\n",
314                                                                 __func__);
315                 goto error;
316         }
317
318 error:
319         return ret;
320 }
321
322 static int __devinit smb349_probe(struct i2c_client *client,
323                         const struct i2c_device_id *id)
324 {
325         struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
326         int ret, irq_num;
327
328         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
329                 return -EIO;
330
331         charger = kzalloc(sizeof(*charger), GFP_KERNEL);
332         if (!charger)
333                 return -ENOMEM;
334
335         charger->client = client;
336         charger->dev = &client->dev;
337         i2c_set_clientdata(client, charger);
338
339         /* Check battery presence */
340         if (!smb349_battery_online()) {
341                 dev_err(&client->dev, "%s() No Battery present, exiting..\n",
342                                         __func__);
343                 goto error;
344         }
345
346         ret = smb349_configure_interrupts(client);
347         if (ret < 0) {
348                 dev_err(&client->dev, "%s() error in configuring charger..\n",
349                                                                 __func__);
350                 goto error;
351         }
352
353         irq_num = gpio_to_irq(client->irq);
354         ret = request_threaded_irq(irq_num,
355                         NULL, smb349_status_isr, IRQ_TYPE_EDGE_FALLING,
356                                 "smb349", charger);
357         if (ret) {
358                 dev_err(&client->dev, "%s(): Failed in requesting isr\n",
359                                 __func__);
360                 goto error;
361         }
362
363         return 0;
364 error:
365         kfree(charger);
366         return ret;
367 }
368
369 static int __devexit smb349_remove(struct i2c_client *client)
370 {
371         struct smb349_charger *charger = i2c_get_clientdata(client);
372
373         kfree(charger);
374         return 0;
375 }
376
377 static const struct i2c_device_id smb349_id[] = {
378         { "smb349", 0 },
379         { }
380 };
381 MODULE_DEVICE_TABLE(i2c, smb349_id);
382
383 static struct i2c_driver smb349_i2c_driver = {
384         .driver = {
385                 .name   = "smb349",
386         },
387         .probe          = smb349_probe,
388         .remove         = __devexit_p(smb349_remove),
389         .id_table       = smb349_id,
390 };
391
392 static int __init smb349_init(void)
393 {
394         return i2c_add_driver(&smb349_i2c_driver);
395 }
396 module_init(smb349_init);
397
398 static void __exit smb349_exit(void)
399 {
400         i2c_del_driver(&smb349_i2c_driver);
401 }
402 module_exit(smb349_exit);
403
404 MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>");
405 MODULE_DESCRIPTION("SMB349 Battery-Charger");
406 MODULE_LICENSE("GPL");