blob: 1c72b1ca15a3cd2c5654e1d63b0279d8ed2f4367 [file] [log] [blame]
Flemmard0fd9b762013-04-26 01:11:12 -07001
2/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
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
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/platform_device.h>
21#include <linux/leds.h>
22#include <linux/workqueue.h>
23#include <linux/err.h>
24#include <linux/wakelock.h>
25#include <linux/mfd/pm8xxx/core.h>
26#include <linux/mfd/pm8xxx/pwm.h>
27#include <linux/leds-pm8xxx-htc.h>
28
29#define SSBI_REG_ADDR_DRV_KEYPAD 0x48
30#define PM8XXX_DRV_KEYPAD_BL_MASK 0xf0
31#define PM8XXX_DRV_KEYPAD_BL_SHIFT 0x04
32
33#define SSBI_REG_ADDR_FLASH_DRV0 0x49
34#define PM8XXX_DRV_FLASH_MASK 0xf0
35#define PM8XXX_DRV_FLASH_SHIFT 0x04
36
37#define SSBI_REG_ADDR_FLASH_DRV1 0xFB
38
39#define SSBI_REG_ADDR_LED_CTRL_BASE 0x131
40#define SSBI_REG_ADDR_LED_CTRL(n) (SSBI_REG_ADDR_LED_CTRL_BASE + (n))
41#define PM8XXX_DRV_LED_CTRL_MASK 0xf8
42#define PM8XXX_DRV_LED_CTRL_SHIFT 0x03
43
44#define MAX_FLASH_LED_CURRENT 300
45#define MAX_LC_LED_CURRENT 40
46#define MAX_KP_BL_LED_CURRENT 300
47
48#define PM8XXX_ID_LED_CURRENT_FACTOR 2
49#define PM8XXX_ID_FLASH_CURRENT_FACTOR 20
50
51#define PM8XXX_FLASH_MODE_DBUS1 1
52#define PM8XXX_FLASH_MODE_DBUS2 2
53#define PM8XXX_FLASH_MODE_PWM 3
54
55#define PM8XXX_LED_OFFSET(id) (PM8XXX_ID_LED_0 - (id))
56
57#define MAX_LC_LED_BRIGHTNESS 20
58#define MAX_FLASH_BRIGHTNESS 15
59#define MAX_KB_LED_BRIGHTNESS 15
60
61#define PM8XXX_LPG_CTL_REGS 7
62
63#define LED_DBG(fmt, ...) \
64 ({ if (0) printk(KERN_DEBUG "[LED]" fmt, ##__VA_ARGS__); })
65#define LED_INFO(fmt, ...) \
66 printk(KERN_INFO "[LED]" fmt, ##__VA_ARGS__)
67#define LED_ERR(fmt, ...) \
68 printk(KERN_ERR "[LED][ERR]" fmt, ##__VA_ARGS__)
69
70static struct workqueue_struct *g_led_work_queue;
71struct wake_lock pmic_led_wake_lock;
72static struct pm8xxx_led_data *pm8xxx_leds , *for_key_led_data, *green_back_led_data, *amber_back_led_data;
73static int flag_hold_virtual_key = 0;
74static int virtual_key_state;
75static int current_blink = 0;
76u8 pm8xxxx_led_pwm_mode(int flag)
77{
78 u8 mode = 0;
79 switch (flag) {
80 case PM8XXX_ID_LED_0:
81 mode = PM8XXX_LED_MODE_PWM3;
82 break;
83 case PM8XXX_ID_LED_1:
84 mode = PM8XXX_LED_MODE_PWM2;
85 break;
86 case PM8XXX_ID_LED_2:
87 mode = PM8XXX_LED_MODE_PWM1;
88 break;
89 }
90 return mode;
91}
92
93static void led_fade_do_work(struct work_struct *work)
94{
95 struct pm8xxx_led_data *led;
96 int rc, offset;
97 u8 level;
98
99 led = container_of(work, struct pm8xxx_led_data, fade_delayed_work.work);
100
101 level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
102 offset = PM8XXX_LED_OFFSET(led->id);
103 led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
104 led->reg |= level;
105 rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
106 if (rc)
107 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
108}
109void pm8xxx_led_current_set_for_key(int brightness_key)
110{
111 int rc, offset;
112 static u8 level, register_key;
113
114 LED_INFO("%s brightness_key: %d\n", __func__,brightness_key);
115
116 if (brightness_key) {
117 flag_hold_virtual_key = 1;
118 level = (40 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
119 offset = PM8XXX_LED_OFFSET(for_key_led_data->id);
120 register_key = pm8xxxx_led_pwm_mode(for_key_led_data->id);
121 register_key &= ~PM8XXX_DRV_LED_CTRL_MASK;
122 register_key |= level;
123 rc = pm8xxx_writeb(for_key_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), register_key);
124 if (rc)
125 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, PM8XXX_ID_LED_0, rc);
126 pwm_config(for_key_led_data->pwm_led, 320000, 640000);
127 pwm_enable(for_key_led_data->pwm_led);
128 } else {
129 pwm_disable(for_key_led_data->pwm_led);
130 level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
131 offset = PM8XXX_LED_OFFSET(for_key_led_data->id);
132 register_key = pm8xxxx_led_pwm_mode(for_key_led_data->id);
133 register_key &= ~PM8XXX_DRV_LED_CTRL_MASK;
134 register_key |= level;
135 rc = pm8xxx_writeb(for_key_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), register_key);
136 if (rc)
137 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, PM8XXX_ID_LED_0, rc);
138 if (virtual_key_state != 0){
139 level = 0;
140 register_key = 0;
141 level = (40 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
142 offset = PM8XXX_LED_OFFSET(for_key_led_data->id);
143 register_key = pm8xxxx_led_pwm_mode(for_key_led_data->id);
144 register_key &= ~PM8XXX_DRV_LED_CTRL_MASK;
145 register_key |= level;
146 rc = pm8xxx_writeb(for_key_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), register_key);
147 if (rc)
148 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, PM8XXX_ID_LED_0, rc);
149 pwm_config(for_key_led_data->pwm_led, 64000, 64000);
150 pwm_enable(for_key_led_data->pwm_led);
151 }
152 flag_hold_virtual_key = 0;
153
154 }
155}
156static void pm8xxx_led_current_set(struct led_classdev *led_cdev, enum led_brightness brightness)
157{
158 struct pm8xxx_led_data *led = container_of(led_cdev, struct pm8xxx_led_data, cdev);
159 int rc, offset;
160 u8 level;
161
162 int *pduties;
163
164 LED_INFO("%s, bank:%d, brightness:%d\n", __func__, led->bank, brightness);
165 cancel_delayed_work_sync(&led->fade_delayed_work);
166 virtual_key_state = brightness;
167 if (flag_hold_virtual_key == 1) {
168 LED_INFO("%s, key control \n", __func__);
169 return;
170 }
171
172 if(brightness) {
173 level = (led->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
174 offset = PM8XXX_LED_OFFSET(led->id);
175 led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
176 led->reg |= level;
177 rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
178 if (rc)
179 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
180
181 if (led->function_flags & LED_BRETH_FUNCTION) {
182 pduties = led->duties;
183 pm8xxx_pwm_lut_config(led->pwm_led,
184 led->period_us,
185 pduties,
186 led->duty_time_ms,
187 led->start_index,
188 led->duites_size,
189 0, 0,
190 led->lut_flag);
191 pm8xxx_pwm_lut_enable(led->pwm_led, 0);
192 pm8xxx_pwm_lut_enable(led->pwm_led, 1);
193 } else {
194 pwm_config(led->pwm_led, 64000, 64000);
195 pwm_enable(led->pwm_led);
196 }
197 } else {
198 if (led->function_flags & LED_BRETH_FUNCTION) {
199 wake_lock_timeout(&pmic_led_wake_lock, HZ*2);
200 pduties = led->duties + led->duites_size;
201 pm8xxx_pwm_lut_config(led->pwm_led,
202 led->period_us,
203 pduties,
204 led->duty_time_ms,
205 led->start_index,
206 led->duites_size,
207 0, 0,
208 led->lut_flag);
209 pm8xxx_pwm_lut_enable(led->pwm_led, 0);
210 pm8xxx_pwm_lut_enable(led->pwm_led, 1);
211 queue_delayed_work(g_led_work_queue,
212 &led->fade_delayed_work,
213 msecs_to_jiffies(led->duty_time_ms*led->duites_size));
214 } else {
215 pwm_disable(led->pwm_led);
216 level = (0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
217 offset = PM8XXX_LED_OFFSET(led->id);
218 led->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
219 led->reg |= level;
220 rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), led->reg);
221 if (rc)
222 LED_ERR("%s can't set (%d) led value rc=%d\n", __func__, led->id, rc);
223 }
224 }
225}
226
227static void pm8xxx_led_gpio_set(struct led_classdev *led_cdev, enum led_brightness brightness)
228{
229 int rc, offset;
230 u8 level;
231
232 struct pm8xxx_led_data *led = container_of(led_cdev, struct pm8xxx_led_data, cdev);
233 LED_INFO("%s, bank:%d, brightness:%d sync: %d\n", __func__, led->bank, brightness, led->led_sync);
234 if (led->gpio_status_switch != NULL)
235 led->gpio_status_switch(0);
236 pwm_disable(led->pwm_led);
237 if(led->led_sync) {
238 if (!strcmp(led->cdev.name, "green")){
239 if (green_back_led_data->gpio_status_switch != NULL)
240 green_back_led_data->gpio_status_switch(0);
241 pwm_disable(green_back_led_data->pwm_led);
242 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
243 offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
244 green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
245 green_back_led_data->reg |= level;
246 rc = pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
247 }
248 if (!strcmp(led->cdev.name, "amber")){
249 if (amber_back_led_data->gpio_status_switch != NULL)
250 amber_back_led_data->gpio_status_switch(0);
251 pwm_disable(amber_back_led_data->pwm_led);
252 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
253 offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
254 amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
255 amber_back_led_data->reg |= level;
256 rc = pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
257 }
258 }
259 if (brightness) {
260 if (led->gpio_status_switch != NULL)
261 led->gpio_status_switch(1);
262 pwm_config(led->pwm_led, 6400 * led->pwm_coefficient / 100, 6400);
263 pwm_enable(led->pwm_led);
264 if(led->led_sync) {
265 if (!strcmp(led->cdev.name, "green")) {
266 if (green_back_led_data->gpio_status_switch != NULL)
267 green_back_led_data->gpio_status_switch(1);
268 level = (green_back_led_data->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
269 offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
270 green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
271 green_back_led_data->reg |= level;
272 rc = pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
273 pwm_config(green_back_led_data->pwm_led, 64000, 64000);
274 pwm_enable(green_back_led_data->pwm_led);
275 }
276 if (!strcmp(led->cdev.name, "amber")) {
277 if (amber_back_led_data->gpio_status_switch != NULL)
278 amber_back_led_data->gpio_status_switch(1);
279 level = (amber_back_led_data->out_current << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
280 offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
281 amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
282 amber_back_led_data->reg |= level;
283 rc = pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
284 pwm_config(amber_back_led_data->pwm_led, 64000, 64000);
285 pwm_enable(amber_back_led_data->pwm_led);
286 }
287 }
288 }
289}
290
291static void led_work_func(struct work_struct *work)
292{
293 struct pm8xxx_led_data *ldata;
294 int rc, offset;
295 u8 level;
296
297 ldata = container_of(work, struct pm8xxx_led_data, led_work);
298 LED_INFO("%s: bank %d sync %d\n", __func__, ldata->bank, ldata->led_sync);
299 pwm_disable(ldata->pwm_led);
300 if (ldata->gpio_status_switch != NULL)
301 ldata->gpio_status_switch(0);
302 if(ldata->led_sync) {
303 if (!strcmp(ldata->cdev.name, "green")){
304 if (green_back_led_data->gpio_status_switch != NULL)
305 green_back_led_data->gpio_status_switch(0);
306 pwm_disable(green_back_led_data->pwm_led);
307 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
308 offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
309 green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
310 green_back_led_data->reg |= level;
311 rc = pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
312 }
313 if (!strcmp(ldata->cdev.name, "amber")){
314 if (amber_back_led_data->gpio_status_switch != NULL)
315 amber_back_led_data->gpio_status_switch(0);
316 pwm_disable(amber_back_led_data->pwm_led);
317 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
318 offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
319 amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
320 amber_back_led_data->reg |= level;
321 rc = pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
322 }
323 }
324}
325
326static void led_alarm_handler(struct alarm *alarm)
327{
328 struct pm8xxx_led_data *ldata;
329
330 ldata = container_of(alarm, struct pm8xxx_led_data, led_alarm);
331 queue_work(g_led_work_queue, &ldata->led_work);
332}
333
334static void led_blink_do_work(struct work_struct *work)
335{
336 struct pm8xxx_led_data *led;
337
338 led = container_of(work, struct pm8xxx_led_data, blink_delayed_work.work);
339
340 if (led->gpio_status_switch != NULL)
341 led->gpio_status_switch(1);
342 pwm_config(led->pwm_led, led->duty_time_ms * 1000, led->period_us);
343 pwm_enable(led->pwm_led);
344 if(led->led_sync) {
345 if (!strcmp(led->cdev.name, "green")) {
346 if (green_back_led_data->gpio_status_switch != NULL)
347 green_back_led_data->gpio_status_switch(1);
348 pwm_config(green_back_led_data->pwm_led, green_back_led_data->duty_time_ms * 1000, green_back_led_data->period_us);
349 pwm_enable(green_back_led_data->pwm_led);
350 }
351 if (!strcmp(led->cdev.name, "amber")) {
352 if (amber_back_led_data->gpio_status_switch != NULL)
353 amber_back_led_data->gpio_status_switch(1);
354 pwm_config(amber_back_led_data->pwm_led, amber_back_led_data->duty_time_ms * 1000, amber_back_led_data->period_us);
355 pwm_enable(amber_back_led_data->pwm_led);
356 }
357 }
358
359}
360
361static ssize_t pm8xxx_led_blink_show(struct device *dev,
362 struct device_attribute *attr,
363 char *buf)
364{
365 return sprintf(buf, "%d\n", current_blink);
366}
367
368static ssize_t pm8xxx_led_blink_store(struct device *dev,
369 struct device_attribute *attr,
370 const char *buf, size_t count)
371{
372 struct led_classdev *led_cdev;
373 struct pm8xxx_led_data *ldata;
374 int val;
375 int level, offset;
376
377 val = -1;
378 sscanf(buf, "%u", &val);
379 if (val < 0 || val > 255)
380 return -EINVAL;
381 current_blink= val;
382 led_cdev = (struct led_classdev *) dev_get_drvdata(dev);
383 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
384
385 LED_INFO("%s: bank %d blink %d sync %d\n", __func__, ldata->bank, val, ldata->led_sync);
386
387 switch (val) {
388 case BLINK_STOP:
389 if (ldata->gpio_status_switch != NULL)
390 ldata->gpio_status_switch(0);
391 pwm_disable(ldata->pwm_led);
392
393 if(ldata->led_sync) {
394 if (!strcmp(ldata->cdev.name, "green")) {
395 if (green_back_led_data->gpio_status_switch != NULL)
396 green_back_led_data->gpio_status_switch(0);
397 pwm_disable(green_back_led_data->pwm_led);
398 }
399 if (!strcmp(ldata->cdev.name, "amber")) {
400 if (amber_back_led_data->gpio_status_switch != NULL)
401 amber_back_led_data->gpio_status_switch(0);
402 pwm_disable(amber_back_led_data->pwm_led);
403 }
404 }
405 break;
406 case BLINK_UNCHANGE:
407 pwm_disable(ldata->pwm_led);
408 if (led_cdev->brightness) {
409 if (ldata->gpio_status_switch != NULL)
410 ldata->gpio_status_switch(1);
411 pwm_config(ldata->pwm_led, 6400 * ldata->pwm_coefficient / 100, 6400);
412 pwm_enable(ldata->pwm_led);
413
414 if(ldata->led_sync) {
415 if (!strcmp(ldata->cdev.name, "green")) {
416 if (green_back_led_data->gpio_status_switch != NULL)
417 green_back_led_data->gpio_status_switch(1);
418 pwm_config(green_back_led_data->pwm_led, 64000, 64000);
419 pwm_enable(green_back_led_data->pwm_led);
420 }
421 if (!strcmp(ldata->cdev.name, "amber")) {
422 if (amber_back_led_data->gpio_status_switch != NULL)
423 amber_back_led_data->gpio_status_switch(1);
424 pwm_config(amber_back_led_data->pwm_led, 64000, 64000);
425 pwm_enable(amber_back_led_data->pwm_led);
426 }
427 }
428 } else {
429 pwm_disable(ldata->pwm_led);
430 if (ldata->gpio_status_switch != NULL)
431 ldata->gpio_status_switch(0);
432
433 if(ldata->led_sync) {
434 if (!strcmp(ldata->cdev.name, "green")){
435 if (green_back_led_data->gpio_status_switch != NULL)
436 green_back_led_data->gpio_status_switch(0);
437 pwm_disable(green_back_led_data->pwm_led);
438 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
439 offset = PM8XXX_LED_OFFSET(green_back_led_data->id);
440 green_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
441 green_back_led_data->reg |= level;
442 pm8xxx_writeb(green_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), green_back_led_data->reg);
443 }
444 if (!strcmp(ldata->cdev.name, "amber")){
445 if (amber_back_led_data->gpio_status_switch != NULL)
446 amber_back_led_data->gpio_status_switch(0);
447 pwm_disable(amber_back_led_data->pwm_led);
448 level = ( 0 << PM8XXX_DRV_LED_CTRL_SHIFT) & PM8XXX_DRV_LED_CTRL_MASK;
449 offset = PM8XXX_LED_OFFSET(amber_back_led_data->id);
450 amber_back_led_data->reg &= ~PM8XXX_DRV_LED_CTRL_MASK;
451 amber_back_led_data->reg |= level;
452 pm8xxx_writeb(amber_back_led_data->dev->parent, SSBI_REG_ADDR_LED_CTRL(offset), amber_back_led_data->reg);
453 }
454 }
455 }
456 break;
457 case BLINK_64MS_PER_2SEC:
458 if (ldata->gpio_status_switch != NULL)
459 ldata->gpio_status_switch(1);
460 pwm_disable(ldata->pwm_led);
461 pwm_config(ldata->pwm_led, 64000, 2000000);
462 pwm_enable(ldata->pwm_led);
463
464 if(ldata->led_sync) {
465 if (!strcmp(ldata->cdev.name, "green")) {
466 if (green_back_led_data->gpio_status_switch != NULL)
467 green_back_led_data->gpio_status_switch(1);
468 pwm_disable(green_back_led_data->pwm_led);
469 pwm_config(green_back_led_data->pwm_led, 64000, 2000000);
470 pwm_enable(green_back_led_data->pwm_led);
471 }
472 if (!strcmp(ldata->cdev.name, "amber")) {
473 if (amber_back_led_data->gpio_status_switch != NULL)
474 amber_back_led_data->gpio_status_switch(1);
475 pwm_disable(amber_back_led_data->pwm_led);
476 pwm_config(amber_back_led_data->pwm_led, 64000, 2000000);
477 pwm_enable(amber_back_led_data->pwm_led);
478 }
479 }
480 break;
481 case BLINK_64MS_ON_310MS_PER_2SEC:
482 cancel_delayed_work_sync(&ldata->blink_delayed_work);
483 pwm_disable(ldata->pwm_led);
484 ldata->duty_time_ms = 64;
485 ldata->period_us = 2000000;
486
487 if(ldata->led_sync) {
488 if (!strcmp(ldata->cdev.name, "green")) {
489 pwm_disable(green_back_led_data->pwm_led);
490 green_back_led_data->duty_time_ms = 64;
491 green_back_led_data->period_us = 2000000;
492 }
493 if (!strcmp(ldata->cdev.name, "amber")) {
494 pwm_disable(amber_back_led_data->pwm_led);
495 amber_back_led_data->duty_time_ms = 64;
496 amber_back_led_data->period_us = 2000000;
497 }
498 }
499 queue_delayed_work(g_led_work_queue, &ldata->blink_delayed_work,
500 msecs_to_jiffies(310));
501 break;
502 case BLINK_64MS_ON_2SEC_PER_2SEC:
503 cancel_delayed_work_sync(&ldata->blink_delayed_work);
504 pwm_disable(ldata->pwm_led);
505 ldata->duty_time_ms = 64;
506 ldata->period_us = 2000000;
507
508 if(ldata->led_sync) {
509 if (!strcmp(ldata->cdev.name, "green")) {
510 pwm_disable(green_back_led_data->pwm_led);
511 green_back_led_data->duty_time_ms = 64;
512 green_back_led_data->period_us = 2000000;
513 }
514 if (!strcmp(ldata->cdev.name, "amber")) {
515 pwm_disable(amber_back_led_data->pwm_led);
516 amber_back_led_data->duty_time_ms = 64;
517 amber_back_led_data->period_us = 2000000;
518 }
519 }
520 queue_delayed_work(g_led_work_queue, &ldata->blink_delayed_work,
521 msecs_to_jiffies(1000));
522 break;
523 case BLINK_1SEC_PER_2SEC:
524 pwm_disable(ldata->pwm_led);
525 pwm_config(ldata->pwm_led, 1000000, 2000000);
526 pwm_enable(ldata->pwm_led);
527
528 if(ldata->led_sync) {
529 if (!strcmp(ldata->cdev.name, "green")) {
530 pwm_disable(green_back_led_data->pwm_led);
531 pwm_config(green_back_led_data->pwm_led, 1000000, 2000000);
532 pwm_enable(green_back_led_data->pwm_led);
533 }
534 if (!strcmp(ldata->cdev.name, "amber")) {
535 pwm_disable(amber_back_led_data->pwm_led);
536 pwm_config(amber_back_led_data->pwm_led, 1000000, 2000000);
537 pwm_enable(amber_back_led_data->pwm_led);
538 }
539 }
540 break;
541 default:
542 LED_ERR("%s: bank %d did not support blink type %d\n", __func__, ldata->bank, val);
543 return -EINVAL;
544 }
545
546 return count;
547}
548static DEVICE_ATTR(blink, 0644, pm8xxx_led_blink_show, pm8xxx_led_blink_store);
549
550static ssize_t pm8xxx_led_off_timer_store(struct device *dev,
551 struct device_attribute *attr,
552 const char *buf, size_t count)
553{
554 struct led_classdev *led_cdev;
555 struct pm8xxx_led_data *ldata;
556 int min, sec;
557 uint16_t off_timer;
558 ktime_t interval;
559 ktime_t next_alarm;
560
561 min = -1;
562 sec = -1;
563 sscanf(buf, "%d %d", &min, &sec);
564
565 if (min < 0 || min > 255)
566 return -EINVAL;
567 if (sec < 0 || sec > 255)
568 return -EINVAL;
569 led_cdev = (struct led_classdev *) dev_get_drvdata(dev);
570 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
571
572 LED_INFO("Setting %s off_timer to %d min %d sec \n", led_cdev->name, min, sec);
573 off_timer = min * 60 + sec;
574
575 alarm_cancel(&ldata->led_alarm);
576 cancel_work_sync(&ldata->led_work);
577 if (off_timer) {
578 interval = ktime_set(off_timer, 0);
579 next_alarm = ktime_add(alarm_get_elapsed_realtime(), interval);
580 alarm_start_range(&ldata->led_alarm, next_alarm, next_alarm);
581 }
582 return count;
583}
584static DEVICE_ATTR(off_timer, 0644, NULL, pm8xxx_led_off_timer_store);
585
586static ssize_t pm8xxx_led_currents_show(struct device *dev,
587 struct device_attribute *attr,
588 char *buf)
589{
590 struct led_classdev *led_cdev;
591 struct pm8xxx_led_data *ldata;
592
593 led_cdev = (struct led_classdev *) dev_get_drvdata(dev);
594 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
595
596 return sprintf(buf, "%d\n", ldata->out_current);
597}
598
599static ssize_t pm8xxx_led_currents_store(struct device *dev,
600 struct device_attribute *attr,
601 const char *buf, size_t count)
602{
603 int currents = 0;
604 struct led_classdev *led_cdev;
605 struct pm8xxx_led_data *ldata;
606
607 sscanf(buf, "%d", &currents);
608 if (currents < 0)
609 return -EINVAL;
610
611 led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
612 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
613
614 LED_INFO("%s: bank %d currents %d\n", __func__, ldata->bank, currents);
615 ldata->out_current = currents;
616
617 ldata->cdev.brightness_set(led_cdev, 0);
618 if (currents)
619 ldata->cdev.brightness_set(led_cdev, 255);
620
621 return count;
622}
623static DEVICE_ATTR(currents, 0644, pm8xxx_led_currents_show, pm8xxx_led_currents_store);
624
625static ssize_t pm8xxx_led_pwm_coefficient_show(struct device *dev,
626 struct device_attribute *attr,
627 char *buf)
628{
629 struct led_classdev *led_cdev;
630 struct pm8xxx_led_data *ldata;
631
632 led_cdev = (struct led_classdev *) dev_get_drvdata(dev);
633 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
634
635 return sprintf(buf, "%d\n", ldata->pwm_coefficient);
636}
637
638static ssize_t pm8xxx_led_pwm_coefficient_store(struct device *dev,
639 struct device_attribute *attr,
640 const char *buf, size_t count)
641{
642 int pwm_coefficient1 = 0;
643 struct led_classdev *led_cdev;
644 struct pm8xxx_led_data *ldata;
645
646 sscanf(buf, "%d", &pwm_coefficient1);
647 if (pwm_coefficient1 < 0)
648 return -EINVAL;
649
650 led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
651 ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev);
652
653 LED_INFO("%s: pwm_coefficient %d\n", __func__, pwm_coefficient1);
654
655 ldata->pwm_coefficient = pwm_coefficient1;
656
657 return count;
658}
659static DEVICE_ATTR(pwm_coefficient, 0644, pm8xxx_led_pwm_coefficient_show, pm8xxx_led_pwm_coefficient_store);
660
661static int __devinit pm8xxx_led_probe(struct platform_device *pdev)
662{
663 const struct pm8xxx_led_platform_data *pdata = pdev->dev.platform_data;
664 struct pm8xxx_led_configure *curr_led;
665 struct pm8xxx_led_data *led, *led_dat;
666 int i, ret = -ENOMEM;
667
668 if (pdata == NULL) {
669 LED_ERR("platform data not supplied\n");
670 return -EINVAL;
671 }
672
673 led = kcalloc(pdata->num_leds + 1, sizeof(*led), GFP_KERNEL);
674 if (led == NULL) {
675 LED_ERR("failed to alloc memory\n");
676 return -ENOMEM;
677 }
678 wake_lock_init(&pmic_led_wake_lock, WAKE_LOCK_SUSPEND, "pmic_led");
679 g_led_work_queue = create_workqueue("pm8xxx-led");
680 if (g_led_work_queue == NULL) {
681 LED_ERR("failed to create workqueue\n");
682 goto err_create_work_queue;
683 }
684
685 for (i = 0; i < pdata->num_leds; i++) {
686 curr_led = &pdata->leds[i];
687 led_dat = &led[i];
688 led_dat->cdev.name = curr_led->name;
689 led_dat->id = curr_led->flags;
690 led_dat->bank = curr_led->flags;
691 led_dat->function_flags = curr_led->function_flags;
692 led_dat->start_index = curr_led->start_index;
693 led_dat->duty_time_ms = curr_led->duty_time_ms;
694 led_dat->period_us = curr_led->period_us;
695 led_dat->duites_size = curr_led->duites_size;
696 led_dat->lut_flag = curr_led->lut_flag;
697 led_dat->out_current = curr_led->out_current;
698 led_dat->duties = &(curr_led->duties[0]);
699 led_dat->led_sync = curr_led->led_sync;
700 led_dat->pwm_led = pwm_request(led_dat->bank, led_dat->cdev.name);
701 if( curr_led->pwm_coefficient > 0 )
702 led_dat->pwm_coefficient = curr_led->pwm_coefficient;
703 else
704 led_dat->pwm_coefficient = 100;
705 switch (led_dat->id) {
706 case PM8XXX_ID_GPIO24:
707 case PM8XXX_ID_GPIO25:
708 case PM8XXX_ID_GPIO26:
709 led_dat->cdev.brightness_set = pm8xxx_led_gpio_set;
710 if (curr_led->gpio_status_switch != NULL)
711 led_dat->gpio_status_switch = curr_led->gpio_status_switch;
712 break;
713 case PM8XXX_ID_LED_0:
714 case PM8XXX_ID_LED_1:
715 case PM8XXX_ID_LED_2:
716 led_dat->cdev.brightness_set = pm8xxx_led_current_set;
717 if (led_dat->function_flags & LED_PWM_FUNCTION) {
718 led_dat->reg = pm8xxxx_led_pwm_mode(led_dat->id);
719 INIT_DELAYED_WORK(&led[i].fade_delayed_work, led_fade_do_work);
720 } else
721 led_dat->reg = PM8XXX_LED_MODE_MANUAL;
722 break;
723 case PM8XXX_ID_LED_KB_LIGHT:
724 break;
725 }
726 led_dat->cdev.brightness = LED_OFF;
727 led_dat->dev = &pdev->dev;
728
729 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
730 if (ret) {
731 LED_ERR("unable to register led %d,ret=%d\n", led_dat->id, ret);
732 goto err_register_led_cdev;
733 }
734
735 if (led_dat->id >= PM8XXX_ID_LED_2 && led_dat->id <= PM8XXX_ID_LED_0) {
736 ret = device_create_file(led_dat->cdev.dev, &dev_attr_currents);
737 if (ret < 0) {
738 LED_ERR("%s: Failed to create %d attr currents\n", __func__, i);
739 goto err_register_attr_currents;
740 }
741 }
742 if (led_dat->id <= PM8XXX_ID_GPIO26) {
743 ret = device_create_file(led_dat->cdev.dev, &dev_attr_pwm_coefficient);
744 if (ret < 0) {
745 LED_ERR("%s: Failed to create %d attr pwm_coefficient\n", __func__, i);
746 goto err_register_attr_pwm_coefficient;
747 }
748 }
749 if (led_dat->function_flags & LED_BLINK_FUNCTION) {
750 INIT_DELAYED_WORK(&led[i].blink_delayed_work, led_blink_do_work);
751 ret = device_create_file(led_dat->cdev.dev, &dev_attr_blink);
752 if (ret < 0) {
753 LED_ERR("%s: Failed to create %d attr blink\n", __func__, i);
754 goto err_register_attr_blink;
755 }
756
757 ret = device_create_file(led_dat->cdev.dev, &dev_attr_off_timer);
758 if (ret < 0) {
759 LED_ERR("%s: Failed to create %d attr off timer\n", __func__, i);
760 goto err_register_attr_off_timer;
761 }
762 alarm_init(&led[i].led_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, led_alarm_handler);
763 INIT_WORK(&led[i].led_work, led_work_func);
764 }
765
766 if (!strcmp(led_dat->cdev.name, "button-backlight")) {
767 for_key_led_data = led_dat;
768 }
769 if (!strcmp(led_dat->cdev.name, "green-back")) {
770 LED_INFO("%s: matt green-back, 000 probe, led_dat = %x\n", __func__, (unsigned int)led_dat);
771 green_back_led_data = led_dat;
772 }
773 if (!strcmp(led_dat->cdev.name, "amber-back")) {
774 LED_INFO("%s: matt amber-back\n", __func__);
775 amber_back_led_data = led_dat;
776 }
777
778 }
779
780 pm8xxx_leds = led;
781
782 platform_set_drvdata(pdev, led);
783
784 return 0;
785
786err_register_attr_off_timer:
787 if (i > 0) {
788 for (i = i - 1; i >= 0; i--) {
789 if (led[i].function_flags & LED_BLINK_FUNCTION)
790 device_remove_file(led[i].cdev.dev, &dev_attr_off_timer);
791 }
792 }
793 i = pdata->num_leds;
794err_register_attr_blink:
795 if (i > 0) {
796 for (i = i - 1; i >= 0; i--) {
797 if (led[i].function_flags & LED_BLINK_FUNCTION)
798 device_remove_file(led[i].cdev.dev, &dev_attr_blink);
799 }
800 }
801 i = pdata->num_leds;
802err_register_attr_pwm_coefficient:
803 if (i > 0) {
804 for (i = i - 1; i >= 0; i--) {
805 if (led[i].function_flags <= PM8XXX_ID_GPIO26)
806 device_remove_file(led[i].cdev.dev, &dev_attr_pwm_coefficient);
807 }
808 }
809 i = pdata->num_leds;
810err_register_attr_currents:
811 if (i > 0) {
812 for (i = i - 1; i >= 0; i--) {
813 if (led[i].function_flags >= PM8XXX_ID_LED_2 && led[i].function_flags <= PM8XXX_ID_LED_0)
814 device_remove_file(led[i].cdev.dev, &dev_attr_currents);
815 }
816 }
817 i = pdata->num_leds;
818err_register_led_cdev:
819 if (i > 0) {
820 for (i = i - 1; i >= 0; i--) {
821 pwm_free(led[i].pwm_led);
822 led_classdev_unregister(&led[i].cdev);
823 }
824 }
825 destroy_workqueue(g_led_work_queue);
826err_create_work_queue:
827 kfree(led);
828 wake_lock_destroy(&pmic_led_wake_lock);
829 return ret;
830}
831
832static int __devexit pm8xxx_led_remove(struct platform_device *pdev)
833{
834 int i;
835 const struct led_platform_data *pdata =
836 pdev->dev.platform_data;
837 struct pm8xxx_led_data *led = platform_get_drvdata(pdev);
838
839 for (i = 0; i < pdata->num_leds; i++) {
840 led_classdev_unregister(&led[i].cdev);
841 if (led[i].function_flags >= PM8XXX_ID_LED_2 && led[i].function_flags <= PM8XXX_ID_LED_0)
842 device_remove_file(led[i].cdev.dev, &dev_attr_currents);
843 if (led[i].function_flags & LED_BLINK_FUNCTION)
844 device_remove_file(led[i].cdev.dev, &dev_attr_blink);
845 if (led[i].function_flags & LED_BLINK_FUNCTION)
846 device_remove_file(led[i].cdev.dev, &dev_attr_off_timer);
847 }
848
849 destroy_workqueue(g_led_work_queue);
850 wake_lock_destroy(&pmic_led_wake_lock);
851 kfree(led);
852
853 return 0;
854}
855
856static struct platform_driver pm8xxx_led_driver = {
857 .probe = pm8xxx_led_probe,
858 .remove = __devexit_p(pm8xxx_led_remove),
859 .driver = {
860 .name = PM8XXX_LEDS_DEV_NAME,
861 .owner = THIS_MODULE,
862 },
863};
864
865static int __init pm8xxx_led_init(void)
866{
867 return platform_driver_register(&pm8xxx_led_driver);
868}
869subsys_initcall(pm8xxx_led_init);
870
871static void __exit pm8xxx_led_exit(void)
872{
873 platform_driver_unregister(&pm8xxx_led_driver);
874}
875module_exit(pm8xxx_led_exit);
876
877MODULE_DESCRIPTION("PM8XXX LEDs driver");
878MODULE_LICENSE("GPL v2");
879MODULE_VERSION("1.0");
880MODULE_ALIAS("platform:pm8xxx-led");