video: sprdfd: disable ESD feature
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / leds / leds-sprd-rgb.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 <mach/hardware.h>
22 #include <mach/adi.h>
23 #include <mach/adc.h>
24
25 #define sprd_rgbled_DBG
26 #ifdef sprd_rgbled_DBG
27 #define ENTER printk(KERN_INFO "[sprd_rgbled_DBG] func: %s  line: %04d\n", __func__, __LINE__);
28 #define PRINT_DBG(x...)  printk(KERN_INFO "[sprd_rgbled_DBG] " x)
29 #define PRINT_INFO(x...)  printk(KERN_INFO "[sprd_rgbled_INFO] " x)
30 #define PRINT_WARN(x...)  printk(KERN_INFO "[sprd_rgbled_WARN] " x)
31 #define PRINT_ERR(format,x...)  printk(KERN_ERR "[sprd_rgbled_ERR] func: %s  line: %04d  info: " format, __func__, __LINE__, ## x)
32 #else
33 #define ENTER
34 #define PRINT_DBG(x...)
35 #define PRINT_INFO(x...)  printk(KERN_INFO "[sprd_rgbled_INFO] " x)
36 #define PRINT_WARN(x...)  printk(KERN_INFO "[sprd_rgbled_WARN] " x)
37 #define PRINT_ERR(format,x...)  printk(KERN_ERR "[sprd_rgbled_ERR] func: %s  line: %04d  info: " format, __func__, __LINE__, ## x)
38 #endif
39
40 #ifdef CONFIG_ARCH_SCX35
41 #define ANA_BTLC_BASE            (SPRD_MISC_BASE + 0x83c0)
42 #define ANA_BTLC_CTRL            (ANA_BTLC_BASE + 0x00)
43 #endif
44
45 enum sprd_led_type
46 {
47         SPRD_LED_TYPE_R = 0,
48         SPRD_LED_TYPE_G,
49         SPRD_LED_TYPE_B,
50         SPRD_LED_TYPE_TOTAL
51 };
52
53
54 static char * sprd_rgbled_name[SPRD_LED_TYPE_TOTAL] =
55 {
56         "red",              
57         "green",              
58         "blue",
59 };
60
61
62 /* sprd rgb led */
63 struct sprd_rgbled {
64         struct platform_device *dev;
65         struct mutex mutex;
66         struct work_struct work;
67         spinlock_t value_lock;
68         enum led_brightness value;
69         struct led_classdev cdev;
70
71         int suspend;
72
73 };
74
75 static struct sprd_rgbled *g_sprd_rgbled[SPRD_LED_TYPE_TOTAL];
76
77
78 #define to_sprd_rgbled(led_cdev) \
79         container_of(led_cdev, struct sprd_rgbled, cdev)
80
81 static void sprd_rgbled_enable(struct sprd_rgbled *led)
82 {
83
84 #ifdef CONFIG_ARCH_SCX35
85         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_R]) == 0)
86         {
87                 sci_adi_set(ANA_BTLC_CTRL, 0x00F);   
88         }
89
90         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_G]) == 0)
91         {
92                 sci_adi_set(ANA_BTLC_CTRL, 0x0F0); 
93         }
94
95         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_B]) == 0)
96         {
97                 sci_adi_set(ANA_BTLC_CTRL, 0xF00); 
98         }
99 #endif
100
101         PRINT_INFO("sprd_rgbled_enable\n");
102
103 }
104
105 static void sprd_rgbled_disable(struct sprd_rgbled *led)
106 {
107 #ifdef CONFIG_ARCH_SCX35
108
109         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_R]) == 0)
110         {
111                 sci_adi_clr(ANA_BTLC_CTRL, 0x00F);   
112         }
113
114         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_G]) == 0)
115         {
116                 sci_adi_clr(ANA_BTLC_CTRL, 0x0F0); 
117         }
118
119         if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_B]) == 0)
120         {
121                 sci_adi_clr(ANA_BTLC_CTRL, 0xF00); 
122         }
123 #endif
124
125         PRINT_INFO("sprd_rgbled_disable\n");
126 }
127
128 static void sprd_rgbled_work(struct work_struct *work)
129 {
130         struct sprd_rgbled *led = container_of(work, struct sprd_rgbled, work);
131         unsigned long flags;
132
133         mutex_lock(&led->mutex);
134         spin_lock_irqsave(&led->value_lock, flags);
135         if (led->value == LED_OFF) {
136                 spin_unlock_irqrestore(&led->value_lock, flags);
137                 sprd_rgbled_disable(led);
138                 goto out;
139         }
140         spin_unlock_irqrestore(&led->value_lock, flags);
141         sprd_rgbled_enable(led);
142 out:
143         mutex_unlock(&led->mutex);
144 }
145
146 static void sprd_rgbled_set(struct led_classdev *led_cdev,
147                 enum led_brightness value)
148 {
149         struct sprd_rgbled *led = to_sprd_rgbled(led_cdev);
150         unsigned long flags;
151
152         spin_lock_irqsave(&led->value_lock, flags);
153         led->value = value;
154         spin_unlock_irqrestore(&led->value_lock, flags);
155
156         if(1 == led->suspend) {
157                 PRINT_WARN("Do NOT change brightness in suspend mode\n");
158                 return;
159         }
160
161         schedule_work(&led->work);      
162 }
163
164 static void sprd_rgbled_shutdown(struct platform_device *dev)
165 {
166         int i;
167
168         for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++)
169         {
170                 if (!g_sprd_rgbled[i])
171                         continue;
172
173                 mutex_lock(&g_sprd_rgbled[i]->mutex);
174                 sprd_rgbled_disable(g_sprd_rgbled[i]);
175                 mutex_unlock(&g_sprd_rgbled[i]->mutex);
176         }
177 }
178
179
180 static int sprd_rgbled_probe(struct platform_device *dev)
181 {
182         int i;
183         int ret;
184
185         for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++) 
186         {
187                 g_sprd_rgbled[i] = kzalloc(sizeof(struct sprd_rgbled), GFP_KERNEL);
188
189                 if (g_sprd_rgbled[i] == NULL) 
190                 {
191                         dev_err(&dev->dev, "No memory for device\n");
192                         ret = -ENOMEM;
193                         goto err;
194                 }
195
196                 g_sprd_rgbled[i]->cdev.brightness_set = sprd_rgbled_set;
197                 g_sprd_rgbled[i]->cdev.name = sprd_rgbled_name[i];
198                 g_sprd_rgbled[i]->cdev.brightness_get = NULL;
199                 //g_sprd_rgbled[i]->cdev.flags |= LED_CORE_SUSPENDRESUME;
200
201                 spin_lock_init(&g_sprd_rgbled[i]->value_lock);
202                 mutex_init(&g_sprd_rgbled[i]->mutex);
203                 INIT_WORK(&g_sprd_rgbled[i]->work, sprd_rgbled_work);
204                 g_sprd_rgbled[i]->value = LED_OFF;
205
206
207                 ret = led_classdev_register(&dev->dev, &g_sprd_rgbled[i]->cdev);
208                 if (ret < 0) 
209                 {
210                         goto err;
211                 }
212
213                 g_sprd_rgbled[i]->value = 15;//set default brightness
214                 g_sprd_rgbled[i]->suspend = 0;
215
216         }
217
218         return 0;
219 err:
220         if (i) 
221         {
222                 for (i = i-1; i >=0; i--) 
223                 {
224                         if (!g_sprd_rgbled[i])
225                                 continue;
226                         led_classdev_unregister(&g_sprd_rgbled[i]->cdev);
227                         kfree(g_sprd_rgbled[i]);
228                         g_sprd_rgbled[i] = NULL;
229                 }
230         }
231
232         return ret;
233 }
234
235 static int sprd_rgbled_remove(struct platform_device *dev)
236 {
237         int i;
238
239         for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++)
240         {
241                 if (!g_sprd_rgbled[i])
242                         continue;
243
244                 led_classdev_unregister(&g_sprd_rgbled[i]->cdev);
245                 g_sprd_rgbled[i]->value = LED_OFF;
246                 sprd_rgbled_disable(g_sprd_rgbled[i]);
247                 cancel_work_sync(&g_sprd_rgbled[i]->work);
248                 kfree(g_sprd_rgbled[i]);
249                 g_sprd_rgbled[i] = NULL;
250         }
251
252         return 0;
253 }
254
255 static struct platform_driver sprd_rgbled_driver = {
256         .driver = {
257                 .name  = "rgb-led",
258                 .owner = THIS_MODULE,
259         },
260         .probe    = sprd_rgbled_probe,
261         .remove   = sprd_rgbled_remove,
262         .shutdown = sprd_rgbled_shutdown,
263 };
264
265 module_platform_driver(sprd_rgbled_driver);
266
267 MODULE_AUTHOR("Lu Chai <lu.chai@spreadtrum.com>");
268 MODULE_DESCRIPTION("Sprd rgb led driver");
269 MODULE_LICENSE("GPL");
270 MODULE_ALIAS("platform:rgb-led");