diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 13:14:23 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 13:14:23 -0400 |
| commit | 45352bbf48e95078b4acd20774f49e72676e1e0f (patch) | |
| tree | 7c7121dae3f4ecebb1c08cea5f3b3d1c6c531756 | |
| parent | da62aa69c181e3bd465a5c868ece166921a81e14 (diff) | |
| parent | 57894517139b283a3cf27e36b29b4b4d7c45b303 (diff) | |
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6:
power_supply: Makefile cleanup
bq27x00_battery: Add missing kfree(di->bus) in bq27x00_battery_remove()
power_supply: Introduce maximum current property
power_supply: Add types for USB chargers
ds2782_battery: Fix units
power_supply: Add driver for TWL4030/TPS65950 BCI charger
bq20z75: Add support for more power supply properties
wm831x_power: Add missing kfree(wm831x_power) in wm831x_power_remove()
jz4740-battery: Add missing kfree(jz_battery) in jz_battery_remove()
ds2760_battery: Add missing kfree(di) in ds2760_battery_remove()
olpc_battery: Fix endian neutral breakage for s16 values
ds2760_battery: Fix W1 and W1_SLAVE_DS2760 dependency
pcf50633-charger: Add missing sysfs_remove_group()
power_supply: Add driver for TI BQ20Z75 gas gauge IC
wm831x_power: Remove duplicate chg mask
omap: rx51: Add support for USB chargers
power_supply: Add isp1704 charger detection driver
| -rw-r--r-- | arch/arm/mach-omap2/board-rx51-peripherals.c | 5 | ||||
| -rw-r--r-- | drivers/power/Kconfig | 23 | ||||
| -rw-r--r-- | drivers/power/Makefile | 19 | ||||
| -rw-r--r-- | drivers/power/bq20z75.c | 493 | ||||
| -rw-r--r-- | drivers/power/bq27x00_battery.c | 1 | ||||
| -rw-r--r-- | drivers/power/ds2760_battery.c | 1 | ||||
| -rw-r--r-- | drivers/power/ds2782_battery.c | 12 | ||||
| -rw-r--r-- | drivers/power/isp1704_charger.c | 369 | ||||
| -rw-r--r-- | drivers/power/jz4740-battery.c | 1 | ||||
| -rw-r--r-- | drivers/power/olpc_battery.c | 8 | ||||
| -rw-r--r-- | drivers/power/pcf50633-charger.c | 1 | ||||
| -rw-r--r-- | drivers/power/power_supply_sysfs.c | 4 | ||||
| -rw-r--r-- | drivers/power/twl4030_charger.c | 565 | ||||
| -rw-r--r-- | drivers/power/wm831x_power.c | 2 | ||||
| -rw-r--r-- | include/linux/power_supply.h | 6 |
15 files changed, 1483 insertions, 27 deletions
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 41285297eafc..3fec4d62a91a 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c | |||
| @@ -107,6 +107,10 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = { | |||
| 107 | }, | 107 | }, |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | static struct platform_device rx51_charger_device = { | ||
| 111 | .name = "isp1704_charger", | ||
| 112 | }; | ||
| 113 | |||
| 110 | #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) | 114 | #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) |
| 111 | 115 | ||
| 112 | #define RX51_GPIO_CAMERA_LENS_COVER 110 | 116 | #define RX51_GPIO_CAMERA_LENS_COVER 110 |
| @@ -919,5 +923,6 @@ void __init rx51_peripherals_init(void) | |||
| 919 | spi_register_board_info(rx51_peripherals_spi_board_info, | 923 | spi_register_board_info(rx51_peripherals_spi_board_info, |
| 920 | ARRAY_SIZE(rx51_peripherals_spi_board_info)); | 924 | ARRAY_SIZE(rx51_peripherals_spi_board_info)); |
| 921 | omap2_hsmmc_init(mmc); | 925 | omap2_hsmmc_init(mmc); |
| 926 | platform_device_register(&rx51_charger_device); | ||
| 922 | } | 927 | } |
| 923 | 928 | ||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 07343568a12e..60d83d983a36 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
| @@ -64,8 +64,7 @@ config TEST_POWER | |||
| 64 | 64 | ||
| 65 | config BATTERY_DS2760 | 65 | config BATTERY_DS2760 |
| 66 | tristate "DS2760 battery driver (HP iPAQ & others)" | 66 | tristate "DS2760 battery driver (HP iPAQ & others)" |
| 67 | select W1 | 67 | depends on W1 && W1_SLAVE_DS2760 |
| 68 | select W1_SLAVE_DS2760 | ||
| 69 | help | 68 | help |
| 70 | Say Y here to enable support for batteries with ds2760 chip. | 69 | Say Y here to enable support for batteries with ds2760 chip. |
| 71 | 70 | ||
| @@ -109,6 +108,13 @@ config BATTERY_WM97XX | |||
| 109 | help | 108 | help |
| 110 | Say Y to enable support for battery measured by WM97xx aux port. | 109 | Say Y to enable support for battery measured by WM97xx aux port. |
| 111 | 110 | ||
| 111 | config BATTERY_BQ20Z75 | ||
| 112 | tristate "TI BQ20z75 gas gauge" | ||
| 113 | depends on I2C | ||
| 114 | help | ||
| 115 | Say Y to include support for TI BQ20z75 SBS-compliant | ||
| 116 | gas gauge and protection IC. | ||
| 117 | |||
| 112 | config BATTERY_BQ27x00 | 118 | config BATTERY_BQ27x00 |
| 113 | tristate "BQ27x00 battery driver" | 119 | tristate "BQ27x00 battery driver" |
| 114 | depends on I2C | 120 | depends on I2C |
| @@ -166,4 +172,17 @@ config BATTERY_INTEL_MID | |||
| 166 | Say Y here to enable the battery driver on Intel MID | 172 | Say Y here to enable the battery driver on Intel MID |
| 167 | platforms. | 173 | platforms. |
| 168 | 174 | ||
| 175 | config CHARGER_ISP1704 | ||
| 176 | tristate "ISP1704 USB Charger Detection" | ||
| 177 | depends on USB_OTG_UTILS | ||
| 178 | help | ||
| 179 | Say Y to enable support for USB Charger Detection with | ||
| 180 | ISP1707/ISP1704 USB transceivers. | ||
| 181 | |||
| 182 | config CHARGER_TWL4030 | ||
| 183 | tristate "OMAP TWL4030 BCI charger driver" | ||
| 184 | depends on TWL4030_CORE | ||
| 185 | help | ||
| 186 | Say Y here to enable support for TWL4030 Battery Charge Interface. | ||
| 187 | |||
| 169 | endif # POWER_SUPPLY | 188 | endif # POWER_SUPPLY |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 10143aaf4ee3..c75772eb157c 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
| @@ -1,16 +1,8 @@ | |||
| 1 | power_supply-objs := power_supply_core.o | 1 | ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG |
| 2 | 2 | ||
| 3 | ifeq ($(CONFIG_SYSFS),y) | 3 | power_supply-y := power_supply_core.o |
| 4 | power_supply-objs += power_supply_sysfs.o | 4 | power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o |
| 5 | endif | 5 | power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o |
| 6 | |||
| 7 | ifeq ($(CONFIG_LEDS_TRIGGERS),y) | ||
| 8 | power_supply-objs += power_supply_leds.o | ||
| 9 | endif | ||
| 10 | |||
| 11 | ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y) | ||
| 12 | EXTRA_CFLAGS += -DDEBUG | ||
| 13 | endif | ||
| 14 | 6 | ||
| 15 | obj-$(CONFIG_POWER_SUPPLY) += power_supply.o | 7 | obj-$(CONFIG_POWER_SUPPLY) += power_supply.o |
| 16 | 8 | ||
| @@ -29,6 +21,7 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | |||
| 29 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o | 21 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o |
| 30 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o | 22 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o |
| 31 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o | 23 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o |
| 24 | obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o | ||
| 32 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o | 25 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o |
| 33 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o | 26 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o |
| 34 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o | 27 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o |
| @@ -37,3 +30,5 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o | |||
| 37 | obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o | 30 | obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o |
| 38 | obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o | 31 | obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o |
| 39 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o | 32 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o |
| 33 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o | ||
| 34 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o | ||
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c new file mode 100644 index 000000000000..492da27e1a47 --- /dev/null +++ b/drivers/power/bq20z75.c | |||
| @@ -0,0 +1,493 @@ | |||
| 1 | /* | ||
| 2 | * Gas Gauge driver for TI's BQ20Z75 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along | ||
| 17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/err.h> | ||
| 25 | #include <linux/power_supply.h> | ||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | |||
| 29 | enum { | ||
| 30 | REG_MANUFACTURER_DATA, | ||
| 31 | REG_TEMPERATURE, | ||
| 32 | REG_VOLTAGE, | ||
| 33 | REG_CURRENT, | ||
| 34 | REG_CAPACITY, | ||
| 35 | REG_TIME_TO_EMPTY, | ||
| 36 | REG_TIME_TO_FULL, | ||
| 37 | REG_STATUS, | ||
| 38 | REG_CYCLE_COUNT, | ||
| 39 | REG_SERIAL_NUMBER, | ||
| 40 | REG_REMAINING_CAPACITY, | ||
| 41 | REG_FULL_CHARGE_CAPACITY, | ||
| 42 | REG_DESIGN_CAPACITY, | ||
| 43 | REG_DESIGN_VOLTAGE, | ||
| 44 | }; | ||
| 45 | |||
| 46 | /* manufacturer access defines */ | ||
| 47 | #define MANUFACTURER_ACCESS_STATUS 0x0006 | ||
| 48 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 | ||
| 49 | |||
| 50 | /* battery status value bits */ | ||
| 51 | #define BATTERY_DISCHARGING 0x40 | ||
| 52 | #define BATTERY_FULL_CHARGED 0x20 | ||
| 53 | #define BATTERY_FULL_DISCHARGED 0x10 | ||
| 54 | |||
| 55 | #define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \ | ||
| 56 | .psp = _psp, \ | ||
| 57 | .addr = _addr, \ | ||
| 58 | .min_value = _min_value, \ | ||
| 59 | .max_value = _max_value, \ | ||
| 60 | } | ||
| 61 | |||
| 62 | static const struct bq20z75_device_data { | ||
| 63 | enum power_supply_property psp; | ||
| 64 | u8 addr; | ||
| 65 | int min_value; | ||
| 66 | int max_value; | ||
| 67 | } bq20z75_data[] = { | ||
| 68 | [REG_MANUFACTURER_DATA] = | ||
| 69 | BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535), | ||
| 70 | [REG_TEMPERATURE] = | ||
| 71 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535), | ||
| 72 | [REG_VOLTAGE] = | ||
| 73 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000), | ||
| 74 | [REG_CURRENT] = | ||
| 75 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, | ||
| 76 | 32767), | ||
| 77 | [REG_CAPACITY] = | ||
| 78 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), | ||
| 79 | [REG_REMAINING_CAPACITY] = | ||
| 80 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), | ||
| 81 | [REG_FULL_CHARGE_CAPACITY] = | ||
| 82 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), | ||
| 83 | [REG_TIME_TO_EMPTY] = | ||
| 84 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, | ||
| 85 | 65535), | ||
| 86 | [REG_TIME_TO_FULL] = | ||
| 87 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, | ||
| 88 | 65535), | ||
| 89 | [REG_STATUS] = | ||
| 90 | BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535), | ||
| 91 | [REG_CYCLE_COUNT] = | ||
| 92 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), | ||
| 93 | [REG_DESIGN_CAPACITY] = | ||
| 94 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, | ||
| 95 | 65535), | ||
| 96 | [REG_DESIGN_VOLTAGE] = | ||
| 97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, | ||
| 98 | 65535), | ||
| 99 | [REG_SERIAL_NUMBER] = | ||
| 100 | BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), | ||
| 101 | }; | ||
| 102 | |||
| 103 | static enum power_supply_property bq20z75_properties[] = { | ||
| 104 | POWER_SUPPLY_PROP_STATUS, | ||
| 105 | POWER_SUPPLY_PROP_HEALTH, | ||
| 106 | POWER_SUPPLY_PROP_PRESENT, | ||
| 107 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
| 108 | POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
| 109 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 110 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
| 111 | POWER_SUPPLY_PROP_CAPACITY, | ||
| 112 | POWER_SUPPLY_PROP_TEMP, | ||
| 113 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | ||
| 114 | POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, | ||
| 115 | POWER_SUPPLY_PROP_SERIAL_NUMBER, | ||
| 116 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
| 117 | POWER_SUPPLY_PROP_ENERGY_NOW, | ||
| 118 | POWER_SUPPLY_PROP_ENERGY_FULL, | ||
| 119 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | ||
| 120 | }; | ||
| 121 | |||
| 122 | struct bq20z75_info { | ||
| 123 | struct i2c_client *client; | ||
| 124 | struct power_supply power_supply; | ||
| 125 | }; | ||
| 126 | |||
| 127 | static int bq20z75_read_word_data(struct i2c_client *client, u8 address) | ||
| 128 | { | ||
| 129 | s32 ret; | ||
| 130 | |||
| 131 | ret = i2c_smbus_read_word_data(client, address); | ||
| 132 | if (ret < 0) { | ||
| 133 | dev_err(&client->dev, | ||
| 134 | "%s: i2c read at address 0x%x failed\n", | ||
| 135 | __func__, address); | ||
| 136 | return ret; | ||
| 137 | } | ||
| 138 | return le16_to_cpu(ret); | ||
| 139 | } | ||
| 140 | |||
| 141 | static int bq20z75_write_word_data(struct i2c_client *client, u8 address, | ||
| 142 | u16 value) | ||
| 143 | { | ||
| 144 | s32 ret; | ||
| 145 | |||
| 146 | ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value)); | ||
| 147 | if (ret < 0) { | ||
| 148 | dev_err(&client->dev, | ||
| 149 | "%s: i2c write to address 0x%x failed\n", | ||
| 150 | __func__, address); | ||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int bq20z75_get_battery_presence_and_health( | ||
| 157 | struct i2c_client *client, enum power_supply_property psp, | ||
| 158 | union power_supply_propval *val) | ||
| 159 | { | ||
| 160 | s32 ret; | ||
| 161 | |||
| 162 | /* Write to ManufacturerAccess with | ||
| 163 | * ManufacturerAccess command and then | ||
| 164 | * read the status */ | ||
| 165 | ret = bq20z75_write_word_data(client, | ||
| 166 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | ||
| 167 | MANUFACTURER_ACCESS_STATUS); | ||
| 168 | if (ret < 0) | ||
| 169 | return ret; | ||
| 170 | |||
| 171 | |||
| 172 | ret = bq20z75_read_word_data(client, | ||
| 173 | bq20z75_data[REG_MANUFACTURER_DATA].addr); | ||
| 174 | if (ret < 0) | ||
| 175 | return ret; | ||
| 176 | |||
| 177 | if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || | ||
| 178 | ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { | ||
| 179 | val->intval = 0; | ||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | /* Mask the upper nibble of 2nd byte and | ||
| 184 | * lower byte of response then | ||
| 185 | * shift the result by 8 to get status*/ | ||
| 186 | ret &= 0x0F00; | ||
| 187 | ret >>= 8; | ||
| 188 | if (psp == POWER_SUPPLY_PROP_PRESENT) { | ||
| 189 | if (ret == 0x0F) | ||
| 190 | /* battery removed */ | ||
| 191 | val->intval = 0; | ||
| 192 | else | ||
| 193 | val->intval = 1; | ||
| 194 | } else if (psp == POWER_SUPPLY_PROP_HEALTH) { | ||
| 195 | if (ret == 0x09) | ||
| 196 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
| 197 | else if (ret == 0x0B) | ||
| 198 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | ||
| 199 | else if (ret == 0x0C) | ||
| 200 | val->intval = POWER_SUPPLY_HEALTH_DEAD; | ||
| 201 | else | ||
| 202 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
| 203 | } | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int bq20z75_get_battery_property(struct i2c_client *client, | ||
| 209 | int reg_offset, enum power_supply_property psp, | ||
| 210 | union power_supply_propval *val) | ||
| 211 | { | ||
| 212 | s32 ret; | ||
| 213 | |||
| 214 | ret = bq20z75_read_word_data(client, | ||
| 215 | bq20z75_data[reg_offset].addr); | ||
| 216 | if (ret < 0) | ||
| 217 | return ret; | ||
| 218 | |||
| 219 | /* returned values are 16 bit */ | ||
| 220 | if (bq20z75_data[reg_offset].min_value < 0) | ||
| 221 | ret = (s16)ret; | ||
| 222 | |||
| 223 | if (ret >= bq20z75_data[reg_offset].min_value && | ||
| 224 | ret <= bq20z75_data[reg_offset].max_value) { | ||
| 225 | val->intval = ret; | ||
| 226 | if (psp == POWER_SUPPLY_PROP_STATUS) { | ||
| 227 | if (ret & BATTERY_FULL_CHARGED) | ||
| 228 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
| 229 | else if (ret & BATTERY_FULL_DISCHARGED) | ||
| 230 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 231 | else if (ret & BATTERY_DISCHARGING) | ||
| 232 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
| 233 | else | ||
| 234 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 235 | } | ||
| 236 | } else { | ||
| 237 | if (psp == POWER_SUPPLY_PROP_STATUS) | ||
| 238 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
| 239 | else | ||
| 240 | val->intval = 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static void bq20z75_unit_adjustment(struct i2c_client *client, | ||
| 247 | enum power_supply_property psp, union power_supply_propval *val) | ||
| 248 | { | ||
| 249 | #define BASE_UNIT_CONVERSION 1000 | ||
| 250 | #define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION) | ||
| 251 | #define TIME_UNIT_CONVERSION 600 | ||
| 252 | #define TEMP_KELVIN_TO_CELCIUS 2731 | ||
| 253 | switch (psp) { | ||
| 254 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
| 255 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
| 256 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
| 257 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; | ||
| 258 | break; | ||
| 259 | |||
| 260 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 261 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
| 262 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
| 263 | val->intval *= BASE_UNIT_CONVERSION; | ||
| 264 | break; | ||
| 265 | |||
| 266 | case POWER_SUPPLY_PROP_TEMP: | ||
| 267 | /* bq20z75 provides battery tempreture in 0.1°K | ||
| 268 | * so convert it to 0.1°C */ | ||
| 269 | val->intval -= TEMP_KELVIN_TO_CELCIUS; | ||
| 270 | val->intval *= 10; | ||
| 271 | break; | ||
| 272 | |||
| 273 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | ||
| 274 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | ||
| 275 | val->intval *= TIME_UNIT_CONVERSION; | ||
| 276 | break; | ||
| 277 | |||
| 278 | default: | ||
| 279 | dev_dbg(&client->dev, | ||
| 280 | "%s: no need for unit conversion %d\n", __func__, psp); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | static int bq20z75_get_battery_capacity(struct i2c_client *client, | ||
| 285 | int reg_offset, enum power_supply_property psp, | ||
| 286 | union power_supply_propval *val) | ||
| 287 | { | ||
| 288 | s32 ret; | ||
| 289 | |||
| 290 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); | ||
| 291 | if (ret < 0) | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | if (psp == POWER_SUPPLY_PROP_CAPACITY) { | ||
| 295 | /* bq20z75 spec says that this can be >100 % | ||
| 296 | * even if max value is 100 % */ | ||
| 297 | val->intval = min(ret, 100); | ||
| 298 | } else | ||
| 299 | val->intval = ret; | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static char bq20z75_serial[5]; | ||
| 305 | static int bq20z75_get_battery_serial_number(struct i2c_client *client, | ||
| 306 | union power_supply_propval *val) | ||
| 307 | { | ||
| 308 | int ret; | ||
| 309 | |||
| 310 | ret = bq20z75_read_word_data(client, | ||
| 311 | bq20z75_data[REG_SERIAL_NUMBER].addr); | ||
| 312 | if (ret < 0) | ||
| 313 | return ret; | ||
| 314 | |||
| 315 | ret = sprintf(bq20z75_serial, "%04x", ret); | ||
| 316 | val->strval = bq20z75_serial; | ||
| 317 | |||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | static int bq20z75_get_property(struct power_supply *psy, | ||
| 322 | enum power_supply_property psp, | ||
| 323 | union power_supply_propval *val) | ||
| 324 | { | ||
| 325 | int count; | ||
| 326 | int ret; | ||
| 327 | struct bq20z75_info *bq20z75_device = container_of(psy, | ||
| 328 | struct bq20z75_info, power_supply); | ||
| 329 | struct i2c_client *client = bq20z75_device->client; | ||
| 330 | |||
| 331 | switch (psp) { | ||
| 332 | case POWER_SUPPLY_PROP_PRESENT: | ||
| 333 | case POWER_SUPPLY_PROP_HEALTH: | ||
| 334 | ret = bq20z75_get_battery_presence_and_health(client, psp, val); | ||
| 335 | if (ret) | ||
| 336 | return ret; | ||
| 337 | break; | ||
| 338 | |||
| 339 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
| 340 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | ||
| 341 | break; | ||
| 342 | |||
| 343 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
| 344 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
| 345 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
| 346 | case POWER_SUPPLY_PROP_CAPACITY: | ||
| 347 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | ||
| 348 | if (psp == bq20z75_data[count].psp) | ||
| 349 | break; | ||
| 350 | } | ||
| 351 | |||
| 352 | ret = bq20z75_get_battery_capacity(client, count, psp, val); | ||
| 353 | if (ret) | ||
| 354 | return ret; | ||
| 355 | |||
| 356 | break; | ||
| 357 | |||
| 358 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: | ||
| 359 | ret = bq20z75_get_battery_serial_number(client, val); | ||
| 360 | if (ret) | ||
| 361 | return ret; | ||
| 362 | break; | ||
| 363 | |||
| 364 | case POWER_SUPPLY_PROP_STATUS: | ||
| 365 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | ||
| 366 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 367 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
| 368 | case POWER_SUPPLY_PROP_TEMP: | ||
| 369 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | ||
| 370 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | ||
| 371 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
| 372 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | ||
| 373 | if (psp == bq20z75_data[count].psp) | ||
| 374 | break; | ||
| 375 | } | ||
| 376 | |||
| 377 | ret = bq20z75_get_battery_property(client, count, psp, val); | ||
| 378 | if (ret) | ||
| 379 | return ret; | ||
| 380 | |||
| 381 | break; | ||
| 382 | |||
| 383 | default: | ||
| 384 | dev_err(&client->dev, | ||
| 385 | "%s: INVALID property\n", __func__); | ||
| 386 | return -EINVAL; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* Convert units to match requirements for power supply class */ | ||
| 390 | bq20z75_unit_adjustment(client, psp, val); | ||
| 391 | |||
| 392 | dev_dbg(&client->dev, | ||
| 393 | "%s: property = %d, value = %d\n", __func__, psp, val->intval); | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | static int bq20z75_probe(struct i2c_client *client, | ||
| 399 | const struct i2c_device_id *id) | ||
| 400 | { | ||
| 401 | struct bq20z75_info *bq20z75_device; | ||
| 402 | int rc; | ||
| 403 | |||
| 404 | bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); | ||
| 405 | if (!bq20z75_device) | ||
| 406 | return -ENOMEM; | ||
| 407 | |||
| 408 | bq20z75_device->client = client; | ||
| 409 | bq20z75_device->power_supply.name = "battery"; | ||
| 410 | bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; | ||
| 411 | bq20z75_device->power_supply.properties = bq20z75_properties; | ||
| 412 | bq20z75_device->power_supply.num_properties = | ||
| 413 | ARRAY_SIZE(bq20z75_properties); | ||
| 414 | bq20z75_device->power_supply.get_property = bq20z75_get_property; | ||
| 415 | |||
| 416 | i2c_set_clientdata(client, bq20z75_device); | ||
| 417 | |||
| 418 | rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); | ||
| 419 | if (rc) { | ||
| 420 | dev_err(&client->dev, | ||
| 421 | "%s: Failed to register power supply\n", __func__); | ||
| 422 | kfree(bq20z75_device); | ||
| 423 | return rc; | ||
| 424 | } | ||
| 425 | |||
| 426 | dev_info(&client->dev, | ||
| 427 | "%s: battery gas gauge device registered\n", client->name); | ||
| 428 | |||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int bq20z75_remove(struct i2c_client *client) | ||
| 433 | { | ||
| 434 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | ||
| 435 | |||
| 436 | power_supply_unregister(&bq20z75_device->power_supply); | ||
| 437 | kfree(bq20z75_device); | ||
| 438 | bq20z75_device = NULL; | ||
| 439 | |||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | #if defined CONFIG_PM | ||
| 444 | static int bq20z75_suspend(struct i2c_client *client, | ||
| 445 | pm_message_t state) | ||
| 446 | { | ||
| 447 | s32 ret; | ||
| 448 | |||
| 449 | /* write to manufacturer access with sleep command */ | ||
| 450 | ret = bq20z75_write_word_data(client, | ||
| 451 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | ||
| 452 | MANUFACTURER_ACCESS_SLEEP); | ||
| 453 | if (ret < 0) | ||
| 454 | return ret; | ||
| 455 | |||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | #else | ||
| 459 | #define bq20z75_suspend NULL | ||
| 460 | #endif | ||
| 461 | /* any smbus transaction will wake up bq20z75 */ | ||
| 462 | #define bq20z75_resume NULL | ||
| 463 | |||
| 464 | static const struct i2c_device_id bq20z75_id[] = { | ||
| 465 | { "bq20z75", 0 }, | ||
| 466 | {} | ||
| 467 | }; | ||
| 468 | |||
| 469 | static struct i2c_driver bq20z75_battery_driver = { | ||
| 470 | .probe = bq20z75_probe, | ||
| 471 | .remove = bq20z75_remove, | ||
| 472 | .suspend = bq20z75_suspend, | ||
| 473 | .resume = bq20z75_resume, | ||
| 474 | .id_table = bq20z75_id, | ||
| 475 | .driver = { | ||
| 476 | .name = "bq20z75-battery", | ||
| 477 | }, | ||
| 478 | }; | ||
| 479 | |||
| 480 | static int __init bq20z75_battery_init(void) | ||
| 481 | { | ||
| 482 | return i2c_add_driver(&bq20z75_battery_driver); | ||
| 483 | } | ||
| 484 | module_init(bq20z75_battery_init); | ||
| 485 | |||
| 486 | static void __exit bq20z75_battery_exit(void) | ||
| 487 | { | ||
| 488 | i2c_del_driver(&bq20z75_battery_driver); | ||
| 489 | } | ||
| 490 | module_exit(bq20z75_battery_exit); | ||
| 491 | |||
| 492 | MODULE_DESCRIPTION("BQ20z75 battery monitor driver"); | ||
| 493 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 3ec9c6a8896b..eff0273d4030 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
| @@ -418,6 +418,7 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
| 418 | 418 | ||
| 419 | power_supply_unregister(&di->bat); | 419 | power_supply_unregister(&di->bat); |
| 420 | 420 | ||
| 421 | kfree(di->bus); | ||
| 421 | kfree(di->bat.name); | 422 | kfree(di->bat.name); |
| 422 | 423 | ||
| 423 | mutex_lock(&battery_mutex); | 424 | mutex_lock(&battery_mutex); |
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index 4d3b27228a2e..b3c01c16a164 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c | |||
| @@ -586,6 +586,7 @@ static int ds2760_battery_remove(struct platform_device *pdev) | |||
| 586 | &di->set_charged_work); | 586 | &di->set_charged_work); |
| 587 | destroy_workqueue(di->monitor_wqueue); | 587 | destroy_workqueue(di->monitor_wqueue); |
| 588 | power_supply_unregister(&di->bat); | 588 | power_supply_unregister(&di->bat); |
| 589 | kfree(di); | ||
| 589 | 590 | ||
| 590 | return 0; | 591 | return 0; |
| 591 | } | 592 | } |
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index 84d3c43cf2bc..6957e8af6449 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c | |||
| @@ -44,8 +44,8 @@ struct ds278x_info; | |||
| 44 | 44 | ||
| 45 | struct ds278x_battery_ops { | 45 | struct ds278x_battery_ops { |
| 46 | int (*get_battery_current)(struct ds278x_info *info, int *current_uA); | 46 | int (*get_battery_current)(struct ds278x_info *info, int *current_uA); |
| 47 | int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uA); | 47 | int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV); |
| 48 | int (*get_battery_capacity)(struct ds278x_info *info, int *capacity_uA); | 48 | int (*get_battery_capacity)(struct ds278x_info *info, int *capacity); |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery) | 51 | #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery) |
| @@ -137,7 +137,7 @@ static int ds2782_get_current(struct ds278x_info *info, int *current_uA) | |||
| 137 | return 0; | 137 | return 0; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA) | 140 | static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV) |
| 141 | { | 141 | { |
| 142 | s16 raw; | 142 | s16 raw; |
| 143 | int err; | 143 | int err; |
| @@ -149,7 +149,7 @@ static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA) | |||
| 149 | err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); | 149 | err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); |
| 150 | if (err) | 150 | if (err) |
| 151 | return err; | 151 | return err; |
| 152 | *voltage_uA = (raw / 32) * 4800; | 152 | *voltage_uV = (raw / 32) * 4800; |
| 153 | return 0; | 153 | return 0; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| @@ -177,7 +177,7 @@ static int ds2786_get_current(struct ds278x_info *info, int *current_uA) | |||
| 177 | return 0; | 177 | return 0; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA) | 180 | static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV) |
| 181 | { | 181 | { |
| 182 | s16 raw; | 182 | s16 raw; |
| 183 | int err; | 183 | int err; |
| @@ -189,7 +189,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA) | |||
| 189 | err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); | 189 | err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); |
| 190 | if (err) | 190 | if (err) |
| 191 | return err; | 191 | return err; |
| 192 | *voltage_uA = (raw / 8) * 1220; | 192 | *voltage_uV = (raw / 8) * 1220; |
| 193 | return 0; | 193 | return 0; |
| 194 | } | 194 | } |
| 195 | 195 | ||
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c new file mode 100644 index 000000000000..72512185f3e2 --- /dev/null +++ b/drivers/power/isp1704_charger.c | |||
| @@ -0,0 +1,369 @@ | |||
| 1 | /* | ||
| 2 | * ISP1704 USB Charger Detection driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Nokia Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/err.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | #include <linux/sysfs.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/power_supply.h> | ||
| 30 | #include <linux/delay.h> | ||
| 31 | |||
| 32 | #include <linux/usb/otg.h> | ||
| 33 | #include <linux/usb/ulpi.h> | ||
| 34 | #include <linux/usb/ch9.h> | ||
| 35 | #include <linux/usb/gadget.h> | ||
| 36 | |||
| 37 | /* Vendor specific Power Control register */ | ||
| 38 | #define ISP1704_PWR_CTRL 0x3d | ||
| 39 | #define ISP1704_PWR_CTRL_SWCTRL (1 << 0) | ||
| 40 | #define ISP1704_PWR_CTRL_DET_COMP (1 << 1) | ||
| 41 | #define ISP1704_PWR_CTRL_BVALID_RISE (1 << 2) | ||
| 42 | #define ISP1704_PWR_CTRL_BVALID_FALL (1 << 3) | ||
| 43 | #define ISP1704_PWR_CTRL_DP_WKPU_EN (1 << 4) | ||
| 44 | #define ISP1704_PWR_CTRL_VDAT_DET (1 << 5) | ||
| 45 | #define ISP1704_PWR_CTRL_DPVSRC_EN (1 << 6) | ||
| 46 | #define ISP1704_PWR_CTRL_HWDETECT (1 << 7) | ||
| 47 | |||
| 48 | #define NXP_VENDOR_ID 0x04cc | ||
| 49 | |||
| 50 | static u16 isp170x_id[] = { | ||
| 51 | 0x1704, | ||
| 52 | 0x1707, | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct isp1704_charger { | ||
| 56 | struct device *dev; | ||
| 57 | struct power_supply psy; | ||
| 58 | struct otg_transceiver *otg; | ||
| 59 | struct notifier_block nb; | ||
| 60 | struct work_struct work; | ||
| 61 | |||
| 62 | char model[7]; | ||
| 63 | unsigned present:1; | ||
| 64 | }; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * 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. | ||
| 69 | */ | ||
| 70 | static inline int isp1704_charger_verify(struct isp1704_charger *isp) | ||
| 71 | { | ||
| 72 | int ret = 0; | ||
| 73 | u8 r; | ||
| 74 | |||
| 75 | /* Reset the transceiver */ | ||
| 76 | r = otg_io_read(isp->otg, ULPI_FUNC_CTRL); | ||
| 77 | r |= ULPI_FUNC_CTRL_RESET; | ||
| 78 | otg_io_write(isp->otg, ULPI_FUNC_CTRL, r); | ||
| 79 | usleep_range(1000, 2000); | ||
| 80 | |||
| 81 | /* Set normal mode */ | ||
| 82 | r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK); | ||
| 83 | otg_io_write(isp->otg, ULPI_FUNC_CTRL, r); | ||
| 84 | |||
| 85 | /* Clear the DP and DM pull-down bits */ | ||
| 86 | r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN; | ||
| 87 | otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r); | ||
| 88 | |||
| 89 | /* Enable strong pull-up on DP (1.5K) and reset */ | ||
| 90 | r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET; | ||
| 91 | otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r); | ||
| 92 | usleep_range(1000, 2000); | ||
| 93 | |||
| 94 | /* Read the line state */ | ||
| 95 | if (!otg_io_read(isp->otg, ULPI_DEBUG)) { | ||
| 96 | /* Disable strong pull-up on DP (1.5K) */ | ||
| 97 | otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL), | ||
| 98 | ULPI_FUNC_CTRL_TERMSELECT); | ||
| 99 | return 1; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Is it a charger or PS/2 connection */ | ||
| 103 | |||
| 104 | /* Enable weak pull-up resistor on DP */ | ||
| 105 | otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), | ||
| 106 | ISP1704_PWR_CTRL_DP_WKPU_EN); | ||
| 107 | |||
| 108 | /* Disable strong pull-up on DP (1.5K) */ | ||
| 109 | otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL), | ||
| 110 | ULPI_FUNC_CTRL_TERMSELECT); | ||
| 111 | |||
| 112 | /* Enable weak pull-down resistor on DM */ | ||
| 113 | otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL), | ||
| 114 | ULPI_OTG_CTRL_DM_PULLDOWN); | ||
| 115 | |||
| 116 | /* It's a charger if the line states are clear */ | ||
| 117 | if (!(otg_io_read(isp->otg, ULPI_DEBUG))) | ||
| 118 | ret = 1; | ||
| 119 | |||
| 120 | /* Disable weak pull-up resistor on DP */ | ||
| 121 | otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL), | ||
| 122 | ISP1704_PWR_CTRL_DP_WKPU_EN); | ||
| 123 | |||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | |||
| 127 | static inline int isp1704_charger_detect(struct isp1704_charger *isp) | ||
| 128 | { | ||
| 129 | unsigned long timeout; | ||
| 130 | u8 r; | ||
| 131 | int ret = 0; | ||
| 132 | |||
| 133 | /* set SW control bit in PWR_CTRL register */ | ||
| 134 | otg_io_write(isp->otg, ISP1704_PWR_CTRL, | ||
| 135 | ISP1704_PWR_CTRL_SWCTRL); | ||
| 136 | |||
| 137 | /* enable manual charger detection */ | ||
| 138 | r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN); | ||
| 139 | otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r); | ||
| 140 | usleep_range(1000, 2000); | ||
| 141 | |||
| 142 | timeout = jiffies + msecs_to_jiffies(300); | ||
| 143 | do { | ||
| 144 | /* Check if there is a charger */ | ||
| 145 | if (otg_io_read(isp->otg, ISP1704_PWR_CTRL) | ||
| 146 | & ISP1704_PWR_CTRL_VDAT_DET) { | ||
| 147 | ret = isp1704_charger_verify(isp); | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | } while (!time_after(jiffies, timeout)); | ||
| 151 | |||
| 152 | return ret; | ||
| 153 | } | ||
| 154 | |||
| 155 | static void isp1704_charger_work(struct work_struct *data) | ||
| 156 | { | ||
| 157 | int detect; | ||
| 158 | struct isp1704_charger *isp = | ||
| 159 | container_of(data, struct isp1704_charger, work); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * FIXME Only supporting dedicated chargers even though isp1704 can | ||
| 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 | |||
| 169 | /* disable data pullups */ | ||
| 170 | if (isp->otg->gadget) | ||
| 171 | usb_gadget_disconnect(isp->otg->gadget); | ||
| 172 | |||
| 173 | /* detect charger */ | ||
| 174 | detect = isp1704_charger_detect(isp); | ||
| 175 | if (detect) { | ||
| 176 | isp->present = detect; | ||
| 177 | power_supply_changed(&isp->psy); | ||
| 178 | } | ||
| 179 | |||
| 180 | /* enable data pullups */ | ||
| 181 | if (isp->otg->gadget) | ||
| 182 | usb_gadget_connect(isp->otg->gadget); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int isp1704_notifier_call(struct notifier_block *nb, | ||
| 186 | unsigned long event, void *unused) | ||
| 187 | { | ||
| 188 | struct isp1704_charger *isp = | ||
| 189 | container_of(nb, struct isp1704_charger, nb); | ||
| 190 | |||
| 191 | switch (event) { | ||
| 192 | case USB_EVENT_VBUS: | ||
| 193 | schedule_work(&isp->work); | ||
| 194 | break; | ||
| 195 | case USB_EVENT_NONE: | ||
| 196 | if (isp->present) { | ||
| 197 | isp->present = 0; | ||
| 198 | power_supply_changed(&isp->psy); | ||
| 199 | } | ||
| 200 | break; | ||
| 201 | default: | ||
| 202 | return NOTIFY_DONE; | ||
| 203 | } | ||
| 204 | |||
| 205 | return NOTIFY_OK; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int isp1704_charger_get_property(struct power_supply *psy, | ||
| 209 | enum power_supply_property psp, | ||
| 210 | union power_supply_propval *val) | ||
| 211 | { | ||
| 212 | struct isp1704_charger *isp = | ||
| 213 | container_of(psy, struct isp1704_charger, psy); | ||
| 214 | |||
| 215 | switch (psp) { | ||
| 216 | case POWER_SUPPLY_PROP_PRESENT: | ||
| 217 | val->intval = isp->present; | ||
| 218 | break; | ||
| 219 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
| 220 | val->strval = isp->model; | ||
| 221 | break; | ||
| 222 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
| 223 | val->strval = "NXP"; | ||
| 224 | break; | ||
| 225 | default: | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static enum power_supply_property power_props[] = { | ||
| 232 | POWER_SUPPLY_PROP_PRESENT, | ||
| 233 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
| 234 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static inline int isp1704_test_ulpi(struct isp1704_charger *isp) | ||
| 238 | { | ||
| 239 | int vendor; | ||
| 240 | int product; | ||
| 241 | int i; | ||
| 242 | int ret = -ENODEV; | ||
| 243 | |||
| 244 | /* Test ULPI interface */ | ||
| 245 | ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa); | ||
| 246 | if (ret < 0) | ||
| 247 | return ret; | ||
| 248 | |||
| 249 | ret = otg_io_read(isp->otg, ULPI_SCRATCH); | ||
| 250 | if (ret < 0) | ||
| 251 | return ret; | ||
| 252 | |||
| 253 | if (ret != 0xaa) | ||
| 254 | return -ENODEV; | ||
| 255 | |||
| 256 | /* Verify the product and vendor id matches */ | ||
| 257 | vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW); | ||
| 258 | vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8; | ||
| 259 | if (vendor != NXP_VENDOR_ID) | ||
| 260 | return -ENODEV; | ||
| 261 | |||
| 262 | product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW); | ||
| 263 | product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8; | ||
| 264 | |||
| 265 | for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) { | ||
| 266 | if (product == isp170x_id[i]) { | ||
| 267 | sprintf(isp->model, "isp%x", product); | ||
| 268 | return product; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | dev_err(isp->dev, "product id %x not matching known ids", product); | ||
| 273 | |||
| 274 | return -ENODEV; | ||
| 275 | } | ||
| 276 | |||
| 277 | static int __devinit isp1704_charger_probe(struct platform_device *pdev) | ||
| 278 | { | ||
| 279 | struct isp1704_charger *isp; | ||
| 280 | int ret = -ENODEV; | ||
| 281 | |||
| 282 | isp = kzalloc(sizeof *isp, GFP_KERNEL); | ||
| 283 | if (!isp) | ||
| 284 | return -ENOMEM; | ||
| 285 | |||
| 286 | isp->otg = otg_get_transceiver(); | ||
| 287 | if (!isp->otg) | ||
| 288 | goto fail0; | ||
| 289 | |||
| 290 | ret = isp1704_test_ulpi(isp); | ||
| 291 | if (ret < 0) | ||
| 292 | goto fail1; | ||
| 293 | |||
| 294 | isp->dev = &pdev->dev; | ||
| 295 | platform_set_drvdata(pdev, isp); | ||
| 296 | |||
| 297 | isp->psy.name = "isp1704"; | ||
| 298 | isp->psy.type = POWER_SUPPLY_TYPE_USB; | ||
| 299 | isp->psy.properties = power_props; | ||
| 300 | isp->psy.num_properties = ARRAY_SIZE(power_props); | ||
| 301 | isp->psy.get_property = isp1704_charger_get_property; | ||
| 302 | |||
| 303 | ret = power_supply_register(isp->dev, &isp->psy); | ||
| 304 | if (ret) | ||
| 305 | goto fail1; | ||
| 306 | |||
| 307 | /* | ||
| 308 | * REVISIT: using work in order to allow the otg notifications to be | ||
| 309 | * made atomically in the future. | ||
| 310 | */ | ||
| 311 | INIT_WORK(&isp->work, isp1704_charger_work); | ||
| 312 | |||
| 313 | isp->nb.notifier_call = isp1704_notifier_call; | ||
| 314 | |||
| 315 | ret = otg_register_notifier(isp->otg, &isp->nb); | ||
| 316 | if (ret) | ||
| 317 | goto fail2; | ||
| 318 | |||
| 319 | dev_info(isp->dev, "registered with product id %s\n", isp->model); | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | fail2: | ||
| 323 | power_supply_unregister(&isp->psy); | ||
| 324 | fail1: | ||
| 325 | otg_put_transceiver(isp->otg); | ||
| 326 | fail0: | ||
| 327 | kfree(isp); | ||
| 328 | |||
| 329 | dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); | ||
| 330 | |||
| 331 | return ret; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int __devexit isp1704_charger_remove(struct platform_device *pdev) | ||
| 335 | { | ||
| 336 | struct isp1704_charger *isp = platform_get_drvdata(pdev); | ||
| 337 | |||
| 338 | otg_unregister_notifier(isp->otg, &isp->nb); | ||
| 339 | power_supply_unregister(&isp->psy); | ||
| 340 | otg_put_transceiver(isp->otg); | ||
| 341 | kfree(isp); | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | static struct platform_driver isp1704_charger_driver = { | ||
| 347 | .driver = { | ||
| 348 | .name = "isp1704_charger", | ||
| 349 | }, | ||
| 350 | .probe = isp1704_charger_probe, | ||
| 351 | .remove = __devexit_p(isp1704_charger_remove), | ||
| 352 | }; | ||
| 353 | |||
| 354 | static int __init isp1704_charger_init(void) | ||
| 355 | { | ||
| 356 | return platform_driver_register(&isp1704_charger_driver); | ||
| 357 | } | ||
| 358 | module_init(isp1704_charger_init); | ||
| 359 | |||
| 360 | static void __exit isp1704_charger_exit(void) | ||
| 361 | { | ||
| 362 | platform_driver_unregister(&isp1704_charger_driver); | ||
| 363 | } | ||
| 364 | module_exit(isp1704_charger_exit); | ||
| 365 | |||
| 366 | MODULE_ALIAS("platform:isp1704_charger"); | ||
| 367 | MODULE_AUTHOR("Nokia Corporation"); | ||
| 368 | MODULE_DESCRIPTION("ISP170x USB Charger driver"); | ||
| 369 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 20c4b952e9bd..a8108a73593e 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c | |||
| @@ -383,6 +383,7 @@ static int __devexit jz_battery_remove(struct platform_device *pdev) | |||
| 383 | 383 | ||
| 384 | iounmap(jz_battery->base); | 384 | iounmap(jz_battery->base); |
| 385 | release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem)); | 385 | release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem)); |
| 386 | kfree(jz_battery); | ||
| 386 | 387 | ||
| 387 | return 0; | 388 | return 0; |
| 388 | } | 389 | } |
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index aafc1c506eda..5bc1dcf7785e 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c | |||
| @@ -271,14 +271,14 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 271 | if (ret) | 271 | if (ret) |
| 272 | return ret; | 272 | return ret; |
| 273 | 273 | ||
| 274 | val->intval = (int)be16_to_cpu(ec_word) * 9760L / 32; | 274 | val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; |
| 275 | break; | 275 | break; |
| 276 | case POWER_SUPPLY_PROP_CURRENT_AVG: | 276 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
| 277 | ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); | 277 | ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); |
| 278 | if (ret) | 278 | if (ret) |
| 279 | return ret; | 279 | return ret; |
| 280 | 280 | ||
| 281 | val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120; | 281 | val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120; |
| 282 | break; | 282 | break; |
| 283 | case POWER_SUPPLY_PROP_CAPACITY: | 283 | case POWER_SUPPLY_PROP_CAPACITY: |
| 284 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); | 284 | ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); |
| @@ -299,7 +299,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 299 | if (ret) | 299 | if (ret) |
| 300 | return ret; | 300 | return ret; |
| 301 | 301 | ||
| 302 | val->intval = (int)be16_to_cpu(ec_word) * 100 / 256; | 302 | val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256; |
| 303 | break; | 303 | break; |
| 304 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: | 304 | case POWER_SUPPLY_PROP_TEMP_AMBIENT: |
| 305 | ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); | 305 | ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); |
| @@ -313,7 +313,7 @@ static int olpc_bat_get_property(struct power_supply *psy, | |||
| 313 | if (ret) | 313 | if (ret) |
| 314 | return ret; | 314 | return ret; |
| 315 | 315 | ||
| 316 | val->intval = (int)be16_to_cpu(ec_word) * 6250 / 15; | 316 | val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15; |
| 317 | break; | 317 | break; |
| 318 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: | 318 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
| 319 | ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); | 319 | ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); |
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 066f994e6fe5..4fa52e1781a2 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c | |||
| @@ -456,6 +456,7 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev) | |||
| 456 | for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) | 456 | for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) |
| 457 | pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]); | 457 | pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]); |
| 458 | 458 | ||
| 459 | sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group); | ||
| 459 | power_supply_unregister(&mbc->usb); | 460 | power_supply_unregister(&mbc->usb); |
| 460 | power_supply_unregister(&mbc->adapter); | 461 | power_supply_unregister(&mbc->adapter); |
| 461 | power_supply_unregister(&mbc->ac); | 462 | power_supply_unregister(&mbc->ac); |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 9d30eeb8c810..cd1f90754a3a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
| @@ -42,7 +42,8 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
| 42 | struct device_attribute *attr, | 42 | struct device_attribute *attr, |
| 43 | char *buf) { | 43 | char *buf) { |
| 44 | static char *type_text[] = { | 44 | static char *type_text[] = { |
| 45 | "Battery", "UPS", "Mains", "USB" | 45 | "Battery", "UPS", "Mains", "USB", |
| 46 | "USB_DCP", "USB_CDP", "USB_ACA" | ||
| 46 | }; | 47 | }; |
| 47 | static char *status_text[] = { | 48 | static char *status_text[] = { |
| 48 | "Unknown", "Charging", "Discharging", "Not charging", "Full" | 49 | "Unknown", "Charging", "Discharging", "Not charging", "Full" |
| @@ -138,6 +139,7 @@ static struct device_attribute power_supply_attrs[] = { | |||
| 138 | POWER_SUPPLY_ATTR(voltage_min_design), | 139 | POWER_SUPPLY_ATTR(voltage_min_design), |
| 139 | POWER_SUPPLY_ATTR(voltage_now), | 140 | POWER_SUPPLY_ATTR(voltage_now), |
| 140 | POWER_SUPPLY_ATTR(voltage_avg), | 141 | POWER_SUPPLY_ATTR(voltage_avg), |
| 142 | POWER_SUPPLY_ATTR(current_max), | ||
| 141 | POWER_SUPPLY_ATTR(current_now), | 143 | POWER_SUPPLY_ATTR(current_now), |
| 142 | POWER_SUPPLY_ATTR(current_avg), | 144 | POWER_SUPPLY_ATTR(current_avg), |
| 143 | POWER_SUPPLY_ATTR(power_now), | 145 | POWER_SUPPLY_ATTR(power_now), |
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c new file mode 100644 index 000000000000..ff1f42398a2e --- /dev/null +++ b/drivers/power/twl4030_charger.c | |||
| @@ -0,0 +1,565 @@ | |||
| 1 | /* | ||
| 2 | * TWL4030/TPS65950 BCI (Battery Charger Interface) driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Gražvydas Ignotas <notasas@gmail.com> | ||
| 5 | * | ||
| 6 | * based on twl4030_bci_battery.c by TI | ||
| 7 | * Copyright (C) 2008 Texas Instruments, Inc. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/i2c/twl.h> | ||
| 21 | #include <linux/power_supply.h> | ||
| 22 | #include <linux/notifier.h> | ||
| 23 | #include <linux/usb/otg.h> | ||
| 24 | |||
| 25 | #define TWL4030_BCIMSTATEC 0x02 | ||
| 26 | #define TWL4030_BCIICHG 0x08 | ||
| 27 | #define TWL4030_BCIVAC 0x0a | ||
| 28 | #define TWL4030_BCIVBUS 0x0c | ||
| 29 | #define TWL4030_BCIMFSTS4 0x10 | ||
| 30 | #define TWL4030_BCICTL1 0x23 | ||
| 31 | |||
| 32 | #define TWL4030_BCIAUTOWEN BIT(5) | ||
| 33 | #define TWL4030_CONFIG_DONE BIT(4) | ||
| 34 | #define TWL4030_BCIAUTOUSB BIT(1) | ||
| 35 | #define TWL4030_BCIAUTOAC BIT(0) | ||
| 36 | #define TWL4030_CGAIN BIT(5) | ||
| 37 | #define TWL4030_USBFASTMCHG BIT(2) | ||
| 38 | #define TWL4030_STS_VBUS BIT(7) | ||
| 39 | #define TWL4030_STS_USB_ID BIT(2) | ||
| 40 | |||
| 41 | /* BCI interrupts */ | ||
| 42 | #define TWL4030_WOVF BIT(0) /* Watchdog overflow */ | ||
| 43 | #define TWL4030_TMOVF BIT(1) /* Timer overflow */ | ||
| 44 | #define TWL4030_ICHGHIGH BIT(2) /* Battery charge current high */ | ||
| 45 | #define TWL4030_ICHGLOW BIT(3) /* Battery cc. low / FSM state change */ | ||
| 46 | #define TWL4030_ICHGEOC BIT(4) /* Battery current end-of-charge */ | ||
| 47 | #define TWL4030_TBATOR2 BIT(5) /* Battery temperature out of range 2 */ | ||
| 48 | #define TWL4030_TBATOR1 BIT(6) /* Battery temperature out of range 1 */ | ||
| 49 | #define TWL4030_BATSTS BIT(7) /* Battery status */ | ||
| 50 | |||
| 51 | #define TWL4030_VBATLVL BIT(0) /* VBAT level */ | ||
| 52 | #define TWL4030_VBATOV BIT(1) /* VBAT overvoltage */ | ||
| 53 | #define TWL4030_VBUSOV BIT(2) /* VBUS overvoltage */ | ||
| 54 | #define TWL4030_ACCHGOV BIT(3) /* Ac charger overvoltage */ | ||
| 55 | |||
| 56 | #define TWL4030_MSTATEC_USB BIT(4) | ||
| 57 | #define TWL4030_MSTATEC_AC BIT(5) | ||
| 58 | #define TWL4030_MSTATEC_MASK 0x0f | ||
| 59 | #define TWL4030_MSTATEC_QUICK1 0x02 | ||
| 60 | #define TWL4030_MSTATEC_QUICK7 0x07 | ||
| 61 | #define TWL4030_MSTATEC_COMPLETE1 0x0b | ||
| 62 | #define TWL4030_MSTATEC_COMPLETE4 0x0e | ||
| 63 | |||
| 64 | static bool allow_usb; | ||
| 65 | module_param(allow_usb, bool, 1); | ||
| 66 | MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current"); | ||
| 67 | |||
| 68 | struct twl4030_bci { | ||
| 69 | struct device *dev; | ||
| 70 | struct power_supply ac; | ||
| 71 | struct power_supply usb; | ||
| 72 | struct otg_transceiver *transceiver; | ||
| 73 | struct notifier_block otg_nb; | ||
| 74 | int irq_chg; | ||
| 75 | int irq_bci; | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * clear and set bits on an given register on a given module | ||
| 80 | */ | ||
| 81 | static int twl4030_clear_set(u8 mod_no, u8 clear, u8 set, u8 reg) | ||
| 82 | { | ||
| 83 | u8 val = 0; | ||
| 84 | int ret; | ||
| 85 | |||
| 86 | ret = twl_i2c_read_u8(mod_no, &val, reg); | ||
| 87 | if (ret) | ||
| 88 | return ret; | ||
| 89 | |||
| 90 | val &= ~clear; | ||
| 91 | val |= set; | ||
| 92 | |||
| 93 | return twl_i2c_write_u8(mod_no, val, reg); | ||
| 94 | } | ||
| 95 | |||
| 96 | static int twl4030_bci_read(u8 reg, u8 *val) | ||
| 97 | { | ||
| 98 | return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg); | ||
| 99 | } | ||
| 100 | |||
| 101 | static int twl4030_clear_set_boot_bci(u8 clear, u8 set) | ||
| 102 | { | ||
| 103 | return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0, | ||
| 104 | TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set, | ||
| 105 | TWL4030_PM_MASTER_BOOT_BCI); | ||
| 106 | } | ||
| 107 | |||
| 108 | static int twl4030bci_read_adc_val(u8 reg) | ||
| 109 | { | ||
| 110 | int ret, temp; | ||
| 111 | u8 val; | ||
| 112 | |||
| 113 | /* read MSB */ | ||
| 114 | ret = twl4030_bci_read(reg + 1, &val); | ||
| 115 | if (ret) | ||
| 116 | return ret; | ||
| 117 | |||
| 118 | temp = (int)(val & 0x03) << 8; | ||
| 119 | |||
| 120 | /* read LSB */ | ||
| 121 | ret = twl4030_bci_read(reg, &val); | ||
| 122 | if (ret) | ||
| 123 | return ret; | ||
| 124 | |||
| 125 | return temp | val; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 129 | * Check if VBUS power is present | ||
| 130 | */ | ||
| 131 | static int twl4030_bci_have_vbus(struct twl4030_bci *bci) | ||
| 132 | { | ||
| 133 | int ret; | ||
| 134 | u8 hwsts; | ||
| 135 | |||
| 136 | ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts, | ||
| 137 | TWL4030_PM_MASTER_STS_HW_CONDITIONS); | ||
| 138 | if (ret < 0) | ||
| 139 | return 0; | ||
| 140 | |||
| 141 | dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts); | ||
| 142 | |||
| 143 | /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */ | ||
| 144 | if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID)) | ||
| 145 | return 1; | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Enable/Disable USB Charge funtionality. | ||
| 152 | */ | ||
| 153 | static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) | ||
| 154 | { | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | if (enable) { | ||
| 158 | /* Check for USB charger conneted */ | ||
| 159 | if (!twl4030_bci_have_vbus(bci)) | ||
| 160 | return -ENODEV; | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Until we can find out what current the device can provide, | ||
| 164 | * require a module param to enable USB charging. | ||
| 165 | */ | ||
| 166 | if (!allow_usb) { | ||
| 167 | dev_warn(bci->dev, "USB charging is disabled.\n"); | ||
| 168 | return -EACCES; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ | ||
| 172 | ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); | ||
| 173 | if (ret < 0) | ||
| 174 | return ret; | ||
| 175 | |||
| 176 | /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ | ||
| 177 | ret = twl4030_clear_set(TWL4030_MODULE_MAIN_CHARGE, 0, | ||
| 178 | TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); | ||
| 179 | } else { | ||
| 180 | ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); | ||
| 181 | } | ||
| 182 | |||
| 183 | return ret; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* | ||
| 187 | * Enable/Disable AC Charge funtionality. | ||
| 188 | */ | ||
| 189 | static int twl4030_charger_enable_ac(bool enable) | ||
| 190 | { | ||
| 191 | int ret; | ||
| 192 | |||
| 193 | if (enable) | ||
| 194 | ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC); | ||
| 195 | else | ||
| 196 | ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0); | ||
| 197 | |||
| 198 | return ret; | ||
| 199 | } | ||
| 200 | |||
| 201 | /* | ||
| 202 | * TWL4030 CHG_PRES (AC charger presence) events | ||
| 203 | */ | ||
| 204 | static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) | ||
| 205 | { | ||
| 206 | struct twl4030_bci *bci = arg; | ||
| 207 | |||
| 208 | dev_dbg(bci->dev, "CHG_PRES irq\n"); | ||
| 209 | power_supply_changed(&bci->ac); | ||
| 210 | power_supply_changed(&bci->usb); | ||
| 211 | |||
| 212 | return IRQ_HANDLED; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * TWL4030 BCI monitoring events | ||
| 217 | */ | ||
| 218 | static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) | ||
| 219 | { | ||
| 220 | struct twl4030_bci *bci = arg; | ||
| 221 | u8 irqs1, irqs2; | ||
| 222 | int ret; | ||
| 223 | |||
| 224 | ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs1, | ||
| 225 | TWL4030_INTERRUPTS_BCIISR1A); | ||
| 226 | if (ret < 0) | ||
| 227 | return IRQ_HANDLED; | ||
| 228 | |||
| 229 | ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs2, | ||
| 230 | TWL4030_INTERRUPTS_BCIISR2A); | ||
| 231 | if (ret < 0) | ||
| 232 | return IRQ_HANDLED; | ||
| 233 | |||
| 234 | dev_dbg(bci->dev, "BCI irq %02x %02x\n", irqs2, irqs1); | ||
| 235 | |||
| 236 | if (irqs1 & (TWL4030_ICHGLOW | TWL4030_ICHGEOC)) { | ||
| 237 | /* charger state change, inform the core */ | ||
| 238 | power_supply_changed(&bci->ac); | ||
| 239 | power_supply_changed(&bci->usb); | ||
| 240 | } | ||
| 241 | |||
| 242 | /* various monitoring events, for now we just log them here */ | ||
| 243 | if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1)) | ||
| 244 | dev_warn(bci->dev, "battery temperature out of range\n"); | ||
| 245 | |||
| 246 | if (irqs1 & TWL4030_BATSTS) | ||
| 247 | dev_crit(bci->dev, "battery disconnected\n"); | ||
| 248 | |||
| 249 | if (irqs2 & TWL4030_VBATOV) | ||
| 250 | dev_crit(bci->dev, "VBAT overvoltage\n"); | ||
| 251 | |||
| 252 | if (irqs2 & TWL4030_VBUSOV) | ||
| 253 | dev_crit(bci->dev, "VBUS overvoltage\n"); | ||
| 254 | |||
| 255 | if (irqs2 & TWL4030_ACCHGOV) | ||
| 256 | dev_crit(bci->dev, "Ac charger overvoltage\n"); | ||
| 257 | |||
| 258 | return IRQ_HANDLED; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
| 262 | void *priv) | ||
| 263 | { | ||
| 264 | struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); | ||
| 265 | |||
| 266 | dev_dbg(bci->dev, "OTG notify %lu\n", val); | ||
| 267 | |||
| 268 | switch (val) { | ||
| 269 | case USB_EVENT_VBUS: | ||
| 270 | case USB_EVENT_CHARGER: | ||
| 271 | twl4030_charger_enable_usb(bci, true); | ||
| 272 | break; | ||
| 273 | case USB_EVENT_NONE: | ||
| 274 | twl4030_charger_enable_usb(bci, false); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | |||
| 278 | return NOTIFY_OK; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | * TI provided formulas: | ||
| 283 | * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85 | ||
| 284 | * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7 | ||
| 285 | * Here we use integer approximation of: | ||
| 286 | * CGAIN == 0: val * 1.6618 - 0.85 | ||
| 287 | * CGAIN == 1: (val * 1.6618 - 0.85) * 2 | ||
| 288 | */ | ||
| 289 | static int twl4030_charger_get_current(void) | ||
| 290 | { | ||
| 291 | int curr; | ||
| 292 | int ret; | ||
| 293 | u8 bcictl1; | ||
| 294 | |||
| 295 | curr = twl4030bci_read_adc_val(TWL4030_BCIICHG); | ||
| 296 | if (curr < 0) | ||
| 297 | return curr; | ||
| 298 | |||
| 299 | ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); | ||
| 300 | if (ret) | ||
| 301 | return ret; | ||
| 302 | |||
| 303 | ret = (curr * 16618 - 850 * 10000) / 10; | ||
| 304 | if (bcictl1 & TWL4030_CGAIN) | ||
| 305 | ret *= 2; | ||
| 306 | |||
| 307 | return ret; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Returns the main charge FSM state | ||
| 312 | * Or < 0 on failure. | ||
| 313 | */ | ||
| 314 | static int twl4030bci_state(struct twl4030_bci *bci) | ||
| 315 | { | ||
| 316 | int ret; | ||
| 317 | u8 state; | ||
| 318 | |||
| 319 | ret = twl4030_bci_read(TWL4030_BCIMSTATEC, &state); | ||
| 320 | if (ret) { | ||
| 321 | pr_err("twl4030_bci: error reading BCIMSTATEC\n"); | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | dev_dbg(bci->dev, "state: %02x\n", state); | ||
| 326 | |||
| 327 | return state; | ||
| 328 | } | ||
| 329 | |||
| 330 | static int twl4030_bci_state_to_status(int state) | ||
| 331 | { | ||
| 332 | state &= TWL4030_MSTATEC_MASK; | ||
| 333 | if (TWL4030_MSTATEC_QUICK1 <= state && state <= TWL4030_MSTATEC_QUICK7) | ||
| 334 | return POWER_SUPPLY_STATUS_CHARGING; | ||
| 335 | else if (TWL4030_MSTATEC_COMPLETE1 <= state && | ||
| 336 | state <= TWL4030_MSTATEC_COMPLETE4) | ||
| 337 | return POWER_SUPPLY_STATUS_FULL; | ||
| 338 | else | ||
| 339 | return POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 340 | } | ||
| 341 | |||
| 342 | static int twl4030_bci_get_property(struct power_supply *psy, | ||
| 343 | enum power_supply_property psp, | ||
| 344 | union power_supply_propval *val) | ||
| 345 | { | ||
| 346 | struct twl4030_bci *bci = dev_get_drvdata(psy->dev->parent); | ||
| 347 | int is_charging; | ||
| 348 | int state; | ||
| 349 | int ret; | ||
| 350 | |||
| 351 | state = twl4030bci_state(bci); | ||
| 352 | if (state < 0) | ||
| 353 | return state; | ||
| 354 | |||
| 355 | if (psy->type == POWER_SUPPLY_TYPE_USB) | ||
| 356 | is_charging = state & TWL4030_MSTATEC_USB; | ||
| 357 | else | ||
| 358 | is_charging = state & TWL4030_MSTATEC_AC; | ||
| 359 | |||
| 360 | switch (psp) { | ||
| 361 | case POWER_SUPPLY_PROP_STATUS: | ||
| 362 | if (is_charging) | ||
| 363 | val->intval = twl4030_bci_state_to_status(state); | ||
| 364 | else | ||
| 365 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 366 | break; | ||
| 367 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 368 | /* charging must be active for meaningful result */ | ||
| 369 | if (!is_charging) | ||
| 370 | return -ENODATA; | ||
| 371 | if (psy->type == POWER_SUPPLY_TYPE_USB) { | ||
| 372 | ret = twl4030bci_read_adc_val(TWL4030_BCIVBUS); | ||
| 373 | if (ret < 0) | ||
| 374 | return ret; | ||
| 375 | /* BCIVBUS uses ADCIN8, 7/1023 V/step */ | ||
| 376 | val->intval = ret * 6843; | ||
| 377 | } else { | ||
| 378 | ret = twl4030bci_read_adc_val(TWL4030_BCIVAC); | ||
| 379 | if (ret < 0) | ||
| 380 | return ret; | ||
| 381 | /* BCIVAC uses ADCIN11, 10/1023 V/step */ | ||
| 382 | val->intval = ret * 9775; | ||
| 383 | } | ||
| 384 | break; | ||
| 385 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
| 386 | if (!is_charging) | ||
| 387 | return -ENODATA; | ||
| 388 | /* current measurement is shared between AC and USB */ | ||
| 389 | ret = twl4030_charger_get_current(); | ||
| 390 | if (ret < 0) | ||
| 391 | return ret; | ||
| 392 | val->intval = ret; | ||
| 393 | break; | ||
| 394 | case POWER_SUPPLY_PROP_ONLINE: | ||
| 395 | val->intval = is_charging && | ||
| 396 | twl4030_bci_state_to_status(state) != | ||
| 397 | POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 398 | break; | ||
| 399 | default: | ||
| 400 | return -EINVAL; | ||
| 401 | } | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | static enum power_supply_property twl4030_charger_props[] = { | ||
| 407 | POWER_SUPPLY_PROP_STATUS, | ||
| 408 | POWER_SUPPLY_PROP_ONLINE, | ||
| 409 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 410 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
| 411 | }; | ||
| 412 | |||
| 413 | static int __init twl4030_bci_probe(struct platform_device *pdev) | ||
| 414 | { | ||
| 415 | struct twl4030_bci *bci; | ||
| 416 | int ret; | ||
| 417 | int reg; | ||
| 418 | |||
| 419 | bci = kzalloc(sizeof(*bci), GFP_KERNEL); | ||
| 420 | if (bci == NULL) | ||
| 421 | return -ENOMEM; | ||
| 422 | |||
| 423 | bci->dev = &pdev->dev; | ||
| 424 | bci->irq_chg = platform_get_irq(pdev, 0); | ||
| 425 | bci->irq_bci = platform_get_irq(pdev, 1); | ||
| 426 | |||
| 427 | platform_set_drvdata(pdev, bci); | ||
| 428 | |||
| 429 | bci->ac.name = "twl4030_ac"; | ||
| 430 | bci->ac.type = POWER_SUPPLY_TYPE_MAINS; | ||
| 431 | bci->ac.properties = twl4030_charger_props; | ||
| 432 | bci->ac.num_properties = ARRAY_SIZE(twl4030_charger_props); | ||
| 433 | bci->ac.get_property = twl4030_bci_get_property; | ||
| 434 | |||
| 435 | ret = power_supply_register(&pdev->dev, &bci->ac); | ||
| 436 | if (ret) { | ||
| 437 | dev_err(&pdev->dev, "failed to register ac: %d\n", ret); | ||
| 438 | goto fail_register_ac; | ||
| 439 | } | ||
| 440 | |||
| 441 | bci->usb.name = "twl4030_usb"; | ||
| 442 | bci->usb.type = POWER_SUPPLY_TYPE_USB; | ||
| 443 | bci->usb.properties = twl4030_charger_props; | ||
| 444 | bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props); | ||
| 445 | bci->usb.get_property = twl4030_bci_get_property; | ||
| 446 | |||
| 447 | ret = power_supply_register(&pdev->dev, &bci->usb); | ||
| 448 | if (ret) { | ||
| 449 | dev_err(&pdev->dev, "failed to register usb: %d\n", ret); | ||
| 450 | goto fail_register_usb; | ||
| 451 | } | ||
| 452 | |||
| 453 | ret = request_threaded_irq(bci->irq_chg, NULL, | ||
| 454 | twl4030_charger_interrupt, 0, pdev->name, bci); | ||
| 455 | if (ret < 0) { | ||
| 456 | dev_err(&pdev->dev, "could not request irq %d, status %d\n", | ||
| 457 | bci->irq_chg, ret); | ||
| 458 | goto fail_chg_irq; | ||
| 459 | } | ||
| 460 | |||
| 461 | ret = request_threaded_irq(bci->irq_bci, NULL, | ||
| 462 | twl4030_bci_interrupt, 0, pdev->name, bci); | ||
| 463 | if (ret < 0) { | ||
| 464 | dev_err(&pdev->dev, "could not request irq %d, status %d\n", | ||
| 465 | bci->irq_bci, ret); | ||
| 466 | goto fail_bci_irq; | ||
| 467 | } | ||
| 468 | |||
| 469 | bci->transceiver = otg_get_transceiver(); | ||
| 470 | if (bci->transceiver != NULL) { | ||
| 471 | bci->otg_nb.notifier_call = twl4030_bci_usb_ncb; | ||
| 472 | otg_register_notifier(bci->transceiver, &bci->otg_nb); | ||
| 473 | } | ||
| 474 | |||
| 475 | /* Enable interrupts now. */ | ||
| 476 | reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 | | ||
| 477 | TWL4030_TBATOR1 | TWL4030_BATSTS); | ||
| 478 | ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, | ||
| 479 | TWL4030_INTERRUPTS_BCIIMR1A); | ||
| 480 | if (ret < 0) { | ||
| 481 | dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); | ||
| 482 | goto fail_unmask_interrupts; | ||
| 483 | } | ||
| 484 | |||
| 485 | reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV); | ||
| 486 | ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, | ||
| 487 | TWL4030_INTERRUPTS_BCIIMR2A); | ||
| 488 | if (ret < 0) | ||
| 489 | dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); | ||
| 490 | |||
| 491 | twl4030_charger_enable_ac(true); | ||
| 492 | twl4030_charger_enable_usb(bci, true); | ||
| 493 | |||
| 494 | return 0; | ||
| 495 | |||
| 496 | fail_unmask_interrupts: | ||
| 497 | if (bci->transceiver != NULL) { | ||
| 498 | otg_unregister_notifier(bci->transceiver, &bci->otg_nb); | ||
| 499 | otg_put_transceiver(bci->transceiver); | ||
| 500 | } | ||
| 501 | free_irq(bci->irq_bci, bci); | ||
| 502 | fail_bci_irq: | ||
| 503 | free_irq(bci->irq_chg, bci); | ||
| 504 | fail_chg_irq: | ||
| 505 | power_supply_unregister(&bci->usb); | ||
| 506 | fail_register_usb: | ||
| 507 | power_supply_unregister(&bci->ac); | ||
| 508 | fail_register_ac: | ||
| 509 | platform_set_drvdata(pdev, NULL); | ||
| 510 | kfree(bci); | ||
| 511 | |||
| 512 | return ret; | ||
| 513 | } | ||
| 514 | |||
| 515 | static int __exit twl4030_bci_remove(struct platform_device *pdev) | ||
| 516 | { | ||
| 517 | struct twl4030_bci *bci = platform_get_drvdata(pdev); | ||
| 518 | |||
| 519 | twl4030_charger_enable_ac(false); | ||
| 520 | twl4030_charger_enable_usb(bci, false); | ||
| 521 | |||
| 522 | /* mask interrupts */ | ||
| 523 | twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, | ||
| 524 | TWL4030_INTERRUPTS_BCIIMR1A); | ||
| 525 | twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, | ||
| 526 | TWL4030_INTERRUPTS_BCIIMR2A); | ||
| 527 | |||
| 528 | if (bci->transceiver != NULL) { | ||
| 529 | otg_unregister_notifier(bci->transceiver, &bci->otg_nb); | ||
| 530 | otg_put_transceiver(bci->transceiver); | ||
| 531 | } | ||
| 532 | free_irq(bci->irq_bci, bci); | ||
| 533 | free_irq(bci->irq_chg, bci); | ||
| 534 | power_supply_unregister(&bci->usb); | ||
| 535 | power_supply_unregister(&bci->ac); | ||
| 536 | platform_set_drvdata(pdev, NULL); | ||
| 537 | kfree(bci); | ||
| 538 | |||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | |||
| 542 | static struct platform_driver twl4030_bci_driver = { | ||
| 543 | .driver = { | ||
| 544 | .name = "twl4030_bci", | ||
| 545 | .owner = THIS_MODULE, | ||
| 546 | }, | ||
| 547 | .remove = __exit_p(twl4030_bci_remove), | ||
| 548 | }; | ||
| 549 | |||
| 550 | static int __init twl4030_bci_init(void) | ||
| 551 | { | ||
| 552 | return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe); | ||
| 553 | } | ||
| 554 | module_init(twl4030_bci_init); | ||
| 555 | |||
| 556 | static void __exit twl4030_bci_exit(void) | ||
| 557 | { | ||
| 558 | platform_driver_unregister(&twl4030_bci_driver); | ||
| 559 | } | ||
| 560 | module_exit(twl4030_bci_exit); | ||
| 561 | |||
| 562 | MODULE_AUTHOR("Gražydas Ignotas"); | ||
| 563 | MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver"); | ||
| 564 | MODULE_LICENSE("GPL"); | ||
| 565 | MODULE_ALIAS("platform:twl4030_bci"); | ||
diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index fbcc36dae470..ddf8cf5f3204 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c | |||
| @@ -267,7 +267,6 @@ static void wm831x_config_battery(struct wm831x *wm831x) | |||
| 267 | ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1, | 267 | ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1, |
| 268 | WM831X_CHG_ENA_MASK | | 268 | WM831X_CHG_ENA_MASK | |
| 269 | WM831X_CHG_FAST_MASK | | 269 | WM831X_CHG_FAST_MASK | |
| 270 | WM831X_CHG_ITERM_MASK | | ||
| 271 | WM831X_CHG_ITERM_MASK, | 270 | WM831X_CHG_ITERM_MASK, |
| 272 | reg1); | 271 | reg1); |
| 273 | if (ret != 0) | 272 | if (ret != 0) |
| @@ -612,6 +611,7 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev) | |||
| 612 | power_supply_unregister(&wm831x_power->battery); | 611 | power_supply_unregister(&wm831x_power->battery); |
| 613 | power_supply_unregister(&wm831x_power->wall); | 612 | power_supply_unregister(&wm831x_power->wall); |
| 614 | power_supply_unregister(&wm831x_power->usb); | 613 | power_supply_unregister(&wm831x_power->usb); |
| 614 | kfree(wm831x_power); | ||
| 615 | return 0; | 615 | return 0; |
| 616 | } | 616 | } |
| 617 | 617 | ||
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 30083a896f36..7d7325685c42 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
| @@ -89,6 +89,7 @@ enum power_supply_property { | |||
| 89 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 89 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
| 90 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 90 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
| 91 | POWER_SUPPLY_PROP_VOLTAGE_AVG, | 91 | POWER_SUPPLY_PROP_VOLTAGE_AVG, |
| 92 | POWER_SUPPLY_PROP_CURRENT_MAX, | ||
| 92 | POWER_SUPPLY_PROP_CURRENT_NOW, | 93 | POWER_SUPPLY_PROP_CURRENT_NOW, |
| 93 | POWER_SUPPLY_PROP_CURRENT_AVG, | 94 | POWER_SUPPLY_PROP_CURRENT_AVG, |
| 94 | POWER_SUPPLY_PROP_POWER_NOW, | 95 | POWER_SUPPLY_PROP_POWER_NOW, |
| @@ -125,7 +126,10 @@ enum power_supply_type { | |||
| 125 | POWER_SUPPLY_TYPE_BATTERY = 0, | 126 | POWER_SUPPLY_TYPE_BATTERY = 0, |
| 126 | POWER_SUPPLY_TYPE_UPS, | 127 | POWER_SUPPLY_TYPE_UPS, |
| 127 | POWER_SUPPLY_TYPE_MAINS, | 128 | POWER_SUPPLY_TYPE_MAINS, |
| 128 | POWER_SUPPLY_TYPE_USB, | 129 | POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */ |
| 130 | POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */ | ||
| 131 | POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */ | ||
| 132 | POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */ | ||
| 129 | }; | 133 | }; |
| 130 | 134 | ||
| 131 | union power_supply_propval { | 135 | union power_supply_propval { |
