1 From 0efb3f9609d3de5a7d8c31e3835d7eb3e6adce79 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
3 Date: Mon, 18 Sep 2023 18:11:04 +0200
4 Subject: [PATCH 6/6] leds: turris-omnia: Add support for enabling/disabling HW
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 If the MCU on Turris Omnia is running newer firmware versions, the LED
11 controller supports RGB gamma correction (and enables it by default for
14 Determine whether the gamma correction setting feature is supported and
15 add the ability to set it via sysfs attribute file.
17 Signed-off-by: Marek BehĂșn <kabel@kernel.org>
18 Link: https://lore.kernel.org/r/20230918161104.20860-5-kabel@kernel.org
19 Signed-off-by: Lee Jones <lee@kernel.org>
21 .../sysfs-class-led-driver-turris-omnia | 14 ++
22 drivers/leds/leds-turris-omnia.c | 137 +++++++++++++++---
23 2 files changed, 134 insertions(+), 17 deletions(-)
25 --- a/Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
26 +++ b/Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
27 @@ -12,3 +12,17 @@ Description: (RW) On the front panel of
28 able to change this setting from software.
32 +What: /sys/class/leds/<led>/device/gamma_correction
35 +Contact: Marek BehĂșn <kabel@kernel.org>
36 +Description: (RW) Newer versions of the microcontroller firmware of the
37 + Turris Omnia router support gamma correction for the RGB LEDs.
38 + This feature can be enabled/disabled by writing to this file.
40 + If the feature is not supported because the MCU firmware is too
41 + old, the file always reads as 0, and writing to the file results
42 + in the EOPNOTSUPP error.
45 --- a/drivers/leds/leds-turris-omnia.c
46 +++ b/drivers/leds/leds-turris-omnia.c
48 #define OMNIA_BOARD_LEDS 12
49 #define OMNIA_LED_NUM_CHANNELS 3
51 -#define CMD_LED_MODE 3
52 -#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
53 -#define CMD_LED_MODE_USER 0x10
55 -#define CMD_LED_STATE 4
56 -#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
57 -#define CMD_LED_STATE_ON 0x10
59 -#define CMD_LED_COLOR 5
60 -#define CMD_LED_SET_BRIGHTNESS 7
61 -#define CMD_LED_GET_BRIGHTNESS 8
62 +/* MCU controller commands at I2C address 0x2a */
63 +#define OMNIA_MCU_I2C_ADDR 0x2a
65 +#define CMD_GET_STATUS_WORD 0x01
66 +#define STS_FEATURES_SUPPORTED BIT(2)
68 +#define CMD_GET_FEATURES 0x10
69 +#define FEAT_LED_GAMMA_CORRECTION BIT(5)
71 +/* LED controller commands at I2C address 0x2b */
72 +#define CMD_LED_MODE 0x03
73 +#define CMD_LED_MODE_LED(l) ((l) & 0x0f)
74 +#define CMD_LED_MODE_USER 0x10
76 +#define CMD_LED_STATE 0x04
77 +#define CMD_LED_STATE_LED(l) ((l) & 0x0f)
78 +#define CMD_LED_STATE_ON 0x10
80 +#define CMD_LED_COLOR 0x05
81 +#define CMD_LED_SET_BRIGHTNESS 0x07
82 +#define CMD_LED_GET_BRIGHTNESS 0x08
84 +#define CMD_SET_GAMMA_CORRECTION 0x30
85 +#define CMD_GET_GAMMA_CORRECTION 0x31
88 struct led_classdev_mc mc_cdev;
89 @@ -40,6 +53,7 @@ struct omnia_led {
91 struct i2c_client *client;
93 + bool has_gamma_correction;
94 struct omnia_led leds[];
97 @@ -50,30 +64,42 @@ static int omnia_cmd_write_u8(const stru
98 return i2c_master_send(client, buf, sizeof(buf));
101 -static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
102 +static int omnia_cmd_read_raw(struct i2c_adapter *adapter, u8 addr, u8 cmd,
103 + void *reply, size_t len)
105 struct i2c_msg msgs[2];
109 - msgs[0].addr = client->addr;
110 + msgs[0].addr = addr;
114 - msgs[1].addr = client->addr;
115 + msgs[1].addr = addr;
116 msgs[1].flags = I2C_M_RD;
118 - msgs[1].buf = &reply;
120 + msgs[1].buf = reply;
122 - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
123 + ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
124 if (likely(ret == ARRAY_SIZE(msgs)))
133 +static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
138 + ret = omnia_cmd_read_raw(client->adapter, client->addr, cmd, &reply, 1);
145 static int omnia_led_send_color_cmd(const struct i2c_client *client,
146 struct omnia_led *led)
148 @@ -352,12 +378,74 @@ static ssize_t brightness_store(struct d
150 static DEVICE_ATTR_RW(brightness);
152 +static ssize_t gamma_correction_show(struct device *dev,
153 + struct device_attribute *a, char *buf)
155 + struct i2c_client *client = to_i2c_client(dev);
156 + struct omnia_leds *leds = i2c_get_clientdata(client);
159 + if (leds->has_gamma_correction) {
160 + ret = omnia_cmd_read_u8(client, CMD_GET_GAMMA_CORRECTION);
167 + return sysfs_emit(buf, "%d\n", !!ret);
170 +static ssize_t gamma_correction_store(struct device *dev,
171 + struct device_attribute *a,
172 + const char *buf, size_t count)
174 + struct i2c_client *client = to_i2c_client(dev);
175 + struct omnia_leds *leds = i2c_get_clientdata(client);
179 + if (!leds->has_gamma_correction)
180 + return -EOPNOTSUPP;
182 + if (kstrtobool(buf, &val) < 0)
185 + ret = omnia_cmd_write_u8(client, CMD_SET_GAMMA_CORRECTION, val);
187 + return ret < 0 ? ret : count;
189 +static DEVICE_ATTR_RW(gamma_correction);
191 static struct attribute *omnia_led_controller_attrs[] = {
192 &dev_attr_brightness.attr,
193 + &dev_attr_gamma_correction.attr,
196 ATTRIBUTE_GROUPS(omnia_led_controller);
198 +static int omnia_mcu_get_features(const struct i2c_client *client)
203 + err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
204 + CMD_GET_STATUS_WORD, &reply, sizeof(reply));
208 + /* Check whether MCU firmware supports the CMD_GET_FEAUTRES command */
209 + if (!(le16_to_cpu(reply) & STS_FEATURES_SUPPORTED))
212 + err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR,
213 + CMD_GET_FEATURES, &reply, sizeof(reply));
217 + return le16_to_cpu(reply);
220 static int omnia_leds_probe(struct i2c_client *client)
222 struct device *dev = &client->dev;
223 @@ -382,6 +470,21 @@ static int omnia_leds_probe(struct i2c_c
224 leds->client = client;
225 i2c_set_clientdata(client, leds);
227 + ret = omnia_mcu_get_features(client);
229 + dev_err(dev, "Cannot determine MCU supported features: %d\n",
234 + leds->has_gamma_correction = ret & FEAT_LED_GAMMA_CORRECTION;
235 + if (!leds->has_gamma_correction) {
237 + "Your board's MCU firmware does not support the LED gamma correction feature.\n");
239 + "Consider upgrading MCU firmware with the omnia-mcutool utility.\n");
242 mutex_init(&leds->lock);
244 ret = devm_led_trigger_register(dev, &omnia_hw_trigger);