Skip to content

Commit cddfbe0

Browse files
committed
Merge remote-tracking branch 'remotes/philmd-gitlab/tags/led-api-20201026' into staging
API to model LED. CI jobs results: . https://cirrus-ci.com/build/4879251751043072 . https://gitlab.com/philmd/qemu/-/pipelines/207661784 . https://travis-ci.org/github/philmd/qemu/builds/738958191 . https://app.shippable.com/github/philmd/qemu/runs/891/summary/console # gpg: Signature made Mon 26 Oct 2020 22:03:59 GMT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <[email protected]>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/led-api-20201026: hw/arm/tosa: Replace fprintf() calls by LED devices hw/misc/mps2-scc: Use the LED device hw/misc/mps2-fpgaio: Use the LED device hw/arm/aspeed: Add the 3 front LEDs drived by the PCA9552 #1 hw/misc/led: Emit a trace event when LED intensity has changed hw/misc/led: Allow connecting from GPIO output hw/misc/led: Add a LED device Signed-off-by: Peter Maydell <[email protected]>
2 parents cfc1105 + 0697206 commit cddfbe0

14 files changed

+365
-43
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,12 @@ F: docs/specs/vmgenid.txt
19671967
F: tests/qtest/vmgenid-test.c
19681968
F: stubs/vmgenid.c
19691969

1970+
LED
1971+
M: Philippe Mathieu-Daudé <[email protected]>
1972+
S: Maintained
1973+
F: include/hw/misc/led.h
1974+
F: hw/misc/led.c
1975+
19701976
Unimplemented device
19711977
M: Peter Maydell <[email protected]>
19721978
R: Philippe Mathieu-Daudé <[email protected]>

hw/arm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ config TOSA
151151
select ZAURUS # scoop
152152
select MICRODRIVE
153153
select PXA2XX
154+
select LED
154155

155156
config SPITZ
156157
bool
@@ -404,6 +405,7 @@ config ASPEED_SOC
404405
select TMP105
405406
select TMP421
406407
select UNIMP
408+
select LED
407409

408410
config MPS2
409411
bool

hw/arm/aspeed.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "hw/i2c/smbus_eeprom.h"
2121
#include "hw/misc/pca9552.h"
2222
#include "hw/misc/tmp105.h"
23+
#include "hw/misc/led.h"
2324
#include "hw/qdev-properties.h"
2425
#include "qemu/log.h"
2526
#include "sysemu/block-backend.h"
@@ -525,9 +526,20 @@ static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc)
525526

526527
static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
527528
{
529+
static const struct {
530+
unsigned gpio_id;
531+
LEDColor color;
532+
const char *description;
533+
bool gpio_polarity;
534+
} pca1_leds[] = {
535+
{13, LED_COLOR_GREEN, "front-fault-4", GPIO_POLARITY_ACTIVE_LOW},
536+
{14, LED_COLOR_GREEN, "front-power-3", GPIO_POLARITY_ACTIVE_LOW},
537+
{15, LED_COLOR_GREEN, "front-id-5", GPIO_POLARITY_ACTIVE_LOW},
538+
};
528539
AspeedSoCState *soc = &bmc->soc;
529540
uint8_t *eeprom_buf = g_malloc0(8 * 1024);
530541
DeviceState *dev;
542+
LEDState *led;
531543

532544
/* Bus 3: TODO bmp280@77 */
533545
/* Bus 3: TODO max31785@52 */
@@ -538,6 +550,14 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
538550
aspeed_i2c_get_bus(&soc->i2c, 3),
539551
&error_fatal);
540552

553+
for (size_t i = 0; i < ARRAY_SIZE(pca1_leds); i++) {
554+
led = led_create_simple(OBJECT(bmc),
555+
pca1_leds[i].gpio_polarity,
556+
pca1_leds[i].color,
557+
pca1_leds[i].description);
558+
qdev_connect_gpio_out(dev, pca1_leds[i].gpio_id,
559+
qdev_get_gpio_in(DEVICE(led), 0));
560+
}
541561
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c);
542562
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c);
543563

hw/arm/tosa.c

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "hw/irq.h"
2525
#include "hw/ssi/ssi.h"
2626
#include "hw/sysbus.h"
27+
#include "hw/misc/led.h"
2728
#include "exec/address-spaces.h"
2829
#include "qom/object.h"
2930

@@ -81,26 +82,6 @@ struct TosaMiscGPIOState {
8182
SysBusDevice parent_obj;
8283
};
8384

