power supply and reset changes for the v5.11 series
battery/charger driver changes: * collie_battery, generic-adc-battery, s3c-adc-battery: convert to GPIO descriptors (incl. ARM board files) * misc. cleanup and fixes reset drivers: * new poweroff driver for force disabling a regulator * Use printk format symbol resolver * ocelot: add support for Luton and Jaguar2 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl/dCdYACgkQ2O7X88g7 +pqv1w//cdmcED3JyxWRNlqNigDhKGj4rHCCTn8qulnGjzt61XqVHt+l8hfANI0h PquhiXnPHJLzo2BtltpofSqsLj9ImlnMNztRw1P6yRBKgldaKiwu+ZYN54JkgBuo nAS9pJNzNUaFMW/D1ISt86794YfYucf08WB5eWW5c866kPm78lF7T0cPbmUjPAaU +nbA0R2b6vFfIqAJkaptMmrmY8AfJYB1lXAXPPPY7eqLXY15EkJxbBoxuQ2omYpt abcDDw1TThczgap5Ds2LAuZlvzvinKCIoa46Q566rRuIKa6R42Is4Znz6mhiroQf EfIH9iiXfSZwqyiK2Lp+NnZL0BJqqdPyKV31XbDSamduh7kXgYr/g1bIhv814NZ7 AGV0yT3vuiZh/07mJTWE+V5tFjxL6C2IrsD0w5fm9Fsjvji5WM0Iq0ZzPcq62RjK zGIuUmj4ndNlA2l07BWEX8+Wa1zj+kHNbpEKqFQ9oNNWuBznJ3Vu6nZ616cKvycN 8zxT4Emazie9N0uzgpvxRy6DV41yix43GMEnb8EKXclKapYlZiwQqIbSxFKerGPR GEcYQvy+EdES4Xzq7jIhklU6QdWfMErOTJoiLthoyzaa7t8ZsgLIaj9vSrnh5sEE ipFDuk8MstYO7808FwlMKgbjMg1v0JKL3FOtgQvqrE5StaG1UYc= =SnH7 -----END PGP SIGNATURE----- Merge tag 'for-v5.11' 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: - collie_battery, generic-adc-battery, s3c-adc-battery: convert to GPIO descriptors (incl ARM board files) - misc cleanup and fixes Reset drivers: - new poweroff driver for force disabling a regulator - use printk format symbol resolver - ocelot: add support for Luton and Jaguar2" * tag 'for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (31 commits) power: supply: Fix a typo in warning message Documentation: DT: binding documentation for regulator-poweroff power: reset: new driver regulator-poweroff power: supply: ab8500: Use dev_err_probe() for IIO channels power: supply: ab8500_fg: Request all IRQs as threaded power: supply: ab8500_charger: Oneshot threaded IRQs power: supply: ab8500: Convert to dev_pm_ops power: supply: ab8500: Use local helper power: supply: wm831x_power: remove unneeded break power: supply: bq24735: Drop unused include power: supply: bq24190_charger: Drop unused include power: supply: generic-adc-battery: Use GPIO descriptors power: supply: collie_battery: Convert to GPIO descriptors power: supply: bq24190_charger: fix reference leak power: supply: s3c-adc-battery: Convert to GPIO descriptors power: reset: Use printk format symbol resolver power: supply: axp20x_usb_power: Use power efficient workqueue for debounce power: supply: axp20x_usb_power: fix typo power: supply: max8997-charger: Improve getting charger status power: supply: max8997-charger: Fix platform data retrieval ...
This commit is contained in:
commit
11c336526e
|
@ -7,7 +7,9 @@ The reset registers are both present in the MSCC vcoreiii MIPS and
|
|||
microchip Sparx5 armv8 SoC's.
|
||||
|
||||
Required Properties:
|
||||
- compatible: "mscc,ocelot-chip-reset" or "microchip,sparx5-chip-reset"
|
||||
|
||||
- compatible: "mscc,ocelot-chip-reset", "mscc,luton-chip-reset",
|
||||
"mscc,jaguar2-chip-reset" or "microchip,sparx5-chip-reset"
|
||||
|
||||
Example:
|
||||
reset@1070008 {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/reset/regulator-poweroff.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Force-disable power regulator to turn the power off.
|
||||
|
||||
maintainers:
|
||||
- Michael Klein <michael@fossekall.de>
|
||||
|
||||
description: |
|
||||
When the power-off handler is called, a power regulator is disabled by
|
||||
calling regulator_force_disable(). If the power is still on and the
|
||||
CPU still running after a 3000ms delay, a warning is emitted.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: "regulator-poweroff"
|
||||
|
||||
cpu-supply:
|
||||
description:
|
||||
regulator to disable on power-down
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- cpu-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
regulator-poweroff {
|
||||
compatible = "regulator-poweroff";
|
||||
cpu-supply = <®_vcc1v2>;
|
||||
};
|
||||
...
|
|
@ -297,6 +297,15 @@ static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
|
|||
{ .volt = 3841, .cur = 0, .level = 0},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table h1940_bat_gpio_table = {
|
||||
.dev_id = "s3c-adc-battery",
|
||||
.table = {
|
||||
/* Charge status S3C2410_GPF(3) */
|
||||
GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static int h1940_bat_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -330,8 +339,6 @@ static struct s3c_adc_bat_pdata h1940_bat_cfg = {
|
|||
.exit = h1940_bat_exit,
|
||||
.enable_charger = h1940_enable_charger,
|
||||
.disable_charger = h1940_disable_charger,
|
||||
.gpio_charge_finished = S3C2410_GPF(3),
|
||||
.gpio_inverted = 1,
|
||||
.lut_noac = bat_lut_noac,
|
||||
.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
|
||||
.lut_acin = bat_lut_acin,
|
||||
|
@ -720,6 +727,7 @@ static void __init h1940_init(void)
|
|||
s3c24xx_fb_set_platdata(&h1940_fb_info);
|
||||
gpiod_add_lookup_table(&h1940_mmc_gpio_table);
|
||||
gpiod_add_lookup_table(&h1940_audio_gpio_table);
|
||||
gpiod_add_lookup_table(&h1940_bat_gpio_table);
|
||||
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
|
||||
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
|
||||
S3C_GPIO_PULL_NONE);
|
||||
|
|
|
@ -206,6 +206,15 @@ static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
|
|||
{ .volt = 3820, .cur = 0, .level = 0},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table rx1950_bat_gpio_table = {
|
||||
.dev_id = "s3c-adc-battery",
|
||||
.table = {
|
||||
/* Charge status S3C2410_GPF(3) */
|
||||
GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static int rx1950_bat_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -331,7 +340,6 @@ static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
|
|||
.exit = rx1950_bat_exit,
|
||||
.enable_charger = rx1950_enable_charger,
|
||||
.disable_charger = rx1950_disable_charger,
|
||||
.gpio_charge_finished = S3C2410_GPF(3),
|
||||
.lut_noac = bat_lut_noac,
|
||||
.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
|
||||
.lut_acin = bat_lut_acin,
|
||||
|
@ -840,6 +848,7 @@ static void __init rx1950_init_machine(void)
|
|||
|
||||
pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup));
|
||||
gpiod_add_lookup_table(&rx1950_audio_gpio_table);
|
||||
gpiod_add_lookup_table(&rx1950_bat_gpio_table);
|
||||
/* Configure the I2S pins (GPE0...GPE4) in correct mode */
|
||||
s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
|
||||
S3C_GPIO_PULL_NONE);
|
||||
|
|
|
@ -98,6 +98,26 @@ static struct mcp_plat_data collie_mcp_data = {
|
|||
.codec_pdata = &collie_ucb1x00_data,
|
||||
};
|
||||
|
||||
/* Battery management GPIOs */
|
||||
static struct gpiod_lookup_table collie_battery_gpiod_table = {
|
||||
/* the MCP codec mcp0 has the ucb1x00 as attached device */
|
||||
.dev_id = "ucb1x00",
|
||||
.table = {
|
||||
/* This is found on the main GPIO on the SA1100 */
|
||||
GPIO_LOOKUP("gpio", COLLIE_GPIO_CO,
|
||||
"main battery full", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("gpio", COLLIE_GPIO_MAIN_BAT_LOW,
|
||||
"main battery low", GPIO_ACTIVE_HIGH),
|
||||
/*
|
||||
* This is GPIO 0 on the Scoop expander, which is registered
|
||||
* from common/scoop.c with this gpio chip label.
|
||||
*/
|
||||
GPIO_LOOKUP("sharp-scoop", 0,
|
||||
"main charge on", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static int collie_ir_startup(struct device *dev)
|
||||
{
|
||||
int rc = gpio_request(COLLIE_GPIO_IR_ON, "IrDA");
|
||||
|
@ -395,6 +415,7 @@ static void __init collie_init(void)
|
|||
platform_scoop_config = &collie_pcmcia_config;
|
||||
|
||||
gpiod_add_lookup_table(&collie_power_gpiod_table);
|
||||
gpiod_add_lookup_table(&collie_battery_gpiod_table);
|
||||
|
||||
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
if (ret) {
|
||||
|
|
|
@ -177,6 +177,13 @@ config POWER_RESET_QNAP
|
|||
|
||||
Say Y if you have a QNAP NAS.
|
||||
|
||||
config POWER_RESET_REGULATOR
|
||||
bool "Regulator subsystem power-off driver"
|
||||
depends on OF && REGULATOR
|
||||
help
|
||||
This driver supports turning off your board by disabling a
|
||||
power regulator defined in the devicetree.
|
||||
|
||||
config POWER_RESET_RESTART
|
||||
bool "Restart power-off driver"
|
||||
help
|
||||
|
|
|
@ -19,6 +19,7 @@ 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
|
||||
obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
|
||||
|
|
|
@ -29,6 +29,8 @@ struct ocelot_reset_context {
|
|||
struct notifier_block restart_handler;
|
||||
};
|
||||
|
||||
#define BIT_OFF_INVALID 32
|
||||
|
||||
#define SOFT_CHIP_RST BIT(0)
|
||||
|
||||
#define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
|
||||
|
@ -50,9 +52,11 @@ static int ocelot_restart_handle(struct notifier_block *this,
|
|||
ctx->props->vcore_protect, 0);
|
||||
|
||||
/* Make the SI back to boot mode */
|
||||
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
|
||||
IF_SI_OWNER_MASK << if_si_owner_bit,
|
||||
IF_SI_OWNER_SIBM << if_si_owner_bit);
|
||||
if (if_si_owner_bit != BIT_OFF_INVALID)
|
||||
regmap_update_bits(ctx->cpu_ctrl,
|
||||
ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
|
||||
IF_SI_OWNER_MASK << if_si_owner_bit,
|
||||
IF_SI_OWNER_SIBM << if_si_owner_bit);
|
||||
|
||||
pr_emerg("Resetting SoC\n");
|
||||
|
||||
|
@ -96,6 +100,20 @@ static int ocelot_reset_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static const struct reset_props reset_props_jaguar2 = {
|
||||
.syscon = "mscc,ocelot-cpu-syscon",
|
||||
.protect_reg = 0x20,
|
||||
.vcore_protect = BIT(2),
|
||||
.if_si_owner_bit = 6,
|
||||
};
|
||||
|
||||
static const struct reset_props reset_props_luton = {
|
||||
.syscon = "mscc,ocelot-cpu-syscon",
|
||||
.protect_reg = 0x20,
|
||||
.vcore_protect = BIT(2),
|
||||
.if_si_owner_bit = BIT_OFF_INVALID, /* n/a */
|
||||
};
|
||||
|
||||
static const struct reset_props reset_props_ocelot = {
|
||||
.syscon = "mscc,ocelot-cpu-syscon",
|
||||
.protect_reg = 0x20,
|
||||
|
@ -112,6 +130,12 @@ static const struct reset_props reset_props_sparx5 = {
|
|||
|
||||
static const struct of_device_id ocelot_reset_of_match[] = {
|
||||
{
|
||||
.compatible = "mscc,jaguar2-chip-reset",
|
||||
.data = &reset_props_jaguar2
|
||||
}, {
|
||||
.compatible = "mscc,luton-chip-reset",
|
||||
.data = &reset_props_luton
|
||||
}, {
|
||||
.compatible = "mscc,ocelot-chip-reset",
|
||||
.data = &reset_props_ocelot
|
||||
}, {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
|
@ -75,7 +74,6 @@ static int qnap_power_off_probe(struct platform_device *pdev)
|
|||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
char symname[KSYM_NAME_LEN];
|
||||
|
||||
const struct of_device_id *match =
|
||||
of_match_node(qnap_power_off_of_match_table, np);
|
||||
|
@ -104,10 +102,8 @@ static int qnap_power_off_probe(struct platform_device *pdev)
|
|||
|
||||
/* Check that nothing else has already setup a handler */
|
||||
if (pm_power_off) {
|
||||
lookup_symbol_name((ulong)pm_power_off, symname);
|
||||
dev_err(&pdev->dev,
|
||||
"pm_power_off already claimed %p %s",
|
||||
pm_power_off, symname);
|
||||
dev_err(&pdev->dev, "pm_power_off already claimed for %ps",
|
||||
pm_power_off);
|
||||
return -EBUSY;
|
||||
}
|
||||
pm_power_off = qnap_power_off;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Force-disables a regulator to power down a device
|
||||
*
|
||||
* Michael Klein <michael@fossekall.de>
|
||||
*
|
||||
* Copyright (C) 2020 Michael Klein
|
||||
*
|
||||
* Based on the gpio-poweroff driver.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define TIMEOUT_MS 3000
|
||||
|
||||
/*
|
||||
* Hold configuration here, cannot be more than one instance of the driver
|
||||
* since pm_power_off itself is global.
|
||||
*/
|
||||
static struct regulator *cpu_regulator;
|
||||
|
||||
static void regulator_poweroff_do_poweroff(void)
|
||||
{
|
||||
if (cpu_regulator && regulator_is_enabled(cpu_regulator))
|
||||
regulator_force_disable(cpu_regulator);
|
||||
|
||||
/* give it some time */
|
||||
mdelay(TIMEOUT_MS);
|
||||
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static int regulator_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
/* If a pm_power_off function has already been added, leave it alone */
|
||||
if (pm_power_off != NULL) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s: pm_power_off function already registered\n",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cpu_regulator = devm_regulator_get(&pdev->dev, "cpu");
|
||||
if (IS_ERR(cpu_regulator))
|
||||
return PTR_ERR(cpu_regulator);
|
||||
|
||||
pm_power_off = ®ulator_poweroff_do_poweroff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regulator_poweroff_remove(__maybe_unused struct platform_device *pdev)
|
||||
{
|
||||
if (pm_power_off == ®ulator_poweroff_do_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_regulator_poweroff_match[] = {
|
||||
{ .compatible = "regulator-poweroff", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver regulator_poweroff_driver = {
|
||||
.probe = regulator_poweroff_probe,
|
||||
.remove = regulator_poweroff_remove,
|
||||
.driver = {
|
||||
.name = "poweroff-regulator",
|
||||
.of_match_table = of_regulator_poweroff_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(regulator_poweroff_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Klein <michael@fossekall.de>");
|
||||
MODULE_DESCRIPTION("Regulator poweroff driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:poweroff-regulator");
|
|
@ -6,7 +6,6 @@
|
|||
* Author: Moritz Fischer <moritz.fischer@ettus.com>
|
||||
*/
|
||||
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/notifier.h>
|
||||
|
@ -34,7 +33,6 @@ static void syscon_poweroff(void)
|
|||
|
||||
static int syscon_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
char symname[KSYM_NAME_LEN];
|
||||
int mask_err, value_err;
|
||||
|
||||
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
|
||||
|
@ -65,10 +63,8 @@ static int syscon_poweroff_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (pm_power_off) {
|
||||
lookup_symbol_name((ulong)pm_power_off, symname);
|
||||
dev_err(&pdev->dev,
|
||||
"pm_power_off already claimed %p %s",
|
||||
pm_power_off, symname);
|
||||
dev_err(&pdev->dev, "pm_power_off already claimed for %ps",
|
||||
pm_power_off);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
|
|
@ -936,29 +936,23 @@ static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = {
|
|||
{"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int ab8500_btemp_resume(struct platform_device *pdev)
|
||||
static int __maybe_unused ab8500_btemp_resume(struct device *dev)
|
||||
{
|
||||
struct ab8500_btemp *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_btemp *di = dev_get_drvdata(dev);
|
||||
|
||||
ab8500_btemp_periodic(di, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_btemp_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
|
||||
{
|
||||
struct ab8500_btemp *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_btemp *di = dev_get_drvdata(dev);
|
||||
|
||||
ab8500_btemp_periodic(di, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ab8500_btemp_suspend NULL
|
||||
#define ab8500_btemp_resume NULL
|
||||
#endif
|
||||
|
||||
static int ab8500_btemp_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -999,48 +993,45 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
struct device_node *np = pdev->dev.of_node;
|
||||
struct abx500_bm_data *plat = pdev->dev.platform_data;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ab8500_btemp *di;
|
||||
int irq, i, ret = 0;
|
||||
u8 val;
|
||||
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
|
||||
di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev, "no battery management data supplied\n");
|
||||
dev_err(dev, "no battery management data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
di->bm = plat;
|
||||
|
||||
if (np) {
|
||||
ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
|
||||
ret = ab8500_bm_of_probe(dev, np, di->bm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get battery information\n");
|
||||
dev_err(dev, "failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->dev = dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
/* Get ADC channels */
|
||||
di->btemp_ball = devm_iio_channel_get(&pdev->dev, "btemp_ball");
|
||||
di->btemp_ball = devm_iio_channel_get(dev, "btemp_ball");
|
||||
if (IS_ERR(di->btemp_ball)) {
|
||||
if (PTR_ERR(di->btemp_ball) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get BTEMP BALL ADC channel\n");
|
||||
return PTR_ERR(di->btemp_ball);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->btemp_ball),
|
||||
"failed to get BTEMP BALL ADC channel\n");
|
||||
return ret;
|
||||
}
|
||||
di->bat_ctrl = devm_iio_channel_get(&pdev->dev, "bat_ctrl");
|
||||
di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
|
||||
if (IS_ERR(di->bat_ctrl)) {
|
||||
if (PTR_ERR(di->bat_ctrl) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get BAT CTRL ADC channel\n");
|
||||
return PTR_ERR(di->bat_ctrl);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->bat_ctrl),
|
||||
"failed to get BAT CTRL ADC channel\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
di->initialized = false;
|
||||
|
@ -1053,7 +1044,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
di->btemp_wq =
|
||||
alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
|
||||
if (di->btemp_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
dev_err(dev, "failed to create work queue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1065,10 +1056,10 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
|
||||
di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
|
||||
|
||||
ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
|
||||
ret = abx500_get_register_interruptible(dev, AB8500_CHARGER,
|
||||
AB8500_BTEMP_HIGH_TH, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
|
||||
dev_err(dev, "%s ab8500 read failed\n", __func__);
|
||||
goto free_btemp_wq;
|
||||
}
|
||||
switch (val) {
|
||||
|
@ -1088,10 +1079,10 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Register BTEMP power supply class */
|
||||
di->btemp_psy = power_supply_register(di->dev, &ab8500_btemp_desc,
|
||||
di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(di->btemp_psy)) {
|
||||
dev_err(di->dev, "failed to register BTEMP psy\n");
|
||||
dev_err(dev, "failed to register BTEMP psy\n");
|
||||
ret = PTR_ERR(di->btemp_psy);
|
||||
goto free_btemp_wq;
|
||||
}
|
||||
|
@ -1105,15 +1096,15 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
ab8500_btemp_irq[i].name, di);
|
||||
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
|
||||
dev_err(dev, "failed to request %s IRQ %d: %d\n"
|
||||
, ab8500_btemp_irq[i].name, irq, ret);
|
||||
goto free_irq;
|
||||
}
|
||||
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
|
||||
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
|
||||
ab8500_btemp_irq[i].name, irq, ret);
|
||||
}
|
||||
|
||||
|
@ -1138,6 +1129,8 @@ free_btemp_wq:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
|
||||
|
||||
static const struct of_device_id ab8500_btemp_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-btemp", },
|
||||
{ },
|
||||
|
@ -1146,11 +1139,10 @@ static const struct of_device_id ab8500_btemp_match[] = {
|
|||
static struct platform_driver ab8500_btemp_driver = {
|
||||
.probe = ab8500_btemp_probe,
|
||||
.remove = ab8500_btemp_remove,
|
||||
.suspend = ab8500_btemp_suspend,
|
||||
.resume = ab8500_btemp_resume,
|
||||
.driver = {
|
||||
.name = "ab8500-btemp",
|
||||
.of_match_table = ab8500_btemp_match,
|
||||
.pm = &ab8500_btemp_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -3209,11 +3209,10 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
|
|||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int ab8500_charger_resume(struct platform_device *pdev)
|
||||
static int __maybe_unused ab8500_charger_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct ab8500_charger *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_charger *di = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* For ABB revision 1.0 and 1.1 there is a bug in the watchdog
|
||||
|
@ -3247,10 +3246,9 @@ static int ab8500_charger_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_charger_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int __maybe_unused ab8500_charger_suspend(struct device *dev)
|
||||
{
|
||||
struct ab8500_charger *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_charger *di = dev_get_drvdata(dev);
|
||||
|
||||
/* Cancel any pending jobs */
|
||||
cancel_delayed_work(&di->check_hw_failure_work);
|
||||
|
@ -3272,10 +3270,6 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ab8500_charger_suspend NULL
|
||||
#define ab8500_charger_resume NULL
|
||||
#endif
|
||||
|
||||
static struct notifier_block charger_nb = {
|
||||
.notifier_call = ab8500_external_charger_prepare,
|
||||
|
@ -3354,23 +3348,22 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {};
|
||||
struct ab8500_charger *di;
|
||||
int irq, i, charger_status, ret = 0, ch_stat;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
|
||||
di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev, "no battery management data supplied\n");
|
||||
dev_err(dev, "no battery management data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
di->bm = plat;
|
||||
|
||||
if (np) {
|
||||
ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
|
||||
ret = ab8500_bm_of_probe(dev, np, di->bm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get battery information\n");
|
||||
dev_err(dev, "failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
|
||||
|
@ -3378,40 +3371,33 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
di->autopower_cfg = false;
|
||||
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->dev = dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
/* Get ADC channels */
|
||||
di->adc_main_charger_v = devm_iio_channel_get(&pdev->dev,
|
||||
"main_charger_v");
|
||||
di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v");
|
||||
if (IS_ERR(di->adc_main_charger_v)) {
|
||||
if (PTR_ERR(di->adc_main_charger_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC main charger voltage\n");
|
||||
return PTR_ERR(di->adc_main_charger_v);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v),
|
||||
"failed to get ADC main charger voltage\n");
|
||||
return ret;
|
||||
}
|
||||
di->adc_main_charger_c = devm_iio_channel_get(&pdev->dev,
|
||||
"main_charger_c");
|
||||
di->adc_main_charger_c = devm_iio_channel_get(dev, "main_charger_c");
|
||||
if (IS_ERR(di->adc_main_charger_c)) {
|
||||
if (PTR_ERR(di->adc_main_charger_c) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC main charger current\n");
|
||||
return PTR_ERR(di->adc_main_charger_c);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_c),
|
||||
"failed to get ADC main charger current\n");
|
||||
return ret;
|
||||
}
|
||||
di->adc_vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
|
||||
di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v");
|
||||
if (IS_ERR(di->adc_vbus_v)) {
|
||||
if (PTR_ERR(di->adc_vbus_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC USB charger voltage\n");
|
||||
return PTR_ERR(di->adc_vbus_v);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v),
|
||||
"failed to get ADC USB charger voltage\n");
|
||||
return ret;
|
||||
}
|
||||
di->adc_usb_charger_c = devm_iio_channel_get(&pdev->dev,
|
||||
"usb_charger_c");
|
||||
di->adc_usb_charger_c = devm_iio_channel_get(dev, "usb_charger_c");
|
||||
if (IS_ERR(di->adc_usb_charger_c)) {
|
||||
if (PTR_ERR(di->adc_usb_charger_c) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get ADC USB charger current\n");
|
||||
return PTR_ERR(di->adc_usb_charger_c);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->adc_usb_charger_c),
|
||||
"failed to get ADC USB charger current\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize lock */
|
||||
|
@ -3467,7 +3453,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
|
||||
WQ_MEM_RECLAIM);
|
||||
if (di->charger_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
dev_err(dev, "failed to create work queue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -3526,10 +3512,10 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
* is a charger connected to avoid erroneous BTEMP_HIGH/LOW
|
||||
* interrupts during charging
|
||||
*/
|
||||
di->regu = devm_regulator_get(di->dev, "vddadc");
|
||||
di->regu = devm_regulator_get(dev, "vddadc");
|
||||
if (IS_ERR(di->regu)) {
|
||||
ret = PTR_ERR(di->regu);
|
||||
dev_err(di->dev, "failed to get vddadc regulator\n");
|
||||
dev_err(dev, "failed to get vddadc regulator\n");
|
||||
goto free_charger_wq;
|
||||
}
|
||||
|
||||
|
@ -3537,17 +3523,17 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
/* Initialize OVV, and other registers */
|
||||
ret = ab8500_charger_init_hw_registers(di);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to initialize ABB registers\n");
|
||||
dev_err(dev, "failed to initialize ABB registers\n");
|
||||
goto free_charger_wq;
|
||||
}
|
||||
|
||||
/* Register AC charger class */
|
||||
if (di->ac_chg.enabled) {
|
||||
di->ac_chg.psy = power_supply_register(di->dev,
|
||||
di->ac_chg.psy = power_supply_register(dev,
|
||||
&ab8500_ac_chg_desc,
|
||||
&ac_psy_cfg);
|
||||
if (IS_ERR(di->ac_chg.psy)) {
|
||||
dev_err(di->dev, "failed to register AC charger\n");
|
||||
dev_err(dev, "failed to register AC charger\n");
|
||||
ret = PTR_ERR(di->ac_chg.psy);
|
||||
goto free_charger_wq;
|
||||
}
|
||||
|
@ -3555,11 +3541,11 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
|
||||
/* Register USB charger class */
|
||||
if (di->usb_chg.enabled) {
|
||||
di->usb_chg.psy = power_supply_register(di->dev,
|
||||
di->usb_chg.psy = power_supply_register(dev,
|
||||
&ab8500_usb_chg_desc,
|
||||
&usb_psy_cfg);
|
||||
if (IS_ERR(di->usb_chg.psy)) {
|
||||
dev_err(di->dev, "failed to register USB charger\n");
|
||||
dev_err(dev, "failed to register USB charger\n");
|
||||
ret = PTR_ERR(di->usb_chg.psy);
|
||||
goto free_ac;
|
||||
}
|
||||
|
@ -3567,14 +3553,14 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
|
||||
di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(di->usb_phy)) {
|
||||
dev_err(di->dev, "failed to get usb transceiver\n");
|
||||
dev_err(dev, "failed to get usb transceiver\n");
|
||||
ret = -EINVAL;
|
||||
goto free_usb;
|
||||
}
|
||||
di->nb.notifier_call = ab8500_charger_usb_notifier_call;
|
||||
ret = usb_register_notifier(di->usb_phy, &di->nb);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to register usb notifier\n");
|
||||
dev_err(dev, "failed to register usb notifier\n");
|
||||
goto put_usb_phy;
|
||||
}
|
||||
|
||||
|
@ -3603,15 +3589,15 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
ab8500_charger_irq[i].name, di);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
|
||||
dev_err(dev, "failed to request %s IRQ %d: %d\n"
|
||||
, ab8500_charger_irq[i].name, irq, ret);
|
||||
goto free_irq;
|
||||
}
|
||||
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
|
||||
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
|
||||
ab8500_charger_irq[i].name, irq, ret);
|
||||
}
|
||||
|
||||
|
@ -3659,6 +3645,8 @@ free_charger_wq:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume);
|
||||
|
||||
static const struct of_device_id ab8500_charger_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-charger", },
|
||||
{ },
|
||||
|
@ -3667,11 +3655,10 @@ static const struct of_device_id ab8500_charger_match[] = {
|
|||
static struct platform_driver ab8500_charger_driver = {
|
||||
.probe = ab8500_charger_probe,
|
||||
.remove = ab8500_charger_remove,
|
||||
.suspend = ab8500_charger_suspend,
|
||||
.resume = ab8500_charger_resume,
|
||||
.driver = {
|
||||
.name = "ab8500-charger",
|
||||
.of_match_table = ab8500_charger_match,
|
||||
.pm = &ab8500_charger_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -2942,10 +2942,9 @@ static void ab8500_fg_sysfs_psy_remove_attrs(struct ab8500_fg *di)
|
|||
|
||||
/* Exposure to the sysfs interface <<END>> */
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int ab8500_fg_resume(struct platform_device *pdev)
|
||||
static int __maybe_unused ab8500_fg_resume(struct device *dev)
|
||||
{
|
||||
struct ab8500_fg *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_fg *di = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Change state if we're not charging. If we're charging we will wake
|
||||
|
@ -2959,10 +2958,9 @@ static int ab8500_fg_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_fg_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int __maybe_unused ab8500_fg_suspend(struct device *dev)
|
||||
{
|
||||
struct ab8500_fg *di = platform_get_drvdata(pdev);
|
||||
struct ab8500_fg *di = dev_get_drvdata(dev);
|
||||
|
||||
flush_delayed_work(&di->fg_periodic_work);
|
||||
flush_work(&di->fg_work);
|
||||
|
@ -2980,10 +2978,6 @@ static int ab8500_fg_suspend(struct platform_device *pdev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ab8500_fg_suspend NULL
|
||||
#define ab8500_fg_resume NULL
|
||||
#endif
|
||||
|
||||
static int ab8500_fg_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -3007,14 +3001,11 @@ static int ab8500_fg_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* ab8500 fg driver interrupts and their respective isr */
|
||||
static struct ab8500_fg_interrupts ab8500_fg_irq_th[] = {
|
||||
static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
|
||||
{"NCONV_ACCU", ab8500_fg_cc_convend_handler},
|
||||
{"BATT_OVV", ab8500_fg_batt_ovv_handler},
|
||||
{"LOW_BAT_F", ab8500_fg_lowbatf_handler},
|
||||
{"CC_INT_CALIB", ab8500_fg_cc_int_calib_handler},
|
||||
};
|
||||
|
||||
static struct ab8500_fg_interrupts ab8500_fg_irq_bh[] = {
|
||||
{"CCEOC", ab8500_fg_cc_data_end_handler},
|
||||
};
|
||||
|
||||
|
@ -3037,26 +3028,25 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
struct device_node *np = pdev->dev.of_node;
|
||||
struct abx500_bm_data *plat = pdev->dev.platform_data;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ab8500_fg *di;
|
||||
int i, irq;
|
||||
int ret = 0;
|
||||
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
|
||||
di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev, "no battery management data supplied\n");
|
||||
dev_err(dev, "no battery management data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
di->bm = plat;
|
||||
|
||||
if (np) {
|
||||
ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
|
||||
ret = ab8500_bm_of_probe(dev, np, di->bm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get battery information\n");
|
||||
dev_err(dev, "failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -3064,15 +3054,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
mutex_init(&di->cc_lock);
|
||||
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->dev = dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v");
|
||||
di->main_bat_v = devm_iio_channel_get(dev, "main_bat_v");
|
||||
if (IS_ERR(di->main_bat_v)) {
|
||||
if (PTR_ERR(di->main_bat_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(&pdev->dev, "failed to get main battery ADC channel\n");
|
||||
return PTR_ERR(di->main_bat_v);
|
||||
ret = dev_err_probe(dev, PTR_ERR(di->main_bat_v),
|
||||
"failed to get main battery ADC channel\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
psy_cfg.supplied_to = supply_interface;
|
||||
|
@ -3094,7 +3083,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
/* Create a work queue for running the FG algorithm */
|
||||
di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
|
||||
if (di->fg_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
dev_err(dev, "failed to create work queue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -3129,7 +3118,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
/* Initialize OVV, and other registers */
|
||||
ret = ab8500_fg_init_hw_registers(di);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to initialize registers\n");
|
||||
dev_err(dev, "failed to initialize registers\n");
|
||||
goto free_inst_curr_wq;
|
||||
}
|
||||
|
||||
|
@ -3138,9 +3127,9 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
di->flags.batt_id_received = false;
|
||||
|
||||
/* Register FG power supply class */
|
||||
di->fg_psy = power_supply_register(di->dev, &ab8500_fg_desc, &psy_cfg);
|
||||
di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
|
||||
if (IS_ERR(di->fg_psy)) {
|
||||
dev_err(di->dev, "failed to register FG psy\n");
|
||||
dev_err(dev, "failed to register FG psy\n");
|
||||
ret = PTR_ERR(di->fg_psy);
|
||||
goto free_inst_curr_wq;
|
||||
}
|
||||
|
@ -3156,45 +3145,26 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
init_completion(&di->ab8500_fg_complete);
|
||||
|
||||
/* Register primary interrupt handlers */
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto free_irq_th;
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
ret = request_irq(irq, ab8500_fg_irq_th[i].isr,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
ab8500_fg_irq_th[i].name, di);
|
||||
ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
ab8500_fg_irq[i].name, di);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq_th[i].name, irq, ret);
|
||||
goto free_irq_th;
|
||||
dev_err(dev, "failed to request %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq[i].name, irq, ret);
|
||||
goto free_irq;
|
||||
}
|
||||
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq_th[i].name, irq, ret);
|
||||
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq[i].name, irq, ret);
|
||||
}
|
||||
|
||||
/* Register threaded interrupt handler */
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto free_irq_th;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, ab8500_fg_irq_bh[0].isr,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
ab8500_fg_irq_bh[0].name, di);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq_bh[0].name, irq, ret);
|
||||
goto free_irq_th;
|
||||
}
|
||||
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
|
||||
ab8500_fg_irq_bh[0].name, irq, ret);
|
||||
|
||||
di->irq = platform_get_irq_byname(pdev, "CCEOC");
|
||||
disable_irq(di->irq);
|
||||
di->nbr_cceoc_irq_cnt = 0;
|
||||
|
@ -3203,13 +3173,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
|
||||
ret = ab8500_fg_sysfs_init(di);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to create sysfs entry\n");
|
||||
dev_err(dev, "failed to create sysfs entry\n");
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
ret = ab8500_fg_sysfs_psy_create_attrs(di);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "failed to create FG psy\n");
|
||||
dev_err(dev, "failed to create FG psy\n");
|
||||
ab8500_fg_sysfs_exit(di);
|
||||
goto free_irq;
|
||||
}
|
||||
|
@ -3230,12 +3200,9 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
|
||||
free_irq:
|
||||
/* We also have to free all registered irqs */
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
|
||||
free_irq(irq, di);
|
||||
free_irq_th:
|
||||
while (--i >= 0) {
|
||||
/* Last assignment of i from primary interrupt handlers */
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
|
||||
irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
|
||||
free_irq(irq, di);
|
||||
}
|
||||
|
||||
|
@ -3245,6 +3212,8 @@ free_inst_curr_wq:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ab8500_fg_pm_ops, ab8500_fg_suspend, ab8500_fg_resume);
|
||||
|
||||
static const struct of_device_id ab8500_fg_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-fg", },
|
||||
{ },
|
||||
|
@ -3253,11 +3222,10 @@ static const struct of_device_id ab8500_fg_match[] = {
|
|||
static struct platform_driver ab8500_fg_driver = {
|
||||
.probe = ab8500_fg_probe,
|
||||
.remove = ab8500_fg_remove,
|
||||
.suspend = ab8500_fg_suspend,
|
||||
.resume = ab8500_fg_resume,
|
||||
.driver = {
|
||||
.name = "ab8500-fg",
|
||||
.of_match_table = ab8500_fg_match,
|
||||
.pm = &ab8500_fg_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1913,10 +1913,9 @@ static int abx500_chargalg_sysfs_init(struct abx500_chargalg *di)
|
|||
}
|
||||
/* Exposure to the sysfs interface <<END>> */
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int abx500_chargalg_resume(struct platform_device *pdev)
|
||||
static int __maybe_unused abx500_chargalg_resume(struct device *dev)
|
||||
{
|
||||
struct abx500_chargalg *di = platform_get_drvdata(pdev);
|
||||
struct abx500_chargalg *di = dev_get_drvdata(dev);
|
||||
|
||||
/* Kick charger watchdog if charging (any charger online) */
|
||||
if (di->chg_info.online_chg)
|
||||
|
@ -1931,10 +1930,9 @@ static int abx500_chargalg_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int abx500_chargalg_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
|
||||
{
|
||||
struct abx500_chargalg *di = platform_get_drvdata(pdev);
|
||||
struct abx500_chargalg *di = dev_get_drvdata(dev);
|
||||
|
||||
if (di->chg_info.online_chg)
|
||||
cancel_delayed_work_sync(&di->chargalg_wd_work);
|
||||
|
@ -1943,10 +1941,6 @@ static int abx500_chargalg_suspend(struct platform_device *pdev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define abx500_chargalg_suspend NULL
|
||||
#define abx500_chargalg_resume NULL
|
||||
#endif
|
||||
|
||||
static int abx500_chargalg_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -2080,6 +2074,8 @@ free_chargalg_wq:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
|
||||
|
||||
static const struct of_device_id ab8500_chargalg_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-chargalg", },
|
||||
{ },
|
||||
|
@ -2088,11 +2084,10 @@ static const struct of_device_id ab8500_chargalg_match[] = {
|
|||
static struct platform_driver abx500_chargalg_driver = {
|
||||
.probe = abx500_chargalg_probe,
|
||||
.remove = abx500_chargalg_remove,
|
||||
.suspend = abx500_chargalg_suspend,
|
||||
.resume = abx500_chargalg_resume,
|
||||
.driver = {
|
||||
.name = "ab8500-chargalg",
|
||||
.of_match_table = ab8500_chargalg_match,
|
||||
.pm = &abx500_chargalg_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
|
|||
|
||||
power_supply_changed(power->supply);
|
||||
|
||||
mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work)
|
|||
|
||||
out:
|
||||
if (axp20x_usb_vbus_needs_polling(power))
|
||||
mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
}
|
||||
|
||||
static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
|
||||
|
@ -397,7 +397,7 @@ static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
|
|||
struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
|
||||
|
||||
/*
|
||||
* The VBUS path select flag works differently on on AXP288 and newer:
|
||||
* The VBUS path select flag works differently on AXP288 and newer:
|
||||
* - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN).
|
||||
* - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN).
|
||||
* We only expose the control on variants where it can be used to force
|
||||
|
@ -525,7 +525,7 @@ static int axp20x_usb_power_resume(struct device *dev)
|
|||
while (i < power->num_irqs)
|
||||
enable_irq(power->irqs[i++]);
|
||||
|
||||
mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -647,7 +647,7 @@ 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_wq, &power->vbus_detect, 0);
|
||||
queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -548,14 +548,15 @@ out:
|
|||
|
||||
/*
|
||||
* 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"
|
||||
* Bay Trail SoC + AXP288 PMIC, Micro-USB, DMI_BOARD_NAME: "8021"
|
||||
* Bay Trail SoC + AXP288 PMIC, Type-C, DMI_BOARD_NAME: "815D"
|
||||
* Cherry Trail SoC + AXP288 PMIC, Type-C, DMI_BOARD_NAME: "813E"
|
||||
* Cherry Trail SoC + TI PMIC, Type-C, DMI_BOARD_NAME: "827C" or "82F4"
|
||||
*
|
||||
* The variants with the AXP288 PMIC are all kinds of special:
|
||||
* The variants with the AXP288 + Type-C connector 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,
|
||||
* 1. They 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,
|
||||
|
@ -578,12 +579,17 @@ out:
|
|||
*/
|
||||
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"),
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "815D"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "813E"),
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
|
||||
|
@ -448,8 +447,10 @@ static ssize_t bq24190_sysfs_show(struct device *dev,
|
|||
return -EINVAL;
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
|
||||
if (ret)
|
||||
|
@ -1077,8 +1078,10 @@ static int bq24190_charger_get_property(struct power_supply *psy,
|
|||
dev_dbg(bdi->dev, "prop: %d\n", psp);
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
|
@ -1149,8 +1152,10 @@ static int bq24190_charger_set_property(struct power_supply *psy,
|
|||
dev_dbg(bdi->dev, "prop: %d\n", psp);
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
|
@ -1410,8 +1415,10 @@ static int bq24190_battery_get_property(struct power_supply *psy,
|
|||
dev_dbg(bdi->dev, "prop: %d\n", psp);
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
|
@ -1456,8 +1463,10 @@ static int bq24190_battery_set_property(struct power_supply *psy,
|
|||
dev_dbg(bdi->dev, "prop: %d\n", psp);
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
@ -299,7 +299,7 @@ static const union {
|
|||
/* TODO: BQ25896 has max ICHG 3008 mA */
|
||||
[TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */
|
||||
[TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */
|
||||
[TBL_IILIM] = { .rt = {50000, 3200000, 50000} }, /* uA */
|
||||
[TBL_IILIM] = { .rt = {100000, 3250000, 50000} }, /* uA */
|
||||
[TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */
|
||||
[TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */
|
||||
[TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mfd/ucb1x00.h>
|
||||
|
||||
#include <asm/mach/sharpsl_param.h>
|
||||
|
@ -31,18 +33,18 @@ struct collie_bat {
|
|||
struct mutex work_lock; /* protects data */
|
||||
|
||||
bool (*is_present)(struct collie_bat *bat);
|
||||
int gpio_full;
|
||||
int gpio_charge_on;
|
||||
struct gpio_desc *gpio_full;
|
||||
struct gpio_desc *gpio_charge_on;
|
||||
|
||||
int technology;
|
||||
|
||||
int gpio_bat;
|
||||
struct gpio_desc *gpio_bat;
|
||||
int adc_bat;
|
||||
int adc_bat_divider;
|
||||
int bat_max;
|
||||
int bat_min;
|
||||
|
||||
int gpio_temp;
|
||||
struct gpio_desc *gpio_temp;
|
||||
int adc_temp;
|
||||
int adc_temp_divider;
|
||||
};
|
||||
|
@ -53,15 +55,15 @@ static unsigned long collie_read_bat(struct collie_bat *bat)
|
|||
{
|
||||
unsigned long value = 0;
|
||||
|
||||
if (bat->gpio_bat < 0 || bat->adc_bat < 0)
|
||||
if (!bat->gpio_bat || bat->adc_bat < 0)
|
||||
return 0;
|
||||
mutex_lock(&bat_lock);
|
||||
gpio_set_value(bat->gpio_bat, 1);
|
||||
gpiod_set_value(bat->gpio_bat, 1);
|
||||
msleep(5);
|
||||
ucb1x00_adc_enable(ucb);
|
||||
value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
|
||||
ucb1x00_adc_disable(ucb);
|
||||
gpio_set_value(bat->gpio_bat, 0);
|
||||
gpiod_set_value(bat->gpio_bat, 0);
|
||||
mutex_unlock(&bat_lock);
|
||||
value = value * 1000000 / bat->adc_bat_divider;
|
||||
|
||||
|
@ -71,16 +73,16 @@ static unsigned long collie_read_bat(struct collie_bat *bat)
|
|||
static unsigned long collie_read_temp(struct collie_bat *bat)
|
||||
{
|
||||
unsigned long value = 0;
|
||||
if (bat->gpio_temp < 0 || bat->adc_temp < 0)
|
||||
if (!bat->gpio_temp || bat->adc_temp < 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&bat_lock);
|
||||
gpio_set_value(bat->gpio_temp, 1);
|
||||
gpiod_set_value(bat->gpio_temp, 1);
|
||||
msleep(5);
|
||||
ucb1x00_adc_enable(ucb);
|
||||
value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
|
||||
ucb1x00_adc_disable(ucb);
|
||||
gpio_set_value(bat->gpio_temp, 0);
|
||||
gpiod_set_value(bat->gpio_temp, 0);
|
||||
mutex_unlock(&bat_lock);
|
||||
|
||||
value = value * 10000 / bat->adc_temp_divider;
|
||||
|
@ -162,23 +164,23 @@ static void collie_bat_update(struct collie_bat *bat)
|
|||
bat->full_chrg = -1;
|
||||
} else if (power_supply_am_i_supplied(psy)) {
|
||||
if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
||||
gpio_set_value(bat->gpio_charge_on, 1);
|
||||
gpiod_set_value(bat->gpio_charge_on, 1);
|
||||
mdelay(15);
|
||||
}
|
||||
|
||||
if (gpio_get_value(bat->gpio_full)) {
|
||||
if (gpiod_get_value(bat->gpio_full)) {
|
||||
if (old == POWER_SUPPLY_STATUS_CHARGING ||
|
||||
bat->full_chrg == -1)
|
||||
bat->full_chrg = collie_read_bat(bat);
|
||||
|
||||
gpio_set_value(bat->gpio_charge_on, 0);
|
||||
gpiod_set_value(bat->gpio_charge_on, 0);
|
||||
bat->status = POWER_SUPPLY_STATUS_FULL;
|
||||
} else {
|
||||
gpio_set_value(bat->gpio_charge_on, 1);
|
||||
gpiod_set_value(bat->gpio_charge_on, 1);
|
||||
bat->status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
} else {
|
||||
gpio_set_value(bat->gpio_charge_on, 0);
|
||||
gpiod_set_value(bat->gpio_charge_on, 0);
|
||||
bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
|
@ -230,18 +232,18 @@ static struct collie_bat collie_bat_main = {
|
|||
.full_chrg = -1,
|
||||
.psy = NULL,
|
||||
|
||||
.gpio_full = COLLIE_GPIO_CO,
|
||||
.gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
|
||||
.gpio_full = NULL,
|
||||
.gpio_charge_on = NULL,
|
||||
|
||||
.technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
||||
|
||||
.gpio_bat = COLLIE_GPIO_MBAT_ON,
|
||||
.gpio_bat = NULL,
|
||||
.adc_bat = UCB_ADC_INP_AD1,
|
||||
.adc_bat_divider = 155,
|
||||
.bat_max = 4310000,
|
||||
.bat_min = 1551 * 1000000 / 414,
|
||||
|
||||
.gpio_temp = COLLIE_GPIO_TMP_ON,
|
||||
.gpio_temp = NULL,
|
||||
.adc_temp = UCB_ADC_INP_AD0,
|
||||
.adc_temp_divider = 10000,
|
||||
};
|
||||
|
@ -260,30 +262,24 @@ static struct collie_bat collie_bat_bu = {
|
|||
.full_chrg = -1,
|
||||
.psy = NULL,
|
||||
|
||||
.gpio_full = -1,
|
||||
.gpio_charge_on = -1,
|
||||
.gpio_full = NULL,
|
||||
.gpio_charge_on = NULL,
|
||||
|
||||
.technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
|
||||
|
||||
.gpio_bat = COLLIE_GPIO_BBAT_ON,
|
||||
.gpio_bat = NULL,
|
||||
.adc_bat = UCB_ADC_INP_AD1,
|
||||
.adc_bat_divider = 155,
|
||||
.bat_max = 3000000,
|
||||
.bat_min = 1900000,
|
||||
|
||||
.gpio_temp = -1,
|
||||
.gpio_temp = NULL,
|
||||
.adc_temp = -1,
|
||||
.adc_temp_divider = -1,
|
||||
};
|
||||
|
||||
static struct gpio collie_batt_gpios[] = {
|
||||
{ COLLIE_GPIO_CO, GPIOF_IN, "main battery full" },
|
||||
{ COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN, "main battery low" },
|
||||
{ COLLIE_GPIO_CHARGE_ON, GPIOF_OUT_INIT_LOW, "main charge on" },
|
||||
{ COLLIE_GPIO_MBAT_ON, GPIOF_OUT_INIT_LOW, "main battery" },
|
||||
{ COLLIE_GPIO_TMP_ON, GPIOF_OUT_INIT_LOW, "main battery temp" },
|
||||
{ COLLIE_GPIO_BBAT_ON, GPIOF_OUT_INIT_LOW, "backup battery" },
|
||||
};
|
||||
/* Obtained but unused GPIO */
|
||||
static struct gpio_desc *collie_mbat_low;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wakeup_enabled;
|
||||
|
@ -295,7 +291,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
|
|||
|
||||
if (device_may_wakeup(&dev->ucb->dev) &&
|
||||
collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING)
|
||||
wakeup_enabled = !enable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
|
||||
wakeup_enabled = !enable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full));
|
||||
else
|
||||
wakeup_enabled = 0;
|
||||
|
||||
|
@ -305,7 +301,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
|
|||
static int collie_bat_resume(struct ucb1x00_dev *dev)
|
||||
{
|
||||
if (wakeup_enabled)
|
||||
disable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
|
||||
disable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full));
|
||||
|
||||
/* things may have changed while we were away */
|
||||
schedule_work(&bat_work);
|
||||
|
@ -320,16 +316,71 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
|
|||
{
|
||||
int ret;
|
||||
struct power_supply_config psy_main_cfg = {}, psy_bu_cfg = {};
|
||||
struct gpio_chip *gc = &dev->ucb->gpio;
|
||||
|
||||
if (!machine_is_collie())
|
||||
return -ENODEV;
|
||||
|
||||
ucb = dev->ucb;
|
||||
|
||||
ret = gpio_request_array(collie_batt_gpios,
|
||||
ARRAY_SIZE(collie_batt_gpios));
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Obtain all the main battery GPIOs */
|
||||
collie_bat_main.gpio_full = gpiod_get(&dev->ucb->dev,
|
||||
"main battery full",
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(collie_bat_main.gpio_full))
|
||||
return PTR_ERR(collie_bat_main.gpio_full);
|
||||
|
||||
collie_mbat_low = gpiod_get(&dev->ucb->dev,
|
||||
"main battery low",
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(collie_mbat_low)) {
|
||||
ret = PTR_ERR(collie_mbat_low);
|
||||
goto err_put_gpio_full;
|
||||
}
|
||||
|
||||
collie_bat_main.gpio_charge_on = gpiod_get(&dev->ucb->dev,
|
||||
"main charge on",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(collie_bat_main.gpio_charge_on)) {
|
||||
ret = PTR_ERR(collie_bat_main.gpio_charge_on);
|
||||
goto err_put_mbat_low;
|
||||
}
|
||||
|
||||
/* COLLIE_GPIO_MBAT_ON = GPIO 7 on the UCB (TC35143) */
|
||||
collie_bat_main.gpio_bat = gpiochip_request_own_desc(gc,
|
||||
7,
|
||||
"main battery",
|
||||
GPIO_ACTIVE_HIGH,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(collie_bat_main.gpio_bat)) {
|
||||
ret = PTR_ERR(collie_bat_main.gpio_bat);
|
||||
goto err_put_gpio_charge_on;
|
||||
}
|
||||
|
||||
/* COLLIE_GPIO_TMP_ON = GPIO 9 on the UCB (TC35143) */
|
||||
collie_bat_main.gpio_temp = gpiochip_request_own_desc(gc,
|
||||
9,
|
||||
"main battery temp",
|
||||
GPIO_ACTIVE_HIGH,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(collie_bat_main.gpio_temp)) {
|
||||
ret = PTR_ERR(collie_bat_main.gpio_temp);
|
||||
goto err_free_gpio_bat;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain the backup battery COLLIE_GPIO_BBAT_ON which is
|
||||
* GPIO 8 on the UCB (TC35143)
|
||||
*/
|
||||
collie_bat_bu.gpio_bat = gpiochip_request_own_desc(gc,
|
||||
8,
|
||||
"backup battery",
|
||||
GPIO_ACTIVE_HIGH,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(collie_bat_bu.gpio_bat)) {
|
||||
ret = PTR_ERR(collie_bat_bu.gpio_bat);
|
||||
goto err_free_gpio_temp;
|
||||
}
|
||||
|
||||
mutex_init(&collie_bat_main.work_lock);
|
||||
|
||||
|
@ -370,27 +421,43 @@ err_irq:
|
|||
err_psy_reg_bu:
|
||||
power_supply_unregister(collie_bat_main.psy);
|
||||
err_psy_reg_main:
|
||||
|
||||
/* see comment in collie_bat_remove */
|
||||
cancel_work_sync(&bat_work);
|
||||
gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
|
||||
gpiochip_free_own_desc(collie_bat_bu.gpio_bat);
|
||||
err_free_gpio_temp:
|
||||
gpiochip_free_own_desc(collie_bat_main.gpio_temp);
|
||||
err_free_gpio_bat:
|
||||
gpiochip_free_own_desc(collie_bat_main.gpio_bat);
|
||||
err_put_gpio_charge_on:
|
||||
gpiod_put(collie_bat_main.gpio_charge_on);
|
||||
err_put_mbat_low:
|
||||
gpiod_put(collie_mbat_low);
|
||||
err_put_gpio_full:
|
||||
gpiod_put(collie_bat_main.gpio_full);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void collie_bat_remove(struct ucb1x00_dev *dev)
|
||||
{
|
||||
free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
|
||||
|
||||
power_supply_unregister(collie_bat_bu.psy);
|
||||
power_supply_unregister(collie_bat_main.psy);
|
||||
|
||||
/* These are obtained from the machine */
|
||||
gpiod_put(collie_bat_main.gpio_full);
|
||||
gpiod_put(collie_mbat_low);
|
||||
gpiod_put(collie_bat_main.gpio_charge_on);
|
||||
/* These are directly from the UCB so let's free them */
|
||||
gpiochip_free_own_desc(collie_bat_main.gpio_bat);
|
||||
gpiochip_free_own_desc(collie_bat_main.gpio_temp);
|
||||
gpiochip_free_own_desc(collie_bat_bu.gpio_bat);
|
||||
/*
|
||||
* Now cancel the bat_work. We won't get any more schedules,
|
||||
* since all sources (isr and external_power_changed) are
|
||||
* unregistered now.
|
||||
*/
|
||||
cancel_work_sync(&bat_work);
|
||||
gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
|
||||
}
|
||||
|
||||
static struct ucb1x00_driver collie_bat_driver = {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -52,6 +52,7 @@ struct gab {
|
|||
int level;
|
||||
int status;
|
||||
bool cable_plugged;
|
||||
struct gpio_desc *charge_finished;
|
||||
};
|
||||
|
||||
static struct gab *to_generic_bat(struct power_supply *psy)
|
||||
|
@ -91,13 +92,9 @@ static const enum power_supply_property gab_dyn_props[] = {
|
|||
|
||||
static bool gab_charge_finished(struct gab *adc_bat)
|
||||
{
|
||||
struct gab_platform_data *pdata = adc_bat->pdata;
|
||||
bool ret = gpio_get_value(pdata->gpio_charge_finished);
|
||||
bool inv = pdata->gpio_inverted;
|
||||
|
||||
if (!gpio_is_valid(pdata->gpio_charge_finished))
|
||||
if (!adc_bat->charge_finished)
|
||||
return false;
|
||||
return ret ^ inv;
|
||||
return gpiod_get_value(adc_bat->charge_finished);
|
||||
}
|
||||
|
||||
static int gab_get_status(struct gab *adc_bat)
|
||||
|
@ -327,18 +324,17 @@ static int gab_probe(struct platform_device *pdev)
|
|||
|
||||
INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work);
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_charge_finished)) {
|
||||
adc_bat->charge_finished = devm_gpiod_get_optional(&pdev->dev,
|
||||
"charged", GPIOD_IN);
|
||||
if (adc_bat->charge_finished) {
|
||||
int irq;
|
||||
ret = gpio_request(pdata->gpio_charge_finished, "charged");
|
||||
if (ret)
|
||||
goto gpio_req_fail;
|
||||
|
||||
irq = gpio_to_irq(pdata->gpio_charge_finished);
|
||||
irq = gpiod_to_irq(adc_bat->charge_finished);
|
||||
ret = request_any_context_irq(irq, gab_charged,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"battery charged", adc_bat);
|
||||
if (ret < 0)
|
||||
goto err_gpio;
|
||||
goto gpio_req_fail;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, adc_bat);
|
||||
|
@ -348,8 +344,6 @@ static int gab_probe(struct platform_device *pdev)
|
|||
msecs_to_jiffies(0));
|
||||
return 0;
|
||||
|
||||
err_gpio:
|
||||
gpio_free(pdata->gpio_charge_finished);
|
||||
gpio_req_fail:
|
||||
power_supply_unregister(adc_bat->psy);
|
||||
err_reg_fail:
|
||||
|
@ -367,14 +361,11 @@ static int gab_remove(struct platform_device *pdev)
|
|||
{
|
||||
int chan;
|
||||
struct gab *adc_bat = platform_get_drvdata(pdev);
|
||||
struct gab_platform_data *pdata = adc_bat->pdata;
|
||||
|
||||
power_supply_unregister(adc_bat->psy);
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_charge_finished)) {
|
||||
free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat);
|
||||
gpio_free(pdata->gpio_charge_finished);
|
||||
}
|
||||
if (adc_bat->charge_finished)
|
||||
free_irq(gpiod_to_irq(adc_bat->charge_finished), adc_bat);
|
||||
|
||||
for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
|
||||
if (adc_bat->channel[chan])
|
||||
|
|
|
@ -78,6 +78,7 @@ static enum power_supply_property max17042_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
|
||||
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
|
||||
|
@ -85,9 +86,10 @@ static enum power_supply_property max17042_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_TEMP_MAX,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
// these two have to be at the end on the list
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
};
|
||||
|
||||
static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
|
||||
|
@ -353,7 +355,8 @@ static int max17042_get_property(struct power_supply *psy,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = data * 1000 / 2;
|
||||
data64 = sign_extend64(data, 15) * 5000000ll;
|
||||
val->intval = div_s64(data64, chip->pdata->r_sns);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = max17042_get_temperature(chip, &val->intval);
|
||||
|
@ -394,8 +397,8 @@ static int max17042_get_property(struct power_supply *psy,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = sign_extend32(data, 15);
|
||||
val->intval *= 1562500 / chip->pdata->r_sns;
|
||||
data64 = sign_extend64(data, 15) * 1562500ll;
|
||||
val->intval = div_s64(data64, chip->pdata->r_sns);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -406,12 +409,20 @@ static int max17042_get_property(struct power_supply *psy,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = sign_extend32(data, 15);
|
||||
val->intval *= 1562500 / chip->pdata->r_sns;
|
||||
data64 = sign_extend64(data, 15) * 1562500ll;
|
||||
val->intval = div_s64(data64, chip->pdata->r_sns);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
||||
ret = regmap_read(map, MAX17042_ICHGTerm, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data64 = data * 1562500ll;
|
||||
val->intval = div_s64(data64, chip->pdata->r_sns);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
|
||||
ret = regmap_read(map, MAX17042_TTE, &data);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -13,6 +13,20 @@
|
|||
#include <linux/mfd/max8997.h>
|
||||
#include <linux/mfd/max8997-private.h>
|
||||
|
||||
/* MAX8997_REG_STATUS4 */
|
||||
#define DCINOK_SHIFT 1
|
||||
#define DCINOK_MASK (1 << DCINOK_SHIFT)
|
||||
#define DETBAT_SHIFT 2
|
||||
#define DETBAT_MASK (1 << DETBAT_SHIFT)
|
||||
|
||||
/* MAX8997_REG_MBCCTRL1 */
|
||||
#define TFCH_SHIFT 4
|
||||
#define TFCH_MASK (7 << TFCH_SHIFT)
|
||||
|
||||
/* MAX8997_REG_MBCCTRL5 */
|
||||
#define ITOPOFF_SHIFT 0
|
||||
#define ITOPOFF_MASK (0xF << ITOPOFF_SHIFT)
|
||||
|
||||
struct charger_data {
|
||||
struct device *dev;
|
||||
struct max8997_dev *iodev;
|
||||
|
@ -20,7 +34,7 @@ struct charger_data {
|
|||
};
|
||||
|
||||
static enum power_supply_property max8997_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
|
||||
POWER_SUPPLY_PROP_STATUS, /* "FULL", "CHARGING" or "DISCHARGING". */
|
||||
POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
|
||||
POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
|
||||
};
|
||||
|
@ -43,6 +57,10 @@ static int max8997_battery_get_property(struct power_supply *psy,
|
|||
return ret;
|
||||
if ((reg & (1 << 0)) == 0x1)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else if ((reg & DCINOK_MASK))
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
|
@ -50,7 +68,7 @@ static int max8997_battery_get_property(struct power_supply *psy,
|
|||
ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
if ((reg & (1 << 2)) == 0x0)
|
||||
if ((reg & DETBAT_MASK) == 0x0)
|
||||
val->intval = 1;
|
||||
|
||||
break;
|
||||
|
@ -59,8 +77,7 @@ static int max8997_battery_get_property(struct power_supply *psy,
|
|||
ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* DCINOK */
|
||||
if (reg & (1 << 1))
|
||||
if (reg & DCINOK_MASK)
|
||||
val->intval = 1;
|
||||
|
||||
break;
|
||||
|
@ -84,11 +101,14 @@ static int max8997_battery_probe(struct platform_device *pdev)
|
|||
int ret = 0;
|
||||
struct charger_data *charger;
|
||||
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
|
||||
struct i2c_client *i2c = iodev->i2c;
|
||||
struct max8997_platform_data *pdata = iodev->pdata;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
|
||||
if (!pdata)
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data supplied.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->eoc_mA) {
|
||||
int val = (pdata->eoc_mA - 50) / 10;
|
||||
|
@ -97,30 +117,29 @@ static int max8997_battery_probe(struct platform_device *pdev)
|
|||
if (val > 0xf)
|
||||
val = 0xf;
|
||||
|
||||
ret = max8997_update_reg(iodev->i2c,
|
||||
MAX8997_REG_MBCCTRL5, val, 0xf);
|
||||
ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL5,
|
||||
val << ITOPOFF_SHIFT, ITOPOFF_MASK);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot use i2c bus.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
switch (pdata->timeout) {
|
||||
case 5:
|
||||
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x2 << 4, 0x7 << 4);
|
||||
ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x2 << TFCH_SHIFT, TFCH_MASK);
|
||||
break;
|
||||
case 6:
|
||||
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x3 << 4, 0x7 << 4);
|
||||
ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x3 << TFCH_SHIFT, TFCH_MASK);
|
||||
break;
|
||||
case 7:
|
||||
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x4 << 4, 0x7 << 4);
|
||||
ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x4 << TFCH_SHIFT, TFCH_MASK);
|
||||
break;
|
||||
case 0:
|
||||
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x7 << 4, 0x7 << 4);
|
||||
ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
|
||||
0x7 << TFCH_SHIFT, TFCH_MASK);
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
|
||||
|
@ -138,7 +157,6 @@ static int max8997_battery_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, charger);
|
||||
|
||||
|
||||
charger->dev = &pdev->dev;
|
||||
charger->iodev = iodev;
|
||||
|
||||
|
@ -168,18 +186,7 @@ static struct platform_driver max8997_battery_driver = {
|
|||
.probe = max8997_battery_probe,
|
||||
.id_table = max8997_battery_id,
|
||||
};
|
||||
|
||||
static int __init max8997_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&max8997_battery_driver);
|
||||
}
|
||||
subsys_initcall(max8997_battery_init);
|
||||
|
||||
static void __exit max8997_battery_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&max8997_battery_driver);
|
||||
}
|
||||
module_exit(max8997_battery_cleanup);
|
||||
module_platform_driver(max8997_battery_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
|
|
|
@ -455,7 +455,6 @@ static int pm2_int_reg4(void *pm2_data, int val)
|
|||
static int pm2_int_reg5(void *pm2_data, int val)
|
||||
{
|
||||
struct pm2xxx_charger *pm2 = pm2_data;
|
||||
int ret = 0;
|
||||
|
||||
if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
|
||||
dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
|
||||
|
@ -468,7 +467,7 @@ static int pm2_int_reg5(void *pm2_data, int val)
|
|||
dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t pm2xxx_irq_int(int irq, void *data)
|
||||
|
|
|
@ -402,7 +402,7 @@ void power_supply_init_attrs(struct device_type *dev_type)
|
|||
struct device_attribute *attr;
|
||||
|
||||
if (!power_supply_attrs[i].prop_name) {
|
||||
pr_warn("%s: Property %d skipped because is is missing from power_supply_attrs\n",
|
||||
pr_warn("%s: Property %d skipped because it is missing from power_supply_attrs\n",
|
||||
__func__, i);
|
||||
sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
|
||||
} else {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -31,6 +31,7 @@ struct s3c_adc_bat {
|
|||
struct power_supply *psy;
|
||||
struct s3c_adc_client *client;
|
||||
struct s3c_adc_bat_pdata *pdata;
|
||||
struct gpio_desc *charge_finished;
|
||||
int volt_value;
|
||||
int cur_value;
|
||||
unsigned int timestamp;
|
||||
|
@ -132,9 +133,7 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
|
|||
|
||||
static int charge_finished(struct s3c_adc_bat *bat)
|
||||
{
|
||||
return bat->pdata->gpio_inverted ?
|
||||
!gpio_get_value(bat->pdata->gpio_charge_finished) :
|
||||
gpio_get_value(bat->pdata->gpio_charge_finished);
|
||||
return gpiod_get_value(bat->charge_finished);
|
||||
}
|
||||
|
||||
static int s3c_adc_bat_get_property(struct power_supply *psy,
|
||||
|
@ -169,7 +168,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
|
|||
}
|
||||
|
||||
if (bat->cable_plugged &&
|
||||
((bat->pdata->gpio_charge_finished < 0) ||
|
||||
(!bat->charge_finished ||
|
||||
!charge_finished(bat))) {
|
||||
lut = bat->pdata->lut_acin;
|
||||
lut_size = bat->pdata->lut_acin_cnt;
|
||||
|
@ -206,7 +205,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
|
|||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (bat->pdata->gpio_charge_finished < 0)
|
||||
if (!bat->charge_finished)
|
||||
val->intval = bat->level == 100000 ?
|
||||
POWER_SUPPLY_STATUS_FULL : bat->status;
|
||||
else
|
||||
|
@ -265,7 +264,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
|
|||
bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
} else {
|
||||
if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
|
||||
if (bat->charge_finished && is_plugged) {
|
||||
is_charged = charge_finished(&main_bat);
|
||||
if (is_charged) {
|
||||
if (bat->pdata->disable_charger)
|
||||
|
@ -294,6 +293,7 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
|
|||
struct s3c_adc_client *client;
|
||||
struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct gpio_desc *gpiod;
|
||||
int ret;
|
||||
|
||||
client = s3c_adc_register(pdev, NULL, NULL, 0);
|
||||
|
@ -304,8 +304,17 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, client);
|
||||
|
||||
gpiod = devm_gpiod_get_optional(&pdev->dev, "charge-status", GPIOD_IN);
|
||||
if (IS_ERR(gpiod)) {
|
||||
/* Could be probe deferral etc */
|
||||
ret = PTR_ERR(gpiod);
|
||||
dev_err(&pdev->dev, "no GPIO %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
main_bat.client = client;
|
||||
main_bat.pdata = pdata;
|
||||
main_bat.charge_finished = gpiod;
|
||||
main_bat.volt_value = -1;
|
||||
main_bat.cur_value = -1;
|
||||
main_bat.cable_plugged = 0;
|
||||
|
@ -323,6 +332,7 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
|
|||
|
||||
backup_bat.client = client;
|
||||
backup_bat.pdata = pdev->dev.platform_data;
|
||||
backup_bat.charge_finished = gpiod;
|
||||
backup_bat.volt_value = -1;
|
||||
backup_bat.psy = power_supply_register(&pdev->dev,
|
||||
&backup_bat_desc,
|
||||
|
@ -335,12 +345,8 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
|
|||
|
||||
INIT_DELAYED_WORK(&bat_work, s3c_adc_bat_work);
|
||||
|
||||
if (pdata->gpio_charge_finished >= 0) {
|
||||
ret = gpio_request(pdata->gpio_charge_finished, "charged");
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
|
||||
ret = request_irq(gpio_to_irq(pdata->gpio_charge_finished),
|
||||
if (gpiod) {
|
||||
ret = request_irq(gpiod_to_irq(gpiod),
|
||||
s3c_adc_bat_charged,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"battery charged", NULL);
|
||||
|
@ -364,12 +370,9 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_platform:
|
||||
if (pdata->gpio_charge_finished >= 0)
|
||||
free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
|
||||
if (gpiod)
|
||||
free_irq(gpiod_to_irq(gpiod), NULL);
|
||||
err_irq:
|
||||
if (pdata->gpio_charge_finished >= 0)
|
||||
gpio_free(pdata->gpio_charge_finished);
|
||||
err_gpio:
|
||||
if (pdata->backup_volt_mult)
|
||||
power_supply_unregister(backup_bat.psy);
|
||||
err_reg_backup:
|
||||
|
@ -389,10 +392,8 @@ static int s3c_adc_bat_remove(struct platform_device *pdev)
|
|||
|
||||
s3c_adc_release(client);
|
||||
|
||||
if (pdata->gpio_charge_finished >= 0) {
|
||||
free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
|
||||
gpio_free(pdata->gpio_charge_finished);
|
||||
}
|
||||
if (main_bat.charge_finished)
|
||||
free_irq(gpiod_to_irq(main_bat.charge_finished), NULL);
|
||||
|
||||
cancel_delayed_work(&bat_work);
|
||||
|
||||
|
@ -408,12 +409,12 @@ static int s3c_adc_bat_suspend(struct platform_device *pdev,
|
|||
{
|
||||
struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata->gpio_charge_finished >= 0) {
|
||||
if (main_bat.charge_finished) {
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(
|
||||
gpio_to_irq(pdata->gpio_charge_finished));
|
||||
gpiod_to_irq(main_bat.charge_finished));
|
||||
else {
|
||||
disable_irq(gpio_to_irq(pdata->gpio_charge_finished));
|
||||
disable_irq(gpiod_to_irq(main_bat.charge_finished));
|
||||
main_bat.pdata->disable_charger();
|
||||
}
|
||||
}
|
||||
|
@ -425,12 +426,12 @@ static int s3c_adc_bat_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata->gpio_charge_finished >= 0) {
|
||||
if (main_bat.charge_finished) {
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(
|
||||
gpio_to_irq(pdata->gpio_charge_finished));
|
||||
gpiod_to_irq(main_bat.charge_finished));
|
||||
else
|
||||
enable_irq(gpio_to_irq(pdata->gpio_charge_finished));
|
||||
enable_irq(gpiod_to_irq(main_bat.charge_finished));
|
||||
}
|
||||
|
||||
/* Schedule timer to check current status */
|
||||
|
|
|
@ -668,7 +668,6 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
fallthrough;
|
||||
case -EPROBE_DEFER:
|
||||
goto err_bat_irq;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -11,16 +11,12 @@
|
|||
* @battery_info: recommended structure to specify static power supply
|
||||
* parameters
|
||||
* @cal_charge: calculate charge level.
|
||||
* @gpio_charge_finished: gpio for the charger.
|
||||
* @gpio_inverted: Should be 1 if the GPIO is active low otherwise 0
|
||||
* @jitter_delay: delay required after the interrupt to check battery
|
||||
* status.Default set is 10ms.
|
||||
*/
|
||||
struct gab_platform_data {
|
||||
struct power_supply_info battery_info;
|
||||
int (*cal_charge)(long value);
|
||||
int gpio_charge_finished;
|
||||
bool gpio_inverted;
|
||||
int jitter_delay;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ struct s3c_adc_bat_pdata {
|
|||
void (*enable_charger)(void);
|
||||
void (*disable_charger)(void);
|
||||
|
||||
int gpio_charge_finished;
|
||||
int gpio_inverted;
|
||||
|
||||
const struct s3c_adc_bat_thresh *lut_noac;
|
||||
unsigned int lut_noac_cnt;
|
||||
const struct s3c_adc_bat_thresh *lut_acin;
|
||||
|
|
Loading…
Reference in New Issue