video: rockchip: fb: add support data format YUYV and UYVY
[firefly-linux-kernel-4.4.55.git] / drivers / video / backlight / fih_touchkey_led.c
1 /* drivers/video/backlight/rk29_backlight.c
2  *
3  * Copyright (C) 2009-2011 Rockchip Corporation.
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
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/err.h>
20 #include <linux/delay.h>
21 #include <linux/platform_device.h>
22 #include <linux/backlight.h>
23 #include <linux/fb.h>
24 #include <linux/clk.h>
25
26 #include <linux/earlysuspend.h>
27 #include <asm/io.h>
28 #include <mach/rk29_iomap.h>
29 #include <mach/board.h>
30
31 #include "rk2818_backlight.h"
32
33 /*
34  * Debug
35  */
36 #if 0
37 #define DBG(x...)       printk(KERN_INFO x)
38 #else
39 #define DBG(x...)
40 #endif
41
42
43 #define write_pwm_reg(id, addr, val)        __raw_writel(val, addr+(RK29_PWM_BASE+id*0x10))
44 #define read_pwm_reg(id, addr)              __raw_readl(addr+(RK29_PWM_BASE+id*0x10))    
45
46 static struct clk *pwm_clk;
47 static struct backlight_device *fih_touchkey_led;
48 static int suspend_flag = 0;
49
50 static int fih_touchkey_led_update_status(struct backlight_device *bl)
51 {
52         u32 divh,div_total;
53         struct rk29_bl_info *fih_touchkey_led_info = bl_get_data(bl);
54         u32 id = fih_touchkey_led_info->pwm_id;
55         u32 ref = fih_touchkey_led_info->bl_ref;
56
57         if (suspend_flag)
58                 return 0;
59
60         if (bl->props.brightness < fih_touchkey_led_info->min_brightness)       /*avoid can't view screen when close backlight*/
61                 bl->props.brightness = fih_touchkey_led_info->min_brightness;
62
63         div_total = read_pwm_reg(id, PWM_REG_LRC);
64         if (ref) {
65                 divh = div_total*(bl->props.brightness)/BL_STEP;
66         } else {
67                 divh = div_total*(BL_STEP-bl->props.brightness)/BL_STEP;
68         }
69         write_pwm_reg(id, PWM_REG_HRC, divh);
70
71         DBG(">>>%s-->%d brightness = %d, div_total = %d, divh = %d\n",__FUNCTION__,__LINE__,bl->props.brightness, div_total, divh);
72         return 0;
73 }
74
75 static int fih_touchkey_led_get_brightness(struct backlight_device *bl)
76 {
77         u32 divh,div_total;
78         struct rk29_bl_info *fih_touchkey_led_info = bl_get_data(bl);
79         u32 id = fih_touchkey_led_info->pwm_id;
80         u32 ref = fih_touchkey_led_info->bl_ref;
81
82         div_total = read_pwm_reg(id, PWM_REG_LRC);
83         divh = read_pwm_reg(id, PWM_REG_HRC);
84
85         if (!div_total)
86                 return 0;
87
88         if (ref) {
89                 return BL_STEP*divh/div_total;
90         } else {
91                 return BL_STEP-(BL_STEP*divh/div_total);
92         }
93 }
94
95 static struct backlight_ops fih_touchkey_led_ops = {
96         .update_status  = fih_touchkey_led_update_status,
97         .get_brightness = fih_touchkey_led_get_brightness,
98 };
99
100 static void fih_touchkey_led_work_func(struct work_struct *work)
101 {
102         suspend_flag = 0;
103         fih_touchkey_led_update_status(fih_touchkey_led);
104 }
105 static DECLARE_DELAYED_WORK(fih_touchkey_led_work, fih_touchkey_led_work_func);
106
107 #ifdef CONFIG_HAS_EARLYSUSPEND
108 static void fih_touchkey_led_suspend(struct early_suspend *h)
109 {
110         struct rk29_bl_info *fih_touchkey_led_info = bl_get_data(fih_touchkey_led);
111         int brightness = fih_touchkey_led->props.brightness;
112
113         cancel_delayed_work_sync(&fih_touchkey_led_work);
114
115         if (fih_touchkey_led->props.brightness) {
116                 fih_touchkey_led->props.brightness = 0;
117                 fih_touchkey_led_update_status(fih_touchkey_led);
118                 fih_touchkey_led->props.brightness = brightness;
119         }
120
121         if (!suspend_flag) {
122                 clk_disable(pwm_clk);
123                 if (fih_touchkey_led_info->pwm_suspend)
124                         fih_touchkey_led_info->pwm_suspend();
125         }
126
127         suspend_flag = 1;
128 }
129
130 static void fih_touchkey_led_resume(struct early_suspend *h)
131 {
132         struct rk29_bl_info *fih_touchkey_led_info = bl_get_data(fih_touchkey_led);
133         DBG("%s : %s\n", __FILE__, __FUNCTION__);
134
135         if (fih_touchkey_led_info->pwm_resume)
136                 fih_touchkey_led_info->pwm_resume();
137
138         clk_enable(pwm_clk);
139
140         schedule_delayed_work(&fih_touchkey_led_work, msecs_to_jiffies(fih_touchkey_led_info->delay_ms));
141 }
142
143 static struct early_suspend fih_touchkey_led_early_suspend = {
144         .suspend = fih_touchkey_led_suspend,
145         .resume = fih_touchkey_led_resume,
146         .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1,
147 };
148 #endif
149
150 static int fih_touchkey_led_probe(struct platform_device *pdev)
151 {               
152         int ret = 0;
153         struct rk29_bl_info *fih_touchkey_led_info = pdev->dev.platform_data;
154         u32 id  =  fih_touchkey_led_info->pwm_id;
155         u32 divh, div_total;
156         unsigned long pwm_clk_rate;
157
158         if (fih_touchkey_led) {
159                 DBG(KERN_CRIT "%s: fih touchkey led device register has existed \n",
160                                 __func__);
161                 return -EEXIST;         
162         }
163
164         if (!fih_touchkey_led_info->delay_ms)
165                 fih_touchkey_led_info->delay_ms = 30;
166
167         if (fih_touchkey_led_info->min_brightness < 0 || fih_touchkey_led_info->min_brightness > BL_STEP)
168                 fih_touchkey_led_info->min_brightness = 52;
169
170         if (fih_touchkey_led_info && fih_touchkey_led_info->io_init) {
171                 fih_touchkey_led_info->io_init();
172         }
173
174         fih_touchkey_led = backlight_device_register("fih_touchkey_led", &pdev->dev, fih_touchkey_led_info, &fih_touchkey_led_ops);
175         if (!fih_touchkey_led) {
176                 DBG(KERN_CRIT "%s: fih touchkey led register error\n",
177                                 __func__);
178                 return -ENODEV;         
179         }
180
181         pwm_clk = clk_get(NULL, "pwm");
182         if (IS_ERR(pwm_clk)) {
183                 printk(KERN_ERR "failed to get pwm clock source\n");
184                 return -ENODEV; 
185         }
186         pwm_clk_rate = clk_get_rate(pwm_clk);
187         div_total = pwm_clk_rate / PWM_APB_PRE_DIV;
188
189         div_total >>= (1 + (PWM_DIV >> 9));
190         div_total = (div_total) ? div_total : 1;
191
192         if(fih_touchkey_led_info->bl_ref) {
193                 divh = 0;
194         } else {
195                 divh = div_total;
196         }
197
198         clk_enable(pwm_clk);
199         write_pwm_reg(id, PWM_REG_CTRL, PWM_DIV|PWM_RESET);
200         write_pwm_reg(id, PWM_REG_LRC, div_total);
201         write_pwm_reg(id, PWM_REG_HRC, divh);
202         write_pwm_reg(id, PWM_REG_CNTR, 0x0);
203         write_pwm_reg(id, PWM_REG_CTRL, PWM_DIV|PWM_ENABLE|PWM_TIME_EN);
204
205         fih_touchkey_led->props.power = FB_BLANK_UNBLANK;
206         fih_touchkey_led->props.fb_blank = FB_BLANK_UNBLANK;
207         fih_touchkey_led->props.max_brightness = BL_STEP;
208         fih_touchkey_led->props.brightness = BL_STEP / 2;
209
210         schedule_delayed_work(&fih_touchkey_led_work, msecs_to_jiffies(fih_touchkey_led_info->delay_ms));
211
212         register_early_suspend(&fih_touchkey_led_early_suspend);
213
214         printk("Fih touchkey led Driver Initialized.\n");
215         return ret;
216 }
217
218 static int fih_touchkey_led_remove(struct platform_device *pdev)
219 {               
220         struct rk29_bl_info *rk29_bl_info = pdev->dev.platform_data;
221
222         if (fih_touchkey_led) {
223                 backlight_device_unregister(fih_touchkey_led);
224                 unregister_early_suspend(&fih_touchkey_led_early_suspend);
225                 clk_disable(pwm_clk);
226                 clk_put(pwm_clk);
227                 if (rk29_bl_info && rk29_bl_info->io_deinit) {
228                         rk29_bl_info->io_deinit();
229                 }
230                 return 0;
231         } else {
232                 DBG(KERN_CRIT "%s: no Fih touchkey led device has registered\n",
233                                 __func__);
234                 return -ENODEV;
235         }
236 }
237
238 static void fih_touchkey_led_shutdown(struct platform_device *pdev)
239 {
240         struct rk29_bl_info *fih_touchkey_led_info = pdev->dev.platform_data;
241
242         fih_touchkey_led->props.brightness >>= 1;
243         fih_touchkey_led_update_status(fih_touchkey_led);
244         mdelay(100);
245
246         fih_touchkey_led->props.brightness >>= 1;
247         fih_touchkey_led_update_status(fih_touchkey_led);
248         mdelay(100);
249
250         fih_touchkey_led->props.brightness = 0;
251         fih_touchkey_led_update_status(fih_touchkey_led);
252
253         if (fih_touchkey_led_info && fih_touchkey_led_info->io_deinit)
254                 fih_touchkey_led_info->io_deinit();
255 }
256
257 static struct platform_driver fih_touchkey_led_driver = {
258         .probe  = fih_touchkey_led_probe,
259         .remove = fih_touchkey_led_remove,
260         .driver = {
261                 .name   = "fih_touchkey_led",
262                 .owner  = THIS_MODULE,
263         },
264         .shutdown       = fih_touchkey_led_shutdown,
265 };
266
267 static int __init fih_touchkey_led_init(void)
268 {
269         platform_driver_register(&fih_touchkey_led_driver);
270         return 0;
271 }
272 fs_initcall_sync(fih_touchkey_led_init);
273 //late_initcall_sync(fih_touchkey_led_init);