xref: /linux/drivers/leds/leds-blinkm.c (revision a031b5fce5265938912d66047ec12b2208dd868f)
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. Acquire a lock now.
360 	 */
361 	if (mutex_lock_interruptible(&data->update_lock) < 0)
362 		return -EAGAIN;
363 
364 	/* switch cmd - usually write before reads */
365 	switch (cmd) {
366 	case BLM_FADE_RAND_RGB:
367 	case BLM_GO_RGB:
368 	case BLM_FADE_RGB:
369 		data->args[0] = data->next_red;
370 		data->args[1] = data->next_green;
371 		data->args[2] = data->next_blue;
372 		blinkm_write(client, cmd, data->args);
373 		data->red = data->args[0];
374 		data->green = data->args[1];
375 		data->blue = data->args[2];
376 		break;
377 	case BLM_FADE_HSB:
378 	case BLM_FADE_RAND_HSB:
379 		data->args[0] = data->next_hue;
380 		data->args[1] = data->next_saturation;
381 		data->args[2] = data->next_brightness;
382 		blinkm_write(client, cmd, data->args);
383 		data->hue = data->next_hue;
384 		data->saturation = data->next_saturation;
385 		data->brightness = data->next_brightness;
386 		break;
387 	case BLM_PLAY_SCRIPT:
388 		data->args[0] = data->script_id;
389 		data->args[1] = data->script_repeats;
390 		data->args[2] = data->script_startline;
391 		blinkm_write(client, cmd, data->args);
392 		break;
393 	case BLM_STOP_SCRIPT:
394 		blinkm_write(client, cmd, NULL);
395 		break;
396 	case BLM_GET_CUR_RGB:
397 		data->args[0] = data->red;
398 		data->args[1] = data->green;
399 		data->args[2] = data->blue;
400 		blinkm_write(client, cmd, NULL);
401 		blinkm_read(client, cmd, data->args);
402 		data->red = data->args[0];
403 		data->green = data->args[1];
404 		data->blue = data->args[2];
405 		break;
406 	case BLM_GET_ADDR:
407 		data->args[0] = data->i2c_addr;
408 		blinkm_write(client, cmd, NULL);
409 		blinkm_read(client, cmd, data->args);
410 		data->i2c_addr = data->args[0];
411 		break;
412 	case BLM_SET_TIME_ADJ:
413 	case BLM_SET_FADE_SPEED:
414 	case BLM_READ_SCRIPT_LINE:
415 	case BLM_WRITE_SCRIPT_LINE:
416 	case BLM_SET_SCRIPT_LR:
417 	case BLM_SET_ADDR:
418 	case BLM_GET_FW_VER:
419 	case BLM_SET_STARTUP_PARAM:
420 		dev_err(&client->dev,
421 				"BlinkM: cmd %d not implemented yet.\n", cmd);
422 		break;
423 	default:
424 		dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd);
425 		mutex_unlock(&data->update_lock);
426 		return -EINVAL;
427 	}			/* end switch(cmd) */
428 
429 	/* transfers done, unlock */
430 	mutex_unlock(&data->update_lock);
431 	return 0;
432 }
433 
434 static int blinkm_set_mc_brightness(struct led_classdev *led_cdev,
435 				 enum led_brightness value)
436 {
437 	struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
438 	struct blinkm_led *led = mcled_cdev_to_led(mcled_cdev);
439 	struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
440 
441 	led_mc_calc_color_components(mcled_cdev, value);
442 
443 	data->next_red = (u8) mcled_cdev->subled_info[RED].brightness;
444 	data->next_green = (u8) mcled_cdev->subled_info[GREEN].brightness;
445 	data->next_blue = (u8) mcled_cdev->subled_info[BLUE].brightness;
446 
447 	blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
448 
449 	return 0;
450 }
451 
452 static int blinkm_led_common_set(struct led_classdev *led_cdev,
453 				 enum led_brightness value, int color)
454 {
455 	/* led_brightness is 0, 127 or 255 - we just use it here as-is */
456 	struct blinkm_led *led = led_cdev_to_blmled(led_cdev);
457 	struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
458 
459 	switch (color) {
460 	case RED:
461 		/* bail out if there's no change */
462 		if (data->next_red == (u8) value)
463 			return 0;
464 		data->next_red = (u8) value;
465 		break;
466 	case GREEN:
467 		/* bail out if there's no change */
468 		if (data->next_green == (u8) value)
469 			return 0;
470 		data->next_green = (u8) value;
471 		break;
472 	case BLUE:
473 		/* bail out if there's no change */
474 		if (data->next_blue == (u8) value)
475 			return 0;
476 		data->next_blue = (u8) value;
477 		break;
478 
479 	default:
480 		dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n");
481 		return -EINVAL;
482 	}
483 
484 	blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
485 	dev_dbg(&led->i2c_client->dev,
486 			"# DONE # next_red = %d, next_green = %d,"
487 			" next_blue = %d\n",
488 			data->next_red, data->next_green,
489 			data->next_blue);
490 	return 0;
491 }
492 
493 static int blinkm_led_red_set(struct led_classdev *led_cdev,
494 			       enum led_brightness value)
495 {
496 	return blinkm_led_common_set(led_cdev, value, RED);
497 }
498 
499 static int blinkm_led_green_set(struct led_classdev *led_cdev,
500 				 enum led_brightness value)
501 {
502 	return blinkm_led_common_set(led_cdev, value, GREEN);
503 }
504 
505 static int blinkm_led_blue_set(struct led_classdev *led_cdev,
506 				enum led_brightness value)
507 {
508 	return blinkm_led_common_set(led_cdev, value, BLUE);
509 }
510 
511 static void blinkm_init_hw(struct i2c_client *client)
512 {
513 	blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
514 	blinkm_transfer_hw(client, BLM_GO_RGB);
515 }
516 
517 static int blinkm_test_run(struct i2c_client *client)
518 {
519 	int ret;
520 	struct blinkm_data *data = i2c_get_clientdata(client);
521 
522 	data->next_red = 0x01;
523 	data->next_green = 0x05;
524 	data->next_blue = 0x10;
525 	ret = blinkm_transfer_hw(client, BLM_GO_RGB);
526 	if (ret < 0)
527 		return ret;
528 	msleep(2000);
529 
530 	data->next_red = 0x25;
531 	data->next_green = 0x10;
532 	data->next_blue = 0x31;
533 	ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
534 	if (ret < 0)
535 		return ret;
536 	msleep(2000);
537 
538 	data->next_hue = 0x50;
539 	data->next_saturation = 0x10;
540 	data->next_brightness = 0x20;
541 	ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
542 	if (ret < 0)
543 		return ret;
544 	msleep(2000);
545 
546 	return 0;
547 }
548 
549 /* Return 0 if detection is successful, -ENODEV otherwise */
550 static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
551 {
552 	struct i2c_adapter *adapter = client->adapter;
553 	int ret;
554 	int count = 99;
555 	u8 tmpargs[7];
556 
557 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
558 				     | I2C_FUNC_SMBUS_WORD_DATA
559 				     | I2C_FUNC_SMBUS_WRITE_BYTE))
560 		return -ENODEV;
561 
562 	/* Now, we do the remaining detection. Simple for now. */
563 	/* We might need more guards to protect other i2c slaves */
564 
565 	/* make sure the blinkM is balanced (read/writes) */
566 	while (count > 0) {
567 		ret = blinkm_write(client, BLM_GET_ADDR, NULL);
568 		if (ret)
569 			return ret;
570 		usleep_range(5000, 10000);
571 		ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
572 		if (ret)
573 			return ret;
574 		usleep_range(5000, 10000);
575 		if (tmpargs[0] == 0x09)
576 			count = 0;
577 		count--;
578 	}
579 
580 	/* Step 1: Read BlinkM address back  -  cmd_char 'a' */
581 	ret = blinkm_write(client, BLM_GET_ADDR, NULL);
582 	if (ret < 0)
583 		return ret;
584 	usleep_range(20000, 30000);	/* allow a small delay */
585 	ret = blinkm_read(client, BLM_GET_ADDR, tmpargs);
586 	if (ret < 0)
587 		return ret;
588 
589 	if (tmpargs[0] != 0x09) {
590 		dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]);
591 		return -ENODEV;
592 	}
593 
594 	strscpy(info->type, "blinkm", I2C_NAME_SIZE);
595 	return 0;
596 }
597 
598 static int register_separate_colors(struct i2c_client *client, struct blinkm_data *data)
599 {
600 	/* 3 separate classes for red, green, and blue respectively */
601 	struct blinkm_led *leds[NUM_LEDS];
602 	int err;
603 	char blinkm_led_name[28];
604 	/* Register red, green, and blue sysfs classes */
605 	for (int i = 0; i < NUM_LEDS; i++) {
606 		/* RED = 0, GREEN = 1, BLUE = 2 */
607 		leds[i] = &data->blinkm_leds[i];
608 		leds[i]->i2c_client = client;
609 		leds[i]->id = i;
610 		leds[i]->cdev.led_cdev.max_brightness = 255;
611 		leds[i]->cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME;
612 		switch (i) {
613 		case RED:
614 			scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
615 					 "blinkm-%d-%d-red",
616 					 client->adapter->nr,
617 					 client->addr);
618 			leds[i]->cdev.led_cdev.name = blinkm_led_name;
619 			leds[i]->cdev.led_cdev.brightness_set_blocking =
620 							blinkm_led_red_set;
621 			err = led_classdev_register(&client->dev,
622 							&leds[i]->cdev.led_cdev);
623 			if (err < 0) {
624 				dev_err(&client->dev,
625 					"couldn't register LED %s\n",
626 					leds[i]->cdev.led_cdev.name);
627 				goto failred;
628 			}
629 			break;
630 		case GREEN:
631 			scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
632 					 "blinkm-%d-%d-green",
633 					 client->adapter->nr,
634 					 client->addr);
635 			leds[i]->cdev.led_cdev.name = blinkm_led_name;
636 			leds[i]->cdev.led_cdev.brightness_set_blocking =
637 							blinkm_led_green_set;
638 			err = led_classdev_register(&client->dev,
639 						&leds[i]->cdev.led_cdev);
640 			if (err < 0) {
641 				dev_err(&client->dev,
642 					"couldn't register LED %s\n",
643 					leds[i]->cdev.led_cdev.name);
644 				goto failgreen;
645 			}
646 			break;
647 		case BLUE:
648 			scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
649 					 "blinkm-%d-%d-blue",
650 					 client->adapter->nr,
651 					 client->addr);
652 			leds[i]->cdev.led_cdev.name = blinkm_led_name;
653 			leds[i]->cdev.led_cdev.brightness_set_blocking =
654 							blinkm_led_blue_set;
655 			err = led_classdev_register(&client->dev,
656 							&leds[i]->cdev.led_cdev);
657 			if (err < 0) {
658 				dev_err(&client->dev,
659 					"couldn't register LED %s\n",
660 					leds[i]->cdev.led_cdev.name);
661 				goto failblue;
662 			}
663 			break;
664 		default:
665 			break;
666 		}		/* end switch */
667 	}			/* end for */
668 	return 0;
669 
670 failblue:
671 	led_classdev_unregister(&leds[GREEN]->cdev.led_cdev);
672 failgreen:
673 	led_classdev_unregister(&leds[RED]->cdev.led_cdev);
674 failred:
675 	sysfs_remove_group(&client->dev.kobj, &blinkm_group);
676 
677 	return err;
678 }
679 
680 static int register_multicolor(struct i2c_client *client, struct blinkm_data *data)
681 {
682 	struct blinkm_led *mc_led;
683 	struct mc_subled *mc_led_info;
684 	char blinkm_led_name[28];
685 	int err;
686 
687 	/* Register multicolor sysfs class */
688 	/* The first element of leds is used for multicolor facilities */
689 	mc_led = &data->blinkm_leds[RED];
690 	mc_led->i2c_client = client;
691 
692 	mc_led_info = devm_kcalloc(&client->dev, NUM_LEDS, sizeof(*mc_led_info),
693 					GFP_KERNEL);
694 	if (!mc_led_info)
695 		return -ENOMEM;
696 
697 	mc_led_info[RED].color_index = LED_COLOR_ID_RED;
698 	mc_led_info[GREEN].color_index = LED_COLOR_ID_GREEN;
699 	mc_led_info[BLUE].color_index = LED_COLOR_ID_BLUE;
700 
701 	mc_led->cdev.mcled_cdev.subled_info = mc_led_info;
702 	mc_led->cdev.mcled_cdev.num_colors = NUM_LEDS;
703 	mc_led->cdev.mcled_cdev.led_cdev.brightness = 255;
704 	mc_led->cdev.mcled_cdev.led_cdev.max_brightness = 255;
705 	mc_led->cdev.mcled_cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME;
706 
707 	scnprintf(blinkm_led_name, sizeof(blinkm_led_name),
708 		 "blinkm-%d-%d:rgb:indicator",
709 		 client->adapter->nr,
710 		 client->addr);
711 	mc_led->cdev.mcled_cdev.led_cdev.name = blinkm_led_name;
712 	mc_led->cdev.mcled_cdev.led_cdev.brightness_set_blocking = blinkm_set_mc_brightness;
713 
714 	err = led_classdev_multicolor_register(&client->dev, &mc_led->cdev.mcled_cdev);
715 	if (err < 0) {
716 		dev_err(&client->dev, "couldn't register LED %s\n",
717 				mc_led->cdev.led_cdev.name);
718 		sysfs_remove_group(&client->dev.kobj, &blinkm_group);
719 	}
720 	return 0;
721 }
722 
723 static int blinkm_probe(struct i2c_client *client)
724 {
725 	struct blinkm_data *data;
726 	int err;
727 
728 	data = devm_kzalloc(&client->dev,
729 			sizeof(struct blinkm_data), GFP_KERNEL);
730 	if (!data)
731 		return -ENOMEM;
732 
733 	data->i2c_addr = 0x08;
734 	/* i2c addr  - use fake addr of 0x08 initially (real is 0x09) */
735 	data->fw_ver = 0xfe;
736 	/* firmware version - use fake until we read real value
737 	 * (currently broken - BlinkM confused!)
738 	 */
739 	data->script_id = 0x01;
740 	data->i2c_client = client;
741 
742 	i2c_set_clientdata(client, data);
743 	mutex_init(&data->update_lock);
744 
745 	/* Register sysfs hooks */
746 	err = sysfs_create_group(&client->dev.kobj, &blinkm_group);
747 	if (err < 0) {
748 		dev_err(&client->dev, "couldn't register sysfs group\n");
749 		return err;
750 	}
751 
752 	if (!IS_ENABLED(CONFIG_LEDS_BLINKM_MULTICOLOR)) {
753 		err = register_separate_colors(client, data);
754 		if (err < 0)
755 			return err;
756 	} else {
757 		err = register_multicolor(client, data);
758 		if (err < 0)
759 			return err;
760 	}
761 
762 	blinkm_init_hw(client);
763 
764 	return 0;
765 }
766 
767 static void blinkm_remove(struct i2c_client *client)
768 {
769 	struct blinkm_data *data = i2c_get_clientdata(client);
770 	int ret = 0;
771 	int i;
772 
773 	/* make sure no workqueue entries are pending */
774 	for (i = 0; i < NUM_LEDS; i++)
775 		led_classdev_unregister(&data->blinkm_leds[i].cdev.led_cdev);
776 
777 	/* reset rgb */
778 	data->next_red = 0x00;
779 	data->next_green = 0x00;
780 	data->next_blue = 0x00;
781 	ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
782 	if (ret < 0)
783 		dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
784 
785 	/* reset hsb */
786 	data->next_hue = 0x00;
787 	data->next_saturation = 0x00;
788 	data->next_brightness = 0x00;
789 	ret = blinkm_transfer_hw(client, BLM_FADE_HSB);
790 	if (ret < 0)
791 		dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
792 
793 	/* red fade to off */
794 	data->next_red = 0xff;
795 	ret = blinkm_transfer_hw(client, BLM_GO_RGB);
796 	if (ret < 0)
797 		dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
798 
799 	/* off */
800 	data->next_red = 0x00;
801 	ret = blinkm_transfer_hw(client, BLM_FADE_RGB);
802 	if (ret < 0)
803 		dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n");
804 
805 	sysfs_remove_group(&client->dev.kobj, &blinkm_group);
806 }
807 
808 static const struct i2c_device_id blinkm_id[] = {
809 	{ .name = "blinkm" },
810 	{ }
811 };
812 
813 MODULE_DEVICE_TABLE(i2c, blinkm_id);
814 
815   /* This is the driver that will be inserted */
816 static struct i2c_driver blinkm_driver = {
817 	.class = I2C_CLASS_HWMON,
818 	.driver = {
819 		   .name = "blinkm",
820 		   },
821 	.probe = blinkm_probe,
822 	.remove = blinkm_remove,
823 	.id_table = blinkm_id,
824 	.detect = blinkm_detect,
825 	.address_list = normal_i2c,
826 };
827 
828 module_i2c_driver(blinkm_driver);
829 
830 MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>");
831 MODULE_AUTHOR("Joseph Strauss <jstrauss@mailbox.org>");
832 MODULE_DESCRIPTION("BlinkM RGB LED driver");
833 MODULE_LICENSE("GPL");
834 
835