84-
static void tosa_gpio_leds(void *opaque, int line, int level)
85-
{
86-
switch (line) {
87-
case 0:
88-
fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
89-
break;
90-
case 1:
91-
fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
92-
break;
93-
case 2:
94-
fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
95-
break;
96-
case 3:
97-
fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
98-
break;
99-
default:
100-
g_assert_not_reached();
101-
}
102-
}
103-
10485
static void tosa_reset(void *opaque, int line, int level)
10586
{
10687
if (level) {
@@ -112,7 +93,6 @@ static void tosa_misc_gpio_init(Object *obj)
11293
{
11394
DeviceState *dev = DEVICE(obj);
11495

115-
qdev_init_gpio_in_named(dev, tosa_gpio_leds, "leds", 4);
11696
qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1);
11797
}
11898

@@ -122,6 +102,7 @@ static void tosa_gpio_setup(PXA2xxState *cpu,
122102
TC6393xbState *tmio)
123103
{
124104
DeviceState *misc_gpio;
105+
LEDState *led[4];
125106

126107
misc_gpio = sysbus_create_simple(TYPE_TOSA_MISC_GPIO, -1, NULL);
127108

@@ -143,14 +124,23 @@ static void tosa_gpio_setup(PXA2xxState *cpu,
143124
qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
144125
NULL);
145126

127+
led[0] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
128+
LED_COLOR_BLUE, "bluetooth");
129+
led[1] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
130+
LED_COLOR_GREEN, "note");
131+
led[2] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
132+
LED_COLOR_AMBER, "charger-error");
133+
led[3] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
134+
LED_COLOR_GREEN, "wlan");
135+
146136
qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED,
147-
qdev_get_gpio_in_named(misc_gpio, "leds", 0));
137+
qdev_get_gpio_in(DEVICE(led[0]), 0));
148138
qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED,
149-
qdev_get_gpio_in_named(misc_gpio, "leds", 1));
139+
qdev_get_gpio_in(DEVICE(led[1]), 0));
150140
qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED,
151-
qdev_get_gpio_in_named(misc_gpio, "leds", 2));
141+
qdev_get_gpio_in(DEVICE(led[2]), 0));
152142
qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED,
153-
qdev_get_gpio_in_named(misc_gpio, "leds", 3));
143+
qdev_get_gpio_in(DEVICE(led[3]), 0));
154144

155145
qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
156146

hw/misc/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ config MIPS_ITU
9393

9494
config MPS2_FPGAIO
9595
bool
96+
select LED
9697

9798
config MPS2_SCC
9899
bool
100+
select LED
99101

100102
config TZ_MPC
101103
bool
@@ -126,6 +128,9 @@ config AUX
126128
config UNIMP
127129
bool
128130

131+
config LED
132+
bool
133+
129134
config MAC_VIA
130135
bool
131136
select MOS6522

