Commit | Line | Data |
---|---|---|
1cac41cb MB |
1 | /* |
2 | * mfc_charger.c | |
3 | * Samsung MFC IC Charger Driver | |
4 | * | |
5 | * Copyright (C) 2016 Samsung Electronics | |
6 | * | |
7 | * This software is licensed under the terms of the GNU General Public | |
8 | * License version 2, as published by the Free Software Foundation, and | |
9 | * may be copied, distributed, and modified under those terms. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include "include/charger/mfc_charger.h" | |
19 | #include <linux/errno.h> | |
20 | #include <linux/version.h> | |
21 | #include <linux/device.h> | |
22 | #include <linux/pm.h> | |
23 | #include <linux/gpio.h> | |
24 | #include <linux/interrupt.h> | |
25 | #include <linux/i2c.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/slab.h> | |
28 | #include <linux/pm_runtime.h> | |
29 | #include <linux/irqdomain.h> | |
30 | #include <linux/of.h> | |
31 | #include <linux/of_gpio.h> | |
32 | #include <linux/kernel.h> | |
33 | #include <asm/uaccess.h> | |
34 | #include <linux/sysctl.h> | |
35 | #include <linux/proc_fs.h> | |
36 | #include <linux/vmalloc.h> | |
37 | #include <linux/ctype.h> | |
38 | #include <linux/firmware.h> | |
39 | ||
40 | #define ENABLE 1 | |
41 | #define DISABLE 0 | |
42 | #define CMD_CNT 3 | |
43 | ||
44 | int mfc_otp_update = 0; | |
45 | ||
46 | extern bool sleep_mode; | |
47 | ||
48 | static enum power_supply_property mfc_charger_props[] = { | |
49 | }; | |
50 | ||
51 | extern unsigned int lpcharge; | |
52 | int mfc_get_firmware_version(struct mfc_charger_data *charger, int firm_mode); | |
53 | static irqreturn_t mfc_wpc_det_irq_thread(int irq, void *irq_data); | |
54 | static irqreturn_t mfc_wpc_irq_thread(int irq, void *irq_data); | |
55 | ||
56 | #define MAX_I2C_ERROR_COUNT 30 | |
57 | static void mfc_check_i2c_error(struct mfc_charger_data *charger, bool is_error) | |
58 | { | |
59 | charger->i2c_error_count = | |
60 | (charger->wc_w_state && gpio_get_value(charger->pdata->wpc_det) && is_error) ? | |
61 | (charger->i2c_error_count + 1) : 0; | |
62 | ||
63 | if (charger->i2c_error_count > MAX_I2C_ERROR_COUNT) { | |
64 | charger->i2c_error_count = 0; | |
65 | queue_delayed_work(charger->wqueue, &charger->wpc_i2c_error_work, 0); | |
66 | } | |
67 | } | |
68 | ||
69 | static int mfc_reg_read(struct i2c_client *client, u16 reg, u8 *val) | |
70 | { | |
71 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
72 | int ret; | |
73 | struct i2c_msg msg[2]; | |
74 | u8 wbuf[2]; | |
75 | u8 rbuf[2]; | |
76 | ||
77 | msg[0].addr = client->addr; | |
78 | msg[0].flags = client->flags & I2C_M_TEN; | |
79 | msg[0].len = 2; | |
80 | msg[0].buf = wbuf; | |
81 | ||
82 | wbuf[0] = (reg & 0xFF00) >> 8; | |
83 | wbuf[1] = (reg & 0xFF); | |
84 | ||
85 | msg[1].addr = client->addr; | |
86 | msg[1].flags = I2C_M_RD; | |
87 | msg[1].len = 1; | |
88 | msg[1].buf = rbuf; | |
89 | ||
90 | mutex_lock(&charger->io_lock); | |
91 | ret = i2c_transfer(client->adapter, msg, 2); | |
92 | mfc_check_i2c_error(charger, (ret < 0)); | |
93 | mutex_unlock(&charger->io_lock); | |
94 | if (ret < 0) | |
95 | { | |
96 | pr_err("%s: i2c read error, reg: 0x%x, ret: %d (called by %ps)\n", | |
97 | __func__, reg, ret, __builtin_return_address(0)); | |
98 | return -1; | |
99 | } | |
100 | *val = rbuf[0]; | |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
105 | static int mfc_reg_multi_read(struct i2c_client *client, u16 reg, u8 *val, int size) | |
106 | { | |
107 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
108 | int ret; | |
109 | struct i2c_msg msg[2]; | |
110 | u8 wbuf[2]; | |
111 | ||
112 | msg[0].addr = client->addr; | |
113 | msg[0].flags = client->flags & I2C_M_TEN; | |
114 | msg[0].len = 2; | |
115 | msg[0].buf = wbuf; | |
116 | ||
117 | wbuf[0] = (reg & 0xFF00) >> 8; | |
118 | wbuf[1] = (reg & 0xFF); | |
119 | ||
120 | msg[1].addr = client->addr; | |
121 | msg[1].flags = I2C_M_RD; | |
122 | msg[1].len = size; | |
123 | msg[1].buf = val; | |
124 | ||
125 | mutex_lock(&charger->io_lock); | |
126 | ret = i2c_transfer(client->adapter, msg, 2); | |
127 | mfc_check_i2c_error(charger, (ret < 0)); | |
128 | mutex_unlock(&charger->io_lock); | |
129 | if (ret < 0) | |
130 | { | |
131 | pr_err("%s: i2c transfer fail", __func__); | |
132 | return -1; | |
133 | } | |
134 | ||
135 | return ret; | |
136 | } | |
137 | ||
138 | static int mfc_reg_write(struct i2c_client *client, u16 reg, u8 val) | |
139 | { | |
140 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
141 | int ret; | |
142 | unsigned char data[3] = { reg >> 8, reg & 0xff, val }; | |
143 | ||
144 | mutex_lock(&charger->io_lock); | |
145 | ret = i2c_master_send(client, data, 3); | |
146 | mfc_check_i2c_error(charger, (ret < 3)); | |
147 | mutex_unlock(&charger->io_lock); | |
148 | if (ret < 3) { | |
149 | pr_err("%s: i2c write error, reg: 0x%x, ret: %d (called by %ps)\n", | |
150 | __func__, reg, ret, __builtin_return_address(0)); | |
151 | return ret < 0 ? ret : -EIO; | |
152 | } | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | static int mfc_reg_update(struct i2c_client *client, u16 reg, u8 val, u8 mask) | |
158 | { | |
159 | //val = 0b 0000 0001 | |
160 | //ms = 0b 1111 1110 | |
161 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
162 | unsigned char data[3] = { reg >> 8, reg & 0xff, val }; | |
163 | u8 data2; | |
164 | int ret; | |
165 | ||
166 | ret = mfc_reg_read(client, reg, &data2); | |
167 | if (ret >= 0) { | |
168 | u8 old_val = data2 & 0xff; | |
169 | u8 new_val = (val & mask) | (old_val & (~mask)); | |
170 | data[2] = new_val; | |
171 | ||
172 | mutex_lock(&charger->io_lock); | |
173 | ret = i2c_master_send(client, data, 3); | |
174 | mfc_check_i2c_error(charger, (ret < 3)); | |
175 | mutex_unlock(&charger->io_lock); | |
176 | if (ret < 3) { | |
177 | pr_err("%s: i2c write error, reg: 0x%x, ret: %d\n", | |
178 | __func__, reg, ret); | |
179 | return ret < 0 ? ret : -EIO; | |
180 | } | |
181 | } | |
182 | mfc_reg_read(client, reg, &data2); | |
183 | ||
184 | return ret; | |
185 | } | |
186 | //// | |
187 | int mfc_get_firmware_version(struct mfc_charger_data *charger, int firm_mode) | |
188 | { | |
189 | int version = -1; | |
190 | int ret; | |
191 | u8 fw_major[2] = {0,}; | |
192 | u8 fw_minor[2] = {0,}; | |
193 | ||
194 | pr_info("%s: called by (%ps)\n", __func__, __builtin_return_address(0)); | |
195 | switch (firm_mode) { | |
196 | case MFC_RX_FIRMWARE: | |
197 | ret = mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_L_REG, &fw_major[0]); | |
198 | ret = mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_H_REG, &fw_major[1]); | |
199 | if (ret >= 0) { | |
200 | version = fw_major[0] | (fw_major[1] << 8); | |
201 | } | |
202 | pr_info("%s rx major firmware version 0x%x \n", __func__, version); | |
203 | ||
204 | ret = mfc_reg_read(charger->client, MFC_FW_MINOR_REV_L_REG, &fw_minor[0]); | |
205 | ret = mfc_reg_read(charger->client, MFC_FW_MINOR_REV_H_REG, &fw_minor[1]); | |
206 | if (ret >= 0) { | |
207 | version = fw_minor[0] | (fw_minor[1] << 8); | |
208 | } | |
209 | pr_info("%s rx minor firmware version 0x%x \n", __func__, version); | |
210 | break; | |
211 | default: | |
212 | pr_err("%s Wrong firmware mode \n", __func__); | |
213 | version = -1; | |
214 | break; | |
215 | } | |
216 | ||
217 | return version; | |
218 | } | |
219 | int mfc_get_chip_id(struct mfc_charger_data *charger) | |
220 | { | |
221 | u8 chip_id; | |
222 | ||
223 | mfc_reg_read(charger->client, MFC_CHIP_ID_L_REG, &chip_id); | |
224 | if (chip_id == 0x40) { | |
225 | charger->chip_id = MFC_CHIP_LSI; | |
226 | pr_info("%s: LSI CHIP\n", __func__); | |
227 | } else { /* 0x20 */ | |
228 | charger->chip_id = MFC_CHIP_IDT; | |
229 | pr_info("%s: IDT CHIP\n", __func__); | |
230 | } | |
231 | return charger->chip_id; | |
232 | } | |
233 | int mfc_get_ic_revision(struct mfc_charger_data *charger, int read_mode) | |
234 | { | |
235 | u8 temp; | |
236 | int ret; | |
237 | ||
238 | pr_info("%s: called by (%ps)\n", __func__, __builtin_return_address(0)); | |
239 | ||
240 | switch (read_mode) { | |
241 | case MFC_IC_REVISION: | |
242 | ret = mfc_reg_read(charger->client, MFC_CHIP_REVISION_REG, &temp); | |
243 | ||
244 | if(ret >= 0) { | |
245 | temp &= MFC_CHIP_REVISION_MASK; | |
246 | pr_info("%s ic revision = %d \n", __func__, temp); | |
247 | ret = temp; | |
248 | } | |
249 | else | |
250 | ret = -1; | |
251 | break; | |
252 | case MFC_IC_FONT: | |
253 | ret = mfc_reg_read(charger->client, MFC_CHIP_REVISION_REG, &temp); | |
254 | ||
255 | if(ret >= 0) { | |
256 | temp &= MFC_CHIP_FONT_MASK; | |
257 | pr_info("%s ic font = %d \n", __func__, temp); | |
258 | ret = temp; | |
259 | } | |
260 | else | |
261 | ret = -1; | |
262 | break; | |
263 | default : | |
264 | ret = -1; | |
265 | break; | |
266 | } | |
267 | return ret; | |
268 | } | |
269 | ||
270 | int mfc_get_adc(struct mfc_charger_data *charger, int adc_type) | |
271 | { | |
272 | int ret = 0; | |
273 | u8 data[2] = {0,}; | |
274 | ||
275 | switch (adc_type) { | |
276 | case MFC_ADC_VOUT: | |
277 | ret = mfc_reg_read(charger->client, MFC_ADC_VOUT_L_REG, &data[0]); | |
278 | ret = mfc_reg_read(charger->client, MFC_ADC_VOUT_H_REG, &data[1]); | |
279 | if(ret >= 0 ) { | |
280 | ret = (data[0] | (data[1] << 8)); | |
281 | } else | |
282 | ret = -1; | |
283 | break; | |
284 | case MFC_ADC_VRECT: | |
285 | ret = mfc_reg_read(charger->client, MFC_ADC_VRECT_L_REG, &data[0]); | |
286 | ret = mfc_reg_read(charger->client, MFC_ADC_VRECT_H_REG, &data[1]); | |
287 | if(ret >= 0 ) { | |
288 | ret = (data[0] | (data[1] << 8)); | |
289 | } else | |
290 | ret = -1; | |
291 | break; | |
292 | case MFC_ADC_TX_ISENSE: | |
293 | ret = mfc_reg_read(charger->client, MFC_ADC_TX_ISENSE_L_REG, &data[0]); | |
294 | ret = mfc_reg_read(charger->client, MFC_ADC_TX_ISENSE_H_REG, &data[1]); | |
295 | if(ret >= 0 ) { | |
296 | ret = (data[0] | (data[1] << 8)); | |
297 | } else | |
298 | ret = -1; | |
299 | break; | |
300 | case MFC_ADC_RX_IOUT: | |
301 | ret = mfc_reg_read(charger->client, MFC_ADC_RX_IOUT_L_REG, &data[0]); | |
302 | ret = mfc_reg_read(charger->client, MFC_ADC_RX_IOUT_H_REG, &data[1]); | |
303 | if(ret >= 0 ) { | |
304 | ret = (data[0] | (data[1] << 8)); | |
305 | } else | |
306 | ret = -1; | |
307 | break; | |
308 | case MFC_ADC_DIE_TEMP: | |
309 | /* only 4 MSB[3:0] field is used, Celsius */ | |
310 | ret = mfc_reg_read(charger->client, MFC_ADC_DIE_TEMP_L_REG, &data[0]); | |
311 | ret = mfc_reg_read(charger->client, MFC_ADC_DIE_TEMP_H_REG, &data[1]); | |
312 | if(ret >= 0 ) { | |
313 | data[1] &= 0x0f; | |
314 | ret = (data[0] | (data[1] << 8)); | |
315 | } else | |
316 | ret = -1; | |
317 | break; | |
318 | case MFC_ADC_OP_FRQ: /* kHz */ | |
319 | ret = mfc_reg_read(charger->client, MFC_RX_OP_FREQ_L_REG, &data[0]); | |
320 | ret = mfc_reg_read(charger->client, MFC_RX_OP_FREQ_H_REG, &data[1]); | |
321 | if(ret >= 0 ) { | |
322 | ret = (data[0] | (data[1] << 8)); | |
323 | } else | |
324 | ret = -1; | |
325 | break; | |
326 | case MFC_ADC_PING_FRQ: | |
327 | ret = mfc_reg_read(charger->client, MFC_RX_PING_FREQ_L_REG, &data[0]); | |
328 | ret = mfc_reg_read(charger->client, MFC_RX_PING_FREQ_H_REG, &data[0]); | |
329 | if(ret >= 0 ) { | |
330 | ret = (data[0] | (data[1] << 8)); | |
331 | } else | |
332 | ret = -1; | |
333 | default: | |
334 | break; | |
335 | } | |
336 | ||
337 | return ret; | |
338 | } | |
339 | ||
340 | void mfc_set_vout(struct mfc_charger_data *charger, int vout) | |
341 | { | |
342 | switch (vout) { | |
343 | case MFC_VOUT_5V: | |
344 | case MFC_VOUT_5_5V: | |
345 | case MFC_VOUT_6V: | |
346 | case MFC_VOUT_7V: | |
347 | case MFC_VOUT_8V: | |
348 | case MFC_VOUT_9V: | |
349 | case MFC_VOUT_10V: | |
350 | if (charger->chip_id == MFC_CHIP_IDT) | |
351 | mfc_reg_write(charger->client, MFC_VOUT_SET_REG, mfc_idt_vout_val[vout]); | |
352 | else /* LSI */ | |
353 | mfc_reg_write(charger->client, MFC_VOUT_SET_REG, mfc_lsi_vout_val[vout]); | |
354 | msleep(100); | |
355 | break; | |
356 | default: | |
357 | break; | |
358 | } | |
359 | ||
360 | pr_info("%s vout(%d) read = %d mV \n", __func__, vout, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
361 | charger->pdata->vout_status = vout; | |
362 | } | |
363 | ||
364 | int mfc_get_vout(struct mfc_charger_data *charger) | |
365 | { | |
366 | u8 data; | |
367 | int ret; | |
368 | ret = mfc_reg_read(charger->client, MFC_VOUT_SET_REG, &data); | |
369 | if (ret < 0) { | |
370 | pr_err("%s: fail to read vout. (%d)\n", __func__, ret); | |
371 | return ret; | |
372 | } else | |
373 | pr_info("%s: vout(0x%x)\n", __func__, data); | |
374 | ||
375 | return data; | |
376 | } | |
377 | void mfc_rpp_set(struct mfc_charger_data *charger) | |
378 | { | |
379 | u8 data; | |
380 | int ret; | |
381 | ||
382 | if (charger->led_cover) { | |
383 | pr_info("%s: LED cover exists. RPP 3/4 (0x%x)\n", __func__, charger->pdata->wc_cover_rpp); | |
384 | mfc_reg_write(charger->client, MFC_RPP_SCALE_COEF_REG, charger->pdata->wc_cover_rpp); | |
385 | } else { | |
386 | pr_info("%s: LED cover not exists. RPP 1/2 (0x%x)\n", __func__, charger->pdata->wc_hv_rpp); | |
387 | mfc_reg_write(charger->client, MFC_RPP_SCALE_COEF_REG, charger->pdata->wc_hv_rpp); | |
388 | } | |
389 | msleep(5); | |
390 | ret = mfc_reg_read(charger->client, MFC_RPP_SCALE_COEF_REG, &data); | |
391 | if (ret < 0) { | |
392 | pr_err("%s: fail to read RPP scaling coefficient. (%d)\n", __func__, ret); | |
393 | } else | |
394 | pr_info("%s: RPP scaling coefficient(0x%x)\n", __func__, data); | |
395 | } | |
396 | ||
397 | void mfc_fod_set(struct mfc_charger_data *charger) | |
398 | { | |
399 | int i = 0; | |
400 | pr_info("%s \n", __func__); | |
401 | ||
402 | switch (charger->pdata->cable_type) { | |
403 | case MFC_PAD_A4WP: | |
404 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
405 | mfc_reg_write(charger->client, MFC_A4WP_FOD_0A_REG+i, charger->pdata->fod_a4wp_data[i]); | |
406 | } | |
407 | break; | |
408 | ||
409 | /* need to unify WPC and PMA */ | |
410 | case MFC_PAD_PMA: | |
411 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
412 | mfc_reg_write(charger->client, MFC_PMA_FOD_0A_REG+i, charger->pdata->fod_pma_data[i]); | |
413 | } | |
414 | break; | |
415 | ||
416 | case MFC_PAD_WPC: | |
417 | case MFC_PAD_WPC_AFC: | |
418 | case MFC_PAD_WPC_PACK: | |
419 | case MFC_PAD_WPC_PACK_HV: | |
420 | case MFC_PAD_WPC_STAND: | |
421 | case MFC_PAD_WPC_STAND_HV: | |
422 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
423 | mfc_reg_write(charger->client, MFC_WPC_FOD_0A_REG+i, charger->pdata->fod_wpc_data[i]); | |
424 | } | |
425 | break; | |
426 | ||
427 | case MFC_PAD_NONE: | |
428 | default: | |
429 | break; | |
430 | } | |
431 | ||
432 | } | |
433 | ||
434 | void mfc_fod_set_cv(struct mfc_charger_data *charger) | |
435 | { | |
436 | int i = 0; | |
437 | ||
438 | pr_info("%s \n", __func__); | |
439 | switch (charger->pdata->cable_type) { | |
440 | case MFC_PAD_A4WP: | |
441 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
442 | mfc_reg_write(charger->client, MFC_A4WP_FOD_0A_REG+i, charger->pdata->fod_a4wp_data_cv[i]); | |
443 | } | |
444 | break; | |
445 | /* need to unify WPC and PMA */ | |
446 | case MFC_PAD_PMA: | |
447 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
448 | mfc_reg_write(charger->client, MFC_PMA_FOD_0A_REG+i, charger->pdata->fod_pma_data_cv[i]); | |
449 | } | |
450 | break; | |
451 | ||
452 | case MFC_PAD_WPC: | |
453 | case MFC_PAD_WPC_AFC: | |
454 | case MFC_PAD_WPC_PACK: | |
455 | case MFC_PAD_WPC_PACK_HV: | |
456 | case MFC_PAD_WPC_STAND: | |
457 | case MFC_PAD_WPC_STAND_HV: | |
458 | case MFC_PAD_NONE: | |
459 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
460 | mfc_reg_write(charger->client, MFC_WPC_FOD_0A_REG+i, charger->pdata->fod_wpc_data_cv[i]); | |
461 | } | |
462 | break; | |
463 | ||
464 | default: | |
465 | break; | |
466 | } | |
467 | ||
468 | } | |
469 | ||
470 | void mfc_fod_set_cs100(struct mfc_charger_data *charger) | |
471 | { | |
472 | int i = 0; | |
473 | ||
474 | pr_info("%s \n", __func__); | |
475 | ||
476 | switch (charger->pdata->cable_type) { | |
477 | case MFC_PAD_A4WP: | |
478 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
479 | mfc_reg_write(charger->client, MFC_A4WP_FOD_0A_REG+i, 0x7f); | |
480 | } | |
481 | break; | |
482 | /* need to unify WPC and PMA */ | |
483 | case MFC_PAD_PMA: | |
484 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
485 | mfc_reg_write(charger->client, MFC_PMA_FOD_0A_REG+i, 0x7f); | |
486 | } | |
487 | break; | |
488 | ||
489 | case MFC_PAD_WPC: | |
490 | case MFC_PAD_WPC_AFC: | |
491 | case MFC_PAD_WPC_PACK: | |
492 | case MFC_PAD_WPC_PACK_HV: | |
493 | case MFC_PAD_WPC_STAND: | |
494 | case MFC_PAD_WPC_STAND_HV: | |
495 | case MFC_PAD_NONE: | |
496 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
497 | mfc_reg_write(charger->client, MFC_WPC_FOD_0A_REG+i, 0x7f); | |
498 | } | |
499 | break; | |
500 | default: | |
501 | break; | |
502 | } | |
503 | ||
504 | } | |
505 | ||
506 | void mfc_fod_set_hero_5v(struct mfc_charger_data *charger) | |
507 | { | |
508 | int i = 0; | |
509 | u8 fod[12] = {0, }; | |
510 | ||
511 | pr_info("%s \n", __func__); | |
512 | ||
513 | if (charger->pdata->fod_hero_5v_data) { | |
514 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
515 | mfc_reg_write(charger->client, MFC_WPC_FOD_0A_REG+i, charger->pdata->fod_hero_5v_data[i]); | |
516 | } | |
517 | msleep(2); | |
518 | for(i=0; i< MFC_NUM_FOD_REG; i++) { | |
519 | mfc_reg_read(charger->client, MFC_WPC_FOD_0A_REG+i, &fod[i]); | |
520 | } | |
521 | pr_info("%s: HERO 5V FOD(%d %d %d %d %d %d %d %d %d %d %d %d)\n", __func__, | |
522 | fod[0], fod[1], fod[2], fod[3], fod[4], fod[5], fod[6], fod[7], fod[8], fod[9], fod[10], fod[11]); | |
523 | } | |
524 | } | |
525 | ||
526 | void mfc_set_cmd_l_reg(struct mfc_charger_data *charger, u8 val, u8 mask) | |
527 | { | |
528 | u8 temp = 0; | |
529 | int ret = 0, i = 0; | |
530 | ||
531 | do { | |
532 | pr_info("%s \n", __func__); | |
533 | ret = mfc_reg_update(charger->client, MFC_AP2MFC_CMD_L_REG, val, mask); // command | |
534 | if(ret >= 0) { | |
535 | ret = mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &temp); // check out set bit exists | |
536 | if(ret < 0 || i > 3 ) | |
537 | break; | |
538 | } | |
539 | i++; | |
540 | } while ((temp != 0) && (i < 3)); | |
541 | } | |
542 | ||
543 | void mfc_set_cmd_h_reg(struct mfc_charger_data *charger, u8 val, u8 mask) | |
544 | { | |
545 | u8 temp = 0; | |
546 | int ret = 0, i = 0; | |
547 | ||
548 | do { | |
549 | pr_info("%s \n", __func__); | |
550 | ret = mfc_reg_update(charger->client, MFC_AP2MFC_CMD_H_REG, val, mask); // command | |
551 | if(ret >= 0) { | |
552 | msleep(250); | |
553 | ret = mfc_reg_read(charger->client, MFC_AP2MFC_CMD_H_REG, &temp); // check out set bit exists | |
554 | if(ret < 0 || i > 3 ) | |
555 | break; | |
556 | } | |
557 | i++; | |
558 | } while ((temp != 0) && (i < 3)); | |
559 | } | |
560 | ||
561 | void mfc_send_eop(struct mfc_charger_data *charger, int health_mode) | |
562 | { | |
563 | int i = 0; | |
564 | int ret = 0; | |
565 | ||
566 | pr_info("%s: health_mode (0x%x)\n", __func__, health_mode); | |
567 | switch(health_mode) { | |
568 | case POWER_SUPPLY_HEALTH_OVERHEAT: | |
569 | case POWER_SUPPLY_HEALTH_OVERHEATLIMIT: | |
570 | case POWER_SUPPLY_HEALTH_COLD: | |
571 | if (charger->pdata->cable_type == MFC_PAD_PMA) { | |
572 | pr_info("%s pma mode\n", __func__); | |
573 | for (i = 0; i < CMD_CNT; i++) { | |
574 | ret = mfc_reg_write(charger->client, MFC_EPT_REG, MFC_WPC_EPT_END_OF_CHG); | |
575 | if (ret >= 0) { | |
576 | mfc_set_cmd_l_reg(charger, MFC_CMD_SEND_EOP_MASK, MFC_CMD_SEND_EOP_MASK); | |
577 | msleep(250); | |
578 | } else | |
579 | break; | |
580 | } | |
581 | } else if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
582 | pr_info("%s a4wp mode\n", __func__); | |
583 | } else { | |
584 | pr_info("%s wpc mode\n", __func__); | |
585 | for (i = 0; i < CMD_CNT; i++) { | |
586 | ret = mfc_reg_write(charger->client, MFC_EPT_REG, MFC_WPC_EPT_OVER_TEMP); | |
587 | if (ret >= 0) { | |
588 | mfc_set_cmd_l_reg(charger, MFC_CMD_SEND_EOP_MASK, MFC_CMD_SEND_EOP_MASK); | |
589 | msleep(250); | |
590 | } else | |
591 | break; | |
592 | } | |
593 | } | |
594 | break; | |
595 | case POWER_SUPPLY_HEALTH_UNDERVOLTAGE: | |
596 | break; | |
597 | default: | |
598 | break; | |
599 | } | |
600 | } | |
601 | ||
602 | void mfc_send_packet(struct mfc_charger_data *charger, u8 header, u8 rx_data_com, u8 *data_val, int data_size) | |
603 | { | |
604 | int i; | |
605 | ||
606 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
607 | /* set AP2BT COM, and VALUE, and trigger INT_B */ | |
608 | mfc_reg_write(charger->client, MFC_AP2BT_DATA_COM_REG, rx_data_com); | |
609 | for(i = 0; i< data_size; i++) { | |
610 | mfc_reg_write(charger->client, MFC_AP2BT_DATA_VALUE0_REG+ i, data_val[i]); | |
611 | } | |
612 | mfc_set_cmd_l_reg(charger, MFC_CMD_AP2BT_DATA_MASK, MFC_CMD_AP2BT_DATA_MASK); | |
613 | } else { | |
614 | mfc_reg_write(charger->client, MFC_WPC_PCKT_HEADER_REG, header); | |
615 | mfc_reg_write(charger->client, MFC_WPC_RX_DATA_COM_REG, rx_data_com); | |
616 | ||
617 | for(i = 0; i< data_size; i++) { | |
618 | mfc_reg_write(charger->client, MFC_WPC_RX_DATA_VALUE0_REG+ i, data_val[i]); | |
619 | } | |
620 | mfc_set_cmd_l_reg(charger, MFC_CMD_SEND_RX_DATA_MASK, MFC_CMD_SEND_RX_DATA_MASK); | |
621 | } | |
622 | } | |
623 | ||
624 | int mfc_send_cs100(struct mfc_charger_data *charger) | |
625 | { | |
626 | int i = 0; | |
627 | int ret = 0; | |
628 | u8 data_val[2]; | |
629 | ||
630 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
631 | data_val[0] = 0x80; /* charge complete */ | |
632 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, AP2BT_COM_CHG_STATUS, data_val, 1); | |
633 | } | |
634 | for(i = 0; i < CMD_CNT; i++) { | |
635 | ret = mfc_reg_write(charger->client, MFC_BATTERY_CHG_STATUS_REG, 100); | |
636 | if(ret >= 0) { | |
637 | mfc_set_cmd_l_reg(charger, MFC_CMD_SEND_CHG_STS_MASK, MFC_CMD_SEND_CHG_STS_MASK); | |
638 | msleep(250); | |
639 | ret = 1; | |
640 | } else { | |
641 | ret = -1; | |
642 | break; | |
643 | } | |
644 | } | |
645 | return ret; | |
646 | } | |
647 | ||
648 | void mfc_send_command(struct mfc_charger_data *charger, int cmd_mode) | |
649 | { | |
650 | u8 data_val[4]; | |
651 | u8 cmd = 0; | |
652 | ||
653 | switch (cmd_mode) { | |
654 | case MFC_AFC_CONF_5V: | |
655 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
656 | pr_info("%s: A4WP set 5V\n", __func__); | |
657 | cmd = AP2BT_COM_AFC_MODE; | |
658 | data_val[0] = 0x00; /* Value for A4WP AFC_SET 5V */ | |
659 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
660 | msleep(120); | |
661 | ||
662 | charger->vout_mode = WIRELESS_VOUT_5V; | |
663 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
664 | wake_lock(&charger->wpc_vout_mode_lock); | |
665 | queue_delayed_work(charger->wqueue, | |
666 | &charger->wpc_vout_mode_work, 0); | |
667 | pr_info("%s vout read = %d\n", __func__, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
668 | ||
669 | mfc_reg_read(charger->client, MFC_AP2BT_DATA_COM_REG, &data_val[0]); | |
670 | mfc_reg_read(charger->client, MFC_AP2BT_DATA_VALUE0_REG, &data_val[0]); | |
671 | mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &data_val[0]); | |
672 | } else { | |
673 | pr_info("%s: WPC/PMA set 5V\n", __func__); | |
674 | cmd = WPC_COM_AFC_SET; | |
675 | data_val[0] = 0x05; /* Value for WPC AFC_SET 5V */ | |
676 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
677 | msleep(120); | |
678 | ||
679 | charger->vout_mode = WIRELESS_VOUT_5V; | |
680 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
681 | wake_lock(&charger->wpc_vout_mode_lock); | |
682 | queue_delayed_work(charger->wqueue, | |
683 | &charger->wpc_vout_mode_work, 0); | |
684 | pr_info("%s vout read = %d\n", __func__, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
685 | ||
686 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_COM_REG, &data_val[0]); | |
687 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_VALUE0_REG, &data_val[0]); | |
688 | mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &data_val[0]); | |
689 | } | |
690 | break; | |
691 | case MFC_AFC_CONF_10V: | |
692 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { /* PAD : A4WP */ | |
693 | pr_info("%s: A4WP set 10V\n", __func__); | |
694 | cmd = AP2BT_COM_AFC_MODE; | |
695 | data_val[0] = 0x01; /* Value for A4WP AFC_SET 10V */ | |
696 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
697 | msleep(120); | |
698 | ||
699 | charger->vout_mode = WIRELESS_VOUT_10V; | |
700 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
701 | wake_lock(&charger->wpc_vout_mode_lock); | |
702 | queue_delayed_work(charger->wqueue, | |
703 | &charger->wpc_vout_mode_work, 0); | |
704 | pr_info("%s vout read = %d\n", __func__, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
705 | ||
706 | mfc_reg_read(charger->client, MFC_AP2BT_DATA_COM_REG, &data_val[0]); | |
707 | mfc_reg_read(charger->client, MFC_AP2BT_DATA_VALUE0_REG, &data_val[0]); | |
708 | mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &data_val[0]); | |
709 | } else { /* PAD : WPC, PMA */ | |
710 | pr_info("%s: WPC set 10V\n", __func__); | |
711 | //trigger 10V vout work after 8sec | |
712 | wake_lock(&charger->wpc_afc_vout_lock); | |
713 | #if defined(CONFIG_SEC_FACTORY) | |
714 | queue_delayed_work(charger->wqueue, &charger->wpc_afc_vout_work, msecs_to_jiffies(0)); | |
715 | #else | |
716 | queue_delayed_work(charger->wqueue, &charger->wpc_afc_vout_work, msecs_to_jiffies(8000)); | |
717 | #endif | |
718 | } | |
719 | break; | |
720 | case MFC_LED_CONTROL_ON: | |
721 | pr_info("%s led on\n", __func__); | |
722 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
723 | cmd = AP2BT_COM_LED_CONTROL; | |
724 | data_val[0] = 0x00; /* Value for A4WP LED ON */ | |
725 | } else { | |
726 | cmd = WPC_COM_LED_CONTROL; | |
727 | data_val[0] = 0x00; /* Value for WPC LED ON */ | |
728 | } | |
729 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
730 | break; | |
731 | case MFC_LED_CONTROL_OFF: | |
732 | pr_info("%s led off\n", __func__); | |
733 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
734 | cmd = AP2BT_COM_LED_CONTROL; | |
735 | data_val[0] = 0xff; /* Value for A4WP LED OFF */ | |
736 | } else { | |
737 | cmd = WPC_COM_LED_CONTROL; | |
738 | data_val[0] = 0xff; /* Value for WPC LED OFF */ | |
739 | } | |
740 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
741 | break; | |
742 | case MFC_FAN_CONTROL_ON: | |
743 | pr_info("%s fan on\n", __func__); | |
744 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
745 | cmd = AP2BT_COM_COOLING_CTRL; | |
746 | data_val[0] = 0x00; /* Value for A4WP FAN ON */ | |
747 | } else { | |
748 | cmd = WPC_COM_COOLING_CTRL; | |
749 | data_val[0] = 0x00; /* Value for WPC FAN ON */ | |
750 | } | |
751 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
752 | break; | |
753 | case MFC_FAN_CONTROL_OFF: | |
754 | pr_info("%s fan off\n", __func__); | |
755 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
756 | cmd = AP2BT_COM_COOLING_CTRL; | |
757 | data_val[0] = 0xff; /* Value for A4WP FAN OFF */ | |
758 | } else { | |
759 | cmd = WPC_COM_COOLING_CTRL; | |
760 | data_val[0] = 0xff; /* Value for WPC FAN OFF */ | |
761 | } | |
762 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
763 | ||
764 | break; | |
765 | case MFC_REQUEST_AFC_TX: | |
766 | pr_info("%s request afc tx, cable(0x%x)\n", __func__, charger->pdata->cable_type); | |
767 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
768 | cmd = AP2BT_COM_REQ_AFC_TX; | |
769 | data_val[0] = 0x00; /* Value for A4WP Request AFC_TX */ | |
770 | } else { | |
771 | cmd = WPC_COM_REQ_AFC_TX; | |
772 | data_val[0] = 0x00; /* Value for WPC Request AFC_TX */ | |
773 | } | |
774 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
775 | break; | |
776 | case MFC_REQUEST_TX_ID: | |
777 | pr_info("%s request TX ID\n", __func__); | |
778 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
779 | cmd = AP2BT_COM_TX_ID; | |
780 | data_val[0] = 0x00; /* Value for A4WP TX ID */ | |
781 | } else { | |
782 | cmd = WPC_COM_TX_ID; | |
783 | data_val[0] = 0x00; /* Value for WPC TX ID */ | |
784 | } | |
785 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
786 | break; | |
787 | case MFC_PHM_ON: | |
788 | pr_info("%s Enter PHM\n", __func__); | |
789 | cmd = WPC_COM_ENTER_PHM; | |
790 | data_val[0] = 0x01; /* Enter PHM */ | |
791 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
792 | break; | |
793 | default: | |
794 | break; | |
795 | } | |
796 | } | |
797 | ||
798 | void mfc_led_control(struct mfc_charger_data *charger, bool on) | |
799 | { | |
800 | int i = 0; | |
801 | ||
802 | if(on) { | |
803 | for(i=0; i< CMD_CNT; i++) | |
804 | mfc_send_command(charger, MFC_LED_CONTROL_ON); | |
805 | } else { | |
806 | for(i=0; i< CMD_CNT; i++) | |
807 | mfc_send_command(charger, MFC_LED_CONTROL_OFF); | |
808 | } | |
809 | } | |
810 | ||
811 | void mfc_fan_control(struct mfc_charger_data *charger, bool on) | |
812 | { | |
813 | int i = 0; | |
814 | ||
815 | if(on) { | |
816 | for(i=0; i< CMD_CNT -1; i++) | |
817 | mfc_send_command(charger, MFC_FAN_CONTROL_ON); | |
818 | } else { | |
819 | for(i=0; i< CMD_CNT -1; i++) | |
820 | mfc_send_command(charger, MFC_FAN_CONTROL_OFF); | |
821 | } | |
822 | } | |
823 | ||
824 | void mfc_set_vrect_adjust(struct mfc_charger_data *charger, int set) | |
825 | { | |
826 | int i = 0; | |
827 | ||
828 | switch (set) { | |
829 | case MFC_HEADROOM_0: | |
830 | for(i=0; i<6; i++) { | |
831 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x0); | |
832 | msleep(50); | |
833 | } | |
834 | break; | |
835 | case MFC_HEADROOM_1: | |
836 | for(i=0; i<6; i++) { | |
837 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x36); | |
838 | msleep(50); | |
839 | } | |
840 | break; | |
841 | case MFC_HEADROOM_2: | |
842 | for(i=0; i<6; i++) { | |
843 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x61); | |
844 | msleep(50); | |
845 | } | |
846 | break; | |
847 | case MFC_HEADROOM_3: | |
848 | for(i=0; i<6; i++) { | |
849 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x7f); | |
850 | msleep(50); | |
851 | } | |
852 | break; | |
853 | case MFC_HEADROOM_4: | |
854 | for(i=0; i<6; i++) { | |
855 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x06); | |
856 | msleep(50); | |
857 | } | |
858 | break; | |
859 | case MFC_HEADROOM_5: | |
860 | for(i=0; i<6; i++) { | |
861 | mfc_reg_write(charger->client, MFC_VRECT_ADJ_REG, 0x10); | |
862 | msleep(50); | |
863 | } | |
864 | break; | |
865 | default: | |
866 | pr_info("%s no headroom mode\n", __func__); | |
867 | break; | |
868 | } | |
869 | } | |
870 | ||
871 | void mfc_mis_align(struct mfc_charger_data *charger) | |
872 | { | |
873 | pr_info("%s: Reset M0\n",__func__); | |
874 | if (charger->pdata->cable_type == MFC_PAD_WPC_AFC || | |
875 | charger->pdata->cable_type == MFC_PAD_PMA) | |
876 | /* reset MCU of MFC IC */ | |
877 | mfc_set_cmd_l_reg(charger, MFC_CMD_MCU_RESET_MASK, MFC_CMD_MCU_RESET_MASK); | |
878 | } | |
879 | ||
880 | static int datacmp(const char *cs, const char *ct, int count) | |
881 | { | |
882 | unsigned char c1, c2; | |
883 | ||
884 | while (count) { | |
885 | c1 = *cs++; | |
886 | c2 = *ct++; | |
887 | if (c1 != c2) { | |
888 | pr_err("%s, cnt %d\n", __func__, count); | |
889 | return c1 < c2 ? -1 : 1; | |
890 | } | |
891 | count--; | |
892 | } | |
893 | return 0; | |
894 | } | |
895 | ||
896 | static int mfc_reg_multi_write_verify(struct i2c_client *client, u16 reg, const u8 * val, int size) | |
897 | { | |
898 | int ret = 0; | |
899 | const int sendsz = 16; | |
900 | int cnt = 0; | |
901 | int retry_cnt = 0; | |
902 | unsigned char data[sendsz+2]; | |
903 | u8 rdata[sendsz+2]; | |
904 | ||
905 | // dev_dbg(&client->dev, "%s: size: 0x%x\n", __func__, size); | |
906 | while(size > sendsz) { | |
907 | data[0] = (reg+cnt) >>8; | |
908 | data[1] = (reg+cnt) & 0xff; | |
909 | memcpy(data+2, val+cnt, sendsz); | |
910 | // dev_dbg(&client->dev, "%s: addr: 0x%x, cnt: 0x%x\n", __func__, reg+cnt, cnt); | |
911 | ret = i2c_master_send(client, data, sendsz+2); | |
912 | if (ret < sendsz+2) { | |
913 | pr_err("%s: i2c write error, reg: 0x%x\n", __func__, reg); | |
914 | return ret < 0 ? ret : -EIO; | |
915 | } | |
916 | if (mfc_reg_multi_read(client, reg+cnt, rdata, sendsz) < 0) { | |
917 | pr_err("%s, read failed(%d)\n", __func__, reg+cnt); | |
918 | return -1; | |
919 | } | |
920 | if (datacmp(val+cnt, rdata, sendsz)) { | |
921 | pr_err("%s, data is not matched. retry(%d)\n", __func__, retry_cnt); | |
922 | retry_cnt++; | |
923 | if(retry_cnt > 4) { | |
924 | pr_err("%s, data is not matched. write failed\n", __func__); | |
925 | retry_cnt = 0; | |
926 | return -1; | |
927 | } | |
928 | continue; | |
929 | } | |
930 | // pr_debug("%s, data is matched!\n", __func__); | |
931 | cnt += sendsz; | |
932 | size -= sendsz; | |
933 | retry_cnt = 0; | |
934 | } | |
935 | while (size > 0) { | |
936 | data[0] = (reg+cnt) >>8; | |
937 | data[1] = (reg+cnt) & 0xff; | |
938 | memcpy(data+2, val+cnt, size); | |
939 | // dev_dbg(&client->dev, "%s: addr: 0x%x, cnt: 0x%x, size: 0x%x\n", __func__, reg+cnt, cnt, size); | |
940 | ret = i2c_master_send(client, data, size+2); | |
941 | if (ret < size+2) { | |
942 | pr_err("%s: i2c write error, reg: 0x%x\n", __func__, reg); | |
943 | return ret < 0 ? ret : -EIO; | |
944 | } | |
945 | if (mfc_reg_multi_read(client, reg+cnt, rdata, size) < 0) { | |
946 | pr_err("%s, read failed(%d)\n", __func__, reg+cnt); | |
947 | return -1; | |
948 | } | |
949 | if (datacmp(val+cnt, rdata, size)) { | |
950 | pr_err("%s, data is not matched. retry(%d)\n", __func__, retry_cnt); | |
951 | retry_cnt++; | |
952 | if(retry_cnt > 4) { | |
953 | pr_err("%s, data is not matched. write failed\n", __func__); | |
954 | retry_cnt = 0; | |
955 | return -1; | |
956 | } | |
957 | continue; | |
958 | } | |
959 | size = 0; | |
960 | pr_err("%s, data is matched!\n", __func__); | |
961 | } | |
962 | return ret; | |
963 | } | |
964 | ||
965 | static int mfc_reg_multi_write(struct i2c_client *client, u16 reg, const u8 * val, int size) | |
966 | { | |
967 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
968 | int ret = 0; | |
969 | const int sendsz = 16; | |
970 | unsigned char data[sendsz+2]; | |
971 | int cnt = 0; | |
972 | ||
973 | pr_err("%s: size: 0x%x\n", | |
974 | __func__, size); | |
975 | while(size > sendsz) { | |
976 | data[0] = (reg+cnt) >>8; | |
977 | data[1] = (reg+cnt) & 0xff; | |
978 | memcpy(data+2, val+cnt, sendsz); | |
979 | mutex_lock(&charger->io_lock); | |
980 | ret = i2c_master_send(client, data, sendsz+2); | |
981 | mutex_unlock(&charger->io_lock); | |
982 | if (ret < sendsz+2) { | |
983 | pr_err("%s: i2c write error, reg: 0x%x\n", | |
984 | __func__, reg); | |
985 | return ret < 0 ? ret : -EIO; | |
986 | } | |
987 | cnt = cnt + sendsz; | |
988 | size = size - sendsz; | |
989 | } | |
990 | if (size > 0) { | |
991 | data[0] = (reg+cnt) >>8; | |
992 | data[1] = (reg+cnt) & 0xff; | |
993 | memcpy(data+2, val+cnt, size); | |
994 | mutex_lock(&charger->io_lock); | |
995 | ret = i2c_master_send(client, data, size+2); | |
996 | mutex_unlock(&charger->io_lock); | |
997 | if (ret < size+2) { | |
998 | dev_err(&client->dev, "%s: i2c write error, reg: 0x%x\n", | |
999 | __func__, reg); | |
1000 | return ret < 0 ? ret : -EIO; | |
1001 | } | |
1002 | } | |
1003 | ||
1004 | return ret; | |
1005 | } | |
1006 | ||
1007 | static int LoadOTPLoaderInRAM(struct mfc_charger_data *charger, u16 addr) | |
1008 | { | |
1009 | int i, size; | |
1010 | u8 data[1024]; | |
1011 | if (mfc_reg_multi_write_verify(charger->client, addr, MTPBootloader9320, sizeof(MTPBootloader9320)) < 0) { | |
1012 | pr_err("%s,fail", __func__); | |
1013 | } | |
1014 | size = sizeof(MTPBootloader9320); | |
1015 | i = 0; | |
1016 | while(size > 0) { | |
1017 | if (mfc_reg_multi_read(charger->client, addr+i, data+i, 16) < 0) { | |
1018 | pr_err("%s, read failed(%d)", __func__, addr+i); | |
1019 | return 0; | |
1020 | } | |
1021 | i += 16; | |
1022 | size -= 16; | |
1023 | } | |
1024 | size = sizeof(MTPBootloader9320); | |
1025 | if (datacmp(data, MTPBootloader9320, size)) { | |
1026 | pr_err("%s, data is not matched\n", __func__); | |
1027 | return 0; | |
1028 | } | |
1029 | return 1; | |
1030 | } | |
1031 | ||
1032 | static int mfc_firmware_verify(struct mfc_charger_data *charger) | |
1033 | { | |
1034 | int ret = 0; | |
1035 | const u16 sendsz = 16; | |
1036 | size_t i = 0; | |
1037 | int block_len = 0; | |
1038 | int block_addr = 0; | |
1039 | u8 rdata[sendsz+2]; | |
1040 | ||
1041 | /* I2C WR to prepare boot-loader write */ | |
1042 | ||
1043 | if (mfc_reg_write(charger->client, 0x3000, 0x5a) < 0) { | |
1044 | pr_err("%s: key error\n", __func__); | |
1045 | return 0; | |
1046 | } | |
1047 | ||
1048 | if (mfc_reg_write(charger->client, 0x3040, 0x11) < 0) { | |
1049 | pr_err("%s: halt M0, OTP_I2C_EN set error\n", __func__); | |
1050 | return 0; | |
1051 | } | |
1052 | ||
1053 | dev_err(&charger->client->dev, "%s, request_firmware\n", __func__); | |
1054 | ret = request_firmware(&charger->firm_data_bin, MFC_FLASH_FW_HEX_PATH, | |
1055 | &charger->client->dev); | |
1056 | if ( ret < 0) { | |
1057 | dev_err(&charger->client->dev, "%s: failed to request firmware %s (%d) \n", | |
1058 | __func__, MFC_FLASH_FW_HEX_PATH, ret); | |
1059 | return 0; | |
1060 | } | |
1061 | ret = 1; | |
1062 | wake_lock(&charger->wpc_update_lock); | |
1063 | for (i = 0; i < charger->firm_data_bin->size; i += sendsz) { | |
1064 | block_len = (i + sendsz) > charger->firm_data_bin->size ? charger->firm_data_bin->size - i : sendsz; | |
1065 | block_addr = 0x8000 + i; | |
1066 | ||
1067 | if (mfc_reg_multi_read(charger->client, block_addr, rdata, block_len) < 0) { | |
1068 | pr_err("%s, read failed\n", __func__); | |
1069 | ret = 0; | |
1070 | break; | |
1071 | } | |
1072 | if (datacmp(charger->firm_data_bin->data + i, rdata, block_len)) { | |
1073 | pr_err("%s, verify data is not matched. block_len(%d), block_addr(%d)\n", | |
1074 | __func__, block_len, block_addr); | |
1075 | ret = -1; | |
1076 | break; | |
1077 | } | |
1078 | } | |
1079 | release_firmware(charger->firm_data_bin); | |
1080 | ||
1081 | wake_unlock(&charger->wpc_update_lock); | |
1082 | return ret; | |
1083 | } | |
1084 | ||
1085 | bool WriteWordToMtp(struct mfc_charger_data *charger, u16 StartAddr, u32 data) | |
1086 | { | |
1087 | int j, cnt; | |
1088 | u8 sBuf[16] = {0,}; | |
1089 | u16 CheckSum = StartAddr; | |
1090 | u16 CodeLength = 4; | |
1091 | //*(u32*)&sBuf[8] = data; | |
1092 | sBuf[8] = (u8)(data >> 0); | |
1093 | sBuf[9] = (u8)(data >> 8); | |
1094 | sBuf[10] = (u8)(data >> 16); | |
1095 | sBuf[11] = (u8)(data >> 24); | |
1096 | ||
1097 | pr_info("%s: changed sBuf codes\n", __func__); | |
1098 | for (j = 3; j >= 0; j--) | |
1099 | CheckSum += sBuf[j + 8]; // add the non zero values | |
1100 | CheckSum += CodeLength; // finish calculation of the check sum | |
1101 | //*(u16*)&sBuf[2] = StartAddr; | |
1102 | //*(u16*)&sBuf[4] = CodeLength; | |
1103 | //*(u16*)&sBuf[6] = CheckSum; | |
1104 | sBuf[2] = (u8)(StartAddr >> 0); | |
1105 | sBuf[3] = (u8)(StartAddr >> 8); | |
1106 | sBuf[4] = (u8)(CodeLength >> 0); | |
1107 | sBuf[5] = (u8)(CodeLength >> 8); | |
1108 | sBuf[6] = (u8)(CheckSum >> 0); | |
1109 | sBuf[7] = (u8)(CheckSum >> 8); | |
1110 | ||
1111 | if (mfc_reg_multi_write(charger->client, 0x400, sBuf, 4 + 8) < 0) | |
1112 | { | |
1113 | pr_err("ERROR: on writing to OTP buffer"); | |
1114 | return false; | |
1115 | } | |
1116 | ||
1117 | sBuf[0] = 0x01; | |
1118 | if (mfc_reg_write(charger->client, 0x400, sBuf[0]) < 0) | |
1119 | { | |
1120 | pr_err("ERROR: on OTP buffer validation"); | |
1121 | return false; | |
1122 | } | |
1123 | ||
1124 | cnt = 0; | |
1125 | do { | |
1126 | msleep(20); | |
1127 | if (mfc_reg_read(charger->client, 0x400, sBuf) < 0) | |
1128 | { | |
1129 | pr_err("ERROR: on readign OTP buffer status(%d)", cnt); | |
1130 | return false; | |
1131 | } | |
1132 | ||
1133 | if (cnt > 1000) { | |
1134 | pr_err("ERROR: time out on buffer program to OTP"); | |
1135 | break; | |
1136 | } | |
1137 | cnt++; | |
1138 | } while ((sBuf[0]&1) != 0); | |
1139 | ||
1140 | if (sBuf[0] != 2) // not OK | |
1141 | { | |
1142 | pr_err("ERROR: buffer write to OTP returned status %d ",sBuf[0]); | |
1143 | return false; | |
1144 | } | |
1145 | return true; | |
1146 | } | |
1147 | ||
1148 | static int PgmOTPwRAM_IDT(struct mfc_charger_data *charger, unsigned short OtpAddr, | |
1149 | const u8 * srcData, int srcOffs, int size) | |
1150 | { | |
1151 | int i, cnt; | |
1152 | u8 fw_major[2] = {0,}; | |
1153 | u8 fw_minor[2] = {0,}; | |
1154 | ||
1155 | mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_L_REG, &fw_major[0]); | |
1156 | mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_H_REG, &fw_major[1]); | |
1157 | mfc_reg_read(charger->client, MFC_FW_MINOR_REV_L_REG, &fw_minor[0]); | |
1158 | mfc_reg_read(charger->client, MFC_FW_MINOR_REV_H_REG, &fw_minor[1]); | |
1159 | ||
1160 | msleep(10); | |
1161 | if (mfc_reg_write(charger->client, 0x3000, 0x5a) < 0) { | |
1162 | pr_err("%s: write key error\n", __func__); | |
1163 | return false; // write key | |
1164 | } | |
1165 | msleep(10); | |
1166 | if (mfc_reg_write(charger->client, 0x3040, 0x10) < 0) { | |
1167 | pr_err("%s: halt M0 error\n", __func__); | |
1168 | return false; // halt M0 | |
1169 | } | |
1170 | msleep(10); | |
1171 | if (!LoadOTPLoaderInRAM(charger, 0x1c00)){ | |
1172 | pr_err("%s: LoadOTPLoaderInRAM error\n", __func__); | |
1173 | return false; // make sure load address and 1KB size are OK | |
1174 | } | |
1175 | msleep(10); | |
1176 | ||
1177 | // Clear MTP program status byte | |
1178 | if (mfc_reg_write(charger->client, 0x0400, 0x00) < 0) { | |
1179 | pr_err("%s: clear MTP programming status byte error\n", __func__); | |
1180 | return false; | |
1181 | } | |
1182 | ||
1183 | if (mfc_reg_write(charger->client, 0x3048, 0x80) < 0) { | |
1184 | pr_err("%s: map RAM to OTP error\n", __func__); | |
1185 | return false; // map RAM to OTP | |
1186 | } | |
1187 | ||
1188 | // Check Key lock state | |
1189 | mfc_reg_write(charger->client, 0x3040, 0x80); //M0 RESET : P9320 will not acknowledge for this transaction !! | |
1190 | msleep(100); | |
1191 | ||
1192 | pr_info("%s: start to write f/w bin to mtp\n", __func__); | |
1193 | for (i = 0; i < size; i += 128) // program pages of 128 bytes | |
1194 | { | |
1195 | u8 sBuf[144] = {0,}; // align size in 16 bytes boundary. may not be important for SS | |
1196 | u16 StartAddr = (u16)i; | |
1197 | u16 CheckSum = StartAddr; | |
1198 | u16 CodeLength = 128; | |
1199 | int j; | |
1200 | memcpy(sBuf + 8, srcData + i + srcOffs, 128); | |
1201 | ||
1202 | if (i == 0x1480) { // the FW rev address for rev 58 is 0x14a8. 0x1280 is the half page base address. | |
1203 | //*(u32*)&sBuf[8 + 0x28] = 0; | |
1204 | sBuf[0x30] = 0; | |
1205 | sBuf[0x31] = 0; | |
1206 | sBuf[0x32] = 0; | |
1207 | sBuf[0x33] = 0; | |
1208 | } | |
1209 | ||
1210 | j = size - i; // calculate how many bytes need to be programmed in the current run and round up to 16 | |
1211 | ||
1212 | if (j < 128) | |
1213 | { | |
1214 | j = ((j + 15) / 16) * 16; | |
1215 | CodeLength = (u16)j; | |
1216 | } | |
1217 | else | |
1218 | { | |
1219 | j = 128; | |
1220 | } | |
1221 | j -= 1; // compensate for index | |
1222 | ||
1223 | for (; j >= 0; j--) | |
1224 | CheckSum += sBuf[j+8]; // add the non zero values | |
1225 | CheckSum += CodeLength; // finish calculation of the check sum | |
1226 | memcpy(sBuf+2, &StartAddr, 2); | |
1227 | memcpy(sBuf+4, &CodeLength, 2); | |
1228 | memcpy(sBuf+6, &CheckSum, 2); | |
1229 | ||
1230 | // FOR REFERENCE HERE IS THE DATA STRUCTURE | |
1231 | //typedef struct { | |
1232 | // u16 Status; | |
1233 | // u16 StartAddr; | |
1234 | // u16 CodeLength; | |
1235 | // u16 DataChksum; | |
1236 | // u8 DataBuf[128]; | |
1237 | //} P9320PgmStrType; // the structure is located at address 0x400 | |
1238 | ||
1239 | // TODO sBuf[0] = 0x00; // done during initialization. | |
1240 | ||
1241 | if (mfc_reg_multi_write(charger->client, 0x400, sBuf, ((CodeLength+8+15)/16)*16) < 0) | |
1242 | { // TODO the write size is aligned to 16 bytes. SS may not need to do this. | |
1243 | pr_err("ERROR: on writing to OTP buffer"); | |
1244 | return false; | |
1245 | } | |
1246 | sBuf[0] = 0x01; // TODO write 0x11 if Vrect is powered from 5V | |
1247 | //write 0x31 if Vrect is powered from 8.2V | |
1248 | //write 0x01 if Vrect is 5V and there is a problem | |
1249 | ||
1250 | if (mfc_reg_write(charger->client, 0x400, sBuf[0]) < 0) | |
1251 | { | |
1252 | pr_err("ERROR: on OTP buffer validation"); | |
1253 | return false; | |
1254 | } | |
1255 | cnt = 0; | |
1256 | do | |
1257 | { | |
1258 | msleep(20); | |
1259 | if (mfc_reg_read(charger->client, 0x400, sBuf) < 0) | |
1260 | { | |
1261 | pr_err("ERROR: on readign OTP buffer status(%d)", cnt); | |
1262 | return false; | |
1263 | } | |
1264 | if (cnt > 1000) { | |
1265 | pr_err("ERROR: time out on buffer program to OTP"); | |
1266 | break; | |
1267 | } | |
1268 | cnt++; | |
1269 | } while ((sBuf[0]&1) != 0); | |
1270 | if (sBuf[0] != 2) // not OK | |
1271 | { | |
1272 | pr_err("ERROR: buffer write to OTP returned status %d in sector 0x%x ",sBuf[0], i); | |
1273 | return false; | |
1274 | } | |
1275 | } | |
1276 | ||
1277 | pr_info("%s: write current f/w rev (0x%x)\n", __func__, MFC_FW_BIN_FULL_VERSION); | |
1278 | if (!WriteWordToMtp(charger, MFC_FW_BIN_VERSION_ADDR, MFC_FW_BIN_FULL_VERSION)) { | |
1279 | // The address for fw rev 58 is 0x14a8 | |
1280 | pr_err("ERROR: on writing FW rev to MTP\n"); | |
1281 | return false; | |
1282 | } | |
1283 | ||
1284 | msleep(10); | |
1285 | if (mfc_reg_write(charger->client, 0x3000, 0x5a) < 0) { | |
1286 | pr_err("%s: write key error..\n", __func__); | |
1287 | return false; // write key | |
1288 | } | |
1289 | ||
1290 | msleep(10); | |
1291 | if (mfc_reg_write(charger->client, 0x3048, 0x00) < 0) { | |
1292 | pr_err("%s: remove code remapping error..\n", __func__); | |
1293 | return false; // remove code remapping | |
1294 | } | |
1295 | ||
1296 | pr_err("OTP Programming finished in"); | |
1297 | pr_info("%s------------------------------------------------- \n", __func__); | |
1298 | return true; | |
1299 | } | |
1300 | ||
1301 | static int mfc_write_fw_flash_LSI(struct mfc_charger_data *charger, u8 addr_l, u8 addr_h, u8 *wdata) | |
1302 | { | |
1303 | if (mfc_reg_write(charger->client, 0x1F11, 0x04) < 0) { | |
1304 | pr_err("%s: failed to write 0x04 at 0x1F11\n", __func__); | |
1305 | return -1; | |
1306 | } | |
1307 | if (mfc_reg_write(charger->client, 0x1F12, addr_l) < 0) { | |
1308 | pr_err("%s: failed to write addr_l(0x%x) at 0x1F11\n", __func__, addr_l); | |
1309 | return -1; | |
1310 | } | |
1311 | if (mfc_reg_write(charger->client, 0x1F13, addr_h) < 0) { | |
1312 | pr_err("%s: failed to write addr_h(0x%x) at 0x1F11\n", __func__, addr_h); | |
1313 | return -1; | |
1314 | } | |
1315 | if (mfc_reg_write(charger->client, 0x1F14, wdata[0]) < 0) { | |
1316 | pr_err("%s: failed to write wdata[0]\n", __func__); | |
1317 | return -1; | |
1318 | } | |
1319 | if (mfc_reg_write(charger->client, 0x1F15, wdata[1]) < 0) { | |
1320 | pr_err("%s: failed to write wdata[1]\n", __func__); | |
1321 | return -1; | |
1322 | } | |
1323 | if (mfc_reg_write(charger->client, 0x1F16, wdata[2]) < 0) { | |
1324 | pr_err("%s: failed to write wdata[2]\n", __func__); | |
1325 | return -1; | |
1326 | } | |
1327 | if (mfc_reg_write(charger->client, 0x1F17, wdata[3]) < 0) { | |
1328 | pr_err("%s: failed to write wdata[3]\n", __func__); | |
1329 | return -1; | |
1330 | } | |
1331 | if (mfc_reg_write(charger->client, 0x1F10, 0x42) < 0) { | |
1332 | pr_err("%s: failed to write 0x42 at 0x1F10\n", __func__); | |
1333 | return -1; | |
1334 | } | |
1335 | ||
1336 | return 0; | |
1337 | } | |
1338 | ||
1339 | #define LSI_MFC_FW_FLASH_START_ADDR 0x1000 | |
1340 | static int PgmOTPwRAM_LSI(struct mfc_charger_data *charger, unsigned short OtpAddr, | |
1341 | const u8 * srcData, int srcOffs, int size) | |
1342 | { | |
1343 | int addr; | |
1344 | u8 fw_major[2] = {0,}; | |
1345 | u8 fw_minor[2] = {0,}; | |
1346 | u8 wdata[4] = {0,}; | |
1347 | // static int startAddr; | |
1348 | u16 temp; | |
1349 | u8 addr_l, addr_h; | |
1350 | ||
1351 | mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_L_REG, &fw_major[0]); | |
1352 | mfc_reg_read(charger->client, MFC_FW_MAJOR_REV_H_REG, &fw_major[1]); | |
1353 | mfc_reg_read(charger->client, MFC_FW_MINOR_REV_L_REG, &fw_minor[0]); | |
1354 | mfc_reg_read(charger->client, MFC_FW_MINOR_REV_H_REG, &fw_minor[1]); | |
1355 | ||
1356 | pr_info("%s: Enter the flash mode (0x1F10)\n", __func__); | |
1357 | if (mfc_reg_write(charger->client, 0x1F10, 0x10) < 0) { | |
1358 | pr_err("%s: failed to enter the flash mode\n", __func__); | |
1359 | return false; | |
1360 | } | |
1361 | msleep(2); | |
1362 | pr_info("%s: Erase the flash memory\n", __func__); | |
1363 | if (mfc_reg_write(charger->client, 0x1F10, 0x44) < 0) { | |
1364 | pr_err("%s: failed to erase flash\n", __func__); | |
1365 | return false; | |
1366 | } | |
1367 | ||
1368 | msleep(250); /* erasing flash needs 200ms delay at least */ | |
1369 | ||
1370 | pr_info("%s: write fwimg by 4 bytes \n", __func__); | |
1371 | size -= 0x1000; | |
1372 | for (addr = 0x00; addr < size; addr += 4) // program pages of 4bytes | |
1373 | { | |
1374 | temp = (0x1000 + addr) & 0xff; | |
1375 | addr_l = (u8)temp; | |
1376 | temp = (((0x1000 + addr) & 0xff00) >> 8); | |
1377 | addr_h = (u8)temp; | |
1378 | pr_info("%s: addr_h(0x%x), addr_l(0x%x)\n", __func__, addr_h, addr_l); | |
1379 | memcpy(wdata, srcData + LSI_MFC_FW_FLASH_START_ADDR + addr, 4); | |
1380 | ||
1381 | mfc_write_fw_flash_LSI(charger, addr_l, addr_h, wdata); | |
1382 | } | |
1383 | ||
1384 | pr_info("%s: write fw length --------------------\n", __func__); | |
1385 | wdata[0] = 0x8C; /* length */ | |
1386 | wdata[1] = 0x3E; | |
1387 | wdata[2] = 0x00; | |
1388 | wdata[3] = 0x00; | |
1389 | mfc_write_fw_flash_LSI(charger, 0xf4, 0x6f, wdata); | |
1390 | ||
1391 | pr_info("%s: write fw checksum --------------------\n", __func__); | |
1392 | wdata[0] = 0x90; /* checksum */ | |
1393 | wdata[1] = 0x00; | |
1394 | wdata[2] = 0x00; | |
1395 | wdata[3] = 0x00; | |
1396 | mfc_write_fw_flash_LSI(charger, 0xf8, 0x6f, wdata); | |
1397 | ||
1398 | pr_info("%s: write fw version --------------------\n", __func__); | |
1399 | wdata[0] = 0x00; /* fw major rev l */ | |
1400 | wdata[1] = 0x00; /* fw major rev h */ | |
1401 | wdata[2] = 0x05; /* fw minor rev l */ | |
1402 | wdata[3] = 0x11; /* fw minor rev h */ | |
1403 | mfc_write_fw_flash_LSI(charger, 0x00, 0x6f, wdata); | |
1404 | ||
1405 | pr_info("%s: write fw date and timer code --------------------\n", __func__); | |
1406 | wdata[0] = 0x4A; /* J , date code start */ | |
1407 | wdata[1] = 0x75; /* u */ | |
1408 | wdata[2] = 0x6E; /* n */ | |
1409 | wdata[3] = 0x20; /* space */ | |
1410 | mfc_write_fw_flash_LSI(charger, 0x04, 0x6f, wdata); | |
1411 | wdata[0] = 0x31; /* 1 */ | |
1412 | wdata[1] = 0x35; /* 5 */ | |
1413 | wdata[2] = 0x20; /* space */ | |
1414 | wdata[3] = 0x32; /* 2 */ | |
1415 | mfc_write_fw_flash_LSI(charger, 0x08, 0x6f, wdata); | |
1416 | wdata[0] = 0x30; /* 0 */ | |
1417 | wdata[1] = 0x31; /* 1 */ | |
1418 | wdata[2] = 0x36; /* 6 */ | |
1419 | wdata[3] = 0x31; /* 1 , timer code start */ | |
1420 | mfc_write_fw_flash_LSI(charger, 0x0c, 0x6f, wdata); | |
1421 | wdata[0] = 0x33; /* 3 */ | |
1422 | wdata[1] = 0x3A; /* : */ | |
1423 | wdata[2] = 0x30; /* 0 */ | |
1424 | wdata[3] = 0x30; /* 0 */ | |
1425 | mfc_write_fw_flash_LSI(charger, 0x10, 0x6f, wdata); | |
1426 | wdata[0] = 0x3A; /* : */ | |
1427 | wdata[1] = 0x30; /* 0 */ | |
1428 | wdata[2] = 0x30; /* 0 */ | |
1429 | wdata[3] = 0x00; /* reserved */ | |
1430 | mfc_write_fw_flash_LSI(charger, 0x14, 0x6f, wdata); | |
1431 | ||
1432 | pr_info("%s: write flash done flag --------------------*\n", __func__); | |
1433 | wdata[0] = 0x01; | |
1434 | wdata[1] = 0x00; | |
1435 | wdata[2] = 0x00; | |
1436 | wdata[3] = 0x00; | |
1437 | mfc_write_fw_flash_LSI(charger, 0xfc, 0x6f, wdata); | |
1438 | ||
1439 | msleep(10); | |
1440 | pr_info("%s: Enter the normal mode\n", __func__); | |
1441 | if (mfc_reg_write(charger->client, 0x1F10, 0x20) < 0) { | |
1442 | pr_err("%s: failed to enter the normal mode\n", __func__); | |
1443 | return false; | |
1444 | } | |
1445 | msleep(10); | |
1446 | ||
1447 | return true; | |
1448 | } | |
1449 | static void mfc_uno_on(struct mfc_charger_data *charger, bool onoff) | |
1450 | { | |
1451 | union power_supply_propval value = {0, }; | |
1452 | ||
1453 | if (onoff) { /* UNO ON */ | |
1454 | psy_do_property("otg", get, | |
1455 | POWER_SUPPLY_PROP_ONLINE, value); | |
1456 | if (value.intval) { | |
1457 | charger->is_otg_on = true; | |
1458 | psy_do_property(charger->pdata->wired_charger_name, set, | |
1459 | POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, value); | |
1460 | pr_info("%s CHGIN_OTG on, check OTG flag\n", __func__); | |
1461 | } else | |
1462 | charger->is_otg_on = false; | |
1463 | value.intval = 1; | |
1464 | psy_do_property(charger->pdata->wired_charger_name, set, | |
1465 | POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value); | |
1466 | pr_info("%s: ENABLE\n", __func__); | |
1467 | } else { /* UNO OFF */ | |
1468 | value.intval = 0; | |
1469 | psy_do_property(charger->pdata->wired_charger_name, set, | |
1470 | POWER_SUPPLY_PROP_CHARGE_UNO_CONTROL, value); | |
1471 | psy_do_property("battery", get, | |
1472 | POWER_SUPPLY_PROP_ONLINE, value); | |
1473 | ||
1474 | if ((charger->is_otg_on) && | |
1475 | value.intval == SEC_BATTERY_CABLE_OTG) { /* OTG status has to be recovered */ | |
1476 | value.intval = 1; | |
1477 | psy_do_property(charger->pdata->wired_charger_name, set, | |
1478 | POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value); | |
1479 | pr_info("%s CHGIN_OTG was ON, recover OTG status\n", __func__); | |
1480 | } | |
1481 | charger->is_otg_on = false; | |
1482 | pr_info("%s: DISABLE\n", __func__); | |
1483 | } | |
1484 | } | |
1485 | ||
1486 | static void mfc_wpc_cm_fet_work(struct work_struct *work) | |
1487 | { | |
1488 | struct mfc_charger_data *charger = | |
1489 | container_of(work, struct mfc_charger_data, wpc_cm_fet_work.work); | |
1490 | u8 tmp = 0; | |
1491 | ||
1492 | /* disable all CM FETs for MST operation */ | |
1493 | mfc_reg_write(charger->client, MFC_RX_COMM_MOD_FET_REG, 0xf0); | |
1494 | mfc_reg_read(charger->client, MFC_RX_COMM_MOD_FET_REG, &tmp); | |
1495 | pr_info("%s: disable CM FET (0x%x)\n", __func__, tmp); | |
1496 | } | |
1497 | ||
1498 | static void mfc_wpc_afc_vout_work(struct work_struct *work) | |
1499 | { | |
1500 | struct mfc_charger_data *charger = | |
1501 | container_of(work, struct mfc_charger_data, wpc_afc_vout_work.work); | |
1502 | u8 data_val[4]; | |
1503 | u8 cmd = 0; | |
1504 | u8 i; | |
1505 | union power_supply_propval value = {0, }; | |
1506 | ||
1507 | pr_info("%s start\n", __func__); | |
1508 | ||
1509 | /* change cable type */ | |
1510 | if (charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV) | |
1511 | value.intval = SEC_WIRELESS_PAD_WPC_STAND_HV; | |
1512 | else if (charger->pdata->cable_type == MFC_PAD_WPC_VEHICLE_HV) | |
1513 | value.intval = SEC_WIRELESS_PAD_VEHICLE_HV; | |
1514 | else if (charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV) | |
1515 | value.intval = SEC_WIRELESS_PAD_WPC_PACK_HV; | |
1516 | else { | |
1517 | charger->pdata->cable_type = MFC_PAD_WPC_AFC; | |
1518 | value.intval = SEC_WIRELESS_PAD_WPC_HV; | |
1519 | } | |
1520 | psy_do_property("wireless", set, | |
1521 | POWER_SUPPLY_PROP_ONLINE, value); | |
1522 | ||
1523 | #if defined(CONFIG_BATTERY_SWELLING) | |
1524 | /* check swelling mode */ | |
1525 | psy_do_property("battery", get, | |
1526 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, value); | |
1527 | pr_info("%s: check swelling mode(%d)\n", __func__, value.intval); | |
1528 | ||
1529 | if (value.intval) | |
1530 | goto skip_set_afc_vout; | |
1531 | #endif | |
1532 | ||
1533 | for(i = 0; i < CMD_CNT; i++) { | |
1534 | cmd = WPC_COM_AFC_SET; | |
1535 | data_val[0] = 0x2c; /* Value for WPC AFC_SET 10V */ | |
1536 | pr_info("%s set 10V , cnt = %d \n", __func__, i); | |
1537 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
1538 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_COM_REG, &data_val[0]); | |
1539 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_VALUE0_REG, &data_val[0]); | |
1540 | mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &data_val[0]); | |
1541 | msleep(100); | |
1542 | } | |
1543 | charger->is_afc_tx = true; | |
1544 | pr_info("%s: is_afc_tx = %d vout read = %d\n", | |
1545 | __func__, charger->is_afc_tx, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
1546 | ||
1547 | /* use all CM FETs for 10V wireless charging */ | |
1548 | mfc_reg_write(charger->client, MFC_RX_COMM_MOD_FET_REG, 0x00); | |
1549 | mfc_reg_read(charger->client, MFC_RX_COMM_MOD_FET_REG, &cmd); | |
1550 | pr_info("%s: CM FET setting(0x%x) \n", __func__, cmd); | |
1551 | ||
1552 | psy_do_property("otg", get, | |
1553 | POWER_SUPPLY_PROP_ONLINE, value); | |
1554 | pr_info("%s: check state(%d, %d, %d)\n", __func__, | |
1555 | charger->vout_mode, charger->pdata->vout_status, value.intval); | |
1556 | ||
1557 | if (!charger->is_full_status && !value.intval && | |
1558 | charger->vout_mode != WIRELESS_VOUT_5V && | |
1559 | charger->vout_mode != WIRELESS_VOUT_5V_STEP) { | |
1560 | charger->vout_mode = WIRELESS_VOUT_10V; | |
1561 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
1562 | wake_lock(&charger->wpc_vout_mode_lock); | |
1563 | queue_delayed_work(charger->wqueue, | |
1564 | &charger->wpc_vout_mode_work, 0); | |
1565 | } | |
1566 | ||
1567 | #if defined(CONFIG_BATTERY_SWELLING) | |
1568 | skip_set_afc_vout: | |
1569 | #endif | |
1570 | wake_unlock(&charger->wpc_afc_vout_lock); | |
1571 | } | |
1572 | ||
1573 | static void mfc_wpc_fw_update_work(struct work_struct *work) | |
1574 | { | |
1575 | struct mfc_charger_data *charger = | |
1576 | container_of(work, struct mfc_charger_data, wpc_fw_update_work.work); | |
1577 | ||
1578 | struct file *fp; | |
1579 | mm_segment_t old_fs; | |
1580 | long fsize, nread; | |
1581 | const u8 *fw_img; | |
1582 | ||
1583 | int ret = 0; | |
1584 | int i = 0; | |
1585 | char fwtime[8] = {32, 32, 32, 32, 32, 32, 32, 32}; | |
1586 | char fwdate[8] = {32, 32, 32, 32, 32, 32, 32, 32}; | |
1587 | u8 data = 32; /* ascii space */ | |
1588 | ||
1589 | pr_info("%s firmware update mode is = %d \n", __func__, charger->fw_cmd); | |
1590 | switch(charger->fw_cmd) { | |
1591 | case SEC_WIRELESS_RX_SDCARD_MODE: | |
1592 | mfc_uno_on(charger, true); | |
1593 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_DOWNLOADING; | |
1594 | msleep(200); | |
1595 | disable_irq(charger->pdata->irq_wpc_int); | |
1596 | disable_irq(charger->pdata->irq_wpc_det); | |
1597 | old_fs = get_fs(); | |
1598 | set_fs(KERNEL_DS); | |
1599 | ||
1600 | fp = filp_open(MFC_FW_SDCARD_BIN_PATH, O_RDONLY, S_IRUSR); | |
1601 | ||
1602 | if (IS_ERR(fp)) { | |
1603 | pr_err("%s: failed to open %s, (%d)\n", __func__, MFC_FW_SDCARD_BIN_PATH, IS_ERR(fp)); | |
1604 | set_fs(old_fs); | |
1605 | goto fw_err; | |
1606 | } | |
1607 | ||
1608 | fsize = fp->f_path.dentry->d_inode->i_size; | |
1609 | pr_err("%s: start, file path %s, size %ld Bytes\n", | |
1610 | __func__, MFC_FW_SDCARD_BIN_PATH, fsize); | |
1611 | ||
1612 | fw_img = kmalloc(fsize, GFP_KERNEL); | |
1613 | ||
1614 | if (fw_img == NULL) { | |
1615 | pr_err("%s, kmalloc failed\n", __func__); | |
1616 | goto malloc_error; | |
1617 | } | |
1618 | ||
1619 | nread = vfs_read(fp, (char __user *)fw_img, | |
1620 | fsize, &fp->f_pos); | |
1621 | pr_err("nread %ld Bytes\n", nread); | |
1622 | if (nread != fsize) { | |
1623 | pr_err("failed to read firmware file, nread %ld Bytes\n", nread); | |
1624 | goto read_err; | |
1625 | } | |
1626 | ||
1627 | filp_close(fp, current->files); | |
1628 | set_fs(old_fs); | |
1629 | mfc_get_chip_id(charger); | |
1630 | pr_info("%s chip_id(%d) \n", __func__, charger->chip_id); | |
1631 | ||
1632 | mfc_otp_update = 1; | |
1633 | if (charger->chip_id == MFC_CHIP_LSI) { | |
1634 | pr_info("%s: S.LSI MFC IC doesn't support sdcard f/w update\n", __func__); | |
1635 | goto read_err; | |
1636 | } | |
1637 | else /* MFC_CHIP_IDT */ | |
1638 | ret = PgmOTPwRAM_IDT(charger, 0 ,fw_img, 0, fsize); | |
1639 | mfc_otp_update = 0; | |
1640 | charger->pdata->otp_firmware_ver = mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
1641 | charger->pdata->wc_ic_grade = mfc_get_ic_revision(charger, MFC_IC_FONT); | |
1642 | charger->pdata->wc_ic_rev = mfc_get_ic_revision(charger, MFC_IC_REVISION); | |
1643 | ||
1644 | if(ret) | |
1645 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_PASS; | |
1646 | else | |
1647 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_FAIL; | |
1648 | ||
1649 | kfree(fw_img); | |
1650 | enable_irq(charger->pdata->irq_wpc_int); | |
1651 | enable_irq(charger->pdata->irq_wpc_det); | |
1652 | break; | |
1653 | case SEC_WIRELESS_RX_BUILT_IN_MODE: | |
1654 | mfc_uno_on(charger, true); | |
1655 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_DOWNLOADING; | |
1656 | msleep(200); | |
1657 | disable_irq(charger->pdata->irq_wpc_int); | |
1658 | disable_irq(charger->pdata->irq_wpc_det); | |
1659 | dev_err(&charger->client->dev, "%s, request_firmware\n", __func__); | |
1660 | ret = request_firmware(&charger->firm_data_bin, MFC_FLASH_FW_HEX_PATH, | |
1661 | &charger->client->dev); | |
1662 | if ( ret < 0) { | |
1663 | dev_err(&charger->client->dev, "%s: failed to request firmware %s (%d) \n", __func__, MFC_FLASH_FW_HEX_PATH, ret); | |
1664 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_FAIL; | |
1665 | goto fw_err; | |
1666 | } | |
1667 | wake_lock(&charger->wpc_update_lock); | |
1668 | mfc_get_chip_id(charger); | |
1669 | pr_info("%s data size = %ld, chip_id(%d) \n", __func__, charger->firm_data_bin->size, charger->chip_id); | |
1670 | mfc_otp_update = 1; | |
1671 | if (charger->chip_id == MFC_CHIP_LSI) | |
1672 | ret = PgmOTPwRAM_LSI(charger, 0 ,charger->firm_data_bin->data, 0, charger->firm_data_bin->size); | |
1673 | else /* MFC_CHIP_IDT */ | |
1674 | ret = PgmOTPwRAM_IDT(charger, 0 ,charger->firm_data_bin->data, 0, charger->firm_data_bin->size); | |
1675 | mfc_otp_update = 0; | |
1676 | release_firmware(charger->firm_data_bin); | |
1677 | ||
1678 | for(i = 0; i < 8; i++) { | |
1679 | if (mfc_reg_read(charger->client, MFC_FW_DATA_CODE_0+i, &data) > 0) | |
1680 | fwdate[i] = (char)data; | |
1681 | } | |
1682 | for(i = 0; i < 8; i++) { | |
1683 | if (mfc_reg_read(charger->client, MFC_FW_TIMER_CODE_0+i, &data) > 0) | |
1684 | fwtime[i] = (char)data; | |
1685 | } | |
1686 | pr_info("%s: %d%d%d%d%d%d%d%d, %d%d%d%d%d%d%d%d\n", __func__, | |
1687 | fwdate[0], fwdate[1], fwdate[2],fwdate[3], fwdate[4], fwdate[5], fwdate[6], fwdate[7], | |
1688 | fwtime[0], fwtime[1], fwtime[2],fwtime[3], fwtime[4], fwtime[5], fwtime[6], fwtime[7]); | |
1689 | ||
1690 | charger->pdata->otp_firmware_ver = mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
1691 | charger->pdata->wc_ic_grade = mfc_get_ic_revision(charger, MFC_IC_FONT); | |
1692 | charger->pdata->wc_ic_rev = mfc_get_ic_revision(charger, MFC_IC_REVISION); | |
1693 | ||
1694 | if(ret) | |
1695 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_PASS; | |
1696 | else | |
1697 | charger->pdata->otp_firmware_result = MFC_FW_RESULT_FAIL; | |
1698 | ||
1699 | for(i = 0; i < 8; i++) { | |
1700 | if (mfc_reg_read(charger->client, MFC_FW_DATA_CODE_0+i, &data) > 0) | |
1701 | fwdate[i] = (char)data; | |
1702 | } | |
1703 | for(i = 0; i < 8; i++) { | |
1704 | if (mfc_reg_read(charger->client, MFC_FW_TIMER_CODE_0+i, &data) > 0) | |
1705 | fwtime[i] = (char)data; | |
1706 | } | |
1707 | pr_info("%s: %d%d%d%d%d%d%d%d, %d%d%d%d%d%d%d%d\n", __func__, | |
1708 | fwdate[0], fwdate[1], fwdate[2],fwdate[3], fwdate[4], fwdate[5], fwdate[6], fwdate[7], | |
1709 | fwtime[0], fwtime[1], fwtime[2],fwtime[3], fwtime[4], fwtime[5], fwtime[6], fwtime[7]); | |
1710 | ||
1711 | enable_irq(charger->pdata->irq_wpc_int); | |
1712 | enable_irq(charger->pdata->irq_wpc_det); | |
1713 | wake_unlock(&charger->wpc_update_lock); | |
1714 | break; | |
1715 | case SEC_WIRELESS_TX_ON_MODE: | |
1716 | charger->pdata->cable_type = MFC_PAD_TX; | |
1717 | break; | |
1718 | case SEC_WIRELESS_TX_OFF_MODE: | |
1719 | /* need to check */ | |
1720 | break; | |
1721 | case SEC_WIRELESS_RX_INIT: | |
1722 | /* need to check */ | |
1723 | break; | |
1724 | default: | |
1725 | break; | |
1726 | } | |
1727 | ||
1728 | msleep(200); | |
1729 | mfc_uno_on(charger, false); | |
1730 | pr_info("%s --------------------------------------------------------------- \n", __func__); | |
1731 | ||
1732 | return; | |
1733 | ||
1734 | read_err: | |
1735 | kfree(fw_img); | |
1736 | malloc_error: | |
1737 | filp_close(fp, current->files); | |
1738 | set_fs(old_fs); | |
1739 | fw_err: | |
1740 | mfc_uno_on(charger, false); | |
1741 | } | |
1742 | ||
1743 | /*#if !defined(CONFIG_SEC_FACTORY) | |
1744 | static void mfc_wpc_fw_booting_work(struct work_struct *work) | |
1745 | { | |
1746 | struct mfc_charger_data *charger = | |
1747 | container_of(work, struct mfc_charger_data, wpc_fw_booting_work.work); | |
1748 | union power_supply_propval value = {0, }; | |
1749 | int fw_version; | |
1750 | ||
1751 | value.intval = | |
1752 | SEC_FUELGAUGE_CAPACITY_TYPE_SCALE; | |
1753 | psy_do_property(charger->pdata->fuelgauge_name, get, | |
1754 | POWER_SUPPLY_PROP_CAPACITY, value); | |
1755 | pr_info("%s: battery capacity (%d)\n", __func__, value.intval); | |
1756 | ||
1757 | if (value.intval >= 10) { | |
1758 | mfc_uno_on(charger, true); | |
1759 | msleep(200); | |
1760 | fw_version = mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
1761 | pr_info("%s: fw version (0x%x)\n", __func__, fw_version); | |
1762 | if (fw_version != MFC_FW_BIN_VERSION) { | |
1763 | charger->fw_cmd = SEC_WIRELESS_RX_BUILT_IN_MODE; | |
1764 | queue_delayed_work(charger->wqueue, &charger->wpc_fw_update_work, 0); | |
1765 | } else { | |
1766 | mfc_uno_on(charger, false); | |
1767 | } | |
1768 | } | |
1769 | } | |
1770 | #endif*/ | |
1771 | ||
1772 | static int mfc_chg_get_property(struct power_supply *psy, | |
1773 | enum power_supply_property psp, | |
1774 | union power_supply_propval *val) | |
1775 | { | |
1776 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
ca34248d | 1777 | enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp; |
1cac41cb MB |
1778 | // union power_supply_propval value; |
1779 | u8 mst_mode; | |
1780 | u8 reg_data; | |
1781 | ||
1782 | switch (psp) { | |
1783 | case POWER_SUPPLY_PROP_STATUS: | |
1784 | pr_info("%s charger->pdata->cs100_status %d \n",__func__,charger->pdata->cs100_status); | |
1785 | val->intval = charger->pdata->cs100_status; | |
1786 | break; | |
1787 | case POWER_SUPPLY_PROP_TECHNOLOGY: | |
1788 | val->intval = mfc_reg_read(charger->client, MFC_MST_MODE_SEL_REG, &mst_mode); | |
1789 | if (val->intval < 0) { | |
1790 | pr_info("%s mst mode(0x2) i2c write failed, val->intval = %d\n", | |
1791 | __func__, val->intval); | |
1792 | break; | |
1793 | } | |
1794 | ||
1795 | val->intval = mfc_reg_read(charger->client, MFC_SYS_OP_MODE_REG, ®_data); | |
1796 | if (val->intval < 0) { | |
1797 | pr_info("%s mst mode change irq(0x4) read failed, val->intval = %d\n", | |
1798 | __func__, val->intval); | |
1799 | break; | |
1800 | } | |
1801 | reg_data &= 0x0C; /* use only [3:2]bit of sys_op_mode register for MST */ | |
1802 | ||
1803 | pr_info("%s mst mode check: mst_mode = %d, reg_data = %d\n", | |
1804 | __func__, mst_mode, reg_data); | |
1805 | val->intval = 0; | |
1806 | if (reg_data == 0x4) | |
1807 | val->intval = mst_mode; | |
1808 | break; | |
1809 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | |
1810 | case POWER_SUPPLY_PROP_HEALTH: | |
1811 | return -ENODATA; | |
1812 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | |
1813 | if(charger->pdata->ic_on_mode || charger->pdata->is_charging) { | |
1814 | val->intval = mfc_get_vout(charger); | |
1815 | } else | |
1816 | val->intval = 0; | |
1817 | break; | |
1818 | case POWER_SUPPLY_PROP_CURRENT_NOW: | |
1819 | case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: | |
1820 | case POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL: | |
1821 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
1822 | return -ENODATA; | |
1823 | case POWER_SUPPLY_PROP_ONLINE: | |
1824 | pr_info("%s cable_type =%d \n ", __func__, charger->pdata->cable_type); | |
1825 | val->intval = charger->pdata->cable_type; | |
1826 | break; | |
1827 | case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: | |
1828 | val->intval = charger->pdata->vout_status; | |
1829 | break; | |
1830 | case POWER_SUPPLY_PROP_MANUFACTURER: | |
1831 | pr_info("%s: POWER_SUPPLY_PROP_MANUFACTURER, intval(0x%x), called by(%ps)\n", __func__, val->intval, __builtin_return_address(0)); | |
1832 | if (val->intval == SEC_WIRELESS_OTP_FIRM_RESULT) { | |
1833 | pr_info("%s otp firmware result = %d,\n",__func__, charger->pdata->otp_firmware_result); | |
1834 | val->intval = charger->pdata->otp_firmware_result; | |
1835 | } else if(val->intval == SEC_WIRELESS_IC_REVISION) { | |
1836 | pr_info("%s: check f/w revision\n", __func__); | |
1837 | val->intval = mfc_get_ic_revision(charger, MFC_IC_REVISION); | |
1838 | } else if(val->intval == SEC_WIRELESS_IC_GRADE) { | |
1839 | pr_info("%s: check f/w revision\n", __func__); | |
1840 | val->intval = mfc_get_ic_revision(charger, MFC_IC_FONT); | |
1841 | } else if(val->intval == SEC_WIRELESS_OTP_FIRM_VER_BIN) { | |
1842 | val->intval = MFC_FW_BIN_VERSION; /* latest MFC F/W binary version */ | |
1843 | } else if(val->intval == SEC_WIRELESS_OTP_FIRM_VER) { | |
1844 | val->intval = mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
1845 | pr_info("%s: check f/w revision (0x%x)\n", __func__, val->intval); | |
1846 | } else if(val->intval == SEC_WIRELESS_TX_FIRM_RESULT) { | |
1847 | val->intval = charger->pdata->tx_firmware_result; | |
1848 | } else if (val->intval == SEC_WIRELESS_TX_FIRM_VER) { | |
1849 | val->intval = charger->pdata->tx_firmware_ver; | |
1850 | } else if(val->intval == SEC_TX_FIRMWARE) { | |
1851 | val->intval = charger->pdata->tx_status; | |
1852 | } else if(val->intval == SEC_WIRELESS_OTP_FIRM_VERIFY) { | |
1853 | mfc_get_chip_id(charger); | |
1854 | if (charger->chip_id == MFC_CHIP_LSI) { | |
1855 | pr_info("%s: LSI FIRM_VERIFY is not implemented\n", __func__); | |
1856 | val->intval = 1; | |
1857 | } else { | |
1858 | pr_info("%s: IDT FIRM_VERIFY\n", __func__); | |
1859 | msleep(10); | |
1860 | val->intval = mfc_firmware_verify(charger); | |
1861 | } | |
1862 | } else if (val->intval == SEC_WIRELESS_MST_SWITCH_VERIFY) { | |
1863 | /* This is the WA codes that reduces VRECT invalid case. */ | |
1864 | charger->mst_off_lock = 1; | |
1865 | gpio_direction_output(charger->pdata->mst_pwr_en, 1); | |
1866 | usleep_range(3600, 4000); | |
1867 | gpio_direction_output(charger->pdata->mst_pwr_en, 0); | |
1868 | mdelay(50); | |
1869 | charger->mst_off_lock = 0; | |
1870 | ||
1871 | gpio_direction_output(charger->pdata->mst_pwr_en, 1); | |
1872 | msleep(charger->pdata->mst_switch_delay); | |
1873 | val->intval = mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
1874 | pr_info("%s: check f/w revision, mst power on (0x%x)\n", __func__, val->intval); | |
1875 | gpio_direction_output(charger->pdata->mst_pwr_en, 0); | |
1876 | } else { | |
1877 | val->intval = -ENODATA; | |
1878 | pr_err("%s wrong mode \n", __func__); | |
1879 | } | |
1880 | break; | |
1881 | case POWER_SUPPLY_PROP_ENERGY_NOW: /* vout */ | |
1882 | if(charger->pdata->ic_on_mode || charger->pdata->is_charging) { | |
1883 | val->intval = mfc_get_adc(charger, MFC_ADC_VOUT); | |
1884 | pr_info("%s: wc vout (%d)\n", __func__, val->intval); | |
1885 | } else | |
1886 | val->intval = 0; | |
1887 | break; | |
1888 | case POWER_SUPPLY_PROP_ENERGY_AVG: /* vrect */ | |
1889 | if(charger->pdata->ic_on_mode || charger->pdata->is_charging) { | |
1890 | val->intval = mfc_get_adc(charger, MFC_ADC_VRECT); | |
1891 | } else | |
1892 | val->intval = 0; | |
1893 | break; | |
1894 | case POWER_SUPPLY_PROP_SCOPE: | |
1895 | val->intval = mfc_get_adc(charger, val->intval); | |
1896 | break; | |
1897 | case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: | |
1898 | break; | |
1899 | case POWER_SUPPLY_PROP_MAX ... POWER_SUPPLY_EXT_PROP_MAX: | |
1900 | switch (ext_psp) { | |
1901 | case POWER_SUPPLY_EXT_PROP_WIRELESS_OP_FREQ: | |
1902 | val->intval = mfc_get_adc(charger, MFC_ADC_OP_FRQ); | |
1903 | pr_info("%s: Operating FQ %dkHz\n", __func__, val->intval); | |
1904 | break; | |
1905 | case POWER_SUPPLY_EXT_PROP_WIRELESS_TX_CMD: | |
1906 | val->intval = charger->pdata->tx_data_cmd; | |
1907 | break; | |
1908 | case POWER_SUPPLY_EXT_PROP_WIRELESS_TX_VAL: | |
1909 | val->intval = charger->pdata->tx_data_val; | |
1910 | break; | |
1911 | case POWER_SUPPLY_EXT_PROP_WIRELESS_TX_ID: | |
1912 | val->intval = charger->tx_id; | |
1913 | break; | |
1914 | default: | |
1915 | return -ENODATA; | |
1916 | } | |
1917 | break; | |
1918 | ||
1919 | default: | |
1920 | return -ENODATA; | |
1921 | } | |
1922 | return 0; | |
1923 | } | |
1924 | ||
1925 | static void mfc_wpc_vout_mode_work(struct work_struct *work) | |
1926 | { | |
1927 | struct mfc_charger_data *charger = | |
1928 | container_of(work, struct mfc_charger_data, wpc_vout_mode_work.work); | |
1929 | int vout_step = charger->pdata->vout_status; | |
1930 | int vout = MFC_VOUT_10V; | |
1931 | union power_supply_propval value; | |
1932 | ||
1933 | pr_info("%s: start - vout_mode(%d), vout_status(%d)\n", | |
1934 | __func__, charger->vout_mode, charger->pdata->vout_status); | |
1935 | switch (charger->vout_mode) { | |
1936 | case WIRELESS_VOUT_5V: | |
1937 | mfc_set_vout(charger, MFC_VOUT_5V); | |
1938 | break; | |
1939 | case WIRELESS_VOUT_9V: | |
1940 | mfc_set_vout(charger, MFC_VOUT_9V); | |
1941 | break; | |
1942 | case WIRELESS_VOUT_10V: | |
1943 | mfc_set_vout(charger, MFC_VOUT_10V); | |
1944 | /* reset AICL */ | |
1945 | psy_do_property("wireless", set, | |
1946 | POWER_SUPPLY_PROP_CURRENT_MAX, value); | |
1947 | break; | |
1948 | case WIRELESS_VOUT_5V_STEP: | |
1949 | vout_step--; | |
1950 | if (vout_step >= MFC_VOUT_5V) { | |
1951 | mfc_set_vout(charger, vout_step); | |
1952 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
1953 | queue_delayed_work(charger->wqueue, | |
1954 | &charger->wpc_vout_mode_work, msecs_to_jiffies(250)); | |
1955 | return; | |
1956 | } | |
1957 | break; | |
1958 | case WIRELESS_VOUT_9V_STEP: | |
1959 | vout = MFC_VOUT_9V; | |
1960 | case WIRELESS_VOUT_10V_STEP: | |
1961 | vout_step++; | |
1962 | if (vout_step <= vout) { | |
1963 | mfc_set_vout(charger, vout_step); | |
1964 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
1965 | queue_delayed_work(charger->wqueue, | |
1966 | &charger->wpc_vout_mode_work, msecs_to_jiffies(250)); | |
1967 | return; | |
1968 | } | |
1969 | break; | |
1970 | case WIRELESS_VOUT_CV_CALL: | |
1971 | case WIRELESS_VOUT_CC_CALL: | |
1972 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_3); | |
1973 | msleep(500); | |
1974 | mfc_set_vout(charger, MFC_VOUT_5V); | |
1975 | msleep(500); | |
1976 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_0); | |
1977 | break; | |
1978 | case WIRELESS_VOUT_CC_CV_VOUT: | |
1979 | mfc_set_vout(charger, MFC_VOUT_5_5V); | |
1980 | break; | |
1981 | default: | |
1982 | break; | |
1983 | } | |
1984 | #if !defined(CONFIG_SEC_FACTORY) | |
1985 | if ((charger->pdata->cable_type == MFC_PAD_WPC_AFC || | |
1986 | charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV || | |
1987 | charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV || | |
1988 | charger->pdata->cable_type == MFC_PAD_WPC_VEHICLE_HV) && | |
1989 | charger->pdata->vout_status <= MFC_VOUT_5V && charger->is_full_status) { | |
1990 | u8 data = 0x05; | |
1991 | /* send data for decreasing VRECT to 5V */ | |
1992 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, | |
1993 | WPC_COM_AFC_SET, &data, 1); | |
1994 | pr_info("%s: set TX 5V after cs100\n", __func__); | |
1995 | } | |
1996 | #endif | |
1997 | pr_info("%s: finish - vout_mode(%d), vout_status(%d)\n", | |
1998 | __func__, charger->vout_mode, charger->pdata->vout_status); | |
1999 | wake_unlock(&charger->wpc_vout_mode_lock); | |
2000 | } | |
2001 | ||
2002 | static void mfc_wpc_i2c_error_work(struct work_struct *work) | |
2003 | { | |
2004 | struct mfc_charger_data *charger = | |
2005 | container_of(work, struct mfc_charger_data, wpc_i2c_error_work.work); | |
2006 | ||
2007 | if (charger->wc_w_state && | |
2008 | gpio_get_value(charger->pdata->wpc_det)) { | |
2009 | union power_supply_propval value; | |
2010 | ||
2011 | psy_do_property("battery", set, | |
2012 | POWER_SUPPLY_EXT_PROP_WC_CONTROL, value); | |
2013 | } | |
2014 | } | |
2015 | ||
2016 | #if defined(CONFIG_UPDATE_BATTERY_DATA) | |
2017 | static int mfc_chg_parse_dt(struct device *dev, mfc_charger_platform_data_t *pdata); | |
2018 | #endif | |
2019 | static int mfc_chg_set_property(struct power_supply *psy, | |
2020 | enum power_supply_property psp, | |
2021 | const union power_supply_propval *val) | |
2022 | { | |
2023 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
77b262dc | 2024 | enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp; |
1cac41cb MB |
2025 | int vout, vrect, iout, freq, i = 0; |
2026 | u8 tmp = 0; | |
2027 | /* int ret; */ | |
2028 | union power_supply_propval value; | |
2029 | u8 fod[12] = {0, }; | |
2030 | ||
2031 | switch (psp) { | |
2032 | case POWER_SUPPLY_PROP_STATUS: | |
2033 | if (val->intval == POWER_SUPPLY_STATUS_FULL) { | |
2034 | pr_info("%s set cs100\n", __func__); | |
2035 | if (charger->pdata->cable_type == SEC_WIRELESS_PAD_WPC) { | |
2036 | /* set fake FOD values before send cs100, need to tune */ | |
2037 | mfc_fod_set_cs100(charger); | |
2038 | } | |
2039 | charger->pdata->cs100_status = mfc_send_cs100(charger); | |
2040 | #if !defined(CONFIG_SEC_FACTORY) | |
2041 | charger->is_full_status = 1; | |
2042 | if (charger->pdata->cable_type == MFC_PAD_WPC_AFC || | |
2043 | charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV || | |
2044 | charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV || | |
2045 | charger->pdata->cable_type == MFC_PAD_WPC_VEHICLE_HV) { | |
2046 | charger->vout_mode = WIRELESS_VOUT_5V_STEP; | |
2047 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
2048 | wake_lock(&charger->wpc_vout_mode_lock); | |
2049 | queue_delayed_work(charger->wqueue, | |
2050 | &charger->wpc_vout_mode_work, msecs_to_jiffies(250)); | |
2051 | } | |
2052 | #endif | |
2053 | } else if (val->intval == POWER_SUPPLY_STATUS_NOT_CHARGING) { | |
2054 | mfc_mis_align(charger); | |
2055 | } else if (val->intval == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE) { | |
2056 | mfc_fod_set_cv(charger); | |
2057 | } | |
2058 | break; | |
2059 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | |
2060 | value.intval = charger->pdata->cable_type; | |
2061 | psy_do_property("wireless", set, POWER_SUPPLY_PROP_ONLINE, value); | |
2062 | break; | |
2063 | case POWER_SUPPLY_PROP_HEALTH: | |
2064 | if (val->intval == POWER_SUPPLY_HEALTH_OVERHEAT || | |
2065 | val->intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT || | |
2066 | val->intval == POWER_SUPPLY_HEALTH_COLD) { | |
2067 | pr_info("%s ept-ot\n", __func__); | |
2068 | mfc_send_eop(charger, val->intval); | |
2069 | } | |
2070 | break; | |
2071 | case POWER_SUPPLY_PROP_ONLINE: | |
2072 | if (is_wireless_type(val->intval)) | |
2073 | charger->pdata->ic_on_mode = true; | |
2074 | else | |
2075 | charger->pdata->ic_on_mode = false; | |
2076 | break; | |
2077 | case POWER_SUPPLY_PROP_TECHNOLOGY: | |
2078 | if (val->intval) { | |
2079 | charger->is_mst_on = MST_MODE_2; | |
2080 | pr_info("%s: set MST mode 2\n", __func__); | |
2081 | /* disable CM FETs to avoid MST/WPC crash situation */ | |
2082 | queue_delayed_work(charger->wqueue, | |
2083 | &charger->wpc_cm_fet_work, msecs_to_jiffies(1000)); | |
2084 | } else { | |
2085 | if (charger->chip_id == MFC_CHIP_LSI) { | |
2086 | /* | |
2087 | * Default Idle voltage of the INT_A is LOW. | |
2088 | * Prevent the un-wanted INT_A Falling handling. | |
2089 | * This is a work-around, and will be fixed by the revision. | |
2090 | */ | |
2091 | charger->mst_off_lock = 1; | |
2092 | if (!delayed_work_pending(&charger->mst_off_work)) | |
2093 | queue_delayed_work(charger->wqueue, &charger->mst_off_work, 0); | |
2094 | } | |
2095 | pr_info("%s: set MST mode off\n", __func__); | |
2096 | charger->is_mst_on = MST_MODE_0; | |
2097 | } | |
2098 | break; | |
2099 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | |
2100 | charger->pdata->siop_level = val->intval; | |
2101 | if (charger->pdata->siop_level == 100) { | |
2102 | pr_info("%s vrect headroom set ROOM 2, siop = %d\n", __func__, charger->pdata->siop_level); | |
2103 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_2); | |
2104 | } else if (charger->pdata->siop_level < 100) { | |
2105 | pr_info("%s vrect headroom set ROOM 0, siop = %d\n", __func__, charger->pdata->siop_level); | |
2106 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_0); | |
2107 | } | |
2108 | break; | |
2109 | case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: | |
2110 | if (val->intval) | |
2111 | charger->pdata->ic_on_mode = true; | |
2112 | else | |
2113 | charger->pdata->ic_on_mode = false; | |
2114 | break; | |
2115 | case POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL: | |
2116 | charger->fw_cmd = val->intval; | |
2117 | queue_delayed_work(charger->wqueue, &charger->wpc_fw_update_work, 0); | |
2118 | pr_info("%s: rx result = %d, tx result = %d\n", __func__, | |
2119 | charger->pdata->otp_firmware_result, charger->pdata->tx_firmware_result); | |
2120 | break; | |
2121 | case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: | |
2122 | if (val->intval == WIRELESS_VOUT_NORMAL_VOLTAGE) { | |
2123 | pr_info("%s: Wireless Vout forced set to 5V. + PAD CMD\n", __func__); | |
2124 | for (i = 0; i < CMD_CNT; i++) { | |
2125 | mfc_send_command(charger, MFC_AFC_CONF_5V); | |
2126 | msleep(250); | |
2127 | } | |
2128 | } else if (val->intval == WIRELESS_VOUT_HIGH_VOLTAGE) { | |
2129 | pr_info("%s: Wireless Vout forced set to 10V. + PAD CMD\n", __func__); | |
2130 | for (i = 0; i < CMD_CNT; i++) { | |
2131 | mfc_send_command(charger, MFC_AFC_CONF_10V); | |
2132 | msleep(250); | |
2133 | } | |
2134 | } else if (val->intval == WIRELESS_VOUT_CC_CV_VOUT || | |
2135 | val->intval == WIRELESS_VOUT_CV_CALL || | |
2136 | val->intval == WIRELESS_VOUT_CC_CALL) { | |
2137 | charger->vout_mode = val->intval; | |
2138 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
2139 | wake_lock(&charger->wpc_vout_mode_lock); | |
2140 | queue_delayed_work(charger->wqueue, | |
2141 | &charger->wpc_vout_mode_work, 0); | |
2142 | } else if (val->intval == WIRELESS_VOUT_5V || | |
2143 | val->intval == WIRELESS_VOUT_5V_STEP) { | |
2144 | int def_delay = 0; | |
2145 | ||
2146 | charger->vout_mode = val->intval; | |
2147 | if ((charger->pdata->cable_type == MFC_PAD_WPC_AFC || | |
2148 | charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV || | |
2149 | charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV || | |
2150 | charger->pdata->cable_type == MFC_PAD_WPC_VEHICLE_HV)) { | |
2151 | def_delay = 250; | |
2152 | } | |
2153 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
2154 | wake_lock(&charger->wpc_vout_mode_lock); | |
2155 | queue_delayed_work(charger->wqueue, | |
2156 | &charger->wpc_vout_mode_work, msecs_to_jiffies(def_delay)); | |
2157 | } else if (val->intval == WIRELESS_VOUT_9V || | |
2158 | val->intval == WIRELESS_VOUT_10V || | |
2159 | val->intval == WIRELESS_VOUT_9V_STEP || | |
2160 | val->intval == WIRELESS_VOUT_10V_STEP) { | |
2161 | if (!charger->is_full_status) { | |
2162 | if (!charger->is_afc_tx) { | |
2163 | u8 data_val[4], cmd = 0; | |
2164 | ||
2165 | pr_info("%s: need to set afc tx before vout control\n", __func__); | |
2166 | for (i = 0; i < CMD_CNT; i++) { | |
2167 | cmd = WPC_COM_AFC_SET; | |
2168 | data_val[0] = 0x2c; /* Value for WPC AFC_SET 10V */ | |
2169 | pr_info("%s set 10V , cnt = %d\n", __func__, i); | |
2170 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, cmd, data_val, 1); | |
2171 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_COM_REG, &data_val[0]); | |
2172 | mfc_reg_read(charger->client, MFC_WPC_RX_DATA_VALUE0_REG, &data_val[0]); | |
2173 | mfc_reg_read(charger->client, MFC_AP2MFC_CMD_L_REG, &data_val[0]); | |
2174 | msleep(100); | |
2175 | } | |
2176 | charger->is_afc_tx = true; | |
2177 | pr_info("%s: is_afc_tx = %d vout read = %d\n", | |
2178 | __func__, charger->is_afc_tx, mfc_get_adc(charger, MFC_ADC_VOUT)); | |
2179 | ||
2180 | /* use all CM FETs for 10V wireless charging */ | |
2181 | mfc_reg_write(charger->client, MFC_RX_COMM_MOD_FET_REG, 0x00); | |
2182 | mfc_reg_read(charger->client, MFC_RX_COMM_MOD_FET_REG, &cmd); | |
2183 | pr_info("%s: CM FET setting(0x%x)\n", __func__, cmd); | |
2184 | } | |
2185 | charger->vout_mode = val->intval; | |
2186 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
2187 | wake_lock(&charger->wpc_vout_mode_lock); | |
2188 | queue_delayed_work(charger->wqueue, | |
2189 | &charger->wpc_vout_mode_work, msecs_to_jiffies(250)); | |
2190 | } else { | |
2191 | pr_info("%s: block to set high vout level(vs=%d) because full status\n", | |
2192 | __func__, charger->pdata->vout_status); | |
2193 | } | |
2194 | } else if (val->intval == WIRELESS_PAD_FAN_OFF) { | |
2195 | pr_info("%s: fan off\n", __func__); | |
2196 | mfc_fan_control(charger, 0); | |
2197 | } else if (val->intval == WIRELESS_PAD_FAN_ON) { | |
2198 | pr_info("%s: fan on\n", __func__); | |
2199 | mfc_fan_control(charger, 1); | |
2200 | } else if (val->intval == WIRELESS_PAD_LED_OFF) { | |
2201 | pr_info("%s: led off\n", __func__); | |
2202 | mfc_led_control(charger, 0); | |
2203 | } else if (val->intval == WIRELESS_PAD_LED_ON) { | |
2204 | pr_info("%s: led on\n", __func__); | |
2205 | mfc_led_control(charger, 1); | |
2206 | } else if (val->intval == WIRELESS_VRECT_ADJ_ON) { | |
2207 | pr_info("%s: vrect adjust to have big headroom(default value)\n", __func__); | |
2208 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_1); | |
2209 | } else if (val->intval == WIRELESS_VRECT_ADJ_OFF) { | |
2210 | pr_info("%s: vrect adjust to have small headroom\n", __func__); | |
2211 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_0); | |
2212 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_0) { | |
2213 | pr_info("%s: vrect adjust to have headroom 0(0mV)\n", __func__); | |
2214 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_0); | |
2215 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_1) { | |
2216 | pr_info("%s: vrect adjust to have headroom 1(277mV)\n", __func__); | |
2217 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_1); | |
2218 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_2) { | |
2219 | pr_info("%s: vrect adjust to have headroom 2(497mV)\n", __func__); | |
2220 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_2); | |
2221 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_3) { | |
2222 | pr_info("%s: vrect adjust to have headroom 3(650mV)\n", __func__); | |
2223 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_3); | |
2224 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_4) { | |
2225 | pr_info("%s: vrect adjust to have headroom 4(30mV)\n", __func__); | |
2226 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_4); | |
2227 | } else if (val->intval == WIRELESS_VRECT_ADJ_ROOM_5) { | |
2228 | pr_info("%s: vrect adjust to have headroom 5(82mV)\n", __func__); | |
2229 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_5); | |
2230 | } else if (val->intval == WIRELESS_CLAMP_ENABLE) { | |
2231 | pr_info("%s: enable clamp1, clamp2 for WPC modulation\n", __func__); | |
2232 | //default enabled state. no need to config. | |
2233 | //mfc_reg_update(charger->client, MFC_RX_COMM_MOD_FET_REG, 0x00, 0x00); | |
2234 | } else { | |
2235 | pr_info("%s: Unknown Command(%d)\n", __func__, val->intval); | |
2236 | } | |
2237 | break; | |
2238 | case POWER_SUPPLY_PROP_MANUFACTURER: | |
2239 | charger->pdata->otp_firmware_result = val->intval; | |
2240 | pr_info("%s: otp_firmware result initialize (%d)\n", __func__, | |
2241 | charger->pdata->otp_firmware_result); | |
2242 | break; | |
2243 | #if defined(CONFIG_UPDATE_BATTERY_DATA) | |
2244 | case POWER_SUPPLY_PROP_POWER_DESIGN: | |
2245 | mfc_chg_parse_dt(charger->dev, charger->pdata); | |
2246 | break; | |
2247 | #endif | |
2248 | case POWER_SUPPLY_PROP_ENERGY_NOW: | |
2249 | vout = mfc_get_adc(charger, MFC_ADC_VOUT); | |
2250 | vrect = mfc_get_adc(charger, MFC_ADC_VRECT); | |
2251 | iout = mfc_get_adc(charger, MFC_ADC_RX_IOUT); | |
2252 | freq = mfc_get_adc(charger, MFC_ADC_OP_FRQ); | |
2253 | pr_info("%s RX_VOUT = %dmV, RX_VRECT = %dmV, RX_IOUT = %dmA, OP_FREQ = %dKHz, IC Rev = 0x%x, IC Font = 0x%x, cable=%d\n", | |
2254 | __func__, vout, vrect, iout, freq, mfc_get_ic_revision(charger, MFC_IC_REVISION), | |
2255 | mfc_get_ic_revision(charger, MFC_IC_FONT), charger->pdata->cable_type); | |
2256 | ||
2257 | charger->pdata->capacity = val->intval; | |
2258 | if ((vout < 6500) && (charger->pdata->capacity >= 85)) { | |
2259 | mfc_reg_read(charger->client, MFC_RX_COMM_MOD_FET_REG, &tmp); | |
2260 | if (tmp != 0x00) { | |
2261 | /* use all CM FETs for 10V wireless charging */ | |
2262 | mfc_reg_write(charger->client, MFC_RX_COMM_MOD_FET_REG, 0x00); | |
2263 | mfc_reg_read(charger->client, MFC_RX_COMM_MOD_FET_REG, &tmp); | |
2264 | pr_info("%s: CM FET setting(0x%x)\n", __func__, tmp); | |
2265 | } | |
2266 | } | |
2267 | ||
2268 | for (i = 0; i < MFC_NUM_FOD_REG; i++) | |
2269 | mfc_reg_read(charger->client, MFC_WPC_FOD_0A_REG+i, &fod[i]); | |
2270 | pr_info("%s: FOD(%d %d %d %d %d %d %d %d %d %d %d %d)\n", __func__, | |
2271 | fod[0], fod[1], fod[2], fod[3], fod[4], fod[5], | |
2272 | fod[6], fod[7], fod[8], fod[9], fod[10], fod[11]); | |
2273 | break; | |
2274 | case POWER_SUPPLY_PROP_FILTER_CFG: | |
2275 | charger->led_cover = val->intval; | |
2276 | pr_info("%s: LED_COVER(%d)\n", __func__, charger->led_cover); | |
2277 | break; | |
2278 | case POWER_SUPPLY_PROP_CHARGE_EMPTY: | |
2279 | mfc_reg_read(charger->client, MFC_STATUS_L_REG, &tmp); | |
2280 | tmp = tmp >> 7; | |
2281 | pr_info("%s: MFC LDO (%d), vout (%d)\n", __func__, val->intval, tmp); | |
2282 | if (val->intval && !tmp) { /* LDO ON */ | |
2283 | mfc_set_cmd_l_reg(charger, MFC_CMD_TOGGLE_LDO_MASK, MFC_CMD_TOGGLE_LDO_MASK); | |
2284 | pr_info("%s: MFC LDO toggle ------------ cable_work\n", __func__); | |
2285 | msleep(3); | |
2286 | mfc_reg_read(charger->client, MFC_STATUS_L_REG, &tmp); | |
2287 | tmp = tmp >> 7; | |
2288 | pr_info("%s: MFC LDO STAT(%d)\n", __func__, tmp); | |
2289 | } else if (!val->intval && tmp) { /* LDO OFF */ | |
2290 | pr_info("%s: MFC LDO toggle ------------ cable_work\n", __func__); | |
2291 | mfc_set_cmd_l_reg(charger, MFC_CMD_TOGGLE_LDO_MASK, MFC_CMD_TOGGLE_LDO_MASK); | |
2292 | msleep(3); | |
2293 | mfc_reg_read(charger->client, MFC_STATUS_L_REG, &tmp); | |
2294 | tmp = tmp >> 7; | |
2295 | pr_info("%s: MFC LDO STAT(%d)\n", __func__, tmp); | |
2296 | } | |
2297 | break; | |
2298 | case POWER_SUPPLY_PROP_SCOPE: | |
2299 | return -ENODATA; | |
2300 | case POWER_SUPPLY_PROP_MAX ... POWER_SUPPLY_EXT_PROP_MAX: | |
2301 | switch (ext_psp) { | |
2302 | case POWER_SUPPLY_EXT_PROP_WC_CONTROL: | |
2303 | if (val->intval == 0) { | |
2304 | tmp = 0x01; | |
2305 | mfc_send_packet(charger, MFC_HEADER_AFC_CONF, | |
2306 | 0x20, &tmp, 1); | |
2307 | pr_info("%s: send command after wc control\n", __func__); | |
2308 | mdelay(150); | |
2309 | } | |
2310 | break; | |
2311 | case POWER_SUPPLY_EXT_PROP_CALL_EVENT: | |
2312 | if (val->intval & BATT_EXT_EVENT_CALL) { | |
2313 | charger->device_event |= BATT_EXT_EVENT_CALL; | |
2314 | ||
2315 | /* call in is after wireless connection */ | |
2316 | if(charger->pdata->cable_type == MFC_PAD_WPC_PACK || | |
2317 | charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV || | |
2318 | charger->pdata->cable_type == MFC_PAD_TX) { | |
2319 | union power_supply_propval value2; | |
2320 | pr_info("%s : enter PHM \n", __func__); | |
2321 | /* notify "wireless" PHM status */ | |
2322 | value2.intval = 1; | |
2323 | psy_do_property("wireless", set, | |
2324 | POWER_SUPPLY_EXT_PROP_CALL_EVENT, value2); | |
2325 | mfc_send_command(charger, MFC_PHM_ON); | |
2326 | msleep(250); | |
2327 | mfc_send_command(charger, MFC_PHM_ON); | |
2328 | } | |
2329 | } else if (val->intval == BATT_EXT_EVENT_NONE) { | |
2330 | charger->device_event &= ~BATT_EXT_EVENT_CALL; | |
2331 | } | |
2332 | break; | |
2333 | default: | |
2334 | return -ENODATA; | |
2335 | } | |
2336 | break; | |
2337 | default: | |
2338 | return -ENODATA; | |
2339 | } | |
2340 | ||
2341 | return 0; | |
2342 | } | |
2343 | ||
2344 | #define FREQ_OFFSET 384000 /* 64*6000 */ | |
2345 | static void mfc_wpc_opfq_work(struct work_struct *work) | |
2346 | { | |
2347 | struct mfc_charger_data *charger = | |
2348 | container_of(work, struct mfc_charger_data, wpc_opfq_work.work); | |
2349 | ||
2350 | u16 op_fq; | |
2351 | u8 pad_mode; | |
2352 | union power_supply_propval value; | |
2353 | ||
2354 | mfc_reg_read(charger->client, MFC_SYS_OP_MODE_REG, &pad_mode); | |
2355 | if ((pad_mode == PAD_MODE_WPC_BASIC) ||\ | |
2356 | (pad_mode == PAD_MODE_WPC_ADV)) { | |
2357 | op_fq = mfc_get_adc(charger, MFC_ADC_OP_FRQ); | |
2358 | pr_info("%s: Operating FQ %dkHz(0x%x)\n", __func__, op_fq, op_fq); | |
2359 | if (op_fq > 230) { /* wpc threshold 230kHz */ | |
2360 | pr_info("%s: Reset M0\n",__func__); | |
2361 | mfc_reg_write(charger->client, 0x3040, 0x80); /*restart M0 */ | |
2362 | ||
2363 | charger->pdata->opfq_cnt++; | |
2364 | if (charger->pdata->opfq_cnt <= CMD_CNT) { | |
2365 | queue_delayed_work(charger->wqueue, &charger->wpc_opfq_work, msecs_to_jiffies(10000)); | |
2366 | return; | |
2367 | } | |
2368 | } | |
2369 | } else if ((pad_mode == PAD_MODE_PMA_SR1) ||\ | |
2370 | (pad_mode == PAD_MODE_PMA_SR1E)) { | |
2371 | charger->pdata->cable_type = MFC_PAD_PMA; | |
2372 | value.intval = SEC_WIRELESS_PAD_PMA; | |
2373 | psy_do_property("wireless", set, POWER_SUPPLY_PROP_ONLINE, value); | |
2374 | } | |
2375 | charger->pdata->opfq_cnt = 0; | |
2376 | wake_unlock(&charger->wpc_opfq_lock); | |
2377 | ||
2378 | } | |
2379 | ||
2380 | static void mfc_wpc_det_work(struct work_struct *work) | |
2381 | { | |
2382 | struct mfc_charger_data *charger = | |
2383 | container_of(work, struct mfc_charger_data, wpc_det_work.work); | |
2384 | int wc_w_state; | |
2385 | union power_supply_propval value; | |
2386 | u8 pad_mode; | |
2387 | u8 vrect; | |
2388 | ||
2389 | mfc_get_chip_id(charger); | |
2390 | pr_info("%s : first chip_id read(%d)\n", __func__, charger->chip_id); | |
2391 | if (charger->chip_id == MFC_CHIP_LSI) { | |
2392 | /* | |
2393 | * We don't have to handle the wpc detect handling, | |
2394 | * when it's the MST mode. | |
2395 | */ | |
2396 | if(charger->is_mst_on == MST_MODE_2) { | |
2397 | pr_info("%s MST RETURN!\n",__func__); | |
2398 | return; | |
2399 | } | |
2400 | ||
2401 | if(charger->mst_off_lock == 1) { | |
2402 | pr_info("%s MST Off Lock!\n",__func__); | |
2403 | return; | |
2404 | } | |
2405 | } | |
2406 | ||
2407 | if (charger->is_mst_on == MST_MODE_2) { | |
2408 | pr_info("%s: check wpc-state(%d - %d)\n", __func__, | |
2409 | charger->wc_w_state, gpio_get_value(charger->pdata->wpc_det)); | |
2410 | ||
2411 | if (charger->wc_w_state == 0) { | |
2412 | pr_info("%s: skip wpc_det_work for MST operation\n", __func__); | |
2413 | return; | |
2414 | } | |
2415 | } | |
2416 | ||
2417 | wake_lock(&charger->wpc_wake_lock); | |
2418 | pr_info("%s\n",__func__); | |
2419 | wc_w_state = gpio_get_value(charger->pdata->wpc_det); | |
2420 | ||
2421 | if ((charger->wc_w_state == 0) && (wc_w_state == 1)) { | |
2422 | charger->pdata->vout_status = MFC_VOUT_5V; | |
2423 | ||
2424 | #if 0 /* To prepare for the future issue */ | |
2425 | /* read firmware version */ | |
2426 | if(mfc_get_firmware_version(charger, MFC_RX_FIRMWARE) == MFC_OTP_FIRM_VERSION && adc_cal > 0) | |
2427 | mfc_runtime_sram_change(charger);/* change sram */ | |
2428 | #endif | |
2429 | ||
2430 | mfc_get_chip_id(charger); | |
2431 | ||
2432 | /* enable Mode Change INT */ | |
2433 | mfc_reg_update(charger->client, MFC_INT_A_ENABLE_L_REG, | |
2434 | MFC_STAT_L_OP_MODE_MASK, MFC_STAT_L_OP_MODE_MASK); | |
2435 | ||
2436 | /* read vrect adjust */ | |
2437 | mfc_reg_read(charger->client, MFC_VRECT_ADJ_REG, &vrect); | |
2438 | ||
2439 | pr_info("%s: wireless charger activated, set V_INT as PN\n",__func__); | |
2440 | ||
2441 | /* read pad mode */ | |
2442 | mfc_reg_read(charger->client, MFC_SYS_OP_MODE_REG, &pad_mode); | |
2443 | pad_mode = pad_mode >> 5; | |
2444 | pr_info("%s: Pad type (0x%x)\n", __func__, pad_mode); | |
2445 | if ((pad_mode == PAD_MODE_PMA_SR1) || | |
2446 | (pad_mode == PAD_MODE_PMA_SR1E)) { | |
2447 | charger->pdata->cable_type = MFC_PAD_PMA; | |
2448 | value.intval = SEC_WIRELESS_PAD_PMA; | |
2449 | psy_do_property("wireless", set, | |
2450 | POWER_SUPPLY_PROP_ONLINE, value); | |
2451 | } else if ((pad_mode == PAD_MODE_WPC_BASIC) || | |
2452 | (pad_mode == PAD_MODE_WPC_ADV)) { | |
2453 | charger->pdata->cable_type = MFC_PAD_WPC; | |
2454 | value.intval = SEC_WIRELESS_PAD_WPC; | |
2455 | psy_do_property("wireless", set, | |
2456 | POWER_SUPPLY_PROP_ONLINE, value); | |
2457 | wake_lock(&charger->wpc_opfq_lock); | |
2458 | queue_delayed_work(charger->wqueue, &charger->wpc_opfq_work, msecs_to_jiffies(10000)); | |
2459 | } else if ((pad_mode == PAD_MODE_A4WP) || | |
2460 | (pad_mode == PAD_MODE_A4WP_LPM)) { | |
2461 | /* Enable BT2AP INT src */ | |
2462 | mfc_reg_write(charger->client, MFC_INT_A_ENABLE_L_REG, 0x03); // ENABLE BT2AP INTR | |
2463 | mfc_reg_write(charger->client, MFC_INT_A_ENABLE_H_REG, 0x80); // ENABLE BT2AP INTR | |
2464 | ||
2465 | /* Enable AP2BT INT src */ | |
2466 | mfc_reg_write(charger->client, MFC_INT_B_ENABLE_REG, 0x83); // ENABLE AP2BT INTR | |
2467 | ||
2468 | charger->pdata->cable_type = MFC_PAD_A4WP; | |
2469 | value.intval = SEC_WIRELESS_PAD_WPC; | |
2470 | psy_do_property("wireless", set, | |
2471 | POWER_SUPPLY_PROP_ONLINE, value); | |
2472 | } | |
2473 | ||
2474 | /* set fod value */ | |
2475 | if(charger->pdata->fod_data_check) | |
2476 | mfc_fod_set(charger); | |
2477 | #if !defined(CONFIG_WIRELESS_NO_HV) | |
2478 | if (!sleep_mode) { | |
2479 | int vrect_level, vout_level; | |
2480 | ||
2481 | vrect_level = mfc_get_adc(charger, MFC_ADC_VRECT); | |
2482 | vout_level = mfc_get_adc(charger, MFC_ADC_VOUT); | |
2483 | pr_info("%s: read vrect(%dmV), vout(%dmV)\n", __func__, vrect_level, vout_level); | |
2484 | if (vrect_level >= 8500 && vout_level >= 8500) { | |
2485 | /* re-set vout level */ | |
2486 | charger->pad_vout = PAD_VOUT_10V; | |
2487 | mfc_set_vout(charger, MFC_VOUT_10V); | |
2488 | ||
2489 | /* change cable type */ | |
2490 | charger->pdata->cable_type = (charger->pdata->cable_type == MFC_PAD_A4WP) ? | |
2491 | MFC_PAD_A4WP : MFC_PAD_WPC_AFC; | |
2492 | value.intval = SEC_WIRELESS_PAD_WPC_HV; | |
2493 | psy_do_property("wireless", set, | |
2494 | POWER_SUPPLY_PROP_ONLINE, value); | |
1cac41cb MB |
2495 | } else { |
2496 | /* send request afc_tx */ | |
2497 | mfc_send_command(charger, MFC_REQUEST_AFC_TX); | |
2498 | } | |
1cac41cb MB |
2499 | } |
2500 | #endif | |
2501 | /* set rpp scaling factor for LED cover */ | |
2502 | mfc_rpp_set(charger); | |
5a068558 MB |
2503 | |
2504 | wake_lock(&charger->wpc_tx_id_lock); | |
2505 | /* request tx id */ | |
2506 | queue_delayed_work(charger->wqueue, &charger->wpc_tx_id_work, msecs_to_jiffies(2500)); | |
1cac41cb MB |
2507 | |
2508 | charger->pdata->is_charging = 1; | |
2509 | } else if ((charger->wc_w_state == 1) && (wc_w_state == 0)) { | |
2510 | ||
2511 | charger->pdata->cable_type = MFC_PAD_NONE; | |
2512 | charger->pdata->is_charging = 0; | |
2513 | charger->pdata->vout_status = MFC_VOUT_5V; | |
2514 | charger->pad_vout = PAD_VOUT_5V; | |
2515 | charger->pdata->opfq_cnt = 0; | |
2516 | charger->pdata->tx_data_cmd = 0; | |
2517 | charger->pdata->tx_data_val = 0; | |
2518 | charger->vout_mode = 0; | |
2519 | charger->is_full_status = 0; | |
2520 | charger->pdata->capacity = 101; | |
2521 | charger->is_afc_tx = false; | |
2522 | charger->tx_id = 0; | |
2523 | charger->i2c_error_count = 0; | |
5a068558 | 2524 | charger->tx_id_cnt = 0; |
1cac41cb MB |
2525 | charger->tx_id_done = false; |
2526 | charger->device_event = 0; | |
2527 | ||
2528 | value.intval = SEC_WIRELESS_PAD_NONE; | |
2529 | psy_do_property("wireless", set, | |
2530 | POWER_SUPPLY_PROP_ONLINE, value); | |
2531 | pr_info("%s: wpc deactivated, set V_INT as PD\n",__func__); | |
2532 | ||
2533 | msleep(1000); | |
2534 | /* if vrect >= 3000mV and vout <= 2000mV, restart M0 */ | |
2535 | if (mfc_get_adc(charger, MFC_ADC_VRECT) >= 3000 && | |
2536 | mfc_get_adc(charger, MFC_ADC_VOUT) <= 2000) { | |
2537 | pr_err("%s Restart M0\n", __func__); | |
2538 | /* reset MCU of MFC IC */ | |
2539 | mfc_set_cmd_l_reg(charger, MFC_CMD_MCU_RESET_MASK, MFC_CMD_MCU_RESET_MASK); | |
2540 | } | |
2541 | ||
2542 | if (delayed_work_pending(&charger->wpc_opfq_work)) { | |
2543 | wake_unlock(&charger->wpc_opfq_lock); | |
2544 | cancel_delayed_work(&charger->wpc_opfq_work); | |
2545 | } | |
2546 | if (delayed_work_pending(&charger->wpc_afc_vout_work)) { | |
2547 | wake_unlock(&charger->wpc_afc_vout_lock); | |
2548 | cancel_delayed_work(&charger->wpc_afc_vout_work); | |
2549 | } | |
2550 | if (delayed_work_pending(&charger->wpc_vout_mode_work)) { | |
2551 | wake_unlock(&charger->wpc_vout_mode_lock); | |
2552 | cancel_delayed_work(&charger->wpc_vout_mode_work); | |
2553 | } | |
2554 | ||
2555 | cancel_delayed_work(&charger->wpc_isr_work); | |
2556 | cancel_delayed_work(&charger->wpc_opfq_work); | |
2557 | cancel_delayed_work(&charger->wpc_tx_id_work); | |
2558 | cancel_delayed_work(&charger->wpc_i2c_error_work); | |
5a068558 | 2559 | wake_unlock(&charger->wpc_tx_id_lock); |
1cac41cb MB |
2560 | } |
2561 | ||
2562 | pr_info("%s: w(%d to %d)\n", __func__, | |
2563 | charger->wc_w_state, wc_w_state); | |
2564 | ||
2565 | charger->wc_w_state = wc_w_state; | |
2566 | wake_unlock(&charger->wpc_wake_lock); | |
2567 | } | |
2568 | ||
2569 | /* INT_A (BT2AP interrupt) */ | |
2570 | static void mfc_wpc_isr_work(struct work_struct *work) | |
2571 | { | |
2572 | struct mfc_charger_data *charger = | |
2573 | container_of(work, struct mfc_charger_data, wpc_isr_work.work); | |
2574 | ||
2575 | u8 cmd_data, val_data; | |
2576 | #if !defined(CONFIG_WIRELESS_NO_HV) | |
2577 | int i; | |
2578 | #endif | |
2579 | union power_supply_propval value; | |
2580 | ||
2581 | if (!charger->wc_w_state) { | |
2582 | pr_info("%s: charger->wc_w_state is 0. exit wpc_isr_work.\n",__func__); | |
2583 | return; | |
2584 | } | |
2585 | ||
2586 | pr_info("%s: cable_type (0x%x)\n", __func__, charger->pdata->cable_type); | |
2587 | wake_lock(&charger->wpc_wake_lock); | |
2588 | pr_info("%s\n",__func__); | |
2589 | ||
2590 | ||
2591 | if (charger->pdata->cable_type == MFC_PAD_A4WP) { | |
2592 | mfc_reg_read(charger->client, MFC_BT2AP_DATA_COM_REG, &cmd_data); | |
2593 | mfc_reg_read(charger->client, MFC_BT2AP_DATA_VALUE0_REG, &val_data); | |
2594 | charger->pdata->tx_data_cmd = cmd_data; | |
2595 | charger->pdata->tx_data_val = val_data; | |
2596 | ||
2597 | pr_info("%s: A4WP Interrupt Occured, CMD : 0x%x, DATA : 0x%x\n", | |
2598 | __func__, cmd_data, val_data); | |
2599 | ||
2600 | switch (cmd_data) | |
2601 | { | |
2602 | case BT2AP_COM_TX_ID: | |
2603 | switch (val_data) { | |
2604 | case TX_ID_UNKNOWN: | |
2605 | case TX_ID_BATT_PACK_TA: | |
2606 | case TX_ID_BATT_PACK: | |
2607 | case TX_ID_STAND_TYPE_START: | |
2608 | default: | |
2609 | break; | |
2610 | } //cmd_data : BT2AP_COM_TX_ID switch end | |
2611 | break; | |
2612 | case BT2AP_COM_REQ_AFC_TX: | |
2613 | break; | |
2614 | case BT2AP_COM_AFC_MODE: | |
2615 | switch (val_data) { | |
2616 | case TX_AFC_SET_5V: | |
2617 | charger->pad_vout = PAD_VOUT_5V; | |
2618 | break; | |
2619 | case TX_AFC_SET_10V: | |
2620 | pr_info("%s data = 0x%x, might be 10V irq\n", __func__, val_data); | |
2621 | if (!gpio_get_value(charger->pdata->wpc_det)) { | |
2622 | wake_unlock(&charger->wpc_wake_lock); | |
2623 | return; | |
2624 | } else if (sleep_mode) { | |
2625 | pr_info("%s: does not needs to check afc mode at sleep_mode\n", __func__); | |
2626 | charger->pad_vout = PAD_VOUT_5V; | |
2627 | break; | |
2628 | } | |
2629 | #if !defined(CONFIG_WIRELESS_NO_HV) | |
2630 | mfc_send_command(charger, MFC_AFC_CONF_10V); | |
2631 | msleep(500); | |
2632 | charger->pdata->cable_type = MFC_PAD_A4WP; | |
2633 | /* If A4WP_HV is supported, then SEC_WIRELESS_PAD_A4WP_HV type should be used. | |
2634 | and sec_battery and charger file also have to change wireless cable type.*/ | |
2635 | value.intval = SEC_WIRELESS_PAD_WPC_HV; | |
2636 | psy_do_property("wireless", set, | |
2637 | POWER_SUPPLY_PROP_ONLINE, value); | |
2638 | ||
2639 | for (i = 0; i < CMD_CNT - 1; i++) { | |
2640 | if (!gpio_get_value(charger->pdata->wpc_det)) { | |
2641 | wake_unlock(&charger->wpc_wake_lock); | |
2642 | return; | |
2643 | } | |
2644 | if (mfc_get_adc(charger, MFC_ADC_VOUT) > 7500) { | |
2645 | pr_info("%s 10V set is done\n", __func__); | |
2646 | break; | |
2647 | } else { | |
2648 | pr_info("%s send AFC_CONF_10V again\n", __func__); | |
2649 | mfc_send_command(charger, MFC_AFC_CONF_10V); | |
2650 | msleep(500); | |
2651 | } | |
2652 | } | |
2653 | ||
2654 | charger->pad_vout = PAD_VOUT_10V; | |
2655 | #endif | |
2656 | break; | |
2657 | case TX_AFC_SET_12V: | |
2658 | case TX_AFC_SET_18V: | |
2659 | case TX_AFC_SET_19V: | |
2660 | case TX_AFC_SET_20V: | |
2661 | case TX_AFC_SET_24V: | |
2662 | default: | |
2663 | pr_info("%s: unsupport : 0x%x", __func__, val_data); | |
2664 | break; | |
2665 | } | |
2666 | break; | |
2667 | case BT2AP_COM_CHG_STATUS: | |
2668 | case BT2AP_COM_UNKNOWN: | |
2669 | case BT2AP_COM_PWR_STATUS: | |
2670 | case BT2AP_COM_SID_TAG: | |
2671 | case BT2AP_COM_SID_TOKEN: | |
2672 | case BT2AP_COM_TX_STANDBY: | |
2673 | case BT2AP_COM_COOLING_CTRL: | |
2674 | default: | |
2675 | break; | |
2676 | } | |
2677 | } else { /* WPC, PMA */ | |
2678 | ||
2679 | mfc_reg_read(charger->client, MFC_WPC_TX_DATA_COM_REG, &cmd_data); | |
2680 | mfc_reg_read(charger->client, MFC_WPC_TX_DATA_VALUE0_REG, &val_data); | |
2681 | charger->pdata->tx_data_cmd = cmd_data; | |
2682 | charger->pdata->tx_data_val = val_data; | |
2683 | ||
2684 | pr_info("%s: WPC Interrupt Occured, CMD : 0x%x, DATA : 0x%x\n", | |
2685 | __func__, cmd_data, val_data); | |
2686 | ||
2687 | if (cmd_data == WPC_TX_COM_AFC_SET) { | |
2688 | switch (val_data) { | |
2689 | case TX_AFC_SET_5V: | |
2690 | pr_info("%s data = 0x%x, might be 5V irq\n", __func__, val_data); | |
2691 | charger->pad_vout = PAD_VOUT_5V; | |
2692 | break; | |
2693 | case TX_AFC_SET_10V: | |
2694 | pr_info("%s data = 0x%x, might be 10V irq\n", __func__, val_data); | |
2695 | if (!gpio_get_value(charger->pdata->wpc_det)) { | |
2696 | pr_err("%s Wireless charging is paused during set high voltage.\n", __func__); | |
2697 | wake_unlock(&charger->wpc_wake_lock); | |
2698 | return; | |
2699 | } else if (sleep_mode) { | |
2700 | pr_info("%s: does not needs to check afc mode at sleep_mode\n", __func__); | |
2701 | charger->pad_vout = PAD_VOUT_5V; | |
2702 | break; | |
2703 | } | |
2704 | #if !defined(CONFIG_WIRELESS_NO_HV) | |
2705 | if (charger->pdata->cable_type == MFC_PAD_WPC_AFC || | |
2706 | charger->pdata->cable_type == MFC_PAD_PREPARE_HV || | |
2707 | charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV || | |
2708 | charger->pdata->cable_type == MFC_PAD_WPC_PACK_HV || | |
2709 | charger->pdata->cable_type == MFC_PAD_WPC_VEHICLE_HV) { | |
2710 | pr_err("%s: It is already HV wireless cable. No need to set again\n", __func__); | |
2711 | wake_unlock(&charger->wpc_wake_lock); | |
2712 | return; | |
2713 | } | |
2714 | ||
2715 | /* send AFC_SET */ | |
2716 | mfc_send_command(charger, MFC_AFC_CONF_10V); | |
2717 | msleep(500); | |
2718 | ||
2719 | /* change cable type */ | |
2720 | charger->pdata->cable_type = MFC_PAD_PREPARE_HV; | |
2721 | value.intval = SEC_WIRELESS_PAD_PREPARE_HV; | |
2722 | psy_do_property("wireless", set, | |
2723 | POWER_SUPPLY_PROP_ONLINE, value); | |
2724 | ||
2725 | charger->pad_vout = PAD_VOUT_10V; | |
2726 | #endif | |
2727 | break; | |
2728 | case TX_AFC_SET_12V: | |
2729 | break; | |
2730 | case TX_AFC_SET_18V: | |
2731 | case TX_AFC_SET_19V: | |
2732 | case TX_AFC_SET_20V: | |
2733 | case TX_AFC_SET_24V: | |
2734 | break; | |
2735 | default: | |
2736 | pr_info("%s: unsupport : 0x%x", __func__, val_data); | |
2737 | break; | |
2738 | } | |
1cac41cb MB |
2739 | } else if (cmd_data == WPC_TX_COM_TX_ID) { |
2740 | if (!charger->tx_id_done) { | |
2741 | switch (val_data) { | |
2742 | case TX_ID_UNKNOWN: | |
2743 | break; | |
2744 | case TX_ID_VEHICLE_PAD: | |
2745 | if (charger->pad_vout == PAD_VOUT_10V) { | |
2746 | if (charger->pdata->cable_type == MFC_PAD_PREPARE_HV) { | |
2747 | charger->pdata->cable_type = MFC_PAD_WPC_VEHICLE_HV; | |
2748 | value.intval = SEC_WIRELESS_PAD_PREPARE_HV; | |
2749 | } else { | |
2750 | charger->pdata->cable_type = MFC_PAD_WPC_VEHICLE_HV; | |
2751 | value.intval = SEC_WIRELESS_PAD_VEHICLE_HV; | |
2752 | } | |
2753 | } else { | |
2754 | charger->pdata->cable_type = MFC_PAD_WPC_VEHICLE; | |
2755 | value.intval = SEC_WIRELESS_PAD_VEHICLE; | |
2756 | } | |
2757 | pr_info("%s: VEHICLE Wireless Charge PAD %s\n", __func__, | |
2758 | charger->pad_vout == PAD_VOUT_10V ? "HV" : ""); | |
2759 | ||
2760 | break; | |
2761 | case TX_ID_STAND_TYPE_START: | |
2762 | if (charger->pad_vout == PAD_VOUT_10V) { | |
2763 | if (charger->pdata->cable_type == MFC_PAD_PREPARE_HV) { | |
2764 | charger->pdata->cable_type = MFC_PAD_WPC_STAND_HV; | |
2765 | value.intval = SEC_WIRELESS_PAD_PREPARE_HV; | |
2766 | } else { | |
2767 | charger->pdata->cable_type = MFC_PAD_WPC_STAND_HV; | |
2768 | value.intval = SEC_WIRELESS_PAD_WPC_STAND_HV; | |
2769 | } | |
2770 | } else { | |
2771 | charger->pdata->cable_type = MFC_PAD_WPC_STAND; | |
2772 | value.intval = SEC_WIRELESS_PAD_WPC_STAND; | |
2773 | mfc_fod_set_hero_5v(charger); | |
2774 | } | |
2775 | pr_info("%s: STAND Wireless Charge PAD %s\n", __func__, | |
2776 | charger->pad_vout == PAD_VOUT_10V ? "HV" : ""); | |
2777 | pr_info("%s: cable_type(%d)\n", __func__, charger->pdata->cable_type); | |
2778 | break; | |
2779 | case TX_ID_BATT_PACK ... TX_ID_BATT_PACK_END: | |
2780 | if (charger->pad_vout == PAD_VOUT_10V) { | |
2781 | if (charger->pdata->cable_type == MFC_PAD_PREPARE_HV) { | |
2782 | charger->pdata->cable_type = MFC_PAD_WPC_PACK_HV; | |
2783 | value.intval = SEC_WIRELESS_PAD_PREPARE_HV; | |
2784 | pr_info("%s: WIRELESS HV BATTERY PACK (PREP) \n", __func__); | |
2785 | } else { | |
2786 | charger->pdata->cable_type = MFC_PAD_WPC_PACK_HV; | |
2787 | value.intval = SEC_WIRELESS_PAD_WPC_PACK_HV; | |
2788 | pr_info("%s: WIRELESS HV BATTERY PACK\n", __func__); | |
2789 | } | |
2790 | } else { | |
2791 | charger->pdata->cable_type = MFC_PAD_WPC_PACK; | |
2792 | value.intval = SEC_WIRELESS_PAD_WPC_PACK; | |
2793 | pr_info("%s: WIRELESS BATTERY PACK\n", __func__); | |
2794 | } | |
2795 | if (charger->device_event & BATT_EXT_EVENT_CALL) { | |
2796 | union power_supply_propval value2; | |
2797 | pr_info("%s enter PHM \n", __func__); | |
2798 | /* notify "wireless" PHM status */ | |
2799 | value2.intval = 1; | |
2800 | psy_do_property("wireless", set, | |
2801 | POWER_SUPPLY_EXT_PROP_CALL_EVENT, value2); | |
2802 | mfc_send_command(charger, MFC_PHM_ON); | |
2803 | msleep(250); | |
2804 | mfc_send_command(charger, MFC_PHM_ON); | |
2805 | } | |
2806 | break; | |
2807 | case TX_ID_UNO_TX: | |
2808 | case TX_ID_UNO_TX_B0 ... TX_ID_UNO_TX_MAX: | |
2809 | charger->pdata->cable_type = MFC_PAD_TX; | |
2810 | value.intval = SEC_WIRELESS_PAD_TX; | |
2811 | pr_info("%s: TX by UNO\n", __func__); | |
2812 | if (charger->device_event & BATT_EXT_EVENT_CALL) { | |
2813 | pr_info("%s: enter PHM \n", __func__); | |
2814 | mfc_send_command(charger, MFC_PHM_ON); | |
2815 | msleep(250); | |
2816 | mfc_send_command(charger, MFC_PHM_ON); | |
2817 | } | |
2818 | break; | |
2819 | default: | |
2820 | value.intval = charger->pdata->cable_type; | |
2821 | pr_info("%s: UNDEFINED PAD : 0x%x\n", __func__, val_data); | |
2822 | break; | |
2823 | } | |
2824 | if (value.intval != MFC_PAD_PREPARE_HV) | |
2825 | psy_do_property("wireless", set, POWER_SUPPLY_PROP_ONLINE, value); | |
2826 | ||
2827 | charger->tx_id_done = true; | |
2828 | charger->tx_id = val_data; | |
2829 | pr_info("%s: TX_ID : 0x%x\n", __func__, val_data); | |
2830 | value.intval = val_data; | |
2831 | psy_do_property("wireless", set, POWER_SUPPLY_PROP_AUTHENTIC, value); | |
2832 | } else { | |
2833 | pr_err("%s: TX ID isr is already done\n", __func__); | |
2834 | } | |
2835 | } else if (cmd_data == WPC_TX_COM_CHG_ERR) { | |
2836 | switch (val_data) { | |
2837 | case TX_CHG_ERR_OTP: | |
2838 | case TX_CHG_ERR_OCP: | |
2839 | case TX_CHG_ERR_DARKZONE: | |
2840 | pr_info("%s: Received CHG error from the TX(0x%x)\n", | |
2841 | __func__, val_data); | |
2842 | break; | |
2843 | case TX_CHG_ERR_FOD: | |
2844 | pr_info("%s: Received FOD state from the TX(0x%x)\n", | |
2845 | __func__, val_data); | |
2846 | value.intval = val_data; | |
2847 | psy_do_property("wireless", set, POWER_SUPPLY_EXT_PROP_WIRELESS_TX_CHG_ERR, value); | |
2848 | break; | |
2849 | default: | |
2850 | pr_info("%s: Undefined Type(0x%x)\n", __func__, val_data); | |
2851 | break; | |
2852 | } | |
2853 | } else if (cmd_data == WPC_TX_COM_WPS) { | |
2854 | switch (val_data) { | |
2855 | case WPS_AICL_RESET: | |
2856 | value.intval = 1; | |
2857 | pr_info("@Tx_mode %s Rx devic AICL Reset\n", __func__); | |
2858 | psy_do_property("wireless", set, POWER_SUPPLY_PROP_CURRENT_MAX, value); | |
2859 | break; | |
2860 | default: | |
2861 | pr_info("%s : Undefined RX Power(0x%x)\n", __func__, val_data); | |
2862 | break; | |
2863 | } | |
2864 | } | |
2865 | } | |
2866 | wake_unlock(&charger->wpc_wake_lock); | |
2867 | } | |
2868 | ||
2869 | static void mfc_wpc_tx_id_work(struct work_struct *work) | |
2870 | { | |
2871 | struct mfc_charger_data *charger = | |
2872 | container_of(work, struct mfc_charger_data, wpc_tx_id_work.work); | |
2873 | ||
2874 | pr_info("%s\n",__func__); | |
5a068558 | 2875 | |
1cac41cb | 2876 | mfc_send_command(charger, MFC_REQUEST_TX_ID); |
5a068558 MB |
2877 | charger->tx_id_cnt++; |
2878 | ||
2879 | if ((charger->tx_id_cnt <= 10) && !charger->tx_id) { | |
2880 | pr_info("%s: request TX ID (%d)\n", __func__, charger->tx_id_cnt); | |
2881 | queue_delayed_work(charger->wqueue, &charger->wpc_tx_id_work, msecs_to_jiffies(1500)); | |
2882 | return; | |
2883 | } else { | |
2884 | if (charger->tx_id) | |
2885 | pr_info("%s: TX ID (0x%x)\n", __func__, charger->tx_id); | |
2886 | else | |
2887 | pr_info("%s: TX ID not Received\n", __func__); | |
2888 | charger->tx_id_cnt = 0; | |
2889 | } | |
2890 | wake_unlock(&charger->wpc_tx_id_lock); | |
1cac41cb MB |
2891 | } |
2892 | ||
2893 | /* | |
2894 | * Prevent the un-wanted INT_A Falling handling. | |
2895 | * This is a work-around, and will be fixed by the revision. | |
2896 | */ | |
2897 | static void mfc_mst_off_work(struct work_struct *work) | |
2898 | { | |
2899 | struct mfc_charger_data *charger = | |
2900 | container_of(work, struct mfc_charger_data, mst_off_work.work); | |
2901 | pr_info("%s\n",__func__); | |
2902 | ||
2903 | charger->mst_off_lock = 1; | |
2904 | msleep(25); | |
2905 | charger->mst_off_lock = 0; | |
2906 | } | |
2907 | ||
2908 | static irqreturn_t mfc_wpc_det_irq_thread(int irq, void *irq_data) | |
2909 | { | |
2910 | struct mfc_charger_data *charger = irq_data; | |
2911 | ||
2912 | pr_info("%s !\n",__func__); | |
2913 | ||
2914 | if (charger->is_probed) | |
2915 | queue_delayed_work(charger->wqueue, &charger->wpc_det_work, 0); | |
2916 | else | |
2917 | pr_info("%s: prevent work thread before device is probed.\n", __func__); | |
2918 | ||
2919 | return IRQ_HANDLED; | |
2920 | } | |
2921 | ||
2922 | /* mfc_mst_routine : MST dedicated codes */ | |
2923 | void mfc_mst_routine(struct mfc_charger_data *charger, u8 *irq_src) | |
2924 | { | |
2925 | if(charger->is_mst_on == MST_MODE_2) { | |
2926 | /* clear intterupt */ | |
2927 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_L_REG, irq_src[0]); // clear int | |
2928 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_H_REG, irq_src[1]); // clear int | |
2929 | mfc_set_cmd_l_reg(charger, 0x20, MFC_CMD_CLEAR_INT_MASK); // command | |
2930 | ||
2931 | mfc_reg_write(charger->client, MFC_MST_MODE_SEL_REG, 0x02); /* set MST mode2 */ | |
2932 | pr_info("%s 2AC Missing ! : MST on REV : %d\n", __func__, charger->pdata->wc_ic_rev); | |
2933 | ||
2934 | /* clear intterupt */ | |
2935 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_L_REG, irq_src[0]); // clear int | |
2936 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_H_REG, irq_src[1]); // clear int | |
2937 | mfc_set_cmd_l_reg(charger, 0x20, MFC_CMD_CLEAR_INT_MASK); // command | |
2938 | ||
2939 | mdelay(10); | |
2940 | } | |
2941 | } | |
2942 | ||
2943 | static irqreturn_t mfc_wpc_irq_thread(int irq, void *irq_data) | |
2944 | { | |
2945 | struct mfc_charger_data *charger = irq_data; | |
2946 | int wc_w_state_irq; | |
2947 | int ret; | |
2948 | u8 irq_src[2]; | |
2949 | u8 reg_data; | |
2950 | // u8 cnt = 0; | |
2951 | ||
2952 | if ((charger->chip_id == MFC_CHIP_LSI) && (charger->mst_off_lock == 1)) { | |
2953 | pr_info("%s MST Off Lock!\n",__func__); | |
2954 | return IRQ_NONE; | |
2955 | } | |
2956 | ||
2957 | pr_info("%s !\n",__func__); | |
2958 | wake_lock(&charger->wpc_wake_lock); | |
2959 | ||
2960 | ret = mfc_reg_read(charger->client, MFC_INT_A_L_REG, &irq_src[0]); | |
2961 | ret = mfc_reg_read(charger->client, MFC_INT_A_H_REG, &irq_src[1]); | |
2962 | ||
2963 | wc_w_state_irq = gpio_get_value(charger->pdata->wpc_int); | |
2964 | pr_info("%s wc_w_state_irq = %d\n", __func__, wc_w_state_irq); | |
2965 | ||
2966 | if (ret < 0) { | |
2967 | pr_err("%s: Failed to read interrupt source: %d\n", | |
2968 | __func__, ret); | |
2969 | wake_unlock(&charger->wpc_wake_lock); | |
2970 | //return IRQ_NONE; | |
2971 | goto INT_ERROR; | |
2972 | } | |
2973 | ||
2974 | if(irq_src[1] & MFC_STAT_H_AC_MISSING_DET_MASK) { | |
2975 | pr_info("%s 1AC Missing ! : MST on REV : %d\n", __func__, charger->pdata->wc_ic_rev); | |
2976 | mfc_mst_routine(charger, irq_src); | |
2977 | } | |
2978 | ||
2979 | pr_info("%s: interrupt source(0x%x)\n", __func__, irq_src[1] << 8 | irq_src[0]); | |
2980 | mfc_get_firmware_version(charger, MFC_RX_FIRMWARE); | |
2981 | ||
2982 | if(irq_src[0] & MFC_STAT_L_OP_MODE_MASK) { | |
2983 | ret = mfc_reg_read(charger->client, MFC_SYS_OP_MODE_REG, ®_data); | |
2984 | reg_data &= 0x0C; /* use only [3:2]bit of sys_op_mode register for MST */ | |
2985 | pr_info("%s MODE CHANGE IRQ ! (0x%x)\n", __func__, reg_data); | |
2986 | } | |
2987 | ||
2988 | if ((irq_src[0] & MFC_STAT_L_OVER_VOL_MASK) || | |
2989 | (irq_src[0] & MFC_STAT_L_OVER_CURR_MASK) || | |
2990 | (irq_src[0] & MFC_STAT_L_OVER_TEMP_MASK)) { | |
2991 | pr_info("%s ABNORMAL STAT IRQ ! \n", __func__); | |
2992 | //ret = mfc_reg_read(charger->client, MFC_SYS_OP_MODE_REG, ®_data); | |
2993 | } | |
2994 | ||
2995 | if(irq_src[0] & MFC_STAT_L_INT_LPM_MASK) { | |
2996 | pr_info("%s INT LPM IRQ ! \n", __func__); | |
2997 | } | |
2998 | ||
2999 | if(irq_src[0] & MFC_STAT_L_BT2AP_DATA_MASK) { | |
3000 | pr_info("%s BT2AP DATA IRQ ! \n", __func__); | |
3001 | if(!delayed_work_pending(&charger->wpc_isr_work)) | |
3002 | queue_delayed_work(charger->wqueue, &charger->wpc_isr_work, msecs_to_jiffies(1000)); | |
3003 | } | |
3004 | ||
3005 | ||
3006 | if(irq_src[1] & MFC_STAT_H_TX_DATA_RECEIVED_MASK) { | |
3007 | pr_info("%s TX RECEIVED IRQ ! \n", __func__); | |
3008 | if(charger->pdata->cable_type == MFC_PAD_WPC_STAND|| | |
3009 | charger->pdata->cable_type == MFC_PAD_WPC_STAND_HV) | |
3010 | pr_info("%s Don't run ISR_WORK for NO ACK ! \n", __func__); | |
3011 | else if(!delayed_work_pending(&charger->wpc_isr_work)) | |
3012 | queue_delayed_work(charger->wqueue, &charger->wpc_isr_work, msecs_to_jiffies(500)); | |
3013 | } | |
3014 | ||
3015 | ||
3016 | if(irq_src[1] & MFC_STAT_H_TX_OVER_CURR_MASK) { | |
3017 | pr_info("%s TX OVER CURRENT IRQ ! \n", __func__); | |
3018 | } | |
3019 | ||
3020 | if(irq_src[1] & MFC_STAT_H_TX_OVER_TEMP_MASK) { | |
3021 | pr_info("%s TX OVER TEMP IRQ ! \n", __func__); | |
3022 | } | |
3023 | ||
3024 | if(irq_src[1] & MFC_STAT_H_TX_CON_DISCON_MASK) { | |
3025 | pr_info("%s TX CONNECT IRQ ! \n", __func__); | |
3026 | charger->pdata->tx_status = SEC_TX_POWER_TRANSFER; | |
3027 | } | |
3028 | ||
3029 | /* clear intterupt */ | |
3030 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_L_REG, irq_src[0]); // clear int | |
3031 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_H_REG, irq_src[1]); // clear int | |
3032 | mfc_set_cmd_l_reg(charger, 0x20, MFC_CMD_CLEAR_INT_MASK); // command | |
3033 | ||
3034 | /* debug */ | |
3035 | ret = mfc_reg_read(charger->client, MFC_INT_A_L_REG, &irq_src[0]); | |
3036 | ret = mfc_reg_read(charger->client, MFC_INT_A_H_REG, &irq_src[1]); | |
3037 | wc_w_state_irq = gpio_get_value(charger->pdata->wpc_int); | |
3038 | pr_info("%s wc_w_state_irq = %d\n", __func__, wc_w_state_irq); | |
3039 | wake_unlock(&charger->wpc_wake_lock); | |
3040 | ||
3041 | return IRQ_HANDLED; | |
3042 | ||
3043 | INT_ERROR: | |
3044 | /* clear intterupt */ | |
3045 | pr_info("%s interrup error!\n", __func__); | |
3046 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_L_REG, irq_src[0]); // clear int | |
3047 | mfc_reg_write(charger->client, MFC_INT_A_CLEAR_H_REG, irq_src[1]); // clear int | |
3048 | mfc_set_cmd_l_reg(charger, 0x20, MFC_CMD_CLEAR_INT_MASK); // command | |
3049 | wake_unlock(&charger->wpc_wake_lock); | |
3050 | ||
3051 | return IRQ_NONE; | |
3052 | } | |
3053 | ||
3054 | ||
3055 | static int mfc_chg_parse_dt(struct device *dev, | |
3056 | mfc_charger_platform_data_t *pdata) | |
3057 | { | |
3058 | int ret = 0; | |
3059 | struct device_node *np = dev->of_node; | |
3060 | enum of_gpio_flags irq_gpio_flags; | |
3061 | int len,i; | |
3062 | const u32 *p; | |
3063 | ||
3064 | if (!np) { | |
3065 | pr_err("%s np NULL\n", __func__); | |
3066 | return 1; | |
3067 | } else { | |
3068 | p = of_get_property(np, "battery,fod_wpc_data", &len); | |
3069 | if (p) { | |
3070 | len = len / sizeof(u32); | |
3071 | pdata->fod_wpc_data = kzalloc(sizeof(*pdata->fod_wpc_data) * len, GFP_KERNEL); | |
3072 | ret = of_property_read_u32_array(np, "battery,fod_wpc_data", | |
3073 | pdata->fod_wpc_data, len); | |
3074 | pdata->fod_data_check = 1; | |
3075 | ||
3076 | for(i = 0; i <len; i++) | |
3077 | pr_info("%s fod WPC data = %d ",__func__,pdata->fod_wpc_data[i]); | |
3078 | } else { | |
3079 | pdata->fod_data_check = 0; | |
3080 | pr_err("%s there is not fod_wpc_data\n", __func__); | |
3081 | } | |
3082 | ||
3083 | p = of_get_property(np, "battery,fod_pma_data", &len); | |
3084 | if (p) { | |
3085 | len = len / sizeof(u32); | |
3086 | pdata->fod_pma_data = kzalloc(sizeof(*pdata->fod_pma_data) * len, GFP_KERNEL); | |
3087 | ret = of_property_read_u32_array(np, "battery,fod_pma_data", | |
3088 | pdata->fod_pma_data, len); | |
3089 | pdata->fod_data_check = 1; | |
3090 | ||
3091 | for(i = 0; i <len; i++) | |
3092 | pr_info("%s fod PMA data = %d ",__func__,pdata->fod_pma_data[i]); | |
3093 | } else { | |
3094 | pdata->fod_data_check = 0; | |
3095 | pr_err("%s there is not fod_pma_data\n", __func__); | |
3096 | } | |
3097 | ||
3098 | p = of_get_property(np, "battery,fod_a4wp_data", &len); | |
3099 | if (p) { | |
3100 | len = len / sizeof(u32); | |
3101 | pdata->fod_a4wp_data = kzalloc(sizeof(*pdata->fod_a4wp_data) * len, GFP_KERNEL); | |
3102 | ret = of_property_read_u32_array(np, "battery,fod_a4wp_data", | |
3103 | pdata->fod_a4wp_data, len); | |
3104 | pdata->fod_data_check = 1; | |
3105 | ||
3106 | for(i = 0; i <len; i++) | |
3107 | pr_info("%s fod A4WP data = %d ",__func__,pdata->fod_a4wp_data[i]); | |
3108 | } else { | |
3109 | pdata->fod_data_check = 0; | |
3110 | pr_err("%s there is not fod_a4wp_data\n", __func__); | |
3111 | } | |
3112 | ||
3113 | p = of_get_property(np, "battery,fod_wpc_data_cv", &len); | |
3114 | if (p) { | |
3115 | len = len / sizeof(u32); | |
3116 | pdata->fod_wpc_data_cv = kzalloc(sizeof(*pdata->fod_wpc_data_cv) * len, GFP_KERNEL); | |
3117 | ret = of_property_read_u32_array(np, "battery,fod_wpc_data_cv", | |
3118 | pdata->fod_wpc_data_cv, len); | |
3119 | pdata->fod_data_check = 1; | |
3120 | ||
3121 | for(i = 0; i <len; i++) | |
3122 | pr_info("%s fod WPC data_cv = %d ",__func__,pdata->fod_wpc_data_cv[i]); | |
3123 | } else { | |
3124 | pdata->fod_data_check = 0; | |
3125 | pr_err("%s there is not fod_wpc_data_cv\n", __func__); | |
3126 | } | |
3127 | ||
3128 | p = of_get_property(np, "battery,fod_pma_data_cv", &len); | |
3129 | if (p) { | |
3130 | len = len / sizeof(u32); | |
3131 | pdata->fod_pma_data_cv = kzalloc(sizeof(*pdata->fod_pma_data_cv) * len, GFP_KERNEL); | |
3132 | ret = of_property_read_u32_array(np, "battery,fod_pma_data_cv", | |
3133 | pdata->fod_pma_data_cv, len); | |
3134 | pdata->fod_data_check = 1; | |
3135 | ||
3136 | for(i = 0; i <len; i++) | |
3137 | pr_info("%s fod PMA data_cv = %d ",__func__,pdata->fod_pma_data_cv[i]); | |
3138 | } else { | |
3139 | pdata->fod_data_check = 0; | |
3140 | pr_err("%s there is not fod_pma_data_cv\n", __func__); | |
3141 | } | |
3142 | ||
3143 | p = of_get_property(np, "battery,fod_a4wp_data_cv", &len); | |
3144 | if (p) { | |
3145 | len = len / sizeof(u32); | |
3146 | pdata->fod_a4wp_data_cv = kzalloc(sizeof(*pdata->fod_a4wp_data_cv) * len, GFP_KERNEL); | |
3147 | ret = of_property_read_u32_array(np, "battery,fod_a4wp_data_cv", | |
3148 | pdata->fod_a4wp_data_cv, len); | |
3149 | pdata->fod_data_check = 1; | |
3150 | ||
3151 | for(i = 0; i <len; i++) | |
3152 | pr_info("%s fod A4WP data_cv = %d ",__func__,pdata->fod_a4wp_data_cv[i]); | |
3153 | } else { | |
3154 | pdata->fod_data_check = 0; | |
3155 | pr_err("%s there is not fod_a4wp_data_cv\n", __func__); | |
3156 | } | |
3157 | ||
3158 | p = of_get_property(np, "battery,fod_hero_5v_data", &len); | |
3159 | if (p) { | |
3160 | len = len / sizeof(u32); | |
3161 | pdata->fod_hero_5v_data = kzalloc(sizeof(*pdata->fod_hero_5v_data) * len, GFP_KERNEL); | |
3162 | ret = of_property_read_u32_array(np, "battery,fod_hero_5v_data", | |
3163 | pdata->fod_hero_5v_data, len); | |
3164 | ||
3165 | for(i = 0; i <len; i++) | |
3166 | pr_info("%s fod Hero 5V data = 0x%x ",__func__,pdata->fod_hero_5v_data[i]); | |
3167 | } else { | |
3168 | pr_err("%s there is not fod_hero_5v_data\n", __func__); | |
3169 | } | |
3170 | ||
3171 | ret = of_property_read_string(np, | |
3172 | "battery,wireless_charger_name", (char const **)&pdata->wireless_charger_name); | |
3173 | if (ret < 0) | |
3174 | pr_info("%s: Wireless Charger name is Empty\n", __func__); | |
3175 | ||
3176 | ret = of_property_read_string(np, | |
3177 | "battery,charger_name", (char const **)&pdata->wired_charger_name); | |
3178 | if (ret < 0) | |
3179 | pr_info("%s: Charger name is Empty\n", __func__); | |
3180 | ||
3181 | ret = of_property_read_string(np, | |
3182 | "battery,fuelgauge_name", (char const **)&pdata->fuelgauge_name); | |
3183 | if (ret < 0) | |
3184 | pr_info("%s: Fuelgauge name is Empty\n", __func__); | |
3185 | ||
3186 | ret = of_property_read_u32(np, "battery,wpc_cc_cv_vout", | |
3187 | &pdata->wpc_cc_cv_vout); | |
3188 | if (ret < 0) | |
3189 | pr_info("%s: wpc_cv_call_vout is Empty \n", __func__); | |
3190 | ||
3191 | ret = of_property_read_u32(np, "battery,wpc_cv_call_vout", | |
3192 | &pdata->wpc_cv_call_vout); | |
3193 | if (ret < 0) | |
3194 | pr_info("%s: wpc_cv_call_vout is Empty \n", __func__); | |
3195 | ||
3196 | ret = of_property_read_u32(np, "battery,wpc_cc_call_vout", | |
3197 | &pdata->wpc_cc_call_vout); | |
3198 | if (ret < 0) | |
3199 | pr_info("%s: wpc_cc_call_vout is Empty \n", __func__); | |
3200 | ||
3201 | ret = of_property_read_u32(np, "battery,hv_vout_wa", | |
3202 | &pdata->hv_vout_wa); | |
3203 | if (ret < 0) { | |
3204 | pr_info("%s: no need hv_vout_wa. \n", __func__); | |
3205 | pdata->hv_vout_wa = 0; | |
3206 | } | |
3207 | ||
3208 | ret = of_property_read_u32(np, "battery,mst_switch_delay", | |
3209 | &pdata->mst_switch_delay); | |
3210 | if (ret < 0) { | |
3211 | pr_info("%s: mst_switch_delay is Empty \n", __func__); | |
3212 | pdata->mst_switch_delay = 1000; /* set default value (dream) */ | |
3213 | } | |
3214 | ||
3215 | ret = of_property_read_u32(np, "battery,wc_cover_rpp", | |
3216 | &pdata->wc_cover_rpp); | |
3217 | if (ret < 0) { | |
3218 | pr_info("%s: fail to read wc_cover_rpp. \n", __func__); | |
3219 | pdata->wc_cover_rpp = 0x55; | |
3220 | } | |
3221 | ||
3222 | ret = of_property_read_u32(np, "battery,wc_hv_rpp", | |
3223 | &pdata->wc_hv_rpp); | |
3224 | if (ret < 0) { | |
3225 | pr_info("%s: fail to read wc_hv_rpp. \n", __func__); | |
3226 | pdata->wc_hv_rpp = 0x40; | |
3227 | } | |
3228 | ||
3229 | /* wpc_det */ | |
3230 | ret = pdata->wpc_det = of_get_named_gpio_flags(np, "battery,wpc_det", | |
3231 | 0, &irq_gpio_flags); | |
3232 | if (ret < 0) { | |
3233 | dev_err(dev, "%s : can't get wpc_det\r\n", __FUNCTION__); | |
3234 | } else { | |
3235 | pdata->irq_wpc_det = gpio_to_irq(pdata->wpc_det); | |
3236 | pr_info("%s wpc_det = 0x%x, irq_wpc_det = 0x%x \n",__func__, pdata->wpc_det, pdata->irq_wpc_det); | |
3237 | } | |
3238 | /* wpc_int (This GPIO means MFC_AP_INT) */ | |
3239 | ret = pdata->wpc_int = of_get_named_gpio_flags(np, "battery,wpc_int", | |
3240 | 0, &irq_gpio_flags); | |
3241 | if (ret < 0) { | |
3242 | dev_err(dev, "%s : can't wpc_int\r\n", __FUNCTION__); | |
3243 | } else { | |
3244 | pdata->irq_wpc_int = gpio_to_irq(pdata->wpc_int); | |
3245 | pr_info("%s wpc_int = 0x%x, irq_wpc_int = 0x%x \n",__func__, pdata->wpc_int, pdata->irq_wpc_int); | |
3246 | } | |
3247 | ||
3248 | /* mst_pwr_en (MST PWR EN) */ | |
3249 | ret = pdata->mst_pwr_en = of_get_named_gpio_flags(np, "battery,mst_pwr_en", | |
3250 | 0, &irq_gpio_flags); | |
3251 | if (ret < 0) { | |
3252 | dev_err(dev, "%s : can't mst_pwr_en\r\n", __FUNCTION__); | |
3253 | } | |
3254 | ||
3255 | /* wpc_en (MFC EN) */ | |
3256 | ret = pdata->wpc_en = of_get_named_gpio_flags(np, "battery,wpc_en", | |
3257 | 0, &irq_gpio_flags); | |
3258 | if (ret < 0) { | |
3259 | dev_err(dev, "%s : can't wpc_en\r\n", __FUNCTION__); | |
3260 | } | |
3261 | ||
3262 | return 0; | |
3263 | } | |
3264 | } | |
3265 | ||
3266 | static ssize_t mfc_store_addr(struct device *dev, | |
3267 | struct device_attribute *attr, | |
3268 | const char *buf, size_t count) | |
3269 | { | |
3270 | struct power_supply *psy = dev_get_drvdata(dev); | |
3271 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3272 | int x; | |
3273 | ||
3274 | if (sscanf(buf, "0x%4x\n", &x) == 1) { | |
3275 | charger->addr = x; | |
3276 | } | |
3277 | return count; | |
3278 | } | |
3279 | ||
3280 | static ssize_t mfc_show_addr(struct device *dev, | |
3281 | struct device_attribute *attr, | |
3282 | char *buf) | |
3283 | { | |
3284 | struct power_supply *psy = dev_get_drvdata(dev); | |
3285 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3286 | ||
3287 | return sprintf(buf, "0x%x\n", charger->addr); | |
3288 | } | |
3289 | ||
3290 | static ssize_t mfc_store_size(struct device *dev, | |
3291 | struct device_attribute *attr, | |
3292 | const char *buf, size_t count) | |
3293 | { | |
3294 | struct power_supply *psy = dev_get_drvdata(dev); | |
3295 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3296 | int x; | |
3297 | ||
3298 | if (sscanf(buf, "%5d\n", &x) == 1) { | |
3299 | charger->size = x; | |
3300 | } | |
3301 | return count; | |
3302 | } | |
3303 | ||
3304 | static ssize_t mfc_show_size(struct device *dev, | |
3305 | struct device_attribute *attr, | |
3306 | char *buf) | |
3307 | { | |
3308 | struct power_supply *psy = dev_get_drvdata(dev); | |
3309 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3310 | ||
3311 | return sprintf(buf, "0x%x\n", charger->size); | |
3312 | } | |
3313 | static ssize_t mfc_store_data(struct device *dev, | |
3314 | struct device_attribute *attr, | |
3315 | const char *buf, size_t count) | |
3316 | { | |
3317 | struct power_supply *psy = dev_get_drvdata(dev); | |
3318 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3319 | int x; | |
3320 | ||
3321 | if (sscanf(buf, "0x%10x", &x) == 1) { | |
3322 | u8 data = x; | |
3323 | ||
3324 | if (mfc_reg_write(charger->client, charger->addr, data) < 0) { | |
3325 | dev_info(charger->dev, | |
3326 | "%s: addr: 0x%x write fail\n", __func__, charger->addr); | |
3327 | } | |
3328 | } | |
3329 | return count; | |
3330 | } | |
3331 | ||
3332 | static ssize_t mfc_show_data(struct device *dev, | |
3333 | struct device_attribute *attr, | |
3334 | char *buf) | |
3335 | { | |
3336 | struct power_supply *psy = dev_get_drvdata(dev); | |
3337 | struct mfc_charger_data *charger = power_supply_get_drvdata(psy); | |
3338 | int count = 0;; | |
3339 | ||
3340 | if (charger->size == 0) { | |
3341 | charger->size = 1; | |
3342 | } else if (charger->size + charger->addr <= 0xFFFF) { | |
3343 | u8 data; | |
3344 | int i; | |
3345 | ||
3346 | for (i = 0; i < charger->size; i++) { | |
3347 | if (mfc_reg_read(charger->client, charger->addr + i, &data) < 0) { | |
3348 | dev_info(charger->dev, | |
3349 | "%s: read fail\n", __func__); | |
3350 | count += sprintf(buf + count, "addr: 0x%x read fail\n", charger->addr + i); | |
3351 | continue; | |
3352 | } | |
3353 | count += sprintf(buf + count, "addr: 0x%x, data: 0x%x\n", charger->addr + i, data); | |
3354 | } | |
3355 | } | |
3356 | ||
3357 | return count; | |
3358 | } | |
3359 | ||
3360 | static DEVICE_ATTR(addr, 0644, mfc_show_addr, mfc_store_addr); | |
3361 | static DEVICE_ATTR(size, 0644, mfc_show_size, mfc_store_size); | |
3362 | static DEVICE_ATTR(data, 0644, mfc_show_data, mfc_store_data); | |
3363 | ||
3364 | static struct attribute *mfc_attributes[] = { | |
3365 | &dev_attr_addr.attr, | |
3366 | &dev_attr_size.attr, | |
3367 | &dev_attr_data.attr, | |
3368 | NULL | |
3369 | }; | |
3370 | ||
3371 | static const struct attribute_group mfc_attr_group = { | |
3372 | .attrs = mfc_attributes, | |
3373 | }; | |
3374 | ||
3375 | static const struct power_supply_desc mfc_charger_power_supply_desc = { | |
3376 | .name = "mfc-charger", | |
3377 | .type = POWER_SUPPLY_TYPE_UNKNOWN, | |
3378 | .properties = mfc_charger_props, | |
3379 | .num_properties = ARRAY_SIZE(mfc_charger_props), | |
3380 | .get_property = mfc_chg_get_property, | |
3381 | .set_property = mfc_chg_set_property, | |
3382 | }; | |
3383 | ||
3384 | static void mfc_wpc_int_req_work(struct work_struct *work) | |
3385 | { | |
3386 | struct mfc_charger_data *charger = | |
3387 | container_of(work, struct mfc_charger_data, wpc_int_req_work.work); | |
3388 | ||
3389 | int ret = 0; | |
3390 | ||
3391 | pr_info("%s\n", __func__); | |
3392 | /* wpc_irq */ | |
3393 | if (charger->pdata->irq_wpc_int) { | |
3394 | msleep(100); | |
3395 | ret = request_threaded_irq(charger->pdata->irq_wpc_int, | |
3396 | NULL, mfc_wpc_irq_thread, | |
3397 | IRQF_TRIGGER_FALLING | | |
3398 | IRQF_ONESHOT, | |
3399 | "wpc-irq", charger); | |
3400 | if (ret) { | |
3401 | pr_err("%s: Failed to Reqeust IRQ\n", __func__); | |
3402 | } | |
3403 | } | |
3404 | if (ret < 0) | |
3405 | free_irq(charger->pdata->irq_wpc_det, NULL); | |
3406 | } | |
3407 | ||
3408 | static int mfc_charger_probe( | |
3409 | struct i2c_client *client, | |
3410 | const struct i2c_device_id *id) | |
3411 | { | |
3412 | struct device_node *of_node = client->dev.of_node; | |
3413 | struct mfc_charger_data *charger; | |
3414 | mfc_charger_platform_data_t *pdata = client->dev.platform_data; | |
3415 | struct power_supply_config mfc_cfg = {}; | |
3416 | int ret = 0; | |
3417 | int wc_w_state_irq; | |
3418 | ||
3419 | dev_info(&client->dev, | |
3420 | "%s: MFC Charger Driver Loading\n", __func__); | |
3421 | ||
3422 | if (of_node) { | |
3423 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); | |
3424 | if (!pdata) { | |
3425 | dev_err(&client->dev, "Failed to allocate memory\n"); | |
3426 | return -ENOMEM; | |
3427 | } | |
3428 | ret = mfc_chg_parse_dt(&client->dev, pdata); | |
3429 | if (ret < 0) | |
3430 | goto err_parse_dt; | |
3431 | } else { | |
3432 | pdata = client->dev.platform_data; | |
3433 | if (!pdata) { | |
3434 | dev_err(&client->dev, "Failed to get platform data\n"); | |
3435 | return -ENOMEM; | |
3436 | } | |
3437 | } | |
3438 | ||
3439 | charger = kzalloc(sizeof(*charger), GFP_KERNEL); | |
3440 | if (charger == NULL) { | |
3441 | dev_err(&client->dev, "Memory is not enough.\n"); | |
3442 | ret = -ENOMEM; | |
3443 | goto err_wpc_nomem; | |
3444 | } | |
3445 | charger->dev = &client->dev; | |
3446 | ||
3447 | ret = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | | |
3448 | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); | |
3449 | if (!ret) { | |
3450 | ret = i2c_get_functionality(client->adapter); | |
3451 | dev_err(charger->dev, "I2C functionality is not supported.\n"); | |
3452 | ret = -ENOSYS; | |
3453 | goto err_i2cfunc_not_support; | |
3454 | } | |
3455 | ||
3456 | charger->client = client; | |
3457 | charger->pdata = pdata; | |
3458 | ||
3459 | pr_info("%s: %s\n", __func__, charger->pdata->wireless_charger_name ); | |
3460 | ||
3461 | i2c_set_clientdata(client, charger); | |
3462 | ||
3463 | charger->pdata->cable_type = MFC_PAD_NONE; | |
3464 | charger->pdata->is_charging = 0; | |
3465 | charger->pdata->tx_status = 0; | |
3466 | charger->pdata->cs100_status = 0; | |
3467 | charger->pdata->capacity = 101; | |
3468 | charger->pdata->vout_status = MFC_VOUT_5V; | |
3469 | charger->pdata->opfq_cnt = 0; | |
3470 | ||
3471 | charger->is_mst_on = MST_MODE_0; | |
3472 | charger->chip_id = MFC_CHIP_IDT; | |
3473 | charger->is_otg_on = false; | |
3474 | charger->led_cover = 0; | |
3475 | charger->vout_mode = MFC_VOUT_5V; | |
3476 | charger->is_full_status = 0; | |
3477 | charger->is_afc_tx = false; | |
3478 | charger->tx_id_done = false; | |
3479 | charger->device_event = 0; | |
3480 | ||
3481 | mutex_init(&charger->io_lock); | |
3482 | ||
3483 | /* wpc_det */ | |
3484 | if (charger->pdata->irq_wpc_det) { | |
3485 | INIT_DELAYED_WORK(&charger->wpc_det_work, mfc_wpc_det_work); | |
3486 | INIT_DELAYED_WORK(&charger->wpc_opfq_work, mfc_wpc_opfq_work); | |
3487 | } | |
3488 | ||
3489 | /* wpc_irq (INT_A) */ | |
3490 | if (charger->pdata->irq_wpc_int) { | |
3491 | INIT_DELAYED_WORK(&charger->wpc_isr_work, mfc_wpc_isr_work); | |
3492 | INIT_DELAYED_WORK(&charger->wpc_tx_id_work, mfc_wpc_tx_id_work); | |
3493 | INIT_DELAYED_WORK(&charger->wpc_int_req_work, mfc_wpc_int_req_work); | |
3494 | } | |
3495 | INIT_DELAYED_WORK(&charger->wpc_vout_mode_work, mfc_wpc_vout_mode_work); | |
3496 | INIT_DELAYED_WORK(&charger->wpc_afc_vout_work, mfc_wpc_afc_vout_work); | |
3497 | INIT_DELAYED_WORK(&charger->wpc_fw_update_work, mfc_wpc_fw_update_work); | |
3498 | INIT_DELAYED_WORK(&charger->wpc_cm_fet_work, mfc_wpc_cm_fet_work); | |
3499 | INIT_DELAYED_WORK(&charger->wpc_i2c_error_work, mfc_wpc_i2c_error_work); | |
3500 | /*#if !defined(CONFIG_SEC_FACTORY) | |
3501 | INIT_DELAYED_WORK(&charger->wpc_fw_booting_work, mfc_wpc_fw_booting_work); | |
3502 | #endif*/ | |
3503 | ||
3504 | /* | |
3505 | * Default Idle voltage of the INT_A is LOW. | |
3506 | * Prevent the un-wanted INT_A Falling handling. | |
3507 | * This is a work-around, and will be fixed by the revision. | |
3508 | */ | |
3509 | INIT_DELAYED_WORK(&charger->mst_off_work, mfc_mst_off_work); | |
3510 | ||
3511 | mfc_cfg.drv_data = charger; | |
3512 | charger->psy_chg = power_supply_register(charger->dev, &mfc_charger_power_supply_desc, &mfc_cfg); | |
3513 | if ((void *)charger->psy_chg < 0) { | |
3514 | pr_err("%s: Failed to Register psy_chg\n", __func__); | |
3515 | goto err_supply_unreg; | |
3516 | } | |
3517 | ||
3518 | charger->wqueue = create_singlethread_workqueue("mfc_workqueue"); | |
3519 | if (!charger->wqueue) { | |
3520 | pr_err("%s: Fail to Create Workqueue\n", __func__); | |
3521 | goto err_pdata_free; | |
3522 | } | |
3523 | ||
3524 | wake_lock_init(&charger->wpc_wake_lock, WAKE_LOCK_SUSPEND, | |
3525 | "wpc_wakelock"); | |
3526 | wake_lock_init(&charger->wpc_update_lock, WAKE_LOCK_SUSPEND, | |
3527 | "wpc_update_lock"); | |
3528 | wake_lock_init(&charger->wpc_opfq_lock, WAKE_LOCK_SUSPEND, | |
3529 | "wpc_opfq_lock"); | |
3530 | wake_lock_init(&charger->wpc_afc_vout_lock, WAKE_LOCK_SUSPEND, | |
3531 | "wpc_afc_vout_lock"); | |
3532 | wake_lock_init(&charger->wpc_vout_mode_lock, WAKE_LOCK_SUSPEND, | |
3533 | "wpc_vout_mode_lock"); | |
5a068558 MB |
3534 | wake_lock_init(&charger->wpc_tx_id_lock, WAKE_LOCK_SUSPEND, |
3535 | "wpc_tx_id_lock"); | |
1cac41cb MB |
3536 | |
3537 | /* Enable interrupts after battery driver load */ | |
3538 | /* wpc_det */ | |
3539 | if (charger->pdata->irq_wpc_det) { | |
3540 | ret = request_threaded_irq(charger->pdata->irq_wpc_det, | |
3541 | NULL, mfc_wpc_det_irq_thread, | |
3542 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | |
3543 | IRQF_ONESHOT, | |
3544 | "wpd-det-irq", charger); | |
3545 | if (ret) { | |
3546 | pr_err("%s: Failed to Reqeust IRQ\n", __func__); | |
3547 | goto err_irq_wpc_det; | |
3548 | } | |
3549 | } | |
3550 | ||
3551 | /* wpc_irq */ | |
5a068558 | 3552 | queue_delayed_work(charger->wqueue, &charger->wpc_int_req_work, 0); |
1cac41cb MB |
3553 | |
3554 | wc_w_state_irq = gpio_get_value(charger->pdata->wpc_int); | |
3555 | pr_info("%s wc_w_state_irq = %d\n", __func__, wc_w_state_irq); | |
3556 | if (gpio_get_value(charger->pdata->wpc_det)) { | |
1cac41cb | 3557 | pr_info("%s: Charger interrupt occured during lpm \n", __func__); |
1cac41cb MB |
3558 | queue_delayed_work(charger->wqueue, &charger->wpc_det_work, 0); |
3559 | if(!wc_w_state_irq && !delayed_work_pending(&charger->wpc_isr_work)) | |
3560 | queue_delayed_work(charger->wqueue, &charger->wpc_isr_work, msecs_to_jiffies(2000)); | |
3561 | } | |
3562 | /*#if !defined(CONFIG_SEC_FACTORY) | |
3563 | else if (!lpcharge) { | |
3564 | pr_info("%s: call wpc_fw_booting_work for firmware update\n", __func__); | |
3565 | queue_delayed_work(charger->wqueue, &charger->wpc_fw_booting_work, 0); | |
3566 | } | |
3567 | #endif*/ | |
3568 | ||
3569 | ret = sysfs_create_group(&charger->psy_chg->dev.kobj, &mfc_attr_group); | |
3570 | if (ret) { | |
3571 | dev_info(&client->dev, | |
3572 | "%s: sysfs_create_group failed\n", __func__); | |
3573 | } | |
3574 | charger->is_probed = true; | |
3575 | dev_info(&client->dev, | |
3576 | "%s: MFC Charger Driver Loaded\n", __func__); | |
3577 | ||
3578 | device_init_wakeup(charger->dev, 1); | |
3579 | return 0; | |
3580 | ||
3581 | err_irq_wpc_det: | |
3582 | err_pdata_free: | |
3583 | power_supply_unregister(charger->psy_chg); | |
3584 | err_supply_unreg: | |
3585 | mutex_destroy(&charger->io_lock); | |
3586 | err_i2cfunc_not_support: | |
3587 | kfree(charger); | |
3588 | err_wpc_nomem: | |
3589 | err_parse_dt: | |
3590 | devm_kfree(&client->dev, pdata); | |
3591 | return ret; | |
3592 | } | |
3593 | ||
3594 | static int mfc_charger_remove(struct i2c_client *client) | |
3595 | { | |
3596 | return 0; | |
3597 | } | |
3598 | ||
3599 | #if defined(CONFIG_PM) | |
3600 | static int mfc_charger_suspend(struct device *dev) | |
3601 | { | |
3602 | struct mfc_charger_data *charger = dev_get_drvdata(dev); | |
3603 | ||
3604 | if (device_may_wakeup(charger->dev)){ | |
3605 | enable_irq_wake(charger->pdata->irq_wpc_int); | |
3606 | enable_irq_wake(charger->pdata->irq_wpc_det); | |
3607 | } | |
3608 | disable_irq(charger->pdata->irq_wpc_int); | |
3609 | disable_irq(charger->pdata->irq_wpc_det); | |
3610 | ||
3611 | return 0; | |
3612 | } | |
3613 | ||
3614 | static int mfc_charger_resume(struct device *dev) | |
3615 | { | |
3616 | struct mfc_charger_data *charger = dev_get_drvdata(dev); | |
3617 | ||
3618 | pr_info("%s \n", __func__); | |
3619 | ||
3620 | if (device_may_wakeup(charger->dev)) { | |
3621 | disable_irq_wake(charger->pdata->irq_wpc_int); | |
3622 | disable_irq_wake(charger->pdata->irq_wpc_det); | |
3623 | } | |
3624 | enable_irq(charger->pdata->irq_wpc_int); | |
3625 | enable_irq(charger->pdata->irq_wpc_det); | |
3626 | ||
3627 | return 0; | |
3628 | } | |
3629 | #else | |
3630 | #define mfc_charger_suspend NULL | |
3631 | #define mfc_charger_resume NULL | |
3632 | #endif | |
3633 | ||
3634 | static void mfc_charger_shutdown(struct i2c_client *client) | |
3635 | { | |
3636 | struct mfc_charger_data *charger = i2c_get_clientdata(client); | |
3637 | ||
3638 | pr_info("%s\n", __func__); | |
1cac41cb | 3639 | |
5a068558 MB |
3640 | if (gpio_get_value(charger->pdata->wpc_det)) { |
3641 | mfc_set_vrect_adjust(charger, MFC_HEADROOM_1); | |
3642 | mfc_set_vout(charger, MFC_VOUT_5V); | |
3643 | pr_info("%s: forced 5V Vout, wc_w_state_irq = %d\n", | |
3644 | __func__, gpio_get_value(charger->pdata->wpc_int)); | |
1cac41cb MB |
3645 | } |
3646 | } | |
3647 | ||
3648 | static const struct i2c_device_id mfc_charger_id_table[] = { | |
3649 | { "mfc-charger", 0 }, | |
3650 | { }, | |
3651 | }; | |
3652 | MODULE_DEVICE_TABLE(i2c, mfc_id_table); | |
3653 | ||
3654 | #ifdef CONFIG_OF | |
3655 | static struct of_device_id mfc_charger_match_table[] = { | |
3656 | { .compatible = "idt,mfc-charger",}, | |
3657 | {}, | |
3658 | }; | |
3659 | #else | |
3660 | #define mfc_charger_match_table NULL | |
3661 | #endif | |
3662 | ||
3663 | const struct dev_pm_ops mfc_pm = { | |
3664 | .suspend = mfc_charger_suspend, | |
3665 | .resume = mfc_charger_resume, | |
3666 | }; | |
3667 | ||
3668 | static struct i2c_driver mfc_charger_driver = { | |
3669 | .driver = { | |
3670 | .name = "mfc-charger", | |
3671 | .owner = THIS_MODULE, | |
3672 | #if defined(CONFIG_PM) | |
3673 | .pm = &mfc_pm, | |
3674 | #endif /* CONFIG_PM */ | |
3675 | .of_match_table = mfc_charger_match_table, | |
3676 | }, | |
3677 | .shutdown = mfc_charger_shutdown, | |
3678 | .probe = mfc_charger_probe, | |
3679 | .remove = mfc_charger_remove, | |
3680 | .id_table = mfc_charger_id_table, | |
3681 | }; | |
3682 | ||
3683 | static int __init mfc_charger_init(void) | |
3684 | { | |
3685 | pr_info("%s \n",__func__); | |
3686 | return i2c_add_driver(&mfc_charger_driver); | |
3687 | } | |
3688 | ||
3689 | static void __exit mfc_charger_exit(void) | |
3690 | { | |
3691 | pr_info("%s \n",__func__); | |
3692 | i2c_del_driver(&mfc_charger_driver); | |
3693 | } | |
3694 | ||
3695 | module_init(mfc_charger_init); | |
3696 | module_exit(mfc_charger_exit); | |
3697 | ||
3698 | MODULE_DESCRIPTION("Samsung MFC Charger Driver"); | |
3699 | MODULE_AUTHOR("Samsung Electronics"); | |
3700 | MODULE_LICENSE("GPL"); | |
3701 |