power supply and reset changes for the v5.3 series
Core: * Add HWMON compat layer * New properties - input power limit - input voltage limit Drivers: * qcom-pon: add gen2 support * New driver for storing reboot move in NVMEM * New driver for Wilco EC charger configuration * simplify getting the adapter of a client -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl0s0xgACgkQ2O7X88g7 +pqxFQ/9GmfgHpzZ+qQmpBR5zyw1+yrhls3BXYEgHtGM+3YZ6n1sF8Yl1eUYpviC ldvN3vHXaxRlG5eDBwMl3ScWZnaxMpZssigO3lL4o+kYng0c0xqaPZZYxA9oJNgn 0ertZrYcQZWmT82aRnjt2/p+8n+Hld6bv89PodWdLvsDvId1qQPXu5ILV0JL/QNK FMQepuaiRu9VXlyPCuWYwoOmKruZjLF7SOyis+I4e55U7lHeyCOySH/tZTTFgd+n hUpWm4ekc7YCAJVVJUQcdBtfNvQm1KtGkLSnSockH/636kP2fh5ESj76z8i5I6/6 yl7OrkCyhespqS9hGCKCPU95s8MQe8HurlGR8aIWHLJJMiv1hIVOq7n9Uj+mmdRS OkKQHo/RUxXn5ioCUF3F3NcB94/95f0AWrx3RXjeXd2kYlUmVKCHyaGjPT9WfSOe MUcLZwM+GsG+3SWBhPGqjuIhIGfBBuQk+mcYLPLP/j3emNeLByYEtEDhvoQbEooU TCyJGR+FGIAyjXcW/uZzxx8MiZPybSXo7a4j837Cx6sRNwZJ4V9Ve/7XdUy7DKD0 kOBH/ndJhoKJQkup+HEGmv/8os4K8gyW/kaiu718mS0oLDfQGDy0C0Y8BNoJnw4k /jo/1q0KY+8Hd6bxqbommA2ORAw7XsDZB7eWWC4gDqMXVcF1S6k= =fmGg -----END PGP SIGNATURE----- Merge tag 'for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Core: - add HWMON compat layer - new properties: - input power limit - input voltage limit Drivers: - qcom-pon: add gen2 support - new driver for storing reboot move in NVMEM - new driver for Wilco EC charger configuration - simplify getting the adapter of a client" * tag 'for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: power: reset: nvmem-reboot-mode: add CONFIG_OF dependency power_supply: wilco_ec: Add charging config driver power: supply: cros: allow to set input voltage and current limit power: supply: add input power and voltage limit properties power: supply: fix semicolon.cocci warnings power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface dt-bindings: power: reset: add document for NVMEM based reboot-mode reset: qcom-pon: Add support for gen2 pon dt-bindings: power: reset: qcom: Add qcom,pm8998-pon compatibility line power: supply: Add HWMON compatibility layer power: supply: sbs-manager: simplify getting the adapter of a client power: supply: rt9455_charger: simplify getting the adapter of a client power: supply: rt5033_battery: simplify getting the adapter of a client power: supply: max17042_battery: simplify getting the adapter of a client power: supply: max17040_battery: simplify getting the adapter of a client power: supply: max14656_charger_detector: simplify getting the adapter of a client power: supply: bq25890_charger: simplify getting the adapter of a client power: supply: bq24257_charger: simplify getting the adapter of a client power: supply: bq24190_charger: simplify getting the adapter of a clientalistair/sunxi64-5.4-dsi
commit
5fe7b600a1
|
@ -376,10 +376,42 @@ Description:
|
||||||
supply. Normally this is configured based on the type of
|
supply. Normally this is configured based on the type of
|
||||||
connection made (e.g. A configured SDP should output a maximum
|
connection made (e.g. A configured SDP should output a maximum
|
||||||
of 500mA so the input current limit is set to the same value).
|
of 500mA so the input current limit is set to the same value).
|
||||||
|
Use preferably input_power_limit, and for problems that can be
|
||||||
|
solved using power limit use input_current_limit.
|
||||||
|
|
||||||
Access: Read, Write
|
Access: Read, Write
|
||||||
Valid values: Represented in microamps
|
Valid values: Represented in microamps
|
||||||
|
|
||||||
|
What: /sys/class/power_supply/<supply_name>/input_voltage_limit
|
||||||
|
Date: May 2019
|
||||||
|
Contact: linux-pm@vger.kernel.org
|
||||||
|
Description:
|
||||||
|
This entry configures the incoming VBUS voltage limit currently
|
||||||
|
set in the supply. Normally this is configured based on
|
||||||
|
system-level knowledge or user input (e.g. This is part of the
|
||||||
|
Pixel C's thermal management strategy to effectively limit the
|
||||||
|
input power to 5V when the screen is on to meet Google's skin
|
||||||
|
temperature targets). Note that this feature should not be
|
||||||
|
used for safety critical things.
|
||||||
|
Use preferably input_power_limit, and for problems that can be
|
||||||
|
solved using power limit use input_voltage_limit.
|
||||||
|
|
||||||
|
Access: Read, Write
|
||||||
|
Valid values: Represented in microvolts
|
||||||
|
|
||||||
|
What: /sys/class/power_supply/<supply_name>/input_power_limit
|
||||||
|
Date: May 2019
|
||||||
|
Contact: linux-pm@vger.kernel.org
|
||||||
|
Description:
|
||||||
|
This entry configures the incoming power limit currently set
|
||||||
|
in the supply. Normally this is configured based on
|
||||||
|
system-level knowledge or user input. Use preferably this
|
||||||
|
feature to limit the incoming power and use current/voltage
|
||||||
|
limit only for problems that can be solved using power limit.
|
||||||
|
|
||||||
|
Access: Read, Write
|
||||||
|
Valid values: Represented in microwatts
|
||||||
|
|
||||||
What: /sys/class/power_supply/<supply_name>/online,
|
What: /sys/class/power_supply/<supply_name>/online,
|
||||||
Date: May 2007
|
Date: May 2007
|
||||||
Contact: linux-pm@vger.kernel.org
|
Contact: linux-pm@vger.kernel.org
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
What: /sys/class/power_supply/wilco-charger/charge_type
|
||||||
|
Date: April 2019
|
||||||
|
KernelVersion: 5.2
|
||||||
|
Description:
|
||||||
|
What charging algorithm to use:
|
||||||
|
|
||||||
|
Standard: Fully charges battery at a standard rate.
|
||||||
|
Adaptive: Battery settings adaptively optimized based on
|
||||||
|
typical battery usage pattern.
|
||||||
|
Fast: Battery charges over a shorter period.
|
||||||
|
Trickle: Extends battery lifespan, intended for users who
|
||||||
|
primarily use their Chromebook while connected to AC.
|
||||||
|
Custom: A low and high threshold percentage is specified.
|
||||||
|
Charging begins when level drops below
|
||||||
|
charge_control_start_threshold, and ceases when
|
||||||
|
level is above charge_control_end_threshold.
|
||||||
|
|
||||||
|
What: /sys/class/power_supply/wilco-charger/charge_control_start_threshold
|
||||||
|
Date: April 2019
|
||||||
|
KernelVersion: 5.2
|
||||||
|
Description:
|
||||||
|
Used when charge_type="Custom", as described above. Measured in
|
||||||
|
percentages. The valid range is [50, 95].
|
||||||
|
|
||||||
|
What: /sys/class/power_supply/wilco-charger/charge_control_end_threshold
|
||||||
|
Date: April 2019
|
||||||
|
KernelVersion: 5.2
|
||||||
|
Description:
|
||||||
|
Used when charge_type="Custom", as described above. Measured in
|
||||||
|
percentages. The valid range is [55, 100].
|
|
@ -0,0 +1,26 @@
|
||||||
|
NVMEM reboot mode driver
|
||||||
|
|
||||||
|
This driver gets reboot mode magic value from reboot-mode driver
|
||||||
|
and stores it in a NVMEM cell named "reboot-mode". Then the bootloader
|
||||||
|
can read it and take different action according to the magic
|
||||||
|
value stored.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "nvmem-reboot-mode".
|
||||||
|
- nvmem-cells: A phandle to the reboot mode provided by a nvmem device.
|
||||||
|
- nvmem-cell-names: Should be "reboot-mode".
|
||||||
|
|
||||||
|
The rest of the properties should follow the generic reboot-mode description
|
||||||
|
found in reboot-mode.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
reboot-mode {
|
||||||
|
compatible = "nvmem-reboot-mode";
|
||||||
|
nvmem-cells = <&reboot_mode>;
|
||||||
|
nvmem-cell-names = "reboot-mode";
|
||||||
|
|
||||||
|
mode-normal = <0xAAAA5501>;
|
||||||
|
mode-bootloader = <0xBBBB5500>;
|
||||||
|
mode-recovery = <0xCCCC5502>;
|
||||||
|
mode-test = <0xDDDD5503>;
|
||||||
|
};
|
|
@ -9,6 +9,7 @@ Required Properties:
|
||||||
-compatible: Must be one of:
|
-compatible: Must be one of:
|
||||||
"qcom,pm8916-pon"
|
"qcom,pm8916-pon"
|
||||||
"qcom,pms405-pon"
|
"qcom,pms405-pon"
|
||||||
|
"qcom,pm8998-pon"
|
||||||
|
|
||||||
-reg: Specifies the physical address of the pon register
|
-reg: Specifies the physical address of the pon register
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,12 @@ CONSTANT_CHARGE_VOLTAGE_MAX
|
||||||
INPUT_CURRENT_LIMIT
|
INPUT_CURRENT_LIMIT
|
||||||
input current limit programmed by charger. Indicates
|
input current limit programmed by charger. Indicates
|
||||||
the current drawn from a charging source.
|
the current drawn from a charging source.
|
||||||
|
INPUT_VOLTAGE_LIMIT
|
||||||
|
input voltage limit programmed by charger. Indicates
|
||||||
|
the voltage limit from a charging source.
|
||||||
|
INPUT_POWER_LIMIT
|
||||||
|
input power limit programmed by charger. Indicates
|
||||||
|
the power limit from a charging source.
|
||||||
|
|
||||||
CHARGE_CONTROL_LIMIT
|
CHARGE_CONTROL_LIMIT
|
||||||
current charge control limit setting
|
current charge control limit setting
|
||||||
|
|
|
@ -246,5 +246,15 @@ config POWER_RESET_SC27XX
|
||||||
PMICs includes the SC2720, SC2721, SC2723, SC2730
|
PMICs includes the SC2720, SC2721, SC2723, SC2730
|
||||||
and SC2731 chips.
|
and SC2731 chips.
|
||||||
|
|
||||||
|
config NVMEM_REBOOT_MODE
|
||||||
|
tristate "Generic NVMEM reboot mode driver"
|
||||||
|
depends on OF
|
||||||
|
select REBOOT_MODE
|
||||||
|
help
|
||||||
|
Say y here will enable reboot mode driver. This will
|
||||||
|
get reboot mode arguments and store it in a NVMEM cell,
|
||||||
|
then the bootloader can read it and take different
|
||||||
|
action according to the mode.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o
|
||||||
obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
|
obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
|
||||||
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
|
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
|
||||||
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
|
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
|
||||||
|
obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright (c) Vaisala Oyj. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/nvmem-consumer.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/reboot-mode.h>
|
||||||
|
|
||||||
|
struct nvmem_reboot_mode {
|
||||||
|
struct reboot_mode_driver reboot;
|
||||||
|
struct nvmem_cell *cell;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot,
|
||||||
|
unsigned int magic)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct nvmem_reboot_mode *nvmem_rbm;
|
||||||
|
|
||||||
|
nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot);
|
||||||
|
|
||||||
|
ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic));
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(reboot->dev, "update reboot mode bits failed\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvmem_reboot_mode_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct nvmem_reboot_mode *nvmem_rbm;
|
||||||
|
|
||||||
|
nvmem_rbm = devm_kzalloc(&pdev->dev, sizeof(*nvmem_rbm), GFP_KERNEL);
|
||||||
|
if (!nvmem_rbm)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
nvmem_rbm->reboot.dev = &pdev->dev;
|
||||||
|
nvmem_rbm->reboot.write = nvmem_reboot_mode_write;
|
||||||
|
|
||||||
|
nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode");
|
||||||
|
if (IS_ERR(nvmem_rbm->cell)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get the nvmem cell reboot-mode\n");
|
||||||
|
return PTR_ERR(nvmem_rbm->cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_reboot_mode_register(&pdev->dev, &nvmem_rbm->reboot);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&pdev->dev, "can't register reboot mode\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id nvmem_reboot_mode_of_match[] = {
|
||||||
|
{ .compatible = "nvmem-reboot-mode" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver nvmem_reboot_mode_driver = {
|
||||||
|
.probe = nvmem_reboot_mode_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "nvmem-reboot-mode",
|
||||||
|
.of_match_table = nvmem_reboot_mode_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(nvmem_reboot_mode_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Nandor Han <nandor.han@vaisala.com>");
|
||||||
|
MODULE_DESCRIPTION("NVMEM reboot mode driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -14,11 +14,15 @@
|
||||||
|
|
||||||
#define PON_SOFT_RB_SPARE 0x8f
|
#define PON_SOFT_RB_SPARE 0x8f
|
||||||
|
|
||||||
|
#define GEN1_REASON_SHIFT 2
|
||||||
|
#define GEN2_REASON_SHIFT 1
|
||||||
|
|
||||||
struct pm8916_pon {
|
struct pm8916_pon {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
u32 baseaddr;
|
u32 baseaddr;
|
||||||
struct reboot_mode_driver reboot_mode;
|
struct reboot_mode_driver reboot_mode;
|
||||||
|
long reason_shift;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
|
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,
|
||||||
|
|
||||||
ret = regmap_update_bits(pon->regmap,
|
ret = regmap_update_bits(pon->regmap,
|
||||||
pon->baseaddr + PON_SOFT_RB_SPARE,
|
pon->baseaddr + PON_SOFT_RB_SPARE,
|
||||||
0xfc, magic << 2);
|
0xfc, magic << pon->reason_shift);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
dev_err(pon->dev, "update reboot mode bits failed\n");
|
dev_err(pon->dev, "update reboot mode bits failed\n");
|
||||||
|
|
||||||
|
@ -60,6 +64,7 @@ static int pm8916_pon_probe(struct platform_device *pdev)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
pon->reboot_mode.dev = &pdev->dev;
|
pon->reboot_mode.dev = &pdev->dev;
|
||||||
|
pon->reason_shift = (long)of_device_get_match_data(&pdev->dev);
|
||||||
pon->reboot_mode.write = pm8916_reboot_mode_write;
|
pon->reboot_mode.write = pm8916_reboot_mode_write;
|
||||||
error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
|
error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -73,8 +78,9 @@ static int pm8916_pon_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id pm8916_pon_id_table[] = {
|
static const struct of_device_id pm8916_pon_id_table[] = {
|
||||||
{ .compatible = "qcom,pm8916-pon" },
|
{ .compatible = "qcom,pm8916-pon", .data = (void *)GEN1_REASON_SHIFT },
|
||||||
{ .compatible = "qcom,pms405-pon" },
|
{ .compatible = "qcom,pms405-pon", .data = (void *)GEN1_REASON_SHIFT },
|
||||||
|
{ .compatible = "qcom,pm8998-pon", .data = (void *)GEN2_REASON_SHIFT },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, pm8916_pon_id_table);
|
MODULE_DEVICE_TABLE(of, pm8916_pon_id_table);
|
||||||
|
|
|
@ -15,6 +15,20 @@ config POWER_SUPPLY_DEBUG
|
||||||
Say Y here to enable debugging messages for power supply class
|
Say Y here to enable debugging messages for power supply class
|
||||||
and drivers.
|
and drivers.
|
||||||
|
|
||||||
|
config POWER_SUPPLY_HWMON
|
||||||
|
bool
|
||||||
|
prompt "Expose power supply sensors as hwmon device"
|
||||||
|
depends on HWMON=y || HWMON=POWER_SUPPLY
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This options enables API that allows sensors found on a
|
||||||
|
power supply device (current, voltage, temperature) to be
|
||||||
|
exposed as a hwmon device.
|
||||||
|
|
||||||
|
Say 'Y' here if you want power supplies to
|
||||||
|
have hwmon sysfs interface too.
|
||||||
|
|
||||||
|
|
||||||
config PDA_POWER
|
config PDA_POWER
|
||||||
tristate "Generic PDA/phone power driver"
|
tristate "Generic PDA/phone power driver"
|
||||||
depends on !S390
|
depends on !S390
|
||||||
|
@ -698,4 +712,13 @@ config CHARGER_BD70528
|
||||||
information and altering charger configurations from charger
|
information and altering charger configurations from charger
|
||||||
block of the ROHM BD70528 Power Management IC.
|
block of the ROHM BD70528 Power Management IC.
|
||||||
|
|
||||||
|
config CHARGER_WILCO
|
||||||
|
tristate "Wilco EC based charger for ChromeOS"
|
||||||
|
depends on WILCO_EC
|
||||||
|
help
|
||||||
|
Say Y here to enable control of the charging routines performed
|
||||||
|
by the Embedded Controller on the Chromebook named Wilco. Further
|
||||||
|
information can be found in
|
||||||
|
Documentation/ABI/testing/sysfs-class-power-wilco
|
||||||
|
|
||||||
endif # POWER_SUPPLY
|
endif # POWER_SUPPLY
|
||||||
|
|
|
@ -6,6 +6,7 @@ power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
|
||||||
power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
|
power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
|
||||||
|
|
||||||
obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
|
obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
|
||||||
|
obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
|
||||||
obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
|
obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
|
||||||
|
|
||||||
obj-$(CONFIG_PDA_POWER) += pda_power.o
|
obj-$(CONFIG_PDA_POWER) += pda_power.o
|
||||||
|
@ -91,3 +92,4 @@ obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
|
||||||
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
|
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
|
||||||
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
|
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
|
||||||
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
|
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
|
||||||
|
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
|
||||||
|
|
|
@ -1697,7 +1697,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
|
||||||
static int bq24190_probe(struct i2c_client *client,
|
static int bq24190_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct power_supply_config charger_cfg = {}, battery_cfg = {};
|
struct power_supply_config charger_cfg = {}, battery_cfg = {};
|
||||||
struct bq24190_dev_info *bdi;
|
struct bq24190_dev_info *bdi;
|
||||||
|
|
|
@ -950,7 +950,7 @@ static int bq24257_fw_probe(struct bq24257_device *bq)
|
||||||
static int bq24257_probe(struct i2c_client *client,
|
static int bq24257_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
const struct acpi_device_id *acpi_id;
|
const struct acpi_device_id *acpi_id;
|
||||||
struct bq24257_device *bq;
|
struct bq24257_device *bq;
|
||||||
|
|
|
@ -817,7 +817,7 @@ static int bq25890_fw_probe(struct bq25890_device *bq)
|
||||||
static int bq25890_probe(struct i2c_client *client,
|
static int bq25890_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct bq25890_device *bq;
|
struct bq25890_device *bq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -53,6 +53,8 @@ struct charger_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum power_supply_property cros_usbpd_charger_props[] = {
|
static enum power_supply_property cros_usbpd_charger_props[] = {
|
||||||
|
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
|
||||||
POWER_SUPPLY_PROP_ONLINE,
|
POWER_SUPPLY_PROP_ONLINE,
|
||||||
POWER_SUPPLY_PROP_STATUS,
|
POWER_SUPPLY_PROP_STATUS,
|
||||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||||
|
@ -80,6 +82,10 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = {
|
||||||
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID
|
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Input voltage/current limit in mV/mA. Default to none. */
|
||||||
|
static u16 input_voltage_limit = EC_POWER_LIMIT_NONE;
|
||||||
|
static u16 input_current_limit = EC_POWER_LIMIT_NONE;
|
||||||
|
|
||||||
static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port)
|
static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port)
|
||||||
{
|
{
|
||||||
return port->port_number >= port->charger->num_usbpd_ports;
|
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,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cros_usbpd_charger_set_ext_power_limit(struct charger_data *charger,
|
||||||
|
u16 current_lim,
|
||||||
|
u16 voltage_lim)
|
||||||
|
{
|
||||||
|
struct ec_params_external_power_limit_v1 req;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
req.current_lim = current_lim;
|
||||||
|
req.voltage_lim = voltage_lim;
|
||||||
|
|
||||||
|
ret = cros_usbpd_charger_ec_command(charger, 0,
|
||||||
|
EC_CMD_EXTERNAL_POWER_LIMIT,
|
||||||
|
&req, sizeof(req), NULL, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(charger->dev,
|
||||||
|
"Unable to set the 'External Power Limit': %d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void cros_usbpd_charger_power_changed(struct power_supply *psy)
|
static void cros_usbpd_charger_power_changed(struct power_supply *psy)
|
||||||
{
|
{
|
||||||
struct port_data *port = power_supply_get_drvdata(psy);
|
struct port_data *port = power_supply_get_drvdata(psy);
|
||||||
|
@ -396,6 +422,18 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy,
|
||||||
case POWER_SUPPLY_PROP_USB_TYPE:
|
case POWER_SUPPLY_PROP_USB_TYPE:
|
||||||
val->intval = port->psy_usb_type;
|
val->intval = port->psy_usb_type;
|
||||||
break;
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||||
|
if (input_current_limit == EC_POWER_LIMIT_NONE)
|
||||||
|
val->intval = -1;
|
||||||
|
else
|
||||||
|
val->intval = input_current_limit * 1000;
|
||||||
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||||
|
if (input_voltage_limit == EC_POWER_LIMIT_NONE)
|
||||||
|
val->intval = -1;
|
||||||
|
else
|
||||||
|
val->intval = input_voltage_limit * 1000;
|
||||||
|
break;
|
||||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||||
val->strval = port->model_name;
|
val->strval = port->model_name;
|
||||||
break;
|
break;
|
||||||
|
@ -409,6 +447,81 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cros_usbpd_charger_set_prop(struct power_supply *psy,
|
||||||
|
enum power_supply_property psp,
|
||||||
|
const union power_supply_propval *val)
|
||||||
|
{
|
||||||
|
struct port_data *port = power_supply_get_drvdata(psy);
|
||||||
|
struct charger_data *charger = port->charger;
|
||||||
|
struct device *dev = charger->dev;
|
||||||
|
u16 intval;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* U16_MAX in mV/mA is the maximum supported value */
|
||||||
|
if (val->intval >= U16_MAX * 1000)
|
||||||
|
return -EINVAL;
|
||||||
|
/* A negative number is used to clear the limit */
|
||||||
|
if (val->intval < 0)
|
||||||
|
intval = EC_POWER_LIMIT_NONE;
|
||||||
|
else /* Convert from uA/uV to mA/mV */
|
||||||
|
intval = val->intval / 1000;
|
||||||
|
|
||||||
|
switch (psp) {
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||||
|
ret = cros_usbpd_charger_set_ext_power_limit(charger, intval,
|
||||||
|
input_voltage_limit);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
input_current_limit = intval;
|
||||||
|
if (input_current_limit == EC_POWER_LIMIT_NONE)
|
||||||
|
dev_info(dev,
|
||||||
|
"External Current Limit cleared for all ports\n");
|
||||||
|
else
|
||||||
|
dev_info(dev,
|
||||||
|
"External Current Limit set to %dmA for all ports\n",
|
||||||
|
input_current_limit);
|
||||||
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||||
|
ret = cros_usbpd_charger_set_ext_power_limit(charger,
|
||||||
|
input_current_limit,
|
||||||
|
intval);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
input_voltage_limit = intval;
|
||||||
|
if (input_voltage_limit == EC_POWER_LIMIT_NONE)
|
||||||
|
dev_info(dev,
|
||||||
|
"External Voltage Limit cleared for all ports\n");
|
||||||
|
else
|
||||||
|
dev_info(dev,
|
||||||
|
"External Voltage Limit set to %dmV for all ports\n",
|
||||||
|
input_voltage_limit);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy,
|
||||||
|
enum power_supply_property psp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (psp) {
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||||
|
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
|
static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
|
||||||
unsigned long queued_during_suspend,
|
unsigned long queued_during_suspend,
|
||||||
void *_notify)
|
void *_notify)
|
||||||
|
@ -525,6 +638,9 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
|
||||||
|
|
||||||
psy_desc = &port->psy_desc;
|
psy_desc = &port->psy_desc;
|
||||||
psy_desc->get_property = cros_usbpd_charger_get_prop;
|
psy_desc->get_property = cros_usbpd_charger_get_prop;
|
||||||
|
psy_desc->set_property = cros_usbpd_charger_set_prop;
|
||||||
|
psy_desc->property_is_writeable =
|
||||||
|
cros_usbpd_charger_property_is_writeable;
|
||||||
psy_desc->external_power_changed =
|
psy_desc->external_power_changed =
|
||||||
cros_usbpd_charger_power_changed;
|
cros_usbpd_charger_power_changed;
|
||||||
psy_cfg.drv_data = port;
|
psy_cfg.drv_data = port;
|
||||||
|
|
|
@ -247,7 +247,7 @@ static void stop_irq_work(void *data)
|
||||||
static int max14656_probe(struct i2c_client *client,
|
static int max14656_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct power_supply_config psy_cfg = {};
|
struct power_supply_config psy_cfg = {};
|
||||||
struct max14656_chip *chip;
|
struct max14656_chip *chip;
|
||||||
|
|
|
@ -193,7 +193,7 @@ static const struct power_supply_desc max17040_battery_desc = {
|
||||||
static int max17040_probe(struct i2c_client *client,
|
static int max17040_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct power_supply_config psy_cfg = {};
|
struct power_supply_config psy_cfg = {};
|
||||||
struct max17040_chip *chip;
|
struct max17040_chip *chip;
|
||||||
|
|
||||||
|
|
|
@ -1005,7 +1005,7 @@ static void max17042_stop_work(void *data)
|
||||||
static int max17042_probe(struct i2c_client *client,
|
static int max17042_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
|
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
|
||||||
struct power_supply_config psy_cfg = {};
|
struct power_supply_config psy_cfg = {};
|
||||||
const struct acpi_device_id *acpi_id = NULL;
|
const struct acpi_device_id *acpi_id = NULL;
|
||||||
|
|
|
@ -1071,6 +1071,10 @@ __power_supply_register(struct device *parent,
|
||||||
if (rc)
|
if (rc)
|
||||||
goto create_triggers_failed;
|
goto create_triggers_failed;
|
||||||
|
|
||||||
|
rc = power_supply_add_hwmon_sysfs(psy);
|
||||||
|
if (rc)
|
||||||
|
goto add_hwmon_sysfs_failed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update use_cnt after any uevents (most notably from device_add()).
|
* Update use_cnt after any uevents (most notably from device_add()).
|
||||||
* We are here still during driver's probe but
|
* We are here still during driver's probe but
|
||||||
|
@ -1089,6 +1093,8 @@ __power_supply_register(struct device *parent,
|
||||||
|
|
||||||
return psy;
|
return psy;
|
||||||
|
|
||||||
|
add_hwmon_sysfs_failed:
|
||||||
|
power_supply_remove_triggers(psy);
|
||||||
create_triggers_failed:
|
create_triggers_failed:
|
||||||
psy_unregister_cooler(psy);
|
psy_unregister_cooler(psy);
|
||||||
register_cooler_failed:
|
register_cooler_failed:
|
||||||
|
@ -1241,6 +1247,7 @@ void power_supply_unregister(struct power_supply *psy)
|
||||||
cancel_work_sync(&psy->changed_work);
|
cancel_work_sync(&psy->changed_work);
|
||||||
cancel_delayed_work_sync(&psy->deferred_register_work);
|
cancel_delayed_work_sync(&psy->deferred_register_work);
|
||||||
sysfs_remove_link(&psy->dev.kobj, "powers");
|
sysfs_remove_link(&psy->dev.kobj, "powers");
|
||||||
|
power_supply_remove_hwmon_sysfs(psy);
|
||||||
power_supply_remove_triggers(psy);
|
power_supply_remove_triggers(psy);
|
||||||
psy_unregister_cooler(psy);
|
psy_unregister_cooler(psy);
|
||||||
psy_unregister_thermal(psy);
|
psy_unregister_thermal(psy);
|
||||||
|
|
|
@ -0,0 +1,355 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* power_supply_hwmon.c - power supply hwmon support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/hwmon.h>
|
||||||
|
#include <linux/power_supply.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
struct power_supply_hwmon {
|
||||||
|
struct power_supply *psy;
|
||||||
|
unsigned long *props;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int power_supply_hwmon_in_to_property(u32 attr)
|
||||||
|
{
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_in_average:
|
||||||
|
return POWER_SUPPLY_PROP_VOLTAGE_AVG;
|
||||||
|
case hwmon_in_min:
|
||||||
|
return POWER_SUPPLY_PROP_VOLTAGE_MIN;
|
||||||
|
case hwmon_in_max:
|
||||||
|
return POWER_SUPPLY_PROP_VOLTAGE_MAX;
|
||||||
|
case hwmon_in_input:
|
||||||
|
return POWER_SUPPLY_PROP_VOLTAGE_NOW;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int power_supply_hwmon_curr_to_property(u32 attr)
|
||||||
|
{
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_curr_average:
|
||||||
|
return POWER_SUPPLY_PROP_CURRENT_AVG;
|
||||||
|
case hwmon_curr_max:
|
||||||
|
return POWER_SUPPLY_PROP_CURRENT_MAX;
|
||||||
|
case hwmon_curr_input:
|
||||||
|
return POWER_SUPPLY_PROP_CURRENT_NOW;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int power_supply_hwmon_temp_to_property(u32 attr, int channel)
|
||||||
|
{
|
||||||
|
if (channel) {
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_temp_input:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_AMBIENT;
|
||||||
|
case hwmon_temp_min_alarm:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN;
|
||||||
|
case hwmon_temp_max_alarm:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_temp_input:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP;
|
||||||
|
case hwmon_temp_max:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_MAX;
|
||||||
|
case hwmon_temp_min:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_MIN;
|
||||||
|
case hwmon_temp_min_alarm:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_ALERT_MIN;
|
||||||
|
case hwmon_temp_max_alarm:
|
||||||
|
return POWER_SUPPLY_PROP_TEMP_ALERT_MAX;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
power_supply_hwmon_to_property(enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case hwmon_in:
|
||||||
|
return power_supply_hwmon_in_to_property(attr);
|
||||||
|
case hwmon_curr:
|
||||||
|
return power_supply_hwmon_curr_to_property(attr);
|
||||||
|
case hwmon_temp:
|
||||||
|
return power_supply_hwmon_temp_to_property(attr, channel);
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool power_supply_hwmon_is_a_label(enum hwmon_sensor_types type,
|
||||||
|
u32 attr)
|
||||||
|
{
|
||||||
|
return type == hwmon_temp && attr == hwmon_temp_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool power_supply_hwmon_is_writable(enum hwmon_sensor_types type,
|
||||||
|
u32 attr)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case hwmon_in:
|
||||||
|
return attr == hwmon_in_min ||
|
||||||
|
attr == hwmon_in_max;
|
||||||
|
case hwmon_curr:
|
||||||
|
return attr == hwmon_curr_max;
|
||||||
|
case hwmon_temp:
|
||||||
|
return attr == hwmon_temp_max ||
|
||||||
|
attr == hwmon_temp_min ||
|
||||||
|
attr == hwmon_temp_min_alarm ||
|
||||||
|
attr == hwmon_temp_max_alarm;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static umode_t power_supply_hwmon_is_visible(const void *data,
|
||||||
|
enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel)
|
||||||
|
{
|
||||||
|
const struct power_supply_hwmon *psyhw = data;
|
||||||
|
int prop;
|
||||||
|
|
||||||
|
|
||||||
|
if (power_supply_hwmon_is_a_label(type, attr))
|
||||||
|
return 0444;
|
||||||
|
|
||||||
|
prop = power_supply_hwmon_to_property(type, attr, channel);
|
||||||
|
if (prop < 0 || !test_bit(prop, psyhw->props))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (power_supply_property_is_writeable(psyhw->psy, prop) > 0 &&
|
||||||
|
power_supply_hwmon_is_writable(type, attr))
|
||||||
|
return 0644;
|
||||||
|
|
||||||
|
return 0444;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int power_supply_hwmon_read_string(struct device *dev,
|
||||||
|
enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel,
|
||||||
|
const char **str)
|
||||||
|
{
|
||||||
|
*str = channel ? "temp" : "temp ambient";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
power_supply_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel, long *val)
|
||||||
|
{
|
||||||
|
struct power_supply_hwmon *psyhw = dev_get_drvdata(dev);
|
||||||
|
struct power_supply *psy = psyhw->psy;
|
||||||
|
union power_supply_propval pspval;
|
||||||
|
int ret, prop;
|
||||||
|
|
||||||
|
prop = power_supply_hwmon_to_property(type, attr, channel);
|
||||||
|
if (prop < 0)
|
||||||
|
return prop;
|
||||||
|
|
||||||
|
ret = power_supply_get_property(psy, prop, &pspval);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
/*
|
||||||
|
* Both voltage and current is reported in units of
|
||||||
|
* microvolts/microamps, so we need to adjust it to
|
||||||
|
* milliamps(volts)
|
||||||
|
*/
|
||||||
|
case hwmon_curr:
|
||||||
|
case hwmon_in:
|
||||||
|
pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 1000);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* Temp needs to be converted from 1/10 C to milli-C
|
||||||
|
*/
|
||||||
|
case hwmon_temp:
|
||||||
|
if (check_mul_overflow(pspval.intval, 100,
|
||||||
|
&pspval.intval))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = pspval.intval;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
power_supply_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel, long val)
|
||||||
|
{
|
||||||
|
struct power_supply_hwmon *psyhw = dev_get_drvdata(dev);
|
||||||
|
struct power_supply *psy = psyhw->psy;
|
||||||
|
union power_supply_propval pspval;
|
||||||
|
int prop;
|
||||||
|
|
||||||
|
prop = power_supply_hwmon_to_property(type, attr, channel);
|
||||||
|
if (prop < 0)
|
||||||
|
return prop;
|
||||||
|
|
||||||
|
pspval.intval = val;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
/*
|
||||||
|
* Both voltage and current is reported in units of
|
||||||
|
* microvolts/microamps, so we need to adjust it to
|
||||||
|
* milliamps(volts)
|
||||||
|
*/
|
||||||
|
case hwmon_curr:
|
||||||
|
case hwmon_in:
|
||||||
|
if (check_mul_overflow(pspval.intval, 1000,
|
||||||
|
&pspval.intval))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* Temp needs to be converted from 1/10 C to milli-C
|
||||||
|
*/
|
||||||
|
case hwmon_temp:
|
||||||
|
pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 100);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return power_supply_set_property(psy, prop, &pspval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct hwmon_ops power_supply_hwmon_ops = {
|
||||||
|
.is_visible = power_supply_hwmon_is_visible,
|
||||||
|
.read = power_supply_hwmon_read,
|
||||||
|
.write = power_supply_hwmon_write,
|
||||||
|
.read_string = power_supply_hwmon_read_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_channel_info *power_supply_hwmon_info[] = {
|
||||||
|
HWMON_CHANNEL_INFO(temp,
|
||||||
|
HWMON_T_LABEL |
|
||||||
|
HWMON_T_INPUT |
|
||||||
|
HWMON_T_MAX |
|
||||||
|
HWMON_T_MIN |
|
||||||
|
HWMON_T_MIN_ALARM |
|
||||||
|
HWMON_T_MIN_ALARM,
|
||||||
|
|
||||||
|
HWMON_T_LABEL |
|
||||||
|
HWMON_T_INPUT |
|
||||||
|
HWMON_T_MIN_ALARM |
|
||||||
|
HWMON_T_LABEL |
|
||||||
|
HWMON_T_MAX_ALARM),
|
||||||
|
|
||||||
|
HWMON_CHANNEL_INFO(curr,
|
||||||
|
HWMON_C_AVERAGE |
|
||||||
|
HWMON_C_MAX |
|
||||||
|
HWMON_C_INPUT),
|
||||||
|
|
||||||
|
HWMON_CHANNEL_INFO(in,
|
||||||
|
HWMON_I_AVERAGE |
|
||||||
|
HWMON_I_MIN |
|
||||||
|
HWMON_I_MAX |
|
||||||
|
HWMON_I_INPUT),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
|
||||||
|
.ops = &power_supply_hwmon_ops,
|
||||||
|
.info = power_supply_hwmon_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void power_supply_hwmon_bitmap_free(void *data)
|
||||||
|
{
|
||||||
|
bitmap_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int power_supply_add_hwmon_sysfs(struct power_supply *psy)
|
||||||
|
{
|
||||||
|
const struct power_supply_desc *desc = psy->desc;
|
||||||
|
struct power_supply_hwmon *psyhw;
|
||||||
|
struct device *dev = &psy->dev;
|
||||||
|
struct device *hwmon;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
if (!devres_open_group(dev, power_supply_add_hwmon_sysfs,
|
||||||
|
GFP_KERNEL))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
psyhw = devm_kzalloc(dev, sizeof(*psyhw), GFP_KERNEL);
|
||||||
|
if (!psyhw) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
psyhw->psy = psy;
|
||||||
|
psyhw->props = bitmap_zalloc(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG + 1,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!psyhw->props) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_add_action(dev, power_supply_hwmon_bitmap_free,
|
||||||
|
psyhw->props);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
for (i = 0; i < desc->num_properties; i++) {
|
||||||
|
const enum power_supply_property prop = desc->properties[i];
|
||||||
|
|
||||||
|
switch (prop) {
|
||||||
|
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||||
|
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||||
|
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_MAX:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_MIN:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
|
||||||
|
case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
|
||||||
|
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||||
|
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
|
||||||
|
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||||
|
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||||
|
set_bit(prop, psyhw->props);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hwmon = devm_hwmon_device_register_with_info(dev, psy->desc->name,
|
||||||
|
psyhw,
|
||||||
|
&power_supply_hwmon_chip_info,
|
||||||
|
NULL);
|
||||||
|
ret = PTR_ERR_OR_ZERO(hwmon);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
devres_close_group(dev, power_supply_add_hwmon_sysfs);
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
devres_release_group(dev, NULL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_supply_remove_hwmon_sysfs(struct power_supply *psy)
|
||||||
|
{
|
||||||
|
devres_release_group(&psy->dev, power_supply_add_hwmon_sysfs);
|
||||||
|
}
|
|
@ -276,6 +276,8 @@ static struct device_attribute power_supply_attrs[] = {
|
||||||
POWER_SUPPLY_ATTR(charge_control_start_threshold),
|
POWER_SUPPLY_ATTR(charge_control_start_threshold),
|
||||||
POWER_SUPPLY_ATTR(charge_control_end_threshold),
|
POWER_SUPPLY_ATTR(charge_control_end_threshold),
|
||||||
POWER_SUPPLY_ATTR(input_current_limit),
|
POWER_SUPPLY_ATTR(input_current_limit),
|
||||||
|
POWER_SUPPLY_ATTR(input_voltage_limit),
|
||||||
|
POWER_SUPPLY_ATTR(input_power_limit),
|
||||||
POWER_SUPPLY_ATTR(energy_full_design),
|
POWER_SUPPLY_ATTR(energy_full_design),
|
||||||
POWER_SUPPLY_ATTR(energy_empty_design),
|
POWER_SUPPLY_ATTR(energy_empty_design),
|
||||||
POWER_SUPPLY_ATTR(energy_full),
|
POWER_SUPPLY_ATTR(energy_full),
|
||||||
|
|
|
@ -115,7 +115,7 @@ static const struct power_supply_desc rt5033_battery_desc = {
|
||||||
static int rt5033_battery_probe(struct i2c_client *client,
|
static int rt5033_battery_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct power_supply_config psy_cfg = {};
|
struct power_supply_config psy_cfg = {};
|
||||||
struct rt5033_battery *battery;
|
struct rt5033_battery *battery;
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
|
|
@ -1584,7 +1584,7 @@ static const struct regmap_config rt9455_regmap_config = {
|
||||||
static int rt9455_probe(struct i2c_client *client,
|
static int rt9455_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct rt9455_info *info;
|
struct rt9455_info *info;
|
||||||
struct power_supply_config rt9455_charger_config = {};
|
struct power_supply_config rt9455_charger_config = {};
|
||||||
|
|
|
@ -314,7 +314,7 @@ static const struct power_supply_desc sbsm_default_psy_desc = {
|
||||||
static int sbsm_probe(struct i2c_client *client,
|
static int sbsm_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct sbsm_data *data;
|
struct sbsm_data *data;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct power_supply_desc *psy_desc;
|
struct power_supply_desc *psy_desc;
|
||||||
|
|
|
@ -336,7 +336,7 @@ static int ucs1002_get_usb_type(struct ucs1002_info *info,
|
||||||
case F_ACTIVE_MODE_BC12_CDP:
|
case F_ACTIVE_MODE_BC12_CDP:
|
||||||
type = POWER_SUPPLY_USB_TYPE_CDP;
|
type = POWER_SUPPLY_USB_TYPE_CDP;
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
val->intval = type;
|
val->intval = type;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Charging control driver for the Wilco EC
|
||||||
|
*
|
||||||
|
* Copyright 2019 Google LLC
|
||||||
|
*
|
||||||
|
* See Documentation/ABI/testing/sysfs-class-power and
|
||||||
|
* Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface
|
||||||
|
* and other info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/platform_data/wilco-ec.h>
|
||||||
|
#include <linux/power_supply.h>
|
||||||
|
|
||||||
|
#define DRV_NAME "wilco-charger"
|
||||||
|
|
||||||
|
/* Property IDs and related EC constants */
|
||||||
|
#define PID_CHARGE_MODE 0x0710
|
||||||
|
#define PID_CHARGE_LOWER_LIMIT 0x0711
|
||||||
|
#define PID_CHARGE_UPPER_LIMIT 0x0712
|
||||||
|
|
||||||
|
enum charge_mode {
|
||||||
|
CHARGE_MODE_STD = 1, /* Used for Standard */
|
||||||
|
CHARGE_MODE_EXP = 2, /* Express Charge, used for Fast */
|
||||||
|
CHARGE_MODE_AC = 3, /* Mostly AC use, used for Trickle */
|
||||||
|
CHARGE_MODE_AUTO = 4, /* Used for Adaptive */
|
||||||
|
CHARGE_MODE_CUSTOM = 5, /* Used for Custom */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHARGE_LOWER_LIMIT_MIN 50
|
||||||
|
#define CHARGE_LOWER_LIMIT_MAX 95
|
||||||
|
#define CHARGE_UPPER_LIMIT_MIN 55
|
||||||
|
#define CHARGE_UPPER_LIMIT_MAX 100
|
||||||
|
|
||||||
|
/* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */
|
||||||
|
static int psp_val_to_charge_mode(int psp_val)
|
||||||
|
{
|
||||||
|
switch (psp_val) {
|
||||||
|
case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
|
||||||
|
return CHARGE_MODE_AC;
|
||||||
|
case POWER_SUPPLY_CHARGE_TYPE_FAST:
|
||||||
|
return CHARGE_MODE_EXP;
|
||||||
|
case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
|
||||||
|
return CHARGE_MODE_STD;
|
||||||
|
case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE:
|
||||||
|
return CHARGE_MODE_AUTO;
|
||||||
|
case POWER_SUPPLY_CHARGE_TYPE_CUSTOM:
|
||||||
|
return CHARGE_MODE_CUSTOM;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */
|
||||||
|
static int charge_mode_to_psp_val(enum charge_mode mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case CHARGE_MODE_AC:
|
||||||
|
return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
|
||||||
|
case CHARGE_MODE_EXP:
|
||||||
|
return POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||||
|
case CHARGE_MODE_STD:
|
||||||
|
return POWER_SUPPLY_CHARGE_TYPE_STANDARD;
|
||||||
|
case CHARGE_MODE_AUTO:
|
||||||
|
return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE;
|
||||||
|
case CHARGE_MODE_CUSTOM:
|
||||||
|
return POWER_SUPPLY_CHARGE_TYPE_CUSTOM;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum power_supply_property wilco_charge_props[] = {
|
||||||
|
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||||
|
POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD,
|
||||||
|
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int wilco_charge_get_property(struct power_supply *psy,
|
||||||
|
enum power_supply_property psp,
|
||||||
|
union power_supply_propval *val)
|
||||||
|
{
|
||||||
|
struct wilco_ec_device *ec = power_supply_get_drvdata(psy);
|
||||||
|
u32 property_id;
|
||||||
|
int ret;
|
||||||
|
u8 raw;
|
||||||
|
|
||||||
|
switch (psp) {
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||||
|
property_id = PID_CHARGE_MODE;
|
||||||
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
|
||||||
|
property_id = PID_CHARGE_LOWER_LIMIT;
|
||||||
|
break;
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
|
||||||
|
property_id = PID_CHARGE_UPPER_LIMIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wilco_ec_get_byte_property(ec, property_id, &raw);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (property_id == PID_CHARGE_MODE) {
|
||||||
|
ret = charge_mode_to_psp_val(raw);
|
||||||
|
if (ret < 0)
|
||||||
|
return -EBADMSG;
|
||||||
|
raw = ret;
|
||||||
|
}
|
||||||
|
val->intval = raw;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wilco_charge_set_property(struct power_supply *psy,
|
||||||
|
enum power_supply_property psp,
|
||||||
|
const union power_supply_propval *val)
|
||||||
|
{
|
||||||
|
struct wilco_ec_device *ec = power_supply_get_drvdata(psy);
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
switch (psp) {
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||||
|
mode = psp_val_to_charge_mode(val->intval);
|
||||||
|
if (mode < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
return wilco_ec_set_byte_property(ec, PID_CHARGE_MODE, mode);
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
|
||||||
|
if (val->intval < CHARGE_LOWER_LIMIT_MIN ||
|
||||||
|
val->intval > CHARGE_LOWER_LIMIT_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
return wilco_ec_set_byte_property(ec, PID_CHARGE_LOWER_LIMIT,
|
||||||
|
val->intval);
|
||||||
|
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
|
||||||
|
if (val->intval < CHARGE_UPPER_LIMIT_MIN ||
|
||||||
|
val->intval > CHARGE_UPPER_LIMIT_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
return wilco_ec_set_byte_property(ec, PID_CHARGE_UPPER_LIMIT,
|
||||||
|
val->intval);
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wilco_charge_property_is_writeable(struct power_supply *psy,
|
||||||
|
enum power_supply_property psp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct power_supply_desc wilco_ps_desc = {
|
||||||
|
.properties = wilco_charge_props,
|
||||||
|
.num_properties = ARRAY_SIZE(wilco_charge_props),
|
||||||
|
.get_property = wilco_charge_get_property,
|
||||||
|
.set_property = wilco_charge_set_property,
|
||||||
|
.property_is_writeable = wilco_charge_property_is_writeable,
|
||||||
|
.name = DRV_NAME,
|
||||||
|
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int wilco_charge_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct power_supply_config psy_cfg = {};
|
||||||
|
struct power_supply *psy;
|
||||||
|
|
||||||
|
psy_cfg.drv_data = ec;
|
||||||
|
psy = devm_power_supply_register(&pdev->dev, &wilco_ps_desc, &psy_cfg);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(psy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver wilco_charge_driver = {
|
||||||
|
.probe = wilco_charge_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = DRV_NAME,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
module_platform_driver(wilco_charge_driver);
|
||||||
|
|
||||||
|
MODULE_ALIAS("platform:" DRV_NAME);
|
||||||
|
MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DESCRIPTION("Wilco EC charge control driver");
|
|
@ -128,6 +128,8 @@ enum power_supply_property {
|
||||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */
|
POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */
|
||||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */
|
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */
|
||||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
|
||||||
|
POWER_SUPPLY_PROP_INPUT_POWER_LIMIT,
|
||||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||||
POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
|
POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
|
||||||
POWER_SUPPLY_PROP_ENERGY_FULL,
|
POWER_SUPPLY_PROP_ENERGY_FULL,
|
||||||
|
@ -480,4 +482,17 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_POWER_SUPPLY_HWMON
|
||||||
|
int power_supply_add_hwmon_sysfs(struct power_supply *psy);
|
||||||
|
void power_supply_remove_hwmon_sysfs(struct power_supply *psy);
|
||||||
|
#else
|
||||||
|
static inline int power_supply_add_hwmon_sysfs(struct power_supply *psy)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __LINUX_POWER_SUPPLY_H__ */
|
#endif /* __LINUX_POWER_SUPPLY_H__ */
|
||||||
|
|
Loading…
Reference in New Issue