aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-power32
-rw-r--r--Documentation/ABI/testing/sysfs-class-power-wilco30
-rw-r--r--Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt26
-rw-r--r--Documentation/devicetree/bindings/power/reset/qcom,pon.txt1
-rw-r--r--Documentation/power/power_supply_class.rst6
-rw-r--r--drivers/power/reset/Kconfig10
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/nvmem-reboot-mode.c76
-rw-r--r--drivers/power/reset/qcom-pon.c12
-rw-r--r--drivers/power/supply/Kconfig23
-rw-r--r--drivers/power/supply/Makefile2
-rw-r--r--drivers/power/supply/bq24190_charger.c2
-rw-r--r--drivers/power/supply/bq24257_charger.c2
-rw-r--r--drivers/power/supply/bq25890_charger.c2
-rw-r--r--drivers/power/supply/cros_usbpd-charger.c116
-rw-r--r--drivers/power/supply/max14656_charger_detector.c2
-rw-r--r--drivers/power/supply/max17040_battery.c2
-rw-r--r--drivers/power/supply/max17042_battery.c2
-rw-r--r--drivers/power/supply/power_supply_core.c7
-rw-r--r--drivers/power/supply/power_supply_hwmon.c355
-rw-r--r--drivers/power/supply/power_supply_sysfs.c2
-rw-r--r--drivers/power/supply/rt5033_battery.c2
-rw-r--r--drivers/power/supply/rt9455_charger.c2
-rw-r--r--drivers/power/supply/sbs-manager.c2
-rw-r--r--drivers/power/supply/ucs1002_power.c2
-rw-r--r--drivers/power/supply/wilco-charger.c187
-rw-r--r--include/linux/power_supply.h15
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
385What: /sys/class/power_supply/<supply_name>/input_voltage_limit
386Date: May 2019
387Contact: linux-pm@vger.kernel.org
388Description:
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
402What: /sys/class/power_supply/<supply_name>/input_power_limit
403Date: May 2019
404Contact: linux-pm@vger.kernel.org
405Description:
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
383What: /sys/class/power_supply/<supply_name>/online, 415What: /sys/class/power_supply/<supply_name>/online,
384Date: May 2007 416Date: May 2007
385Contact: linux-pm@vger.kernel.org 417Contact: 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 @@
1What: /sys/class/power_supply/wilco-charger/charge_type
2Date: April 2019
3KernelVersion: 5.2
4Description:
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
18What: /sys/class/power_supply/wilco-charger/charge_control_start_threshold
19Date: April 2019
20KernelVersion: 5.2
21Description:
22 Used when charge_type="Custom", as described above. Measured in
23 percentages. The valid range is [50, 95].
24
25What: /sys/class/power_supply/wilco-charger/charge_control_end_threshold
26Date: April 2019
27KernelVersion: 5.2
28Description:
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 @@
1NVMEM reboot mode driver
2
3This driver gets reboot mode magic value from reboot-mode driver
4and stores it in a NVMEM cell named "reboot-mode". Then the bootloader
5can read it and take different action according to the magic
6value stored.
7
8Required 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
13The rest of the properties should follow the generic reboot-mode description
14found in reboot-mode.txt
15
16Example:
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
165INPUT_CURRENT_LIMIT 165INPUT_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.
168INPUT_VOLTAGE_LIMIT
169 input voltage limit programmed by charger. Indicates
170 the voltage limit from a charging source.
171INPUT_POWER_LIMIT
172 input power limit programmed by charger. Indicates
173 the power limit from a charging source.
168 174
169CHARGE_CONTROL_LIMIT 175CHARGE_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
249config 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
249endif 259endif
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
29obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o 29obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
30obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o 30obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
31obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o 31obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
32obj-$(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
14struct nvmem_reboot_mode {
15 struct reboot_mode_driver reboot;
16 struct nvmem_cell *cell;
17};
18
19static 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
34static 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
59static const struct of_device_id nvmem_reboot_mode_of_match[] = {
60 { .compatible = "nvmem-reboot-mode" },
61 {}
62};
63MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match);
64
65static 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};
72module_platform_driver(nvmem_reboot_mode_driver);
73
74MODULE_AUTHOR("Nandor Han <nandor.han@vaisala.com>");
75MODULE_DESCRIPTION("NVMEM reboot mode driver");
76MODULE_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
17struct pm8916_pon { 20struct 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
24static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, 28static 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
75static const struct of_device_id pm8916_pon_id_table[] = { 80static 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};
80MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); 86MODULE_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
18config 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
18config PDA_POWER 32config 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
715config 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
701endif # POWER_SUPPLY 724endif # 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
6power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o 6power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
7 7
8obj-$(CONFIG_POWER_SUPPLY) += power_supply.o 8obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
9obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
9obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o 10obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
10 11
11obj-$(CONFIG_PDA_POWER) += pda_power.o 12obj-$(CONFIG_PDA_POWER) += pda_power.o
@@ -91,3 +92,4 @@ obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
91obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o 92obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
92obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o 93obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
93obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o 94obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
95obj-$(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)
1697static int bq24190_probe(struct i2c_client *client, 1697static 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)
950static int bq24257_probe(struct i2c_client *client, 950static 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)
817static int bq25890_probe(struct i2c_client *client, 817static 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
55static enum power_supply_property cros_usbpd_charger_props[] = { 55static 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. */
86static u16 input_voltage_limit = EC_POWER_LIMIT_NONE;
87static u16 input_current_limit = EC_POWER_LIMIT_NONE;
88
83static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port) 89static 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
333static 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
327static void cros_usbpd_charger_power_changed(struct power_supply *psy) 353static 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
450static 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
508static 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
412static int cros_usbpd_charger_ec_event(struct notifier_block *nb, 525static 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)
247static int max14656_probe(struct i2c_client *client, 247static 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 = {
193static int max17040_probe(struct i2c_client *client, 193static 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)
1005static int max17042_probe(struct i2c_client *client, 1005static 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
1096add_hwmon_sysfs_failed:
1097 power_supply_remove_triggers(psy);
1092create_triggers_failed: 1098create_triggers_failed:
1093 psy_unregister_cooler(psy); 1099 psy_unregister_cooler(psy);
1094register_cooler_failed: 1100register_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
11struct power_supply_hwmon {
12 struct power_supply *psy;
13 unsigned long *props;
14};
15
16static 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
32static 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
46static 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
79static int
80power_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
95static 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
101static 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
120static 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
142static 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
151static int
152power_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
195static int
196power_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
235static 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
242static 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
270static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
271 .ops = &power_supply_hwmon_ops,
272 .info = power_supply_hwmon_info,
273};
274
275static void power_supply_hwmon_bitmap_free(void *data)
276{
277 bitmap_free(data);
278}
279
280int 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;
347error:
348 devres_release_group(dev, NULL);
349 return ret;
350}
351
352void 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 = {
115static int rt5033_battery_probe(struct i2c_client *client, 115static 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 = {
1584static int rt9455_probe(struct i2c_client *client, 1584static 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 = {
314static int sbsm_probe(struct i2c_client *client, 314static 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
24enum 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 */
38static 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 */
57static 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
75static 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
81static 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
118static 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
148static int wilco_charge_property_is_writeable(struct power_supply *psy,
149 enum power_supply_property psp)
150{
151 return 1;
152}
153
154static 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
164static 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
176static struct platform_driver wilco_charge_driver = {
177 .probe = wilco_charge_probe,
178 .driver = {
179 .name = DRV_NAME,
180 }
181};
182module_platform_driver(wilco_charge_driver);
183
184MODULE_ALIAS("platform:" DRV_NAME);
185MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
186MODULE_LICENSE("GPL v2");
187MODULE_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
486int power_supply_add_hwmon_sysfs(struct power_supply *psy);
487void power_supply_remove_hwmon_sysfs(struct power_supply *psy);
488#else
489static inline int power_supply_add_hwmon_sysfs(struct power_supply *psy)
490{
491 return 0;
492}
493
494static inline
495void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {}
496#endif
497
483#endif /* __LINUX_POWER_SUPPLY_H__ */ 498#endif /* __LINUX_POWER_SUPPLY_H__ */