forked from Minki/linux
power supply and reset changes for the v4.21 series
* New core support - battery internal resistance - battery OCV capacity lookup table - support for custom sysfs attributes * Convert all drivers to use power-supply core support for custom sysfs attributes * bq24190-charger: bq24196 support * axp20x-charger: AXP813 support * sc27xx-battery: new fuel gauge driver * gpio-poweroff: support for specific active and inactive delays * Misc fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAlwlThQACgkQ2O7X88g7 +pqmHg/+PPPeJVIfAAdxFe4KPvP/sAUnAGxqgJc7yeaKOq03eIWnm0JFbEsQLazM XDyk+8N7PQ254n2hU/DQln/OKrkVMo/QaOsn3HbbxaDbUiM5Mj8WjKOzgjWtgUy0 OZOEk6n4SQNx6Ib7Wp/e+H6b/K+EglO5CVZDXmTBJfFKiKp5g4A3ZaUe8bCa1xuG 4AB3QWQPomtI8o/nD37c4lpegojabUGN8hHI6r9TFT1PaYEzAmOQsb0NnGqEKAUw ECPBeH4jVoLN9Bie4u5Fgdr0lqukG+EAEHlHhPRea92oDLFfXEjPOI9JDM4XWBg/ P47KNuvsVrIAUQ3rnCHUP4aC2ElL0G9bcEyADiLOuw9FIjMMjBm65pyRDORwkH+L TAu/28fL2Rzwenk+N8OLZ5lpvYlrqpDFISJkwO7gSGq4wyNW8I62GXJPFAYuSZsf dvlEOTgUCwNUnnF2ehx1AkvOBE+eh1CHvtcbKUMLwtBgWOhVi664Gm2znaLy6PwN XPkcRCNFIr/FZRuAo1x9GyxYv483Nk+27LcKfwz+HtmHHMRRDHDWtJ/K0KqK/y7a 7HE7tBhCMpWikIXT1pAz7A0XYlMqfaMsyHlOqmeFgsNUBuDvJAArDz3Gff935PL3 KGIr4lp+YeTHv6nJT/EMtGIG2dsJZUHh/NAtWZ07usI2fOgE3J4= =59iw -----END PGP SIGNATURE----- Merge tag 'for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: - New core support: - battery internal resistance - battery OCV capacity lookup table - support for custom sysfs attributes - Convert all drivers to use power-supply core support for custom sysfs attributes - bq24190-charger: bq24196 support - axp20x-charger: AXP813 support - sc27xx-battery: new fuel gauge driver - gpio-poweroff: support for specific active and inactive delays - Misc fixes * tag 'for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (53 commits) power: supply: bq25890: fix BAT_COMP field definition power: supply: gpio-charger: Do not use deprecated POWER_SUPPLY_TYPE_USB_* power: supply: ds2781: switch to devm_power_supply_register power: supply: ds2780: switch to devm_power_supply_register power: supply: ds2781: fix race-condition in bin attribute registration power: supply: ds2780: fix race-condition in bin attribute registration power: supply: pcf50633: fix race-condition in sysfs registration power: supply: charger-manager: fix race-condition in sysfs registration power: supply: charger-manager: simplify generation of sysfs attribute group name power: supply: bq24257: fix race-condition in sysfs registration power: supply: bq24190_charger: fix race-condition in sysfs registration power: supply: lp8788: fix race-condition in sysfs registration power: supply: ds2781: fix race-condition in sysfs registration power: supply: ds2780: fix race-condition in sysfs registration power: supply: bq2415x: fix race-condition in sysfs registration power: supply: core: add support for custom sysfs attributes power: supply: sc27xx: Save last battery capacity power: reset: at91-poweroff: move shdwc related data to one structure power: supply: sc27xx: Add suspend/resume interfaces power: supply: sc27xx: Add fuel gauge low voltage alarm ...
This commit is contained in:
commit
579a700359
@ -27,6 +27,8 @@ Optional properties:
|
||||
it to an output when the power-off handler is called. If this optional
|
||||
property is not specified, the GPIO is initialized as an output in its
|
||||
inactive state.
|
||||
- active-delay-ms: Delay (default 100) to wait after driving gpio active
|
||||
- inactive-delay-ms: Delay (default 100) to wait after driving gpio inactive
|
||||
- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is
|
||||
specified, 3000 ms is used.
|
||||
|
||||
|
@ -4,6 +4,7 @@ Required Properties:
|
||||
- compatible: One of:
|
||||
"x-powers,axp202-ac-power-supply"
|
||||
"x-powers,axp221-ac-power-supply"
|
||||
"x-powers,axp813-ac-power-supply"
|
||||
|
||||
This node is a subnode of the axp20x PMIC.
|
||||
|
||||
@ -13,6 +14,8 @@ reading ADC channels from the AXP20X ADC.
|
||||
The AXP22X is only able to tell if an AC power supply is present and
|
||||
usable.
|
||||
|
||||
AXP813/AXP803 are able to limit current and supply voltage
|
||||
|
||||
Example:
|
||||
|
||||
&axp209 {
|
||||
|
@ -22,6 +22,18 @@ Optional Properties:
|
||||
- charge-term-current-microamp: current for charge termination phase
|
||||
- constant-charge-current-max-microamp: maximum constant input current
|
||||
- constant-charge-voltage-max-microvolt: maximum constant input voltage
|
||||
- factory-internal-resistance-micro-ohms: battery factory internal resistance
|
||||
- ocv-capacity-table-0: An array providing the open circuit voltage (OCV)
|
||||
of the battery and corresponding battery capacity percent, which is used
|
||||
to look up battery capacity according to current OCV value. And the open
|
||||
circuit voltage unit is microvolt.
|
||||
- ocv-capacity-table-1: Same as ocv-capacity-table-0
|
||||
......
|
||||
- ocv-capacity-table-n: Same as ocv-capacity-table-0
|
||||
- ocv-capacity-celsius: An array containing the temperature in degree Celsius,
|
||||
for each of the battery capacity lookup table. The first temperature value
|
||||
specifies the OCV table 0, and the second temperature value specifies the
|
||||
OCV table 1, and so on.
|
||||
|
||||
Battery properties are named, where possible, for the corresponding
|
||||
elements in enum power_supply_property, defined in
|
||||
@ -42,6 +54,11 @@ Example:
|
||||
charge-term-current-microamp = <128000>;
|
||||
constant-charge-current-max-microamp = <900000>;
|
||||
constant-charge-voltage-max-microvolt = <4200000>;
|
||||
factory-internal-resistance-micro-ohms = <250000>;
|
||||
ocv-capacity-celsius = <(-10) 0 10>;
|
||||
ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
|
||||
ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
|
||||
ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
|
||||
};
|
||||
|
||||
charger: charger@11 {
|
||||
|
@ -3,7 +3,9 @@ TI BQ24190 Li-Ion Battery Charger
|
||||
Required properties:
|
||||
- compatible: contains one of the following:
|
||||
* "ti,bq24190"
|
||||
* "ti,bq24192"
|
||||
* "ti,bq24192i"
|
||||
* "ti,bq24196"
|
||||
- reg: integer, I2C address of the charger.
|
||||
- interrupts[-extended]: configuration for charger INT pin.
|
||||
|
||||
@ -19,6 +21,12 @@ Optional properties:
|
||||
- ti,system-minimum-microvolt: when power is connected and the battery is below
|
||||
minimum system voltage, the system will be regulated above this setting.
|
||||
|
||||
child nodes:
|
||||
- usb-otg-vbus:
|
||||
Usage: optional
|
||||
Description: Regulator that is used to control the VBUS voltage direction for
|
||||
either USB host mode or for charging on the OTG port.
|
||||
|
||||
Notes:
|
||||
- Some circuit boards wire the chip's "OTG" pin high (enabling 500mA default
|
||||
charge current on USB SDP ports, among other features). To simulate this on
|
||||
@ -39,6 +47,8 @@ Example:
|
||||
interrupts-extended = <&gpiochip 10 IRQ_TYPE_EDGE_FALLING>;
|
||||
monitored-battery = <&bat>;
|
||||
ti,system-minimum-microvolt = <3200000>;
|
||||
|
||||
usb_otg_vbus: usb-otg-vbus { };
|
||||
};
|
||||
|
||||
&twl_gpio {
|
||||
|
56
Documentation/devicetree/bindings/power/supply/sc27xx-fg.txt
Normal file
56
Documentation/devicetree/bindings/power/supply/sc27xx-fg.txt
Normal file
@ -0,0 +1,56 @@
|
||||
Spreadtrum SC27XX PMICs Fuel Gauge Unit Power Supply Bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
"sprd,sc2720-fgu",
|
||||
"sprd,sc2721-fgu",
|
||||
"sprd,sc2723-fgu",
|
||||
"sprd,sc2730-fgu",
|
||||
"sprd,sc2731-fgu".
|
||||
- reg: The address offset of fuel gauge unit.
|
||||
- battery-detect-gpios: GPIO for battery detection.
|
||||
- io-channels: Specify the IIO ADC channel to get temperature.
|
||||
- io-channel-names: Should be "bat-temp".
|
||||
- nvmem-cells: A phandle to the calibration cells provided by eFuse device.
|
||||
- nvmem-cell-names: Should be "fgu_calib".
|
||||
- monitored-battery: Phandle of battery characteristics devicetree node.
|
||||
See Documentation/devicetree/bindings/power/supply/battery.txt
|
||||
|
||||
Example:
|
||||
|
||||
bat: battery {
|
||||
compatible = "simple-battery";
|
||||
charge-full-design-microamp-hours = <1900000>;
|
||||
constant-charge-voltage-max-microvolt = <4350000>;
|
||||
ocv-capacity-celsius = <20>;
|
||||
ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>,
|
||||
<4022000 85>, <3983000 80>, <3949000 75>,
|
||||
<3917000 70>, <3889000 65>, <3864000 60>,
|
||||
<3835000 55>, <3805000 50>, <3787000 45>,
|
||||
<3777000 40>, <3773000 35>, <3770000 30>,
|
||||
<3765000 25>, <3752000 20>, <3724000 15>,
|
||||
<3680000 10>, <3605000 5>, <3400000 0>;
|
||||
......
|
||||
};
|
||||
|
||||
sc2731_pmic: pmic@0 {
|
||||
compatible = "sprd,sc2731";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <26000000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fgu@a00 {
|
||||
compatible = "sprd,sc2731-fgu";
|
||||
reg = <0xa00>;
|
||||
battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>;
|
||||
io-channels = <&pmic_adc 5>;
|
||||
io-channel-names = "bat-temp";
|
||||
nvmem-cells = <&fgu_calib>;
|
||||
nvmem-cell-names = "fgu_calib";
|
||||
monitored-battery = <&bat>;
|
||||
};
|
||||
};
|
@ -51,14 +51,16 @@ static const char *shdwc_wakeup_modes[] = {
|
||||
[AT91_SHDW_WKMODE0_ANYLEVEL] = "any",
|
||||
};
|
||||
|
||||
static void __iomem *at91_shdwc_base;
|
||||
static struct clk *sclk;
|
||||
static void __iomem *mpddrc_base;
|
||||
static struct shdwc {
|
||||
struct clk *sclk;
|
||||
void __iomem *shdwc_base;
|
||||
void __iomem *mpddrc_base;
|
||||
} at91_shdwc;
|
||||
|
||||
static void __init at91_wakeup_status(struct platform_device *pdev)
|
||||
{
|
||||
const char *reason;
|
||||
u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR);
|
||||
u32 reg = readl(at91_shdwc.shdwc_base + AT91_SHDW_SR);
|
||||
|
||||
/* Simple power-on, just bail out */
|
||||
if (!reg)
|
||||
@ -75,11 +77,6 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static void at91_poweroff(void)
|
||||
{
|
||||
writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
|
||||
}
|
||||
|
||||
static void at91_lpddr_poweroff(void)
|
||||
{
|
||||
asm volatile(
|
||||
/* Align to cache lines */
|
||||
@ -89,15 +86,17 @@ static void at91_lpddr_poweroff(void)
|
||||
" ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
/* Power down SDRAM0 */
|
||||
" tst %0, #0\n\t"
|
||||
" beq 1f\n\t"
|
||||
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
|
||||
/* Shutdown CPU */
|
||||
" str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
"1: str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
" b .\n\t"
|
||||
:
|
||||
: "r" (mpddrc_base),
|
||||
: "r" (at91_shdwc.mpddrc_base),
|
||||
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
|
||||
"r" (at91_shdwc_base),
|
||||
"r" (at91_shdwc.shdwc_base),
|
||||
"r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
|
||||
: "r6");
|
||||
}
|
||||
@ -147,7 +146,7 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
|
||||
if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
|
||||
mode |= AT91_SHDW_RTTWKEN;
|
||||
|
||||
writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR);
|
||||
writel(wakeup_mode | mode, at91_shdwc.shdwc_base + AT91_SHDW_MR);
|
||||
}
|
||||
|
||||
static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
@ -158,15 +157,15 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(at91_shdwc_base))
|
||||
return PTR_ERR(at91_shdwc_base);
|
||||
at91_shdwc.shdwc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(at91_shdwc.shdwc_base))
|
||||
return PTR_ERR(at91_shdwc.shdwc_base);
|
||||
|
||||
sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sclk))
|
||||
return PTR_ERR(sclk);
|
||||
at91_shdwc.sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(at91_shdwc.sclk))
|
||||
return PTR_ERR(at91_shdwc.sclk);
|
||||
|
||||
ret = clk_prepare_enable(sclk);
|
||||
ret = clk_prepare_enable(at91_shdwc.sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
@ -177,44 +176,47 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
if (pdev->dev.of_node)
|
||||
at91_poweroff_dt_set_wakeup_mode(pdev);
|
||||
|
||||
pm_power_off = at91_poweroff;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
mpddrc_base = of_iomap(np, 0);
|
||||
if (np) {
|
||||
at91_shdwc.mpddrc_base = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
|
||||
if (!mpddrc_base)
|
||||
return 0;
|
||||
if (!at91_shdwc.mpddrc_base) {
|
||||
ret = -ENOMEM;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
|
||||
if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
|
||||
(ddr_type == AT91_DDRSDRC_MD_LPDDR3))
|
||||
pm_power_off = at91_lpddr_poweroff;
|
||||
else
|
||||
iounmap(mpddrc_base);
|
||||
ddr_type = readl(at91_shdwc.mpddrc_base + AT91_DDRSDRC_MDR) &
|
||||
AT91_DDRSDRC_MD;
|
||||
if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 &&
|
||||
ddr_type != AT91_DDRSDRC_MD_LPDDR3) {
|
||||
iounmap(at91_shdwc.mpddrc_base);
|
||||
at91_shdwc.mpddrc_base = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pm_power_off = at91_poweroff;
|
||||
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
clk_disable_unprepare(at91_shdwc.sclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit at91_poweroff_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (pm_power_off == at91_poweroff ||
|
||||
pm_power_off == at91_lpddr_poweroff)
|
||||
if (pm_power_off == at91_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
clk_disable_unprepare(sclk);
|
||||
if (at91_shdwc.mpddrc_base)
|
||||
iounmap(at91_shdwc.mpddrc_base);
|
||||
|
||||
clk_disable_unprepare(at91_shdwc.sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_ramc_of_match[] = {
|
||||
{ .compatible = "atmel,sama5d3-ddramc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct of_device_id at91_poweroff_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-shdwc", },
|
||||
{ .compatible = "atmel,at91sam9rl-shdwc", },
|
||||
|
@ -26,6 +26,8 @@
|
||||
*/
|
||||
static struct gpio_desc *reset_gpio;
|
||||
static u32 timeout = DEFAULT_TIMEOUT_MS;
|
||||
static u32 active_delay = 100;
|
||||
static u32 inactive_delay = 100;
|
||||
|
||||
static void gpio_poweroff_do_poweroff(void)
|
||||
{
|
||||
@ -33,10 +35,11 @@ static void gpio_poweroff_do_poweroff(void)
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
gpiod_direction_output(reset_gpio, 1);
|
||||
mdelay(100);
|
||||
mdelay(active_delay);
|
||||
|
||||
/* drive inactive, also active->inactive edge */
|
||||
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||
mdelay(100);
|
||||
mdelay(inactive_delay);
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||
@ -66,6 +69,9 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
|
||||
else
|
||||
flags = GPIOD_OUT_LOW;
|
||||
|
||||
device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay);
|
||||
device_property_read_u32(&pdev->dev, "inactive-delay-ms",
|
||||
&inactive_delay);
|
||||
device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
|
||||
|
||||
reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
|
||||
|
@ -26,6 +26,13 @@ struct ocelot_reset_context {
|
||||
|
||||
#define SOFT_CHIP_RST BIT(0)
|
||||
|
||||
#define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
|
||||
#define IF_SI_OWNER_MASK GENMASK(1, 0)
|
||||
#define IF_SI_OWNER_SISL 0
|
||||
#define IF_SI_OWNER_SIBM 1
|
||||
#define IF_SI_OWNER_SIMC 2
|
||||
#define IF_SI_OWNER_OFFSET 4
|
||||
|
||||
static int ocelot_restart_handle(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
@ -37,6 +44,11 @@ static int ocelot_restart_handle(struct notifier_block *this,
|
||||
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
|
||||
CORE_RST_PROTECT, 0);
|
||||
|
||||
/* Make the SI back to boot mode */
|
||||
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
|
||||
IF_SI_OWNER_MASK << IF_SI_OWNER_OFFSET,
|
||||
IF_SI_OWNER_SIBM << IF_SI_OWNER_OFFSET);
|
||||
|
||||
writel(SOFT_CHIP_RST, ctx->base);
|
||||
|
||||
pr_emerg("Unable to restart system\n");
|
||||
|
@ -652,4 +652,12 @@ config CHARGER_SC2731
|
||||
Say Y here to enable support for battery charging with SC2731
|
||||
PMIC chips.
|
||||
|
||||
config FUEL_GAUGE_SC27XX
|
||||
tristate "Spreadtrum SC27XX fuel gauge driver"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
depends on IIO
|
||||
help
|
||||
Say Y here to enable support for fuel gauge with SC27XX
|
||||
PMIC chips.
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
@ -86,3 +86,4 @@ obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
|
||||
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
|
||||
obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
|
||||
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
|
||||
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
|
||||
|
@ -27,6 +27,16 @@
|
||||
#define AXP20X_PWR_STATUS_ACIN_PRESENT BIT(7)
|
||||
#define AXP20X_PWR_STATUS_ACIN_AVAIL BIT(6)
|
||||
|
||||
#define AXP813_VHOLD_MASK GENMASK(5, 3)
|
||||
#define AXP813_VHOLD_UV_TO_BIT(x) ((((x) / 100000) - 40) << 3)
|
||||
#define AXP813_VHOLD_REG_TO_UV(x) \
|
||||
(((((x) & AXP813_VHOLD_MASK) >> 3) + 40) * 100000)
|
||||
|
||||
#define AXP813_CURR_LIMIT_MASK GENMASK(2, 0)
|
||||
#define AXP813_CURR_LIMIT_UA_TO_BIT(x) (((x) / 500000) - 3)
|
||||
#define AXP813_CURR_LIMIT_REG_TO_UA(x) \
|
||||
((((x) & AXP813_CURR_LIMIT_MASK) + 3) * 500000)
|
||||
|
||||
#define DRVNAME "axp20x-ac-power-supply"
|
||||
|
||||
struct axp20x_ac_power {
|
||||
@ -102,6 +112,27 @@ static int axp20x_ac_power_get_property(struct power_supply *psy,
|
||||
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
|
||||
ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = AXP813_VHOLD_REG_TO_UV(reg);
|
||||
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = AXP813_CURR_LIMIT_REG_TO_UA(reg);
|
||||
/* AXP813 datasheet defines values 11x as 4000mA */
|
||||
if (val->intval > 4000000)
|
||||
val->intval = 4000000;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -109,6 +140,43 @@ static int axp20x_ac_power_get_property(struct power_supply *psy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int axp813_ac_power_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
|
||||
if (val->intval < 4000000 || val->intval > 4700000)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
|
||||
AXP813_VHOLD_MASK,
|
||||
AXP813_VHOLD_UV_TO_BIT(val->intval));
|
||||
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
if (val->intval < 1500000 || val->intval > 4000000)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
|
||||
AXP813_CURR_LIMIT_MASK,
|
||||
AXP813_CURR_LIMIT_UA_TO_BIT(val->intval));
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int axp813_ac_power_prop_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
|
||||
psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
|
||||
}
|
||||
|
||||
static enum power_supply_property axp20x_ac_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
@ -123,6 +191,14 @@ static enum power_supply_property axp22x_ac_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static enum power_supply_property axp813_ac_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc axp20x_ac_power_desc = {
|
||||
.name = "axp20x-ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
@ -139,6 +215,16 @@ static const struct power_supply_desc axp22x_ac_power_desc = {
|
||||
.get_property = axp20x_ac_power_get_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc axp813_ac_power_desc = {
|
||||
.name = "axp813-ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = axp813_ac_power_properties,
|
||||
.num_properties = ARRAY_SIZE(axp813_ac_power_properties),
|
||||
.property_is_writeable = axp813_ac_power_prop_writeable,
|
||||
.get_property = axp20x_ac_power_get_property,
|
||||
.set_property = axp813_ac_power_set_property,
|
||||
};
|
||||
|
||||
struct axp_data {
|
||||
const struct power_supply_desc *power_desc;
|
||||
bool acin_adc;
|
||||
@ -154,6 +240,11 @@ static const struct axp_data axp22x_data = {
|
||||
.acin_adc = false,
|
||||
};
|
||||
|
||||
static const struct axp_data axp813_data = {
|
||||
.power_desc = &axp813_ac_power_desc,
|
||||
.acin_adc = false,
|
||||
};
|
||||
|
||||
static int axp20x_ac_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
@ -234,6 +325,9 @@ static const struct of_device_id axp20x_ac_power_match[] = {
|
||||
}, {
|
||||
.compatible = "x-powers,axp221-ac-power-supply",
|
||||
.data = &axp22x_data,
|
||||
}, {
|
||||
.compatible = "x-powers,axp813-ac-power-supply",
|
||||
.data = &axp813_data,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axp20x_ac_power_match);
|
||||
|
@ -10,6 +10,7 @@
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -29,17 +30,17 @@
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/extcon.h>
|
||||
|
||||
#define PS_STAT_VBUS_TRIGGER (1 << 0)
|
||||
#define PS_STAT_BAT_CHRG_DIR (1 << 2)
|
||||
#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3)
|
||||
#define PS_STAT_VBUS_VALID (1 << 4)
|
||||
#define PS_STAT_VBUS_PRESENT (1 << 5)
|
||||
#define PS_STAT_VBUS_TRIGGER BIT(0)
|
||||
#define PS_STAT_BAT_CHRG_DIR BIT(2)
|
||||
#define PS_STAT_VBAT_ABOVE_VHOLD BIT(3)
|
||||
#define PS_STAT_VBUS_VALID BIT(4)
|
||||
#define PS_STAT_VBUS_PRESENT BIT(5)
|
||||
|
||||
#define CHRG_STAT_BAT_SAFE_MODE (1 << 3)
|
||||
#define CHRG_STAT_BAT_VALID (1 << 4)
|
||||
#define CHRG_STAT_BAT_PRESENT (1 << 5)
|
||||
#define CHRG_STAT_CHARGING (1 << 6)
|
||||
#define CHRG_STAT_PMIC_OTP (1 << 7)
|
||||
#define CHRG_STAT_BAT_SAFE_MODE BIT(3)
|
||||
#define CHRG_STAT_BAT_VALID BIT(4)
|
||||
#define CHRG_STAT_BAT_PRESENT BIT(5)
|
||||
#define CHRG_STAT_CHARGING BIT(6)
|
||||
#define CHRG_STAT_PMIC_OTP BIT(7)
|
||||
|
||||
#define VBUS_ISPOUT_CUR_LIM_MASK 0x03
|
||||
#define VBUS_ISPOUT_CUR_LIM_BIT_POS 0
|
||||
@ -52,33 +53,33 @@
|
||||
#define VBUS_ISPOUT_VHOLD_SET_OFFSET 4000 /* 4000mV */
|
||||
#define VBUS_ISPOUT_VHOLD_SET_LSB_RES 100 /* 100mV */
|
||||
#define VBUS_ISPOUT_VHOLD_SET_4300MV 0x3 /* 4300mV */
|
||||
#define VBUS_ISPOUT_VBUS_PATH_DIS (1 << 7)
|
||||
#define VBUS_ISPOUT_VBUS_PATH_DIS BIT(7)
|
||||
|
||||
#define CHRG_CCCV_CC_MASK 0xf /* 4 bits */
|
||||
#define CHRG_CCCV_CC_BIT_POS 0
|
||||
#define CHRG_CCCV_CC_OFFSET 200 /* 200mA */
|
||||
#define CHRG_CCCV_CC_LSB_RES 200 /* 200mA */
|
||||
#define CHRG_CCCV_ITERM_20P (1 << 4) /* 20% of CC */
|
||||
#define CHRG_CCCV_ITERM_20P BIT(4) /* 20% of CC */
|
||||
#define CHRG_CCCV_CV_MASK 0x60 /* 2 bits */
|
||||
#define CHRG_CCCV_CV_BIT_POS 5
|
||||
#define CHRG_CCCV_CV_4100MV 0x0 /* 4.10V */
|
||||
#define CHRG_CCCV_CV_4150MV 0x1 /* 4.15V */
|
||||
#define CHRG_CCCV_CV_4200MV 0x2 /* 4.20V */
|
||||
#define CHRG_CCCV_CV_4350MV 0x3 /* 4.35V */
|
||||
#define CHRG_CCCV_CHG_EN (1 << 7)
|
||||
#define CHRG_CCCV_CHG_EN BIT(7)
|
||||
|
||||
#define CNTL2_CC_TIMEOUT_MASK 0x3 /* 2 bits */
|
||||
#define CNTL2_CC_TIMEOUT_OFFSET 6 /* 6 Hrs */
|
||||
#define CNTL2_CC_TIMEOUT_LSB_RES 2 /* 2 Hrs */
|
||||
#define CNTL2_CC_TIMEOUT_12HRS 0x3 /* 12 Hrs */
|
||||
#define CNTL2_CHGLED_TYPEB (1 << 4)
|
||||
#define CNTL2_CHG_OUT_TURNON (1 << 5)
|
||||
#define CNTL2_CHGLED_TYPEB BIT(4)
|
||||
#define CNTL2_CHG_OUT_TURNON BIT(5)
|
||||
#define CNTL2_PC_TIMEOUT_MASK 0xC0
|
||||
#define CNTL2_PC_TIMEOUT_OFFSET 40 /* 40 mins */
|
||||
#define CNTL2_PC_TIMEOUT_LSB_RES 10 /* 10 mins */
|
||||
#define CNTL2_PC_TIMEOUT_70MINS 0x3
|
||||
|
||||
#define CHRG_ILIM_TEMP_LOOP_EN (1 << 3)
|
||||
#define CHRG_ILIM_TEMP_LOOP_EN BIT(3)
|
||||
#define CHRG_VBUS_ILIM_MASK 0xf0
|
||||
#define CHRG_VBUS_ILIM_BIT_POS 4
|
||||
#define CHRG_VBUS_ILIM_100MA 0x0 /* 100mA */
|
||||
@ -94,7 +95,7 @@
|
||||
#define CHRG_VLTFC_0C 0xA5 /* 0 DegC */
|
||||
#define CHRG_VHTFC_45C 0x1F /* 45 DegC */
|
||||
|
||||
#define FG_CNTL_OCV_ADJ_EN (1 << 3)
|
||||
#define FG_CNTL_OCV_ADJ_EN BIT(3)
|
||||
|
||||
#define CV_4100MV 4100 /* 4100mV */
|
||||
#define CV_4150MV 4150 /* 4150mV */
|
||||
|
@ -1032,54 +1032,6 @@ static int bq2415x_power_supply_get_property(struct power_supply *psy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
|
||||
{
|
||||
int ret;
|
||||
int chip;
|
||||
char revstr[8];
|
||||
struct power_supply_config psy_cfg = {
|
||||
.drv_data = bq,
|
||||
.of_node = bq->dev->of_node,
|
||||
};
|
||||
|
||||
bq->charger_desc.name = bq->name;
|
||||
bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
|
||||
bq->charger_desc.properties = bq2415x_power_supply_props;
|
||||
bq->charger_desc.num_properties =
|
||||
ARRAY_SIZE(bq2415x_power_supply_props);
|
||||
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
|
||||
|
||||
ret = bq2415x_detect_chip(bq);
|
||||
if (ret < 0)
|
||||
chip = BQUNKNOWN;
|
||||
else
|
||||
chip = ret;
|
||||
|
||||
ret = bq2415x_detect_revision(bq);
|
||||
if (ret < 0)
|
||||
strcpy(revstr, "unknown");
|
||||
else
|
||||
sprintf(revstr, "1.%d", ret);
|
||||
|
||||
bq->model = kasprintf(GFP_KERNEL,
|
||||
"chip %s, revision %s, vender code %.3d",
|
||||
bq2415x_chip_name[chip], revstr,
|
||||
bq2415x_get_vender_code(bq));
|
||||
if (!bq->model) {
|
||||
dev_err(bq->dev, "failed to allocate model name\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(bq->charger)) {
|
||||
kfree(bq->model);
|
||||
return PTR_ERR(bq->charger);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bq2415x_power_supply_exit(struct bq2415x_device *bq)
|
||||
{
|
||||
bq->autotimer = 0;
|
||||
@ -1496,7 +1448,7 @@ static DEVICE_ATTR(charge_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
|
||||
static DEVICE_ATTR(boost_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
|
||||
static DEVICE_ATTR(fault_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
|
||||
|
||||
static struct attribute *bq2415x_sysfs_attributes[] = {
|
||||
static struct attribute *bq2415x_sysfs_attrs[] = {
|
||||
/*
|
||||
* TODO: some (appropriate) of these attrs should be switched to
|
||||
* use power supply class props.
|
||||
@ -1525,19 +1477,55 @@ static struct attribute *bq2415x_sysfs_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group bq2415x_sysfs_attr_group = {
|
||||
.attrs = bq2415x_sysfs_attributes,
|
||||
ATTRIBUTE_GROUPS(bq2415x_sysfs);
|
||||
|
||||
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
|
||||
{
|
||||
int ret;
|
||||
int chip;
|
||||
char revstr[8];
|
||||
struct power_supply_config psy_cfg = {
|
||||
.drv_data = bq,
|
||||
.of_node = bq->dev->of_node,
|
||||
.attr_grp = bq2415x_sysfs_groups,
|
||||
};
|
||||
|
||||
static int bq2415x_sysfs_init(struct bq2415x_device *bq)
|
||||
{
|
||||
return sysfs_create_group(&bq->charger->dev.kobj,
|
||||
&bq2415x_sysfs_attr_group);
|
||||
bq->charger_desc.name = bq->name;
|
||||
bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
|
||||
bq->charger_desc.properties = bq2415x_power_supply_props;
|
||||
bq->charger_desc.num_properties =
|
||||
ARRAY_SIZE(bq2415x_power_supply_props);
|
||||
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
|
||||
|
||||
ret = bq2415x_detect_chip(bq);
|
||||
if (ret < 0)
|
||||
chip = BQUNKNOWN;
|
||||
else
|
||||
chip = ret;
|
||||
|
||||
ret = bq2415x_detect_revision(bq);
|
||||
if (ret < 0)
|
||||
strcpy(revstr, "unknown");
|
||||
else
|
||||
sprintf(revstr, "1.%d", ret);
|
||||
|
||||
bq->model = kasprintf(GFP_KERNEL,
|
||||
"chip %s, revision %s, vender code %.3d",
|
||||
bq2415x_chip_name[chip], revstr,
|
||||
bq2415x_get_vender_code(bq));
|
||||
if (!bq->model) {
|
||||
dev_err(bq->dev, "failed to allocate model name\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void bq2415x_sysfs_exit(struct bq2415x_device *bq)
|
||||
{
|
||||
sysfs_remove_group(&bq->charger->dev.kobj, &bq2415x_sysfs_attr_group);
|
||||
bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(bq->charger)) {
|
||||
kfree(bq->model);
|
||||
return PTR_ERR(bq->charger);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* main bq2415x probe function */
|
||||
@ -1651,16 +1639,10 @@ static int bq2415x_probe(struct i2c_client *client,
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
ret = bq2415x_sysfs_init(bq);
|
||||
if (ret) {
|
||||
dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret);
|
||||
goto error_3;
|
||||
}
|
||||
|
||||
ret = bq2415x_set_defaults(bq);
|
||||
if (ret) {
|
||||
dev_err(bq->dev, "failed to set default values: %d\n", ret);
|
||||
goto error_4;
|
||||
goto error_3;
|
||||
}
|
||||
|
||||
if (bq->notify_node || bq->init_data.notify_device) {
|
||||
@ -1668,7 +1650,7 @@ static int bq2415x_probe(struct i2c_client *client,
|
||||
ret = power_supply_reg_notifier(&bq->nb);
|
||||
if (ret) {
|
||||
dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
|
||||
goto error_4;
|
||||
goto error_3;
|
||||
}
|
||||
|
||||
bq->automode = 1;
|
||||
@ -1707,8 +1689,6 @@ static int bq2415x_probe(struct i2c_client *client,
|
||||
dev_info(bq->dev, "driver registered\n");
|
||||
return 0;
|
||||
|
||||
error_4:
|
||||
bq2415x_sysfs_exit(bq);
|
||||
error_3:
|
||||
bq2415x_power_supply_exit(bq);
|
||||
error_2:
|
||||
@ -1733,7 +1713,6 @@ static int bq2415x_remove(struct i2c_client *client)
|
||||
power_supply_unreg_notifier(&bq->nb);
|
||||
|
||||
of_node_put(bq->notify_node);
|
||||
bq2415x_sysfs_exit(bq);
|
||||
bq2415x_power_supply_exit(bq);
|
||||
|
||||
bq2415x_reset_chip(bq);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
|
||||
#define BQ24190_MANUFACTURER "Texas Instruments"
|
||||
|
||||
@ -142,7 +143,7 @@
|
||||
#define BQ24190_REG_VPRS_PN_MASK (BIT(5) | BIT(4) | BIT(3))
|
||||
#define BQ24190_REG_VPRS_PN_SHIFT 3
|
||||
#define BQ24190_REG_VPRS_PN_24190 0x4
|
||||
#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193 */
|
||||
#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193, 24196 */
|
||||
#define BQ24190_REG_VPRS_PN_24192I 0x3
|
||||
#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2)
|
||||
#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2
|
||||
@ -159,6 +160,7 @@
|
||||
struct bq24190_dev_info {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct extcon_dev *edev;
|
||||
struct power_supply *charger;
|
||||
struct power_supply *battery;
|
||||
struct delayed_work input_current_limit_work;
|
||||
@ -174,6 +176,11 @@ struct bq24190_dev_info {
|
||||
u8 watchdog;
|
||||
};
|
||||
|
||||
static const unsigned int bq24190_usb_extcon_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
/*
|
||||
* The tables below provide a 2-way mapping for the value that goes in
|
||||
* the register field and the real-world value that it represents.
|
||||
@ -402,9 +409,7 @@ static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
|
||||
static struct attribute *
|
||||
bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
|
||||
|
||||
static const struct attribute_group bq24190_sysfs_attr_group = {
|
||||
.attrs = bq24190_sysfs_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bq24190_sysfs);
|
||||
|
||||
static void bq24190_sysfs_init_attrs(void)
|
||||
{
|
||||
@ -491,26 +496,6 @@ static ssize_t bq24190_sysfs_store(struct device *dev,
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
bq24190_sysfs_init_attrs();
|
||||
|
||||
return sysfs_create_group(&bdi->charger->dev.kobj,
|
||||
&bq24190_sysfs_attr_group);
|
||||
}
|
||||
|
||||
static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
sysfs_remove_group(&bdi->charger->dev.kobj, &bq24190_sysfs_attr_group);
|
||||
}
|
||||
#else
|
||||
static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
@ -577,6 +562,7 @@ static const struct regulator_ops bq24190_vbus_ops = {
|
||||
|
||||
static const struct regulator_desc bq24190_vbus_desc = {
|
||||
.name = "usb_otg_vbus",
|
||||
.of_match = "usb-otg-vbus",
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &bq24190_vbus_ops,
|
||||
@ -1527,6 +1513,20 @@ static const struct power_supply_desc bq24190_battery_desc = {
|
||||
.property_is_writeable = bq24190_battery_property_is_writeable,
|
||||
};
|
||||
|
||||
static int bq24190_configure_usb_otg(struct bq24190_dev_info *bdi, u8 ss_reg)
|
||||
{
|
||||
bool otg_enabled;
|
||||
int ret;
|
||||
|
||||
otg_enabled = !!(ss_reg & BQ24190_REG_SS_VBUS_STAT_MASK);
|
||||
ret = extcon_set_state_sync(bdi->edev, EXTCON_USB, otg_enabled);
|
||||
if (ret < 0)
|
||||
dev_err(bdi->dev, "Can't set extcon state to %d: %d\n",
|
||||
otg_enabled, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bq24190_check_status(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
|
||||
@ -1596,8 +1596,10 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi)
|
||||
bdi->ss_reg = ss_reg;
|
||||
}
|
||||
|
||||
if (alert_charger || alert_battery)
|
||||
if (alert_charger || alert_battery) {
|
||||
power_supply_changed(bdi->charger);
|
||||
bq24190_configure_usb_otg(bdi, ss_reg);
|
||||
}
|
||||
if (alert_battery && bdi->battery)
|
||||
power_supply_changed(bdi->battery);
|
||||
|
||||
@ -1637,8 +1639,12 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (v != BQ24190_REG_VPRS_PN_24190 &&
|
||||
v != BQ24190_REG_VPRS_PN_24192I) {
|
||||
switch (v) {
|
||||
case BQ24190_REG_VPRS_PN_24190:
|
||||
case BQ24190_REG_VPRS_PN_24192:
|
||||
case BQ24190_REG_VPRS_PN_24192I:
|
||||
break;
|
||||
default:
|
||||
dev_err(bdi->dev, "Error unknown model: 0x%02x\n", v);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1727,6 +1733,14 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bdi->edev = devm_extcon_dev_allocate(dev, bq24190_usb_extcon_cable);
|
||||
if (IS_ERR(bdi->edev))
|
||||
return PTR_ERR(bdi->edev);
|
||||
|
||||
ret = devm_extcon_dev_register(dev, bdi->edev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 600);
|
||||
@ -1736,6 +1750,11 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
goto out_pmrt;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
bq24190_sysfs_init_attrs();
|
||||
charger_cfg.attr_grp = bq24190_sysfs_groups;
|
||||
#endif
|
||||
|
||||
charger_cfg.drv_data = bdi;
|
||||
charger_cfg.of_node = dev->of_node;
|
||||
charger_cfg.supplied_to = bq24190_charger_supplied_to;
|
||||
@ -1773,11 +1792,9 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
goto out_charger;
|
||||
}
|
||||
|
||||
ret = bq24190_sysfs_create_group(bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't create sysfs entries\n");
|
||||
ret = bq24190_configure_usb_otg(bdi, bdi->ss_reg);
|
||||
if (ret < 0)
|
||||
goto out_charger;
|
||||
}
|
||||
|
||||
bdi->initialized = true;
|
||||
|
||||
@ -1787,12 +1804,12 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
"bq24190-charger", bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't set up irq handler\n");
|
||||
goto out_sysfs;
|
||||
goto out_charger;
|
||||
}
|
||||
|
||||
ret = bq24190_register_vbus_regulator(bdi);
|
||||
if (ret < 0)
|
||||
goto out_sysfs;
|
||||
goto out_charger;
|
||||
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
@ -1801,9 +1818,6 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
|
||||
return 0;
|
||||
|
||||
out_sysfs:
|
||||
bq24190_sysfs_remove_group(bdi);
|
||||
|
||||
out_charger:
|
||||
if (!IS_ERR_OR_NULL(bdi->battery))
|
||||
power_supply_unregister(bdi->battery);
|
||||
@ -1828,7 +1842,6 @@ static int bq24190_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
bq24190_register_reset(bdi);
|
||||
bq24190_sysfs_remove_group(bdi);
|
||||
if (bdi->battery)
|
||||
power_supply_unregister(bdi->battery);
|
||||
power_supply_unregister(bdi->charger);
|
||||
@ -1931,7 +1944,9 @@ static const struct dev_pm_ops bq24190_pm_ops = {
|
||||
|
||||
static const struct i2c_device_id bq24190_i2c_ids[] = {
|
||||
{ "bq24190" },
|
||||
{ "bq24192" },
|
||||
{ "bq24192i" },
|
||||
{ "bq24196" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
|
||||
@ -1939,7 +1954,9 @@ MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id bq24190_of_match[] = {
|
||||
{ .compatible = "ti,bq24190", },
|
||||
{ .compatible = "ti,bq24192", },
|
||||
{ .compatible = "ti,bq24192i", },
|
||||
{ .compatible = "ti,bq24196", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bq24190_of_match);
|
||||
|
@ -845,7 +845,7 @@ static DEVICE_ATTR(high_impedance_enable, S_IWUSR | S_IRUGO,
|
||||
static DEVICE_ATTR(sysoff_enable, S_IWUSR | S_IRUGO,
|
||||
bq24257_sysfs_show_enable, bq24257_sysfs_set_enable);
|
||||
|
||||
static struct attribute *bq24257_charger_attr[] = {
|
||||
static struct attribute *bq24257_charger_sysfs_attrs[] = {
|
||||
&dev_attr_ovp_voltage.attr,
|
||||
&dev_attr_in_dpm_voltage.attr,
|
||||
&dev_attr_high_impedance_enable.attr,
|
||||
@ -853,14 +853,13 @@ static struct attribute *bq24257_charger_attr[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group bq24257_attr_group = {
|
||||
.attrs = bq24257_charger_attr,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bq24257_charger_sysfs);
|
||||
|
||||
static int bq24257_power_supply_init(struct bq24257_device *bq)
|
||||
{
|
||||
struct power_supply_config psy_cfg = { .drv_data = bq, };
|
||||
|
||||
psy_cfg.attr_grp = bq24257_charger_sysfs_groups;
|
||||
psy_cfg.supplied_to = bq24257_charger_supplied_to;
|
||||
psy_cfg.num_supplicants = ARRAY_SIZE(bq24257_charger_supplied_to);
|
||||
|
||||
@ -1084,12 +1083,6 @@ static int bq24257_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't create sysfs entries\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1100,8 +1093,6 @@ static int bq24257_remove(struct i2c_client *client)
|
||||
if (bq->iilimit_autoset_enable)
|
||||
cancel_delayed_work_sync(&bq->iilimit_setup_work);
|
||||
|
||||
sysfs_remove_group(&bq->charger->dev.kobj, &bq24257_attr_group);
|
||||
|
||||
bq24257_field_write(bq, F_RESET, 1); /* reset to defaults */
|
||||
|
||||
return 0;
|
||||
|
@ -183,7 +183,7 @@ static const struct reg_field bq25890_reg_fields[] = {
|
||||
[F_CHG_TMR] = REG_FIELD(0x07, 1, 2),
|
||||
[F_JEITA_ISET] = REG_FIELD(0x07, 0, 0),
|
||||
/* REG08 */
|
||||
[F_BATCMP] = REG_FIELD(0x08, 6, 7), // 5-7 on BQ25896
|
||||
[F_BATCMP] = REG_FIELD(0x08, 5, 7),
|
||||
[F_VCLAMP] = REG_FIELD(0x08, 2, 4),
|
||||
[F_TREG] = REG_FIELD(0x08, 0, 1),
|
||||
/* REG09 */
|
||||
|
@ -363,7 +363,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
|
||||
int err = 0, i;
|
||||
struct charger_desc *desc = cm->desc;
|
||||
|
||||
/* Ignore if it's redundent command */
|
||||
/* Ignore if it's redundant command */
|
||||
if (enable == cm->charger_enabled)
|
||||
return 0;
|
||||
|
||||
@ -1212,7 +1212,6 @@ static int charger_extcon_init(struct charger_manager *cm,
|
||||
if (ret < 0) {
|
||||
pr_info("Cannot register extcon_dev for %s(cable: %s)\n",
|
||||
cable->extcon_name, cable->name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1352,7 +1351,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
|
||||
}
|
||||
|
||||
/**
|
||||
* charger_manager_register_sysfs - Register sysfs entry for each charger
|
||||
* charger_manager_prepare_sysfs - Prepare sysfs entry for each charger
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*
|
||||
* This function add sysfs entry for charger(regulator) to control charger from
|
||||
@ -1364,34 +1363,30 @@ static ssize_t charger_externally_control_store(struct device *dev,
|
||||
* externally_control, this charger isn't controlled from charger-manager and
|
||||
* always stay off state of regulator.
|
||||
*/
|
||||
static int charger_manager_register_sysfs(struct charger_manager *cm)
|
||||
static int charger_manager_prepare_sysfs(struct charger_manager *cm)
|
||||
{
|
||||
struct charger_desc *desc = cm->desc;
|
||||
struct charger_regulator *charger;
|
||||
int chargers_externally_control = 1;
|
||||
char buf[11];
|
||||
char *str;
|
||||
int ret;
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
/* Create sysfs entry to control charger(regulator) */
|
||||
for (i = 0; i < desc->num_charger_regulators; i++) {
|
||||
charger = &desc->charger_regulators[i];
|
||||
|
||||
snprintf(buf, 10, "charger.%d", i);
|
||||
str = devm_kzalloc(cm->dev,
|
||||
strlen(buf) + 1, GFP_KERNEL);
|
||||
if (!str)
|
||||
name = devm_kasprintf(cm->dev, GFP_KERNEL, "charger.%d", i);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(str, buf);
|
||||
|
||||
charger->attrs[0] = &charger->attr_name.attr;
|
||||
charger->attrs[1] = &charger->attr_state.attr;
|
||||
charger->attrs[2] = &charger->attr_externally_control.attr;
|
||||
charger->attrs[3] = NULL;
|
||||
charger->attr_g.name = str;
|
||||
charger->attr_g.attrs = charger->attrs;
|
||||
|
||||
charger->attr_grp.name = name;
|
||||
charger->attr_grp.attrs = charger->attrs;
|
||||
desc->sysfs_groups[i] = &charger->attr_grp;
|
||||
|
||||
sysfs_attr_init(&charger->attr_name.attr);
|
||||
charger->attr_name.attr.name = "name";
|
||||
@ -1418,14 +1413,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
|
||||
|
||||
dev_info(cm->dev, "'%s' regulator's externally_control is %d\n",
|
||||
charger->regulator_name, charger->externally_control);
|
||||
|
||||
ret = sysfs_create_group(&cm->charger_psy->dev.kobj,
|
||||
&charger->attr_g);
|
||||
if (ret < 0) {
|
||||
dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n",
|
||||
charger->regulator_name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (chargers_externally_control) {
|
||||
@ -1521,19 +1508,19 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
|
||||
/* chargers */
|
||||
of_property_read_u32(np, "cm-num-chargers", &num_chgs);
|
||||
if (num_chgs) {
|
||||
int i;
|
||||
|
||||
/* Allocate empty bin at the tail of array */
|
||||
desc->psy_charger_stat = devm_kcalloc(dev,
|
||||
num_chgs + 1,
|
||||
sizeof(char *),
|
||||
GFP_KERNEL);
|
||||
if (desc->psy_charger_stat) {
|
||||
int i;
|
||||
if (!desc->psy_charger_stat)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < num_chgs; i++)
|
||||
of_property_read_string_index(np, "cm-chargers",
|
||||
i, &desc->psy_charger_stat[i]);
|
||||
} else {
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge);
|
||||
@ -1566,6 +1553,13 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
|
||||
|
||||
desc->charger_regulators = chg_regs;
|
||||
|
||||
desc->sysfs_groups = devm_kcalloc(dev,
|
||||
desc->num_charger_regulators + 1,
|
||||
sizeof(*desc->sysfs_groups),
|
||||
GFP_KERNEL);
|
||||
if (!desc->sysfs_groups)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
struct charger_cable *cables;
|
||||
struct device_node *_child;
|
||||
@ -1633,7 +1627,7 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
|
||||
if (IS_ERR(desc)) {
|
||||
dev_err(&pdev->dev, "No platform data (desc) found\n");
|
||||
return -ENODEV;
|
||||
return PTR_ERR(desc);
|
||||
}
|
||||
|
||||
cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL);
|
||||
@ -1687,10 +1681,6 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Counting index only */
|
||||
while (desc->psy_charger_stat[i])
|
||||
i++;
|
||||
|
||||
/* Check if charger's supplies are present at probe */
|
||||
for (i = 0; desc->psy_charger_stat[i]; i++) {
|
||||
struct power_supply *psy;
|
||||
@ -1772,6 +1762,15 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
|
||||
INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
|
||||
|
||||
/* Register sysfs entry for charger(regulator) */
|
||||
ret = charger_manager_prepare_sysfs(cm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot prepare sysfs entry of regulators\n");
|
||||
return ret;
|
||||
}
|
||||
psy_cfg.attr_grp = desc->sysfs_groups;
|
||||
|
||||
cm->charger_psy = power_supply_register(&pdev->dev,
|
||||
&cm->charger_psy_desc,
|
||||
&psy_cfg);
|
||||
@ -1788,14 +1787,6 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
goto err_reg_extcon;
|
||||
}
|
||||
|
||||
/* Register sysfs entry for charger(regulator) */
|
||||
ret = charger_manager_register_sysfs(cm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot initialize sysfs entry of regulator\n");
|
||||
goto err_reg_sysfs;
|
||||
}
|
||||
|
||||
/* Add to the list */
|
||||
mutex_lock(&cm_list_mtx);
|
||||
list_add(&cm->entry, &cm_list);
|
||||
@ -1803,7 +1794,7 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
|
||||
/*
|
||||
* Charger-manager is capable of waking up the systme from sleep
|
||||
* when event is happend through cm_notify_event()
|
||||
* when event is happened through cm_notify_event()
|
||||
*/
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
device_set_wakeup_capable(&pdev->dev, false);
|
||||
@ -1819,14 +1810,6 @@ static int charger_manager_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_sysfs:
|
||||
for (i = 0; i < desc->num_charger_regulators; i++) {
|
||||
struct charger_regulator *charger;
|
||||
|
||||
charger = &desc->charger_regulators[i];
|
||||
sysfs_remove_group(&cm->charger_psy->dev.kobj,
|
||||
&charger->attr_g);
|
||||
}
|
||||
err_reg_extcon:
|
||||
for (i = 0; i < desc->num_charger_regulators; i++) {
|
||||
struct charger_regulator *charger;
|
||||
@ -2023,7 +2006,7 @@ module_exit(charger_manager_cleanup);
|
||||
* cm_notify_event - charger driver notify Charger Manager of charger event
|
||||
* @psy: pointer to instance of charger's power_supply
|
||||
* @type: type of charger event
|
||||
* @msg: optional message passed to uevent_notify fuction
|
||||
* @msg: optional message passed to uevent_notify function
|
||||
*/
|
||||
void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
|
||||
char *msg)
|
||||
|
@ -620,7 +620,7 @@ static int cpcap_battery_init_irq(struct platform_device *pdev,
|
||||
static int cpcap_battery_init_interrupts(struct platform_device *pdev,
|
||||
struct cpcap_battery_ddata *ddata)
|
||||
{
|
||||
const char * const cpcap_battery_irqs[] = {
|
||||
static const char * const cpcap_battery_irqs[] = {
|
||||
"eol", "lowbph", "lowbpl",
|
||||
"chrgcurr1", "battdetb"
|
||||
};
|
||||
|
@ -658,7 +658,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct bin_attribute ds2780_param_eeprom_bin_attr = {
|
||||
static struct bin_attribute ds2780_param_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "param_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
@ -703,7 +703,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct bin_attribute ds2780_user_eeprom_bin_attr = {
|
||||
static struct bin_attribute ds2780_user_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "user_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
@ -722,8 +722,7 @@ static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting,
|
||||
static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin,
|
||||
ds2780_set_pio_pin);
|
||||
|
||||
|
||||
static struct attribute *ds2780_attributes[] = {
|
||||
static struct attribute *ds2780_sysfs_attrs[] = {
|
||||
&dev_attr_pmod_enabled.attr,
|
||||
&dev_attr_sense_resistor_value.attr,
|
||||
&dev_attr_rsgain_setting.attr,
|
||||
@ -731,21 +730,30 @@ static struct attribute *ds2780_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ds2780_attr_group = {
|
||||
.attrs = ds2780_attributes,
|
||||
static struct bin_attribute *ds2780_sysfs_bin_attrs[] = {
|
||||
&ds2780_param_eeprom_bin_attr,
|
||||
&ds2780_user_eeprom_bin_attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ds2780_sysfs_group = {
|
||||
.attrs = ds2780_sysfs_attrs,
|
||||
.bin_attrs = ds2780_sysfs_bin_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ds2780_sysfs_groups[] = {
|
||||
&ds2780_sysfs_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int ds2780_battery_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
int ret = 0;
|
||||
struct ds2780_device_info *dev_info;
|
||||
|
||||
dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL);
|
||||
if (!dev_info) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!dev_info)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, dev_info);
|
||||
|
||||
@ -758,62 +766,16 @@ static int ds2780_battery_probe(struct platform_device *pdev)
|
||||
dev_info->bat_desc.get_property = ds2780_battery_get_property;
|
||||
|
||||
psy_cfg.drv_data = dev_info;
|
||||
psy_cfg.attr_grp = ds2780_sysfs_groups;
|
||||
|
||||
dev_info->bat = power_supply_register(&pdev->dev, &dev_info->bat_desc,
|
||||
dev_info->bat = devm_power_supply_register(&pdev->dev,
|
||||
&dev_info->bat_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(dev_info->bat)) {
|
||||
dev_err(dev_info->dev, "failed to register battery\n");
|
||||
ret = PTR_ERR(dev_info->bat);
|
||||
goto fail;
|
||||
return PTR_ERR(dev_info->bat);
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev, "failed to create sysfs group\n");
|
||||
goto fail_unregister;
|
||||
}
|
||||
|
||||
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2780_param_eeprom_bin_attr);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev,
|
||||
"failed to create param eeprom bin file");
|
||||
goto fail_remove_group;
|
||||
}
|
||||
|
||||
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2780_user_eeprom_bin_attr);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev,
|
||||
"failed to create user eeprom bin file");
|
||||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
sysfs_remove_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2780_param_eeprom_bin_attr);
|
||||
fail_remove_group:
|
||||
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
|
||||
fail_unregister:
|
||||
power_supply_unregister(dev_info->bat);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ds2780_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Remove attributes before unregistering power supply
|
||||
* because 'bat' will be freed on power_supply_unregister() call.
|
||||
*/
|
||||
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2780_attr_group);
|
||||
|
||||
power_supply_unregister(dev_info->bat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -822,7 +784,6 @@ static struct platform_driver ds2780_battery_driver = {
|
||||
.name = "ds2780-battery",
|
||||
},
|
||||
.probe = ds2780_battery_probe,
|
||||
.remove = ds2780_battery_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ds2780_battery_driver);
|
||||
|
@ -660,7 +660,7 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct bin_attribute ds2781_param_eeprom_bin_attr = {
|
||||
static struct bin_attribute ds2781_param_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "param_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
@ -706,7 +706,7 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct bin_attribute ds2781_user_eeprom_bin_attr = {
|
||||
static struct bin_attribute ds2781_user_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "user_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
@ -725,8 +725,7 @@ static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2781_get_rsgain_setting,
|
||||
static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2781_get_pio_pin,
|
||||
ds2781_set_pio_pin);
|
||||
|
||||
|
||||
static struct attribute *ds2781_attributes[] = {
|
||||
static struct attribute *ds2781_sysfs_attrs[] = {
|
||||
&dev_attr_pmod_enabled.attr,
|
||||
&dev_attr_sense_resistor_value.attr,
|
||||
&dev_attr_rsgain_setting.attr,
|
||||
@ -734,14 +733,26 @@ static struct attribute *ds2781_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ds2781_attr_group = {
|
||||
.attrs = ds2781_attributes,
|
||||
static struct bin_attribute *ds2781_sysfs_bin_attrs[] = {
|
||||
&ds2781_param_eeprom_bin_attr,
|
||||
&ds2781_user_eeprom_bin_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ds2781_sysfs_group = {
|
||||
.attrs = ds2781_sysfs_attrs,
|
||||
.bin_attrs = ds2781_sysfs_bin_attrs,
|
||||
|
||||
};
|
||||
|
||||
static const struct attribute_group *ds2781_sysfs_groups[] = {
|
||||
&ds2781_sysfs_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int ds2781_battery_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
int ret = 0;
|
||||
struct ds2781_device_info *dev_info;
|
||||
|
||||
dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL);
|
||||
@ -759,62 +770,16 @@ static int ds2781_battery_probe(struct platform_device *pdev)
|
||||
dev_info->bat_desc.get_property = ds2781_battery_get_property;
|
||||
|
||||
psy_cfg.drv_data = dev_info;
|
||||
psy_cfg.attr_grp = ds2781_sysfs_groups;
|
||||
|
||||
dev_info->bat = power_supply_register(&pdev->dev, &dev_info->bat_desc,
|
||||
dev_info->bat = devm_power_supply_register(&pdev->dev,
|
||||
&dev_info->bat_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(dev_info->bat)) {
|
||||
dev_err(dev_info->dev, "failed to register battery\n");
|
||||
ret = PTR_ERR(dev_info->bat);
|
||||
goto fail;
|
||||
return PTR_ERR(dev_info->bat);
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev, "failed to create sysfs group\n");
|
||||
goto fail_unregister;
|
||||
}
|
||||
|
||||
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2781_param_eeprom_bin_attr);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev,
|
||||
"failed to create param eeprom bin file");
|
||||
goto fail_remove_group;
|
||||
}
|
||||
|
||||
ret = sysfs_create_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2781_user_eeprom_bin_attr);
|
||||
if (ret) {
|
||||
dev_err(dev_info->dev,
|
||||
"failed to create user eeprom bin file");
|
||||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
sysfs_remove_bin_file(&dev_info->bat->dev.kobj,
|
||||
&ds2781_param_eeprom_bin_attr);
|
||||
fail_remove_group:
|
||||
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
|
||||
fail_unregister:
|
||||
power_supply_unregister(dev_info->bat);
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ds2781_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Remove attributes before unregistering power supply
|
||||
* because 'bat' will be freed on power_supply_unregister() call.
|
||||
*/
|
||||
sysfs_remove_group(&dev_info->bat->dev.kobj, &ds2781_attr_group);
|
||||
|
||||
power_supply_unregister(dev_info->bat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -823,7 +788,6 @@ static struct platform_driver ds2781_battery_driver = {
|
||||
.name = "ds2781-battery",
|
||||
},
|
||||
.probe = ds2781_battery_probe,
|
||||
.remove = ds2781_battery_remove,
|
||||
};
|
||||
module_platform_driver(ds2781_battery_driver);
|
||||
|
||||
|
@ -82,11 +82,11 @@ static enum power_supply_type gpio_charger_get_type(struct device *dev)
|
||||
if (!strcmp("usb-sdp", chargetype))
|
||||
return POWER_SUPPLY_TYPE_USB;
|
||||
if (!strcmp("usb-dcp", chargetype))
|
||||
return POWER_SUPPLY_TYPE_USB_DCP;
|
||||
return POWER_SUPPLY_TYPE_USB;
|
||||
if (!strcmp("usb-cdp", chargetype))
|
||||
return POWER_SUPPLY_TYPE_USB_CDP;
|
||||
return POWER_SUPPLY_TYPE_USB;
|
||||
if (!strcmp("usb-aca", chargetype))
|
||||
return POWER_SUPPLY_TYPE_USB_ACA;
|
||||
return POWER_SUPPLY_TYPE_USB;
|
||||
}
|
||||
dev_warn(dev, "unknown charger type %s\n", chargetype);
|
||||
|
||||
|
@ -410,30 +410,6 @@ static const struct power_supply_desc lp8788_psy_battery_desc = {
|
||||
.get_property = lp8788_battery_get_property,
|
||||
};
|
||||
|
||||
static int lp8788_psy_register(struct platform_device *pdev,
|
||||
struct lp8788_charger *pchg)
|
||||
{
|
||||
struct power_supply_config charger_cfg = {};
|
||||
|
||||
charger_cfg.supplied_to = battery_supplied_to;
|
||||
charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);
|
||||
|
||||
pchg->charger = power_supply_register(&pdev->dev,
|
||||
&lp8788_psy_charger_desc,
|
||||
&charger_cfg);
|
||||
if (IS_ERR(pchg->charger))
|
||||
return -EPERM;
|
||||
|
||||
pchg->battery = power_supply_register(&pdev->dev,
|
||||
&lp8788_psy_battery_desc, NULL);
|
||||
if (IS_ERR(pchg->battery)) {
|
||||
power_supply_unregister(pchg->charger);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp8788_psy_unregister(struct lp8788_charger *pchg)
|
||||
{
|
||||
power_supply_unregister(pchg->battery);
|
||||
@ -690,16 +666,39 @@ static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
|
||||
static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);
|
||||
static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);
|
||||
|
||||
static struct attribute *lp8788_charger_attr[] = {
|
||||
static struct attribute *lp8788_charger_sysfs_attrs[] = {
|
||||
&dev_attr_charger_status.attr,
|
||||
&dev_attr_eoc_time.attr,
|
||||
&dev_attr_eoc_level.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group lp8788_attr_group = {
|
||||
.attrs = lp8788_charger_attr,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lp8788_charger_sysfs);
|
||||
|
||||
static int lp8788_psy_register(struct platform_device *pdev,
|
||||
struct lp8788_charger *pchg)
|
||||
{
|
||||
struct power_supply_config charger_cfg = {};
|
||||
|
||||
charger_cfg.attr_grp = lp8788_charger_sysfs_groups;
|
||||
charger_cfg.supplied_to = battery_supplied_to;
|
||||
charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);
|
||||
|
||||
pchg->charger = power_supply_register(&pdev->dev,
|
||||
&lp8788_psy_charger_desc,
|
||||
&charger_cfg);
|
||||
if (IS_ERR(pchg->charger))
|
||||
return -EPERM;
|
||||
|
||||
pchg->battery = power_supply_register(&pdev->dev,
|
||||
&lp8788_psy_battery_desc, NULL);
|
||||
if (IS_ERR(pchg->battery)) {
|
||||
power_supply_unregister(pchg->charger);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -726,12 +725,6 @@ static int lp8788_charger_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group);
|
||||
if (ret) {
|
||||
lp8788_psy_unregister(pchg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lp8788_irq_register(pdev, pchg);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed to register charger irq: %d\n", ret);
|
||||
@ -745,7 +738,6 @@ static int lp8788_charger_remove(struct platform_device *pdev)
|
||||
|
||||
flush_work(&pchg->charger_work);
|
||||
lp8788_irq_unregister(pdev, pchg);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group);
|
||||
lp8788_psy_unregister(pchg);
|
||||
lp8788_release_adc_channel(pchg);
|
||||
|
||||
|
@ -428,14 +428,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
|
||||
val->intval = (s16)be16_to_cpu(ec_word) * 10 / 256;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
||||
ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
|
||||
val->intval = (int)be16_to_cpu(ec_word) * 10 / 256;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
||||
ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
|
||||
|
@ -245,17 +245,14 @@ static ssize_t set_chglim(struct device *dev,
|
||||
*/
|
||||
static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
|
||||
|
||||
static struct attribute *pcf50633_mbc_sysfs_entries[] = {
|
||||
static struct attribute *pcf50633_mbc_sysfs_attrs[] = {
|
||||
&dev_attr_chgmode.attr,
|
||||
&dev_attr_usb_curlim.attr,
|
||||
&dev_attr_chg_curlim.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group mbc_attr_group = {
|
||||
.name = NULL, /* put in device directory */
|
||||
.attrs = pcf50633_mbc_sysfs_entries,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(pcf50633_mbc_sysfs);
|
||||
|
||||
static void
|
||||
pcf50633_mbc_irq_handler(int irq, void *data)
|
||||
@ -390,6 +387,7 @@ static const struct power_supply_desc pcf50633_mbc_ac_desc = {
|
||||
static int pcf50633_mbc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct power_supply_config usb_psy_cfg;
|
||||
struct pcf50633_mbc *mbc;
|
||||
int i;
|
||||
u8 mbcs1;
|
||||
@ -419,8 +417,11 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(mbc->adapter);
|
||||
}
|
||||
|
||||
usb_psy_cfg = psy_cfg;
|
||||
usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups;
|
||||
|
||||
mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc,
|
||||
&psy_cfg);
|
||||
&usb_psy_cfg);
|
||||
if (IS_ERR(mbc->usb)) {
|
||||
dev_err(mbc->pcf->dev, "failed to register usb\n");
|
||||
power_supply_unregister(mbc->adapter);
|
||||
@ -436,9 +437,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(mbc->ac);
|
||||
}
|
||||
|
||||
if (sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group))
|
||||
dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
|
||||
|
||||
mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
|
||||
if (mbcs1 & PCF50633_MBCS1_USBPRES)
|
||||
pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
|
||||
@ -457,7 +455,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev)
|
||||
for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
|
||||
pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group);
|
||||
power_supply_unregister(mbc->usb);
|
||||
power_supply_unregister(mbc->adapter);
|
||||
power_supply_unregister(mbc->ac);
|
||||
|
@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
||||
{
|
||||
struct device_node *battery_np;
|
||||
const char *value;
|
||||
int err;
|
||||
int err, len, index;
|
||||
|
||||
info->energy_full_design_uwh = -EINVAL;
|
||||
info->charge_full_design_uah = -EINVAL;
|
||||
@ -579,6 +579,13 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
||||
info->charge_term_current_ua = -EINVAL;
|
||||
info->constant_charge_current_max_ua = -EINVAL;
|
||||
info->constant_charge_voltage_max_uv = -EINVAL;
|
||||
info->factory_internal_resistance_uohm = -EINVAL;
|
||||
|
||||
for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
|
||||
info->ocv_table[index] = NULL;
|
||||
info->ocv_temp[index] = -EINVAL;
|
||||
info->ocv_table_size[index] = -EINVAL;
|
||||
}
|
||||
|
||||
if (!psy->of_node) {
|
||||
dev_warn(&psy->dev, "%s currently only supports devicetree\n",
|
||||
@ -616,11 +623,142 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
||||
&info->constant_charge_current_max_ua);
|
||||
of_property_read_u32(battery_np, "constant_charge_voltage_max_microvolt",
|
||||
&info->constant_charge_voltage_max_uv);
|
||||
of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms",
|
||||
&info->factory_internal_resistance_uohm);
|
||||
|
||||
len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
|
||||
if (len < 0 && len != -EINVAL) {
|
||||
return len;
|
||||
} else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
|
||||
dev_err(&psy->dev, "Too many temperature values\n");
|
||||
return -EINVAL;
|
||||
} else if (len > 0) {
|
||||
of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
|
||||
info->ocv_temp, len);
|
||||
}
|
||||
|
||||
for (index = 0; index < len; index++) {
|
||||
struct power_supply_battery_ocv_table *table;
|
||||
char *propname;
|
||||
const __be32 *list;
|
||||
int i, tab_len, size;
|
||||
|
||||
propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", index);
|
||||
list = of_get_property(battery_np, propname, &size);
|
||||
if (!list || !size) {
|
||||
dev_err(&psy->dev, "failed to get %s\n", propname);
|
||||
kfree(propname);
|
||||
power_supply_put_battery_info(psy, info);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kfree(propname);
|
||||
tab_len = size / (2 * sizeof(__be32));
|
||||
info->ocv_table_size[index] = tab_len;
|
||||
|
||||
table = info->ocv_table[index] =
|
||||
devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL);
|
||||
if (!info->ocv_table[index]) {
|
||||
power_supply_put_battery_info(psy, info);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < tab_len; i++) {
|
||||
table[i].ocv = be32_to_cpu(*list++);
|
||||
table[i].capacity = be32_to_cpu(*list++);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
|
||||
|
||||
void power_supply_put_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) {
|
||||
if (info->ocv_table[i])
|
||||
devm_kfree(&psy->dev, info->ocv_table[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
|
||||
|
||||
/**
|
||||
* power_supply_ocv2cap_simple() - find the battery capacity
|
||||
* @table: Pointer to battery OCV lookup table
|
||||
* @table_len: OCV table length
|
||||
* @ocv: Current OCV value
|
||||
*
|
||||
* This helper function is used to look up battery capacity according to
|
||||
* current OCV value from one OCV table, and the OCV table must be ordered
|
||||
* descending.
|
||||
*
|
||||
* Return: the battery capacity.
|
||||
*/
|
||||
int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
|
||||
int table_len, int ocv)
|
||||
{
|
||||
int i, cap, tmp;
|
||||
|
||||
for (i = 0; i < table_len; i++)
|
||||
if (ocv > table[i].ocv)
|
||||
break;
|
||||
|
||||
if (i > 0 && i < table_len) {
|
||||
tmp = (table[i - 1].capacity - table[i].capacity) *
|
||||
(ocv - table[i].ocv);
|
||||
tmp /= table[i - 1].ocv - table[i].ocv;
|
||||
cap = tmp + table[i].capacity;
|
||||
} else if (i == 0) {
|
||||
cap = table[0].capacity;
|
||||
} else {
|
||||
cap = table[table_len - 1].capacity;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple);
|
||||
|
||||
struct power_supply_battery_ocv_table *
|
||||
power_supply_find_ocv2cap_table(struct power_supply_battery_info *info,
|
||||
int temp, int *table_len)
|
||||
{
|
||||
int best_temp_diff = INT_MAX, temp_diff;
|
||||
u8 i, best_index = 0;
|
||||
|
||||
if (!info->ocv_table[0])
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++) {
|
||||
temp_diff = abs(info->ocv_temp[i] - temp);
|
||||
|
||||
if (temp_diff < best_temp_diff) {
|
||||
best_temp_diff = temp_diff;
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
*table_len = info->ocv_table_size[best_index];
|
||||
return info->ocv_table[best_index];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_find_ocv2cap_table);
|
||||
|
||||
int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info,
|
||||
int ocv, int temp)
|
||||
{
|
||||
struct power_supply_battery_ocv_table *table;
|
||||
int table_len;
|
||||
|
||||
table = power_supply_find_ocv2cap_table(info, temp, &table_len);
|
||||
if (!table)
|
||||
return -EINVAL;
|
||||
|
||||
return power_supply_ocv2cap_simple(table, table_len, ocv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_batinfo_ocv2cap);
|
||||
|
||||
int power_supply_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
@ -880,6 +1018,7 @@ __power_supply_register(struct device *parent,
|
||||
dev_set_drvdata(dev, psy);
|
||||
psy->desc = desc;
|
||||
if (cfg) {
|
||||
dev->groups = cfg->attr_grp;
|
||||
psy->drv_data = cfg->drv_data;
|
||||
psy->of_node =
|
||||
cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node;
|
||||
|
@ -57,9 +57,11 @@ struct sc2731_charger_info {
|
||||
struct usb_phy *usb_phy;
|
||||
struct notifier_block usb_notify;
|
||||
struct power_supply *psy_usb;
|
||||
struct work_struct work;
|
||||
struct mutex lock;
|
||||
bool charging;
|
||||
u32 base;
|
||||
u32 limit;
|
||||
};
|
||||
|
||||
static void sc2731_charger_stop_charge(struct sc2731_charger_info *info)
|
||||
@ -318,22 +320,21 @@ static const struct power_supply_desc sc2731_charger_desc = {
|
||||
.property_is_writeable = sc2731_charger_property_is_writeable,
|
||||
};
|
||||
|
||||
static int sc2731_charger_usb_change(struct notifier_block *nb,
|
||||
unsigned long limit, void *data)
|
||||
static void sc2731_charger_work(struct work_struct *data)
|
||||
{
|
||||
struct sc2731_charger_info *info =
|
||||
container_of(nb, struct sc2731_charger_info, usb_notify);
|
||||
int ret = 0;
|
||||
container_of(data, struct sc2731_charger_info, work);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
if (limit > 0) {
|
||||
if (info->limit > 0 && !info->charging) {
|
||||
/* set current limitation and start to charge */
|
||||
ret = sc2731_charger_set_current_limit(info, limit);
|
||||
ret = sc2731_charger_set_current_limit(info, info->limit);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = sc2731_charger_set_current(info, limit);
|
||||
ret = sc2731_charger_set_current(info, info->limit);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -342,7 +343,7 @@ static int sc2731_charger_usb_change(struct notifier_block *nb,
|
||||
goto out;
|
||||
|
||||
info->charging = true;
|
||||
} else {
|
||||
} else if (!info->limit && info->charging) {
|
||||
/* Stop charging */
|
||||
info->charging = false;
|
||||
sc2731_charger_stop_charge(info);
|
||||
@ -350,7 +351,19 @@ static int sc2731_charger_usb_change(struct notifier_block *nb,
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sc2731_charger_usb_change(struct notifier_block *nb,
|
||||
unsigned long limit, void *data)
|
||||
{
|
||||
struct sc2731_charger_info *info =
|
||||
container_of(nb, struct sc2731_charger_info, usb_notify);
|
||||
|
||||
info->limit = limit;
|
||||
|
||||
schedule_work(&info->work);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
@ -395,6 +408,8 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
vol_val = (term_voltage - 4200) / 100;
|
||||
else
|
||||
vol_val = 0;
|
||||
|
||||
power_supply_put_battery_info(info->psy_usb, &bat_info);
|
||||
}
|
||||
|
||||
/* Set charge termination current */
|
||||
@ -419,6 +434,24 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sc2731_charger_detect_status(struct sc2731_charger_info *info)
|
||||
{
|
||||
unsigned int min, max;
|
||||
|
||||
/*
|
||||
* If the USB charger status has been USB_CHARGER_PRESENT before
|
||||
* registering the notifier, we should start to charge with getting
|
||||
* the charge current.
|
||||
*/
|
||||
if (info->usb_phy->chg_state != USB_CHARGER_PRESENT)
|
||||
return;
|
||||
|
||||
usb_phy_get_charger_current(info->usb_phy, &min, &max);
|
||||
info->limit = min;
|
||||
|
||||
schedule_work(&info->work);
|
||||
}
|
||||
|
||||
static int sc2731_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@ -432,6 +465,7 @@ static int sc2731_charger_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&info->lock);
|
||||
info->dev = &pdev->dev;
|
||||
INIT_WORK(&info->work, sc2731_charger_work);
|
||||
|
||||
info->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!info->regmap) {
|
||||
@ -472,6 +506,8 @@ static int sc2731_charger_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sc2731_charger_detect_status(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
1075
drivers/power/supply/sc27xx_fuel_gauge.c
Normal file
1075
drivers/power/supply/sc27xx_fuel_gauge.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -266,6 +266,7 @@ enum axp20x_variants {
|
||||
#define AXP288_RT_BATT_V_H 0xa0
|
||||
#define AXP288_RT_BATT_V_L 0xa1
|
||||
|
||||
#define AXP813_ACIN_PATH_CTRL 0x3a
|
||||
#define AXP813_ADC_RATE 0x85
|
||||
|
||||
/* Fuel Gauge */
|
||||
|
@ -119,7 +119,7 @@ struct charger_regulator {
|
||||
struct charger_cable *cables;
|
||||
int num_cables;
|
||||
|
||||
struct attribute_group attr_g;
|
||||
struct attribute_group attr_grp;
|
||||
struct device_attribute attr_name;
|
||||
struct device_attribute attr_state;
|
||||
struct device_attribute attr_externally_control;
|
||||
@ -186,6 +186,7 @@ struct charger_desc {
|
||||
|
||||
int num_charger_regulators;
|
||||
struct charger_regulator *charger_regulators;
|
||||
const struct attribute_group **sysfs_groups;
|
||||
|
||||
const char *psy_fuel_gauge;
|
||||
|
||||
|
@ -204,6 +204,9 @@ struct power_supply_config {
|
||||
/* Driver private data */
|
||||
void *drv_data;
|
||||
|
||||
/* Device specific sysfs attributes */
|
||||
const struct attribute_group **attr_grp;
|
||||
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
};
|
||||
@ -309,6 +312,13 @@ struct power_supply_info {
|
||||
int use_for_apm;
|
||||
};
|
||||
|
||||
struct power_supply_battery_ocv_table {
|
||||
int ocv; /* microVolts */
|
||||
int capacity; /* percent */
|
||||
};
|
||||
|
||||
#define POWER_SUPPLY_OCV_TEMP_MAX 20
|
||||
|
||||
/*
|
||||
* This is the recommended struct to manage static battery parameters,
|
||||
* populated by power_supply_get_battery_info(). Most platform drivers should
|
||||
@ -326,6 +336,10 @@ struct power_supply_battery_info {
|
||||
int charge_term_current_ua; /* microAmps */
|
||||
int constant_charge_current_max_ua; /* microAmps */
|
||||
int constant_charge_voltage_max_uv; /* microVolts */
|
||||
int factory_internal_resistance_uohm; /* microOhms */
|
||||
int ocv_temp[POWER_SUPPLY_OCV_TEMP_MAX];/* celsius */
|
||||
struct power_supply_battery_ocv_table *ocv_table[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
};
|
||||
|
||||
extern struct atomic_notifier_head power_supply_notifier;
|
||||
@ -349,6 +363,15 @@ devm_power_supply_get_by_phandle(struct device *dev, const char *property)
|
||||
|
||||
extern int power_supply_get_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info);
|
||||
extern void power_supply_put_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info);
|
||||
extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
|
||||
int table_len, int ocv);
|
||||
extern struct power_supply_battery_ocv_table *
|
||||
power_supply_find_ocv2cap_table(struct power_supply_battery_info *info,
|
||||
int temp, int *table_len);
|
||||
extern int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info,
|
||||
int ocv, int temp);
|
||||
extern void power_supply_changed(struct power_supply *psy);
|
||||
extern int power_supply_am_i_supplied(struct power_supply *psy);
|
||||
extern int power_supply_set_input_current_limit_from_supplier(
|
||||
|
Loading…
Reference in New Issue
Block a user