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