Merge git://git.infradead.org/battery-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 14 Jan 2011 17:25:59 +0000 (09:25 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 14 Jan 2011 17:25:59 +0000 (09:25 -0800)
* 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
  ...

18 files changed:
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/collie_battery.c
drivers/power/ds2760_battery.c
drivers/power/gpio-charger.c [new file with mode: 0644]
drivers/power/intel_mid_battery.c
drivers/power/isp1704_charger.c
drivers/power/jz4740-battery.c
drivers/power/max17042_battery.c [new file with mode: 0644]
drivers/power/olpc_battery.c
drivers/power/power_supply_core.c
drivers/power/s3c_adc_battery.c
drivers/power/tosa_battery.c
drivers/power/wm97xx_battery.c
drivers/power/z2_battery.c
include/linux/power/gpio-charger.h [new file with mode: 0644]
include/linux/power/max17042_battery.h [new file with mode: 0644]
include/linux/s3c_adc_battery.h

index 60d83d9..61bf5d7 100644 (file)
@@ -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
index c75772e..8385bfa 100644 (file)
@@ -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
index 039f41a..548d263 100644 (file)
@@ -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);
index e7f8978..e534290 100644 (file)
@@ -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
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644 (file)
index 0000000..25b88ac
--- /dev/null
@@ -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");
index 36cf402..bce3a01 100644 (file)
@@ -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;
 }
index 7251218..2ad9b14 100644 (file)
@@ -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);
+
+       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);
+               }
 
-       /* detect charger */
-       detect = isp1704_charger_detect(isp);
-       if (detect) {
-               isp->present = detect;
-               power_supply_changed(&isp->psy);
+               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);
index a8108a7..02414db 100644 (file)
@@ -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);
 
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644 (file)
index 0000000..c5c8805
--- /dev/null
@@ -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");
index 5bc1dcf..0b0ff3a 100644 (file)
@@ -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)
index 91606bb..970f733 100644 (file)
@@ -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);
 }
index 4a8ae39..4255f23 100644 (file)
@@ -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();
index ee04936..53f0d35 100644 (file)
@@ -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);
index 5071d85..156559e 100644 (file)
@@ -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;
index 85064a9..e5ed52d 100644 (file)
@@ -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;
 }
 
diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h
new file mode 100644 (file)
index 0000000..de1dfe0
--- /dev/null
@@ -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
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
new file mode 100644 (file)
index 0000000..7995deb
--- /dev/null
@@ -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_ */
index dbce22f..fbe58b7 100644 (file)
@@ -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;