Lines Matching +full:usb +full:- +full:current +full:- +full:limit +full:- +full:microamp

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * AXP20x PMIC USB power supply status driver
6 * Copyright (C) 2014 Bruno Prémont <bonbons@linux-vserver.org>
11 #include <linux/devm-helpers.h>
26 #define DRVNAME "axp20x-usb-power-supply"
105 * present->absent transition implies an online->offline transition in axp20x_usb_vbus_needs_polling()
108 if (power->axp_data->vbus_needs_polling && !power->online) in axp20x_usb_vbus_needs_polling()
118 power_supply_changed(power->supply); in axp20x_usb_power_irq()
120 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_irq()
132 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp20x_usb_power_poll_vbus()
137 if (val != power->old_status) in axp20x_usb_power_poll_vbus()
138 power_supply_changed(power->supply); in axp20x_usb_power_poll_vbus()
140 if (power->usb_bc_en_bit && (val & AXP20X_PWR_STATUS_VBUS_PRESENT) != in axp20x_usb_power_poll_vbus()
141 (power->old_status & AXP20X_PWR_STATUS_VBUS_PRESENT)) { in axp20x_usb_power_poll_vbus()
142 dev_dbg(power->dev, "Cable status changed, re-enabling USB BC"); in axp20x_usb_power_poll_vbus()
143 ret = regmap_field_write(power->usb_bc_en_bit, 1); in axp20x_usb_power_poll_vbus()
145 dev_err(power->dev, "failed to enable USB BC: errno %d", in axp20x_usb_power_poll_vbus()
149 power->old_status = val; in axp20x_usb_power_poll_vbus()
150 power->online = val & AXP20X_PWR_STATUS_VBUS_USED; in axp20x_usb_power_poll_vbus()
154 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_poll_vbus()
164 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &val); in axp717_usb_power_poll_vbus()
169 if (val != power->old_status) in axp717_usb_power_poll_vbus()
170 power_supply_changed(power->supply); in axp717_usb_power_poll_vbus()
172 power->old_status = val; in axp717_usb_power_poll_vbus()
181 if (!power->usb_bc_det_fld) in axp20x_get_usb_type()
182 return -EINVAL; in axp20x_get_usb_type()
184 ret = regmap_field_read(power->usb_bc_det_fld, &reg); in axp20x_get_usb_type()
190 val->intval = POWER_SUPPLY_USB_TYPE_SDP; in axp20x_get_usb_type()
193 val->intval = POWER_SUPPLY_USB_TYPE_CDP; in axp20x_get_usb_type()
196 val->intval = POWER_SUPPLY_USB_TYPE_DCP; in axp20x_get_usb_type()
199 val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN; in axp20x_get_usb_type()
215 ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); in axp20x_usb_power_get_property()
219 val->intval = AXP20X_VBUS_VHOLD_uV(v); in axp20x_usb_power_get_property()
223 ret = iio_read_channel_processed(power->vbus_v, in axp20x_usb_power_get_property()
224 &val->intval); in axp20x_usb_power_get_property()
232 val->intval *= 1000; in axp20x_usb_power_get_property()
236 ret = axp20x_read_variable_width(power->regmap, in axp20x_usb_power_get_property()
241 val->intval = ret * 1700; /* 1 step = 1.7 mV */ in axp20x_usb_power_get_property()
244 ret = regmap_field_read(power->curr_lim_fld, &v); in axp20x_usb_power_get_property()
248 if (v < power->axp_data->curr_lim_table_size) in axp20x_usb_power_get_property()
249 val->intval = power->axp_data->curr_lim_table[v]; in axp20x_usb_power_get_property()
251 val->intval = power->axp_data->curr_lim_table[ in axp20x_usb_power_get_property()
252 power->axp_data->curr_lim_table_size - 1]; in axp20x_usb_power_get_property()
256 ret = iio_read_channel_processed(power->vbus_i, in axp20x_usb_power_get_property()
257 &val->intval); in axp20x_usb_power_get_property()
265 val->intval *= 1000; in axp20x_usb_power_get_property()
269 ret = axp20x_read_variable_width(power->regmap, in axp20x_usb_power_get_property()
274 val->intval = ret * 375; /* 1 step = 0.375 mA */ in axp20x_usb_power_get_property()
283 /* All the properties below need the input-status reg value */ in axp20x_usb_power_get_property()
284 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input); in axp20x_usb_power_get_property()
291 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; in axp20x_usb_power_get_property()
295 val->intval = POWER_SUPPLY_HEALTH_GOOD; in axp20x_usb_power_get_property()
297 if (power->vbus_valid_bit) { in axp20x_usb_power_get_property()
298 ret = regmap_field_read(power->vbus_valid_bit, &v); in axp20x_usb_power_get_property()
303 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; in axp20x_usb_power_get_property()
308 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); in axp20x_usb_power_get_property()
311 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED); in axp20x_usb_power_get_property()
314 return -EINVAL; in axp20x_usb_power_get_property()
329 val->intval = POWER_SUPPLY_HEALTH_GOOD; in axp717_usb_power_get_property()
330 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); in axp717_usb_power_get_property()
335 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; in axp717_usb_power_get_property()
337 ret = regmap_read(power->regmap, AXP717_PMU_FAULT_VBUS, &v); in axp717_usb_power_get_property()
343 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; in axp717_usb_power_get_property()
344 regmap_write(power->regmap, AXP717_PMU_FAULT_VBUS, v); in axp717_usb_power_get_property()
349 ret = regmap_read(power->regmap, AXP717_INPUT_CUR_LIMIT_CTRL, &v); in axp717_usb_power_get_property()
355 val->intval = (v * 50000) + 100000; in axp717_usb_power_get_property()
359 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); in axp717_usb_power_get_property()
362 val->intval = !!(v & AXP717_PWR_STATUS_VBUS_GOOD); in axp717_usb_power_get_property()
367 ret = regmap_read(power->regmap, AXP717_INPUT_VOL_LIMIT_CTRL, &v); in axp717_usb_power_get_property()
373 val->intval = (v * 80000) + 3880000; in axp717_usb_power_get_property()
377 ret = iio_read_channel_processed(power->vbus_v, in axp717_usb_power_get_property()
378 &val->intval); in axp717_usb_power_get_property()
386 val->intval *= 1000; in axp717_usb_power_get_property()
390 ret = axp20x_read_variable_width(power->regmap, in axp717_usb_power_get_property()
395 val->intval = (ret % AXP717_ADC_DATA_MASK) * 1000; in axp717_usb_power_get_property()
398 return -EINVAL; in axp717_usb_power_get_property()
419 val = (intval - 4000000) / 100000; in axp20x_usb_power_set_voltage_min()
420 return regmap_update_bits(power->regmap, in axp20x_usb_power_set_voltage_min()
425 return -EINVAL; in axp20x_usb_power_set_voltage_min()
428 return -EINVAL; in axp20x_usb_power_set_voltage_min()
438 return -EINVAL; in axp717_usb_power_set_voltage_min()
441 val = (intval - 3880000) / 80000; in axp717_usb_power_set_voltage_min()
442 return regmap_update_bits(power->regmap, in axp717_usb_power_set_voltage_min()
452 const unsigned int max = power->axp_data->curr_lim_table_size; in axp20x_usb_power_set_input_current_limit()
454 if (intval == -1) in axp20x_usb_power_set_input_current_limit()
455 return -EINVAL; in axp20x_usb_power_set_input_current_limit()
457 if (power->max_input_cur && (intval > power->max_input_cur)) { in axp20x_usb_power_set_input_current_limit()
458 dev_warn(power->dev, in axp20x_usb_power_set_input_current_limit()
459 "requested current %d clamped to max current %d\n", in axp20x_usb_power_set_input_current_limit()
460 intval, power->max_input_cur); in axp20x_usb_power_set_input_current_limit()
461 intval = power->max_input_cur; in axp20x_usb_power_set_input_current_limit()
465 * BC1.2 detection can cause a race condition if we try to set a current in axp20x_usb_power_set_input_current_limit()
466 * limit while it's in progress. When it finishes it will overwrite the in axp20x_usb_power_set_input_current_limit()
467 * current limit we just set. in axp20x_usb_power_set_input_current_limit()
469 if (power->usb_bc_en_bit) { in axp20x_usb_power_set_input_current_limit()
470 dev_dbg(power->dev, in axp20x_usb_power_set_input_current_limit()
471 "disabling BC1.2 detection because current limit was set"); in axp20x_usb_power_set_input_current_limit()
472 ret = regmap_field_write(power->usb_bc_en_bit, 0); in axp20x_usb_power_set_input_current_limit()
477 for (reg = max - 1; reg > 0; reg--) in axp20x_usb_power_set_input_current_limit()
478 if (power->axp_data->curr_lim_table[reg] <= intval) in axp20x_usb_power_set_input_current_limit()
481 dev_dbg(power->dev, "setting input current limit reg to %d (%d uA), requested %d uA", in axp20x_usb_power_set_input_current_limit()
482 reg, power->axp_data->curr_lim_table[reg], intval); in axp20x_usb_power_set_input_current_limit()
484 return regmap_field_write(power->curr_lim_fld, reg); in axp20x_usb_power_set_input_current_limit()
494 return -EINVAL; in axp717_usb_power_set_input_current_limit()
496 if (power->max_input_cur && (intval > power->max_input_cur)) { in axp717_usb_power_set_input_current_limit()
497 dev_warn(power->dev, in axp717_usb_power_set_input_current_limit()
498 "reqested current %d clamped to max current %d\n", in axp717_usb_power_set_input_current_limit()
499 intval, power->max_input_cur); in axp717_usb_power_set_input_current_limit()
500 intval = power->max_input_cur; in axp717_usb_power_set_input_current_limit()
504 tmp = (intval - 100000) / 50000; in axp717_usb_power_set_input_current_limit()
505 return regmap_update_bits(power->regmap, in axp717_usb_power_set_input_current_limit()
518 if (!power->vbus_disable_bit) in axp20x_usb_power_set_property()
519 return -EINVAL; in axp20x_usb_power_set_property()
521 return regmap_field_write(power->vbus_disable_bit, !val->intval); in axp20x_usb_power_set_property()
524 return axp20x_usb_power_set_voltage_min(power, val->intval); in axp20x_usb_power_set_property()
527 return axp20x_usb_power_set_input_current_limit(power, val->intval); in axp20x_usb_power_set_property()
530 return -EINVAL; in axp20x_usb_power_set_property()
542 return axp717_usb_power_set_input_current_limit(power, val->intval); in axp717_usb_power_set_property()
545 return axp717_usb_power_set_voltage_min(power, val->intval); in axp717_usb_power_set_property()
548 return -EINVAL; in axp717_usb_power_set_property()
551 return -EINVAL; in axp717_usb_power_set_property()
561 * - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN). in axp20x_usb_power_prop_writeable()
562 * - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN). in axp20x_usb_power_prop_writeable()
567 return power->vbus_disable_bit != NULL; in axp20x_usb_power_prop_writeable()
583 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); in axp20x_configure_iio_channels()
584 if (IS_ERR(power->vbus_v)) { in axp20x_configure_iio_channels()
585 if (PTR_ERR(power->vbus_v) == -ENODEV) in axp20x_configure_iio_channels()
586 return -EPROBE_DEFER; in axp20x_configure_iio_channels()
587 return PTR_ERR(power->vbus_v); in axp20x_configure_iio_channels()
590 power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); in axp20x_configure_iio_channels()
591 if (IS_ERR(power->vbus_i)) { in axp20x_configure_iio_channels()
592 if (PTR_ERR(power->vbus_i) == -ENODEV) in axp20x_configure_iio_channels()
593 return -EPROBE_DEFER; in axp20x_configure_iio_channels()
594 return PTR_ERR(power->vbus_i); in axp20x_configure_iio_channels()
603 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); in axp717_configure_iio_channels()
604 if (IS_ERR(power->vbus_v)) { in axp717_configure_iio_channels()
605 if (PTR_ERR(power->vbus_v) == -ENODEV) in axp717_configure_iio_channels()
606 return -EPROBE_DEFER; in axp717_configure_iio_channels()
607 return PTR_ERR(power->vbus_v); in axp717_configure_iio_channels()
615 /* Enable vbus voltage and current measurement */ in axp20x_configure_adc_registers()
616 return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, in axp20x_configure_adc_registers()
626 return regmap_update_bits(power->regmap, AXP717_ADC_CH_EN_CONTROL, in axp717_configure_adc_registers()
669 .name = "axp20x-usb",
679 .name = "axp20x-usb",
689 .name = "axp20x-usb",
703 .name = "axp20x-usb",
735 -1,
736 -1,
745 -1,
751 -1,
752 -1,
863 if (device_may_wakeup(&power->supply->dev)) in axp20x_usb_power_suspend()
864 enable_irq_wake(power->irqs[i++]); in axp20x_usb_power_suspend()
865 while (i < power->num_irqs) in axp20x_usb_power_suspend()
866 disable_irq(power->irqs[i++]); in axp20x_usb_power_suspend()
876 if (device_may_wakeup(&power->supply->dev)) in axp20x_usb_power_resume()
877 disable_irq_wake(power->irqs[i++]); in axp20x_usb_power_resume()
878 while (i < power->num_irqs) in axp20x_usb_power_resume()
879 enable_irq(power->irqs[i++]); in axp20x_usb_power_resume()
881 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_resume()
910 /* Optionally allow users to specify a maximum charging current. */
916 ret = device_property_read_u32(dev, "input-current-limit-microamp", in axp20x_usb_power_parse_dt()
917 &power->max_input_cur); in axp20x_usb_power_parse_dt()
919 dev_dbg(dev, "%s() no input-current-limit specified\n", __func__); in axp20x_usb_power_parse_dt()
924 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp20x_usb_power_probe()
930 if (!of_device_is_available(pdev->dev.of_node)) in axp20x_usb_power_probe()
931 return -ENODEV; in axp20x_usb_power_probe()
934 dev_err(&pdev->dev, "Parent drvdata not set\n"); in axp20x_usb_power_probe()
935 return -EINVAL; in axp20x_usb_power_probe()
938 axp_data = of_device_get_match_data(&pdev->dev); in axp20x_usb_power_probe()
940 power = devm_kzalloc(&pdev->dev, in axp20x_usb_power_probe()
941 struct_size(power, irqs, axp_data->num_irq_names), in axp20x_usb_power_probe()
944 return -ENOMEM; in axp20x_usb_power_probe()
948 power->dev = &pdev->dev; in axp20x_usb_power_probe()
949 power->axp_data = axp_data; in axp20x_usb_power_probe()
950 power->regmap = axp20x->regmap; in axp20x_usb_power_probe()
951 power->num_irqs = axp_data->num_irq_names; in axp20x_usb_power_probe()
953 power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
954 axp_data->curr_lim_fld); in axp20x_usb_power_probe()
955 if (IS_ERR(power->curr_lim_fld)) in axp20x_usb_power_probe()
956 return PTR_ERR(power->curr_lim_fld); in axp20x_usb_power_probe()
958 axp20x_usb_power_parse_dt(&pdev->dev, power); in axp20x_usb_power_probe()
960 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
961 axp_data->vbus_valid_bit, in axp20x_usb_power_probe()
962 &power->vbus_valid_bit); in axp20x_usb_power_probe()
966 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
967 axp_data->vbus_mon_bit, in axp20x_usb_power_probe()
968 &power->vbus_mon_bit); in axp20x_usb_power_probe()
972 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
973 axp_data->usb_bc_en_bit, in axp20x_usb_power_probe()
974 &power->usb_bc_en_bit); in axp20x_usb_power_probe()
978 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
979 axp_data->usb_bc_det_fld, in axp20x_usb_power_probe()
980 &power->usb_bc_det_fld); in axp20x_usb_power_probe()
984 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
985 axp_data->vbus_disable_bit, in axp20x_usb_power_probe()
986 &power->vbus_disable_bit); in axp20x_usb_power_probe()
990 ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect, in axp20x_usb_power_probe()
991 axp_data->axp20x_read_vbus); in axp20x_usb_power_probe()
995 if (power->vbus_mon_bit) { in axp20x_usb_power_probe()
997 ret = regmap_field_write(power->vbus_mon_bit, 1); in axp20x_usb_power_probe()
1002 ret = axp_data->axp20x_cfg_iio_chan(pdev, power); in axp20x_usb_power_probe()
1004 ret = axp_data->axp20x_cfg_adc_reg(power); in axp20x_usb_power_probe()
1010 if (power->usb_bc_en_bit) { in axp20x_usb_power_probe()
1011 /* Enable USB Battery Charging specification detection */ in axp20x_usb_power_probe()
1012 ret = regmap_field_write(power->usb_bc_en_bit, 1); in axp20x_usb_power_probe()
1017 psy_cfg.of_node = pdev->dev.of_node; in axp20x_usb_power_probe()
1020 power->supply = devm_power_supply_register(&pdev->dev, in axp20x_usb_power_probe()
1021 axp_data->power_desc, in axp20x_usb_power_probe()
1023 if (IS_ERR(power->supply)) in axp20x_usb_power_probe()
1024 return PTR_ERR(power->supply); in axp20x_usb_power_probe()
1027 for (i = 0; i < axp_data->num_irq_names; i++) { in axp20x_usb_power_probe()
1028 irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]); in axp20x_usb_power_probe()
1032 power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq); in axp20x_usb_power_probe()
1033 ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i], in axp20x_usb_power_probe()
1037 dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n", in axp20x_usb_power_probe()
1038 axp_data->irq_names[i], ret); in axp20x_usb_power_probe()
1044 queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0); in axp20x_usb_power_probe()
1051 .compatible = "x-powers,axp192-usb-power-supply",
1054 .compatible = "x-powers,axp202-usb-power-supply",
1057 .compatible = "x-powers,axp221-usb-power-supply",
1060 .compatible = "x-powers,axp223-usb-power-supply",
1063 .compatible = "x-powers,axp717-usb-power-supply",
1066 .compatible = "x-powers,axp813-usb-power-supply",
1084 MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");