blob: 5568eb48c45a6d2e2d7064395c6c81def88fbfea [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/*
2 * Driver for the TI zx234502 battery charger.
3 *
4 * Author: Mark A. Greer <mgreer@animalcreek.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/interrupt.h>
13#include <linux/delay.h>
14#include <linux/of_irq.h>
15#include <linux/of_device.h>
16#include <linux/pm_runtime.h>
17#include <linux/power_supply.h>
18#include <linux/gpio.h>
19#include <linux/i2c.h>
20#include <linux/irq.h>
21#include <linux/kthread.h>
22//#include <linux/mutex.h>
23#include <linux/semaphore.h>
24
25#include <linux/power/aw3215_charger.h>
26#include <linux/mfd/zx234290.h>
27
28#include <mach/gpio.h>
29#include <mach/pcu.h>
30#include <mach/zx29_usb.h>
31#include <linux/workqueue.h>
32
33#include <linux/slab.h>
34#include <linux/debugfs.h>
35#include <asm/uaccess.h>
36#include <linux/wakelock.h>
37
38#define CHG_DEBUG
39#ifdef CHG_DEBUG
40#define GIC_DIST_ENABLE_SET 0x100
41#define GIC_DIST_PENDING_SET 0x200
42extern void __iomem *base_testtt;
43#endif
44
45static volatile int s_chg_chin_cnt = 0;
46static volatile int s_chg_chstate_cnt = 0;
47
48
49#define USB_IN GPIO_LOW
50#define USB_OUT GPIO_HIGH
51#define CHG_START GPIO_LOW
52#define CHG_STOP GPIO_HIGH
53#ifdef _USE_V3PHONE_TYPE_XRSD_
54#define CHG_EN_TYPE GPIO_HIGH
55#define CHG_DISEN_TYPE GPIO_LOW
56#else
57#define CHG_EN_TYPE GPIO_LOW
58#define CHG_DISEN_TYPE GPIO_HIGH
59#endif
60
61//*when the bat voltage <3.2V usb will not enum ,then the sys fall in lowpower*/
62#define USB_ENUM_MIN 3400
63
64/*
65 * The FAULT register is latched by the zx234502 (except for NTC_FAULT)
66 * so the first read after a fault returns the latched value and subsequent
67 * reads return the current value. In order to return the fault status
68 * to the user, have the interrupt handler save the reg's value and retrieve
69 * it in the appropriate health/status routine. Each routine has its own
70 * flag indicating whether it should use the value stored by the last run
71 * of the interrupt handler or do an actual reg read. That way each routine
72 * can report back whatever fault may have occured.
73 */
74 enum chg_stop_reason{
75 CHG_STOP_REASON_NO = 0,
76 CHG_STOP_REASON_TEMP= 1,
77 CHG_STOP_REASON_FULL = 2,
78 CHG_STOP_DEFALT= 0xff
79};
80struct aw3215_dev_info {
81 struct device *dev;
82 struct power_supply charger;
83 struct power_supply battery;
84
85 kernel_ulong_t model;
86 unsigned int chgin_irq;
87 unsigned int chgstate_irq;
88 //struct task_struct *chgin_irq_thread;
89 struct task_struct *chgstate_irq_thread;
90
91 u8 watchdog;
92
93 struct aw3215_platform_data *pdata;
94 unsigned int chgin_type;
95 unsigned int chgstate_type;
96 bool chg_en;
97 unsigned int chg_state;
98 //struct semaphore chgin_sem;
99 struct semaphore chgstate_sem;
100 enum chg_stop_reason stopchg_flag;
101 struct timer_list changed_timer;
102 struct wake_lock wlock_chgfull;
103
104};
105
106struct aw3215_dev_info *g_bdi = NULL;
107
108/* Charger power supply property routines */
109
110static int aw3215_charger_get_charge_type(struct aw3215_dev_info *bdi,union power_supply_propval *val)
111{
112 val->intval = bdi->charger.type;
113 return 0;
114}
115
116static int aw3215_charger_get_status(struct aw3215_dev_info *bdi,union power_supply_propval *val)
117{
118#if 1
119 val->intval = bdi->chg_state;
120#else
121 if(false==bdi->chg_en){
122 val->intval=POWER_SUPPLY_STATUS_NOT_CHARGING;/*diaable chg*/
123 return 0;
124 }
125 if (USB_IN==bdi->chgin_type) {
126 if(CHG_STOP==bdi->chgstate_type)
127 val->intval= POWER_SUPPLY_STATUS_FULL;
128 else if (CHG_START==bdi->chgstate_type)
129 val->intval= POWER_SUPPLY_STATUS_CHARGING;
130 else
131 val->intval=POWER_SUPPLY_STATUS_NOT_CHARGING;/*diaable chg*/
132 } else {
133 val->intval=POWER_SUPPLY_STATUS_DISCHARGING;/*usb not insert*/
134 }
135#endif
136 return 0;
137}
138
139static int aw3215_charger_get_health(struct aw3215_dev_info *bdi,union power_supply_propval *val)
140{
141 val->intval = POWER_SUPPLY_HEALTH_GOOD;
142
143 return 0;
144}
145
146int aw3215_charger_get_online(struct aw3215_dev_info *bdi,union power_supply_propval *val)
147{
148 if (USB_IN==bdi->chgin_type) {
149 val->intval= 1;
150 } else {
151 val->intval=0;/*usb not insert*/
152 }
153
154 return 0;
155}EXPORT_SYMBOL (aw3215_charger_get_online);
156
157
158static int aw3215_charger_get_charger_enabled(struct aw3215_dev_info *bdi,union power_supply_propval *val)
159{
160 val->intval = bdi->chg_en;
161
162 return 0;
163}
164static int aw3215_charger_get_voltage_max(struct aw3215_dev_info *bdi,union power_supply_propval *val)
165{
166 val->intval = 4200;
167
168 return 0;
169}
170
171static int aw3215_charger_set_voltage(struct aw3215_dev_info *bdi,const union power_supply_propval *val)
172{
173 return 0;
174}
175static int aw3215_charger_set_charger_config(struct aw3215_dev_info *bdi,const union power_supply_propval *val)
176{
177 int ret = 0;
178 int gpio_state = 0;
179
180 if (val->intval==1) {
181 if (bdi->chg_en)
182 return 0;
183 gpio_state = CHG_EN_TYPE ;/*gpio low en chg*/
184 printk("mmi start chg\n");
185 } else {
186 if (!bdi->chg_en)
187 return 0;
188 gpio_state = CHG_DISEN_TYPE ;/*gpio high stop chg*/
189 printk("mmi stop chg\n");
190 }
191
192 disable_irq(bdi->chgstate_irq);
193
194 if (gpio_state == CHG_EN_TYPE) {
195 bdi->chg_en = true; /*(~gpio_state)*/
196 bdi->chgstate_type = CHG_START;
197 bdi->stopchg_flag = CHG_STOP_REASON_NO;
198 gpio_set_value(bdi->pdata->gpio_chgen, gpio_state);
199
200 if (bdi->chgin_type == USB_IN) {
201 bdi->chg_state = POWER_SUPPLY_STATUS_CHARGING;
202 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_HIGH);
203 /* start charging in 5.3ms after enable */
204 if (gpio_get_value(bdi->pdata->gpio_chgstate))
205 mdelay(40);
206 if (gpio_get_value(bdi->pdata->gpio_chgstate)){
207 printk(KERN_INFO "chg still not chargin\n"); /* should not go here */
208 bdi->chg_state = POWER_SUPPLY_STATUS_FULL;
209 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_LOW);
210 }
211
212 }
213 } else {
214 bdi->chg_en = false;
215 bdi->chgstate_type = CHG_STOP;
216 bdi->stopchg_flag = CHG_STOP_REASON_TEMP;
217 if (2==val->intval){/*chg full stop*/
218 bdi->stopchg_flag = CHG_STOP_REASON_FULL;
219 bdi->chg_state = POWER_SUPPLY_STATUS_FULL;
220 printk("mmi full stop chg\n");
221
222 }
223 else if (bdi->chgin_type == USB_IN)
224 bdi->chg_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
225
226 gpio_set_value(bdi->pdata->gpio_chgen, gpio_state);
227 /* charger state changes from 0 to 1 in 0.12ms */
228 if (!gpio_get_value(bdi->pdata->gpio_chgstate))
229 udelay(500);
230
231 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_LOW);
232
233 }
234
235 enable_irq(bdi->chgstate_irq);
236#ifdef CHG_DEBUG
237 printk("irq1 chg_in= %d,chg_state_cnt= %d\n",s_chg_chstate_cnt,s_chg_chin_cnt);
238 printk("chg int enable reg1 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_ENABLE_SET+0x4));
239 printk("chg int enable reg2 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_ENABLE_SET+0x8));
240 printk("chg int pending reg1 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_PENDING_SET+0x4));
241 printk("chg int pending reg2 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_PENDING_SET+0x8));
242 printk("irq2 chg_in= %d,chg_state_cnt= %d\n",s_chg_chstate_cnt,s_chg_chin_cnt);
243#endif
244
245 power_supply_changed(&bdi->charger);
246
247 return ret;
248}
249
250
251static int aw3215_charger_get_property(struct power_supply *psy,enum power_supply_property psp, union power_supply_propval *val)
252{
253 struct aw3215_dev_info *bdi = container_of(psy, struct aw3215_dev_info, charger);
254 int ret;
255
256 //dev_dbg(bdi->dev, "prop: %d\n", psp);
257
258 //pm_runtime_get_sync(bdi->dev);
259
260 switch (psp) {
261 case POWER_SUPPLY_PROP_PC1_AC2:
262 ret = aw3215_charger_get_charge_type(bdi, val);
263 break;
264
265 case POWER_SUPPLY_PROP_STATUS:
266 ret = aw3215_charger_get_status(bdi, val);
267 break;
268 case POWER_SUPPLY_PROP_HEALTH:
269 ret = aw3215_charger_get_health(bdi, val);
270 break;
271 case POWER_SUPPLY_PROP_ONLINE:
272 ret = aw3215_charger_get_online(bdi, val);
273 break;
274
275 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
276 ret = aw3215_charger_get_voltage_max(bdi, val);
277 break;
278
279 case POWER_SUPPLY_PROP_CHARGE_ENABLED:
280 ret = aw3215_charger_get_charger_enabled(bdi, val);
281 break;
282 default:
283 ret = -ENODATA;
284 }
285
286 //pm_runtime_put_sync(bdi->dev);
287 return ret;
288}
289
290static int aw3215_charger_set_property(struct power_supply *psy,enum power_supply_property psp,
291 const union power_supply_propval *val)
292{
293 struct aw3215_dev_info *bdi =
294 container_of(psy, struct aw3215_dev_info, charger);
295 int ret;
296
297 //dev_dbg(bdi->dev, "prop: %d\n", psp);
298
299 //pm_runtime_get_sync(bdi->dev);
300
301 switch (psp) {
302#if 0
303 case POWER_SUPPLY_PROP_CURRENT_NOW:
304 ret = zx234502_charger_set_current(bdi, val);
305 break;
306#endif
307 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
308 ret = aw3215_charger_set_voltage(bdi, val);
309 break;
310
311 case POWER_SUPPLY_PROP_CHARGE_ENABLED:
312 ret = aw3215_charger_set_charger_config(bdi, val);
313 break;
314 default:
315 ret = -EINVAL;
316 }
317
318 //pm_runtime_put_sync(bdi->dev);
319 return ret;
320}
321
322static int aw3215_charger_property_is_writeable(struct power_supply *psy,enum power_supply_property psp)
323{
324 int ret;
325
326 switch (psp)
327 {
328 //case POWER_SUPPLY_PROP_CURRENT_NOW:
329 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
330 case POWER_SUPPLY_PROP_CHARGE_ENABLED:
331 ret = 1;
332 break;
333 default:
334 ret = 0;
335 break;
336 }
337
338 return ret;
339}
340
341static enum power_supply_property aw3215_charger_properties[] = {
342 POWER_SUPPLY_PROP_PC1_AC2,
343 POWER_SUPPLY_PROP_STATUS,
344 POWER_SUPPLY_PROP_HEALTH,
345 POWER_SUPPLY_PROP_ONLINE,
346 //POWER_SUPPLY_PROP_CURRENT_NOW,
347 //POWER_SUPPLY_PROP_CURRENT_MAX,
348 //POWER_SUPPLY_PROP_VOLTAGE_NOW,
349 POWER_SUPPLY_PROP_VOLTAGE_MAX,
350 POWER_SUPPLY_PROP_CHARGE_ENABLED,
351};
352
353static char *aw3215_charger_supplied_to[] = {
354 "main-battery",
355};
356
357static void aw3215_charger_init(struct power_supply *charger)
358{
359 charger->name = "charger";
360 charger->type = POWER_SUPPLY_PCAC_UNKNOWN;
361 charger->properties = aw3215_charger_properties;
362 charger->num_properties = ARRAY_SIZE(aw3215_charger_properties);
363 charger->supplied_to = aw3215_charger_supplied_to;
364 //charger->num_supplies = ARRAY_SIZE(aw3215_charger_supplied_to);
365 charger->get_property = aw3215_charger_get_property;
366 charger->set_property = aw3215_charger_set_property;
367 charger->property_is_writeable = aw3215_charger_property_is_writeable;
368}
369
370/* Battery power supply property routines */
371
372static int aw3215_battery_get_health(struct aw3215_dev_info *bdi,union power_supply_propval *val)
373{
374 val->intval = POWER_SUPPLY_HEALTH_GOOD;
375
376 return 0;
377}
378
379static int aw3215_battery_get_online(struct aw3215_dev_info *bdi,union power_supply_propval *val)
380{
381 val->intval = 1;/*bat on*/
382
383 return 0;
384}
385
386static int aw3215_battery_set_online(struct aw3215_dev_info *bdi,const union power_supply_propval *val)
387{
388 return 0;
389}
390
391
392static int aw3215_battery_get_property(struct power_supply *psy,enum power_supply_property psp,
393 union power_supply_propval *val)
394{
395 struct aw3215_dev_info *bdi =
396 container_of(psy, struct aw3215_dev_info, battery);
397 int ret;
398
399 //dev_dbg(bdi->dev, "prop: %d\n", psp);
400
401 //pm_runtime_get_sync(bdi->dev);
402
403 switch (psp) {
404
405 case POWER_SUPPLY_PROP_HEALTH:
406 ret = aw3215_battery_get_health(bdi, val);
407 break;
408 case POWER_SUPPLY_PROP_ONLINE:
409 ret = aw3215_battery_get_online(bdi, val);
410 break;
411
412 case POWER_SUPPLY_PROP_TEMP:
413 val->intval = get_adc2_voltage();
414 ret = 0;
415 break;
416
417 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
418 //#ifdef CONFIG_ZX234290_ADC
419 val->intval = get_adc1_voltage() - 15;
420 ret = 0;
421 break;
422 default:
423 ret = -ENODATA;
424 }
425
426 //pm_runtime_put_sync(bdi->dev);
427 return ret;
428}
429
430static int aw3215_battery_set_property(struct power_supply *psy,enum power_supply_property psp,
431 const union power_supply_propval *val)
432{
433 struct aw3215_dev_info *bdi =
434 container_of(psy, struct aw3215_dev_info, battery);
435 int ret;
436
437 //dev_dbg(bdi->dev, "prop: %d\n", psp);
438
439 //pm_runtime_put_sync(bdi->dev);
440
441 switch (psp) {
442 case POWER_SUPPLY_PROP_ONLINE:
443 ret = aw3215_battery_set_online(bdi, val);
444 break;
445 default:
446 ret = -EINVAL;
447 }
448
449 //pm_runtime_put_sync(bdi->dev);
450 return ret;
451}
452
453static int aw3215_battery_property_is_writeable(struct power_supply *psy,enum power_supply_property psp)
454{
455 int ret;
456
457 switch (psp) {
458 case POWER_SUPPLY_PROP_ONLINE:
459 ret = 1;
460 break;
461 default:
462 ret = 0;
463 }
464
465 return ret;
466}
467
468static enum power_supply_property aw3215_battery_properties[] = {
469 POWER_SUPPLY_PROP_HEALTH,
470 POWER_SUPPLY_PROP_ONLINE,
471 POWER_SUPPLY_PROP_TEMP,
472 POWER_SUPPLY_PROP_VOLTAGE_NOW,
473 //POWER_SUPPLY_PROP_CAPACITY,
474};
475
476static void aw3215_battery_init(struct power_supply *battery)
477{
478 battery->name = "battery";
479 battery->type = POWER_SUPPLY_PCAC_UNKNOWN;
480 battery->properties = aw3215_battery_properties;
481 battery->num_properties = ARRAY_SIZE(aw3215_battery_properties);
482 battery->get_property = aw3215_battery_get_property;
483 battery->set_property = aw3215_battery_set_property;
484 battery->property_is_writeable = aw3215_battery_property_is_writeable;
485}
486
487#if 1
488static irqreturn_t aw3215_charger_in_irq_primary_handler(int irq, struct aw3215_dev_info * bdi)
489{
490 s_chg_chin_cnt++;
491 disable_irq_nosync(irq);
492 //pcu_int_clear(irq);
493 pcu_clr_irq_pending(irq);
494 up(&bdi->chgstate_sem);
495 //up(&bdi->chgin_sem);
496 return IRQ_HANDLED;
497}
498static irqreturn_t aw3215_charger_state_irq_primary_handler(int irq, struct aw3215_dev_info * bdi)
499{
500 s_chg_chstate_cnt++;
501 disable_irq_nosync(irq);
502 //pcu_int_clear(irq);
503 pcu_clr_irq_pending(irq);
504 up(&bdi->chgstate_sem);
505
506 return IRQ_HANDLED;
507}
508
509#endif
510#if 1
511static irqreturn_t aw3215_chg_irq_handler_thread(void *data)
512{
513 struct aw3215_dev_info *bdi = data;
514 struct aw3215_platform_data *pdata = bdi->pdata;
515 //unsigned int state_rcd = bdi->chg_state;
516 int g_gpio_state=CHG_STOP;
517 int g_gpio_in =USB_IN;
518 bool chg_changed_flag = false;
519
520 struct sched_param param = { .sched_priority = 2 };
521 param.sched_priority= 31;
522 sched_setscheduler(current, SCHED_FIFO, &param);
523
524 while(1)
525 {
526 down(&bdi->chgstate_sem);
527 g_gpio_in = gpio_get_value(pdata->gpio_chgin);
528 g_gpio_state = gpio_get_value(pdata->gpio_chgstate);
529 if(bdi->chgin_type!=g_gpio_in){
530
531 bdi->chgin_type = g_gpio_in;
532 if(g_gpio_in == USB_IN){
533 irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_HIGH);
534 printk("chg usb in\n");
535 dwc_otg_chg_inform(0);/*usb in*/
536 if(CHG_START == g_gpio_state){
537 bdi->chg_state = POWER_SUPPLY_STATUS_CHARGING;
538 printk("chg charging\n");
539 }
540 else if(bdi->stopchg_flag == CHG_STOP_REASON_TEMP){
541 bdi->chg_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
542 printk("chg temp abnormal\n");
543 }
544 else{
545 bdi->chg_state = POWER_SUPPLY_STATUS_FULL;
546 printk("chg full\n");
547 }
548 }
549 else{/*usb out*/
550 bdi->chg_state = POWER_SUPPLY_STATUS_DISCHARGING;
551 printk("chg usb out\n");
552 irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_LOW);
553 dwc_otg_chg_inform(1);/*usb out*/
554
555 }
556 chg_changed_flag = true;
557 s_chg_chin_cnt--;
558 enable_irq(bdi->chgin_irq);
559 }
560 else if(bdi->chgstate_type!=g_gpio_state){
561
562 bdi->chgstate_type=g_gpio_state;
563 if (CHG_START == g_gpio_state){
564 printk("chg state charging\n");
565 bdi->chg_state=POWER_SUPPLY_STATUS_CHARGING;
566 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_HIGH);
567 chg_changed_flag = true;
568 }
569 else {
570 if( bdi->chgin_type == USB_IN){
571 printk("chg state maybe full\n");
572 bdi->chg_state=POWER_SUPPLY_STATUS_FULL;
573 wake_lock(&(bdi->wlock_chgfull));
574 mod_timer(&bdi->changed_timer, jiffies + msecs_to_jiffies(500));
575 }
576 else{
577 printk("chg state dischargeing\n");
578 bdi->chg_state=POWER_SUPPLY_STATUS_DISCHARGING;
579 chg_changed_flag = true;
580 }
581 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_LOW);
582 }
583
584 s_chg_chstate_cnt--;
585 enable_irq(bdi->chgstate_irq);
586 }
587 else{
588 printk("chg int maybe handled,in=%d,state = %d\n",s_chg_chin_cnt,s_chg_chstate_cnt);
589 if(s_chg_chstate_cnt){
590 s_chg_chstate_cnt--;
591 enable_irq(bdi->chgstate_irq);
592 }
593 if(s_chg_chin_cnt){
594 s_chg_chin_cnt--;
595 enable_irq(bdi->chgin_irq);
596 }
597 }
598 if(true == chg_changed_flag){
599 power_supply_changed(&bdi->charger);
600 power_supply_changed(&bdi->battery);
601 chg_changed_flag = false;
602 }
603 }
604
605 return 0;
606}
607#endif
608#if 0
609static irqreturn_t aw3215_chgin_irq_handler_thread(void *data)
610{
611 struct aw3215_dev_info *bdi = data;
612 struct aw3215_platform_data *pdata = bdi->pdata;
613 int g_gpio_in =0;
614 struct sched_param param = { .sched_priority = 2 };
615
616 param.sched_priority= 31;
617 sched_setscheduler(current, SCHED_FIFO, &param);
618
619 while(1)
620 {
621 down(&bdi->chgin_sem);
622
623 g_gpio_in = gpio_get_value(pdata->gpio_chgin);
624
625 /*charging status*/
626 if (g_gpio_in == USB_IN) {
627 if (bdi->chgin_type == USB_IN) {
628 printk(KERN_INFO"chg usb in err\n");
629 }
630 else if (bdi->stopchg_flag == CHG_STOP_REASON_TEMP){
631 bdi->chgin_type = USB_IN;
632 printk(KERN_INFO"chg usb in temp err\n");
633 bdi->chg_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
634 dwc_otg_chg_inform(0);/*usb in*/
635 }
636 else{
637 bdi->chgin_type = USB_IN;
638
639 disable_irq(bdi->chgstate_irq);
640 //gpio_set_value(pdata->gpio_chgen, CHG_EN_TYPE);
641 //bdi->chg_en = true;
642 //bdi->chgstate_type = CHG_START;
643
644 /* start charging in 5.3ms after enable */
645 if (gpio_get_value(pdata->gpio_chgstate))
646 mdelay(7);
647 if (bdi->chgstate_type == gpio_get_value(pdata->gpio_chgstate))
648 printk(KERN_INFO "chg still not chargin"); /* should not go here */
649 bdi->chgstate_type = gpio_get_value(pdata->gpio_chgstate);
650 bdi->chg_state = POWER_SUPPLY_STATUS_CHARGING;
651
652 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_HIGH);
653
654 enable_irq(bdi->chgstate_irq);
655
656 printk(KERN_INFO"chg usb in\n");
657 dwc_otg_chg_inform(0);/*usb in*/
658
659 //irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_HIGH);
660 }
661
662 irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_HIGH);
663 } else {
664 bdi->chg_state = POWER_SUPPLY_STATUS_DISCHARGING;
665 if (bdi->chgin_type == USB_OUT) {
666 printk(KERN_INFO"chg usb out err\n");
667 } else {
668 bdi->chgin_type = USB_OUT;
669 //SINT32 Usb_plug = DISCONNECTED_FROM_HOST;
670 printk(KERN_INFO"chg usb out\n");
671
672 dwc_otg_chg_inform(1);/*usb out*/
673
674 //irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_LOW);
675 }
676 irq_set_irq_type(bdi->chgin_irq, IRQ_TYPE_LEVEL_LOW);
677 }
678
679 power_supply_changed(&bdi->charger);
680 power_supply_changed(&bdi->battery);
681 enable_irq(bdi->chgin_irq);
682
683 }
684 return 0;
685}
686
687static irqreturn_t aw3215_chgstate_irq_handler_thread(void *data)
688{
689 struct aw3215_dev_info *bdi = data;
690 struct aw3215_platform_data *pdata = bdi->pdata;
691 //unsigned int state_rcd = bdi->chg_state;
692 int g_gpio_state=CHG_STOP;
693 uint adc1_v= 0;
694 struct sched_param param = { .sched_priority = 2 };
695
696 param.sched_priority= 31;
697 sched_setscheduler(current, SCHED_FIFO, &param);
698
699 while(1)
700 {
701 down(&bdi->chgstate_sem);
702
703 g_gpio_state = gpio_get_value(pdata->gpio_chgstate);
704
705 /*charging status*/
706 if (g_gpio_state == CHG_START) { /*low charging*/
707 bdi->chg_state = POWER_SUPPLY_STATUS_CHARGING;
708
709 if (bdi->chgstate_type == CHG_START) {
710 printk(KERN_INFO"chg chging err!\n");
711 } else {
712 bdi->chgstate_type = CHG_START;
713
714 //irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_HIGH);
715 power_supply_changed(&bdi->charger);
716 power_supply_changed(&bdi->battery);
717 printk(KERN_INFO"chg charging\n");
718 }
719 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_HIGH);
720 } else {/*high stop charging*/
721 if (bdi->chgstate_type == CHG_STOP) {
722 printk(KERN_INFO"chg full err!\n");
723 } else {
724 if ((bdi->chgin_type == USB_IN)&&(bdi->stopchg_flag == CHG_STOP_REASON_TEMP)){
725 bdi->chg_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
726 power_supply_changed(&bdi->charger);
727 power_supply_changed(&bdi->battery);
728 }
729 else if(bdi->chgin_type == USB_IN){
730 bdi->chg_state = POWER_SUPPLY_STATUS_FULL;
731 wake_lock(&(bdi->wlock_chgfull));
732 mod_timer(&bdi->changed_timer, jiffies + msecs_to_jiffies(500));
733 }
734 else{
735 bdi->chg_state = POWER_SUPPLY_STATUS_DISCHARGING;
736 power_supply_changed(&bdi->charger);
737 power_supply_changed(&bdi->battery);
738 }
739
740 bdi->chgstate_type = CHG_STOP;
741
742 printk(KERN_INFO "chg %s %s stop\n",
743 (bdi->chg_state == POWER_SUPPLY_STATUS_FULL) ? "full" : " ",
744 (bdi->chg_state == POWER_SUPPLY_STATUS_NOT_CHARGING) ? "temp error":"discharging");
745
746 }
747 irq_set_irq_type(bdi->chgstate_irq, IRQ_TYPE_LEVEL_LOW);
748 }
749 enable_irq(bdi->chgstate_irq);
750
751 }
752 return 0;
753}
754
755#endif
756static int aw3215_setup_pdata(struct aw3215_dev_info *bdi,
757 struct aw3215_platform_data *pdata)
758{
759 int ret;
760
761
762 if (!gpio_is_valid(pdata->gpio_chgen))
763 return -1;
764
765 ret = gpio_request(pdata->gpio_chgen, "chg_en");
766 if (ret < 0)
767 goto out;
768 ret = zx29_gpio_config(pdata->gpio_chgen, pdata->gpio_chgen_gpio_sel);
769 ret = gpio_direction_output(pdata->gpio_chgen, CHG_EN_TYPE);
770 bdi->chg_en =true;
771 bdi->stopchg_flag=CHG_STOP_DEFALT;
772#ifndef CONFIG_AIC8800_MIFI_EN
773 //chg termination current ctrl
774 if (!gpio_is_valid(pdata->gpio_chgctrl))
775 return -1;
776
777 ret = gpio_request(pdata->gpio_chgctrl, "chg_ctrl");
778 if (ret < 0)
779 goto out;
780 ret = zx29_gpio_config(pdata->gpio_chgctrl, pdata->gpio_chgctrl_gpio_sel);
781 if (ret < 0)
782 goto out;
783 ret = gpio_direction_output(pdata->gpio_chgctrl, 0);
784 if (ret < 0)
785 goto out;
786#endif
787 return 0;
788out:
789 //gpio_free(pdata->gpio_int);
790 return -1;
791}
792
793
794static int aw3215_init_state(struct aw3215_dev_info *bdi)
795{
796 struct aw3215_platform_data *pdata;
797 int ret = 0;
798 unsigned int g_gpio_in,g_gpio_state;
799 unsigned int chgin_irq_type=IRQ_TYPE_NONE;
800 unsigned int chgstate_irq_type=IRQ_TYPE_NONE;
801
802 pdata = bdi->pdata;
803
804 if (!gpio_is_valid(pdata->gpio_chgin))
805 goto error;
806
807 ret = gpio_request(pdata->gpio_chgin, "chg_usbin");
808 if (ret < 0)
809 goto error;
810
811 zx29_gpio_pd_pu_set(pdata->gpio_chgin, IO_CFG_PULL_DISABLE);
812 ret = zx29_gpio_config(pdata->gpio_chgin, pdata->gpio_chgin_gpio_sel);
813 if (ret < 0)
814 goto error;
815
816 ret = gpio_direction_input(pdata->gpio_chgin);
817 if (ret < 0)
818 goto error;
819
820 mdelay(20);/*?*/
821 g_gpio_in = gpio_get_value(pdata->gpio_chgin);
822
823 if ( USB_IN == g_gpio_in){
824 bdi->chgin_type = USB_IN;
825 printk(KERN_INFO"init usb in\n");
826 chgin_irq_type = IRQ_TYPE_LEVEL_HIGH;
827#ifdef _CHARGER_UNNOTIFY_USB_
828 if(get_adc1_voltage()>USB_ENUM_MIN)
829#endif
830 dwc_otg_chg_inform(0);/*usb in*/
831 }
832 else {
833 bdi->chgin_type = USB_OUT;
834 bdi->chg_state=POWER_SUPPLY_STATUS_DISCHARGING;
835 printk(KERN_INFO"init usb out\n");
836 chgin_irq_type = IRQ_TYPE_LEVEL_LOW;
837 dwc_otg_chg_inform(1);/*usb out*/
838 }
839
840 bdi->chgin_irq= gpio_to_irq(pdata->gpio_chgin);
841
842 ret = zx29_gpio_config(pdata->gpio_chgin,pdata->gpio_chgin_fun_sel);
843 if (ret < 0)
844 goto error;
845 //zx29_gpio_set_inttype(pdata->gpio_chgin,chgin_irq_type); //INT_POSEDGE
846 //pcu_clr_irq_pending(bdi->chgin_irq);
847 irq_set_irq_type(bdi->chgin_irq, chgin_irq_type);
848
849 if (!gpio_is_valid(pdata->gpio_chgstate))
850 goto error;
851
852 ret = gpio_request(pdata->gpio_chgstate, "chg_state");
853 if (ret < 0)
854 goto error;
855
856 zx29_gpio_pd_pu_set(pdata->gpio_chgstate, IO_CFG_PULL_DISABLE);
857
858 bdi->chgstate_irq= gpio_to_irq(pdata->gpio_chgstate);
859
860 ret = zx29_gpio_config(pdata->gpio_chgstate, pdata->gpio_chgstate_gpio_sel);
861 if (ret < 0)
862 goto error;
863
864 ret = gpio_direction_input(pdata->gpio_chgstate);
865 if (ret < 0)
866 goto error;
867
868 mdelay(20);/*?*/
869 g_gpio_state = gpio_get_value(pdata->gpio_chgstate);
870
871 if (CHG_START == g_gpio_state){
872 bdi->chgstate_type=CHG_START ;
873 bdi->chg_state=POWER_SUPPLY_STATUS_CHARGING;
874
875 printk(KERN_INFO"init chg state chargeing\n");
876 chgstate_irq_type = IRQ_TYPE_LEVEL_HIGH;
877 //dwc_otg_chg_inform(0);/*usb in*/
878 }
879 else {
880 bdi->chgstate_type =CHG_STOP ;
881
882 printk(KERN_INFO"init chg state discharger or full\n");
883 chgstate_irq_type = IRQ_TYPE_LEVEL_LOW;
884 //dwc_otg_chg_inform(1);/*usb out*/
885 if( bdi->chgin_type == USB_IN)
886 bdi->chg_state=POWER_SUPPLY_STATUS_FULL;
887 else
888 bdi->chg_state=POWER_SUPPLY_STATUS_DISCHARGING;
889 }
890
891 ret = zx29_gpio_config(pdata->gpio_chgstate,pdata->gpio_chgstate_fun_sel);
892 if (ret < 0)
893 goto error;
894
895 //zx29_gpio_set_inttype(pdata->gpio_chgstate,chgstate_irq_type); //INT_POSEDGE
896
897 //pcu_clr_irq_pending(bdi->chgstate_irq);
898 irq_set_irq_type(bdi->chgstate_irq, chgstate_irq_type);
899
900 return 0;
901error:
902 printk(KERN_INFO"chg gpio error ret = %d\n",ret);
903 return -1;
904}
905
906
907
908static void aw3215_charge_typedet(T_TYPE_USB_DETECT chg_type)
909{
910 //u8 ret;
911 #ifdef DBG_CHARGE
912 //printk(KERN_INFO"charge type is %d in\n",chg_type);
913 #endif
914
915 if(TYPE_ADAPTER == chg_type){
916 printk(KERN_INFO"chg type DC\n");
917 g_bdi->charger.type = POWER_SUPPLY_PCAC__AC;
918 }
919 else{
920 printk(KERN_INFO"chg type PC\n");
921 g_bdi->charger.type = POWER_SUPPLY_PCAC__PC;
922 }
923
924}
925
926
927#if defined(CONFIG_DEBUG_FS)
928static ssize_t debugfs_regs_write(struct file *file, const char __user *buf,size_t nbytes, loff_t *ppos)
929{
930 unsigned int val1, val2;
931 //u8 reg, value;
932 int ret = 0;
933 char *kern_buf;
934 //struct seq_file *s = file->private_data;
935 //struct aw3215_dev_info *aw3215 = s->private;
936
937 kern_buf = kzalloc(nbytes, GFP_KERNEL);
938
939 if (!kern_buf) {
940 printk(KERN_INFO "aw3215_charger: Failed to allocate buffer\n");
941 return -ENOMEM;
942 }
943
944 if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
945 kfree(kern_buf);
946 return -ENOMEM;
947 }
948 printk(KERN_INFO "%s input str=%s,nbytes=%d \n", __func__, kern_buf,nbytes);
949
950 ret = sscanf(kern_buf, "%x:%x", &val1, &val2);
951 if (ret < 2) {
952 printk(KERN_INFO "sgm40561_charger: failed to read user buf, ret=%d, input 0x%x:0x%x\n",
953 ret,val1, val2);
954 kfree(kern_buf);
955 return -EINVAL;
956 }
957 kfree(kern_buf);
958
959 return ret ? ret : nbytes;
960}
961
962static int debugfs_regs_show(struct seq_file *s, void *v)
963{
964 //int i;
965 int ret=0;
966 //int curr = 0;
967 struct aw3215_dev_info *aw3215 = s->private;
968
969 /*charger type*/
970 if((int)aw3215->charger.type == POWER_SUPPLY_PCAC__PC){
971 seq_printf(s, "charger type is PC\n");
972 }
973 else if((int)aw3215->charger.type == POWER_SUPPLY_PCAC__AC){
974 seq_printf(s, "charger type is AC\n");
975 }
976 else
977 seq_printf(s, "charger type is unknow = %d\n",aw3215->charger.type);
978
979 seq_printf(s, "mmi charger config state = %d\n",aw3215->chg_en);
980 seq_printf(s, "chg in state = %s\n",(aw3215->chgin_type==USB_IN)? "USB_IN": "USB_OUT");
981 seq_printf(s, "chg_state state = %s\n",aw3215->chgstate_type ? "CHG_STOP": "CHG_START");
982#ifdef CHG_DEBUG
983 seq_printf("chgstate int en reg1 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_ENABLE_SET+0x4));
984 seq_printf("chgstate int en reg2 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_ENABLE_SET+0x8));
985 seq_printf("chgstate int pending reg1 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_PENDING_SET+0x4));
986 seq_printf("chgstate int pending reg2 =0x%x:\n", zx_read_reg(base_testtt + GIC_DIST_PENDING_SET+0x8));
987#endif
988 return ret;
989}
990
991#define DEBUGFS_FILE_ENTRY(name) \
992static int debugfs_##name##_open(struct inode *inode, struct file *file) \
993{\
994return single_open(file, debugfs_##name##_show, inode->i_private); \
995}\
996\
997static const struct file_operations debugfs_##name##_fops = { \
998.owner= THIS_MODULE, \
999.open= debugfs_##name##_open, \
1000.write=debugfs_##name##_write, \
1001.read= seq_read, \
1002.llseek= seq_lseek, \
1003.release= single_release, \
1004}
1005
1006DEBUGFS_FILE_ENTRY(regs);
1007
1008static struct dentry *g_charger_root;
1009
1010static void debugfs_charger_init(struct aw3215_dev_info *aw3215)
1011{
1012 struct dentry *root;
1013 struct dentry *node;
1014 //int i;
1015
1016 if(!aw3215)
1017 return;
1018
1019 //create root
1020 root = debugfs_create_dir("charger_zx29", NULL);
1021 if (!root) {
1022 dev_err(aw3215->dev, "debugfs_create_dir err=%ld\n", IS_ERR(root));
1023 goto err;
1024 }
1025
1026 //print regs;
1027 node = debugfs_create_file("regs", S_IRUGO | S_IWUGO, root, aw3215, &debugfs_regs_fops);
1028 if (!node){
1029 dev_err(aw3215->dev, "debugfs_create_dir err=%ld\n", IS_ERR(node));
1030 goto err;
1031 }
1032
1033 g_charger_root = (void *)root;
1034 return;
1035err:
1036 dev_err(aw3215->dev, "debugfs_charger_init err\n");
1037}
1038
1039#endif
1040
1041static void aw3215_changed_timer_function(unsigned long data)
1042{
1043 struct aw3215_dev_info *bdi = (void *)data;
1044 power_supply_changed(&bdi->charger);
1045 power_supply_changed(&bdi->battery);
1046 //printk("chg timer callback\n");
1047 del_timer(&bdi->changed_timer);
1048 wake_unlock(&(bdi->wlock_chgfull));
1049 printk("chg timer callback end\n");
1050
1051}
1052
1053static int __devinit aw3215_charger_probe(struct platform_device *pdev)
1054{
1055 struct aw3215_platform_data *pdata = pdev->dev.platform_data;
1056 struct device *dev = &pdev->dev;
1057 struct aw3215_dev_info *bdi;
1058 //unsigned long flag;
1059 int ret;
1060
1061 bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
1062 if (!bdi) {
1063 dev_err(dev, "Can't alloc bdi struct\n");
1064 return -ENOMEM;
1065 }
1066 bdi->dev = dev;
1067 bdi->pdata = pdata;
1068
1069 //printk(KERN_INFO "charger probe.\n");
1070
1071 bdi->chg_state = POWER_SUPPLY_STATUS_UNKNOWN;
1072 bdi->charger.type = POWER_SUPPLY_TYPE_UNKNOWN;
1073
1074 g_bdi = bdi;
1075
1076 ret = aw3215_setup_pdata(bdi, pdata);
1077 if (ret) {
1078 dev_err(dev, "Can't get irq info\n");
1079 return -EINVAL;
1080 }
1081
1082 aw3215_charger_init(&bdi->charger);
1083
1084 ret = power_supply_register(dev, &bdi->charger);
1085 if (ret) {
1086 dev_err(dev, "Can't register charger\n");
1087 goto out2;
1088 }
1089 //printk(KERN_INFO "aw3215_probe power_supply_register charger ok.\n");
1090
1091 aw3215_battery_init(&bdi->battery);
1092
1093 ret = power_supply_register(dev, &bdi->battery);
1094 if (ret) {
1095 dev_err(dev, "Can't register battery\n");
1096 goto out1;
1097 }
1098 //printk(KERN_INFO "aw3215_probe power_supply_register battery ok.\n");
1099 //sema_init(&bdi->chgin_sem, 0);
1100 sema_init(&bdi->chgstate_sem, 0);
1101
1102 dwc_chg_Regcallback(aw3215_charge_typedet);/*register for usb*/
1103 aw3215_init_state(bdi);
1104 init_timer(&bdi->changed_timer);
1105 bdi->changed_timer.function = aw3215_changed_timer_function;
1106 bdi->changed_timer.data = (unsigned long)bdi;
1107 wake_lock_init(&(bdi->wlock_chgfull), WAKE_LOCK_SUSPEND, "aw3215_wake_lock_chgfull");
1108
1109/*chg in*/
1110 ret = request_irq(bdi->chgin_irq, aw3215_charger_in_irq_primary_handler,IRQF_NO_THREAD, "aw3215-chgin", bdi);
1111 if (ret < 0) {
1112 dev_err(dev, "Can't set up irq handler\n");
1113 if (bdi->pdata->gpio_chgin)
1114 gpio_free(bdi->pdata->gpio_chgin);
1115
1116 goto out3;
1117 }
1118 irq_set_irq_wake(bdi->chgin_irq, 1);
1119 //bdi->chgin_irq_thread = kthread_run(aw3215_chgin_irq_handler_thread, bdi, "aw3215-chgin");
1120 //BUG_ON(IS_ERR(bdi->chgin_irq_thread));
1121
1122/*chg state*/
1123 ret = request_irq(bdi->chgstate_irq, aw3215_charger_state_irq_primary_handler,IRQF_NO_THREAD, "aw3215-chgstate", bdi);
1124 if (ret < 0) {
1125 dev_err(dev, "Can't set up irq handler\n");
1126 if (bdi->pdata->gpio_chgstate)
1127 gpio_free(bdi->pdata->gpio_chgstate);
1128
1129 goto out3;
1130 }
1131 irq_set_irq_wake(bdi->chgstate_irq, 1);
1132 //bdi->chgstate_irq_thread = kthread_run(aw3215_chgstate_irq_handler_thread, bdi, "aw3215-chgstate");
1133 //BUG_ON(IS_ERR(bdi->chgstate_irq_thread));
1134 bdi->chgstate_irq_thread = kthread_run(aw3215_chg_irq_handler_thread, bdi, "aw3215-chgstate");
1135 BUG_ON(IS_ERR(bdi->chgstate_irq_thread));
1136
1137#if defined(CONFIG_DEBUG_FS)
1138 debugfs_charger_init(bdi);
1139#endif
1140
1141#ifdef DBG_CHARGE
1142 //printk(KERN_INFO "aw3215_probe end.\n");
1143#endif
1144
1145 return 0;
1146
1147out1:
1148 power_supply_unregister(&bdi->battery);
1149out2:
1150 //pm_runtime_disable(dev);
1151 power_supply_unregister(&bdi->charger);
1152out3:
1153
1154 return ret;
1155
1156}
1157
1158static int aw3215_charger_remove(struct platform_device *pdev)
1159{
1160 struct aw3215_platform_data *pdata = pdev->dev.platform_data;
1161
1162 power_supply_unregister(&(g_bdi->battery));
1163 power_supply_unregister(&(g_bdi->charger));
1164
1165 pm_runtime_disable(g_bdi->dev);
1166
1167 if (pdata->gpio_chgctrl)
1168 gpio_free(pdata->gpio_chgctrl);
1169 if (pdata->gpio_chgen)
1170 gpio_free(pdata->gpio_chgen);
1171 if (pdata->gpio_chgin)
1172 gpio_free(pdata->gpio_chgin);
1173 if (pdata->gpio_chgstate)
1174 gpio_free(pdata->gpio_chgstate);
1175
1176
1177#if defined(CONFIG_DEBUG_FS)
1178 if(g_charger_root){
1179 //printk(KERN_INFO "aw3215_device_exit:debugfs_remove_recursive \n");
1180 debugfs_remove_recursive(g_charger_root);
1181 }
1182#endif
1183
1184 return 0;
1185}
1186
1187
1188static struct platform_driver zx29_charger_driver = {
1189 .probe = aw3215_charger_probe,
1190 .remove = __devexit_p(aw3215_charger_remove),
1191 .driver = {
1192 .name = "aw3215-charger",
1193 .owner = THIS_MODULE,
1194 },
1195};
1196
1197//module_platform_driver(zx29_charger_driver);
1198
1199
1200static int __init zx29_charger_init(void)
1201{
1202 return platform_driver_register(&zx29_charger_driver);
1203}
1204
1205static void __exit zx29_charger_exit(void)
1206{
1207 platform_driver_unregister(&zx29_charger_driver);
1208}
1209
1210module_init(zx29_charger_init);
1211module_exit(zx29_charger_exit);
1212
1213
1214MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
1215MODULE_DESCRIPTION("AW3215 Charger Driver");
1216MODULE_LICENSE("GPL");
1217MODULE_ALIAS("platform:zx29_charger");
1218