mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-14 08:13:56 +08:00
power supply and reset changes for the v5.7 series
Core: * Nothing Drivers: * at91-reset: cleanups, proper handling for sam9x60 * sc27xx, charger-manager: allow building as module * sc27xx: add support to read current charge capacity * axp288: more quirks for weird hardware * misc. fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl6I5QEACgkQ2O7X88g7 +pqAuw//a7kiTyhmRVd06OrYZRJNXjHB2bGqsZhW6skjgfZnIGqd8RAGEEFvfFkf ga9ChtIbWAscZwcud77t9NeNksQEBDjHaekL9LtQ1zuwYHWbpS2fZb89SHrGhk0q tJ/JegZpEWFH+6ZqmXrIxMV32/XSs2prWZRb+8RyuTq6mJE3DOaeL9e9rfkXUW1N s+wWW2a6JXAriFHgPk/BZMM/AUOlYpRaRmF77QvYK3Tfq2x2CeEvzHNr4e6fI9af LycVLkK5kjTXTnGyPn11LhGia8I+YGDB6NXyOEYD9wfnDRA/IlLAOYbuNzmxA+U7 oTm/swY8yHYpiOWM9A+I57c44wUIAp/rxIs6xafz6f1gPScClXKX9SQ0WjQfknCp vS7VZ4WjIjZSFrghND/CUjE0bEtbYNZC25T3NomU2MXuJAUvO83QjSaPG0Q9DzCw jVkrbS3gcq9ePAmZEvVhMh37By5IWzalM2DxRE9zuNxRZ2Px4T+zP6sJ4Wp4LWpK Ufss2WtjzpixYIEc3M3WjptXEaGWynpOnj69iDkPekSTOhuHH69ykiwyM4fA0jGN bttCV19e0HVSGxeXXyOEznwMqeBwv+EMgxEasm71TewEJzu/5caagihLCZuJv/Ji /O+T5uHiONhIHXKZMkYIa3SCcHSCKVBxbADuyCNUEWT7pehm2Uk= =BCS7 -----END PGP SIGNATURE----- Merge tag 'for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset changes from Sebastian Reichel: "Core: - Nothing Drivers: - at91-reset: cleanups, proper handling for sam9x60 - sc27xx, charger-manager: allow building as module - sc27xx: add support to read current charge capacity - axp288: more quirks for weird hardware - misc fixes" * tag 'for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (26 commits) power: reset: sc27xx: Allow the SC27XX poweroff driver building into a module power: reset: sc27xx: Change to use cpu_down() power: reset: sc27xx: Power off the external subsystems' connection power: twl4030: Use scnprintf() for avoiding potential buffer overflow power: supply: bq27xxx_battery: Silence deferred-probe error power: reset: at91-reset: handle nrst async for sam9x60 power: reset: at91-reset: get rid of at91_reset_data power: reset: at91-reset: keep only one reset function power: reset: at91-reset: make at91sam9g45_restart() generic power: reset: at91-reset: introduce ramc_lpr to struct at91_reset power: reset: at91-reset: use r4 as tmp argument power: reset: at91-reset: introduce args member in at91_reset_data power: reset: at91-reset: introduce struct at91_reset_data power: reset: at91-reset: devm_kzalloc() for at91_reset data structure power: reset: at91-reset: pass rstc base address to at91_reset_status() power: reset: at91-reset: convert reset in pointer to struct at91_reset power: reset: at91-reset: add notifier block to struct at91_reset power: reset: at91-reset: add sclk to struct at91_reset power: reset: at91-reset: add ramc_base[] to struct at91_reset power: reset: at91-reset: introduce struct at91_reset ...
This commit is contained in:
commit
a10c9c710f
@ -248,7 +248,7 @@ config SYSCON_REBOOT_MODE
|
||||
action according to the mode.
|
||||
|
||||
config POWER_RESET_SC27XX
|
||||
bool "Spreadtrum SC27xx PMIC power-off driver"
|
||||
tristate "Spreadtrum SC27xx PMIC power-off driver"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
help
|
||||
This driver supports powering off a system through
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */
|
||||
#define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */
|
||||
#define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */
|
||||
#define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */
|
||||
#define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */
|
||||
|
||||
@ -49,105 +50,63 @@ enum reset_type {
|
||||
RESET_TYPE_ULP2 = 8,
|
||||
};
|
||||
|
||||
static void __iomem *at91_ramc_base[2], *at91_rstc_base;
|
||||
static struct clk *sclk;
|
||||
struct at91_reset {
|
||||
void __iomem *rstc_base;
|
||||
void __iomem *ramc_base[2];
|
||||
struct clk *sclk;
|
||||
struct notifier_block nb;
|
||||
u32 args;
|
||||
u32 ramc_lpr;
|
||||
};
|
||||
|
||||
/*
|
||||
* unless the SDRAM is cleanly shutdown before we hit the
|
||||
* reset register it can be left driving the data bus and
|
||||
* killing the chance of a subsequent boot from NAND
|
||||
*/
|
||||
static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
static int at91_reset(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
struct at91_reset *reset = container_of(this, struct at91_reset, nb);
|
||||
|
||||
asm volatile(
|
||||
/* Align to cache lines */
|
||||
".balign 32\n\t"
|
||||
|
||||
/* Disable SDRAM accesses */
|
||||
"str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t"
|
||||
|
||||
/* Power down SDRAM */
|
||||
"str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t"
|
||||
|
||||
/* Reset CPU */
|
||||
"str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"
|
||||
|
||||
"b .\n\t"
|
||||
:
|
||||
: "r" (at91_ramc_base[0]),
|
||||
"r" (at91_rstc_base),
|
||||
"r" (1),
|
||||
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
|
||||
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
asm volatile(
|
||||
/*
|
||||
* Test wether we have a second RAM controller to care
|
||||
* about.
|
||||
*
|
||||
* First, test that we can dereference the virtual address.
|
||||
*/
|
||||
"cmp %1, #0\n\t"
|
||||
"beq 1f\n\t"
|
||||
|
||||
/* Then, test that the RAM controller is enabled */
|
||||
"ldr r0, [%1]\n\t"
|
||||
"cmp r0, #0\n\t"
|
||||
|
||||
/* Align to cache lines */
|
||||
".balign 32\n\t"
|
||||
|
||||
/* Disable SDRAM0 accesses */
|
||||
"1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
|
||||
" tst %0, #0\n\t"
|
||||
" beq 1f\n\t"
|
||||
" str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
|
||||
/* Power down SDRAM0 */
|
||||
" str %4, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
|
||||
" str %4, [%0, %6]\n\t"
|
||||
/* Disable SDRAM1 accesses */
|
||||
"1: tst %1, #0\n\t"
|
||||
" beq 2f\n\t"
|
||||
" strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
|
||||
/* Power down SDRAM1 */
|
||||
" strne %4, [%1, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
|
||||
" strne %4, [%1, %6]\n\t"
|
||||
/* Reset CPU */
|
||||
" str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
|
||||
"2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
|
||||
|
||||
" b .\n\t"
|
||||
:
|
||||
: "r" (at91_ramc_base[0]),
|
||||
"r" (at91_ramc_base[1]),
|
||||
"r" (at91_rstc_base),
|
||||
: "r" (reset->ramc_base[0]),
|
||||
"r" (reset->ramc_base[1]),
|
||||
"r" (reset->rstc_base),
|
||||
"r" (1),
|
||||
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
|
||||
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
|
||||
: "r0");
|
||||
"r" (reset->args),
|
||||
"r" (reset->ramc_lpr)
|
||||
: "r4");
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
|
||||
at91_rstc_base);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int samx7_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void __init at91_reset_status(struct platform_device *pdev)
|
||||
static void __init at91_reset_status(struct platform_device *pdev,
|
||||
void __iomem *base)
|
||||
{
|
||||
const char *reason;
|
||||
u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
|
||||
u32 reg = readl(base + AT91_RSTC_SR);
|
||||
|
||||
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
|
||||
case RESET_TYPE_GENERAL:
|
||||
@ -183,42 +142,68 @@ static void __init at91_reset_status(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_ramc_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-sdramc", },
|
||||
{ .compatible = "atmel,at91sam9g45-ddramc", },
|
||||
{
|
||||
.compatible = "atmel,at91sam9260-sdramc",
|
||||
.data = (void *)AT91_SDRAMC_LPR,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9g45-ddramc",
|
||||
.data = (void *)AT91_DDRSDRC_LPR,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct of_device_id at91_reset_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart },
|
||||
{ .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
|
||||
{ .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
|
||||
{ .compatible = "atmel,samx7-rstc", .data = samx7_restart },
|
||||
{ .compatible = "microchip,sam9x60-rstc", .data = samx7_restart },
|
||||
{
|
||||
.compatible = "atmel,at91sam9260-rstc",
|
||||
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
|
||||
AT91_RSTC_PROCRST),
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9g45-rstc",
|
||||
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
|
||||
AT91_RSTC_PROCRST)
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,sama5d3-rstc",
|
||||
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
|
||||
AT91_RSTC_PROCRST)
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,samx7-rstc",
|
||||
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
|
||||
},
|
||||
{
|
||||
.compatible = "microchip,sam9x60-rstc",
|
||||
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_reset_of_match);
|
||||
|
||||
static struct notifier_block at91_restart_nb = {
|
||||
.priority = 192,
|
||||
};
|
||||
|
||||
static int __init at91_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct at91_reset *reset;
|
||||
struct device_node *np;
|
||||
int ret, idx = 0;
|
||||
|
||||
at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
|
||||
if (!at91_rstc_base) {
|
||||
reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
|
||||
if (!reset)
|
||||
return -ENOMEM;
|
||||
|
||||
reset->rstc_base = of_iomap(pdev->dev.of_node, 0);
|
||||
if (!reset->rstc_base) {
|
||||
dev_err(&pdev->dev, "Could not map reset controller address\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
|
||||
/* we need to shutdown the ddr controller, so get ramc base */
|
||||
for_each_matching_node(np, at91_ramc_of_match) {
|
||||
at91_ramc_base[idx] = of_iomap(np, 0);
|
||||
if (!at91_ramc_base[idx]) {
|
||||
for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
|
||||
reset->ramc_lpr = (u32)match->data;
|
||||
reset->ramc_base[idx] = of_iomap(np, 0);
|
||||
if (!reset->ramc_base[idx]) {
|
||||
dev_err(&pdev->dev, "Could not map ram controller address\n");
|
||||
of_node_put(np);
|
||||
return -ENODEV;
|
||||
@ -228,33 +213,46 @@ static int __init at91_reset_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
|
||||
at91_restart_nb.notifier_call = match->data;
|
||||
reset->nb.notifier_call = at91_reset;
|
||||
reset->nb.priority = 192;
|
||||
reset->args = (u32)match->data;
|
||||
|
||||
sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sclk))
|
||||
return PTR_ERR(sclk);
|
||||
reset->sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(reset->sclk))
|
||||
return PTR_ERR(reset->sclk);
|
||||
|
||||
ret = clk_prepare_enable(sclk);
|
||||
ret = clk_prepare_enable(reset->sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = register_restart_handler(&at91_restart_nb);
|
||||
platform_set_drvdata(pdev, reset);
|
||||
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) {
|
||||
u32 val = readl(reset->rstc_base + AT91_RSTC_MR);
|
||||
|
||||
writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val,
|
||||
reset->rstc_base + AT91_RSTC_MR);
|
||||
}
|
||||
|
||||
ret = register_restart_handler(&reset->nb);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sclk);
|
||||
clk_disable_unprepare(reset->sclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
at91_reset_status(pdev);
|
||||
at91_reset_status(pdev, reset->rstc_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit at91_reset_remove(struct platform_device *pdev)
|
||||
{
|
||||
unregister_restart_handler(&at91_restart_nb);
|
||||
clk_disable_unprepare(sclk);
|
||||
struct at91_reset *reset = platform_get_drvdata(pdev);
|
||||
|
||||
unregister_restart_handler(&reset->nb);
|
||||
clk_disable_unprepare(reset->sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -13,6 +14,8 @@
|
||||
|
||||
#define SC27XX_PWR_PD_HW 0xc2c
|
||||
#define SC27XX_PWR_OFF_EN BIT(0)
|
||||
#define SC27XX_SLP_CTRL 0xdf0
|
||||
#define SC27XX_LDO_XTL_EN BIT(3)
|
||||
|
||||
static struct regmap *regmap;
|
||||
|
||||
@ -27,10 +30,13 @@ static struct regmap *regmap;
|
||||
*/
|
||||
static void sc27xx_poweroff_shutdown(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP_SMP
|
||||
int cpu = smp_processor_id();
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int cpu;
|
||||
|
||||
freeze_secondary_cpus(cpu);
|
||||
for_each_online_cpu(cpu) {
|
||||
if (cpu != smp_processor_id())
|
||||
remove_cpu(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -40,6 +46,9 @@ static struct syscore_ops poweroff_syscore_ops = {
|
||||
|
||||
static void sc27xx_poweroff_do_poweroff(void)
|
||||
{
|
||||
/* Disable the external subsys connection's power firstly */
|
||||
regmap_write(regmap, SC27XX_SLP_CTRL, SC27XX_LDO_XTL_EN);
|
||||
|
||||
regmap_write(regmap, SC27XX_PWR_PD_HW, SC27XX_PWR_OFF_EN);
|
||||
}
|
||||
|
||||
@ -63,4 +72,8 @@ static struct platform_driver sc27xx_poweroff_driver = {
|
||||
.name = "sc27xx-poweroff",
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(sc27xx_poweroff_driver);
|
||||
module_platform_driver(sc27xx_poweroff_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Power off driver for SC27XX PMIC Device");
|
||||
MODULE_AUTHOR("Baolin Wang <baolin.wang@unisoc.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -480,7 +480,7 @@ config CHARGER_GPIO
|
||||
called gpio-charger.
|
||||
|
||||
config CHARGER_MANAGER
|
||||
bool "Battery charger manager for multiple chargers"
|
||||
tristate "Battery charger manager for multiple chargers"
|
||||
depends on REGULATOR
|
||||
select EXTCON
|
||||
help
|
||||
|
@ -404,7 +404,7 @@ disable_otp:
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_power_supply_changed - a wrapper with local extentions for
|
||||
* ab8500_power_supply_changed - a wrapper with local extensions for
|
||||
* power_supply_changed
|
||||
* @di: pointer to the ab8500_charger structure
|
||||
* @psy: pointer to power_supply_that have changed.
|
||||
@ -683,7 +683,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
|
||||
/*
|
||||
* Platform only supports USB 2.0.
|
||||
* This means that charging current from USB source
|
||||
* is maximum 500 mA. Every occurence of USB_STAT_*_HOST_*
|
||||
* is maximum 500 mA. Every occurrence of USB_STAT_*_HOST_*
|
||||
* should set USB_CH_IP_CUR_LVL_0P5.
|
||||
*/
|
||||
|
||||
@ -1379,13 +1379,13 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
|
||||
|
||||
/*
|
||||
* Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
|
||||
* will be triggered everytime we enable the VDD ADC supply.
|
||||
* will be triggered every time we enable the VDD ADC supply.
|
||||
* This will turn off charging for a short while.
|
||||
* It can be avoided by having the supply on when
|
||||
* there is a charger enabled. Normally the VDD ADC supply
|
||||
* is enabled everytime a GPADC conversion is triggered. We will
|
||||
* force it to be enabled from this driver to have
|
||||
* the GPADC module independant of the AB8500 chargers
|
||||
* is enabled every time a GPADC conversion is triggered.
|
||||
* We will force it to be enabled from this driver to have
|
||||
* the GPADC module independent of the AB8500 chargers
|
||||
*/
|
||||
if (!di->vddadc_en_ac) {
|
||||
ret = regulator_enable(di->regu);
|
||||
@ -1455,7 +1455,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
|
||||
if (is_ab8500_1p1_or_earlier(di->parent)) {
|
||||
/*
|
||||
* For ABB revision 1.0 and 1.1 there is a bug in the
|
||||
* watchdog logic. That means we have to continously
|
||||
* watchdog logic. That means we have to continuously
|
||||
* kick the charger watchdog even when no charger is
|
||||
* connected. This is only valid once the AC charger
|
||||
* has been enabled. This is a bug that is not handled
|
||||
@ -1552,13 +1552,13 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
|
||||
|
||||
/*
|
||||
* Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
|
||||
* will be triggered everytime we enable the VDD ADC supply.
|
||||
* will be triggered every time we enable the VDD ADC supply.
|
||||
* This will turn off charging for a short while.
|
||||
* It can be avoided by having the supply on when
|
||||
* there is a charger enabled. Normally the VDD ADC supply
|
||||
* is enabled everytime a GPADC conversion is triggered. We will
|
||||
* force it to be enabled from this driver to have
|
||||
* the GPADC module independant of the AB8500 chargers
|
||||
* is enabled every time a GPADC conversion is triggered.
|
||||
* We will force it to be enabled from this driver to have
|
||||
* the GPADC module independent of the AB8500 chargers
|
||||
*/
|
||||
if (!di->vddadc_en_usb) {
|
||||
ret = regulator_enable(di->regu);
|
||||
@ -1582,7 +1582,10 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* ChVoltLevel: max voltage upto which battery can be charged */
|
||||
/*
|
||||
* ChVoltLevel: max voltage up to which battery can be
|
||||
* charged
|
||||
*/
|
||||
ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
|
||||
AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
|
||||
if (ret) {
|
||||
@ -2014,7 +2017,7 @@ static void ab8500_charger_check_hw_failure_work(struct work_struct *work)
|
||||
* Work queue function for kicking the charger watchdog.
|
||||
*
|
||||
* For ABB revision 1.0 and 1.1 there is a bug in the watchdog
|
||||
* logic. That means we have to continously kick the charger
|
||||
* logic. That means we have to continuously kick the charger
|
||||
* watchdog even when no charger is connected. This is only
|
||||
* valid once the AC charger has been enabled. This is
|
||||
* a bug that is not handled by the algorithm and the
|
||||
@ -2262,7 +2265,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
|
||||
* Some chargers that breaks the USB spec is
|
||||
* identified as invalid by AB8500 and it refuse
|
||||
* to start the charging process. but by jumping
|
||||
* thru a few hoops it can be forced to start.
|
||||
* through a few hoops it can be forced to start.
|
||||
*/
|
||||
if (is_ab8500(di->parent))
|
||||
ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
|
||||
@ -3214,7 +3217,7 @@ static int ab8500_charger_resume(struct platform_device *pdev)
|
||||
|
||||
/*
|
||||
* For ABB revision 1.0 and 1.1 there is a bug in the watchdog
|
||||
* logic. That means we have to continously kick the charger
|
||||
* logic. That means we have to continuously kick the charger
|
||||
* watchdog even when no charger is connected. This is only
|
||||
* valid once the AC charger has been enabled. This is
|
||||
* a bug that is not handled by the algorithm and the
|
||||
@ -3483,7 +3486,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
||||
|
||||
/*
|
||||
* For ABB revision 1.0 and 1.1 there is a bug in the watchdog
|
||||
* logic. That means we have to continously kick the charger
|
||||
* logic. That means we have to continuously kick the charger
|
||||
* watchdog even when no charger is connected. This is only
|
||||
* valid once the AC charger has been enabled. This is
|
||||
* a bug that is not handled by the algorithm and the
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#define PS_STAT_VBUS_TRIGGER BIT(0)
|
||||
#define PS_STAT_BAT_CHRG_DIR BIT(2)
|
||||
@ -545,6 +546,49 @@ out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* The HP Pavilion x2 10 series comes in a number of variants:
|
||||
* Bay Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "815D"
|
||||
* Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E"
|
||||
* Cherry Trail SoC + TI PMIC, DMI_BOARD_NAME: "827C" or "82F4"
|
||||
*
|
||||
* The variants with the AXP288 PMIC are all kinds of special:
|
||||
*
|
||||
* 1. All variants use a Type-C connector which the AXP288 does not support, so
|
||||
* when using a Type-C charger it is not recognized. Unlike most AXP288 devices,
|
||||
* this model actually has mostly working ACPI AC / Battery code, the ACPI code
|
||||
* "solves" this by simply setting the input_current_limit to 3A.
|
||||
* There are still some issues with the ACPI code, so we use this native driver,
|
||||
* and to solve the charging not working (500mA is not enough) issue we hardcode
|
||||
* the 3A input_current_limit like the ACPI code does.
|
||||
*
|
||||
* 2. If no charger is connected the machine boots with the vbus-path disabled.
|
||||
* Normally this is done when a 5V boost converter is active to avoid the PMIC
|
||||
* trying to charge from the 5V boost converter's output. This is done when
|
||||
* an OTG host cable is inserted and the ID pin on the micro-B receptacle is
|
||||
* pulled low and the ID pin has an ACPI event handler associated with it
|
||||
* which re-enables the vbus-path when the ID pin is pulled high when the
|
||||
* OTG host cable is removed. The Type-C connector has no ID pin, there is
|
||||
* no ID pin handler and there appears to be no 5V boost converter, so we
|
||||
* end up not charging because the vbus-path is disabled, until we unplug
|
||||
* the charger which automatically clears the vbus-path disable bit and then
|
||||
* on the second plug-in of the adapter we start charging. To solve the not
|
||||
* charging on first charger plugin we unconditionally enable the vbus-path at
|
||||
* probe on this model, which is safe since there is no 5V boost converter.
|
||||
*/
|
||||
static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = {
|
||||
{
|
||||
/*
|
||||
* Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry
|
||||
* Trail model has "HP", so we only match on product_name.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
static void axp288_charger_extcon_evt_worker(struct work_struct *work)
|
||||
{
|
||||
struct axp288_chrg_info *info =
|
||||
@ -568,7 +612,11 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Determine cable/charger type */
|
||||
if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
|
||||
if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
|
||||
/* See comment above axp288_hp_x2_dmi_ids declaration */
|
||||
dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n");
|
||||
current_limit = 3000000;
|
||||
} else if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) {
|
||||
dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n");
|
||||
current_limit = 500000;
|
||||
} else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) {
|
||||
@ -685,6 +733,13 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dmi_check_system(axp288_hp_x2_dmi_ids)) {
|
||||
/* See comment above axp288_hp_x2_dmi_ids declaration */
|
||||
ret = axp288_charger_vbus_path_select(info, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read current charge voltage and current limit */
|
||||
ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
|
||||
if (ret < 0) {
|
||||
|
@ -706,14 +706,14 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
|
||||
{
|
||||
/* Intel Cherry Trail Compute Stick, Windows version */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "STK1AW32SC"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Intel Cherry Trail Compute Stick, version without an OS */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "STK1A32SC"),
|
||||
},
|
||||
},
|
||||
|
@ -1885,7 +1885,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
||||
|
||||
di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg);
|
||||
if (IS_ERR(di->bat)) {
|
||||
dev_err(di->dev, "failed to register battery\n");
|
||||
if (PTR_ERR(di->bat) == -EPROBE_DEFER)
|
||||
dev_dbg(di->dev, "failed to register battery, deferring probe\n");
|
||||
else
|
||||
dev_err(di->dev, "failed to register battery\n");
|
||||
return PTR_ERR(di->bat);
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,8 @@ static int ingenic_battery_probe(struct platform_device *pdev)
|
||||
|
||||
bat->battery = devm_power_supply_register(dev, desc, &psy_cfg);
|
||||
if (IS_ERR(bat->battery)) {
|
||||
dev_err(dev, "Unable to register battery\n");
|
||||
if (PTR_ERR(bat->battery) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Unable to register battery\n");
|
||||
return PTR_ERR(bat->battery);
|
||||
}
|
||||
|
||||
|
@ -614,6 +614,17 @@ static int sc27xx_fgu_get_property(struct power_supply *psy,
|
||||
val->intval = data->total_cap * 1000;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
ret = sc27xx_fgu_get_clbcnt(data, &value);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
value = DIV_ROUND_CLOSEST(value * 10,
|
||||
36 * SC27XX_FGU_SAMPLE_HZ);
|
||||
val->intval = sc27xx_fgu_adc_to_current(data, value);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@ -682,6 +693,7 @@ static enum power_supply_property sc27xx_fgu_props[] = {
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CALIBRATE,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW
|
||||
};
|
||||
|
||||
static const struct power_supply_desc sc27xx_fgu_desc = {
|
||||
|
@ -726,10 +726,10 @@ twl4030_bci_mode_show(struct device *dev,
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(modes); i++)
|
||||
if (mode == i)
|
||||
len += snprintf(buf+len, PAGE_SIZE-len,
|
||||
len += scnprintf(buf+len, PAGE_SIZE-len,
|
||||
"[%s] ", modes[i]);
|
||||
else
|
||||
len += snprintf(buf+len, PAGE_SIZE-len,
|
||||
len += scnprintf(buf+len, PAGE_SIZE-len,
|
||||
"%s ", modes[i]);
|
||||
buf[len-1] = '\n';
|
||||
return len;
|
||||
|
@ -248,7 +248,7 @@ struct charger_manager {
|
||||
u64 charging_end_time;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CHARGER_MANAGER
|
||||
#if IS_ENABLED(CONFIG_CHARGER_MANAGER)
|
||||
extern void cm_notify_event(struct power_supply *psy,
|
||||
enum cm_event_types type, char *msg);
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user