Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.infradead.org/battery-2.6

* git://git.infradead.org/battery-2.6: (21 commits)
power_supply: Add MAX17042 Fuel Gauge Driver
olpc_battery: Fix up XO-1.5 properties list
olpc_battery: Add support for CURRENT_NOW and VOLTAGE_NOW
olpc_battery: Add support for CHARGE_NOW
olpc_battery: Add support for CHARGE_FULL_DESIGN
olpc_battery: Ambient temperature is not available on XO-1.5
jz4740-battery: Should include linux/io.h
s3c_adc_battery: Add gpio_inverted field to pdata
power_supply: Don't use flush_scheduled_work()
power_supply: Fix use after free and memory leak
gpio-charger: Fix potential race between irq handler and probe/remove
gpio-charger: Provide default name for the power_supply
gpio-charger: Check result of kzalloc
jz4740-battery: Check if platform_data is supplied
isp1704_charger: Detect charger after probe
isp1704_charger: Set isp->dev before anything needs it
isp1704_charger: Detect HUB/Host chargers
isp1704_charger: Correct length for storing model
power_supply: Add gpio charger driver
jz4740-battery: Protect against concurrent battery readings
...

+838 -69
+20
drivers/power/Kconfig
··· 136 136 in handheld and portable equipment. The MAX17040 is configured 137 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 149 config BATTERY_Z2 140 150 tristate "Z2 battery driver" 141 151 depends on I2C && MACH_ZIPIT2 ··· 194 184 depends on TWL4030_CORE 195 185 help 196 186 Say Y here to enable support for TWL4030 Battery Charge Interface. 187 + 188 + config CHARGER_GPIO 189 + tristate "GPIO charger" 190 + depends on GPIOLIB 191 + help 192 + Say Y to include support for chargers which report their online status 193 + through a GPIO pin. 194 + 195 + This driver can be build as a module. If so, the module will be 196 + called gpio-charger. 197 197 198 198 endif # POWER_SUPPLY
+2
drivers/power/Makefile
··· 25 25 obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 26 26 obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o 27 27 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o 28 + obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o 28 29 obj-$(CONFIG_BATTERY_Z2) += z2_battery.o 29 30 obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o 30 31 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o ··· 33 32 obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o 34 33 obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o 35 34 obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o 35 + obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
+6 -7
drivers/power/collie_battery.c
··· 295 295 static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) 296 296 { 297 297 /* flush all pending status updates */ 298 - flush_scheduled_work(); 298 + flush_work_sync(&bat_work); 299 299 return 0; 300 300 } 301 301 ··· 362 362 err_psy_reg_main: 363 363 364 364 /* see comment in collie_bat_remove */ 365 - flush_scheduled_work(); 365 + cancel_work_sync(&bat_work); 366 366 367 367 i--; 368 368 err_gpio: ··· 382 382 power_supply_unregister(&collie_bat_main.psy); 383 383 384 384 /* 385 - * now flush all pending work. 386 - * we won't get any more schedules, since all 387 - * sources (isr and external_power_changed) 388 - * are unregistered now. 385 + * Now cancel the bat_work. We won't get any more schedules, 386 + * since all sources (isr and external_power_changed) are 387 + * unregistered now. 389 388 */ 390 - flush_scheduled_work(); 389 + cancel_work_sync(&bat_work); 391 390 392 391 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) 393 392 gpio_free(gpios[i].gpio);
+1 -1
drivers/power/ds2760_battery.c
··· 212 212 if (di->rem_capacity > 100) 213 213 di->rem_capacity = 100; 214 214 215 - if (di->current_uA >= 100L) 215 + if (di->current_uA < -100L) 216 216 di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L) 217 217 / (di->current_uA / 100L); 218 218 else
+188
drivers/power/gpio-charger.c
··· 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");
+1 -1
drivers/power/intel_mid_battery.c
··· 765 765 power_supply_unregister(&pbi->usb); 766 766 power_supply_unregister(&pbi->batt); 767 767 768 - flush_scheduled_work(); 768 + cancel_work_sync(&pbi->handler); 769 769 kfree(pbi); 770 770 return 0; 771 771 }
+161 -40
drivers/power/isp1704_charger.c
··· 59 59 struct notifier_block nb; 60 60 struct work_struct work; 61 61 62 - char model[7]; 62 + /* properties */ 63 + char model[8]; 63 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 }; 72 + 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 + } 65 115 66 116 /* 67 117 * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger ··· 177 127 static inline int isp1704_charger_detect(struct isp1704_charger *isp) 178 128 { 179 129 unsigned long timeout; 180 - u8 r; 130 + u8 pwr_ctrl; 181 131 int ret = 0; 132 + 133 + pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL); 182 134 183 135 /* set SW control bit in PWR_CTRL register */ 184 136 otg_io_write(isp->otg, ISP1704_PWR_CTRL, 185 137 ISP1704_PWR_CTRL_SWCTRL); 186 138 187 139 /* enable manual charger detection */ 188 - r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN); 189 - otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r); 140 + otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), 141 + ISP1704_PWR_CTRL_SWCTRL 142 + | ISP1704_PWR_CTRL_DPVSRC_EN); 190 143 usleep_range(1000, 2000); 191 144 192 145 timeout = jiffies + msecs_to_jiffies(300); ··· 200 147 ret = isp1704_charger_verify(isp); 201 148 break; 202 149 } 203 - } while (!time_after(jiffies, timeout)); 150 + } while (!time_after(jiffies, timeout) && isp->online); 151 + 152 + /* recover original state */ 153 + otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl); 204 154 205 155 return ret; 206 156 } ··· 211 155 static void isp1704_charger_work(struct work_struct *data) 212 156 { 213 157 int detect; 158 + unsigned long event; 159 + unsigned power; 214 160 struct isp1704_charger *isp = 215 161 container_of(data, struct isp1704_charger, work); 162 + static DEFINE_MUTEX(lock); 216 163 217 - /* 218 - * FIXME Only supporting dedicated chargers even though isp1704 can 219 - * detect HUB and HOST chargers. If the device has already been 220 - * enumerated, the detection will break the connection. 221 - */ 222 - if (isp->otg->state != OTG_STATE_B_IDLE) 223 - return; 164 + event = isp->event; 165 + power = isp->max_power; 224 166 225 - /* disable data pullups */ 226 - if (isp->otg->gadget) 227 - usb_gadget_disconnect(isp->otg->gadget); 167 + mutex_lock(&lock); 228 168 229 - /* detect charger */ 230 - detect = isp1704_charger_detect(isp); 231 - if (detect) { 232 - isp->present = detect; 233 - power_supply_changed(&isp->psy); 169 + switch (event) { 170 + case USB_EVENT_VBUS: 171 + isp->online = true; 172 + 173 + /* detect charger */ 174 + detect = isp1704_charger_detect(isp); 175 + 176 + if (detect) { 177 + isp->present = detect; 178 + isp->psy.type = isp1704_charger_type(isp); 179 + } 180 + 181 + switch (isp->psy.type) { 182 + case POWER_SUPPLY_TYPE_USB_DCP: 183 + isp->current_max = 1800; 184 + break; 185 + case POWER_SUPPLY_TYPE_USB_CDP: 186 + /* 187 + * Only 500mA here or high speed chirp 188 + * handshaking may break 189 + */ 190 + isp->current_max = 500; 191 + /* FALLTHROUGH */ 192 + case POWER_SUPPLY_TYPE_USB: 193 + default: 194 + /* enable data pullups */ 195 + if (isp->otg->gadget) 196 + usb_gadget_connect(isp->otg->gadget); 197 + } 198 + break; 199 + case USB_EVENT_NONE: 200 + isp->online = false; 201 + isp->current_max = 0; 202 + isp->present = 0; 203 + isp->current_max = 0; 204 + isp->psy.type = POWER_SUPPLY_TYPE_USB; 205 + 206 + /* 207 + * Disable data pullups. We need to prevent the controller from 208 + * enumerating. 209 + * 210 + * FIXME: This is here to allow charger detection with Host/HUB 211 + * chargers. The pullups may be enabled elsewhere, so this can 212 + * not be the final solution. 213 + */ 214 + if (isp->otg->gadget) 215 + usb_gadget_disconnect(isp->otg->gadget); 216 + break; 217 + case USB_EVENT_ENUMERATED: 218 + if (isp->present) 219 + isp->current_max = 1800; 220 + else 221 + isp->current_max = power; 222 + break; 223 + default: 224 + goto out; 234 225 } 235 226 236 - /* enable data pullups */ 237 - if (isp->otg->gadget) 238 - usb_gadget_connect(isp->otg->gadget); 227 + power_supply_changed(&isp->psy); 228 + out: 229 + mutex_unlock(&lock); 239 230 } 240 231 241 232 static int isp1704_notifier_call(struct notifier_block *nb, 242 - unsigned long event, void *unused) 233 + unsigned long event, void *power) 243 234 { 244 235 struct isp1704_charger *isp = 245 236 container_of(nb, struct isp1704_charger, nb); 246 237 247 - switch (event) { 248 - case USB_EVENT_VBUS: 249 - schedule_work(&isp->work); 250 - break; 251 - case USB_EVENT_NONE: 252 - if (isp->present) { 253 - isp->present = 0; 254 - power_supply_changed(&isp->psy); 255 - } 256 - break; 257 - default: 258 - return NOTIFY_DONE; 259 - } 238 + isp->event = event; 239 + 240 + if (power) 241 + isp->max_power = *((unsigned *)power); 242 + 243 + schedule_work(&isp->work); 260 244 261 245 return NOTIFY_OK; 262 246 } ··· 312 216 case POWER_SUPPLY_PROP_PRESENT: 313 217 val->intval = isp->present; 314 218 break; 219 + case POWER_SUPPLY_PROP_ONLINE: 220 + val->intval = isp->online; 221 + break; 222 + case POWER_SUPPLY_PROP_CURRENT_MAX: 223 + val->intval = isp->current_max; 224 + break; 315 225 case POWER_SUPPLY_PROP_MODEL_NAME: 316 226 val->strval = isp->model; 317 227 break; ··· 332 230 333 231 static enum power_supply_property power_props[] = { 334 232 POWER_SUPPLY_PROP_PRESENT, 233 + POWER_SUPPLY_PROP_ONLINE, 234 + POWER_SUPPLY_PROP_CURRENT_MAX, 335 235 POWER_SUPPLY_PROP_MODEL_NAME, 336 236 POWER_SUPPLY_PROP_MANUFACTURER, 337 237 }; ··· 391 287 if (!isp->otg) 392 288 goto fail0; 393 289 290 + isp->dev = &pdev->dev; 291 + platform_set_drvdata(pdev, isp); 292 + 394 293 ret = isp1704_test_ulpi(isp); 395 294 if (ret < 0) 396 295 goto fail1; 397 - 398 - isp->dev = &pdev->dev; 399 - platform_set_drvdata(pdev, isp); 400 296 401 297 isp->psy.name = "isp1704"; 402 298 isp->psy.type = POWER_SUPPLY_TYPE_USB; ··· 421 317 goto fail2; 422 318 423 319 dev_info(isp->dev, "registered with product id %s\n", isp->model); 320 + 321 + /* 322 + * Taking over the D+ pullup. 323 + * 324 + * FIXME: The device will be disconnected if it was already 325 + * enumerated. The charger driver should be always loaded before any 326 + * gadget is loaded. 327 + */ 328 + if (isp->otg->gadget) 329 + usb_gadget_disconnect(isp->otg->gadget); 330 + 331 + /* Detect charger if VBUS is valid (the cable was already plugged). */ 332 + ret = otg_io_read(isp->otg, ULPI_USB_INT_STS); 333 + if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) { 334 + isp->event = USB_EVENT_VBUS; 335 + schedule_work(&isp->work); 336 + } 424 337 425 338 return 0; 426 339 fail2:
+13
drivers/power/jz4740-battery.c
··· 19 19 #include <linux/module.h> 20 20 #include <linux/platform_device.h> 21 21 #include <linux/slab.h> 22 + #include <linux/io.h> 22 23 23 24 #include <linux/delay.h> 24 25 #include <linux/gpio.h> ··· 48 47 49 48 struct power_supply battery; 50 49 struct delayed_work work; 50 + 51 + struct mutex lock; 51 52 }; 52 53 53 54 static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy) ··· 70 67 unsigned long t; 71 68 unsigned long val; 72 69 long voltage; 70 + 71 + mutex_lock(&battery->lock); 73 72 74 73 INIT_COMPLETION(battery->read_completion); 75 74 ··· 95 90 96 91 battery->cell->disable(battery->pdev); 97 92 disable_irq(battery->irq); 93 + 94 + mutex_unlock(&battery->lock); 98 95 99 96 return voltage; 100 97 } ··· 247 240 struct jz_battery *jz_battery; 248 241 struct power_supply *battery; 249 242 243 + if (!pdata) { 244 + dev_err(&pdev->dev, "No platform_data supplied\n"); 245 + return -ENXIO; 246 + } 247 + 250 248 jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL); 251 249 if (!jz_battery) { 252 250 dev_err(&pdev->dev, "Failed to allocate driver structure\n"); ··· 303 291 jz_battery->pdev = pdev; 304 292 305 293 init_completion(&jz_battery->read_completion); 294 + mutex_init(&jz_battery->lock); 306 295 307 296 INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); 308 297
+239
drivers/power/max17042_battery.c
··· 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");
+111 -3
drivers/power/olpc_battery.c
··· 201 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 271 * Battery properties 206 272 *********************************************************************/ ··· 333 267 return ret; 334 268 break; 335 269 case POWER_SUPPLY_PROP_VOLTAGE_AVG: 270 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 336 271 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); 337 272 if (ret) 338 273 return ret; ··· 341 274 val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; 342 275 break; 343 276 case POWER_SUPPLY_PROP_CURRENT_AVG: 277 + case POWER_SUPPLY_PROP_CURRENT_NOW: 344 278 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); 345 279 if (ret) 346 280 return ret; ··· 361 293 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 362 294 else 363 295 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 296 + break; 297 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 298 + ret = olpc_bat_get_charge_full_design(val); 299 + if (ret) 300 + return ret; 301 + break; 302 + case POWER_SUPPLY_PROP_CHARGE_NOW: 303 + ret = olpc_bat_get_charge_now(val); 304 + if (ret) 305 + return ret; 364 306 break; 365 307 case POWER_SUPPLY_PROP_TEMP: 366 308 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); ··· 409 331 return ret; 410 332 } 411 333 412 - static enum power_supply_property olpc_bat_props[] = { 334 + static enum power_supply_property olpc_xo1_bat_props[] = { 413 335 POWER_SUPPLY_PROP_STATUS, 414 336 POWER_SUPPLY_PROP_CHARGE_TYPE, 415 337 POWER_SUPPLY_PROP_PRESENT, 416 338 POWER_SUPPLY_PROP_HEALTH, 417 339 POWER_SUPPLY_PROP_TECHNOLOGY, 418 340 POWER_SUPPLY_PROP_VOLTAGE_AVG, 341 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 419 342 POWER_SUPPLY_PROP_CURRENT_AVG, 343 + POWER_SUPPLY_PROP_CURRENT_NOW, 420 344 POWER_SUPPLY_PROP_CAPACITY, 421 345 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 346 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 347 + POWER_SUPPLY_PROP_CHARGE_NOW, 422 348 POWER_SUPPLY_PROP_TEMP, 423 349 POWER_SUPPLY_PROP_TEMP_AMBIENT, 350 + POWER_SUPPLY_PROP_MANUFACTURER, 351 + POWER_SUPPLY_PROP_SERIAL_NUMBER, 352 + POWER_SUPPLY_PROP_CHARGE_COUNTER, 353 + }; 354 + 355 + /* XO-1.5 does not have ambient temperature property */ 356 + static enum power_supply_property olpc_xo15_bat_props[] = { 357 + POWER_SUPPLY_PROP_STATUS, 358 + POWER_SUPPLY_PROP_CHARGE_TYPE, 359 + POWER_SUPPLY_PROP_PRESENT, 360 + POWER_SUPPLY_PROP_HEALTH, 361 + POWER_SUPPLY_PROP_TECHNOLOGY, 362 + POWER_SUPPLY_PROP_VOLTAGE_AVG, 363 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 364 + POWER_SUPPLY_PROP_CURRENT_AVG, 365 + POWER_SUPPLY_PROP_CURRENT_NOW, 366 + POWER_SUPPLY_PROP_CAPACITY, 367 + POWER_SUPPLY_PROP_CAPACITY_LEVEL, 368 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 369 + POWER_SUPPLY_PROP_CHARGE_NOW, 370 + POWER_SUPPLY_PROP_TEMP, 424 371 POWER_SUPPLY_PROP_MANUFACTURER, 425 372 POWER_SUPPLY_PROP_SERIAL_NUMBER, 426 373 POWER_SUPPLY_PROP_CHARGE_COUNTER, ··· 522 419 static struct platform_device *bat_pdev; 523 420 524 421 static struct power_supply olpc_bat = { 525 - .properties = olpc_bat_props, 526 - .num_properties = ARRAY_SIZE(olpc_bat_props), 527 422 .get_property = olpc_bat_get_property, 528 423 .use_for_apm = 1, 529 424 }; ··· 567 466 goto ac_failed; 568 467 569 468 olpc_bat.name = bat_pdev->name; 469 + if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ 470 + olpc_bat.properties = olpc_xo15_bat_props; 471 + olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); 472 + } else { /* XO-1 */ 473 + olpc_bat.properties = olpc_xo1_bat_props; 474 + olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); 475 + } 570 476 571 477 ret = power_supply_register(&bat_pdev->dev, &olpc_bat); 572 478 if (ret)
+3 -3
drivers/power/power_supply_core.c
··· 190 190 goto success; 191 191 192 192 create_triggers_failed: 193 - device_unregister(psy->dev); 193 + device_del(dev); 194 194 kobject_set_name_failed: 195 195 device_add_failed: 196 - kfree(dev); 196 + put_device(dev); 197 197 success: 198 198 return rc; 199 199 } ··· 201 201 202 202 void power_supply_unregister(struct power_supply *psy) 203 203 { 204 - flush_scheduled_work(); 204 + cancel_work_sync(&psy->changed_work); 205 205 power_supply_remove_triggers(psy); 206 206 device_unregister(psy->dev); 207 207 }
+9 -3
drivers/power/s3c_adc_battery.c
··· 112 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 122 static int s3c_adc_bat_get_property(struct power_supply *psy, 116 123 enum power_supply_property psp, 117 124 union power_supply_propval *val) ··· 147 140 148 141 if (bat->cable_plugged && 149 142 ((bat->pdata->gpio_charge_finished < 0) || 150 - !gpio_get_value(bat->pdata->gpio_charge_finished))) { 143 + !charge_finished(bat))) { 151 144 lut = bat->pdata->lut_acin; 152 145 lut_size = bat->pdata->lut_acin_cnt; 153 146 } ··· 243 236 } 244 237 } else { 245 238 if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) { 246 - is_charged = gpio_get_value( 247 - main_bat.pdata->gpio_charge_finished); 239 + is_charged = charge_finished(&main_bat); 248 240 if (is_charged) { 249 241 if (bat->pdata->disable_charger) 250 242 bat->pdata->disable_charger();
+6 -7
drivers/power/tosa_battery.c
··· 332 332 static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) 333 333 { 334 334 /* flush all pending status updates */ 335 - flush_scheduled_work(); 335 + flush_work_sync(&bat_work); 336 336 return 0; 337 337 } 338 338 ··· 422 422 err_psy_reg_main: 423 423 424 424 /* see comment in tosa_bat_remove */ 425 - flush_scheduled_work(); 425 + cancel_work_sync(&bat_work); 426 426 427 427 i--; 428 428 err_gpio: ··· 445 445 power_supply_unregister(&tosa_bat_main.psy); 446 446 447 447 /* 448 - * now flush all pending work. 449 - * we won't get any more schedules, since all 450 - * sources (isr and external_power_changed) 451 - * are unregistered now. 448 + * Now cancel the bat_work. We won't get any more schedules, 449 + * since all sources (isr and external_power_changed) are 450 + * unregistered now. 452 451 */ 453 - flush_scheduled_work(); 452 + cancel_work_sync(&bat_work); 454 453 455 454 for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) 456 455 gpio_free(gpios[i].gpio);
+2 -2
drivers/power/wm97xx_battery.c
··· 147 147 #ifdef CONFIG_PM 148 148 static int wm97xx_bat_suspend(struct device *dev) 149 149 { 150 - flush_scheduled_work(); 150 + flush_work_sync(&bat_work); 151 151 return 0; 152 152 } 153 153 ··· 273 273 free_irq(gpio_to_irq(pdata->charge_gpio), dev); 274 274 gpio_free(pdata->charge_gpio); 275 275 } 276 - flush_scheduled_work(); 276 + cancel_work_sync(&bat_work); 277 277 power_supply_unregister(&bat_ps); 278 278 kfree(prop); 279 279 return 0;
+4 -2
drivers/power/z2_battery.c
··· 254 254 struct z2_charger *charger = i2c_get_clientdata(client); 255 255 struct z2_battery_info *info = charger->info; 256 256 257 - flush_scheduled_work(); 257 + cancel_work_sync(&charger->bat_work); 258 258 power_supply_unregister(&charger->batt_ps); 259 259 260 260 kfree(charger->batt_ps.properties); ··· 271 271 #ifdef CONFIG_PM 272 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 277 return 0; 276 278 } 277 279
+41
include/linux/power/gpio-charger.h
··· 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
+30
include/linux/power/max17042_battery.h
··· 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_ */
+1
include/linux/s3c_adc_battery.h
··· 14 14 void (*disable_charger)(void); 15 15 16 16 int gpio_charge_finished; 17 + int gpio_inverted; 17 18 18 19 const struct s3c_adc_bat_thresh *lut_noac; 19 20 unsigned int lut_noac_cnt;