Commit a22a0fdb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v3.12' of git://git.infradead.org/battery-2.6

Pull battery/power supply driver updates from Anton Vorontsov:
 "New drivers:

   - APM X-Gene system reboot driver by Feng Kan and Loc Ho (APM).

   - Qualcomm MSM reboot/poweroff driver by Abhimanyu Kapur (Codeaurora).

   - Texas Instruments BQ24190 charger driver by Mark A.  Greer (Animal
     Creek Technologies).

   - Texas Instruments TWL4030 MADC battery driver by Lukas Märdian and
     Marek Belisko (Golden Delicious Computers).  The driver is used on
     Freerunner GTA04 phones.

  Highlighted fixes and improvements:

   - Suspend/wakeup logic improvements: power supply objects will block
     system suspend until all power supply events are processed.  Thanks
     to Zoran Markovic (Linaro), Arve Hjonnevag and Todd Poynor (Google)"

* tag 'for-v3.12' of git://git.infradead.org/battery-2.6:
  rx51_battery: Fix channel number when reading adc value
  power: Add twl4030_madc battery driver.
  bq24190_charger: Workaround SS definition problem on i386 builds
  power_supply: Prevent suspend until power supply events are processed
  vexpress-poweroff: Should depend on the required infrastructure
  twl4030-charger: Fix compiler warning with regulator_enable()
  rx51_battery: Replace hardcoded channels values.
  bq24190_charger: Add support for TI BQ24190 Battery Charger
  ab8500-charger: We print an unintended error message
  max8925_power: Fix missing of_node_put
  power_supply: Replace strict_strtol() with kstrtol()
  power: Add APM X-Gene system reboot driver
  power_supply: tosa_battery: Get rid of irq_to_gpio usage
  power supply: collie_battery: Convert to use dev_pm_ops
  power_supply: Make goldfish_battery depend on GOLDFISH || COMPILE_TEST
  power: reset: Add msm restart support
  MAINTAINERS: drivers/power: add entry for SmartReflex AVS drivers
