diff options
| -rw-r--r-- | drivers/power/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/power/Makefile | 2 | ||||
| -rw-r--r-- | drivers/power/collie_battery.c | 13 | ||||
| -rw-r--r-- | drivers/power/ds2760_battery.c | 2 | ||||
| -rw-r--r-- | drivers/power/gpio-charger.c | 188 | ||||
| -rw-r--r-- | drivers/power/intel_mid_battery.c | 2 | ||||
| -rw-r--r-- | drivers/power/isp1704_charger.c | 201 | ||||
| -rw-r--r-- | drivers/power/jz4740-battery.c | 13 | ||||
| -rw-r--r-- | drivers/power/max17042_battery.c | 239 | ||||
| -rw-r--r-- | drivers/power/olpc_battery.c | 114 | ||||
| -rw-r--r-- | drivers/power/power_supply_core.c | 6 | ||||
| -rw-r--r-- | drivers/power/s3c_adc_battery.c | 12 | ||||
| -rw-r--r-- | drivers/power/tosa_battery.c | 13 | ||||
| -rw-r--r-- | drivers/power/wm97xx_battery.c | 4 | ||||
| -rw-r--r-- | drivers/power/z2_battery.c | 6 | ||||
| -rw-r--r-- | include/linux/power/gpio-charger.h | 41 | ||||
| -rw-r--r-- | include/linux/power/max17042_battery.h | 30 | ||||
| -rw-r--r-- | include/linux/s3c_adc_battery.h | 1 |
18 files changed, 838 insertions, 69 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 60d83d983a36..61bf5d724139 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
| @@ -136,6 +136,16 @@ config BATTERY_MAX17040 | |||
| 136 | in handheld and portable equipment. The MAX17040 is configured | 136 | in handheld and portable equipment. The MAX17040 is configured |
| 137 | to operate with a single lithium cell | 137 | to operate with a single lithium cell |
| 138 | 138 | ||
| 139 | config BATTERY_MAX17042 | ||
| 140 | tristate "Maxim MAX17042/8997/8966 Fuel Gauge" | ||
| 141 | depends on I2C | ||
| 142 | help | ||
| 143 | MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries | ||
| 144 | in handheld and portable equipment. The MAX17042 is configured | ||
| 145 | to operate with a single lithium cell. MAX8997 and MAX8966 are | ||
| 146 | multi-function devices that include fuel gauages that are compatible | ||
| 147 | with MAX17042. | ||
| 148 | |||
| 139 | config BATTERY_Z2 | 149 | config BATTERY_Z2 |
| 140 | tristate "Z2 battery driver" | 150 | tristate "Z2 battery driver" |
| 141 | depends on I2C && MACH_ZIPIT2 | 151 | depends on I2C && MACH_ZIPIT2 |
| @@ -185,4 +195,14 @@ config CHARGER_TWL4030 | |||
| 185 | help | 195 | help |
| 186 | Say Y here to enable support for TWL4030 Battery Charge Interface. | 196 | Say Y here to enable support for TWL4030 Battery Charge Interface. |
| 187 | 197 | ||
| 198 | config CHARGER_GPIO | ||
| 199 | tristate "GPIO charger" | ||
| 200 | depends on GPIOLIB | ||
| 201 | help | ||
| 202 | Say Y to include support for chargers which report their online status | ||
| 203 | through a GPIO pin. | ||
| 204 | |||
| 205 | This driver can be build as a module. If so, the module will be | ||
| 206 | called gpio-charger. | ||
| 207 | |||
| 188 | endif # POWER_SUPPLY | 208 | endif # POWER_SUPPLY |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index c75772eb157c..8385bfae8728 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
| @@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o | |||
| 25 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o | 25 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o |
| 26 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o | 26 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o |
| 27 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o | 27 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o |
| 28 | obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o | ||
| 28 | obj-$(CONFIG_BATTERY_Z2) += z2_battery.o | 29 | obj-$(CONFIG_BATTERY_Z2) += z2_battery.o |
| 29 | obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o | 30 | obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o |
| 30 | obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o | 31 | obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o |
| @@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o | |||
| 32 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o | 33 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o |
| 33 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o | 34 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o |
| 34 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o | 35 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o |
| 36 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o | ||
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index 039f41ae217d..548d263b1ad0 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c | |||
| @@ -295,7 +295,7 @@ static struct { | |||
| 295 | static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) | 295 | static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) |
| 296 | { | 296 | { |
| 297 | /* flush all pending status updates */ | 297 | /* flush all pending status updates */ |
| 298 | flush_scheduled_work(); | 298 | flush_work_sync(&bat_work); |
| 299 | return 0; | 299 | return 0; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| @@ -362,7 +362,7 @@ err_psy_reg_bu: | |||
| 362 | err_psy_reg_main: | 362 | err_psy_reg_main: |
| 363 | 363 | ||
| 364 | /* see comment in collie_bat_remove */ | 364 | /* see comment in collie_bat_remove */ |
| 365 | flush_scheduled_work(); | 365 | cancel_work_sync(&bat_work); |
| 366 | 366 | ||
| 367 | i--; | 367 | i--; |
| 368 | err_gpio: | 368 | err_gpio: |
| @@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) | |||
| 382 | power_supply_unregister(&collie_bat_main.psy); | 382 | power_supply_unregister(&collie_bat_main.psy); |
| 383 | 383 | ||
| 384 | /* | 384 | /* |
| 385 | * now flush all pending work. | 385 | * Now cancel the bat_work. We won't get any more schedules, |
| 386 | * we won't get any more schedules, since all | 386 | * since all sources (isr and external_power_changed) are |
| 387 | * sources (isr and external_power_changed) | 387 | * unregistered now. |
| 388 | * are unregistered now. | ||
| 389 | */ | 388 | */ |
| 390 | flush_scheduled_work(); | 389 | cancel_work_sync(&bat_work); |
| 391 | 390 | ||
| 392 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) | 391 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) |
| 393 | gpio_free(gpios[i].gpio); | 392 | gpio_free(gpios[i].gpio); |
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index e7f89785beef..e534290f3256 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c | |||
| @@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di) | |||
| 212 | if (di->rem_capacity > 100) | 212 | if (di->rem_capacity > 100) |
| 213 | di->rem_capacity = 100; | 213 | di->rem_capacity = 100; |
| 214 | 214 | ||
| 215 | if (di->current_uA >= 100L) | 215 | if (di->current_uA < -100L) |
| 216 | di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L) | 216 | di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L) |
| 217 | / (di->current_uA / 100L); | 217 | / (di->current_uA / 100L); |
| 218 | else | 218 | else |
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c new file mode 100644 index 000000000000..25b88ac1d44c --- /dev/null +++ b/drivers/power/gpio-charger.c | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
| 3 | * Driver for chargers which report their online status through a GPIO pin | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 8 | * option) any later version. | ||
| 9 | * | ||
| 10 | * You should have received a copy of the GNU General Public License along | ||
| 11 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 12 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/power_supply.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include <linux/power/gpio-charger.h> | ||
| 27 | |||
| 28 | struct gpio_charger { | ||
| 29 | const struct gpio_charger_platform_data *pdata; | ||
| 30 | unsigned int irq; | ||
| 31 | |||
| 32 | struct power_supply charger; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static irqreturn_t gpio_charger_irq(int irq, void *devid) | ||
| 36 | { | ||
| 37 | struct power_supply *charger = devid; | ||
| 38 | |||
| 39 | power_supply_changed(charger); | ||
| 40 | |||
| 41 | return IRQ_HANDLED; | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) | ||
| 45 | { | ||
| 46 | return container_of(psy, struct gpio_charger, charger); | ||
| 47 | } | ||
| 48 | |||
| 49 | static int gpio_charger_get_property(struct power_supply *psy, | ||
| 50 | enum power_supply_property psp, union power_supply_propval *val) | ||
| 51 | { | ||
| 52 | struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); | ||
| 53 | const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; | ||
| 54 | |||
| 55 | switch (psp) { | ||
| 56 | case POWER_SUPPLY_PROP_ONLINE: | ||
| 57 | val->intval = gpio_get_value(pdata->gpio); | ||
| 58 | val->intval ^= pdata->gpio_active_low; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | return -EINVAL; | ||
| 62 | } | ||
| 63 | |||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | static enum power_supply_property gpio_charger_properties[] = { | ||
| 68 | POWER_SUPPLY_PROP_ONLINE, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static int __devinit gpio_charger_probe(struct platform_device *pdev) | ||
| 72 | { | ||
| 73 | const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; | ||
| 74 | struct gpio_charger *gpio_charger; | ||
| 75 | struct power_supply *charger; | ||
| 76 | int ret; | ||
| 77 | int irq; | ||
| 78 | |||
| 79 | if (!pdata) { | ||
| 80 | dev_err(&pdev->dev, "No platform data\n"); | ||
| 81 | return -EINVAL; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (!gpio_is_valid(pdata->gpio)) { | ||
| 85 | dev_err(&pdev->dev, "Invalid gpio pin\n"); | ||
| 86 | return -EINVAL; | ||
| 87 | } | ||
| 88 | |||
| 89 | gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); | ||
| 90 | if (!gpio_charger) { | ||
| 91 | dev_err(&pdev->dev, "Failed to alloc driver structure\n"); | ||
| 92 | return -ENOMEM; | ||
| 93 | } | ||
| 94 | |||
| 95 | charger = &gpio_charger->charger; | ||
| 96 | |||
| 97 | charger->name = pdata->name ? pdata->name : "gpio-charger"; | ||
| 98 | charger->type = pdata->type; | ||
| 99 | charger->properties = gpio_charger_properties; | ||
| 100 | charger->num_properties = ARRAY_SIZE(gpio_charger_properties); | ||
| 101 | charger->get_property = gpio_charger_get_property; | ||
| 102 | charger->supplied_to = pdata->supplied_to; | ||
| 103 | charger->num_supplicants = pdata->num_supplicants; | ||
| 104 | |||
| 105 | ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); | ||
| 106 | if (ret) { | ||
| 107 | dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); | ||
| 108 | goto err_free; | ||
| 109 | } | ||
| 110 | ret = gpio_direction_input(pdata->gpio); | ||
| 111 | if (ret) { | ||
| 112 | dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); | ||
| 113 | goto err_gpio_free; | ||
| 114 | } | ||
| 115 | |||
| 116 | gpio_charger->pdata = pdata; | ||
| 117 | |||
| 118 | ret = power_supply_register(&pdev->dev, charger); | ||
| 119 | if (ret < 0) { | ||
| 120 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", | ||
| 121 | ret); | ||
| 122 | goto err_gpio_free; | ||
| 123 | } | ||
| 124 | |||
| 125 | irq = gpio_to_irq(pdata->gpio); | ||
| 126 | if (irq > 0) { | ||
| 127 | ret = request_any_context_irq(irq, gpio_charger_irq, | ||
| 128 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
| 129 | dev_name(&pdev->dev), charger); | ||
| 130 | if (ret) | ||
| 131 | dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret); | ||
| 132 | else | ||
| 133 | gpio_charger->irq = irq; | ||
| 134 | } | ||
| 135 | |||
| 136 | platform_set_drvdata(pdev, gpio_charger); | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | |||
| 140 | err_gpio_free: | ||
| 141 | gpio_free(pdata->gpio); | ||
| 142 | err_free: | ||
| 143 | kfree(gpio_charger); | ||
| 144 | return ret; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int __devexit gpio_charger_remove(struct platform_device *pdev) | ||
| 148 | { | ||
| 149 | struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | ||
| 150 | |||
| 151 | if (gpio_charger->irq) | ||
| 152 | free_irq(gpio_charger->irq, &gpio_charger->charger); | ||
| 153 | |||
| 154 | power_supply_unregister(&gpio_charger->charger); | ||
| 155 | |||
| 156 | gpio_free(gpio_charger->pdata->gpio); | ||
| 157 | |||
| 158 | platform_set_drvdata(pdev, NULL); | ||
| 159 | kfree(gpio_charger); | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct platform_driver gpio_charger_driver = { | ||
| 165 | .probe = gpio_charger_probe, | ||
| 166 | .remove = __devexit_p(gpio_charger_remove), | ||
| 167 | .driver = { | ||
| 168 | .name = "gpio-charger", | ||
| 169 | .owner = THIS_MODULE, | ||
| 170 | }, | ||
| 171 | }; | ||
| 172 | |||
| 173 | static int __init gpio_charger_init(void) | ||
| 174 | { | ||
| 175 | return platform_driver_register(&gpio_charger_driver); | ||
| 176 | } | ||
| 177 | module_init(gpio_charger_init); | ||
| 178 | |||
| 179 | static void __exit gpio_charger_exit(void) | ||
| 180 | { | ||
| 181 | platform_driver_unregister(&gpio_charger_driver); | ||
| 182 | } | ||
| 183 | module_exit(gpio_charger_exit); | ||
| 184 | |||
| 185 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 186 | MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); | ||
| 187 | MODULE_LICENSE("GPL"); | ||
| 188 | MODULE_ALIAS("platform:gpio-charger"); | ||
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index 36cf402c0677..bce3a01da2f0 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c | |||
| @@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev) | |||
| 765 | power_supply_unregister(&pbi->usb); | 765 | power_supply_unregister(&pbi->usb); |
| 766 | power_supply_unregister(&pbi->batt); | 766 | power_supply_unregister(&pbi->batt); |
| 767 | 767 | ||
| 768 | flush_scheduled_work(); | 768 | cancel_work_sync(&pbi->handler); |
| 769 | kfree(pbi); | 769 | kfree(pbi); |
| 770 | return 0; | 770 | return 0; |
| 771 | } | 771 | } |
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 72512185f3e2..2ad9b14a5ce3 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c | |||
| @@ -59,11 +59,61 @@ struct isp1704_charger { | |||
| 59 | struct notifier_block nb; | 59 | struct notifier_block nb; |
| 60 | struct work_struct work; | 60 | struct work_struct work; |
| 61 | 61 | ||
| 62 | char model[7]; | 62 | /* properties */ |
| 63 | char model[8]; | ||
| 63 | unsigned present:1; | 64 | unsigned present:1; |
| 65 | unsigned online:1; | ||
| 66 | unsigned current_max; | ||
| 67 | |||
| 68 | /* temp storage variables */ | ||
| 69 | unsigned long event; | ||
| 70 | unsigned max_power; | ||
| 64 | }; | 71 | }; |
| 65 | 72 | ||
| 66 | /* | 73 | /* |
| 74 | * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB | ||
| 75 | * chargers). | ||
| 76 | * | ||
| 77 | * REVISIT: The method is defined in Battery Charging Specification and is | ||
| 78 | * applicable to any ULPI transceiver. Nothing isp170x specific here. | ||
| 79 | */ | ||
| 80 | static inline int isp1704_charger_type(struct isp1704_charger *isp) | ||
| 81 | { | ||
| 82 | u8 reg; | ||
| 83 | u8 func_ctrl; | ||
| 84 | u8 otg_ctrl; | ||
| 85 | int type = POWER_SUPPLY_TYPE_USB_DCP; | ||
| 86 | |||
| 87 | func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL); | ||
| 88 | otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL); | ||
| 89 | |||
| 90 | /* disable pulldowns */ | ||
| 91 | reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN; | ||
| 92 | otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg); | ||
| 93 | |||
| 94 | /* full speed */ | ||
| 95 | otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL), | ||
| 96 | ULPI_FUNC_CTRL_XCVRSEL_MASK); | ||
| 97 | otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), | ||
| 98 | ULPI_FUNC_CTRL_FULL_SPEED); | ||
| 99 | |||
| 100 | /* Enable strong pull-up on DP (1.5K) and reset */ | ||
| 101 | reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET; | ||
| 102 | otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg); | ||
| 103 | usleep_range(1000, 2000); | ||
| 104 | |||
| 105 | reg = otg_io_read(isp->otg, ULPI_DEBUG); | ||
| 106 | if ((reg & 3) != 3) | ||
| 107 | type = POWER_SUPPLY_TYPE_USB_CDP; | ||
| 108 | |||
| 109 | /* recover original state */ | ||
| 110 | otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl); | ||
| 111 | otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl); | ||
| 112 | |||
| 113 | return type; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 67 | * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger | 117 | * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger |
| 68 | * is actually a dedicated charger, the following steps need to be taken. | 118 | * is actually a dedicated charger, the following steps need to be taken. |
| 69 | */ | 119 | */ |
| @@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp) | |||
| 127 | static inline int isp1704_charger_detect(struct isp1704_charger *isp) | 177 | static inline int isp1704_charger_detect(struct isp1704_charger *isp) |
| 128 | { | 178 | { |
| 129 | unsigned long timeout; | 179 | unsigned long timeout; |
| 130 | u8 r; | 180 | u8 pwr_ctrl; |
| 131 | int ret = 0; | 181 | int ret = 0; |
| 132 | 182 | ||
| 183 | pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL); | ||
| 184 | |||
| 133 | /* set SW control bit in PWR_CTRL register */ | 185 | /* set SW control bit in PWR_CTRL register */ |
| 134 | otg_io_write(isp->otg, ISP1704_PWR_CTRL, | 186 | otg_io_write(isp->otg, ISP1704_PWR_CTRL, |
| 135 | ISP1704_PWR_CTRL_SWCTRL); | 187 | ISP1704_PWR_CTRL_SWCTRL); |
| 136 | 188 | ||
| 137 | /* enable manual charger detection */ | 189 | /* enable manual charger detection */ |
| 138 | r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN); | 190 | otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), |
| 139 | otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r); | 191 | ISP1704_PWR_CTRL_SWCTRL |
| 192 | | ISP1704_PWR_CTRL_DPVSRC_EN); | ||
| 140 | usleep_range(1000, 2000); | 193 | usleep_range(1000, 2000); |
| 141 | 194 | ||
| 142 | timeout = jiffies + msecs_to_jiffies(300); | 195 | timeout = jiffies + msecs_to_jiffies(300); |
| @@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp) | |||
| 147 | ret = isp1704_charger_verify(isp); | 200 | ret = isp1704_charger_verify(isp); |
| 148 | break; | 201 | break; |
| 149 | } | 202 | } |
| 150 | } while (!time_after(jiffies, timeout)); | 203 | } while (!time_after(jiffies, timeout) && isp->online); |
| 204 | |||
| 205 | /* recover original state */ | ||
| 206 | otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl); | ||
| 151 | 207 | ||
| 152 | return ret; | 208 | return ret; |
| 153 | } | 209 | } |
| @@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp) | |||
| 155 | static void isp1704_charger_work(struct work_struct *data) | 211 | static void isp1704_charger_work(struct work_struct *data) |
| 156 | { | 212 | { |
| 157 | int detect; | 213 | int detect; |
| 214 | unsigned long event; | ||
| 215 | unsigned power; | ||
| 158 | struct isp1704_charger *isp = | 216 | struct isp1704_charger *isp = |
| 159 | container_of(data, struct isp1704_charger, work); | 217 | container_of(data, struct isp1704_charger, work); |
| 218 | static DEFINE_MUTEX(lock); | ||
| 160 | 219 | ||
| 161 | /* | 220 | event = isp->event; |
| 162 | * FIXME Only supporting dedicated chargers even though isp1704 can | 221 | power = isp->max_power; |
| 163 | * detect HUB and HOST chargers. If the device has already been | ||
| 164 | * enumerated, the detection will break the connection. | ||
| 165 | */ | ||
| 166 | if (isp->otg->state != OTG_STATE_B_IDLE) | ||
| 167 | return; | ||
| 168 | 222 | ||
| 169 | /* disable data pullups */ | 223 | mutex_lock(&lock); |
| 170 | if (isp->otg->gadget) | 224 | |
| 171 | usb_gadget_disconnect(isp->otg->gadget); | 225 | switch (event) { |
| 226 | case USB_EVENT_VBUS: | ||
| 227 | isp->online = true; | ||
| 228 | |||
| 229 | /* detect charger */ | ||
| 230 | detect = isp1704_charger_detect(isp); | ||
| 231 | |||
| 232 | if (detect) { | ||
| 233 | isp->present = detect; | ||
| 234 | isp->psy.type = isp1704_charger_type(isp); | ||
| 235 | } | ||
| 172 | 236 | ||
| 173 | /* detect charger */ | 237 | switch (isp->psy.type) { |
| 174 | detect = isp1704_charger_detect(isp); | 238 | case POWER_SUPPLY_TYPE_USB_DCP: |
| 175 | if (detect) { | 239 | isp->current_max = 1800; |
| 176 | isp->present = detect; | 240 | break; |
| 177 | power_supply_changed(&isp->psy); | 241 | case POWER_SUPPLY_TYPE_USB_CDP: |
| 242 | /* | ||
| 243 | * Only 500mA here or high speed chirp | ||
| 244 | * handshaking may break | ||
| 245 | */ | ||
| 246 | isp->current_max = 500; | ||
| 247 | /* FALLTHROUGH */ | ||
| 248 | case POWER_SUPPLY_TYPE_USB: | ||
| 249 | default: | ||
| 250 | /* enable data pullups */ | ||
| 251 | if (isp->otg->gadget) | ||
| 252 | usb_gadget_connect(isp->otg->gadget); | ||
| 253 | } | ||
| 254 | break; | ||
| 255 | case USB_EVENT_NONE: | ||
| 256 | isp->online = false; | ||
| 257 | isp->current_max = 0; | ||
| 258 | isp->present = 0; | ||
| 259 | isp->current_max = 0; | ||
| 260 | isp->psy.type = POWER_SUPPLY_TYPE_USB; | ||
| 261 | |||
| 262 | /* | ||
| 263 | * Disable data pullups. We need to prevent the controller from | ||
| 264 | * enumerating. | ||
| 265 | * | ||
| 266 | * FIXME: This is here to allow charger detection with Host/HUB | ||
| 267 | * chargers. The pullups may be enabled elsewhere, so this can | ||
| 268 | * not be the final solution. | ||
| 269 | */ | ||
| 270 | if (isp->otg->gadget) | ||
| 271 | usb_gadget_disconnect(isp->otg->gadget); | ||
| 272 | break; | ||
| 273 | case USB_EVENT_ENUMERATED: | ||
| 274 | if (isp->present) | ||
| 275 | isp->current_max = 1800; | ||
| 276 | else | ||
| 277 | isp->current_max = power; | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | goto out; | ||
| 178 | } | 281 | } |
| 179 | 282 | ||
| 180 | /* enable data pullups */ | 283 | power_supply_changed(&isp->psy); |
| 181 | if (isp->otg->gadget) | 284 | out: |
| 182 | usb_gadget_connect(isp->otg->gadget); | 285 | mutex_unlock(&lock); |
| 183 | } | 286 | } |
| 184 | 287 | ||
| 185 | static int isp1704_notifier_call(struct notifier_block *nb, | 288 | static int isp1704_notifier_call(struct notifier_block *nb, |
| 186 | unsigned long event, void *unused) | 289 | unsigned long event, void *power) |
| 187 | { | 290 | { |
| 188 | struct isp1704_charger *isp = | 291 | struct isp1704_charger *isp = |
| 189 | container_of(nb, struct isp1704_charger, nb); | 292 | container_of(nb, struct isp1704_charger, nb); |
| 190 | 293 | ||
| 191 | switch (event) { | 294 | isp->event = event; |
| 192 | case USB_EVENT_VBUS: | 295 | |
| 193 | schedule_work(&isp->work); | 296 | if (power) |
| 194 | break; | 297 | isp->max_power = *((unsigned *)power); |
| 195 | case USB_EVENT_NONE: | 298 | |
| 196 | if (isp->present) { | 299 | schedule_work(&isp->work); |
| 197 | isp->present = 0; | ||
| 198 | power_supply_changed(&isp->psy); | ||
| 199 | } | ||
| 200 | break; | ||
| 201 | default: | ||
| 202 | return NOTIFY_DONE; | ||
| 203 | } | ||
| 204 | 300 | ||
| 205 | return NOTIFY_OK; | 301 | return NOTIFY_OK; |
| 206 | } | 302 | } |
| @@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy, | |||
| 216 | case POWER_SUPPLY_PROP_PRESENT: | 312 | case POWER_SUPPLY_PROP_PRESENT: |
| 217 | val->intval = isp->present; | 313 | val->intval = isp->present; |
| 218 | break; | 314 | break; |
| 315 | case POWER_SUPPLY_PROP_ONLINE: | ||
| 316 | val->intval = isp->online; | ||
| 317 | break; | ||
| 318 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
| 319 | val->intval = isp->current_max; | ||
| 320 | break; | ||
| 219 | case POWER_SUPPLY_PROP_MODEL_NAME: | 321 | case POWER_SUPPLY_PROP_MODEL_NAME: |
| 220 | val->strval = isp->model; | 322 | val->strval = isp->model; |
| 221 | break; | 323 | break; |
| @@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy, | |||
| 230 | 332 | ||
| 231 | static enum power_supply_property power_props[] = { | 333 | static enum power_supply_property power_props[] = { |
| 232 | POWER_SUPPLY_PROP_PRESENT, | 334 | POWER_SUPPLY_PROP_PRESENT, |
| 335 | POWER_SUPPLY_PROP_ONLINE, | ||
| 336 | POWER_SUPPLY_PROP_CURRENT_MAX, | ||
| 233 | POWER_SUPPLY_PROP_MODEL_NAME, | 337 | POWER_SUPPLY_PROP_MODEL_NAME, |
| 234 | POWER_SUPPLY_PROP_MANUFACTURER, | 338 | POWER_SUPPLY_PROP_MANUFACTURER, |
| 235 | }; | 339 | }; |
| @@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) | |||
| 287 | if (!isp->otg) | 391 | if (!isp->otg) |
| 288 | goto fail0; | 392 | goto fail0; |
| 289 | 393 | ||
| 394 | isp->dev = &pdev->dev; | ||
| 395 | platform_set_drvdata(pdev, isp); | ||
| 396 | |||
| 290 | ret = isp1704_test_ulpi(isp); | 397 | ret = isp1704_test_ulpi(isp); |
| 291 | if (ret < 0) | 398 | if (ret < 0) |
| 292 | goto fail1; | 399 | goto fail1; |
| 293 | 400 | ||
| 294 | isp->dev = &pdev->dev; | ||
| 295 | platform_set_drvdata(pdev, isp); | ||
| 296 | |||
| 297 | isp->psy.name = "isp1704"; | 401 | isp->psy.name = "isp1704"; |
| 298 | isp->psy.type = POWER_SUPPLY_TYPE_USB; | 402 | isp->psy.type = POWER_SUPPLY_TYPE_USB; |
| 299 | isp->psy.properties = power_props; | 403 | isp->psy.properties = power_props; |
| @@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) | |||
| 318 | 422 | ||
| 319 | dev_info(isp->dev, "registered with product id %s\n", isp->model); | 423 | dev_info(isp->dev, "registered with product id %s\n", isp->model); |
| 320 | 424 | ||
| 425 | /* | ||
| 426 | * Taking over the D+ pullup. | ||
| 427 | * | ||
| 428 | * FIXME: The device will be disconnected if it was already | ||
| 429 | * enumerated. The charger driver should be always loaded before any | ||
| 430 | * gadget is loaded. | ||
| 431 | */ | ||
| 432 | if (isp->otg->gadget) | ||
| 433 | usb_gadget_disconnect(isp->otg->gadget); | ||
| 434 | |||
| 435 | /* Detect charger if VBUS is valid (the cable was already plugged). */ | ||
| 436 | ret = otg_io_read(isp->otg, ULPI_USB_INT_STS); | ||
| 437 | if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) { | ||
| 438 | isp->event = USB_EVENT_VBUS; | ||
| 439 | schedule_work(&isp->work); | ||
| 440 | } | ||
| 441 | |||
| 321 | return 0; | 442 | return 0; |
| 322 | fail2: | 443 | fail2: |
| 323 | power_supply_unregister(&isp->psy); | 444 | power_supply_unregister(&isp->psy); |
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index a8108a73593e..02414db6a94c 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <linux/io.h> | ||
| 22 | 23 | ||
| 23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 24 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
| @@ -47,6 +48,8 @@ struct jz_battery { | |||
| 47 | 48 | ||
| 48 | struct power_supply battery; | 49 | struct power_supply battery; |
| 49 | struct delayed_work work; | 50 | struct delayed_work work; |
| 51 | |||
| 52 | struct mutex lock; | ||
| 50 | }; | 53 | }; |
| 51 | 54 | ||
| 52 | static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy) | 55 | 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) | |||
| 68 | unsigned long val; | 71 | unsigned long val; |
| 69 | long voltage; | 72 | long voltage; |
| 70 | 73 | ||
| 74 | mutex_lock(&battery->lock); | ||
| 75 | |||
| 71 | INIT_COMPLETION(battery->read_completion); | 76 | INIT_COMPLETION(battery->read_completion); |
| 72 | 77 | ||
| 73 | enable_irq(battery->irq); | 78 | enable_irq(battery->irq); |
| @@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery) | |||
| 91 | battery->cell->disable(battery->pdev); | 96 | battery->cell->disable(battery->pdev); |
| 92 | disable_irq(battery->irq); | 97 | disable_irq(battery->irq); |
| 93 | 98 | ||
| 99 | mutex_unlock(&battery->lock); | ||
| 100 | |||
| 94 | return voltage; | 101 | return voltage; |
| 95 | } | 102 | } |
| 96 | 103 | ||
| @@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev) | |||
| 240 | struct jz_battery *jz_battery; | 247 | struct jz_battery *jz_battery; |
| 241 | struct power_supply *battery; | 248 | struct power_supply *battery; |
| 242 | 249 | ||
| 250 | if (!pdata) { | ||
| 251 | dev_err(&pdev->dev, "No platform_data supplied\n"); | ||
| 252 | return -ENXIO; | ||
| 253 | } | ||
| 254 | |||
| 243 | jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL); | 255 | jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL); |
| 244 | if (!jz_battery) { | 256 | if (!jz_battery) { |
| 245 | dev_err(&pdev->dev, "Failed to allocate driver structure\n"); | 257 | dev_err(&pdev->dev, "Failed to allocate driver structure\n"); |
| @@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev) | |||
| 291 | jz_battery->pdev = pdev; | 303 | jz_battery->pdev = pdev; |
| 292 | 304 | ||
| 293 | init_completion(&jz_battery->read_completion); | 305 | init_completion(&jz_battery->read_completion); |
| 306 | mutex_init(&jz_battery->lock); | ||
| 294 | 307 | ||
| 295 | INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); | 308 | INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); |
| 296 | 309 | ||
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c new file mode 100644 index 000000000000..c5c8805156cb --- /dev/null +++ b/drivers/power/max17042_battery.c | |||
| @@ -0,0 +1,239 @@ | |||
| 1 | /* | ||
| 2 | * Fuel gauge driver for Maxim 17042 / 8966 / 8997 | ||
| 3 | * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2011 Samsung Electronics | ||
| 6 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | * This driver is based on max17040_battery.c | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <linux/mod_devicetable.h> | ||
| 29 | #include <linux/power_supply.h> | ||
| 30 | #include <linux/power/max17042_battery.h> | ||
| 31 | |||
| 32 | enum max17042_register { | ||
| 33 | MAX17042_STATUS = 0x00, | ||
| 34 | MAX17042_VALRT_Th = 0x01, | ||
| 35 | MAX17042_TALRT_Th = 0x02, | ||
| 36 | MAX17042_SALRT_Th = 0x03, | ||
| 37 | MAX17042_AtRate = 0x04, | ||
| 38 | MAX17042_RepCap = 0x05, | ||
| 39 | MAX17042_RepSOC = 0x06, | ||
| 40 | MAX17042_Age = 0x07, | ||
| 41 | MAX17042_TEMP = 0x08, | ||
| 42 | MAX17042_VCELL = 0x09, | ||
| 43 | MAX17042_Current = 0x0A, | ||
| 44 | MAX17042_AvgCurrent = 0x0B, | ||
| 45 | MAX17042_Qresidual = 0x0C, | ||
| 46 | MAX17042_SOC = 0x0D, | ||
| 47 | MAX17042_AvSOC = 0x0E, | ||
| 48 | MAX17042_RemCap = 0x0F, | ||
| 49 | MAX17402_FullCAP = 0x10, | ||
| 50 | MAX17042_TTE = 0x11, | ||
| 51 | MAX17042_V_empty = 0x12, | ||
| 52 | |||
| 53 | MAX17042_RSLOW = 0x14, | ||
| 54 | |||
| 55 | MAX17042_AvgTA = 0x16, | ||
| 56 | MAX17042_Cycles = 0x17, | ||
| 57 | MAX17042_DesignCap = 0x18, | ||
| 58 | MAX17042_AvgVCELL = 0x19, | ||
| 59 | MAX17042_MinMaxTemp = 0x1A, | ||
| 60 | MAX17042_MinMaxVolt = 0x1B, | ||
| 61 | MAX17042_MinMaxCurr = 0x1C, | ||
| 62 | MAX17042_CONFIG = 0x1D, | ||
| 63 | MAX17042_ICHGTerm = 0x1E, | ||
| 64 | MAX17042_AvCap = 0x1F, | ||
| 65 | MAX17042_ManName = 0x20, | ||
| 66 | MAX17042_DevName = 0x21, | ||
| 67 | MAX17042_DevChem = 0x22, | ||
| 68 | |||
| 69 | MAX17042_TempNom = 0x24, | ||
| 70 | MAX17042_TempCold = 0x25, | ||
| 71 | MAX17042_TempHot = 0x26, | ||
| 72 | MAX17042_AIN = 0x27, | ||
| 73 | MAX17042_LearnCFG = 0x28, | ||
| 74 | MAX17042_SHFTCFG = 0x29, | ||
| 75 | MAX17042_RelaxCFG = 0x2A, | ||
| 76 | MAX17042_MiscCFG = 0x2B, | ||
| 77 | MAX17042_TGAIN = 0x2C, | ||
| 78 | MAx17042_TOFF = 0x2D, | ||
| 79 | MAX17042_CGAIN = 0x2E, | ||
| 80 | MAX17042_COFF = 0x2F, | ||
| 81 | |||
| 82 | MAX17042_Q_empty = 0x33, | ||
| 83 | MAX17042_T_empty = 0x34, | ||
| 84 | |||
| 85 | MAX17042_RCOMP0 = 0x38, | ||
| 86 | MAX17042_TempCo = 0x39, | ||
| 87 | MAX17042_Rx = 0x3A, | ||
| 88 | MAX17042_T_empty0 = 0x3B, | ||
| 89 | MAX17042_TaskPeriod = 0x3C, | ||
| 90 | MAX17042_FSTAT = 0x3D, | ||
| 91 | |||
| 92 | MAX17042_SHDNTIMER = 0x3F, | ||
| 93 | |||
| 94 | MAX17042_VFRemCap = 0x4A, | ||
| 95 | |||
| 96 | MAX17042_QH = 0x4D, | ||
| 97 | MAX17042_QL = 0x4E, | ||
| 98 | }; | ||
| 99 | |||
| 100 | struct max17042_chip { | ||
| 101 | struct i2c_client *client; | ||
| 102 | struct power_supply battery; | ||
| 103 | struct max17042_platform_data *pdata; | ||
| 104 | }; | ||
| 105 | |||
| 106 | static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value) | ||
| 107 | { | ||
| 108 | int ret = i2c_smbus_write_word_data(client, reg, value); | ||
| 109 | |||
| 110 | if (ret < 0) | ||
| 111 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
| 112 | |||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int max17042_read_reg(struct i2c_client *client, u8 reg) | ||
| 117 | { | ||
| 118 | int ret = i2c_smbus_read_word_data(client, reg); | ||
| 119 | |||
| 120 | if (ret < 0) | ||
| 121 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
| 122 | |||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | |||
| 126 | static enum power_supply_property max17042_battery_props[] = { | ||
| 127 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 128 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
| 129 | POWER_SUPPLY_PROP_CAPACITY, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static int max17042_get_property(struct power_supply *psy, | ||
| 133 | enum power_supply_property psp, | ||
| 134 | union power_supply_propval *val) | ||
| 135 | { | ||
| 136 | struct max17042_chip *chip = container_of(psy, | ||
| 137 | struct max17042_chip, battery); | ||
| 138 | |||
| 139 | switch (psp) { | ||
| 140 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 141 | val->intval = max17042_read_reg(chip->client, | ||
| 142 | MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */ | ||
| 143 | break; | ||
| 144 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
| 145 | val->intval = max17042_read_reg(chip->client, | ||
| 146 | MAX17042_AvgVCELL) * 83; | ||
| 147 | break; | ||
| 148 | case POWER_SUPPLY_PROP_CAPACITY: | ||
| 149 | val->intval = max17042_read_reg(chip->client, | ||
| 150 | MAX17042_SOC) / 256; | ||
| 151 | break; | ||
| 152 | default: | ||
| 153 | return -EINVAL; | ||
| 154 | } | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static int __devinit max17042_probe(struct i2c_client *client, | ||
| 159 | const struct i2c_device_id *id) | ||
| 160 | { | ||
| 161 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
| 162 | struct max17042_chip *chip; | ||
| 163 | int ret; | ||
| 164 | |||
| 165 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | ||
| 166 | return -EIO; | ||
| 167 | |||
| 168 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
| 169 | if (!chip) | ||
| 170 | return -ENOMEM; | ||
| 171 | |||
| 172 | chip->client = client; | ||
| 173 | chip->pdata = client->dev.platform_data; | ||
| 174 | |||
| 175 | i2c_set_clientdata(client, chip); | ||
| 176 | |||
| 177 | chip->battery.name = "max17042_battery"; | ||
| 178 | chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; | ||
| 179 | chip->battery.get_property = max17042_get_property; | ||
| 180 | chip->battery.properties = max17042_battery_props; | ||
| 181 | chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props); | ||
| 182 | |||
| 183 | ret = power_supply_register(&client->dev, &chip->battery); | ||
| 184 | if (ret) { | ||
| 185 | dev_err(&client->dev, "failed: power supply register\n"); | ||
| 186 | i2c_set_clientdata(client, NULL); | ||
| 187 | kfree(chip); | ||
| 188 | return ret; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (!chip->pdata->enable_current_sense) { | ||
| 192 | max17042_write_reg(client, MAX17042_CGAIN, 0x0000); | ||
| 193 | max17042_write_reg(client, MAX17042_MiscCFG, 0x0003); | ||
| 194 | max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); | ||
| 195 | } | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int __devexit max17042_remove(struct i2c_client *client) | ||
| 201 | { | ||
| 202 | struct max17042_chip *chip = i2c_get_clientdata(client); | ||
| 203 | |||
| 204 | power_supply_unregister(&chip->battery); | ||
| 205 | i2c_set_clientdata(client, NULL); | ||
| 206 | kfree(chip); | ||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static const struct i2c_device_id max17042_id[] = { | ||
| 211 | { "max17042", 0 }, | ||
| 212 | { } | ||
| 213 | }; | ||
| 214 | MODULE_DEVICE_TABLE(i2c, max17042_id); | ||
| 215 | |||
| 216 | static struct i2c_driver max17042_i2c_driver = { | ||
| 217 | .driver = { | ||
| 218 | .name = "max17042", | ||
| 219 | }, | ||
| 220 | .probe = max17042_probe, | ||
| 221 | .remove = __devexit_p(max17042_remove), | ||
| 222 | .id_table = max17042_id, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static int __init max17042_init(void) | ||
| 226 | { | ||
| 227 | return i2c_add_driver(&max17042_i2c_driver); | ||
| 228 | } | ||
| 229 | module_init(max17042_init); | ||
| 230 | |||
| 231 | static void __exit max17042_exit(void) | ||
| 232 | { | ||
| 233 | i2c_del_driver(&max17042_i2c_driver); | ||
| 234 | } | ||
| 235 | module_exit(max17042_exit); | ||
| 236 | |||
| 237 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
| 238 | MODULE_DESCRIPTION("MAX17042 Fuel Gauge"); | ||
| 239 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 5bc1dcf7785e..0b0ff3a936a6 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c | |||
| @@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val) | |||
| 201 | return ret; | 201 | return ret; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | static int olpc_bat_get_charge_full_design(union power_supply_propval *val) | ||
| 205 | { | ||
| 206 | uint8_t ec_byte; | ||
| 207 | union power_supply_propval tech; | ||
| 208 | int ret, mfr; | ||
| 209 | |||
| 210 | ret = olpc_bat_get_tech(&tech); | ||
| 211 | if (ret) | ||
| 212 | return ret; | ||
| 213 | |||
| 214 | ec_byte = BAT_ADDR_MFR_TYPE; | ||
| 215 | ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); | ||
| 216 | if (ret) | ||
| 217 | return ret; | ||
| 218 | |||
| 219 | mfr = ec_byte >> 4; | ||
| 220 | |||
| 221 | switch (tech.intval) { | ||
| 222 | case POWER_SUPPLY_TECHNOLOGY_NiMH: | ||
| 223 | switch (mfr) { | ||
| 224 | case 1: /* Gold Peak */ | ||
| 225 | val->intval = 3000000*.8; | ||
| 226 | break; | ||
| 227 | default: | ||
| 228 | return -EIO; | ||
| 229 | } | ||
| 230 | break; | ||
| 231 | |||
| 232 | case POWER_SUPPLY_TECHNOLOGY_LiFe: | ||
| 233 | switch (mfr) { | ||
| 234 | case 1: /* Gold Peak */ | ||
| 235 | val->intval = 2800000; | ||
| 236 | break; | ||
| 237 | case 2: /* BYD */ | ||
| 238 | val->intval = 3100000; | ||
| 239 | break; | ||
| 240 | default: | ||
| 241 | return -EIO; | ||
| 242 | } | ||
| 243 | break; | ||
| 244 | |||
| 245 | default: | ||
| 246 | return -EIO; | ||
| 247 | } | ||
| 248 | |||
| 249 | return ret; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int olpc_bat_get_charge_now(union power_supply_propval *val) | ||
| 253 | { | ||
| 254 | uint8_t soc; | ||
| 255 | union power_supply_propval full; | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1); | ||
| 259 | if (ret) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | ret = olpc_bat_get_charge_full_design(&full); | ||
| 263 | if (ret) | ||
| 264 | return ret; | ||
| 265 | |||
| 266 | val->intval = soc * (full.intval / 100); | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 204 | /********************************************************************* | 270 | /********************************************************************* |
| 205 | * Battery properties | 271 | * Battery properties |
| 206 | *********************************************************************/ | 272 | *********************************************************************/ |
| @@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 267 | return ret; | 333 | return ret; |
| 268 | break; | 334 | break; |
| 269 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | 335 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: |
| 336 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 270 | ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); | 337 | ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); |
| 271 | if (ret) | 338 | if (ret) |
| 272 | return ret; | 339 | return ret; |
| @@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 274 | val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; | 341 | val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; |
| 275 | break; | 342 | break; |
| 276 | case POWER_SUPPLY_PROP_CURRENT_AVG: | 343 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
| 344 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
| 277 | ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); | 345 | ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); |
| 278 | if (ret) | 346 | if (ret) |
| 279 | return ret; | 347 | return ret; |
| @@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 294 | else | 362 | else |
| 295 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | 363 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; |
| 296 | break; | 364 | break; |
| 365 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
| 366 | ret = olpc_bat_get_charge_full_design(val); | ||
| 367 | if (ret) | ||
| 368 | return ret; | ||
| 369 | break; | ||
| 370 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
| 371 | ret = olpc_bat_get_charge_now(val); | ||
| 372 | if (ret) | ||
| 373 | return ret; | ||
| 374 | break; | ||
| 297 | case POWER_SUPPLY_PROP_TEMP: | 375 | case POWER_SUPPLY_PROP_TEMP: |
| 298 | ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); | 376 | ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); |
| 299 | if (ret) | 377 | if (ret) |
| @@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 331 | return ret; | 409 | return ret; |
| 332 | } | 410 | } |
| 333 | 411 | ||
| 334 | static enum power_supply_property olpc_bat_props[] = { | 412 | static enum power_supply_property olpc_xo1_bat_props[] = { |
| 335 | POWER_SUPPLY_PROP_STATUS, | 413 | POWER_SUPPLY_PROP_STATUS, |
| 336 | POWER_SUPPLY_PROP_CHARGE_TYPE, | 414 | POWER_SUPPLY_PROP_CHARGE_TYPE, |
| 337 | POWER_SUPPLY_PROP_PRESENT, | 415 | POWER_SUPPLY_PROP_PRESENT, |
| 338 | POWER_SUPPLY_PROP_HEALTH, | 416 | POWER_SUPPLY_PROP_HEALTH, |
| 339 | POWER_SUPPLY_PROP_TECHNOLOGY, | 417 | POWER_SUPPLY_PROP_TECHNOLOGY, |
| 340 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | 418 | POWER_SUPPLY_PROP_VOLTAGE_AVG, |
| 419 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 341 | POWER_SUPPLY_PROP_CURRENT_AVG, | 420 | POWER_SUPPLY_PROP_CURRENT_AVG, |
| 421 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
| 342 | POWER_SUPPLY_PROP_CAPACITY, | 422 | POWER_SUPPLY_PROP_CAPACITY, |
| 343 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | 423 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, |
| 424 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
| 425 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
| 344 | POWER_SUPPLY_PROP_TEMP, | 426 | POWER_SUPPLY_PROP_TEMP, |
| 345 | POWER_SUPPLY_PROP_TEMP_AMBIENT, | 427 | POWER_SUPPLY_PROP_TEMP_AMBIENT, |
| 346 | POWER_SUPPLY_PROP_MANUFACTURER, | 428 | POWER_SUPPLY_PROP_MANUFACTURER, |
| @@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = { | |||
| 348 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | 430 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
| 349 | }; | 431 | }; |
| 350 | 432 | ||
| 433 | /* XO-1.5 does not have ambient temperature property */ | ||
| 434 | static enum power_supply_property olpc_xo15_bat_props[] = { | ||
| 435 | POWER_SUPPLY_PROP_STATUS, | ||
| 436 | POWER_SUPPLY_PROP_CHARGE_TYPE, | ||
| 437 | POWER_SUPPLY_PROP_PRESENT, | ||
| 438 | POWER_SUPPLY_PROP_HEALTH, | ||
| 439 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
| 440 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | ||
| 441 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 442 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
| 443 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
| 444 | POWER_SUPPLY_PROP_CAPACITY, | ||
| 445 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
| 446 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
| 447 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
| 448 | POWER_SUPPLY_PROP_TEMP, | ||
| 449 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
| 450 | POWER_SUPPLY_PROP_SERIAL_NUMBER, | ||
| 451 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
| 452 | }; | ||
| 453 | |||
| 351 | /* EEPROM reading goes completely around the power_supply API, sadly */ | 454 | /* EEPROM reading goes completely around the power_supply API, sadly */ |
| 352 | 455 | ||
| 353 | #define EEPROM_START 0x20 | 456 | #define EEPROM_START 0x20 |
| @@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = { | |||
| 419 | static struct platform_device *bat_pdev; | 522 | static struct platform_device *bat_pdev; |
| 420 | 523 | ||
| 421 | static struct power_supply olpc_bat = { | 524 | static struct power_supply olpc_bat = { |
| 422 | .properties = olpc_bat_props, | ||
| 423 | .num_properties = ARRAY_SIZE(olpc_bat_props), | ||
| 424 | .get_property = olpc_bat_get_property, | 525 | .get_property = olpc_bat_get_property, |
| 425 | .use_for_apm = 1, | 526 | .use_for_apm = 1, |
| 426 | }; | 527 | }; |
| @@ -466,6 +567,13 @@ static int __init olpc_bat_init(void) | |||
| 466 | goto ac_failed; | 567 | goto ac_failed; |
| 467 | 568 | ||
| 468 | olpc_bat.name = bat_pdev->name; | 569 | olpc_bat.name = bat_pdev->name; |
| 570 | if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ | ||
| 571 | olpc_bat.properties = olpc_xo15_bat_props; | ||
| 572 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); | ||
| 573 | } else { /* XO-1 */ | ||
| 574 | olpc_bat.properties = olpc_xo1_bat_props; | ||
| 575 | olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); | ||
| 576 | } | ||
| 469 | 577 | ||
| 470 | ret = power_supply_register(&bat_pdev->dev, &olpc_bat); | 578 | ret = power_supply_register(&bat_pdev->dev, &olpc_bat); |
| 471 | if (ret) | 579 | if (ret) |
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 91606bb55318..970f7335d3a7 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
| @@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy) | |||
| 190 | goto success; | 190 | goto success; |
| 191 | 191 | ||
| 192 | create_triggers_failed: | 192 | create_triggers_failed: |
| 193 | device_unregister(psy->dev); | 193 | device_del(dev); |
| 194 | kobject_set_name_failed: | 194 | kobject_set_name_failed: |
| 195 | device_add_failed: | 195 | device_add_failed: |
| 196 | kfree(dev); | 196 | put_device(dev); |
| 197 | success: | 197 | success: |
| 198 | return rc; | 198 | return rc; |
| 199 | } | 199 | } |
| @@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register); | |||
| 201 | 201 | ||
| 202 | void power_supply_unregister(struct power_supply *psy) | 202 | void power_supply_unregister(struct power_supply *psy) |
| 203 | { | 203 | { |
| 204 | flush_scheduled_work(); | 204 | cancel_work_sync(&psy->changed_work); |
| 205 | power_supply_remove_triggers(psy); | 205 | power_supply_remove_triggers(psy); |
| 206 | device_unregister(psy->dev); | 206 | device_unregister(psy->dev); |
| 207 | } | 207 | } |
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index 4a8ae3935b3b..4255f2358b13 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c | |||
| @@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance) | |||
| 112 | return volt_val + cur_val * impedance / 1000; | 112 | return volt_val + cur_val * impedance / 1000; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | static int charge_finished(struct s3c_adc_bat *bat) | ||
| 116 | { | ||
| 117 | return bat->pdata->gpio_inverted ? | ||
| 118 | !gpio_get_value(bat->pdata->gpio_charge_finished) : | ||
| 119 | gpio_get_value(bat->pdata->gpio_charge_finished); | ||
| 120 | } | ||
| 121 | |||
| 115 | static int s3c_adc_bat_get_property(struct power_supply *psy, | 122 | static int s3c_adc_bat_get_property(struct power_supply *psy, |
| 116 | enum power_supply_property psp, | 123 | enum power_supply_property psp, |
| 117 | union power_supply_propval *val) | 124 | union power_supply_propval *val) |
| @@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy, | |||
| 140 | 147 | ||
| 141 | if (bat->cable_plugged && | 148 | if (bat->cable_plugged && |
| 142 | ((bat->pdata->gpio_charge_finished < 0) || | 149 | ((bat->pdata->gpio_charge_finished < 0) || |
| 143 | !gpio_get_value(bat->pdata->gpio_charge_finished))) { | 150 | !charge_finished(bat))) { |
| 144 | lut = bat->pdata->lut_acin; | 151 | lut = bat->pdata->lut_acin; |
| 145 | lut_size = bat->pdata->lut_acin_cnt; | 152 | lut_size = bat->pdata->lut_acin_cnt; |
| 146 | } | 153 | } |
| @@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work) | |||
| 236 | } | 243 | } |
| 237 | } else { | 244 | } else { |
| 238 | if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) { | 245 | if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) { |
| 239 | is_charged = gpio_get_value( | 246 | is_charged = charge_finished(&main_bat); |
| 240 | main_bat.pdata->gpio_charge_finished); | ||
| 241 | if (is_charged) { | 247 | if (is_charged) { |
| 242 | if (bat->pdata->disable_charger) | 248 | if (bat->pdata->disable_charger) |
| 243 | bat->pdata->disable_charger(); | 249 | bat->pdata->disable_charger(); |
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c index ee04936b2db5..53f0d3524fcd 100644 --- a/drivers/power/tosa_battery.c +++ b/drivers/power/tosa_battery.c | |||
| @@ -332,7 +332,7 @@ static struct { | |||
| 332 | static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) | 332 | static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) |
| 333 | { | 333 | { |
| 334 | /* flush all pending status updates */ | 334 | /* flush all pending status updates */ |
| 335 | flush_scheduled_work(); | 335 | flush_work_sync(&bat_work); |
| 336 | return 0; | 336 | return 0; |
| 337 | } | 337 | } |
| 338 | 338 | ||
| @@ -422,7 +422,7 @@ err_psy_reg_jacket: | |||
| 422 | err_psy_reg_main: | 422 | err_psy_reg_main: |
| 423 | 423 | ||
| 424 | /* see comment in tosa_bat_remove */ | 424 | /* see comment in tosa_bat_remove */ |
| 425 | flush_scheduled_work(); | 425 | cancel_work_sync(&bat_work); |
| 426 | 426 | ||
| 427 | i--; | 427 | i--; |
| 428 | err_gpio: | 428 | err_gpio: |
| @@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev) | |||
| 445 | power_supply_unregister(&tosa_bat_main.psy); | 445 | power_supply_unregister(&tosa_bat_main.psy); |
| 446 | 446 | ||
| 447 | /* | 447 | /* |
| 448 | * now flush all pending work. | 448 | * Now cancel the bat_work. We won't get any more schedules, |
| 449 | * we won't get any more schedules, since all | 449 | * since all sources (isr and external_power_changed) are |
| 450 | * sources (isr and external_power_changed) | 450 | * unregistered now. |
| 451 | * are unregistered now. | ||
| 452 | */ | 451 | */ |
| 453 | flush_scheduled_work(); | 452 | cancel_work_sync(&bat_work); |
| 454 | 453 | ||
| 455 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) | 454 | for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) |
| 456 | gpio_free(gpios[i].gpio); | 455 | gpio_free(gpios[i].gpio); |
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index 5071d85ec12d..156559e56fa5 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c | |||
| @@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data) | |||
| 147 | #ifdef CONFIG_PM | 147 | #ifdef CONFIG_PM |
| 148 | static int wm97xx_bat_suspend(struct device *dev) | 148 | static int wm97xx_bat_suspend(struct device *dev) |
| 149 | { | 149 | { |
| 150 | flush_scheduled_work(); | 150 | flush_work_sync(&bat_work); |
| 151 | return 0; | 151 | return 0; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| @@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev) | |||
| 273 | free_irq(gpio_to_irq(pdata->charge_gpio), dev); | 273 | free_irq(gpio_to_irq(pdata->charge_gpio), dev); |
| 274 | gpio_free(pdata->charge_gpio); | 274 | gpio_free(pdata->charge_gpio); |
| 275 | } | 275 | } |
| 276 | flush_scheduled_work(); | 276 | cancel_work_sync(&bat_work); |
| 277 | power_supply_unregister(&bat_ps); | 277 | power_supply_unregister(&bat_ps); |
| 278 | kfree(prop); | 278 | kfree(prop); |
| 279 | return 0; | 279 | return 0; |
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 85064a9f649e..e5ed52d71937 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c | |||
| @@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client) | |||
| 254 | struct z2_charger *charger = i2c_get_clientdata(client); | 254 | struct z2_charger *charger = i2c_get_clientdata(client); |
| 255 | struct z2_battery_info *info = charger->info; | 255 | struct z2_battery_info *info = charger->info; |
| 256 | 256 | ||
| 257 | flush_scheduled_work(); | 257 | cancel_work_sync(&charger->bat_work); |
| 258 | power_supply_unregister(&charger->batt_ps); | 258 | power_supply_unregister(&charger->batt_ps); |
| 259 | 259 | ||
| 260 | kfree(charger->batt_ps.properties); | 260 | kfree(charger->batt_ps.properties); |
| @@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client) | |||
| 271 | #ifdef CONFIG_PM | 271 | #ifdef CONFIG_PM |
| 272 | static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) | 272 | static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) |
| 273 | { | 273 | { |
| 274 | flush_scheduled_work(); | 274 | struct z2_charger *charger = i2c_get_clientdata(client); |
| 275 | |||
| 276 | flush_work_sync(&charger->bat_work); | ||
| 275 | return 0; | 277 | return 0; |
| 276 | } | 278 | } |
| 277 | 279 | ||
diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h new file mode 100644 index 000000000000..de1dfe09a03d --- /dev/null +++ b/include/linux/power/gpio-charger.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License as published by the | ||
| 6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 7 | * option) any later version. | ||
| 8 | * | ||
| 9 | * You should have received a copy of the GNU General Public License along | ||
| 10 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 11 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __LINUX_POWER_GPIO_CHARGER_H__ | ||
| 16 | #define __LINUX_POWER_GPIO_CHARGER_H__ | ||
| 17 | |||
| 18 | #include <linux/power_supply.h> | ||
| 19 | #include <linux/types.h> | ||
| 20 | |||
| 21 | /** | ||
| 22 | * struct gpio_charger_platform_data - platform_data for gpio_charger devices | ||
| 23 | * @name: Name for the chargers power_supply device | ||
| 24 | * @type: Type of the charger | ||
| 25 | * @gpio: GPIO which is used to indicate the chargers status | ||
| 26 | * @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0 | ||
| 27 | * @supplied_to: Array of battery names to which this chargers supplies power | ||
| 28 | * @num_supplicants: Number of entries in the supplied_to array | ||
| 29 | */ | ||
| 30 | struct gpio_charger_platform_data { | ||
| 31 | const char *name; | ||
| 32 | enum power_supply_type type; | ||
| 33 | |||
| 34 | int gpio; | ||
| 35 | int gpio_active_low; | ||
| 36 | |||
| 37 | char **supplied_to; | ||
| 38 | size_t num_supplicants; | ||
| 39 | }; | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h new file mode 100644 index 000000000000..7995deb8bfc1 --- /dev/null +++ b/include/linux/power/max17042_battery.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Fuel gauge driver for Maxim 17042 / 8966 / 8997 | ||
| 3 | * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2011 Samsung Electronics | ||
| 6 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __MAX17042_BATTERY_H_ | ||
| 24 | #define __MAX17042_BATTERY_H_ | ||
| 25 | |||
| 26 | struct max17042_platform_data { | ||
| 27 | bool enable_current_sense; | ||
| 28 | }; | ||
| 29 | |||
| 30 | #endif /* __MAX17042_BATTERY_H_ */ | ||
diff --git a/include/linux/s3c_adc_battery.h b/include/linux/s3c_adc_battery.h index dbce22faa660..fbe58b7e63eb 100644 --- a/include/linux/s3c_adc_battery.h +++ b/include/linux/s3c_adc_battery.h | |||
| @@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata { | |||
| 14 | void (*disable_charger)(void); | 14 | void (*disable_charger)(void); |
| 15 | 15 | ||
| 16 | int gpio_charge_finished; | 16 | int gpio_charge_finished; |
| 17 | int gpio_inverted; | ||
| 17 | 18 | ||
| 18 | const struct s3c_adc_bat_thresh *lut_noac; | 19 | const struct s3c_adc_bat_thresh *lut_noac; |
| 19 | unsigned int lut_noac_cnt; | 20 | unsigned int lut_noac_cnt; |
