1 /* 2 * leds-blinkm.c 3 * (c) Jan-Simon Möller (dl9pf@gmx.de) 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 #include <linux/module.h> 21 #include <linux/init.h> 22 #include <linux/slab.h> 23 #include <linux/jiffies.h> 24 #include <linux/i2c.h> 25 #include <linux/err.h> 26 #include <linux/mutex.h> 27 #include <linux/sysfs.h> 28 #include <linux/printk.h> 29 #include <linux/pm_runtime.h> 30 #include <linux/leds.h> 31 #include <linux/delay.h> 32 33 /* Addresses to scan - BlinkM is on 0x09 by default*/ 34 static const unsigned short normal_i2c[] = { 0x09, I2C_CLIENT_END }; 35 36 static int blinkm_transfer_hw(struct i2c_client *client, int cmd); 37 static int blinkm_test_run(struct i2c_client *client); 38 39 struct blinkm_led { 40 struct i2c_client *i2c_client; 41 struct led_classdev led_cdev; 42 int id; 43 atomic_t active; 44 }; 45 46 struct blinkm_work { 47 struct blinkm_led *blinkm_led; 48 struct work_struct work; 49 }; 50 51 #define cdev_to_blmled(c) container_of(c, struct blinkm_led, led_cdev) 52 #define work_to_blmwork(c) container_of(c, struct blinkm_work, work) 53 54 struct blinkm_data { 55 struct i2c_client *i2c_client; 56 struct mutex update_lock; 57 /* used for led class interface */ 58 struct blinkm_led blinkm_leds[3]; 59 /* used for "blinkm" sysfs interface */ 60 u8 red; /* color red */ 61 u8 green; /* color green */ 62 u8 blue; /* color blue */ 63 /* next values to use for transfer */ 64 u8 next_red; /* color red */ 65 u8 next_green; /* color green */ 66 u8 next_blue; /* color blue */ 67 /* internal use */ 68 u8 args[7]; /* set of args for transmission */ 69 u8 i2c_addr; /* i2c addr */ 70 u8 fw_ver; /* firmware version */ 71 /* used, but not from userspace */ 72 u8 hue; /* HSB hue */ 73 u8 saturation; /* HSB saturation */ 74 u8 brightness; /* HSB brightness */ 75 u8 next_hue; /* HSB hue */ 76 u8 next_saturation; /* HSB saturation */ 77 u8 next_brightness; /* HSB brightness */ 78 /* currently unused / todo */ 79 u8 fade_speed; /* fade speed 1 - 255 */ 80 s8 time_adjust; /* time adjust -128 - 127 */ 81 u8 fade:1; /* fade on = 1, off = 0 */ 82 u8 rand:1; /* rand fade mode on = 1 */ 83 u8 script_id; /* script ID */ 84 u8 script_repeats; /* repeats of script */ 85 u8 script_startline; /* line to start */ 86 }; 87 88 /* Colors */ 89 #define RED 0 90 #define GREEN 1 91 #define BLUE 2 92 93 /* mapping command names to cmd chars - see datasheet */ 94 #define BLM_GO_RGB 0 95 #define BLM_FADE_RGB 1 96 #define BLM_FADE_HSB 2 97 #define BLM_FADE_RAND_RGB 3 98 #define BLM_FADE_RAND_HSB 4 99 #define BLM_PLAY_SCRIPT 5 100 #define BLM_STOP_SCRIPT 6 101 #define BLM_SET_FADE_SPEED 7 102 #define BLM_SET_TIME_ADJ 8 103 #define BLM_GET_CUR_RGB 9 104 #define BLM_WRITE_SCRIPT_LINE 10 105 #define BLM_READ_SCRIPT_LINE 11 106 #define BLM_SET_SCRIPT_LR 12 /* Length & Repeats */ 107 #define BLM_SET_ADDR 13 108 #define BLM_GET_ADDR 14 109 #define BLM_GET_FW_VER 15 110 #define BLM_SET_STARTUP_PARAM 16 111 112 /* BlinkM Commands 113 * as extracted out of the datasheet: 114 * 115 * cmdchar = command (ascii) 116 * cmdbyte = command in hex 117 * nr_args = number of arguments (to send) 118 * nr_ret = number of return values (to read) 119 * dir = direction (0 = read, 1 = write, 2 = both) 120 * 121 */ 122 static const struct { 123 char cmdchar; 124 u8 cmdbyte; 125 u8 nr_args; 126 u8 nr_ret; 127 u8 dir:2; 128 } blinkm_cmds[17] = { 129 /* cmdchar, cmdbyte, nr_args, nr_ret, dir */ 130 { 'n', 0x6e, 3, 0, 1}, 131 { 'c', 0x63, 3, 0, 1}, 132 { 'h', 0x68, 3, 0, 1}, 133 { 'C', 0x43, 3, 0, 1}, 134 { 'H', 0x48, 3, 0, 1}, 135 { 'p', 0x70, 3, 0, 1}, 136 { 'o', 0x6f, 0, 0, 1}, 137 { 'f', 0x66, 1, 0, 1}, 138 { 't', 0x74, 1, 0, 1}, 139 { 'g', 0x67, 0, 3, 0}, 140 { 'W', 0x57, 7, 0, 1}, 141 { 'R', 0x52, 2, 5, 2}, 142 { 'L', 0x4c, 3, 0, 1}, 143 { 'A', 0x41, 4, 0, 1}, 144 { 'a', 0x61, 0, 1, 0}, 145 { 'Z', 0x5a, 0, 1, 0}, 146 { 'B', 0x42, 5, 0, 1}, 147 }; 148 149 static ssize_t show_color_common(struct device *dev, char *buf, int color) 150 { 151 struct i2c_client *client; 152 struct blinkm_data *data; 153 int ret; 154 155 client = to_i2c_client(dev); 156 data = i2c_get_clientdata(client); 157 158 ret = blinkm_transfer_hw(client, BLM_GET_CUR_RGB); 159 if (ret < 0) 160 return ret; 161 switch (color) { 162 case RED: 163 return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red); 164 break; 165 case GREEN: 166 return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green); 167 break; 168 case BLUE: 169 return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue); 170 break; 171 default: 172 return -EINVAL; 173 } 174 return -EINVAL; 175 } 176 177 static int store_color_common(struct device *dev, const char *buf, int color) 178 { 179 struct i2c_client *client; 180 struct blinkm_data *data; 181 int ret; 182 u8 value; 183 184 client = to_i2c_client(dev); 185 data = i2c_get_clientdata(client); 186 187 ret = kstrtou8(buf, 10, &value); 188 if (ret < 0) { 189 dev_err(dev, "BlinkM: value too large!\n"); 190 return ret; 191 } 192 193 switch (color) { 194 case RED: 195 data->next_red = value; 196 break; 197 case GREEN: 198 data->next_green = value; 199 break; 200 case BLUE: 201 data->next_blue = value; 202 break; 203 default: 204 return -EINVAL; 205 } 206 207 dev_dbg(dev, "next_red = %d, next_green = %d, next_blue = %d\n", 208 data->next_red, data->next_green, data->next_blue); 209 210 /* if mode ... */ 211 ret = blinkm_transfer_hw(client, BLM_GO_RGB); 212 if (ret < 0) { 213 dev_err(dev, "BlinkM: can't set RGB\n"); 214 return ret; 215 } 216 return 0; 217 } 218 219 static ssize_t show_red(struct device *dev, struct device_attribute *attr, 220 char *buf) 221 { 222 return show_color_common(dev, buf, RED); 223 } 224 225 static ssize_t store_red(struct device *dev, struct device_attribute *attr, 226 const char *buf, size_t count) 227 { 228 int ret; 229 230 ret = store_color_common(dev, buf, RED); 231 if (ret < 0) 232 return ret; 233 return count; 234 } 235 236 static DEVICE_ATTR(red, S_IRUGO | S_IWUSR, show_red, store_red); 237 238 static ssize_t show_green(struct device *dev, struct device_attribute *attr, 239 char *buf) 240 { 241 return show_color_common(dev, buf, GREEN); 242 } 243 244 static ssize_t store_green(struct device *dev, struct device_attribute *attr, 245 const char *buf, size_t count) 246 { 247 248 int ret; 249 250 ret = store_color_common(dev, buf, GREEN); 251 if (ret < 0) 252 return ret; 253 return count; 254 } 255 256 static DEVICE_ATTR(green, S_IRUGO | S_IWUSR, show_green, store_green); 257 258 static ssize_t show_blue(struct device *dev, struct device_attribute *attr, 259 char *buf) 260 { 261 return show_color_common(dev, buf, BLUE); 262 } 263 264 static ssize_t store_blue(struct device *dev, struct device_attribute *attr, 265 const char *buf, size_t count) 266 { 267 int ret; 268 269 ret = store_color_common(dev, buf, BLUE); 270 if (ret < 0) 271 return ret; 272 return count; 273 } 274 275 static DEVICE_ATTR(blue, S_IRUGO | S_IWUSR, show_blue, store_blue); 276 277 static ssize_t show_test(struct device *dev, struct device_attribute *attr, 278 char *buf) 279 { 280 return scnprintf(buf, PAGE_SIZE, 281 "#Write into test to start test sequence!#\n"); 282 } 283 284 static ssize_t store_test(struct device *dev, struct device_attribute *attr, 285 const char *buf, size_t count) 286 { 287 288 struct i2c_client *client; 289 int ret; 290 client = to_i2c_client(dev); 291 292 /*test */ 293 ret = blinkm_test_run(client); 294 if (ret < 0) 295 return ret; 296 297 return count; 298 } 299 300 static DEVICE_ATTR(test, S_IRUGO | S_IWUSR, show_test, store_test); 301 302 /* TODO: HSB, fade, timeadj, script ... */ 303 304 static struct attribute *blinkm_attrs[] = { 305 &dev_attr_red.attr, 306 &dev_attr_green.attr, 307 &dev_attr_blue.attr, 308 &dev_attr_test.attr, 309 NULL, 310 }; 311 312 static struct attribute_group blinkm_group = { 313 .name = "blinkm", 314 .attrs = blinkm_attrs, 315 }; 316 317 static int blinkm_write(struct i2c_client *client, int cmd, u8 *arg) 318 { 319 int result; 320 int i; 321 int arglen = blinkm_cmds[cmd].nr_args; 322 /* write out cmd to blinkm - always / default step */ 323 result = i2c_smbus_write_byte(client, blinkm_cmds[cmd].cmdbyte); 324 if (result < 0) 325 return result; 326 /* no args to write out */ 327 if (arglen == 0) 328 return 0; 329 330 for (i = 0; i < arglen; i++) { 331 /* repeat for arglen */ 332 result = i2c_smbus_write_byte(client, arg[i]); 333 if (result < 0) 334 return result; 335 } 336 return 0; 337 } 338 339 static int blinkm_read(struct i2c_client *client, int cmd, u8 *arg) 340 { 341 int result; 342 int i; 343 int retlen = blinkm_cmds[cmd].nr_ret; 344 for (i = 0; i < retlen; i++) { 345 /* repeat for retlen */ 346 result = i2c_smbus_read_byte(client); 347 if (result < 0) 348 return result; 349 arg[i] = result; 350 } 351 352 return 0; 353 } 354 355 static int blinkm_transfer_hw(struct i2c_client *client, int cmd) 356 { 357 /* the protocol is simple but non-standard: 358 * e.g. cmd 'g' (= 0x67) for "get device address" 359 * - which defaults to 0x09 - would be the sequence: 360 * a) write 0x67 to the device (byte write) 361 * b) read the value (0x09) back right after (byte read) 362 * 363 * Watch out for "unfinished" sequences (i.e. not enough reads 364 * or writes after a command. It will make the blinkM misbehave. 365 * Sequence is key here. 366 */ 367 368 /* args / return are in private data struct */ 369 struct blinkm_data *data = i2c_get_clientdata(client); 370 371 /* We start hardware transfers which are not to be 372 * mixed with other commands. Aquire a lock now. */ 373 if (mutex_lock_interruptible(&data->update_lock) < 0) 374 return -EAGAIN; 375 376 /* switch cmd - usually write before reads */ 377 switch (cmd) { 378 case BLM_FADE_RAND_RGB: 379 case BLM_GO_RGB: 380 case BLM_FADE_RGB: 381 data->args[0] = data->next_red; 382 data->args[1] = data->next_green; 383 data->args[2] = data->next_blue; 384 blinkm_write(client, cmd, data->args); 385 data->red = data->args[0]; 386 data->green = data->args[1]; 387 data->blue = data->args[2]; 388 break; 389 case BLM_FADE_HSB: 390 case BLM_FADE_RAND_HSB: 391 data->args[0] = data->next_hue; 392 data->args[1] = data->next_saturation; 393 data->args[2] = data->next_brightness; 394 blinkm_write(client, cmd, data->args); 395 data->hue = data->next_hue; 396 data->saturation = data->next_saturation; 397 data->brightness = data->next_brightness; 398 break; 399 case BLM_PLAY_SCRIPT: 400 data->args[0] = data->script_id; 401 data->args[1] = data->script_repeats; 402 data->args[2] = data->script_startline; 403 blinkm_write(client, cmd, data->args); 404 break; 405 case BLM_STOP_SCRIPT: 406 blinkm_write(client, cmd, NULL); 407 break; 408 case BLM_GET_CUR_RGB: 409 data->args[0] = data->red; 410 data->args[1] = data->green; 411 data->args[2] = data->blue; 412 blinkm_write(client, cmd, NULL); 413 blinkm_read(client, cmd, data->args); 414 data->red = data->args[0]; 415 data->green = data->args[1]; 416 data->blue = data->args[2]; 417 break; 418 case BLM_GET_ADDR: 419 data->args[0] = data->i2c_addr; 420 blinkm_write(client, cmd, NULL); 421 blinkm_read(client, cmd, data->args); 422 data->i2c_addr = data->args[0]; 423 break; 424 case BLM_SET_TIME_ADJ: 425 case BLM_SET_FADE_SPEED: 426 case BLM_READ_SCRIPT_LINE: 427 case BLM_WRITE_SCRIPT_LINE: 428 case BLM_SET_SCRIPT_LR: 429 case BLM_SET_ADDR: 430 case BLM_GET_FW_VER: 431 case BLM_SET_STARTUP_PARAM: 432 dev_err(&client->dev, 433 "BlinkM: cmd %d not implemented yet.\n", cmd); 434 break; 435 default: 436 dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd); 437 mutex_unlock(&data->update_lock); 438 return -EINVAL; 439 } /* end switch(cmd) */ 440 441 /* transfers done, unlock */ 442 mutex_unlock(&data->update_lock); 443 return 0; 444 } 445 446 static void led_work(struct work_struct *work) 447 { 448 int ret; 449 struct blinkm_led *led; 450 struct blinkm_data *data ; 451 struct blinkm_work *blm_work = work_to_blmwork(work); 452 453 led = blm_work->blinkm_led; 454 data = i2c_get_clientdata(led->i2c_client); 455 ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB); 456 atomic_dec(&led->active); 457 dev_dbg(&led->i2c_client->dev, 458 "# DONE # next_red = %d, next_green = %d," 459 " next_blue = %d, active = %d\n", 460 data->next_red, data->next_green, 461 data->next_blue, atomic_read(&led->active)); 462 kfree(blm_work); 463 } 464 465 static int blinkm_led_common_set(struct led_classdev *led_cdev, 466 enum led_brightness value, int color) 467 { 468 /* led_brightness is 0, 127 or 255 - we just use it here as-is */ 469 struct blinkm_led *led = cdev_to_blmled(led_cdev); 470 struct blinkm_data *data = i2c_get_clientdata(led->i2c_client); 471 struct blinkm_work *bl_work; 472 473 switch (color) { 474 case RED: 475 /* bail out if there's no change */ 476 if (data->next_red == (u8) value) 477 return 0; 478 /* we assume a quite fast sequence here ([off]->on->off) 479 * think of network led trigger - we cannot blink that fast, so 480 * in case we already have a off->on->off transition queued up, 481 * we refuse to queue up more. 482 * Revisit: fast-changing brightness. */ 483 if (atomic_read(&led->active) > 1) 484 return 0; 485 data->next_red = (u8) value; 486 break; 487 case GREEN: 488 /* bail out if there's no change */ 489 if (data->next_green == (u8) value) 490 return 0; 491 /* we assume a quite fast sequence here ([off]->on->off) 492 * Revisit: fast-changing brightness. */ 493 if (atomic_read(&led->active) > 1) 494 return 0; 495 data->next_green = (u8) value; 496 break; 497 case BLUE: 498 /* bail out if there's no change */ 499 if (data->next_blue == (u8) value) 500 return 0; 501 /* we assume a quite fast sequence here ([off]->on->off) 502 * Revisit: fast-changing brightness. */ 503 if (atomic_read(&led->active) > 1) 504 return 0; 505 data->next_blue = (u8) value; 506 break; 507 508 default: 509 dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n"); 510 return -EINVAL; 511 } 512 513 bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC); 514 if (!bl_work) 515 return -ENOMEM; 516 517 atomic_inc(&led->active); 518 dev_dbg(&led->i2c_client->dev, 519 "#TO_SCHED# next_red = %d, next_green = %d," 520 " next_blue = %d, active = %d\n", 521 data->next_red, data->next_green, 522 data->next_blue, atomic_read(&led->active)); 523 524 /* a fresh work _item_ for each change */ 525 bl_work->blinkm_led = led; 526 INIT_WORK(&bl_work->work, led_work); 527 /* queue work in own queue for easy sync on exit*/ 528 schedule_work(&bl_work->work); 529 530 return 0; 531 } 532 533 static void blinkm_led_red_set(struct led_classdev *led_cdev, 534 enum led_brightness value) 535 { 536 blinkm_led_common_set(led_cdev, value, RED); 537 } 538 539 static void blinkm_led_green_set(struct led_classdev *led_cdev, 540 enum led_brightness value) 541 { 542 blinkm_led_common_set(led_cdev, value, GREEN); 543 } 544 545 static void blinkm_led_blue_set(struct led_classdev *led_cdev, 546 enum led_brightness value) 547 { 548 blinkm_led_common_set(led_cdev, value, BLUE); 549 } 550 551 static void blinkm_init_hw(struct i2c_client *client) 552 { 553 int ret; 554 ret = blinkm_transfer_hw(client, BLM_STOP_SCRIPT); 555 ret = blinkm_transfer_hw(client, BLM_GO_RGB); 556 } 557 558 static int blinkm_test_run(struct i2c_client *client) 559 { 560 int ret; 561 struct blinkm_data *data = i2c_get_clientdata(client); 562 563 data->next_red = 0x01; 564 data->next_green = 0x05; 565 data->next_blue = 0x10; 566 ret = blinkm_transfer_hw(client, BLM_GO_RGB); 567 if (ret < 0) 568 return ret; 569 msleep(2000); 570 571 data->next_red = 0x25; 572 data->next_green = 0x10; 573 data->next_blue = 0x31; 574 ret = blinkm_transfer_hw(client, BLM_FADE_RGB); 575 if (ret < 0) 576 return ret; 577 msleep(2000); 578 579 data->next_hue = 0x50; 580 data->next_saturation = 0x10; 581 data->next_brightness = 0x20; 582 ret = blinkm_transfer_hw(client, BLM_FADE_HSB); 583 if (ret < 0) 584 return ret; 585 msleep(2000); 586 587 return 0; 588 } 589 590 /* Return 0 if detection is successful, -ENODEV otherwise */ 591 static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info) 592 { 593 struct i2c_adapter *adapter = client->adapter; 594 int ret; 595 int count = 99; 596 u8 tmpargs[7]; 597 598 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 599 | I2C_FUNC_SMBUS_WORD_DATA 600 | I2C_FUNC_SMBUS_WRITE_BYTE)) 601 return -ENODEV; 602 603 /* Now, we do the remaining detection. Simple for now. */ 604 /* We might need more guards to protect other i2c slaves */ 605 606 /* make sure the blinkM is balanced (read/writes) */ 607 while (count > 0) { 608 ret = blinkm_write(client, BLM_GET_ADDR, NULL); 609 usleep_range(5000, 10000); 610 ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); 611 usleep_range(5000, 10000); 612 if (tmpargs[0] == 0x09) 613 count = 0; 614 count--; 615 } 616 617 /* Step 1: Read BlinkM address back - cmd_char 'a' */ 618 ret = blinkm_write(client, BLM_GET_ADDR, NULL); 619 if (ret < 0) 620 return ret; 621 usleep_range(20000, 30000); /* allow a small delay */ 622 ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); 623 if (ret < 0) 624 return ret; 625 626 if (tmpargs[0] != 0x09) { 627 dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]); 628 return -ENODEV; 629 } 630 631 strlcpy(info->type, "blinkm", I2C_NAME_SIZE); 632 return 0; 633 } 634 635 static int blinkm_probe(struct i2c_client *client, 636 const struct i2c_device_id *id) 637 { 638 struct blinkm_data *data; 639 struct blinkm_led *led[3]; 640 int err, i; 641 char blinkm_led_name[28]; 642 643 data = devm_kzalloc(&client->dev, 644 sizeof(struct blinkm_data), GFP_KERNEL); 645 if (!data) { 646 err = -ENOMEM; 647 goto exit; 648 } 649 650 data->i2c_addr = 0x09; 651 data->i2c_addr = 0x08; 652 /* i2c addr - use fake addr of 0x08 initially (real is 0x09) */ 653 data->fw_ver = 0xfe; 654 /* firmware version - use fake until we read real value 655 * (currently broken - BlinkM confused!) */ 656 data->script_id = 0x01; 657 data->i2c_client = client; 658 659 i2c_set_clientdata(client, data); 660 mutex_init(&data->update_lock); 661 662 /* Register sysfs hooks */ 663 err = sysfs_create_group(&client->dev.kobj, &blinkm_group); 664 if (err < 0) { 665 dev_err(&client->dev, "couldn't register sysfs group\n"); 666 goto exit; 667 } 668 669 for (i = 0; i < 3; i++) { 670 /* RED = 0, GREEN = 1, BLUE = 2 */ 671 led[i] = &data->blinkm_leds[i]; 672 led[i]->i2c_client = client; 673 led[i]->id = i; 674 led[i]->led_cdev.max_brightness = 255; 675 led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME; 676 atomic_set(&led[i]->active, 0); 677 switch (i) { 678 case RED: 679 snprintf(blinkm_led_name, sizeof(blinkm_led_name), 680 "blinkm-%d-%d-red", 681 client->adapter->nr, 682 client->addr); 683 led[i]->led_cdev.name = blinkm_led_name; 684 led[i]->led_cdev.brightness_set = blinkm_led_red_set; 685 err = led_classdev_register(&client->dev, 686 &led[i]->led_cdev); 687 if (err < 0) { 688 dev_err(&client->dev, 689 "couldn't register LED %s\n", 690 led[i]->led_cdev.name); 691 goto failred; 692 } 693 break; 694 case GREEN: 695 snprintf(blinkm_led_name, sizeof(blinkm_led_name), 696 "blinkm-%d-%d-green", 697 client->adapter->nr, 698 client->addr); 699 led[i]->led_cdev.name = blinkm_led_name; 700 led[i]->led_cdev.brightness_set = blinkm_led_green_set; 701 err = led_classdev_register(&client->dev, 702 &led[i]->led_cdev); 703 if (err < 0) { 704 dev_err(&client->dev, 705 "couldn't register LED %s\n", 706 led[i]->led_cdev.name); 707 goto failgreen; 708 } 709 break; 710 case BLUE: 711 snprintf(blinkm_led_name, sizeof(blinkm_led_name), 712 "blinkm-%d-%d-blue", 713 client->adapter->nr, 714 client->addr); 715 led[i]->led_cdev.name = blinkm_led_name; 716 led[i]->led_cdev.brightness_set = blinkm_led_blue_set; 717 err = led_classdev_register(&client->dev, 718 &led[i]->led_cdev); 719 if (err < 0) { 720 dev_err(&client->dev, 721 "couldn't register LED %s\n", 722 led[i]->led_cdev.name); 723 goto failblue; 724 } 725 break; 726 } /* end switch */ 727 } /* end for */ 728 729 /* Initialize the blinkm */ 730 blinkm_init_hw(client); 731 732 return 0; 733 734 failblue: 735 led_classdev_unregister(&led[GREEN]->led_cdev); 736 737 failgreen: 738 led_classdev_unregister(&led[RED]->led_cdev); 739 740 failred: 741 sysfs_remove_group(&client->dev.kobj, &blinkm_group); 742 exit: 743 return err; 744 } 745 746 static int blinkm_remove(struct i2c_client *client) 747 { 748 struct blinkm_data *data = i2c_get_clientdata(client); 749 int ret = 0; 750 int i; 751 752 /* make sure no workqueue entries are pending */ 753 for (i = 0; i < 3; i++) { 754 flush_scheduled_work(); 755 led_classdev_unregister(&data->blinkm_leds[i].led_cdev); 756 } 757 758 /* reset rgb */ 759 data->next_red = 0x00; 760 data->next_green = 0x00; 761 data->next_blue = 0x00; 762 ret = blinkm_transfer_hw(client, BLM_FADE_RGB); 763 if (ret < 0) 764 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); 765 766 /* reset hsb */ 767 data->next_hue = 0x00; 768 data->next_saturation = 0x00; 769 data->next_brightness = 0x00; 770 ret = blinkm_transfer_hw(client, BLM_FADE_HSB); 771 if (ret < 0) 772 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); 773 774 /* red fade to off */ 775 data->next_red = 0xff; 776 ret = blinkm_transfer_hw(client, BLM_GO_RGB); 777 if (ret < 0) 778 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); 779 780 /* off */ 781 data->next_red = 0x00; 782 ret = blinkm_transfer_hw(client, BLM_FADE_RGB); 783 if (ret < 0) 784 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); 785 786 sysfs_remove_group(&client->dev.kobj, &blinkm_group); 787 return 0; 788 } 789 790 static const struct i2c_device_id blinkm_id[] = { 791 {"blinkm", 0}, 792 {} 793 }; 794 795 MODULE_DEVICE_TABLE(i2c, blinkm_id); 796 797 /* This is the driver that will be inserted */ 798 static struct i2c_driver blinkm_driver = { 799 .class = I2C_CLASS_HWMON, 800 .driver = { 801 .name = "blinkm", 802 }, 803 .probe = blinkm_probe, 804 .remove = blinkm_remove, 805 .id_table = blinkm_id, 806 .detect = blinkm_detect, 807 .address_list = normal_i2c, 808 }; 809 810 module_i2c_driver(blinkm_driver); 811 812 MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>"); 813 MODULE_DESCRIPTION("BlinkM RGB LED driver"); 814 MODULE_LICENSE("GPL"); 815 816