diff options
author | Cheng-Yi Chiang <cychiang@chromium.org> | 2014-08-04 07:47:45 -0400 |
---|---|---|
committer | Sebastian Reichel <sre@kernel.org> | 2014-09-06 14:57:43 -0400 |
commit | 9ea89402e25edafb6ad8ec92848d12c1d5d3969f (patch) | |
tree | db5028e0f60c3a413498a68e7e555c995346a416 /drivers/power/sbs-battery.c | |
parent | 86ba8b0aee711b01fa5a14868035a3f4d6b1e1d9 (diff) |
sbs-battery: export manufacturer and model name to sysfs
This CL supports two power_supply_property items for smart battery:
POWER_SUPPLY_PROP_MANUFACTURER and POWER_SUPPLY_PROP_MODEL_NAME such
that battery information 'manufacturer' and 'model_name' can be exported
to sysfs.
Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Diffstat (limited to 'drivers/power/sbs-battery.c')
-rw-r--r-- | drivers/power/sbs-battery.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c index b5f2a76b6cdf..08feb38cefc0 100644 --- a/drivers/power/sbs-battery.c +++ b/drivers/power/sbs-battery.c | |||
@@ -49,6 +49,8 @@ enum { | |||
49 | REG_DESIGN_CAPACITY, | 49 | REG_DESIGN_CAPACITY, |
50 | REG_DESIGN_CAPACITY_CHARGE, | 50 | REG_DESIGN_CAPACITY_CHARGE, |
51 | REG_DESIGN_VOLTAGE, | 51 | REG_DESIGN_VOLTAGE, |
52 | REG_MANUFACTURER, | ||
53 | REG_MODEL_NAME, | ||
52 | }; | 54 | }; |
53 | 55 | ||
54 | /* Battery Mode defines */ | 56 | /* Battery Mode defines */ |
@@ -68,6 +70,7 @@ enum sbs_battery_mode { | |||
68 | #define BATTERY_FULL_CHARGED 0x20 | 70 | #define BATTERY_FULL_CHARGED 0x20 |
69 | #define BATTERY_FULL_DISCHARGED 0x10 | 71 | #define BATTERY_FULL_DISCHARGED 0x10 |
70 | 72 | ||
73 | /* min_value and max_value are only valid for numerical data */ | ||
71 | #define SBS_DATA(_psp, _addr, _min_value, _max_value) { \ | 74 | #define SBS_DATA(_psp, _addr, _min_value, _max_value) { \ |
72 | .psp = _psp, \ | 75 | .psp = _psp, \ |
73 | .addr = _addr, \ | 76 | .addr = _addr, \ |
@@ -115,6 +118,11 @@ static const struct chip_data { | |||
115 | SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535), | 118 | SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535), |
116 | [REG_SERIAL_NUMBER] = | 119 | [REG_SERIAL_NUMBER] = |
117 | SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), | 120 | SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535), |
121 | /* Properties of type `const char *' */ | ||
122 | [REG_MANUFACTURER] = | ||
123 | SBS_DATA(POWER_SUPPLY_PROP_MANUFACTURER, 0x20, 0, 65535), | ||
124 | [REG_MODEL_NAME] = | ||
125 | SBS_DATA(POWER_SUPPLY_PROP_MODEL_NAME, 0x21, 0, 65535) | ||
118 | }; | 126 | }; |
119 | 127 | ||
120 | static enum power_supply_property sbs_properties[] = { | 128 | static enum power_supply_property sbs_properties[] = { |
@@ -137,6 +145,9 @@ static enum power_supply_property sbs_properties[] = { | |||
137 | POWER_SUPPLY_PROP_CHARGE_NOW, | 145 | POWER_SUPPLY_PROP_CHARGE_NOW, |
138 | POWER_SUPPLY_PROP_CHARGE_FULL, | 146 | POWER_SUPPLY_PROP_CHARGE_FULL, |
139 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 147 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
148 | /* Properties of type `const char *' */ | ||
149 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
150 | POWER_SUPPLY_PROP_MODEL_NAME | ||
140 | }; | 151 | }; |
141 | 152 | ||
142 | struct sbs_info { | 153 | struct sbs_info { |
@@ -153,6 +164,9 @@ struct sbs_info { | |||
153 | int ignore_changes; | 164 | int ignore_changes; |
154 | }; | 165 | }; |
155 | 166 | ||
167 | static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; | ||
168 | static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
169 | |||
156 | static int sbs_read_word_data(struct i2c_client *client, u8 address) | 170 | static int sbs_read_word_data(struct i2c_client *client, u8 address) |
157 | { | 171 | { |
158 | struct sbs_info *chip = i2c_get_clientdata(client); | 172 | struct sbs_info *chip = i2c_get_clientdata(client); |
@@ -179,6 +193,74 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address) | |||
179 | return le16_to_cpu(ret); | 193 | return le16_to_cpu(ret); |
180 | } | 194 | } |
181 | 195 | ||
196 | static int sbs_read_string_data(struct i2c_client *client, u8 address, | ||
197 | char *values) | ||
198 | { | ||
199 | struct sbs_info *chip = i2c_get_clientdata(client); | ||
200 | s32 ret = 0, block_length = 0; | ||
201 | int retries_length = 1, retries_block = 1; | ||
202 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
203 | |||
204 | if (chip->pdata) { | ||
205 | retries_length = max(chip->pdata->i2c_retry_count + 1, 1); | ||
206 | retries_block = max(chip->pdata->i2c_retry_count + 1, 1); | ||
207 | } | ||
208 | |||
209 | /* Adapter needs to support these two functions */ | ||
210 | if (!i2c_check_functionality(client->adapter, | ||
211 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
212 | I2C_FUNC_SMBUS_I2C_BLOCK)){ | ||
213 | return -ENODEV; | ||
214 | } | ||
215 | |||
216 | /* Get the length of block data */ | ||
217 | while (retries_length > 0) { | ||
218 | ret = i2c_smbus_read_byte_data(client, address); | ||
219 | if (ret >= 0) | ||
220 | break; | ||
221 | retries_length--; | ||
222 | } | ||
223 | |||
224 | if (ret < 0) { | ||
225 | dev_dbg(&client->dev, | ||
226 | "%s: i2c read at address 0x%x failed\n", | ||
227 | __func__, address); | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | /* block_length does not include NULL terminator */ | ||
232 | block_length = ret; | ||
233 | if (block_length > I2C_SMBUS_BLOCK_MAX) { | ||
234 | dev_err(&client->dev, | ||
235 | "%s: Returned block_length is longer than 0x%x\n", | ||
236 | __func__, I2C_SMBUS_BLOCK_MAX); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | /* Get the block data */ | ||
241 | while (retries_block > 0) { | ||
242 | ret = i2c_smbus_read_i2c_block_data( | ||
243 | client, address, | ||
244 | block_length + 1, block_buffer); | ||
245 | if (ret >= 0) | ||
246 | break; | ||
247 | retries_block--; | ||
248 | } | ||
249 | |||
250 | if (ret < 0) { | ||
251 | dev_dbg(&client->dev, | ||
252 | "%s: i2c read at address 0x%x failed\n", | ||
253 | __func__, address); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | /* block_buffer[0] == block_length */ | ||
258 | memcpy(values, block_buffer + 1, block_length); | ||
259 | values[block_length] = '\0'; | ||
260 | |||
261 | return le16_to_cpu(ret); | ||
262 | } | ||
263 | |||
182 | static int sbs_write_word_data(struct i2c_client *client, u8 address, | 264 | static int sbs_write_word_data(struct i2c_client *client, u8 address, |
183 | u16 value) | 265 | u16 value) |
184 | { | 266 | { |
@@ -318,6 +400,19 @@ static int sbs_get_battery_property(struct i2c_client *client, | |||
318 | return 0; | 400 | return 0; |
319 | } | 401 | } |
320 | 402 | ||
403 | static int sbs_get_battery_string_property(struct i2c_client *client, | ||
404 | int reg_offset, enum power_supply_property psp, char *val) | ||
405 | { | ||
406 | s32 ret; | ||
407 | |||
408 | ret = sbs_read_string_data(client, sbs_data[reg_offset].addr, val); | ||
409 | |||
410 | if (ret < 0) | ||
411 | return ret; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
321 | static void sbs_unit_adjustment(struct i2c_client *client, | 416 | static void sbs_unit_adjustment(struct i2c_client *client, |
322 | enum power_supply_property psp, union power_supply_propval *val) | 417 | enum power_supply_property psp, union power_supply_propval *val) |
323 | { | 418 | { |
@@ -505,6 +600,26 @@ static int sbs_get_property(struct power_supply *psy, | |||
505 | ret = sbs_get_battery_property(client, ret, psp, val); | 600 | ret = sbs_get_battery_property(client, ret, psp, val); |
506 | break; | 601 | break; |
507 | 602 | ||
603 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
604 | ret = sbs_get_property_index(client, psp); | ||
605 | if (ret < 0) | ||
606 | break; | ||
607 | |||
608 | ret = sbs_get_battery_string_property(client, ret, psp, | ||
609 | model_name); | ||
610 | val->strval = model_name; | ||
611 | break; | ||
612 | |||
613 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
614 | ret = sbs_get_property_index(client, psp); | ||
615 | if (ret < 0) | ||
616 | break; | ||
617 | |||
618 | ret = sbs_get_battery_string_property(client, ret, psp, | ||
619 | manufacturer); | ||
620 | val->strval = manufacturer; | ||
621 | break; | ||
622 | |||
508 | default: | 623 | default: |
509 | dev_err(&client->dev, | 624 | dev_err(&client->dev, |
510 | "%s: INVALID property\n", __func__); | 625 | "%s: INVALID property\n", __func__); |