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