Commit 3ac684b8 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull power supply and reset updates from Sebastian Reichel:

 - Microsemi Ocelot reset support

 - Spreadtrum SC27xx reset support

 - generic gpio charger: lot's of cleanups

 - axp20x fuel gauge: add AXP813 support

 - misc fixes, including one devicetree change for the Nokia N900, that
   has been Acked-by Tony Lindgren

* tag 'for-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (27 commits)
  power: reset: at91-reset: Switch from the pr_*() to the dev_*() logging functions
  power: reset: at91-poweroff: Remove redundant dev_err call in at91_poweroff_probe()
  power: reset: at91-poweroff: Switch from the pr_*() to the dev_*() logging functions
  power: reset: make function sc27xx_poweroff_shutdown static
  power: supply: da9150-fg: remove VLA usage
  ARM: dts: omap3-n900: Add link between battery and charger
  power: supply: bq2415x: add DT referencing support
  power: supply: bq27xxx: support missing supplier device
  max17042: propagate of_node to power supply device
  power: supply: axp288_fuel_gauge: Fix full status reporting
  power: supply: axp288_fuel_gauge: Do not register FG on ECS EF20EA
  power: reset: gpio-poweroff: Support for timeout from device property
  dt-bindings: power: reset: gpio-poweroff: Add 'timeout-ms' property
  power: reset: Add Spreadtrum SC27xx PMIC power off support
  power: supply: axp20x_battery: add support for AXP813
  dt-bindings: power: supply: axp20x: add AXP813 battery DT binding
  power: supply: axp20x_battery: use data struct for variant specific code
  power: supply: gpio-charger: Remove pdata from gpio_charger
  power: supply: gpio-charger: Use GPIOF_ACTIVE_LOW for legacy setup
  power: supply: gpio-charger: Remove redundant dev_err call in probe function
  ...
