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