upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / power / max8922_charger.c
1 /*
2  *  max8922-charger.c
3  *  MAXIM 8922 charger interface driver
4  *
5  *  Copyright (C) 2011 Samsung Electronics
6  *
7  *  <ms925.kim@samsung.com>
8  *
9  * This program is not provided / owned by Maxim Integrated Products.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/err.h>
20 #include <linux/slab.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
23 #include <linux/gpio.h>
24 #include <linux/delay.h>
25 #include <linux/power_supply.h>
26 #include <linux/max8922-charger.h>
27 #include <linux/regulator/driver.h>
28 #include <linux/notifier.h>
29 #include <linux/switch.h>
30 #include <plat/gpio-core.h>
31
32 #define MAX8922_USB_MAX_CURRENT 450000
33 #define MAX8922_TA_TYP_CURRENT  650000
34
35 enum max8922_cable_type {
36         CABLE_NONE,
37         CABLE_USB,
38         CABLE_TA,
39 };
40
41 struct max8922_info {
42         struct device *dev;
43         struct power_supply psy_bat;
44         struct max8922_platform_data *pdata;
45         struct regulator_dev *rdev;
46         int cable_type;
47         int irq_chg_ing;
48         int is_enabled;
49         int max_uA;
50
51         struct switch_dev *switch_dev;
52         struct notifier_block nb;
53         int event_code_ta, event_code_usb;
54 };
55
56 static enum power_supply_property max8922_battery_props[] = {
57         POWER_SUPPLY_PROP_STATUS,
58         POWER_SUPPLY_PROP_ONLINE,
59 };
60
61 static inline int max8922_is_charging(struct max8922_info *info)
62 {
63         int ta_nconnected = gpio_get_value(info->pdata->gpio_ta_nconnected);
64         int chg_ing = gpio_get_value(info->pdata->gpio_chg_ing);
65
66         dev_info(info->dev, "%s: charging state = 0x%x\n", __func__,
67                  (ta_nconnected << 1) | chg_ing) ;
68
69         return (ta_nconnected << 1) | chg_ing;
70 }
71
72 static int max8922_get_property(struct power_supply *psy,
73                                 enum power_supply_property psp,
74                                 union power_supply_propval *val)
75 {
76         struct max8922_info *info =
77             container_of(psy, struct max8922_info, psy_bat);
78
79         int ta_nconnected = 0;
80
81         switch (psp) {
82         case POWER_SUPPLY_PROP_STATUS:
83                 switch (max8922_is_charging(info)) {
84                 case 0:
85                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
86                         break;
87                 case 1:
88                         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
89                         break;
90                 default:
91                         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
92                         break;
93                 }
94                 break;
95         case POWER_SUPPLY_PROP_ONLINE:
96                 ta_nconnected = gpio_get_value(info->pdata->gpio_ta_nconnected);
97                 val->intval = !ta_nconnected;
98                 break;
99         default:
100                 return -EINVAL;
101         }
102         return 0;
103 }
104
105 static int max8922_enable_charging(struct max8922_info *info, bool enable,
106                                         int cable_type)
107 {
108         int gpio_chg_en = info->pdata->gpio_chg_en;
109         unsigned long flags;
110
111         dev_info(info->dev, "%s: %s charging,%s\n", __func__,
112                  enable ? "enable" : "disable",
113                  cable_type == CABLE_USB ? "USB" : "TA");
114
115         if (info->is_enabled == enable && info->cable_type == cable_type)
116                 goto out;
117
118         if (enable) {
119                 info->is_enabled = true;
120                 if (cable_type == CABLE_USB ||
121                         (cable_type == CABLE_TA &&
122                          info->max_uA <= MAX8922_USB_MAX_CURRENT)) {
123                         /* Charging by USB cable */
124                         gpio_set_value(gpio_chg_en, GPIO_LEVEL_HIGH);
125                 } else if (cable_type == CABLE_TA &&
126                         info->max_uA > MAX8922_USB_MAX_CURRENT) {
127                         /* Charging by TA cable */
128                         gpio_set_value(gpio_chg_en, GPIO_LEVEL_HIGH);
129                         mdelay(5);
130
131                         local_irq_save(flags);
132                         gpio_set_value(gpio_chg_en, GPIO_LEVEL_LOW);
133                         udelay(120);
134                         gpio_set_value(gpio_chg_en, GPIO_LEVEL_HIGH);
135                         local_irq_restore(flags);
136                 } else {
137                         info->is_enabled = false;
138                 }
139         } else {
140                 gpio_set_value(gpio_chg_en, GPIO_LEVEL_LOW);
141                 info->is_enabled = false;
142         }
143
144         msleep(300);
145 out:
146         return max8922_is_charging(info);
147 }
148
149 static int max8922_set_property(struct power_supply *psy,
150                                 enum power_supply_property psp,
151                                 const union power_supply_propval *val)
152 {
153         struct max8922_info *info =
154             container_of(psy, struct max8922_info, psy_bat);
155         bool enable;
156
157         switch (psp) {
158         case POWER_SUPPLY_PROP_CURRENT_NOW:     /* Set charging current */
159                 info->cable_type = val->intval > 450 ? CABLE_TA : CABLE_USB;
160                 break;
161         case POWER_SUPPLY_PROP_STATUS:  /* Enable/Disable charging */
162                 enable = (val->intval == POWER_SUPPLY_STATUS_CHARGING);
163                 max8922_enable_charging(info, enable, info->cable_type);
164                 break;
165         default:
166                 return -EINVAL;
167         }
168         return 0;
169 }
170
171 static irqreturn_t max8922_chg_ing_irq(int irq, void *data)
172 {
173         struct max8922_info *info = data;
174         int ret = 0;
175
176         dev_info(info->dev, "chg_ing IRQ occurred!\n");
177
178         if (gpio_get_value(info->pdata->gpio_ta_nconnected))
179                 return IRQ_HANDLED;
180
181         if (info->pdata->topoff_cb)
182                 ret = info->pdata->topoff_cb();
183
184         if (ret) {
185                 dev_err(info->dev, "%s: error from topoff_cb(%d)\n", __func__,
186                         ret);
187                 return IRQ_HANDLED;
188         }
189
190         return IRQ_HANDLED;
191 }
192
193 static int max8922_is_enabled(struct regulator_dev *rdev)
194 {
195         struct max8922_info *max8922 = rdev_get_drvdata(rdev);
196
197         return max8922->is_enabled;
198 }
199
200 static int max8922_enable(struct regulator_dev *rdev)
201 {
202         struct max8922_info *max8922 = rdev_get_drvdata(rdev);
203
204         max8922_enable_charging(max8922, true, max8922->cable_type);
205
206         return 0;
207 }
208
209 static int max8922_disable(struct regulator_dev *rdev)
210 {
211         struct max8922_info *max8922 = rdev_get_drvdata(rdev);
212
213         max8922_enable_charging(max8922, false, max8922->cable_type);
214
215         return 0;
216 }
217
218 static int max8922_get_current_limit(struct regulator_dev *rdev)
219 {
220         struct max8922_info *max8922 = rdev_get_drvdata(rdev);
221
222         return max8922->max_uA;
223 }
224
225 static int max8922_set_current_limit(struct regulator_dev *rdev,
226                                 int min_uA, int max_uA)
227 {
228         struct max8922_info *max8922 = rdev_get_drvdata(rdev);
229
230         if (max8922->max_uA != max_uA) {
231                 max8922->max_uA = max_uA;
232
233                 /* Reset charger if it was already enabled */
234                 if (max8922->is_enabled) {
235                         max8922_enable_charging(max8922, false,
236                                         max8922->cable_type);
237                         max8922_enable_charging(max8922, true,
238                                         max8922->cable_type);
239                 }
240         }
241
242         return 0;
243 }
244
245 static struct regulator_ops max8922_ops = {
246         .is_enabled             = max8922_is_enabled,
247         .enable                 = max8922_enable,
248         .disable                = max8922_disable,
249         .get_current_limit      = max8922_get_current_limit,
250         .set_current_limit      = max8922_set_current_limit,
251 };
252
253 static struct regulator_desc regulator = {
254         .name           = "MAX8922_CHARGER",
255         .id             = 0,
256         .ops            = &max8922_ops,
257         .type           = REGULATOR_CURRENT,
258         .owner          = THIS_MODULE,
259 };
260
261 static int max8922_charger_notifier(struct notifier_block *self,
262                 unsigned long event, void *ptr)
263 {
264         struct max8922_info *info =
265                 container_of(self, struct max8922_info, nb);
266         bool charger_enable = false;
267         int cable_type = CABLE_NONE;
268
269         if (info->event_code_ta > 0) {
270                 if (event & info->event_code_ta) {
271                         cable_type = CABLE_TA;
272                         info->max_uA = MAX8922_TA_TYP_CURRENT;
273                         charger_enable = true;
274                 }
275         }
276
277         if (info->event_code_usb > 0) {
278                 if (event & info->event_code_usb) {
279                         cable_type = CABLE_USB;
280                         info->max_uA = MAX8922_USB_MAX_CURRENT;
281                         charger_enable = true;
282                 }
283         }
284
285         max8922_enable_charging(info, charger_enable, cable_type);
286
287         info->cable_type = cable_type;
288
289         return NOTIFY_DONE;
290 }
291
292 static struct notifier_block max8922_charger_nb = {
293         .notifier_call = max8922_charger_notifier,
294 };
295
296 static __devinit int max8922_probe(struct platform_device *pdev)
297 {
298         struct max8922_platform_data *pdata = dev_get_platdata(&pdev->dev);
299         struct max8922_info *info;
300         int ret;
301
302         dev_info(&pdev->dev, "%s : MAX8922 Charger Driver Loading\n", __func__);
303
304         info = kzalloc(sizeof(*info), GFP_KERNEL);
305         if (!info)
306                 return -ENOMEM;
307
308         platform_set_drvdata(pdev, info);
309
310         info->dev = &pdev->dev;
311         info->pdata = pdata;
312
313         info->psy_bat.name = "max8922-charger",
314             info->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY,
315             info->psy_bat.properties = max8922_battery_props,
316             info->psy_bat.num_properties = ARRAY_SIZE(max8922_battery_props),
317             info->psy_bat.get_property = max8922_get_property,
318             info->psy_bat.set_property = max8922_set_property,
319             ret = power_supply_register(&pdev->dev, &info->psy_bat);
320         if (ret) {
321                 dev_err(info->dev, "Failed to register psy_bat\n");
322                 goto err_kfree;
323         }
324
325         if (pdata->cfg_gpio) {
326                 ret = pdata->cfg_gpio();
327                 if (ret) {
328                         dev_err(info->dev, "failed to configure GPIO\n");
329                         goto err_kfree;
330                 }
331         }
332
333         if (gpio_is_valid(pdata->gpio_chg_en)) {
334                 if (!pdata->gpio_chg_en) {
335                         dev_err(info->dev, "gpio_chg_en defined as 0\n");
336                         WARN_ON(!pdata->gpio_chg_en);
337                         ret = -EIO;
338                         goto err_kfree;
339                 }
340                 gpio_request(pdata->gpio_chg_en, "MAX8922 CHG_EN");
341         }
342
343         if (gpio_is_valid(pdata->gpio_chg_ing)) {
344                 if (!pdata->gpio_chg_ing) {
345                         dev_err(info->dev, "gpio_chg_ing defined as 0\n");
346                         WARN_ON(!pdata->gpio_chg_ing);
347                         ret = -EIO;
348                         goto err_kfree;
349                 }
350                 gpio_request(pdata->gpio_chg_ing, "MAX8922 CHG_ING");
351         }
352
353         if (gpio_is_valid(pdata->gpio_ta_nconnected)) {
354                 if (!pdata->gpio_ta_nconnected) {
355                         dev_err(info->dev, "gpio_ta_nconnected defined as 0\n");
356                         WARN_ON(!pdata->gpio_ta_nconnected);
357                         ret = -EIO;
358                         goto err_kfree;
359                 }
360                 gpio_request(pdata->gpio_ta_nconnected,
361                              "MAX8922 TA_nCONNECTED");
362         }
363
364         info->rdev = regulator_register(&regulator, &pdev->dev,
365                         pdata->init_data, info);
366
367         if (IS_ERR(info->rdev)) {
368                 ret = PTR_ERR(info->rdev);
369                 dev_err(&pdev->dev, "regulator init failed (%d)\n", ret);
370                 goto err_kfree;
371         }
372
373         info->nb = max8922_charger_nb;
374         info->switch_dev = switch_get_switch_dev("switch-usb");
375         if (info->switch_dev) {
376                 switch_register_notifier(info->switch_dev, &info->nb);
377                 info->event_code_ta =
378                     switch_get_event_code(info->switch_dev, "TA");
379                 info->event_code_usb =
380                     switch_get_event_code(info->switch_dev, "USB");
381         }
382
383         info->cable_type = CABLE_NONE;
384
385         return 0;
386 err_kfree:
387         power_supply_unregister(&info->psy_bat);
388         platform_set_drvdata(pdev, NULL);
389         kfree(info);
390         return ret;
391 }
392
393 static int __devexit max8922_remove(struct platform_device *pdev)
394 {
395         struct max8922_info *info = platform_get_drvdata(pdev);
396
397         power_supply_unregister(&info->psy_bat);
398
399         gpio_free(info->pdata->gpio_chg_en);
400         gpio_free(info->pdata->gpio_chg_ing);
401         gpio_free(info->pdata->gpio_ta_nconnected);
402
403         if (info->switch_dev)
404                 switch_unregister_notifier(info->switch_dev, &info->nb);
405
406         kfree(info);
407
408         return 0;
409 }
410
411 #ifdef CONFIG_PM
412 static int max8922_suspend(struct device *dev)
413 {
414         struct max8922_info *info = dev_get_drvdata(dev);
415
416         if (info && info->irq_chg_ing)
417                 disable_irq(info->irq_chg_ing);
418
419         return 0;
420 }
421
422 static int max8922_resume(struct device *dev)
423 {
424         struct max8922_info *info = dev_get_drvdata(dev);
425
426         if (info && info->irq_chg_ing)
427                 enable_irq(info->irq_chg_ing);
428
429         return 0;
430 }
431 #else
432 #define max8922_charger_suspend NULL
433 #define max8922_charger_resume  NULL
434 #endif
435
436 static const struct dev_pm_ops max8922_pm_ops = {
437         .suspend = max8922_suspend,
438         .resume = max8922_resume,
439 };
440
441 static struct platform_driver max8922_driver = {
442         .driver = {
443                    .name = "max8922-charger",
444                    .owner = THIS_MODULE,
445                    .pm = &max8922_pm_ops,
446                    },
447         .probe = max8922_probe,
448         .remove = __devexit_p(max8922_remove),
449 };
450
451 static int __init max8922_init(void)
452 {
453         return platform_driver_register(&max8922_driver);
454 }
455
456 static void __exit max8922_exit(void)
457 {
458         platform_driver_register(&max8922_driver);
459 }
460
461 subsys_initcall(max8922_init);
462 module_exit(max8922_exit);
463
464 MODULE_DESCRIPTION("MAXIM 8922 charger control driver");
465 MODULE_AUTHOR("<ms925.kim@samsung.com>");
466 MODULE_LICENSE("GPL");