diff options
author | Falong Li | 2020-01-20 00:17:04 -0600 |
---|---|---|
committer | Falong Li | 2020-01-20 00:17:04 -0600 |
commit | a7b3ff61409623a308c0d1acb1d8da98b1356512 (patch) | |
tree | 895ab2e922fe0562d2b402127611cbb130434452 | |
parent | 4fa386e339f62dff273bb2ba24c7265486d634ae (diff) | |
download | bms-kernel-4-4-a7b3ff61409623a308c0d1acb1d8da98b1356512.tar.gz bms-kernel-4-4-a7b3ff61409623a308c0d1acb1d8da98b1356512.tar.xz bms-kernel-4-4-a7b3ff61409623a308c0d1acb1d8da98b1356512.zip |
add bq27426 driver
-rw-r--r-- | drivers/power/Kconfig | 1 | ||||
-rw-r--r-- | drivers/power/Makefile | 5 | ||||
-rw-r--r-- | drivers/power/bq27426/Kconfig | 6 | ||||
-rw-r--r-- | drivers/power/bq27426/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/bq27426/bq27426_fg.c | 2005 | ||||
-rw-r--r-- | drivers/power/bq27426/bq27426_gmfs_coslight.h | 945 | ||||
-rw-r--r-- | drivers/power/bq27426/bqfs_cmd_type.h | 42 |
7 files changed, 3003 insertions, 2 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 59881a83ac8b..987e6176f77a 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -523,6 +523,7 @@ source "drivers/power/bq28z610/Kconfig" | |||
523 | source "drivers/power/bq34z100/Kconfig" | 523 | source "drivers/power/bq34z100/Kconfig" |
524 | source "drivers/power/bq2560x/Kconfig" | 524 | source "drivers/power/bq2560x/Kconfig" |
525 | source "drivers/power/bq24725a/Kconfig" | 525 | source "drivers/power/bq24725a/Kconfig" |
526 | source "drivers/power/bq27426/Kconfig" | ||
526 | 527 | ||
527 | endif # POWER_SUPPLY | 528 | endif # POWER_SUPPLY |
528 | 529 | ||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index d9023c9e16de..3b3ad1876ed1 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -74,7 +74,7 @@ obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o | |||
74 | obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o | 74 | obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o |
75 | obj-y += bq25600-slave/ | 75 | obj-y += bq25600-slave/ |
76 | obj-y += bq25606-slave/ | 76 | obj-y += bq25606-slave/ |
77 | obj-y += bq25910-slave/ | 77 | #obj-y += bq25910-slave/ |
78 | obj-y += bq27z860/ | 78 | obj-y += bq27z860/ |
79 | obj-y += bq27532/ | 79 | obj-y += bq27532/ |
80 | obj-y += bq27z561/ | 80 | obj-y += bq27z561/ |
@@ -85,6 +85,7 @@ obj-y += bq40z50/ | |||
85 | #obj-y += bq2429x/ | 85 | #obj-y += bq2429x/ |
86 | obj-y += bq28z610/ | 86 | obj-y += bq28z610/ |
87 | obj-y += bq34z100/ | 87 | obj-y += bq34z100/ |
88 | obj-y += bq2560x/ | 88 | #obj-y += bq2560x/ |
89 | obj-y += bq24725a/ | 89 | obj-y += bq24725a/ |
90 | obj-y += bq27426/ | ||
90 | 91 | ||
diff --git a/drivers/power/bq27426/Kconfig b/drivers/power/bq27426/Kconfig new file mode 100644 index 000000000000..538c1382e373 --- /dev/null +++ b/drivers/power/bq27426/Kconfig | |||
@@ -0,0 +1,6 @@ | |||
1 | config FUEL_GAUGE_BQ27426 | ||
2 | tristate "TI bq27426 battery gauge driver" | ||
3 | depends on I2C | ||
4 | default y | ||
5 | help | ||
6 | Say Y to enable support for TI bq27426 fuel gauge driver | ||
diff --git a/drivers/power/bq27426/Makefile b/drivers/power/bq27426/Makefile new file mode 100644 index 000000000000..247bba2694f3 --- /dev/null +++ b/drivers/power/bq27426/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_FUEL_GAUGE_BQ27426) += bq27426_fg.o | |||
diff --git a/drivers/power/bq27426/bq27426_fg.c b/drivers/power/bq27426/bq27426_fg.c new file mode 100644 index 000000000000..ec7b8555d01b --- /dev/null +++ b/drivers/power/bq27426/bq27426_fg.c | |||
@@ -0,0 +1,2005 @@ | |||
1 | /* | ||
2 | * bqGauge battery driver | ||
3 | * | ||
4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> | ||
5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> | ||
6 | * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> | ||
7 | * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com> | ||
8 | * | ||
9 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. | ||
10 | * | ||
11 | * This package is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
17 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * Datasheets: | ||
23 | */ | ||
24 | #define pr_fmt(fmt) "bq27426- %s: " fmt, __func__ | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/param.h> | ||
27 | #include <linux/jiffies.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/power_supply.h> | ||
32 | #include <linux/idr.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/acpi.h> | ||
36 | #include <asm/unaligned.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | #include <linux/gpio/consumer.h> | ||
40 | #include <linux/debugfs.h> | ||
41 | #include <linux/alarmtimer.h> | ||
42 | #include "bqfs_cmd_type.h" | ||
43 | //#include "bq27426_gmfs.h" | ||
44 | #include "bq27426_gmfs_coslight.h" | ||
45 | |||
46 | #if 1 | ||
47 | #undef pr_debug | ||
48 | #define pr_debug pr_err | ||
49 | #undef pr_info | ||
50 | #define pr_info pr_err | ||
51 | #undef dev_dbg | ||
52 | #define dev_dbg dev_err | ||
53 | #else | ||
54 | #undef pr_info | ||
55 | #define pr_info pr_debug | ||
56 | #endif | ||
57 | |||
58 | #define MONITOR_ALARM_CHECK_NS 5000000000 | ||
59 | #define INVALID_REG_ADDR 0xFF | ||
60 | #define BQFS_UPDATE_KEY 0x8F91 | ||
61 | |||
62 | |||
63 | #define FG_FLAGS_OT BIT(15) | ||
64 | #define FG_FLAGS_UT BIT(14) | ||
65 | #define FG_FLAGS_FC BIT(9) | ||
66 | #define FG_FLAGS_CHG BIT(8) | ||
67 | #define FG_FLAGS_OCVTAKEN BIT(7) | ||
68 | #define FG_FLAGS_ITPOR BIT(5) | ||
69 | #define FG_FLAGS_CFGUPMODE BIT(4) | ||
70 | #define FG_FLAGS_BAT_DET BIT(3) | ||
71 | #define FG_FLAGS_SOC1 BIT(2) | ||
72 | #define FG_FLAGS_SOCF BIT(1) | ||
73 | #define FG_FLAGS_DSG BIT(0) | ||
74 | |||
75 | |||
76 | enum bq_fg_reg_idx { | ||
77 | BQ_FG_REG_CTRL = 0, | ||
78 | BQ_FG_REG_TEMP, /* Battery Temperature */ | ||
79 | BQ_FG_REG_VOLT, /* Battery Voltage */ | ||
80 | BQ_FG_REG_AI, /* Average Current */ | ||
81 | BQ_FG_REG_FLAGS, /* Flags */ | ||
82 | BQ_FG_REG_TTE, /* Time to Empty */ | ||
83 | BQ_FG_REG_TTF, /* Time to Full */ | ||
84 | BQ_FG_REG_FCC, /* Full Charge Capacity */ | ||
85 | BQ_FG_REG_RM, /* Remaining Capacity */ | ||
86 | BQ_FG_REG_CC, /* Cycle Count */ | ||
87 | BQ_FG_REG_SOC, /* Relative State of Charge */ | ||
88 | BQ_FG_REG_SOH, /* State of Health */ | ||
89 | BQ_FG_REG_DC, /* Design Capacity */ | ||
90 | |||
91 | NUM_REGS, | ||
92 | }; | ||
93 | |||
94 | enum bq_fg_subcmd { | ||
95 | FG_SUBCMD_CTRL_STATUS = 0x0000, | ||
96 | FG_SUBCMD_PART_NUM = 0x0001, | ||
97 | FG_SUBCMD_FW_VER = 0x0002, | ||
98 | FG_SUBCMD_DM_CODE = 0x0004, | ||
99 | FG_SUBCMD_CHEM_ID = 0x0008, | ||
100 | FG_SUBCMD_BAT_INSERT = 0x000C, | ||
101 | FG_SUBCMD_BAT_REMOVE = 0x000D, | ||
102 | FG_SUBCMD_SET_CFGUPDATE = 0x0013, | ||
103 | FG_SUBCMD_SEAL = 0x0020, | ||
104 | FG_SUBCMD_PULSE_SOC_INT = 0x0023, | ||
105 | FG_SUBCMD_CHEM_A = 0x0030, | ||
106 | FG_SUBCMD_CHEM_B = 0x0031, | ||
107 | FG_SUBCMD_CHEM_C = 0x0032, | ||
108 | FG_SUBCMD_SOFT_RESET = 0x0042, | ||
109 | FG_SUBCMD_EXIT_CFGMODE = 0x0043, | ||
110 | }; | ||
111 | |||
112 | |||
113 | enum { | ||
114 | SEAL_STATE_FA, | ||
115 | SEAL_STATE_UNSEALED, | ||
116 | SEAL_STATE_SEALED, | ||
117 | }; | ||
118 | |||
119 | |||
120 | enum bq_fg_device { | ||
121 | BQ27X00, | ||
122 | BQ27426, | ||
123 | }; | ||
124 | |||
125 | enum { | ||
126 | UPDATE_REASON_FG_RESET = 1, | ||
127 | UPDATE_REASON_NEW_VERSION, | ||
128 | UPDATE_REASON_FORCED, | ||
129 | }; | ||
130 | |||
131 | struct fg_batt_profile { | ||
132 | const bqfs_cmd_t * bqfs_image; | ||
133 | u32 array_size; | ||
134 | u8 version; | ||
135 | }; | ||
136 | |||
137 | static const struct fg_batt_profile bqfs_image[] = { | ||
138 | { bqfs_coslight, ARRAY_SIZE(bqfs_coslight), 1 },//100 | ||
139 | /* Add more entries if multiple batteries are supported */ | ||
140 | |||
141 | }; | ||
142 | |||
143 | static const unsigned char *device2str[] = { | ||
144 | "bq27x00", | ||
145 | "bq27426", | ||
146 | }; | ||
147 | |||
148 | static const unsigned char *update_reason_str[] = { | ||
149 | "Reset", | ||
150 | "New Version", | ||
151 | "Force" | ||
152 | }; | ||
153 | |||
154 | static u8 bq27426_regs[NUM_REGS] = { | ||
155 | 0x00, /* CONTROL */ | ||
156 | 0x02, /* TEMP */ | ||
157 | 0x04, /* VOLT */ | ||
158 | 0x10, /* AVG CURRENT */ | ||
159 | 0x06, /* FLAGS */ | ||
160 | 0xFF, /* Time to empty */ | ||
161 | 0xFF, /* Time to full */ | ||
162 | 0x0E, /* Full charge capacity */ | ||
163 | 0x0C, /* Remaining Capacity */ | ||
164 | 0xFF, /* CycleCount */ | ||
165 | 0x1C, /* State of Charge */ | ||
166 | 0x20, /* State of Health */ | ||
167 | 0xFF, /* Design Capacity */ | ||
168 | }; | ||
169 | |||
170 | struct bq_fg_chip; | ||
171 | |||
172 | struct bq_fg_chip { | ||
173 | struct device *dev; | ||
174 | struct i2c_client *client; | ||
175 | |||
176 | |||
177 | struct mutex i2c_rw_lock; | ||
178 | struct mutex data_lock; | ||
179 | struct mutex update_lock; | ||
180 | struct mutex irq_complete; | ||
181 | |||
182 | bool irq_waiting; | ||
183 | bool irq_disabled; | ||
184 | bool resume_completed; | ||
185 | |||
186 | int force_update; | ||
187 | int fw_ver; | ||
188 | int df_ver; | ||
189 | |||
190 | u8 chip; | ||
191 | u8 regs[NUM_REGS]; | ||
192 | |||
193 | int batt_id; | ||
194 | |||
195 | /* status tracking */ | ||
196 | |||
197 | bool batt_present; | ||
198 | bool batt_fc; | ||
199 | bool batt_ot; | ||
200 | bool batt_ut; | ||
201 | bool batt_soc1; | ||
202 | bool batt_socf; | ||
203 | bool batt_dsg; | ||
204 | bool allow_chg; | ||
205 | bool cfg_update_mode; | ||
206 | bool itpor; | ||
207 | |||
208 | int seal_state; /* 0 - Full Access, 1 - Unsealed, 2 - Sealed */ | ||
209 | int batt_tte; | ||
210 | int batt_soc; | ||
211 | int batt_fcc; /* Full charge capacity */ | ||
212 | int batt_rm; /* Remaining capacity */ | ||
213 | int batt_dc; /* Design Capacity */ | ||
214 | int batt_volt; | ||
215 | int batt_temp; | ||
216 | int batt_curr; | ||
217 | |||
218 | int batt_cyclecnt; /* cycle count */ | ||
219 | |||
220 | |||
221 | struct work_struct update_work; | ||
222 | |||
223 | unsigned long last_update; | ||
224 | |||
225 | /* debug */ | ||
226 | int skip_reads; | ||
227 | int skip_writes; | ||
228 | |||
229 | int fake_soc; | ||
230 | int fake_temp; | ||
231 | |||
232 | struct dentry *debug_root; | ||
233 | |||
234 | struct power_supply *fg_psy; | ||
235 | struct power_supply_desc fg_psy_d; | ||
236 | }; | ||
237 | |||
238 | |||
239 | |||
240 | static int __fg_read_byte(struct i2c_client *client, u8 reg, u8 *val) | ||
241 | { | ||
242 | s32 ret; | ||
243 | |||
244 | ret = i2c_smbus_read_byte_data(client, reg); | ||
245 | if (ret < 0) { | ||
246 | pr_err("i2c read byte fail: can't read from reg 0x%02X\n", reg); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | *val = (u8)ret; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int __fg_write_byte(struct i2c_client *client, u8 reg, u8 val) | ||
256 | { | ||
257 | s32 ret; | ||
258 | |||
259 | ret = i2c_smbus_write_byte_data(client, reg, val); | ||
260 | if (ret < 0) { | ||
261 | pr_err("i2c write byte fail: can't write 0x%02X to reg 0x%02X\n", | ||
262 | val, reg); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | |||
270 | static int __fg_read_word(struct i2c_client *client, u8 reg, u16 *val) | ||
271 | { | ||
272 | s32 ret; | ||
273 | |||
274 | ret = i2c_smbus_read_word_data(client, reg); | ||
275 | if (ret < 0) { | ||
276 | pr_err("i2c read word fail: can't read from reg 0x%02X\n", reg); | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | *val = (u16)ret; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | |||
286 | static int __fg_write_word(struct i2c_client *client, u8 reg, u16 val) | ||
287 | { | ||
288 | s32 ret; | ||
289 | |||
290 | ret = i2c_smbus_write_word_data(client, reg, val); | ||
291 | if (ret < 0) { | ||
292 | pr_err("i2c write word fail: can't write 0x%02X to reg 0x%02X\n", | ||
293 | val, reg); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int __fg_read_block(struct i2c_client *client, u8 reg, u8 *buf, u8 len) | ||
301 | { | ||
302 | int ret; | ||
303 | struct i2c_msg msg[2]; | ||
304 | int i; | ||
305 | |||
306 | msg[0].addr = client->addr; | ||
307 | msg[0].flags = 0; | ||
308 | msg[0].buf = ® | ||
309 | msg[0].len = 1; | ||
310 | |||
311 | msg[1].addr = client->addr; | ||
312 | msg[1].flags = I2C_M_RD; | ||
313 | msg[1].buf = buf; | ||
314 | msg[1].len = len; | ||
315 | |||
316 | for (i = 0; i < 3; i++) { | ||
317 | ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); | ||
318 | if (ret >= 0) | ||
319 | return ret; | ||
320 | else | ||
321 | msleep(5); | ||
322 | } | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | static int __fg_write_block(struct i2c_client *client, u8 reg, u8 *buf, u8 len) | ||
327 | { | ||
328 | int ret; | ||
329 | struct i2c_msg msg; | ||
330 | u8 data[64]; | ||
331 | int i = 0; | ||
332 | |||
333 | data[0] = reg; | ||
334 | memcpy(&data[1], buf, len); | ||
335 | |||
336 | msg.addr = client->addr; | ||
337 | msg.flags = 0; | ||
338 | msg.buf = data; | ||
339 | msg.len = len + 1; | ||
340 | |||
341 | for (i = 0; i < 3; i++) { | ||
342 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
343 | if (ret >= 0) | ||
344 | return ret; | ||
345 | else | ||
346 | msleep(5); | ||
347 | } | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | |||
352 | static int fg_read_byte(struct bq_fg_chip *bq, u8 reg, u8 *val) | ||
353 | { | ||
354 | int ret; | ||
355 | |||
356 | if (bq->skip_reads) { | ||
357 | *val = 0; | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | mutex_lock(&bq->i2c_rw_lock); | ||
362 | ret = __fg_read_byte(bq->client, reg, val); | ||
363 | mutex_unlock(&bq->i2c_rw_lock); | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static int fg_write_byte(struct bq_fg_chip *bq, u8 reg, u8 val) | ||
369 | { | ||
370 | int ret; | ||
371 | |||
372 | if (bq->skip_writes) | ||
373 | return 0; | ||
374 | |||
375 | mutex_lock(&bq->i2c_rw_lock); | ||
376 | ret = __fg_write_byte(bq->client, reg, val); | ||
377 | mutex_unlock(&bq->i2c_rw_lock); | ||
378 | |||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int fg_read_word(struct bq_fg_chip *bq, u8 reg, u16 *val) | ||
383 | { | ||
384 | int ret; | ||
385 | |||
386 | if (bq->skip_reads) { | ||
387 | *val = 0; | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | mutex_lock(&bq->i2c_rw_lock); | ||
392 | ret = __fg_read_word(bq->client, reg, val); | ||
393 | mutex_unlock(&bq->i2c_rw_lock); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int fg_write_word(struct bq_fg_chip *bq, u8 reg, u16 val) | ||
399 | { | ||
400 | int ret; | ||
401 | |||
402 | if (bq->skip_writes) | ||
403 | return 0; | ||
404 | |||
405 | mutex_lock(&bq->i2c_rw_lock); | ||
406 | ret = __fg_write_word(bq->client, reg, val); | ||
407 | mutex_unlock(&bq->i2c_rw_lock); | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static int fg_read_block(struct bq_fg_chip *bq, u8 reg, u8 *buf, u8 len) | ||
413 | { | ||
414 | int ret; | ||
415 | |||
416 | if (bq->skip_reads) | ||
417 | return 0; | ||
418 | mutex_lock(&bq->i2c_rw_lock); | ||
419 | ret = __fg_read_block(bq->client, reg, buf, len); | ||
420 | mutex_unlock(&bq->i2c_rw_lock); | ||
421 | |||
422 | return ret; | ||
423 | |||
424 | } | ||
425 | |||
426 | static int fg_write_block(struct bq_fg_chip *bq, u8 reg, u8 *data, u8 len) | ||
427 | { | ||
428 | int ret; | ||
429 | |||
430 | if (bq->skip_writes) | ||
431 | return 0; | ||
432 | |||
433 | mutex_lock(&bq->i2c_rw_lock); | ||
434 | ret = __fg_write_block(bq->client, reg, data, len); | ||
435 | mutex_unlock(&bq->i2c_rw_lock); | ||
436 | |||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | #define CTRL_REG 0x00 | ||
441 | |||
442 | #define FG_DFT_UNSEAL_KEY1 0x80008000 | ||
443 | #define FG_DFT_UNSEAL_KEY2 0x36724614 | ||
444 | |||
445 | #define FG_DFT_UNSEAL_FA_KEY 0xFFFFFFFF | ||
446 | |||
447 | static u8 checksum(u8 *data, u8 len) | ||
448 | { | ||
449 | u8 i; | ||
450 | u16 sum = 0; | ||
451 | |||
452 | for (i = 0; i < len; i++) | ||
453 | sum += data[i]; | ||
454 | |||
455 | sum &= 0xFF; | ||
456 | |||
457 | return (0xFF - sum); | ||
458 | } | ||
459 | |||
460 | #if 0 | ||
461 | static void fg_print_buf(const char *msg, u8 *buf, u8 len) | ||
462 | { | ||
463 | int i; | ||
464 | int idx = 0; | ||
465 | int num; | ||
466 | u8 strbuf[128]; | ||
467 | |||
468 | pr_err("%s buf: ", msg); | ||
469 | for(i = 0; i < len; i++) { | ||
470 | num = sprintf(&strbuf[idx], "%02X ", buf[i]); | ||
471 | idx += num; | ||
472 | } | ||
473 | pr_err("%s\n", strbuf); | ||
474 | } | ||
475 | #else | ||
476 | static void fg_print_buf(const char *msg, u8 *buf, u8 len) | ||
477 | {} | ||
478 | #endif | ||
479 | |||
480 | |||
481 | #define TIMEOUT_INIT_COMPLETED 100 | ||
482 | static int fg_check_init_completed(struct bq_fg_chip *bq) | ||
483 | { | ||
484 | int ret; | ||
485 | int i = 0; | ||
486 | u16 status; | ||
487 | |||
488 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], FG_SUBCMD_CTRL_STATUS); | ||
489 | if (ret < 0) { | ||
490 | pr_err("Failed to write control status cmd, ret = %d\n", ret); | ||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | msleep(5); | ||
495 | |||
496 | while (i++ < TIMEOUT_INIT_COMPLETED) { | ||
497 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_CTRL], &status); | ||
498 | if (ret >= 0 && (status & 0x0080)) | ||
499 | return 0; | ||
500 | msleep(100); | ||
501 | } | ||
502 | pr_err("wait for FG INITCOMP timeout\n"); | ||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static int fg_get_seal_state(struct bq_fg_chip *bq) | ||
507 | { | ||
508 | int ret; | ||
509 | u16 status; | ||
510 | |||
511 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], FG_SUBCMD_CTRL_STATUS); | ||
512 | if (ret < 0) { | ||
513 | pr_err("Failed to write control status cmd, ret = %d\n", ret); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | msleep(5); | ||
518 | |||
519 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_CTRL], &status); | ||
520 | if (ret < 0) { | ||
521 | pr_err("Failed to read control status, ret = %d\n", ret); | ||
522 | return ret; | ||
523 | } | ||
524 | pr_err("control_status = 0x%04X", status); | ||
525 | if (status & 0x2000) | ||
526 | bq->seal_state = SEAL_STATE_SEALED; | ||
527 | else | ||
528 | bq->seal_state = SEAL_STATE_UNSEALED; | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int fg_unseal(struct bq_fg_chip *bq, u32 key) | ||
534 | { | ||
535 | int ret; | ||
536 | int retry = 0; | ||
537 | |||
538 | ret = fg_get_seal_state(bq); | ||
539 | if (ret) | ||
540 | return ret; | ||
541 | if (bq->seal_state == SEAL_STATE_UNSEALED) | ||
542 | return 0; | ||
543 | |||
544 | pr_info(":key - 0x%08X\n", key); | ||
545 | |||
546 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], key & 0xFFFF); | ||
547 | if (ret < 0) { | ||
548 | pr_err("unable to write unseal key step 1, ret = %d\n", ret); | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | msleep(5); | ||
553 | |||
554 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], (key >> 16) & 0xFFFF); | ||
555 | if (ret < 0) { | ||
556 | pr_err("unable to write unseal key step 2, ret = %d\n", ret); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | msleep(5); | ||
561 | |||
562 | while (retry++ < 1000) { | ||
563 | fg_get_seal_state(bq); | ||
564 | if (bq->seal_state == SEAL_STATE_UNSEALED) { | ||
565 | return 0; | ||
566 | } | ||
567 | msleep(100); | ||
568 | } | ||
569 | |||
570 | return -1; | ||
571 | } | ||
572 | |||
573 | #if 0 | ||
574 | static int fg_unseal_fa(struct bq_fg_chip *bq, u32 key) | ||
575 | { | ||
576 | int ret; | ||
577 | int retry = 0; | ||
578 | |||
579 | pr_info(":key - %d\n", key); | ||
580 | |||
581 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], key & 0xFFFF); | ||
582 | if (ret < 0) { | ||
583 | pr_err("unable to write unseal key step 1, ret = %d\n", ret); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | msleep(5); | ||
588 | |||
589 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], (key >> 16) & 0xFFFF); | ||
590 | if (ret < 0) { | ||
591 | pr_err("unable to write unseal key step 2, ret = %d\n", ret); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | msleep(5); | ||
596 | |||
597 | while (retry++ < 1000) { | ||
598 | fg_get_seal_state(bq); | ||
599 | if (bq->seal_state == SEAL_STATE_FA) { | ||
600 | return 0; | ||
601 | } | ||
602 | msleep(10); | ||
603 | } | ||
604 | |||
605 | return -1; | ||
606 | } | ||
607 | EXPORT_SYMBOL_GPL(fg_unseal_fa); | ||
608 | #endif | ||
609 | |||
610 | static int fg_seal(struct bq_fg_chip *bq) | ||
611 | { | ||
612 | int ret; | ||
613 | int retry = 0; | ||
614 | |||
615 | fg_get_seal_state(bq); | ||
616 | |||
617 | if (bq->seal_state == SEAL_STATE_SEALED) | ||
618 | return 0; | ||
619 | msleep(5); | ||
620 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], FG_SUBCMD_SEAL); | ||
621 | |||
622 | if (ret < 0) { | ||
623 | pr_err("Failed to send seal command\n"); | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | while (retry++ < 1000) { | ||
628 | fg_get_seal_state(bq); | ||
629 | if (bq->seal_state == SEAL_STATE_SEALED) | ||
630 | return 0; | ||
631 | msleep(200); | ||
632 | } | ||
633 | |||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | |||
638 | |||
639 | static int fg_check_cfg_update_mode(struct bq_fg_chip *bq) | ||
640 | { | ||
641 | int ret; | ||
642 | u16 flags; | ||
643 | |||
644 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_FLAGS], &flags); | ||
645 | if (ret < 0) { | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | bq->cfg_update_mode = !!(flags & FG_FLAGS_CFGUPMODE); | ||
650 | |||
651 | return 0; | ||
652 | |||
653 | } | ||
654 | |||
655 | static int fg_check_itpor(struct bq_fg_chip *bq) | ||
656 | { | ||
657 | int ret; | ||
658 | u16 flags; | ||
659 | |||
660 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_FLAGS], &flags); | ||
661 | if (ret < 0) { | ||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | bq->itpor = !!(flags & FG_FLAGS_ITPOR); | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | |||
671 | static int fg_read_dm_version(struct bq_fg_chip* bq, u8 *ver) | ||
672 | { | ||
673 | int ret; | ||
674 | u16 dm_code = 0; | ||
675 | |||
676 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], FG_SUBCMD_DM_CODE); | ||
677 | if (ret < 0) { | ||
678 | pr_err("Failed to write control status cmd, ret = %d\n", ret); | ||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | msleep(5); | ||
683 | |||
684 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_CTRL], &dm_code); | ||
685 | if (!ret) | ||
686 | *ver = dm_code & 0xFF; | ||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | #define CFG_UPDATE_POLLING_RETRY_LIMIT 50 | ||
691 | static int fg_dm_pre_access(struct bq_fg_chip *bq) | ||
692 | { | ||
693 | int ret; | ||
694 | int i = 0; | ||
695 | |||
696 | ret = fg_check_init_completed(bq); | ||
697 | if (ret < 0) | ||
698 | return ret; | ||
699 | ret = fg_unseal(bq, FG_DFT_UNSEAL_KEY1); | ||
700 | if (ret < 0) | ||
701 | return ret; | ||
702 | |||
703 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], FG_SUBCMD_SET_CFGUPDATE); | ||
704 | if (ret < 0) | ||
705 | return ret; | ||
706 | |||
707 | msleep(10); | ||
708 | |||
709 | while(i++ < CFG_UPDATE_POLLING_RETRY_LIMIT) { | ||
710 | ret = fg_check_cfg_update_mode(bq); | ||
711 | if (!ret && bq->cfg_update_mode) | ||
712 | return 0; | ||
713 | msleep(400); | ||
714 | } | ||
715 | |||
716 | pr_err("Failed to enter cfgupdate mode\n"); | ||
717 | |||
718 | return -1; | ||
719 | } | ||
720 | EXPORT_SYMBOL_GPL(fg_dm_pre_access); | ||
721 | |||
722 | static int fg_dm_post_access(struct bq_fg_chip *bq) | ||
723 | { | ||
724 | int ret; | ||
725 | int i = 0; | ||
726 | |||
727 | |||
728 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], | ||
729 | FG_SUBCMD_SOFT_RESET); | ||
730 | if (ret < 0) | ||
731 | return ret; | ||
732 | |||
733 | msleep(100); | ||
734 | |||
735 | while(i++ < CFG_UPDATE_POLLING_RETRY_LIMIT) { | ||
736 | ret = fg_check_cfg_update_mode(bq); | ||
737 | if (!ret && !bq->cfg_update_mode) | ||
738 | break; | ||
739 | msleep(100); | ||
740 | } | ||
741 | |||
742 | if (i == CFG_UPDATE_POLLING_RETRY_LIMIT) { | ||
743 | pr_err("Failed to exit cfgupdate mode\n"); | ||
744 | return -1; | ||
745 | } else { | ||
746 | return fg_seal(bq); | ||
747 | } | ||
748 | } | ||
749 | EXPORT_SYMBOL_GPL(fg_dm_post_access); | ||
750 | |||
751 | static int fg_dm_enter_cfg_mode(struct bq_fg_chip *bq) | ||
752 | { | ||
753 | return fg_dm_pre_access(bq); | ||
754 | } | ||
755 | |||
756 | static int fg_dm_exit_cfg_mode(struct bq_fg_chip *bq) | ||
757 | { | ||
758 | int ret; | ||
759 | int i = 0; | ||
760 | |||
761 | |||
762 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], | ||
763 | FG_SUBCMD_EXIT_CFGMODE); | ||
764 | if (ret < 0) | ||
765 | return ret; | ||
766 | |||
767 | msleep(100); | ||
768 | |||
769 | while(i++ < CFG_UPDATE_POLLING_RETRY_LIMIT) { | ||
770 | ret = fg_check_cfg_update_mode(bq); | ||
771 | if (!ret && !bq->cfg_update_mode) | ||
772 | break; | ||
773 | msleep(100); | ||
774 | } | ||
775 | |||
776 | if (i == CFG_UPDATE_POLLING_RETRY_LIMIT) { | ||
777 | pr_err("Failed to exit cfgupdate mode\n"); | ||
778 | return -1; | ||
779 | } else { | ||
780 | return fg_seal(bq); | ||
781 | } | ||
782 | } | ||
783 | EXPORT_SYMBOL_GPL(fg_dm_exit_cfg_mode); | ||
784 | |||
785 | |||
786 | |||
787 | #define DM_ACCESS_BLOCK_DATA_CHKSUM 0x60 | ||
788 | #define DM_ACCESS_BLOCK_DATA_CTRL 0x61 | ||
789 | #define DM_ACCESS_BLOCK_DATA_CLASS 0x3E | ||
790 | #define DM_ACCESS_DATA_BLOCK 0x3F | ||
791 | #define DM_ACCESS_BLOCK_DATA 0x40 | ||
792 | |||
793 | |||
794 | static int fg_dm_read_block(struct bq_fg_chip *bq, u8 classid, | ||
795 | u8 offset, u8 *buf) | ||
796 | { | ||
797 | int ret; | ||
798 | u8 cksum_calc, cksum; | ||
799 | u8 blk_offset = offset >> 5; | ||
800 | |||
801 | pr_info("subclass:%d, offset:%d\n", classid, offset); | ||
802 | |||
803 | ret = fg_write_byte(bq, DM_ACCESS_BLOCK_DATA_CTRL, 0); | ||
804 | if (ret < 0) | ||
805 | return ret; | ||
806 | msleep(5); | ||
807 | ret = fg_write_byte(bq, DM_ACCESS_BLOCK_DATA_CLASS, classid); | ||
808 | if (ret < 0) | ||
809 | return ret; | ||
810 | msleep(5); | ||
811 | ret = fg_write_byte(bq, DM_ACCESS_DATA_BLOCK, blk_offset); | ||
812 | if (ret < 0) | ||
813 | return ret; | ||
814 | msleep(5); | ||
815 | ret = fg_read_block(bq, DM_ACCESS_BLOCK_DATA, buf, 32); | ||
816 | if (ret < 0) | ||
817 | return ret; | ||
818 | |||
819 | fg_print_buf(__func__, buf, 32); | ||
820 | |||
821 | msleep(5); | ||
822 | cksum_calc = checksum(buf, 32); | ||
823 | ret = fg_read_byte(bq, DM_ACCESS_BLOCK_DATA_CHKSUM, &cksum); | ||
824 | if (!ret && cksum_calc == cksum) | ||
825 | return 0; | ||
826 | else | ||
827 | return 1; | ||
828 | } | ||
829 | EXPORT_SYMBOL_GPL(fg_dm_read_block); | ||
830 | |||
831 | static int fg_dm_write_block(struct bq_fg_chip *bq, u8 classid, | ||
832 | u8 offset, u8 *data) | ||
833 | { | ||
834 | int ret; | ||
835 | u8 cksum; | ||
836 | u8 buf[64]; | ||
837 | u8 blk_offset = offset >> 5; | ||
838 | |||
839 | pr_info("subclass:%d, offset:%d\n", classid, offset); | ||
840 | |||
841 | ret = fg_write_byte(bq, DM_ACCESS_BLOCK_DATA_CTRL, 0); | ||
842 | if (ret < 0) | ||
843 | return ret; | ||
844 | msleep(5); | ||
845 | ret = fg_write_byte(bq, DM_ACCESS_BLOCK_DATA_CLASS, classid); | ||
846 | if (ret < 0) | ||
847 | return ret; | ||
848 | msleep(5); | ||
849 | ret = fg_write_byte(bq, DM_ACCESS_DATA_BLOCK, blk_offset); | ||
850 | if (ret < 0) | ||
851 | return ret; | ||
852 | ret = fg_write_block(bq, DM_ACCESS_BLOCK_DATA, data, 32); | ||
853 | msleep(5); | ||
854 | |||
855 | fg_print_buf(__func__, data, 32); | ||
856 | |||
857 | cksum = checksum(data, 32); | ||
858 | ret = fg_write_byte(bq, DM_ACCESS_BLOCK_DATA_CHKSUM, cksum); | ||
859 | if (ret < 0) | ||
860 | return ret; | ||
861 | msleep(5); | ||
862 | |||
863 | ret = fg_write_byte(bq, DM_ACCESS_DATA_BLOCK, blk_offset); | ||
864 | if (ret < 0) | ||
865 | return ret; | ||
866 | msleep(5); | ||
867 | ret = fg_read_block(bq, DM_ACCESS_BLOCK_DATA, buf, 32); | ||
868 | if (ret < 0) | ||
869 | return ret; | ||
870 | if (memcpy(data, buf, 32)) { | ||
871 | pr_err("Error updating subclass %d offset %d\n", | ||
872 | classid, offset); | ||
873 | return 1; | ||
874 | } | ||
875 | return 0; | ||
876 | } | ||
877 | EXPORT_SYMBOL_GPL(fg_dm_write_block); | ||
878 | |||
879 | static int fg_read_fw_version(struct bq_fg_chip *bq) | ||
880 | { | ||
881 | |||
882 | int ret; | ||
883 | u16 version; | ||
884 | |||
885 | ret = fg_write_word(bq, bq->regs[BQ_FG_REG_CTRL], 0x0002); | ||
886 | |||
887 | if (ret < 0) { | ||
888 | pr_err("Failed to send firmware version subcommand:%d\n", ret); | ||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | mdelay(2); | ||
893 | |||
894 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_CTRL], &version); | ||
895 | if (ret < 0) { | ||
896 | pr_err("Failed to read firmware version:%d\n", ret); | ||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | return version; | ||
901 | } | ||
902 | |||
903 | |||
904 | static int fg_read_status(struct bq_fg_chip *bq) | ||
905 | { | ||
906 | int ret; | ||
907 | u16 flags; | ||
908 | |||
909 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_FLAGS], &flags); | ||
910 | if (ret < 0) { | ||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | mutex_lock(&bq->data_lock); | ||
915 | bq->batt_present = !!(flags & FG_FLAGS_BAT_DET); | ||
916 | bq->batt_ot = !!(flags & FG_FLAGS_OT); | ||
917 | bq->batt_ut = !!(flags & FG_FLAGS_UT); | ||
918 | bq->batt_fc = !!(flags & FG_FLAGS_FC); | ||
919 | bq->batt_soc1 = !!(flags & FG_FLAGS_SOC1); | ||
920 | bq->batt_socf = !!(flags & FG_FLAGS_SOCF); | ||
921 | bq->batt_dsg = !!(flags & FG_FLAGS_DSG); | ||
922 | bq->allow_chg = !!(flags & FG_FLAGS_CHG); | ||
923 | mutex_unlock(&bq->data_lock); | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | |||
929 | static int fg_read_rsoc(struct bq_fg_chip *bq) | ||
930 | { | ||
931 | int ret; | ||
932 | u16 soc = 0; | ||
933 | |||
934 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_SOC], &soc); | ||
935 | if (ret < 0) { | ||
936 | pr_err("could not read RSOC, ret = %d\n", ret); | ||
937 | return ret; | ||
938 | } | ||
939 | |||
940 | return soc; | ||
941 | |||
942 | } | ||
943 | |||
944 | static int fg_read_temperature(struct bq_fg_chip *bq) | ||
945 | { | ||
946 | int ret; | ||
947 | u16 temp = 0; | ||
948 | |||
949 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_TEMP], &temp); | ||
950 | if (ret < 0) { | ||
951 | pr_err("could not read temperature, ret = %d\n", ret); | ||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | return temp; | ||
956 | |||
957 | } | ||
958 | |||
959 | static int fg_read_volt(struct bq_fg_chip *bq) | ||
960 | { | ||
961 | int ret; | ||
962 | u16 volt = 0; | ||
963 | |||
964 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_VOLT], &volt); | ||
965 | if (ret < 0) { | ||
966 | pr_err("could not read voltage, ret = %d\n", ret); | ||
967 | return ret; | ||
968 | } | ||
969 | |||
970 | return volt; | ||
971 | |||
972 | } | ||
973 | |||
974 | static int fg_read_current(struct bq_fg_chip *bq, int *curr) | ||
975 | { | ||
976 | int ret; | ||
977 | u16 avg_curr = 0; | ||
978 | |||
979 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_AI], &avg_curr); | ||
980 | if (ret < 0) { | ||
981 | pr_err("could not read current, ret = %d\n", ret); | ||
982 | return ret; | ||
983 | } | ||
984 | *curr = (int)((s16)avg_curr); | ||
985 | |||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | static int fg_read_fcc(struct bq_fg_chip *bq) | ||
990 | { | ||
991 | int ret; | ||
992 | u16 fcc; | ||
993 | |||
994 | if (bq->regs[BQ_FG_REG_FCC] == INVALID_REG_ADDR) { | ||
995 | pr_err("FCC command not supported!\n"); | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_FCC], &fcc); | ||
1000 | |||
1001 | if (ret < 0) { | ||
1002 | pr_err("could not read FCC, ret=%d\n", ret); | ||
1003 | } | ||
1004 | |||
1005 | return fcc; | ||
1006 | } | ||
1007 | |||
1008 | static int fg_read_dc(struct bq_fg_chip *bq) | ||
1009 | { | ||
1010 | |||
1011 | int ret; | ||
1012 | u16 dc; | ||
1013 | |||
1014 | if (bq->regs[BQ_FG_REG_DC] == INVALID_REG_ADDR) { | ||
1015 | pr_err("DesignCapacity command not supported!\n"); | ||
1016 | return 0; | ||
1017 | } | ||
1018 | |||
1019 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_DC], &dc); | ||
1020 | |||
1021 | if (ret < 0) { | ||
1022 | pr_err("could not read DC, ret=%d\n", ret); | ||
1023 | return ret; | ||
1024 | } | ||
1025 | |||
1026 | return dc; | ||
1027 | } | ||
1028 | |||
1029 | |||
1030 | static int fg_read_rm(struct bq_fg_chip *bq) | ||
1031 | { | ||
1032 | int ret; | ||
1033 | u16 rm; | ||
1034 | |||
1035 | if (bq->regs[BQ_FG_REG_RM] == INVALID_REG_ADDR) { | ||
1036 | pr_err("RemainingCapacity command not supported!\n"); | ||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_RM], &rm); | ||
1041 | |||
1042 | if (ret < 0) { | ||
1043 | pr_err("could not read DC, ret=%d\n", ret); | ||
1044 | return ret; | ||
1045 | } | ||
1046 | |||
1047 | return rm; | ||
1048 | |||
1049 | } | ||
1050 | |||
1051 | static int fg_read_cyclecount(struct bq_fg_chip *bq) | ||
1052 | { | ||
1053 | int ret; | ||
1054 | u16 cc; | ||
1055 | |||
1056 | if (bq->regs[BQ_FG_REG_CC] == INVALID_REG_ADDR) { | ||
1057 | pr_err("Cycle Count not supported!\n"); | ||
1058 | return -1; | ||
1059 | } | ||
1060 | |||
1061 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_CC], &cc); | ||
1062 | |||
1063 | if (ret < 0) { | ||
1064 | pr_err("could not read Cycle Count, ret=%d\n", ret); | ||
1065 | return ret; | ||
1066 | } | ||
1067 | |||
1068 | return cc; | ||
1069 | } | ||
1070 | |||
1071 | static int fg_read_tte(struct bq_fg_chip *bq) | ||
1072 | { | ||
1073 | int ret; | ||
1074 | u16 tte; | ||
1075 | |||
1076 | if (bq->regs[BQ_FG_REG_TTE] == INVALID_REG_ADDR) { | ||
1077 | pr_err("Time To Empty not supported!\n"); | ||
1078 | return -1; | ||
1079 | } | ||
1080 | |||
1081 | ret = fg_read_word(bq, bq->regs[BQ_FG_REG_TTE], &tte); | ||
1082 | |||
1083 | if (ret < 0) { | ||
1084 | pr_err("could not read Time To Empty, ret=%d\n", ret); | ||
1085 | return ret; | ||
1086 | } | ||
1087 | |||
1088 | if (ret == 0xFFFF) | ||
1089 | return -ENODATA; | ||
1090 | |||
1091 | return tte; | ||
1092 | } | ||
1093 | |||
1094 | static int fg_get_batt_status(struct bq_fg_chip *bq) | ||
1095 | { | ||
1096 | |||
1097 | fg_read_status(bq); | ||
1098 | |||
1099 | if (!bq->batt_present) | ||
1100 | return POWER_SUPPLY_STATUS_UNKNOWN; | ||
1101 | else if (bq->batt_fc) | ||
1102 | return POWER_SUPPLY_STATUS_FULL; | ||
1103 | else if (bq->batt_dsg) | ||
1104 | return POWER_SUPPLY_STATUS_DISCHARGING; | ||
1105 | else if (bq->batt_curr > 0) | ||
1106 | return POWER_SUPPLY_STATUS_CHARGING; | ||
1107 | else | ||
1108 | return POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
1109 | |||
1110 | } | ||
1111 | |||
1112 | |||
1113 | static int fg_get_batt_capacity_level(struct bq_fg_chip *bq) | ||
1114 | { | ||
1115 | if (!bq->batt_present) | ||
1116 | return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; | ||
1117 | else if (bq->batt_fc) | ||
1118 | return POWER_SUPPLY_CAPACITY_LEVEL_FULL; | ||
1119 | else if (bq->batt_soc1) | ||
1120 | return POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
1121 | else if (bq->batt_socf) | ||
1122 | return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; | ||
1123 | else | ||
1124 | return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
1125 | |||
1126 | } | ||
1127 | |||
1128 | |||
1129 | static int fg_get_batt_health(struct bq_fg_chip *bq) | ||
1130 | { | ||
1131 | if (!bq->batt_present) | ||
1132 | return POWER_SUPPLY_HEALTH_UNKNOWN; | ||
1133 | else if (bq->batt_ot) | ||
1134 | return POWER_SUPPLY_HEALTH_OVERHEAT; | ||
1135 | else if (bq->batt_ut) | ||
1136 | return POWER_SUPPLY_HEALTH_COLD; | ||
1137 | else | ||
1138 | return POWER_SUPPLY_HEALTH_GOOD; | ||
1139 | |||
1140 | } | ||
1141 | |||
1142 | static enum power_supply_property fg_props[] = { | ||
1143 | POWER_SUPPLY_PROP_STATUS, | ||
1144 | POWER_SUPPLY_PROP_PRESENT, | ||
1145 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
1146 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
1147 | POWER_SUPPLY_PROP_CAPACITY, | ||
1148 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
1149 | POWER_SUPPLY_PROP_TEMP, | ||
1150 | // POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, | ||
1151 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
1152 | // POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
1153 | // POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
1154 | POWER_SUPPLY_PROP_HEALTH, | ||
1155 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
1156 | POWER_SUPPLY_PROP_UPDATE_NOW, | ||
1157 | }; | ||
1158 | |||
1159 | static int fg_get_property(struct power_supply *psy, enum power_supply_property psp, | ||
1160 | union power_supply_propval *val) | ||
1161 | { | ||
1162 | struct bq_fg_chip *bq = power_supply_get_drvdata(psy); | ||
1163 | int ret; | ||
1164 | |||
1165 | mutex_lock(&bq->update_lock); | ||
1166 | switch (psp) { | ||
1167 | case POWER_SUPPLY_PROP_STATUS: | ||
1168 | val->intval = fg_get_batt_status(bq); | ||
1169 | break; | ||
1170 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
1171 | ret = fg_read_volt(bq); | ||
1172 | mutex_lock(&bq->data_lock); | ||
1173 | if (ret >= 0) | ||
1174 | bq->batt_volt = ret; | ||
1175 | val->intval = bq->batt_volt * 1000; | ||
1176 | mutex_unlock(&bq->data_lock); | ||
1177 | |||
1178 | break; | ||
1179 | case POWER_SUPPLY_PROP_PRESENT: | ||
1180 | val->intval = bq->batt_present; | ||
1181 | break; | ||
1182 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
1183 | mutex_lock(&bq->data_lock); | ||
1184 | fg_read_current(bq, &bq->batt_curr); | ||
1185 | val->intval = -bq->batt_curr * 1000; | ||
1186 | pr_info("bq27426 current=%d\n", val->intval); | ||
1187 | mutex_unlock(&bq->data_lock); | ||
1188 | break; | ||
1189 | |||
1190 | case POWER_SUPPLY_PROP_CAPACITY: | ||
1191 | if (bq->fake_soc >= 0) { | ||
1192 | val->intval = bq->fake_soc; | ||
1193 | break; | ||
1194 | } | ||
1195 | ret = fg_read_rsoc(bq); | ||
1196 | mutex_lock(&bq->data_lock); | ||
1197 | if (ret >= 0) | ||
1198 | bq->batt_soc = ret; | ||
1199 | val->intval = bq->batt_soc; | ||
1200 | mutex_unlock(&bq->data_lock); | ||
1201 | break; | ||
1202 | |||
1203 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | ||
1204 | val->intval = fg_get_batt_capacity_level(bq); | ||
1205 | break; | ||
1206 | |||
1207 | case POWER_SUPPLY_PROP_TEMP: | ||
1208 | if (bq->fake_temp != -EINVAL){ | ||
1209 | val->intval = bq->fake_temp; | ||
1210 | break; | ||
1211 | } | ||
1212 | ret = fg_read_temperature(bq); | ||
1213 | mutex_lock(&bq->data_lock); | ||
1214 | if (ret > 0) | ||
1215 | bq->batt_temp = ret; | ||
1216 | val->intval = bq->batt_temp - 2730; | ||
1217 | mutex_unlock(&bq->data_lock); | ||
1218 | break; | ||
1219 | |||
1220 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: | ||
1221 | ret = fg_read_tte(bq); | ||
1222 | mutex_lock(&bq->data_lock); | ||
1223 | if (ret >=0) | ||
1224 | bq->batt_tte = ret; | ||
1225 | |||
1226 | val->intval = bq->batt_tte; | ||
1227 | mutex_unlock(&bq->data_lock); | ||
1228 | break; | ||
1229 | |||
1230 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
1231 | ret = fg_read_fcc(bq); | ||
1232 | mutex_lock(&bq->data_lock); | ||
1233 | if (ret > 0) | ||
1234 | bq->batt_fcc = ret; | ||
1235 | val->intval = bq->batt_fcc * 1000; | ||
1236 | mutex_unlock(&bq->data_lock); | ||
1237 | break; | ||
1238 | |||
1239 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
1240 | ret = fg_read_dc(bq); | ||
1241 | mutex_lock(&bq->data_lock); | ||
1242 | if (ret > 0) | ||
1243 | bq->batt_dc = ret; | ||
1244 | val->intval = bq->batt_dc * 1000; | ||
1245 | mutex_unlock(&bq->data_lock); | ||
1246 | break; | ||
1247 | |||
1248 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | ||
1249 | ret = fg_read_cyclecount(bq); | ||
1250 | mutex_lock(&bq->data_lock); | ||
1251 | if (ret >= 0) | ||
1252 | bq->batt_cyclecnt = ret; | ||
1253 | val->intval = bq->batt_cyclecnt; | ||
1254 | mutex_unlock(&bq->data_lock); | ||
1255 | break; | ||
1256 | |||
1257 | case POWER_SUPPLY_PROP_HEALTH: | ||
1258 | val->intval = fg_get_batt_health(bq); | ||
1259 | break; | ||
1260 | |||
1261 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
1262 | val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; | ||
1263 | break; | ||
1264 | |||
1265 | case POWER_SUPPLY_PROP_UPDATE_NOW: | ||
1266 | val->intval = 0; | ||
1267 | break; | ||
1268 | |||
1269 | default: | ||
1270 | mutex_unlock(&bq->update_lock); | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | mutex_unlock(&bq->update_lock); | ||
1274 | return 0; | ||
1275 | } | ||
1276 | static void fg_dump_registers(struct bq_fg_chip *bq); | ||
1277 | |||
1278 | static int fg_set_property(struct power_supply *psy, | ||
1279 | enum power_supply_property prop, | ||
1280 | const union power_supply_propval *val) | ||
1281 | { | ||
1282 | struct bq_fg_chip *bq = power_supply_get_drvdata(psy); | ||
1283 | |||
1284 | switch (prop) { | ||
1285 | case POWER_SUPPLY_PROP_TEMP: | ||
1286 | bq->fake_temp = val->intval; | ||
1287 | break; | ||
1288 | case POWER_SUPPLY_PROP_CAPACITY: | ||
1289 | bq->fake_soc = val->intval; | ||
1290 | power_supply_changed(bq->fg_psy); | ||
1291 | break; | ||
1292 | case POWER_SUPPLY_PROP_UPDATE_NOW: | ||
1293 | fg_dump_registers(bq); | ||
1294 | break; | ||
1295 | default: | ||
1296 | return -EINVAL; | ||
1297 | } | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | |||
1303 | static int fg_prop_is_writeable(struct power_supply *psy, | ||
1304 | enum power_supply_property prop) | ||
1305 | { | ||
1306 | int ret; | ||
1307 | |||
1308 | switch (prop) { | ||
1309 | case POWER_SUPPLY_PROP_TEMP: | ||
1310 | case POWER_SUPPLY_PROP_CAPACITY: | ||
1311 | case POWER_SUPPLY_PROP_UPDATE_NOW: | ||
1312 | ret = 1; | ||
1313 | break; | ||
1314 | default: | ||
1315 | ret = 0; | ||
1316 | break; | ||
1317 | } | ||
1318 | return ret; | ||
1319 | } | ||
1320 | |||
1321 | static int fg_psy_register(struct bq_fg_chip *bq) | ||
1322 | { | ||
1323 | struct power_supply_config fg_psy_cfg = {}; | ||
1324 | |||
1325 | bq->fg_psy_d.name = "bms"; | ||
1326 | bq->fg_psy_d.type = POWER_SUPPLY_TYPE_BMS; | ||
1327 | bq->fg_psy_d.properties = fg_props; | ||
1328 | bq->fg_psy_d.num_properties = ARRAY_SIZE(fg_props); | ||
1329 | bq->fg_psy_d.get_property = fg_get_property; | ||
1330 | bq->fg_psy_d.set_property = fg_set_property; | ||
1331 | bq->fg_psy_d.property_is_writeable = fg_prop_is_writeable; | ||
1332 | |||
1333 | fg_psy_cfg.drv_data = bq; | ||
1334 | fg_psy_cfg.num_supplicants = 0; | ||
1335 | bq->fg_psy = devm_power_supply_register(bq->dev, | ||
1336 | &bq->fg_psy_d, | ||
1337 | &fg_psy_cfg); | ||
1338 | if (IS_ERR(bq->fg_psy)) { | ||
1339 | pr_err("Failed to register fg_psy"); | ||
1340 | return PTR_ERR(bq->fg_psy); | ||
1341 | } | ||
1342 | |||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | static void fg_psy_unregister(struct bq_fg_chip *bq) | ||
1348 | { | ||
1349 | |||
1350 | power_supply_unregister(bq->fg_psy); | ||
1351 | } | ||
1352 | |||
1353 | |||
1354 | static int fg_check_update_necessary(struct bq_fg_chip *bq) | ||
1355 | { | ||
1356 | int ret; | ||
1357 | u8 dm_ver = 0xFF; | ||
1358 | |||
1359 | ret = fg_check_itpor(bq); | ||
1360 | if (!ret && bq->itpor) | ||
1361 | return UPDATE_REASON_FG_RESET; | ||
1362 | |||
1363 | ret = fg_read_dm_version(bq, &dm_ver); | ||
1364 | if (!ret && dm_ver < bqfs_image[bq->batt_id].version) | ||
1365 | return UPDATE_REASON_NEW_VERSION; | ||
1366 | else | ||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | static bool fg_update_bqfs_execute_cmd(struct bq_fg_chip *bq, | ||
1371 | const bqfs_cmd_t *cmd) | ||
1372 | { | ||
1373 | int ret; | ||
1374 | int i; | ||
1375 | u8 tmp_buf[CMD_MAX_DATA_SIZE]; | ||
1376 | |||
1377 | switch (cmd->cmd_type) { | ||
1378 | case CMD_R: | ||
1379 | ret = fg_read_block(bq, cmd->reg, (u8 *)&cmd->data.bytes, cmd->data_len); | ||
1380 | if (ret < 0) | ||
1381 | return false; | ||
1382 | else | ||
1383 | return true; | ||
1384 | break; | ||
1385 | case CMD_W: | ||
1386 | ret = fg_write_block(bq, cmd->reg, (u8 *)&cmd->data.bytes, cmd->data_len); | ||
1387 | if (ret < 0) | ||
1388 | return false; | ||
1389 | else | ||
1390 | return true; | ||
1391 | break; | ||
1392 | case CMD_C: | ||
1393 | if (fg_read_block(bq, cmd->reg, tmp_buf, cmd->data_len) < 0) | ||
1394 | return false; | ||
1395 | if (memcmp(tmp_buf, cmd->data.bytes, cmd->data_len)) { | ||
1396 | pr_info("CMD_C failed at line %d\n", cmd->line_num); | ||
1397 | for(i = 0; i < cmd->data_len; i++) { | ||
1398 | pr_err("Read: %02X, Cmp:%02X", tmp_buf[i], cmd->data.bytes[i]); | ||
1399 | } | ||
1400 | return false; | ||
1401 | } | ||
1402 | |||
1403 | return true; | ||
1404 | break; | ||
1405 | case CMD_X: | ||
1406 | mdelay(cmd->data.delay); | ||
1407 | return true; | ||
1408 | break; | ||
1409 | default: | ||
1410 | pr_err("Unsupported command at line %d\n", cmd->line_num); | ||
1411 | return false; | ||
1412 | } | ||
1413 | |||
1414 | } | ||
1415 | EXPORT_SYMBOL_GPL(fg_update_bqfs_execute_cmd); | ||
1416 | |||
1417 | static void fg_update_bqfs(struct bq_fg_chip *bq) | ||
1418 | { | ||
1419 | int i; | ||
1420 | const bqfs_cmd_t *image; | ||
1421 | int reason = 0; | ||
1422 | |||
1423 | |||
1424 | if (bq->force_update == ~BQFS_UPDATE_KEY) | ||
1425 | reason = UPDATE_REASON_FORCED; | ||
1426 | else | ||
1427 | reason = fg_check_update_necessary(bq); | ||
1428 | |||
1429 | if (!reason) { | ||
1430 | pr_info("Fuel Gauge parameter no need update, ignored\n"); | ||
1431 | return; | ||
1432 | } | ||
1433 | |||
1434 | if (bq->batt_id >= ARRAY_SIZE(bqfs_image) || | ||
1435 | bq->batt_id < 0) { | ||
1436 | pr_err("batt_id is out of range"); | ||
1437 | return; | ||
1438 | } | ||
1439 | /* TODO:if unseal, enter cfg update mode cmd sequence are in gmfs file, | ||
1440 | no need to do explicitly */ | ||
1441 | fg_dm_pre_access(bq); | ||
1442 | |||
1443 | pr_err("Fuel Gauge parameter update, reason:%s, version:%d, batt_id=%d Start...\n", | ||
1444 | update_reason_str[reason - 1], bqfs_image[bq->batt_id].version, bq->batt_id); | ||
1445 | |||
1446 | mutex_lock(&bq->update_lock); | ||
1447 | image = bqfs_image[bq->batt_id].bqfs_image; | ||
1448 | for (i = 0; i < bqfs_image[bq->batt_id].array_size; i++) { | ||
1449 | if (!fg_update_bqfs_execute_cmd(bq, &image[i])) { | ||
1450 | mutex_unlock(&bq->update_lock); | ||
1451 | pr_err("Failed at command: %d\n", i); | ||
1452 | fg_dm_post_access(bq); | ||
1453 | return; | ||
1454 | } | ||
1455 | mdelay(5); | ||
1456 | } | ||
1457 | mutex_unlock(&bq->update_lock); | ||
1458 | |||
1459 | pr_err("Done!\n"); | ||
1460 | |||
1461 | /* TODO:exit cfg update mode and seal device if these are not handled in gmfs file */ | ||
1462 | fg_dm_post_access(bq); | ||
1463 | return; | ||
1464 | |||
1465 | } | ||
1466 | |||
1467 | static const u8 fg_dump_regs[] = { | ||
1468 | 0x00, 0x02, 0x04, 0x06, | ||
1469 | 0x08, 0x0A, 0x0C, 0x0E, | ||
1470 | 0x10, 0x16, 0x18, 0x1A, | ||
1471 | 0x1C, 0x1E, 0x20, 0x28, | ||
1472 | 0x2A, 0x2C, 0x2E, 0x30, | ||
1473 | 0x66, 0x68, 0x6C, 0x6E, | ||
1474 | 0x70, | ||
1475 | }; | ||
1476 | |||
1477 | static int show_registers(struct seq_file *m, void *data) | ||
1478 | { | ||
1479 | struct bq_fg_chip *bq = m->private; | ||
1480 | int i; | ||
1481 | int ret; | ||
1482 | u16 val = 0; | ||
1483 | |||
1484 | for (i = 0; i < ARRAY_SIZE(fg_dump_regs); i++) { | ||
1485 | msleep(5); | ||
1486 | ret = fg_read_word(bq, fg_dump_regs[i], &val); | ||
1487 | if (!ret) | ||
1488 | seq_printf(m, "Reg[%02X] = 0x%04X\n", | ||
1489 | fg_dump_regs[i], val); | ||
1490 | } | ||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | static int reg_debugfs_open(struct inode *inode, struct file *file) | ||
1496 | { | ||
1497 | struct bq_fg_chip *bq = inode->i_private; | ||
1498 | |||
1499 | return single_open(file, show_registers, bq); | ||
1500 | } | ||
1501 | |||
1502 | static const struct file_operations reg_debugfs_ops = { | ||
1503 | .owner = THIS_MODULE, | ||
1504 | .open = reg_debugfs_open, | ||
1505 | .read = seq_read, | ||
1506 | .llseek = seq_lseek, | ||
1507 | .release = single_release, | ||
1508 | }; | ||
1509 | |||
1510 | static void create_debugfs_entry(struct bq_fg_chip *bq) | ||
1511 | { | ||
1512 | bq->debug_root = debugfs_create_dir("bq_fg", NULL); | ||
1513 | if (!bq->debug_root) | ||
1514 | pr_err("Failed to create debug dir\n"); | ||
1515 | |||
1516 | if (bq->debug_root) { | ||
1517 | |||
1518 | debugfs_create_file("registers", S_IFREG | S_IRUGO, | ||
1519 | bq->debug_root, bq, ®_debugfs_ops); | ||
1520 | |||
1521 | debugfs_create_x32("fake_soc", | ||
1522 | S_IFREG | S_IWUSR | S_IRUGO, | ||
1523 | bq->debug_root, | ||
1524 | &(bq->fake_soc)); | ||
1525 | |||
1526 | debugfs_create_x32("fake_temp", | ||
1527 | S_IFREG | S_IWUSR | S_IRUGO, | ||
1528 | bq->debug_root, | ||
1529 | &(bq->fake_temp)); | ||
1530 | |||
1531 | debugfs_create_x32("skip_reads", | ||
1532 | S_IFREG | S_IWUSR | S_IRUGO, | ||
1533 | bq->debug_root, | ||
1534 | &(bq->skip_reads)); | ||
1535 | debugfs_create_x32("skip_writes", | ||
1536 | S_IFREG | S_IWUSR | S_IRUGO, | ||
1537 | bq->debug_root, | ||
1538 | &(bq->skip_writes)); | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | static ssize_t fg_attr_show_qmax_ratable(struct device *dev, | ||
1543 | struct device_attribute *attr, char *buf) | ||
1544 | { | ||
1545 | struct i2c_client *client = to_i2c_client(dev); | ||
1546 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1547 | |||
1548 | int ret; | ||
1549 | u8 rd_buf[512]; | ||
1550 | int len; | ||
1551 | int idx = 0; | ||
1552 | int i; | ||
1553 | |||
1554 | mutex_lock(&bq->update_lock); | ||
1555 | ret = fg_dm_pre_access(bq); | ||
1556 | if (ret) { | ||
1557 | mutex_unlock(&bq->update_lock); | ||
1558 | return 0; | ||
1559 | } | ||
1560 | |||
1561 | ret = fg_dm_read_block(bq, 82, 0, rd_buf); //Qmax, offset 0 | ||
1562 | if (ret) { | ||
1563 | fg_dm_post_access(bq); | ||
1564 | mutex_unlock(&bq->update_lock); | ||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | len = sprintf(&buf[idx], "Qmax Cell 0: %d\n", (rd_buf[0] << 8) | rd_buf[1]); | ||
1569 | idx += len; | ||
1570 | len = sprintf(&buf[idx], "Avg I Last Run: %d\n", (short)(rd_buf[25] << 8 | rd_buf[26])); | ||
1571 | idx += len; | ||
1572 | len = sprintf(&buf[idx], "Avg P Last Run:%d\n", (short)(rd_buf[27] << 8 | rd_buf[28])); | ||
1573 | idx += len; | ||
1574 | len = sprintf(&buf[idx], "Delta Voltage:%d\n", (rd_buf[29] << 8 | rd_buf[30])); | ||
1575 | idx += len; | ||
1576 | |||
1577 | ret = fg_dm_read_block(bq, 89, 0, rd_buf); //Ra Table | ||
1578 | if (ret) { | ||
1579 | fg_dm_post_access(bq); | ||
1580 | mutex_unlock(&bq->update_lock); | ||
1581 | return idx; | ||
1582 | } | ||
1583 | |||
1584 | len = sprintf(&buf[idx], "Ra Table:\n"); | ||
1585 | idx += len; | ||
1586 | |||
1587 | for (i = 0; i < 15; i += 2) { | ||
1588 | len = sprintf(&buf[idx], "%d ", rd_buf[i] << 8 | rd_buf[i+1]); | ||
1589 | idx += len; | ||
1590 | } | ||
1591 | |||
1592 | |||
1593 | ret = fg_dm_read_block(bq, 109, 6, rd_buf); //V at Chg Term | ||
1594 | if (ret) { | ||
1595 | fg_dm_post_access(bq); | ||
1596 | mutex_unlock(&bq->update_lock); | ||
1597 | return idx; | ||
1598 | } | ||
1599 | |||
1600 | len = sprintf(&buf[idx], "V at Chg Term:%d\n", rd_buf[6] << 8 | rd_buf[7]); | ||
1601 | idx += len; | ||
1602 | |||
1603 | fg_dm_post_access(bq); | ||
1604 | |||
1605 | mutex_unlock(&bq->update_lock); | ||
1606 | |||
1607 | return idx; | ||
1608 | } | ||
1609 | |||
1610 | static ssize_t fg_attr_store_update(struct device *dev, | ||
1611 | struct device_attribute *attr, const char *buf, size_t count) | ||
1612 | { | ||
1613 | |||
1614 | struct i2c_client *client = to_i2c_client(dev); | ||
1615 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1616 | unsigned int key = 0; | ||
1617 | |||
1618 | sscanf(buf, "%x", &key); | ||
1619 | if (key == BQFS_UPDATE_KEY) { | ||
1620 | bq->force_update = ~key; | ||
1621 | schedule_work(&bq->update_work); | ||
1622 | } | ||
1623 | return count; | ||
1624 | } | ||
1625 | |||
1626 | static ssize_t fg_attr_show_dmcode(struct device *dev, | ||
1627 | struct device_attribute *attr, char *buf) | ||
1628 | { | ||
1629 | struct i2c_client *client = to_i2c_client(dev); | ||
1630 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1631 | |||
1632 | int ret; | ||
1633 | u8 ver; | ||
1634 | |||
1635 | ret = fg_read_dm_version(bq, &ver); | ||
1636 | if (!ret) | ||
1637 | return sprintf(buf, "0x%02X\n", ver); | ||
1638 | else | ||
1639 | return sprintf(buf, "Read DM code error"); | ||
1640 | } | ||
1641 | |||
1642 | |||
1643 | |||
1644 | static DEVICE_ATTR(qmax_ratable, S_IRUGO, fg_attr_show_qmax_ratable, NULL); | ||
1645 | static DEVICE_ATTR(update, S_IWUSR, NULL, fg_attr_store_update); | ||
1646 | static DEVICE_ATTR(dmcode, S_IRUGO, fg_attr_show_dmcode, NULL); | ||
1647 | |||
1648 | static struct attribute *fg_attributes[] = { | ||
1649 | &dev_attr_qmax_ratable.attr, | ||
1650 | &dev_attr_update.attr, | ||
1651 | &dev_attr_dmcode.attr, | ||
1652 | NULL, | ||
1653 | }; | ||
1654 | |||
1655 | static const struct attribute_group fg_attr_group = { | ||
1656 | .attrs = fg_attributes, | ||
1657 | }; | ||
1658 | |||
1659 | |||
1660 | |||
1661 | static int fg_enable_sleep(struct bq_fg_chip *bq, bool enable) | ||
1662 | { | ||
1663 | |||
1664 | int ret; | ||
1665 | u8 rd_buf[64]; | ||
1666 | |||
1667 | memset(rd_buf, 0, 64); | ||
1668 | mutex_lock(&bq->update_lock); | ||
1669 | ret = fg_dm_enter_cfg_mode(bq); | ||
1670 | if (ret) { | ||
1671 | mutex_unlock(&bq->update_lock); | ||
1672 | return ret; | ||
1673 | } | ||
1674 | |||
1675 | ret = fg_dm_read_block(bq, 64, 0, rd_buf); //OpConfig | ||
1676 | if (ret) { | ||
1677 | fg_dm_exit_cfg_mode(bq); | ||
1678 | mutex_unlock(&bq->update_lock); | ||
1679 | return ret; | ||
1680 | } | ||
1681 | |||
1682 | if (enable) | ||
1683 | rd_buf[1] |=0x20; // set SLEEP bit | ||
1684 | else | ||
1685 | rd_buf[1] &=~0x20; // clear SLEEP bit | ||
1686 | |||
1687 | |||
1688 | ret = fg_dm_write_block(bq, 64, 0, rd_buf); | ||
1689 | |||
1690 | fg_dm_exit_cfg_mode(bq); | ||
1691 | |||
1692 | mutex_unlock(&bq->update_lock); | ||
1693 | |||
1694 | return ret; | ||
1695 | } | ||
1696 | EXPORT_SYMBOL_GPL(fg_enable_sleep); | ||
1697 | |||
1698 | static void fg_update_bqfs_workfunc(struct work_struct *work) | ||
1699 | { | ||
1700 | struct bq_fg_chip *bq = container_of(work, | ||
1701 | struct bq_fg_chip, update_work); | ||
1702 | |||
1703 | fg_update_bqfs(bq); | ||
1704 | } | ||
1705 | |||
1706 | static void fg_dump_registers(struct bq_fg_chip *bq) | ||
1707 | { | ||
1708 | int i; | ||
1709 | int ret; | ||
1710 | u16 val; | ||
1711 | |||
1712 | for (i = 0; i < ARRAY_SIZE(fg_dump_regs); i++) { | ||
1713 | msleep(5); | ||
1714 | ret = fg_read_word(bq, fg_dump_regs[i], &val); | ||
1715 | if (!ret) | ||
1716 | pr_err("Reg[%02X] = 0x%04X\n", fg_dump_regs[i], val); | ||
1717 | } | ||
1718 | } | ||
1719 | |||
1720 | static irqreturn_t fg_irq_thread(int irq, void *dev_id) | ||
1721 | { | ||
1722 | struct bq_fg_chip *bq = dev_id; | ||
1723 | bool last_batt_present; | ||
1724 | |||
1725 | mutex_lock(&bq->irq_complete); | ||
1726 | bq->irq_waiting = true; | ||
1727 | if (!bq->resume_completed) { | ||
1728 | pr_info("IRQ triggered before device resume\n"); | ||
1729 | if (!bq->irq_disabled) { | ||
1730 | disable_irq_nosync(irq); | ||
1731 | bq->irq_disabled = true; | ||
1732 | } | ||
1733 | mutex_unlock(&bq->irq_complete); | ||
1734 | return IRQ_HANDLED; | ||
1735 | } | ||
1736 | bq->irq_waiting = false; | ||
1737 | |||
1738 | last_batt_present = bq->batt_present; | ||
1739 | |||
1740 | mutex_lock(&bq->update_lock); | ||
1741 | fg_read_status(bq); | ||
1742 | mutex_unlock(&bq->update_lock); | ||
1743 | |||
1744 | fg_dump_registers(bq); | ||
1745 | |||
1746 | pr_info("itpor=%d, cfg_mode = %d, seal_state=%d, batt_present=%d", | ||
1747 | bq->itpor, bq->cfg_update_mode, bq->seal_state, bq->batt_present); | ||
1748 | |||
1749 | if (!last_batt_present && bq->batt_present ) {/* battery inserted */ | ||
1750 | pr_info("Battery inserted\n"); | ||
1751 | } else if (last_batt_present && !bq->batt_present) {/* battery removed */ | ||
1752 | pr_info("Battery removed\n"); | ||
1753 | bq->batt_soc = -ENODATA; | ||
1754 | bq->batt_fcc = -ENODATA; | ||
1755 | bq->batt_rm = -ENODATA; | ||
1756 | bq->batt_volt = -ENODATA; | ||
1757 | bq->batt_curr = -ENODATA; | ||
1758 | bq->batt_temp = -ENODATA; | ||
1759 | bq->batt_cyclecnt = -ENODATA; | ||
1760 | } | ||
1761 | |||
1762 | if (bq->batt_present) { | ||
1763 | mutex_lock(&bq->update_lock); | ||
1764 | |||
1765 | bq->batt_soc = fg_read_rsoc(bq); | ||
1766 | bq->batt_volt = fg_read_volt(bq); | ||
1767 | fg_read_current(bq, &bq->batt_curr); | ||
1768 | bq->batt_temp = fg_read_temperature(bq); | ||
1769 | bq->batt_rm = fg_read_rm(bq); | ||
1770 | |||
1771 | mutex_unlock(&bq->update_lock); | ||
1772 | pr_err("RSOC:%d, Volt:%d, Current:%d, Temperature:%d\n", | ||
1773 | bq->batt_soc, bq->batt_volt, bq->batt_curr, bq->batt_temp - 2730); | ||
1774 | } | ||
1775 | |||
1776 | power_supply_changed(bq->fg_psy); | ||
1777 | mutex_unlock(&bq->irq_complete); | ||
1778 | |||
1779 | return IRQ_HANDLED; | ||
1780 | } | ||
1781 | |||
1782 | |||
1783 | static void determine_initial_status(struct bq_fg_chip *bq) | ||
1784 | { | ||
1785 | fg_irq_thread(bq->client->irq, bq); | ||
1786 | } | ||
1787 | |||
1788 | static int bq_parse_dt(struct bq_fg_chip *bq) | ||
1789 | { | ||
1790 | return 0; | ||
1791 | } | ||
1792 | |||
1793 | static int bq_fg_probe(struct i2c_client *client, | ||
1794 | const struct i2c_device_id *id) | ||
1795 | { | ||
1796 | |||
1797 | int ret; | ||
1798 | struct bq_fg_chip *bq; | ||
1799 | u8 *regs; | ||
1800 | |||
1801 | bq = devm_kzalloc(&client->dev, sizeof(*bq), GFP_KERNEL); | ||
1802 | |||
1803 | if (!bq) { | ||
1804 | pr_err("Could not allocate memory\n"); | ||
1805 | return -ENOMEM; | ||
1806 | } | ||
1807 | |||
1808 | bq->dev = &client->dev; | ||
1809 | bq->client = client; | ||
1810 | bq->chip = id->driver_data; | ||
1811 | |||
1812 | bq->batt_soc = -ENODATA; | ||
1813 | bq->batt_fcc = -ENODATA; | ||
1814 | bq->batt_rm = -ENODATA; | ||
1815 | bq->batt_dc = -ENODATA; | ||
1816 | bq->batt_volt = -ENODATA; | ||
1817 | bq->batt_temp = -ENODATA; | ||
1818 | bq->batt_curr = -ENODATA; | ||
1819 | bq->batt_cyclecnt = -ENODATA; | ||
1820 | |||
1821 | bq->fake_soc = -EINVAL; | ||
1822 | bq->fake_temp = -EINVAL; | ||
1823 | |||
1824 | if (bq->chip == BQ27426) { | ||
1825 | regs = bq27426_regs; | ||
1826 | } else { | ||
1827 | pr_err("unexpected fuel gauge: %d\n", bq->chip); | ||
1828 | regs = bq27426_regs; | ||
1829 | } | ||
1830 | |||
1831 | memcpy(bq->regs, regs, NUM_REGS); | ||
1832 | |||
1833 | i2c_set_clientdata(client, bq); | ||
1834 | |||
1835 | mutex_init(&bq->i2c_rw_lock); | ||
1836 | mutex_init(&bq->data_lock); | ||
1837 | mutex_init(&bq->update_lock); | ||
1838 | mutex_init(&bq->irq_complete); | ||
1839 | |||
1840 | bq->resume_completed = true; | ||
1841 | bq->irq_waiting = false; | ||
1842 | |||
1843 | ret = bq_parse_dt(bq); | ||
1844 | if (ret < 0) { | ||
1845 | dev_err(&client->dev, "Unable to parse DT nodes\n"); | ||
1846 | //goto destroy_mutex; | ||
1847 | } | ||
1848 | INIT_WORK(&bq->update_work, fg_update_bqfs_workfunc); | ||
1849 | |||
1850 | |||
1851 | fg_update_bqfs(bq); | ||
1852 | |||
1853 | if (client->irq) { | ||
1854 | ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, | ||
1855 | fg_irq_thread, | ||
1856 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
1857 | "bq fuel gauge irq", bq); | ||
1858 | if (ret < 0) { | ||
1859 | pr_err("request irq for irq=%d failed, ret = %d\n", client->irq, ret); | ||
1860 | goto err_1; | ||
1861 | } | ||
1862 | enable_irq_wake(client->irq); | ||
1863 | } | ||
1864 | |||
1865 | device_init_wakeup(bq->dev, 1); | ||
1866 | |||
1867 | bq->fw_ver = fg_read_fw_version(bq); | ||
1868 | |||
1869 | fg_psy_register(bq); | ||
1870 | |||
1871 | create_debugfs_entry(bq); | ||
1872 | ret = sysfs_create_group(&bq->dev->kobj, &fg_attr_group); | ||
1873 | if (ret) { | ||
1874 | pr_err("Failed to register sysfs, err:%d\n", ret); | ||
1875 | } | ||
1876 | |||
1877 | determine_initial_status(bq); | ||
1878 | |||
1879 | pr_err("bq fuel gauge probe successfully, %s FW ver:%d\n", | ||
1880 | device2str[bq->chip], bq->fw_ver); | ||
1881 | |||
1882 | return 0; | ||
1883 | |||
1884 | err_1: | ||
1885 | fg_psy_unregister(bq); | ||
1886 | return ret; | ||
1887 | } | ||
1888 | |||
1889 | |||
1890 | static inline bool is_device_suspended(struct bq_fg_chip *bq) | ||
1891 | { | ||
1892 | return !bq->resume_completed; | ||
1893 | } | ||
1894 | |||
1895 | |||
1896 | static int bq_fg_suspend(struct device *dev) | ||
1897 | { | ||
1898 | struct i2c_client *client = to_i2c_client(dev); | ||
1899 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1900 | |||
1901 | mutex_lock(&bq->irq_complete); | ||
1902 | bq->resume_completed = false; | ||
1903 | mutex_unlock(&bq->irq_complete); | ||
1904 | |||
1905 | return 0; | ||
1906 | } | ||
1907 | |||
1908 | static int bq_fg_suspend_noirq(struct device *dev) | ||
1909 | { | ||
1910 | struct i2c_client *client = to_i2c_client(dev); | ||
1911 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1912 | |||
1913 | if (bq->irq_waiting) { | ||
1914 | pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n"); | ||
1915 | return -EBUSY; | ||
1916 | } | ||
1917 | return 0; | ||
1918 | |||
1919 | } | ||
1920 | |||
1921 | |||
1922 | static int bq_fg_resume(struct device *dev) | ||
1923 | { | ||
1924 | struct i2c_client *client = to_i2c_client(dev); | ||
1925 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1926 | |||
1927 | mutex_lock(&bq->irq_complete); | ||
1928 | bq->resume_completed = true; | ||
1929 | if (bq->irq_waiting) { | ||
1930 | bq->irq_disabled = false; | ||
1931 | enable_irq(client->irq); | ||
1932 | mutex_unlock(&bq->irq_complete); | ||
1933 | fg_irq_thread(client->irq, bq); | ||
1934 | } else { | ||
1935 | mutex_unlock(&bq->irq_complete); | ||
1936 | } | ||
1937 | |||
1938 | power_supply_changed(bq->fg_psy); | ||
1939 | |||
1940 | return 0; | ||
1941 | |||
1942 | |||
1943 | } | ||
1944 | |||
1945 | static int bq_fg_remove(struct i2c_client *client) | ||
1946 | { | ||
1947 | struct bq_fg_chip *bq = i2c_get_clientdata(client); | ||
1948 | |||
1949 | fg_psy_unregister(bq); | ||
1950 | |||
1951 | mutex_destroy(&bq->data_lock); | ||
1952 | mutex_destroy(&bq->i2c_rw_lock); | ||
1953 | mutex_destroy(&bq->update_lock); | ||
1954 | mutex_destroy(&bq->irq_complete); | ||
1955 | |||
1956 | debugfs_remove_recursive(bq->debug_root); | ||
1957 | sysfs_remove_group(&bq->dev->kobj, &fg_attr_group); | ||
1958 | |||
1959 | return 0; | ||
1960 | |||
1961 | } | ||
1962 | |||
1963 | static void bq_fg_shutdown(struct i2c_client *client) | ||
1964 | { | ||
1965 | pr_info("bq fuel gauge driver shutdown!\n"); | ||
1966 | } | ||
1967 | |||
1968 | static struct of_device_id bq_fg_match_table[] = { | ||
1969 | {.compatible = "ti,bq27426",}, | ||
1970 | {}, | ||
1971 | }; | ||
1972 | MODULE_DEVICE_TABLE(of,bq_fg_match_table); | ||
1973 | |||
1974 | static const struct i2c_device_id bq_fg_id[] = { | ||
1975 | { "bq27426", BQ27426 }, | ||
1976 | {}, | ||
1977 | }; | ||
1978 | MODULE_DEVICE_TABLE(i2c, bq_fg_id); | ||
1979 | |||
1980 | static const struct dev_pm_ops bq_fg_pm_ops = { | ||
1981 | .resume = bq_fg_resume, | ||
1982 | .suspend_noirq = bq_fg_suspend_noirq, | ||
1983 | .suspend = bq_fg_suspend, | ||
1984 | }; | ||
1985 | |||
1986 | static struct i2c_driver bq_fg_driver = { | ||
1987 | .driver = { | ||
1988 | .name = "bq_fg", | ||
1989 | .owner = THIS_MODULE, | ||
1990 | .of_match_table = bq_fg_match_table, | ||
1991 | .pm = &bq_fg_pm_ops, | ||
1992 | }, | ||
1993 | .id_table = bq_fg_id, | ||
1994 | |||
1995 | .probe = bq_fg_probe, | ||
1996 | .remove = bq_fg_remove, | ||
1997 | .shutdown = bq_fg_shutdown, | ||
1998 | |||
1999 | }; | ||
2000 | |||
2001 | module_i2c_driver(bq_fg_driver); | ||
2002 | |||
2003 | MODULE_DESCRIPTION("TI BQ2742x Gauge Driver"); | ||
2004 | MODULE_LICENSE("GPL v2"); | ||
2005 | MODULE_AUTHOR("Texas Instruments"); | ||
diff --git a/drivers/power/bq27426/bq27426_gmfs_coslight.h b/drivers/power/bq27426/bq27426_gmfs_coslight.h new file mode 100644 index 000000000000..4c55bb2dff16 --- /dev/null +++ b/drivers/power/bq27426/bq27426_gmfs_coslight.h | |||
@@ -0,0 +1,945 @@ | |||
1 | /***************************************************************************** | ||
2 | * Copyright 2010 Texas Instruments Corporation, All Rights Reserved. | ||
3 | * TI makes NO WARRANTY as to software products, which are supplied "AS-IS" | ||
4 | *****************************************************************************/ | ||
5 | |||
6 | /***************************************************************************** | ||
7 | * This code is automatically generated from bqfs/dffs file. * | ||
8 | * DO NOT MODIFY THIS FILE DIRECTLY * | ||
9 | *****************************************************************************/ | ||
10 | |||
11 | |||
12 | #ifndef __BQFS_FILE__ | ||
13 | #define __BQFS_FILE__ | ||
14 | |||
15 | #include "bqfs_cmd_type.h" | ||
16 | |||
17 | static const bqfs_cmd_t bqfs_coslight[] = { | ||
18 | { | ||
19 | .cmd_type = CMD_W, | ||
20 | .addr = 0xAA, | ||
21 | .reg = 0x00, | ||
22 | .data = {.bytes = {0x01, 0x00}}, | ||
23 | .data_len = 2, | ||
24 | }, | ||
25 | { | ||
26 | .cmd_type = CMD_C, | ||
27 | .addr = 0xAA, | ||
28 | .reg = 0x00, | ||
29 | .data = {.bytes = {0x26, 0x04}}, | ||
30 | .data_len = 2, | ||
31 | }, | ||
32 | { | ||
33 | .cmd_type = CMD_W, | ||
34 | .addr = 0xAA, | ||
35 | .reg = 0x00, | ||
36 | .data = {.bytes = {0x02, 0x00}}, | ||
37 | .data_len = 2, | ||
38 | }, | ||
39 | { | ||
40 | .cmd_type = CMD_C, | ||
41 | .addr = 0xAA, | ||
42 | .reg = 0x00, | ||
43 | .data = {.bytes = {0x02, 0x02}}, | ||
44 | .data_len = 2, | ||
45 | }, | ||
46 | { | ||
47 | .cmd_type = CMD_W, | ||
48 | .addr = 0xAA, | ||
49 | .reg = 0x3E, | ||
50 | .data = {.bytes = {0x02, 0x00}}, | ||
51 | .data_len = 2, | ||
52 | }, | ||
53 | { | ||
54 | .cmd_type = CMD_W, | ||
55 | .addr = 0xAA, | ||
56 | .reg = 0x40, | ||
57 | .data = {.bytes = {0x02, 0x26, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
58 | .data_len = 32, | ||
59 | }, | ||
60 | { | ||
61 | .cmd_type = CMD_W, | ||
62 | .addr = 0xAA, | ||
63 | .reg = 0x60, | ||
64 | .data = {.bytes = {0xA5}}, | ||
65 | .data_len = 1, | ||
66 | }, | ||
67 | { | ||
68 | .cmd_type = CMD_X, | ||
69 | .data = {.delay = 10}, | ||
70 | }, | ||
71 | { | ||
72 | .cmd_type = CMD_W, | ||
73 | .addr = 0xAA, | ||
74 | .reg = 0x3E, | ||
75 | .data = {.bytes = {0x02, 0x00}}, | ||
76 | .data_len = 2, | ||
77 | }, | ||
78 | { | ||
79 | .cmd_type = CMD_C, | ||
80 | .addr = 0xAA, | ||
81 | .reg = 0x60, | ||
82 | .data = {.bytes = {0xA5}}, | ||
83 | .data_len = 1, | ||
84 | }, | ||
85 | { | ||
86 | .cmd_type = CMD_W, | ||
87 | .addr = 0xAA, | ||
88 | .reg = 0x3E, | ||
89 | .data = {.bytes = {0x24, 0x00}}, | ||
90 | .data_len = 2, | ||
91 | }, | ||
92 | { | ||
93 | .cmd_type = CMD_W, | ||
94 | .addr = 0xAA, | ||
95 | .reg = 0x40, | ||
96 | .data = {.bytes = {0x00, 0x19, 0x28, 0x63, 0x5F, 0xFF, 0x62, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
97 | .data_len = 32, | ||
98 | }, | ||
99 | { | ||
100 | .cmd_type = CMD_W, | ||
101 | .addr = 0xAA, | ||
102 | .reg = 0x60, | ||
103 | .data = {.bytes = {0x69}}, | ||
104 | .data_len = 1, | ||
105 | }, | ||
106 | { | ||
107 | .cmd_type = CMD_X, | ||
108 | .data = {.delay = 10}, | ||
109 | }, | ||
110 | { | ||
111 | .cmd_type = CMD_W, | ||
112 | .addr = 0xAA, | ||
113 | .reg = 0x3E, | ||
114 | .data = {.bytes = {0x24, 0x00}}, | ||
115 | .data_len = 2, | ||
116 | }, | ||
117 | { | ||
118 | .cmd_type = CMD_C, | ||
119 | .addr = 0xAA, | ||
120 | .reg = 0x60, | ||
121 | .data = {.bytes = {0x69}}, | ||
122 | .data_len = 1, | ||
123 | }, | ||
124 | { | ||
125 | .cmd_type = CMD_W, | ||
126 | .addr = 0xAA, | ||
127 | .reg = 0x3E, | ||
128 | .data = {.bytes = {0x31, 0x00}}, | ||
129 | .data_len = 2, | ||
130 | }, | ||
131 | { | ||
132 | .cmd_type = CMD_W, | ||
133 | .addr = 0xAA, | ||
134 | .reg = 0x40, | ||
135 | .data = {.bytes = {0x0A, 0x0F, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
136 | .data_len = 32, | ||
137 | }, | ||
138 | { | ||
139 | .cmd_type = CMD_W, | ||
140 | .addr = 0xAA, | ||
141 | .reg = 0x60, | ||
142 | .data = {.bytes = {0xDF}}, | ||
143 | .data_len = 1, | ||
144 | }, | ||
145 | { | ||
146 | .cmd_type = CMD_X, | ||
147 | .data = {.delay = 10}, | ||
148 | }, | ||
149 | { | ||
150 | .cmd_type = CMD_W, | ||
151 | .addr = 0xAA, | ||
152 | .reg = 0x3E, | ||
153 | .data = {.bytes = {0x31, 0x00}}, | ||
154 | .data_len = 2, | ||
155 | }, | ||
156 | { | ||
157 | .cmd_type = CMD_C, | ||
158 | .addr = 0xAA, | ||
159 | .reg = 0x60, | ||
160 | .data = {.bytes = {0xDF}}, | ||
161 | .data_len = 1, | ||
162 | }, | ||
163 | { | ||
164 | .cmd_type = CMD_W, | ||
165 | .addr = 0xAA, | ||
166 | .reg = 0x3E, | ||
167 | .data = {.bytes = {0x40, 0x00}}, | ||
168 | .data_len = 2, | ||
169 | }, | ||
170 | { | ||
171 | .cmd_type = CMD_W, | ||
172 | .addr = 0xAA, | ||
173 | .reg = 0x40, | ||
174 | .data = {.bytes = {0x64, 0x79, 0x07, 0x9F, 0x23, 0x00, 0x00, 0x14, 0x04, 0x00, 0x09, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
175 | .data_len = 32, | ||
176 | }, | ||
177 | { | ||
178 | .cmd_type = CMD_W, | ||
179 | .addr = 0xAA, | ||
180 | .reg = 0x60, | ||
181 | .data = {.bytes = {0x0E}}, | ||
182 | .data_len = 1, | ||
183 | }, | ||
184 | { | ||
185 | .cmd_type = CMD_X, | ||
186 | .data = {.delay = 10}, | ||
187 | }, | ||
188 | { | ||
189 | .cmd_type = CMD_W, | ||
190 | .addr = 0xAA, | ||
191 | .reg = 0x3E, | ||
192 | .data = {.bytes = {0x40, 0x00}}, | ||
193 | .data_len = 2, | ||
194 | }, | ||
195 | { | ||
196 | .cmd_type = CMD_C, | ||
197 | .addr = 0xAA, | ||
198 | .reg = 0x60, | ||
199 | .data = {.bytes = {0x0E}}, | ||
200 | .data_len = 1, | ||
201 | }, | ||
202 | { | ||
203 | .cmd_type = CMD_W, | ||
204 | .addr = 0xAA, | ||
205 | .reg = 0x3E, | ||
206 | .data = {.bytes = {0x44, 0x00}}, | ||
207 | .data_len = 2, | ||
208 | }, | ||
209 | { | ||
210 | .cmd_type = CMD_W, | ||
211 | .addr = 0xAA, | ||
212 | .reg = 0x40, | ||
213 | .data = {.bytes = {0x00, 0x32, 0x01, 0xC2, 0x30, 0x00, 0x03, 0x08, 0x98, 0x01, 0x00, 0x3C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
214 | .data_len = 32, | ||
215 | }, | ||
216 | { | ||
217 | .cmd_type = CMD_W, | ||
218 | .addr = 0xAA, | ||
219 | .reg = 0x60, | ||
220 | .data = {.bytes = {0xF9}}, | ||
221 | .data_len = 1, | ||
222 | }, | ||
223 | { | ||
224 | .cmd_type = CMD_X, | ||
225 | .data = {.delay = 10}, | ||
226 | }, | ||
227 | { | ||
228 | .cmd_type = CMD_W, | ||
229 | .addr = 0xAA, | ||
230 | .reg = 0x3E, | ||
231 | .data = {.bytes = {0x44, 0x00}}, | ||
232 | .data_len = 2, | ||
233 | }, | ||
234 | { | ||
235 | .cmd_type = CMD_C, | ||
236 | .addr = 0xAA, | ||
237 | .reg = 0x60, | ||
238 | .data = {.bytes = {0xF9}}, | ||
239 | .data_len = 1, | ||
240 | }, | ||
241 | { | ||
242 | .cmd_type = CMD_W, | ||
243 | .addr = 0xAA, | ||
244 | .reg = 0x3E, | ||
245 | .data = {.bytes = {0x50, 0x00}}, | ||
246 | .data_len = 2, | ||
247 | }, | ||
248 | { | ||
249 | .cmd_type = CMD_W, | ||
250 | .addr = 0xAA, | ||
251 | .reg = 0x40, | ||
252 | .data = {.bytes = {0x01, 0xF4, 0x00, 0x1E, 0xC8, 0x14, 0x08, 0x00, 0x3C, 0x0E, 0x10, 0x00, 0x0A, 0x46, 0x05, 0x14, 0x05, 0x0F, 0x03, 0x20, 0x7F, 0xFF, 0x00, 0xF0, 0x46, 0x50, 0x18, 0x01, 0x90, 0x00, 0x64, 0x19}}, | ||
253 | .data_len = 32, | ||
254 | }, | ||
255 | { | ||
256 | .cmd_type = CMD_W, | ||
257 | .addr = 0xAA, | ||
258 | .reg = 0x60, | ||
259 | .data = {.bytes = {0xE4}}, | ||
260 | .data_len = 1, | ||
261 | }, | ||
262 | { | ||
263 | .cmd_type = CMD_X, | ||
264 | .data = {.delay = 10}, | ||
265 | }, | ||
266 | { | ||
267 | .cmd_type = CMD_W, | ||
268 | .addr = 0xAA, | ||
269 | .reg = 0x3E, | ||
270 | .data = {.bytes = {0x50, 0x00}}, | ||
271 | .data_len = 2, | ||
272 | }, | ||
273 | { | ||
274 | .cmd_type = CMD_C, | ||
275 | .addr = 0xAA, | ||
276 | .reg = 0x60, | ||
277 | .data = {.bytes = {0xE4}}, | ||
278 | .data_len = 1, | ||
279 | }, | ||
280 | { | ||
281 | .cmd_type = CMD_W, | ||
282 | .addr = 0xAA, | ||
283 | .reg = 0x3E, | ||
284 | .data = {.bytes = {0x50, 0x01}}, | ||
285 | .data_len = 2, | ||
286 | }, | ||
287 | { | ||
288 | .cmd_type = CMD_W, | ||
289 | .addr = 0xAA, | ||
290 | .reg = 0x40, | ||
291 | .data = {.bytes = {0xDC, 0x5C, 0x60, 0x00, 0x7D, 0x00, 0x04, 0x03, 0x19, 0x25, 0x0F, 0x14, 0x0A, 0x78, 0x60, 0x28, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x43, 0x80, 0x04, 0x01, 0x14, 0x00, 0x08, 0x0B, 0xB8, 0x01}}, | ||
292 | .data_len = 32, | ||
293 | }, | ||
294 | { | ||
295 | .cmd_type = CMD_W, | ||
296 | .addr = 0xAA, | ||
297 | .reg = 0x60, | ||
298 | .data = {.bytes = {0xDB}}, | ||
299 | .data_len = 1, | ||
300 | }, | ||
301 | { | ||
302 | .cmd_type = CMD_X, | ||
303 | .data = {.delay = 10}, | ||
304 | }, | ||
305 | { | ||
306 | .cmd_type = CMD_W, | ||
307 | .addr = 0xAA, | ||
308 | .reg = 0x3E, | ||
309 | .data = {.bytes = {0x50, 0x01}}, | ||
310 | .data_len = 2, | ||
311 | }, | ||
312 | { | ||
313 | .cmd_type = CMD_C, | ||
314 | .addr = 0xAA, | ||
315 | .reg = 0x60, | ||
316 | .data = {.bytes = {0xDB}}, | ||
317 | .data_len = 1, | ||
318 | }, | ||
319 | { | ||
320 | .cmd_type = CMD_W, | ||
321 | .addr = 0xAA, | ||
322 | .reg = 0x3E, | ||
323 | .data = {.bytes = {0x50, 0x02}}, | ||
324 | .data_len = 2, | ||
325 | }, | ||
326 | { | ||
327 | .cmd_type = CMD_W, | ||
328 | .addr = 0xAA, | ||
329 | .reg = 0x40, | ||
330 | .data = {.bytes = {0x2C, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x64, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x01, 0x03, 0x5A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
331 | .data_len = 32, | ||
332 | }, | ||
333 | { | ||
334 | .cmd_type = CMD_W, | ||
335 | .addr = 0xAA, | ||
336 | .reg = 0x60, | ||
337 | .data = {.bytes = {0x59}}, | ||
338 | .data_len = 1, | ||
339 | }, | ||
340 | { | ||
341 | .cmd_type = CMD_X, | ||
342 | .data = {.delay = 10}, | ||
343 | }, | ||
344 | { | ||
345 | .cmd_type = CMD_W, | ||
346 | .addr = 0xAA, | ||
347 | .reg = 0x3E, | ||
348 | .data = {.bytes = {0x50, 0x02}}, | ||
349 | .data_len = 2, | ||
350 | }, | ||
351 | { | ||
352 | .cmd_type = CMD_C, | ||
353 | .addr = 0xAA, | ||
354 | .reg = 0x60, | ||
355 | .data = {.bytes = {0x59}}, | ||
356 | .data_len = 1, | ||
357 | }, | ||
358 | { | ||
359 | .cmd_type = CMD_W, | ||
360 | .addr = 0xAA, | ||
361 | .reg = 0x3E, | ||
362 | .data = {.bytes = {0x51, 0x00}}, | ||
363 | .data_len = 2, | ||
364 | }, | ||
365 | { | ||
366 | .cmd_type = CMD_W, | ||
367 | .addr = 0xAA, | ||
368 | .reg = 0x40, | ||
369 | .data = {.bytes = {0x01, 0x77, 0x01, 0x2C, 0x02, 0x58, 0x00, 0x3C, 0x3C, 0x01, 0xB3, 0xB3, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
370 | .data_len = 32, | ||
371 | }, | ||
372 | { | ||
373 | .cmd_type = CMD_W, | ||
374 | .addr = 0xAA, | ||
375 | .reg = 0x60, | ||
376 | .data = {.bytes = {0x90}}, | ||
377 | .data_len = 1, | ||
378 | }, | ||
379 | { | ||
380 | .cmd_type = CMD_X, | ||
381 | .data = {.delay = 10}, | ||
382 | }, | ||
383 | { | ||
384 | .cmd_type = CMD_W, | ||
385 | .addr = 0xAA, | ||
386 | .reg = 0x3E, | ||
387 | .data = {.bytes = {0x51, 0x00}}, | ||
388 | .data_len = 2, | ||
389 | }, | ||
390 | { | ||
391 | .cmd_type = CMD_C, | ||
392 | .addr = 0xAA, | ||
393 | .reg = 0x60, | ||
394 | .data = {.bytes = {0x90}}, | ||
395 | .data_len = 1, | ||
396 | }, | ||
397 | { | ||
398 | .cmd_type = CMD_W, | ||
399 | .addr = 0xAA, | ||
400 | .reg = 0x3E, | ||
401 | .data = {.bytes = {0x52, 0x00}}, | ||
402 | .data_len = 2, | ||
403 | }, | ||
404 | { | ||
405 | .cmd_type = CMD_W, | ||
406 | .addr = 0xAA, | ||
407 | .reg = 0x40, | ||
408 | .data = {.bytes = {0x40, 0x00, 0x02, 0x00, 0x32, 0x81, 0x0C, 0x08, 0x2E, 0x52, 0x0C, 0x1C, 0x00, 0xC8, 0x00, 0x32, 0x00, 0x14, 0x03, 0xE8, 0x01, 0x01, 0x00, 0x00, 0x0A, 0xFF, 0xCE, 0xFF, 0xCE, 0x00, 0x01, 0x00}}, | ||
409 | .data_len = 32, | ||
410 | }, | ||
411 | { | ||
412 | .cmd_type = CMD_W, | ||
413 | .addr = 0xAA, | ||
414 | .reg = 0x60, | ||
415 | .data = {.bytes = {0xAE}}, | ||
416 | .data_len = 1, | ||
417 | }, | ||
418 | { | ||
419 | .cmd_type = CMD_X, | ||
420 | .data = {.delay = 10}, | ||
421 | }, | ||
422 | { | ||
423 | .cmd_type = CMD_W, | ||
424 | .addr = 0xAA, | ||
425 | .reg = 0x3E, | ||
426 | .data = {.bytes = {0x52, 0x00}}, | ||
427 | .data_len = 2, | ||
428 | }, | ||
429 | { | ||
430 | .cmd_type = CMD_C, | ||
431 | .addr = 0xAA, | ||
432 | .reg = 0x60, | ||
433 | .data = {.bytes = {0xAE}}, | ||
434 | .data_len = 1, | ||
435 | }, | ||
436 | { | ||
437 | .cmd_type = CMD_W, | ||
438 | .addr = 0xAA, | ||
439 | .reg = 0x3E, | ||
440 | .data = {.bytes = {0x53, 0x00}}, | ||
441 | .data_len = 2, | ||
442 | }, | ||
443 | { | ||
444 | .cmd_type = CMD_W, | ||
445 | .addr = 0xAA, | ||
446 | .reg = 0x40, | ||
447 | .data = {.bytes = {0x15, 0x07, 0x11, 0x2C, 0xD3, 0xD7, 0xE0, 0xE0, 0xE3, 0xE3, 0xE6, 0xE5, 0xE5, 0xEA, 0xF4, 0xD3, 0xCA, 0xF3, 0xF3, 0xEB, 0xF0, 0xE2, 0xF0, 0xEE, 0xF2, 0xF2, 0xF7, 0xF9, 0xFA, 0xFA, 0xFC, 0xFE}}, | ||
448 | .data_len = 32, | ||
449 | }, | ||
450 | { | ||
451 | .cmd_type = CMD_W, | ||
452 | .addr = 0xAA, | ||
453 | .reg = 0x60, | ||
454 | .data = {.bytes = {0x08}}, | ||
455 | .data_len = 1, | ||
456 | }, | ||
457 | { | ||
458 | .cmd_type = CMD_X, | ||
459 | .data = {.delay = 10}, | ||
460 | }, | ||
461 | { | ||
462 | .cmd_type = CMD_W, | ||
463 | .addr = 0xAA, | ||
464 | .reg = 0x3E, | ||
465 | .data = {.bytes = {0x53, 0x00}}, | ||
466 | .data_len = 2, | ||
467 | }, | ||
468 | { | ||
469 | .cmd_type = CMD_C, | ||
470 | .addr = 0xAA, | ||
471 | .reg = 0x60, | ||
472 | .data = {.bytes = {0x08}}, | ||
473 | .data_len = 1, | ||
474 | }, | ||
475 | { | ||
476 | .cmd_type = CMD_W, | ||
477 | .addr = 0xAA, | ||
478 | .reg = 0x3E, | ||
479 | .data = {.bytes = {0x53, 0x01}}, | ||
480 | .data_len = 2, | ||
481 | }, | ||
482 | { | ||
483 | .cmd_type = CMD_W, | ||
484 | .addr = 0xAA, | ||
485 | .reg = 0x40, | ||
486 | .data = {.bytes = {0xF8, 0xF9, 0xF8, 0xF6, 0xEF, 0xF0, 0xF0, 0xFE, 0xFD, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
487 | .data_len = 32, | ||
488 | }, | ||
489 | { | ||
490 | .cmd_type = CMD_W, | ||
491 | .addr = 0xAA, | ||
492 | .reg = 0x60, | ||
493 | .data = {.bytes = {0xED}}, | ||
494 | .data_len = 1, | ||
495 | }, | ||
496 | { | ||
497 | .cmd_type = CMD_X, | ||
498 | .data = {.delay = 10}, | ||
499 | }, | ||
500 | { | ||
501 | .cmd_type = CMD_W, | ||
502 | .addr = 0xAA, | ||
503 | .reg = 0x3E, | ||
504 | .data = {.bytes = {0x53, 0x01}}, | ||
505 | .data_len = 2, | ||
506 | }, | ||
507 | { | ||
508 | .cmd_type = CMD_C, | ||
509 | .addr = 0xAA, | ||
510 | .reg = 0x60, | ||
511 | .data = {.bytes = {0xED}}, | ||
512 | .data_len = 1, | ||
513 | }, | ||
514 | { | ||
515 | .cmd_type = CMD_W, | ||
516 | .addr = 0xAA, | ||
517 | .reg = 0x3E, | ||
518 | .data = {.bytes = {0x54, 0x00}}, | ||
519 | .data_len = 2, | ||
520 | }, | ||
521 | { | ||
522 | .cmd_type = CMD_W, | ||
523 | .addr = 0xAA, | ||
524 | .reg = 0x40, | ||
525 | .data = {.bytes = {0xFB, 0x1D, 0x05, 0x09, 0x06, 0x03, 0x02, 0xFF, 0x00, 0xFC, 0xFF, 0xFD, 0xFF, 0xFA, 0x0E, 0x19, 0x02, 0x01, 0x02, 0xFB, 0xF5, 0xF5, 0x02, 0x01, 0x05, 0xFE, 0xFB, 0xFD, 0xFE, 0xFC, 0xF7, 0xFB}}, | ||
526 | .data_len = 32, | ||
527 | }, | ||
528 | { | ||
529 | .cmd_type = CMD_W, | ||
530 | .addr = 0xAA, | ||
531 | .reg = 0x60, | ||
532 | .data = {.bytes = {0xE3}}, | ||
533 | .data_len = 1, | ||
534 | }, | ||
535 | { | ||
536 | .cmd_type = CMD_X, | ||
537 | .data = {.delay = 10}, | ||
538 | }, | ||
539 | { | ||
540 | .cmd_type = CMD_W, | ||
541 | .addr = 0xAA, | ||
542 | .reg = 0x3E, | ||
543 | .data = {.bytes = {0x54, 0x00}}, | ||
544 | .data_len = 2, | ||
545 | }, | ||
546 | { | ||
547 | .cmd_type = CMD_C, | ||
548 | .addr = 0xAA, | ||
549 | .reg = 0x60, | ||
550 | .data = {.bytes = {0xE3}}, | ||
551 | .data_len = 1, | ||
552 | }, | ||
553 | { | ||
554 | .cmd_type = CMD_W, | ||
555 | .addr = 0xAA, | ||
556 | .reg = 0x3E, | ||
557 | .data = {.bytes = {0x54, 0x01}}, | ||
558 | .data_len = 2, | ||
559 | }, | ||
560 | { | ||
561 | .cmd_type = CMD_W, | ||
562 | .addr = 0xAA, | ||
563 | .reg = 0x40, | ||
564 | .data = {.bytes = {0xFA, 0xFD, 0xFE, 0x03, 0xFA, 0x0B, 0xFE, 0x03, 0xB9, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
565 | .data_len = 32, | ||
566 | }, | ||
567 | { | ||
568 | .cmd_type = CMD_W, | ||
569 | .addr = 0xAA, | ||
570 | .reg = 0x60, | ||
571 | .data = {.bytes = {0xC7}}, | ||
572 | .data_len = 1, | ||
573 | }, | ||
574 | { | ||
575 | .cmd_type = CMD_X, | ||
576 | .data = {.delay = 10}, | ||
577 | }, | ||
578 | { | ||
579 | .cmd_type = CMD_W, | ||
580 | .addr = 0xAA, | ||
581 | .reg = 0x3E, | ||
582 | .data = {.bytes = {0x54, 0x01}}, | ||
583 | .data_len = 2, | ||
584 | }, | ||
585 | { | ||
586 | .cmd_type = CMD_C, | ||
587 | .addr = 0xAA, | ||
588 | .reg = 0x60, | ||
589 | .data = {.bytes = {0xC7}}, | ||
590 | .data_len = 1, | ||
591 | }, | ||
592 | { | ||
593 | .cmd_type = CMD_W, | ||
594 | .addr = 0xAA, | ||
595 | .reg = 0x3E, | ||
596 | .data = {.bytes = {0x55, 0x00}}, | ||
597 | .data_len = 2, | ||
598 | }, | ||
599 | { | ||
600 | .cmd_type = CMD_W, | ||
601 | .addr = 0xAA, | ||
602 | .reg = 0x40, | ||
603 | .data = {.bytes = {0xFF, 0x4B, 0x01, 0x05, 0x02, 0x06, 0x06, 0xFF, 0x03, 0xFA, 0x01, 0xFD, 0xFA, 0x01, 0x1A, 0xE5, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
604 | .data_len = 32, | ||
605 | }, | ||
606 | { | ||
607 | .cmd_type = CMD_W, | ||
608 | .addr = 0xAA, | ||
609 | .reg = 0x60, | ||
610 | .data = {.bytes = {0x33}}, | ||
611 | .data_len = 1, | ||
612 | }, | ||
613 | { | ||
614 | .cmd_type = CMD_X, | ||
615 | .data = {.delay = 10}, | ||
616 | }, | ||
617 | { | ||
618 | .cmd_type = CMD_W, | ||
619 | .addr = 0xAA, | ||
620 | .reg = 0x3E, | ||
621 | .data = {.bytes = {0x55, 0x00}}, | ||
622 | .data_len = 2, | ||
623 | }, | ||
624 | { | ||
625 | .cmd_type = CMD_C, | ||
626 | .addr = 0xAA, | ||
627 | .reg = 0x60, | ||
628 | .data = {.bytes = {0x33}}, | ||
629 | .data_len = 1, | ||
630 | }, | ||
631 | { | ||
632 | .cmd_type = CMD_W, | ||
633 | .addr = 0xAA, | ||
634 | .reg = 0x3E, | ||
635 | .data = {.bytes = {0x6C, 0x00}}, | ||
636 | .data_len = 2, | ||
637 | }, | ||
638 | { | ||
639 | .cmd_type = CMD_W, | ||
640 | .addr = 0xAA, | ||
641 | .reg = 0x40, | ||
642 | .data = {.bytes = {0xFE, 0xE0, 0x00, 0x00, 0x28, 0x08, 0x42, 0xDF, 0xFE, 0xE5, 0xFB, 0xFD, 0xF8, 0xED, 0x0F, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
643 | .data_len = 32, | ||
644 | }, | ||
645 | { | ||
646 | .cmd_type = CMD_W, | ||
647 | .addr = 0xAA, | ||
648 | .reg = 0x60, | ||
649 | .data = {.bytes = {0xEE}}, | ||
650 | .data_len = 1, | ||
651 | }, | ||
652 | { | ||
653 | .cmd_type = CMD_X, | ||
654 | .data = {.delay = 10}, | ||
655 | }, | ||
656 | { | ||
657 | .cmd_type = CMD_W, | ||
658 | .addr = 0xAA, | ||
659 | .reg = 0x3E, | ||
660 | .data = {.bytes = {0x6C, 0x00}}, | ||
661 | .data_len = 2, | ||
662 | }, | ||
663 | { | ||
664 | .cmd_type = CMD_C, | ||
665 | .addr = 0xAA, | ||
666 | .reg = 0x60, | ||
667 | .data = {.bytes = {0xEE}}, | ||
668 | .data_len = 1, | ||
669 | }, | ||
670 | { | ||
671 | .cmd_type = CMD_W, | ||
672 | .addr = 0xAA, | ||
673 | .reg = 0x3E, | ||
674 | .data = {.bytes = {0x59, 0x00}}, | ||
675 | .data_len = 2, | ||
676 | }, | ||
677 | { | ||
678 | .cmd_type = CMD_W, | ||
679 | .addr = 0xAA, | ||
680 | .reg = 0x40, | ||
681 | .data = {.bytes = {0x00, 0x0D, 0x00, 0x09, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x23, 0x00, 0x15, 0x00, 0x18, 0x00, 0x17, 0x00, 0x17, 0x00, 0x18, 0x00, 0x18, 0x00, 0x16, 0x00, 0x24, 0x00, 0x25, 0x00, 0x5B, 0x00, 0x00}}, | ||
682 | .data_len = 32, | ||
683 | }, | ||
684 | { | ||
685 | .cmd_type = CMD_W, | ||
686 | .addr = 0xAA, | ||
687 | .reg = 0x60, | ||
688 | .data = {.bytes = {0x63}}, | ||
689 | .data_len = 1, | ||
690 | }, | ||
691 | { | ||
692 | .cmd_type = CMD_X, | ||
693 | .data = {.delay = 10}, | ||
694 | }, | ||
695 | { | ||
696 | .cmd_type = CMD_W, | ||
697 | .addr = 0xAA, | ||
698 | .reg = 0x3E, | ||
699 | .data = {.bytes = {0x59, 0x00}}, | ||
700 | .data_len = 2, | ||
701 | }, | ||
702 | { | ||
703 | .cmd_type = CMD_C, | ||
704 | .addr = 0xAA, | ||
705 | .reg = 0x60, | ||
706 | .data = {.bytes = {0x63}}, | ||
707 | .data_len = 1, | ||
708 | }, | ||
709 | { | ||
710 | .cmd_type = CMD_W, | ||
711 | .addr = 0xAA, | ||
712 | .reg = 0x3E, | ||
713 | .data = {.bytes = {0x6D, 0x00}}, | ||
714 | .data_len = 2, | ||
715 | }, | ||
716 | { | ||
717 | .cmd_type = CMD_W, | ||
718 | .addr = 0xAA, | ||
719 | .reg = 0x40, | ||
720 | .data = {.bytes = {0x0E, 0xBB, 0x0E, 0xE3, 0x0E, 0x9C, 0x11, 0x30, 0x10, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
721 | .data_len = 32, | ||
722 | }, | ||
723 | { | ||
724 | .cmd_type = CMD_W, | ||
725 | .addr = 0xAA, | ||
726 | .reg = 0x60, | ||
727 | .data = {.bytes = {0x4C}}, | ||
728 | .data_len = 1, | ||
729 | }, | ||
730 | { | ||
731 | .cmd_type = CMD_X, | ||
732 | .data = {.delay = 10}, | ||
733 | }, | ||
734 | { | ||
735 | .cmd_type = CMD_W, | ||
736 | .addr = 0xAA, | ||
737 | .reg = 0x3E, | ||
738 | .data = {.bytes = {0x6D, 0x00}}, | ||
739 | .data_len = 2, | ||
740 | }, | ||
741 | { | ||
742 | .cmd_type = CMD_C, | ||
743 | .addr = 0xAA, | ||
744 | .reg = 0x60, | ||
745 | .data = {.bytes = {0x4C}}, | ||
746 | .data_len = 1, | ||
747 | }, | ||
748 | { | ||
749 | .cmd_type = CMD_W, | ||
750 | .addr = 0xAA, | ||
751 | .reg = 0x3E, | ||
752 | .data = {.bytes = {0x68, 0x00}}, | ||
753 | .data_len = 2, | ||
754 | }, | ||
755 | { | ||
756 | .cmd_type = CMD_W, | ||
757 | .addr = 0xAA, | ||
758 | .reg = 0x40, | ||
759 | .data = {.bytes = {0x00, 0x00, 0x00, 0x00, 0xD4, 0x86, 0x4A, 0xC6, 0xB4, 0xC2, 0x6E, 0x2B, 0x03, 0x7C, 0x01, 0x48, 0xFD, 0xA3, 0xF6, 0x75, 0x12, 0x58, 0x2D, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xD4, 0x1A, 0x05}}, | ||
760 | .data_len = 32, | ||
761 | }, | ||
762 | { | ||
763 | .cmd_type = CMD_W, | ||
764 | .addr = 0xAA, | ||
765 | .reg = 0x60, | ||
766 | .data = {.bytes = {0xA7}}, | ||
767 | .data_len = 1, | ||
768 | }, | ||
769 | { | ||
770 | .cmd_type = CMD_X, | ||
771 | .data = {.delay = 10}, | ||
772 | }, | ||
773 | { | ||
774 | .cmd_type = CMD_W, | ||
775 | .addr = 0xAA, | ||
776 | .reg = 0x3E, | ||
777 | .data = {.bytes = {0x68, 0x00}}, | ||
778 | .data_len = 2, | ||
779 | }, | ||
780 | { | ||
781 | .cmd_type = CMD_C, | ||
782 | .addr = 0xAA, | ||
783 | .reg = 0x60, | ||
784 | .data = {.bytes = {0xA7}}, | ||
785 | .data_len = 1, | ||
786 | }, | ||
787 | { | ||
788 | .cmd_type = CMD_W, | ||
789 | .addr = 0xAA, | ||
790 | .reg = 0x3E, | ||
791 | .data = {.bytes = {0x68, 0x01}}, | ||
792 | .data_len = 2, | ||
793 | }, | ||
794 | { | ||
795 | .cmd_type = CMD_W, | ||
796 | .addr = 0xAA, | ||
797 | .reg = 0x40, | ||
798 | .data = {.bytes = {0x1C, 0x98, 0x02, 0xD3, 0xFF, 0xB9, 0x30, 0xEF, 0x05, 0x11, 0x05, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3C, 0x00, 0x50, 0x3C, 0x00, 0x64, 0x3C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
799 | .data_len = 32, | ||
800 | }, | ||
801 | { | ||
802 | .cmd_type = CMD_W, | ||
803 | .addr = 0xAA, | ||
804 | .reg = 0x60, | ||
805 | .data = {.bytes = {0xEA}}, | ||
806 | .data_len = 1, | ||
807 | }, | ||
808 | { | ||
809 | .cmd_type = CMD_X, | ||
810 | .data = {.delay = 10}, | ||
811 | }, | ||
812 | { | ||
813 | .cmd_type = CMD_W, | ||
814 | .addr = 0xAA, | ||
815 | .reg = 0x3E, | ||
816 | .data = {.bytes = {0x68, 0x01}}, | ||
817 | .data_len = 2, | ||
818 | }, | ||
819 | { | ||
820 | .cmd_type = CMD_C, | ||
821 | .addr = 0xAA, | ||
822 | .reg = 0x60, | ||
823 | .data = {.bytes = {0xEA}}, | ||
824 | .data_len = 1, | ||
825 | }, | ||
826 | { | ||
827 | .cmd_type = CMD_W, | ||
828 | .addr = 0xAA, | ||
829 | .reg = 0x3E, | ||
830 | .data = {.bytes = {0x69, 0x00}}, | ||
831 | .data_len = 2, | ||
832 | }, | ||
833 | { | ||
834 | .cmd_type = CMD_W, | ||
835 | .addr = 0xAA, | ||
836 | .reg = 0x40, | ||
837 | .data = {.bytes = {0xFF, 0xFF, 0x0B, 0xD6, 0x7E, 0x74, 0x6D, 0xC6, 0x93, 0x0B, 0x0D, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
838 | .data_len = 32, | ||
839 | }, | ||
840 | { | ||
841 | .cmd_type = CMD_W, | ||
842 | .addr = 0xAA, | ||
843 | .reg = 0x60, | ||
844 | .data = {.bytes = {0xCA}}, | ||
845 | .data_len = 1, | ||
846 | }, | ||
847 | { | ||
848 | .cmd_type = CMD_X, | ||
849 | .data = {.delay = 10}, | ||
850 | }, | ||
851 | { | ||
852 | .cmd_type = CMD_W, | ||
853 | .addr = 0xAA, | ||
854 | .reg = 0x3E, | ||
855 | .data = {.bytes = {0x69, 0x00}}, | ||
856 | .data_len = 2, | ||
857 | }, | ||
858 | { | ||
859 | .cmd_type = CMD_C, | ||
860 | .addr = 0xAA, | ||
861 | .reg = 0x60, | ||
862 | .data = {.bytes = {0xCA}}, | ||
863 | .data_len = 1, | ||
864 | }, | ||
865 | { | ||
866 | .cmd_type = CMD_W, | ||
867 | .addr = 0xAA, | ||
868 | .reg = 0x3E, | ||
869 | .data = {.bytes = {0x6B, 0x00}}, | ||
870 | .data_len = 2, | ||
871 | }, | ||
872 | { | ||
873 | .cmd_type = CMD_W, | ||
874 | .addr = 0xAA, | ||
875 | .reg = 0x40, | ||
876 | .data = {.bytes = {0xEF, 0x05, 0x11, 0x05, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3C, 0x00, 0x50, 0x3C, 0x00, 0x64, 0x3C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
877 | .data_len = 32, | ||
878 | }, | ||
879 | { | ||
880 | .cmd_type = CMD_W, | ||
881 | .addr = 0xAA, | ||
882 | .reg = 0x60, | ||
883 | .data = {.bytes = {0x5B}}, | ||
884 | .data_len = 1, | ||
885 | }, | ||
886 | { | ||
887 | .cmd_type = CMD_X, | ||
888 | .data = {.delay = 10}, | ||
889 | }, | ||
890 | { | ||
891 | .cmd_type = CMD_W, | ||
892 | .addr = 0xAA, | ||
893 | .reg = 0x3E, | ||
894 | .data = {.bytes = {0x6B, 0x00}}, | ||
895 | .data_len = 2, | ||
896 | }, | ||
897 | { | ||
898 | .cmd_type = CMD_C, | ||
899 | .addr = 0xAA, | ||
900 | .reg = 0x60, | ||
901 | .data = {.bytes = {0x5B}}, | ||
902 | .data_len = 1, | ||
903 | }, | ||
904 | { | ||
905 | .cmd_type = CMD_W, | ||
906 | .addr = 0xAA, | ||
907 | .reg = 0x3E, | ||
908 | .data = {.bytes = {0x70, 0x00}}, | ||
909 | .data_len = 2, | ||
910 | }, | ||
911 | { | ||
912 | .cmd_type = CMD_W, | ||
913 | .addr = 0xAA, | ||
914 | .reg = 0x40, | ||
915 | .data = {.bytes = {0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, | ||
916 | .data_len = 32, | ||
917 | }, | ||
918 | { | ||
919 | .cmd_type = CMD_W, | ||
920 | .addr = 0xAA, | ||
921 | .reg = 0x60, | ||
922 | .data = {.bytes = {0xFF}}, | ||
923 | .data_len = 1, | ||
924 | }, | ||
925 | { | ||
926 | .cmd_type = CMD_X, | ||
927 | .data = {.delay = 10}, | ||
928 | }, | ||
929 | { | ||
930 | .cmd_type = CMD_W, | ||
931 | .addr = 0xAA, | ||
932 | .reg = 0x3E, | ||
933 | .data = {.bytes = {0x70, 0x00}}, | ||
934 | .data_len = 2, | ||
935 | }, | ||
936 | { | ||
937 | .cmd_type = CMD_C, | ||
938 | .addr = 0xAA, | ||
939 | .reg = 0x60, | ||
940 | .data = {.bytes = {0xFF}}, | ||
941 | .data_len = 1, | ||
942 | }, | ||
943 | }; | ||
944 | //end of const bqfs_cmd_t bqfs_image[] | ||
945 | #endif | ||
diff --git a/drivers/power/bq27426/bqfs_cmd_type.h b/drivers/power/bq27426/bqfs_cmd_type.h new file mode 100644 index 000000000000..b6027ac3ff8b --- /dev/null +++ b/drivers/power/bq27426/bqfs_cmd_type.h | |||
@@ -0,0 +1,42 @@ | |||
1 | |||
2 | |||
3 | #ifndef __BQFS_CMD_TYPE__ | ||
4 | #define __BQFS_CMD_TYPE__ | ||
5 | |||
6 | |||
7 | #define CMD_MAX_DATA_SIZE 110 | ||
8 | #define RETRY_LIMIT 3 | ||
9 | #define CMD_RETRY_DELAY 100 /* in ms */ | ||
10 | |||
11 | #ifdef __GNUC__ | ||
12 | #define __PACKED __attribute__((packed)) | ||
13 | #else | ||
14 | #error "Make sure structure cmd_t is packed" | ||
15 | #endif | ||
16 | |||
17 | typedef enum { | ||
18 | CMD_INVALID = 0, | ||
19 | CMD_R, /* Read */ | ||
20 | CMD_W, /* Write */ | ||
21 | CMD_C, /* Compare */ | ||
22 | CMD_X, /* Delay */ | ||
23 | } cmd_type_t; | ||
24 | |||
25 | /* | ||
26 | * DO NOT change the order of fields - particularly reg | ||
27 | * should be immediately followed by data | ||
28 | */ | ||
29 | typedef struct { | ||
30 | cmd_type_t cmd_type; | ||
31 | u8 addr; | ||
32 | u8 reg; | ||
33 | union { | ||
34 | u8 bytes[CMD_MAX_DATA_SIZE + 1]; | ||
35 | u16 delay; | ||
36 | } data; | ||
37 | u8 data_len; | ||
38 | u16 line_num; | ||
39 | } __PACKED bqfs_cmd_t; | ||
40 | |||
41 | |||
42 | #endif | ||