parents bf83e614 db15e631
MSM Restart Driver
A power supply hold (ps-hold) bit is set to power the msm chipsets.
Clearing that bit allows us to restart/poweroff. The difference
between poweroff and restart is determined by unique power manager IC
settings.
Required Properties:
-compatible: "qcom,pshold"
-reg: Specifies the physical address of the ps-hold register
Example:
restart@fc4ab000 {
compatible = "qcom,pshold";
reg = <0xfc4ab000 0x4>;
};
...@@ -7624,6 +7624,14 @@ S: Maintained ...@@ -7624,6 +7624,14 @@ S: Maintained
F: Documentation/security/Smack.txt F: Documentation/security/Smack.txt
F: security/smack/ F: security/smack/
SMARTREFLEX DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
M: Kevin Hilman <khilman@kernel.org>
M: Nishanth Menon <nm@ti.com>
S: Maintained
F: drivers/power/avs/smartreflex.c
F: include/linux/power/smartreflex.h
L: linux-pm@vger.kernel.org
SMC91x ETHERNET DRIVER SMC91x ETHERNET DRIVER
M: Nicolas Pitre <nico@fluxnic.net> M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes S: Odd Fixes
......
...@@ -216,6 +216,13 @@ config BATTERY_S3C_ADC ...@@ -216,6 +216,13 @@ config BATTERY_S3C_ADC
help help
Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
config BATTERY_TWL4030_MADC
tristate "TWL4030 MADC battery driver"
depends on TWL4030_MADC
help
Say Y here to enable this dumb driver for batteries managed
through the TWL4030 MADC.
config CHARGER_88PM860X config CHARGER_88PM860X
tristate "Marvell 88PM860x Charger driver" tristate "Marvell 88PM860x Charger driver"
depends on MFD_88PM860X && BATTERY_88PM860X depends on MFD_88PM860X && BATTERY_88PM860X
...@@ -334,6 +341,12 @@ config CHARGER_BQ2415X ...@@ -334,6 +341,12 @@ config CHARGER_BQ2415X
You'll need this driver to charge batteries on e.g. Nokia You'll need this driver to charge batteries on e.g. Nokia
RX-51/N900. RX-51/N900.
config CHARGER_BQ24190
tristate "TI BQ24190 battery charger driver"
depends on I2C && GPIOLIB
help
Say Y to enable support for the TI BQ24190 battery charger.
config CHARGER_SMB347 config CHARGER_SMB347
tristate "Summit Microelectronics SMB347 Battery Charger" tristate "Summit Microelectronics SMB347 Battery Charger"
depends on I2C depends on I2C
...@@ -357,7 +370,7 @@ config AB8500_BM ...@@ -357,7 +370,7 @@ config AB8500_BM
config BATTERY_GOLDFISH config BATTERY_GOLDFISH
tristate "Goldfish battery driver" tristate "Goldfish battery driver"
depends on GENERIC_HARDIRQS depends on GENERIC_HARDIRQS && (GOLDFISH || COMPILE_TEST)
help help
Say Y to enable support for the battery and AC power in the Say Y to enable support for the battery and AC power in the
Goldfish emulator. Goldfish emulator.
......
...@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o ...@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
...@@ -50,6 +51,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o ...@@ -50,6 +51,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
......
...@@ -774,6 +774,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, ...@@ -774,6 +774,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
di->max_usb_in_curr.usb_type_max); di->max_usb_in_curr.usb_type_max);
break;
case USB_STAT_NOT_VALID_LINK: case USB_STAT_NOT_VALID_LINK:
dev_err(di->dev, "USB Type invalid - try charging anyway\n"); dev_err(di->dev, "USB Type invalid - try charging anyway\n");
di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
......
This diff is collapsed.
...@@ -287,7 +287,7 @@ static struct gpio collie_batt_gpios[] = { ...@@ -287,7 +287,7 @@ static struct gpio collie_batt_gpios[] = {
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) static int collie_bat_suspend(struct ucb1x00_dev *dev)
{ {
/* flush all pending status updates */ /* flush all pending status updates */
flush_work(&bat_work); flush_work(&bat_work);
......
...@@ -458,6 +458,7 @@ max8925_power_dt_init(struct platform_device *pdev) ...@@ -458,6 +458,7 @@ max8925_power_dt_init(struct platform_device *pdev)
of_property_read_u32(np, "fast-charge", &fast_charge); of_property_read_u32(np, "fast-charge", &fast_charge);
of_property_read_u32(np, "no-insert-detect", &no_insert_detect); of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
of_property_read_u32(np, "no-temp-support", &no_temp_support); of_property_read_u32(np, "no-temp-support", &no_temp_support);
of_node_put(np);
pdata->batt_detect = batt_detect; pdata->batt_detect = batt_detect;
pdata->fast_charge = fast_charge; pdata->fast_charge = fast_charge;
......
...@@ -67,23 +67,42 @@ static int __power_supply_changed_work(struct device *dev, void *data) ...@@ -67,23 +67,42 @@ static int __power_supply_changed_work(struct device *dev, void *data)
static void power_supply_changed_work(struct work_struct *work) static void power_supply_changed_work(struct work_struct *work)
{ {
unsigned long flags;
struct power_supply *psy = container_of(work, struct power_supply, struct power_supply *psy = container_of(work, struct power_supply,
changed_work); changed_work);
dev_dbg(psy->dev, "%s\n", __func__); dev_dbg(psy->dev, "%s\n", __func__);
spin_lock_irqsave(&psy->changed_lock, flags);
if (psy->changed) {
psy->changed = false;
spin_unlock_irqrestore(&psy->changed_lock, flags);
class_for_each_device(power_supply_class, NULL, psy, class_for_each_device(power_supply_class, NULL, psy,
__power_supply_changed_work); __power_supply_changed_work);
power_supply_update_leds(psy); power_supply_update_leds(psy);
kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
spin_lock_irqsave(&psy->changed_lock, flags);
}
/*
* Dependent power supplies (e.g. battery) may have changed state
* as a result of this event, so poll again and hold the
* wakeup_source until all events are processed.
*/
if (!psy->changed)
pm_relax(psy->dev);
spin_unlock_irqrestore(&psy->changed_lock, flags);
} }
void power_supply_changed(struct power_supply *psy) void power_supply_changed(struct power_supply *psy)
{ {
unsigned long flags;
dev_dbg(psy->dev, "%s\n", __func__); dev_dbg(psy->dev, "%s\n", __func__);
spin_lock_irqsave(&psy->changed_lock, flags);
psy->changed = true;
pm_stay_awake(psy->dev);
spin_unlock_irqrestore(&psy->changed_lock, flags);
schedule_work(&psy->changed_work); schedule_work(&psy->changed_work);
} }
EXPORT_SYMBOL_GPL(power_supply_changed); EXPORT_SYMBOL_GPL(power_supply_changed);
...@@ -500,6 +519,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy) ...@@ -500,6 +519,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto check_supplies_failed; goto check_supplies_failed;
} }
spin_lock_init(&psy->changed_lock);
rc = device_init_wakeup(dev, true);
if (rc)
goto wakeup_init_failed;
rc = kobject_set_name(&dev->kobj, "%s", psy->name); rc = kobject_set_name(&dev->kobj, "%s", psy->name);
if (rc) if (rc)
goto kobject_set_name_failed; goto kobject_set_name_failed;
...@@ -529,6 +553,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy) ...@@ -529,6 +553,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
register_cooler_failed: register_cooler_failed:
psy_unregister_thermal(psy); psy_unregister_thermal(psy);
register_thermal_failed: register_thermal_failed:
wakeup_init_failed:
device_del(dev); device_del(dev);
kobject_set_name_failed: kobject_set_name_failed:
device_add_failed: device_add_failed:
...@@ -546,6 +571,7 @@ void power_supply_unregister(struct power_supply *psy) ...@@ -546,6 +571,7 @@ void power_supply_unregister(struct power_supply *psy)
power_supply_remove_triggers(psy); power_supply_remove_triggers(psy);
psy_unregister_cooler(psy); psy_unregister_cooler(psy);
psy_unregister_thermal(psy); psy_unregister_thermal(psy);
device_init_wakeup(psy->dev, false);
device_unregister(psy->dev); device_unregister(psy->dev);
} }
EXPORT_SYMBOL_GPL(power_supply_unregister); EXPORT_SYMBOL_GPL(power_supply_unregister);
......
...@@ -118,7 +118,7 @@ static ssize_t power_supply_store_property(struct device *dev, ...@@ -118,7 +118,7 @@ static ssize_t power_supply_store_property(struct device *dev,
long long_val; long long_val;
/* TODO: support other types than int */ /* TODO: support other types than int */
ret = strict_strtol(buf, 10, &long_val); ret = kstrtol(buf, 10, &long_val);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -14,6 +14,12 @@ config POWER_RESET_GPIO ...@@ -14,6 +14,12 @@ config POWER_RESET_GPIO
If your board needs a GPIO high/low to power down, say Y and If your board needs a GPIO high/low to power down, say Y and
create a binding in your devicetree. create a binding in your devicetree.
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on POWER_RESET && ARCH_MSM
help
Power off and restart support for Qualcomm boards.
config POWER_RESET_QNAP config POWER_RESET_QNAP
bool "QNAP power-off driver" bool "QNAP power-off driver"
depends on OF_GPIO && POWER_RESET && PLAT_ORION depends on OF_GPIO && POWER_RESET && PLAT_ORION
...@@ -34,7 +40,14 @@ config POWER_RESET_RESTART ...@@ -34,7 +40,14 @@ config POWER_RESET_RESTART
config POWER_RESET_VEXPRESS config POWER_RESET_VEXPRESS
bool "ARM Versatile Express power-off and reset driver" bool "ARM Versatile Express power-off and reset driver"
depends on ARM || ARM64 depends on ARM || ARM64
depends on POWER_RESET depends on POWER_RESET && VEXPRESS_CONFIG
help help
Power off and reset support for the ARM Ltd. Versatile Power off and reset support for the ARM Ltd. Versatile
Express boards. Express boards.
config POWER_RESET_XGENE
bool "APM SoC X-Gene reset driver"
depends on ARM64
depends on POWER_RESET
help
Reboot support for the APM SoC X-Gene Eval boards.
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <asm/system_misc.h>
static void __iomem *msm_ps_hold;
static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
{
writel(0, msm_ps_hold);
mdelay(10000);
}
static void do_msm_poweroff(void)
{
/* TODO: Add poweroff capability */
do_msm_restart(REBOOT_HARD, NULL);
}
static int msm_restart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *mem;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
msm_ps_hold = devm_ioremap_resource(dev, mem);
if (IS_ERR(msm_ps_hold))
return PTR_ERR(msm_ps_hold);
pm_power_off = do_msm_poweroff;
arm_pm_restart = do_msm_restart;
return 0;
}
static const struct of_device_id of_msm_restart_match[] = {
{ .compatible = "qcom,pshold", },
{},
};
MODULE_DEVICE_TABLE(of, of_msm_restart_match);
static struct platform_driver msm_restart_driver = {
.probe = msm_restart_probe,
.driver = {
.name = "msm-restart",
.of_match_table = of_match_ptr(of_msm_restart_match),
},
};
static int __init msm_restart_init(void)
{
return platform_driver_register(&msm_restart_driver);
}
device_initcall(msm_restart_init);
/*
* AppliedMicro X-Gene SoC Reboot Driver
*
* Copyright (c) 2013, Applied Micro Circuits Corporation
* Author: Feng Kan <fkan@apm.com>
* Author: Loc Ho <lho@apm.com>
*
* 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
*
* This driver provides system reboot functionality for APM X-Gene SoC.
* For system shutdown, this is board specify. If a board designer
* implements GPIO shutdown, use the gpio-poweroff.c driver.
*/
#include <linux/io.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <asm/system_misc.h>
struct xgene_reboot_context {
struct platform_device *pdev;
void *csr;
u32 mask;
};
static struct xgene_reboot_context *xgene_restart_ctx;
static void xgene_restart(char str, const char *cmd)
{
struct xgene_reboot_context *ctx = xgene_restart_ctx;
unsigned long timeout;
/* Issue the reboot */
if (ctx)
writel(ctx->mask, ctx->csr);
timeout = jiffies + HZ;
while (time_before(jiffies, timeout))
cpu_relax();
dev_emerg(&ctx->pdev->dev, "Unable to restart system\n");
}
static int xgene_reboot_probe(struct platform_device *pdev)
{
struct xgene_reboot_context *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
dev_err(&pdev->dev, "out of memory for context\n");
return -ENODEV;
}
ctx->csr = of_iomap(pdev->dev.of_node, 0);
if (!ctx->csr) {
devm_kfree(&pdev->dev, ctx);
dev_err(&pdev->dev, "can not map resource\n");
return -ENODEV;
}
if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
ctx->mask = 0xFFFFFFFF;
ctx->pdev = pdev;
arm_pm_restart = xgene_restart;
xgene_restart_ctx = ctx;
return 0;
}
static struct of_device_id xgene_reboot_of_match[] = {
{ .compatible = "apm,xgene-reboot" },
{}
};
static struct platform_driver xgene_reboot_driver = {
.probe = xgene_reboot_probe,
.driver = {
.name = "xgene-reboot",
.of_match_table = xgene_reboot_of_match,
},
};
static int __init xgene_reboot_init(void)
{
return platform_driver_register(&xgene_reboot_driver);
}
device_initcall(xgene_reboot_init);
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c/twl4030-madc.h> #include <linux/i2c/twl4030-madc.h>
/* RX51 specific channels */
#define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
#define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
struct rx51_device_info { struct rx51_device_info {
struct device *dev; struct device *dev;
struct power_supply bat; struct power_supply bat;
...@@ -37,7 +41,7 @@ static int rx51_battery_read_adc(int channel) ...@@ -37,7 +41,7 @@ static int rx51_battery_read_adc(int channel)
{ {
struct twl4030_madc_request req; struct twl4030_madc_request req;
req.channels = 1 << channel; req.channels = channel;
req.do_avg = 1; req.do_avg = 1;
req.method = TWL4030_MADC_SW1; req.method = TWL4030_MADC_SW1;
req.func_cb = NULL; req.func_cb = NULL;
...@@ -47,7 +51,7 @@ static int rx51_battery_read_adc(int channel) ...@@ -47,7 +51,7 @@ static int rx51_battery_read_adc(int channel)
if (twl4030_madc_conversion(&req) <= 0) if (twl4030_madc_conversion(&req) <= 0)
return -ENODATA; return -ENODATA;
return req.rbuf[channel]; return req.rbuf[ffs(channel) - 1];
} }
/* /*
...@@ -56,7 +60,7 @@ static int rx51_battery_read_adc(int channel) ...@@ -56,7 +60,7 @@ static int rx51_battery_read_adc(int channel)
*/ */
static int rx51_battery_read_voltage(struct rx51_device_info *di) static int rx51_battery_read_voltage(struct rx51_device_info *di)
{ {
int voltage = rx51_battery_read_adc(12); int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
if (voltage < 0) if (voltage < 0)
return voltage; return voltage;
...@@ -108,7 +112,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) ...@@ -108,7 +112,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
{ {
int min = 0; int min = 0;
int max = ARRAY_SIZE(rx51_temp_table2) - 1; int max = ARRAY_SIZE(rx51_temp_table2) - 1;
int raw = rx51_battery_read_adc(0); int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
/* Zero and negative values are undefined */ /* Zero and negative values are undefined */
if (raw <= 0) if (raw <= 0)
...@@ -142,7 +146,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) ...@@ -142,7 +146,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
*/ */
static int rx51_battery_read_capacity(struct rx51_device_info *di) static int rx51_battery_read_capacity(struct rx51_device_info *di)
{ {
int capacity = rx51_battery_read_adc(4); int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
if (capacity < 0) if (capacity < 0)
return capacity; return capacity;
......
...@@ -150,7 +150,7 @@ static void tosa_bat_external_power_changed(struct power_supply *psy) ...@@ -150,7 +150,7 @@ static void tosa_bat_external_power_changed(struct power_supply *psy)
static irqreturn_t tosa_bat_gpio_isr(int irq, void *data) static irqreturn_t tosa_bat_gpio_isr(int irq, void *data)
{ {
pr_info("tosa_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq))); pr_info("tosa_bat_gpio irq\n");
schedule_work(&bat_work); schedule_work(&bat_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -189,7 +189,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) ...@@ -189,7 +189,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
/* Need to keep regulator on */ /* Need to keep regulator on */
if (!bci->usb_enabled) { if (!bci->usb_enabled) {
regulator_enable(bci->usb_reg); ret = regulator_enable(bci->usb_reg);
if (ret) {
dev_err(bci->dev,
"Failed to enable regulator\n");
return ret;
}
bci->usb_enabled = 1; bci->usb_enabled = 1;
} }
......
/*
* Dumb driver for LiIon batteries using TWL4030 madc.
*
* Copyright 2013 Golden Delicious Computers
* Lukas Märdian <lukas@goldelico.com>
*
* Based on dumb driver for gta01 battery
* Copyright 2009 Openmoko, Inc
* Balaji Rao <balajirrao@openmoko.org>
*/
#include <linux/module.h>
#include <linux/param.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/power/twl4030_madc_battery.h>
struct twl4030_madc_battery {
struct power_supply psy;
struct twl4030_madc_bat_platform_data *pdata;
};
static enum power_supply_property twl4030_madc_bat_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
};
static int madc_read(int index)
{
struct twl4030_madc_request req;
int val;
req.channels = index;
req.method = TWL4030_MADC_SW2;
req.type = TWL4030_MADC_WAIT;
req.do_avg = 0;
req.raw = false;
req.func_cb = NULL;
val = twl4030_madc_conversion(&req);
if (val < 0)
return val;
return req.rbuf[ffs(index) - 1];
}
static int twl4030_madc_bat_get_charging_status(void)
{
return (madc_read(TWL4030_MADC_ICHG) > 0) ? 1 : 0;
}
static int twl4030_madc_bat_get_voltage(void)
{
return madc_read(TWL4030_MADC_VBAT);
}
static int twl4030_madc_bat_get_current(void)
{
return madc_read(TWL4030_MADC_ICHG) * 1000;
}
static int twl4030_madc_bat_get_temp(void)
{
return madc_read(TWL4030_MADC_BTEMP) * 10;
}
static int twl4030_madc_bat_voltscale(struct twl4030_madc_battery *bat,
int volt)
{
struct twl4030_madc_bat_calibration *calibration;
int i, res = 0;
/* choose charging curve */
if (twl4030_madc_bat_get_charging_status())
calibration = bat->pdata->charging;
else
calibration = bat->pdata->discharging;
if (volt > calibration[0].voltage) {
res = calibration[0].level;
} else {
for (i = 0; calibration[i+1].voltage >= 0; i++) {
if (volt <= calibration[i].voltage &&
volt >= calibration[i+1].voltage) {
/* interval found - interpolate within range */
res = calibration[i].level -
((calibration[i].voltage - volt) *
(calibration[i].level -
calibration[i+1].level)) /
(calibration[i].voltage -
calibration[i+1].voltage);
break;
}
}
}
return res;
}
static int twl4030_madc_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct twl4030_madc_battery *bat = container_of(psy,
struct twl4030_madc_battery, psy);
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
if (twl4030_madc_bat_voltscale(bat,
twl4030_madc_bat_get_voltage()) > 95)
val->intval = POWER_SUPPLY_STATUS_FULL;
else {
if (twl4030_madc_bat_get_charging_status())
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
}
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = twl4030_madc_bat_get_voltage() * 1000;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = twl4030_madc_bat_get_current();
break;
case POWER_SUPPLY_PROP_PRESENT:
/* assume battery is always present */
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW: {
int percent = twl4030_madc_bat_voltscale(bat,
twl4030_madc_bat_get_voltage());
val->intval = (percent * bat->pdata->capacity) / 100;
break;
}
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = twl4030_madc_bat_voltscale(bat,
twl4030_madc_bat_get_voltage());
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
val->intval = bat->pdata->capacity;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = twl4030_madc_bat_get_temp();
break;
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: {
int percent = twl4030_madc_bat_voltscale(bat,
twl4030_madc_bat_get_voltage());
/* in mAh */
int chg = (percent * (bat->pdata->capacity/1000))/100;
/* assume discharge with 400 mA (ca. 1.5W) */
val->intval = (3600l * chg) / 400;
break;
}
default:
return -EINVAL;
}
return 0;
}
static void twl4030_madc_bat_ext_changed(struct power_supply *psy)
{
struct twl4030_madc_battery *bat = container_of(psy,
struct twl4030_madc_battery, psy);
power_supply_changed(&bat->psy);
}
static int twl4030_cmp(const void *a, const void *b)
{
return ((struct twl4030_madc_bat_calibration *)b)->voltage -
((struct twl4030_madc_bat_calibration *)a)->voltage;
}
static int twl4030_madc_battery_probe(struct platform_device *pdev)
{
struct twl4030_madc_battery *twl4030_madc_bat;
struct twl4030_madc_bat_platform_data *pdata = pdev->dev.platform_data;
twl4030_madc_bat = kzalloc(sizeof(*twl4030_madc_bat), GFP_KERNEL);
if (!twl4030_madc_bat)
return -ENOMEM;
twl4030_madc_bat->psy.name = "twl4030_battery";
twl4030_madc_bat->psy.type = POWER_SUPPLY_TYPE_BATTERY;
twl4030_madc_bat->psy.properties = twl4030_madc_bat_props;
twl4030_madc_bat->psy.num_properties =
ARRAY_SIZE(twl4030_madc_bat_props);
twl4030_madc_bat->psy.get_property = twl4030_madc_bat_get_property;
twl4030_madc_bat->psy.external_power_changed =
twl4030_madc_bat_ext_changed;
/* sort charging and discharging calibration data */
sort(pdata->charging, pdata->charging_size,
sizeof(struct twl4030_madc_bat_calibration),
twl4030_cmp, NULL);
sort(pdata->discharging, pdata->discharging_size,
sizeof(struct twl4030_madc_bat_calibration),
twl4030_cmp, NULL);
twl4030_madc_bat->pdata = pdata;
platform_set_drvdata(pdev, twl4030_madc_bat);
power_supply_register(&pdev->dev, &twl4030_madc_bat->psy);
return 0;
}
static int twl4030_madc_battery_remove(struct platform_device *pdev)
{
struct twl4030_madc_battery *bat = platform_get_drvdata(pdev);
power_supply_unregister(&bat->psy);
kfree(bat);
return 0;
}
static struct platform_driver twl4030_madc_battery_driver = {
.driver = {
.name = "twl4030_madc_battery",
},
.probe = twl4030_madc_battery_probe,
.remove = twl4030_madc_battery_remove,
};
module_platform_driver(twl4030_madc_battery_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>");
MODULE_DESCRIPTION("twl4030_madc battery driver");
/*
* Platform data for the TI bq24190 battery charger driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _BQ24190_CHARGER_H_
#define _BQ24190_CHARGER_H_
struct bq24190_platform_data {
unsigned int gpio_int; /* GPIO pin that's connected to INT# */
};
#endif
/*
* Dumb driver for LiIon batteries using TWL4030 madc.
*
* Copyright 2013 Golden Delicious Computers
* Nikolaus Schaller <hns@goldelico.com>
*
* 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.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __TWL4030_MADC_BATTERY_H
#define __TWL4030_MADC_BATTERY_H
/*
* Usually we can assume 100% @ 4.15V and 0% @ 3.3V but curves differ for
* charging and discharging!
*/
struct twl4030_madc_bat_calibration {
short voltage; /* in mV - specify -1 for end of list */
short level; /* in percent (0 .. 100%) */
};
struct twl4030_madc_bat_platform_data {
unsigned int capacity; /* total capacity in uAh */
struct twl4030_madc_bat_calibration *charging;
int charging_size;
struct twl4030_madc_bat_calibration *discharging;
int discharging_size;
};
#endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/spinlock.h>
struct device; struct device;
...@@ -194,6 +195,8 @@ struct power_supply { ...@@ -194,6 +195,8 @@ struct power_supply {
/* private */ /* private */
struct device *dev; struct device *dev;
struct work_struct changed_work; struct work_struct changed_work;
spinlock_t changed_lock;
bool changed;
#ifdef CONFIG_THERMAL #ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd; struct thermal_zone_device *tzd;
struct thermal_cooling_device *tcd; struct thermal_cooling_device *tcd;
......
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