Lines Matching +full:turris +full:- +full:omnia +full:- +full:mcu

1 // SPDX-License-Identifier: GPL-2.0
3 * CZ.NIC's Turris Omnia LEDs driver
9 #include <linux/led-class-multicolor.h>
13 #include <linux/turris-omnia-mcu-interface.h>
18 /* MCU controller I2C address 0x2a, needed for detecting MCU features */
22 * struct omnia_led - per-LED part of driver private data structure
23 * @mc_cdev: multi-color LED class device
24 * @subled_info: per-channel information
25 * @cached_channels: cached values of per-channel brightness that was sent to the MCU
27 * @hwtrig: whether the LED blinking was offloaded to the MCU
28 * @reg: LED identifier to the MCU
41 * struct omnia_leds - driver private data structure
44 * @has_gamma_correction: whether the MCU firmware supports gamma correction
47 * @leds: flexible array of per-LED data
70 ret = omnia_cmd_set_color(client, led->reg, led->subled_info[0].brightness, in omnia_led_send_color_cmd()
71 led->subled_info[1].brightness, led->subled_info[2].brightness); in omnia_led_send_color_cmd()
77 led->cached_channels[i] = led->subled_info[i].brightness; in omnia_led_send_color_cmd()
86 if (led->subled_info[i].brightness != led->cached_channels[i]) in omnia_led_channels_changed()
96 struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); in omnia_led_brightness_set_blocking()
100 mutex_lock(&leds->lock); in omnia_led_brightness_set_blocking()
104 * non-zero (if it is zero and the LED is in HW blinking mode, we use in omnia_led_brightness_set_blocking()
106 * we can save ourselves some software divisions (Omnia's CPU does not in omnia_led_brightness_set_blocking()
109 if (brightness || led->hwtrig) { in omnia_led_brightness_set_blocking()
111 cdev->max_brightness); in omnia_led_brightness_set_blocking()
114 * Send color command only if brightness is non-zero and the RGB in omnia_led_brightness_set_blocking()
118 err = omnia_led_send_color_cmd(leds->client, led); in omnia_led_brightness_set_blocking()
125 if (!err && !led->hwtrig && !brightness != !led->on) { in omnia_led_brightness_set_blocking()
126 u8 state = OMNIA_CMD_LED_STATE_LED(led->reg); in omnia_led_brightness_set_blocking()
131 err = omnia_cmd_write_u8(leds->client, OMNIA_CMD_LED_STATE, state); in omnia_led_brightness_set_blocking()
133 led->on = !!brightness; in omnia_led_brightness_set_blocking()
136 mutex_unlock(&leds->lock); in omnia_led_brightness_set_blocking()
146 struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); in omnia_hwtrig_activate()
150 mutex_lock(&leds->lock); in omnia_hwtrig_activate()
152 if (!led->on) { in omnia_hwtrig_activate()
155 * configured color was not necessarily sent to the MCU. in omnia_hwtrig_activate()
158 led_mc_calc_color_components(mc_cdev, cdev->max_brightness); in omnia_hwtrig_activate()
161 err = omnia_led_send_color_cmd(leds->client, led); in omnia_hwtrig_activate()
165 /* Put the LED into MCU controlled mode */ in omnia_hwtrig_activate()
166 err = omnia_cmd_write_u8(leds->client, OMNIA_CMD_LED_MODE, in omnia_hwtrig_activate()
167 OMNIA_CMD_LED_MODE_LED(led->reg)); in omnia_hwtrig_activate()
169 led->hwtrig = true; in omnia_hwtrig_activate()
172 mutex_unlock(&leds->lock); in omnia_hwtrig_activate()
179 struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); in omnia_hwtrig_deactivate()
183 mutex_lock(&leds->lock); in omnia_hwtrig_deactivate()
185 led->hwtrig = false; in omnia_hwtrig_deactivate()
188 err = omnia_cmd_write_u8(leds->client, OMNIA_CMD_LED_MODE, in omnia_hwtrig_deactivate()
189 OMNIA_CMD_LED_MODE_LED(led->reg) | OMNIA_CMD_LED_MODE_USER); in omnia_hwtrig_deactivate()
191 mutex_unlock(&leds->lock); in omnia_hwtrig_deactivate()
194 dev_err(cdev->dev, "Cannot put LED to software mode: %i\n", in omnia_hwtrig_deactivate()
199 .name = "omnia-mcu",
209 struct device *dev = &client->dev; in omnia_led_register()
213 ret = of_property_read_u32(np, "reg", &led->reg); in omnia_led_register()
214 if (ret || led->reg >= OMNIA_BOARD_LEDS) { in omnia_led_register()
217 np, OMNIA_BOARD_LEDS - 1); in omnia_led_register()
229 led->subled_info[0].color_index = LED_COLOR_ID_RED; in omnia_led_register()
230 led->subled_info[1].color_index = LED_COLOR_ID_GREEN; in omnia_led_register()
231 led->subled_info[2].color_index = LED_COLOR_ID_BLUE; in omnia_led_register()
235 led->subled_info[i].intensity = 255; in omnia_led_register()
236 led->subled_info[i].brightness = 255; in omnia_led_register()
237 led->subled_info[i].channel = i; in omnia_led_register()
240 led->mc_cdev.subled_info = led->subled_info; in omnia_led_register()
241 led->mc_cdev.num_colors = OMNIA_LED_NUM_CHANNELS; in omnia_led_register()
243 init_data.fwnode = &np->fwnode; in omnia_led_register()
245 cdev = &led->mc_cdev.led_cdev; in omnia_led_register()
246 cdev->max_brightness = 255; in omnia_led_register()
247 cdev->brightness_set_blocking = omnia_led_brightness_set_blocking; in omnia_led_register()
248 cdev->trigger_type = &omnia_hw_trigger_type; in omnia_led_register()
250 * Use the omnia-mcu trigger as the default trigger. It may be rewritten in omnia_led_register()
251 * by LED class from the linux,default-trigger property. in omnia_led_register()
253 cdev->default_trigger = omnia_hw_trigger.name; in omnia_led_register()
256 ret = omnia_cmd_write_u8(client, OMNIA_CMD_LED_MODE, OMNIA_CMD_LED_MODE_LED(led->reg) | in omnia_led_register()
262 ret = omnia_cmd_write_u8(client, OMNIA_CMD_LED_STATE, OMNIA_CMD_LED_STATE_LED(led->reg)); in omnia_led_register()
271 ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc_cdev, in omnia_led_register()
280 * On the front panel of the Turris Omnia router there is also a button which
312 return -EINVAL; in brightness_store()
315 return -EINVAL; in brightness_store()
331 if (leds->has_gamma_correction) { in gamma_correction_show()
349 if (!leds->has_gamma_correction) in gamma_correction_store()
350 return -EOPNOTSUPP; in gamma_correction_store()
353 return -EINVAL; in gamma_correction_store()
372 if (unlikely(!leds->brightness_knode)) { in omnia_brightness_changed_threaded_fn()
377 leds->brightness_knode = sysfs_get_dirent(leds->client->dev.kobj.sd, "brightness"); in omnia_brightness_changed_threaded_fn()
378 if (!leds->brightness_knode) in omnia_brightness_changed_threaded_fn()
382 sysfs_notify_dirent(leds->brightness_knode); in omnia_brightness_changed_threaded_fn()
391 if (leds->brightness_knode) in omnia_brightness_knode_put()
392 sysfs_put(leds->brightness_knode); in omnia_brightness_knode_put()
397 struct device *dev = &leds->client->dev; in omnia_request_brightness_irq()
400 if (!leds->client->irq) { in omnia_request_brightness_irq()
402 "Brightness change interrupt supported by MCU firmware but not described in device-tree\n"); in omnia_request_brightness_irq()
416 return devm_request_threaded_irq(dev, leds->client->irq, NULL, in omnia_request_brightness_irq()
418 "leds-turris-omnia", leds); in omnia_request_brightness_irq()
430 /* Check whether MCU firmware supports the OMNIA_CMD_GET_FEAUTRES command */ in omnia_mcu_get_features()
449 return client->addr == OMNIA_MCU_I2C_ADDR; in omnia_match_mcu_client()
457 mcu_dev = device_find_child(dev->parent, NULL, omnia_match_mcu_client); in omnia_find_mcu_and_get_features()
459 return -ENODEV; in omnia_find_mcu_and_get_features()
470 struct device *dev = &client->dev; in omnia_leds_probe()
478 return dev_err_probe(dev, -ENODEV, "LEDs are not defined in device tree!\n"); in omnia_leds_probe()
480 return dev_err_probe(dev, -EINVAL, "Too many LEDs defined in device tree!\n"); in omnia_leds_probe()
484 return -ENOMEM; in omnia_leds_probe()
486 leds->client = client; in omnia_leds_probe()
491 return dev_err_probe(dev, ret, "Cannot determine MCU supported features\n"); in omnia_leds_probe()
493 leds->has_gamma_correction = ret & OMNIA_FEAT_LED_GAMMA_CORRECTION; in omnia_leds_probe()
501 mutex_init(&leds->lock); in omnia_leds_probe()
507 led = &leds->leds[0]; in omnia_leds_probe()
529 { .compatible = "cznic,turris-omnia-leds", },
535 { "omnia" },
545 .name = "leds-turris-omnia",
554 MODULE_DESCRIPTION("CZ.NIC's Turris Omnia LEDs");