Commit a7dcf5f2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:
 "Battery/charger driver changes:
   - acer_a500: new fuel gauge driver for Acer Iconia Tab A500
   - bq256xx: new charger driver
   - bq27xxx: Support CHARGE_NOW for bq27z561/bq28z610/bq34z100
   - bq27xxx: Fix inverted CURRENT_NOW sign
   - cpcap: rework fuel gauge and charger drivers
   - ltc4162l: new charger driver
   - max8997-charger: add extcon based current limit configuration
   - max8903, wm97xx, z2: convert to GPIO descriptors (incl. ARM board files)
   - misc cleanup and fixes

  Reset drivers:
   - new poweroff driver for ATC260x
   - at91-sama5d2_shdwc: add support for sama7g5
   - drop zte zx driver (SoC support is removed from kernel)"

* tag 'for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (55 commits)
  power-supply: use kobj_to_dev()
  power: supply: charger-manager: fix typo
  power/reset: remove zte zx driver
  power: supply: bq25980: Fix repetive bq25975 with bq25960
  power: supply: smb347-charger: Fix interrupt usage if interrupt is unavailable
  power: supply: axp20x_usb_power: Init work before enabling IRQs
  power: supply: fix sbs-charger build, needs REGMAP_I2C
  power: supply: bq27xxx: fix polarity of current_now
  power: supply: charger-manager: fix incorrect health status
  power: reset: at91-sama5d2_shdwc: add support for sama7g5
  dt-bindings: atmel-sysreg: add microchip,sama7g5-shdwc
  power: reset: at91-sama5d2_shdwc: fix wkupdbc mask
  dt-bindings: power/supply: Add ltc4162-l-charger
  power: supply: bq24190_charger: convert comma to semicolon
  power: supply: ab8500_fg: convert comma to semicolon
  power: supply: ds2780: Switch to using the new API kobj_to_dev()
  power: supply: bq27xxx: Support CHARGE_NOW for bq27z561/bq28z610/bq34z100
  power: supply: cpcap-charger: Fix power_supply_put on null battery pointer
  power: supply: cpcap-battery: constify psy_desc
  power: supply: cpcap-battery: Fix typo
  ...
