Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: (21 commits) power_supply: Add MAX17042 Fuel Gauge Driver olpc_battery: Fix up XO-1.5 properties list olpc_battery: Add support for CURRENT_NOW and VOLTAGE_NOW olpc_battery: Add support for CHARGE_NOW olpc_battery: Add support for CHARGE_FULL_DESIGN olpc_battery: Ambient temperature is not available on XO-1.5 jz4740-battery: Should include linux/io.h s3c_adc_battery: Add gpio_inverted field to pdata power_supply: Don't use flush_scheduled_work() power_supply: Fix use after free and memory leak gpio-charger: Fix potential race between irq handler and probe/remove gpio-charger: Provide default name for the power_supply gpio-charger: Check result of kzalloc jz4740-battery: Check if platform_data is supplied isp1704_charger: Detect charger after probe isp1704_charger: Set isp->dev before anything needs it isp1704_charger: Detect HUB/Host chargers isp1704_charger: Correct length for storing model power_supply: Add gpio charger driver jz4740-battery: Protect against concurrent battery readings ...
This commit is contained in:
commit
5957e33d6a
|
@ -136,6 +136,16 @@ config BATTERY_MAX17040
|
|||
in handheld and portable equipment. The MAX17040 is configured
|
||||
to operate with a single lithium cell
|
||||
|
||||
config BATTERY_MAX17042
|
||||
tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
|
||||
depends on I2C
|
||||
help
|
||||
MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
|
||||
in handheld and portable equipment. The MAX17042 is configured
|
||||
to operate with a single lithium cell. MAX8997 and MAX8966 are
|
||||
multi-function devices that include fuel gauages that are compatible
|
||||
with MAX17042.
|
||||
|
||||
config BATTERY_Z2
|
||||
tristate "Z2 battery driver"
|
||||
depends on I2C && MACH_ZIPIT2
|
||||
|
@ -185,4 +195,14 @@ config CHARGER_TWL4030
|
|||
help
|
||||
Say Y here to enable support for TWL4030 Battery Charge Interface.
|
||||
|
||||
config CHARGER_GPIO
|
||||
tristate "GPIO charger"
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Say Y to include support for chargers which report their online status
|
||||
through a GPIO pin.
|
||||
|
||||
This driver can be build as a module. If so, the module will be
|
||||
called gpio-charger.
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
|
|||
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
|
||||
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
|
||||
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
|
||||
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
|
||||
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||
|
@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
|
|||
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
|
||||
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
|
||||
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
|
||||
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
|
||||
|
|
|
@ -295,7 +295,7 @@ static struct {
|
|||
static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
|
||||
{
|
||||
/* flush all pending status updates */
|
||||
flush_scheduled_work();
|
||||
flush_work_sync(&bat_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ err_psy_reg_bu:
|
|||
err_psy_reg_main:
|
||||
|
||||
/* see comment in collie_bat_remove */
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
i--;
|
||||
err_gpio:
|
||||
|
@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
|
|||
power_supply_unregister(&collie_bat_main.psy);
|
||||
|
||||
/*
|
||||
* now flush all pending work.
|
||||
* we won't get any more schedules, since all
|
||||
* sources (isr and external_power_changed)
|
||||
* are unregistered now.
|
||||
* Now cancel the bat_work. We won't get any more schedules,
|
||||
* since all sources (isr and external_power_changed) are
|
||||
* unregistered now.
|
||||
*/
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
|
|
|
@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
|
|||
if (di->rem_capacity > 100)
|
||||
di->rem_capacity = 100;
|
||||
|
||||
if (di->current_uA >= 100L)
|
||||
if (di->current_uA < -100L)
|
||||
di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
|
||||
/ (di->current_uA / 100L);
|
||||
else
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
|
||||
* Driver for chargers which report their online status through a GPIO pin
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/power/gpio-charger.h>
|
||||
|
||||
struct gpio_charger {
|
||||
const struct gpio_charger_platform_data *pdata;
|
||||
unsigned int irq;
|
||||
|
||||
struct power_supply charger;
|
||||
};
|
||||
|
||||
static irqreturn_t gpio_charger_irq(int irq, void *devid)
|
||||
{
|
||||
struct power_supply *charger = devid;
|
||||
|
||||
power_supply_changed(charger);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
|
||||
{
|
||||
return container_of(psy, struct gpio_charger, charger);
|
||||
}
|
||||
|
||||
static int gpio_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp, union power_supply_propval *val)
|
||||
{
|
||||
struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
|
||||
const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = gpio_get_value(pdata->gpio);
|
||||
val->intval ^= pdata->gpio_active_low;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property gpio_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static int __devinit gpio_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_charger *gpio_charger;
|
||||
struct power_supply *charger;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!gpio_is_valid(pdata->gpio)) {
|
||||
dev_err(&pdev->dev, "Invalid gpio pin\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
|
||||
if (!gpio_charger) {
|
||||
dev_err(&pdev->dev, "Failed to alloc driver structure\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
charger = &gpio_charger->charger;
|
||||
|
||||
charger->name = pdata->name ? pdata->name : "gpio-charger";
|
||||
charger->type = pdata->type;
|
||||
charger->properties = gpio_charger_properties;
|
||||
charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
|
||||
charger->get_property = gpio_charger_get_property;
|
||||
charger->supplied_to = pdata->supplied_to;
|
||||
charger->num_supplicants = pdata->num_supplicants;
|
||||
|
||||
ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
|
||||
goto err_free;
|
||||
}
|
||||
ret = gpio_direction_input(pdata->gpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
|
||||
goto err_gpio_free;
|
||||
}
|
||||
|
||||
gpio_charger->pdata = pdata;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, charger);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register power supply: %d\n",
|
||||
ret);
|
||||
goto err_gpio_free;
|
||||
}
|
||||
|
||||
irq = gpio_to_irq(pdata->gpio);
|
||||
if (irq > 0) {
|
||||
ret = request_any_context_irq(irq, gpio_charger_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
dev_name(&pdev->dev), charger);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
|
||||
else
|
||||
gpio_charger->irq = irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpio_charger);
|
||||
|
||||
return 0;
|
||||
|
||||
err_gpio_free:
|
||||
gpio_free(pdata->gpio);
|
||||
err_free:
|
||||
kfree(gpio_charger);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit gpio_charger_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
|
||||
|
||||
if (gpio_charger->irq)
|
||||
free_irq(gpio_charger->irq, &gpio_charger->charger);
|
||||
|
||||
power_supply_unregister(&gpio_charger->charger);
|
||||
|
||||
gpio_free(gpio_charger->pdata->gpio);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(gpio_charger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_charger_driver = {
|
||||
.probe = gpio_charger_probe,
|
||||
.remove = __devexit_p(gpio_charger_remove),
|
||||
.driver = {
|
||||
.name = "gpio-charger",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init gpio_charger_init(void)
|
||||
{
|
||||
return platform_driver_register(&gpio_charger_driver);
|
||||
}
|
||||
module_init(gpio_charger_init);
|
||||
|
||||
static void __exit gpio_charger_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&gpio_charger_driver);
|
||||
}
|
||||
module_exit(gpio_charger_exit);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:gpio-charger");
|
|
@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
|
|||
power_supply_unregister(&pbi->usb);
|
||||
power_supply_unregister(&pbi->batt);
|
||||
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&pbi->handler);
|
||||
kfree(pbi);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -59,10 +59,60 @@ struct isp1704_charger {
|
|||
struct notifier_block nb;
|
||||
struct work_struct work;
|
||||
|
||||
char model[7];
|
||||
/* properties */
|
||||
char model[8];
|
||||
unsigned present:1;
|
||||
unsigned online:1;
|
||||
unsigned current_max;
|
||||
|
||||
/* temp storage variables */
|
||||
unsigned long event;
|
||||
unsigned max_power;
|
||||
};
|
||||
|
||||
/*
|
||||
* Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
|
||||
* chargers).
|
||||
*
|
||||
* REVISIT: The method is defined in Battery Charging Specification and is
|
||||
* applicable to any ULPI transceiver. Nothing isp170x specific here.
|
||||
*/
|
||||
static inline int isp1704_charger_type(struct isp1704_charger *isp)
|
||||
{
|
||||
u8 reg;
|
||||
u8 func_ctrl;
|
||||
u8 otg_ctrl;
|
||||
int type = POWER_SUPPLY_TYPE_USB_DCP;
|
||||
|
||||
func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
|
||||
otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
|
||||
|
||||
/* disable pulldowns */
|
||||
reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
|
||||
otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
|
||||
|
||||
/* full speed */
|
||||
otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
|
||||
ULPI_FUNC_CTRL_XCVRSEL_MASK);
|
||||
otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
|
||||
ULPI_FUNC_CTRL_FULL_SPEED);
|
||||
|
||||
/* Enable strong pull-up on DP (1.5K) and reset */
|
||||
reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
|
||||
otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
reg = otg_io_read(isp->otg, ULPI_DEBUG);
|
||||
if ((reg & 3) != 3)
|
||||
type = POWER_SUPPLY_TYPE_USB_CDP;
|
||||
|
||||
/* recover original state */
|
||||
otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
|
||||
otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
|
||||
* is actually a dedicated charger, the following steps need to be taken.
|
||||
|
@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
|
|||
static inline int isp1704_charger_detect(struct isp1704_charger *isp)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u8 r;
|
||||
u8 pwr_ctrl;
|
||||
int ret = 0;
|
||||
|
||||
pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
|
||||
|
||||
/* set SW control bit in PWR_CTRL register */
|
||||
otg_io_write(isp->otg, ISP1704_PWR_CTRL,
|
||||
ISP1704_PWR_CTRL_SWCTRL);
|
||||
|
||||
/* enable manual charger detection */
|
||||
r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
|
||||
otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
|
||||
otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
|
||||
ISP1704_PWR_CTRL_SWCTRL
|
||||
| ISP1704_PWR_CTRL_DPVSRC_EN);
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(300);
|
||||
|
@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
|
|||
ret = isp1704_charger_verify(isp);
|
||||
break;
|
||||
}
|
||||
} while (!time_after(jiffies, timeout));
|
||||
} while (!time_after(jiffies, timeout) && isp->online);
|
||||
|
||||
/* recover original state */
|
||||
otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
|
|||
static void isp1704_charger_work(struct work_struct *data)
|
||||
{
|
||||
int detect;
|
||||
unsigned long event;
|
||||
unsigned power;
|
||||
struct isp1704_charger *isp =
|
||||
container_of(data, struct isp1704_charger, work);
|
||||
static DEFINE_MUTEX(lock);
|
||||
|
||||
/*
|
||||
* FIXME Only supporting dedicated chargers even though isp1704 can
|
||||
* detect HUB and HOST chargers. If the device has already been
|
||||
* enumerated, the detection will break the connection.
|
||||
*/
|
||||
if (isp->otg->state != OTG_STATE_B_IDLE)
|
||||
return;
|
||||
event = isp->event;
|
||||
power = isp->max_power;
|
||||
|
||||
/* disable data pullups */
|
||||
if (isp->otg->gadget)
|
||||
usb_gadget_disconnect(isp->otg->gadget);
|
||||
mutex_lock(&lock);
|
||||
|
||||
/* detect charger */
|
||||
detect = isp1704_charger_detect(isp);
|
||||
if (detect) {
|
||||
isp->present = detect;
|
||||
power_supply_changed(&isp->psy);
|
||||
switch (event) {
|
||||
case USB_EVENT_VBUS:
|
||||
isp->online = true;
|
||||
|
||||
/* detect charger */
|
||||
detect = isp1704_charger_detect(isp);
|
||||
|
||||
if (detect) {
|
||||
isp->present = detect;
|
||||
isp->psy.type = isp1704_charger_type(isp);
|
||||
}
|
||||
|
||||
switch (isp->psy.type) {
|
||||
case POWER_SUPPLY_TYPE_USB_DCP:
|
||||
isp->current_max = 1800;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB_CDP:
|
||||
/*
|
||||
* Only 500mA here or high speed chirp
|
||||
* handshaking may break
|
||||
*/
|
||||
isp->current_max = 500;
|
||||
/* FALLTHROUGH */
|
||||
case POWER_SUPPLY_TYPE_USB:
|
||||
default:
|
||||
/* enable data pullups */
|
||||
if (isp->otg->gadget)
|
||||
usb_gadget_connect(isp->otg->gadget);
|
||||
}
|
||||
break;
|
||||
case USB_EVENT_NONE:
|
||||
isp->online = false;
|
||||
isp->current_max = 0;
|
||||
isp->present = 0;
|
||||
isp->current_max = 0;
|
||||
isp->psy.type = POWER_SUPPLY_TYPE_USB;
|
||||
|
||||
/*
|
||||
* Disable data pullups. We need to prevent the controller from
|
||||
* enumerating.
|
||||
*
|
||||
* FIXME: This is here to allow charger detection with Host/HUB
|
||||
* chargers. The pullups may be enabled elsewhere, so this can
|
||||
* not be the final solution.
|
||||
*/
|
||||
if (isp->otg->gadget)
|
||||
usb_gadget_disconnect(isp->otg->gadget);
|
||||
break;
|
||||
case USB_EVENT_ENUMERATED:
|
||||
if (isp->present)
|
||||
isp->current_max = 1800;
|
||||
else
|
||||
isp->current_max = power;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* enable data pullups */
|
||||
if (isp->otg->gadget)
|
||||
usb_gadget_connect(isp->otg->gadget);
|
||||
power_supply_changed(&isp->psy);
|
||||
out:
|
||||
mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
static int isp1704_notifier_call(struct notifier_block *nb,
|
||||
unsigned long event, void *unused)
|
||||
unsigned long event, void *power)
|
||||
{
|
||||
struct isp1704_charger *isp =
|
||||
container_of(nb, struct isp1704_charger, nb);
|
||||
|
||||
switch (event) {
|
||||
case USB_EVENT_VBUS:
|
||||
schedule_work(&isp->work);
|
||||
break;
|
||||
case USB_EVENT_NONE:
|
||||
if (isp->present) {
|
||||
isp->present = 0;
|
||||
power_supply_changed(&isp->psy);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
isp->event = event;
|
||||
|
||||
if (power)
|
||||
isp->max_power = *((unsigned *)power);
|
||||
|
||||
schedule_work(&isp->work);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = isp->present;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = isp->online;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
val->intval = isp->current_max;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
val->strval = isp->model;
|
||||
break;
|
||||
|
@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
|
|||
|
||||
static enum power_supply_property power_props[] = {
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
|
|||
if (!isp->otg)
|
||||
goto fail0;
|
||||
|
||||
isp->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, isp);
|
||||
|
||||
ret = isp1704_test_ulpi(isp);
|
||||
if (ret < 0)
|
||||
goto fail1;
|
||||
|
||||
isp->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, isp);
|
||||
|
||||
isp->psy.name = "isp1704";
|
||||
isp->psy.type = POWER_SUPPLY_TYPE_USB;
|
||||
isp->psy.properties = power_props;
|
||||
|
@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
|
|||
|
||||
dev_info(isp->dev, "registered with product id %s\n", isp->model);
|
||||
|
||||
/*
|
||||
* Taking over the D+ pullup.
|
||||
*
|
||||
* FIXME: The device will be disconnected if it was already
|
||||
* enumerated. The charger driver should be always loaded before any
|
||||
* gadget is loaded.
|
||||
*/
|
||||
if (isp->otg->gadget)
|
||||
usb_gadget_disconnect(isp->otg->gadget);
|
||||
|
||||
/* Detect charger if VBUS is valid (the cable was already plugged). */
|
||||
ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
|
||||
if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
|
||||
isp->event = USB_EVENT_VBUS;
|
||||
schedule_work(&isp->work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail2:
|
||||
power_supply_unregister(&isp->psy);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
|
@ -47,6 +48,8 @@ struct jz_battery {
|
|||
|
||||
struct power_supply battery;
|
||||
struct delayed_work work;
|
||||
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
|
||||
|
@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
|
|||
unsigned long val;
|
||||
long voltage;
|
||||
|
||||
mutex_lock(&battery->lock);
|
||||
|
||||
INIT_COMPLETION(battery->read_completion);
|
||||
|
||||
enable_irq(battery->irq);
|
||||
|
@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
|
|||
battery->cell->disable(battery->pdev);
|
||||
disable_irq(battery->irq);
|
||||
|
||||
mutex_unlock(&battery->lock);
|
||||
|
||||
return voltage;
|
||||
}
|
||||
|
||||
|
@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
|
|||
struct jz_battery *jz_battery;
|
||||
struct power_supply *battery;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform_data supplied\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
|
||||
if (!jz_battery) {
|
||||
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
|
||||
|
@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
|
|||
jz_battery->pdev = pdev;
|
||||
|
||||
init_completion(&jz_battery->read_completion);
|
||||
mutex_init(&jz_battery->lock);
|
||||
|
||||
INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
|
||||
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Fuel gauge driver for Maxim 17042 / 8966 / 8997
|
||||
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.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 is based on max17040_battery.c
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/power/max17042_battery.h>
|
||||
|
||||
enum max17042_register {
|
||||
MAX17042_STATUS = 0x00,
|
||||
MAX17042_VALRT_Th = 0x01,
|
||||
MAX17042_TALRT_Th = 0x02,
|
||||
MAX17042_SALRT_Th = 0x03,
|
||||
MAX17042_AtRate = 0x04,
|
||||
MAX17042_RepCap = 0x05,
|
||||
MAX17042_RepSOC = 0x06,
|
||||
MAX17042_Age = 0x07,
|
||||
MAX17042_TEMP = 0x08,
|
||||
MAX17042_VCELL = 0x09,
|
||||
MAX17042_Current = 0x0A,
|
||||
MAX17042_AvgCurrent = 0x0B,
|
||||
MAX17042_Qresidual = 0x0C,
|
||||
MAX17042_SOC = 0x0D,
|
||||
MAX17042_AvSOC = 0x0E,
|
||||
MAX17042_RemCap = 0x0F,
|
||||
MAX17402_FullCAP = 0x10,
|
||||
MAX17042_TTE = 0x11,
|
||||
MAX17042_V_empty = 0x12,
|
||||
|
||||
MAX17042_RSLOW = 0x14,
|
||||
|
||||
MAX17042_AvgTA = 0x16,
|
||||
MAX17042_Cycles = 0x17,
|
||||
MAX17042_DesignCap = 0x18,
|
||||
MAX17042_AvgVCELL = 0x19,
|
||||
MAX17042_MinMaxTemp = 0x1A,
|
||||
MAX17042_MinMaxVolt = 0x1B,
|
||||
MAX17042_MinMaxCurr = 0x1C,
|
||||
MAX17042_CONFIG = 0x1D,
|
||||
MAX17042_ICHGTerm = 0x1E,
|
||||
MAX17042_AvCap = 0x1F,
|
||||
MAX17042_ManName = 0x20,
|
||||
MAX17042_DevName = 0x21,
|
||||
MAX17042_DevChem = 0x22,
|
||||
|
||||
MAX17042_TempNom = 0x24,
|
||||
MAX17042_TempCold = 0x25,
|
||||
MAX17042_TempHot = 0x26,
|
||||
MAX17042_AIN = 0x27,
|
||||
MAX17042_LearnCFG = 0x28,
|
||||
MAX17042_SHFTCFG = 0x29,
|
||||
MAX17042_RelaxCFG = 0x2A,
|
||||
MAX17042_MiscCFG = 0x2B,
|
||||
MAX17042_TGAIN = 0x2C,
|
||||
MAx17042_TOFF = 0x2D,
|
||||
MAX17042_CGAIN = 0x2E,
|
||||
MAX17042_COFF = 0x2F,
|
||||
|
||||
MAX17042_Q_empty = 0x33,
|
||||
MAX17042_T_empty = 0x34,
|
||||
|
||||
MAX17042_RCOMP0 = 0x38,
|
||||
MAX17042_TempCo = 0x39,
|
||||
MAX17042_Rx = 0x3A,
|
||||
MAX17042_T_empty0 = 0x3B,
|
||||
MAX17042_TaskPeriod = 0x3C,
|
||||
MAX17042_FSTAT = 0x3D,
|
||||
|
||||
MAX17042_SHDNTIMER = 0x3F,
|
||||
|
||||
MAX17042_VFRemCap = 0x4A,
|
||||
|
||||
MAX17042_QH = 0x4D,
|
||||
MAX17042_QL = 0x4E,
|
||||
};
|
||||
|
||||
struct max17042_chip {
|
||||
struct i2c_client *client;
|
||||
struct power_supply battery;
|
||||
struct max17042_platform_data *pdata;
|
||||
};
|
||||
|
||||
static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
int ret = i2c_smbus_write_word_data(client, reg, value);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max17042_read_reg(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int ret = i2c_smbus_read_word_data(client, reg);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum power_supply_property max17042_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_AVG,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
};
|
||||
|
||||
static int max17042_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max17042_chip *chip = container_of(psy,
|
||||
struct max17042_chip, battery);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_AvgVCELL) * 83;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_SOC) / 256;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit max17042_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct max17042_chip *chip;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -EIO;
|
||||
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->client = client;
|
||||
chip->pdata = client->dev.platform_data;
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
chip->battery.name = "max17042_battery";
|
||||
chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
chip->battery.get_property = max17042_get_property;
|
||||
chip->battery.properties = max17042_battery_props;
|
||||
chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
|
||||
|
||||
ret = power_supply_register(&client->dev, &chip->battery);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed: power supply register\n");
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!chip->pdata->enable_current_sense) {
|
||||
max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
|
||||
max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
|
||||
max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit max17042_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max17042_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
power_supply_unregister(&chip->battery);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max17042_id[] = {
|
||||
{ "max17042", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max17042_id);
|
||||
|
||||
static struct i2c_driver max17042_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max17042",
|
||||
},
|
||||
.probe = max17042_probe,
|
||||
.remove = __devexit_p(max17042_remove),
|
||||
.id_table = max17042_id,
|
||||
};
|
||||
|
||||
static int __init max17042_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max17042_i2c_driver);
|
||||
}
|
||||
module_init(max17042_init);
|
||||
|
||||
static void __exit max17042_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max17042_i2c_driver);
|
||||
}
|
||||
module_exit(max17042_exit);
|
||||
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
|
||||
{
|
||||
uint8_t ec_byte;
|
||||
union power_supply_propval tech;
|
||||
int ret, mfr;
|
||||
|
||||
ret = olpc_bat_get_tech(&tech);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ec_byte = BAT_ADDR_MFR_TYPE;
|
||||
ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mfr = ec_byte >> 4;
|
||||
|
||||
switch (tech.intval) {
|
||||
case POWER_SUPPLY_TECHNOLOGY_NiMH:
|
||||
switch (mfr) {
|
||||
case 1: /* Gold Peak */
|
||||
val->intval = 3000000*.8;
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_TECHNOLOGY_LiFe:
|
||||
switch (mfr) {
|
||||
case 1: /* Gold Peak */
|
||||
val->intval = 2800000;
|
||||
break;
|
||||
case 2: /* BYD */
|
||||
val->intval = 3100000;
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int olpc_bat_get_charge_now(union power_supply_propval *val)
|
||||
{
|
||||
uint8_t soc;
|
||||
union power_supply_propval full;
|
||||
int ret;
|
||||
|
||||
ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = olpc_bat_get_charge_full_design(&full);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = soc * (full.intval / 100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Battery properties
|
||||
*********************************************************************/
|
||||
|
@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
|
|||
return ret;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
|
|||
val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
|
|||
else
|
||||
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
ret = olpc_bat_get_charge_full_design(val);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
ret = olpc_bat_get_charge_now(val);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
|
||||
if (ret)
|
||||
|
@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static enum power_supply_property olpc_bat_props[] = {
|
||||
static enum power_supply_property olpc_xo1_bat_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_AVG,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TEMP_AMBIENT,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
|
@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
};
|
||||
|
||||
/* XO-1.5 does not have ambient temperature property */
|
||||
static enum power_supply_property olpc_xo15_bat_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_AVG,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
};
|
||||
|
||||
/* EEPROM reading goes completely around the power_supply API, sadly */
|
||||
|
||||
#define EEPROM_START 0x20
|
||||
|
@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
|
|||
static struct platform_device *bat_pdev;
|
||||
|
||||
static struct power_supply olpc_bat = {
|
||||
.properties = olpc_bat_props,
|
||||
.num_properties = ARRAY_SIZE(olpc_bat_props),
|
||||
.get_property = olpc_bat_get_property,
|
||||
.use_for_apm = 1,
|
||||
};
|
||||
|
@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
|
|||
goto ac_failed;
|
||||
|
||||
olpc_bat.name = bat_pdev->name;
|
||||
if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
|
||||
olpc_bat.properties = olpc_xo15_bat_props;
|
||||
olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
|
||||
} else { /* XO-1 */
|
||||
olpc_bat.properties = olpc_xo1_bat_props;
|
||||
olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
|
||||
}
|
||||
|
||||
ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
|
||||
if (ret)
|
||||
|
|
|
@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
|
|||
goto success;
|
||||
|
||||
create_triggers_failed:
|
||||
device_unregister(psy->dev);
|
||||
device_del(dev);
|
||||
kobject_set_name_failed:
|
||||
device_add_failed:
|
||||
kfree(dev);
|
||||
put_device(dev);
|
||||
success:
|
||||
return rc;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
|
|||
|
||||
void power_supply_unregister(struct power_supply *psy)
|
||||
{
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&psy->changed_work);
|
||||
power_supply_remove_triggers(psy);
|
||||
device_unregister(psy->dev);
|
||||
}
|
||||
|
|
|
@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
|
|||
return volt_val + cur_val * impedance / 1000;
|
||||
}
|
||||
|
||||
static int charge_finished(struct s3c_adc_bat *bat)
|
||||
{
|
||||
return bat->pdata->gpio_inverted ?
|
||||
!gpio_get_value(bat->pdata->gpio_charge_finished) :
|
||||
gpio_get_value(bat->pdata->gpio_charge_finished);
|
||||
}
|
||||
|
||||
static int s3c_adc_bat_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
|
|||
|
||||
if (bat->cable_plugged &&
|
||||
((bat->pdata->gpio_charge_finished < 0) ||
|
||||
!gpio_get_value(bat->pdata->gpio_charge_finished))) {
|
||||
!charge_finished(bat))) {
|
||||
lut = bat->pdata->lut_acin;
|
||||
lut_size = bat->pdata->lut_acin_cnt;
|
||||
}
|
||||
|
@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
|
|||
}
|
||||
} else {
|
||||
if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
|
||||
is_charged = gpio_get_value(
|
||||
main_bat.pdata->gpio_charge_finished);
|
||||
is_charged = charge_finished(&main_bat);
|
||||
if (is_charged) {
|
||||
if (bat->pdata->disable_charger)
|
||||
bat->pdata->disable_charger();
|
||||
|
|
|
@ -332,7 +332,7 @@ static struct {
|
|||
static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
/* flush all pending status updates */
|
||||
flush_scheduled_work();
|
||||
flush_work_sync(&bat_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ err_psy_reg_jacket:
|
|||
err_psy_reg_main:
|
||||
|
||||
/* see comment in tosa_bat_remove */
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
i--;
|
||||
err_gpio:
|
||||
|
@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
|
|||
power_supply_unregister(&tosa_bat_main.psy);
|
||||
|
||||
/*
|
||||
* now flush all pending work.
|
||||
* we won't get any more schedules, since all
|
||||
* sources (isr and external_power_changed)
|
||||
* are unregistered now.
|
||||
* Now cancel the bat_work. We won't get any more schedules,
|
||||
* since all sources (isr and external_power_changed) are
|
||||
* unregistered now.
|
||||
*/
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
|
|
|
@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
|
|||
#ifdef CONFIG_PM
|
||||
static int wm97xx_bat_suspend(struct device *dev)
|
||||
{
|
||||
flush_scheduled_work();
|
||||
flush_work_sync(&bat_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
|
|||
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
|
||||
gpio_free(pdata->charge_gpio);
|
||||
}
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&bat_work);
|
||||
power_supply_unregister(&bat_ps);
|
||||
kfree(prop);
|
||||
return 0;
|
||||
|
|
|
@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
|
|||
struct z2_charger *charger = i2c_get_clientdata(client);
|
||||
struct z2_battery_info *info = charger->info;
|
||||
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&charger->bat_work);
|
||||
power_supply_unregister(&charger->batt_ps);
|
||||
|
||||
kfree(charger->batt_ps.properties);
|
||||
|
@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
|
|||
#ifdef CONFIG_PM
|
||||
static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
|
||||
{
|
||||
flush_scheduled_work();
|
||||
struct z2_charger *charger = i2c_get_clientdata(client);
|
||||
|
||||
flush_work_sync(&charger->bat_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* 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 __LINUX_POWER_GPIO_CHARGER_H__
|
||||
#define __LINUX_POWER_GPIO_CHARGER_H__
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct gpio_charger_platform_data - platform_data for gpio_charger devices
|
||||
* @name: Name for the chargers power_supply device
|
||||
* @type: Type of the charger
|
||||
* @gpio: GPIO which is used to indicate the chargers status
|
||||
* @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0
|
||||
* @supplied_to: Array of battery names to which this chargers supplies power
|
||||
* @num_supplicants: Number of entries in the supplied_to array
|
||||
*/
|
||||
struct gpio_charger_platform_data {
|
||||
const char *name;
|
||||
enum power_supply_type type;
|
||||
|
||||
int gpio;
|
||||
int gpio_active_low;
|
||||
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Fuel gauge driver for Maxim 17042 / 8966 / 8997
|
||||
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.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
|
||||
*/
|
||||
|
||||
#ifndef __MAX17042_BATTERY_H_
|
||||
#define __MAX17042_BATTERY_H_
|
||||
|
||||
struct max17042_platform_data {
|
||||
bool enable_current_sense;
|
||||
};
|
||||
|
||||
#endif /* __MAX17042_BATTERY_H_ */
|
|
@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata {
|
|||
void (*disable_charger)(void);
|
||||
|
||||
int gpio_charge_finished;
|
||||
int gpio_inverted;
|
||||
|
||||
const struct s3c_adc_bat_thresh *lut_noac;
|
||||
unsigned int lut_noac_cnt;
|
||||
|
|
Loading…
Reference in New Issue