Commit 1cabd3e0 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull power supply and reset updates from Sebastian Reichel:
 "Nothing too fancy in the power-supply subsystem this time. There are
  less patches than usual, since I did not have enough time to review
  them in time. The good news is, that all patches have been in
  linux-next for more than two weeks and there are no complicated
  cross-subsystem patchsets this time!

  Summary:

   - at91-reset: add sam9x60 support

   - sc27xx: improve capacity logic

   - goldfish_battery: enhance driver by adding many new properties

   - isp1704: drop platform data and migrate to gpiod

   - misc small fixes and improvements"

* tag 'for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (25 commits)
  power: reset: at91-reset: add support for sam9x60 SoC
  dt-bindings: arm: atmel: add new sam9x60 reset controller binding
  dt-bindings: arm: atmel: add missing samx7 to reset controller
  max17042_battery: fix potential use-after-free on device remove
  power: supply: core: Add a field to support battery max voltage
  dt-bindings: power: supply: Add voltage-max-design-microvolt property
  bq27x00: use cached flags
  power: supply: ds2782: fix possible use-after-free on remove
  power: supply: bq25890: show max charge current/voltage as configured
  power: supply: sc27xx: Fix capacity saving function
  power: supply: sc27xx: Fix the incorrect formula when converting capacity to coulomb counter
  power: supply: sc27xx: Add one property to read charge voltage
  dt-bindings: power: sc27xx: Add one IIO channel to read charge voltage
  drivers: power: supply: goldfish_battery: Add support for reading more properties
  power: supply: charger-manager: Fix trivial language typos
  cpcap-charger: generate events for userspace
  power: supply: remove some duplicated includes
  power: twl4030: fix a missing check of return value
  drivers: power: supply: goldfish_battery: Use tabs for alignment
  drivers: power: supply: goldfish_battery: Fix alignment
  ...
