leds-blinkm.c 21 KB

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