Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/philmd-gitlab/tags/led-api-2020…
Browse files Browse the repository at this point in the history
…1026' 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 qemu#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]>
  • Loading branch information
pm215 committed Oct 27, 2020
2 parents cfc1105 + 0697206 commit cddfbe0
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 43 deletions.
6 changes: 6 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,12 @@ F: docs/specs/vmgenid.txt
F: tests/qtest/vmgenid-test.c
F: stubs/vmgenid.c

LED
M: Philippe Mathieu-Daudé <[email protected]>
S: Maintained
F: include/hw/misc/led.h
F: hw/misc/led.c

Unimplemented device
M: Peter Maydell <[email protected]>
R: Philippe Mathieu-Daudé <[email protected]>
Expand Down
2 changes: 2 additions & 0 deletions hw/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ config TOSA
select ZAURUS # scoop
select MICRODRIVE
select PXA2XX
select LED

config SPITZ
bool
Expand Down Expand Up @@ -404,6 +405,7 @@ config ASPEED_SOC
select TMP105
select TMP421
select UNIMP
select LED

config MPS2
bool
Expand Down
20 changes: 20 additions & 0 deletions hw/arm/aspeed.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "hw/i2c/smbus_eeprom.h"
#include "hw/misc/pca9552.h"
#include "hw/misc/tmp105.h"
#include "hw/misc/led.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
Expand Down Expand Up @@ -525,9 +526,20 @@ static void sonorapass_bmc_i2c_init(AspeedMachineState *bmc)

static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
{
static const struct {
unsigned gpio_id;
LEDColor color;
const char *description;
bool gpio_polarity;
} pca1_leds[] = {
{13, LED_COLOR_GREEN, "front-fault-4", GPIO_POLARITY_ACTIVE_LOW},
{14, LED_COLOR_GREEN, "front-power-3", GPIO_POLARITY_ACTIVE_LOW},
{15, LED_COLOR_GREEN, "front-id-5", GPIO_POLARITY_ACTIVE_LOW},
};
AspeedSoCState *soc = &bmc->soc;
uint8_t *eeprom_buf = g_malloc0(8 * 1024);
DeviceState *dev;
LEDState *led;

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

for (size_t i = 0; i < ARRAY_SIZE(pca1_leds); i++) {
led = led_create_simple(OBJECT(bmc),
pca1_leds[i].gpio_polarity,
pca1_leds[i].color,
pca1_leds[i].description);
qdev_connect_gpio_out(dev, pca1_leds[i].gpio_id,
qdev_get_gpio_in(DEVICE(led), 0));
}
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "tmp423", 0x4c);
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "tmp423", 0x4c);

Expand Down
40 changes: 15 additions & 25 deletions hw/arm/tosa.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "hw/irq.h"
#include "hw/ssi/ssi.h"
#include "hw/sysbus.h"
#include "hw/misc/led.h"
#include "exec/address-spaces.h"
#include "qom/object.h"

Expand Down Expand Up @@ -81,26 +82,6 @@ struct TosaMiscGPIOState {
SysBusDevice parent_obj;
};

static void tosa_gpio_leds(void *opaque, int line, int level)
{
switch (line) {
case 0:
fprintf(stderr, "blue LED %s.\n", level ? "on" : "off");
break;
case 1:
fprintf(stderr, "green LED %s.\n", level ? "on" : "off");
break;
case 2:
fprintf(stderr, "amber LED %s.\n", level ? "on" : "off");
break;
case 3:
fprintf(stderr, "wlan LED %s.\n", level ? "on" : "off");
break;
default:
g_assert_not_reached();
}
}

static void tosa_reset(void *opaque, int line, int level)
{
if (level) {
Expand All @@ -112,7 +93,6 @@ static void tosa_misc_gpio_init(Object *obj)
{
DeviceState *dev = DEVICE(obj);

qdev_init_gpio_in_named(dev, tosa_gpio_leds, "leds", 4);
qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1);
}

Expand All @@ -122,6 +102,7 @@ static void tosa_gpio_setup(PXA2xxState *cpu,
TC6393xbState *tmio)
{
DeviceState *misc_gpio;
LEDState *led[4];

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

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

led[0] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
LED_COLOR_BLUE, "bluetooth");
led[1] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
LED_COLOR_GREEN, "note");
led[2] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
LED_COLOR_AMBER, "charger-error");
led[3] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
LED_COLOR_GREEN, "wlan");

qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED,
qdev_get_gpio_in_named(misc_gpio, "leds", 0));
qdev_get_gpio_in(DEVICE(led[0]), 0));
qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED,
qdev_get_gpio_in_named(misc_gpio, "leds", 1));
qdev_get_gpio_in(DEVICE(led[1]), 0));
qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED,
qdev_get_gpio_in_named(misc_gpio, "leds", 2));
qdev_get_gpio_in(DEVICE(led[2]), 0));
qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED,
qdev_get_gpio_in_named(misc_gpio, "leds", 3));
qdev_get_gpio_in(DEVICE(led[3]), 0));

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