parents 75dcc7ef fd73a3e6
......@@ -27,10 +27,13 @@ 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.
- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is
specified, 3000 ms is used.
Examples:
gpio-poweroff {
compatible = "gpio-poweroff";
gpios = <&gpio 4 0>;
timeout-ms = <3000>;
};
Microsemi Ocelot reset controller
The DEVCPU_GCB:CHIP_REGS have a SOFT_RST register that can be used to reset the
SoC MIPS core.
Required Properties:
- compatible: "mscc,ocelot-chip-reset"
Example:
reset@1070008 {
compatible = "mscc,ocelot-chip-reset";
reg = <0x1070008 0x4>;
};
......@@ -4,12 +4,12 @@ Required Properties:
- compatible, one of:
"x-powers,axp209-battery-power-supply"
"x-powers,axp221-battery-power-supply"
"x-powers,axp813-battery-power-supply"
This node is a subnode of the axp20x/axp22x PMIC.
This node is a subnode of its respective PMIC DT node.
The AXP20X and AXP22X can read the battery voltage, charge and discharge
currents of the battery by reading ADC channels from the AXP20X/AXP22X
ADC.
The supported devices can read the battery voltage, charge and discharge
currents of the battery by reading ADC channels from the ADC.
Example:
......
......@@ -673,6 +673,7 @@
bq27200: bq27200@55 {
compatible = "ti,bq27200";
reg = <0x55>;
power-supplies = <&bq24150a>;
};
/* Stereo headphone amplifier */
......
......@@ -104,6 +104,13 @@ config POWER_RESET_MSM
help
Power off and restart support for Qualcomm boards.
config POWER_RESET_OCELOT_RESET
bool "Microsemi Ocelot reset driver"
depends on MSCC_OCELOT || COMPILE_TEST
select MFD_SYSCON
help
This driver supports restart for Microsemi Ocelot SoC.
config POWER_RESET_PIIX4_POWEROFF
tristate "Intel PIIX4 power-off driver"
depends on PCI
......@@ -218,5 +225,14 @@ config SYSCON_REBOOT_MODE
register, then the bootloader can read it to take different
action according to the mode.
config POWER_RESET_SC27XX
bool "Spreadtrum SC27xx PMIC power-off driver"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
help
This driver supports powering off a system through
Spreadtrum SC27xx series PMICs. The SC27xx series
PMICs includes the SC2720, SC2721, SC2723, SC2730
and SC2731 chips.
endif
......@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
......@@ -26,3 +27,4 @@ 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
......@@ -55,10 +55,10 @@ static void __iomem *at91_shdwc_base;
static struct clk *sclk;
static void __iomem *mpddrc_base;
static void __init at91_wakeup_status(void)
static void __init at91_wakeup_status(struct platform_device *pdev)
{
const char *reason;
u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR);
char *reason = "unknown";
/* Simple power-on, just bail out */
if (!reg)
......@@ -68,8 +68,10 @@ static void __init at91_wakeup_status(void)
reason = "RTT";
else if (reg & AT91_SHDW_RTCWK)
reason = "RTC";
else
reason = "unknown";
pr_info("AT91: Wake-Up source: %s\n", reason);
dev_info(&pdev->dev, "Wake-Up source: %s\n", reason);
}
static void at91_poweroff(void)
......@@ -157,10 +159,8 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(at91_shdwc_base)) {
dev_err(&pdev->dev, "Could not map reset controller address\n");
if (IS_ERR(at91_shdwc_base))
return PTR_ERR(at91_shdwc_base);
}
sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(sclk))
......@@ -172,7 +172,7 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
return ret;
}
at91_wakeup_status();
at91_wakeup_status(pdev);
if (pdev->dev.of_node)
at91_poweroff_dt_set_wakeup_mode(pdev);
......
......@@ -145,8 +145,8 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode,
static void __init at91_reset_status(struct platform_device *pdev)
{
const char *reason;
u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
char *reason;
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
case RESET_TYPE_GENERAL:
......@@ -169,7 +169,7 @@ static void __init at91_reset_status(struct platform_device *pdev)
break;
}
pr_info("AT91: Starting after %s\n", reason);
dev_info(&pdev->dev, "Starting after %s\n", reason);
}
static const struct of_device_id at91_ramc_of_match[] = {
......
......@@ -47,8 +47,12 @@ static irqreturn_t gemini_powerbutton_interrupt(int irq, void *data)
val &= 0x70U;
switch (val) {
case GEMINI_STAT_CIR:
dev_info(gpw->dev, "infrared poweroff\n");
orderly_poweroff(true);
/*
* We do not yet have a driver for the infrared
* controller so it can cause spurious poweroff
* events. Ignore those for now.
*/
dev_info(gpw->dev, "infrared poweroff - ignored\n");
break;
case GEMINI_STAT_RTC:
dev_info(gpw->dev, "RTC poweroff\n");
......@@ -116,7 +120,17 @@ static int gemini_poweroff_probe(struct platform_device *pdev)
return -ENODEV;
}
/* Clear the power management IRQ */
/*
* Enable the power controller. This is crucial on Gemini
* systems: if this is not done, pressing the power button
* will result in unconditional poweroff without any warning.
* This makes the kernel handle the poweroff.
*/
val = readl(gpw->base + GEMINI_PWC_CTRLREG);
val |= GEMINI_CTRL_ENABLE;
writel(val, gpw->base + GEMINI_PWC_CTRLREG);
/* Now that the state machine is active, clear the IRQ */
val = readl(gpw->base + GEMINI_PWC_CTRLREG);
val |= GEMINI_CTRL_IRQ_CLR;
writel(val, gpw->base + GEMINI_PWC_CTRLREG);
......@@ -129,16 +143,6 @@ static int gemini_poweroff_probe(struct platform_device *pdev)
pm_power_off = gemini_poweroff;
gpw_poweroff = gpw;
/*
* Enable the power controller. This is crucial on Gemini
* systems: if this is not done, pressing the power button
* will result in unconditional poweroff without any warning.
* This makes the kernel handle the poweroff.
*/
val = readl(gpw->base + GEMINI_PWC_CTRLREG);
val |= GEMINI_CTRL_ENABLE;
writel(val, gpw->base + GEMINI_PWC_CTRLREG);
dev_info(dev, "Gemini poweroff driver registered\n");
return 0;
......
......@@ -19,11 +19,13 @@
#include <linux/of_platform.h>
#include <linux/module.h>
#define DEFAULT_TIMEOUT_MS 3000
/*
* Hold configuration here, cannot be more than one instance of the driver
* since pm_power_off itself is global.
*/
static struct gpio_desc *reset_gpio;
static u32 timeout = DEFAULT_TIMEOUT_MS;
static void gpio_poweroff_do_poweroff(void)
{
......@@ -40,7 +42,7 @@ static void gpio_poweroff_do_poweroff(void)
gpiod_set_value(reset_gpio, 1);
/* give it some time */
mdelay(3000);
mdelay(timeout);
WARN_ON(1);
}
......@@ -58,12 +60,14 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
return -EBUSY;
}
input = of_property_read_bool(pdev->dev.of_node, "input");
input = device_property_read_bool(&pdev->dev, "input");
if (input)
flags = GPIOD_IN;
else
flags = GPIOD_OUT_LOW;
device_property_read_u32(&pdev->dev, "timeout-ms", &timeout);
reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
......
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi MIPS SoC reset driver
*
* License: Dual MIT/GPL
* Copyright (c) 2017 Microsemi Corporation
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/notifier.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
struct ocelot_reset_context {
void __iomem *base;
struct regmap *cpu_ctrl;
struct notifier_block restart_handler;
};
#define ICPU_CFG_CPU_SYSTEM_CTRL_RESET 0x20
#define CORE_RST_PROTECT BIT(2)
#define SOFT_CHIP_RST BIT(0)
static int ocelot_restart_handle(struct notifier_block *this,
unsigned long mode, void *cmd)
{
struct ocelot_reset_context *ctx = container_of(this, struct
ocelot_reset_context,
restart_handler);
/* Make sure the core is not protected from reset */
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
CORE_RST_PROTECT, 0);
writel(SOFT_CHIP_RST, ctx->base);
pr_emerg("Unable to restart system\n");
return NOTIFY_DONE;
}
static int ocelot_reset_probe(struct platform_device *pdev)
{
struct ocelot_reset_context *ctx;
struct resource *res;
struct device *dev = &pdev->dev;
int err;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ctx->base))
return PTR_ERR(ctx->base);
ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
if (IS_ERR(ctx->cpu_ctrl))
return PTR_ERR(ctx->cpu_ctrl);
ctx->restart_handler.notifier_call = ocelot_restart_handle;
ctx->restart_handler.priority = 192;
err = register_restart_handler(&ctx->restart_handler);
if (err)
dev_err(dev, "can't register restart notifier (err=%d)\n", err);
return err;
}
static const struct of_device_id ocelot_reset_of_match[] = {
{ .compatible = "mscc,ocelot-chip-reset" },
{}
};
static struct platform_driver ocelot_reset_driver = {
.probe = ocelot_reset_probe,
.driver = {
.name = "ocelot-chip-reset",
.of_match_table = ocelot_reset_of_match,
},
};
builtin_platform_driver(ocelot_reset_driver);
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Spreadtrum Communications Inc.
* Copyright (C) 2018 Linaro Ltd.
*/
#include <linux/cpu.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/syscore_ops.h>
#define SC27XX_PWR_PD_HW 0xc2c
#define SC27XX_PWR_OFF_EN BIT(0)
static struct regmap *regmap;
/*
* On Spreadtrum platform, we need power off system through external SC27xx
* series PMICs, and it is one similar SPI bus mapped by regmap to access PMIC,
* which is not fast io access.
*
* So before stopping other cores, we need release other cores' resource by
* taking cpus down to avoid racing regmap or spi mutex lock when poweroff
* system through PMIC.
*/
static void sc27xx_poweroff_shutdown(void)
{
#ifdef CONFIG_PM_SLEEP_SMP
int cpu = smp_processor_id();
freeze_secondary_cpus(cpu);
#endif
}
static struct syscore_ops poweroff_syscore_ops = {
.shutdown = sc27xx_poweroff_shutdown,
};
static void sc27xx_poweroff_do_poweroff(void)
{
regmap_write(regmap, SC27XX_PWR_PD_HW, SC27XX_PWR_OFF_EN);
}
static int sc27xx_poweroff_probe(struct platform_device *pdev)
{
if (regmap)
return -EINVAL;
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
return -ENODEV;
pm_power_off = sc27xx_poweroff_do_poweroff;
register_syscore_ops(&poweroff_syscore_ops);
return 0;
}
static struct platform_driver sc27xx_poweroff_driver = {
.probe = sc27xx_poweroff_probe,
.driver = {
.name = "sc27xx-poweroff",
},
};
builtin_platform_driver(sc27xx_poweroff_driver);
......@@ -49,10 +49,22 @@
#define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5)
#define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5)
#define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5)
#define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0)
#define AXP20X_V_OFF_MASK GENMASK(2, 0)
struct axp20x_batt_ps;
struct axp_data {
int ccc_scale;
int ccc_offset;
bool has_fg_valid;
int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
};
struct axp20x_batt_ps {
struct regmap *regmap;
struct power_supply *batt;
......@@ -62,7 +74,7 @@ struct axp20x_batt_ps {
struct iio_channel *batt_v;
/* Maximum constant charge current */
unsigned int max_ccc;
u8 axp_id;
const struct axp_data *data;
};
static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
......@@ -123,20 +135,33 @@ static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
return 0;
}
static void raw_to_constant_charge_current(struct axp20x_batt_ps *axp, int *val)
static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int *val)
{
if (axp->axp_id == AXP209_ID)
*val = *val * 100000 + 300000;
else
*val = *val * 150000 + 300000;
}
int ret, reg;
static void constant_charge_current_to_raw(struct axp20x_batt_ps *axp, int *val)
{
if (axp->axp_id == AXP209_ID)
*val = (*val - 300000) / 100000;
else
*val = (*val - 300000) / 150000;
ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
if (ret)
return ret;
switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
case AXP20X_CHRG_CTRL1_TGT_4_1V:
*val = 4100000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_15V:
*val = 4150000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_2V:
*val = 4200000;
break;
case AXP813_CHRG_CTRL1_TGT_4_35V:
*val = 4350000;
break;
default:
return -EINVAL;
}
return 0;
}
static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
......@@ -150,7 +175,7 @@ static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
*val &= AXP20X_CHRG_CTRL1_TGT_CURR;
raw_to_constant_charge_current(axp, val);
*val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
return 0;
}
......@@ -269,8 +294,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
if (ret)
return ret;
if (axp20x_batt->axp_id == AXP221_ID &&
!(reg & AXP22X_FG_VALID))
if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))
return -EINVAL;
/*
......@@ -281,11 +305,8 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
if (axp20x_batt->axp_id == AXP209_ID)
return axp20x_battery_get_max_voltage(axp20x_batt,
&val->intval);
return axp22x_battery_get_max_voltage(axp20x_batt,
&val->intval);
return axp20x_batt->data->get_max_voltage(axp20x_batt,
&val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, &reg);
......@@ -312,6 +333,32 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
return 0;
}
static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int val)
{
switch (val) {
case 4100000:
val = AXP20X_CHRG_CTRL1_TGT_4_1V;
break;
case 4200000:
val = AXP20X_CHRG_CTRL1_TGT_4_2V;
break;
default:
/*
* AXP20x max voltage can be set to 4.36V and AXP22X max voltage
* can be set to 4.22V and 4.24V, but these voltages are too
* high for Lithium based batteries (AXP PMICs are supposed to
* be used with these kinds of battery).
*/
return -EINVAL;
}
return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
AXP20X_CHRG_CTRL1_TGT_VOLT, val);
}
static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int val)
{
......@@ -321,9 +368,6 @@ static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
break;
case 4150000:
if (axp20x_batt->axp_id == AXP221_ID)
return -EINVAL;
val = AXP20X_CHRG_CTRL1_TGT_4_15V;
break;
......@@ -351,7 +395,8 @@ static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
if (charge_current > axp_batt->max_ccc)
return -EINVAL;
constant_charge_current_to_raw(axp_batt, &charge_current);
charge_current = (charge_current - axp_batt->data->ccc_offset) /
axp_batt->data->ccc_scale;
if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
return -EINVAL;
......@@ -365,12 +410,14 @@ static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
{
bool lower_max = false;
constant_charge_current_to_raw(axp, &charge_current);
charge_current = (charge_current - axp->data->ccc_offset) /
axp->data->ccc_scale;
if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
return -EINVAL;
raw_to_constant_charge_current(axp, &charge_current);
charge_current = charge_current * axp->data->ccc_scale +
axp->data->ccc_offset;
if (charge_current > axp->max_ccc)
dev_warn(axp->dev,
......@@ -413,7 +460,7 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
return axp20x_set_voltage_min_design(axp20x_batt, val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
return axp20x_battery_set_max_voltage(axp20x_batt, val->intval);
return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
return axp20x_set_constant_charge_current(axp20x_batt,
......@@ -460,13 +507,39 @@ static const struct power_supply_desc axp20x_batt_ps_desc = {
.set_property = axp20x_battery_set_prop,
};
static const struct axp_data axp209_data = {
.ccc_scale = 100000,
.ccc_offset = 300000,
.get_max_voltage = axp20x_battery_get_max_voltage,
.set_max_voltage = axp20x_battery_set_max_voltage,
};
static const struct axp_data axp221_data = {
.ccc_scale = 150000,
.ccc_offset = 300000,
.has_fg_valid = true,
.get_max_voltage = axp22x_battery_get_max_voltage,
.set_max_voltage = axp22x_battery_set_max_voltage,
};
static const struct axp_data axp813_data = {
.ccc_scale = 200000,
.ccc_offset = 200000,
.has_fg_valid = true,