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