aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRhyland Klein <rklein@nvidia.com>2010-09-21 18:33:55 -0400
committerAnton Vorontsov <cbouatmailru@gmail.com>2010-09-28 08:42:35 -0400
commitd3ab61ecbab2b8950108b3541bc9eda515d605e0 (patch)
tree52d98e62f965faa915220042b34858efe2137229 /drivers
parent9c99f08991b38bf6ab62ffe9013ee46ff41d66d0 (diff)
bq20z75: Add support for more power supply properties
This patch adds properties to support devicekit power. Also, create IO wrapper functions and fix some issues found while testing, including unit conversions to match the power_supply types. Signed-off-by: Rhyland Klein <rklein@nvidia.com> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/bq20z75.c204
1 files changed, 156 insertions, 48 deletions
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c
index a1c7ae2ec9f8..492da27e1a47 100644
--- a/drivers/power/bq20z75.c
+++ b/drivers/power/bq20z75.c
@@ -36,7 +36,11 @@ enum {
36 REG_TIME_TO_FULL, 36 REG_TIME_TO_FULL,
37 REG_STATUS, 37 REG_STATUS,
38 REG_CYCLE_COUNT, 38 REG_CYCLE_COUNT,
39 REG_SERIAL_NUMBER 39 REG_SERIAL_NUMBER,
40 REG_REMAINING_CAPACITY,
41 REG_FULL_CHARGE_CAPACITY,
42 REG_DESIGN_CAPACITY,
43 REG_DESIGN_VOLTAGE,
40}; 44};
41 45
42/* manufacturer access defines */ 46/* manufacturer access defines */
@@ -44,7 +48,7 @@ enum {
44#define MANUFACTURER_ACCESS_SLEEP 0x0011 48#define MANUFACTURER_ACCESS_SLEEP 0x0011
45 49
46/* battery status value bits */ 50/* battery status value bits */
47#define BATTERY_CHARGING 0x40 51#define BATTERY_DISCHARGING 0x40
48#define BATTERY_FULL_CHARGED 0x20 52#define BATTERY_FULL_CHARGED 0x20
49#define BATTERY_FULL_DISCHARGED 0x10 53#define BATTERY_FULL_DISCHARGED 0x10
50 54
@@ -72,6 +76,10 @@ static const struct bq20z75_device_data {
72 32767), 76 32767),
73 [REG_CAPACITY] = 77 [REG_CAPACITY] =
74 BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), 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),
75 [REG_TIME_TO_EMPTY] = 83 [REG_TIME_TO_EMPTY] =
76 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 84 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
77 65535), 85 65535),
@@ -82,6 +90,12 @@ static const struct bq20z75_device_data {
82 BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535), 90 BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
83 [REG_CYCLE_COUNT] = 91 [REG_CYCLE_COUNT] =
84 BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535), 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),
85 [REG_SERIAL_NUMBER] = 99 [REG_SERIAL_NUMBER] =
86 BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), 100 BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
87}; 101};
@@ -99,6 +113,10 @@ static enum power_supply_property bq20z75_properties[] = {
99 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 113 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
100 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 114 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
101 POWER_SUPPLY_PROP_SERIAL_NUMBER, 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,
102}; 120};
103 121
104struct bq20z75_info { 122struct bq20z75_info {
@@ -106,6 +124,35 @@ struct bq20z75_info {
106 struct power_supply power_supply; 124 struct power_supply power_supply;
107}; 125};
108 126
127static 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
141static 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
109static int bq20z75_get_battery_presence_and_health( 156static int bq20z75_get_battery_presence_and_health(
110 struct i2c_client *client, enum power_supply_property psp, 157 struct i2c_client *client, enum power_supply_property psp,
111 union power_supply_propval *val) 158 union power_supply_propval *val)
@@ -115,24 +162,17 @@ static int bq20z75_get_battery_presence_and_health(
115 /* Write to ManufacturerAccess with 162 /* Write to ManufacturerAccess with
116 * ManufacturerAccess command and then 163 * ManufacturerAccess command and then
117 * read the status */ 164 * read the status */
118 ret = i2c_smbus_write_word_data(client, 165 ret = bq20z75_write_word_data(client,
119 bq20z75_data[REG_MANUFACTURER_DATA].addr, 166 bq20z75_data[REG_MANUFACTURER_DATA].addr,
120 MANUFACTURER_ACCESS_STATUS); 167 MANUFACTURER_ACCESS_STATUS);
121 if (ret < 0) { 168 if (ret < 0)
122 dev_err(&client->dev, 169 return ret;
123 "%s: i2c write for battery presence failed\n",
124 __func__);
125 return -ENODEV;
126 }
127 170
128 ret = i2c_smbus_read_word_data(client, 171
172 ret = bq20z75_read_word_data(client,
129 bq20z75_data[REG_MANUFACTURER_DATA].addr); 173 bq20z75_data[REG_MANUFACTURER_DATA].addr);
130 if (ret < 0) { 174 if (ret < 0)
131 dev_err(&client->dev, 175 return ret;
132 "%s: i2c read for battery presence failed\n",
133 __func__);
134 return -EIO;
135 }
136 176
137 if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || 177 if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
138 ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { 178 ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
@@ -171,31 +211,28 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
171{ 211{
172 s32 ret; 212 s32 ret;
173 213
174 ret = i2c_smbus_read_word_data(client, 214 ret = bq20z75_read_word_data(client,
175 bq20z75_data[reg_offset].addr); 215 bq20z75_data[reg_offset].addr);
176 if (ret < 0) { 216 if (ret < 0)
177 dev_err(&client->dev, 217 return ret;
178 "%s: i2c read for %d failed\n", __func__, reg_offset); 218
179 return -EIO; 219 /* returned values are 16 bit */
180 } 220 if (bq20z75_data[reg_offset].min_value < 0)
221 ret = (s16)ret;
181 222
182 if (ret >= bq20z75_data[reg_offset].min_value && 223 if (ret >= bq20z75_data[reg_offset].min_value &&
183 ret <= bq20z75_data[reg_offset].max_value) { 224 ret <= bq20z75_data[reg_offset].max_value) {
184 val->intval = ret; 225 val->intval = ret;
185 if (psp == POWER_SUPPLY_PROP_STATUS) { 226 if (psp == POWER_SUPPLY_PROP_STATUS) {
186 if (ret & BATTERY_CHARGING) 227 if (ret & BATTERY_FULL_CHARGED)
187 val->intval = POWER_SUPPLY_STATUS_CHARGING;
188 else if (ret & BATTERY_FULL_CHARGED)
189 val->intval = POWER_SUPPLY_STATUS_FULL; 228 val->intval = POWER_SUPPLY_STATUS_FULL;
190 else if (ret & BATTERY_FULL_DISCHARGED) 229 else if (ret & BATTERY_FULL_DISCHARGED)
191 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 230 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
192 else 231 else if (ret & BATTERY_DISCHARGING)
193 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 232 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
233 else
234 val->intval = POWER_SUPPLY_STATUS_CHARGING;
194 } 235 }
195 /* bq20z75 provides battery tempreture in 0.1°K
196 * so convert it to °C */
197 else if (psp == POWER_SUPPLY_PROP_TEMP)
198 val->intval = ret - 2731;
199 } else { 236 } else {
200 if (psp == POWER_SUPPLY_PROP_STATUS) 237 if (psp == POWER_SUPPLY_PROP_STATUS)
201 val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 238 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
@@ -206,21 +243,77 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
206 return 0; 243 return 0;
207} 244}
208 245
246static 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
209static int bq20z75_get_battery_capacity(struct i2c_client *client, 284static int bq20z75_get_battery_capacity(struct i2c_client *client,
285 int reg_offset, enum power_supply_property psp,
210 union power_supply_propval *val) 286 union power_supply_propval *val)
211{ 287{
212 s32 ret; 288 s32 ret;
213 289
214 ret = i2c_smbus_read_byte_data(client, bq20z75_data[REG_CAPACITY].addr); 290 ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
215 if (ret < 0) { 291 if (ret < 0)
216 dev_err(&client->dev, 292 return ret;
217 "%s: i2c read for %d failed\n", __func__, REG_CAPACITY);
218 return -EIO;
219 }
220 293
221 /* bq20z75 spec says that this can be >100 % 294 if (psp == POWER_SUPPLY_PROP_CAPACITY) {
222 * even if max value is 100 % */ 295 /* bq20z75 spec says that this can be >100 %
223 val->intval = min(ret, 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
304static char bq20z75_serial[5];
305static 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;
224 317
225 return 0; 318 return 0;
226} 319}
@@ -247,8 +340,23 @@ static int bq20z75_get_property(struct power_supply *psy,
247 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 340 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
248 break; 341 break;
249 342
343 case POWER_SUPPLY_PROP_ENERGY_NOW:
344 case POWER_SUPPLY_PROP_ENERGY_FULL:
345 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
250 case POWER_SUPPLY_PROP_CAPACITY: 346 case POWER_SUPPLY_PROP_CAPACITY:
251 ret = bq20z75_get_battery_capacity(client, val); 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);
252 if (ret) 360 if (ret)
253 return ret; 361 return ret;
254 break; 362 break;
@@ -260,7 +368,7 @@ static int bq20z75_get_property(struct power_supply *psy,
260 case POWER_SUPPLY_PROP_TEMP: 368 case POWER_SUPPLY_PROP_TEMP:
261 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 369 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
262 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 370 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
263 case POWER_SUPPLY_PROP_SERIAL_NUMBER: 371 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
264 for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { 372 for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
265 if (psp == bq20z75_data[count].psp) 373 if (psp == bq20z75_data[count].psp)
266 break; 374 break;
@@ -269,6 +377,7 @@ static int bq20z75_get_property(struct power_supply *psy,
269 ret = bq20z75_get_battery_property(client, count, psp, val); 377 ret = bq20z75_get_battery_property(client, count, psp, val);
270 if (ret) 378 if (ret)
271 return ret; 379 return ret;
380
272 break; 381 break;
273 382
274 default: 383 default:
@@ -277,6 +386,9 @@ static int bq20z75_get_property(struct power_supply *psy,
277 return -EINVAL; 386 return -EINVAL;
278 } 387 }
279 388
389 /* Convert units to match requirements for power supply class */
390 bq20z75_unit_adjustment(client, psp, val);
391
280 dev_dbg(&client->dev, 392 dev_dbg(&client->dev,
281 "%s: property = %d, value = %d\n", __func__, psp, val->intval); 393 "%s: property = %d, value = %d\n", __func__, psp, val->intval);
282 394
@@ -335,15 +447,11 @@ static int bq20z75_suspend(struct i2c_client *client,
335 s32 ret; 447 s32 ret;
336 448
337 /* write to manufacturer access with sleep command */ 449 /* write to manufacturer access with sleep command */
338 ret = i2c_smbus_write_word_data(client, 450 ret = bq20z75_write_word_data(client,
339 bq20z75_data[REG_MANUFACTURER_DATA].addr, 451 bq20z75_data[REG_MANUFACTURER_DATA].addr,
340 MANUFACTURER_ACCESS_SLEEP); 452 MANUFACTURER_ACCESS_SLEEP);
341 if (ret < 0) { 453 if (ret < 0)
342 dev_err(&client->dev, 454 return ret;
343 "%s: i2c write for %d failed\n",
344 __func__, MANUFACTURER_ACCESS_SLEEP);
345 return -EIO;
346 }
347 455
348 return 0; 456 return 0;
349} 457}