Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/leds/leds-bd2802.c
15109 views
1
/*
2
* leds-bd2802.c - RGB LED Driver
3
*
4
* Copyright (C) 2009 Samsung Electronics
5
* Kim Kyuwon <[email protected]>
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 2 as
9
* published by the Free Software Foundation.
10
*
11
* Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
12
*
13
*/
14
15
#include <linux/module.h>
16
#include <linux/i2c.h>
17
#include <linux/gpio.h>
18
#include <linux/delay.h>
19
#include <linux/leds.h>
20
#include <linux/leds-bd2802.h>
21
#include <linux/slab.h>
22
#include <linux/pm.h>
23
24
#define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
25
26
#define BD2802_LED_OFFSET 0xa
27
#define BD2802_COLOR_OFFSET 0x3
28
29
#define BD2802_REG_CLKSETUP 0x00
30
#define BD2802_REG_CONTROL 0x01
31
#define BD2802_REG_HOURSETUP 0x02
32
#define BD2802_REG_CURRENT1SETUP 0x03
33
#define BD2802_REG_CURRENT2SETUP 0x04
34
#define BD2802_REG_WAVEPATTERN 0x05
35
36
#define BD2802_CURRENT_032 0x10 /* 3.2mA */
37
#define BD2802_CURRENT_000 0x00 /* 0.0mA */
38
39
#define BD2802_PATTERN_FULL 0x07
40
#define BD2802_PATTERN_HALF 0x03
41
42
enum led_ids {
43
LED1,
44
LED2,
45
LED_NUM,
46
};
47
48
enum led_colors {
49
RED,
50
GREEN,
51
BLUE,
52
};
53
54
enum led_bits {
55
BD2802_OFF,
56
BD2802_BLINK,
57
BD2802_ON,
58
};
59
60
/*
61
* State '0' : 'off'
62
* State '1' : 'blink'
63
* State '2' : 'on'.
64
*/
65
struct led_state {
66
unsigned r:2;
67
unsigned g:2;
68
unsigned b:2;
69
};
70
71
struct bd2802_led {
72
struct bd2802_led_platform_data *pdata;
73
struct i2c_client *client;
74
struct rw_semaphore rwsem;
75
struct work_struct work;
76
77
struct led_state led[2];
78
79
/*
80
* Making led_classdev as array is not recommended, because array
81
* members prevent using 'container_of' macro. So repetitive works
82
* are needed.
83
*/
84
struct led_classdev cdev_led1r;
85
struct led_classdev cdev_led1g;
86
struct led_classdev cdev_led1b;
87
struct led_classdev cdev_led2r;
88
struct led_classdev cdev_led2g;
89
struct led_classdev cdev_led2b;
90
91
/*
92
* Advanced Configuration Function(ADF) mode:
93
* In ADF mode, user can set registers of BD2802GU directly,
94
* therefore BD2802GU doesn't enter reset state.
95
*/
96
int adf_on;
97
98
enum led_ids led_id;
99
enum led_colors color;
100
enum led_bits state;
101
102
/* General attributes of RGB LEDs */
103
int wave_pattern;
104
int rgb_current;
105
};
106
107
108
/*--------------------------------------------------------------*/
109
/* BD2802GU helper functions */
110
/*--------------------------------------------------------------*/
111
112
static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
113
enum led_colors color)
114
{
115
switch (color) {
116
case RED:
117
return !led->led[id].r;
118
case GREEN:
119
return !led->led[id].g;
120
case BLUE:
121
return !led->led[id].b;
122
default:
123
dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
124
return -EINVAL;
125
}
126
}
127
128
static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
129
{
130
if (led->led[id].r || led->led[id].g || led->led[id].b)
131
return 0;
132
133
return 1;
134
}
135
136
static inline int bd2802_is_all_off(struct bd2802_led *led)
137
{
138
int i;
139
140
for (i = 0; i < LED_NUM; i++)
141
if (!bd2802_is_led_off(led, i))
142
return 0;
143
144
return 1;
145
}
146
147
static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
148
{
149
return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
150
}
151
152
static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
153
u8 reg_offset)
154
{
155
return reg_offset + bd2802_get_base_offset(id, color);
156
}
157
158
159
/*--------------------------------------------------------------*/
160
/* BD2802GU core functions */
161
/*--------------------------------------------------------------*/
162
163
static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
164
{
165
int ret = i2c_smbus_write_byte_data(client, reg, val);
166
if (ret >= 0)
167
return 0;
168
169
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
170
__func__, reg, val, ret);
171
172
return ret;
173
}
174
175
static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
176
enum led_colors color, enum led_bits led_bit)
177
{
178
int i;
179
u8 value;
180
181
for (i = 0; i < LED_NUM; i++) {
182
if (i == id) {
183
switch (color) {
184
case RED:
185
led->led[i].r = led_bit;
186
break;
187
case GREEN:
188
led->led[i].g = led_bit;
189
break;
190
case BLUE:
191
led->led[i].b = led_bit;
192
break;
193
default:
194
dev_err(&led->client->dev,
195
"%s: Invalid color\n", __func__);
196
return;
197
}
198
}
199
}
200
201
if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
202
return;
203
204
if (!bd2802_is_led_off(led, id))
205
return;
206
207
if (bd2802_is_all_off(led) && !led->adf_on) {
208
gpio_set_value(led->pdata->reset_gpio, 0);
209
return;
210
}
211
212
/*
213
* In this case, other led is turned on, and current led is turned
214
* off. So set RGB LED Control register to stop the current RGB LED
215
*/
216
value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
217
bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
218
}
219
220
static void bd2802_configure(struct bd2802_led *led)
221
{
222
struct bd2802_led_platform_data *pdata = led->pdata;
223
u8 reg;
224
225
reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
226
bd2802_write_byte(led->client, reg, pdata->rgb_time);
227
228
reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
229
bd2802_write_byte(led->client, reg, pdata->rgb_time);
230
}
231
232
static void bd2802_reset_cancel(struct bd2802_led *led)
233
{
234
gpio_set_value(led->pdata->reset_gpio, 1);
235
udelay(100);
236
bd2802_configure(led);
237
}
238
239
static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
240
{
241
enum led_ids other_led = (id == LED1) ? LED2 : LED1;
242
u8 value, other_led_on;
243
244
other_led_on = !bd2802_is_led_off(led, other_led);
245
if (id == LED1)
246
value = LED_CTL(other_led_on, 1);
247
else
248
value = LED_CTL(1 , other_led_on);
249
250
bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
251
}
252
253
static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
254
enum led_colors color)
255
{
256
u8 reg;
257
258
if (bd2802_is_all_off(led) && !led->adf_on)
259
bd2802_reset_cancel(led);
260
261
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
262
bd2802_write_byte(led->client, reg, led->rgb_current);
263
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
264
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
265
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
266
bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
267
268
bd2802_enable(led, id);
269
bd2802_update_state(led, id, color, BD2802_ON);
270
}
271
272
static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
273
enum led_colors color)
274
{
275
u8 reg;
276
277
if (bd2802_is_all_off(led) && !led->adf_on)
278
bd2802_reset_cancel(led);
279
280
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
281
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
282
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
283
bd2802_write_byte(led->client, reg, led->rgb_current);
284
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
285
bd2802_write_byte(led->client, reg, led->wave_pattern);
286
287
bd2802_enable(led, id);
288
bd2802_update_state(led, id, color, BD2802_BLINK);
289
}
290
291
static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
292
enum led_colors color, enum led_bits led_bit)
293
{
294
if (led_bit == BD2802_OFF) {
295
dev_err(&led->client->dev,
296
"Only 'blink' and 'on' are allowed\n");
297
return;
298
}
299
300
if (led_bit == BD2802_BLINK)
301
bd2802_set_blink(led, id, color);
302
else
303
bd2802_set_on(led, id, color);
304
}
305
306
static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
307
enum led_colors color)
308
{
309
u8 reg;
310
311
if (bd2802_is_rgb_off(led, id, color))
312
return;
313
314
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
315
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
316
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
317
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
318
319
bd2802_update_state(led, id, color, BD2802_OFF);
320
}
321
322
#define BD2802_SET_REGISTER(reg_addr, reg_name) \
323
static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
324
struct device_attribute *attr, const char *buf, size_t count) \
325
{ \
326
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
327
unsigned long val; \
328
int ret; \
329
if (!count) \
330
return -EINVAL; \
331
ret = strict_strtoul(buf, 16, &val); \
332
if (ret) \
333
return ret; \
334
down_write(&led->rwsem); \
335
bd2802_write_byte(led->client, reg_addr, (u8) val); \
336
up_write(&led->rwsem); \
337
return count; \
338
} \
339
static struct device_attribute bd2802_reg##reg_addr##_attr = { \
340
.attr = {.name = reg_name, .mode = 0644}, \
341
.store = bd2802_store_reg##reg_addr, \
342
};
343
344
BD2802_SET_REGISTER(0x00, "0x00");
345
BD2802_SET_REGISTER(0x01, "0x01");
346
BD2802_SET_REGISTER(0x02, "0x02");
347
BD2802_SET_REGISTER(0x03, "0x03");
348
BD2802_SET_REGISTER(0x04, "0x04");
349
BD2802_SET_REGISTER(0x05, "0x05");
350
BD2802_SET_REGISTER(0x06, "0x06");
351
BD2802_SET_REGISTER(0x07, "0x07");
352
BD2802_SET_REGISTER(0x08, "0x08");
353
BD2802_SET_REGISTER(0x09, "0x09");
354
BD2802_SET_REGISTER(0x0a, "0x0a");
355
BD2802_SET_REGISTER(0x0b, "0x0b");
356
BD2802_SET_REGISTER(0x0c, "0x0c");
357
BD2802_SET_REGISTER(0x0d, "0x0d");
358
BD2802_SET_REGISTER(0x0e, "0x0e");
359
BD2802_SET_REGISTER(0x0f, "0x0f");
360
BD2802_SET_REGISTER(0x10, "0x10");
361
BD2802_SET_REGISTER(0x11, "0x11");
362
BD2802_SET_REGISTER(0x12, "0x12");
363
BD2802_SET_REGISTER(0x13, "0x13");
364
BD2802_SET_REGISTER(0x14, "0x14");
365
BD2802_SET_REGISTER(0x15, "0x15");
366
367
static struct device_attribute *bd2802_addr_attributes[] = {
368
&bd2802_reg0x00_attr,
369
&bd2802_reg0x01_attr,
370
&bd2802_reg0x02_attr,
371
&bd2802_reg0x03_attr,
372
&bd2802_reg0x04_attr,
373
&bd2802_reg0x05_attr,
374
&bd2802_reg0x06_attr,
375
&bd2802_reg0x07_attr,
376
&bd2802_reg0x08_attr,
377
&bd2802_reg0x09_attr,
378
&bd2802_reg0x0a_attr,
379
&bd2802_reg0x0b_attr,
380
&bd2802_reg0x0c_attr,
381
&bd2802_reg0x0d_attr,
382
&bd2802_reg0x0e_attr,
383
&bd2802_reg0x0f_attr,
384
&bd2802_reg0x10_attr,
385
&bd2802_reg0x11_attr,
386
&bd2802_reg0x12_attr,
387
&bd2802_reg0x13_attr,
388
&bd2802_reg0x14_attr,
389
&bd2802_reg0x15_attr,
390
};
391
392
static void bd2802_enable_adv_conf(struct bd2802_led *led)
393
{
394
int i, ret;
395
396
for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
397
ret = device_create_file(&led->client->dev,
398
bd2802_addr_attributes[i]);
399
if (ret) {
400
dev_err(&led->client->dev, "failed: sysfs file %s\n",
401
bd2802_addr_attributes[i]->attr.name);
402
goto failed_remove_files;
403
}
404
}
405
406
if (bd2802_is_all_off(led))
407
bd2802_reset_cancel(led);
408
409
led->adf_on = 1;
410
411
return;
412
413
failed_remove_files:
414
for (i--; i >= 0; i--)
415
device_remove_file(&led->client->dev,
416
bd2802_addr_attributes[i]);
417
}
418
419
static void bd2802_disable_adv_conf(struct bd2802_led *led)
420
{
421
int i;
422
423
for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
424
device_remove_file(&led->client->dev,
425
bd2802_addr_attributes[i]);
426
427
if (bd2802_is_all_off(led))
428
gpio_set_value(led->pdata->reset_gpio, 0);
429
430
led->adf_on = 0;
431
}
432
433
static ssize_t bd2802_show_adv_conf(struct device *dev,
434
struct device_attribute *attr, char *buf)
435
{
436
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
437
ssize_t ret;
438
439
down_read(&led->rwsem);
440
if (led->adf_on)
441
ret = sprintf(buf, "on\n");
442
else
443
ret = sprintf(buf, "off\n");
444
up_read(&led->rwsem);
445
446
return ret;
447
}
448
449
static ssize_t bd2802_store_adv_conf(struct device *dev,
450
struct device_attribute *attr, const char *buf, size_t count)
451
{
452
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
453
454
if (!count)
455
return -EINVAL;
456
457
down_write(&led->rwsem);
458
if (!led->adf_on && !strncmp(buf, "on", 2))
459
bd2802_enable_adv_conf(led);
460
else if (led->adf_on && !strncmp(buf, "off", 3))
461
bd2802_disable_adv_conf(led);
462
up_write(&led->rwsem);
463
464
return count;
465
}
466
467
static struct device_attribute bd2802_adv_conf_attr = {
468
.attr = {
469
.name = "advanced_configuration",
470
.mode = 0644,
471
},
472
.show = bd2802_show_adv_conf,
473
.store = bd2802_store_adv_conf,
474
};
475
476
#define BD2802_CONTROL_ATTR(attr_name, name_str) \
477
static ssize_t bd2802_show_##attr_name(struct device *dev, \
478
struct device_attribute *attr, char *buf) \
479
{ \
480
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
481
ssize_t ret; \
482
down_read(&led->rwsem); \
483
ret = sprintf(buf, "0x%02x\n", led->attr_name); \
484
up_read(&led->rwsem); \
485
return ret; \
486
} \
487
static ssize_t bd2802_store_##attr_name(struct device *dev, \
488
struct device_attribute *attr, const char *buf, size_t count) \
489
{ \
490
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
491
unsigned long val; \
492
int ret; \
493
if (!count) \
494
return -EINVAL; \
495
ret = strict_strtoul(buf, 16, &val); \
496
if (ret) \
497
return ret; \
498
down_write(&led->rwsem); \
499
led->attr_name = val; \
500
up_write(&led->rwsem); \
501
return count; \
502
} \
503
static struct device_attribute bd2802_##attr_name##_attr = { \
504
.attr = { \
505
.name = name_str, \
506
.mode = 0644, \
507
}, \
508
.show = bd2802_show_##attr_name, \
509
.store = bd2802_store_##attr_name, \
510
};
511
512
BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
513
BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
514
515
static struct device_attribute *bd2802_attributes[] = {
516
&bd2802_adv_conf_attr,
517
&bd2802_wave_pattern_attr,
518
&bd2802_rgb_current_attr,
519
};
520
521
static void bd2802_led_work(struct work_struct *work)
522
{
523
struct bd2802_led *led = container_of(work, struct bd2802_led, work);
524
525
if (led->state)
526
bd2802_turn_on(led, led->led_id, led->color, led->state);
527
else
528
bd2802_turn_off(led, led->led_id, led->color);
529
}
530
531
#define BD2802_CONTROL_RGBS(name, id, clr) \
532
static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
533
enum led_brightness value) \
534
{ \
535
struct bd2802_led *led = \
536
container_of(led_cdev, struct bd2802_led, cdev_##name); \
537
led->led_id = id; \
538
led->color = clr; \
539
if (value == LED_OFF) \
540
led->state = BD2802_OFF; \
541
else \
542
led->state = BD2802_ON; \
543
schedule_work(&led->work); \
544
} \
545
static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
546
unsigned long *delay_on, unsigned long *delay_off) \
547
{ \
548
struct bd2802_led *led = \
549
container_of(led_cdev, struct bd2802_led, cdev_##name); \
550
if (*delay_on == 0 || *delay_off == 0) \
551
return -EINVAL; \
552
led->led_id = id; \
553
led->color = clr; \
554
led->state = BD2802_BLINK; \
555
schedule_work(&led->work); \
556
return 0; \
557
}
558
559
BD2802_CONTROL_RGBS(led1r, LED1, RED);
560
BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
561
BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
562
BD2802_CONTROL_RGBS(led2r, LED2, RED);
563
BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
564
BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
565
566
static int bd2802_register_led_classdev(struct bd2802_led *led)
567
{
568
int ret;
569
570
INIT_WORK(&led->work, bd2802_led_work);
571
572
led->cdev_led1r.name = "led1_R";
573
led->cdev_led1r.brightness = LED_OFF;
574
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
575
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
576
577
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
578
if (ret < 0) {
579
dev_err(&led->client->dev, "couldn't register LED %s\n",
580
led->cdev_led1r.name);
581
goto failed_unregister_led1_R;
582
}
583
584
led->cdev_led1g.name = "led1_G";
585
led->cdev_led1g.brightness = LED_OFF;
586
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
587
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
588
589
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
590
if (ret < 0) {
591
dev_err(&led->client->dev, "couldn't register LED %s\n",
592
led->cdev_led1g.name);
593
goto failed_unregister_led1_G;
594
}
595
596
led->cdev_led1b.name = "led1_B";
597
led->cdev_led1b.brightness = LED_OFF;
598
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
599
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
600
601
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
602
if (ret < 0) {
603
dev_err(&led->client->dev, "couldn't register LED %s\n",
604
led->cdev_led1b.name);
605
goto failed_unregister_led1_B;
606
}
607
608
led->cdev_led2r.name = "led2_R";
609
led->cdev_led2r.brightness = LED_OFF;
610
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
611
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
612
613
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
614
if (ret < 0) {
615
dev_err(&led->client->dev, "couldn't register LED %s\n",
616
led->cdev_led2r.name);
617
goto failed_unregister_led2_R;
618
}
619
620
led->cdev_led2g.name = "led2_G";
621
led->cdev_led2g.brightness = LED_OFF;
622
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
623
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
624
625
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
626
if (ret < 0) {
627
dev_err(&led->client->dev, "couldn't register LED %s\n",
628
led->cdev_led2g.name);
629
goto failed_unregister_led2_G;
630
}
631
632
led->cdev_led2b.name = "led2_B";
633
led->cdev_led2b.brightness = LED_OFF;
634
led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
635
led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
636
led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
637
638
ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
639
if (ret < 0) {
640
dev_err(&led->client->dev, "couldn't register LED %s\n",
641
led->cdev_led2b.name);
642
goto failed_unregister_led2_B;
643
}
644
645
return 0;
646
647
failed_unregister_led2_B:
648
led_classdev_unregister(&led->cdev_led2g);
649
failed_unregister_led2_G:
650
led_classdev_unregister(&led->cdev_led2r);
651
failed_unregister_led2_R:
652
led_classdev_unregister(&led->cdev_led1b);
653
failed_unregister_led1_B:
654
led_classdev_unregister(&led->cdev_led1g);
655
failed_unregister_led1_G:
656
led_classdev_unregister(&led->cdev_led1r);
657
failed_unregister_led1_R:
658
659
return ret;
660
}
661
662
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
663
{
664
cancel_work_sync(&led->work);
665
led_classdev_unregister(&led->cdev_led1r);
666
}
667
668
static int __devinit bd2802_probe(struct i2c_client *client,
669
const struct i2c_device_id *id)
670
{
671
struct bd2802_led *led;
672
struct bd2802_led_platform_data *pdata;
673
int ret, i;
674
675
led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
676
if (!led) {
677
dev_err(&client->dev, "failed to allocate driver data\n");
678
return -ENOMEM;
679
}
680
681
led->client = client;
682
pdata = led->pdata = client->dev.platform_data;
683
i2c_set_clientdata(client, led);
684
685
/* Configure RESET GPIO (L: RESET, H: RESET cancel) */
686
gpio_request(pdata->reset_gpio, "RGB_RESETB");
687
gpio_direction_output(pdata->reset_gpio, 1);
688
689
/* Tacss = min 0.1ms */
690
udelay(100);
691
692
/* Detect BD2802GU */
693
ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
694
if (ret < 0) {
695
dev_err(&client->dev, "failed to detect device\n");
696
goto failed_free;
697
} else
698
dev_info(&client->dev, "return 0x%02x\n", ret);
699
700
/* To save the power, reset BD2802 after detecting */
701
gpio_set_value(led->pdata->reset_gpio, 0);
702
703
/* Default attributes */
704
led->wave_pattern = BD2802_PATTERN_HALF;
705
led->rgb_current = BD2802_CURRENT_032;
706
707
init_rwsem(&led->rwsem);
708
709
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
710
ret = device_create_file(&led->client->dev,
711
bd2802_attributes[i]);
712
if (ret) {
713
dev_err(&led->client->dev, "failed: sysfs file %s\n",
714
bd2802_attributes[i]->attr.name);
715
goto failed_unregister_dev_file;
716
}
717
}
718
719
ret = bd2802_register_led_classdev(led);
720
if (ret < 0)
721
goto failed_unregister_dev_file;
722
723
return 0;
724
725
failed_unregister_dev_file:
726
for (i--; i >= 0; i--)
727
device_remove_file(&led->client->dev, bd2802_attributes[i]);
728
failed_free:
729
kfree(led);
730
731
return ret;
732
}
733
734
static int __exit bd2802_remove(struct i2c_client *client)
735
{
736
struct bd2802_led *led = i2c_get_clientdata(client);
737
int i;
738
739
gpio_set_value(led->pdata->reset_gpio, 0);
740
bd2802_unregister_led_classdev(led);
741
if (led->adf_on)
742
bd2802_disable_adv_conf(led);
743
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
744
device_remove_file(&led->client->dev, bd2802_attributes[i]);
745
kfree(led);
746
747
return 0;
748
}
749
750
#ifdef CONFIG_PM
751
752
static void bd2802_restore_state(struct bd2802_led *led)
753
{
754
int i;
755
756
for (i = 0; i < LED_NUM; i++) {
757
if (led->led[i].r)
758
bd2802_turn_on(led, i, RED, led->led[i].r);
759
if (led->led[i].g)
760
bd2802_turn_on(led, i, GREEN, led->led[i].g);
761
if (led->led[i].b)
762
bd2802_turn_on(led, i, BLUE, led->led[i].b);
763
}
764
}
765
766
static int bd2802_suspend(struct device *dev)
767
{
768
struct i2c_client *client = to_i2c_client(dev);
769
struct bd2802_led *led = i2c_get_clientdata(client);
770
771
gpio_set_value(led->pdata->reset_gpio, 0);
772
773
return 0;
774
}
775
776
static int bd2802_resume(struct device *dev)
777
{
778
struct i2c_client *client = to_i2c_client(dev);
779
struct bd2802_led *led = i2c_get_clientdata(client);
780
781
if (!bd2802_is_all_off(led) || led->adf_on) {
782
bd2802_reset_cancel(led);
783
bd2802_restore_state(led);
784
}
785
786
return 0;
787
}
788
789
static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
790
#define BD2802_PM (&bd2802_pm)
791
#else /* CONFIG_PM */
792
#define BD2802_PM NULL
793
#endif
794
795
static const struct i2c_device_id bd2802_id[] = {
796
{ "BD2802", 0 },
797
{ }
798
};
799
MODULE_DEVICE_TABLE(i2c, bd2802_id);
800
801
static struct i2c_driver bd2802_i2c_driver = {
802
.driver = {
803
.name = "BD2802",
804
.pm = BD2802_PM,
805
},
806
.probe = bd2802_probe,
807
.remove = __exit_p(bd2802_remove),
808
.id_table = bd2802_id,
809
};
810
811
static int __init bd2802_init(void)
812
{
813
return i2c_add_driver(&bd2802_i2c_driver);
814
}
815
module_init(bd2802_init);
816
817
static void __exit bd2802_exit(void)
818
{
819
i2c_del_driver(&bd2802_i2c_driver);
820
}
821
module_exit(bd2802_exit);
822
823
MODULE_AUTHOR("Kim Kyuwon <[email protected]>");
824
MODULE_DESCRIPTION("BD2802 LED driver");
825
MODULE_LICENSE("GPL v2");
826
827