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

leds: ariel: Add driver for status LEDs on Dell Wyse 3020

This adds support for controlling the LEDs attached to the Embedded
Controller on a Dell Wyse 3020 "Ariel" board.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Pavel Machek <pavel@ucw.cz>

authored by

Lubomir Rintel and committed by
Pavel Machek
03f613f0 44c606b0

+145
+11
drivers/leds/Kconfig
··· 83 83 To compile this driver as a module, choose M here: the 84 84 module will be called leds-apu. 85 85 86 + config LEDS_ARIEL 87 + tristate "Dell Wyse 3020 status LED support" 88 + depends on LEDS_CLASS 89 + depends on (MACH_MMP3_DT && MFD_ENE_KB3930) || COMPILE_TEST 90 + help 91 + This driver adds support for controlling the front panel status 92 + LEDs on Dell Wyse 3020 (Ariel) board via the KB3930 Embedded 93 + Controller. 94 + 95 + Say Y to if your machine is a Dell Wyse 3020 thin client. 96 + 86 97 config LEDS_AS3645A 87 98 tristate "AS3645A and LM3555 LED flash controllers support" 88 99 depends on I2C && LEDS_CLASS_FLASH
+1
drivers/leds/Makefile
··· 12 12 obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o 13 13 obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o 14 14 obj-$(CONFIG_LEDS_APU) += leds-apu.o 15 + obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o 15 16 obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o 16 17 obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o 17 18 obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
+133
drivers/leds/leds-ariel.c
··· 1 + // SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0-or-later 2 + /* 3 + * Dell Wyse 3020 a.k.a. "Ariel" Embedded Controller LED Driver 4 + * 5 + * Copyright (C) 2020 Lubomir Rintel 6 + */ 7 + 8 + #include <linux/module.h> 9 + #include <linux/leds.h> 10 + #include <linux/regmap.h> 11 + #include <linux/of_platform.h> 12 + 13 + enum ec_index { 14 + EC_BLUE_LED = 0x01, 15 + EC_AMBER_LED = 0x02, 16 + EC_GREEN_LED = 0x03, 17 + }; 18 + 19 + enum { 20 + EC_LED_OFF = 0x00, 21 + EC_LED_STILL = 0x01, 22 + EC_LED_FADE = 0x02, 23 + EC_LED_BLINK = 0x03, 24 + }; 25 + 26 + struct ariel_led { 27 + struct regmap *ec_ram; 28 + enum ec_index ec_index; 29 + struct led_classdev led_cdev; 30 + }; 31 + 32 + #define led_cdev_to_ariel_led(c) container_of(c, struct ariel_led, led_cdev) 33 + 34 + static enum led_brightness ariel_led_get(struct led_classdev *led_cdev) 35 + { 36 + struct ariel_led *led = led_cdev_to_ariel_led(led_cdev); 37 + unsigned int led_status = 0; 38 + 39 + if (regmap_read(led->ec_ram, led->ec_index, &led_status)) 40 + return LED_OFF; 41 + 42 + if (led_status == EC_LED_STILL) 43 + return LED_FULL; 44 + else 45 + return LED_OFF; 46 + } 47 + 48 + static void ariel_led_set(struct led_classdev *led_cdev, 49 + enum led_brightness brightness) 50 + { 51 + struct ariel_led *led = led_cdev_to_ariel_led(led_cdev); 52 + 53 + if (brightness == LED_OFF) 54 + regmap_write(led->ec_ram, led->ec_index, EC_LED_OFF); 55 + else 56 + regmap_write(led->ec_ram, led->ec_index, EC_LED_STILL); 57 + } 58 + 59 + static int ariel_blink_set(struct led_classdev *led_cdev, 60 + unsigned long *delay_on, unsigned long *delay_off) 61 + { 62 + struct ariel_led *led = led_cdev_to_ariel_led(led_cdev); 63 + 64 + if (*delay_on == 0 && *delay_off == 0) 65 + return -EINVAL; 66 + 67 + if (*delay_on == 0) { 68 + regmap_write(led->ec_ram, led->ec_index, EC_LED_OFF); 69 + } else if (*delay_off == 0) { 70 + regmap_write(led->ec_ram, led->ec_index, EC_LED_STILL); 71 + } else { 72 + *delay_on = 500; 73 + *delay_off = 500; 74 + regmap_write(led->ec_ram, led->ec_index, EC_LED_BLINK); 75 + } 76 + 77 + return 0; 78 + } 79 + 80 + #define NLEDS 3 81 + 82 + static int ariel_led_probe(struct platform_device *pdev) 83 + { 84 + struct device *dev = &pdev->dev; 85 + struct ariel_led *leds; 86 + struct regmap *ec_ram; 87 + int ret; 88 + int i; 89 + 90 + ec_ram = dev_get_regmap(dev->parent, "ec_ram"); 91 + if (!ec_ram) 92 + return -ENODEV; 93 + 94 + leds = devm_kcalloc(dev, NLEDS, sizeof(*leds), GFP_KERNEL); 95 + if (!leds) 96 + return -ENOMEM; 97 + 98 + leds[0].ec_index = EC_BLUE_LED; 99 + leds[0].led_cdev.name = "blue:power", 100 + leds[0].led_cdev.default_trigger = "default-on"; 101 + 102 + leds[1].ec_index = EC_AMBER_LED; 103 + leds[1].led_cdev.name = "amber:status", 104 + 105 + leds[2].ec_index = EC_GREEN_LED; 106 + leds[2].led_cdev.name = "green:status", 107 + leds[2].led_cdev.default_trigger = "default-on"; 108 + 109 + for (i = 0; i < NLEDS; i++) { 110 + leds[i].ec_ram = ec_ram; 111 + leds[i].led_cdev.brightness_get = ariel_led_get; 112 + leds[i].led_cdev.brightness_set = ariel_led_set; 113 + leds[i].led_cdev.blink_set = ariel_blink_set; 114 + 115 + ret = devm_led_classdev_register(dev, &leds[i].led_cdev); 116 + if (ret) 117 + return ret; 118 + } 119 + 120 + return 0; 121 + } 122 + 123 + static struct platform_driver ariel_led_driver = { 124 + .probe = ariel_led_probe, 125 + .driver = { 126 + .name = "dell-wyse-ariel-led", 127 + }, 128 + }; 129 + module_platform_driver(ariel_led_driver); 130 + 131 + MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 132 + MODULE_DESCRIPTION("Dell Wyse 3020 Status LEDs Driver"); 133 + MODULE_LICENSE("Dual BSD/GPL");