parents 28b9aaac a72acc56
What: /sys/class/power_supply/ltc4162-l/charge_status
Date: Januari 2021
KernelVersion: 5.11
Description:
Detailed charge status information as reported by the chip.
Access: Read
Valid values:
ilim_reg_active
thermal_reg_active
vin_uvcl_active
iin_limit_active
constant_current
constant_voltage
charger_off
What: /sys/class/power_supply/ltc4162-l/ibat
Date: Januari 2021
KernelVersion: 5.11
Description:
Battery input current as measured by the charger. Negative value
means that the battery is discharging.
Access: Read
Valid values: Signed value in microamps
What: /sys/class/power_supply/ltc4162-l/vbat
Date: Januari 2021
KernelVersion: 5.11
Description:
Battery voltage as measured by the charger.
Access: Read
Valid values: In microvolts
What: /sys/class/power_supply/ltc4162-l/vbat_avg
Date: Januari 2021
KernelVersion: 5.11
Description:
Battery voltage, averaged over time, as measured by the charger.
Access: Read
Valid values: In microvolts
What: /sys/class/power_supply/ltc4162-l/force_telemetry
Date: Januari 2021
KernelVersion: 5.11
Description:
To save battery current, the measurement system is disabled if
the battery is the only source of power. This affects all
voltage, current and temperature measurements.
Write a "1" to this to keep performing telemetry once every few
seconds, even when running on battery (as reported by the online
property, which is "1" when external power is available and "0"
when the system runs on battery).
Access: Read, Write
Valid values: 0 (disabled) or 1 (enabled)
What: /sys/class/power_supply/ltc4162-l/arm_ship_mode
Date: Januari 2021
KernelVersion: 5.11
Description:
The charger will normally drain the battery while inactive,
typically drawing about 54 microamps. Write a "1" to this
property to arm a special "ship" mode that extends shelf life
by reducing the leakage to about 2.8 microamps. The chip will
remain in this mode (and no longer respond to I2C commands)
until some external power-supply is attached raising the input
voltage above 1V. It will then automatically revert to "0".
Writing a "0" to the property cancels the "ship" mode request.
The ship mode, when armed, activates once the input voltage
drops below 1V.
Access: Read, Write
Valid values: 0 (disable) or 1 (enable)
......@@ -91,7 +91,8 @@ SHDWC SAMA5D2-Compatible Shutdown Controller
1) shdwc node
required properties:
- compatible: should be "atmel,sama5d2-shdwc" or "microchip,sam9x60-shdwc".
- compatible: should be "atmel,sama5d2-shdwc", "microchip,sam9x60-shdwc" or
"microchip,sama7g5-shdwc"
- reg: should contain registers location and length
- clocks: phandle to input clock.
- #address-cells: should be one. The cell is the wake-up input index.
......@@ -103,7 +104,7 @@ optional properties:
microseconds. It's usually a board-related property.
- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up.
optional microchip,sam9x60-shdwc properties:
optional microchip,sam9x60-shdwc or microchip,sama7g5-shdwc properties:
- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
The node contains child nodes for each wake-up input that the platform uses.
......
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
# Copyright (C) 2020 Texas Instruments Incorporated
%YAML 1.2
---
$id: "http://devicetree.org/schemas/power/supply/bq256xx.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: TI bq256xx Switch Mode Buck Charger
maintainers:
- Ricardo Rivera-Matos <r-rivera-matos@ti.com>
description: |
The bq256xx devices are a family of highly-integrated battery charge
management and system power management ICs for single cell Li-ion and Li-
polymer batteries.
Datasheets:
- https://www.ti.com/lit/ds/symlink/bq25600.pdf
- https://www.ti.com/lit/ds/symlink/bq25601.pdf
- https://www.ti.com/lit/ds/symlink/bq25600d.pdf
- https://www.ti.com/lit/ds/symlink/bq25601d.pdf
- https://www.ti.com/lit/ds/symlink/bq25611d.pdf
- https://www.ti.com/lit/ds/symlink/bq25618.pdf
- https://www.ti.com/lit/ds/symlink/bq25619.pdf
properties:
compatible:
enum:
- ti,bq25600
- ti,bq25601
- ti,bq25600d
- ti,bq25601d
- ti,bq25611d
- ti,bq25618
- ti,bq25619
reg:
maxItems: 1
ti,watchdog-timeout-ms:
$ref: /schemas/types.yaml#/definitions/uint32
default: 0
description: |
Watchdog timer in ms. 0 (default) disables the watchdog
minimum: 0
maximum: 160000
enum: [ 0, 40000, 80000, 160000]
input-voltage-limit-microvolt:
description: |
Minimum input voltage limit in µV with a 100000 µV step
minimum: 3900000
maximum: 5400000
input-current-limit-microamp:
description: |
Maximum input current limit in µA with a 100000 µA step
minimum: 100000
maximum: 3200000
monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the battery node being monitored
interrupts:
maxItems: 1
description: |
Interrupt sends an active low, 256 μs pulse to host to report the charger
device status and faults.
required:
- compatible
- reg
- monitored-battery
additionalProperties: false
examples:
- |
bat: battery {
compatible = "simple-battery";
constant-charge-current-max-microamp = <2040000>;
constant-charge-voltage-max-microvolt = <4352000>;
precharge-current-microamp = <180000>;
charge-term-current-microamp = <180000>;
};
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
charger@6b {
compatible = "ti,bq25601";
reg = <0x6b>;
monitored-battery = <&bat>;
interrupt-parent = <&gpio1>;
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
ti,watchdog-timeout-ms = <40000>;
input-voltage-limit-microvolt = <4500000>;
input-current-limit-microamp = <2400000>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (C) 2020 Topic Embedded Products
%YAML 1.2
---
$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Linear Technology (Analog Devices) LTC4162-L Charger
maintainers:
- Mike Looijmans <mike.looijmans@topic.nl>
description: |
The LTC ® 4162-L is an advanced monolithic synchronous step-down switching
battery charger and PowerPath (TM) manager that seamlessly manages power
distribution between input sources such as wall adapters, backplanes, solar
panels, etc., and a rechargeable Lithium-Ion/Polymer battery.
Specifications about the charger can be found at:
https://www.analog.com/en/products/ltc4162-s.html
properties:
compatible:
enum:
- lltc,ltc4162-l
reg:
maxItems: 1
description: I2C address of the charger.
lltc,rsnsb-micro-ohms:
$ref: /schemas/types.yaml#/definitions/uint32
description: Battery sense resistor in microohm.
minimum: 1000
lltc,rsnsi-micro-ohms:
$ref: /schemas/types.yaml#/definitions/uint32
description: Input current sense resistor in microohm.
minimum: 1000
lltc,cell-count:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Number of battery cells. If not provided, will be obtained from the chip
once the external power is applied. Omit this when the number of cells
is somewhat dynamic. Without it, several measurements will return 0 until
the charger is connected to an external supply.
required:
- compatible
- reg
- lltc,rsnsb-micro-ohms
- lltc,rsnsi-micro-ohms
additionalProperties: false
examples:
- |
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
charger: battery-charger@68 {
compatible = "lltc,ltc4162-l";
reg = <0x68>;
lltc,rsnsb-micro-ohms = <10000>;
lltc,rsnsi-micro-ohms = <16000>;
lltc,cell-count = <2>;
};
};
......@@ -577,7 +577,6 @@ static struct platform_device power_dev = {
static struct wm97xx_batt_pdata mioa701_battery_data = {
.batt_aux = WM97XX_AUX_ID1,
.temp_aux = -1,
.charge_gpio = -1,
.min_voltage = 0xc00,
.max_voltage = 0xfc0,
.batt_tech = POWER_SUPPLY_TECHNOLOGY_LION,
......
......@@ -212,7 +212,6 @@ void __init palm27x_irda_init(int pwdn)
static struct wm97xx_batt_pdata palm27x_batt_pdata = {
.batt_aux = WM97XX_AUX_ID3,
.temp_aux = WM97XX_AUX_ID2,
.charge_gpio = -1,
.batt_mult = 1000,
.batt_div = 414,
.temp_mult = 1,
......
......@@ -273,7 +273,6 @@ static struct platform_device power_supply = {
static struct wm97xx_batt_pdata palmte2_batt_pdata = {
.batt_aux = WM97XX_AUX_ID3,
.temp_aux = WM97XX_AUX_ID2,
.charge_gpio = -1,
.max_voltage = PALMTE2_BAT_MAX_VOLTAGE,
.min_voltage = PALMTE2_BAT_MIN_VOLTAGE,
.batt_mult = 1000,
......
......@@ -487,7 +487,6 @@ static struct z2_battery_info batt_chip_info = {
.batt_I2C_bus = 0,
.batt_I2C_addr = 0x55,
.batt_I2C_reg = 2,
.charge_gpio = GPIO0_ZIPITZ2_AC_DETECT,
.min_voltage = 3475000,
.max_voltage = 4190000,
.batt_div = 59,
......@@ -496,9 +495,19 @@ static struct z2_battery_info batt_chip_info = {
.batt_name = "Z2",
};
static struct gpiod_lookup_table z2_battery_gpio_table = {
.dev_id = "aer915",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO0_ZIPITZ2_AC_DETECT,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct i2c_board_info __initdata z2_i2c_board_info[] = {
{
I2C_BOARD_INFO("aer915", 0x55),
.dev_name = "aer915",
.platform_data = &batt_chip_info,
}, {
I2C_BOARD_INFO("wm8750", 0x1b),
......@@ -509,6 +518,7 @@ static struct i2c_board_info __initdata z2_i2c_board_info[] = {
static void __init z2_i2c_init(void)
{
pxa_set_i2c_info(NULL);
gpiod_add_lookup_table(&z2_battery_gpio_table);
i2c_register_board_info(0, ARRAY_AND_SIZE(z2_i2c_board_info));
}
#else
......
......@@ -39,6 +39,13 @@ config POWER_RESET_AT91_SAMA5D2_SHDWC
This driver supports the alternate shutdown controller for some Atmel
SAMA5 SoCs. It is present for example on SAMA5D2 SoC.
config POWER_RESET_ATC260X
tristate "Actions Semi ATC260x PMIC power-off driver"
depends on MFD_ATC260X
help
This driver provides power-off and restart support for a system
through Actions Semi ATC260x series PMICs.
config POWER_RESET_AXXIA
bool "LSI Axxia reset driver"
depends on ARCH_AXXIA
......@@ -251,13 +258,6 @@ config POWER_RESET_RMOBILE
help
Reboot support for Renesas R-Mobile and SH-Mobile SoCs.
config POWER_RESET_ZX
tristate "ZTE SoCs reset driver"
depends on ARCH_ZX || COMPILE_TEST
depends on HAS_IOMEM
help
Reboot support for ZTE SoCs.
config REBOOT_MODE
tristate
......@@ -292,4 +292,3 @@ config NVMEM_REBOOT_MODE
action according to the mode.
endif
......@@ -3,6 +3,7 @@ obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o
obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
obj-$(CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC) += at91-sama5d2_shdwc.o
obj-$(CONFIG_POWER_RESET_ATC260X) += atc260x-poweroff.o
obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
obj-$(CONFIG_POWER_RESET_BRCMKONA) += brcm-kona-reset.o
obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
......@@ -29,7 +30,6 @@ obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o
obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o
obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
......
......@@ -37,7 +37,7 @@
#define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */
#define AT91_SHDW_WKUPDBC_SHIFT 24
#define AT91_SHDW_WKUPDBC_MASK GENMASK(31, 16)
#define AT91_SHDW_WKUPDBC_MASK GENMASK(26, 24)
#define AT91_SHDW_WKUPDBC(x) (((x) << AT91_SHDW_WKUPDBC_SHIFT) \
& AT91_SHDW_WKUPDBC_MASK)
......@@ -78,9 +78,15 @@ struct pmc_reg_config {
u8 mckr;
};
struct ddrc_reg_config {
u32 type_offset;
u32 type_mask;
};
struct reg_config {
struct shdwc_reg_config shdwc;
struct pmc_reg_config pmc;
struct ddrc_reg_config ddrc;
};
struct shdwc {
......@@ -262,6 +268,10 @@ static const struct reg_config sama5d2_reg_config = {
.pmc = {
.mckr = 0x30,
},
.ddrc = {
.type_offset = AT91_DDRSDRC_MDR,
.type_mask = AT91_DDRSDRC_MD
},
};
static const struct reg_config sam9x60_reg_config = {
......@@ -275,6 +285,23 @@ static const struct reg_config sam9x60_reg_config = {
.pmc = {
.mckr = 0x28,
},
.ddrc = {
.type_offset = AT91_DDRSDRC_MDR,
.type_mask = AT91_DDRSDRC_MD
},
};
static const struct reg_config sama7g5_reg_config = {
.shdwc = {
.wkup_pin_input = 0,
.mr_rtcwk_shift = 17,
.mr_rttwk_shift = 16,
.sr_rtcwk_shift = 5,
.sr_rttwk_shift = 4,
},
.pmc = {
.mckr = 0x28,
},
};
static const struct of_device_id at91_shdwc_of_match[] = {
......@@ -285,6 +312,10 @@ static const struct of_device_id at91_shdwc_of_match[] = {
{
.compatible = "microchip,sam9x60-shdwc",
.data = &sam9x60_reg_config,
},
{
.compatible = "microchip,sama7g5-shdwc",
.data = &sama7g5_reg_config,
}, {
/*sentinel*/
}
......@@ -294,6 +325,7 @@ MODULE_DEVICE_TABLE(of, at91_shdwc_of_match);
static const struct of_device_id at91_pmc_ids[] = {
{ .compatible = "atmel,sama5d2-pmc" },
{ .compatible = "microchip,sam9x60-pmc" },
{ .compatible = "microchip,sama7g5-pmc" },
{ /* Sentinel. */ }
};
......@@ -355,7 +387,9 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
goto clk_disable;
}
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
if (at91_shdwc->rcfg->ddrc.type_mask) {
np = of_find_compatible_node(NULL, NULL,
"atmel,sama5d3-ddramc");
if (!np) {
ret = -ENODEV;
goto unmap;
......@@ -369,15 +403,17 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
goto unmap;
}
pm_power_off = at91_poweroff;
ddr_type = readl(at91_shdwc->mpddrc_base + AT91_DDRSDRC_MDR) &
AT91_DDRSDRC_MD;
ddr_type = readl(at91_shdwc->mpddrc_base +
at91_shdwc->rcfg->ddrc.type_offset) &
at91_shdwc->rcfg->ddrc.type_mask;
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;
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Poweroff & reset driver for Actions Semi ATC260x PMICs
*
* Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
*/
#include <linux/delay.h>
#include <linux/mfd/atc260x/core.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
struct atc260x_pwrc {
struct device *dev;
struct regmap *regmap;
struct notifier_block restart_nb;
int (*do_poweroff)(const struct atc260x_pwrc *pwrc, bool restart);
};
/* Global variable needed only for pm_power_off */
static struct atc260x_pwrc *atc260x_pwrc_data;
static int atc2603c_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart)
{
int ret, deep_sleep = 0;
uint reg_mask, reg_val;
/* S4-Deep Sleep Mode is NOT available for WALL/USB power */
if (!restart && !power_supply_is_system_supplied()) {
deep_sleep = 1;
dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode");
}
/* Update wakeup sources */
reg_val = ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN |
(restart ? ATC2603C_PMU_SYS_CTL0_RESET_WK_EN
: ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN);
ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0,
ATC2603C_PMU_SYS_CTL0_WK_ALL, reg_val);
if (ret)
dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
/* Update power mode */
reg_mask = ATC2603C_PMU_SYS_CTL3_EN_S2 | ATC2603C_PMU_SYS_CTL3_EN_S3;
ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3, reg_mask,
deep_sleep ? 0 : ATC2603C_PMU_SYS_CTL3_EN_S3);
if (ret) {
dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
return ret;
}
/* Trigger poweroff / restart sequence */
reg_mask = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN
: ATC2603C_PMU_SYS_CTL1_EN_S1;
reg_val = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN : 0;
ret = regmap_update_bits(pwrc->regmap,
restart ? ATC2603C_PMU_SYS_CTL0 : ATC2603C_PMU_SYS_CTL1,
reg_mask, reg_val);
if (ret) {
dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n",
restart ? 0 : 1, ret);
return ret;
}
/* Wait for trigger completion */
mdelay(200);
return 0;
}
static int atc2609a_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart)
{
int ret, deep_sleep = 0;
uint reg_mask, reg_val;
/* S4-Deep Sleep Mode is NOT available for WALL/USB power */
if (!restart && !power_supply_is_system_supplied()) {
deep_sleep = 1;
dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode");
}
/* Update wakeup sources */
reg_val = ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN |
(restart ? ATC2609A_PMU_SYS_CTL0_RESET_WK_EN
: ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN);
ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0,
ATC2609A_PMU_SYS_CTL0_WK_ALL, reg_val);
if (ret)
dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
/* Update power mode */
reg_mask = ATC2609A_PMU_SYS_CTL3_EN_S2 | ATC2609A_PMU_SYS_CTL3_EN_S3;
ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL3, reg_mask,
deep_sleep ? 0 : ATC2609A_PMU_SYS_CTL3_EN_S3);
if (ret) {
dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
return ret;
}
/* Trigger poweroff / restart sequence */
reg_mask = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN
: ATC2609A_PMU_SYS_CTL1_EN_S1;
reg_val = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN : 0;
ret = regmap_update_bits(pwrc->regmap,
restart ? ATC2609A_PMU_SYS_CTL0 : ATC2609A_PMU_SYS_CTL1,
reg_mask, reg_val);
if (ret) {
dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n",
restart ? 0 : 1, ret);
return ret;
}
/* Wait for trigger completion */
mdelay(200);
return 0;
}
static int atc2603c_init(const struct atc260x_pwrc *pwrc)
{
int ret;
/*
* Delay transition from S2/S3 to S1 in order to avoid
* DDR init failure in Bootloader.
*/
ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3,
ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN,
ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN);
if (ret)
dev_warn(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
/* Set wakeup sources */
ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0,
ATC2603C_PMU_SYS_CTL0_WK_ALL,
ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN |
ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN);
if (ret)
dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
return ret;
}
static int atc2609a_init(const struct atc260x_pwrc *pwrc)
{
int ret;
/* Set wakeup sources */
ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0,
ATC2609A_PMU_SYS_CTL0_WK_ALL,
ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN |
ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN);
if (ret)
dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
return ret;
}
static void atc260x_pwrc_pm_handler(void)
{
atc260x_pwrc_data->do_poweroff(atc260x_pwrc_data, false);
WARN_ONCE(1, "Unable to power off system\n");
}
static int atc260x_pwrc_restart_handler(struct notifier_block *nb,
unsigned long mode, void *cmd)
{
struct atc260x_pwrc *pwrc = container_of(nb, struct atc260x_pwrc,
restart_nb);
pwrc->do_poweroff(pwrc, true);
return NOTIFY_DONE;
}
static int atc260x_pwrc_probe(struct platform_device *pdev)
{
struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
struct atc260x_pwrc *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
priv->regmap = atc260x->regmap;
priv->restart_nb.notifier_call = atc260x_pwrc_restart_handler;
priv->restart_nb.priority = 192;
switch (atc260x->ic_type) {
case ATC2603C:
priv->do_poweroff = atc2603c_do_poweroff;
ret = atc2603c_init(priv);
break;
case ATC2609A:
priv->do_poweroff = atc2609a_do_poweroff;
ret = atc2609a_init(priv);
break;
default:
dev_err(priv->dev,
"Poweroff not supported for ATC260x PMIC type: %u\n",
atc260x->ic_type);
return -EINVAL;
}
if (ret)
return ret;
platform_set_drvdata(pdev, priv);
if (!pm_power_off) {
atc260x_pwrc_data = priv;
pm_power_off = atc260x_pwrc_pm_handler;
} else {
dev_warn(priv->dev, "Poweroff callback already assigned\n");
}
ret = register_restart_handler(&priv->restart_nb);
if (ret)
dev_err(priv->dev, "failed to register restart handler: %d\n",
ret);
return ret;
}
static int atc260x_pwrc_remove(struct platform_device *pdev)
{
struct atc260x_pwrc *priv = platform_get_drvdata(pdev);
if (atc260x_pwrc_data == priv) {
pm_power_off = NULL;
atc260x_pwrc_data = NULL;
}
unregister_restart_handler(&priv->restart_nb);
return 0;
}
static struct platform_driver atc260x_pwrc_driver = {
.probe = atc260x_pwrc_probe,
.remove = atc260x_pwrc_remove,
.driver = {
.name = "atc260x-pwrc",
},
};
module_platform_driver(atc260x_pwrc_driver);
MODULE_DESCRIPTION("Poweroff & reset driver for ATC260x PMICs");
MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
MODULE_LICENSE("GPL");
......@@ -113,6 +113,7 @@ static int __init linkstation_poweroff_init(void)
return -EPROBE_DEFER;
phydev = phy_find_first(bus);
put_device(&bus->dev);
if (!phydev)
return -EPROBE_DEFER;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* ZTE zx296702 SoC reset code
*
* Copyright (c) 2015 Linaro Ltd.
*
* Author: Jun Nie <jun.nie@linaro.org>
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
static void __iomem *base;
static void __iomem *pcu_base;
static int zx_restart_handler(struct notifier_block *this,
unsigned long mode, void *cmd)
{
writel_relaxed(1, base + 0xb0);
writel_relaxed(1, pcu_base + 0x34);
mdelay(50);
pr_emerg("Unable to restart system\n");
return NOTIFY_DONE;
}
static struct notifier_block zx_restart_nb = {
.notifier_call = zx_restart_handler,
.priority = 128,
};
static int zx_reboot_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int err;
base = of_iomap(np, 0);
if (!base) {
WARN(1, "failed to map base address");
return -ENODEV;
}
np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu");
pcu_base = of_iomap(np, 0);
of_node_put(np);
if (!pcu_base) {
iounmap(base);
WARN(1, "failed to map pcu_base address");
return -ENODEV;
}
err = register_restart_handler(&zx_restart_nb);
if (err) {
iounmap(base);
iounmap(pcu_base);
dev_err(&pdev->dev, "Register restart handler failed(err=%d)\n",
err);
}
return err;
}
static const struct of_device_id zx_reboot_of_match[] = {
{ .compatible = "zte,sysctrl" },
{}
};
MODULE_DEVICE_TABLE(of, zx_reboot_of_match);
static struct platform_driver zx_reboot_driver = {
.probe = zx_reboot_probe,
.driver = {
.name = "zx-reboot",
.of_match_table = zx_reboot_of_match,
},
};
module_platform_driver(zx_reboot_driver);
MODULE_DESCRIPTION("ZTE SoCs reset driver");
MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
MODULE_LICENSE("GPL v2");
......@@ -229,6 +229,7 @@ config BATTERY_SBS
config CHARGER_SBS
tristate "SBS Compliant charger"
depends on I2C
select REGMAP_I2C
help
Say Y to include support for SBS compliant battery chargers.
......@@ -513,6 +514,14 @@ config CHARGER_LT3651
Say Y to include support for the Analog Devices (Linear Technology)
LT3651 battery charger which reports its status via GPIO lines.
config CHARGER_LTC4162L
tristate "LTC4162-L charger"
depends on I2C
select REGMAP_I2C
help
Say Y to include support for the Analog Devices (Linear Technology)
LTC4162-L battery charger connected to I2C.
config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
......@@ -546,6 +555,7 @@ config CHARGER_MAX77693
config CHARGER_MAX8997
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
depends on MFD_MAX8997 && REGULATOR_MAX8997
depends on EXTCON || !EXTCON
help
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8997/LP3974 PMICs.
......@@ -645,6 +655,17 @@ config CHARGER_BQ25980
Say Y to enable support for the TI BQ25980, BQ25975 and BQ25960
series of fast battery chargers.
config CHARGER_BQ256XX
tristate "TI BQ256XX battery charger driver"
depends on I2C
depends on GPIOLIB || COMPILE_TEST
select REGMAP_I2C
help
Say Y to enable support for the TI BQ256XX battery chargers. The
BQ256XX family of devices are highly-integrated, switch-mode battery
charge management and system power path management devices for single
cell Li-ion and Li-polymer batteries.
config CHARGER_SMB347
tristate "Summit Microelectronics SMB3XX Battery Charger"
depends on I2C
......@@ -774,4 +795,10 @@ config RN5T618_POWER
This driver can also be built as a module. If so, the module will be
called rn5t618_power.
config BATTERY_ACER_A500
tristate "Acer Iconia Tab A500 battery driver"
depends on MFD_ACER_A500_EC
help
Say Y to include support for Acer Iconia Tab A500 battery fuel gauge.
endif # POWER_SUPPLY
......@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_LT3651) += lt3651-charger.o
obj-$(CONFIG_CHARGER_LTC4162L) += ltc4162-l-charger.o
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
......@@ -85,6 +86,7 @@ obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o
obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
obj-$(CONFIG_CHARGER_BQ25980) += bq25980_charger.o
obj-$(CONFIG_CHARGER_BQ256XX) += bq256xx_charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
......@@ -98,3 +100,4 @@ obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o
......@@ -857,7 +857,7 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
const struct abx500_v_to_cap *tbl;
int cap = 0;
tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl,
tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl;
tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements;
for (i = 0; i < tbl_size; ++i) {
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Battery driver for Acer Iconia Tab A500.
*
* Copyright 2020 GRATE-driver project.
*
* Based on downstream driver from Acer Inc.
* Based on NVIDIA Gas Gauge driver for SBS Compliant Batteries.
*
* Copyright (c) 2010, NVIDIA Corporation.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
enum {
REG_CAPACITY,
REG_VOLTAGE,
REG_CURRENT,
REG_DESIGN_CAPACITY,
REG_TEMPERATURE,
};
#define EC_DATA(_reg, _psp) { \
.psp = POWER_SUPPLY_PROP_ ## _psp, \
.reg = _reg, \
}
static const struct battery_register {
enum power_supply_property psp;
unsigned int reg;
} ec_data[] = {
[REG_CAPACITY] = EC_DATA(0x00, CAPACITY),
[REG_VOLTAGE] = EC_DATA(0x01, VOLTAGE_NOW),
[REG_CURRENT] = EC_DATA(0x03, CURRENT_NOW),
[REG_DESIGN_CAPACITY] = EC_DATA(0x08, CHARGE_FULL_DESIGN),
[REG_TEMPERATURE] = EC_DATA(0x0a, TEMP),
};
static const enum power_supply_property a500_battery_properties[] = {
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
struct a500_battery {
struct delayed_work poll_work;
struct power_supply *psy;
struct regmap *regmap;
unsigned int capacity;
};
static bool a500_battery_update_capacity(struct a500_battery *bat)
{
unsigned int capacity;
int err;
err = regmap_read(bat->regmap, ec_data[REG_CAPACITY].reg, &capacity);
if (err)
return false;
/* capacity can be >100% even if max value is 100% */
capacity = min(capacity, 100u);
if (bat->capacity != capacity) {
bat->capacity = capacity;
return true;
}
return false;
}
static int a500_battery_get_status(struct a500_battery *bat)
{
if (bat->capacity < 100) {
if (power_supply_am_i_supplied(bat->psy))
return POWER_SUPPLY_STATUS_CHARGING;
else
return POWER_SUPPLY_STATUS_DISCHARGING;
}
return POWER_SUPPLY_STATUS_FULL;
}
static void a500_battery_unit_adjustment(struct device *dev,
enum power_supply_property psp,
union power_supply_propval *val)
{
const unsigned int base_unit_conversion = 1000;
const unsigned int temp_kelvin_to_celsius = 2731;
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval *= base_unit_conversion;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval -= temp_kelvin_to_celsius;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = !!val->intval;
break;
default:
dev_dbg(dev,
"%s: no need for unit conversion %d\n", __func__, psp);
}
}
static int a500_battery_get_ec_data_index(struct device *dev,
enum power_supply_property psp)
{
unsigned int i;
/*
* DESIGN_CAPACITY register always returns a non-zero value if
* battery is connected and zero if disconnected, hence we'll use
* it for judging the battery presence.
*/
if (psp == POWER_SUPPLY_PROP_PRESENT)
psp = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
for (i = 0; i < ARRAY_SIZE(ec_data); i++)
if (psp == ec_data[i].psp)
return i;
dev_dbg(dev, "%s: invalid property %u\n", __func__, psp);
return -EINVAL;
}
static int a500_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct a500_battery *bat = power_supply_get_drvdata(psy);
struct device *dev = psy->dev.parent;
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = a500_battery_get_status(bat);
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CAPACITY:
a500_battery_update_capacity(bat);
val->intval = bat->capacity;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_TEMP:
ret = a500_battery_get_ec_data_index(dev, psp);
if (ret < 0)
break;
ret = regmap_read(bat->regmap, ec_data[ret].reg, &val->intval);
break;
default:
dev_err(dev, "%s: invalid property %u\n", __func__, psp);
return -EINVAL;
}
if (!ret) {
/* convert units to match requirements of power supply class */
a500_battery_unit_adjustment(dev, psp, val);
}
dev_dbg(dev, "%s: property = %d, value = %x\n",
__func__, psp, val->intval);
/* return NODATA for properties if battery not presents */
if (ret)
return -ENODATA;
return 0;
}
static void a500_battery_poll_work(struct work_struct *work)
{
struct a500_battery *bat;
bool capacity_changed;
bat = container_of(work, struct a500_battery, poll_work.work);
capacity_changed = a500_battery_update_capacity(bat);
if (capacity_changed)
power_supply_changed(bat->psy);
/* continuously send uevent notification */
schedule_delayed_work(&bat->poll_work, 30 * HZ);
}
static const struct power_supply_desc a500_battery_desc = {
.name = "ec-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = a500_battery_properties,
.get_property = a500_battery_get_property,
.num_properties = ARRAY_SIZE(a500_battery_properties),
.external_power_changed = power_supply_changed,
};
static int a500_battery_probe(struct platform_device *pdev)
{
struct power_supply_config psy_cfg = {};
struct a500_battery *bat;
bat = devm_kzalloc(&pdev->dev, sizeof(*bat), GFP_KERNEL);
if (!bat)
return -ENOMEM;
platform_set_drvdata(pdev, bat);
psy_cfg.of_node = pdev->dev.parent->of_node;
psy_cfg.drv_data = bat;
bat->regmap = dev_get_regmap(pdev->dev.parent, "KB930");
if (!bat->regmap)
return -EINVAL;
bat->psy = devm_power_supply_register_no_ws(&pdev->dev,
&a500_battery_desc,
&psy_cfg);
if (IS_ERR(bat->psy))
return dev_err_probe(&pdev->dev, PTR_ERR(bat->psy),
"failed to register battery\n");
INIT_DELAYED_WORK(&bat->poll_work, a500_battery_poll_work);
schedule_delayed_work(&bat->poll_work, HZ);
return 0;
}
static int a500_battery_remove(struct platform_device *pdev)
{
struct a500_battery *bat = dev_get_drvdata(&pdev->dev);
cancel_delayed_work_sync(&bat->poll_work);
return 0;
}
static int __maybe_unused a500_battery_suspend(struct device *dev)
{
struct a500_battery *bat = dev_get_drvdata(dev);
cancel_delayed_work_sync(&bat->poll_work);
return 0;
}
static int __maybe_unused a500_battery_resume(struct device *dev)
{
struct a500_battery *bat = dev_get_drvdata(dev);
schedule_delayed_work(&bat->poll_work, HZ);
return 0;
}
static SIMPLE_DEV_PM_OPS(a500_battery_pm_ops,
a500_battery_suspend, a500_battery_resume);
static struct platform_driver a500_battery_driver = {
.driver = {
.name = "acer-a500-iconia-battery",
.pm = &a500_battery_pm_ops,
},
.probe = a500_battery_probe,
.remove = a500_battery_remove,
};
module_platform_driver(a500_battery_driver);
MODULE_DESCRIPTION("Battery gauge driver for Acer Iconia Tab A500");
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
MODULE_ALIAS("platform:acer-a500-iconia-battery");
MODULE_LICENSE("GPL");
......@@ -593,6 +593,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
power->axp20x_id = axp_data->axp20x_id;
power->regmap = axp20x->regmap;
power->num_irqs = axp_data->num_irq_names;
INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
if (power->axp20x_id == AXP202_ID) {
/* Enable vbus valid checking */
......@@ -645,7 +646,6 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
}
}
INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
if (axp20x_usb_vbus_needs_polling(power))
queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0);
......
......@@ -732,6 +732,12 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
},
},
{ /* Mele PCG03 Mini PC */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Mini PC"),
},
},
{
/* Minix Neo Z83-4 mini PC */
.matches = {
......
......@@ -1766,7 +1766,7 @@ static int bq24190_probe(struct i2c_client *client,
charger_cfg.drv_data = bdi;
charger_cfg.of_node = dev->of_node;
charger_cfg.supplied_to = bq24190_charger_supplied_to;
charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to),
charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to);
bdi->charger = power_supply_register(dev, &bq24190_charger_desc,
&charger_cfg);
if (IS_ERR(bdi->charger)) {
......
This diff is collapsed.
......@@ -1285,7 +1285,7 @@ static int bq25980_probe(struct i2c_client *client,
static const struct i2c_device_id bq25980_i2c_ids[] = {
{ "bq25980", BQ25980 },
{ "bq25975", BQ25975 },
{ "bq25975", BQ25975 },
{ "bq25960", BQ25960 },
{},
};
MODULE_DEVICE_TABLE(i2c, bq25980_i2c_ids);
......
......@@ -110,6 +110,7 @@ enum bq27xxx_reg_index {
BQ27XXX_REG_TTES, /* Time-to-Empty Standby */
BQ27XXX_REG_TTECP, /* Time-to-Empty at Constant Power */
BQ27XXX_REG_NAC, /* Nominal Available Capacity */
BQ27XXX_REG_RC, /* Remaining Capacity */
BQ27XXX_REG_FCC, /* Full Charge Capacity */
BQ27XXX_REG_CYCT, /* Cycle Count */
BQ27XXX_REG_AE, /* Available Energy */
......@@ -145,6 +146,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = INVALID_REG_ADDR,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -169,6 +171,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = INVALID_REG_ADDR,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -193,6 +196,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1a,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -215,6 +219,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -237,6 +242,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1a,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x1e,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -257,6 +263,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = INVALID_REG_ADDR,
[BQ27XXX_REG_AE] = 0x22,
......@@ -277,6 +284,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -297,6 +305,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = 0x26,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -317,6 +326,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1c,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x1e,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -337,6 +347,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
[BQ27XXX_REG_RC] = INVALID_REG_ADDR,
[BQ27XXX_REG_FCC] = INVALID_REG_ADDR,
[BQ27XXX_REG_CYCT] = INVALID_REG_ADDR,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -361,6 +372,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -382,6 +394,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -405,6 +418,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x0c,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -425,6 +439,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = 0x08,
[BQ27XXX_REG_RC] = 0x0c,
[BQ27XXX_REG_FCC] = 0x0e,
[BQ27XXX_REG_CYCT] = INVALID_REG_ADDR,
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
......@@ -450,6 +465,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -470,6 +486,7 @@ static u8
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
[BQ27XXX_REG_RC] = 0x10,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
......@@ -490,6 +507,7 @@ static u8
[BQ27XXX_REG_TTES] = 0x1e,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
[BQ27XXX_REG_RC] = 0x04,
[BQ27XXX_REG_FCC] = 0x06,
[BQ27XXX_REG_CYCT] = 0x2c,
[BQ27XXX_REG_AE] = 0x24,
......@@ -745,6 +763,7 @@ static enum power_supply_property bq27z561_props[] = {
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_POWER_AVG,
......@@ -764,6 +783,7 @@ static enum power_supply_property bq28z610_props[] = {
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_POWER_AVG,
......@@ -784,6 +804,7 @@ static enum power_supply_property bq34z100_props[] = {
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_ENERGY_NOW,
......@@ -1518,6 +1539,15 @@ static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di)
return bq27xxx_battery_read_charge(di, BQ27XXX_REG_NAC);
}
/*
* Return the battery Remaining Capacity in µAh
* Or < 0 if something fails.
*/
static inline int bq27xxx_battery_read_rc(struct bq27xxx_device_info *di)
{
return bq27xxx_battery_read_charge(di, BQ27XXX_REG_RC);
}
/*
* Return the battery Full Charge Capacity in µAh
* Or < 0 if something fails.
......@@ -1789,7 +1819,7 @@ static int bq27xxx_battery_current(struct bq27xxx_device_info *di,
if (di->opts & BQ27XXX_O_ZERO) {
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true);
if (flags & BQ27000_FLAG_CHGS) {
if (!(flags & BQ27000_FLAG_CHGS)) {
dev_dbg(di->dev, "negative current!\n");
curr = -curr;
}
......@@ -1797,7 +1827,7 @@ static int bq27xxx_battery_current(struct bq27xxx_device_info *di,
val->intval = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
} else {
/* Other gauges return signed value */
val->intval = (int)((s16)curr) * 1000;
val->intval = -(int)((s16)curr) * 1000;
}
return 0;
......@@ -1965,7 +1995,10 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
if (di->regs[BQ27XXX_REG_NAC] != INVALID_REG_ADDR)
ret = bq27xxx_simple_value(bq27xxx_battery_read_nac(di), val);
else
ret = bq27xxx_simple_value(bq27xxx_battery_read_rc(di), val);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = bq27xxx_simple_value(di->cache.charge_full, val);
......
......@@ -570,7 +570,7 @@ static int cm_get_target_status(struct charger_manager *cm)
return POWER_SUPPLY_STATUS_DISCHARGING;
if (cm_check_thermal_status(cm)) {
/* Check if discharging duration exeeds limit. */
/* Check if discharging duration exceeds limit. */
if (check_charging_duration(cm))
goto charging_ok;
return POWER_SUPPLY_STATUS_NOT_CHARGING;
......@@ -578,7 +578,7 @@ static int cm_get_target_status(struct charger_manager *cm)
switch (cm->battery_status) {
case POWER_SUPPLY_STATUS_CHARGING:
/* Check if charging duration exeeds limit. */
/* Check if charging duration exceeds limit. */
if (check_charging_duration(cm))
return POWER_SUPPLY_STATUS_FULL;
fallthrough;
......@@ -723,9 +723,9 @@ static int charger_get_property(struct power_supply *psy,
val->intval = cm->battery_status;
break;
case POWER_SUPPLY_PROP_HEALTH:
if (cm->emergency_stop > 0)
if (cm->emergency_stop == CM_BATT_OVERHEAT)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (cm->emergency_stop < 0)
else if (cm->emergency_stop == CM_BATT_COLD)
val->intval = POWER_SUPPLY_HEALTH_COLD;
else
val->intval = POWER_SUPPLY_HEALTH_GOOD;
......
This diff is collapsed.
This diff is collapsed.
......@@ -198,7 +198,7 @@ static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
return w1_ds2760_read(dev, buf, off, count);
}
......
......@@ -624,7 +624,7 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct power_supply *psy = to_power_supply(dev);
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
......@@ -637,7 +637,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct power_supply *psy = to_power_supply(dev);
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
int ret;
......@@ -669,7 +669,7 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct power_supply *psy = to_power_supply(dev);
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
......@@ -682,7 +682,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct power_supply *psy = to_power_supply(dev);
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
int ret;
......
......@@ -52,7 +52,7 @@ static int ingenic_battery_get_property(struct power_supply *psy,
return 0;
default:
return -EINVAL;
};
}
}
/* Set the most appropriate IIO channel voltage reference scale
......
This diff is collapsed.
......@@ -15,8 +15,6 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
......
This diff is collapsed.
......@@ -6,12 +6,14 @@
// MyungJoo Ham <myungjoo.ham@samsung.com>
#include <linux/err.h>
#include <linux/extcon.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
#include <linux/regulator/consumer.h>
/* MAX8997_REG_STATUS4 */
#define DCINOK_SHIFT 1
......@@ -31,6 +33,10 @@ struct charger_data {
struct device *dev;
struct max8997_dev *iodev;
struct power_supply *battery;
struct regulator *reg;
struct extcon_dev *edev;
struct notifier_block extcon_nb;
struct work_struct extcon_work;
};
static enum power_supply_property max8997_battery_props[] = {
......@@ -88,6 +94,67 @@ static int max8997_battery_get_property(struct power_supply *psy,
return 0;
}
static void max8997_battery_extcon_evt_stop_work(void *data)
{
struct charger_data *charger = data;
cancel_work_sync(&charger->extcon_work);
}
static void max8997_battery_extcon_evt_worker(struct work_struct *work)
{
struct charger_data *charger =
container_of(work, struct charger_data, extcon_work);
struct extcon_dev *edev = charger->edev;
int current_limit;
if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
dev_dbg(charger->dev, "USB SDP charger is connected\n");
current_limit = 450000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) {
dev_dbg(charger->dev, "USB DCP charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_FAST) > 0) {
dev_dbg(charger->dev, "USB FAST charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_SLOW) > 0) {
dev_dbg(charger->dev, "USB SLOW charger is connected\n");
current_limit = 650000;
} else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
dev_dbg(charger->dev, "USB CDP charger is connected\n");
current_limit = 650000;
} else {
dev_dbg(charger->dev, "USB charger is disconnected\n");
current_limit = -1;
}
if (current_limit > 0) {
int ret = regulator_set_current_limit(charger->reg, current_limit, current_limit);
if (ret) {
dev_err(charger->dev, "failed to set current limit: %d\n", ret);
return;
}
ret = regulator_enable(charger->reg);
if (ret)
dev_err(charger->dev, "failed to enable regulator: %d\n", ret);
} else {
int ret = regulator_disable(charger->reg);
if (ret)
dev_err(charger->dev, "failed to disable regulator: %d\n", ret);
}
}
static int max8997_battery_extcon_evt(struct notifier_block *nb,
unsigned long event, void *param)
{
struct charger_data *charger =
container_of(nb, struct charger_data, extcon_nb);
schedule_work(&charger->extcon_work);
return NOTIFY_OK;
}
static const struct power_supply_desc max8997_battery_desc = {
.name = "max8997_pmic",
.type = POWER_SUPPLY_TYPE_BATTERY,
......@@ -170,6 +237,35 @@ static int max8997_battery_probe(struct platform_device *pdev)
return PTR_ERR(charger->battery);
}
charger->reg = devm_regulator_get_optional(&pdev->dev, "charger");
if (IS_ERR(charger->reg)) {
if (PTR_ERR(charger->reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(&pdev->dev, "couldn't get charger regulator\n");
}
charger->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(charger->edev)) {
if (PTR_ERR(charger->edev) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(charger->dev, "couldn't get extcon device\n");
}
if (!IS_ERR(charger->reg) && !IS_ERR(charger->edev)) {
INIT_WORK(&charger->extcon_work, max8997_battery_extcon_evt_worker);
ret = devm_add_action(&pdev->dev, max8997_battery_extcon_evt_stop_work, charger);
if (ret) {
dev_err(&pdev->dev, "failed to add extcon evt stop action: %d\n", ret);
return ret;
}
charger->extcon_nb.notifier_call = max8997_battery_extcon_evt;
ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev,
&charger->extcon_nb);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon notifier\n");
return ret;
};
}
return 0;
}
......
......@@ -299,13 +299,11 @@ static const struct hwmon_channel_info *power_supply_hwmon_info[] = {
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,
......
......@@ -374,7 +374,7 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
return 0;
}
static struct attribute_group power_supply_attr_group = {
static const struct attribute_group power_supply_attr_group = {
.attrs = __power_supply_attrs,
.is_visible = power_supply_attr_is_visible,
};
......
......@@ -137,6 +137,7 @@
* @mains_online: is AC/DC input connected
* @usb_online: is USB input connected
* @charging_enabled: is charging enabled
* @irq_unsupported: is interrupt unsupported by SMB hardware
* @max_charge_current: maximum current (in uA) the battery can be charged
* @max_charge_voltage: maximum voltage (in uV) the battery can be charged
* @pre_charge_current: current (in uA) to use in pre-charging phase
......@@ -193,6 +194,7 @@ struct smb347_charger {
bool mains_online;
bool usb_online;
bool charging_enabled;
bool irq_unsupported;
unsigned int max_charge_current;
unsigned int max_charge_voltage;
......@@ -862,6 +864,9 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable)
{
int ret;
if (smb->irq_unsupported)
return 0;
ret = smb347_set_writable(smb, true);
if (ret < 0)
return ret;
......@@ -923,8 +928,6 @@ static int smb347_irq_init(struct smb347_charger *smb,
ret = regmap_update_bits(smb->regmap, CFG_STAT,
CFG_STAT_ACTIVE_HIGH | CFG_STAT_DISABLED,
CFG_STAT_DISABLED);
if (ret < 0)
client->irq = 0;
smb347_set_writable(smb, false);
......@@ -1345,6 +1348,7 @@ static int smb347_probe(struct i2c_client *client,
if (ret < 0) {
dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
dev_warn(dev, "disabling IRQ support\n");
smb->irq_unsupported = true;
} else {
smb347_irq_enable(smb);
}
......@@ -1357,8 +1361,8 @@ static int smb347_remove(struct i2c_client *client)
{
struct smb347_charger *smb = i2c_get_clientdata(client);
if (client->irq)
smb347_irq_disable(smb);
return 0;
}
......
......@@ -15,11 +15,12 @@
#include <linux/wm97xx.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/irq.h>
#include <linux/slab.h>
static struct work_struct bat_work;
static struct gpio_desc *charge_gpiod;
static DEFINE_MUTEX(work_lock);
static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
static enum power_supply_property *prop;
......@@ -96,12 +97,11 @@ static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps)
static void wm97xx_bat_update(struct power_supply *bat_ps)
{
int old_status = bat_status;
struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps);
mutex_lock(&work_lock);
bat_status = (pdata->charge_gpio >= 0) ?
(gpio_get_value(pdata->charge_gpio) ?
bat_status = (charge_gpiod) ?
(gpiod_get_value(charge_gpiod) ?
POWER_SUPPLY_STATUS_DISCHARGING :
POWER_SUPPLY_STATUS_CHARGING) :
POWER_SUPPLY_STATUS_UNKNOWN;
......@@ -171,18 +171,19 @@ static int wm97xx_bat_probe(struct platform_device *dev)
if (dev->id != -1)
return -EINVAL;
if (gpio_is_valid(pdata->charge_gpio)) {
ret = gpio_request(pdata->charge_gpio, "BATT CHRG");
if (ret)
goto err;
ret = gpio_direction_input(pdata->charge_gpio);
if (ret)
goto err2;
ret = request_irq(gpio_to_irq(pdata->charge_gpio),
charge_gpiod = devm_gpiod_get_optional(&dev->dev, NULL, GPIOD_IN);
if (IS_ERR(charge_gpiod))
return dev_err_probe(&dev->dev,
PTR_ERR(charge_gpiod),
"failed to get charge GPIO\n");
if (charge_gpiod) {
gpiod_set_consumer_name(charge_gpiod, "BATT CHRG");
ret = request_irq(gpiod_to_irq(charge_gpiod),
wm97xx_chrg_irq, 0,
"AC Detect", dev);
if (ret)
goto err2;
return dev_err_probe(&dev->dev, ret,
"failed to request GPIO irq\n");
props++; /* POWER_SUPPLY_PROP_STATUS */
}
......@@ -204,7 +205,7 @@ static int wm97xx_bat_probe(struct platform_device *dev)
}
prop[i++] = POWER_SUPPLY_PROP_PRESENT;
if (pdata->charge_gpio >= 0)
if (charge_gpiod)
prop[i++] = POWER_SUPPLY_PROP_STATUS;
if (pdata->batt_tech >= 0)
prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
......@@ -242,23 +243,15 @@ static int wm97xx_bat_probe(struct platform_device *dev)
err4:
kfree(prop);
err3:
if (gpio_is_valid(pdata->charge_gpio))
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
err2:
if (gpio_is_valid(pdata->charge_gpio))
gpio_free(pdata->charge_gpio);
err:
if (charge_gpiod)
free_irq(gpiod_to_irq(charge_gpiod), dev);
return ret;
}
static int wm97xx_bat_remove(struct platform_device *dev)
{
struct wm97xx_batt_pdata *pdata = dev->dev.platform_data;
if (pdata && gpio_is_valid(pdata->charge_gpio)) {
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
gpio_free(pdata->charge_gpio);
}
if (charge_gpiod)
free_irq(gpiod_to_irq(charge_gpiod), dev);
cancel_work_sync(&bat_work);
power_supply_unregister(bat_psy);
kfree(prop);
......
......@@ -6,7 +6,7 @@
*/
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......@@ -18,6 +18,7 @@
struct z2_charger {
struct z2_battery_info *info;
struct gpio_desc *charge_gpiod;
int bat_status;
struct i2c_client *client;
struct power_supply *batt_ps;
......@@ -95,8 +96,8 @@ static void z2_batt_update(struct z2_charger *charger)
mutex_lock(&charger->work_lock);
charger->bat_status = (info->charge_gpio >= 0) ?
(gpio_get_value(info->charge_gpio) ?
charger->bat_status = charger->charge_gpiod ?
(gpiod_get_value(charger->charge_gpiod) ?
POWER_SUPPLY_STATUS_CHARGING :
POWER_SUPPLY_STATUS_DISCHARGING) :
POWER_SUPPLY_STATUS_UNKNOWN;
......@@ -131,7 +132,7 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props)
enum power_supply_property *prop;
struct z2_battery_info *info = charger->info;
if (info->charge_gpio >= 0)
if (charger->charge_gpiod)
props++; /* POWER_SUPPLY_PROP_STATUS */
if (info->batt_tech >= 0)
props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
......@@ -147,7 +148,7 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props)
return -ENOMEM;
prop[i++] = POWER_SUPPLY_PROP_PRESENT;
if (info->charge_gpio >= 0)
if (charger->charge_gpiod)
prop[i++] = POWER_SUPPLY_PROP_STATUS;
if (info->batt_tech >= 0)
prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
......@@ -206,22 +207,23 @@ static int z2_batt_probe(struct i2c_client *client,
mutex_init(&charger->work_lock);
if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
ret = gpio_request(info->charge_gpio, "BATT CHRG");
if (ret)
goto err;
charger->charge_gpiod = devm_gpiod_get_optional(&client->dev,
NULL, GPIOD_IN);
if (IS_ERR(charger->charge_gpiod))
return dev_err_probe(&client->dev,
PTR_ERR(charger->charge_gpiod),
"failed to get charge GPIO\n");
ret = gpio_direction_input(info->charge_gpio);
if (ret)
goto err2;
if (charger->charge_gpiod) {
gpiod_set_consumer_name(charger->charge_gpiod, "BATT CHRG");
irq_set_irq_type(gpio_to_irq(info->charge_gpio),
irq_set_irq_type(gpiod_to_irq(charger->charge_gpiod),
IRQ_TYPE_EDGE_BOTH);
ret = request_irq(gpio_to_irq(info->charge_gpio),
ret = request_irq(gpiod_to_irq(charger->charge_gpiod),
z2_charge_switch_irq, 0,
"AC Detect", charger);
if (ret)
goto err3;
goto err;
}
ret = z2_batt_ps_init(charger, props);
......@@ -245,11 +247,8 @@ static int z2_batt_probe(struct i2c_client *client,
err4:
kfree(charger->batt_ps_desc.properties);
err3:
if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
free_irq(gpio_to_irq(info->charge_gpio), charger);
err2:
if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
gpio_free(info->charge_gpio);
if (charger->charge_gpiod)
free_irq(gpiod_to_irq(charger->charge_gpiod), charger);
err:
kfree(charger);
return ret;
......@@ -258,16 +257,13 @@ static int z2_batt_probe(struct i2c_client *client,
static int z2_batt_remove(struct i2c_client *client)
{
struct z2_charger *charger = i2c_get_clientdata(client);
struct z2_battery_info *info = charger->info;
cancel_work_sync(&charger->bat_work);
power_supply_unregister(charger->batt_ps);
kfree(charger->batt_ps_desc.properties);
if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
free_irq(gpio_to_irq(info->charge_gpio), charger);
gpio_free(info->charge_gpio);
}
if (charger->charge_gpiod)
free_irq(gpiod_to_irq(charger->charge_gpiod), charger);
kfree(charger);
......
This diff is collapsed.
......@@ -294,7 +294,6 @@ struct wm97xx {
struct wm97xx_batt_pdata {
int batt_aux;
int temp_aux;
int charge_gpio;
int min_voltage;
int max_voltage;
int batt_div;
......
......@@ -6,7 +6,6 @@ struct z2_battery_info {
int batt_I2C_bus;
int batt_I2C_addr;
int batt_I2C_reg;
int charge_gpio;
int min_voltage;
int max_voltage;
int batt_div;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment