Seperate charger logic from battery driver
authorLars-Peter Clausen <lars@metafoo.de>
Wed, 3 Feb 2010 13:16:23 +0000 (13:16 +0000)
committerLars-Peter Clausen <lars@metafoo.de>
Wed, 3 Feb 2010 13:16:23 +0000 (13:16 +0000)
SVN-Revision: 19504

target/linux/xburst/config-2.6.32
target/linux/xburst/files-2.6.32/arch/mips/jz4740/board-qi_lb60.c
target/linux/xburst/files-2.6.32/drivers/power/gpio-charger.c [new file with mode: 0644]
target/linux/xburst/files-2.6.32/drivers/power/jz4740-battery.c
target/linux/xburst/files-2.6.32/include/linux/power/gpio-charger.h [new file with mode: 0644]
target/linux/xburst/files-2.6.32/include/linux/power/jz4740-battery.h
target/linux/xburst/patches-2.6.32/106-gpio-charger.patch [new file with mode: 0644]

index d2bbb5a0db038c7971053392982519b5302583a2..453098b3e54cfdc5e6554f2fcfed3aebd86acd95 100644 (file)
@@ -24,6 +24,7 @@ CONFIG_BITREVERSE=y
 # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
 # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
 CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+CONFIG_CHARGER_GPIO=y
 CONFIG_CONSOLE_TRANSLATIONS=y
 # CONFIG_CPU_BIG_ENDIAN is not set
 # CONFIG_CPU_CAVIUM_OCTEON is not set
index 5d22e20377dfb5196bb5dce1d5c7c51b7ee3b590..643f9c838356530d98c09957ba7039f2dbf94f05 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/spi/spi_gpio.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
+#include <linux/power/gpio-charger.h>
 #include <linux/mmc/jz4740_mmc.h>
 
 
