Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /***************************************************************************** |
2 | * | |
3 | * Filename: | |
4 | * --------- | |
5 | * charging_pmic.c | |
6 | * | |
7 | * Project: | |
8 | * -------- | |
9 | * ALPS_Software | |
10 | * | |
11 | * Description: | |
12 | * ------------ | |
13 | * This file implements the interface between BMT and ADC scheduler. | |
14 | * | |
15 | * Author: | |
16 | * ------- | |
17 | * Oscar Liu | |
18 | * | |
19 | *============================================================================ | |
20 | * $Revision: 1.0 $ | |
21 | * $Modtime: 11 Aug 2005 10:28:16 $ | |
22 | * $Log: //mtkvs01/vmdata/Maui_sw/archives/mcu/hal/peripheral/inc/bmt_chr_setting.h-arc $ | |
23 | * HISTORY | |
24 | * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!! | |
25 | *------------------------------------------------------------------------------ | |
26 | *------------------------------------------------------------------------------ | |
27 | * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!! | |
28 | *============================================================================ | |
29 | ****************************************************************************/ | |
30 | #include <mach/charging.h> | |
31 | #include <mach/upmu_common.h> | |
32 | #include <mach/upmu_hw.h> | |
33 | #include <linux/xlog.h> | |
34 | #include <linux/delay.h> | |
35 | #include <linux/mutex.h> | |
36 | #include <cust_charging.h> | |
37 | #include <mach/mt_gpio.h> | |
38 | #include <mach/mt_sleep.h> | |
39 | #include <mach/mt_boot.h> | |
40 | #include <mach/system.h> | |
41 | ||
42 | #include "cust_battery_meter.h" | |
43 | #include <cust_charging.h> | |
44 | #include <linux/wakelock.h> | |
45 | #include <mach/battery_common.h> | |
46 | ||
47 | #ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT | |
48 | #include <mach/diso.h> | |
49 | #include "cust_diso.h" | |
50 | #include <linux/of.h> | |
51 | #include <linux/of_irq.h> | |
52 | #ifdef MTK_DISCRETE_SWITCH | |
53 | #include <mach/eint.h> | |
54 | #include <cust_eint.h> | |
55 | #include <mach/mt_gpio.h> | |
56 | #include <cust_gpio_usage.h> | |
57 | #endif | |
58 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
59 | #include <linux/kthread.h> | |
60 | #include <linux/wakelock.h> | |
61 | #include <linux/mutex.h> | |
62 | #include <linux/hrtimer.h> | |
63 | #include <linux/workqueue.h> | |
64 | #endif | |
65 | #endif | |
66 | ||
67 | // ============================================================ // | |
68 | //define | |
69 | // ============================================================ // | |
70 | #define STATUS_OK 0 | |
71 | #define STATUS_UNSUPPORTED -1 | |
72 | #define GETARRAYNUM(array) (sizeof(array)/sizeof(array[0])) | |
73 | ||
74 | ||
75 | // ============================================================ // | |
76 | //global variable | |
77 | // ============================================================ // | |
78 | kal_bool chargin_hw_init_done = KAL_TRUE; | |
79 | kal_bool charging_type_det_done = KAL_TRUE; | |
80 | static CHARGER_TYPE g_charger_type = CHARGER_UNKNOWN; | |
81 | ||
82 | #if defined(CONFIG_MTK_WIRELESS_CHARGER_SUPPORT) | |
83 | #define WIRELESS_CHARGER_EXIST_STATE 0 | |
84 | int wireless_charger_gpio_number = (168 | 0x80000000); | |
85 | #endif | |
86 | ||
87 | const kal_uint32 VBAT_CV_VTH[]= | |
88 | { | |
89 | BATTERY_VOLT_04_200000_V, BATTERY_VOLT_04_212500_V, BATTERY_VOLT_04_225000_V, BATTERY_VOLT_04_237500_V, | |
90 | BATTERY_VOLT_04_250000_V, BATTERY_VOLT_04_262500_V, BATTERY_VOLT_04_275000_V, BATTERY_VOLT_04_300000_V, | |
91 | BATTERY_VOLT_04_325000_V, BATTERY_VOLT_04_350000_V, BATTERY_VOLT_04_375000_V, BATTERY_VOLT_04_400000_V, | |
92 | BATTERY_VOLT_04_425000_V, BATTERY_VOLT_04_162500_V, BATTERY_VOLT_04_175000_V, BATTERY_VOLT_02_200000_V, | |
93 | BATTERY_VOLT_04_050000_V, BATTERY_VOLT_04_100000_V, BATTERY_VOLT_04_125000_V, BATTERY_VOLT_03_775000_V, | |
94 | BATTERY_VOLT_03_800000_V, BATTERY_VOLT_03_850000_V, BATTERY_VOLT_03_900000_V, BATTERY_VOLT_04_000000_V, | |
95 | BATTERY_VOLT_04_050000_V, BATTERY_VOLT_04_100000_V, BATTERY_VOLT_04_125000_V, BATTERY_VOLT_04_137500_V, | |
96 | BATTERY_VOLT_04_150000_V, BATTERY_VOLT_04_162500_V, BATTERY_VOLT_04_175000_V, BATTERY_VOLT_04_187500_V | |
97 | ||
98 | }; | |
99 | ||
100 | const kal_uint32 CS_VTH[]= | |
101 | { | |
102 | CHARGE_CURRENT_1600_00_MA, CHARGE_CURRENT_1500_00_MA, CHARGE_CURRENT_1400_00_MA, CHARGE_CURRENT_1300_00_MA, | |
103 | CHARGE_CURRENT_1200_00_MA, CHARGE_CURRENT_1100_00_MA, CHARGE_CURRENT_1000_00_MA, CHARGE_CURRENT_900_00_MA, | |
104 | CHARGE_CURRENT_800_00_MA, CHARGE_CURRENT_700_00_MA, CHARGE_CURRENT_650_00_MA, CHARGE_CURRENT_550_00_MA, | |
105 | CHARGE_CURRENT_450_00_MA, CHARGE_CURRENT_300_00_MA, CHARGE_CURRENT_200_00_MA, CHARGE_CURRENT_70_00_MA | |
106 | }; | |
107 | ||
108 | ||
109 | const kal_uint32 VCDT_HV_VTH[]= | |
110 | { | |
111 | BATTERY_VOLT_04_200000_V, BATTERY_VOLT_04_250000_V, BATTERY_VOLT_04_300000_V, BATTERY_VOLT_04_350000_V, | |
112 | BATTERY_VOLT_04_400000_V, BATTERY_VOLT_04_450000_V, BATTERY_VOLT_04_500000_V, BATTERY_VOLT_04_550000_V, | |
113 | BATTERY_VOLT_04_600000_V, BATTERY_VOLT_06_000000_V, BATTERY_VOLT_06_500000_V, BATTERY_VOLT_07_000000_V, | |
114 | BATTERY_VOLT_07_500000_V, BATTERY_VOLT_08_500000_V, BATTERY_VOLT_09_500000_V, BATTERY_VOLT_10_500000_V | |
115 | }; | |
116 | ||
117 | ||
118 | #ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT | |
119 | #ifndef CUST_GPIO_VIN_SEL | |
120 | #define CUST_GPIO_VIN_SEL 18 | |
121 | #endif | |
122 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
123 | #define SW_POLLING_PERIOD 100 //100 ms | |
124 | #define MSEC_TO_NSEC(x) (x * 1000000UL) | |
125 | ||
126 | static DEFINE_MUTEX(diso_polling_mutex); | |
127 | static DECLARE_WAIT_QUEUE_HEAD(diso_polling_thread_wq); | |
128 | static struct hrtimer diso_kthread_timer; | |
129 | static kal_bool diso_thread_timeout = KAL_FALSE; | |
130 | static struct delayed_work diso_polling_work; | |
131 | static void diso_polling_handler(struct work_struct *work); | |
132 | static DISO_Polling_Data DISO_Polling; | |
133 | #else | |
134 | DISO_IRQ_Data DISO_IRQ; | |
135 | #endif | |
136 | int g_diso_state = 0; | |
137 | int vin_sel_gpio_number = (CUST_GPIO_VIN_SEL | 0x80000000); | |
138 | static kal_bool g_diso_otg = KAL_FALSE; | |
139 | ||
140 | static char *DISO_state_s[8] = { | |
141 | "IDLE", | |
142 | "OTG_ONLY", | |
143 | "USB_ONLY", | |
144 | "USB_WITH_OTG", | |
145 | "DC_ONLY", | |
146 | "DC_WITH_OTG", | |
147 | "DC_WITH_USB", | |
148 | "DC_USB_OTG", | |
149 | }; | |
150 | #endif | |
151 | ||
152 | // ============================================================ // | |
153 | // function prototype | |
154 | // ============================================================ // | |
155 | ||
156 | ||
157 | // ============================================================ // | |
158 | //extern variable | |
159 | // ============================================================ // | |
160 | ||
161 | // ============================================================ // | |
162 | //extern function | |
163 | // ============================================================ // | |
164 | extern kal_uint32 upmu_get_reg_value(kal_uint32 reg); | |
165 | extern bool mt_usb_is_device(void); | |
166 | extern void Charger_Detect_Init(void); | |
167 | extern void Charger_Detect_Release(void); | |
168 | extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); | |
169 | extern U32 pmic_config_interface (U32 RegNum, U32 val, U32 MASK, U32 SHIFT); | |
170 | extern U32 pmic_read_interface (U32 RegNum, U32 *val, U32 MASK, U32 SHIFT); | |
171 | extern void mt_power_off(void); | |
172 | ||
173 | static kal_uint32 charging_error = false; | |
174 | static kal_uint32 charging_get_error_state(void); | |
175 | static kal_uint32 charging_set_error_state(void *data); | |
176 | // ============================================================ // | |
177 | static kal_uint32 charging_get_csdac_value(void) | |
178 | { | |
179 | kal_uint32 tempA, tempB, tempC; | |
180 | kal_uint32 sum; | |
181 | ||
182 | pmic_config_interface(CHR_CON11,0xC,0xF,0); | |
183 | pmic_read_interface(CHR_CON10, &tempC, 0xF, 0x0); // bit 1 and 2 mapping bit 8 and bit9 | |
184 | ||
185 | pmic_config_interface(CHR_CON11,0xA,0xF,0); | |
186 | pmic_read_interface(CHR_CON10, &tempA, 0xF, 0x0); //bit 0 ~ 3 mapping bit 4 ~7 | |
187 | ||
188 | pmic_config_interface(CHR_CON11,0xB,0xF,0); | |
189 | pmic_read_interface(CHR_CON10, &tempB, 0xF, 0x0); //bit 0~3 mapping bit 0~3 | |
190 | ||
191 | sum = (((tempC & 0x6) >> 1)<<8) | (tempA << 4) | tempB; | |
192 | ||
193 | battery_xlog_printk(BAT_LOG_CRTI, "tempC=%d,tempA=%d,tempB=%d, csdac=%d\n", tempC,tempA,tempB,sum); | |
194 | ||
195 | return sum; | |
196 | } | |
197 | ||
198 | kal_uint32 charging_value_to_parameter(const kal_uint32 *parameter, const kal_uint32 array_size, const kal_uint32 val) | |
199 | { | |
200 | if (val < array_size) | |
201 | { | |
202 | return parameter[val]; | |
203 | } | |
204 | else | |
205 | { | |
206 | battery_xlog_printk(BAT_LOG_CRTI, "Can't find the parameter \r\n"); | |
207 | return parameter[0]; | |
208 | } | |
209 | } | |
210 | ||
211 | ||
212 | kal_uint32 charging_parameter_to_value(const kal_uint32 *parameter, const kal_uint32 array_size, const kal_uint32 val) | |
213 | { | |
214 | kal_uint32 i; | |
215 | ||
216 | for(i=0;i<array_size;i++) | |
217 | { | |
218 | if (val == *(parameter + i)) | |
219 | { | |
220 | return i; | |
221 | } | |
222 | } | |
223 | ||
224 | battery_xlog_printk(BAT_LOG_CRTI, "NO register value match \r\n"); | |
225 | //TODO: ASSERT(0); // not find the value | |
226 | return 0; | |
227 | } | |
228 | ||
229 | ||
230 | static kal_uint32 bmt_find_closest_level(const kal_uint32 *pList,kal_uint32 number,kal_uint32 level) | |
231 | { | |
232 | kal_uint32 i; | |
233 | kal_uint32 max_value_in_last_element; | |
234 | ||
235 | if(pList[0] < pList[1]) | |
236 | max_value_in_last_element = KAL_TRUE; | |
237 | else | |
238 | max_value_in_last_element = KAL_FALSE; | |
239 | ||
240 | if(max_value_in_last_element == KAL_TRUE) | |
241 | { | |
242 | for(i = (number-1); i != 0; i--) //max value in the last element | |
243 | { | |
244 | if(pList[i] <= level) | |
245 | { | |
246 | return pList[i]; | |
247 | } | |
248 | } | |
249 | ||
250 | battery_xlog_printk(BAT_LOG_CRTI, "Can't find closest level \r\n"); | |
251 | return pList[0]; | |
252 | //return CHARGE_CURRENT_0_00_MA; | |
253 | } | |
254 | else | |
255 | { | |
256 | for(i = 0; i< number; i++) // max value in the first element | |
257 | { | |
258 | if(pList[i] <= level) | |
259 | { | |
260 | return pList[i]; | |
261 | } | |
262 | } | |
263 | ||
264 | battery_xlog_printk(BAT_LOG_CRTI, "Can't find closest level \r\n"); | |
265 | return pList[number -1]; | |
266 | //return CHARGE_CURRENT_0_00_MA; | |
267 | } | |
268 | } | |
269 | ||
270 | #if defined(CONFIG_POWER_EXT) | |
271 | #else | |
272 | static void hw_bc11_dump_register(void) | |
273 | { | |
274 | kal_uint32 reg_val = 0; | |
275 | kal_uint32 reg_num = CHR_CON18; | |
276 | kal_uint32 i = 0; | |
277 | ||
278 | for(i=reg_num ; i<=CHR_CON19 ; i+=2) | |
279 | { | |
280 | reg_val = upmu_get_reg_value(i); | |
281 | battery_xlog_printk(BAT_LOG_FULL, "Chr Reg[0x%x]=0x%x \r\n", i, reg_val); | |
282 | } | |
283 | } | |
284 | ||
285 | ||
286 | static void hw_bc11_init(void) | |
287 | { | |
288 | msleep(300); | |
289 | //FIXME_8127 | |
290 | Charger_Detect_Init(); | |
291 | ||
292 | //RG_BC11_BIAS_EN=1 | |
293 | upmu_set_rg_bc11_bias_en(0x1); | |
294 | //RG_BC11_VSRC_EN[1:0]=00 | |
295 | upmu_set_rg_bc11_vsrc_en(0x0); | |
296 | //RG_BC11_VREF_VTH = [1:0]=00 | |
297 | upmu_set_rg_bc11_vref_vth(0x0); | |
298 | //RG_BC11_CMP_EN[1.0] = 00 | |
299 | upmu_set_rg_bc11_cmp_en(0x0); | |
300 | //RG_BC11_IPU_EN[1.0] = 00 | |
301 | upmu_set_rg_bc11_ipu_en(0x0); | |
302 | //RG_BC11_IPD_EN[1.0] = 00 | |
303 | upmu_set_rg_bc11_ipd_en(0x0); | |
304 | //BC11_RST=1 | |
305 | upmu_set_rg_bc11_rst(0x1); | |
306 | //BC11_BB_CTRL=1 | |
307 | upmu_set_rg_bc11_bb_ctrl(0x1); | |
308 | ||
309 | //msleep(10); | |
310 | mdelay(50); | |
311 | ||
312 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
313 | { | |
314 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_init() \r\n"); | |
315 | hw_bc11_dump_register(); | |
316 | } | |
317 | ||
318 | } | |
319 | ||
320 | ||
321 | static U32 hw_bc11_DCD(void) | |
322 | { | |
323 | U32 wChargerAvail = 0; | |
324 | ||
325 | //RG_BC11_IPU_EN[1.0] = 10 | |
326 | upmu_set_rg_bc11_ipu_en(0x2); | |
327 | //RG_BC11_IPD_EN[1.0] = 01 | |
328 | upmu_set_rg_bc11_ipd_en(0x1); | |
329 | //RG_BC11_VREF_VTH = [1:0]=01 | |
330 | upmu_set_rg_bc11_vref_vth(0x1); | |
331 | //RG_BC11_CMP_EN[1.0] = 10 | |
332 | upmu_set_rg_bc11_cmp_en(0x2); | |
333 | ||
334 | //msleep(20); | |
335 | mdelay(80); | |
336 | ||
337 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
338 | ||
339 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
340 | { | |
341 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_DCD() \r\n"); | |
342 | hw_bc11_dump_register(); | |
343 | } | |
344 | ||
345 | //RG_BC11_IPU_EN[1.0] = 00 | |
346 | upmu_set_rg_bc11_ipu_en(0x0); | |
347 | //RG_BC11_IPD_EN[1.0] = 00 | |
348 | upmu_set_rg_bc11_ipd_en(0x0); | |
349 | //RG_BC11_CMP_EN[1.0] = 00 | |
350 | upmu_set_rg_bc11_cmp_en(0x0); | |
351 | //RG_BC11_VREF_VTH = [1:0]=00 | |
352 | upmu_set_rg_bc11_vref_vth(0x0); | |
353 | ||
354 | return wChargerAvail; | |
355 | } | |
356 | ||
357 | ||
358 | static U32 hw_bc11_stepA1(void) | |
359 | { | |
360 | U32 wChargerAvail = 0; | |
361 | ||
362 | //RG_BC11_IPU_EN[1.0] = 10 | |
363 | upmu_set_rg_bc11_ipu_en(0x2); | |
364 | //RG_BC11_VREF_VTH = [1:0]=10 | |
365 | upmu_set_rg_bc11_vref_vth(0x2); | |
366 | //RG_BC11_CMP_EN[1.0] = 10 | |
367 | upmu_set_rg_bc11_cmp_en(0x2); | |
368 | ||
369 | //msleep(80); | |
370 | mdelay(80); | |
371 | ||
372 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
373 | ||
374 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
375 | { | |
376 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_stepA1() \r\n"); | |
377 | hw_bc11_dump_register(); | |
378 | } | |
379 | ||
380 | //RG_BC11_IPU_EN[1.0] = 00 | |
381 | upmu_set_rg_bc11_ipu_en(0x0); | |
382 | //RG_BC11_CMP_EN[1.0] = 00 | |
383 | upmu_set_rg_bc11_cmp_en(0x0); | |
384 | ||
385 | return wChargerAvail; | |
386 | } | |
387 | ||
388 | ||
389 | static U32 hw_bc11_stepB1(void) | |
390 | { | |
391 | U32 wChargerAvail = 0; | |
392 | ||
393 | //RG_BC11_IPU_EN[1.0] = 01 | |
394 | //upmu_set_rg_bc11_ipu_en(0x1); | |
395 | upmu_set_rg_bc11_ipd_en(0x1); | |
396 | //RG_BC11_VREF_VTH = [1:0]=10 | |
397 | //upmu_set_rg_bc11_vref_vth(0x2); | |
398 | upmu_set_rg_bc11_vref_vth(0x0); | |
399 | //RG_BC11_CMP_EN[1.0] = 01 | |
400 | upmu_set_rg_bc11_cmp_en(0x1); | |
401 | ||
402 | //msleep(80); | |
403 | mdelay(80); | |
404 | ||
405 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
406 | ||
407 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
408 | { | |
409 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_stepB1() \r\n"); | |
410 | hw_bc11_dump_register(); | |
411 | } | |
412 | ||
413 | //RG_BC11_IPU_EN[1.0] = 00 | |
414 | upmu_set_rg_bc11_ipu_en(0x0); | |
415 | //RG_BC11_CMP_EN[1.0] = 00 | |
416 | upmu_set_rg_bc11_cmp_en(0x0); | |
417 | //RG_BC11_VREF_VTH = [1:0]=00 | |
418 | upmu_set_rg_bc11_vref_vth(0x0); | |
419 | ||
420 | return wChargerAvail; | |
421 | } | |
422 | ||
423 | ||
424 | static U32 hw_bc11_stepC1(void) | |
425 | { | |
426 | U32 wChargerAvail = 0; | |
427 | ||
428 | //RG_BC11_IPU_EN[1.0] = 01 | |
429 | upmu_set_rg_bc11_ipu_en(0x1); | |
430 | //RG_BC11_VREF_VTH = [1:0]=10 | |
431 | upmu_set_rg_bc11_vref_vth(0x2); | |
432 | //RG_BC11_CMP_EN[1.0] = 01 | |
433 | upmu_set_rg_bc11_cmp_en(0x1); | |
434 | ||
435 | //msleep(80); | |
436 | mdelay(80); | |
437 | ||
438 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
439 | ||
440 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
441 | { | |
442 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_stepC1() \r\n"); | |
443 | hw_bc11_dump_register(); | |
444 | } | |
445 | ||
446 | //RG_BC11_IPU_EN[1.0] = 00 | |
447 | upmu_set_rg_bc11_ipu_en(0x0); | |
448 | //RG_BC11_CMP_EN[1.0] = 00 | |
449 | upmu_set_rg_bc11_cmp_en(0x0); | |
450 | //RG_BC11_VREF_VTH = [1:0]=00 | |
451 | upmu_set_rg_bc11_vref_vth(0x0); | |
452 | ||
453 | return wChargerAvail; | |
454 | } | |
455 | ||
456 | ||
457 | static U32 hw_bc11_stepA2(void) | |
458 | { | |
459 | U32 wChargerAvail = 0; | |
460 | ||
461 | //RG_BC11_VSRC_EN[1.0] = 10 | |
462 | upmu_set_rg_bc11_vsrc_en(0x2); | |
463 | //RG_BC11_IPD_EN[1:0] = 01 | |
464 | upmu_set_rg_bc11_ipd_en(0x1); | |
465 | //RG_BC11_VREF_VTH = [1:0]=00 | |
466 | upmu_set_rg_bc11_vref_vth(0x0); | |
467 | //RG_BC11_CMP_EN[1.0] = 01 | |
468 | upmu_set_rg_bc11_cmp_en(0x1); | |
469 | ||
470 | //msleep(80); | |
471 | mdelay(80); | |
472 | ||
473 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
474 | ||
475 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
476 | { | |
477 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_stepA2() \r\n"); | |
478 | hw_bc11_dump_register(); | |
479 | } | |
480 | ||
481 | //RG_BC11_VSRC_EN[1:0]=00 | |
482 | upmu_set_rg_bc11_vsrc_en(0x0); | |
483 | //RG_BC11_IPD_EN[1.0] = 00 | |
484 | upmu_set_rg_bc11_ipd_en(0x0); | |
485 | //RG_BC11_CMP_EN[1.0] = 00 | |
486 | upmu_set_rg_bc11_cmp_en(0x0); | |
487 | ||
488 | return wChargerAvail; | |
489 | } | |
490 | ||
491 | ||
492 | static U32 hw_bc11_stepB2(void) | |
493 | { | |
494 | U32 wChargerAvail = 0; | |
495 | ||
496 | //RG_BC11_IPU_EN[1:0]=10 | |
497 | upmu_set_rg_bc11_ipu_en(0x2); | |
498 | //RG_BC11_VREF_VTH = [1:0]=10 | |
499 | upmu_set_rg_bc11_vref_vth(0x1); | |
500 | //RG_BC11_CMP_EN[1.0] = 01 | |
501 | upmu_set_rg_bc11_cmp_en(0x1); | |
502 | ||
503 | //msleep(80); | |
504 | mdelay(80); | |
505 | ||
506 | wChargerAvail = upmu_get_rgs_bc11_cmp_out(); | |
507 | ||
508 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
509 | { | |
510 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_stepB2() \r\n"); | |
511 | hw_bc11_dump_register(); | |
512 | } | |
513 | ||
514 | //RG_BC11_IPU_EN[1.0] = 00 | |
515 | upmu_set_rg_bc11_ipu_en(0x0); | |
516 | //RG_BC11_CMP_EN[1.0] = 00 | |
517 | upmu_set_rg_bc11_cmp_en(0x0); | |
518 | //RG_BC11_VREF_VTH = [1:0]=00 | |
519 | upmu_set_rg_bc11_vref_vth(0x0); | |
520 | ||
521 | return wChargerAvail; | |
522 | } | |
523 | ||
524 | ||
525 | static void hw_bc11_done(void) | |
526 | { | |
527 | //RG_BC11_VSRC_EN[1:0]=00 | |
528 | upmu_set_rg_bc11_vsrc_en(0x0); | |
529 | //RG_BC11_VREF_VTH = [1:0]=0 | |
530 | upmu_set_rg_bc11_vref_vth(0x0); | |
531 | //RG_BC11_CMP_EN[1.0] = 00 | |
532 | upmu_set_rg_bc11_cmp_en(0x0); | |
533 | //RG_BC11_IPU_EN[1.0] = 00 | |
534 | upmu_set_rg_bc11_ipu_en(0x0); | |
535 | //RG_BC11_IPD_EN[1.0] = 00 | |
536 | upmu_set_rg_bc11_ipd_en(0x0); | |
537 | //RG_BC11_BIAS_EN=0 | |
538 | upmu_set_rg_bc11_bias_en(0x0); | |
539 | ||
540 | //FIXME_8127 | |
541 | Charger_Detect_Release(); | |
542 | ||
543 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
544 | { | |
545 | battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_done() \r\n"); | |
546 | hw_bc11_dump_register(); | |
547 | } | |
548 | ||
549 | } | |
550 | #endif | |
551 | ||
552 | static kal_uint32 charging_hw_init(void *data) | |
553 | { | |
554 | kal_uint32 status = STATUS_OK; | |
555 | #ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT | |
556 | mt_set_gpio_mode(vin_sel_gpio_number,0); // 0:GPIO mode | |
557 | mt_set_gpio_dir(vin_sel_gpio_number,0); // 0: input, 1: output | |
558 | #endif | |
559 | ||
560 | #if defined(CONFIG_MTK_WIRELESS_CHARGER_SUPPORT) | |
561 | mt_set_gpio_mode(wireless_charger_gpio_number,0); // 0:GPIO mode | |
562 | mt_set_gpio_dir(wireless_charger_gpio_number,0); // 0: input, 1: output | |
563 | #endif | |
564 | upmu_set_rg_chrwdt_td(0x0); // CHRWDT_TD, 4s | |
565 | upmu_set_rg_chrwdt_int_en(1); // CHRWDT_INT_EN | |
566 | upmu_set_rg_chrwdt_en(1); // CHRWDT_EN | |
567 | upmu_set_rg_chrwdt_wr(1); // CHRWDT_WR | |
568 | ||
569 | upmu_set_rg_vcdt_mode(0); //VCDT_MODE | |
570 | upmu_set_rg_vcdt_hv_en(1); //VCDT_HV_EN | |
4b9e9796 | 571 | |
6fa3eb70 S |
572 | upmu_set_rg_usbdl_set(0); //force leave USBDL mode |
573 | upmu_set_rg_usbdl_rst(1); //force leave USBDL mode | |
574 | ||
575 | upmu_set_rg_bc11_bb_ctrl(1); //BC11_BB_CTRL | |
576 | upmu_set_rg_bc11_rst(1); //BC11_RST | |
577 | ||
578 | upmu_set_rg_csdac_mode(1); //CSDAC_MODE | |
579 | upmu_set_rg_vbat_ov_en(1); //VBAT_OV_EN | |
580 | #ifdef HIGH_BATTERY_VOLTAGE_SUPPORT | |
581 | upmu_set_rg_vbat_ov_vth(0x2); //VBAT_OV_VTH, 4.4V, | |
582 | #else | |
583 | upmu_set_rg_vbat_ov_vth(0x1); //VBAT_OV_VTH, 4.3V, | |
584 | #endif | |
585 | upmu_set_rg_baton_en(1); //BATON_EN | |
586 | ||
587 | //Tim, for TBAT | |
588 | //upmu_set_rg_buf_pwd_b(1); //RG_BUF_PWD_B | |
589 | upmu_set_rg_baton_ht_en(0); //BATON_HT_EN | |
590 | ||
591 | upmu_set_rg_ulc_det_en(1); // RG_ULC_DET_EN=1 | |
592 | upmu_set_rg_low_ich_db(1); // RG_LOW_ICH_DB=000001'b | |
593 | ||
594 | #if defined(CONFIG_MTK_PUMP_EXPRESS_SUPPORT) | |
595 | upmu_set_rg_chrwdt_td(0x0); // CHRWDT_TD, 4s | |
596 | upmu_set_rg_chrwdt_wr(1); // CHRWDT_WR | |
597 | upmu_set_rg_chrwdt_int_en(1); // CHRWDT_INT_EN | |
598 | upmu_set_rg_chrwdt_en(1); // CHRWDT_EN | |
599 | upmu_set_rg_chrwdt_flag_wr(1); // CHRWDT_WR | |
600 | ||
601 | upmu_set_rg_csdac_dly(0x0); // CSDAC_DLY | |
602 | upmu_set_rg_csdac_stp(0x1); // CSDAC_STP | |
603 | upmu_set_rg_csdac_stp_inc(0x1); // CSDAC_STP_INC | |
604 | upmu_set_rg_csdac_stp_dec(0x7); // CSDAC_STP_DEC | |
605 | upmu_set_rg_cs_en(1); // CS_EN | |
606 | ||
607 | upmu_set_rg_hwcv_en(1); | |
608 | upmu_set_rg_vbat_cv_en(1); // CV_EN | |
609 | upmu_set_rg_csdac_en(1); // CSDAC_EN | |
610 | upmu_set_rg_chr_en(1); // CHR_EN | |
611 | #endif | |
612 | #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT) && defined(MTK_LOAD_SWITCH_FPF3040) | |
613 | upmu_set_rg_chr_en(0); // CHR_EN | |
614 | #endif | |
615 | ||
616 | return status; | |
617 | } | |
618 | ||
619 | ||
620 | static kal_uint32 charging_dump_register(void *data) | |
621 | { | |
622 | kal_uint32 status = STATUS_OK; | |
623 | ||
624 | kal_uint32 reg_val = 0; | |
625 | kal_uint32 reg_num = CHR_CON0; | |
626 | kal_uint32 i = 0; | |
627 | ||
628 | for(i=reg_num ; i<=CHR_CON29 ; i+=2) | |
629 | { | |
630 | reg_val = upmu_get_reg_value(i); | |
631 | battery_xlog_printk(BAT_LOG_FULL, "Chr Reg[0x%x]=0x%x \r\n", i, reg_val); | |
632 | } | |
633 | ||
634 | return status; | |
635 | } | |
636 | ||
637 | ||
638 | static kal_uint32 charging_enable(void *data) | |
639 | { | |
640 | kal_uint32 status = STATUS_OK; | |
641 | kal_uint32 enable = *(kal_uint32*)(data); | |
642 | ||
643 | if(KAL_TRUE == enable) | |
644 | { | |
645 | upmu_set_rg_csdac_dly(0x4); // CSDAC_DLY | |
646 | upmu_set_rg_csdac_stp(0x1); // CSDAC_STP | |
647 | upmu_set_rg_csdac_stp_inc(0x1); // CSDAC_STP_INC | |
648 | upmu_set_rg_csdac_stp_dec(0x2); // CSDAC_STP_DEC | |
649 | upmu_set_rg_cs_en(1); // CS_EN, check me | |
650 | ||
651 | upmu_set_rg_hwcv_en(1); | |
652 | ||
653 | upmu_set_rg_vbat_cv_en(1); // CV_EN | |
654 | upmu_set_rg_csdac_en(1); // CSDAC_EN | |
655 | ||
656 | upmu_set_rg_pchr_flag_en(1); // enable debug flag output | |
657 | upmu_set_rg_chr_en(1); // CHR_EN | |
658 | ||
659 | if(Enable_BATDRV_LOG == BAT_LOG_FULL) | |
660 | charging_dump_register(NULL); | |
661 | } | |
662 | else | |
663 | { | |
664 | upmu_set_rg_chrwdt_int_en(0); // CHRWDT_INT_EN | |
665 | upmu_set_rg_chrwdt_en(0); // CHRWDT_EN | |
666 | upmu_set_rg_chrwdt_flag_wr(0); // CHRWDT_FLAG | |
667 | ||
668 | upmu_set_rg_csdac_en(0); // CSDAC_EN | |
669 | upmu_set_rg_chr_en(0); // CHR_EN | |
670 | upmu_set_rg_hwcv_en(0); // RG_HWCV_EN | |
671 | } | |
672 | return status; | |
673 | } | |
674 | ||
675 | ||
676 | static kal_uint32 charging_set_cv_voltage(void *data) | |
677 | { | |
678 | kal_uint32 status = STATUS_OK; | |
679 | kal_uint16 register_value; | |
680 | ||
681 | register_value = charging_parameter_to_value(VBAT_CV_VTH, GETARRAYNUM(VBAT_CV_VTH) ,*(kal_uint32 *)(data)); | |
682 | upmu_set_rg_vbat_cv_vth(register_value); | |
683 | ||
684 | return status; | |
685 | } | |
686 | ||
687 | ||
688 | static kal_uint32 charging_get_current(void *data) | |
689 | { | |
690 | kal_uint32 status = STATUS_OK; | |
691 | kal_uint32 array_size; | |
692 | kal_uint32 reg_value; | |
693 | ||
694 | array_size = GETARRAYNUM(CS_VTH); | |
695 | reg_value=upmu_get_reg_value(0x8); //RG_CS_VTH | |
696 | *(kal_uint32 *)data = charging_value_to_parameter(CS_VTH,array_size,reg_value); | |
697 | ||
698 | return status; | |
699 | } | |
700 | ||
701 | ||
702 | ||
703 | static kal_uint32 charging_set_current(void *data) | |
704 | { | |
705 | kal_uint32 status = STATUS_OK; | |
706 | kal_uint32 set_chr_current; | |
707 | kal_uint32 array_size; | |
708 | kal_uint32 register_value; | |
709 | ||
710 | array_size = GETARRAYNUM(CS_VTH); | |
711 | set_chr_current = bmt_find_closest_level(CS_VTH, array_size, *(kal_uint32 *)data); | |
712 | register_value = charging_parameter_to_value(CS_VTH, array_size ,set_chr_current); | |
713 | upmu_set_rg_cs_vth(register_value); | |
714 | ||
715 | return status; | |
716 | } | |
717 | ||
718 | ||
719 | static kal_uint32 charging_set_input_current(void *data) | |
720 | { | |
721 | kal_uint32 status = STATUS_OK; | |
722 | return status; | |
723 | } | |
724 | ||
725 | static kal_uint32 charging_get_charging_status(void *data) | |
726 | { | |
727 | kal_uint32 status = STATUS_OK; | |
728 | return status; | |
729 | } | |
730 | ||
731 | ||
732 | static kal_uint32 charging_reset_watch_dog_timer(void *data) | |
733 | { | |
734 | kal_uint32 status = STATUS_OK; | |
735 | ||
736 | upmu_set_rg_chrwdt_td(0x0); // CHRWDT_TD, 4s | |
737 | upmu_set_rg_chrwdt_wr(1); // CHRWDT_WR | |
738 | upmu_set_rg_chrwdt_int_en(1); // CHRWDT_INT_EN | |
739 | upmu_set_rg_chrwdt_en(1); // CHRWDT_EN | |
740 | upmu_set_rg_chrwdt_flag_wr(1); // CHRWDT_WR | |
741 | ||
742 | return status; | |
743 | } | |
744 | ||
745 | ||
746 | static kal_uint32 charging_set_hv_threshold(void *data) | |
747 | { | |
748 | kal_uint32 status = STATUS_OK; | |
749 | ||
750 | kal_uint32 set_hv_voltage; | |
751 | kal_uint32 array_size; | |
752 | kal_uint16 register_value; | |
753 | kal_uint32 voltage = *(kal_uint32*)(data); | |
754 | ||
755 | array_size = GETARRAYNUM(VCDT_HV_VTH); | |
756 | set_hv_voltage = bmt_find_closest_level(VCDT_HV_VTH, array_size, voltage); | |
757 | register_value = charging_parameter_to_value(VCDT_HV_VTH, array_size ,set_hv_voltage); | |
758 | upmu_set_rg_vcdt_hv_vth(register_value); | |
759 | ||
760 | return status; | |
761 | } | |
762 | ||
763 | ||
764 | static kal_uint32 charging_get_hv_status(void *data) | |
765 | { | |
766 | kal_uint32 status = STATUS_OK; | |
767 | ||
768 | *(kal_bool*)(data) = upmu_get_rgs_vcdt_hv_det(); | |
769 | ||
770 | return status; | |
771 | } | |
772 | ||
773 | ||
774 | static kal_uint32 charging_get_battery_status(void *data) | |
775 | { | |
776 | kal_uint32 status = STATUS_OK; | |
777 | ||
778 | upmu_set_baton_tdet_en(1); | |
779 | upmu_set_rg_baton_en(1); | |
780 | *(kal_bool*)(data) = upmu_get_rgs_baton_undet(); | |
781 | ||
782 | return status; | |
783 | } | |
784 | ||
785 | ||
786 | static kal_uint32 charging_get_charger_det_status(void *data) | |
787 | { | |
788 | kal_uint32 status = STATUS_OK; | |
789 | kal_uint32 val = 0; | |
790 | ||
791 | #if defined(CONFIG_POWER_EXT) || defined(CONFIG_MTK_FPGA) | |
792 | val = 1; | |
793 | battery_xlog_printk(BAT_LOG_CRTI,"[charging_get_charger_det_status] charger exist for bring up.\n"); | |
794 | #else | |
795 | #if !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT) | |
796 | val = upmu_get_rgs_chrdet(); | |
797 | #else | |
798 | if(((g_diso_state >> 1) & 0x3) != 0x0 || (upmu_get_rgs_chrdet() && !g_diso_otg)) | |
799 | val = KAL_TRUE; | |
800 | else | |
801 | val = KAL_FALSE; | |
802 | #endif | |
803 | ||
804 | #endif | |
805 | ||
806 | *(kal_bool*)(data) = val; | |
807 | if(val == 0) | |
808 | g_charger_type = CHARGER_UNKNOWN; | |
809 | ||
810 | return status; | |
811 | ||
812 | } | |
813 | ||
814 | ||
815 | kal_bool charging_type_detection_done(void) | |
816 | { | |
817 | return charging_type_det_done; | |
818 | } | |
819 | ||
820 | ||
821 | static kal_uint32 charging_get_charger_type(void *data) | |
822 | { | |
823 | kal_uint32 status = STATUS_OK; | |
824 | #if defined(CONFIG_POWER_EXT) | |
825 | *(CHARGER_TYPE*)(data) = STANDARD_HOST; | |
826 | #else | |
827 | #if defined(CONFIG_MTK_WIRELESS_CHARGER_SUPPORT) | |
828 | int wireless_state = 0; | |
829 | wireless_state = mt_get_gpio_in(wireless_charger_gpio_number); | |
830 | if(wireless_state == WIRELESS_CHARGER_EXIST_STATE) | |
831 | { | |
832 | *(CHARGER_TYPE*)(data) = WIRELESS_CHARGER; | |
833 | battery_xlog_printk(BAT_LOG_CRTI, "WIRELESS_CHARGER!\r\n"); | |
834 | return status; | |
835 | } | |
836 | #endif | |
837 | ||
838 | if(g_charger_type!=CHARGER_UNKNOWN && g_charger_type!=WIRELESS_CHARGER) | |
839 | { | |
840 | *(CHARGER_TYPE*)(data) = g_charger_type; | |
841 | battery_xlog_printk(BAT_LOG_CRTI, "return %d!\r\n", g_charger_type); | |
842 | return status; | |
843 | } | |
844 | ||
845 | charging_type_det_done = KAL_FALSE; | |
846 | ||
847 | /********* Step initial ***************/ | |
848 | hw_bc11_init(); | |
849 | ||
850 | /********* Step DCD ***************/ | |
851 | if(1 == hw_bc11_DCD()) | |
852 | { | |
853 | /********* Step A1 ***************/ | |
854 | if(1 == hw_bc11_stepA1()) | |
855 | { | |
856 | /********* Step B1 ***************/ | |
857 | if(1 == hw_bc11_stepB1()) | |
858 | { | |
859 | //*(CHARGER_TYPE*)(data) = NONSTANDARD_CHARGER; | |
860 | //battery_xlog_printk(BAT_LOG_CRTI, "step B1 : Non STANDARD CHARGER!\r\n"); | |
861 | *(CHARGER_TYPE*)(data) = APPLE_2_1A_CHARGER; | |
862 | battery_xlog_printk(BAT_LOG_CRTI, "step B1 : Apple 2.1A CHARGER!\r\n"); | |
863 | } | |
864 | else | |
865 | { | |
866 | //*(CHARGER_TYPE*)(data) = APPLE_2_1A_CHARGER; | |
867 | //battery_xlog_printk(BAT_LOG_CRTI, "step B1 : Apple 2.1A CHARGER!\r\n"); | |
868 | *(CHARGER_TYPE*)(data) = NONSTANDARD_CHARGER; | |
869 | battery_xlog_printk(BAT_LOG_CRTI, "step B1 : Non STANDARD CHARGER!\r\n"); | |
870 | } | |
871 | } | |
872 | else | |
873 | { | |
874 | /********* Step C1 ***************/ | |
875 | if(1 == hw_bc11_stepC1()) | |
876 | { | |
877 | *(CHARGER_TYPE*)(data) = APPLE_1_0A_CHARGER; | |
878 | battery_xlog_printk(BAT_LOG_CRTI, "step C1 : Apple 1A CHARGER!\r\n"); | |
879 | } | |
880 | else | |
881 | { | |
882 | *(CHARGER_TYPE*)(data) = APPLE_0_5A_CHARGER; | |
883 | battery_xlog_printk(BAT_LOG_CRTI, "step C1 : Apple 0.5A CHARGER!\r\n"); | |
884 | } | |
885 | } | |
886 | ||
887 | } | |
888 | else | |
889 | { | |
890 | /********* Step A2 ***************/ | |
891 | if(1 == hw_bc11_stepA2()) | |
892 | { | |
893 | /********* Step B2 ***************/ | |
894 | if(1 == hw_bc11_stepB2()) | |
895 | { | |
896 | *(CHARGER_TYPE*)(data) = STANDARD_CHARGER; | |
897 | battery_xlog_printk(BAT_LOG_CRTI, "step B2 : STANDARD CHARGER!\r\n"); | |
898 | } | |
899 | else | |
900 | { | |
901 | *(CHARGER_TYPE*)(data) = CHARGING_HOST; | |
902 | battery_xlog_printk(BAT_LOG_CRTI, "step B2 : Charging Host!\r\n"); | |
903 | } | |
904 | } | |
905 | else | |
906 | { | |
907 | *(CHARGER_TYPE*)(data) = STANDARD_HOST; | |
908 | battery_xlog_printk(BAT_LOG_CRTI, "step A2 : Standard USB Host!\r\n"); | |
909 | } | |
910 | ||
911 | } | |
912 | ||
913 | /********* Finally setting *******************************/ | |
914 | hw_bc11_done(); | |
915 | ||
916 | charging_type_det_done = KAL_TRUE; | |
917 | ||
918 | g_charger_type = *(CHARGER_TYPE*)(data); | |
919 | #endif | |
920 | return status; | |
921 | } | |
922 | ||
923 | static kal_uint32 charging_get_is_pcm_timer_trigger(void *data) | |
924 | { | |
925 | kal_uint32 status = STATUS_OK; | |
926 | ||
927 | #if defined(CONFIG_MTK_FPGA) | |
928 | battery_xlog_printk(BAT_LOG_CRTI, "[Early porting] no slp_get_wake_reason at FPGA\n"); | |
929 | #else | |
930 | if(slp_get_wake_reason() == WR_PCM_TIMER) | |
931 | *(kal_bool*)(data) = KAL_TRUE; | |
932 | else | |
933 | *(kal_bool*)(data) = KAL_FALSE; | |
934 | ||
935 | battery_xlog_printk(BAT_LOG_CRTI, "slp_get_wake_reason=%d\n", slp_get_wake_reason()); | |
936 | #endif | |
937 | ||
938 | return status; | |
939 | } | |
940 | ||
941 | static kal_uint32 charging_set_platform_reset(void *data) | |
942 | { | |
943 | kal_uint32 status = STATUS_OK; | |
944 | ||
945 | battery_xlog_printk(BAT_LOG_CRTI, "charging_set_platform_reset\n"); | |
946 | ||
947 | arch_reset(0,NULL); | |
948 | ||
949 | return status; | |
950 | } | |
951 | ||
952 | static kal_uint32 charging_get_platfrom_boot_mode(void *data) | |
953 | { | |
954 | kal_uint32 status = STATUS_OK; | |
955 | ||
956 | *(kal_uint32*)(data) = get_boot_mode(); | |
957 | ||
958 | battery_xlog_printk(BAT_LOG_CRTI, "get_boot_mode=%d\n", get_boot_mode()); | |
959 | ||
960 | return status; | |
961 | } | |
962 | ||
963 | static kal_uint32 charging_get_power_srouce(void *data) | |
964 | { | |
965 | kal_uint32 status = STATUS_OK; | |
966 | ||
967 | return status; | |
968 | } | |
969 | static kal_uint32 charging_set_power_off(void *data) | |
970 | { | |
971 | kal_uint32 status = STATUS_OK; | |
972 | ||
973 | //battery_xlog_printk(BAT_LOG_CRTI, "charging_set_power_off=%d\n"); | |
974 | battery_xlog_printk(BAT_LOG_CRTI, "charging_set_power_off=\n"); | |
975 | mt_power_off(); | |
976 | ||
977 | return status; | |
978 | } | |
979 | ||
980 | static kal_uint32 charging_get_csdac_full_flag(void *data) | |
981 | { | |
982 | kal_uint32 status = STATUS_OK; | |
983 | kal_uint32 csdac_value; | |
984 | ||
985 | ||
986 | csdac_value = charging_get_csdac_value(); | |
987 | ||
988 | if(csdac_value > 800) //10 bit, treat as full if csdac more than 800 | |
989 | *(kal_bool *)data = KAL_TRUE; | |
990 | else | |
991 | *(kal_bool *)data = KAL_FALSE; | |
992 | ||
993 | return status; | |
994 | } | |
995 | ||
996 | ||
997 | static kal_uint32 charging_set_ta_current_pattern(void *data) | |
998 | { | |
999 | kal_uint32 status = STATUS_OK; | |
1000 | kal_uint32 array_size; | |
1001 | kal_uint32 ta_on_current = CHARGE_CURRENT_450_00_MA; | |
1002 | kal_uint32 ta_off_current= CHARGE_CURRENT_70_00_MA; | |
1003 | kal_uint32 set_ta_on_current_reg_value; | |
1004 | kal_uint32 set_ta_off_current_reg_value; | |
1005 | kal_uint32 increase = *(kal_uint32*)(data); | |
1006 | ||
1007 | array_size = GETARRAYNUM(CS_VTH); | |
1008 | set_ta_on_current_reg_value = charging_parameter_to_value(CS_VTH, array_size ,ta_on_current); | |
1009 | set_ta_off_current_reg_value = charging_parameter_to_value(CS_VTH, array_size ,ta_off_current); | |
1010 | ||
1011 | if(increase == KAL_TRUE) | |
1012 | { | |
1013 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() start\n"); | |
1014 | ||
1015 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1016 | msleep(50); | |
1017 | ||
1018 | // patent start | |
1019 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1020 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 1"); | |
1021 | msleep(100); | |
1022 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1023 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 1"); | |
1024 | msleep(100); | |
1025 | ||
1026 | ||
1027 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1028 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 2"); | |
1029 | msleep(100); | |
1030 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1031 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 2"); | |
1032 | msleep(100); | |
1033 | ||
1034 | ||
1035 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1036 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 3"); | |
1037 | msleep(300); | |
1038 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1039 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 3"); | |
1040 | msleep(100); | |
1041 | ||
1042 | ||
1043 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1044 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 4"); | |
1045 | msleep(300); | |
1046 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1047 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 4"); | |
1048 | msleep(100); | |
1049 | ||
1050 | ||
1051 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1052 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 5"); | |
1053 | msleep(300); | |
1054 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1055 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 5"); | |
1056 | msleep(100); | |
1057 | ||
1058 | ||
1059 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1060 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() on 6"); | |
1061 | msleep(500); | |
1062 | ||
1063 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1064 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() off 6"); | |
1065 | msleep(50); | |
1066 | // patent end | |
1067 | ||
1068 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_increase() end \n"); | |
1069 | } | |
1070 | else //decrease | |
1071 | { | |
1072 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() start\n"); | |
1073 | ||
1074 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1075 | msleep(50); | |
1076 | ||
1077 | // patent start | |
1078 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1079 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 1"); | |
1080 | msleep(300); | |
1081 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1082 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 1"); | |
1083 | msleep(100); | |
1084 | ||
1085 | ||
1086 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1087 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 2"); | |
1088 | msleep(300); | |
1089 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1090 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 2"); | |
1091 | msleep(100); | |
1092 | ||
1093 | ||
1094 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1095 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 3"); | |
1096 | msleep(300); | |
1097 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1098 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 3"); | |
1099 | msleep(100); | |
1100 | ||
1101 | ||
1102 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1103 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 4"); | |
1104 | msleep(100); | |
1105 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1106 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 4"); | |
1107 | msleep(100); | |
1108 | ||
1109 | ||
1110 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1111 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 5"); | |
1112 | msleep(100); | |
1113 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1114 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 5"); | |
1115 | msleep(100); | |
1116 | ||
1117 | ||
1118 | upmu_set_rg_cs_vth(set_ta_on_current_reg_value); | |
1119 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() on 6"); | |
1120 | msleep(500); | |
1121 | ||
1122 | upmu_set_rg_cs_vth(set_ta_off_current_reg_value); | |
1123 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() off 6"); | |
1124 | msleep(50); | |
1125 | // patent end | |
1126 | ||
1127 | battery_xlog_printk(BAT_LOG_CRTI, "mtk_ta_decrease() end \n"); | |
1128 | } | |
1129 | ||
1130 | return status; | |
1131 | } | |
1132 | ||
1133 | #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT) | |
1134 | void set_diso_otg(bool enable) | |
1135 | { | |
1136 | g_diso_otg = enable; | |
1137 | } | |
1138 | ||
1139 | void set_vusb_auxadc_irq(bool enable, bool flag) | |
1140 | { | |
1141 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
1142 | hrtimer_cancel(&diso_kthread_timer); | |
1143 | ||
1144 | DISO_Polling.reset_polling = KAL_TRUE; | |
1145 | DISO_Polling.vusb_polling_measure.notify_irq_en = enable; | |
1146 | DISO_Polling.vusb_polling_measure.notify_irq = flag; | |
1147 | ||
1148 | hrtimer_start(&diso_kthread_timer, ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)), HRTIMER_MODE_REL); | |
1149 | #else | |
1150 | kal_uint16 threshold = 0; | |
1151 | if (enable) { | |
1152 | if (flag == 0) | |
1153 | threshold = DISO_IRQ.vusb_measure_channel.falling_threshold; | |
1154 | else | |
1155 | threshold = DISO_IRQ.vusb_measure_channel.rising_threshold; | |
1156 | ||
1157 | threshold = (threshold *R_DISO_VBUS_PULL_DOWN)/(R_DISO_VBUS_PULL_DOWN + R_DISO_VBUS_PULL_UP); | |
1158 | mt_auxadc_enableBackgroundDection(DISO_IRQ.vusb_measure_channel.number, threshold, \ | |
1159 | DISO_IRQ.vusb_measure_channel.period, DISO_IRQ.vusb_measure_channel.debounce, flag); | |
1160 | } else { | |
1161 | mt_auxadc_disableBackgroundDection(DISO_IRQ.vusb_measure_channel.number); | |
1162 | } | |
1163 | #endif | |
1164 | battery_xlog_printk(BAT_LOG_FULL, " [%s] enable: %d, flag: %d!\n", __func__, enable, flag); | |
1165 | } | |
1166 | ||
1167 | void set_vdc_auxadc_irq(bool enable, bool flag) | |
1168 | { | |
1169 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
1170 | hrtimer_cancel(&diso_kthread_timer); | |
1171 | ||
1172 | DISO_Polling.reset_polling = KAL_TRUE; | |
1173 | DISO_Polling.vdc_polling_measure.notify_irq_en = enable; | |
1174 | DISO_Polling.vdc_polling_measure.notify_irq = flag; | |
1175 | ||
1176 | hrtimer_start(&diso_kthread_timer, ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)), HRTIMER_MODE_REL); | |
1177 | #else | |
1178 | kal_uint16 threshold = 0; | |
1179 | if(enable) { | |
1180 | if(flag == 0) | |
1181 | threshold = DISO_IRQ.vdc_measure_channel.falling_threshold; | |
1182 | else | |
1183 | threshold = DISO_IRQ.vdc_measure_channel.rising_threshold; | |
1184 | ||
1185 | threshold = (threshold *R_DISO_DC_PULL_DOWN)/(R_DISO_DC_PULL_DOWN + R_DISO_DC_PULL_UP); | |
1186 | mt_auxadc_enableBackgroundDection(DISO_IRQ.vdc_measure_channel.number, threshold, \ | |
1187 | DISO_IRQ.vdc_measure_channel.period, DISO_IRQ.vdc_measure_channel.debounce, flag); | |
1188 | } else { | |
1189 | mt_auxadc_disableBackgroundDection(DISO_IRQ.vdc_measure_channel.number); | |
1190 | } | |
1191 | #endif | |
1192 | battery_xlog_printk(BAT_LOG_FULL, " [%s] enable: %d, flag: %d!\n", __func__, enable, flag); | |
1193 | } | |
1194 | ||
1195 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
1196 | static void diso_polling_handler(struct work_struct *work) | |
1197 | { | |
1198 | int trigger_channel = -1; | |
1199 | int trigger_flag = -1; | |
1200 | ||
1201 | if(DISO_Polling.vdc_polling_measure.notify_irq_en) | |
1202 | trigger_channel = AP_AUXADC_DISO_VDC_CHANNEL; | |
1203 | else if(DISO_Polling.vusb_polling_measure.notify_irq_en) | |
1204 | trigger_channel = AP_AUXADC_DISO_VUSB_CHANNEL; | |
1205 | ||
1206 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]auxadc handler triggered\n" ); | |
1207 | switch(trigger_channel) | |
1208 | { | |
1209 | case AP_AUXADC_DISO_VDC_CHANNEL: | |
1210 | trigger_flag = DISO_Polling.vdc_polling_measure.notify_irq; | |
1211 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VDC IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel, trigger_flag ); | |
1212 | #ifdef MTK_DISCRETE_SWITCH /*for DSC DC plugin handle */ | |
1213 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1214 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1215 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_FALLING); | |
1216 | if (trigger_flag == DISO_IRQ_RISING) { | |
1217 | DISO_data.diso_state.pre_vusb_state = DISO_ONLINE; | |
1218 | DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE; | |
1219 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1220 | DISO_data.diso_state.cur_vusb_state = DISO_ONLINE; | |
1221 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1222 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1223 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[2]); | |
1224 | } | |
1225 | #else //for load switch OTG leakage handle | |
1226 | set_vdc_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag) & 0x1); | |
1227 | if (trigger_flag == DISO_IRQ_RISING) { | |
1228 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1229 | DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE; | |
1230 | DISO_data.diso_state.pre_otg_state = DISO_ONLINE; | |
1231 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1232 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1233 | DISO_data.diso_state.cur_otg_state = DISO_ONLINE; | |
1234 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[5]); | |
1235 | } else if (trigger_flag == DISO_IRQ_FALLING) { | |
1236 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1237 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1238 | DISO_data.diso_state.pre_otg_state = DISO_ONLINE; | |
1239 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1240 | DISO_data.diso_state.cur_vdc_state = DISO_OFFLINE; | |
1241 | DISO_data.diso_state.cur_otg_state = DISO_ONLINE; | |
1242 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[1]); | |
1243 | } | |
1244 | else | |
1245 | battery_xlog_printk(BAT_LOG_CRTI, "[%s] wrong trigger flag!\n",__func__); | |
1246 | #endif | |
1247 | break; | |
1248 | case AP_AUXADC_DISO_VUSB_CHANNEL: | |
1249 | trigger_flag = DISO_Polling.vusb_polling_measure.notify_irq; | |
1250 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VUSB IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel, trigger_flag); | |
1251 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1252 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1253 | if(trigger_flag == DISO_IRQ_FALLING) { | |
1254 | DISO_data.diso_state.pre_vusb_state = DISO_ONLINE; | |
1255 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1256 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1257 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1258 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1259 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1260 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[4]); | |
1261 | } else if (trigger_flag == DISO_IRQ_RISING) { | |
1262 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1263 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1264 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1265 | DISO_data.diso_state.cur_vusb_state = DISO_ONLINE; | |
1266 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1267 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1268 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[6]); | |
1269 | } | |
1270 | else | |
1271 | battery_xlog_printk(BAT_LOG_CRTI, "[%s] wrong trigger flag!\n",__func__); | |
1272 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag)&0x1); | |
1273 | break; | |
1274 | default: | |
1275 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1276 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1277 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VUSB auxadc IRQ triggered ERROR OR TEST\n"); | |
1278 | return; /* in error or unexecpt state just return */ | |
1279 | } | |
1280 | ||
1281 | g_diso_state = *(int*)&DISO_data.diso_state; | |
1282 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]g_diso_state: 0x%x\n", g_diso_state); | |
1283 | DISO_data.irq_callback_func(0, NULL); | |
1284 | ||
1285 | return ; | |
1286 | } | |
1287 | #else | |
1288 | static irqreturn_t diso_auxadc_irq_handler(int irq, void *dev_id) | |
1289 | { | |
1290 | int trigger_channel = -1; | |
1291 | int trigger_flag = -1; | |
1292 | trigger_channel = mt_auxadc_getCurrentChannel(); | |
1293 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]auxadc handler triggered\n" ); | |
1294 | switch(trigger_channel) | |
1295 | { | |
1296 | case AP_AUXADC_DISO_VDC_CHANNEL: | |
1297 | trigger_flag = mt_auxadc_getCurrentTrigger(); | |
1298 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VDC IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel, trigger_flag ); | |
1299 | #ifdef MTK_DISCRETE_SWITCH /*for DSC DC plugin handle */ | |
1300 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1301 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1302 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_FALLING); | |
1303 | if (trigger_flag == DISO_IRQ_RISING) { | |
1304 | DISO_data.diso_state.pre_vusb_state = DISO_ONLINE; | |
1305 | DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE; | |
1306 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1307 | DISO_data.diso_state.cur_vusb_state = DISO_ONLINE; | |
1308 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1309 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1310 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[2]); | |
1311 | } | |
1312 | #else //for load switch OTG leakage handle | |
1313 | set_vdc_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag) & 0x1); | |
1314 | if (trigger_flag == DISO_IRQ_RISING) { | |
1315 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1316 | DISO_data.diso_state.pre_vdc_state = DISO_OFFLINE; | |
1317 | DISO_data.diso_state.pre_otg_state = DISO_ONLINE; | |
1318 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1319 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1320 | DISO_data.diso_state.cur_otg_state = DISO_ONLINE; | |
1321 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[5]); | |
1322 | } else { | |
1323 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1324 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1325 | DISO_data.diso_state.pre_otg_state = DISO_ONLINE; | |
1326 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1327 | DISO_data.diso_state.cur_vdc_state = DISO_OFFLINE; | |
1328 | DISO_data.diso_state.cur_otg_state = DISO_ONLINE; | |
1329 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[1]); | |
1330 | } | |
1331 | #endif | |
1332 | break; | |
1333 | case AP_AUXADC_DISO_VUSB_CHANNEL: | |
1334 | trigger_flag = mt_auxadc_getCurrentTrigger(); | |
1335 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VUSB IRQ triggered, channel ==%d, flag ==%d\n", trigger_channel, trigger_flag); | |
1336 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1337 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1338 | if(trigger_flag == DISO_IRQ_FALLING) { | |
1339 | DISO_data.diso_state.pre_vusb_state = DISO_ONLINE; | |
1340 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1341 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1342 | DISO_data.diso_state.cur_vusb_state = DISO_OFFLINE; | |
1343 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1344 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1345 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[4]); | |
1346 | } else { | |
1347 | DISO_data.diso_state.pre_vusb_state = DISO_OFFLINE; | |
1348 | DISO_data.diso_state.pre_vdc_state = DISO_ONLINE; | |
1349 | DISO_data.diso_state.pre_otg_state = DISO_OFFLINE; | |
1350 | DISO_data.diso_state.cur_vusb_state = DISO_ONLINE; | |
1351 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1352 | DISO_data.diso_state.cur_otg_state = DISO_OFFLINE; | |
1353 | battery_xlog_printk(BAT_LOG_CRTI, " cur diso_state is %s!\n",DISO_state_s[6]); | |
1354 | } | |
1355 | ||
1356 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE, (~trigger_flag)&0x1); | |
1357 | break; | |
1358 | default: | |
1359 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1360 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1361 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO]VUSB auxadc IRQ triggered ERROR OR TEST\n"); | |
1362 | return IRQ_HANDLED; /* in error or unexecpt state just return */ | |
1363 | } | |
1364 | g_diso_state = *(int*)&DISO_data.diso_state; | |
1365 | return IRQ_WAKE_THREAD; | |
1366 | } | |
1367 | #endif | |
1368 | ||
1369 | #if defined(MTK_DISCRETE_SWITCH) && defined(MTK_DSC_USE_EINT) | |
1370 | void vdc_eint_handler() | |
1371 | { | |
1372 | battery_xlog_printk(BAT_LOG_CRTI, "[diso_eint] vdc eint irq triger\n"); | |
1373 | DISO_data.diso_state.cur_vdc_state = DISO_ONLINE; | |
1374 | mt_eint_mask(CUST_EINT_VDC_NUM); | |
1375 | do_chrdet_int_task(); | |
1376 | } | |
1377 | #endif | |
1378 | ||
1379 | static kal_uint32 diso_get_current_voltage(int Channel) | |
1380 | { | |
1381 | int ret = 0, data[4], i, ret_value = 0, ret_temp = 0, times = 5; | |
1382 | ||
1383 | if( IMM_IsAdcInitReady() == 0 ) { | |
1384 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO] AUXADC is not ready"); | |
1385 | return 0; | |
1386 | } | |
1387 | ||
1388 | i = times; | |
1389 | while (i--) | |
1390 | { | |
1391 | ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp); | |
1392 | if(ret_value == 0) { | |
1393 | ret += ret_temp; | |
1394 | } else { | |
1395 | times = times > 1 ? times - 1 : 1; | |
1396 | battery_xlog_printk(BAT_LOG_CRTI, "[diso_get_current_voltage] ret_value=%d, times=%d\n", | |
1397 | ret_value, times); | |
1398 | } | |
1399 | } | |
1400 | ||
1401 | ret = ret*1500/4096 ; | |
1402 | ret = ret/times; | |
1403 | ||
1404 | return ret; | |
1405 | } | |
1406 | ||
1407 | static void _get_diso_interrupt_state(void) | |
1408 | { | |
1409 | int vol = 0; | |
1410 | int diso_state =0; | |
1411 | int check_times = 30; | |
1412 | kal_bool vin_state = KAL_FALSE; | |
1413 | ||
1414 | #ifndef VIN_SEL_FLAG | |
1415 | mdelay(AUXADC_CHANNEL_DELAY_PERIOD); | |
1416 | #endif | |
1417 | ||
1418 | vol = diso_get_current_voltage(AP_AUXADC_DISO_VDC_CHANNEL); | |
1419 | vol =(R_DISO_DC_PULL_UP + R_DISO_DC_PULL_DOWN)*100*vol/(R_DISO_DC_PULL_DOWN)/100; | |
1420 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO] Current DC voltage mV = %d\n", vol); | |
1421 | ||
1422 | #ifdef VIN_SEL_FLAG | |
1423 | /* set gpio mode for kpoc issue as DWS has no default setting */ | |
1424 | mt_set_gpio_mode(vin_sel_gpio_number,0); // 0:GPIO mode | |
1425 | mt_set_gpio_dir(vin_sel_gpio_number,0); // 0: input, 1: output | |
1426 | ||
1427 | if (vol > VDC_MIN_VOLTAGE/1000 && vol < VDC_MAX_VOLTAGE/1000) { | |
1428 | /* make sure load switch already switch done */ | |
1429 | do{ | |
1430 | check_times--; | |
1431 | #ifdef VIN_SEL_FLAG_DEFAULT_LOW | |
1432 | vin_state = mt_get_gpio_in(vin_sel_gpio_number); | |
1433 | #else | |
1434 | vin_state = mt_get_gpio_in(vin_sel_gpio_number); | |
1435 | vin_state = (~vin_state) & 0x1; | |
1436 | #endif | |
1437 | if(!vin_state) | |
1438 | mdelay(5); | |
1439 | } while ((!vin_state) && check_times); | |
1440 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO] i==%d gpio_state= %d\n", | |
1441 | check_times, mt_get_gpio_in(vin_sel_gpio_number)); | |
1442 | ||
1443 | if (0 == check_times) | |
1444 | diso_state &= ~0x4; //SET DC bit as 0 | |
1445 | else | |
1446 | diso_state |= 0x4; //SET DC bit as 1 | |
1447 | } else { | |
1448 | diso_state &= ~0x4; //SET DC bit as 0 | |
1449 | } | |
1450 | #else | |
1451 | mdelay(SWITCH_RISING_TIMING + LOAD_SWITCH_TIMING_MARGIN); /* force delay for switching as no flag for check switching done */ | |
1452 | if (vol > VDC_MIN_VOLTAGE/1000 && vol < VDC_MAX_VOLTAGE/1000) | |
1453 | diso_state |= 0x4; //SET DC bit as 1 | |
1454 | else | |
1455 | diso_state &= ~0x4; //SET DC bit as 0 | |
1456 | #endif | |
1457 | ||
1458 | ||
1459 | vol = diso_get_current_voltage(AP_AUXADC_DISO_VUSB_CHANNEL); | |
1460 | vol =(R_DISO_VBUS_PULL_UP + R_DISO_VBUS_PULL_DOWN)*100*vol/(R_DISO_VBUS_PULL_DOWN)/100; | |
1461 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO] Current VBUS voltage mV = %d\n",vol); | |
1462 | ||
1463 | if (vol > VBUS_MIN_VOLTAGE/1000 && vol < VBUS_MAX_VOLTAGE/1000) { | |
1464 | if(!mt_usb_is_device()) { | |
1465 | diso_state |= 0x1; //SET OTG bit as 1 | |
1466 | diso_state &= ~0x2; //SET VBUS bit as 0 | |
1467 | } else { | |
1468 | diso_state &= ~0x1; //SET OTG bit as 0 | |
1469 | diso_state |= 0x2; //SET VBUS bit as 1; | |
1470 | } | |
1471 | ||
1472 | } else { | |
1473 | diso_state &= 0x4; //SET OTG and VBUS bit as 0 | |
1474 | } | |
1475 | battery_xlog_printk(BAT_LOG_CRTI, "[DISO] DISO_STATE==0x%x \n",diso_state); | |
1476 | g_diso_state = diso_state; | |
1477 | return; | |
1478 | } | |
1479 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
1480 | int _get_irq_direction(int pre_vol, int cur_vol) | |
1481 | { | |
1482 | int ret = -1; | |
1483 | ||
1484 | //threshold 1000mv | |
1485 | if((cur_vol - pre_vol) > 1000) | |
1486 | ret = DISO_IRQ_RISING; | |
1487 | else if((pre_vol - cur_vol) > 1000) | |
1488 | ret = DISO_IRQ_FALLING; | |
1489 | ||
1490 | return ret; | |
1491 | } | |
1492 | ||
1493 | static void _get_polling_state(void) | |
1494 | { | |
1495 | int vdc_vol = 0, vusb_vol = 0; | |
1496 | int vdc_vol_dir = -1; | |
1497 | int vusb_vol_dir = -1; | |
1498 | ||
1499 | DISO_polling_channel* VDC_Polling = &DISO_Polling.vdc_polling_measure; | |
1500 | DISO_polling_channel* VUSB_Polling = &DISO_Polling.vusb_polling_measure; | |
1501 | ||
1502 | vdc_vol = diso_get_current_voltage(AP_AUXADC_DISO_VDC_CHANNEL); | |
1503 | vdc_vol =(R_DISO_DC_PULL_UP + R_DISO_DC_PULL_DOWN)*100*vdc_vol/(R_DISO_DC_PULL_DOWN)/100; | |
1504 | ||
1505 | vusb_vol = diso_get_current_voltage(AP_AUXADC_DISO_VUSB_CHANNEL); | |
1506 | vusb_vol =(R_DISO_VBUS_PULL_UP + R_DISO_VBUS_PULL_DOWN)*100*vusb_vol/(R_DISO_VBUS_PULL_DOWN)/100; | |
1507 | ||
1508 | VDC_Polling->preVoltage = VDC_Polling->curVoltage; | |
1509 | VUSB_Polling->preVoltage = VUSB_Polling->curVoltage; | |
1510 | VDC_Polling->curVoltage = vdc_vol; | |
1511 | VUSB_Polling->curVoltage = vusb_vol; | |
1512 | ||
1513 | if (DISO_Polling.reset_polling) | |
1514 | { | |
1515 | DISO_Polling.reset_polling = KAL_FALSE; | |
1516 | VDC_Polling->preVoltage = vdc_vol; | |
1517 | VUSB_Polling->preVoltage = vusb_vol; | |
1518 | ||
1519 | if(vdc_vol > 1000) | |
1520 | vdc_vol_dir = DISO_IRQ_RISING; | |
1521 | else | |
1522 | vdc_vol_dir = DISO_IRQ_FALLING; | |
1523 | ||
1524 | if(vusb_vol > 1000) | |
1525 | vusb_vol_dir = DISO_IRQ_RISING; | |
1526 | else | |
1527 | vusb_vol_dir = DISO_IRQ_FALLING; | |
1528 | } | |
1529 | else | |
1530 | { | |
1531 | //get voltage direction | |
1532 | vdc_vol_dir = _get_irq_direction(VDC_Polling->preVoltage, VDC_Polling->curVoltage); | |
1533 | vusb_vol_dir = _get_irq_direction(VUSB_Polling->preVoltage, VUSB_Polling->curVoltage); | |
1534 | } | |
1535 | ||
1536 | if(VDC_Polling->notify_irq_en && | |
1537 | (vdc_vol_dir == VDC_Polling->notify_irq)) { | |
1538 | schedule_delayed_work(&diso_polling_work, 10*HZ/1000); //10ms | |
1539 | battery_xlog_printk(BAT_LOG_CRTI, "[%s] ready to trig VDC irq, irq: %d\n", | |
1540 | __func__,VDC_Polling->notify_irq); | |
1541 | } else if(VUSB_Polling->notify_irq_en && | |
1542 | (vusb_vol_dir == VUSB_Polling->notify_irq)) { | |
1543 | schedule_delayed_work(&diso_polling_work, 10*HZ/1000); | |
1544 | battery_xlog_printk(BAT_LOG_CRTI, "[%s] ready to trig VUSB irq, irq: %d\n", | |
1545 | __func__, VUSB_Polling->notify_irq); | |
1546 | } else if((vdc_vol == 0) && (vusb_vol == 0)) { | |
1547 | VDC_Polling->notify_irq_en = 0; | |
1548 | VUSB_Polling->notify_irq_en = 0; | |
1549 | } | |
1550 | ||
1551 | return; | |
1552 | } | |
1553 | ||
1554 | enum hrtimer_restart diso_kthread_hrtimer_func(struct hrtimer *timer) | |
1555 | { | |
1556 | diso_thread_timeout = KAL_TRUE; | |
1557 | wake_up(&diso_polling_thread_wq); | |
1558 | ||
1559 | return HRTIMER_NORESTART; | |
1560 | } | |
1561 | ||
1562 | int diso_thread_kthread(void *x) | |
1563 | { | |
1564 | /* Run on a process content */ | |
1565 | while (1) { | |
1566 | wait_event(diso_polling_thread_wq, (diso_thread_timeout == KAL_TRUE)); | |
1567 | ||
1568 | diso_thread_timeout = KAL_FALSE; | |
1569 | ||
1570 | mutex_lock(&diso_polling_mutex); | |
1571 | ||
1572 | _get_polling_state(); | |
1573 | ||
1574 | if (DISO_Polling.vdc_polling_measure.notify_irq_en || | |
1575 | DISO_Polling.vusb_polling_measure.notify_irq_en) | |
1576 | hrtimer_start(&diso_kthread_timer,ktime_set(0, MSEC_TO_NSEC(SW_POLLING_PERIOD)),HRTIMER_MODE_REL); | |
1577 | else | |
1578 | hrtimer_cancel(&diso_kthread_timer); | |
1579 | ||
1580 | mutex_unlock(&diso_polling_mutex); | |
1581 | } | |
1582 | ||
1583 | return 0; | |
1584 | } | |
1585 | #endif | |
1586 | #endif | |
1587 | ||
1588 | ||
1589 | static kal_uint32 charging_get_error_state(void) | |
1590 | { | |
1591 | return charging_error; | |
1592 | } | |
1593 | ||
1594 | static kal_uint32 charging_set_error_state(void *data) | |
1595 | { | |
1596 | kal_uint32 status = STATUS_OK; | |
1597 | charging_error = *(kal_uint32*)(data); | |
1598 | ||
1599 | return status; | |
1600 | } | |
1601 | ||
1602 | static kal_uint32 charging_diso_init(void *data) | |
1603 | { | |
1604 | kal_uint32 status = STATUS_OK; | |
1605 | ||
1606 | #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT) | |
1607 | DISO_ChargerStruct *pDISO_data = (DISO_ChargerStruct *)data; | |
1608 | ||
1609 | /* Initialization DISO Struct */ | |
1610 | pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE; | |
1611 | pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE; | |
1612 | pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE; | |
1613 | ||
1614 | pDISO_data->diso_state.pre_otg_state = DISO_OFFLINE; | |
1615 | pDISO_data->diso_state.pre_vusb_state = DISO_OFFLINE; | |
1616 | pDISO_data->diso_state.pre_vdc_state = DISO_OFFLINE; | |
1617 | ||
1618 | pDISO_data->chr_get_diso_state = KAL_FALSE; | |
1619 | pDISO_data->hv_voltage = VBUS_MAX_VOLTAGE; | |
1620 | ||
1621 | #if !defined(MTK_AUXADC_IRQ_SUPPORT) | |
1622 | hrtimer_init(&diso_kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | |
1623 | diso_kthread_timer.function = diso_kthread_hrtimer_func; | |
1624 | INIT_DELAYED_WORK(&diso_polling_work, diso_polling_handler); | |
1625 | ||
1626 | kthread_run(diso_thread_kthread, NULL, "diso_thread_kthread"); | |
1627 | battery_xlog_printk(BAT_LOG_CRTI, "[%s] done\n", __func__); | |
1628 | #else | |
1629 | struct device_node *node; | |
1630 | int ret; | |
1631 | ||
1632 | //Initial AuxADC IRQ | |
1633 | DISO_data.irq_line_number = LOWBATTERY_IRQ_ID; | |
1634 | DISO_IRQ.vdc_measure_channel.number = AP_AUXADC_DISO_VDC_CHANNEL; | |
1635 | DISO_IRQ.vusb_measure_channel.number = AP_AUXADC_DISO_VUSB_CHANNEL; | |
1636 | DISO_IRQ.vdc_measure_channel.period = AUXADC_CHANNEL_DELAY_PERIOD; | |
1637 | DISO_IRQ.vusb_measure_channel.period = AUXADC_CHANNEL_DELAY_PERIOD; | |
1638 | DISO_IRQ.vdc_measure_channel.debounce = AUXADC_CHANNEL_DEBOUNCE; | |
1639 | DISO_IRQ.vusb_measure_channel.debounce = AUXADC_CHANNEL_DEBOUNCE; | |
1640 | ||
1641 | /* use default threshold voltage, if use high voltage,maybe refine*/ | |
1642 | DISO_IRQ.vusb_measure_channel.falling_threshold = VBUS_MIN_VOLTAGE/1000; | |
1643 | DISO_IRQ.vdc_measure_channel.falling_threshold = VDC_MIN_VOLTAGE/1000; | |
1644 | DISO_IRQ.vusb_measure_channel.rising_threshold = VBUS_MIN_VOLTAGE/1000; | |
1645 | DISO_IRQ.vdc_measure_channel.rising_threshold = VDC_MIN_VOLTAGE/1000; | |
1646 | ||
1647 | mt_irq_set_sens(pDISO_data->irq_line_number, MT_EDGE_SENSITIVE); | |
1648 | mt_irq_set_polarity(pDISO_data->irq_line_number, MT_POLARITY_LOW); | |
1649 | ||
1650 | ret = request_threaded_irq(pDISO_data->irq_line_number, diso_auxadc_irq_handler, \ | |
1651 | pDISO_data->irq_callback_func, IRQF_ONESHOT , "DISO_ADC_IRQ", NULL); | |
1652 | ||
1653 | if (ret) { | |
1654 | battery_xlog_printk(BAT_LOG_CRTI, "[diso_adc]: request_irq failed.\n"); | |
1655 | } else { | |
1656 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1657 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1658 | battery_xlog_printk(BAT_LOG_CRTI, "[diso_adc]: diso_init success.\n"); | |
1659 | } | |
1660 | #endif | |
1661 | ||
1662 | #if defined(MTK_DISCRETE_SWITCH) && defined(MTK_DSC_USE_EINT) | |
1663 | battery_xlog_printk(BAT_LOG_CRTI, "[diso_eint]vdc eint irq registitation\n"); | |
1664 | mt_eint_set_hw_debounce(CUST_EINT_VDC_NUM, CUST_EINT_VDC_DEBOUNCE_CN); | |
1665 | mt_eint_registration(CUST_EINT_VDC_NUM, CUST_EINTF_TRIGGER_LOW, vdc_eint_handler, 0); | |
1666 | mt_eint_mask(CUST_EINT_VDC_NUM); | |
1667 | #endif | |
1668 | #endif | |
1669 | ||
1670 | return status; | |
1671 | } | |
1672 | ||
1673 | static kal_uint32 charging_get_diso_state(void *data) | |
1674 | { | |
1675 | kal_uint32 status = STATUS_OK; | |
1676 | ||
1677 | #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT) | |
1678 | int diso_state = 0x0; | |
1679 | DISO_ChargerStruct *pDISO_data = (DISO_ChargerStruct *)data; | |
1680 | ||
1681 | _get_diso_interrupt_state(); | |
1682 | diso_state = g_diso_state; | |
1683 | battery_xlog_printk(BAT_LOG_CRTI, "[do_chrdet_int_task] current diso state is %s!\n", DISO_state_s[diso_state]); | |
1684 | if(((diso_state >> 1) & 0x3) != 0x0) | |
1685 | { | |
1686 | switch (diso_state){ | |
1687 | case USB_ONLY: | |
1688 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1689 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1690 | #ifdef MTK_DISCRETE_SWITCH | |
1691 | #ifdef MTK_DSC_USE_EINT | |
1692 | mt_eint_unmask(CUST_EINT_VDC_NUM); | |
1693 | #else | |
1694 | set_vdc_auxadc_irq(DISO_IRQ_ENABLE, 1); | |
1695 | #endif | |
1696 | #endif | |
1697 | pDISO_data->diso_state.cur_vusb_state = DISO_ONLINE; | |
1698 | pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE; | |
1699 | pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE; | |
1700 | break; | |
1701 | case DC_ONLY: | |
1702 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1703 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1704 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE, DISO_IRQ_RISING); | |
1705 | pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE; | |
1706 | pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE; | |
1707 | pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE; | |
1708 | break; | |
1709 | case DC_WITH_USB: | |
1710 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1711 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1712 | set_vusb_auxadc_irq(DISO_IRQ_ENABLE,DISO_IRQ_FALLING); | |
1713 | pDISO_data->diso_state.cur_vusb_state = DISO_ONLINE; | |
1714 | pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE; | |
1715 | pDISO_data->diso_state.cur_otg_state = DISO_OFFLINE; | |
1716 | break; | |
1717 | case DC_WITH_OTG: | |
1718 | set_vdc_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1719 | set_vusb_auxadc_irq(DISO_IRQ_DISABLE, 0); | |
1720 | pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE; | |
1721 | pDISO_data->diso_state.cur_vdc_state = DISO_ONLINE; | |
1722 | pDISO_data->diso_state.cur_otg_state = DISO_ONLINE; | |
1723 | break; | |
1724 | default: // OTG only also can trigger vcdt IRQ | |
1725 | pDISO_data->diso_state.cur_vusb_state = DISO_OFFLINE; | |
1726 | pDISO_data->diso_state.cur_vdc_state = DISO_OFFLINE; | |
1727 | pDISO_data->diso_state.cur_otg_state = DISO_ONLINE; | |
1728 | battery_xlog_printk(BAT_LOG_CRTI, " switch load vcdt irq triggerd by OTG Boost!\n"); | |
1729 | break; // OTG plugin no need battery sync action | |
1730 | } | |
1731 | } | |
1732 | ||
1733 | if (DISO_ONLINE == pDISO_data->diso_state.cur_vdc_state) | |
1734 | pDISO_data->hv_voltage = VDC_MAX_VOLTAGE; | |
1735 | else | |
1736 | pDISO_data->hv_voltage = VBUS_MAX_VOLTAGE; | |
1737 | #endif | |
1738 | ||
1739 | return status; | |
1740 | } | |
1741 | ||
1742 | ||
1743 | static kal_uint32 (*charging_func[CHARGING_CMD_NUMBER])(void *data)= | |
1744 | { | |
1745 | charging_hw_init | |
1746 | ,charging_dump_register | |
1747 | ,charging_enable | |
1748 | ,charging_set_cv_voltage | |
1749 | ,charging_get_current | |
1750 | ,charging_set_current | |
1751 | ,charging_set_input_current // not support, empty function | |
1752 | ,charging_get_charging_status // not support, empty function | |
1753 | ,charging_reset_watch_dog_timer | |
1754 | ,charging_set_hv_threshold | |
1755 | ,charging_get_hv_status | |
1756 | ,charging_get_battery_status | |
1757 | ,charging_get_charger_det_status | |
1758 | ,charging_get_charger_type | |
1759 | ,charging_get_is_pcm_timer_trigger | |
1760 | ,charging_set_platform_reset | |
1761 | ,charging_get_platfrom_boot_mode | |
1762 | ,charging_set_power_off | |
1763 | ,charging_get_power_srouce | |
1764 | ,charging_get_csdac_full_flag | |
1765 | ,charging_set_ta_current_pattern | |
1766 | ,charging_set_error_state | |
1767 | ,charging_diso_init | |
1768 | ,charging_get_diso_state | |
1769 | }; | |
1770 | ||
1771 | ||
1772 | /* | |
1773 | * FUNCTION | |
1774 | * Internal_chr_control_handler | |
1775 | * | |
1776 | * DESCRIPTION | |
1777 | * This function is called to set the charger hw | |
1778 | * | |
1779 | * CALLS | |
1780 | * | |
1781 | * PARAMETERS | |
1782 | * None | |
1783 | * | |
1784 | * RETURNS | |
1785 | * | |
1786 | * | |
1787 | * GLOBALS AFFECTED | |
1788 | * None | |
1789 | */ | |
1790 | kal_int32 chr_control_interface(CHARGING_CTRL_CMD cmd, void *data) | |
1791 | { | |
1792 | kal_int32 status; | |
1793 | if(cmd < CHARGING_CMD_NUMBER) | |
1794 | status = charging_func[cmd](data); | |
1795 | else | |
1796 | return STATUS_UNSUPPORTED; | |
1797 | ||
1798 | return status; | |
1799 | } | |
1800 | ||
1801 |