Commit 11c33652 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents c2703b66 c2362519
......@@ -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 {
......
# 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 = <&reg_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;
......
// 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 = &regulator_poweroff_do_poweroff;
return 0;
}
static int regulator_poweroff_remove(__maybe_unused struct platform_device *pdev)
{
if (pm_power_off == &regulator_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 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
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 @@ static int ab8500_charger_probe(struct platform_device *pdev)
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 @@ static int ab8500_fg_probe(struct platform_device *pdev)
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 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
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 @@ static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
/*
* 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 @@ static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
*/
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 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
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, &reg);
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, &reg);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment