drivers: pwm: initial device driver for ENE KB1200
Add pwm driver for ENE KB1200 Signed-off-by: Steven Chang <steven@ene.com.tw>
This commit is contained in:
parent
14c6468bdd
commit
1147c39fe9
|
@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU8 pwm_xmc4xxx_ccu8.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_PWM_MCUX_CTIMER pwm_mcux_ctimer.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_NUMAKER pwm_numaker.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_NXP_S32_EMIOS pwm_nxp_s32_emios.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_ENE_KB1200 pwm_ene_kb1200.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c)
|
||||
|
|
|
@ -100,4 +100,6 @@ source "drivers/pwm/Kconfig.numaker"
|
|||
|
||||
source "drivers/pwm/Kconfig.nxp_s32_emios"
|
||||
|
||||
source "drivers/pwm/Kconfig.ene"
|
||||
|
||||
endif # PWM
|
||||
|
|
10
drivers/pwm/Kconfig.ene
Normal file
10
drivers/pwm/Kconfig.ene
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) 2024 ENE Technology Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config PWM_ENE_KB1200
|
||||
bool "ENE KB1200 PWM driver"
|
||||
default y
|
||||
depends on DT_HAS_ENE_KB1200_PWM_ENABLED
|
||||
select PINCTRL
|
||||
help
|
||||
This option enables the PWM driver for KB1200 processors.
|
123
drivers/pwm/pwm_ene_kb1200.c
Normal file
123
drivers/pwm/pwm_ene_kb1200.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2024 ENE Technology Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT ene_kb1200_pwm
|
||||
|
||||
#include <zephyr/drivers/pwm.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <reg/pwm.h>
|
||||
|
||||
/* Device config */
|
||||
struct pwm_kb1200_config {
|
||||
/* pwm controller base address */
|
||||
struct pwm_regs *pwm;
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
};
|
||||
|
||||
/* Driver data */
|
||||
struct pwm_kb1200_data {
|
||||
/* PWM cycles per second */
|
||||
uint32_t cycles_per_sec;
|
||||
};
|
||||
|
||||
/* PWM api functions */
|
||||
static int pwm_kb1200_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles,
|
||||
uint32_t pulse_cycles, pwm_flags_t flags)
|
||||
{
|
||||
/* Single channel for each pwm device */
|
||||
ARG_UNUSED(channel);
|
||||
const struct pwm_kb1200_config *config = dev->config;
|
||||
int prescaler;
|
||||
uint32_t high_len;
|
||||
uint32_t cycle_len;
|
||||
|
||||
/*
|
||||
* Calculate PWM prescaler that let period_cycles map to
|
||||
* maximum pwm period cycles and won't exceed it.
|
||||
* Then prescaler = ceil (period_cycles / pwm_max_period_cycles)
|
||||
*/
|
||||
prescaler = DIV_ROUND_UP(period_cycles, PWM_MAX_CYCLES);
|
||||
if (prescaler > PWM_MAX_PRESCALER) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If pulse_cycles is 0, switch PWM off and return. */
|
||||
if (pulse_cycles == 0) {
|
||||
config->pwm->PWMCFG &= ~PWM_ENABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
high_len = (pulse_cycles / prescaler);
|
||||
cycle_len = (period_cycles / prescaler);
|
||||
|
||||
/* Select PWM inverted polarity (ie. active-low pulse). */
|
||||
if (flags & PWM_POLARITY_INVERTED) {
|
||||
high_len = cycle_len - high_len;
|
||||
}
|
||||
|
||||
/* Set PWM prescaler. */
|
||||
config->pwm->PWMCFG = (config->pwm->PWMCFG & ~GENMASK(13, 8)) | ((prescaler - 1) << 8);
|
||||
|
||||
/*
|
||||
* period_cycles: PWM Cycle Length
|
||||
* pulse_cycles : PWM High Length
|
||||
*/
|
||||
config->pwm->PWMHIGH = high_len;
|
||||
config->pwm->PWMCYC = cycle_len;
|
||||
|
||||
/* Start pwm */
|
||||
config->pwm->PWMCFG |= PWM_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_kb1200_get_cycles_per_sec(const struct device *dev, uint32_t channel,
|
||||
uint64_t *cycles)
|
||||
{
|
||||
/* Single channel for each pwm device */
|
||||
ARG_UNUSED(channel);
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
if (cycles) {
|
||||
/* User does not have to know about lowest clock,
|
||||
* the driver will select the most relevant one.
|
||||
*/
|
||||
*cycles = PWM_INPUT_FREQ_HI; /*32Mhz*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_driver_api pwm_kb1200_driver_api = {
|
||||
.set_cycles = pwm_kb1200_set_cycles,
|
||||
.get_cycles_per_sec = pwm_kb1200_get_cycles_per_sec,
|
||||
};
|
||||
|
||||
static int pwm_kb1200_init(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
const struct pwm_kb1200_config *config = dev->config;
|
||||
|
||||
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
config->pwm->PWMCFG = PWM_SOURCE_CLK_32M | PWM_RULE1 | PWM_PUSHPULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KB1200_PWM_INIT(inst) \
|
||||
PINCTRL_DT_INST_DEFINE(inst); \
|
||||
static const struct pwm_kb1200_config pwm_kb1200_cfg_##inst = { \
|
||||
.pwm = (struct pwm_regs *)DT_INST_REG_ADDR(inst), \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
|
||||
}; \
|
||||
static struct pwm_kb1200_data pwm_kb1200_data_##inst; \
|
||||
DEVICE_DT_INST_DEFINE(inst, &pwm_kb1200_init, NULL, &pwm_kb1200_data_##inst, \
|
||||
&pwm_kb1200_cfg_##inst, PRE_KERNEL_1, CONFIG_PWM_INIT_PRIORITY, \
|
||||
&pwm_kb1200_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KB1200_PWM_INIT)
|
Loading…
Reference in a new issue