video: sprdfd: disable ESD feature
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / leds / leds-sprd-kpled-2723.c
1 /*
2 * Copyright (C) 2012 Spreadtrum Communications Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 */
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/leds.h>
18 #include <linux/err.h>
19 #include <linux/delay.h>
20 #include <linux/slab.h>
21 #include <soc/sprd/adi.h>
22 #include <soc/sprd/adc.h>
23 #include <soc/sprd/sci_glb_regs.h>
24 #ifdef CONFIG_HAS_EARLYSUSPEND
25 #include <linux/earlysuspend.h>
26 #endif
27 #include <linux/of.h>
28 #include <linux/leds-sprd-kpled-2723.h>
29 //#define SPRD_KPLED_DBG
30 #ifdef SPRD_KPLED_DBG
31 #define ENTER printk(KERN_INFO "[SPRD_KPLED_DBG] func: %s  line: %04d\n", __func__, __LINE__);
32 #define PRINT_DBG(x...)  printk(KERN_INFO "[SPRD_KPLED_DBG] " x)
33 #define PRINT_INFO(x...)  printk(KERN_INFO "[SPRD_KPLED_INFO] " x)
34 #define PRINT_WARN(x...)  printk(KERN_INFO "[SPRD_KPLED_WARN] " x)
35 #define PRINT_ERR(format,x...)  printk(KERN_ERR "[SPRD_KPLED_ERR] func: %s  line: %04d  info: " format, __func__, __LINE__, ## x)
36 #else
37 #define ENTER
38 #define PRINT_DBG(x...)
39 #define PRINT_INFO(x...)  printk(KERN_INFO "[SPRD_KPLED_INFO] " x)
40 #define PRINT_WARN(x...)  printk(KERN_INFO "[SPRD_KPLED_WARN] " x)
41 #define PRINT_ERR(format,x...)  printk(KERN_ERR "[SPRD_KPLED_ERR] func: %s  line: %04d  info: " format, __func__, __LINE__, ## x)
42 #endif
43 #if 0
44 #define SPRD_ANA_BASE           (SPRD_MISC_BASE + 0x8800)
45
46 #define ANA_REG_BASE            SPRD_ANA_BASE
47
48 #define ANA_LED_CTRL           (ANA_REG_BASE + 0xF4)
49 #endif
50 #define KPLED_CTL               (ANA_REGS_GLB_BASE + 0xf4)
51
52 #define KPLED_V_SHIFT           12
53 #define KPLED_V_MSK             (0x0F << KPLED_V_SHIFT)
54 #define LDO_KPLED_PD                    (1 << 8)
55 #define LDO_KPLED_V_SHIFT               (0x00)
56 #define LDO_KPLED_V_MSK                 (0xff)
57 #define KPLED_PD                (1 << 11)
58 #define KPLED_PULLDOWN_EN               (1 << 10)
59
60 /* sprd keypad backlight */
61 struct sprd_kpled {
62         struct platform_device *dev;
63         struct mutex mutex;
64         struct work_struct work;
65         spinlock_t value_lock;
66         enum led_brightness value;
67         struct led_classdev cdev;
68         int enabled;
69                 int brightness_max;
70                 int brightness_min;
71                 int run_mode;
72 #ifdef CONFIG_HAS_EARLYSUSPEND
73         struct early_suspend    early_suspend;
74 #endif
75
76 };
77
78 #define to_sprd_led(led_cdev) \
79         container_of(led_cdev, struct sprd_kpled, cdev)
80
81 static inline uint32_t kpled_read(uint32_t reg)
82 {
83         return sci_adi_read(reg);
84 }
85
86 static void sprd_kpled_set_brightness(struct sprd_kpled *led)
87 {
88                 unsigned long brightness = led->value;
89                 unsigned long brightness_level;
90         brightness_level = brightness;
91
92                 PRINT_INFO("sprd_kpled_set_brightness:led->run_mode = %d\n",led->run_mode);
93         if(brightness_level > 255)
94                 brightness_level = 255;
95
96         /*brightness steps = 16*/
97         if(led->run_mode == 1){
98                 sci_adi_write(KPLED_CTL, ((brightness_level << KPLED_V_SHIFT) & KPLED_V_MSK), KPLED_V_MSK);
99                 }
100         else
101                 sci_adi_write(KPLED_CTL, ((brightness_level << LDO_KPLED_V_SHIFT) & LDO_KPLED_V_MSK), LDO_KPLED_V_MSK);
102                         PRINT_INFO("reg:0x%08X set_val:0x%08X  brightness:%ld  brightness_level:%ld(0~15)\n", \
103                    KPLED_CTL, kpled_read(KPLED_CTL), brightness, brightness_level);
104 }
105
106 static void sprd_kpled_enable(struct sprd_kpled *led)
107 {
108         if(led->run_mode == 1){
109                 sci_adi_clr(KPLED_CTL, KPLED_PD);
110                 }
111         else{
112                 sci_adi_set(KPLED_CTL, KPLED_PULLDOWN_EN);
113                         sci_adi_clr(KPLED_CTL, LDO_KPLED_PD);
114                 }
115         PRINT_INFO("sprd_kpled_enable\n");
116         sprd_kpled_set_brightness(led);
117         led->enabled = 1;
118 }
119
120 static void sprd_kpled_disable(struct sprd_kpled *led)
121 {
122         if(led->run_mode == 1){
123                 sci_adi_set(KPLED_CTL, KPLED_PD);
124                 }
125         else{
126                 sci_adi_set(KPLED_CTL, KPLED_PULLDOWN_EN);
127                         sci_adi_set(KPLED_CTL, LDO_KPLED_PD);
128                 }
129         PRINT_INFO("sprd_kpled_disable\n");
130         led->enabled = 0;
131 }
132
133 static void sprd_kpled_work(struct work_struct *work)
134 {
135         struct sprd_kpled *led = container_of(work, struct sprd_kpled, work);
136         unsigned long flags;
137
138         mutex_lock(&led->mutex);
139         spin_lock_irqsave(&led->value_lock, flags);
140         if (led->value == LED_OFF) {
141                 spin_unlock_irqrestore(&led->value_lock, flags);
142                 sprd_kpled_disable(led);
143                 goto out;
144         }
145         spin_unlock_irqrestore(&led->value_lock, flags);
146         sprd_kpled_enable(led);
147 out:
148         mutex_unlock(&led->mutex);
149 }
150
151 static void sprd_kpled_set(struct led_classdev *led_cdev,
152                            enum led_brightness value)
153 {
154         struct sprd_kpled *led = to_sprd_led(led_cdev);
155         unsigned long flags;
156
157         PRINT_INFO("sprd_kpled_set!\n");
158         spin_lock_irqsave(&led->value_lock, flags);
159         led->value = value;
160         spin_unlock_irqrestore(&led->value_lock, flags);
161
162         schedule_work(&led->work);
163 }
164
165 static void sprd_kpled_shutdown(struct platform_device *dev)
166 {
167         struct sprd_kpled *led = platform_get_drvdata(dev);
168
169         mutex_lock(&led->mutex);
170         sprd_kpled_disable(led);
171         mutex_unlock(&led->mutex);
172 }
173
174 #ifdef CONFIG_EARLYSUSPEND
175 static void sprd_kpled_early_suspend(struct early_suspend *es)
176 {
177         struct sprd_kpled *led = container_of(es, struct sprd_kpled, early_suspend);
178         PRINT_INFO("sprd_kpled_early_suspend\n");
179 }
180
181 static void sprd_kpled_late_resume(struct early_suspend *es)
182 {
183         struct sprd_kpled *led = container_of(es, struct sprd_kpled, early_suspend);
184         PRINT_INFO("sprd_kpled_late_resume\n");
185 }
186 #endif
187
188 #ifdef CONFIG_OF
189 static struct sprd_kpled_2723_platform_data *sprd_kpled_2723_parse_dt(struct platform_device *pdev)
190 {
191         int ret;
192         struct device_node *np = pdev->dev.of_node;
193         struct sprd_kpled_2723_platform_data *pdata = NULL;
194
195         pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
196         if (!pdata) {
197                 dev_err(pdev, "sprd_kpled Could not allocate pdata");
198                 return NULL;
199         }
200         ret = of_property_read_u32(np, "brightness_max", &pdata->brightness_max);
201         if(ret){
202                 dev_err(pdev, "fail to get pdata->brightness_max\n");
203                 goto fail;
204         }
205         ret = of_property_read_u32(np, "brightness_min", &pdata->brightness_min);
206         if(ret){
207                 dev_err(pdev, "fail to get pdata->brightness_min\n");
208                 goto fail;
209         }
210         ret = of_property_read_u32(np, "run_mode", &pdata->run_mode);
211         if(ret){
212                 dev_err(pdev, "fail to get pdata->run_mode\n");
213                 goto fail;
214         }
215
216         return pdata;
217 fail:
218         kfree(pdata);
219         return NULL;
220 }
221 #endif
222
223 static int sprd_kpled_probe(struct platform_device *dev)
224 {
225         struct sprd_kpled *led;
226         int ret;
227                 struct sprd_kpled_2723_platform_data *pdata = NULL;
228
229         #ifdef CONFIG_OF
230
231         struct device_node *np = dev->dev.of_node;
232
233         if(np) {
234                 pdata = sprd_kpled_2723_parse_dt(dev);
235                 if (pdata == NULL) {
236                         PRINT_ERR("get dts data failed!\n");
237                         return -ENODEV;
238                 }
239         } else {
240                 PRINT_ERR("dev.of_node is NULL!\n");
241                 return -ENODEV;
242         }
243         #else
244                 pdata = dev->dev.platform_data;
245         if (!pdata){
246                 PRINT_ERR("No kpled_platform data!\n");
247                 return -ENODEV;
248         }
249         #endif
250
251         led = kzalloc(sizeof(struct sprd_kpled), GFP_KERNEL);
252         if (led == NULL) {
253                 dev_err(&dev->dev, "No memory for device\n");
254                 return -ENOMEM;
255         }
256
257         led->cdev.brightness_set = sprd_kpled_set;
258         //led->cdev.default_trigger = "heartbeat";
259         led->cdev.default_trigger = "none";
260         led->cdev.name = "keyboard-backlight";
261         led->cdev.brightness_get = NULL;
262         led->cdev.flags |= LED_CORE_SUSPENDRESUME;
263         led->enabled = 0;
264                 led->brightness_max = pdata->brightness_max;
265                 led->brightness_min = pdata->brightness_min;
266                 led->run_mode = pdata->run_mode;
267                 PRINT_INFO("led->run_mode = %d\n",led->run_mode);
268                 PRINT_INFO("led->brightness_max = %d\n",led->brightness_max);
269
270         spin_lock_init(&led->value_lock);
271         mutex_init(&led->mutex);
272         INIT_WORK(&led->work, sprd_kpled_work);
273         led->value = LED_OFF;
274         platform_set_drvdata(dev, led);
275
276         /* register our new led device */
277
278         ret = led_classdev_register(&dev->dev, &led->cdev);
279         if (ret < 0) {
280                 dev_err(&dev->dev, "led_classdev_register failed\n");
281                 kfree(led);
282                 return ret;
283         }
284
285 #ifdef CONFIG_HAS_EARLYSUSPEND
286         led->early_suspend.suspend = sprd_kpled_early_suspend;
287         led->early_suspend.resume  = sprd_kpled_late_resume;
288         led->early_suspend.level   = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
289         register_early_suspend(&led->early_suspend);
290 #endif
291
292         sprd_kpled_disable(led);//disabled by default
293
294         return 0;
295 }
296
297 static int sprd_kpled_remove(struct platform_device *dev)
298 {
299         struct sprd_kpled *led = platform_get_drvdata(dev);
300
301         led_classdev_unregister(&led->cdev);
302         flush_scheduled_work();
303         led->value = LED_OFF;
304         led->enabled = 1;
305         sprd_kpled_disable(led);
306         kfree(led);
307
308         return 0;
309 }
310
311 static const struct of_device_id kpled_2723_of_match[] = {
312         { .compatible = "sprd,sprd-kpled-2723", },
313         { }
314 };
315
316 static struct platform_driver sprd_kpled_2723_driver = {
317         .driver = {
318                 .name  = "sprd-kpled-2723",
319                 .owner = THIS_MODULE,
320                 .of_match_table = kpled_2723_of_match,
321         },
322         .probe    = sprd_kpled_probe,
323         .remove   = sprd_kpled_remove,
324         .shutdown = sprd_kpled_shutdown,
325 };
326
327 static int __init sprd_kpled_2723_init(void)
328 {
329                 PRINT_INFO("Locate in sprd_kpled_2723_init!\n");
330         return platform_driver_register(&sprd_kpled_2723_driver);
331 }
332
333 static void sprd_kpled_2723_exit(void)
334 {
335         platform_driver_unregister(&sprd_kpled_2723_driver);
336 }
337
338 module_init(sprd_kpled_2723_init);
339 module_exit(sprd_kpled_2723_exit);
340
341 MODULE_AUTHOR("ya huang <ya.huang@spreadtrum.com>");
342 MODULE_DESCRIPTION("Sprd Keyboard backlight driver for 2723s");
343 MODULE_LICENSE("GPL");
344 MODULE_ALIAS("platform:sprd_kpled_2723");
345
346
347