Merge tag 'lsk-v4.4-16.06-android'
[firefly-linux-kernel-4.4.55.git] / drivers / video / backlight / aw9364_bl.c
1 /*
2  * Backlight driver for Wolfson Microelectronics WM831x PMICs
3  *
4  * Copyright 2009 Wolfson Microelectonics plc
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/kernel.h>
12 #include <linux/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/fb.h>
15 #include <linux/backlight.h>
16 #include <linux/slab.h>
17 #include <mach/gpio.h>
18 #ifdef CONFIG_HAS_EARLYSUSPEND
19 #include <linux/earlysuspend.h>
20 #endif
21 #include <linux/delay.h>
22 #include <linux/ktime.h>
23 #include "aw9364_bl.h"
24
25 /*
26  * Debug
27  */
28 #if 0
29 #define DBG(x...)       printk(KERN_INFO x)
30 #else
31 #define DBG(x...)
32 #endif
33
34 #define BL_SET   255
35 #define BL_INIT_VALUE 102
36 struct aw9364_backlight_data {
37         int pin_en;
38         int current_brightness;
39 #ifdef CONFIG_HAS_EARLYSUSPEND
40         struct  early_suspend early_suspend;
41         struct delayed_work work;
42         int suspend_flag;
43         int shutdown_flag;
44 #endif
45
46         spinlock_t bl_lock;
47 };
48
49 #ifdef CONFIG_HAS_EARLYSUSPEND
50 static struct backlight_device *g_aw9364_bl;
51 static struct aw9364_backlight_data *g_aw9364_data;
52 #endif
53
54 static int aw9364_backlight_set(struct backlight_device *bl, int brightness)
55 {
56         struct aw9364_backlight_data *data = bl_get_data(bl);
57         int i,num_clk, num_clk_to, num_clk_from;
58         unsigned long flags;
59                 
60         brightness = brightness & 0xff; //0-256
61
62         num_clk_from = 16 -(data->current_brightness>>4);       
63         num_clk_to = 16 -(brightness>>4);
64         num_clk = (16 + num_clk_to - num_clk_from)%16;
65         
66         
67         if(brightness < 16)
68         {
69                 gpio_direction_output(data->pin_en, GPIO_LOW);
70                 mdelay(3);
71         }
72         else {
73                 spin_lock_irqsave(&data->bl_lock, flags);
74                 for(i=0; i<num_clk; i++)        //the wave should not be intterupted
75                 {
76                         gpio_set_value(data->pin_en, GPIO_LOW); 
77                         gpio_set_value(data->pin_en, GPIO_HIGH);
78                         if(i==0)
79                         udelay(30);     
80                 }
81                 spin_unlock_irqrestore(&data->bl_lock, flags);
82         }
83         
84         DBG("%s:current_bl=%d,bl=%d,num_clk_to=%d,num_clk_from=%d,num_clk=%d\n",__FUNCTION__,
85                 data->current_brightness,brightness,num_clk_to,num_clk_from,num_clk);
86
87         if((num_clk) || (brightness < 16))
88         data->current_brightness = brightness;
89         
90         return 0;
91         
92 }
93
94
95 static int aw9364_backlight_update_status(struct backlight_device *bl)
96 {
97
98         int brightness = bl->props.brightness;
99         
100         if(g_aw9364_data->suspend_flag == 1)
101                 brightness = 0;
102         
103         if (g_aw9364_data->shutdown_flag == 1)
104                 brightness = 0;
105                 
106         if (bl->props.power != FB_BLANK_UNBLANK)
107                 brightness = 0;
108
109         if (bl->props.fb_blank != FB_BLANK_UNBLANK)
110                 brightness = 0;
111
112         if (bl->props.state & BL_CORE_SUSPENDED)
113                 brightness = 0;
114
115         DBG("backlight brightness=%d\n", brightness);
116
117         return aw9364_backlight_set(bl, brightness);
118 }
119
120 static int aw9364_backlight_get_brightness(struct backlight_device *bl)
121 {
122         struct aw9364_backlight_data *data = bl_get_data(bl);
123         return data->current_brightness;
124 }
125
126 static struct backlight_ops aw9364_backlight_ops = {
127         .options = BL_CORE_SUSPENDRESUME,
128         .update_status  = aw9364_backlight_update_status,
129         .get_brightness = aw9364_backlight_get_brightness,
130 };
131 #ifdef CONFIG_HAS_EARLYSUSPEND
132 static void aw9364_bl_work(struct work_struct *work)
133 {
134         //struct aw9364_backlight_data *aw9364_data = container_of(work, struct aw9364_backlight_data,
135                                                    //work.work);
136         backlight_update_status(g_aw9364_bl);
137 }
138
139 static void aw9364_bl_suspend(struct early_suspend *h)
140 {
141         struct aw9364_backlight_data *aw9364_data;
142         aw9364_data = container_of(h, struct aw9364_backlight_data, early_suspend);
143         aw9364_data->suspend_flag = 1;
144
145         schedule_delayed_work(&aw9364_data->work, msecs_to_jiffies(100));               
146 }
147
148
149 static void aw9364_bl_resume(struct early_suspend *h)
150 {
151         struct aw9364_backlight_data *aw9364_data;
152         aw9364_data = container_of(h, struct aw9364_backlight_data, early_suspend);
153         aw9364_data->suspend_flag = 0;
154
155         schedule_delayed_work(&aw9364_data->work, msecs_to_jiffies(100));
156         
157 }
158
159 #endif
160
161
162 int rk29_backlight_ctrl(int open)
163 {
164         if(open)
165                 g_aw9364_data->suspend_flag = 0;
166         else
167                 g_aw9364_data->suspend_flag = 1;
168
169         backlight_update_status(g_aw9364_bl);
170         return 0;
171 }
172
173 static int aw9364_backlight_probe(struct platform_device *pdev)
174 {
175         struct aw9364_backlight_data *data;
176         struct aw9364_platform_data *pdata = pdev->dev.platform_data;
177         struct backlight_device *bl;
178
179         data = kzalloc(sizeof(*data), GFP_KERNEL);
180         if (data == NULL)
181                 return -ENOMEM;
182         
183         if(pdata && pdata->io_init)
184         pdata->io_init();
185
186         data->current_brightness = 0;
187         data->pin_en = pdata->pin_en;
188
189
190         bl = backlight_device_register("wm831x", &pdev->dev, data,
191                                        &aw9364_backlight_ops, NULL);
192         if (IS_ERR(bl)) {
193                 dev_err(&pdev->dev, "failed to register backlight\n");
194                 kfree(data);
195                 return PTR_ERR(bl);
196         }
197
198         bl->props.brightness = BL_INIT_VALUE;
199         bl->props.max_brightness= BL_SET;
200
201         if(data && data->pin_en)
202         gpio_request(data->pin_en, NULL);
203         else
204         return -1;
205
206         spin_lock_init(&data->bl_lock); 
207
208         platform_set_drvdata(pdev, bl);
209
210 #ifdef CONFIG_HAS_EARLYSUSPEND  
211         data->early_suspend.level = ~0x0;
212         data->early_suspend.suspend = aw9364_bl_suspend;
213         data->early_suspend.resume = aw9364_bl_resume;
214         register_early_suspend(&data->early_suspend);
215         INIT_DELAYED_WORK(&data->work, aw9364_bl_work);
216         g_aw9364_bl = bl;
217         g_aw9364_data = data;
218 #endif
219
220         gpio_direction_output(data->pin_en, GPIO_LOW);
221         mdelay(3);
222
223         backlight_update_status(bl);
224         schedule_delayed_work(&data->work, msecs_to_jiffies(100));
225
226         printk("%s\n",__FUNCTION__);
227
228         return 0;
229 }
230
231 static int aw9364_backlight_remove(struct platform_device *pdev)
232 {
233         struct backlight_device *bl = platform_get_drvdata(pdev);
234         struct aw9364_backlight_data *data = bl_get_data(bl);
235
236         backlight_device_unregister(bl);
237 #ifdef CONFIG_HAS_EARLYSUSPEND
238         unregister_early_suspend(&data->early_suspend);
239 #endif 
240         kfree(data);
241         return 0;
242 }
243
244 static void aw9364_backlight_shutdown(struct platform_device *pdev)
245 {
246         struct backlight_device *bl = platform_get_drvdata(pdev);
247         struct aw9364_backlight_data *data = bl_get_data(bl);
248         
249         printk("%s\n",__FUNCTION__);
250         data->shutdown_flag = 1;
251         aw9364_backlight_update_status(bl);
252         return;
253 }
254
255 static struct platform_driver aw9364_backlight_driver = {
256         .driver         = {
257                 .name   = "aw9364_backlight",
258                 .owner  = THIS_MODULE,
259         },
260         .probe          = aw9364_backlight_probe,
261         .remove         = aw9364_backlight_remove,
262         .shutdown       = aw9364_backlight_shutdown,
263 };
264
265 static int __init aw9364_backlight_init(void)
266 {
267         return platform_driver_register(&aw9364_backlight_driver);
268 }
269 module_init(aw9364_backlight_init);
270
271 static void __exit aw9364_backlight_exit(void)
272 {
273         platform_driver_unregister(&aw9364_backlight_driver);
274 }
275 module_exit(aw9364_backlight_exit);
276
277 MODULE_DESCRIPTION("Backlight Driver for AW9364");
278 MODULE_AUTHOR("luo wei <lw@rock-chips.com");
279 MODULE_LICENSE("GPL");
280 MODULE_ALIAS("platform:aw9364-backlight");