add wm831x charger display support
[firefly-linux-kernel-4.4.55.git] / drivers / power / wm831x_charger_display.c
1 /* drivers/power/wm831x_charger_display.c
2  *
3  * battery detect driver for the rk2818 
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/slab.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/input.h>
21 #include <linux/interrupt.h>
22 #include <linux/fb.h>
23 #include <linux/delay.h>
24 #include <linux/suspend.h>
25 #include <linux/linux_logo.h>
26 #include <linux/regulator/consumer.h>
27 #include <linux/platform_device.h>
28 #include <linux/workqueue.h>
29 #include <linux/mfd/wm831x/core.h>
30 #include <mach/gpio.h>
31 #include <mach/iomux.h>
32 #include <mach/rk29_iomap.h>
33
34 #include <linux/mfd/wm831x/core.h>
35 #include <linux/mfd/wm831x/auxadc.h>
36 #include <linux/mfd/wm831x/pmu.h>
37 #include <linux/mfd/wm831x/pdata.h>
38 #include <linux/power_supply.h>
39
40
41 #define READ_ON_PIN_CNT 20/*11*/
42 #define BACKLIGHT_CNT   2
43 #define OPEN_CNT                18
44 #define MC_OPEN 7/*10*/ 
45 #define BAT_CHARGING    1
46 #define BAT_DISCHARGING 0
47 #define BL_DELAY_TIME   (8*1000)
48
49
50 #define SET_BACKLIGHT_ON        1
51 #define OPEN_SYSTEM                     2
52 #define SUSPEND_SYSTEM          3
53
54 #if 0
55 #define DBG(x...)   printk(x)
56 #else
57 #define DBG(x...)
58 #endif 
59
60 extern void request_suspend_state(suspend_state_t new_state);
61 extern void kernel_restart(char *cmd);
62 extern void kernel_power_off(void);
63
64 extern unsigned g_vbus_status_register;
65 extern unsigned long *g_pcd_for_charger;
66
67 extern int rk29_backlight_ctrl(int open);
68
69 extern void fb_show_charge_logo(struct linux_logo *logo);
70
71 extern void kernel_restart_prepare(char *cmd);
72 extern int dwc_vbus_status( void );
73 extern int dwc_otg_pcd_check_vbus_detech( unsigned long pdata );
74
75 #if defined(CONFIG_LOGO_A22_CLUT224)
76 extern struct linux_logo logo_a22_charger01_clut224;
77 extern struct linux_logo logo_a22_charger02_clut224;
78 extern struct linux_logo logo_a22_charger03_clut224;
79 extern struct linux_logo logo_a22_charger04_clut224;
80 extern struct linux_logo logo_a22_charger05_clut224;
81 extern struct linux_logo logo_a22_charger06_clut224;
82 extern struct linux_logo logo_a22_charger07_clut224;
83 extern struct linux_logo logo_a22_charger08_clut224;
84 #endif
85
86 extern struct fb_info *g_fb0_inf;
87
88 static struct linux_logo* g_chargerlogo[8]= {
89 #if defined(CONFIG_LOGO_A22_CLUT224)
90         &logo_a22_charger01_clut224,&logo_a22_charger02_clut224,&logo_a22_charger03_clut224,&logo_a22_charger04_clut224,
91                 &logo_a22_charger05_clut224,&logo_a22_charger06_clut224,&logo_a22_charger07_clut224,&logo_a22_charger08_clut224
92 #endif
93 };
94
95 #if 1
96 struct wm831x_chg {
97         struct wm831x *wm831x;
98         int logo_id;
99         int flag_chg;
100         int bat_vol;
101         int cnt_on;
102         int cnt_disp;
103         int flag_bl;
104         int flag_suspend;
105         
106 };
107
108 static int charger_logo_display(struct linux_logo *logo)
109 {
110         fb_show_charge_logo(logo);
111         fb_show_logo(g_fb0_inf, 0);
112         return 0;
113 }
114
115 static int charger_backlight_ctrl(int open)
116 {
117         DBG("%s:open=%d\n",__FUNCTION__,open);
118         return rk29_backlight_ctrl(open);
119 }
120
121 static int wm831x_read_on_pin_status(struct wm831x_chg *wm831x_chg)
122 {
123         int ret;
124         
125         if(!wm831x_chg)
126         {
127                 printk("err:%s:wm831x_chg address is 0\n",__FUNCTION__);
128                 return -1;
129         }
130         
131         ret = wm831x_reg_read(wm831x_chg->wm831x, WM831X_ON_PIN_CONTROL);
132         if (ret < 0)
133                 return ret;
134
135         return !(ret & WM831X_ON_PIN_STS) ? 1 : 0;
136 }
137
138
139 static int wm831x_read_chg_status(struct wm831x_chg *wm831x_chg)
140 {
141         int ret, usb_chg = 0, wall_chg = 0;
142         
143         if(!wm831x_chg)
144         {
145                 printk("err:%s:wm831x_chg address is 0\n",__FUNCTION__);
146                 return -1;
147         }
148         
149         ret = wm831x_reg_read(wm831x_chg->wm831x, WM831X_SYSTEM_STATUS);
150         if (ret < 0)
151                 return ret;
152
153         if (ret & WM831X_PWR_USB)
154                 usb_chg = 1;
155         if (ret & WM831X_PWR_WALL)
156                 wall_chg = 1;
157
158         return ((usb_chg | wall_chg) ? 1 : 0);
159 }
160
161 static int wm831x_bat_check_status(struct wm831x *wm831x, int *status)
162 {
163         int ret;
164
165         ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
166         if (ret < 0)
167                 return ret;
168
169         if (ret & WM831X_PWR_SRC_BATT) {
170                 *status = POWER_SUPPLY_STATUS_DISCHARGING;
171                 return 0;
172         }
173
174         ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
175         if (ret < 0)
176                 return ret;
177
178         
179         switch (ret & WM831X_CHG_STATE_MASK) {
180         case WM831X_CHG_STATE_OFF:
181                 *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
182                 break;
183         case WM831X_CHG_STATE_TRICKLE:
184         case WM831X_CHG_STATE_FAST:
185                 *status = POWER_SUPPLY_STATUS_CHARGING;
186                 break;
187
188         default:
189                 *status = POWER_SUPPLY_STATUS_UNKNOWN;
190                 break;
191         }
192
193         return 0;
194 }
195
196 static int wm831x_read_bat_charging_status(struct wm831x_chg *wm831x_chg)
197 {
198         int ret, status;
199         
200         if(!wm831x_chg)
201         {
202                 printk("err:%s:g_wm831x_power address is 0\n",__FUNCTION__);
203                 return -1;
204         }
205         
206         ret = wm831x_bat_check_status(wm831x_chg->wm831x, &status);
207         if (ret < 0)
208                 return ret;
209         if (status == POWER_SUPPLY_STATUS_CHARGING) 
210                 return 1;
211         return 0;
212 }
213
214 static int wm831x_read_batt_voltage(struct wm831x_chg *wm831x_chg)
215 {
216         int ret = 0;
217         
218         if(!wm831x_chg)
219         {
220                 printk("err:%s:wm831x_chg address is 0\n",__FUNCTION__);
221                 return -1;
222         }
223         
224         ret = wm831x_auxadc_read_uv(wm831x_chg->wm831x, WM831X_AUX_BATT);
225         return ret / 1000;
226 }
227
228
229 static int get_charger_logo_start_num(struct wm831x_chg *wm831x_chg)
230 {
231         int rlogonum, bat_vol;
232
233         /*check charger voltage*/
234         bat_vol = wm831x_read_batt_voltage(wm831x_chg);
235         if(bat_vol <= 3610) {
236                 rlogonum = 0;
237         }
238         else if(bat_vol <= 3700) {
239                 rlogonum = 1;
240         }
241         else if(bat_vol <= 3760) {
242                 rlogonum = 2;
243         }
244         else if(bat_vol <= 3840) {
245                 rlogonum = 3;
246         }
247         else if(bat_vol <= 3900) {
248                 rlogonum = 4;
249         }
250         else if(bat_vol <= 3990) {
251                 rlogonum = 5;
252         }
253         else if(bat_vol <= 4130) {
254                 rlogonum = 6;
255         }
256         else if(bat_vol <= 4200) {
257                 rlogonum = 7;
258         }
259         else{
260                 rlogonum = 7;
261         }
262                 
263         return rlogonum;
264 }
265
266 static int wm831x_check_on_pin(struct wm831x_chg *wm831x_chg)
267 {
268         int ret;
269         ret = wm831x_read_on_pin_status(wm831x_chg);
270         if(ret)
271         {
272                 if(wm831x_chg->cnt_on++ > 1000)
273                         wm831x_chg->cnt_on = 1000;
274         }
275         else
276         {
277                 //control backlight if press on pin
278                 if(wm831x_chg->cnt_on >= 1)
279                 {
280                         wm831x_chg->flag_bl = !wm831x_chg->flag_bl;
281                         charger_backlight_ctrl(wm831x_chg->flag_bl);                    
282                         wm831x_chg->cnt_on = 0; 
283                         if(wm831x_chg->flag_bl)
284                         {
285                                 wm831x_chg->flag_suspend = 0;
286                                 wm831x_chg->cnt_disp = 0;
287                         }
288                 }
289         }
290
291         return 0;
292 }
293
294 static int rk29_charger_display(struct wm831x_chg *wm831x_chg)
295 {
296         int status;
297         struct linux_logo* chargerlogo[8];
298         int ret,i;
299         
300         wm831x_chg->flag_chg = wm831x_read_chg_status(wm831x_chg);
301         if(!wm831x_chg->flag_chg)
302                 return -1;
303
304         while(1)
305         {
306                 wm831x_chg->flag_chg = wm831x_read_chg_status(wm831x_chg);
307                 if(!wm831x_chg->flag_chg)
308                         kernel_power_off();
309
310                 status = wm831x_read_bat_charging_status(wm831x_chg);
311
312                 for(i=0; i<8; i++)
313                 chargerlogo[i] = g_chargerlogo[i];
314         
315                 if(status == BAT_CHARGING)
316                 {       
317                         for(i=get_charger_logo_start_num(wm831x_chg); i<8; i++ )
318                         {
319                                 wm831x_chg->flag_chg = wm831x_read_chg_status(wm831x_chg);
320                                 if(!wm831x_chg->flag_chg)
321                                 kernel_power_off();
322
323                                 ret = charger_logo_display(chargerlogo[i]);
324
325                                 DBG("%s:i=%d\n",__FUNCTION__,i);
326
327                                 mdelay(300);    
328                                 wm831x_check_on_pin(wm831x_chg);
329                         }
330                                         
331                 }
332                 else if(status == BAT_DISCHARGING)
333                 {
334                         charger_logo_display(chargerlogo[7]);
335                         mdelay(300);
336                         wm831x_check_on_pin(wm831x_chg);
337                 }
338                 
339                 //suspend when timeout(100*200ms)
340                 if(wm831x_chg->cnt_disp++ > 100)
341                 {
342                         if(wm831x_chg->flag_suspend == 0)
343                         {
344                                 wm831x_chg->flag_suspend = 1;
345                                 wm831x_chg->cnt_disp = 0;
346                                 wm831x_chg->flag_bl = 0;
347                                 charger_backlight_ctrl(wm831x_chg->flag_bl);
348                         }
349                         wm831x_chg->cnt_disp = 0;
350                 }
351
352                 printk("%s,status=%d,cnt_on=%d,cnt_disp=%d\n",__FUNCTION__,status,wm831x_chg->cnt_on,wm831x_chg->cnt_disp);
353
354                 //open system if long time press
355                 if(wm831x_chg->cnt_on > 4)
356                 {
357                         wm831x_chg->cnt_on = 0;
358                         wm831x_chg->flag_bl = 1;
359                         charger_backlight_ctrl(wm831x_chg->flag_bl);
360                         wm831x_chg->flag_suspend = 0;
361                         wm831x_chg->cnt_disp = 0;
362                         break;
363                 }       
364                 
365         }
366
367         return 0;
368
369 }
370
371 static int __devinit wm831x_chg_probe(struct platform_device *pdev)
372 {
373         struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);;
374         struct wm831x_chg *wm831x_chg;
375         int ret;
376         
377         wm831x_chg = kzalloc(sizeof(struct wm831x_chg), GFP_KERNEL);
378         if (!wm831x_chg) {
379                 dev_err(&pdev->dev, "Can't allocate data\n");
380                 return -ENOMEM;
381         }
382         printk("%s:start\n",__FUNCTION__);
383         wm831x_chg->wm831x = wm831x;
384         wm831x_chg->flag_chg = 0;
385         wm831x_chg->logo_id = 0;
386         wm831x_chg->flag_bl = 1;
387         wm831x_chg->cnt_on = 0;
388         wm831x_chg->flag_suspend = 0;
389         
390         platform_set_drvdata(pdev, wm831x_chg);
391
392         ret = rk29_charger_display(wm831x_chg);
393
394         wm831x_chg->flag_chg = 0;
395         wm831x_chg->flag_bl = 1;
396         wm831x_chg->cnt_on = 0;
397         wm831x_chg->flag_suspend = 0;
398
399         printk("%s:exit\n",__FUNCTION__);
400         return 0;
401
402 }
403
404
405 static int __devexit wm831x_chg_remove(struct platform_device *pdev)
406 {
407         struct wm831x_chg *wm831x_chg = platform_get_drvdata(pdev);
408
409         kfree(wm831x_chg);
410
411         return 0;
412 }
413
414 static struct platform_driver wm831x_chg_driver = {
415         .probe          = wm831x_chg_probe,
416         .remove         = __devexit_p(wm831x_chg_remove),
417         .driver         = {
418                 .name   = "wm831x_charger_display",
419                 .owner  = THIS_MODULE,
420         },
421 };
422
423 static int __init wm831x_chg_init(void)
424 {
425         return platform_driver_register(&wm831x_chg_driver);
426 }
427 late_initcall(wm831x_chg_init);
428
429 static void __exit wm831x_chg_exit(void)
430 {
431         platform_driver_unregister(&wm831x_chg_driver);
432 }
433 module_exit(wm831x_chg_exit);
434 #endif
435
436
437 MODULE_LICENSE("GPL");
438 MODULE_AUTHOR("linjh<linjh@rock-chips.com>");
439 MODULE_DESCRIPTION("charger display");