diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-18 10:24:22 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-18 10:24:22 +0200 |
commit | 288cb34ead03c0d09932317b239f1f4d38fc9d4f (patch) | |
tree | 754fc6bb55d5d30cb3a79d96e21f91c8de27a3ec | |
parent | bfbb96324a4a8dfd44c88f64e4e0ef8ea4ab128b (diff) | |
parent | e50a57d16f897e45de1112eb6478577b197fab52 (diff) |
Merge tag 'for-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply and reset updates from Sebastian Reichel:
"Power-supply core:
- introduce power_supply_show_enum_with_available() helper
- change usb_types from an array into a bitmask
- fix early usage of power_supply_property_is_writeable() resulting
in sysfs files not being writable
- fix missing temp1_max_alarm attribute in power-supply's hwmon
devices
Drivers:
- max1720x: expose nvmem device
- brcmstb: cleanup driver to use latest APIs
- max77693: expose input and charging current limit
- max17042_battery: fix state of charge reading for devices without
current sensing
- axp20x_battery: add AXP717 support
- axp20x_battery: fix min/max voltage properties
- axp20x_usb_power: add AXP717 support
- axp20x_usb_power: add DT based input current limit
Documentation updates
Misc minor cleanups and fixes"
* tag 'for-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (38 commits)
power: supply: hwmon: Fix missing temp1_max_alarm attribute
power: supply: Drop use_cnt check from power_supply_property_is_writeable()
power: supply: ab8500: Constify struct kobj_type
power: supply: max1720x: fix a double free on error in probe()
power: supply: axp20x_battery: add support for AXP717
power: supply: axp20x_usb_power: Add support for AXP717
dt-bindings: power: supply: axp20x: Add AXP717 compatible
dt-bindings: power: supply: axp20x: Add AXP717 compatible
power: supply: axp20x_usb_power: Fix spelling mistake "reqested" -> "requested"
power: supply: Change usb_types from an array into a bitmask
power: supply: sysfs: Move power_supply_show_enum_with_available() up
power: supply: sysfs: Add power_supply_show_enum_with_available() helper
power: supply: rt9467-charger: Remove "usb_type" property write support
power: supply: ucs1002: Adjust ucs1002_set_usb_type() to accept string values
power: supply: "usb_type" property may be written to
power: supply: max1720x: add read support for nvmem
mfd: axp20x: Add ADC, BAT, and USB cells for AXP717
power: supply: core: constify psy_tzd_ops
power: reset: brcmstb: Do not go into infinite loop if reset fails
power: reset: brcmstb: Use devm_register_sys_off_handler()
...
42 files changed, 1433 insertions, 444 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 7c81f0a25a48..45180b62d426 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -377,17 +377,33 @@ What: /sys/class/power_supply/<supply_name>/charge_type Date: July 2009 Contact: linux-pm@vger.kernel.org Description: - Represents the type of charging currently being applied to the - battery. "Trickle", "Fast", and "Standard" all mean different - charging speeds. "Adaptive" means that the charger uses some - algorithm to adjust the charge rate dynamically, without - any user configuration required. "Custom" means that the charger - uses the charge_control_* properties as configuration for some - different algorithm. "Long Life" means the charger reduces its - charging rate in order to prolong the battery health. "Bypass" - means the charger bypasses the charging path around the - integrated converter allowing for a "smart" wall adaptor to - perform the power conversion externally. + Select the charging algorithm to use for a battery. + + Standard: + Fully charge the battery at a moderate rate. + Fast: + Quickly charge the battery using fast-charge + technology. This is typically harder on the battery + than standard charging and may lower its lifespan. + Trickle: + Users who primarily operate the system while + plugged into an external power source can extend + battery life with this mode. Vendor tooling may + call this "Primarily AC Use". + Adaptive: + Automatically optimize battery charge rate based + on typical usage pattern. + Custom: + Use the charge_control_* properties to determine + when to start and stop charging. Advanced users + can use this to drastically extend battery life. + Long Life: + The charger reduces its charging rate in order to + prolong the battery health. + Bypass: + The charger bypasses the charging path around the + integrated converter allowing for a "smart" wall + adaptor to perform the power conversion externally. Access: Read, Write @@ -592,7 +608,12 @@ Description: the supply, for example it can show if USB-PD capable source is attached. - Access: Read-Only + Access: For power-supplies which consume USB power such + as battery charger chips, this indicates the type of + the connected USB power source and is Read-Only. + + For power-supplies which act as a USB power-source such as + e.g. the UCS1002 USB Port Power Controller this is writable. Valid values: "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD", diff --git a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml index de43e45a43b7..9108a2841caf 100644 --- a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml @@ -27,6 +27,9 @@ properties: battery-detect-gpios: maxItems: 1 + interrupts: + maxItems: 1 + io-channels: items: - description: Battery Temperature ADC @@ -53,6 +56,7 @@ required: - compatible - reg - battery-detect-gpios + - interrupts - io-channels - io-channel-names - nvmem-cells @@ -88,6 +92,8 @@ examples: compatible = "sprd,sc2731-fgu"; reg = <0xa00>; battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <4>; io-channels = <&pmic_adc 5>, <&pmic_adc 14>; io-channel-names = "bat-temp", "charge-vol"; nvmem-cells = <&fgu_calib>; diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml index e0b95ecbbebd..5ccd375eb294 100644 --- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml @@ -23,11 +23,18 @@ properties: - const: x-powers,axp202-battery-power-supply - const: x-powers,axp209-battery-power-supply - const: x-powers,axp221-battery-power-supply + - const: x-powers,axp717-battery-power-supply - items: - const: x-powers,axp803-battery-power-supply - const: x-powers,axp813-battery-power-supply - const: x-powers,axp813-battery-power-supply + monitored-battery: + description: + Specifies the phandle of an optional simple-battery connected to + this gauge. + $ref: /schemas/types.yaml#/definitions/phandle + required: - compatible diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml index 34b7959d6772..2ec036405ae4 100644 --- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml @@ -15,9 +15,6 @@ maintainers: - Chen-Yu Tsai <wens@csie.org> - Sebastian Reichel <sre@kernel.org> -allOf: - - $ref: power-supply.yaml# - properties: compatible: oneOf: @@ -26,13 +23,82 @@ properties: - x-powers,axp202-usb-power-supply - x-powers,axp221-usb-power-supply - x-powers,axp223-usb-power-supply + - x-powers,axp717-usb-power-supply - x-powers,axp813-usb-power-supply - items: - const: x-powers,axp803-usb-power-supply - const: x-powers,axp813-usb-power-supply + input-current-limit-microamp: + description: + Optional value to clamp the maximum input current limit to for + the device. If omitted, the programmed value from the EFUSE will + be used. + minimum: 100000 + maximum: 4000000 required: - compatible +allOf: + - $ref: power-supply.yaml# + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp192-usb-power-supply + then: + properties: + input-current-limit-microamp: + enum: [100000, 500000] + + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp202-usb-power-supply + - x-powers,axp223-usb-power-supply + then: + properties: + input-current-limit-microamp: + enum: [100000, 500000, 900000] + + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp221-usb-power-supply + then: + properties: + input-current-limit-microamp: + enum: [500000, 900000] + + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp717-usb-power-supply + then: + properties: + input-current-limit-microamp: + description: Maximum input current in increments of 50000 uA. + minimum: 100000 + maximum: 3250000 + + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp813-usb-power-supply + then: + properties: + input-current-limit-microamp: + enum: [100000, 500000, 900000, 1500000, 2000000, 2500000, + 3000000, 3500000, 4000000] + additionalProperties: false diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 733c470c3102..93552dc3c895 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -461,14 +461,6 @@ static int cht_wc_extcon_psy_get_prop(struct power_supply *psy, return 0; } -static const enum power_supply_usb_type cht_wc_extcon_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_ACA, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static const enum power_supply_property cht_wc_extcon_psy_props[] = { POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, @@ -477,8 +469,11 @@ static const enum power_supply_property cht_wc_extcon_psy_props[] = { static const struct power_supply_desc cht_wc_extcon_psy_desc = { .name = "cht_wcove_pwrsrc", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = cht_wc_extcon_psy_usb_types, - .num_usb_types = ARRAY_SIZE(cht_wc_extcon_psy_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_ACA) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = cht_wc_extcon_psy_props, .num_properties = ARRAY_SIZE(cht_wc_extcon_psy_props), .get_property = cht_wc_extcon_psy_get_prop, diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 16950c3206d7..4051551757f2 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -209,15 +209,23 @@ static const struct regmap_access_table axp313a_volatile_table = { }; static const struct regmap_range axp717_writeable_ranges[] = { - regmap_reg_range(AXP717_MODULE_EN_CONTROL_2, AXP717_MODULE_EN_CONTROL_2), - regmap_reg_range(AXP717_BOOST_CONTROL, AXP717_BOOST_CONTROL), + regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1), + regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL), + regmap_reg_range(AXP717_VSYS_V_POWEROFF, AXP717_VSYS_V_POWEROFF), regmap_reg_range(AXP717_IRQ0_EN, AXP717_IRQ4_EN), regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE), + regmap_reg_range(AXP717_ICC_CHG_SET, AXP717_CV_CHG_SET), regmap_reg_range(AXP717_DCDC_OUTPUT_CONTROL, AXP717_CPUSLDO_CONTROL), + regmap_reg_range(AXP717_ADC_CH_EN_CONTROL, AXP717_ADC_CH_EN_CONTROL), + regmap_reg_range(AXP717_ADC_DATA_SEL, AXP717_ADC_DATA_SEL), }; static const struct regmap_range axp717_volatile_ranges[] = { + regmap_reg_range(AXP717_ON_INDICATE, AXP717_PMU_FAULT), regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE), + regmap_reg_range(AXP717_BATT_PERCENT_DATA, AXP717_BATT_PERCENT_DATA), + regmap_reg_range(AXP717_BATT_V_H, AXP717_BATT_CHRG_I_L), + regmap_reg_range(AXP717_ADC_DATA_H, AXP717_ADC_DATA_L), }; static const struct regmap_access_table axp717_writeable_table = { @@ -310,6 +318,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), }; +static const struct resource axp717_usb_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_OVER_V, "VBUS_OVER_V"), + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), +}; + /* AXP803 and AXP813/AXP818 share the same interrupts */ static const struct resource axp803_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), @@ -424,7 +438,7 @@ static const struct regmap_config axp717_regmap_config = { .val_bits = 8, .wr_table = &axp717_writeable_table, .volatile_table = &axp717_volatile_table, - .max_register = AXP717_CPUSLDO_CONTROL, + .max_register = AXP717_ADC_DATA_L, .cache_type = REGCACHE_MAPLE, }; @@ -1026,6 +1040,13 @@ static struct mfd_cell axp313a_cells[] = { static struct mfd_cell axp717_cells[] = { MFD_CELL_NAME("axp20x-regulator"), MFD_CELL_RES("axp20x-pek", axp717_pek_resources), + MFD_CELL_OF("axp717-adc", + NULL, NULL, 0, 0, "x-powers,axp717-adc"), + MFD_CELL_OF("axp20x-usb-power-supply", + axp717_usb_power_supply_resources, NULL, 0, 0, + "x-powers,axp717-usb-power-supply"), + MFD_CELL_OF("axp20x-battery-power-supply", + NULL, NULL, 0, 0, "x-powers,axp717-battery-power-supply"), }; static const struct resource axp288_adc_resources[] = { diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index 751fecd466e3..c3ae9d7948d7 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -411,12 +411,6 @@ static int tusb1210_psy_get_prop(struct power_supply *psy, return 0; } -static const enum power_supply_usb_type tusb1210_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static const enum power_supply_property tusb1210_psy_props[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, @@ -426,8 +420,9 @@ static const enum power_supply_property tusb1210_psy_props[] = { static const struct power_supply_desc tusb1210_psy_desc = { .name = "tusb1211-charger-detect", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = tusb1210_psy_usb_types, - .num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = tusb1210_psy_props, .num_properties = ARRAY_SIZE(tusb1210_psy_props), .get_property = tusb1210_psy_get_prop, diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c index 0f2944dc9355..b9c093f6064c 100644 --- a/drivers/power/reset/brcmstb-reboot.c +++ b/drivers/power/reset/brcmstb-reboot.c @@ -18,9 +18,6 @@ #include <linux/smp.h> #include <linux/mfd/syscon.h> -#define RESET_SOURCE_ENABLE_REG 1 -#define SW_MASTER_RESET_REG 2 - static struct regmap *regmap; static u32 rst_src_en; static u32 sw_mstr_rst; @@ -32,8 +29,7 @@ struct reset_reg_mask { static const struct reset_reg_mask *reset_masks; -static int brcmstb_restart_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int brcmstb_restart_handler(struct sys_off_data *data) { int rc; u32 tmp; @@ -62,17 +58,9 @@ static int brcmstb_restart_handler(struct notifier_block *this, return NOTIFY_DONE; } - while (1) - ; - return NOTIFY_DONE; } -static struct notifier_block brcmstb_restart_nb = { - .notifier_call = brcmstb_restart_handler, - .priority = 128, -}; - static const struct reset_reg_mask reset_bits_40nm = { .rst_src_en_mask = BIT(0), .sw_mstr_rst_mask = BIT(0), @@ -83,46 +71,28 @@ static const struct reset_reg_mask reset_bits_65nm = { .sw_mstr_rst_mask = BIT(31), }; -static const struct of_device_id of_match[] = { - { .compatible = "brcm,brcmstb-reboot", .data = &reset_bits_40nm }, - { .compatible = "brcm,bcm7038-reboot", .data = &reset_bits_65nm }, - {}, -}; - static int brcmstb_reboot_probe(struct platform_device *pdev) { int rc; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id; + unsigned int args[2]; - of_id = of_match_node(of_match, np); - if (!of_id) { - pr_err("failed to look up compatible string\n"); + reset_masks = device_get_match_data(&pdev->dev); + if (!reset_masks) { + pr_err("failed to get match data\n"); return -EINVAL; } - reset_masks = of_id->data; - regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); + regmap = syscon_regmap_lookup_by_phandle_args(np, "syscon", ARRAY_SIZE(args), args); if (IS_ERR(regmap)) { pr_err("failed to get syscon phandle\n"); return -EINVAL; } + rst_src_en = args[0]; + sw_mstr_rst = args[1]; - rc = of_property_read_u32_index(np, "syscon", RESET_SOURCE_ENABLE_REG, - &rst_src_en); - if (rc) { - pr_err("can't get rst_src_en offset (%d)\n", rc); - return -EINVAL; - } - - rc = of_property_read_u32_index(np, "syscon", SW_MASTER_RESET_REG, - &sw_mstr_rst); - if (rc) { - pr_err("can't get sw_mstr_rst offset (%d)\n", rc); - return -EINVAL; - } - - rc = register_restart_handler(&brcmstb_restart_nb); + rc = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, + 128, brcmstb_restart_handler, NULL); if (rc) dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", rc); @@ -130,6 +100,12 @@ static int brcmstb_reboot_probe(struct platform_device *pdev) return rc; } +static const struct of_device_id of_match[] = { + { .compatible = "brcm,brcmstb-reboot", .data = &reset_bits_40nm }, + { .compatible = "brcm,bcm7038-reboot", .data = &reset_bits_65nm }, + {}, +}; + static struct platform_driver brcmstb_reboot_driver = { .probe = brcmstb_reboot_probe, .driver = { @@ -140,7 +116,6 @@ static struct platform_driver brcmstb_reboot_driver = { static int __init brcmstb_reboot_init(void) { - return platform_driver_probe(&brcmstb_reboot_driver, - brcmstb_reboot_probe); + return platform_driver_register(&brcmstb_reboot_driver); } subsys_initcall(brcmstb_reboot_init); diff --git a/drivers/power/reset/pwr-mlxbf.c b/drivers/power/reset/pwr-mlxbf.c index 1775b318d0ef..4f1cd1c0018c 100644 --- a/drivers/power/reset/pwr-mlxbf.c +++ b/drivers/power/reset/pwr-mlxbf.c @@ -18,7 +18,6 @@ struct pwr_mlxbf { struct work_struct reboot_work; - struct work_struct shutdown_work; const char *hid; }; @@ -27,22 +26,17 @@ static void pwr_mlxbf_reboot_work(struct work_struct *work) acpi_bus_generate_netlink_event("button/reboot.*", "Reboot Button", 0x80, 1); } -static void pwr_mlxbf_shutdown_work(struct work_struct *work) -{ - acpi_bus_generate_netlink_event("button/power.*", "Power Button", 0x80, 1); -} - static irqreturn_t pwr_mlxbf_irq(int irq, void *ptr) { const char *rst_pwr_hid = "MLNXBF24"; - const char *low_pwr_hid = "MLNXBF29"; + const char *shutdown_hid = "MLNXBF29"; struct pwr_mlxbf *priv = ptr; if (!strncmp(priv->hid, rst_pwr_hid, 8)) schedule_work(&priv->reboot_work); - if (!strncmp(priv->hid, low_pwr_hid, 8)) - schedule_work(&priv->shutdown_work); + if (!strncmp(priv->hid, shutdown_hid, 8)) + orderly_poweroff(true); return IRQ_HANDLED; } @@ -70,10 +64,6 @@ static int pwr_mlxbf_probe(struct platform_device *pdev) if (irq < 0) return dev_err_probe(dev, irq, "Error getting %s irq.\n", priv->hid); - err = devm_work_autocancel(dev, &priv->shutdown_work, pwr_mlxbf_shutdown_work); - if (err) - return err; - err = devm_work_autocancel(dev, &priv->reboot_work, pwr_mlxbf_reboot_work); if (err) return err; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 270874eeb934..a71903b1bf78 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2531,7 +2531,7 @@ static struct attribute *ab8500_fg_attrs[] = { }; ATTRIBUTE_GROUPS(ab8500_fg); -static struct kobj_type ab8500_fg_ktype = { +static const struct kobj_type ab8500_fg_ktype = { .sysfs_ops = &ab8500_fg_sysfs_ops, .default_groups = ab8500_fg_groups, }; diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index 6ac5c80cfda2..f71cc90fea12 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -17,6 +17,7 @@ * GNU General Public License for more details. */ +#include <linux/bitfield.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -32,9 +33,19 @@ #include <linux/mfd/axp20x.h> #define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2) +#define AXP717_PWR_STATUS_MASK GENMASK(6, 5) +#define AXP717_PWR_STATUS_BAT_STANDBY 0 +#define AXP717_PWR_STATUS_BAT_CHRG 1 +#define AXP717_PWR_STATUS_BAT_DISCHRG 2 #define AXP20X_PWR_OP_BATT_PRESENT BIT(5) #define AXP20X_PWR_OP_BATT_ACTIVATED BIT(3) +#define AXP717_PWR_OP_BATT_PRESENT BIT(3) + +#define AXP717_BATT_PMU_FAULT_MASK GENMASK(2, 0) +#define AXP717_BATT_UVLO_2_5V BIT(2) +#define AXP717_BATT_OVER_TEMP BIT(1) +#define AXP717_BATT_UNDER_TEMP BIT(0) #define AXP209_FG_PERCENT GENMASK(6, 0) #define AXP22X_FG_VALID BIT(7) @@ -49,20 +60,51 @@ #define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5) #define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5) +#define AXP717_CHRG_ENABLE BIT(1) +#define AXP717_CHRG_CV_VOLT_MASK GENMASK(2, 0) +#define AXP717_CHRG_CV_4_0V 0 +#define AXP717_CHRG_CV_4_1V 1 +#define AXP717_CHRG_CV_4_2V 2 +#define AXP717_CHRG_CV_4_35V 3 +#define AXP717_CHRG_CV_4_4V 4 +/* Values 5 and 6 reserved. */ +#define AXP717_CHRG_CV_5_0V 7 + #define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5) #define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0) +#define AXP717_ICC_CHARGER_LIM_MASK GENMASK(5, 0) + +#define AXP717_ITERM_CHG_LIM_MASK GENMASK(3, 0) +#define AXP717_ITERM_CC_STEP 64000 #define AXP20X_V_OFF_MASK GENMASK(2, 0) +#define AXP717_V_OFF_MASK GENMASK(6, 4) + +#define AXP717_BAT_VMIN_MIN_UV 2600000 +#define AXP717_BAT_VMIN_MAX_UV 3300000 +#define AXP717_BAT_VMIN_STEP 100000 +#define AXP717_BAT_CV_MIN_UV 4000000 +#define AXP717_BAT_CV_MAX_UV 5000000 +#define AXP717_BAT_CC_MIN_UA 0 +#define AXP717_BAT_CC_MAX_UA 3008000 struct axp20x_batt_ps; struct axp_data { - int ccc_scale; - int ccc_offset; - bool has_fg_valid; + int ccc_scale; + int ccc_offset; + unsigned int ccc_reg; + unsigned int ccc_mask; + bool has_fg_valid; + const struct power_supply_desc *bat_ps_desc; int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val); int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val); + int (*cfg_iio_chan)(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt); + void (*set_bat_info)(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt, + struct power_supply_battery_info *info); }; struct axp20x_batt_ps { @@ -135,6 +177,39 @@ static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, return 0; } +static int axp717_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, + int *val) +{ + int ret, reg; + + ret = regmap_read(axp20x_batt->regmap, AXP717_CV_CHG_SET, ®); + if (ret) + return ret; + + switch (reg & AXP717_CHRG_CV_VOLT_MASK) { + case AXP717_CHRG_CV_4_0V: + *val = 4000000; + return 0; + case AXP717_CHRG_CV_4_1V: + *val = 4100000; + return 0; + case AXP717_CHRG_CV_4_2V: + *val = 4200000; + return 0; + case AXP717_CHRG_CV_4_35V: + *val = 4350000; + return 0; + case AXP717_CHRG_CV_4_4V: + *val = 4400000; + return 0; + case AXP717_CHRG_CV_5_0V: + *val = 5000000; + return 0; + default: + return -EINVAL; + } +} + static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt, int *val) { @@ -180,6 +255,21 @@ static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp, return 0; } +static int axp717_get_constant_charge_current(struct axp20x_batt_ps *axp, + int *val) +{ + int ret; + + ret = regmap_read(axp->regmap, AXP717_ICC_CHG_SET, val); + if (ret) + return ret; + + *val = FIELD_GET(AXP717_ICC_CHARGER_LIM_MASK, *val) * + axp->data->ccc_scale; + + return 0; +} + static int axp20x_battery_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -303,11 +393,11 @@ static int axp20x_battery_get_prop(struct power_supply *psy, val->intval = reg & AXP209_FG_PERCENT; break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_MAX: return axp20x_batt->data->get_max_voltage(axp20x_batt, &val->intval); - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, ®); if (ret) return ret; @@ -332,6 +422,171 @@ static int axp20x_battery_get_prop(struct power_supply *psy, return 0; } +static int axp717_battery_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy); + int ret = 0, reg; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_ONLINE: + ret = regmap_read(axp20x_batt->regmap, AXP717_ON_INDICATE, + ®); + if (ret) + return ret; + + val->intval = FIELD_GET(AXP717_PWR_OP_BATT_PRESENT, reg); + return 0; + + case POWER_SUPPLY_PROP_STATUS: + ret = regmap_read(axp20x_batt->regmap, AXP717_PMU_STATUS_2, + ®); + if (ret) + return ret; + + switch (FIELD_GET(AXP717_PWR_STATUS_MASK, reg)) { + case AXP717_PWR_STATUS_BAT_STANDBY: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return 0; + + case AXP717_PWR_STATUS_BAT_CHRG: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return 0; + + case AXP717_PWR_STATUS_BAT_DISCHRG: + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } + + /* + * If a fault is detected it must also be cleared; if the + * condition persists it should reappear (This is an + * assumption, it's actually not documented). A restart was + * not sufficient to clear the bit in testing despite the + * register listed as POR. + */ + case POWER_SUPPLY_PROP_HEALTH: + ret = regmap_read(axp20x_batt->regmap, AXP717_PMU_FAULT, + ®); + if (ret) + return ret; + + switch (reg & AXP717_BATT_PMU_FAULT_MASK) { + case AXP717_BATT_UVLO_2_5V: + val->intval = POWER_SUPPLY_HEALTH_DEAD; + regmap_update_bits(axp20x_batt->regmap, + AXP717_PMU_FAULT, + AXP717_BATT_UVLO_2_5V, + AXP717_BATT_UVLO_2_5V); + return 0; + + case AXP717_BATT_OVER_TEMP: + val->intval = POWER_SUPPLY_HEALTH_HOT; + regmap_update_bits(axp20x_batt->regmap, + AXP717_PMU_FAULT, + AXP717_BATT_OVER_TEMP, + AXP717_BATT_OVER_TEMP); + return 0; + + case AXP717_BATT_UNDER_TEMP: + val->intval = POWER_SUPPLY_HEALTH_COLD; + regmap_update_bits(axp20x_batt->regmap, + AXP717_PMU_FAULT, + AXP717_BATT_UNDER_TEMP, + AXP717_BATT_UNDER_TEMP); + return 0; + + default: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return 0; + } + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = axp717_get_constant_charge_current(axp20x_batt, + &val->intval); + if (ret) + return ret; + return 0; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + /* + * The offset of this value is currently unknown and is + * not documented in the datasheet. Based on + * observation it's assumed to be somewhere around + * 450ma. I will leave the value raw for now. + */ + ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval); + if (ret) + return ret; + /* IIO framework gives mA but Power Supply framework gives uA */ + val->intval *= 1000; + return 0; + + case POWER_SUPPLY_PROP_CAPACITY: + ret = regmap_read(axp20x_batt->regmap, AXP717_ON_INDICATE, + ®); + if (ret) + return ret; + + if (!FIELD_GET(AXP717_PWR_OP_BATT_PRESENT, reg)) + return -ENODEV; + + ret = regmap_read(axp20x_batt->regmap, + AXP717_BATT_PERCENT_DATA, ®); + if (ret) + return ret; + + /* + * Fuel Gauge data takes 7 bits but the stored value seems to be + * directly the raw percentage without any scaling to 7 bits. + */ + val->intval = reg & AXP209_FG_PERCENT; + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + return axp20x_batt->data->get_max_voltage(axp20x_batt, + &val->intval); + + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + ret = regmap_read(axp20x_batt->regmap, + AXP717_VSYS_V_POWEROFF, ®); + if (ret) + return ret; + + val->intval = AXP717_BAT_VMIN_MIN_UV + AXP717_BAT_VMIN_STEP * + (reg & AXP717_V_OFF_MASK); + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = iio_read_channel_processed(axp20x_batt->batt_v, + &val->intval); + if (ret) + return ret; + + /* IIO framework gives mV but Power Supply framework gives uV */ + val->intval *= 1000; + return 0; + + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = regmap_read(axp20x_batt->regmap, + AXP717_ITERM_CHG_SET, ®); + if (ret) + return ret; + + val->intval = (reg & AXP717_ITERM_CHG_LIM_MASK) * AXP717_ITERM_CC_STEP; + return 0; + + default: + return -EINVAL; + } +} + static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt, int val) { @@ -388,6 +643,35 @@ static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt, AXP20X_CHRG_CTRL1_TGT_VOLT, val); } +static int axp717_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt, + int val) +{ + switch (val) { + case 4000000: + val = AXP717_CHRG_CV_4_0V; + break; + + case 4100000: + val = AXP717_CHRG_CV_4_1V; + break; + + case 4200000: + val = AXP717_CHRG_CV_4_2V; + break; + + default: + /* + * AXP717 can go up to 4.35, 4.4, and 5.0 volts which + * seem too high for lithium batteries, so do not allow. + */ + return -EINVAL; + } + + return regmap_update_bits(axp20x_batt->regmap, + AXP717_CV_CHG_SET, + AXP717_CHRG_CV_VOLT_MASK, val); +} + static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt, int charge_current) { @@ -404,6 +688,24 @@ static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt, AXP20X_CHRG_CTRL1_TGT_CURR, charge_current); } +static int axp717_set_constant_charge_current(struct axp20x_batt_ps *axp, + int charge_current) +{ + int val; + + if (charge_current > axp->max_ccc) + return -EINVAL; + + if (charge_current > AXP717_BAT_CC_MAX_UA || charge_current < 0) + return -EINVAL; + + val = (charge_current - axp->data->ccc_offset) / + axp->data->ccc_scale; + + return regmap_update_bits(axp->regmap, AXP717_ICC_CHG_SET, + AXP717_ICC_CHARGER_LIM_MASK, val); +} + static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp, int charge_current) { @@ -448,6 +750,19 @@ static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt, AXP20X_V_OFF_MASK, val1); } +static int axp717_set_voltage_min_design(struct axp20x_batt_ps *axp_batt, + int min_voltage) +{ + int val1 = (min_voltage - AXP717_BAT_VMIN_MIN_UV) / AXP717_BAT_VMIN_STEP; + + if (val1 < 0 || val1 > AXP717_V_OFF_MASK) + return -EINVAL; + + return regmap_update_bits(axp_batt->regmap, + AXP717_VSYS_V_POWEROFF, + AXP717_V_OFF_MASK, val1); +} + static int axp20x_battery_set_prop(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) @@ -455,10 +770,10 @@ static int axp20x_battery_set_prop(struct power_supply *psy, struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy); switch (psp) { - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: return axp20x_set_voltage_min_design(axp20x_batt, val->intval); - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_MAX: return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval); case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: @@ -484,6 +799,42 @@ static int axp20x_battery_set_prop(struct power_supply *psy, } } +static int axp717_battery_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + return axp717_set_voltage_min_design(axp20x_batt, val->intval); + + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval); + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + return axp717_set_constant_charge_current(axp20x_batt, + val->intval); + case POWER_SUPPLY_PROP_STATUS: + switch (val->intval) { + case POWER_SUPPLY_STATUS_CHARGING: + return regmap_update_bits(axp20x_batt->regmap, + AXP717_MODULE_EN_CONTROL_2, + AXP717_CHRG_ENABLE, + AXP717_CHRG_ENABLE); + + case POWER_SUPPLY_STATUS_DISCHARGING: + case POWER_SUPPLY_STATUS_NOT_CHARGING: + return regmap_update_bits(axp20x_batt->regmap, + AXP717_MODULE_EN_CONTROL_2, + AXP717_CHRG_ENABLE, 0); + } + return -EINVAL; + default: + return -EINVAL; + } +} + static enum power_supply_property axp20x_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, @@ -493,22 +844,45 @@ static enum power_supply_property axp20x_battery_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN, POWER_SUPPLY_PROP_CAPACITY, }; +static enum power_supply_property axp717_battery_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, +}; + static int axp20x_battery_prop_writeable(struct power_supply *psy, enum power_supply_property psp) { return psp == POWER_SUPPLY_PROP_STATUS || - psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN || - psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || + psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || + psp == POWER_SUPPLY_PROP_VOLTAGE_MAX || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; } -static const struct power_supply_desc axp20x_batt_ps_desc = { +static int axp717_battery_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + return psp == POWER_SUPPLY_PROP_STATUS || + psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || + psp == POWER_SUPPLY_PROP_VOLTAGE_MAX || + psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; +} + +static const struct power_supply_desc axp209_batt_ps_desc = { .name = "axp20x-battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = axp20x_battery_props, @@ -518,27 +892,163 @@ static const struct power_supply_desc axp20x_batt_ps_desc = { .set_property = axp20x_battery_set_prop, }; +static const struct power_supply_desc axp717_batt_ps_desc = { + .name = "axp20x-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = axp717_battery_props, + .num_properties = ARRAY_SIZE(axp717_battery_props), + .property_is_writeable = axp717_battery_prop_writeable, + .get_property = axp717_battery_get_prop, + .set_property = axp717_battery_set_prop, +}; + +static int axp209_bat_cfg_iio_channels(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt) +{ + axp_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v"); + if (IS_ERR(axp_batt->batt_v)) { + if (PTR_ERR(axp_batt->batt_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(axp_batt->batt_v); + } + + axp_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev, + "batt_chrg_i"); + if (IS_ERR(axp_batt->batt_chrg_i)) { + if (PTR_ERR(axp_batt->batt_chrg_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(axp_batt->batt_chrg_i); + } + + axp_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev, + "batt_dischrg_i"); + if (IS_ERR(axp_batt->batt_dischrg_i)) { + if (PTR_ERR(axp_batt->batt_dischrg_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(axp_batt->batt_dischrg_i); + } + + return 0; +} + +static int axp717_bat_cfg_iio_channels(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt) +{ + axp_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v"); + if (IS_ERR(axp_batt->batt_v)) { + if (PTR_ERR(axp_batt->batt_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(axp_batt->batt_v); + } + + axp_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev, + "batt_chrg_i"); + if (IS_ERR(axp_batt->batt_chrg_i)) { + if (PTR_ERR(axp_batt->batt_chrg_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(axp_batt->batt_chrg_i); + } + + return 0; +} + +static void axp209_set_battery_info(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt, + struct power_supply_battery_info *info) +{ + int vmin = info->voltage_min_design_uv; + int ccc = info->constant_charge_current_max_ua; + + if (vmin > 0 && axp20x_set_voltage_min_design(axp_batt, vmin)) + dev_err(&pdev->dev, + "couldn't set voltage_min_design\n"); + + /* Set max to unverified value to be able to set CCC */ + axp_batt->max_ccc = ccc; + + if (ccc <= 0 || axp20x_set_constant_charge_current(axp_batt, ccc)) { + dev_err(&pdev->dev, + "couldn't set ccc from DT: fallback to min value\n"); + ccc = 300000; + axp_batt->max_ccc = ccc; + axp20x_set_constant_charge_current(axp_batt, ccc); + } +} + +static void axp717_set_battery_info(struct platform_device *pdev, + struct axp20x_batt_ps *axp_batt, + struct power_supply_battery_info *info) +{ + int vmin = info->voltage_min_design_uv; + int vmax = info->voltage_max_design_uv; + int ccc = info->constant_charge_current_max_ua; + int val; + + if (vmin > 0 && axp717_set_voltage_min_design(axp_batt, vmin)) + dev_err(&pdev->dev, + "couldn't set voltage_min_design\n"); + + if (vmax > 0 && axp717_battery_set_max_voltage(axp_batt, vmax)) + dev_err(&pdev->dev, + "couldn't set voltage_max_design\n"); + + axp717_get_constant_charge_current(axp_batt, &val); + axp_batt->max_ccc = ccc; + if (ccc <= 0 || axp717_set_constant_charge_current(axp_batt, ccc)) { + dev_err(&pdev->dev, + "couldn't set ccc from DT: current ccc is %d\n", + val); + } +} + static const struct axp_data axp209_data = { .ccc_scale = 100000, .ccc_offset = 300000, + .ccc_reg = AXP20X_CHRG_CTRL1, + .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR, + .bat_ps_desc = &axp209_batt_ps_desc, .get_max_voltage = axp20x_battery_get_max_voltage, .set_max_voltage = axp20x_battery_set_max_voltage, + .cfg_iio_chan = axp209_bat_cfg_iio_channels, + .set_bat_info = axp209_set_battery_info, }; static const struct axp_data axp221_data = { .ccc_scale = 150000, .ccc_offset = 300000, + .ccc_reg = AXP20X_CHRG_CTRL1, + .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR, .has_fg_valid = true, + .bat_ps_desc = &axp209_batt_ps_desc, .get_max_voltage = axp22x_battery_get_max_voltage, .set_max_voltage = axp22x_battery_set_max_voltage, + .cfg_iio_chan = axp209_bat_cfg_iio_channels, + .set_bat_info = axp209_set_battery_info, +}; + +static const struct axp_data axp717_data = { + .ccc_scale = 64000, + .ccc_offset = 0, + .ccc_reg = AXP717_ICC_CHG_SET, + .ccc_mask = AXP717_ICC_CHARGER_LIM_MASK, + .bat_ps_desc = &axp717_batt_ps_desc, + .get_max_voltage = axp717_battery_get_max_voltage, + .set_max_voltage = axp717_battery_set_max_voltage, + .cfg_iio_chan = axp717_bat_cfg_iio_channels, + .set_bat_info = axp717_set_battery_info, }; static const struct axp_data axp813_data = { .ccc_scale = 200000, .ccc_offset = 200000, + .ccc_reg = AXP20X_CHRG_CTRL1, + .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR, .has_fg_valid = true, + .bat_ps_desc = &axp209_batt_ps_desc, .get_max_voltage = axp813_battery_get_max_voltage, .set_max_voltage = axp20x_battery_set_max_voltage, + .cfg_iio_chan = axp209_bat_cfg_iio_channels, + .set_bat_info = axp209_set_battery_info, }; static const struct of_device_id axp20x_battery_ps_id[] = { @@ -549,6 +1059,9 @@ static const struct of_device_id axp20x_battery_ps_id[] = { .compatible = "x-powers,axp221-battery-power-supply", .data = (void *)&axp221_data, }, { + .compatible = "x-powers,axp717-battery-power-supply", + .data = (void *)&axp717_data, + }, { .compatible = "x-powers,axp813-battery-power-supply", .data = (void *)&axp813_data, }, { /* sentinel */ }, @@ -561,6 +1074,7 @@ static int axp20x_power_probe(struct platform_device *pdev) struct power_supply_config psy_cfg = {}; struct power_supply_battery_info *info; struct device *dev = &pdev->dev; + int ret; if (!of_device_is_available(pdev->dev.of_node)) return -ENODEV; @@ -572,29 +1086,6 @@ static int axp20x_power_probe(struct platform_device *pdev) axp20x_batt->dev = &pdev->dev; - axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v"); - if (IS_ERR(axp20x_batt->batt_v)) { - if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(axp20x_batt->batt_v); - } - - axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev, - "batt_chrg_i"); - if (IS_ERR(axp20x_batt->batt_chrg_i)) { - if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(axp20x_batt->batt_chrg_i); - } - - axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev, - "batt_dischrg_i"); - if (IS_ERR(axp20x_batt->batt_dischrg_i)) { - if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(axp20x_batt->batt_dischrg_i); - } - axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL); platform_set_drvdata(pdev, axp20x_batt); @@ -603,8 +1094,12 @@ static int axp20x_power_probe(struct platform_device *pdev) axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev); + ret = axp20x_batt->data->cfg_iio_chan(pdev, axp20x_batt); + if (ret) + return ret; + axp20x_batt->batt = devm_power_supply_register(&pdev->dev, - &axp20x_batt_ps_desc, + axp20x_batt->data->bat_ps_desc, &psy_cfg); if (IS_ERR(axp20x_batt->batt)) { dev_err(&pdev->dev, "failed to register power supply: %ld\n", @@ -613,33 +1108,15 @@ static int axp20x_power_probe(struct platform_device *pdev) } if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) { - int vmin = info->voltage_min_design_uv; - int ccc = info->constant_charge_current_max_ua; - - if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt, - vmin)) - dev_err(&pdev->dev, - "couldn't set voltage_min_design\n"); - - /* Set max to unverified value to be able to set CCC */ - axp20x_batt->max_ccc = ccc; - - if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt, - ccc)) { - dev_err(&pdev->dev, - "couldn't set constant charge current from DT: fallback to minimum value\n"); - ccc = 300000; - axp20x_batt->max_ccc = ccc; - axp20x_set_constant_charge_current(axp20x_batt, ccc); - } + axp20x_batt->data->set_bat_info(pdev, axp20x_batt, info); + power_supply_put_battery_info(axp20x_batt->batt, info); } /* * Update max CCC to a valid value if battery info is present or set it * to current register value by default. */ - axp20x_get_constant_charge_current(axp20x_batt, - &axp20x_batt->max_ccc); + axp20x_get_constant_charge_current(axp20x_batt, &axp20x_batt->max_ccc); return 0; } diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index dae7e5cfc54e..2766352ab737 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -30,8 +30,13 @@ #define AXP20X_PWR_STATUS_VBUS_PRESENT BIT(5) #define AXP20X_PWR_STATUS_VBUS_USED BIT(4) +#define AXP717_PWR_STATUS_VBUS_GOOD BIT(5) + #define AXP20X_USB_STATUS_VBUS_VALID BIT(2) +#define AXP717_PMU_FAULT_VBUS BIT(5) +#define AXP717_PMU_FAULT_VSYS BIT(3) + #define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000) #define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3) #define AXP20X_VBUS_VHOLD_OFFSET 3 @@ -39,12 +44,20 @@ #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) +#define AXP717_INPUT_VOL_LIMIT_MASK GENMASK(3, 0) +#define AXP717_INPUT_CUR_LIMIT_MASK GENMASK(5, 0) +#define AXP717_ADC_DATA_MASK GENMASK(14, 0) + +#define AXP717_ADC_EN_VBUS_VOLT BIT(2) + /* * Note do not raise the debounce time, we must report Vusb high within * 100ms otherwise we get Vbus errors in musb. */ #define DEBOUNCE_TIME msecs_to_jiffies(50) +struct axp20x_usb_power; + struct axp_data { const struct power_supply_desc *power_desc; const char * const *irq_names; @@ -58,6 +71,10 @@ struct axp_data { struct reg_field usb_bc_det_fld; struct reg_field vbus_disable_bit; bool vbus_needs_polling: 1; + void (*axp20x_read_vbus)(struct work_struct *work); + int (*axp20x_cfg_iio_chan)(struct platform_device *pdev, + struct axp20x_usb_power *power); + int (*axp20x_cfg_adc_reg)(struct axp20x_usb_power *power); }; struct axp20x_usb_power { @@ -74,6 +91,7 @@ struct axp20x_usb_power { struct iio_channel *vbus_v; struct iio_channel *vbus_i; struct delayed_work vbus_detect; + int max_input_cur; unsigned int old_status; unsigned int online; unsigned int num_irqs; @@ -136,6 +154,24 @@ out: mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); } +static void axp717_usb_power_poll_vbus(struct work_struct *work) +{ + struct axp20x_usb_power *power = + container_of(work, struct axp20x_usb_power, vbus_detect.work); + unsigned int val; + int ret; + + ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &val); + if (ret) + return; + + val &= AXP717_PWR_STATUS_VBUS_GOOD; + if (val != power->old_status) + power_supply_changed(power->supply); + + power->old_status = val; +} + static int axp20x_get_usb_type(struct axp20x_usb_power *power, union power_supply_propval *val) { @@ -281,6 +317,91 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, return 0; } +static int axp717_usb_power_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct axp20x_usb_power *power = power_supply_get_drvdata(psy); + unsigned int v; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_HEALTH: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); + if (ret) + return ret; + + if (!(v & AXP717_PWR_STATUS_VBUS_GOOD)) + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + + ret = regmap_read(power->regmap, AXP717_PMU_FAULT_VBUS, &v); + if (ret) + return ret; + + v &= (AXP717_PMU_FAULT_VBUS | AXP717_PMU_FAULT_VSYS); + if (v) { + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + regmap_write(power->regmap, AXP717_PMU_FAULT_VBUS, v); + } + + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = regmap_read(power->regmap, AXP717_INPUT_CUR_LIMIT_CTRL, &v); + if (ret) + return ret; + + /* 50ma step size with 100ma offset. */ + v &= AXP717_INPUT_CUR_LIMIT_MASK; + val->intval = (v * 50000) + 100000; + break; + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_PRESENT: + ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v); + if (ret) + return ret; + val->intval = !!(v & AXP717_PWR_STATUS_VBUS_GOOD); + break; + case POWER_SUPPLY_PROP_USB_TYPE: + return axp20x_get_usb_type(power, val); + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + ret = regmap_read(power->regmap, AXP717_INPUT_VOL_LIMIT_CTRL, &v); + if (ret) + return ret; + + /* 80mv step size with 3.88v offset. */ + v &= AXP717_INPUT_VOL_LIMIT_MASK; + val->intval = (v * 80000) + 3880000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (IS_ENABLED(CONFIG_AXP20X_ADC)) { + ret = iio_read_channel_processed(power->vbus_v, + &val->intval); + if (ret) + return ret; + + /* + * IIO framework gives mV but Power Supply framework + * gives uV. + */ + val->intval *= 1000; + return 0; + } + + ret = axp20x_read_variable_width(power->regmap, + AXP717_VBUS_V_H, 16); + if (ret < 0) + return ret; + + val->intval = (ret % AXP717_ADC_DATA_MASK) * 1000; + break; + default: + return -EINVAL; + } + + return 0; + +} + static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, int intval) { @@ -307,6 +428,22 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, return -EINVAL; } +static int axp717_usb_power_set_voltage_min(struct axp20x_usb_power *power, + int intval) +{ + int val; + + /* Minimum value of 3.88v and maximum of 5.08v. */ + if (intval < 3880000 || intval > 5080000) + return -EINVAL; + + /* step size of 80ma with 3.88v offset. */ + val = (intval - 3880000) / 80000; + return regmap_update_bits(power->regmap, + AXP717_INPUT_VOL_LIMIT_CTRL, + AXP717_INPUT_VOL_LIMIT_MASK, val); +} + static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *power, int intval) { @@ -317,6 +454,13 @@ static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *pow if (intval == -1) return -EINVAL; + if (power->max_input_cur && (intval > power->max_input_cur)) { + dev_warn(power->dev, + "requested current %d clamped to max current %d\n", + intval, power->max_input_cur); + intval = power->max_input_cur; + } + /* * BC1.2 detection can cause a race condition if we try to set a current * limit while it's in progress. When it finishes it will overwrite the @@ -340,6 +484,29 @@ static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *pow return regmap_field_write(power->curr_lim_fld, reg); } +static int axp717_usb_power_set_input_current_limit(struct axp20x_usb_power *power, + int intval) +{ + int tmp; + + /* Minimum value of 100mA and maximum value of 3.25A*/ + if (intval < 100000 || intval > 3250000) + return -EINVAL; + + if (power->max_input_cur && (intval > power->max_input_cur)) { + dev_warn(power->dev, + "reqested current %d clamped to max current %d\n", + intval, power->max_input_cur); + intval = power->max_input_cur; + } + + /* Minimum value of 100mA with step size of 50mA. */ + tmp = (intval - 100000) / 50000; + return regmap_update_bits(power->regmap, + AXP717_INPUT_CUR_LIMIT_CTRL, + AXP717_INPUT_CUR_LIMIT_MASK, tmp); +} + static int axp20x_usb_power_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) @@ -362,6 +529,24 @@ static int axp20x_usb_power_set_property(struct power_supply *psy, default: return -EINVAL; } +} + +static int axp717_usb_power_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct axp20x_usb_power *power = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return axp717_usb_power_set_input_current_limit(power, val->intval); + + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + return axp717_usb_power_set_voltage_min(power, val->intval); + + default: + return -EINVAL; + } return -EINVAL; } @@ -385,6 +570,64 @@ static int axp20x_usb_power_prop_writeable(struct power_supply *psy, psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT; } +static int axp717_usb_power_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || + psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT; +} + +static int axp20x_configure_iio_channels(struct platform_device *pdev, + struct axp20x_usb_power *power) +{ + power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); + if (IS_ERR(power->vbus_v)) { + if (PTR_ERR(power->vbus_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->vbus_v); + } + + power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); + if (IS_ERR(power->vbus_i)) { + if (PTR_ERR(power->vbus_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->vbus_i); + } + + return 0; +} + +static int axp717_configure_iio_channels(struct platform_device *pdev, + struct axp20x_usb_power *power) +{ + power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); + if (IS_ERR(power->vbus_v)) { + if (PTR_ERR(power->vbus_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->vbus_v); + } + + return 0; +} + +static int axp20x_configure_adc_registers(struct axp20x_usb_power *power) +{ + /* Enable vbus voltage and current measurement */ + return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, + AXP20X_ADC_EN1_VBUS_CURR | + AXP20X_ADC_EN1_VBUS_VOLT, + AXP20X_ADC_EN1_VBUS_CURR | + AXP20X_ADC_EN1_VBUS_VOLT); +} + +static int axp717_configure_adc_registers(struct axp20x_usb_power *power) +{ + /* Enable vbus voltage measurement */ + return regmap_update_bits(power->regmap, AXP717_ADC_CH_EN_CONTROL, + AXP717_ADC_EN_VBUS_VOLT, + AXP717_ADC_EN_VBUS_VOLT); +} + static enum power_supply_property axp20x_usb_power_properties[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, @@ -403,6 +646,16 @@ static enum power_supply_property axp22x_usb_power_properties[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, }; +static enum power_supply_property axp717_usb_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + static enum power_supply_property axp813_usb_power_properties[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, @@ -412,13 +665,6 @@ static enum power_supply_property axp813_usb_power_properties[] = { POWER_SUPPLY_PROP_USB_TYPE, }; -static enum power_supply_usb_type axp813_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static const struct power_supply_desc axp20x_usb_power_desc = { .name = "axp20x-usb", .type = POWER_SUPPLY_TYPE_USB, @@ -439,6 +685,20 @@ static const struct power_supply_desc axp22x_usb_power_desc = { .set_property = axp20x_usb_power_set_property, }; +static const struct power_supply_desc axp717_usb_power_desc = { + .name = "axp20x-usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = axp717_usb_power_properties, + .num_properties = ARRAY_SIZE(axp717_usb_power_properties), + .property_is_writeable = axp717_usb_power_prop_writeable, + .get_property = axp717_usb_power_get_property, + .set_property = axp717_usb_power_set_property, + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), +}; + static const struct power_supply_desc axp813_usb_power_desc = { .name = "axp20x-usb", .type = POWER_SUPPLY_TYPE_USB, @@ -447,8 +707,10 @@ static const struct power_supply_desc axp813_usb_power_desc = { .property_is_writeable = axp20x_usb_power_prop_writeable, .get_property = axp20x_usb_power_get_property, .set_property = axp20x_usb_power_set_property, - .usb_types = axp813_usb_types, - .num_usb_types = ARRAY_SIZE(axp813_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), }; static const char * const axp20x_irq_names[] = { @@ -463,6 +725,12 @@ static const char * const axp22x_irq_names[] = { "VBUS_REMOVAL", }; +static const char * const axp717_irq_names[] = { + "VBUS_PLUGIN", + "VBUS_REMOVAL", + "VBUS_OVER_V", +}; + static int axp192_usb_curr_lim_table[] = { -1, -1, @@ -505,6 +773,9 @@ static const struct axp_data axp192_data = { .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_valid_bit = REG_FIELD(AXP192_USB_OTG_STATUS, 2, 2), .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), + .axp20x_read_vbus = &axp20x_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp20x_configure_iio_channels, + .axp20x_cfg_adc_reg = axp20x_configure_adc_registers, }; static const struct axp_data axp202_data = { @@ -516,6 +787,9 @@ static const struct axp_data axp202_data = { .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_valid_bit = REG_FIELD(AXP20X_USB_OTG_STATUS, 2, 2), .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), + .axp20x_read_vbus = &axp20x_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp20x_configure_iio_channels, + .axp20x_cfg_adc_reg = axp20x_configure_adc_registers, }; static const struct axp_data axp221_data = { @@ -526,6 +800,9 @@ static const struct axp_data axp221_data = { .curr_lim_table_size = ARRAY_SIZE(axp221_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_needs_polling = true, + .axp20x_read_vbus = &axp20x_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp20x_configure_iio_channels, + .axp20x_cfg_adc_reg = axp20x_configure_adc_registers, }; static const struct axp_data axp223_data = { @@ -536,6 +813,23 @@ static const struct axp_data axp223_data = { .curr_lim_table_size = ARRAY_SIZE(axp20x_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_needs_polling = true, + .axp20x_read_vbus = &axp20x_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp20x_configure_iio_channels, + .axp20x_cfg_adc_reg = axp20x_configure_adc_registers, +}; + +static const struct axp_data axp717_data = { + .power_desc = &axp717_usb_power_desc, + .irq_names = axp717_irq_names, + .num_irq_names = ARRAY_SIZE(axp717_irq_names), + .curr_lim_fld = REG_FIELD(AXP717_INPUT_CUR_LIMIT_CTRL, 0, 5), + .usb_bc_en_bit = REG_FIELD(AXP717_MODULE_EN_CONTROL_1, 4, 4), + .usb_bc_det_fld = REG_FIELD(AXP717_BC_DETECT, 5, 7), + .vbus_mon_bit = REG_FIELD(AXP717_ADC_CH_EN_CONTROL, 2, 2), + .vbus_needs_polling = false, + .axp20x_read_vbus = &axp717_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp717_configure_iio_channels, + .axp20x_cfg_adc_reg = axp717_configure_adc_registers, }; static const struct axp_data axp813_data = { @@ -549,6 +843,9 @@ static const struct axp_data axp813_data = { .usb_bc_det_fld = REG_FIELD(AXP288_BC_DET_STAT, 5, 7), .vbus_disable_bit = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 7, 7), .vbus_needs_polling = true, + .axp20x_read_vbus = &axp20x_usb_power_poll_vbus, + .axp20x_cfg_iio_chan = axp20x_configure_iio_channels, + .axp20x_cfg_adc_reg = axp20x_configure_adc_registers, }; #ifdef CONFIG_PM_SLEEP @@ -590,36 +887,6 @@ static int axp20x_usb_power_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(axp20x_usb_power_pm_ops, axp20x_usb_power_suspend, axp20x_usb_power_resume); -static int configure_iio_channels(struct platform_device *pdev, - struct axp20x_usb_power *power) -{ - power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); - if (IS_ERR(power->vbus_v)) { - if (PTR_ERR(power->vbus_v) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(power->vbus_v); - } - - power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); - if (IS_ERR(power->vbus_i)) { - if (PTR_ERR(power->vbus_i) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(power->vbus_i); - } - - return 0; -} - -static int configure_adc_registers(struct axp20x_usb_power *power) -{ - /* Enable vbus voltage and current measurement */ - return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, - AXP20X_ADC_EN1_VBUS_CURR | - AXP20X_ADC_EN1_VBUS_VOLT, - AXP20X_ADC_EN1_VBUS_CURR | - AXP20X_ADC_EN1_VBUS_VOLT); -} - static int axp20x_regmap_field_alloc_optional(struct device *dev, struct regmap *regmap, struct reg_field fdesc, @@ -640,6 +907,18 @@ static int axp20x_regmap_field_alloc_optional(struct device *dev, return 0; } +/* Optionally allow users to specify a maximum charging current. */ +static void axp20x_usb_power_parse_dt(struct device *dev, + struct axp20x_usb_power *power) +{ + int ret; + + ret = device_property_read_u32(dev, "input-current-limit-microamp", + &power->max_input_cur); + if (ret) + dev_dbg(dev, "%s() no input-current-limit specified\n", __func__); +} + static int axp20x_usb_power_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); @@ -676,6 +955,8 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (IS_ERR(power->curr_lim_fld)) return PTR_ERR(power->curr_lim_fld); + axp20x_usb_power_parse_dt(&pdev->dev, power); + ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, axp_data->vbus_valid_bit, &power->vbus_valid_bit); @@ -707,7 +988,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) return ret; ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect, - axp20x_usb_power_poll_vbus); + axp_data->axp20x_read_vbus); if (ret) return ret; @@ -718,9 +999,9 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) return ret; if (IS_ENABLED(CONFIG_AXP20X_ADC)) - ret = configure_iio_channels(pdev, power); + ret = axp_data->axp20x_cfg_iio_chan(pdev, power); else - ret = configure_adc_registers(power); + ret = axp_data->axp20x_cfg_adc_reg(power); if (ret) return ret; @@ -779,6 +1060,9 @@ static const struct of_device_id axp20x_usb_power_match[] = { .compatible = "x-powers,axp223-usb-power-supply", .data = &axp223_data, }, { + .compatible = "x-powers,axp717-usb-power-supply", + .data = &axp717_data, + }, { .compatible = "x-powers,axp813-usb-power-supply", .data = &axp813_data, }, { /* sentinel */ } diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index 1a935bc88510..5514d1896bb8 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -334,14 +334,6 @@ static const int bq25618_619_ichg_values[] = { 1290000, 1360000, 1430000, 1500000 }; -static enum power_supply_usb_type bq256xx_usb_type[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_ACA, -}; - static int bq256xx_array_parse(int array_size, int val, const int array[]) { int i = 0; @@ -1252,8 +1244,11 @@ static int bq256xx_property_is_writeable(struct power_supply *psy, static const struct power_supply_desc bq256xx_power_supply_desc = { .name = "bq256xx-charger", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = bq256xx_usb_type, - .num_usb_types = ARRAY_SIZE(bq256xx_usb_type), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_ACA) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = bq256xx_power_supply_props, .num_properties = ARRAY_SIZE(bq256xx_power_supply_props), .get_property = bq256xx_get_charger_property, diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index cebca34ff872..91e7292d86bb 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -904,7 +904,7 @@ static int cpcap_charger_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = ddata; psy_cfg.supplied_to = cpcap_charger_supplied_to; - psy_cfg.num_supplicants = ARRAY_SIZE(cpcap_charger_supplied_to), + psy_cfg.num_supplicants = ARRAY_SIZE(cpcap_charger_supplied_to); ddata->usb = devm_power_supply_register(ddata->dev, &cpcap_charger_usb_desc, diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 8008e31c0c09..bed3e2e9bfea 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -73,17 +73,6 @@ static enum power_supply_property cros_usbpd_dedicated_charger_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; -static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_DRP, - POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID -}; - /* Input voltage/current limit in mV/mA. Default to none. */ static u16 input_voltage_limit = EC_POWER_LIMIT_NONE; static u16 input_current_limit = EC_POWER_LIMIT_NONE; @@ -643,9 +632,14 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) psy_desc->properties = cros_usbpd_charger_props; psy_desc->num_properties = ARRAY_SIZE(cros_usbpd_charger_props); - psy_desc->usb_types = cros_usbpd_charger_usb_types; - psy_desc->num_usb_types = - ARRAY_SIZE(cros_usbpd_charger_usb_types); + psy_desc->usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) | + BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | + BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID); } psy_desc->name = port->name; diff --git a/drivers/power/supply/lenovo_yoga_c630_battery.c b/drivers/power/supply/lenovo_yoga_c630_battery.c index d4d422cc5353..f98f65e00831 100644 --- a/drivers/power/supply/lenovo_yoga_c630_battery.c +++ b/drivers/power/supply/lenovo_yoga_c630_battery.c @@ -353,15 +353,10 @@ static enum power_supply_property yoga_c630_psy_adpt_properties[] = { POWER_SUPPLY_PROP_USB_TYPE, }; -static const enum power_supply_usb_type yoga_c630_psy_adpt_usb_type[] = { - POWER_SUPPLY_USB_TYPE_C, -}; - static const struct power_supply_desc yoga_c630_psy_adpt_psy_desc = { .name = "yoga-c630-adapter", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = yoga_c630_psy_adpt_usb_type, - .num_usb_types = ARRAY_SIZE(yoga_c630_psy_adpt_usb_type), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_C), .properties = yoga_c630_psy_adpt_properties, .num_properties = ARRAY_SIZE(yoga_c630_psy_adpt_properties), .get_property = yoga_c630_psy_adpt_get_property, diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index e7d37e422c3f..496c3e1f2ee6 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -853,7 +853,10 @@ static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off) /* program interrupt thresholds such that we should * get interrupt for every 'off' perc change in the soc */ - regmap_read(map, MAX17042_RepSOC, &soc); + if (chip->pdata->enable_current_sense) + regmap_read(map, MAX17042_RepSOC, &soc); + else + regmap_read(map, MAX17042_VFSOC, &soc); soc >>= 8; soc_tr = (soc + off) << 8; if (off < soc) diff --git a/drivers/power/supply/max1720x_battery.c b/drivers/power/supply/max1720x_battery.c index edc262f0a62f..2bc3dce963a3 100644 --- a/drivers/power/supply/max1720x_battery.c +++ b/drivers/power/supply/max1720x_battery.c @@ -10,13 +10,16 @@ #include <linux/bitfield.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/nvmem-provider.h> #include <linux/power_supply.h> #include <linux/regmap.h> #include <asm/unaligned.h> /* Nonvolatile registers */ +#define MAX1720X_NXTABLE0 0x80 #define MAX1720X_NRSENSE 0xCF /* RSense in 10^-5 Ohm */ +#define MAX1720X_NDEVICE_NAME4 0xDF /* ModelGauge m5 */ #define MAX172XX_STATUS 0x00 /* Status */ @@ -46,6 +49,8 @@ static const char *const max17205_model = "MAX17205"; struct max1720x_device_info { struct regmap *regmap; + struct regmap *regmap_nv; + struct i2c_client *ancillary; int rsense; }; @@ -106,6 +111,134 @@ static const struct regmap_config max1720x_regmap_cfg = { .cache_type = REGCACHE_RBTREE, }; +static const struct regmap_range max1720x_nvmem_allow[] = { + regmap_reg_range(MAX1720X_NXTABLE0, MAX1720X_NDEVICE_NAME4), +}; + +static const struct regmap_range max1720x_nvmem_deny[] = { + regmap_reg_range(0x00, 0x7F), + regmap_reg_range(0xE0, 0xFF), +}; + +static const struct regmap_access_table max1720x_nvmem_regs = { + .yes_ranges = max1720x_nvmem_allow, + .n_yes_ranges = ARRAY_SIZE(max1720x_nvmem_allow), + .no_ranges = max1720x_nvmem_deny, + .n_no_ranges = ARRAY_SIZE(max1720x_nvmem_deny), +}; + +static const struct regmap_config max1720x_nvmem_regmap_cfg = { + .reg_bits = 8, + .val_bits = 16, + .max_register = MAX1720X_NDEVICE_NAME4, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + .rd_table = &max1720x_nvmem_regs, +}; + +static const struct nvmem_cell_info max1720x_nvmem_cells[] = { + { .name = "nXTable0", .offset = 0, .bytes = 2, }, + { .name = "nXTable1", .offset = 2, .bytes = 2, }, + { .name = "nXTable2", .offset = 4, .bytes = 2, }, + { .name = "nXTable3", .offset = 6, .bytes = 2, }, + { .name = "nXTable4", .offset = 8, .bytes = 2, }, + { .name = "nXTable5", .offset = 10, .bytes = 2, }, + { .name = "nXTable6", .offset = 12, .bytes = 2, }, + { .name = "nXTable7", .offset = 14, .bytes = 2, }, + { .name = "nXTable8", .offset = 16, .bytes = 2, }, + { .name = "nXTable9", .offset = 18, .bytes = 2, }, + { .name = "nXTable10", .offset = 20, .bytes = 2, }, + { .name = "nXTable11", .offset = 22, .bytes = 2, }, + { .name = "nUser18C", .offset = 24, .bytes = 2, }, + { .name = "nUser18D", .offset = 26, .bytes = 2, }, + { .name = "nODSCTh", .offset = 28, .bytes = 2, }, + { .name = "nODSCCfg", .offset = 30, .bytes = 2, }, + + { .name = "nOCVTable0", .offset = 32, .bytes = 2, }, + { .name = "nOCVTable1", .offset = 34, .bytes = 2, }, + { .name = "nOCVTable2", .offset = 36, .bytes = 2, }, + { .name = "nOCVTable3", .offset = 38, .bytes = 2, }, + { .name = "nOCVTable4", .offset = 40, .bytes = 2, }, + { .name = "nOCVTable5", .offset = 42, .bytes = 2, }, + { .name = "nOCVTable6", .offset = 44, .bytes = 2, }, + { .name = "nOCVTable7", .offset = 46, .bytes = 2, }, + { .name = "nOCVTable8", .offset = 48, .bytes = 2, }, + { .name = "nOCVTable9", .offset = 50, .bytes = 2, }, + { .name = "nOCVTable10", .offset = 52, .bytes = 2, }, + { .name = "nOCVTable11", .offset = 54, .bytes = 2, }, + { .name = "nIChgTerm", .offset = 56, .bytes = 2, }, + { .name = "nFilterCfg", .offset = 58, .bytes = 2, }, + { .name = "nVEmpty", .offset = 60, .bytes = 2, }, + { .name = "nLearnCfg", .offset = 62, .bytes = 2, }, + + { .name = "nQRTable00", .offset = 64, .bytes = 2, }, + { .name = "nQRTable10", .offset = 66, .bytes = 2, }, + { .name = "nQRTable20", .offset = 68, .bytes = 2, }, + { .name = "nQRTable30", .offset = 70, .bytes = 2, }, + { .name = "nCycles", .offset = 72, .bytes = 2, }, + { .name = "nFullCapNom", .offset = 74, .bytes = 2, }, + { .name = "nRComp0", .offset = 76, .bytes = 2, }, + { .name = "nTempCo", .offset = 78, .bytes = 2, }, + { .name = "nIAvgEmpty", .offset = 80, .bytes = 2, }, + { .name = "nFullCapRep", .offset = 82, .bytes = 2, }, + { .name = "nVoltTemp", .offset = 84, .bytes = 2, }, + { .name = "nMaxMinCurr", .offset = 86, .bytes = 2, }, + { .name = "nMaxMinVolt", .offset = 88, .bytes = 2, }, + { .name = "nMaxMinTemp", .offset = 90, .bytes = 2, }, + { .name = "nSOC", .offset = 92, .bytes = 2, }, + { .name = "nTimerH", .offset = 94, .bytes = 2, }, + + { .name = "nConfig", .offset = 96, .bytes = 2, }, + { .name = "nRippleCfg", .offset = 98, .bytes = 2, }, + { .name = "nMiscCfg", .offset = 100, .bytes = 2, }, + { .name = "nDesignCap", .offset = 102, .bytes = 2, }, + { .name = "nHibCfg", .offset = 104, .bytes = 2, }, + { .name = "nPackCfg", .offset = 106, .bytes = 2, }, + { .name = "nRelaxCfg", .offset = 108, .bytes = 2, }, + { .name = "nConvgCfg", .offset = 110, .bytes = 2, }, + { .name = "nNVCfg0", .offset = 112, .bytes = 2, }, + { .name = "nNVCfg1", .offset = 114, .bytes = 2, }, + { .name = "nNVCfg2", .offset = 116, .bytes = 2, }, + { .name = "nSBSCfg", .offset = 118, .bytes = 2, }, + { .name = "nROMID0", .offset = 120, .bytes = 2, }, + { .name = "nROMID1", .offset = 122, .bytes = 2, }, + { .name = "nROMID2", .offset = 124, .bytes = 2, }, + { .name = "nROMID3", .offset = 126, .bytes = 2, }, + + { .name = "nVAlrtTh", .offset = 128, .bytes = 2, }, + { .name = "nTAlrtTh", .offset = 130, .bytes = 2, }, + { .name = "nSAlrtTh", .offset = 132, .bytes = 2, }, + { .name = "nIAlrtTh", .offset = 134, .bytes = 2, }, + { .name = "nUser1C4", .offset = 136, .bytes = 2, }, + { .name = "nUser1C5", .offset = 138, .bytes = 2, }, + { .name = "nFullSOCThr", .offset = 140, .bytes = 2, }, + { .name = "nTTFCfg", .offset = 142, .bytes = 2, }, + { .name = "nCGain", .offset = 144, .bytes = 2, }, + { .name = "nTCurve", .offset = 146, .bytes = 2, }, + { .name = "nTGain", .offset = 148, .bytes = 2, }, + { .name = "nTOff", .offset = 150, .bytes = 2, }, + { .name = "nManfctrName0", .offset = 152, .bytes = 2, }, + { .name = "nManfctrName1", .offset = 154, .bytes = 2, }, + { .name = "nManfctrName2", .offset = 156, .bytes = 2, }, + { .name = "nRSense", .offset = 158, .bytes = 2, }, + + { .name = "nUser1D0", .offset = 160, .bytes = 2, }, + { .name = "nUser1D1", .offset = 162, .bytes = 2, }, + { .name = "nAgeFcCfg", .offset = 164, .bytes = 2, }, + { .name = "nDesignVoltage", .offset = 166, .bytes = 2, }, + { .name = "nUser1D4", .offset = 168, .bytes = 2, }, + { .name = "nRFastVShdn", .offset = 170, .bytes = 2, }, + { .name = "nManfctrDate", .offset = 172, .bytes = 2, }, + { .name = "nFirstUsed", .offset = 174, .bytes = 2, }, + { .name = "nSerialNumber0", .offset = 176, .bytes = 2, }, + { .name = "nSerialNumber1", .offset = 178, .bytes = 2, }, + { .name = "nSerialNumber2", .offset = 180, .bytes = 2, }, + { .name = "nDeviceName0", .offset = 182, .bytes = 2, }, + { .name = "nDeviceName1", .offset = 184, .bytes = 2, }, + { .name = "nDeviceName2", .offset = 186, .bytes = 2, }, + { .name = "nDeviceName3", .offset = 188, .bytes = 2, }, + { .name = "nDeviceName4", .offset = 190, .bytes = 2, }, +}; + static const enum power_supply_property max1720x_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, @@ -249,30 +382,80 @@ static int max1720x_battery_get_property(struct power_supply *psy, return ret; } -static int max1720x_probe_sense_resistor(struct i2c_client *client, - struct max1720x_device_info *info) +static +int max1720x_nvmem_reg_read(void *priv, unsigned int off, void *val, size_t len) +{ + struct max1720x_device_info *info = priv; + unsigned int reg = MAX1720X_NXTABLE0 + (off / 2); + + return regmap_bulk_read(info->regmap_nv, reg, val, len / 2); +} + +static void max1720x_unregister_ancillary(void *data) +{ + struct max1720x_device_info *info = data; + + i2c_unregister_device(info->ancillary); +} + +static int max1720x_probe_nvmem(struct i2c_client *client, + struct max1720x_device_info *info) { struct device *dev = &client->dev; - struct i2c_client *ancillary; + struct nvmem_config nvmem_config = { + .dev = dev, + .name = "max1720x_nvmem", + .cells = max1720x_nvmem_cells, + .ncells = ARRAY_SIZE(max1720x_nvmem_cells), + .read_only = true, + .root_only = true, + .reg_read = max1720x_nvmem_reg_read, + .size = ARRAY_SIZE(max1720x_nvmem_cells) * 2, + .word_size = 2, + .stride = 2, + .priv = info, + }; + struct nvmem_device *nvmem; + unsigned int val; int ret; - ancillary = i2c_new_ancillary_device(client, "nvmem", 0xb); - if (IS_ERR(ancillary)) { + info->ancillary = i2c_new_ancillary_device(client, "nvmem", 0xb); + if (IS_ERR(info->ancillary)) { dev_err(dev, "Failed to initialize ancillary i2c device\n"); - return PTR_ERR(ancillary); + return PTR_ERR(info->ancillary); } - ret = i2c_smbus_read_word_data(ancillary, MAX1720X_NRSENSE); - i2c_unregister_device(ancillary); - if (ret < 0) + ret = devm_add_action_or_reset(dev, max1720x_unregister_ancillary, info); + if (ret) { + dev_err(dev, "Failed to add unregister callback\n"); return ret; + } + + info->regmap_nv = devm_regmap_init_i2c(info->ancillary, + &max1720x_nvmem_regmap_cfg); + if (IS_ERR(info->regmap_nv)) { + dev_err(dev, "regmap initialization of nvmem failed\n"); + return PTR_ERR(info->regmap_nv); + } + + ret = regmap_read(info->regmap_nv, MAX1720X_NRSENSE, &val); + if (ret < 0) { + dev_err(dev, "Failed to read sense resistor value\n"); + return ret; + } - info->rsense = ret; + info->rsense = val; if (!info->rsense) { dev_warn(dev, "RSense not calibrated, set 10 mOhms!\n"); info->rsense = 1000; /* in regs in 10^-5 */ } + nvmem = devm_nvmem_register(dev, &nvmem_config); + if (IS_ERR(nvmem)) { + dev_err(dev, "Could not register nvmem!"); + return PTR_ERR(nvmem); + } + return 0; } @@ -299,15 +482,15 @@ static int max1720x_probe(struct i2c_client *client) psy_cfg.drv_data = info; psy_cfg.fwnode = dev_fwnode(dev); + i2c_set_clientdata(client, info); info->regmap = devm_regmap_init_i2c(client, &max1720x_regmap_cfg); if (IS_ERR(info->regmap)) return dev_err_probe(dev, PTR_ERR(info->regmap), "regmap initialization failed\n"); - ret = max1720x_probe_sense_resistor(client, info); + ret = max1720x_probe_nvmem(client, info); if (ret) - return dev_err_probe(dev, ret, - "Failed to read sense resistor value\n"); + return dev_err_probe(dev, ret, "Failed to probe nvmem\n"); bat = devm_power_supply_register(dev, &max1720x_bat_desc, &psy_cfg); if (IS_ERR(bat)) diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 2001e12c9f7d..4caac142c428 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -197,12 +197,58 @@ static int max77693_get_online(struct regmap *regmap, int *val) return 0; } +/* + * There are *two* current limit registers: + * - CHGIN limit, which limits the input current from the external charger; + * - Fast charge current limit, which limits the current going to the battery. + */ + +static int max77693_get_input_current_limit(struct regmap *regmap, int *val) +{ + unsigned int data; + int ret; + + ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_CNFG_09, &data); + if (ret < 0) + return ret; + + data &= CHG_CNFG_09_CHGIN_ILIM_MASK; + data >>= CHG_CNFG_09_CHGIN_ILIM_SHIFT; + + if (data <= 0x03) + /* The first four values (0x00..0x03) are 60mA */ + *val = 60000; + else + *val = data * 20000; /* 20mA steps */ + + return 0; +} + +static int max77693_get_fast_charge_current(struct regmap *regmap, int *val) +{ + unsigned int data; + int ret; + + ret = regmap_read(regmap, MAX77693_CHG_REG_CHG_CNFG_02, &data); + if (ret < 0) + return ret; + + data &= CHG_CNFG_02_CC_MASK; + data >>= CHG_CNFG_02_CC_SHIFT; + + *val = data * 33300; /* 33.3mA steps */ + + return 0; +} + static enum power_supply_property max77693_charger_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, }; @@ -231,6 +277,12 @@ static int max77693_charger_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: ret = max77693_get_online(regmap, &val->intval); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = max77693_get_input_current_limit(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = max77693_get_fast_charge_current(regmap, &val->intval); + break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = max77693_charger_model; break; diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c index c26023b19f26..418b882b163d 100644 --- a/drivers/power/supply/max8998_charger.c +++ b/drivers/power/supply/max8998_charger.c @@ -191,6 +191,7 @@ static const struct platform_device_id max8998_battery_id[] = { { "max8998-battery", TYPE_MAX8998 }, { } }; +MODULE_DEVICE_TABLE(platform, max8998_battery_id); static struct platform_driver max8998_battery_driver = { .driver = { diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c index 3a2a28fbba73..d281c1059629 100644 --- a/drivers/power/supply/mp2629_charger.c +++ b/drivers/power/supply/mp2629_charger.c @@ -94,14 +94,6 @@ struct mp2629_prop { int shift; }; -static enum power_supply_usb_type mp2629_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_PD_DRP, - POWER_SUPPLY_USB_TYPE_UNKNOWN -}; - static enum power_supply_property mp2629_charger_usb_props[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, @@ -487,8 +479,11 @@ unlock: static const struct power_supply_desc mp2629_usb_desc = { .name = "mp2629_usb", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = mp2629_usb_types, - .num_usb_types = ARRAY_SIZE(mp2629_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = mp2629_charger_usb_props, .num_properties = ARRAY_SIZE(mp2629_charger_usb_props), .get_property = mp2629_charger_usb_get_prop, diff --git a/drivers/power/supply/mt6360_charger.c b/drivers/power/supply/mt6360_charger.c index aca123783efc..e99e55148976 100644 --- a/drivers/power/supply/mt6360_charger.c +++ b/drivers/power/supply/mt6360_charger.c @@ -154,13 +154,6 @@ enum mt6360_pmu_chg_type { MT6360_CHG_TYPE_MAX, }; -static enum power_supply_usb_type mt6360_charger_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, -}; - static int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci, bool *pwr_rdy) { @@ -574,8 +567,10 @@ static const struct power_supply_desc mt6360_charger_desc = { .get_property = mt6360_charger_get_property, .set_property = mt6360_charger_set_property, .property_is_writeable = mt6360_charger_property_is_writeable, - .usb_types = mt6360_charger_usb_types, - .num_usb_types = ARRAY_SIZE(mt6360_charger_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), }; static const struct regulator_ops mt6360_chg_otg_ops = { diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c index e24fce087d80..ad8793bf997e 100644 --- a/drivers/power/supply/mt6370-charger.c +++ b/drivers/power/supply/mt6370-charger.c @@ -624,13 +624,6 @@ static enum power_supply_property mt6370_chg_properties[] = { POWER_SUPPLY_PROP_USB_TYPE, }; -static enum power_supply_usb_type mt6370_chg_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_DCP, -}; - static const struct power_supply_desc mt6370_chg_psy_desc = { .name = "mt6370-charger", .type = POWER_SUPPLY_TYPE_USB, @@ -639,8 +632,10 @@ static const struct power_supply_desc mt6370_chg_psy_desc = { .get_property = mt6370_chg_get_property, .set_property = mt6370_chg_set_property, .property_is_writeable = mt6370_chg_property_is_writeable, - .usb_types = mt6370_chg_usb_types, - .num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), }; static const struct regulator_ops mt6370_chg_otg_ops = { diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 8f6025acd10a..49534458a9f7 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -9,6 +9,7 @@ * Modified: 2004, Oct Szabolcs Gyurko */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> @@ -756,10 +757,10 @@ int power_supply_get_battery_info(struct power_supply *psy, for (index = 0; index < len; index++) { struct power_supply_battery_ocv_table *table; - char *propname; int i, tab_len, size; - propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", index); + char *propname __free(kfree) = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", + index); if (!propname) { power_supply_put_battery_info(psy, info); err = -ENOMEM; @@ -768,13 +769,11 @@ int power_supply_get_battery_info(struct power_supply *psy, list = of_get_property(battery_np, propname, &size); if (!list || !size) { dev_err(&psy->dev, "failed to get %s\n", propname); - kfree(propname); power_supply_put_battery_info(psy, info); err = -EINVAL; goto out_put_node; } - kfree(propname); tab_len = size / (2 * sizeof(__be32)); info->ocv_table_size[index] = tab_len; @@ -1232,11 +1231,7 @@ EXPORT_SYMBOL_GPL(power_supply_set_property); int power_supply_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { - if (atomic_read(&psy->use_cnt) <= 0 || - !psy->desc->property_is_writeable) - return -ENODEV; - - return psy->desc->property_is_writeable(psy, psp); + return psy->desc->property_is_writeable && psy->desc->property_is_writeable(psy, psp); } EXPORT_SYMBOL_GPL(power_supply_property_is_writeable); @@ -1296,7 +1291,7 @@ static int power_supply_read_temp(struct thermal_zone_device *tzd, return ret; } -static struct thermal_zone_device_ops psy_tzd_ops = { +static const struct thermal_zone_device_ops psy_tzd_ops = { .get_temp = power_supply_read_temp, }; @@ -1361,10 +1356,6 @@ __power_supply_register(struct device *parent, pr_warn("%s: Expected proper parent device for '%s'\n", __func__, desc->name); - if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) && - (!desc->usb_types || !desc->num_usb_types)) - return ERR_PTR(-EINVAL); - psy = kzalloc(sizeof(*psy), GFP_KERNEL); if (!psy) return ERR_PTR(-ENOMEM); diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c index baacefbdf768..6fbbfb1c685e 100644 --- a/drivers/power/supply/power_supply_hwmon.c +++ b/drivers/power/supply/power_supply_hwmon.c @@ -318,7 +318,8 @@ static const struct hwmon_channel_info * const power_supply_hwmon_info[] = { HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | - HWMON_T_MIN_ALARM, + HWMON_T_MIN_ALARM | + HWMON_T_MAX_ALARM, HWMON_T_LABEL | HWMON_T_INPUT | diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 3e63d165b2f7..16b3c5880cd8 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -209,7 +209,7 @@ static struct power_supply_attr power_supply_attrs[] = { POWER_SUPPLY_ATTR(TIME_TO_FULL_NOW), POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG), POWER_SUPPLY_ENUM_ATTR(TYPE), - POWER_SUPPLY_ATTR(USB_TYPE), + POWER_SUPPLY_ENUM_ATTR(USB_TYPE), POWER_SUPPLY_ENUM_ATTR(SCOPE), POWER_SUPPLY_ATTR(PRECHARGE_CURRENT), POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT), @@ -237,31 +237,28 @@ static enum power_supply_property dev_attr_psp(struct device_attribute *attr) return to_ps_attr(attr) - power_supply_attrs; } -static ssize_t power_supply_show_usb_type(struct device *dev, - const struct power_supply_desc *desc, - union power_supply_propval *value, - char *buf) +static ssize_t power_supply_show_enum_with_available( + struct device *dev, const char * const labels[], int label_count, + unsigned int available_values, int value, char *buf) { - enum power_supply_usb_type usb_type; + bool match = false, available, active; ssize_t count = 0; - bool match = false; int i; - for (i = 0; i < desc->num_usb_types; ++i) { - usb_type = desc->usb_types[i]; + for (i = 0; i < label_count; i++) { + available = available_values & BIT(i); + active = i == value; - if (value->intval == usb_type) { - count += sysfs_emit_at(buf, count, "[%s] ", - POWER_SUPPLY_USB_TYPE_TEXT[usb_type]); + if (available && active) { + count += sysfs_emit_at(buf, count, "[%s] ", labels[i]); match = true; - } else { - count += sysfs_emit_at(buf, count, "%s ", - POWER_SUPPLY_USB_TYPE_TEXT[usb_type]); + } else if (available) { + count += sysfs_emit_at(buf, count, "%s ", labels[i]); } } if (!match) { - dev_warn(dev, "driver reporting unsupported connected type\n"); + dev_warn(dev, "driver reporting unavailable enum value %d\n", value); return -EINVAL; } @@ -300,8 +297,10 @@ static ssize_t power_supply_show_property(struct device *dev, switch (psp) { case POWER_SUPPLY_PROP_USB_TYPE: - ret = power_supply_show_usb_type(dev, psy->desc, - &value, buf); + ret = power_supply_show_enum_with_available( + dev, POWER_SUPPLY_USB_TYPE_TEXT, + ARRAY_SIZE(POWER_SUPPLY_USB_TYPE_TEXT), + psy->desc->usb_types, value.intval, buf); break; case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ret = power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours, @@ -523,33 +522,10 @@ ssize_t power_supply_charge_behaviour_show(struct device *dev, enum power_supply_charge_behaviour current_behaviour, char *buf) { - bool match = false, available, active; - ssize_t count = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT); i++) { - available = available_behaviours & BIT(i); - active = i == current_behaviour; - - if (available && active) { - count += sysfs_emit_at(buf, count, "[%s] ", - POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); - match = true; - } else if (available) { - count += sysfs_emit_at(buf, count, "%s ", - POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); - } - } - - if (!match) { - dev_warn(dev, "driver reporting unsupported charge behaviour\n"); - return -EINVAL; - } - - if (count) - buf[count - 1] = '\n'; - - return count; + return power_supply_show_enum_with_available( + dev, POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT, + ARRAY_SIZE(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT), + available_behaviours, current_behaviour, buf); } EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_show); diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c index 8b3df3ee59ba..f0a64c00ddaa 100644 --- a/drivers/power/supply/qcom_battmgr.c +++ b/drivers/power/supply/qcom_battmgr.c @@ -786,19 +786,6 @@ static int qcom_battmgr_usb_get_property(struct power_supply *psy, return 0; } -static const enum power_supply_usb_type usb_psy_supported_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_ACA, - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_DRP, - POWER_SUPPLY_USB_TYPE_PD_PPS, - POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, -}; - static const enum power_supply_property sc8280xp_usb_props[] = { POWER_SUPPLY_PROP_ONLINE, }; @@ -809,8 +796,16 @@ static const struct power_supply_desc sc8280xp_usb_psy_desc = { .properties = sc8280xp_usb_props, .num_properties = ARRAY_SIZE(sc8280xp_usb_props), .get_property = qcom_battmgr_usb_get_property, - .usb_types = usb_psy_supported_types, - .num_usb_types = ARRAY_SIZE(usb_psy_supported_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) | + BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_ACA) | + BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) | + BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID), }; static const enum power_supply_property sm8350_usb_props[] = { @@ -829,8 +824,16 @@ static const struct power_supply_desc sm8350_usb_psy_desc = { .properties = sm8350_usb_props, .num_properties = ARRAY_SIZE(sm8350_usb_props), .get_property = qcom_battmgr_usb_get_property, - .usb_types = usb_psy_supported_types, - .num_usb_types = ARRAY_SIZE(usb_psy_supported_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) | + BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_ACA) | + BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) | + BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID), }; static const u8 sm8350_wls_prop_map[] = { diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c index 9bb777406013..81acbd8b2169 100644 --- a/drivers/power/supply/qcom_pmi8998_charger.c +++ b/drivers/power/supply/qcom_pmi8998_charger.c @@ -411,13 +411,6 @@ static enum power_supply_property smb2_properties[] = { POWER_SUPPLY_PROP_USB_TYPE, }; -static enum power_supply_usb_type smb2_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, -}; - static int smb2_get_prop_usb_online(struct smb2_chip *chip, int *val) { unsigned int stat; @@ -775,8 +768,10 @@ static irqreturn_t smb2_handle_wdog_bark(int irq, void *data) static const struct power_supply_desc smb2_psy_desc = { .name = "pmi8998_charger", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = smb2_usb_types, - .num_usb_types = ARRAY_SIZE(smb2_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = smb2_properties, .num_properties = ARRAY_SIZE(smb2_properties), .get_property = smb2_get_property, diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index 7ca91739c6cc..a3d377a32b49 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -673,11 +673,6 @@ static enum power_supply_property rk817_chg_props[] = { POWER_SUPPLY_PROP_VOLTAGE_AVG, }; -static enum power_supply_usb_type rk817_usb_type[] = { - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static const struct power_supply_desc rk817_bat_desc = { .name = "rk817-battery", .type = POWER_SUPPLY_TYPE_BATTERY, @@ -689,8 +684,8 @@ static const struct power_supply_desc rk817_bat_desc = { static const struct power_supply_desc rk817_chg_desc = { .name = "rk817-charger", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = rk817_usb_type, - .num_usb_types = ARRAY_SIZE(rk817_usb_type), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = rk817_chg_props, .num_properties = ARRAY_SIZE(rk817_chg_props), .get_property = rk817_chg_get_prop, diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c index ebea3522a2ac..40dec55a9f73 100644 --- a/drivers/power/supply/rn5t618_power.c +++ b/drivers/power/supply/rn5t618_power.c @@ -70,13 +70,6 @@ struct rn5t618_power_info { int irq; }; -static enum power_supply_usb_type rn5t618_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_UNKNOWN -}; - static enum power_supply_property rn5t618_usb_props[] = { /* input current limit is not very accurate */ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, @@ -681,8 +674,10 @@ static const struct power_supply_desc rn5t618_adp_desc = { static const struct power_supply_desc rn5t618_usb_desc = { .name = "rn5t618-usb", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = rn5t618_usb_types, - .num_usb_types = ARRAY_SIZE(rn5t618_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = rn5t618_usb_props, .num_properties = ARRAY_SIZE(rn5t618_usb_props), .get_property = rn5t618_usb_get_property, diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index fdfdc83ab045..235169c85c5d 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -630,13 +630,6 @@ out: return ret; } -static const enum power_supply_usb_type rt9467_chg_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, -}; - static const enum power_supply_property rt9467_chg_properties[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, @@ -745,8 +738,6 @@ static int rt9467_psy_set_property(struct power_supply *psy, RT9467_RANGE_IPREC, val->intval); case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: return rt9467_psy_set_ieoc(data, val->intval); - case POWER_SUPPLY_PROP_USB_TYPE: - return regmap_field_write(data->rm_field[F_USBCHGEN], val->intval); default: return -EINVAL; } @@ -764,7 +755,6 @@ static int rt9467_chg_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: - case POWER_SUPPLY_PROP_USB_TYPE: return 1; default: return 0; @@ -774,8 +764,10 @@ static int rt9467_chg_prop_is_writeable(struct power_supply *psy, static const struct power_supply_desc rt9467_chg_psy_desc = { .name = "rt9467-charger", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = rt9467_chg_usb_types, - .num_usb_types = ARRAY_SIZE(rt9467_chg_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = rt9467_chg_properties, .num_properties = ARRAY_SIZE(rt9467_chg_properties), .property_is_writeable = rt9467_chg_prop_is_writeable, diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c index 868b0703d15c..c04af1ee89c6 100644 --- a/drivers/power/supply/rt9471.c +++ b/drivers/power/supply/rt9471.c @@ -333,14 +333,6 @@ static enum power_supply_property rt9471_charger_properties[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_usb_type rt9471_charger_usb_types[] = { - POWER_SUPPLY_USB_TYPE_UNKNOWN, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, -}; - static int rt9471_charger_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { @@ -726,8 +718,11 @@ static int rt9471_register_psy(struct rt9471_chip *chip) desc->name = psy_name; desc->type = POWER_SUPPLY_TYPE_USB; - desc->usb_types = rt9471_charger_usb_types; - desc->num_usb_types = ARRAY_SIZE(rt9471_charger_usb_types); + desc->usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN); desc->properties = rt9471_charger_properties; desc->num_properties = ARRAY_SIZE(rt9471_charger_properties); desc->get_property = rt9471_charger_get_property; diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 7b9b0b3e164e..f3f1a0862e93 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -363,7 +363,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) if (status < 0) return status; cur_reg |= oldreg << 8; - if (reg != oldreg) { + if (reg != cur_reg) { /* disable write protection for one write access for * BCIIREF */ status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c index 7970843a4f48..7382bec6a43c 100644 --- a/drivers/power/supply/ucs1002_power.c +++ b/drivers/power/supply/ucs1002_power.c @@ -296,22 +296,17 @@ static int ucs1002_set_max_current(struct ucs1002_info *info, u32 val) return 0; } -static enum power_supply_usb_type ucs1002_usb_types[] = { - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_CDP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static int ucs1002_set_usb_type(struct ucs1002_info *info, int val) { unsigned int mode; - if (val < 0 || val >= ARRAY_SIZE(ucs1002_usb_types)) - return -EINVAL; - - switch (ucs1002_usb_types[val]) { + switch (val) { + /* + * POWER_SUPPLY_USB_TYPE_UNKNOWN == 0, map this to dedicated for + * userspace API compatibility with older versions of this driver + * which mapped 0 to dedicated. + */ + case POWER_SUPPLY_USB_TYPE_UNKNOWN: case POWER_SUPPLY_USB_TYPE_PD: mode = V_SET_ACTIVE_MODE_DEDICATED; break; @@ -428,8 +423,11 @@ static int ucs1002_property_is_writeable(struct power_supply *psy, static const struct power_supply_desc ucs1002_charger_desc = { .name = "ucs1002", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = ucs1002_usb_types, - .num_usb_types = ARRAY_SIZE(ucs1002_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_CDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .get_property = ucs1002_get_property, .set_property = ucs1002_set_property, .property_is_writeable = ucs1002_property_is_writeable, diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 5a5bf3532ad7..31e3e9544bc0 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1339,12 +1339,6 @@ static void anx7411_get_gpio_irq(struct anx7411_data *ctx) dev_err(dev, "failed to get GPIO IRQ\n"); } -static enum power_supply_usb_type anx7411_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - static enum power_supply_property anx7411_psy_props[] = { POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, @@ -1422,8 +1416,9 @@ static int anx7411_psy_register(struct anx7411_data *ctx) psy_desc->name = psy_name; psy_desc->type = POWER_SUPPLY_TYPE_USB; - psy_desc->usb_types = anx7411_psy_usb_types; - psy_desc->num_usb_types = ARRAY_SIZE(anx7411_psy_usb_types); + psy_desc->usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); psy_desc->properties = anx7411_psy_props; psy_desc->num_properties = ARRAY_SIZE(anx7411_psy_props); diff --git a/drivers/usb/typec/rt1719.c b/drivers/usb/typec/rt1719.c index be02d420920e..0b0c23a0b014 100644 --- a/drivers/usb/typec/rt1719.c +++ b/drivers/usb/typec/rt1719.c @@ -109,12 +109,6 @@ struct rt1719_data { u16 conn_stat; }; -static const enum power_supply_usb_type rt1719_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS -}; - static const enum power_supply_property rt1719_psy_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, @@ -572,8 +566,9 @@ static int devm_rt1719_psy_register(struct rt1719_data *data) data->psy_desc.name = psy_name; data->psy_desc.type = POWER_SUPPLY_TYPE_USB; - data->psy_desc.usb_types = rt1719_psy_usb_types; - data->psy_desc.num_usb_types = ARRAY_SIZE(rt1719_psy_usb_types); + data->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); data->psy_desc.properties = rt1719_psy_properties; data->psy_desc.num_properties = ARRAY_SIZE(rt1719_psy_properties); data->psy_desc.get_property = rt1719_psy_get_property; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4b02d6474259..fc619478200f 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7483,12 +7483,6 @@ static int tcpm_psy_prop_writeable(struct power_supply *psy, } } -static enum power_supply_usb_type tcpm_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - static const char *tcpm_psy_name_prefix = "tcpm-source-psy-"; static int devm_tcpm_psy_register(struct tcpm_port *port) @@ -7509,8 +7503,9 @@ static int devm_tcpm_psy_register(struct tcpm_port *port) port_dev_name); port->psy_desc.name = psy_name; port->psy_desc.type = POWER_SUPPLY_TYPE_USB; - port->psy_desc.usb_types = tcpm_psy_usb_types; - port->psy_desc.num_usb_types = ARRAY_SIZE(tcpm_psy_usb_types); + port->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); port->psy_desc.properties = tcpm_psy_props; port->psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props); port->psy_desc.get_property = tcpm_psy_get_prop; diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index dd51a25480bf..d532670885e4 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -150,11 +150,6 @@ static enum power_supply_property tps6598x_psy_props[] = { POWER_SUPPLY_PROP_ONLINE, }; -static enum power_supply_usb_type tps6598x_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, -}; - static const char *tps6598x_psy_name_prefix = "tps6598x-source-psy-"; /* @@ -827,8 +822,8 @@ static int devm_tps6598_psy_register(struct tps6598x *tps) tps->psy_desc.name = psy_name; tps->psy_desc.type = POWER_SUPPLY_TYPE_USB; - tps->psy_desc.usb_types = tps6598x_psy_usb_types; - tps->psy_desc.num_usb_types = ARRAY_SIZE(tps6598x_psy_usb_types); + tps->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD); tps->psy_desc.properties = tps6598x_psy_props; tps->psy_desc.num_properties = ARRAY_SIZE(tps6598x_psy_props); tps->psy_desc.get_property = tps6598x_psy_get_prop; diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c index e623d80e177c..1c631c7855a9 100644 --- a/drivers/usb/typec/ucsi/psy.c +++ b/drivers/usb/typec/ucsi/psy.c @@ -254,12 +254,6 @@ static int ucsi_psy_get_prop(struct power_supply *psy, } } -static enum power_supply_usb_type ucsi_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - int ucsi_register_port_psy(struct ucsi_connector *con) { struct power_supply_config psy_cfg = {}; @@ -276,8 +270,9 @@ int ucsi_register_port_psy(struct ucsi_connector *con) con->psy_desc.name = psy_name; con->psy_desc.type = POWER_SUPPLY_TYPE_USB; - con->psy_desc.usb_types = ucsi_psy_usb_types; - con->psy_desc.num_usb_types = ARRAY_SIZE(ucsi_psy_usb_types); + con->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); con->psy_desc.properties = ucsi_psy_props; con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props); con->psy_desc.get_property = ucsi_psy_get_prop; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index e0cd66bd3b6d..f4dfc1871a95 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -115,8 +115,16 @@ enum axp20x_variants { #define AXP313A_IRQ_STATE 0x21 #define AXP717_ON_INDICATE 0x00 +#define AXP717_PMU_STATUS_2 0x01 +#define AXP717_BC_DETECT 0x05 +#define AXP717_PMU_FAULT 0x08 +#define AXP717_MODULE_EN_CONTROL_1 0x0b +#define AXP717_MIN_SYS_V_CONTROL 0x15 +#define AXP717_INPUT_VOL_LIMIT_CTRL 0x16 +#define AXP717_INPUT_CUR_LIMIT_CTRL 0x17 #define AXP717_MODULE_EN_CONTROL_2 0x19 #define AXP717_BOOST_CONTROL 0x1e +#define AXP717_VSYS_V_POWEROFF 0x24 #define AXP717_IRQ0_EN 0x40 #define AXP717_IRQ1_EN 0x41 #define AXP717_IRQ2_EN 0x42 @@ -127,6 +135,9 @@ enum axp20x_variants { #define AXP717_IRQ2_STATE 0x4a #define AXP717_IRQ3_STATE 0x4b #define AXP717_IRQ4_STATE 0x4c +#define AXP717_ICC_CHG_SET 0x62 +#define AXP717_ITERM_CHG_SET 0x63 +#define AXP717_CV_CHG_SET 0x64 #define AXP717_DCDC_OUTPUT_CONTROL 0x80 #define AXP717_DCDC1_CONTROL 0x83 #define AXP717_DCDC2_CONTROL 0x84 @@ -147,6 +158,19 @@ enum axp20x_variants { #define AXP717_CLDO3_CONTROL 0x9d #define AXP717_CLDO4_CONTROL 0x9e #define AXP717_CPUSLDO_CONTROL 0x9f +#define AXP717_BATT_PERCENT_DATA 0xa4 +#define AXP717_ADC_CH_EN_CONTROL 0xc0 +#define AXP717_BATT_V_H 0xc4 +#define AXP717_BATT_V_L 0xc5 +#define AXP717_VBUS_V_H 0xc6 +#define AXP717_VBUS_V_L 0xc7 +#define AXP717_VSYS_V_H 0xc8 +#define AXP717_VSYS_V_L 0xc9 +#define AXP717_BATT_CHRG_I_H 0xca +#define AXP717_BATT_CHRG_I_L 0xcb +#define AXP717_ADC_DATA_SEL 0xcd +#define AXP717_ADC_DATA_H 0xce +#define AXP717_ADC_DATA_L 0xcf #define AXP806_STARTUP_SRC 0x00 #define AXP806_CHIP_ID 0x03 diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index 54444ff2a5de..20c5e02ed9da 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -217,6 +217,10 @@ enum max77693_charger_battery_state { #define CHG_CNFG_01_CHGRSTRT_MASK (0x3 << CHG_CNFG_01_CHGRSTRT_SHIFT) #define CHG_CNFG_01_PQEN_MAKS BIT(CHG_CNFG_01_PQEN_SHIFT) +/* MAX77693_CHG_REG_CHG_CNFG_02 register */ +#define CHG_CNFG_02_CC_SHIFT 0 +#define CHG_CNFG_02_CC_MASK 0x3F + /* MAX77693_CHG_REG_CHG_CNFG_03 register */ #define CHG_CNFG_03_TOITH_SHIFT 0 #define CHG_CNFG_03_TOTIME_SHIFT 3 @@ -244,6 +248,7 @@ enum max77693_charger_battery_state { #define CHG_CNFG_12_VCHGINREG_MASK (0x3 << CHG_CNFG_12_VCHGINREG_SHIFT) /* MAX77693 CHG_CNFG_09 Register */ +#define CHG_CNFG_09_CHGIN_ILIM_SHIFT 0 #define CHG_CNFG_09_CHGIN_ILIM_MASK 0x7F /* MAX77693 CHG_CTRL Register */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 72dc7e45c90c..910d407ebe63 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -243,8 +243,7 @@ struct power_supply_desc { const char *name; enum power_supply_type type; u8 charge_behaviours; - const enum power_supply_usb_type *usb_types; - size_t num_usb_types; + u32 usb_types; const enum power_supply_property *properties; size_t num_properties; |