2 * Copyright (C) 2012 Spreadtrum Communications Inc.
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.
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.
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>
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)
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)
40 #ifdef CONFIG_ARCH_SCX35
41 #define ANA_BTLC_BASE (SPRD_MISC_BASE + 0x83c0)
42 #define ANA_BTLC_CTRL (ANA_BTLC_BASE + 0x00)
54 static char * sprd_rgbled_name[SPRD_LED_TYPE_TOTAL] =
64 struct platform_device *dev;
66 struct work_struct work;
67 spinlock_t value_lock;
68 enum led_brightness value;
69 struct led_classdev cdev;
75 static struct sprd_rgbled *g_sprd_rgbled[SPRD_LED_TYPE_TOTAL];
78 #define to_sprd_rgbled(led_cdev) \
79 container_of(led_cdev, struct sprd_rgbled, cdev)
81 static void sprd_rgbled_enable(struct sprd_rgbled *led)
84 #ifdef CONFIG_ARCH_SCX35
85 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_R]) == 0)
87 sci_adi_set(ANA_BTLC_CTRL, 0x00F);
90 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_G]) == 0)
92 sci_adi_set(ANA_BTLC_CTRL, 0x0F0);
95 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_B]) == 0)
97 sci_adi_set(ANA_BTLC_CTRL, 0xF00);
101 PRINT_INFO("sprd_rgbled_enable\n");
105 static void sprd_rgbled_disable(struct sprd_rgbled *led)
107 #ifdef CONFIG_ARCH_SCX35
109 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_R]) == 0)
111 sci_adi_clr(ANA_BTLC_CTRL, 0x00F);
114 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_G]) == 0)
116 sci_adi_clr(ANA_BTLC_CTRL, 0x0F0);
119 if(strcmp(led->cdev.name,sprd_rgbled_name[SPRD_LED_TYPE_B]) == 0)
121 sci_adi_clr(ANA_BTLC_CTRL, 0xF00);
125 PRINT_INFO("sprd_rgbled_disable\n");
128 static void sprd_rgbled_work(struct work_struct *work)
130 struct sprd_rgbled *led = container_of(work, struct sprd_rgbled, work);
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);
140 spin_unlock_irqrestore(&led->value_lock, flags);
141 sprd_rgbled_enable(led);
143 mutex_unlock(&led->mutex);
146 static void sprd_rgbled_set(struct led_classdev *led_cdev,
147 enum led_brightness value)
149 struct sprd_rgbled *led = to_sprd_rgbled(led_cdev);
152 spin_lock_irqsave(&led->value_lock, flags);
154 spin_unlock_irqrestore(&led->value_lock, flags);
156 if(1 == led->suspend) {
157 PRINT_WARN("Do NOT change brightness in suspend mode\n");
161 schedule_work(&led->work);
164 static void sprd_rgbled_shutdown(struct platform_device *dev)
168 for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++)
170 if (!g_sprd_rgbled[i])
173 mutex_lock(&g_sprd_rgbled[i]->mutex);
174 sprd_rgbled_disable(g_sprd_rgbled[i]);
175 mutex_unlock(&g_sprd_rgbled[i]->mutex);
180 static int sprd_rgbled_probe(struct platform_device *dev)
185 for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++)
187 g_sprd_rgbled[i] = kzalloc(sizeof(struct sprd_rgbled), GFP_KERNEL);
189 if (g_sprd_rgbled[i] == NULL)
191 dev_err(&dev->dev, "No memory for device\n");
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;
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;
207 ret = led_classdev_register(&dev->dev, &g_sprd_rgbled[i]->cdev);
213 g_sprd_rgbled[i]->value = 15;//set default brightness
214 g_sprd_rgbled[i]->suspend = 0;
222 for (i = i-1; i >=0; i--)
224 if (!g_sprd_rgbled[i])
226 led_classdev_unregister(&g_sprd_rgbled[i]->cdev);
227 kfree(g_sprd_rgbled[i]);
228 g_sprd_rgbled[i] = NULL;
235 static int sprd_rgbled_remove(struct platform_device *dev)
239 for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++)
241 if (!g_sprd_rgbled[i])
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;
255 static struct platform_driver sprd_rgbled_driver = {
258 .owner = THIS_MODULE,
260 .probe = sprd_rgbled_probe,
261 .remove = sprd_rgbled_remove,
262 .shutdown = sprd_rgbled_shutdown,
265 module_platform_driver(sprd_rgbled_driver);
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");