@@ -51,6 +51,14 @@ enum {
51
51
REG_CHARGE_VOLTAGE ,
52
52
};
53
53
54
+ #define REG_ADDR_SPEC_INFO 0x1A
55
+ #define SPEC_INFO_VERSION_MASK GENMASK(7, 4)
56
+ #define SPEC_INFO_VERSION_SHIFT 4
57
+
58
+ #define SBS_VERSION_1_0 1
59
+ #define SBS_VERSION_1_1 2
60
+ #define SBS_VERSION_1_1_WITH_PEC 3
61
+
54
62
#define REG_ADDR_MANUFACTURE_DATE 0x1B
55
63
56
64
/* Battery Mode defines */
@@ -224,14 +232,57 @@ static void sbs_disable_charger_broadcasts(struct sbs_info *chip)
224
232
225
233
static int sbs_update_presence (struct sbs_info * chip , bool is_present )
226
234
{
235
+ struct i2c_client * client = chip -> client ;
236
+ int retries = chip -> i2c_retry_count ;
237
+ s32 ret = 0 ;
238
+ u8 version ;
239
+
227
240
if (chip -> is_present == is_present )
228
241
return 0 ;
229
242
230
243
if (!is_present ) {
231
244
chip -> is_present = false;
245
+ /* Disable PEC when no device is present */
246
+ client -> flags &= ~I2C_CLIENT_PEC ;
232
247
return 0 ;
233
248
}
234
249
250
+ /* Check if device supports packet error checking and use it */
251
+ while (retries > 0 ) {
252
+ ret = i2c_smbus_read_word_data (client , REG_ADDR_SPEC_INFO );
253
+ if (ret >= 0 )
254
+ break ;
255
+
256
+ /*
257
+ * Some batteries trigger the detection pin before the
258
+ * I2C bus is properly connected. This works around the
259
+ * issue.
260
+ */
261
+ msleep (100 );
262
+
263
+ retries -- ;
264
+ }
265
+
266
+ if (ret < 0 ) {
267
+ dev_dbg (& client -> dev , "failed to read spec info: %d\n" , ret );
268
+
269
+ /* fallback to old behaviour */
270
+ client -> flags &= ~I2C_CLIENT_PEC ;
271
+ chip -> is_present = true;
272
+
273
+ return ret ;
274
+ }
275
+
276
+ version = (ret & SPEC_INFO_VERSION_MASK ) >> SPEC_INFO_VERSION_SHIFT ;
277
+
278
+ if (version == SBS_VERSION_1_1_WITH_PEC )
279
+ client -> flags |= I2C_CLIENT_PEC ;
280
+ else
281
+ client -> flags &= ~I2C_CLIENT_PEC ;
282
+
283
+ dev_dbg (& client -> dev , "PEC: %s\n" , (client -> flags & I2C_CLIENT_PEC ) ?
284
+ "enabled" : "disabled" );
285
+
235
286
if (!chip -> is_present && is_present && !chip -> charger_broadcasts )
236
287
sbs_disable_charger_broadcasts (chip );
237
288
@@ -273,7 +324,8 @@ static int sbs_read_string_data_fallback(struct i2c_client *client, u8 address,
273
324
retries_length = chip -> i2c_retry_count ;
274
325
retries_block = chip -> i2c_retry_count ;
275
326
276
- dev_warn_once (& client -> dev , "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n" );
327
+ dev_warn_once (& client -> dev , "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n"
328
+ "Fallback method does not support PEC.\n" );
277
329
278
330
/* Adapter needs to support these two functions */
279
331
if (!i2c_check_functionality (client -> adapter ,
@@ -336,8 +388,14 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address, char *val
336
388
int retries = chip -> i2c_retry_count ;
337
389
int ret = 0 ;
338
390
339
- if (!i2c_check_functionality (client -> adapter , I2C_FUNC_SMBUS_READ_BLOCK_DATA ))
340
- return sbs_read_string_data_fallback (client , address , values );
391
+ if (!i2c_check_functionality (client -> adapter , I2C_FUNC_SMBUS_READ_BLOCK_DATA )) {
392
+ bool pec = client -> flags & I2C_CLIENT_PEC ;
393
+ client -> flags &= ~I2C_CLIENT_PEC ;
394
+ ret = sbs_read_string_data_fallback (client , address , values );
395
+ if (pec )
396
+ client -> flags |= I2C_CLIENT_PEC ;
397
+ return ret ;
398
+ }
341
399
342
400
while (retries > 0 ) {
343
401
ret = i2c_smbus_read_block_data (client , address , values );
0 commit comments