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