From 56db098a55445b58c44ff4651ac2afef401bc93a Mon Sep 17 00:00:00 2001 From: Robert Winkler Date: Fri, 12 Jul 2019 15:06:30 +0200 Subject: [PATCH] drivers: pwm: Add driver for LiteX PWM peripherial PWM driver for LiteX SoC builder was created. Because LiteX supports only one channel for each PWM device, an appropriate restriction was made. Signed-off-by: Robert Winkler Signed-off-by: Mateusz Holenko --- CODEOWNERS | 1 + drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.litex | 22 +++++ drivers/pwm/pwm_litex.c | 148 ++++++++++++++++++++++++++++++++ dts/bindings/pwm/litex,pwm.yaml | 15 ++++ 6 files changed, 189 insertions(+) create mode 100644 drivers/pwm/Kconfig.litex create mode 100644 drivers/pwm/pwm_litex.c create mode 100644 dts/bindings/pwm/litex,pwm.yaml diff --git a/CODEOWNERS b/CODEOWNERS index baf967dbc04..0514ef2f5d9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -155,6 +155,7 @@ /drivers/pcie/ @andrewboie /drivers/pinmux/stm32/ @rsalveti @idlethread /drivers/pinmux/*hsdk* @iriszzw +/drivers/pwm/*litex* @mateusz-holenko @kgugala @pgielda /drivers/sensor/ @MaureenHelm /drivers/sensor/ams_iAQcore/ @alexanderwachter /drivers/sensor/ens210/ @alexanderwachter diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index fcb48f18bba..86e23c80336 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_LED_ESP32 pwm_led_esp32.c) zephyr_library_sources_ifdef(CONFIG_PWM_SAM pwm_sam.c) zephyr_library_sources_ifdef(CONFIG_PWM_MCUX pwm_mcux.c) zephyr_library_sources_ifdef(CONFIG_PWM_XEC pwm_mchp_xec.c) +zephyr_library_sources_ifdef(CONFIG_PWM_LITEX pwm_litex.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c) zephyr_library_sources_ifdef(CONFIG_PWM_SHELL pwm_shell.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 3072eb20f28..c25c3702dba 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -59,4 +59,6 @@ source "drivers/pwm/Kconfig.mcux" source "drivers/pwm/Kconfig.xec" +source "drivers/pwm/Kconfig.litex" + endif # PWM diff --git a/drivers/pwm/Kconfig.litex b/drivers/pwm/Kconfig.litex new file mode 100644 index 00000000000..28db526872e --- /dev/null +++ b/drivers/pwm/Kconfig.litex @@ -0,0 +1,22 @@ +# +# Copyright (c) 2019 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig PWM_LITEX + bool "LiteX PWM driver" + depends on SOC_RISCV32_LITEX_VEXRISCV + depends on HAS_DTS + help + Enable support for LiteX PWM driver + +if PWM_LITEX + +config PWM_LITEX_INIT_PRIORITY + int "Init priority" + default 70 + help + PWM device driver initialization priority. + +endif # PWM_LITEX diff --git a/drivers/pwm/pwm_litex.c b/drivers/pwm/pwm_litex.c new file mode 100644 index 00000000000..67f0c2cecb2 --- /dev/null +++ b/drivers/pwm/pwm_litex.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define REG_EN_ENABLE 0x1 +#define REG_EN_DISABLE 0x0 + +/* PWM device in LiteX has only one channel */ +#define NUMBER_OF_CHANNELS 1 + +struct pwm_litex_cfg { + u32_t reg_en_size; + u32_t reg_width_size; + u32_t reg_period_size; + volatile u32_t *reg_en; + volatile u32_t *reg_width; + volatile u32_t *reg_period; +}; + +#define GET_PWM_CFG(dev) \ + ((const struct pwm_litex_cfg *) dev->config->config_info) + +static void litex_set_reg(volatile u32_t *reg, u32_t reg_size, u32_t val) +{ + u32_t shifted_data; + volatile u32_t *reg_addr; + + for (int i = 0; i < reg_size; ++i) { + shifted_data = val >> ((reg_size - i - 1) * 8); + reg_addr = ((volatile u32_t *) reg) + i; + *(reg_addr) = shifted_data; + } +} + +int pwm_litex_init(struct device *dev) +{ + const struct pwm_litex_cfg *cfg = GET_PWM_CFG(dev); + + litex_set_reg(cfg->reg_en, cfg->reg_en_size, REG_EN_ENABLE); + return 0; +} + +int pwm_litex_pin_set(struct device *dev, u32_t pwm, u32_t period_cycles, + u32_t pulse_cycles, pwm_flags_t flags) +{ + const struct pwm_litex_cfg *cfg = GET_PWM_CFG(dev); + + if (pwm >= NUMBER_OF_CHANNELS) { + return -EINVAL; + } + + litex_set_reg(cfg->reg_en, cfg->reg_en_size, REG_EN_DISABLE); + litex_set_reg(cfg->reg_width, cfg->reg_width_size, pulse_cycles); + litex_set_reg(cfg->reg_period, cfg->reg_period_size, period_cycles); + litex_set_reg(cfg->reg_en, cfg->reg_en_size, REG_EN_ENABLE); + + return 0; +} + +int pwm_litex_get_cycles_per_sec(struct device *dev, u32_t pwm, u64_t *cycles) +{ + if (pwm >= NUMBER_OF_CHANNELS) { + return -EINVAL; + } + + *cycles = sys_clock_hw_cycles_per_sec(); + return 0; +} + +static const struct pwm_driver_api pwm_litex_driver_api = { + .pin_set = pwm_litex_pin_set, + .get_cycles_per_sec = pwm_litex_get_cycles_per_sec, +}; + +/* Device Instantiation */ + +/* LiteX regisers use only first byte from 4-bytes register, that's why they + * occupy larger space in memory. We need to know the size that is + * actually used, that is why the register size from dts is divided by 4. + */ + +#define PWM_LITEX_INIT(n) \ + static const struct pwm_litex_cfg pwm_litex_cfg_##n = { \ + .reg_en = \ + (volatile u32_t *) \ + DT_INST_##n##_LITEX_PWM_ENABLE_BASE_ADDRESS, \ + .reg_en_size = DT_INST_##n##_LITEX_PWM_ENABLE_SIZE / 4, \ + .reg_width = \ + (volatile u32_t *) \ + DT_INST_##n##_LITEX_PWM_WIDTH_BASE_ADDRESS, \ + .reg_width_size = DT_INST_##n##_LITEX_PWM_WIDTH_SIZE / 4, \ + .reg_period = \ + (volatile u32_t *) \ + DT_INST_##n##_LITEX_PWM_PERIOD_BASE_ADDRESS, \ + .reg_period_size = DT_INST_##n##_LITEX_PWM_PERIOD_SIZE / 4, \ + }; \ + \ + DEVICE_AND_API_INIT(pwm_##n, \ + DT_INST_##n##_LITEX_PWM_LABEL, \ + pwm_litex_init, \ + NULL, \ + &pwm_litex_cfg_##n, \ + POST_KERNEL, \ + CONFIG_PWM_LITEX_INIT_PRIORITY, \ + &pwm_litex_driver_api \ + ) + +#ifdef DT_INST_0_LITEX_PWM_LABEL +PWM_LITEX_INIT(0); +#endif + +#ifdef DT_INST_1_LITEX_PWM_LABEL +PWM_LITEX_INIT(1); +#endif + +#ifdef DT_INST_2_LITEX_PWM_LABEL +PWM_LITEX_INIT(2); +#endif + +#ifdef DT_INST_3_LITEX_PWM_LABEL +PWM_LITEX_INIT(3); +#endif + +#ifdef DT_INST_4_LITEX_PWM_LABEL +PWM_LITEX_INIT(4); +#endif + +#ifdef DT_INST_5_LITEX_PWM_LABEL +PWM_LITEX_INIT(5); +#endif + +#ifdef DT_INST_6_LITEX_PWM_LABEL +PWM_LITEX_INIT(6); +#endif + +#ifdef DT_INST_7_LITEX_PWM_LABEL +PWM_LITEX_INIT(7); +#endif + +#ifdef DT_INST_8_LITEX_PWM_LABEL +PWM_LITEX_INIT(8); +#endif diff --git a/dts/bindings/pwm/litex,pwm.yaml b/dts/bindings/pwm/litex,pwm.yaml new file mode 100644 index 00000000000..92bef618889 --- /dev/null +++ b/dts/bindings/pwm/litex,pwm.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2019 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: LiteX PWM controller + +include: [pwm-controller.yaml, base.yaml] + +compatible: "litex,pwm" +properties: + + reg: + required: true