xref: /linux/drivers/leds/leds-blinkm.c (revision 55d0969c451159cff86949b38c39171cab962069)
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