Lines Matching +full:gpio +full:- +full:charger

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Motorola CPCAP PMIC battery charger driver
10 * Copyright (C) 2009-2010 Motorola, Inc.
25 #include <linux/gpio/consumer.h>
30 #include <linux/mfd/motorola-cpcap.h>
37 * similar. Also see the Motorola Linux kernel cpcap-regbits.h. CPCAP_REG_CHRGR_1
42 #define CPCAP_REG_CRM_CHRG_LED_EN BIT(13) /* Charger LED */
89 * values in "Table 8-3. Charge Path Regulator Current Limit
130 struct gpio_desc *gpio[2]; /* gpio_reven0 & 1 */ member
180 channel = ddata->channels[CPCAP_CHARGER_IIO_VOLTAGE]; in cpcap_charger_get_charge_voltage()
183 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_charger_get_charge_voltage()
196 channel = ddata->channels[CPCAP_CHARGER_IIO_CHRG_CURRENT]; in cpcap_charger_get_charge_current()
199 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_charger_get_charge_current()
211 struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent); in cpcap_charger_get_property()
215 val->intval = ddata->status; in cpcap_charger_get_property()
218 val->intval = ddata->limit_current; in cpcap_charger_get_property()
221 val->intval = ddata->voltage; in cpcap_charger_get_property()
224 if (ddata->status == POWER_SUPPLY_STATUS_CHARGING) in cpcap_charger_get_property()
225 val->intval = cpcap_charger_get_charge_voltage(ddata) * in cpcap_charger_get_property()
228 val->intval = 0; in cpcap_charger_get_property()
231 if (ddata->status == POWER_SUPPLY_STATUS_CHARGING) in cpcap_charger_get_property()
232 val->intval = cpcap_charger_get_charge_current(ddata) * in cpcap_charger_get_property()
235 val->intval = 0; in cpcap_charger_get_property()
238 val->intval = ddata->status == POWER_SUPPLY_STATUS_CHARGING; in cpcap_charger_get_property()
241 return -EINVAL; in cpcap_charger_get_property()
250 case 0 ... 4100000 - 1: return 3800000; in cpcap_charger_match_voltage()
251 case 4100000 ... 4120000 - 1: return 4100000; in cpcap_charger_match_voltage()
252 case 4120000 ... 4150000 - 1: return 4120000; in cpcap_charger_match_voltage()
253 case 4150000 ... 4170000 - 1: return 4150000; in cpcap_charger_match_voltage()
254 case 4170000 ... 4200000 - 1: return 4170000; in cpcap_charger_match_voltage()
255 case 4200000 ... 4230000 - 1: return 4200000; in cpcap_charger_match_voltage()
256 case 4230000 ... 4250000 - 1: return 4230000; in cpcap_charger_match_voltage()
257 case 4250000 ... 4270000 - 1: return 4250000; in cpcap_charger_match_voltage()
258 case 4270000 ... 4300000 - 1: return 4270000; in cpcap_charger_match_voltage()
259 case 4300000 ... 4330000 - 1: return 4300000; in cpcap_charger_match_voltage()
260 case 4330000 ... 4350000 - 1: return 4330000; in cpcap_charger_match_voltage()
261 case 4350000 ... 4380000 - 1: return 4350000; in cpcap_charger_match_voltage()
262 case 4380000 ... 4400000 - 1: return 4380000; in cpcap_charger_match_voltage()
263 case 4400000 ... 4420000 - 1: return 4400000; in cpcap_charger_match_voltage()
264 case 4420000 ... 4440000 - 1: return 4420000; in cpcap_charger_match_voltage()
275 int voltage = ddata->voltage; in cpcap_charger_get_bat_const_charge_voltage()
298 return -EINVAL; in cpcap_charger_current_to_regval()
316 struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent); in cpcap_charger_set_property()
321 if (cpcap_charger_current_to_regval(val->intval) < 0) in cpcap_charger_set_property()
322 return -EINVAL; in cpcap_charger_set_property()
323 ddata->limit_current = val->intval; in cpcap_charger_set_property()
324 schedule_delayed_work(&ddata->detect_work, 0); in cpcap_charger_set_property()
327 voltage = cpcap_charger_match_voltage(val->intval); in cpcap_charger_set_property()
331 ddata->voltage = voltage; in cpcap_charger_set_property()
332 schedule_delayed_work(&ddata->detect_work, 0); in cpcap_charger_set_property()
335 return -EINVAL; in cpcap_charger_set_property()
356 if (!ddata->gpio[0]) in cpcap_charger_set_cable_path()
359 gpiod_set_value(ddata->gpio[0], enabled); in cpcap_charger_set_cable_path()
365 if (!ddata->gpio[1]) in cpcap_charger_set_inductive_path()
368 gpiod_set_value(ddata->gpio[1], enabled); in cpcap_charger_set_inductive_path()
377 dev_warn(ddata->dev, "unknown state: %i\n", state); in cpcap_charger_update_state()
382 ddata->status = state; in cpcap_charger_update_state()
401 dev_dbg(ddata->dev, "state: %s\n", status); in cpcap_charger_update_state()
408 error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff, in cpcap_charger_disable()
412 dev_err(ddata->dev, "%s failed with %i\n", __func__, error); in cpcap_charger_disable()
424 return -EINVAL; in cpcap_charger_enable()
426 dev_dbg(ddata->dev, "enable: %i %i %i\n", in cpcap_charger_enable()
429 error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, 0x3fff, in cpcap_charger_enable()
437 dev_err(ddata->dev, "%s failed with %i\n", __func__, error); in cpcap_charger_enable()
446 ddata->channels[CPCAP_CHARGER_IIO_VBUS]; in cpcap_charger_vbus_valid()
452 dev_err(ddata->dev, "error reading VBUS: %i\n", error); in cpcap_charger_vbus_valid()
467 if (ddata->vbus_enabled) { in cpcap_charger_vbus_work()
470 dev_dbg(ddata->dev, "VBUS already provided\n"); in cpcap_charger_vbus_work()
475 ddata->feeding_vbus = true; in cpcap_charger_vbus_work()
486 error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC, in cpcap_charger_vbus_work()
492 error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, in cpcap_charger_vbus_work()
498 error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC, in cpcap_charger_vbus_work()
503 error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, in cpcap_charger_vbus_work()
510 ddata->feeding_vbus = false; in cpcap_charger_vbus_work()
517 dev_err(ddata->dev, "%s could not %s vbus: %i\n", __func__, in cpcap_charger_vbus_work()
518 ddata->vbus_enabled ? "enable" : "disable", error); in cpcap_charger_vbus_work()
528 ddata->vbus_enabled = enabled; in cpcap_charger_set_vbus()
529 schedule_delayed_work(&ddata->vbus_work, 0); in cpcap_charger_set_vbus()
534 /* Charger interrupt handling functions */
541 error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val); in cpcap_charger_get_ints_state()
545 s->chrg_det = val & BIT(13); in cpcap_charger_get_ints_state()
546 s->rvrs_chrg = val & BIT(12); in cpcap_charger_get_ints_state()
547 s->vbusov = val & BIT(11); in cpcap_charger_get_ints_state()
549 error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val); in cpcap_charger_get_ints_state()
553 s->chrg_se1b = val & BIT(13); in cpcap_charger_get_ints_state()
554 s->rvrs_mode = val & BIT(6); in cpcap_charger_get_ints_state()
555 s->chrgcurr2 = val & BIT(5); in cpcap_charger_get_ints_state()
556 s->chrgcurr1 = val & BIT(4); in cpcap_charger_get_ints_state()
557 s->vbusvld = val & BIT(3); in cpcap_charger_get_ints_state()
559 error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val); in cpcap_charger_get_ints_state()
563 s->battdetb = val & BIT(6); in cpcap_charger_get_ints_state()
573 case 0 ... 4100000 - 1: in cpcap_charger_voltage_to_regval()
575 case 4100000 ... 4200000 - 1: in cpcap_charger_voltage_to_regval()
578 case 4200000 ... 4300000 - 1: in cpcap_charger_voltage_to_regval()
581 case 4300000 ... 4380000 - 1: in cpcap_charger_voltage_to_regval()
582 offset = -1; in cpcap_charger_voltage_to_regval()
585 offset = -2; in cpcap_charger_voltage_to_regval()
591 return ((voltage - 4100000) / 20000) + offset; in cpcap_charger_voltage_to_regval()
599 /* Update battery state before disconnecting the charger */ in cpcap_charger_disconnect()
603 power_supply_changed(ddata->usb); in cpcap_charger_disconnect()
616 power_supply_changed(ddata->usb); in cpcap_charger_disconnect()
617 schedule_delayed_work(&ddata->detect_work, delay); in cpcap_charger_disconnect()
633 /* Just init the state if a charger is connected with no chrg_det set */ in cpcap_usb_detect()
645 if (cpcap_charger_get_charge_voltage(ddata) > ddata->voltage) { in cpcap_usb_detect()
656 /* Throttle chrgcurr2 interrupt for charger done and retry */ in cpcap_usb_detect()
657 switch (ddata->status) { in cpcap_usb_detect()
683 if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) && in cpcap_usb_detect()
692 dev_err(ddata->dev, "battery power_supply not available %li\n", in cpcap_usb_detect()
705 dev_info(ddata->dev, "battery not inserted, charging disabled\n"); in cpcap_usb_detect()
709 if (max_current > ddata->limit_current) in cpcap_usb_detect()
710 max_current = ddata->limit_current; in cpcap_usb_detect()
713 vchrg = cpcap_charger_voltage_to_regval(ddata->voltage); in cpcap_usb_detect()
729 power_supply_changed(ddata->usb); in cpcap_usb_detect()
734 dev_err(ddata->dev, "%s failed with %i\n", __func__, error); in cpcap_usb_detect()
741 if (!atomic_read(&ddata->active)) in cpcap_charger_irq_thread()
744 schedule_delayed_work(&ddata->detect_work, 0); in cpcap_charger_irq_thread()
758 return -ENODEV; in cpcap_usb_init_irq()
760 error = devm_request_threaded_irq(ddata->dev, irq, NULL, in cpcap_usb_init_irq()
765 dev_err(ddata->dev, "could not get irq %s: %i\n", in cpcap_usb_init_irq()
771 d = devm_kzalloc(ddata->dev, sizeof(*d), GFP_KERNEL); in cpcap_usb_init_irq()
773 return -ENOMEM; in cpcap_usb_init_irq()
775 d->name = name; in cpcap_usb_init_irq()
776 d->irq = irq; in cpcap_usb_init_irq()
777 list_add(&d->node, &ddata->irq_list); in cpcap_usb_init_irq()
812 ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode", in cpcap_charger_init_optional_gpios()
814 if (IS_ERR(ddata->gpio[i])) { in cpcap_charger_init_optional_gpios()
815 dev_info(ddata->dev, "no mode change GPIO%i: %li\n", in cpcap_charger_init_optional_gpios()
816 i, PTR_ERR(ddata->gpio[i])); in cpcap_charger_init_optional_gpios()
817 ddata->gpio[i] = NULL; in cpcap_charger_init_optional_gpios()
830 ddata->channels[i] = devm_iio_channel_get(ddata->dev, in cpcap_charger_init_iio()
832 if (IS_ERR(ddata->channels[i])) { in cpcap_charger_init_iio()
833 error = PTR_ERR(ddata->channels[i]); in cpcap_charger_init_iio()
837 if (!ddata->channels[i]->indio_dev) { in cpcap_charger_init_iio()
838 error = -ENXIO; in cpcap_charger_init_iio()
846 if (error != -EPROBE_DEFER) in cpcap_charger_init_iio()
847 dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", in cpcap_charger_init_iio()
869 .compatible = "motorola,mapphone-cpcap-charger",
881 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); in cpcap_charger_probe()
883 return -ENOMEM; in cpcap_charger_probe()
885 ddata->dev = &pdev->dev; in cpcap_charger_probe()
886 ddata->voltage = 4200000; in cpcap_charger_probe()
887 ddata->limit_current = 532000; in cpcap_charger_probe()
889 ddata->reg = dev_get_regmap(ddata->dev->parent, NULL); in cpcap_charger_probe()
890 if (!ddata->reg) in cpcap_charger_probe()
891 return -ENODEV; in cpcap_charger_probe()
893 INIT_LIST_HEAD(&ddata->irq_list); in cpcap_charger_probe()
894 INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect); in cpcap_charger_probe()
895 INIT_DELAYED_WORK(&ddata->vbus_work, cpcap_charger_vbus_work); in cpcap_charger_probe()
902 atomic_set(&ddata->active, 1); in cpcap_charger_probe()
904 psy_cfg.of_node = pdev->dev.of_node; in cpcap_charger_probe()
909 ddata->usb = devm_power_supply_register(ddata->dev, in cpcap_charger_probe()
912 if (IS_ERR(ddata->usb)) { in cpcap_charger_probe()
913 error = PTR_ERR(ddata->usb); in cpcap_charger_probe()
914 dev_err(ddata->dev, "failed to register USB charger: %i\n", in cpcap_charger_probe()
924 ddata->comparator.set_vbus = cpcap_charger_set_vbus; in cpcap_charger_probe()
925 error = omap_usb2_set_comparator(&ddata->comparator); in cpcap_charger_probe()
926 if (error == -ENODEV) { in cpcap_charger_probe()
927 dev_info(ddata->dev, "charger needs phy, deferring probe\n"); in cpcap_charger_probe()
928 return -EPROBE_DEFER; in cpcap_charger_probe()
933 schedule_delayed_work(&ddata->detect_work, 0); in cpcap_charger_probe()
943 atomic_set(&ddata->active, 0); in cpcap_charger_shutdown()
946 dev_warn(ddata->dev, "could not clear USB comparator: %i\n", in cpcap_charger_shutdown()
952 dev_warn(ddata->dev, "could not clear charger: %i\n", in cpcap_charger_shutdown()
956 cancel_delayed_work_sync(&ddata->vbus_work); in cpcap_charger_shutdown()
957 cancel_delayed_work_sync(&ddata->detect_work); in cpcap_charger_shutdown()
968 .name = "cpcap-charger",
977 MODULE_DESCRIPTION("CPCAP Battery Charger Interface driver");
979 MODULE_ALIAS("platform:cpcap-charger");