summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Short <keithshort@chromium.org>2020-12-15 15:13:10 -0700
committerCommit Bot <commit-bot@chromium.org>2021-01-29 21:57:44 +0000
commit9a2920efeffc04953ce01489ef1a5669e8662232 (patch)
tree5c0120bc2785a0b92ae8b5fa9ded524078d34205
parent40b2572cf845020c9380fb7052af5a2d804ac1c9 (diff)
downloadchrome-ec-9a2920efeffc04953ce01489ef1a5669e8662232.tar.gz
zephyr: add PWM shim
Adds PWM shim to connect the platform/ec PWM API to the Zephyr PWM API. BUG=b:174850923 BRANCH=none TEST=make buildall TEST=Run "pwmduty" command against Volteer LEDs Signed-off-by: Keith Short <keithshort@chromium.org> Change-Id: I49047734bc1a3fb3d4010f0040145171275c5657 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2623163 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r--common/pwm.c11
-rw-r--r--zephyr/CMakeLists.txt1
-rw-r--r--zephyr/Kconfig7
-rw-r--r--zephyr/dts/bindings/pwm/named-pwms.yaml24
-rw-r--r--zephyr/projects/volteer/boards/arm/volteer/volteer.dts45
-rw-r--r--zephyr/projects/volteer/prj.conf4
-rw-r--r--zephyr/shim/include/config_chip.h5
-rw-r--r--zephyr/shim/include/pwm/pwm.h24
-rw-r--r--zephyr/shim/src/CMakeLists.txt1
-rw-r--r--zephyr/shim/src/pwm.c187
10 files changed, 308 insertions, 1 deletions
diff --git a/common/pwm.c b/common/pwm.c
index 73b12fc20c..41989a94e0 100644
--- a/common/pwm.c
+++ b/common/pwm.c
@@ -11,6 +11,10 @@
#include "pwm.h"
#include "util.h"
+#ifdef CONFIG_ZEPHYR
+#include "pwm/pwm.h"
+#endif
+
#ifdef CONFIG_PWM
/*
@@ -162,10 +166,15 @@ DECLARE_CONSOLE_COMMAND(pwmduty, cc_pwm_duty,
"Get/set PWM duty cycles ");
#endif /* CONFIG_PWM */
-/* Initialize all PWM pins as functional */
+#ifndef CONFIG_ZEPHYR
+/*
+ * Initialize all PWM pins as functional. This is not required under
+ * Zephyr as pin configuration is automatically performed by chip driver
+ */
static void pwm_pin_init(void)
{
gpio_config_module(MODULE_PWM, 1);
}
/* HOOK_PRIO_INIT_PWM may be used for chip PWM unit init, so use PRIO + 1 */
DECLARE_HOOK(HOOK_INIT, pwm_pin_init, HOOK_PRIO_INIT_PWM + 1);
+#endif /* CONFIG_ZEPHYR */
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt
index 7a62e4d7e4..a23a862f57 100644
--- a/zephyr/CMakeLists.txt
+++ b/zephyr/CMakeLists.txt
@@ -155,6 +155,7 @@ zephyr_sources_ifdef(CONFIG_PLATFORM_EC_THROTTLE_AP
"${PLATFORM_EC}/common/throttle_ap.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_TABLET_MODE
"${PLATFORM_EC}/common/tablet_mode.c")
+zephyr_sources_ifdef(CONFIG_PLATFORM_EC_PWM "${PLATFORM_EC}/common/pwm.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_TIMER "${PLATFORM_EC}/common/timer.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_USB_CHARGER
diff --git a/zephyr/Kconfig b/zephyr/Kconfig
index 9a318358a0..e74aa487c7 100644
--- a/zephyr/Kconfig
+++ b/zephyr/Kconfig
@@ -453,6 +453,13 @@ config PLATFORM_EC_POWER_BUTTON
This requires a GPIO named GPIO_POWER_BUTTON_L in gpio_map.h.
+config PLATFORM_EC_PWM
+ bool "PWM (Pulse Width Modulation) module"
+ help
+ Enable the PWM (Pulse Width Modulation) module. This module is used to
+ support variable brightness LEDs, backlight controls, and
+ variable-speed fans.
+
config PLATFORM_EC_CONSOLE_CMD_SHMEM
bool "Console command: shmem"
default y
diff --git a/zephyr/dts/bindings/pwm/named-pwms.yaml b/zephyr/dts/bindings/pwm/named-pwms.yaml
new file mode 100644
index 0000000000..f01fd5a30a
--- /dev/null
+++ b/zephyr/dts/bindings/pwm/named-pwms.yaml
@@ -0,0 +1,24 @@
+# Copyright 2021 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 KEYS parent node
+
+compatible: "named-pwms"
+
+child-binding:
+ description: Named PWMs child node
+ properties:
+ pwms:
+ type: phandle-array
+ required: true
+ label:
+ required: true
+ type: string
+ description:
+ Human readable string describing the device (used as
+ device_get_binding() argument)
+ frequency:
+ required: true
+ type: int
+ description: PWM frequency, in Hz
diff --git a/zephyr/projects/volteer/boards/arm/volteer/volteer.dts b/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
index e35b59240c..59cc5f2cbc 100644
--- a/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
+++ b/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
@@ -57,6 +57,31 @@
};
};
+ named-pwms {
+ compatible = "named-pwms";
+
+ led1_blue {
+ pwms = <&pwm2 0 PWM_POLARITY_INVERTED>;
+ label = "LED1_BLUE";
+ frequency = <4800>;
+ };
+ led2_green {
+ pwms = <&pwm0 0 PWM_POLARITY_INVERTED>;
+ label = "LED2_GREEN";
+ frequency = <4800>;
+ };
+ led3_red {
+ pwms = <&pwm1 0 PWM_POLARITY_INVERTED>;
+ label = "LED3_RED";
+ frequency = <4800>;
+ };
+ led3_sidesel {
+ pwms = <&pwm7 0 PWM_POLARITY_INVERTED>;
+ label = "LED4_SIDESEL";
+ frequency = <2400>;
+ };
+ };
+
named-gpios {
compatible = "named-gpios";
@@ -467,3 +492,23 @@
&cros_kb_raw {
status = "okay";
};
+
+/* Green LED */
+&pwm0 {
+ status = "okay";
+};
+
+/* Red LED */
+&pwm1 {
+ status = "okay";
+};
+
+/* Blue LED */
+&pwm2 {
+ status = "okay";
+};
+
+/* Side selection LED */
+&pwm7 {
+ status = "okay";
+};
diff --git a/zephyr/projects/volteer/prj.conf b/zephyr/projects/volteer/prj.conf
index 8a23041b54..b113b9af8c 100644
--- a/zephyr/projects/volteer/prj.conf
+++ b/zephyr/projects/volteer/prj.conf
@@ -35,6 +35,10 @@ CONFIG_PLATFORM_EC_POWERSEQ=y
CONFIG_PLATFORM_EC_POWERSEQ_RTC_RESET=y
CONFIG_PLATFORM_EC_POWERSEQ_S0IX=y
+# PWM
+CONFIG_PWM=y
+CONFIG_PLATFORM_EC_PWM=y
+
# Miscellaneous tasks
CONFIG_HAS_TASK_KEYPROTO=y
CONFIG_HAS_TASK_POWERBTN=y
diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h
index ce9063d4f9..5da5f63a72 100644
--- a/zephyr/shim/include/config_chip.h
+++ b/zephyr/shim/include/config_chip.h
@@ -252,6 +252,11 @@ enum battery_type {
#define CONFIG_FAKE_SHMEM
#endif
+#undef CONFIG_PWM
+#ifdef CONFIG_PLATFORM_EC_PWM
+#define CONFIG_PWM
+#endif
+
#undef CONFIG_CMD_SHMEM
#ifdef CONFIG_PLATFORM_EC_CONSOLE_CMD_SHMEM
#define CONFIG_CMD_SHMEM
diff --git a/zephyr/shim/include/pwm/pwm.h b/zephyr/shim/include/pwm/pwm.h
new file mode 100644
index 0000000000..38720abb39
--- /dev/null
+++ b/zephyr/shim/include/pwm/pwm.h
@@ -0,0 +1,24 @@
+/* Copyright 2021 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.
+ */
+
+#ifndef ZEPHYR_SHIM_INCLUDE_PWM_PWM_H_
+#define ZEPHYR_SHIM_INCLUDE_PWM_PWM_H_
+
+#include <device.h>
+#include <devicetree.h>
+
+#if DT_NODE_EXISTS(DT_PATH(named_pwms))
+
+#define PWM_CHANNEL(id) DT_CAT(PWM_, id)
+#define PWM_CHANNEL_WITH_COMMA(id) PWM_CHANNEL(id),
+
+enum pwm_channel {
+ DT_FOREACH_CHILD(DT_PATH(named_pwms), PWM_CHANNEL_WITH_COMMA)
+ PWM_CH_COUNT,
+};
+
+#endif /* named_pwms */
+
+#endif /* ZEPHYR_SHIM_INCLUDE_PWM_PWM_H_ */
diff --git a/zephyr/shim/src/CMakeLists.txt b/zephyr/shim/src/CMakeLists.txt
index 6512938e56..1a4a75025e 100644
--- a/zephyr/shim/src/CMakeLists.txt
+++ b/zephyr/shim/src/CMakeLists.txt
@@ -15,6 +15,7 @@ zephyr_sources_ifdef(CONFIG_PLATFORM_EC_HOOKS hooks.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_HOSTCMD host_command.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_MKBP_EVENT mkbp_event.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_PANIC panic.c)
+zephyr_sources_ifdef(CONFIG_PLATFORM_EC_PWM pwm.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_TIMER hwtimer.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_I2C i2c.c)
zephyr_sources_ifdef(CONFIG_CROS_EC system.c)
diff --git a/zephyr/shim/src/pwm.c b/zephyr/shim/src/pwm.c
new file mode 100644
index 0000000000..a9466684d6
--- /dev/null
+++ b/zephyr/shim/src/pwm.c
@@ -0,0 +1,187 @@
+/* Copyright 2021 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.
+ */
+
+#include <device.h>
+#include <devicetree.h>
+#include <drivers/pwm.h>
+#include <logging/log.h>
+
+#include "common.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "pwm.h"
+#include "util.h"
+
+#include "pwm/pwm.h"
+
+LOG_MODULE_REGISTER(pwm_shim, LOG_LEVEL_ERR);
+
+#define USECS_PER_SEC 1000000
+
+/*
+ * Initialize the device bindings in pwm_channels.
+ * This macro is called from within DT_FOREACH_CHILD
+ */
+#define INIT_DEV_BINDING(id) { \
+ pwm_configs[PWM_CHANNEL(id)].name = DT_LABEL(id); \
+ pwm_configs[PWM_CHANNEL(id)].dev = device_get_binding( \
+ DT_PROP_BY_PHANDLE(id, pwms, label)); \
+ pwm_configs[PWM_CHANNEL(id)].pin = DT_PWMS_CHANNEL(id); \
+ pwm_configs[PWM_CHANNEL(id)].flags = DT_PWMS_FLAGS(id); \
+ pwm_configs[PWM_CHANNEL(id)].freq = DT_PROP(id, frequency); \
+ }
+
+struct pwm_config {
+ /* Name */
+ const char *name;
+ /* PWM pin */
+ uint32_t pin;
+ /* PWM channel flags. See dt-bindings/pwm/pwm.h */
+ pwm_flags_t flags;
+ /* PWM operating frequency. Configured by the devicetree */
+ uint32_t freq;
+
+ /* PWM period in microseconds. Automatically set to 1/frequency */
+ uint32_t period_us;
+ /* PWM pulse in microseconds. Set by pwm_set_raw_duty */
+ uint32_t pulse_us;
+ /* Saves whether the PWM channel is currently enabled */
+ bool enabled;
+
+ /* Runtime device for PWM */
+ const struct device *dev;
+};
+
+static struct pwm_config pwm_configs[PWM_CH_COUNT];
+
+static int init_pwms(const struct device *unused)
+{
+ struct pwm_config *pwm;
+ int rv = 0;
+
+ ARG_UNUSED(unused);
+
+ /* Initialize PWM data from the device tree */
+ DT_FOREACH_CHILD(DT_PATH(named_pwms), INIT_DEV_BINDING)
+
+ /* Read the PWM operating frequency, set by the chip driver */
+ for (size_t i = 0; i < PWM_CH_COUNT; ++i) {
+ pwm = &pwm_configs[i];
+
+ if (pwm->dev == NULL) {
+ LOG_ERR("Not found (%s)", pwm->name);
+ rv = -ENODEV;
+ continue;
+ }
+
+ /*
+ * TODO - check that devicetree frequency is less than 1/2
+ * max frequency from the chip driver.
+ */
+ pwm->period_us = USECS_PER_SEC / pwm->freq;
+ }
+
+ return rv;
+}
+SYS_INIT(init_pwms, PRE_KERNEL_1, 50);
+
+static struct pwm_config* pwm_lookup(enum pwm_channel ch)
+{
+ __ASSERT(ch < ARRAY_SIZE(pwm_configs), "Invalid PWM channel %d", ch);
+
+ return &pwm_configs[ch];
+}
+
+void pwm_enable(enum pwm_channel ch, int enabled)
+{
+ struct pwm_config *pwm;
+ uint32_t pulse_us;
+ int rv;
+
+ pwm = pwm_lookup(ch);
+ pwm->enabled = enabled;
+
+ /*
+ * The Zephyr API doesn't provide explicit enable and disable
+ * commands. However, setting the pulse width to zero disables
+ * the PWM.
+ */
+ if (enabled)
+ pulse_us = pwm->pulse_us;
+ else
+ pulse_us = 0;
+
+ rv = pwm_pin_set_usec(pwm->dev, pwm->pin, pwm->period_us, pulse_us,
+ pwm->flags);
+
+ if (rv)
+ LOG_ERR("pwm_pin_set_usec() failed %s (%d)", pwm->name, rv);
+}
+
+int pwm_get_enabled(enum pwm_channel ch)
+{
+ struct pwm_config *pwm;
+
+ pwm = pwm_lookup(ch);
+ return pwm->enabled;
+}
+
+void pwm_set_raw_duty(enum pwm_channel ch, uint16_t duty)
+{
+ struct pwm_config *pwm;
+ int rv;
+
+ pwm = pwm_lookup(ch);
+
+ pwm->pulse_us =
+ DIV_ROUND_NEAREST(pwm->period_us * duty, EC_PWM_MAX_DUTY);
+
+ LOG_DBG("PWM %s set raw duty (0x%04x), pulse %d", pwm->name, duty,
+ pwm->pulse_us);
+
+ rv = pwm_pin_set_usec(pwm->dev, pwm->pin, pwm->period_us, pwm->pulse_us,
+ pwm->flags);
+
+ if (rv)
+ LOG_ERR("pwm_pin_set_usec() failed %s (%d)", pwm->name, rv);
+}
+
+uint16_t pwm_get_raw_duty(enum pwm_channel ch)
+{
+ struct pwm_config *pwm;
+
+ pwm = pwm_lookup(ch);
+
+ return DIV_ROUND_NEAREST(pwm->pulse_us * EC_PWM_MAX_DUTY,
+ pwm->period_us);
+}
+
+void pwm_set_duty(enum pwm_channel ch, int percent)
+{
+ struct pwm_config *pwm;
+ int rv;
+
+ pwm = pwm_lookup(ch);
+
+ pwm->pulse_us = DIV_ROUND_NEAREST(pwm->period_us * percent, 100);
+
+ LOG_DBG("PWM %s set percent (%d), pulse %d", pwm->name, percent,
+ pwm->pulse_us);
+
+ rv = pwm_pin_set_usec(pwm->dev, pwm->pin, pwm->period_us, pwm->pulse_us,
+ pwm->flags);
+
+ if (rv)
+ LOG_ERR("pwm_pin_set_usec() failed %s (%d)", pwm->name, rv);
+}
+
+int pwm_get_duty(enum pwm_channel ch)
+{
+ struct pwm_config *pwm;
+
+ pwm = pwm_lookup(ch);
+
+ return DIV_ROUND_NEAREST(pwm->pulse_us * 100, pwm->period_us);
+}