diff options
27 files changed, 908 insertions, 13 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index b77e30b9014e..27edc06e2495 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power | |||
| @@ -376,10 +376,42 @@ Description: | |||
| 376 | supply. Normally this is configured based on the type of | 376 | supply. Normally this is configured based on the type of |
| 377 | connection made (e.g. A configured SDP should output a maximum | 377 | connection made (e.g. A configured SDP should output a maximum |
| 378 | of 500mA so the input current limit is set to the same value). | 378 | of 500mA so the input current limit is set to the same value). |
| 379 | Use preferably input_power_limit, and for problems that can be | ||
| 380 | solved using power limit use input_current_limit. | ||
| 379 | 381 | ||
| 380 | Access: Read, Write | 382 | Access: Read, Write |
| 381 | Valid values: Represented in microamps | 383 | Valid values: Represented in microamps |
| 382 | 384 | ||
| 385 | What: /sys/class/power_supply/<supply_name>/input_voltage_limit | ||
| 386 | Date: May 2019 | ||
| 387 | Contact: linux-pm@vger.kernel.org | ||
| 388 | Description: | ||
| 389 | This entry configures the incoming VBUS voltage limit currently | ||
| 390 | set in the supply. Normally this is configured based on | ||
| 391 | system-level knowledge or user input (e.g. This is part of the | ||
| 392 | Pixel C's thermal management strategy to effectively limit the | ||
| 393 | input power to 5V when the screen is on to meet Google's skin | ||
| 394 | temperature targets). Note that this feature should not be | ||
| 395 | used for safety critical things. | ||
| 396 | Use preferably input_power_limit, and for problems that can be | ||
| 397 | solved using power limit use input_voltage_limit. | ||
| 398 | |||
| 399 | Access: Read, Write | ||
| 400 | Valid values: Represented in microvolts | ||
| 401 | |||
| 402 | What: /sys/class/power_supply/<supply_name>/input_power_limit | ||
| 403 | Date: May 2019 | ||
| 404 | Contact: linux-pm@vger.kernel.org | ||
| 405 | Description: | ||
| 406 | This entry configures the incoming power limit currently set | ||
| 407 | in the supply. Normally this is configured based on | ||
| 408 | system-level knowledge or user input. Use preferably this | ||
| 409 | feature to limit the incoming power and use current/voltage | ||
| 410 | limit only for problems that can be solved using power limit. | ||
| 411 | |||
| 412 | Access: Read, Write | ||
| 413 | Valid values: Represented in microwatts | ||
| 414 | |||
| 383 | What: /sys/class/power_supply/<supply_name>/online, | 415 | What: /sys/class/power_supply/<supply_name>/online, |
| 384 | Date: May 2007 | 416 | Date: May 2007 |
| 385 | Contact: linux-pm@vger.kernel.org | 417 | Contact: linux-pm@vger.kernel.org |
diff --git a/Documentation/ABI/testing/sysfs-class-power-wilco b/Documentation/ABI/testing/sysfs-class-power-wilco new file mode 100644 index 000000000000..da1d6ffe5e3c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-power-wilco | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | What: /sys/class/power_supply/wilco-charger/charge_type | ||
| 2 | Date: April 2019 | ||
| 3 | KernelVersion: 5.2 | ||
| 4 | Description: | ||
| 5 | What charging algorithm to use: | ||
| 6 | |||
| 7 | Standard: Fully charges battery at a standard rate. | ||
| 8 | Adaptive: Battery settings adaptively optimized based on | ||
| 9 | typical battery usage pattern. | ||
| 10 | Fast: Battery charges over a shorter period. | ||
| 11 | Trickle: Extends battery lifespan, intended for users who | ||
| 12 | primarily use their Chromebook while connected to AC. | ||
| 13 | Custom: A low and high threshold percentage is specified. | ||
| 14 | Charging begins when level drops below | ||
| 15 | charge_control_start_threshold, and ceases when | ||
| 16 | level is above charge_control_end_threshold. | ||
| 17 | |||
| 18 | What: /sys/class/power_supply/wilco-charger/charge_control_start_threshold | ||
| 19 | Date: April 2019 | ||
| 20 | KernelVersion: 5.2 | ||
| 21 | Description: | ||
| 22 | Used when charge_type="Custom", as described above. Measured in | ||
| 23 | percentages. The valid range is [50, 95]. | ||
| 24 | |||
| 25 | What: /sys/class/power_supply/wilco-charger/charge_control_end_threshold | ||
| 26 | Date: April 2019 | ||
| 27 | KernelVersion: 5.2 | ||
| 28 | Description: | ||
| 29 | Used when charge_type="Custom", as described above. Measured in | ||
| 30 | percentages. The valid range is [55, 100]. | ||
diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt new file mode 100644 index 000000000000..752d6126d5da --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | NVMEM reboot mode driver | ||
| 2 | |||
| 3 | This driver gets reboot mode magic value from reboot-mode driver | ||
| 4 | and stores it in a NVMEM cell named "reboot-mode". Then the bootloader | ||
| 5 | can read it and take different action according to the magic | ||
| 6 | value stored. | ||
| 7 | |||
| 8 | Required properties: | ||
| 9 | - compatible: should be "nvmem-reboot-mode". | ||
| 10 | - nvmem-cells: A phandle to the reboot mode provided by a nvmem device. | ||
| 11 | - nvmem-cell-names: Should be "reboot-mode". | ||
| 12 | |||
| 13 | The rest of the properties should follow the generic reboot-mode description | ||
| 14 | found in reboot-mode.txt | ||
| 15 | |||
| 16 | Example: | ||
| 17 | reboot-mode { | ||
| 18 | compatible = "nvmem-reboot-mode"; | ||
| 19 | nvmem-cells = <&reboot_mode>; | ||
| 20 | nvmem-cell-names = "reboot-mode"; | ||
| 21 | |||
| 22 | mode-normal = <0xAAAA5501>; | ||
| 23 | mode-bootloader = <0xBBBB5500>; | ||
| 24 | mode-recovery = <0xCCCC5502>; | ||
| 25 | mode-test = <0xDDDD5503>; | ||
| 26 | }; | ||
diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt b/Documentation/devicetree/bindings/power/reset/qcom,pon.txt index 5705f575862d..0c0dc3a1e693 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.txt | |||
| @@ -9,6 +9,7 @@ Required Properties: | |||
| 9 | -compatible: Must be one of: | 9 | -compatible: Must be one of: |
| 10 | "qcom,pm8916-pon" | 10 | "qcom,pm8916-pon" |
| 11 | "qcom,pms405-pon" | 11 | "qcom,pms405-pon" |
| 12 | "qcom,pm8998-pon" | ||
| 12 | 13 | ||
| 13 | -reg: Specifies the physical address of the pon register | 14 | -reg: Specifies the physical address of the pon register |
| 14 | 15 | ||
diff --git a/Documentation/power/power_supply_class.rst b/Documentation/power/power_supply_class.rst index 3f2c3fe38a61..7b8c42f8b1de 100644 --- a/Documentation/power/power_supply_class.rst +++ b/Documentation/power/power_supply_class.rst | |||
| @@ -165,6 +165,12 @@ CONSTANT_CHARGE_VOLTAGE_MAX | |||
| 165 | INPUT_CURRENT_LIMIT | 165 | INPUT_CURRENT_LIMIT |
| 166 | input current limit programmed by charger. Indicates | 166 | input current limit programmed by charger. Indicates |
| 167 | the current drawn from a charging source. | 167 | the current drawn from a charging source. |
| 168 | INPUT_VOLTAGE_LIMIT | ||
| 169 | input voltage limit programmed by charger. Indicates | ||
| 170 | the voltage limit from a charging source. | ||
| 171 | INPUT_POWER_LIMIT | ||
| 172 | input power limit programmed by charger. Indicates | ||
| 173 | the power limit from a charging source. | ||
| 168 | 174 | ||
| 169 | CHARGE_CONTROL_LIMIT | 175 | CHARGE_CONTROL_LIMIT |
| 170 | current charge control limit setting | 176 | current charge control limit setting |
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 980951dff834..a564237278ff 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
| @@ -246,5 +246,15 @@ config POWER_RESET_SC27XX | |||
| 246 | PMICs includes the SC2720, SC2721, SC2723, SC2730 | 246 | PMICs includes the SC2720, SC2721, SC2723, SC2730 |
| 247 | and SC2731 chips. | 247 | and SC2731 chips. |
| 248 | 248 | ||
| 249 | config NVMEM_REBOOT_MODE | ||
| 250 | tristate "Generic NVMEM reboot mode driver" | ||
| 251 | depends on OF | ||
| 252 | select REBOOT_MODE | ||
| 253 | help | ||
| 254 | Say y here will enable reboot mode driver. This will | ||
| 255 | get reboot mode arguments and store it in a NVMEM cell, | ||
| 256 | then the bootloader can read it and take different | ||
| 257 | action according to the mode. | ||
| 258 | |||
| 249 | endif | 259 | endif |
| 250 | 260 | ||
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0aebee954ac1..85da3198e4e0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
| @@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o | |||
| 29 | obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o | 29 | obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o |
| 30 | obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o | 30 | obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o |
| 31 | obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o | 31 | obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o |
| 32 | obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o | ||
diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index 000000000000..e229308d43e2 --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright (c) Vaisala Oyj. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/init.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/of.h> | ||
| 10 | #include <linux/nvmem-consumer.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/reboot-mode.h> | ||
| 13 | |||
| 14 | struct nvmem_reboot_mode { | ||
| 15 | struct reboot_mode_driver reboot; | ||
| 16 | struct nvmem_cell *cell; | ||
| 17 | }; | ||
| 18 | |||
| 19 | static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, | ||
| 20 | unsigned int magic) | ||
| 21 | { | ||
| 22 | int ret; | ||
| 23 | struct nvmem_reboot_mode *nvmem_rbm; | ||
| 24 | |||
| 25 | nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); | ||
| 26 | |||
| 27 | ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); | ||
| 28 | if (ret < 0) | ||
| 29 | dev_err(reboot->dev, "update reboot mode bits failed\n"); | ||
| 30 | |||
| 31 | return ret; | ||
| 32 | } | ||
| 33 | |||
| 34 | static int nvmem_reboot_mode_probe(struct platform_device *pdev) | ||
| 35 | { | ||
| 36 | int ret; | ||
| 37 | struct nvmem_reboot_mode *nvmem_rbm; | ||
| 38 | |||
| 39 | nvmem_rbm = devm_kzalloc(&pdev->dev, sizeof(*nvmem_rbm), GFP_KERNEL); | ||
| 40 | if (!nvmem_rbm) | ||
| 41 | return -ENOMEM; | ||
| 42 | |||
| 43 | nvmem_rbm->reboot.dev = &pdev->dev; | ||
| 44 | nvmem_rbm->reboot.write = nvmem_reboot_mode_write; | ||
| 45 | |||
| 46 | nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode"); | ||
| 47 | if (IS_ERR(nvmem_rbm->cell)) { | ||
| 48 | dev_err(&pdev->dev, "failed to get the nvmem cell reboot-mode\n"); | ||
| 49 | return PTR_ERR(nvmem_rbm->cell); | ||
| 50 | } | ||
| 51 | |||
| 52 | ret = devm_reboot_mode_register(&pdev->dev, &nvmem_rbm->reboot); | ||
| 53 | if (ret) | ||
| 54 | dev_err(&pdev->dev, "can't register reboot mode\n"); | ||
| 55 | |||
| 56 | return ret; | ||
| 57 | } | ||
| 58 | |||
| 59 | static const struct of_device_id nvmem_reboot_mode_of_match[] = { | ||
| 60 | { .compatible = "nvmem-reboot-mode" }, | ||
| 61 | {} | ||
| 62 | }; | ||
| 63 | MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match); | ||
| 64 | |||
| 65 | static struct platform_driver nvmem_reboot_mode_driver = { | ||
| 66 | .probe = nvmem_reboot_mode_probe, | ||
| 67 | .driver = { | ||
| 68 | .name = "nvmem-reboot-mode", | ||
| 69 | .of_match_table = nvmem_reboot_mode_of_match, | ||
| 70 | }, | ||
| 71 | }; | ||
| 72 | module_platform_driver(nvmem_reboot_mode_driver); | ||
| 73 | |||
| 74 | MODULE_AUTHOR("Nandor Han <nandor.han@vaisala.com>"); | ||
| 75 | MODULE_DESCRIPTION("NVMEM reboot mode driver"); | ||
| 76 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c index 3fa1642d4c54..22a743a0bf28 100644 --- a/drivers/power/reset/qcom-pon.c +++ b/drivers/power/reset/qcom-pon.c | |||
| @@ -14,11 +14,15 @@ | |||
| 14 | 14 | ||
| 15 | #define PON_SOFT_RB_SPARE 0x8f | 15 | #define PON_SOFT_RB_SPARE 0x8f |
| 16 | 16 | ||
| 17 | #define GEN1_REASON_SHIFT 2 | ||
| 18 | #define GEN2_REASON_SHIFT 1 | ||
| 19 | |||
| 17 | struct pm8916_pon { | 20 | struct pm8916_pon { |
| 18 | struct device *dev; | 21 | struct device *dev; |
| 19 | struct regmap *regmap; | 22 | struct regmap *regmap; |
| 20 | u32 baseaddr; | 23 | u32 baseaddr; |
| 21 | struct reboot_mode_driver reboot_mode; | 24 | struct reboot_mode_driver reboot_mode; |
| 25 | long reason_shift; | ||
| 22 | }; | 26 | }; |
| 23 | 27 | ||
| 24 | static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, | 28 | static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, |
| @@ -30,7 +34,7 @@ static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, | |||
| 30 | 34 | ||
| 31 | ret = regmap_update_bits(pon->regmap, | 35 | ret = regmap_update_bits(pon->regmap, |
| 32 | pon->baseaddr + PON_SOFT_RB_SPARE, | 36 | pon->baseaddr + PON_SOFT_RB_SPARE, |
| 33 | 0xfc, magic << 2); | 37 | 0xfc, magic << pon->reason_shift); |
| 34 | if (ret < 0) | 38 | if (ret < 0) |
| 35 | dev_err(pon->dev, "update reboot mode bits failed\n"); | 39 | dev_err(pon->dev, "update reboot mode bits failed\n"); |
| 36 | 40 | ||
| @@ -60,6 +64,7 @@ static int pm8916_pon_probe(struct platform_device *pdev) | |||
| 60 | return error; | 64 | return error; |
| 61 | 65 | ||
| 62 | pon->reboot_mode.dev = &pdev->dev; | 66 | pon->reboot_mode.dev = &pdev->dev; |
| 67 | pon->reason_shift = (long)of_device_get_match_data(&pdev->dev); | ||
| 63 | pon->reboot_mode.write = pm8916_reboot_mode_write; | 68 | pon->reboot_mode.write = pm8916_reboot_mode_write; |
| 64 | error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode); | 69 | error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode); |
| 65 | if (error) { | 70 | if (error) { |
| @@ -73,8 +78,9 @@ static int pm8916_pon_probe(struct platform_device *pdev) | |||
| 73 | } | 78 | } |
| 74 | 79 | ||
| 75 | static const struct of_device_id pm8916_pon_id_table[] = { | 80 | static const struct of_device_id pm8916_pon_id_table[] = { |
| 76 | { .compatible = "qcom,pm8916-pon" }, | 81 | { .compatible = "qcom,pm8916-pon", .data = (void *)GEN1_REASON_SHIFT }, |
| 77 | { .compatible = "qcom,pms405-pon" }, | 82 | { .compatible = "qcom,pms405-pon", .data = (void *)GEN1_REASON_SHIFT }, |
| 83 | { .compatible = "qcom,pm8998-pon", .data = (void *)GEN2_REASON_SHIFT }, | ||
| 78 | { } | 84 | { } |
| 79 | }; | 85 | }; |
| 80 | MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); | 86 | MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); |
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index a873a0038cc8..5d91b5160b41 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig | |||
| @@ -15,6 +15,20 @@ config POWER_SUPPLY_DEBUG | |||
| 15 | Say Y here to enable debugging messages for power supply class | 15 | Say Y here to enable debugging messages for power supply class |
| 16 | and drivers. | 16 | and drivers. |
| 17 | 17 | ||
| 18 | config POWER_SUPPLY_HWMON | ||
| 19 | bool | ||
| 20 | prompt "Expose power supply sensors as hwmon device" | ||
| 21 | depends on HWMON=y || HWMON=POWER_SUPPLY | ||
| 22 | default y | ||
| 23 | help | ||
| 24 | This options enables API that allows sensors found on a | ||
| 25 | power supply device (current, voltage, temperature) to be | ||
| 26 | exposed as a hwmon device. | ||
| 27 | |||
| 28 | Say 'Y' here if you want power supplies to | ||
| 29 | have hwmon sysfs interface too. | ||
| 30 | |||
| 31 | |||
| 18 | config PDA_POWER | 32 | config PDA_POWER |
| 19 | tristate "Generic PDA/phone power driver" | 33 | tristate "Generic PDA/phone power driver" |
| 20 | depends on !S390 | 34 | depends on !S390 |
| @@ -698,4 +712,13 @@ config CHARGER_BD70528 | |||
| 698 | information and altering charger configurations from charger | 712 | information and altering charger configurations from charger |
| 699 | block of the ROHM BD70528 Power Management IC. | 713 | block of the ROHM BD70528 Power Management IC. |
| 700 | 714 | ||
| 715 | config CHARGER_WILCO | ||
| 716 | tristate "Wilco EC based charger for ChromeOS" | ||
| 717 | depends on WILCO_EC | ||
| 718 | help | ||
| 719 | Say Y here to enable control of the charging routines performed | ||
| 720 | by the Embedded Controller on the Chromebook named Wilco. Further | ||
| 721 | information can be found in | ||
| 722 | Documentation/ABI/testing/sysfs-class-power-wilco | ||
| 723 | |||
| 701 | endif # POWER_SUPPLY | 724 | endif # POWER_SUPPLY |
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 346a8ef5f348..96c2b74b36bf 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile | |||
| @@ -6,6 +6,7 @@ power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o | |||
| 6 | power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o | 6 | power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_POWER_SUPPLY) += power_supply.o | 8 | obj-$(CONFIG_POWER_SUPPLY) += power_supply.o |
| 9 | obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o | ||
| 9 | obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o | 10 | obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o |
| 10 | 11 | ||
| 11 | obj-$(CONFIG_PDA_POWER) += pda_power.o | 12 | obj-$(CONFIG_PDA_POWER) += pda_power.o |
| @@ -91,3 +92,4 @@ obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o | |||
| 91 | obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o | 92 | obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o |
| 92 | obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o | 93 | obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o |
| 93 | obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o | 94 | obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o |
| 95 | obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o | ||
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index a3dd1cfcfa8b..453d6332d43a 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c | |||
| @@ -1697,7 +1697,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi) | |||
| 1697 | static int bq24190_probe(struct i2c_client *client, | 1697 | static int bq24190_probe(struct i2c_client *client, |
| 1698 | const struct i2c_device_id *id) | 1698 | const struct i2c_device_id *id) |
| 1699 | { | 1699 | { |
| 1700 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1700 | struct i2c_adapter *adapter = client->adapter; |
| 1701 | struct device *dev = &client->dev; | 1701 | struct device *dev = &client->dev; |
| 1702 | struct power_supply_config charger_cfg = {}, battery_cfg = {}; | 1702 | struct power_supply_config charger_cfg = {}, battery_cfg = {}; |
| 1703 | struct bq24190_dev_info *bdi; | 1703 | struct bq24190_dev_info *bdi; |
diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index 7eb58f10e092..eb151687beb3 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c | |||
| @@ -950,7 +950,7 @@ static int bq24257_fw_probe(struct bq24257_device *bq) | |||
| 950 | static int bq24257_probe(struct i2c_client *client, | 950 | static int bq24257_probe(struct i2c_client *client, |
| 951 | const struct i2c_device_id *id) | 951 | const struct i2c_device_id *id) |
| 952 | { | 952 | { |
| 953 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 953 | struct i2c_adapter *adapter = client->adapter; |
| 954 | struct device *dev = &client->dev; | 954 | struct device *dev = &client->dev; |
| 955 | const struct acpi_device_id *acpi_id; | 955 | const struct acpi_device_id *acpi_id; |
| 956 | struct bq24257_device *bq; | 956 | struct bq24257_device *bq; |
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index b2ff82b4707a..d333f2b321b9 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c | |||
| @@ -817,7 +817,7 @@ static int bq25890_fw_probe(struct bq25890_device *bq) | |||
| 817 | static int bq25890_probe(struct i2c_client *client, | 817 | static int bq25890_probe(struct i2c_client *client, |
| 818 | const struct i2c_device_id *id) | 818 | const struct i2c_device_id *id) |
| 819 | { | 819 | { |
| 820 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 820 | struct i2c_adapter *adapter = client->adapter; |
| 821 | struct device *dev = &client->dev; | 821 | struct device *dev = &client->dev; |
| 822 | struct bq25890_device *bq; | 822 | struct bq25890_device *bq; |
| 823 | int ret; | 823 | int ret; |
diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 7e9c3984ef6a..3a9ea94c3de3 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c | |||
| @@ -53,6 +53,8 @@ struct charger_data { | |||
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | static enum power_supply_property cros_usbpd_charger_props[] = { | 55 | static enum power_supply_property cros_usbpd_charger_props[] = { |
| 56 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, | ||
| 57 | POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, | ||
| 56 | POWER_SUPPLY_PROP_ONLINE, | 58 | POWER_SUPPLY_PROP_ONLINE, |
| 57 | POWER_SUPPLY_PROP_STATUS, | 59 | POWER_SUPPLY_PROP_STATUS, |
| 58 | POWER_SUPPLY_PROP_CURRENT_MAX, | 60 | POWER_SUPPLY_PROP_CURRENT_MAX, |
| @@ -80,6 +82,10 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { | |||
| 80 | POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID | 82 | POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID |
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| 85 | /* Input voltage/current limit in mV/mA. Default to none. */ | ||
| 86 | static u16 input_voltage_limit = EC_POWER_LIMIT_NONE; | ||
| 87 | static u16 input_current_limit = EC_POWER_LIMIT_NONE; | ||
| 88 | |||
| 83 | static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port) | 89 | static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port) |
| 84 | { | 90 | { |
| 85 | return port->port_number >= port->charger->num_usbpd_ports; | 91 | return port->port_number >= port->charger->num_usbpd_ports; |
| @@ -324,6 +330,26 @@ static int cros_usbpd_charger_get_port_status(struct port_data *port, | |||
| 324 | return ret; | 330 | return ret; |
| 325 | } | 331 | } |
| 326 | 332 | ||
| 333 | static int cros_usbpd_charger_set_ext_power_limit(struct charger_data *charger, | ||
| 334 | u16 current_lim, | ||
| 335 | u16 voltage_lim) | ||
| 336 | { | ||
| 337 | struct ec_params_external_power_limit_v1 req; | ||
| 338 | int ret; | ||
| 339 | |||
| 340 | req.current_lim = current_lim; | ||
| 341 | req.voltage_lim = voltage_lim; | ||
| 342 | |||
| 343 | ret = cros_usbpd_charger_ec_command(charger, 0, | ||
| 344 | EC_CMD_EXTERNAL_POWER_LIMIT, | ||
| 345 | &req, sizeof(req), NULL, 0); | ||
| 346 | if (ret < 0) | ||
| 347 | dev_err(charger->dev, | ||
| 348 | "Unable to set the 'External Power Limit': %d\n", ret); | ||
| 349 | |||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 327 | static void cros_usbpd_charger_power_changed(struct power_supply *psy) | 353 | static void cros_usbpd_charger_power_changed(struct power_supply *psy) |
| 328 | { | 354 | { |
| 329 | struct port_data *port = power_supply_get_drvdata(psy); | 355 | struct port_data *port = power_supply_get_drvdata(psy); |
| @@ -396,6 +422,18 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy, | |||
| 396 | case POWER_SUPPLY_PROP_USB_TYPE: | 422 | case POWER_SUPPLY_PROP_USB_TYPE: |
| 397 | val->intval = port->psy_usb_type; | 423 | val->intval = port->psy_usb_type; |
| 398 | break; | 424 | break; |
| 425 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
| 426 | if (input_current_limit == EC_POWER_LIMIT_NONE) | ||
| 427 | val->intval = -1; | ||
| 428 | else | ||
| 429 | val->intval = input_current_limit * 1000; | ||
| 430 | break; | ||
| 431 | case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: | ||
| 432 | if (input_voltage_limit == EC_POWER_LIMIT_NONE) | ||
| 433 | val->intval = -1; | ||
| 434 | else | ||
| 435 | val->intval = input_voltage_limit * 1000; | ||
| 436 | break; | ||
| 399 | case POWER_SUPPLY_PROP_MODEL_NAME: | 437 | case POWER_SUPPLY_PROP_MODEL_NAME: |
| 400 | val->strval = port->model_name; | 438 | val->strval = port->model_name; |
| 401 | break; | 439 | break; |
| @@ -409,6 +447,81 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy, | |||
| 409 | return 0; | 447 | return 0; |
| 410 | } | 448 | } |
| 411 | 449 | ||
| 450 | static int cros_usbpd_charger_set_prop(struct power_supply *psy, | ||
| 451 | enum power_supply_property psp, | ||
| 452 | const union power_supply_propval *val) | ||
| 453 | { | ||
| 454 | struct port_data *port = power_supply_get_drvdata(psy); | ||
| 455 | struct charger_data *charger = port->charger; | ||
| 456 | struct device *dev = charger->dev; | ||
| 457 | u16 intval; | ||
| 458 | int ret; | ||
| 459 | |||
| 460 | /* U16_MAX in mV/mA is the maximum supported value */ | ||
| 461 | if (val->intval >= U16_MAX * 1000) | ||
| 462 | return -EINVAL; | ||
| 463 | /* A negative number is used to clear the limit */ | ||
| 464 | if (val->intval < 0) | ||
| 465 | intval = EC_POWER_LIMIT_NONE; | ||
| 466 | else /* Convert from uA/uV to mA/mV */ | ||
| 467 | intval = val->intval / 1000; | ||
| 468 | |||
| 469 | switch (psp) { | ||
| 470 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
| 471 | ret = cros_usbpd_charger_set_ext_power_limit(charger, intval, | ||
| 472 | input_voltage_limit); | ||
| 473 | if (ret < 0) | ||
| 474 | break; | ||
| 475 | |||
| 476 | input_current_limit = intval; | ||
| 477 | if (input_current_limit == EC_POWER_LIMIT_NONE) | ||
| 478 | dev_info(dev, | ||
| 479 | "External Current Limit cleared for all ports\n"); | ||
| 480 | else | ||
| 481 | dev_info(dev, | ||
| 482 | "External Current Limit set to %dmA for all ports\n", | ||
| 483 | input_current_limit); | ||
| 484 | break; | ||
| 485 | case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: | ||
| 486 | ret = cros_usbpd_charger_set_ext_power_limit(charger, | ||
| 487 | input_current_limit, | ||
| 488 | intval); | ||
| 489 | if (ret < 0) | ||
| 490 | break; | ||
| 491 | |||
| 492 | input_voltage_limit = intval; | ||
| 493 | if (input_voltage_limit == EC_POWER_LIMIT_NONE) | ||
| 494 | dev_info(dev, | ||
| 495 | "External Voltage Limit cleared for all ports\n"); | ||
| 496 | else | ||
| 497 | dev_info(dev, | ||
| 498 | "External Voltage Limit set to %dmV for all ports\n", | ||
| 499 | input_voltage_limit); | ||
| 500 | break; | ||
| 501 | default: | ||
| 502 | ret = -EINVAL; | ||
| 503 | } | ||
| 504 | |||
| 505 | return ret; | ||
| 506 | } | ||
| 507 | |||
| 508 | static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy, | ||
| 509 | enum power_supply_property psp) | ||
| 510 | { | ||
| 511 | int ret; | ||
| 512 | |||
| 513 | switch (psp) { | ||
| 514 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: | ||
| 515 | case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: | ||
| 516 | ret = 1; | ||
| 517 | break; | ||
| 518 | default: | ||
| 519 | ret = 0; | ||
| 520 | } | ||
| 521 | |||
| 522 | return ret; | ||
| 523 | } | ||
| 524 | |||
| 412 | static int cros_usbpd_charger_ec_event(struct notifier_block *nb, | 525 | static int cros_usbpd_charger_ec_event(struct notifier_block *nb, |
| 413 | unsigned long queued_during_suspend, | 526 | unsigned long queued_during_suspend, |
| 414 | void *_notify) | 527 | void *_notify) |
| @@ -525,6 +638,9 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) | |||
| 525 | 638 | ||
| 526 | psy_desc = &port->psy_desc; | 639 | psy_desc = &port->psy_desc; |
| 527 | psy_desc->get_property = cros_usbpd_charger_get_prop; | 640 | psy_desc->get_property = cros_usbpd_charger_get_prop; |
| 641 | psy_desc->set_property = cros_usbpd_charger_set_prop; | ||
| 642 | psy_desc->property_is_writeable = | ||
| 643 | cros_usbpd_charger_property_is_writeable; | ||
| 528 | psy_desc->external_power_changed = | 644 | psy_desc->external_power_changed = |
| 529 | cros_usbpd_charger_power_changed; | 645 | cros_usbpd_charger_power_changed; |
| 530 | psy_cfg.drv_data = port; | 646 | psy_cfg.drv_data = port; |
diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c index 68cfde4be632..3bbb8b4c8ae7 100644 --- a/drivers/power/supply/max14656_charger_detector.c +++ b/drivers/power/supply/max14656_charger_detector.c | |||
| @@ -247,7 +247,7 @@ static void stop_irq_work(void *data) | |||
| 247 | static int max14656_probe(struct i2c_client *client, | 247 | static int max14656_probe(struct i2c_client *client, |
| 248 | const struct i2c_device_id *id) | 248 | const struct i2c_device_id *id) |
| 249 | { | 249 | { |
| 250 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 250 | struct i2c_adapter *adapter = client->adapter; |
| 251 | struct device *dev = &client->dev; | 251 | struct device *dev = &client->dev; |
| 252 | struct power_supply_config psy_cfg = {}; | 252 | struct power_supply_config psy_cfg = {}; |
| 253 | struct max14656_chip *chip; | 253 | struct max14656_chip *chip; |
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 91cafc7bed30..62499018e68b 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c | |||
| @@ -193,7 +193,7 @@ static const struct power_supply_desc max17040_battery_desc = { | |||
| 193 | static int max17040_probe(struct i2c_client *client, | 193 | static int max17040_probe(struct i2c_client *client, |
| 194 | const struct i2c_device_id *id) | 194 | const struct i2c_device_id *id) |
| 195 | { | 195 | { |
| 196 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 196 | struct i2c_adapter *adapter = client->adapter; |
| 197 | struct power_supply_config psy_cfg = {}; | 197 | struct power_supply_config psy_cfg = {}; |
| 198 | struct max17040_chip *chip; | 198 | struct max17040_chip *chip; |
| 199 | 199 | ||
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 581c6bd23388..64f3358eaa3c 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c | |||
| @@ -1005,7 +1005,7 @@ static void max17042_stop_work(void *data) | |||
| 1005 | static int max17042_probe(struct i2c_client *client, | 1005 | static int max17042_probe(struct i2c_client *client, |
| 1006 | const struct i2c_device_id *id) | 1006 | const struct i2c_device_id *id) |
| 1007 | { | 1007 | { |
| 1008 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1008 | struct i2c_adapter *adapter = client->adapter; |
| 1009 | const struct power_supply_desc *max17042_desc = &max17042_psy_desc; | 1009 | const struct power_supply_desc *max17042_desc = &max17042_psy_desc; |
| 1010 | struct power_supply_config psy_cfg = {}; | 1010 | struct power_supply_config psy_cfg = {}; |
| 1011 | const struct acpi_device_id *acpi_id = NULL; | 1011 | const struct acpi_device_id *acpi_id = NULL; |
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index b55cdfe22a2e..82e84801264c 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c | |||
| @@ -1071,6 +1071,10 @@ __power_supply_register(struct device *parent, | |||
| 1071 | if (rc) | 1071 | if (rc) |
| 1072 | goto create_triggers_failed; | 1072 | goto create_triggers_failed; |
| 1073 | 1073 | ||
| 1074 | rc = power_supply_add_hwmon_sysfs(psy); | ||
| 1075 | if (rc) | ||
| 1076 | goto add_hwmon_sysfs_failed; | ||
| 1077 | |||
| 1074 | /* | 1078 | /* |
| 1075 | * Update use_cnt after any uevents (most notably from device_add()). | 1079 | * Update use_cnt after any uevents (most notably from device_add()). |
| 1076 | * We are here still during driver's probe but | 1080 | * We are here still during driver's probe but |
| @@ -1089,6 +1093,8 @@ __power_supply_register(struct device *parent, | |||
| 1089 | 1093 | ||
| 1090 | return psy; | 1094 | return psy; |
| 1091 | 1095 | ||
| 1096 | add_hwmon_sysfs_failed: | ||
| 1097 | power_supply_remove_triggers(psy); | ||
| 1092 | create_triggers_failed: | 1098 | create_triggers_failed: |
| 1093 | psy_unregister_cooler(psy); | 1099 | psy_unregister_cooler(psy); |
| 1094 | register_cooler_failed: | 1100 | register_cooler_failed: |
| @@ -1241,6 +1247,7 @@ void power_supply_unregister(struct power_supply *psy) | |||
| 1241 | cancel_work_sync(&psy->changed_work); | 1247 | cancel_work_sync(&psy->changed_work); |
| 1242 | cancel_delayed_work_sync(&psy->deferred_register_work); | 1248 | cancel_delayed_work_sync(&psy->deferred_register_work); |
| 1243 | sysfs_remove_link(&psy->dev.kobj, "powers"); | 1249 | sysfs_remove_link(&psy->dev.kobj, "powers"); |
| 1250 | power_supply_remove_hwmon_sysfs(psy); | ||
| 1244 | power_supply_remove_triggers(psy); | 1251 | power_supply_remove_triggers(psy); |
| 1245 | psy_unregister_cooler(psy); | 1252 | psy_unregister_cooler(psy); |
| 1246 | psy_unregister_thermal(psy); | 1253 | psy_unregister_thermal(psy); |
diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c new file mode 100644 index 000000000000..51fe60440d12 --- /dev/null +++ b/drivers/power/supply/power_supply_hwmon.c | |||
| @@ -0,0 +1,355 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * power_supply_hwmon.c - power supply hwmon support. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/err.h> | ||
| 7 | #include <linux/hwmon.h> | ||
| 8 | #include <linux/power_supply.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | |||
| 11 | struct power_supply_hwmon { | ||
| 12 | struct power_supply *psy; | ||
| 13 | unsigned long *props; | ||
| 14 | }; | ||
| 15 | |||
| 16 | static int power_supply_hwmon_in_to_property(u32 attr) | ||
| 17 | { | ||
| 18 | switch (attr) { | ||
| 19 | case hwmon_in_average: | ||
| 20 | return POWER_SUPPLY_PROP_VOLTAGE_AVG; | ||
| 21 | case hwmon_in_min: | ||
| 22 | return POWER_SUPPLY_PROP_VOLTAGE_MIN; | ||
| 23 | case hwmon_in_max: | ||
| 24 | return POWER_SUPPLY_PROP_VOLTAGE_MAX; | ||
| 25 | case hwmon_in_input: | ||
| 26 | return POWER_SUPPLY_PROP_VOLTAGE_NOW; | ||
| 27 | default: | ||
| 28 | return -EINVAL; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | static int power_supply_hwmon_curr_to_property(u32 attr) | ||
| 33 | { | ||
| 34 | switch (attr) { | ||
| 35 | case hwmon_curr_average: | ||
| 36 | return POWER_SUPPLY_PROP_CURRENT_AVG; | ||
| 37 | case hwmon_curr_max: | ||
| 38 | return POWER_SUPPLY_PROP_CURRENT_MAX; | ||
| 39 | case hwmon_curr_input: | ||
| 40 | return POWER_SUPPLY_PROP_CURRENT_NOW; | ||
| 41 | default: | ||
| 42 | return -EINVAL; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | static int power_supply_hwmon_temp_to_property(u32 attr, int channel) | ||
| 47 | { | ||
| 48 | if (channel) { | ||
| 49 | switch (attr) { | ||
| 50 | case hwmon_temp_input: | ||
| 51 | return POWER_SUPPLY_PROP_TEMP_AMBIENT; | ||
| 52 | case hwmon_temp_min_alarm: | ||
| 53 | return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN; | ||
| 54 | case hwmon_temp_max_alarm: | ||
| 55 | return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX; | ||
| 56 | default: | ||
| 57 | break; | ||
| 58 | } | ||
| 59 | } else { | ||
| 60 | switch (attr) { | ||
| 61 | case hwmon_temp_input: | ||
| 62 | return POWER_SUPPLY_PROP_TEMP; | ||
| 63 | case hwmon_temp_max: | ||
| 64 | return POWER_SUPPLY_PROP_TEMP_MAX; | ||
| 65 | case hwmon_temp_min: | ||
| 66 | return POWER_SUPPLY_PROP_TEMP_MIN; | ||
| 67 | case hwmon_temp_min_alarm: | ||
| 68 | return POWER_SUPPLY_PROP_TEMP_ALERT_MIN; | ||
| 69 | case hwmon_temp_max_alarm: | ||
| 70 | return POWER_SUPPLY_PROP_TEMP_ALERT_MAX; | ||
| 71 | default: | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | return -EINVAL; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int | ||
| 80 | power_supply_hwmon_to_property(enum hwmon_sensor_types type, | ||
| 81 | u32 attr, int channel) | ||
| 82 | { | ||
| 83 | switch (type) { | ||
| 84 | case hwmon_in: | ||
| 85 | return power_supply_hwmon_in_to_property(attr); | ||
| 86 | case hwmon_curr: | ||
| 87 | return power_supply_hwmon_curr_to_property(attr); | ||
| 88 | case hwmon_temp: | ||
| 89 | return power_supply_hwmon_temp_to_property(attr, channel); | ||
| 90 | default: | ||
| 91 | return -EINVAL; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | static bool power_supply_hwmon_is_a_label(enum hwmon_sensor_types type, | ||
| 96 | u32 attr) | ||
| 97 | { | ||
| 98 | return type == hwmon_temp && attr == hwmon_temp_label; | ||
| 99 | } | ||
| 100 | |||
| 101 | static bool power_supply_hwmon_is_writable(enum hwmon_sensor_types type, | ||
| 102 | u32 attr) | ||
| 103 | { | ||
| 104 | switch (type) { | ||
| 105 | case hwmon_in: | ||
| 106 | return attr == hwmon_in_min || | ||
| 107 | attr == hwmon_in_max; | ||
| 108 | case hwmon_curr: | ||
| 109 | return attr == hwmon_curr_max; | ||
| 110 | case hwmon_temp: | ||
| 111 | return attr == hwmon_temp_max || | ||
| 112 | attr == hwmon_temp_min || | ||
| 113 | attr == hwmon_temp_min_alarm || | ||
| 114 | attr == hwmon_temp_max_alarm; | ||
| 115 | default: | ||
| 116 | return false; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static umode_t power_supply_hwmon_is_visible(const void *data, | ||
| 121 | enum hwmon_sensor_types type, | ||
| 122 | u32 attr, int channel) | ||
| 123 | { | ||
| 124 | const struct power_supply_hwmon *psyhw = data; | ||
| 125 | int prop; | ||
| 126 | |||
| 127 | |||
| 128 | if (power_supply_hwmon_is_a_label(type, attr)) | ||
| 129 | return 0444; | ||
| 130 | |||
| 131 | prop = power_supply_hwmon_to_property(type, attr, channel); | ||
| 132 | if (prop < 0 || !test_bit(prop, psyhw->props)) | ||
| 133 | return 0; | ||
| 134 | |||
| 135 | if (power_supply_property_is_writeable(psyhw->psy, prop) > 0 && | ||
| 136 | power_supply_hwmon_is_writable(type, attr)) | ||
| 137 | return 0644; | ||
| 138 | |||
| 139 | return 0444; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int power_supply_hwmon_read_string(struct device *dev, | ||
| 143 | enum hwmon_sensor_types type, | ||
| 144 | u32 attr, int channel, | ||
| 145 | const char **str) | ||
| 146 | { | ||
| 147 | *str = channel ? "temp" : "temp ambient"; | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int | ||
| 152 | power_supply_hwmon_read(struct device *dev, enum hwmon_sensor_types type, | ||
| 153 | u32 attr, int channel, long *val) | ||
| 154 | { | ||
| 155 | struct power_supply_hwmon *psyhw = dev_get_drvdata(dev); | ||
| 156 | struct power_supply *psy = psyhw->psy; | ||
| 157 | union power_supply_propval pspval; | ||
| 158 | int ret, prop; | ||
| 159 | |||
| 160 | prop = power_supply_hwmon_to_property(type, attr, channel); | ||
| 161 | if (prop < 0) | ||
| 162 | return prop; | ||
| 163 | |||
| 164 | ret = power_supply_get_property(psy, prop, &pspval); | ||
| 165 | if (ret) | ||
| 166 | return ret; | ||
| 167 | |||
| 168 | switch (type) { | ||
| 169 | /* | ||
| 170 | * Both voltage and current is reported in units of | ||
| 171 | * microvolts/microamps, so we need to adjust it to | ||
| 172 | * milliamps(volts) | ||
| 173 | */ | ||
| 174 | case hwmon_curr: | ||
| 175 | case hwmon_in: | ||
| 176 | pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 1000); | ||
| 177 | break; | ||
| 178 | /* | ||
| 179 | * Temp needs to be converted from 1/10 C to milli-C | ||
| 180 | */ | ||
| 181 | case hwmon_temp: | ||
| 182 | if (check_mul_overflow(pspval.intval, 100, | ||
| 183 | &pspval.intval)) | ||
| 184 | return -EOVERFLOW; | ||
| 185 | break; | ||
| 186 | default: | ||
| 187 | return -EINVAL; | ||
| 188 | } | ||
| 189 | |||
| 190 | *val = pspval.intval; | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | static int | ||
| 196 | power_supply_hwmon_write(struct device *dev, enum hwmon_sensor_types type, | ||
| 197 | u32 attr, int channel, long val) | ||
| 198 | { | ||
| 199 | struct power_supply_hwmon *psyhw = dev_get_drvdata(dev); | ||
| 200 | struct power_supply *psy = psyhw->psy; | ||
| 201 | union power_supply_propval pspval; | ||
| 202 | int prop; | ||
| 203 | |||
| 204 | prop = power_supply_hwmon_to_property(type, attr, channel); | ||
| 205 | if (prop < 0) | ||
| 206 | return prop; | ||
| 207 | |||
| 208 | pspval.intval = val; | ||
| 209 | |||
| 210 | switch (type) { | ||
| 211 | /* | ||
| 212 | * Both voltage and current is reported in units of | ||
| 213 | * microvolts/microamps, so we need to adjust it to | ||
| 214 | * milliamps(volts) | ||
| 215 | */ | ||
| 216 | case hwmon_curr: | ||
| 217 | case hwmon_in: | ||
| 218 | if (check_mul_overflow(pspval.intval, 1000, | ||
| 219 | &pspval.intval)) | ||
| 220 | return -EOVERFLOW; | ||
| 221 | break; | ||
| 222 | /* | ||
| 223 | * Temp needs to be converted from 1/10 C to milli-C | ||
| 224 | */ | ||
| 225 | case hwmon_temp: | ||
| 226 | pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 100); | ||
| 227 | break; | ||
| 228 | default: | ||
| 229 | return -EINVAL; | ||
| 230 | } | ||
| 231 | |||
| 232 | return power_supply_set_property(psy, prop, &pspval); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct hwmon_ops power_supply_hwmon_ops = { | ||
| 236 | .is_visible = power_supply_hwmon_is_visible, | ||
| 237 | .read = power_supply_hwmon_read, | ||
| 238 | .write = power_supply_hwmon_write, | ||
| 239 | .read_string = power_supply_hwmon_read_string, | ||
| 240 | }; | ||
| 241 | |||
| 242 | static const struct hwmon_channel_info *power_supply_hwmon_info[] = { | ||
| 243 | HWMON_CHANNEL_INFO(temp, | ||
| 244 | HWMON_T_LABEL | | ||
| 245 | HWMON_T_INPUT | | ||
| 246 | HWMON_T_MAX | | ||
| 247 | HWMON_T_MIN | | ||
| 248 | HWMON_T_MIN_ALARM | | ||
| 249 | HWMON_T_MIN_ALARM, | ||
| 250 | |||
| 251 | HWMON_T_LABEL | | ||
| 252 | HWMON_T_INPUT | | ||
| 253 | HWMON_T_MIN_ALARM | | ||
| 254 | HWMON_T_LABEL | | ||
| 255 | HWMON_T_MAX_ALARM), | ||
| 256 | |||
| 257 | HWMON_CHANNEL_INFO(curr, | ||
| 258 | HWMON_C_AVERAGE | | ||
| 259 | HWMON_C_MAX | | ||
| 260 | HWMON_C_INPUT), | ||
| 261 | |||
| 262 | HWMON_CHANNEL_INFO(in, | ||
| 263 | HWMON_I_AVERAGE | | ||
| 264 | HWMON_I_MIN | | ||
| 265 | HWMON_I_MAX | | ||
| 266 | HWMON_I_INPUT), | ||
| 267 | NULL | ||
| 268 | }; | ||
| 269 | |||
| 270 | static const struct hwmon_chip_info power_supply_hwmon_chip_info = { | ||
| 271 | .ops = &power_supply_hwmon_ops, | ||
| 272 | .info = power_supply_hwmon_info, | ||
| 273 | }; | ||
| 274 | |||
| 275 | static void power_supply_hwmon_bitmap_free(void *data) | ||
| 276 | { | ||
| 277 | bitmap_free(data); | ||
| 278 | } | ||
| 279 | |||
| 280 | int power_supply_add_hwmon_sysfs(struct power_supply *psy) | ||
| 281 | { | ||
| 282 | const struct power_supply_desc *desc = psy->desc; | ||
| 283 | struct power_supply_hwmon *psyhw; | ||
| 284 | struct device *dev = &psy->dev; | ||
| 285 | struct device *hwmon; | ||
| 286 | int ret, i; | ||
| 287 | |||
| 288 | if (!devres_open_group(dev, power_supply_add_hwmon_sysfs, | ||
| 289 | GFP_KERNEL)) | ||
| 290 | return -ENOMEM; | ||
| 291 | |||
| 292 | psyhw = devm_kzalloc(dev, sizeof(*psyhw), GFP_KERNEL); | ||
| 293 | if (!psyhw) { | ||
| 294 | ret = -ENOMEM; | ||
| 295 | goto error; | ||
| 296 | } | ||
| 297 | |||
| 298 | psyhw->psy = psy; | ||
| 299 | psyhw->props = bitmap_zalloc(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG + 1, | ||
| 300 | GFP_KERNEL); | ||
| 301 | if (!psyhw->props) { | ||
| 302 | ret = -ENOMEM; | ||
| 303 | goto error; | ||
| 304 | } | ||
| 305 | |||
| 306 | ret = devm_add_action(dev, power_supply_hwmon_bitmap_free, | ||
| 307 | psyhw->props); | ||
| 308 | if (ret) | ||
| 309 | goto error; | ||
| 310 | |||
| 311 | for (i = 0; i < desc->num_properties; i++) { | ||
| 312 | const enum power_supply_property prop = desc->properties[i]; | ||
| 313 | |||
| 314 | switch (prop) { | ||
| 315 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
| 316 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
| 317 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
| 318 | case POWER_SUPPLY_PROP_TEMP: | ||
| 319 | case POWER_SUPPLY_PROP_TEMP_MAX: | ||
| 320 | case POWER_SUPPLY_PROP_TEMP_MIN: | ||
| 321 | case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: | ||
| 322 | case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: | ||
| 323 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | ||
| 324 | case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: | ||
| 325 | case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: | ||
| 326 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
| 327 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
| 328 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
| 329 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 330 | set_bit(prop, psyhw->props); | ||
| 331 | break; | ||
| 332 | default: | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | hwmon = devm_hwmon_device_register_with_info(dev, psy->desc->name, | ||
| 338 | psyhw, | ||
| 339 | &power_supply_hwmon_chip_info, | ||
| 340 | NULL); | ||
| 341 | ret = PTR_ERR_OR_ZERO(hwmon); | ||
| 342 | if (ret) | ||
| 343 | goto error; | ||
| 344 | |||
| 345 | devres_close_group(dev, power_supply_add_hwmon_sysfs); | ||
| 346 | return 0; | ||
| 347 | error: | ||
| 348 | devres_release_group(dev, NULL); | ||
| 349 | return ret; | ||
| 350 | } | ||
| 351 | |||
| 352 | void power_supply_remove_hwmon_sysfs(struct power_supply *psy) | ||
| 353 | { | ||
| 354 | devres_release_group(&psy->dev, power_supply_add_hwmon_sysfs); | ||
| 355 | } | ||
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 61430ae878d3..f37ad4eae60b 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c | |||
| @@ -276,6 +276,8 @@ static struct device_attribute power_supply_attrs[] = { | |||
| 276 | POWER_SUPPLY_ATTR(charge_control_start_threshold), | 276 | POWER_SUPPLY_ATTR(charge_control_start_threshold), |
| 277 | POWER_SUPPLY_ATTR(charge_control_end_threshold), | 277 | POWER_SUPPLY_ATTR(charge_control_end_threshold), |
| 278 | POWER_SUPPLY_ATTR(input_current_limit), | 278 | POWER_SUPPLY_ATTR(input_current_limit), |
| 279 | POWER_SUPPLY_ATTR(input_voltage_limit), | ||
| 280 | POWER_SUPPLY_ATTR(input_power_limit), | ||
| 279 | POWER_SUPPLY_ATTR(energy_full_design), | 281 | POWER_SUPPLY_ATTR(energy_full_design), |
| 280 | POWER_SUPPLY_ATTR(energy_empty_design), | 282 | POWER_SUPPLY_ATTR(energy_empty_design), |
| 281 | POWER_SUPPLY_ATTR(energy_full), | 283 | POWER_SUPPLY_ATTR(energy_full), |
diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index 9f0d70648e41..d8667a9fc49b 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c | |||
| @@ -115,7 +115,7 @@ static const struct power_supply_desc rt5033_battery_desc = { | |||
| 115 | static int rt5033_battery_probe(struct i2c_client *client, | 115 | static int rt5033_battery_probe(struct i2c_client *client, |
| 116 | const struct i2c_device_id *id) | 116 | const struct i2c_device_id *id) |
| 117 | { | 117 | { |
| 118 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 118 | struct i2c_adapter *adapter = client->adapter; |
| 119 | struct power_supply_config psy_cfg = {}; | 119 | struct power_supply_config psy_cfg = {}; |
| 120 | struct rt5033_battery *battery; | 120 | struct rt5033_battery *battery; |
| 121 | u32 ret; | 121 | u32 ret; |
diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c index 40a9d329418a..29161ae90245 100644 --- a/drivers/power/supply/rt9455_charger.c +++ b/drivers/power/supply/rt9455_charger.c | |||
| @@ -1584,7 +1584,7 @@ static const struct regmap_config rt9455_regmap_config = { | |||
| 1584 | static int rt9455_probe(struct i2c_client *client, | 1584 | static int rt9455_probe(struct i2c_client *client, |
| 1585 | const struct i2c_device_id *id) | 1585 | const struct i2c_device_id *id) |
| 1586 | { | 1586 | { |
| 1587 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1587 | struct i2c_adapter *adapter = client->adapter; |
| 1588 | struct device *dev = &client->dev; | 1588 | struct device *dev = &client->dev; |
| 1589 | struct rt9455_info *info; | 1589 | struct rt9455_info *info; |
| 1590 | struct power_supply_config rt9455_charger_config = {}; | 1590 | struct power_supply_config rt9455_charger_config = {}; |
diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c index 63173068a1ab..666243d9dd59 100644 --- a/drivers/power/supply/sbs-manager.c +++ b/drivers/power/supply/sbs-manager.c | |||
| @@ -314,7 +314,7 @@ static const struct power_supply_desc sbsm_default_psy_desc = { | |||
| 314 | static int sbsm_probe(struct i2c_client *client, | 314 | static int sbsm_probe(struct i2c_client *client, |
| 315 | const struct i2c_device_id *id) | 315 | const struct i2c_device_id *id) |
| 316 | { | 316 | { |
| 317 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 317 | struct i2c_adapter *adapter = client->adapter; |
| 318 | struct sbsm_data *data; | 318 | struct sbsm_data *data; |
| 319 | struct device *dev = &client->dev; | 319 | struct device *dev = &client->dev; |
| 320 | struct power_supply_desc *psy_desc; | 320 | struct power_supply_desc *psy_desc; |
diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c index 1c89d030c045..1b80ae479e7d 100644 --- a/drivers/power/supply/ucs1002_power.c +++ b/drivers/power/supply/ucs1002_power.c | |||
| @@ -336,7 +336,7 @@ static int ucs1002_get_usb_type(struct ucs1002_info *info, | |||
| 336 | case F_ACTIVE_MODE_BC12_CDP: | 336 | case F_ACTIVE_MODE_BC12_CDP: |
| 337 | type = POWER_SUPPLY_USB_TYPE_CDP; | 337 | type = POWER_SUPPLY_USB_TYPE_CDP; |
| 338 | break; | 338 | break; |
| 339 | }; | 339 | } |
| 340 | 340 | ||
| 341 | val->intval = type; | 341 | val->intval = type; |
| 342 | 342 | ||
diff --git a/drivers/power/supply/wilco-charger.c b/drivers/power/supply/wilco-charger.c new file mode 100644 index 000000000000..b3c6d7cdd731 --- /dev/null +++ b/drivers/power/supply/wilco-charger.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Charging control driver for the Wilco EC | ||
| 4 | * | ||
| 5 | * Copyright 2019 Google LLC | ||
| 6 | * | ||
| 7 | * See Documentation/ABI/testing/sysfs-class-power and | ||
| 8 | * Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface | ||
| 9 | * and other info. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/platform_data/wilco-ec.h> | ||
| 15 | #include <linux/power_supply.h> | ||
| 16 | |||
| 17 | #define DRV_NAME "wilco-charger" | ||
| 18 | |||
| 19 | /* Property IDs and related EC constants */ | ||
| 20 | #define PID_CHARGE_MODE 0x0710 | ||
| 21 | #define PID_CHARGE_LOWER_LIMIT 0x0711 | ||
| 22 | #define PID_CHARGE_UPPER_LIMIT 0x0712 | ||
| 23 | |||
| 24 | enum charge_mode { | ||
| 25 | CHARGE_MODE_STD = 1, /* Used for Standard */ | ||
| 26 | CHARGE_MODE_EXP = 2, /* Express Charge, used for Fast */ | ||
| 27 | CHARGE_MODE_AC = 3, /* Mostly AC use, used for Trickle */ | ||
| 28 | CHARGE_MODE_AUTO = 4, /* Used for Adaptive */ | ||
| 29 | CHARGE_MODE_CUSTOM = 5, /* Used for Custom */ | ||
| 30 | }; | ||
| 31 | |||
| 32 | #define CHARGE_LOWER_LIMIT_MIN 50 | ||
| 33 | #define CHARGE_LOWER_LIMIT_MAX 95 | ||
| 34 | #define CHARGE_UPPER_LIMIT_MIN 55 | ||
| 35 | #define CHARGE_UPPER_LIMIT_MAX 100 | ||
| 36 | |||
| 37 | /* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */ | ||
| 38 | static int psp_val_to_charge_mode(int psp_val) | ||
| 39 | { | ||
| 40 | switch (psp_val) { | ||
| 41 | case POWER_SUPPLY_CHARGE_TYPE_TRICKLE: | ||
| 42 | return CHARGE_MODE_AC; | ||
| 43 | case POWER_SUPPLY_CHARGE_TYPE_FAST: | ||
| 44 | return CHARGE_MODE_EXP; | ||
| 45 | case POWER_SUPPLY_CHARGE_TYPE_STANDARD: | ||
| 46 | return CHARGE_MODE_STD; | ||
| 47 | case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE: | ||
| 48 | return CHARGE_MODE_AUTO; | ||
| 49 | case POWER_SUPPLY_CHARGE_TYPE_CUSTOM: | ||
| 50 | return CHARGE_MODE_CUSTOM; | ||
| 51 | default: | ||
| 52 | return -EINVAL; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */ | ||
| 57 | static int charge_mode_to_psp_val(enum charge_mode mode) | ||
| 58 | { | ||
| 59 | switch (mode) { | ||
| 60 | case CHARGE_MODE_AC: | ||
| 61 | return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; | ||
| 62 | case CHARGE_MODE_EXP: | ||
| 63 | return POWER_SUPPLY_CHARGE_TYPE_FAST; | ||
| 64 | case CHARGE_MODE_STD: | ||
| 65 | return POWER_SUPPLY_CHARGE_TYPE_STANDARD; | ||
| 66 | case CHARGE_MODE_AUTO: | ||
| 67 | return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE; | ||
| 68 | case CHARGE_MODE_CUSTOM: | ||
| 69 | return POWER_SUPPLY_CHARGE_TYPE_CUSTOM; | ||
| 70 | default: | ||
| 71 | return -EINVAL; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | static enum power_supply_property wilco_charge_props[] = { | ||
| 76 | POWER_SUPPLY_PROP_CHARGE_TYPE, | ||
| 77 | POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, | ||
| 78 | POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, | ||
| 79 | }; | ||
| 80 | |||
| 81 | static int wilco_charge_get_property(struct power_supply *psy, | ||
| 82 | enum power_supply_property psp, | ||
| 83 | union power_supply_propval *val) | ||
| 84 | { | ||
| 85 | struct wilco_ec_device *ec = power_supply_get_drvdata(psy); | ||
| 86 | u32 property_id; | ||
| 87 | int ret; | ||
| 88 | u8 raw; | ||
| 89 | |||
| 90 | switch (psp) { | ||
| 91 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
| 92 | property_id = PID_CHARGE_MODE; | ||
| 93 | break; | ||
| 94 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: | ||
| 95 | property_id = PID_CHARGE_LOWER_LIMIT; | ||
| 96 | break; | ||
| 97 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: | ||
| 98 | property_id = PID_CHARGE_UPPER_LIMIT; | ||
| 99 | break; | ||
| 100 | default: | ||
| 101 | return -EINVAL; | ||
| 102 | } | ||
| 103 | |||
| 104 | ret = wilco_ec_get_byte_property(ec, property_id, &raw); | ||
| 105 | if (ret < 0) | ||
| 106 | return ret; | ||
| 107 | if (property_id == PID_CHARGE_MODE) { | ||
| 108 | ret = charge_mode_to_psp_val(raw); | ||
| 109 | if (ret < 0) | ||
| 110 | return -EBADMSG; | ||
| 111 | raw = ret; | ||
| 112 | } | ||
| 113 | val->intval = raw; | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int wilco_charge_set_property(struct power_supply *psy, | ||
| 119 | enum power_supply_property psp, | ||
| 120 | const union power_supply_propval *val) | ||
| 121 | { | ||
| 122 | struct wilco_ec_device *ec = power_supply_get_drvdata(psy); | ||
| 123 | int mode; | ||
| 124 | |||
| 125 | switch (psp) { | ||
| 126 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
| 127 | mode = psp_val_to_charge_mode(val->intval); | ||
| 128 | if (mode < 0) | ||
| 129 | return -EINVAL; | ||
| 130 | return wilco_ec_set_byte_property(ec, PID_CHARGE_MODE, mode); | ||
| 131 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: | ||
| 132 | if (val->intval < CHARGE_LOWER_LIMIT_MIN || | ||
| 133 | val->intval > CHARGE_LOWER_LIMIT_MAX) | ||
| 134 | return -EINVAL; | ||
| 135 | return wilco_ec_set_byte_property(ec, PID_CHARGE_LOWER_LIMIT, | ||
| 136 | val->intval); | ||
| 137 | case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: | ||
| 138 | if (val->intval < CHARGE_UPPER_LIMIT_MIN || | ||
| 139 | val->intval > CHARGE_UPPER_LIMIT_MAX) | ||
| 140 | return -EINVAL; | ||
| 141 | return wilco_ec_set_byte_property(ec, PID_CHARGE_UPPER_LIMIT, | ||
| 142 | val->intval); | ||
| 143 | default: | ||
| 144 | return -EINVAL; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | static int wilco_charge_property_is_writeable(struct power_supply *psy, | ||
| 149 | enum power_supply_property psp) | ||
| 150 | { | ||
| 151 | return 1; | ||
| 152 | } | ||
| 153 | |||
| 154 | static const struct power_supply_desc wilco_ps_desc = { | ||
| 155 | .properties = wilco_charge_props, | ||
| 156 | .num_properties = ARRAY_SIZE(wilco_charge_props), | ||
| 157 | .get_property = wilco_charge_get_property, | ||
| 158 | .set_property = wilco_charge_set_property, | ||
| 159 | .property_is_writeable = wilco_charge_property_is_writeable, | ||
| 160 | .name = DRV_NAME, | ||
| 161 | .type = POWER_SUPPLY_TYPE_MAINS, | ||
| 162 | }; | ||
| 163 | |||
| 164 | static int wilco_charge_probe(struct platform_device *pdev) | ||
| 165 | { | ||
| 166 | struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
| 167 | struct power_supply_config psy_cfg = {}; | ||
| 168 | struct power_supply *psy; | ||
| 169 | |||
| 170 | psy_cfg.drv_data = ec; | ||
| 171 | psy = devm_power_supply_register(&pdev->dev, &wilco_ps_desc, &psy_cfg); | ||
| 172 | |||
| 173 | return PTR_ERR_OR_ZERO(psy); | ||
| 174 | } | ||
| 175 | |||
| 176 | static struct platform_driver wilco_charge_driver = { | ||
| 177 | .probe = wilco_charge_probe, | ||
| 178 | .driver = { | ||
| 179 | .name = DRV_NAME, | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | module_platform_driver(wilco_charge_driver); | ||
| 183 | |||
| 184 | MODULE_ALIAS("platform:" DRV_NAME); | ||
| 185 | MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); | ||
| 186 | MODULE_LICENSE("GPL v2"); | ||
| 187 | MODULE_DESCRIPTION("Wilco EC charge control driver"); | ||
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 6f348b3ee2e0..28413f737e7d 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
| @@ -128,6 +128,8 @@ enum power_supply_property { | |||
| 128 | POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */ | 128 | POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */ |
| 129 | POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */ | 129 | POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */ |
| 130 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, | 130 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, |
| 131 | POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, | ||
| 132 | POWER_SUPPLY_PROP_INPUT_POWER_LIMIT, | ||
| 131 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | 133 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
| 132 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, | 134 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, |
| 133 | POWER_SUPPLY_PROP_ENERGY_FULL, | 135 | POWER_SUPPLY_PROP_ENERGY_FULL, |
| @@ -480,4 +482,17 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp) | |||
| 480 | return 0; | 482 | return 0; |
| 481 | } | 483 | } |
| 482 | 484 | ||
| 485 | #ifdef CONFIG_POWER_SUPPLY_HWMON | ||
| 486 | int power_supply_add_hwmon_sysfs(struct power_supply *psy); | ||
| 487 | void power_supply_remove_hwmon_sysfs(struct power_supply *psy); | ||
| 488 | #else | ||
| 489 | static inline int power_supply_add_hwmon_sysfs(struct power_supply *psy) | ||
| 490 | { | ||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | static inline | ||
| 495 | void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {} | ||
| 496 | #endif | ||
| 497 | |||
| 483 | #endif /* __LINUX_POWER_SUPPLY_H__ */ | 498 | #endif /* __LINUX_POWER_SUPPLY_H__ */ |