parents 7427e286 655ab0bc
...@@ -21,7 +21,8 @@ Its subnodes can be: ...@@ -21,7 +21,8 @@ Its subnodes can be:
RSTC Reset Controller required properties: RSTC Reset Controller required properties:
- compatible: Should be "atmel,<chip>-rstc". - compatible: Should be "atmel,<chip>-rstc".
<chip> can be "at91sam9260" or "at91sam9g45" or "sama5d3" <chip> can be "at91sam9260", "at91sam9g45", "sama5d3" or "samx7"
it also can be "microchip,sam9x60-rstc"
- reg: Should contain registers location and length - reg: Should contain registers location and length
- clocks: phandle to input clock. - clocks: phandle to input clock.
......
...@@ -16,6 +16,7 @@ Required Properties: ...@@ -16,6 +16,7 @@ Required Properties:
Optional Properties: Optional Properties:
- voltage-min-design-microvolt: drained battery voltage - voltage-min-design-microvolt: drained battery voltage
- voltage-max-design-microvolt: fully charged battery voltage
- energy-full-design-microwatt-hours: battery design energy - energy-full-design-microwatt-hours: battery design energy
- charge-full-design-microamp-hours: battery design capacity - charge-full-design-microamp-hours: battery design capacity
- precharge-current-microamp: current for pre-charge phase - precharge-current-microamp: current for pre-charge phase
...@@ -48,6 +49,7 @@ Example: ...@@ -48,6 +49,7 @@ Example:
bat: battery { bat: battery {
compatible = "simple-battery"; compatible = "simple-battery";
voltage-min-design-microvolt = <3200000>; voltage-min-design-microvolt = <3200000>;
voltage-max-design-microvolt = <4200000>;
energy-full-design-microwatt-hours = <5290000>; energy-full-design-microwatt-hours = <5290000>;
charge-full-design-microamp-hours = <1430000>; charge-full-design-microamp-hours = <1430000>;
precharge-current-microamp = <256000>; precharge-current-microamp = <256000>;
......
...@@ -9,8 +9,8 @@ Required properties: ...@@ -9,8 +9,8 @@ Required properties:
"sprd,sc2731-fgu". "sprd,sc2731-fgu".
- reg: The address offset of fuel gauge unit. - reg: The address offset of fuel gauge unit.
- battery-detect-gpios: GPIO for battery detection. - battery-detect-gpios: GPIO for battery detection.
- io-channels: Specify the IIO ADC channel to get temperature. - io-channels: Specify the IIO ADC channels to get temperature and charge voltage.
- io-channel-names: Should be "bat-temp". - io-channel-names: Should be "bat-temp" or "charge-vol".
- nvmem-cells: A phandle to the calibration cells provided by eFuse device. - nvmem-cells: A phandle to the calibration cells provided by eFuse device.
- nvmem-cell-names: Should be "fgu_calib". - nvmem-cell-names: Should be "fgu_calib".
- monitored-battery: Phandle of battery characteristics devicetree node. - monitored-battery: Phandle of battery characteristics devicetree node.
...@@ -47,8 +47,8 @@ Example: ...@@ -47,8 +47,8 @@ Example:
compatible = "sprd,sc2731-fgu"; compatible = "sprd,sc2731-fgu";
reg = <0xa00>; reg = <0xa00>;
battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>; battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>;
io-channels = <&pmic_adc 5>; io-channels = <&pmic_adc 5>, <&pmic_adc 14>;
io-channel-names = "bat-temp"; io-channel-names = "bat-temp", "charge-vol";
nvmem-cells = <&fgu_calib>; nvmem-cells = <&fgu_calib>;
nvmem-cell-names = "fgu_calib"; nvmem-cell-names = "fgu_calib";
monitored-battery = <&bat>; monitored-battery = <&bat>;
......
...@@ -44,6 +44,9 @@ enum reset_type { ...@@ -44,6 +44,9 @@ enum reset_type {
RESET_TYPE_WATCHDOG = 2, RESET_TYPE_WATCHDOG = 2,
RESET_TYPE_SOFTWARE = 3, RESET_TYPE_SOFTWARE = 3,
RESET_TYPE_USER = 4, RESET_TYPE_USER = 4,
RESET_TYPE_CPU_FAIL = 6,
RESET_TYPE_XTAL_FAIL = 7,
RESET_TYPE_ULP2 = 8,
}; };
static void __iomem *at91_ramc_base[2], *at91_rstc_base; static void __iomem *at91_ramc_base[2], *at91_rstc_base;
...@@ -164,6 +167,15 @@ static void __init at91_reset_status(struct platform_device *pdev) ...@@ -164,6 +167,15 @@ static void __init at91_reset_status(struct platform_device *pdev)
case RESET_TYPE_USER: case RESET_TYPE_USER:
reason = "user reset"; reason = "user reset";
break; break;
case RESET_TYPE_CPU_FAIL:
reason = "CPU clock failure detection";
break;
case RESET_TYPE_XTAL_FAIL:
reason = "32.768 kHz crystal failure detection";
break;
case RESET_TYPE_ULP2:
reason = "ULP2 reset";
break;
default: default:
reason = "unknown reset"; reason = "unknown reset";
break; break;
...@@ -183,6 +195,7 @@ static const struct of_device_id at91_reset_of_match[] = { ...@@ -183,6 +195,7 @@ static const struct of_device_id at91_reset_of_match[] = {
{ .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
{ .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
{ .compatible = "atmel,samx7-rstc", .data = samx7_restart }, { .compatible = "atmel,samx7-rstc", .data = samx7_restart },
{ .compatible = "microchip,sam9x60-rstc", .data = samx7_restart },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, at91_reset_of_match); MODULE_DEVICE_TABLE(of, at91_reset_of_match);
......
...@@ -307,22 +307,12 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data) ...@@ -307,22 +307,12 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data)
return 0; return 0;
} }
static int debug_open(struct inode *inode, struct file *file) DEFINE_SHOW_ATTRIBUTE(fuel_gauge_debug);
{
return single_open(file, fuel_gauge_debug_show, inode->i_private);
}
static const struct file_operations fg_debug_fops = {
.open = debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void fuel_gauge_create_debugfs(struct axp288_fg_info *info) static void fuel_gauge_create_debugfs(struct axp288_fg_info *info)
{ {
info->debug_file = debugfs_create_file("fuelgauge", 0666, NULL, info->debug_file = debugfs_create_file("fuelgauge", 0666, NULL,
info, &fg_debug_fops); info, &fuel_gauge_debug_fops);
} }
static void fuel_gauge_remove_debugfs(struct axp288_fg_info *info) static void fuel_gauge_remove_debugfs(struct axp288_fg_info *info)
......
...@@ -436,7 +436,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, ...@@ -436,7 +436,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = bq25890_tables[TBL_ICHG].rt.max; val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG);
break; break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
...@@ -454,7 +454,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, ...@@ -454,7 +454,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
val->intval = bq25890_tables[TBL_VREG].rt.max; val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG);
break; break;
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
......
...@@ -1555,27 +1555,14 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) ...@@ -1555,27 +1555,14 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF);
} }
/*
* Read flag register.
* Return < 0 if something fails.
*/
static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
{ {
int flags;
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
if (flags < 0) {
dev_err(di->dev, "error reading flag register:%d\n", flags);
return flags;
}
/* Unlikely but important to return first */ /* Unlikely but important to return first */
if (unlikely(bq27xxx_battery_overtemp(di, flags))) if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags)))
return POWER_SUPPLY_HEALTH_OVERHEAT; return POWER_SUPPLY_HEALTH_OVERHEAT;
if (unlikely(bq27xxx_battery_undertemp(di, flags))) if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags)))
return POWER_SUPPLY_HEALTH_COLD; return POWER_SUPPLY_HEALTH_COLD;
if (unlikely(bq27xxx_battery_dead(di, flags))) if (unlikely(bq27xxx_battery_dead(di, di->cache.flags)))
return POWER_SUPPLY_HEALTH_DEAD; return POWER_SUPPLY_HEALTH_DEAD;
return POWER_SUPPLY_HEALTH_GOOD; return POWER_SUPPLY_HEALTH_GOOD;
...@@ -1612,6 +1599,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) ...@@ -1612,6 +1599,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di)
cache.capacity = bq27xxx_battery_read_soc(di); cache.capacity = bq27xxx_battery_read_soc(di);
if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR)
cache.energy = bq27xxx_battery_read_energy(di); cache.energy = bq27xxx_battery_read_energy(di);
di->cache.flags = cache.flags;
cache.health = bq27xxx_battery_read_health(di); cache.health = bq27xxx_battery_read_health(di);
} }
if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* This driver enables to monitor battery health and control charger * This driver enables to monitor battery health and control charger
* during suspend-to-mem. * during suspend-to-mem.
* Charger manager depends on other devices. register this later than * Charger manager depends on other devices. Register this later than
* the depending devices. * the depending devices.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <linux/thermal.h> #include <linux/thermal.h>
/* /*
* Default termperature threshold for charging. * Default temperature threshold for charging.
* Every temperature units are in tenth of centigrade. * Every temperature units are in tenth of centigrade.
*/ */
#define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 #define CM_DEFAULT_RECHARGE_TEMP_DIFF 50
...@@ -356,7 +356,7 @@ static bool is_polling_required(struct charger_manager *cm) ...@@ -356,7 +356,7 @@ static bool is_polling_required(struct charger_manager *cm)
* Note that Charger Manager keeps the charger enabled regardless whether * Note that Charger Manager keeps the charger enabled regardless whether
* the charger is charging or not (because battery is full or no external * the charger is charging or not (because battery is full or no external
* power source exists) except when CM needs to disable chargers forcibly * power source exists) except when CM needs to disable chargers forcibly
* bacause of emergency causes; when the battery is overheated or too cold. * because of emergency causes; when the battery is overheated or too cold.
*/ */
static int try_charger_enable(struct charger_manager *cm, bool enable) static int try_charger_enable(struct charger_manager *cm, bool enable)
{ {
...@@ -643,7 +643,7 @@ static int cm_check_thermal_status(struct charger_manager *cm) ...@@ -643,7 +643,7 @@ static int cm_check_thermal_status(struct charger_manager *cm)
if (ret) { if (ret) {
/* FIXME: /* FIXME:
* No information of battery temperature might * No information of battery temperature might
* occur hazadous result. We have to handle it * occur hazardous result. We have to handle it
* depending on battery type. * depending on battery type.
*/ */
dev_err(cm->dev, "Failed to get battery temperature\n"); dev_err(cm->dev, "Failed to get battery temperature\n");
...@@ -693,7 +693,7 @@ static bool _cm_monitor(struct charger_manager *cm) ...@@ -693,7 +693,7 @@ static bool _cm_monitor(struct charger_manager *cm)
uevent_notify(cm, default_event_names[temp_alrt]); uevent_notify(cm, default_event_names[temp_alrt]);
/* /*
* Check whole charging duration and discharing duration * Check whole charging duration and discharging duration
* after full-batt. * after full-batt.
*/ */
} else if (!cm->emergency_stop && check_charging_duration(cm)) { } else if (!cm->emergency_stop && check_charging_duration(cm)) {
...@@ -866,7 +866,7 @@ static void battout_handler(struct charger_manager *cm) ...@@ -866,7 +866,7 @@ static void battout_handler(struct charger_manager *cm)
} }
/** /**
* misc_event_handler - Handler for other evnets * misc_event_handler - Handler for other events
* @cm: the Charger Manager representing the battery. * @cm: the Charger Manager representing the battery.
* @type: the Charger Manager representing the battery. * @type: the Charger Manager representing the battery.
*/ */
...@@ -1218,7 +1218,7 @@ static int charger_extcon_init(struct charger_manager *cm, ...@@ -1218,7 +1218,7 @@ static int charger_extcon_init(struct charger_manager *cm,
} }
/** /**
* charger_manager_register_extcon - Register extcon device to recevie state * charger_manager_register_extcon - Register extcon device to receive state
* of charger cable. * of charger cable.
* @cm: the Charger Manager representing the battery. * @cm: the Charger Manager representing the battery.
* *
...@@ -1538,7 +1538,7 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) ...@@ -1538,7 +1538,7 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
of_property_read_u32(np, "cm-discharging-max", of_property_read_u32(np, "cm-discharging-max",
&desc->discharging_max_duration_ms); &desc->discharging_max_duration_ms);
/* battery charger regualtors */ /* battery charger regulators */
desc->num_charger_regulators = of_get_child_count(np); desc->num_charger_regulators = of_get_child_count(np);
if (desc->num_charger_regulators) { if (desc->num_charger_regulators) {
struct charger_regulator *chg_regs; struct charger_regulator *chg_regs;
...@@ -1801,7 +1801,7 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1801,7 +1801,7 @@ static int charger_manager_probe(struct platform_device *pdev)
/* /*
* Charger-manager have to check the charging state right after * Charger-manager have to check the charging state right after
* tialization of charger-manager and then update current charging * initialization of charger-manager and then update current charging
* state. * state.
*/ */
cm_monitor(); cm_monitor();
......
...@@ -458,6 +458,7 @@ static void cpcap_usb_detect(struct work_struct *work) ...@@ -458,6 +458,7 @@ static void cpcap_usb_detect(struct work_struct *work)
goto out_err; goto out_err;
} }
power_supply_changed(ddata->usb);
return; return;
out_err: out_err:
......
...@@ -319,17 +319,17 @@ static void ds278x_power_supply_init(struct power_supply_desc *battery) ...@@ -319,17 +319,17 @@ static void ds278x_power_supply_init(struct power_supply_desc *battery)
static int ds278x_battery_remove(struct i2c_client *client) static int ds278x_battery_remove(struct i2c_client *client)
{ {
struct ds278x_info *info = i2c_get_clientdata(client); struct ds278x_info *info = i2c_get_clientdata(client);
int id = info->id;
power_supply_unregister(info->battery); power_supply_unregister(info->battery);
cancel_delayed_work_sync(&info->bat_work);
kfree(info->battery_desc.name); kfree(info->battery_desc.name);
kfree(info);
mutex_lock(&battery_lock); mutex_lock(&battery_lock);
idr_remove(&battery_id, info->id); idr_remove(&battery_id, id);
mutex_unlock(&battery_lock); mutex_unlock(&battery_lock);
cancel_delayed_work(&info->bat_work);
kfree(info);
return 0; return 0;
} }
......
// SPDX-License-Identifier: GPL
/* /*
* Power supply driver for the goldfish emulator * Power supply driver for the goldfish emulator
* *
...@@ -5,15 +6,6 @@ ...@@ -5,15 +6,6 @@
* Copyright (C) 2012 Intel, Inc. * Copyright (C) 2012 Intel, Inc.
* Copyright (C) 2013 Intel, Inc. * Copyright (C) 2013 Intel, Inc.
* Author: Mike Lockwood <lockwood@android.com> * Author: Mike Lockwood <lockwood@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -40,27 +32,30 @@ struct goldfish_battery_data { ...@@ -40,27 +32,30 @@ struct goldfish_battery_data {
#define GOLDFISH_BATTERY_WRITE(data, addr, x) \ #define GOLDFISH_BATTERY_WRITE(data, addr, x) \
(writel(x, data->reg_base + addr)) (writel(x, data->reg_base + addr))
/*
* Temporary variable used between goldfish_battery_probe() and
* goldfish_battery_open().
*/
static struct goldfish_battery_data *battery_data;
enum { enum {
/* status register */ /* status register */
BATTERY_INT_STATUS = 0x00, BATTERY_INT_STATUS = 0x00,
/* set this to enable IRQ */ /* set this to enable IRQ */
BATTERY_INT_ENABLE = 0x04, BATTERY_INT_ENABLE = 0x04,
BATTERY_AC_ONLINE = 0x08, BATTERY_AC_ONLINE = 0x08,
BATTERY_STATUS = 0x0C, BATTERY_STATUS = 0x0C,
BATTERY_HEALTH = 0x10, BATTERY_HEALTH = 0x10,
BATTERY_PRESENT = 0x14, BATTERY_PRESENT = 0x14,
BATTERY_CAPACITY = 0x18, BATTERY_CAPACITY = 0x18,
BATTERY_VOLTAGE = 0x1C,
BATTERY_TEMP = 0x20,
BATTERY_CHARGE_COUNTER = 0x24,
BATTERY_VOLTAGE_MAX = 0x28,
BATTERY_CURRENT_MAX = 0x2C,
BATTERY_CURRENT_NOW = 0x30,
BATTERY_CURRENT_AVG = 0x34,
BATTERY_CHARGE_FULL_UAH = 0x38,
BATTERY_CYCLE_COUNT = 0x40,
BATTERY_STATUS_CHANGED = 1U << 0, BATTERY_STATUS_CHANGED = 1U << 0,
AC_STATUS_CHANGED = 1U << 1, AC_STATUS_CHANGED = 1U << 1,
BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
}; };
...@@ -75,6 +70,12 @@ static int goldfish_ac_get_property(struct power_supply *psy, ...@@ -75,6 +70,12 @@ static int goldfish_ac_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_ONLINE:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE); val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE_MAX);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_MAX);
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -105,6 +106,29 @@ static int goldfish_battery_get_property(struct power_supply *psy, ...@@ -105,6 +106,29 @@ static int goldfish_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY: case POWER_SUPPLY_PROP_CAPACITY:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY); val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE);
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_TEMP);
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
val->intval = GOLDFISH_BATTERY_READ(data,
BATTERY_CHARGE_COUNTER);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_NOW);
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_AVG);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
val->intval = GOLDFISH_BATTERY_READ(data,
BATTERY_CHARGE_FULL_UAH);
break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CYCLE_COUNT);
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -119,10 +143,19 @@ static enum power_supply_property goldfish_battery_props[] = { ...@@ -119,10 +143,19 @@ static enum power_supply_property goldfish_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CYCLE_COUNT,
}; };
static enum power_supply_property goldfish_ac_props[] = { static enum power_supply_property goldfish_ac_props[] = {
POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CURRENT_MAX,
}; };
static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id) static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
...@@ -193,8 +226,9 @@ static int goldfish_battery_probe(struct platform_device *pdev) ...@@ -193,8 +226,9 @@ static int goldfish_battery_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt, ret = devm_request_irq(&pdev->dev, data->irq,
IRQF_SHARED, pdev->name, data); goldfish_battery_interrupt,
IRQF_SHARED, pdev->name, data);
if (ret) if (ret)
return ret; return ret;
...@@ -212,7 +246,6 @@ static int goldfish_battery_probe(struct platform_device *pdev) ...@@ -212,7 +246,6 @@ static int goldfish_battery_probe(struct platform_device *pdev)
} }
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
battery_data = data;
GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
return 0; return 0;
...@@ -224,7 +257,6 @@ static int goldfish_battery_remove(struct platform_device *pdev) ...@@ -224,7 +257,6 @@ static int goldfish_battery_remove(struct platform_device *pdev)
power_supply_unregister(data->battery); power_supply_unregister(data->battery);
power_supply_unregister(data->ac); power_supply_unregister(data->ac);
battery_data = NULL;
return 0; return 0;
} }
......
...@@ -30,13 +30,12 @@ ...@@ -30,13 +30,12 @@
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/usb/ulpi.h> #include <linux/usb/ulpi.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/power/isp1704_charger.h>
/* Vendor specific Power Control register */ /* Vendor specific Power Control register */
#define ISP1704_PWR_CTRL 0x3d #define ISP1704_PWR_CTRL 0x3d
...@@ -60,6 +59,7 @@ struct isp1704_charger { ...@@ -60,6 +59,7 @@ struct isp1704_charger {
struct device *dev; struct device *dev;
struct power_supply *psy; struct power_supply *psy;
struct power_supply_desc psy_desc; struct power_supply_desc psy_desc;
struct gpio_desc *enable_gpio;
struct usb_phy *phy; struct usb_phy *phy;
struct notifier_block nb; struct notifier_block nb;
struct work_struct work; struct work_struct work;
...@@ -81,18 +81,9 @@ static inline int isp1704_write(struct isp1704_charger *isp, u32 reg, u32 val) ...@@ -81,18 +81,9 @@ static inline int isp1704_write(struct isp1704_charger *isp, u32 reg, u32 val)
return usb_phy_io_write(isp->phy, val, reg); return usb_phy_io_write(isp->phy, val, reg);
} }
/*
* Disable/enable the power from the isp1704 if a function for it
* has been provided with platform data.
*/
static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on)
{ {
struct isp1704_charger_data *board = isp->dev->platform_data; gpiod_set_value(isp->enable_gpio, on);
if (board && board->set_power)
board->set_power(on);
else if (board)
gpio_set_value(board->enable_gpio, on);
} }
/* /*
...@@ -405,46 +396,19 @@ static int isp1704_charger_probe(struct platform_device *pdev) ...@@ -405,46 +396,19 @@ static int isp1704_charger_probe(struct platform_device *pdev)
int ret = -ENODEV; int ret = -ENODEV;
struct power_supply_config psy_cfg = {}; struct power_supply_config psy_cfg = {};
struct isp1704_charger_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
if (np) {
int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0);
if (gpio < 0) {
dev_err(&pdev->dev, "missing DT GPIO nxp,enable-gpio\n");
return gpio;
}
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct isp1704_charger_data), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto fail0;
}
pdata->enable_gpio = gpio;
dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio);
ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
GPIOF_OUT_INIT_HIGH, "isp1704_reset");
if (ret) {
dev_err(&pdev->dev, "gpio request failed\n");
goto fail0;
}
}
if (!pdata) {
dev_err(&pdev->dev, "missing platform data!\n");
return -ENODEV;
}
isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
if (!isp) if (!isp)
return -ENOMEM; return -ENOMEM;
if (np) isp->enable_gpio = devm_gpiod_get(&pdev->dev, "nxp,enable",
GPIOD_OUT_HIGH);
if (IS_ERR(isp->enable_gpio)) {
ret = PTR_ERR(isp->enable_gpio);
dev_err(&pdev->dev, "Could not get reset gpio: %d\n", ret);
return ret;
}
if (pdev->dev.of_node)
isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
else else
isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
......
...@@ -995,6 +995,13 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = { ...@@ -995,6 +995,13 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
.num_properties = ARRAY_SIZE(max17042_battery_props) - 2, .num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
}; };
static void max17042_stop_work(void *data)
{
struct max17042_chip *chip = data;
cancel_work_sync(&chip->work);
}
static int max17042_probe(struct i2c_client *client, static int max17042_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -1101,6 +1108,9 @@ static int max17042_probe(struct i2c_client *client, ...@@ -1101,6 +1108,9 @@ static int max17042_probe(struct i2c_client *client,
regmap_read(chip->regmap, MAX17042_STATUS, &val); regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (val & STATUS_POR_BIT) { if (val & STATUS_POR_BIT) {
INIT_WORK(&chip->work, max17042_init_worker); INIT_WORK(&chip->work, max17042_init_worker);
ret = devm_add_action(&client->dev, max17042_stop_work, chip);
if (ret)
return ret;
schedule_work(&chip->work); schedule_work(&chip->work);
} else { } else {
chip->init_complete = 1; chip->init_complete = 1;
......
...@@ -156,8 +156,6 @@ static void power_supply_deferred_register_work(struct work_struct *work) ...@@ -156,8 +156,6 @@ static void power_supply_deferred_register_work(struct work_struct *work)
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
#include <linux/of.h>
static int __power_supply_populate_supplied_from(struct device *dev, static int __power_supply_populate_supplied_from(struct device *dev,
void *data) void *data)
{ {
...@@ -575,6 +573,7 @@ int power_supply_get_battery_info(struct power_supply *psy, ...@@ -575,6 +573,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->energy_full_design_uwh = -EINVAL; info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL; info->charge_full_design_uah = -EINVAL;
info->voltage_min_design_uv = -EINVAL; info->voltage_min_design_uv = -EINVAL;
info->voltage_max_design_uv = -EINVAL;
info->precharge_current_ua = -EINVAL; info->precharge_current_ua = -EINVAL;
info->charge_term_current_ua = -EINVAL; info->charge_term_current_ua = -EINVAL;
info->constant_charge_current_max_ua = -EINVAL; info->constant_charge_current_max_ua = -EINVAL;
...@@ -615,6 +614,8 @@ int power_supply_get_battery_info(struct power_supply *psy, ...@@ -615,6 +614,8 @@ int power_supply_get_battery_info(struct power_supply *psy,
&info->charge_full_design_uah); &info->charge_full_design_uah);
of_property_read_u32(battery_np, "voltage-min-design-microvolt", of_property_read_u32(battery_np, "voltage-min-design-microvolt",
&info->voltage_min_design_uv); &info->voltage_min_design_uv);
of_property_read_u32(battery_np, "voltage-max-design-microvolt",
&info->voltage_max_design_uv);
of_property_read_u32(battery_np, "precharge-current-microamp", of_property_read_u32(battery_np, "precharge-current-microamp",
&info->precharge_current_ua); &info->precharge_current_ua);
of_property_read_u32(battery_np, "charge-term-current-microamp", of_property_read_u32(battery_np, "charge-term-current-microamp",
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
* @lock: protect the structure * @lock: protect the structure
* @gpiod: GPIO for battery detection * @gpiod: GPIO for battery detection
* @channel: IIO channel to get battery temperature * @channel: IIO channel to get battery temperature
* @charge_chan: IIO channel to get charge voltage
* @internal_resist: the battery internal resistance in mOhm * @internal_resist: the battery internal resistance in mOhm
* @total_cap: the total capacity of the battery in mAh * @total_cap: the total capacity of the battery in mAh
* @init_cap: the initial capacity of the battery in mAh * @init_cap: the initial capacity of the battery in mAh
...@@ -92,6 +93,7 @@ struct sc27xx_fgu_data { ...@@ -92,6 +93,7 @@ struct sc27xx_fgu_data {
struct mutex lock; struct mutex lock;
struct gpio_desc *gpiod; struct gpio_desc *gpiod;
struct iio_channel *channel; struct iio_channel *channel;
struct iio_channel *charge_chan;
bool bat_present; bool bat_present;
int internal_resist; int internal_resist;
int total_cap; int total_cap;
...@@ -169,10 +171,37 @@ static int sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data *data, ...@@ -169,10 +171,37 @@ static int sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data *data,
if (ret) if (ret)
return ret; return ret;
/*
* Since the user area registers are put on power always-on region,
* then these registers changing time will be a little long. Thus
* here we should delay 200us to wait until values are updated
* successfully according to the datasheet.
*/
udelay(200);
ret = regmap_update_bits(data->regmap,
data->base + SC27XX_FGU_USER_AREA_SET,
SC27XX_FGU_MODE_AREA_MASK,
boot_mode << SC27XX_FGU_MODE_AREA_SHIFT);
if (ret)
return ret;
/*
* Since the user area registers are put on power always-on region,
* then these registers changing time will be a little long. Thus
* here we should delay 200us to wait until values are updated
* successfully according to the datasheet.
*/
udelay(200);
/*
* According to the datasheet, we should set the USER_AREA_CLEAR to 0 to
* make the user area data available, otherwise we can not save the user
* area data.
*/
return regmap_update_bits(data->regmap, return regmap_update_bits(data->regmap,
data->base + SC27XX_FGU_USER_AREA_SET, data->base + SC27XX_FGU_USER_AREA_CLEAR,
SC27XX_FGU_MODE_AREA_MASK, SC27XX_FGU_MODE_AREA_MASK, 0);
boot_mode << SC27XX_FGU_MODE_AREA_SHIFT);
} }
static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap) static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap)
...@@ -186,9 +215,36 @@ static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap) ...@@ -186,9 +215,36 @@ static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap)
if (ret) if (ret)
return ret; return ret;
/*
* Since the user area registers are put on power always-on region,
* then these registers changing time will be a little long. Thus
* here we should delay 200us to wait until values are updated
* successfully according to the datasheet.
*/
udelay(200);
ret = regmap_update_bits(data->regmap,
data->base + SC27XX_FGU_USER_AREA_SET,
SC27XX_FGU_CAP_AREA_MASK, cap);
if (ret)
return ret;
/*
* Since the user area registers are put on power always-on region,
* then these registers changing time will be a little long. Thus
* here we should delay 200us to wait until values are updated
* successfully according to the datasheet.
*/
udelay(200);
/*
* According to the datasheet, we should set the USER_AREA_CLEAR to 0 to
* make the user area data available, otherwise we can not save the user
* area data.
*/
return regmap_update_bits(data->regmap, return regmap_update_bits(data->regmap,
data->base + SC27XX_FGU_USER_AREA_SET, data->base + SC27XX_FGU_USER_AREA_CLEAR,
SC27XX_FGU_CAP_AREA_MASK, cap); SC27XX_FGU_CAP_AREA_MASK, 0);
} }
static int sc27xx_fgu_read_last_cap(struct sc27xx_fgu_data *data, int *cap) static int sc27xx_fgu_read_last_cap(struct sc27xx_fgu_data *data, int *cap)
...@@ -391,6 +447,18 @@ static int sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data *data, int *val) ...@@ -391,6 +447,18 @@ static int sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data *data, int *val)
return 0; return 0;
} }
static int sc27xx_fgu_get_charge_vol(struct sc27xx_fgu_data *data, int *val)
{
int ret, vol;
ret = iio_read_channel_processed(data->charge_chan, &vol);
if (ret < 0)
return ret;
*val = vol * 1000;
return 0;
}
static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp) static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp)
{ {
return iio_read_channel_processed(data->channel, temp); return iio_read_channel_processed(data->channel, temp);
...@@ -502,6 +570,14 @@ static int sc27xx_fgu_get_property(struct power_supply *psy, ...@@ -502,6 +570,14 @@ static int sc27xx_fgu_get_property(struct power_supply *psy,
val->intval = value; val->intval = value;
break; break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = sc27xx_fgu_get_charge_vol(data, &value);
if (ret)
goto error;
val->intval = value;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_CURRENT_AVG:
ret = sc27xx_fgu_get_current(data, &value); ret = sc27xx_fgu_get_current(data, &value);
...@@ -567,6 +643,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { ...@@ -567,6 +643,7 @@ static enum power_supply_property sc27xx_fgu_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
}; };
static const struct power_supply_desc sc27xx_fgu_desc = { static const struct power_supply_desc sc27xx_fgu_desc = {
...@@ -708,7 +785,7 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity) ...@@ -708,7 +785,7 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity)
* Convert current capacity (mAh) to coulomb counter according to the * Convert current capacity (mAh) to coulomb counter according to the
* formula: 1 mAh =3.6 coulomb. * formula: 1 mAh =3.6 coulomb.
*/ */
return DIV_ROUND_CLOSEST(cur_cap * 36, 10); return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc, 10);
} }
static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data)
...@@ -907,6 +984,12 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) ...@@ -907,6 +984,12 @@ static int sc27xx_fgu_probe(struct platform_device *pdev)
return PTR_ERR(data->channel); return PTR_ERR(data->channel);
} }
data->charge_chan = devm_iio_channel_get(&pdev->dev, "charge-vol");
if (IS_ERR(data->charge_chan)) {
dev_err(&pdev->dev, "failed to get charge IIO channel\n");
return PTR_ERR(data->charge_chan);
}
data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN); data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN);
if (IS_ERR(data->gpiod)) { if (IS_ERR(data->gpiod)) {
dev_err(&pdev->dev, "failed to get battery detection GPIO\n"); dev_err(&pdev->dev, "failed to get battery detection GPIO\n");
......
...@@ -809,7 +809,9 @@ static int twl4030_bci_get_property(struct power_supply *psy, ...@@ -809,7 +809,9 @@ static int twl4030_bci_get_property(struct power_supply *psy,
is_charging = state & TWL4030_MSTATEC_AC; is_charging = state & TWL4030_MSTATEC_AC;
if (!is_charging) { if (!is_charging) {
u8 s; u8 s;
twl4030_bci_read(TWL4030_BCIMDEN, &s); ret = twl4030_bci_read(TWL4030_BCIMDEN, &s);
if (ret < 0)
return ret;
if (psy->desc->type == POWER_SUPPLY_TYPE_USB) if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
is_charging = s & 1; is_charging = s & 1;
else else
......
/*
* ISP1704 USB Charger Detection driver
*
* Copyright (C) 2011 Nokia Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ISP1704_CHARGER_H
#define __ISP1704_CHARGER_H
struct isp1704_charger_data {
void (*set_power)(bool on);
int enable_gpio;
};
#endif
...@@ -332,6 +332,7 @@ struct power_supply_battery_info { ...@@ -332,6 +332,7 @@ struct power_supply_battery_info {
int energy_full_design_uwh; /* microWatt-hours */ int energy_full_design_uwh; /* microWatt-hours */
int charge_full_design_uah; /* microAmp-hours */ int charge_full_design_uah; /* microAmp-hours */
int voltage_min_design_uv; /* microVolts */ int voltage_min_design_uv; /* microVolts */
int voltage_max_design_uv; /* microVolts */
int precharge_current_ua; /* microAmps */ int precharge_current_ua; /* microAmps */
int charge_term_current_ua; /* microAmps */ int charge_term_current_ua; /* microAmps */
int constant_charge_current_max_ua; /* microAmps */ int constant_charge_current_max_ua; /* microAmps */
......
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