3 * Samsung Mobile Charger Driver
5 * Copyright (C) 2012 Samsung Electronics
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.
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>
21 extern int sec_chg_dt_init(struct device_node *np,
23 sec_battery_platform_data_t *pdata);
25 static struct device_attribute sec_charger_attrs[] = {
26 SEC_CHARGER_ATTR(reg),
27 SEC_CHARGER_ATTR(data),
28 SEC_CHARGER_ATTR(regs),
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,
48 static int input_current[] = {
54 static int sec_chg_get_property(struct power_supply *psy,
55 enum power_supply_property psp,
56 union power_supply_propval *val)
58 struct sec_charger_info *charger =
59 container_of(psy, struct sec_charger_info, psy_chg);
62 case POWER_SUPPLY_PROP_CURRENT_MAX: /* input current limit set */
63 val->intval = charger->charging_current_max;
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:
79 if (!sec_hal_chg_get_property(charger_variable, psp, val))
82 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
83 val->intval = charger->charging_current * val->intval / 100;
85 case POWER_SUPPLY_PROP_PRESENT:
86 if (!sec_hal_chg_get_property(charger_variable, psp, val))
95 static int sec_chg_set_property(struct power_supply *psy,
96 enum power_supply_property psp,
97 const union power_supply_propval *val)
99 struct sec_charger_info *charger =
100 container_of(psy, struct sec_charger_info, psy_chg);
101 union power_supply_propval input_value;
104 case POWER_SUPPLY_PROP_STATUS:
105 charger->status = val->intval;
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;
114 charger->is_charging = true;
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];
123 charger->charging_current_max =
124 charger->pdata->charging_current[
125 val->intval].input_current_limit;
128 charger->charging_current =
129 charger->pdata->charging_current[
130 val->intval].fast_charging_current;
132 if (!sec_hal_chg_set_property(charger_variable, psp, val))
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
143 case POWER_SUPPLY_PROP_CURRENT_NOW:
144 if (!sec_hal_chg_set_property(charger_variable, psp, val))
148 /* val->intval : charging current */
149 case POWER_SUPPLY_PROP_CURRENT_AVG:
150 charger->charging_current = val->intval;
152 if (!sec_hal_chg_set_property(charger_variable, psp, val))
156 /* val->intval : SIOP level (%)
157 * SIOP charging current setting
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
163 #ifdef CONFIG_CHARGER_SM5414
164 if (!sec_hal_chg_set_property(charger_variable, psp, val))
168 charger->charging_current * val->intval / 100;
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 &&
175 charger->pdata->charging_current[
176 POWER_SUPPLY_TYPE_USB].fast_charging_current)
178 charger->pdata->charging_current[
179 POWER_SUPPLY_TYPE_USB].fast_charging_current;
182 /* set charging current as new value */
183 if (!sec_hal_chg_set_property(charger_variable,
184 POWER_SUPPLY_PROP_CURRENT_AVG, &input_value))
188 #ifdef CONFIG_CHARGER_SM5414
189 case POWER_SUPPLY_PROP_HEALTH:
190 if (!sec_hal_chg_set_property(charger_variable, psp, val))
201 static void sec_chg_isr_work(struct work_struct *work)
203 struct sec_charger_info *charger =
204 container_of(work, struct sec_charger_info, isr_work.work);
205 union power_supply_propval val;
208 dev_info(&charger->client->dev,
209 "%s: Charger Interrupt\n", __func__);
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;
216 full_check_type = charger->pdata->full_check_type_2nd;
218 if (full_check_type == SEC_BATTERY_FULLCHARGED_CHGINT) {
219 if (!sec_hal_chg_get_property(charger_variable,
220 POWER_SUPPLY_PROP_STATUS, &val))
223 switch (val.intval) {
224 case POWER_SUPPLY_STATUS_DISCHARGING:
225 dev_err(&charger->client->dev,
226 "%s: Interrupted but Discharging\n", __func__);
229 case POWER_SUPPLY_STATUS_NOT_CHARGING:
230 dev_err(&charger->client->dev,
231 "%s: Interrupted but NOT Charging\n", __func__);
234 case POWER_SUPPLY_STATUS_FULL:
235 dev_info(&charger->client->dev,
236 "%s: Interrupted by Full\n", __func__);
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__);
246 psy_do_property("battery", set,
247 POWER_SUPPLY_PROP_STATUS, val);
250 case POWER_SUPPLY_STATUS_CHARGING:
251 dev_err(&charger->client->dev,
252 "%s: Interrupted but Charging\n", __func__);
255 case POWER_SUPPLY_STATUS_UNKNOWN:
257 dev_err(&charger->client->dev,
258 "%s: Invalid Charger Status\n", __func__);
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))
271 #if defined(CONFIG_CHARGER_SM5414)
273 val.intval = sec_get_charging_health(charger->client);
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__);
283 case POWER_SUPPLY_HEALTH_DEAD:
284 dev_err(&charger->client->dev,
285 "%s: Interrupted but Dead\n", __func__);
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);
296 case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
297 dev_err(&charger->client->dev,
298 "%s: Interrupted but Unspec\n", __func__);
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);
308 case POWER_SUPPLY_HEALTH_UNKNOWN:
310 dev_err(&charger->client->dev,
311 "%s: Invalid Charger Health\n", __func__);
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))
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
325 if (get_power_supply_by_name("battery")) {
326 psy_do_property("battery", set,
327 POWER_SUPPLY_PROP_ONLINE, val);
329 charger->pdata->check_cable_result_callback(val.intval);
333 static irqreturn_t sec_chg_irq_thread(int irq, void *irq_data)
335 struct sec_charger_info *charger = irq_data;
336 #if defined(CONFIG_CHARGER_BQ24157)
337 schedule_delayed_work(&charger->isr_work, HZ * 0.5);
339 schedule_delayed_work(&charger->isr_work, 0);
345 static int sec_chg_create_attrs(struct device *dev)
349 for (i = 0; i < ARRAY_SIZE(sec_charger_attrs); i++) {
350 rc = device_create_file(dev, &sec_charger_attrs[i]);
352 goto create_attrs_failed;
354 goto create_attrs_succeed;
357 dev_err(dev, "%s: failed (%d)\n", __func__, rc);
359 device_remove_file(dev, &sec_charger_attrs[i]);
360 create_attrs_succeed:
364 ssize_t sec_chg_show_attrs(struct device *dev,
365 struct device_attribute *attr, char *buf)
367 const ptrdiff_t offset = attr - sec_charger_attrs;
374 i = sec_hal_chg_show_attrs(dev, offset, buf);
384 ssize_t sec_chg_store_attrs(struct device *dev,
385 struct device_attribute *attr,
386 const char *buf, size_t count)
388 const ptrdiff_t offset = attr - sec_charger_attrs;
394 ret = sec_hal_chg_store_attrs(dev, offset, buf, count);
404 #if defined(CONFIG_CHARGER_MFD)
405 static int sec_charger_probe(struct platform_device *pdev)
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);
413 "%s: SEC Charger Driver Loading\n", __func__);
415 charger = kzalloc(sizeof(*charger), GFP_KERNEL);
419 platform_set_drvdata(pdev, charger);
421 charger->client = mfd_dev->i2c;
422 charger->pdata = pdata->charger_data;
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);
431 if (charger->pdata->chg_gpio_init) {
432 if (!charger->pdata->chg_gpio_init()) {
434 "%s: Failed to Initialize GPIO\n", __func__);
439 if (!sec_hal_chg_init(charger)) {
441 "%s: Failed to Initialize Charger\n", __func__);
445 ret = power_supply_register(&pdev->dev, &charger->psy_chg);
448 "%s: Failed to Register psy_chg\n", __func__);
452 if (charger->pdata->chg_irq) {
453 INIT_DELAYED_WORK_DEFERRABLE(
454 &charger->isr_work, sec_chg_isr_work);
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);
462 "%s: Failed to Reqeust IRQ\n", __func__);
463 goto err_supply_unreg;
466 ret = enable_irq_wake(charger->pdata->chg_irq);
469 "%s: Failed to Enable Wakeup Source(%d)\n",
473 ret = sec_chg_create_attrs(charger->psy_chg.dev);
476 "%s : Failed to create_attrs\n", __func__);
481 "%s: SEC Charger Driver Loaded\n", __func__);
485 if (charger->pdata->chg_irq)
486 free_irq(charger->pdata->chg_irq, charger);
488 power_supply_unregister(&charger->psy_chg);
495 static int sec_charger_remove(struct platform_device *pdev)
500 static int sec_charger_suspend(struct device *dev)
502 struct sec_charger_info *charger = dev_get_drvdata(dev);
504 if (!sec_hal_chg_suspend(charger))
505 dev_err(dev, "%s: Failed to Suspend Charger\n", __func__);
510 static int sec_charger_resume(struct device *dev)
512 struct sec_charger_info *charger = dev_get_drvdata(dev);
514 if (!sec_hal_chg_resume(charger))
515 dev_err(dev, "%s: Failed to Resume Charger\n", __func__);
520 static void sec_charger_shutdown(struct device *dev)
522 if (!sec_hal_chg_shutdown(client))
523 dev_err(&client->dev,
524 "%s: Failed to Shutdown Charger\n", __func__);
527 static const struct dev_pm_ops sec_charger_pm_ops = {
528 .suspend = sec_charger_suspend,
529 .resume = sec_charger_resume,
532 static struct platform_driver sec_charger_driver = {
534 .name = "sec-charger",
535 .owner = THIS_MODULE,
536 .pm = &sec_charger_pm_ops,
537 .shutdown = sec_charger_shutdown,
539 .probe = sec_charger_probe,
540 .remove = sec_charger_remove,
543 static int __init sec_charger_init(void)
545 pr_info("[%s]!!!!!!!! \n", __func__);
546 return platform_driver_register(&sec_charger_driver);
549 static void __exit sec_charger_exit(void)
551 platform_driver_unregister(&sec_charger_driver);
556 static struct of_device_id sec_charger_dt_ids[] = {
557 { .compatible = "samsung,sec-charger", },
560 MODULE_DEVICE_TABLE(of, sec_charger_dt_ids);
562 static int sec_charger_probe(struct i2c_client *client,
563 const struct i2c_device_id *id)
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);
570 struct device_node *np = client->dev.of_node;
572 dev_info(&client->dev,
573 "%s: SEC Charger Driver Loading\n", __func__);
576 if (IS_ENABLED(CONFIG_OF)) {
578 pdata = kzalloc(sizeof(sec_battery_platform_data_t),
583 ret = sec_chg_dt_init(np, &client->dev, pdata);
587 dev_err(&client->dev, "%s: no platform data defined\n",
593 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
596 charger = kzalloc(sizeof(*charger), GFP_KERNEL);
600 charger->client = client;
601 charger->pdata = pdata;
603 i2c_set_clientdata(client, charger);
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);
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__);
620 if (!sec_hal_chg_init(client)) {
621 dev_err(&client->dev,
622 "%s: Failed to Initialize Charger\n", __func__);
626 ret = power_supply_register(&client->dev, &charger->psy_chg);
628 dev_err(&client->dev,
629 "%s: Failed to Register psy_chg\n", __func__);
633 if (charger->pdata->chg_irq) {
634 INIT_DEFERRABLE_WORK(
635 &charger->isr_work, sec_chg_isr_work);
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);
642 dev_err(&client->dev,
643 "%s: Failed to Reqeust IRQ\n", __func__);
644 goto err_supply_unreg;
647 ret = enable_irq_wake(charger->pdata->chg_irq);
649 dev_err(&client->dev,
650 "%s: Failed to Enable Wakeup Source(%d)\n",
654 ret = sec_chg_create_attrs(charger->psy_chg.dev);
656 dev_err(&client->dev,
657 "%s : Failed to create_attrs\n", __func__);
661 dev_dbg(&client->dev,
662 "%s: SEC Charger Driver Loaded\n", __func__);
666 if (charger->pdata->chg_irq)
667 free_irq(charger->pdata->chg_irq, charger);
669 power_supply_unregister(&charger->psy_chg);
677 static int sec_charger_remove(
678 struct i2c_client *client)
683 static int sec_charger_suspend(struct i2c_client *client,
686 if (!sec_hal_chg_suspend(client))
687 dev_err(&client->dev,
688 "%s: Failed to Suspend Charger\n", __func__);
693 static int sec_charger_resume(struct i2c_client *client)
695 if (!sec_hal_chg_resume(client))
696 dev_err(&client->dev,
697 "%s: Failed to Resume Charger\n", __func__);
702 static void sec_charger_shutdown(struct i2c_client *client)
704 if (!sec_hal_chg_shutdown(client))
705 dev_err(&client->dev,
706 "%s: Failed to Shutdown Charger\n", __func__);
709 static const struct i2c_device_id sec_charger_id[] = {
714 MODULE_DEVICE_TABLE(i2c, sec_charger_id);
716 static struct i2c_driver sec_charger_driver = {
718 .name = "sec-charger",
719 .of_match_table = sec_charger_dt_ids,
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,
729 static int __init sec_charger_init(void)
731 return i2c_add_driver(&sec_charger_driver);
734 static void __exit sec_charger_exit(void)
736 i2c_del_driver(&sec_charger_driver);
740 module_init(sec_charger_init);
741 module_exit(sec_charger_exit);
743 MODULE_DESCRIPTION("Samsung Charger Driver");
744 MODULE_AUTHOR("Samsung Electronics");
745 MODULE_LICENSE("GPL");