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