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