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:
RSTC Reset Controller required properties:
- 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
- clocks: phandle to input clock.
......
......@@ -16,6 +16,7 @@ Required Properties:
Optional Properties:
- voltage-min-design-microvolt: drained battery voltage
- voltage-max-design-microvolt: fully charged battery voltage
- energy-full-design-microwatt-hours: battery design energy
- charge-full-design-microamp-hours: battery design capacity
- precharge-current-microamp: current for pre-charge phase
......@@ -48,6 +49,7 @@ Example:
bat: battery {
compatible = "simple-battery";
voltage-min-design-microvolt = <3200000>;
voltage-max-design-microvolt = <4200000>;
energy-full-design-microwatt-hours = <5290000>;
charge-full-design-microamp-hours = <1430000>;
precharge-current-microamp = <256000>;
......
......@@ -9,8 +9,8 @@ Required properties:
"sprd,sc2731-fgu".
- reg: The address offset of fuel gauge unit.
- battery-detect-gpios: GPIO for battery detection.
- io-channels: Specify the IIO ADC channel to get temperature.
- io-channel-names: Should be "bat-temp".
- io-channels: Specify the IIO ADC channels to get temperature and charge voltage.
- io-channel-names: Should be "bat-temp" or "charge-vol".
- nvmem-cells: A phandle to the calibration cells provided by eFuse device.
- nvmem-cell-names: Should be "fgu_calib".
- monitored-battery: Phandle of battery characteristics devicetree node.
......@@ -47,8 +47,8 @@ Example:
compatible = "sprd,sc2731-fgu";
reg = <0xa00>;
battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>;
io-channels = <&pmic_adc 5>;
io-channel-names = "bat-temp";
io-channels = <&pmic_adc 5>, <&pmic_adc 14>;
io-channel-names = "bat-temp", "charge-vol";
nvmem-cells = <&fgu_calib>;
nvmem-cell-names = "fgu_calib";
monitored-battery = <&bat>;
......
......@@ -44,6 +44,9 @@ enum reset_type {
RESET_TYPE_WATCHDOG = 2,
RESET_TYPE_SOFTWARE = 3,
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;
......@@ -164,6 +167,15 @@ static void __init at91_reset_status(struct platform_device *pdev)
case RESET_TYPE_USER:
reason = "user reset";
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:
reason = "unknown reset";
break;
......@@ -183,6 +195,7 @@ static const struct of_device_id at91_reset_of_match[] = {
{ .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
{ .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
{ .compatible = "atmel,samx7-rstc", .data = samx7_restart },
{ .compatible = "microchip,sam9x60-rstc", .data = samx7_restart },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at91_reset_of_match);
......
......@@ -307,22 +307,12 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data)
return 0;
}
static int debug_open(struct inode *inode, struct file *file)
{
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,
};
DEFINE_SHOW_ATTRIBUTE(fuel_gauge_debug);
static void fuel_gauge_create_debugfs(struct axp288_fg_info *info)
{
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)
......
......@@ -436,7 +436,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break;
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;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
......@@ -454,7 +454,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break;
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;
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
......
......@@ -1555,27 +1555,14 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
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)
{
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 */
if (unlikely(bq27xxx_battery_overtemp(di, flags)))
if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags)))
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;
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_GOOD;
......@@ -1612,6 +1599,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di)
cache.capacity = bq27xxx_battery_read_soc(di);
if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR)
cache.energy = bq27xxx_battery_read_energy(di);
di->cache.flags = cache.flags;
cache.health = bq27xxx_battery_read_health(di);
}
if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR)
......
......@@ -4,7 +4,7 @@
*
* This driver enables to monitor battery health and control charger
* 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.
*
* This program is free software; you can redistribute it and/or modify
......@@ -29,7 +29,7 @@
#include <linux/thermal.h>
/*
* Default termperature threshold for charging.
* Default temperature threshold for charging.
* Every temperature units are in tenth of centigrade.
*/
#define CM_DEFAULT_RECHARGE_TEMP_DIFF 50
......@@ -356,7 +356,7 @@ static bool is_polling_required(struct charger_manager *cm)
* Note that Charger Manager keeps the charger enabled regardless whether
* the charger is charging or not (because battery is full or no external
* 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)
{
......@@ -643,7 +643,7 @@ static int cm_check_thermal_status(struct charger_manager *cm)
if (ret) {
/* FIXME:
* 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.
*/
dev_err(cm->dev, "Failed to get battery temperature\n");
......@@ -693,7 +693,7 @@ static bool _cm_monitor(struct charger_manager *cm)
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.
*/
} else if (!cm->emergency_stop && check_charging_duration(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.
* @type: the Charger Manager representing the battery.
*/
......@@ -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.
* @cm: the Charger Manager representing the battery.
*
......@@ -1538,7 +1538,7 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
of_property_read_u32(np, "cm-discharging-max",
&desc->discharging_max_duration_ms);
/* battery charger regualtors */
/* battery charger regulators */
desc->num_charger_regulators = of_get_child_count(np);
if (desc->num_charger_regulators) {
struct charger_regulator *chg_regs;
......@@ -1801,7 +1801,7 @@ static int charger_manager_probe(struct platform_device *pdev)
/*
* 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.
*/
cm_monitor();
......
......@@ -458,6 +458,7 @@ static void cpcap_usb_detect(struct work_struct *work)
goto out_err;
}
power_supply_changed(ddata->usb);
return;
out_err:
......
......@@ -319,17 +319,17 @@ static void ds278x_power_supply_init(struct power_supply_desc *battery)
static int ds278x_battery_remove(struct i2c_client *client)
{
struct ds278x_info *info = i2c_get_clientdata(client);
int id = info->id;
power_supply_unregister(info->battery);
cancel_delayed_work_sync(&info->bat_work);
kfree(info->battery_desc.name);
kfree(info);
mutex_lock(&battery_lock);
idr_remove(&battery_id, info->id);
idr_remove(&battery_id, id);
mutex_unlock(&battery_lock);
cancel_delayed_work(&info->bat_work);
kfree(info);
return 0;
}
......
// SPDX-License-Identifier: GPL
/*
* Power supply driver for the goldfish emulator
*
......@@ -5,15 +6,6 @@
* Copyright (C) 2012 Intel, Inc.
* Copyright (C) 2013 Intel, Inc.
* 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>
......@@ -40,27 +32,30 @@ struct goldfish_battery_data {
#define GOLDFISH_BATTERY_WRITE(data, addr, x) \
(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 {
/* status register */
BATTERY_INT_STATUS = 0x00,
BATTERY_INT_STATUS = 0x00,
/* set this to enable IRQ */
BATTERY_INT_ENABLE = 0x04,
BATTERY_AC_ONLINE = 0x08,
BATTERY_STATUS = 0x0C,
BATTERY_HEALTH = 0x10,
BATTERY_PRESENT = 0x14,
BATTERY_CAPACITY = 0x18,
BATTERY_INT_ENABLE = 0x04,
BATTERY_AC_ONLINE = 0x08,
BATTERY_STATUS = 0x0C,
BATTERY_HEALTH = 0x10,
BATTERY_PRESENT = 0x14,
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,
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,
case POWER_SUPPLY_PROP_ONLINE:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
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:
ret = -EINVAL;
break;
......@@ -105,6 +106,29 @@ static int goldfish_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
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:
ret = -EINVAL;
break;
......@@ -119,10 +143,19 @@ static enum power_supply_property goldfish_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
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[] = {
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)
......@@ -193,8 +226,9 @@ static int goldfish_battery_probe(struct platform_device *pdev)
return -ENODEV;
}
ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt,
IRQF_SHARED, pdev->name, data);
ret = devm_request_irq(&pdev->dev, data->irq,
goldfish_battery_interrupt,
IRQF_SHARED, pdev->name, data);
if (ret)
return ret;
......@@ -212,7 +246,6 @@ static int goldfish_battery_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, data);
battery_data = data;
GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
return 0;
......@@ -224,7 +257,6 @@ static int goldfish_battery_remove(struct platform_device *pdev)
power_supply_unregister(data->battery);
power_supply_unregister(data->ac);
battery_data = NULL;
return 0;
}
......
......@@ -30,13 +30,12 @@
#include <linux/power_supply.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/power/isp1704_charger.h>
/* Vendor specific Power Control register */
#define ISP1704_PWR_CTRL 0x3d
......@@ -60,6 +59,7 @@ struct isp1704_charger {
struct device *dev;
struct power_supply *psy;
struct power_supply_desc psy_desc;
struct gpio_desc *enable_gpio;
struct usb_phy *phy;
struct notifier_block nb;
struct work_struct work;
......@@ -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);
}
/*
* 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)
{
struct isp1704_charger_data *board = isp->dev->platform_data;
if (board && board->set_power)
board->set_power(on);
else if (board)
gpio_set_value(board->enable_gpio, on);
gpiod_set_value(isp->enable_gpio, on);
}
/*
......@@ -405,46 +396,19 @@ static int isp1704_charger_probe(struct platform_device *pdev)
int ret = -ENODEV;
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);
if (!isp)
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);
else
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 = {
.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,
const struct i2c_device_id *id)
{
......@@ -1101,6 +1108,9 @@ static int max17042_probe(struct i2c_client *client,
regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (val & STATUS_POR_BIT) {
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);
} else {
chip->init_complete = 1;
......
......@@ -156,8 +156,6 @@ static void power_supply_deferred_register_work(struct work_struct *work)
}
#ifdef CONFIG_OF
#include <linux/of.h>
static int __power_supply_populate_supplied_from(struct device *dev,
void *data)
{
......@@ -575,6 +573,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL;
info->voltage_min_design_uv = -EINVAL;
info->voltage_max_design_uv = -EINVAL;
info->precharge_current_ua = -EINVAL;
info->charge_term_current_ua = -EINVAL;
info->constant_charge_current_max_ua = -EINVAL;
......@@ -615,6 +614,8 @@ int power_supply_get_battery_info(struct power_supply *psy,
&info->charge_full_design_uah);
of_property_read_u32(battery_np, "voltage-min-design-microvolt",
&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",
&info->precharge_current_ua);
of_property_read_u32(battery_np, "charge-term-current-microamp",
......
......@@ -72,6 +72,7 @@
* @lock: protect the structure
* @gpiod: GPIO for battery detection
* @channel: IIO channel to get battery temperature
* @charge_chan: IIO channel to get charge voltage
* @internal_resist: the battery internal resistance in mOhm
* @total_cap: the total capacity of the battery in mAh
* @init_cap: the initial capacity of the battery in mAh
......@@ -92,6 +93,7 @@ struct sc27xx_fgu_data {
struct mutex lock;
struct gpio_desc *gpiod;
struct iio_channel *channel;
struct iio_channel *charge_chan;
bool bat_present;
int internal_resist;
int total_cap;
......@@ -169,10 +171,37 @@ static int sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data *data,
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);
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,
data->base + SC27XX_FGU_USER_AREA_SET,
SC27XX_FGU_MODE_AREA_MASK,
boot_mode << SC27XX_FGU_MODE_AREA_SHIFT);
data->base + SC27XX_FGU_USER_AREA_CLEAR,
SC27XX_FGU_MODE_AREA_MASK, 0);
}
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)
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,
data->base + SC27XX_FGU_USER_AREA_SET,
SC27XX_FGU_CAP_AREA_MASK, cap);
data->base + SC27XX_FGU_USER_AREA_CLEAR,
SC27XX_FGU_CAP_AREA_MASK, 0);
}
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)
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)
{
return iio_read_channel_processed(data->channel, temp);
......@@ -502,6 +570,14 @@ static int sc27xx_fgu_get_property(struct power_supply *psy,
val->intval = value;
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_AVG:
ret = sc27xx_fgu_get_current(data, &value);
......@@ -567,6 +643,7 @@ static enum power_supply_property sc27xx_fgu_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
};
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)
* Convert current capacity (mAh) to coulomb counter according to the
* 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)
......@@ -907,6 +984,12 @@ static int sc27xx_fgu_probe(struct platform_device *pdev)
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);
if (IS_ERR(data->gpiod)) {
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,
is_charging = state & TWL4030_MSTATEC_AC;
if (!is_charging) {
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)
is_charging = s & 1;
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 {
int energy_full_design_uwh; /* microWatt-hours */
int charge_full_design_uah; /* microAmp-hours */
int voltage_min_design_uv; /* microVolts */
int voltage_max_design_uv; /* microVolts */
int precharge_current_ua; /* microAmps */
int charge_term_current_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