2 * QEMU single LED device
4 * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
6 * SPDX-License-Identifier: GPL-2.0-or-later
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"
16 #define LED_INTENSITY_PERCENT_MAX 100
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_YELLOW
] = "yellow",
24 [LED_COLOR_AMBER
] = "amber",
25 [LED_COLOR_ORANGE
] = "orange",
26 [LED_COLOR_RED
] = "red",
29 static bool led_color_name_is_valid(const char *color_name
)
31 for (size_t i
= 0; i
< ARRAY_SIZE(led_color_name
); i
++) {
32 if (strcmp(color_name
, led_color_name
[i
]) == 0) {
39 void led_set_intensity(LEDState
*s
, unsigned intensity_percent
)
41 if (intensity_percent
> LED_INTENSITY_PERCENT_MAX
) {
42 intensity_percent
= LED_INTENSITY_PERCENT_MAX
;
44 trace_led_set_intensity(s
->description
, s
->color
, intensity_percent
);
45 if (intensity_percent
!= s
->intensity_percent
) {
46 trace_led_change_intensity(s
->description
, s
->color
,
47 s
->intensity_percent
, intensity_percent
);
49 s
->intensity_percent
= intensity_percent
;
52 unsigned led_get_intensity(LEDState
*s
)
54 return s
->intensity_percent
;
57 void led_set_state(LEDState
*s
, bool is_emitting
)
59 led_set_intensity(s
, is_emitting
? LED_INTENSITY_PERCENT_MAX
: 0);
62 static void led_set_state_gpio_handler(void *opaque
, int line
, int new_state
)
64 LEDState
*s
= LED(opaque
);
67 led_set_state(s
, !!new_state
!= s
->gpio_active_high
);
70 static void led_reset(DeviceState
*dev
)
72 LEDState
*s
= LED(dev
);
74 led_set_state(s
, s
->gpio_active_high
);
77 static const VMStateDescription vmstate_led
= {
80 .minimum_version_id
= 1,
81 .fields
= (VMStateField
[]) {
82 VMSTATE_UINT8(intensity_percent
, LEDState
),
87 static void led_realize(DeviceState
*dev
, Error
**errp
)
89 LEDState
*s
= LED(dev
);
91 if (s
->color
== NULL
) {
92 error_setg(errp
, "property 'color' not specified");
94 } else if (!led_color_name_is_valid(s
->color
)) {
95 error_setg(errp
, "property 'color' invalid or not supported");
98 if (s
->description
== NULL
) {
99 s
->description
= g_strdup("n/a");
102 qdev_init_gpio_in(DEVICE(s
), led_set_state_gpio_handler
, 1);
105 static Property led_properties
[] = {
106 DEFINE_PROP_STRING("color", LEDState
, color
),
107 DEFINE_PROP_STRING("description", LEDState
, description
),
108 DEFINE_PROP_BOOL("gpio-active-high", LEDState
, gpio_active_high
, true),
109 DEFINE_PROP_END_OF_LIST(),
112 static void led_class_init(ObjectClass
*klass
, void *data
)
114 DeviceClass
*dc
= DEVICE_CLASS(klass
);
117 dc
->vmsd
= &vmstate_led
;
118 dc
->reset
= led_reset
;
119 dc
->realize
= led_realize
;
120 set_bit(DEVICE_CATEGORY_DISPLAY
, dc
->categories
);
121 device_class_set_props(dc
, led_properties
);
124 static const TypeInfo led_info
= {
126 .parent
= TYPE_DEVICE
,
127 .instance_size
= sizeof(LEDState
),
128 .class_init
= led_class_init
131 static void led_register_types(void)
133 type_register_static(&led_info
);
136 type_init(led_register_types
)
138 LEDState
*led_create_simple(Object
*parentobj
,
139 GpioPolarity gpio_polarity
,
141 const char *description
)
143 g_autofree
char *name
= NULL
;
146 dev
= qdev_new(TYPE_LED
);
147 qdev_prop_set_bit(dev
, "gpio-active-high",
148 gpio_polarity
== GPIO_POLARITY_ACTIVE_HIGH
);
149 qdev_prop_set_string(dev
, "color", led_color_name
[color
]);
151 static unsigned undescribed_led_id
;
152 name
= g_strdup_printf("undescribed-led-#%u", undescribed_led_id
++);
154 qdev_prop_set_string(dev
, "description", description
);
155 name
= g_ascii_strdown(description
, -1);
156 name
= g_strdelimit(name
, " #", '-');
158 object_property_add_child(parentobj
, name
, OBJECT(dev
));
159 qdev_realize_and_unref(dev
, NULL
, &error_fatal
);