summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zephyr/dts/bindings/leds/cros-ec,pwm-led-pin-config.yaml19
-rw-r--r--zephyr/dts/bindings/leds/cros-ec,pwm-led-pins.yaml39
-rw-r--r--zephyr/shim/src/led_driver/CMakeLists.txt1
-rw-r--r--zephyr/shim/src/led_driver/led.c3
-rw-r--r--zephyr/shim/src/led_driver/led.h3
-rw-r--r--zephyr/shim/src/led_driver/led_gpio.c3
-rw-r--r--zephyr/shim/src/led_driver/led_pwm.c102
7 files changed, 169 insertions, 1 deletions
diff --git a/zephyr/dts/bindings/leds/cros-ec,pwm-led-pin-config.yaml b/zephyr/dts/bindings/leds/cros-ec,pwm-led-pin-config.yaml
new file mode 100644
index 0000000000..0813847bba
--- /dev/null
+++ b/zephyr/dts/bindings/leds/cros-ec,pwm-led-pin-config.yaml
@@ -0,0 +1,19 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: PWM LED pin configuration
+
+compatible: "cros-ec,pwm-pin-config"
+
+child-binding:
+ description: PWMs associated with LEDs
+ properties:
+ pwms:
+ type: phandle-array
+ required: true
+ "#led-pin-cells":
+ type: int
+ required: false
+ led-pin-cells:
+ - value
diff --git a/zephyr/dts/bindings/leds/cros-ec,pwm-led-pins.yaml b/zephyr/dts/bindings/leds/cros-ec,pwm-led-pins.yaml
new file mode 100644
index 0000000000..deabf0227f
--- /dev/null
+++ b/zephyr/dts/bindings/leds/cros-ec,pwm-led-pins.yaml
@@ -0,0 +1,39 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: PWM LED pins parent node
+
+compatible: "cros-ec,pwm-led-pins"
+
+properties:
+ pwm-frequency:
+ type: int
+ required: true
+ description: PWM frequency in Hz.
+
+child-binding:
+ description: Each child node describes all the PWM pins that need to be
+ altered to set a specific color. Eg. For blue and amber PWM
+ channels, in order to set color amber, a node looks like
+ this where 100 is PWM duty cycle in percentage
+ color-amber {
+ led-color = "LED_AMBER";
+ led-pins = <&pwm_led_y 100>,
+ <&pwm_led_b 0>;
+ };
+ properties:
+ led-color:
+ type: string
+ required: true
+ enum:
+ - LED_OFF
+ - LED_RED
+ - LED_GREEN
+ - LED_BLUE
+ - LED_YELLOW
+ - LED_WHITE
+ - LED_AMBER
+ led-pins:
+ type: phandle-array
+ required: false
diff --git a/zephyr/shim/src/led_driver/CMakeLists.txt b/zephyr/shim/src/led_driver/CMakeLists.txt
index 20c49cce6c..7c21d6827e 100644
--- a/zephyr/shim/src/led_driver/CMakeLists.txt
+++ b/zephyr/shim/src/led_driver/CMakeLists.txt
@@ -4,3 +4,4 @@
zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_LED_DT led.c)
zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_LED_DT led_gpio.c)
+zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_LED_DT led_pwm.c)
diff --git a/zephyr/shim/src/led_driver/led.c b/zephyr/shim/src/led_driver/led.c
index 5adbffaa23..1e97c98a86 100644
--- a/zephyr/shim/src/led_driver/led.c
+++ b/zephyr/shim/src/led_driver/led.c
@@ -245,7 +245,8 @@ static int find_color(int node_idx, int ticks)
/* If period value at index 0 is not 0, it's a blinking LED */
if (GET_PERIOD(node_idx, 0) != 0) {
/* Period is accumulated at the last index */
- ticks = ticks % GET_PERIOD(node_idx, MAX_COLOR - 1);
+ ticks = (ticks * LED_ONE_SEC) %
+ GET_PERIOD(node_idx, MAX_COLOR - 1);
for (color_idx = 0; color_idx < MAX_COLOR; color_idx++) {
if (ticks < GET_PERIOD(node_idx, color_idx))
diff --git a/zephyr/shim/src/led_driver/led.h b/zephyr/shim/src/led_driver/led.h
index 5eadb61680..4354df5125 100644
--- a/zephyr/shim/src/led_driver/led.h
+++ b/zephyr/shim/src/led_driver/led.h
@@ -6,6 +6,9 @@
#ifndef __CROS_EC_LED_H__
#define __CROS_EC_LED_H__
+#define COMPAT_GPIO_LED cros_ec_gpio_led_pins
+#define COMPAT_PWM_LED cros_ec_pwm_led_pins
+
#define GET_PROP(id, prop) \
COND_CODE_1(DT_NODE_HAS_PROP(id, prop), \
(DT_STRING_UPPER_TOKEN(id, prop)), \
diff --git a/zephyr/shim/src/led_driver/led_gpio.c b/zephyr/shim/src/led_driver/led_gpio.c
index cdc465eafb..46d94db4dc 100644
--- a/zephyr/shim/src/led_driver/led_gpio.c
+++ b/zephyr/shim/src/led_driver/led_gpio.c
@@ -12,6 +12,8 @@
#include <drivers/gpio.h>
#include <logging/log.h>
+#if DT_HAS_COMPAT_STATUS_OKAY(COMPAT_GPIO_LED)
+
LOG_MODULE_REGISTER(gpio_led, LOG_LEVEL_ERR);
#define GPIO_LED_PINS_NODE DT_PATH(gpio_led_pins)
@@ -72,3 +74,4 @@ void led_set_color(enum led_color color)
}
}
}
+#endif /* DT_HAS_COMPAT_STATUS_OKAY(COMPAT_GPIO_LED) */
diff --git a/zephyr/shim/src/led_driver/led_pwm.c b/zephyr/shim/src/led_driver/led_pwm.c
new file mode 100644
index 0000000000..57cd6eb92f
--- /dev/null
+++ b/zephyr/shim/src/led_driver/led_pwm.c
@@ -0,0 +1,102 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * PWM LED control.
+ */
+
+#include "led.h"
+#include "util.h"
+
+#include <devicetree.h>
+#include <drivers/pwm.h>
+#include <logging/log.h>
+
+#if DT_HAS_COMPAT_STATUS_OKAY(COMPAT_PWM_LED)
+
+LOG_MODULE_REGISTER(pwm_led, LOG_LEVEL_ERR);
+
+#define PWM_LED_PINS_NODE DT_PATH(pwm_led_pins)
+#define LED_PIN_COUNT (LED_COLOR_COUNT - 1)
+
+/*
+ * Struct defining LED PWM pin and duty cycle to set.
+ */
+struct pwm_pin_t {
+ const struct device *pwm;
+ uint8_t channel;
+ pwm_flags_t flags;
+ uint32_t pulse_us; /* PWM Duty cycle us */
+};
+
+/*
+ * Pin node contains LED color and array of PWM channels
+ * to alter in order to enable the given color.
+ */
+struct led_pins_node_t {
+ int led_color;
+ struct pwm_pin_t pwm_pins[LED_PIN_COUNT];
+};
+
+/*
+ * Period in us from frequency(Hz) defined in pins node
+ * period in sec = 1/freq
+ * period in usec = (1*usec_per_sec)/freq
+ * This value is also used calculate duty_cycle in us (pulse_us below).
+ * Duty cycle in perct defined in pin node is used to calculate pulse_us
+ * pulse_us = (period_us*duty_cycle_in_perct)/100
+ * Eg. freq = 500 Hz, period_us = 1000000/500 = 2000us
+ * duty_cycle = 50 %, pulse_us = (2000*50)/100 = 1000us
+ */
+const uint32_t period_us =
+ (USEC_PER_SEC / DT_PROP(PWM_LED_PINS_NODE, pwm_frequency));
+
+#define SET_PIN(node_id, prop, i) \
+{ \
+ .pwm = DEVICE_DT_GET( \
+ DT_PWMS_CTLR(DT_PHANDLE_BY_IDX(node_id, prop, i))), \
+ .channel = DT_PWMS_CHANNEL( \
+ DT_PHANDLE_BY_IDX(node_id, prop, i)), \
+ .flags = DT_PWMS_FLAGS(DT_PHANDLE_BY_IDX(node_id, prop, i)), \
+ .pulse_us = DIV_ROUND_NEAREST( \
+ period_us * DT_PHA_BY_IDX(node_id, prop, i, value), 100), \
+},
+
+#define SET_PWM_PIN(node_id) \
+{ \
+ DT_FOREACH_PROP_ELEM(node_id, led_pins, SET_PIN) \
+}
+
+#define SET_PIN_NODE(node_id) \
+{ \
+ .led_color = GET_PROP(node_id, led_color), \
+ .pwm_pins = SET_PWM_PIN(node_id) \
+},
+
+struct led_pins_node_t pins_node[LED_COLOR_COUNT] = {
+ DT_FOREACH_CHILD(PWM_LED_PINS_NODE, SET_PIN_NODE)
+};
+
+/*
+ * Iterate through LED pins nodes to find the color matching node.
+ * Set all the PWM channels defined in the node to the defined value,
+ * to enable the color. Defined value is duty cycle in percentage
+ * converted to duty cycle in us (pulse_us)
+ */
+void led_set_color(enum led_color color)
+{
+ for (int i = 0; i < LED_COLOR_COUNT; i++) {
+ if (pins_node[i].led_color == color) {
+ for (int j = 0; j < LED_PIN_COUNT; j++) {
+ pwm_pin_set_usec(
+ pins_node[i].pwm_pins[j].pwm,
+ pins_node[i].pwm_pins[j].channel,
+ period_us,
+ pins_node[i].pwm_pins[j].pulse_us,
+ pins_node[i].pwm_pins[j].flags);
+ }
+ break; /* Found the matching pin node, break here */
+ }
+ }
+}
+#endif /* DT_HAS_COMPAT_STATUS_OKAY(COMPAT_PWM_LED) */