hw/misc/led.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* QEMU single LED device
3+
*
4+
* Copyright (C) 2020 Philippe Mathieu-Daudé <[email protected]>
5+
*
6+
* SPDX-License-Identifier: GPL-2.0-or-later
7+
*/
8+
#include "qemu/osdep.h"
9+
#include "qapi/error.h"
10+
#include "migration/vmstate.h"
11+
#include "hw/qdev-properties.h"
12+
#include "hw/misc/led.h"
13+
#include "hw/irq.h"
14+
#include "trace.h"
15+
16+
#define LED_INTENSITY_PERCENT_MAX 100
17+
18+
static const char * const led_color_name[] = {
19+
[LED_COLOR_VIOLET] = "violet",
20+
[LED_COLOR_BLUE] = "blue",
21+
[LED_COLOR_CYAN] = "cyan",
22+
[LED_COLOR_GREEN] = "green",
23+
[LED_COLOR_AMBER] = "amber",
24+
[LED_COLOR_ORANGE] = "orange",
25+
[LED_COLOR_RED] = "red",
26+
};
27+
28+
static bool led_color_name_is_valid(const char *color_name)
29+
{
30+
for (size_t i = 0; i < ARRAY_SIZE(led_color_name); i++) {
31+
if (strcmp(color_name, led_color_name[i]) == 0) {
32+
return true;
33+
}
34+
}
35+
return false;
36+
}
37+
38+
void led_set_intensity(LEDState *s, unsigned intensity_percent)
39+
{
40+
if (intensity_percent > LED_INTENSITY_PERCENT_MAX) {
41+
intensity_percent = LED_INTENSITY_PERCENT_MAX;
42+
}
43+
trace_led_set_intensity(s->description, s->color, intensity_percent);
44+
if (intensity_percent != s->intensity_percent) {
45+
trace_led_change_intensity(s->description, s->color,
46+
s->intensity_percent, intensity_percent);
47+
}
48+
s->intensity_percent = intensity_percent;
49+
}
50+
51+
unsigned led_get_intensity(LEDState *s)
52+
{
53+
return s->intensity_percent;
54+
}
55+
56+
void led_set_state(LEDState *s, bool is_emitting)
57+
{
58+
led_set_intensity(s, is_emitting ? LED_INTENSITY_PERCENT_MAX : 0);
59+
}
60+
61+
static void led_set_state_gpio_handler(void *opaque, int line, int new_state)
62+
{
63+
LEDState *s = LED(opaque);
64+
65+
assert(line == 0);
66+
led_set_state(s, !!new_state != s->gpio_active_high);
67+
}
68+
69+
static void led_reset(DeviceState *dev)
70+
{
71+
LEDState *s = LED(dev);
72+
73+
led_set_state(s, s->gpio_active_high);
74+
}
75+
76+
static const VMStateDescription vmstate_led = {
77+
.name = TYPE_LED,
78+
.version_id = 1,
79+
.minimum_version_id = 1,
80+
.fields = (VMStateField[]) {
81+
VMSTATE_UINT8(intensity_percent, LEDState),
82+
VMSTATE_END_OF_LIST()
83+
}
84+
};
85+
86+
static void led_realize(DeviceState *dev, Error **errp)
87+
{
88+
LEDState *s = LED(dev);
89+
90+
if (s->color == NULL) {
91+
error_setg(errp, "property 'color' not specified");
92+
return;
93+
} else if (!led_color_name_is_valid(s->color)) {
94+
error_setg(errp, "property 'color' invalid or not supported");
95+
return;
96+
}
97+
if (s->description == NULL) {
98+
s->description = g_strdup("n/a");
99+
}
100+
101+
qdev_init_gpio_in(DEVICE(s), led_set_state_gpio_handler, 1);
102+
}
103+
104+
static Property led_properties[] = {
105+
DEFINE_PROP_STRING("color", LEDState, color),
106+
DEFINE_PROP_STRING("description", LEDState, description),
107+
DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true),
108+
DEFINE_PROP_END_OF_LIST(),
109+
};
110+
111+
static void led_class_init(ObjectClass *klass, void *data)
112+
{
113+
DeviceClass *dc = DEVICE_CLASS(klass);
114+
115+
dc->desc = "LED";
116+
dc->vmsd = &vmstate_led;
117+
dc->reset = led_reset;
118+
dc->realize = led_realize;
119+
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
120+
device_class_set_props(dc, led_properties);
121+
}
122+
123+
static const TypeInfo led_info = {
124+
.name = TYPE_LED,
125+
.parent = TYPE_DEVICE,
126+
.instance_size = sizeof(LEDState),
127+
.class_init = led_class_init
128+
};
129+
130+
static void led_register_types(void)
131+
{
132+
type_register_static(&led_info);
133+
}
134+
135+
type_init(led_register_types)
136+
137+
LEDState *led_create_simple(Object *parentobj,
138+
GpioPolarity gpio_polarity,
139+
LEDColor color,
140+
const char *description)
141+
{
142+
g_autofree char *name = NULL;
143+
DeviceState *dev;
144+
145+
dev = qdev_new(TYPE_LED);
146+
qdev_prop_set_bit(dev, "gpio-active-high",
147+
gpio_polarity == GPIO_POLARITY_ACTIVE_HIGH);
148+
qdev_prop_set_string(dev, "color", led_color_name[color]);
149+
if (!description) {
150+
static unsigned undescribed_led_id;
151+
name = g_strdup_printf("undescribed-led-#%u", undescribed_led_id++);
152+
} else {
153+
qdev_prop_set_string(dev, "description", description);
154+
name = g_ascii_strdown(description, -1);
155+
name = g_strdelimit(name, " #", '-');
156+
}
157+
object_property_add_child(parentobj, name, OBJECT(dev));
158+
qdev_realize_and_unref(dev, NULL, &error_fatal);
159+
160+
return LED(dev);
161+
}

hw/misc/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c'))
1111
softmmu_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c'))
1212
softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
1313
softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
14+
softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c'))
1415

1516
# ARM devices
1617
softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c'))

0 commit comments

Comments
 (0)