From 0e81f9208fcf5384c9ac3eecced97a4b513d6d26 Mon Sep 17 00:00:00 2001 From: Parth Malkan Date: Sun, 3 Apr 2022 08:27:09 -0700 Subject: zephyr: LED: Add single PWM LED support This patch adds single PWM LED support to the common LED layer. BUG=b:227755022, b:194430340 TEST=manual LED test on Lazor BRANCH=none Signed-off-by: Parth Malkan Cq-Depend: chromium:3564077 Change-Id: Ib5070b8afb94d4771e753394f0495fe7a6811612 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3567463 Reviewed-by: Wai-Hong Tam --- zephyr/shim/src/led_driver/CMakeLists.txt | 1 + zephyr/shim/src/led_driver/led.c | 3 +- zephyr/shim/src/led_driver/led.h | 3 + zephyr/shim/src/led_driver/led_gpio.c | 3 + zephyr/shim/src/led_driver/led_pwm.c | 102 ++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 zephyr/shim/src/led_driver/led_pwm.c (limited to 'zephyr/shim/src') 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 #include +#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 +#include +#include + +#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) */ -- cgit v1.2.1