tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / battery / sec_charger.c
1 /*
2  *  sec_charger.c
3  *  Samsung Mobile Charger Driver
4  *
5  *  Copyright (C) 2012 Samsung Electronics
6  *
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 version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #define DEBUG
14
15 #include <linux/of_device.h>
16 #include <linux/of_gpio.h>
17 #include <linux/of_irq.h>
18 #include <linux/interrupt.h>
19 #include <linux/battery/sec_charger.h>
20
21 extern int sec_chg_dt_init(struct device_node *np,
22                          struct device *dev,
23                          sec_battery_platform_data_t *pdata);
24
25 static struct device_attribute sec_charger_attrs[] = {
26         SEC_CHARGER_ATTR(reg),
27         SEC_CHARGER_ATTR(data),
28         SEC_CHARGER_ATTR(regs),
29 };
30
31 static enum power_supply_property sec_charger_props[] = {
32         POWER_SUPPLY_PROP_STATUS,
33         POWER_SUPPLY_PROP_CHARGE_TYPE,
34         POWER_SUPPLY_PROP_HEALTH,
35         POWER_SUPPLY_PROP_ONLINE,
36         POWER_SUPPLY_PROP_CURRENT_MAX,
37         POWER_SUPPLY_PROP_CURRENT_AVG,
38         POWER_SUPPLY_PROP_CURRENT_NOW,
39         POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
40 #if defined(CONFIG_FUELGAUGE_88PM822) || \
41         defined(CONFIG_FUELGAUGE_88PM800) || \
42         defined(CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3)
43         POWER_SUPPLY_PROP_POWER_STATUS,
44         POWER_SUPPLY_PROP_CHARGE_NOW,
45 #endif
46 };
47
48 static int input_current[] = {
49         800,
50         800,
51         800,
52 };
53
54 static int sec_chg_get_property(struct power_supply *psy,
55                             enum power_supply_property psp,
56                             union power_supply_propval *val)
57 {
58         struct sec_charger_info *charger =
59                 container_of(psy, struct sec_charger_info, psy_chg);
60
61         switch (psp) {
62         case POWER_SUPPLY_PROP_CURRENT_MAX:     /* input current limit set */
63                 val->intval = charger->charging_current_max;
64                 break;
65
66         case POWER_SUPPLY_PROP_ONLINE:
67         case POWER_SUPPLY_PROP_STATUS:
68         case POWER_SUPPLY_PROP_CHARGE_TYPE:
69         case POWER_SUPPLY_PROP_HEALTH:
70         case POWER_SUPPLY_PROP_CURRENT_AVG:     /* charging current */
71         /* calculated input current limit value */
72         case POWER_SUPPLY_PROP_CURRENT_NOW:
73 #if defined(CONFIG_FUELGAUGE_88PM822) || \
74         defined(CONFIG_FUELGAUGE_88PM800) || \
75         defined(CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3)
76         case POWER_SUPPLY_PROP_POWER_STATUS:
77         case POWER_SUPPLY_PROP_CHARGE_NOW:
78 #endif
79                 if (!sec_hal_chg_get_property(charger_variable, psp, val))
80                         return -EINVAL;
81                 break;
82         case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
83                 val->intval = charger->charging_current * val->intval / 100;
84                 break;
85         case POWER_SUPPLY_PROP_PRESENT:
86                 if (!sec_hal_chg_get_property(charger_variable, psp, val))
87                         return -EINVAL;
88                 break;
89         default:
90                 return -EINVAL;
91         }
92         return 0;
93 }
94
95 static int sec_chg_set_property(struct power_supply *psy,
96                             enum power_supply_property psp,
97                             const union power_supply_propval *val)
98 {
99         struct sec_charger_info *charger =
100                 container_of(psy, struct sec_charger_info, psy_chg);
101         union power_supply_propval input_value;
102
103         switch (psp) {
104         case POWER_SUPPLY_PROP_STATUS:
105                 charger->status = val->intval;
106                 break;
107
108         /* val->intval : type */
109         case POWER_SUPPLY_PROP_ONLINE:
110                 charger->cable_type = val->intval;
111                 if (val->intval == POWER_SUPPLY_TYPE_BATTERY)
112                         charger->is_charging = false;
113                 else
114                         charger->is_charging = true;
115
116                 /* current setting */
117                 if ((charger->pdata->siop_activated) &&
118                         ((charger->cable_type == POWER_SUPPLY_TYPE_MAINS) ||
119                          (charger->cable_type == POWER_SUPPLY_TYPE_MISC))) {
120                         charger->charging_current_max = input_current[
121                                 charger->pdata->siop_level];
122                 } else {
123                 charger->charging_current_max =
124                         charger->pdata->charging_current[
125                         val->intval].input_current_limit;
126                 }
127
128                 charger->charging_current =
129                         charger->pdata->charging_current[
130                         val->intval].fast_charging_current;
131
132                 if (!sec_hal_chg_set_property(charger_variable, psp, val))
133                         return -EINVAL;
134                 break;
135
136         /* val->intval : input current limit set */
137         case POWER_SUPPLY_PROP_CURRENT_MAX:
138                 charger->charging_current_max = val->intval;
139         /* to control charging current,
140          * use input current limit and set charging current as much as possible
141          * so we only control input current limit to control charge current
142          */
143         case POWER_SUPPLY_PROP_CURRENT_NOW:
144                 if (!sec_hal_chg_set_property(charger_variable, psp, val))
145                         return -EINVAL;
146                 break;
147
148         /* val->intval : charging current */
149         case POWER_SUPPLY_PROP_CURRENT_AVG:
150                 charger->charging_current = val->intval;
151
152                 if (!sec_hal_chg_set_property(charger_variable, psp, val))
153                         return -EINVAL;
154                 break;
155
156         /* val->intval : SIOP level (%)
157          * SIOP charging current setting
158          */
159         case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
160                 /* change val as charging current by SIOP level
161                  * do NOT change initial charging current setting
162                  */
163 #ifdef CONFIG_CHARGER_SM5414
164                 if (!sec_hal_chg_set_property(charger_variable, psp, val))
165                         return -EINVAL;
166 #else
167                 input_value.intval =
168                         charger->charging_current * val->intval / 100;
169
170                 /* charging current should be over than USB charging current */
171                 if (charger->pdata->chg_functions_setting &
172                         SEC_CHARGER_MINIMUM_SIOP_CHARGING_CURRENT) {
173                         if (input_value.intval > 0 &&
174                                 input_value.intval <
175                                 charger->pdata->charging_current[
176                                 POWER_SUPPLY_TYPE_USB].fast_charging_current)
177                                 input_value.intval =
178                                 charger->pdata->charging_current[
179                                 POWER_SUPPLY_TYPE_USB].fast_charging_current;
180                 }
181
182                 /* set charging current as new value */
183                 if (!sec_hal_chg_set_property(charger_variable,
184                         POWER_SUPPLY_PROP_CURRENT_AVG, &input_value))
185                         return -EINVAL;
186 #endif
187                 break;
188 #ifdef CONFIG_CHARGER_SM5414
189         case POWER_SUPPLY_PROP_HEALTH:
190                 if (!sec_hal_chg_set_property(charger_variable, psp, val))
191                         return -EINVAL;
192                 break;
193 #endif
194
195         default:
196                 return -EINVAL;
197         }
198         return 0;
199 }
200
201 static void sec_chg_isr_work(struct work_struct *work)
202 {
203         struct sec_charger_info *charger =
204                 container_of(work, struct sec_charger_info, isr_work.work);
205         union power_supply_propval val;
206         int full_check_type;
207
208         dev_info(&charger->client->dev,
209                 "%s: Charger Interrupt\n", __func__);
210
211         psy_do_property("battery", get,
212                 POWER_SUPPLY_PROP_CHARGE_NOW, val);
213         if (val.intval == SEC_BATTERY_CHARGING_1ST)
214                 full_check_type = charger->pdata->full_check_type;
215         else
216                 full_check_type = charger->pdata->full_check_type_2nd;
217
218         if (full_check_type == SEC_BATTERY_FULLCHARGED_CHGINT) {
219                 if (!sec_hal_chg_get_property(charger_variable,
220                         POWER_SUPPLY_PROP_STATUS, &val))
221                         return;
222
223                 switch (val.intval) {
224                 case POWER_SUPPLY_STATUS_DISCHARGING:
225                         dev_err(&charger->client->dev,
226                                 "%s: Interrupted but Discharging\n", __func__);
227                         break;
228
229                 case POWER_SUPPLY_STATUS_NOT_CHARGING:
230                         dev_err(&charger->client->dev,
231                                 "%s: Interrupted but NOT Charging\n", __func__);
232                         break;
233
234                 case POWER_SUPPLY_STATUS_FULL:
235                         dev_info(&charger->client->dev,
236                                 "%s: Interrupted by Full\n", __func__);
237
238 #if defined(CONFIG_CHARGER_BQ24157)
239                                                 charger->cable_type = POWER_SUPPLY_TYPE_BATTERY;
240                                                 charger->is_charging = false;
241                                                 if (!sec_hal_chg_set_property(charger_variable, POWER_SUPPLY_PROP_ONLINE, &val))
242                                                         dev_err(&charger->client->dev,
243                                                                 "%s: Charging disable error\n", __func__);
244 #endif
245                         
246                         psy_do_property("battery", set,
247                                 POWER_SUPPLY_PROP_STATUS, val);
248                         break;
249
250                 case POWER_SUPPLY_STATUS_CHARGING:
251                         dev_err(&charger->client->dev,
252                                 "%s: Interrupted but Charging\n", __func__);
253                         break;
254
255                 case POWER_SUPPLY_STATUS_UNKNOWN:
256                 default:
257                         dev_err(&charger->client->dev,
258                                 "%s: Invalid Charger Status\n", __func__);
259                         break;
260                 }
261         }
262
263         if (charger->pdata->ovp_uvlo_check_type ==
264                 SEC_BATTERY_OVP_UVLO_CHGINT) {
265 #if !defined(CONFIG_CHARGER_SM5414)
266                 if (!sec_hal_chg_get_property(charger_variable,
267                         POWER_SUPPLY_PROP_HEALTH, &val))
268                         return;
269 #endif
270
271 #if defined(CONFIG_CHARGER_SM5414)
272                 msleep(200);
273                 val.intval = sec_get_charging_health(charger->client);
274 #endif
275
276                 switch (val.intval) {
277                 case POWER_SUPPLY_HEALTH_OVERHEAT:
278                 case POWER_SUPPLY_HEALTH_COLD:
279                         dev_err(&charger->client->dev,
280                                 "%s: Interrupted but Hot/Cold\n", __func__);
281                         break;
282
283                 case POWER_SUPPLY_HEALTH_DEAD:
284                         dev_err(&charger->client->dev,
285                                 "%s: Interrupted but Dead\n", __func__);
286                         break;
287
288                 case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
289                 case POWER_SUPPLY_HEALTH_UNDERVOLTAGE:
290                         dev_info(&charger->client->dev,
291                                 "%s: Interrupted by OVP/UVLO\n", __func__);
292                         psy_do_property("battery", set,
293                                 POWER_SUPPLY_PROP_HEALTH, val);
294                         break;
295
296                 case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
297                         dev_err(&charger->client->dev,
298                                 "%s: Interrupted but Unspec\n", __func__);
299                         break;
300
301                 case POWER_SUPPLY_HEALTH_GOOD:
302                         dev_err(&charger->client->dev,
303                                 "%s: Interrupted but Good\n", __func__);
304                         psy_do_property("battery", set,
305                                 POWER_SUPPLY_PROP_HEALTH, val);
306                         break;
307
308                 case POWER_SUPPLY_HEALTH_UNKNOWN:
309                 default:
310                         dev_err(&charger->client->dev,
311                                 "%s: Invalid Charger Health\n", __func__);
312                         break;
313                 }
314         }
315
316         if (charger->pdata->cable_check_type & SEC_BATTERY_CABLE_CHECK_CHGINT) {
317                 if (!sec_hal_chg_get_property(charger_variable,
318                         POWER_SUPPLY_PROP_ONLINE, &val))
319                         return;
320
321                 /* use SEC_BATTERY_CABLE_SOURCE_EXTERNAL for cable_source_type
322                  * charger would call battery driver to set ONLINE property
323                  * check battery driver loaded or not
324                  */
325                 if (get_power_supply_by_name("battery")) {
326                         psy_do_property("battery", set,
327                                 POWER_SUPPLY_PROP_ONLINE, val);
328                 } else
329                         charger->pdata->check_cable_result_callback(val.intval);
330         }
331 }
332
333 static irqreturn_t sec_chg_irq_thread(int irq, void *irq_data)
334 {
335         struct sec_charger_info *charger = irq_data;
336 #if defined(CONFIG_CHARGER_BQ24157)
337         schedule_delayed_work(&charger->isr_work, HZ * 0.5);
338 #else
339         schedule_delayed_work(&charger->isr_work, 0);
340 #endif
341
342         return IRQ_HANDLED;
343 }
344
345 static int sec_chg_create_attrs(struct device *dev)
346 {
347         int i, rc;
348
349         for (i = 0; i < ARRAY_SIZE(sec_charger_attrs); i++) {
350                 rc = device_create_file(dev, &sec_charger_attrs[i]);
351                 if (rc)
352                         goto create_attrs_failed;
353         }
354         goto create_attrs_succeed;
355
356 create_attrs_failed:
357         dev_err(dev, "%s: failed (%d)\n", __func__, rc);
358         while (i--)
359                 device_remove_file(dev, &sec_charger_attrs[i]);
360 create_attrs_succeed:
361         return rc;
362 }
363
364 ssize_t sec_chg_show_attrs(struct device *dev,
365                                 struct device_attribute *attr, char *buf)
366 {
367         const ptrdiff_t offset = attr - sec_charger_attrs;
368         int i = 0;
369
370         switch (offset) {
371         case CHG_REG:
372         case CHG_DATA:
373         case CHG_REGS:
374                 i = sec_hal_chg_show_attrs(dev, offset, buf);
375                 break;
376         default:
377                 i = -EINVAL;
378                 break;
379         }
380
381         return i;
382 }
383
384 ssize_t sec_chg_store_attrs(struct device *dev,
385                                 struct device_attribute *attr,
386                                 const char *buf, size_t count)
387 {
388         const ptrdiff_t offset = attr - sec_charger_attrs;
389         int ret = 0;
390
391         switch (offset) {
392         case CHG_REG:
393         case CHG_DATA:
394                 ret = sec_hal_chg_store_attrs(dev, offset, buf, count);
395                 break;
396         default:
397                 ret = -EINVAL;
398                 break;
399         }
400
401         return ret;
402 }
403
404 #if defined(CONFIG_CHARGER_MFD)
405 static int sec_charger_probe(struct platform_device *pdev)
406 {
407         struct sec_charger_info *charger;
408         sec_charger_dev_t *mfd_dev = dev_get_drvdata(pdev->dev.parent);
409         sec_charger_pdata_t *pdata = dev_get_platdata(mfd_dev->dev);
410         int ret = 0;
411
412         dev_info(&pdev->dev,
413                 "%s: SEC Charger Driver Loading\n", __func__);
414
415         charger = kzalloc(sizeof(*charger), GFP_KERNEL);
416         if (!charger)
417                 return -ENOMEM;
418
419         platform_set_drvdata(pdev, charger);
420
421         charger->client = mfd_dev->i2c;
422         charger->pdata = pdata->charger_data;
423
424         charger->psy_chg.name           = "sec-charger";
425         charger->psy_chg.type           = POWER_SUPPLY_TYPE_UNKNOWN;
426         charger->psy_chg.get_property   = sec_chg_get_property;
427         charger->psy_chg.set_property   = sec_chg_set_property;
428         charger->psy_chg.properties     = sec_charger_props;
429         charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props);
430
431         if (charger->pdata->chg_gpio_init) {
432                 if (!charger->pdata->chg_gpio_init()) {
433                         dev_err(&pdev->dev,
434                                 "%s: Failed to Initialize GPIO\n", __func__);
435                         goto err_free;
436                 }
437         }
438
439         if (!sec_hal_chg_init(charger)) {
440                 dev_err(&pdev->dev,
441                         "%s: Failed to Initialize Charger\n", __func__);
442                 goto err_free;
443         }
444
445         ret = power_supply_register(&pdev->dev, &charger->psy_chg);
446         if (ret) {
447                 dev_err(&pdev->dev,
448                         "%s: Failed to Register psy_chg\n", __func__);
449                 goto err_free;
450         }
451
452         if (charger->pdata->chg_irq) {
453                 INIT_DELAYED_WORK_DEFERRABLE(
454                         &charger->isr_work, sec_chg_isr_work);
455
456                 ret = request_threaded_irq(charger->pdata->chg_irq,
457                                 NULL, sec_chg_irq_thread,
458                                 charger->pdata->chg_irq_attr,
459                                 "charger-irq", charger);
460                 if (ret) {
461                         dev_err(&pdev->dev,
462                                 "%s: Failed to Reqeust IRQ\n", __func__);
463                         goto err_supply_unreg;
464                 }
465
466                         ret = enable_irq_wake(charger->pdata->chg_irq);
467                         if (ret < 0)
468                                 dev_err(&pdev->dev,
469                                         "%s: Failed to Enable Wakeup Source(%d)\n",
470                                         __func__, ret);
471                 }
472
473         ret = sec_chg_create_attrs(charger->psy_chg.dev);
474         if (ret) {
475                 dev_err(&pdev->dev,
476                         "%s : Failed to create_attrs\n", __func__);
477                 goto err_req_irq;
478         }
479
480         dev_info(&pdev->dev,
481                 "%s: SEC Charger Driver Loaded\n", __func__);
482         return 0;
483
484 err_req_irq:
485         if (charger->pdata->chg_irq)
486                 free_irq(charger->pdata->chg_irq, charger);
487 err_supply_unreg:
488         power_supply_unregister(&charger->psy_chg);
489 err_free:
490         kfree(charger);
491
492         return ret;
493 }
494
495 static int sec_charger_remove(struct platform_device *pdev)
496 {
497         return 0;
498 }
499
500 static int sec_charger_suspend(struct device *dev)
501 {
502         struct sec_charger_info *charger = dev_get_drvdata(dev);
503
504         if (!sec_hal_chg_suspend(charger))
505                 dev_err(dev, "%s: Failed to Suspend Charger\n", __func__);
506
507         return 0;
508 }
509
510 static int sec_charger_resume(struct device *dev)
511 {
512         struct sec_charger_info *charger = dev_get_drvdata(dev);
513
514         if (!sec_hal_chg_resume(charger))
515                 dev_err(dev, "%s: Failed to Resume Charger\n", __func__);
516
517         return 0;
518 }
519
520 static void sec_charger_shutdown(struct device *dev)
521 {
522         if (!sec_hal_chg_shutdown(client))
523                 dev_err(&client->dev,
524                         "%s: Failed to Shutdown Charger\n", __func__);
525 }
526
527 static const struct dev_pm_ops sec_charger_pm_ops = {
528         .suspend = sec_charger_suspend,
529         .resume = sec_charger_resume,
530 };
531
532 static struct platform_driver sec_charger_driver = {
533         .driver = {
534                    .name = "sec-charger",
535                    .owner = THIS_MODULE,
536                    .pm = &sec_charger_pm_ops,
537                    .shutdown = sec_charger_shutdown,
538                    },
539         .probe = sec_charger_probe,
540         .remove = sec_charger_remove,
541 };
542
543 static int __init sec_charger_init(void)
544 {
545         pr_info("[%s]!!!!!!!! \n", __func__);
546         return platform_driver_register(&sec_charger_driver);
547 }
548
549 static void __exit sec_charger_exit(void)
550 {
551         platform_driver_unregister(&sec_charger_driver);
552 }
553
554 #else
555
556 static struct of_device_id sec_charger_dt_ids[] = {
557         { .compatible = "samsung,sec-charger", },
558         {}
559 };
560 MODULE_DEVICE_TABLE(of, sec_charger_dt_ids);
561
562 static int sec_charger_probe(struct i2c_client *client,
563                                                 const struct i2c_device_id *id)
564 {
565         sec_battery_platform_data_t *pdata = client->dev.platform_data;
566         struct sec_charger_info *charger;
567         struct i2c_adapter *adapter =
568                 to_i2c_adapter(client->dev.parent);
569         int ret = 0;
570         struct device_node *np = client->dev.of_node;
571
572         dev_info(&client->dev,
573                 "%s: SEC Charger Driver Loading\n", __func__);
574
575
576         if (IS_ENABLED(CONFIG_OF)) {
577                 if (!pdata)
578                         pdata = kzalloc(sizeof(sec_battery_platform_data_t),
579                                                                 GFP_KERNEL);
580                 if (!pdata)
581                         return -ENOMEM;
582
583                 ret = sec_chg_dt_init(np, &client->dev, pdata);
584                 if (ret)
585                         return ret;
586         } else if (!pdata) {
587                 dev_err(&client->dev, "%s: no platform data defined\n",
588                         __func__);
589                 return -EINVAL;
590         }
591
592
593         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
594                 return -EIO;
595
596         charger = kzalloc(sizeof(*charger), GFP_KERNEL);
597         if (!charger)
598                 return -ENOMEM;
599
600         charger->client = client;
601         charger->pdata = pdata;
602
603         i2c_set_clientdata(client, charger);
604
605         charger->psy_chg.name           = "sec-charger";
606         charger->psy_chg.type           = POWER_SUPPLY_TYPE_UNKNOWN;
607         charger->psy_chg.get_property   = sec_chg_get_property;
608         charger->psy_chg.set_property   = sec_chg_set_property;
609         charger->psy_chg.properties     = sec_charger_props;
610         charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props);
611
612         if (charger->pdata->chg_gpio_init) {
613                 if (!charger->pdata->chg_gpio_init()) {
614                         dev_err(&client->dev,
615                         "%s: Failed to Initialize GPIO\n", __func__);
616                         goto err_free;
617                 }
618         }
619
620         if (!sec_hal_chg_init(client)) {
621                 dev_err(&client->dev,
622                         "%s: Failed to Initialize Charger\n", __func__);
623                 goto err_free;
624         }
625
626         ret = power_supply_register(&client->dev, &charger->psy_chg);
627         if (ret) {
628                 dev_err(&client->dev,
629                         "%s: Failed to Register psy_chg\n", __func__);
630                 goto err_free;
631         }
632
633         if (charger->pdata->chg_irq) {
634                 INIT_DEFERRABLE_WORK(
635                         &charger->isr_work, sec_chg_isr_work);
636
637                 ret = request_threaded_irq(charger->pdata->chg_irq,
638                                 NULL, sec_chg_irq_thread,
639                                 charger->pdata->chg_irq_attr | IRQF_ONESHOT,
640                                 "charger-irq", charger);
641                 if (ret) {
642                         dev_err(&client->dev,
643                                 "%s: Failed to Reqeust IRQ\n", __func__);
644                         goto err_supply_unreg;
645                 }
646
647                 ret = enable_irq_wake(charger->pdata->chg_irq);
648                 if (ret < 0)
649                         dev_err(&client->dev,
650                                 "%s: Failed to Enable Wakeup Source(%d)\n",
651                                 __func__, ret);
652         }
653
654         ret = sec_chg_create_attrs(charger->psy_chg.dev);
655         if (ret) {
656                 dev_err(&client->dev,
657                         "%s : Failed to create_attrs\n", __func__);
658                 goto err_req_irq;
659         }
660
661         dev_dbg(&client->dev,
662                 "%s: SEC Charger Driver Loaded\n", __func__);
663         return 0;
664
665 err_req_irq:
666         if (charger->pdata->chg_irq)
667                 free_irq(charger->pdata->chg_irq, charger);
668 err_supply_unreg:
669         power_supply_unregister(&charger->psy_chg);
670 err_free:
671         kfree(charger);
672         kfree(pdata);
673
674         return ret;
675 }
676
677 static int sec_charger_remove(
678                                                 struct i2c_client *client)
679 {
680         return 0;
681 }
682
683 static int sec_charger_suspend(struct i2c_client *client,
684                                 pm_message_t state)
685 {
686         if (!sec_hal_chg_suspend(client))
687                 dev_err(&client->dev,
688                         "%s: Failed to Suspend Charger\n", __func__);
689
690         return 0;
691 }
692
693 static int sec_charger_resume(struct i2c_client *client)
694 {
695         if (!sec_hal_chg_resume(client))
696                 dev_err(&client->dev,
697                         "%s: Failed to Resume Charger\n", __func__);
698
699         return 0;
700 }
701
702 static void sec_charger_shutdown(struct i2c_client *client)
703 {
704         if (!sec_hal_chg_shutdown(client))
705                 dev_err(&client->dev,
706                         "%s: Failed to Shutdown Charger\n", __func__);
707 }
708
709 static const struct i2c_device_id sec_charger_id[] = {
710         {"sec-charger", 0},
711         {}
712 };
713
714 MODULE_DEVICE_TABLE(i2c, sec_charger_id);
715
716 static struct i2c_driver sec_charger_driver = {
717         .driver = {
718                 .name   = "sec-charger",
719                 .of_match_table = sec_charger_dt_ids,
720         },
721         .probe  = sec_charger_probe,
722         .remove = sec_charger_remove,
723         .suspend        = sec_charger_suspend,
724         .resume         = sec_charger_resume,
725         .shutdown       = sec_charger_shutdown,
726         .id_table       = sec_charger_id,
727 };
728
729 static int __init sec_charger_init(void)
730 {
731         return i2c_add_driver(&sec_charger_driver);
732 }
733
734 static void __exit sec_charger_exit(void)
735 {
736         i2c_del_driver(&sec_charger_driver);
737 }
738 #endif
739
740 module_init(sec_charger_init);
741 module_exit(sec_charger_exit);
742
743 MODULE_DESCRIPTION("Samsung Charger Driver");
744 MODULE_AUTHOR("Samsung Electronics");
745 MODULE_LICENSE("GPL");