@@ -286,8 +287,6 @@ static struct spi_board_info qi_lb60_spi_board_info[] = {
 
 /* Battery */
 static struct jz_batt_info qi_lb60_battery_pdata = {
-       .dc_dect_gpio   = GPIO_DC_DETE_N,
-       .usb_dect_gpio  = GPIO_USB_DETE,
        .charg_stat_gpio  = GPIO_CHARG_STAT_N,
 
        .min_voltag     = 3600000,
@@ -295,6 +294,26 @@ static struct jz_batt_info qi_lb60_battery_pdata = {
        .batt_tech      = POWER_SUPPLY_TECHNOLOGY_LIPO,
 };
 
+static char *qi_lb60_batteries[] = {
+       "battery",
+};
+
+static struct gpio_charger_platform_data qi_lb60_charger_pdata = {
+       .name = "USB",
+       .type = POWER_SUPPLY_TYPE_USB,
+       .gpio = GPIO_USB_DETE,
+       .gpio_active_low = 1,
+       .batteries = qi_lb60_batteries,
+       .num_batteries = ARRAY_SIZE(qi_lb60_batteries),
+};
+
+static struct platform_device qi_lb60_charger_device = {
+       .name = "gpio-charger",
+       .dev = {
+               .platform_data = &qi_lb60_charger_pdata,
+       },
+};
+
 /* GPIO Key: power */
 static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = {
        [0] = {
@@ -340,6 +359,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_adc_device,
        &jz4740_battery_device,
        &qi_lb60_gpio_keys,
+       &qi_lb60_charger_device,
 };
 
 static void __init board_gpio_setup(void)
diff --git a/target/linux/xburst/files-2.6.32/drivers/power/gpio-charger.c b/target/linux/xburst/files-2.6.32/drivers/power/gpio-charger.c
new file mode 100644 (file)
index 0000000..95c6ba7
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *     Driver for chargers indicating their 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/power/gpio-charger.h>
+
+struct gpio_charger {
+       const struct gpio_charger_platform_data *pdata;
+
+       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;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data");
+               return -EINVAL;
+       }
+
+       gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+
+       charger = &gpio_charger->charger;
+
+       charger->name = pdata->name;
+       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->batteries;
+       charger->num_supplicants = pdata->num_batteries;
+
+       if (gpio_is_valid(pdata->gpio)) {
+               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;
+               }
+               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->irq = gpio_to_irq(pdata->gpio);
+               if (gpio_charger->irq >= 0) {
+                       ret = request_irq(gpio_charger->irq, gpio_charger_irq,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                       dev_name(&pdev->dev), charger);
+                       if (ret) {
+                               dev_warn(&pdev->dev, "Failed to request online gpio irq: %d\n", ret);
+                               gpio_charger->irq = -1;
+                       }
+               }
+       }
+
+       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;
+       }
+
+       gpio_charger->pdata = pdata;
+       platform_set_drvdata(pdev, gpio_charger);
+
+       return 0;
+
+err_gpio_free:
+       if (gpio_is_valid(pdata->gpio)) {
+               if (gpio_charger->irq >= 0)
+                       free_irq(gpio_charger->irq, charger);
+               gpio_free(pdata->gpio);
+       }
+err:
+       return ret;
+}
+
+static int __devexit gpio_charger_remove(struct platform_device *pdev)
+{
+       struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+       const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
+
+       power_supply_unregister(&gpio_charger->charger);
+
+       if (gpio_is_valid(pdata->gpio)) {
+               if (gpio_charger->irq >= 0)
+                       free_irq(gpio_charger->irq, &gpio_charger->charger);
+               gpio_free(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 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 indicating their status through a gpio");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-charger");
index fe03d8076823127f96edf35e73e7d6fe98d8a315..f4c18a57b5089d4d43b70baa4a5bf8e9783d21fc 100644 (file)
@@ -24,9 +24,7 @@
 #include <linux/jz4740-adc.h>
 
 struct jz_battery_info {
-       struct power_supply usb;
        struct power_supply bat;
-       struct power_supply ac;
        int bat_status;
        struct jz_batt_info *pdata;
        struct mutex work_lock;
@@ -36,74 +34,6 @@ struct jz_battery_info {
 
 #define ps_to_jz_battery(x) container_of((x), struct jz_battery_info, bat);
 
-/*********************************************************************
- *             Power
- *********************************************************************/
-
-
-static int jz_get_power_prop(struct jz_battery_info *bat_info,
-                            struct power_supply *psy,
-                            enum power_supply_property psp,
-                            union power_supply_propval *val)
-{
-       int gpio;
-       
-       if (bat_info == 0 || bat_info->pdata == 0)
-               return -EINVAL;
-       gpio = (psy->type == POWER_SUPPLY_TYPE_MAINS) ?
-               bat_info->pdata->dc_dect_gpio :
-               bat_info->pdata->usb_dect_gpio;
-       if (!gpio_is_valid(gpio))
-               return -EINVAL;
-       switch (psp) {
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = !gpio_get_value(gpio);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int jz_usb_get_power_prop(struct power_supply *psy,
-                                enum power_supply_property psp,
-                                union power_supply_propval *val)
-{
-       struct jz_battery_info *bat_info = container_of(psy, struct jz_battery_info, usb);
-       return jz_get_power_prop(bat_info, psy, psp, val);
-}
-
-static int jz_ac_get_power_prop(struct power_supply *psy,
-                                enum power_supply_property psp,
-                                union power_supply_propval *val)
-{
-       struct jz_battery_info *bat_info = container_of(psy, struct jz_battery_info, ac);
-       return jz_get_power_prop(bat_info, psy, psp, val);
-}
-
-
-static enum power_supply_property jz_power_props[] = {
-       POWER_SUPPLY_PROP_ONLINE,
-};
-
-static struct power_supply jz_ac = {
-       .name = "ac",
-       .type = POWER_SUPPLY_TYPE_MAINS,
-       .properties = jz_power_props,
-       .num_properties = ARRAY_SIZE(jz_power_props),
-       .get_property = jz_ac_get_power_prop,
-};
-
-static struct power_supply jz_usb = {
-       .name = "usb",
-       .type = POWER_SUPPLY_TYPE_USB,
-       .properties = jz_power_props,
-       .num_properties = ARRAY_SIZE(jz_power_props),
-       .get_property = jz_usb_get_power_prop,
-};
-
-
 /*********************************************************************
  *             Battery properties
  *********************************************************************/
@@ -307,58 +237,24 @@ static int jz_bat_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct jz_battery_info *bat_info;
-       
+
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "Please set battery info\n");
+               return -EINVAL;
+       }
+
        bat_info = kzalloc(sizeof(struct jz_battery_info), GFP_KERNEL);
 
        if (!bat_info) {
                return -ENOMEM;
        }
 
-       if (!pdev->dev.platform_data) {
-               dev_err(&pdev->dev, "Please set battery info\n");
-               ret = -EINVAL;
-               goto err_platform_data;
-       }
        platform_set_drvdata(pdev, bat_info);
        bat_info->pdata = pdev->dev.platform_data;
        bat_info->bat = bat_ps;
-       bat_info->usb = jz_usb;
-       bat_info->ac =  jz_ac;
        mutex_init(&bat_info->work_lock);
        INIT_DELAYED_WORK(&bat_info->bat_work, jz_bat_work);
 
-       if (gpio_is_valid(bat_info->pdata->dc_dect_gpio)) {
-               ret = gpio_request(bat_info->pdata->dc_dect_gpio, "AC/DC DECT");
-               if (ret) {
-                       dev_err(&pdev->dev, "ac/dc dect gpio request failed.\n");
-
-                       goto err_dc_gpio_request;
-               }
-               ret = gpio_direction_input(bat_info->pdata->dc_dect_gpio);
-               if (ret) {
-                       dev_err(&pdev->dev, "ac/dc dect gpio direction failed.\n");
-
-                       goto err_dc_gpio_direction;
-               }
-       }
-
-       if (gpio_is_valid(bat_info->pdata->usb_dect_gpio)) {
-               ret = gpio_request(bat_info->pdata->usb_dect_gpio, "USB DECT");
-               if (ret) {
-                       dev_err(&pdev->dev, "usb dect gpio request failed.\n");
-
-                       goto err_usb_gpio_request;
-               }
-               ret = gpio_direction_input(bat_info->pdata->usb_dect_gpio);
-               if (ret) {
-                       dev_err(&pdev->dev, "usb dect gpio set direction failed.\n");
-                       goto err_usb_gpio_direction;
-               }
-
-               jz_gpio_disable_pullup(bat_info->pdata->usb_dect_gpio);
-               /* TODO: Use generic gpio is better */
-       }
-
        if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) {
                ret = gpio_request(bat_info->pdata->charg_stat_gpio, "CHARG STAT");
                if (ret) {
@@ -370,25 +266,7 @@ static int jz_bat_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "charger state gpio set direction failed.\n");
                        goto err_charg_gpio_direction;
                }
-       }
-       
-       if (gpio_is_valid(bat_info->pdata->dc_dect_gpio)) {
-               ret = power_supply_register(&pdev->dev, &bat_info->ac);
-               if (ret) {
-                       dev_err(&pdev->dev, "power supply ac/dc register failed.\n");
-                       goto err_power_register_ac;
-               }
-       }
-
-       if (gpio_is_valid(bat_info->pdata->usb_dect_gpio)) {
-               ret = power_supply_register(&pdev->dev, &bat_info->usb);
-               if (ret) {
-                       dev_err(&pdev->dev, "power supply usb register failed.\n");
-                       goto err_power_register_usb;
-               }
-       }
 
-       if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) {
                ret = power_supply_register(&pdev->dev, &bat_info->bat);
                if (ret) {
                        dev_err(&pdev->dev, "power supply battery register failed.\n");
@@ -405,20 +283,9 @@ static int jz_bat_probe(struct platform_device *pdev)
        return ret;
 
 err_power_register_bat:
-       power_supply_unregister(&bat_info->usb);
-err_power_register_usb:
-       power_supply_unregister(&bat_info->ac);
-err_power_register_ac:
 err_charg_gpio_direction:
        gpio_free(bat_info->pdata->charg_stat_gpio);
 err_charg_gpio_request:
-err_usb_gpio_direction:
-       gpio_free(bat_info->pdata->usb_dect_gpio);
-err_usb_gpio_request:
-err_dc_gpio_direction:
-       gpio_free(bat_info->pdata->dc_dect_gpio);
-err_dc_gpio_request:
-err_platform_data:
        kfree(bat_info);
        return ret;
 }
@@ -426,19 +293,13 @@ err_platform_data:
 static int jz_bat_remove(struct platform_device *pdev)
 {
        struct jz_battery_info *bat_info = platform_get_drvdata(pdev);
-               
+
        if (bat_info->pdata) {
-               if (gpio_is_valid(bat_info->pdata->dc_dect_gpio))
-                       gpio_free(bat_info->pdata->dc_dect_gpio);
-               if (gpio_is_valid(bat_info->pdata->usb_dect_gpio))
-                       gpio_free(bat_info->pdata->usb_dect_gpio);
                if (gpio_is_valid(bat_info->pdata->charg_stat_gpio))
                        gpio_free(bat_info->pdata->charg_stat_gpio);
        }
 
        power_supply_unregister(&bat_ps);
-       power_supply_unregister(&jz_ac);
-       power_supply_unregister(&jz_usb);
 
        return 0;
 }
diff --git a/target/linux/xburst/files-2.6.32/include/linux/power/gpio-charger.h b/target/linux/xburst/files-2.6.32/include/linux/power/gpio-charger.h
new file mode 100644 (file)
index 0000000..95cdfc3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  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__
+
+struct gpio_charger_platform_data {
+       const char *name;
+       enum power_supply_type type;
+       int gpio;
+       int gpio_active_low;
+
+       char **batteries;
+       size_t num_batteries;
+};
+
+#endif
index 2bcd7728301de6cb1a9fdabd5c5338514ff5c755..42e122ea7e6e9730d7a00ab7010952d703deceb9 100644 (file)
@@ -16,8 +16,6 @@
 #define __JZ4740_BATTERY_H
 
 struct jz_batt_info {
-       int dc_dect_gpio;       /* GPIO port of DC charger detection */
-       int usb_dect_gpio;      /* GPIO port of USB charger detection */
        int charg_stat_gpio;    /* GPIO port of Charger state */
 
        int min_voltag;         /* Mininal battery voltage in uV */
diff --git a/target/linux/xburst/patches-2.6.32/106-gpio-charger.patch b/target/linux/xburst/patches-2.6.32/106-gpio-charger.patch
new file mode 100644 (file)
index 0000000..dd1713a
--- /dev/null
@@ -0,0 +1,21 @@
+--- a/drivers/power/Makefile   2010-02-03 13:16:32.000000000 +0100
++++ b/drivers/power/Makefile   2010-02-01 14:55:46.000000000 +0100
+@@ -30,3 +30,4 @@
+ obj-$(CONFIG_BATTERY_MAX17040)        += max17040_battery.o
+ obj-$(CONFIG_CHARGER_PCF50633)        += pcf50633-charger.o
+ obj-$(CONFIG_BATTERY_JZ4740)  += jz4740-battery.o
++obj-$(CONFIG_CHARGER_GPIO)    += gpio-charger.o
+--- a/drivers/power/Kconfig    2010-02-03 13:16:32.000000000 +0100
++++ b/drivers/power/Kconfig    2010-02-01 14:58:24.000000000 +0100
+@@ -121,4 +121,11 @@
+         This driver can be build as a module. If so, the module will be
+         called jz4740-battery.
++config CHARGER_GPIO
++      tristate "GPIO charger"
++      depends on GPIOLIB
++      help
++        Say Y to include support for chargers indicating their status through
++        a GPIO pin.
++
+ endif # POWER_SUPPLY