Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: trigger: netdev: Add core support for hw not supporting fallback to LED sw control

If hw doesn't support sw control of the LED and we switch to a mode
not supported by hw, currently we get lots of errors because neither
brigthness_set() nor brithness_set_blocking() is set.
Deal with this by not falling back to sw control, and return
-EOPNOTSUPP to the user. Note that we still store the new mode.
This is needed in case an intermediate unsupported mode is necessary
to switch from one supported mode to another.

Add a comment explaining how a driver for such hw is supposed to behave.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/3fd5184c-3641-4b0b-b59a-f489ec69a6cd@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Heiner Kallweit and committed by
Lee Jones
4289e434 afacb218

+15
+15
drivers/leds/trigger/ledtrig-netdev.c
··· 38 38 * tx - LED blinks on transmitted data 39 39 * rx - LED blinks on receive data 40 40 * 41 + * Note: If the user selects a mode that is not supported by hw, default 42 + * behavior is to fall back to software control of the LED. However not every 43 + * hw supports software control. LED callbacks brightness_set() and 44 + * brightness_set_blocking() are NULL in this case. hw_control_is_supported() 45 + * should use available means supported by hw to inform the user that selected 46 + * mode isn't supported by hw. This could be switching off the LED or any 47 + * hw blink mode. If software control fallback isn't possible, we return 48 + * -EOPNOTSUPP to the user, but still store the selected mode. This is needed 49 + * in case an intermediate unsupported mode is necessary to switch from one 50 + * supported mode to another. 41 51 */ 42 52 43 53 struct led_netdev_data { ··· 328 318 size_t size, enum led_trigger_netdev_modes attr) 329 319 { 330 320 struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); 321 + struct led_classdev *led_cdev = trigger_data->led_cdev; 331 322 unsigned long state, mode = trigger_data->mode; 332 323 int ret; 333 324 int bit; ··· 373 362 374 363 trigger_data->mode = mode; 375 364 trigger_data->hw_control = can_hw_control(trigger_data); 365 + 366 + if (!led_cdev->brightness_set && !led_cdev->brightness_set_blocking && 367 + !trigger_data->hw_control) 368 + return -EOPNOTSUPP; 376 369 377 370 set_baseline_state(trigger_data); 378 371