Expand Down
5 changes: 5 additions & 0 deletions hw/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ config MIPS_ITU

config MPS2_FPGAIO
bool
select LED

config MPS2_SCC
bool
select LED

config TZ_MPC
bool
Expand Down Expand Up @@ -126,6 +128,9 @@ config AUX
config UNIMP
bool

config LED
bool

config MAC_VIA
bool
select MOS6522
Expand Down
161 changes: 161 additions & 0 deletions hw/misc/led.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* QEMU single LED device
*
* Copyright (C) 2020 Philippe Mathieu-Daudé <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/misc/led.h"
#include "hw/irq.h"
#include "trace.h"

#define LED_INTENSITY_PERCENT_MAX 100

static const char * const led_color_name[] = {
[LED_COLOR_VIOLET] = "violet",
[LED_COLOR_BLUE] = "blue",
[LED_COLOR_CYAN] = "cyan",
[LED_COLOR_GREEN] = "green",
[LED_COLOR_AMBER] = "amber",
[LED_COLOR_ORANGE] = "orange",
[LED_COLOR_RED] = "red",
};

static bool led_color_name_is_valid(const char *color_name)
{
for (size_t i = 0; i < ARRAY_SIZE(led_color_name); i++) {
if (strcmp(color_name, led_color_name[i]) == 0) {
return true;
}
}
return false;
}

void led_set_intensity(LEDState *s, unsigned intensity_percent)
{
if (intensity_percent > LED_INTENSITY_PERCENT_MAX) {
intensity_percent = LED_INTENSITY_PERCENT_MAX;
}
trace_led_set_intensity(s->description, s->color, intensity_percent);
if (intensity_percent != s->intensity_percent) {
trace_led_change_intensity(s->description, s->color,
s->intensity_percent, intensity_percent);
}
s->intensity_percent = intensity_percent;
}

unsigned led_get_intensity(LEDState *s)
{
return s->intensity_percent;
}

void led_set_state(LEDState *s, bool is_emitting)
{
led_set_intensity(s, is_emitting ? LED_INTENSITY_PERCENT_MAX : 0);
}

static void led_set_state_gpio_handler(void *opaque, int line, int new_state)
{
LEDState *s = LED(opaque);

assert(line == 0);
led_set_state(s, !!new_state != s->gpio_active_high);
}

static void led_reset(DeviceState *dev)
{
LEDState *s = LED(dev);

led_set_state(s, s->gpio_active_high);
}

static const VMStateDescription vmstate_led = {
.name = TYPE_LED,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(intensity_percent, LEDState),
VMSTATE_END_OF_LIST()
}
};

static void led_realize(DeviceState *dev, Error **errp)
{
LEDState *s = LED(dev);

if (s->color == NULL) {
error_setg(errp, "property 'color' not specified");
return;
} else if (!led_color_name_is_valid(s->color)) {
error_setg(errp, "property 'color' invalid or not supported");
return;
}
if (s->description == NULL) {
s->description = g_strdup("n/a");
}

qdev_init_gpio_in(DEVICE(s), led_set_state_gpio_handler, 1);
}

static Property led_properties[] = {
DEFINE_PROP_STRING("color", LEDState, color),
DEFINE_PROP_STRING("description", LEDState, description),
DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true),
DEFINE_PROP_END_OF_LIST(),
};

static void led_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);

dc->desc = "LED";
dc->vmsd = &vmstate_led;
dc->reset = led_reset;
dc->realize = led_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_props(dc, led_properties);
}

static const TypeInfo led_info = {
.name = TYPE_LED,
.parent = TYPE_DEVICE,
.instance_size = sizeof(LEDState),
.class_init = led_class_init
};

static void led_register_types(void)
{
type_register_static(&led_info);
}

type_init(led_register_types)

LEDState *led_create_simple(Object *parentobj,
GpioPolarity gpio_polarity,
LEDColor color,
const char *description)
{
g_autofree char *name = NULL;
DeviceState *dev;

dev = qdev_new(TYPE_LED);
qdev_prop_set_bit(dev, "gpio-active-high",
gpio_polarity == GPIO_POLARITY_ACTIVE_HIGH);
qdev_prop_set_string(dev, "color", led_color_name[color]);
if (!description) {
static unsigned undescribed_led_id;
name = g_strdup_printf("undescribed-led-#%u", undescribed_led_id++);
} else {
qdev_prop_set_string(dev, "description", description);
name = g_ascii_strdown(description, -1);
name = g_strdelimit(name, " #", '-');
}
object_property_add_child(parentobj, name, OBJECT(dev));
qdev_realize_and_unref(dev, NULL, &error_fatal);

return LED(dev);
}
1 change: 1 addition & 0 deletions hw/misc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c'))
softmmu_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c'))
softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c'))

# ARM devices
softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c'))
Expand Down
Loading

0 comments on commit cddfbe0

Please sign in to comment.