aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/sbs-battery.c
diff options
context:
space:
mode:
authorCheng-Yi Chiang <cychiang@chromium.org>2014-08-04 07:47:45 -0400
committerSebastian Reichel <sre@kernel.org>2014-09-06 14:57:43 -0400
commit9ea89402e25edafb6ad8ec92848d12c1d5d3969f (patch)
treedb5028e0f60c3a413498a68e7e555c995346a416 /drivers/power/sbs-battery.c
parent86ba8b0aee711b01fa5a14868035a3f4d6b1e1d9 (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.c115
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
120static enum power_supply_property sbs_properties[] = { 128static 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
142struct sbs_info { 153struct sbs_info {
@@ -153,6 +164,9 @@ struct sbs_info {
153 int ignore_changes; 164 int ignore_changes;
154}; 165};
155 166
167static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
168static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1];
169
156static int sbs_read_word_data(struct i2c_client *client, u8 address) 170static 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
196static 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
182static int sbs_write_word_data(struct i2c_client *client, u8 address, 264static 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
403static 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
321static void sbs_unit_adjustment(struct i2c_client *client, 416static 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__);