Skip to content

Commit 0ef2929

Browse files
thom24lag-linaro
authored andcommitted
leds: Add AAEON UP board LED driver
Add support for LEDs on AAEON UP boards. These leds are managed by the onboard FPGA: - UP boards: yellow, green, red - UP Squared boards: blue, yellow, green, red Based on the work done by Gary Wang <garywang@aaeon.com.tw>, largely rewritten. Signed-off-by: Thomas Richard <thomas.richard@bootlin.com> Link: https://lore.kernel.org/r/20241211-aaeon-up-board-pinctrl-support-v1-2-24719be27631@bootlin.com Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 0dfda50 commit 0ef2929

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

drivers/leds/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,15 @@ config LEDS_SC27XX_BLTC
817817
This driver can also be built as a module. If so the module will be
818818
called leds-sc27xx-bltc.
819819

820+
config LEDS_UPBOARD
821+
tristate "LED support for the UP board"
822+
depends on LEDS_CLASS && MFD_UPBOARD_FPGA
823+
help
824+
This option enables support for the UP board LEDs.
825+
826+
This driver can also be built as a module. If so the module will be
827+
called leds-upboard.
828+
820829
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
821830

822831
config LEDS_BLINKM

drivers/leds/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
8989
obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o
9090
obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o
9191
obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o
92+
obj-$(CONFIG_LEDS_UPBOARD) += leds-upboard.o
9293
obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
9394
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
9495
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o

drivers/leds/leds-upboard.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* UP board LED driver.
4+
*
5+
* Copyright (c) AAEON. All rights reserved.
6+
* Copyright (C) 2024 Bootlin
7+
*
8+
* Author: Gary Wang <garywang@aaeon.com.tw>
9+
* Author: Thomas Richard <thomas.richard@bootlin.com>
10+
*/
11+
12+
#include <linux/device.h>
13+
#include <linux/container_of.h>
14+
#include <linux/leds.h>
15+
#include <linux/mfd/upboard-fpga.h>
16+
#include <linux/module.h>
17+
#include <linux/platform_device.h>
18+
#include <linux/regmap.h>
19+
20+
#define led_cdev_to_led_upboard(c) container_of(c, struct upboard_led, cdev)
21+
22+
struct upboard_led {
23+
struct regmap_field *field;
24+
struct led_classdev cdev;
25+
};
26+
27+
struct upboard_led_profile {
28+
const char *name;
29+
unsigned int bit;
30+
};
31+
32+
static struct upboard_led_profile upboard_up_led_profile[] = {
33+
{ "upboard:yellow:" LED_FUNCTION_STATUS, 0 },
34+
{ "upboard:green:" LED_FUNCTION_STATUS, 1 },
35+
{ "upboard:red:" LED_FUNCTION_STATUS, 2 },
36+
};
37+
38+
static struct upboard_led_profile upboard_up2_led_profile[] = {
39+
{ "upboard:blue:" LED_FUNCTION_STATUS, 0 },
40+
{ "upboard:yellow:" LED_FUNCTION_STATUS, 1 },
41+
{ "upboard:green:" LED_FUNCTION_STATUS, 2 },
42+
{ "upboard:red:" LED_FUNCTION_STATUS, 3 },
43+
};
44+
45+
static enum led_brightness upboard_led_brightness_get(struct led_classdev *cdev)
46+
{
47+
struct upboard_led *led = led_cdev_to_led_upboard(cdev);
48+
int brightness, ret;
49+
50+
ret = regmap_field_read(led->field, &brightness);
51+
52+
return ret ? LED_OFF : brightness;
53+
};
54+
55+
static int upboard_led_brightness_set(struct led_classdev *cdev, enum led_brightness brightness)
56+
{
57+
struct upboard_led *led = led_cdev_to_led_upboard(cdev);
58+
59+
return regmap_field_write(led->field, brightness != LED_OFF);
60+
};
61+
62+
static int upboard_led_probe(struct platform_device *pdev)
63+
{
64+
struct device *dev = &pdev->dev;
65+
struct upboard_fpga *fpga = dev_get_drvdata(dev->parent);
66+
struct upboard_led_profile *led_profile;
67+
struct upboard_led *led;
68+
int led_instances, ret, i;
69+
70+
switch (fpga->fpga_data->type) {
71+
case UPBOARD_UP_FPGA:
72+
led_profile = upboard_up_led_profile;
73+
led_instances = ARRAY_SIZE(upboard_up_led_profile);
74+
break;
75+
case UPBOARD_UP2_FPGA:
76+
led_profile = upboard_up2_led_profile;
77+
led_instances = ARRAY_SIZE(upboard_up2_led_profile);
78+
break;
79+
default:
80+
return dev_err_probe(dev, -EINVAL, "Unknown device type %d\n",
81+
fpga->fpga_data->type);
82+
}
83+
84+
for (i = 0; i < led_instances; i++) {
85+
const struct reg_field fldconf = {
86+
.reg = UPBOARD_REG_FUNC_EN0,
87+
.lsb = led_profile[i].bit,
88+
.msb = led_profile[i].bit,
89+
};
90+
91+
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
92+
if (!led)
93+
return -ENOMEM;
94+
95+
led->field = devm_regmap_field_alloc(&pdev->dev, fpga->regmap, fldconf);
96+
if (IS_ERR(led->field))
97+
return PTR_ERR(led->field);
98+
99+
led->cdev.brightness_get = upboard_led_brightness_get;
100+
led->cdev.brightness_set_blocking = upboard_led_brightness_set;
101+
led->cdev.max_brightness = LED_ON;
102+
103+
led->cdev.name = led_profile[i].name;
104+
105+
ret = devm_led_classdev_register(dev, &led->cdev);
106+
if (ret)
107+
return ret;
108+
}
109+
110+
return 0;
111+
}
112+
113+
static struct platform_driver upboard_led_driver = {
114+
.driver = {
115+
.name = "upboard-leds",
116+
},
117+
.probe = upboard_led_probe,
118+
};
119+
120+
module_platform_driver(upboard_led_driver);
121+
122+
MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>");
123+
MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
124+
MODULE_DESCRIPTION("UP Board LED driver");
125+
MODULE_LICENSE("GPL");
126+
MODULE_ALIAS("platform:upboard-led");

0 commit comments

Comments
 (0)