123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- /*
- * Copyright (c) 2018 Actions Semiconductor Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @brief PWM controller driver for Actions SoC
- */
- #include <errno.h>
- #include <sys/__assert.h>
- #include <stdbool.h>
- #include <kernel.h>
- #include <device.h>
- #include <init.h>
- #include <drivers/pwm.h>
- #include <soc.h>
- #include <drivers/dma.h>
- #include <errno.h>
- #include <board.h>
- #define LOG_LEVEL CONFIG_LOG_PWM_DEV_LEVEL
- #include <logging/log.h>
- LOG_MODULE_REGISTER(pwm);
- #define CMU_PWMCLK_CLKSEL_SHIFT (9)
- #define CMU_PWMCLK_CLKSEL_MASK (0x3 << CMU_PWMCLK_CLKSEL_SHIFT)
- #define CMU_PWMCLK_CLK_SEL(x) ((x) << CMU_PWMCLK_CLKSEL_SHIFT)
- #define CMU_PWMCLK_CLKSEL_16K CMU_PWMCLK_CLK_SEL(0)
- #define CMU_PWMCLK_CLKSEL_HOSC CMU_PWMCLK_CLK_SEL(1)
- #define CMU_PWMCLK_CLKSEL_CK64M CMU_PWMCLK_CLK_SEL(2)
- #define CMU_PWMCLK_CLKSEL_32K CMU_PWMCLK_CLK_SEL(0)
- #define CMU_PWMCLK_CLKDIV_SHIFT (0)
- #define CMU_PWMCLK_CLKDIV(x) ((x) << CMU_PWMCLK_CLKDIV_SHIFT)
- #define CMU_PWMCLK_CLKDIV_MASK CMU_PWMCLK_CLKDIV(0x1FF)
- #define PWM_CTRL_MODE_SEL_SHIFT (0)
- #define PWM_CTRL_MODE_SEL_MASK (0x3 << PWM_CTRL_MODE_SEL_SHIFT)
- #define PWM_CTRL_MODE_SEL(x) ((x) << PWM_CTRL_MODE_SEL_SHIFT)
- #define PWM_CTRL_MODE_SEL_FIXED PWM_CTRL_MODE_SEL(0)
- #define PWM_CTRL_MODE_SEL_BREATH PWM_CTRL_MODE_SEL(1)
- #define PWM_CTRL_MODE_SEL_PROGRAM PWM_CTRL_MODE_SEL(2)
- #define PWM_CTRL_POL_SEL_HIGH BIT(2)
- #define PWM_CTRL_CHANNEL_EN BIT(3)
- #define PWM_CTRL_CHANNEL_START BIT(4)
- #define PWM_BREATH_MODE_C_SHIFT (0)
- #define PWM_BREATH_MODE_C_MASK (0xFF << PWM_BREATH_MODE_C_SHIFT)
- #define PWM_BREATH_MODE_C(x) ((x) << PWM_BREATH_MODE_C_SHIFT)
- #define PWM_BREATH_MODE_QU_SHIFT (0)
- #define PWM_BREATH_MODE_QU_MASK (0xFF << PWM_BREATH_MODE_QU_SHIFT)
- #define PWM_BREATH_MODE_QU(x) ((x) << PWM_BREATH_MODE_QU_SHIFT)
- #define PWM_BREATH_MODE_QD_SHIFT (16)
- #define PWM_BREATH_MODE_QD_MASK (0xFF << PWM_BREATH_MODE_QD_SHIFT)
- #define PWM_BREATH_MODE_QD(x) ((x) << PWM_BREATH_MODE_QD_SHIFT)
- #define PWM_BREATH_MODE_H_SHIFT (0)
- #define PWM_BREATH_MODE_H_MASK (0xFFFF << PWM_BREATH_MODE_H_SHIFT)
- #define PWM_BREATH_MODE_H(x) ((x) << PWM_BREATH_MODE_H_SHIFT)
- #define PWM_BREATH_MODE_L_SHIFT (0)
- #define PWM_BREATH_MODE_L_MASK (0xFFFF << PWM_BREATH_MODE_L_SHIFT)
- #define PWM_BREATH_MODE_L(x) ((x) << PWM_BREATH_MODE_L_SHIFT)
- #define PWM_DUTYMAX_SHIFT (0)
- #define PWM_DUTYMAX_MASK (0xFFFF << PWM_DUTYMAX_SHIFT)
- #define PWM_DUTYMAX(x) ((x) << PWM_DUTYMAX_SHIFT)
- #define PWM_DUTY_SHIFT (0)
- #define PWM_DUTY_MASK (0xFFFF << PWM_DUTY_SHIFT)
- #define PWM_DUTY(x) ((x) << PWM_DUTY_SHIFT)
- #define PWM_DMA_CTL_START BIT(0)
- #define PWM_FIFO_CLK_SEL_SHIFT (4)
- #define PWM_FIFO_CLK_SEL_MASK (0xF << PWM_FIFO_CLK_SEL_SHIFT)
- #define PWM_FIFO_CLK_SEL(x) ((x) << PWM_FIFO_CLK_SEL_SHIFT)
- #define PWM_FIFOSTA_ERROR BIT(0)
- #define PWM_FIFOSTA_FULL BIT(1)
- #define PWM_FIFOSTA_EMPTY BIT(2)
- #define PWM_FIFOSTA_LEVEL_SHIFT (3)
- #define PWM_FIFOSTA_LEVEL_MASK (0x3 << PWM_FIFOSTA_LEVEL_SHIFT)
- #ifdef CHIP_LEOPARD
- #define PWM_CLK_CYCLES_PER_SEC (32000000)
- #else
- #define PWM_CLK_CYCLES_PER_SEC (16000)
- #endif
- #define PWM_PIN_CYCLES_PER_SEC (8000)
- #define PWM_PIN_CLK_PERIOD_USEC (1000000UL / PWM_PIN_CYCLES_PER_SEC)
- #define PWM_DUTYMAX_DEFAULT (16000) /* 1s / PWM_PIN_CYCLES_PER_SEC x PWM_DUTYMAX_DEFAULT = 2s */
- #define PWM_PROGRAM_PIN_INVALID (0xFF)
- #define PWM_BREATH_MODE_DEFAULT_C (32)
- #define PWM_DMACTL_REG_OFFSET (0x0F00)
- #define PWM_DMACTL_REG(x) ((struct acts_pwm_dmactl *)((x)->base + PWM_DMACTL_REG_OFFSET))
- #define PWM_CHAN(base, chan_id) ((struct acts_pwm_chan *)((base) + (chan_id * 0x100)))
- #define PWM_CYCLES_MAX (0xFFFF)
- #define DMA_IRQ_TC (0) /* DMA completion flag */
- #define DMA_IRQ_HF (1) /* DMA half-full flag */
- #define PWM_MFP (0x12 | (0x1 << 5) | ((3) << GPIO_CTL_PADDRV_SHIFT))
- #define LOW_DIV_FACTOR 1
- #define HIG_DIV_FACTOR 2
- #define LOW_DIV_MAX_VAL 256
- #define BOARD_RC32K_FREQ 32000
- #define BOARD_HOSC_FREQ 32000000
- #define BOARD_RC64M_FREQ 64000000
- enum {
- /**start voltage level low */
- START_VOLTAGE_LOW = 0,
- /**start voltage level high */
- START_VOLTAGE_HIGH,
- };
- /* pwm control registers */
- struct acts_pwm_chan {
- volatile u32_t ctrl;
- volatile u32_t c;
- volatile u32_t q;
- volatile u32_t h;
- volatile u32_t l;
- volatile u32_t duty_max;
- volatile u32_t duty;
- };
- /* pwm dma control registers */
- struct acts_pwm_dmactl {
- volatile u32_t dmactl;
- volatile u32_t fifodat;
- volatile u32_t fifosta;
- };
- struct pwm_acts_data {
- struct k_mutex mutex;
- const struct device *dma_dev;
- int dma_chan;
- int (*program_callback)(void *cb_data, u8_t reason);
- void *cb_data;
- u8_t program_pin;
- struct acts_pin_config pins_pwm_mfp[9];
- };
- struct pwm_acts_config {
- u32_t base;
- u32_t pwmclk_reg;
- u32_t cycle;
- u32_t chans;
- #if CHIP_LEOPARD
- u8_t clock0_id;
- u8_t clock1_id;
- u8_t clock2_id;
- u8_t clock3_id;
- #else
- u8_t clock_id;
- #endif
- u8_t reset_id;
- const char *dma_dev_name;
- u8_t txdma_id;
- u8_t flag_use_dma;
- };
- struct pwm_acts_chans{
- u8_t chan;
- u8_t gpio_num;
- };
- /*
- * Each line represents a set of pwm channels {0, 3}, {0, 4}, {0, 14}, {0, 36}, {0, 49}
- * The first numeric value of each set represents the pwm channel, and the second numeric value represents the pin number
- * For example: 0 represents pwm channel 0 3 represents GPIO3
- * The pwm driver scans the form to confirm if a channel has a gpio available
- */
- #ifdef CHIP_LEOPARD
- #define CONFIG_PWM_PIN_CHAN_MAP {0, 3}, {0, 14}, {0, 21}, {0, 49}, {0, 53}, {0, 64},\
- {1, 15}, {1, 18}, {1, 22}, {1, 50}, {1, 54}, {1, 57}, {1, 74},\
- {2, 6}, {2, 16}, {2, 19}, {2, 51}, {2, 55}, {2, 75},\
- {3, 7}, {3, 17}, {3, 20}, {3, 52}, {3, 56}, {3, 76}
- #else
- #define CONFIG_PWM_PIN_CHAN_MAP {0, 3}, {0, 4}, {0, 14}, {0, 36}, {0, 49},\
- {1, 5}, {1, 15}, {1, 37}, {1, 50},\
- {2, 6}, {2, 21}, {2, 38}, {2, 51},\
- {3, 7}, {3, 17}, {3, 39}, {3, 52},\
- {4, 8}, {4, 18}, {4, 40}, {4, 53},\
- {5, 9}, {5, 19}, {5, 41}, {5, 54},\
- {6, 10}, {6, 20}, {6, 42}, {6, 55},\
- {7, 11}, {7, 21}, {7, 43}, {7, 45}, {7, 56},\
- {8, 12}, {8, 22}, {8, 44}, {8, 46}, {8, 57}
- #endif
- static const struct pwm_acts_chans pwm_acts_chan_gpio_num[] = {CONFIG_PWM_PIN_CHAN_MAP};
- /*
- * Convert frequency and duty to clkdiv/dutymax/duty of pwm register.
- *
- * Input Parameters
- * clk_src_freq: clock source frequency [Hz]
- * pwm_freq: PWM channel to set
- * duty: duty
- * Output Parameters
- * reg_div_index: set value of PWMxCLKDIV in CMU_PWMxCLK register
- * reg_dutymax: set value of PWMx_DUTYMAX register
- * reg_duty: set value of PWMx_DUTY register
- * return 0, or negative errno code
- */
- static int convert_freq2pwmreg(uint32_t clk_src_freq, uint32_t pwm_freq,
- uint16_t duty, uint16_t *reg_div_index,
- uint16_t *reg_dutymax, uint16_t *reg_duty)
- {
- uint32_t i;
- uint16_t div = 0;
- uint32_t pwm_clk;
- uint32_t dutymax;
- uint8_t found_presc_flag = 0;
- static const uint16_t high_presc_values[6] =
- {256, 512, 1024, 2048, 4096, 8192};
- if (clk_src_freq < pwm_freq) {
- LOG_ERR("Undesirable input pwm setting frequency\n");
- return -ESPIPE;
- }
- /* Calculate optimal values of the pwmclk prescaler and dutymax for
- * the pwm register.
- * Example:
- *
- * clk_src_freq = 24 MHz
- * pwm_freq = 100 Hz
- *
- * div = 24,000,000 / 65,535 / 100
- * = 3.6 (or 4 -- taking the ceiling always)
- * pwmclk = 24,000,000 / 4
- * = 6,000,000
- * dutymax = 6,000,000 / 100
- * = 60,000
- */
- div = (clk_src_freq / pwm_freq + 65534) / 65535;
- for (i = 0; i < LOW_DIV_MAX_VAL; i++) {
- if (div <= (i + 1)) {
- found_presc_flag = LOW_DIV_FACTOR;
- break;
- }
- }
- if (found_presc_flag == 0) {
- for (i = 0; i < 6; i++) {
- if (div <= high_presc_values[i]) {
- found_presc_flag = HIG_DIV_FACTOR;
- break;
- }
- }
- }
- if (found_presc_flag == LOW_DIV_FACTOR) {
- div = i + 1;
- *reg_div_index = div - 1;
- } else if (found_presc_flag == HIG_DIV_FACTOR) {
- div = high_presc_values[i];
- *reg_div_index = ((LOW_DIV_MAX_VAL - 1) + i);
- } else {
- LOG_ERR("cannot find proper prescale\n");
- return -EACCES;
- }
- pwm_clk = clk_src_freq / div;
- dutymax = pwm_clk / pwm_freq;
- if (dutymax < 1)
- dutymax = 1;
- else if (dutymax > 65535)
- dutymax = 65535;
- *reg_dutymax = dutymax;
- *reg_duty = dutymax * duty / 100;
- LOG_DBG("div=%d, dutymax=%d, duty=%d", *reg_div_index, *reg_dutymax, *reg_duty);
- return 0;
- }
- int pwm_acts_mfp(unsigned int pin, unsigned int mode, bool set)
- {
- unsigned int key, ctl_reg, val;
- if (pin >= GPIO_MAX_PIN_NUM)
- return -EINVAL;
- ctl_reg = GPIO_REG_CTL(GPIO_REG_BASE, pin);
- key = irq_lock();
- if(set)
- val = (sys_read32(ctl_reg) & ~PINMUX_MODE_MASK) | mode;
- else
- val = (sys_read32(ctl_reg) & ~PINMUX_MODE_MASK);
- sys_write32(val, ctl_reg);
- irq_unlock(key);
- return 0;
- }
- static u16_t pwm_acts_check_chan(u32_t pwm, u32_t pin)
- {
- for(int i = 0; i < sizeof(pwm_acts_chan_gpio_num)/sizeof(struct pwm_acts_chans); i++)
- if(pwm == pwm_acts_chan_gpio_num[i].chan && pin == pwm_acts_chan_gpio_num[i].gpio_num)
- return 0;
- return -EINVAL;
- }
- static int pwm_acts_set_pinmux(const struct device *dev, u32_t chan)
- {
- //const struct pwm_acts_config *cfg = dev->config;
- struct pwm_acts_data *data = dev->data;
- if(data->pins_pwm_mfp[chan].pin_num == 0xffffffff) {
- LOG_ERR("this pin is not initialized");
- return -1;
- }
- pwm_acts_mfp(data->pins_pwm_mfp[chan].pin_num, data->pins_pwm_mfp[chan].mode, true);
- return 0;
- }
- static void pwm_acts_dma_reload(const struct device *dev, void *user_data,
- uint32_t channel, int status)
- {
- u32_t _reason;
- int ret;
- struct pwm_acts_data *data = (struct pwm_acts_data *)user_data;
- if (status == DMA_IRQ_HF) {
- _reason = PWM_PROGRAM_DMA_IRQ_HF;
- } else if (status == DMA_IRQ_TC) {
- _reason = PWM_PROGRAM_DMA_IRQ_TC;
- } else {
- LOG_ERR("Unknown DMA reason %d", status);
- dma_stop(dev, data->dma_chan);
- return ;
- }
- ret = data->program_callback(data->cb_data, _reason);
- if (ret < 0)
- dma_stop(dev, data->dma_chan);
- }
- static void pwm_acts_dma_direct(const struct device *dev, void *user_data,
- uint32_t channel, int status)
- {
- struct pwm_acts_data *data = (struct pwm_acts_data *)user_data;
- ARG_UNUSED(dev);
- if ((status == DMA_IRQ_TC) && data->program_callback) {
- data->program_callback(data->cb_data, PWM_PROGRAM_DMA_IRQ_TC);
- }
- }
- int pwm_acts_dma_prepare(struct device *dev, u32_t chan, pwm_program_ctrl_t *ctrl)
- {
- const struct pwm_acts_config *cfg = dev->config;
- struct pwm_acts_data *data = dev->data;
- struct acts_pwm_dmactl *dmactrl = PWM_DMACTL_REG(cfg);
- struct dma_config dma_cfg = {0};
- struct dma_block_config dma_block_cfg = {0};
- /* request dma channel handle */
- if (data->dma_chan == -1) {
- data->dma_chan = dma_request(data->dma_dev, 0xFF);
- if (!data->dma_chan) {
- LOG_ERR("Failed to request dma channel");
- return -ENXIO;
- }
- }
- dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
- dma_cfg.source_burst_length = 8;
- dma_cfg.dest_burst_length = 8;
- dma_cfg.source_data_size = 2;
- dma_cfg.dma_slot = cfg->txdma_id;
- dma_block_cfg.source_address = (u32_t)ctrl->ram_buf;
- dma_block_cfg.dest_address = (u32_t)&dmactrl->fifodat;
- dma_block_cfg.block_size = ctrl->ram_buf_len;
- dma_block_cfg.source_reload_en = ctrl->reload_en;
- dma_cfg.block_count = 1;
- dma_cfg.head_block = &dma_block_cfg;
- if (ctrl->program_callback) {
- if (ctrl->reload_en)
- dma_cfg.dma_callback = pwm_acts_dma_reload;
- else
- dma_cfg.dma_callback = pwm_acts_dma_direct;
- dma_cfg.user_data = data;
- dma_cfg.complete_callback_en = 1;
- // dma_cfg.half_complete_callback_en = 1;
- data->program_callback = ctrl->program_callback;
- data->cb_data = ctrl->cb_data;
- }
- if (dma_config(data->dma_dev, data->dma_chan, &dma_cfg)) {
- LOG_ERR("DMA config error");
- return -EFAULT;
- }
- return 0;
- }
- /*
- * Set the period and pulse width for a PWM pin.
- *
- * Parameters
- * dev: Pointer to PWM device structure
- * pwm: PWM channel to set
- * period_cycles: Period (in timer count)
- * pulse_cycles: Pulse width (in timer count).
- * @param flags Flags for pin configuration (polarity).
- * return 0, or negative errno code
- */
- static int pwm_acts_pin_set(const struct device *dev, u32_t chan,
- u32_t period_cycles, u32_t pulse_cycles, pwm_flags_t flags)
- {
- const struct pwm_acts_config *cfg = dev->config;
- //struct pwm_acts_data *data = dev->data;
- struct acts_pwm_chan *pwm_chan;
- uint32_t key;
- LOG_INF("PWM@%d set period cycles %d, pulse cycles %d",
- chan, period_cycles, pulse_cycles);
- if (chan >= cfg->chans) {
- LOG_ERR("invalid chan %d", chan);
- return -EINVAL;
- }
- if (pulse_cycles > period_cycles) {
- LOG_ERR("pulse cycles %d is biger than period's %d",
- pulse_cycles, period_cycles);
- return -EINVAL;
- }
- if (period_cycles > PWM_CYCLES_MAX || period_cycles < 1) {
- LOG_ERR("period cycles invalid %d (max %d min 1)",
- period_cycles, PWM_CYCLES_MAX);
- return -EINVAL;
- }
- if (pwm_acts_set_pinmux(dev, chan)) {
- LOG_DBG("set pwm pinmux error");
- return -EFAULT;
- }
- key = irq_lock();
- pwm_chan = PWM_CHAN(cfg->base, chan);
- LOG_DBG("pwm_chan %p", pwm_chan);
- /* disable pwm */
- pwm_chan->ctrl = 0;
- /* setup pwm parameters */
- if (START_VOLTAGE_HIGH == flags)
- pwm_chan->ctrl = PWM_CTRL_POL_SEL_HIGH | PWM_CTRL_MODE_SEL_FIXED;
- else
- pwm_chan->ctrl = PWM_CTRL_MODE_SEL_FIXED;
- /* PWM period = PWM_CLK period x PWM_DUTYMAX */
- pwm_chan->duty_max = PWM_DUTYMAX(period_cycles);
- /* PWM DUTY = DUTY / PWM_DUTYMAX */
- pwm_chan->duty = pulse_cycles * (pwm_chan->duty_max & PWM_DUTYMAX_MASK) / period_cycles;
- /* enable pwm */
- pwm_chan->ctrl |= (PWM_CTRL_CHANNEL_EN | PWM_CTRL_CHANNEL_START);
- irq_unlock(key);
- return 0;
- }
- /*
- * Set the frequency and duty for a PWM channel.
- *
- * Parameters
- * dev: Pointer to PWM device structure
- * pwm: PWM channel to set
- * freq: frequency of pwm.
- * duty: duty cycle from 0~100.
- * @param flags Flags for pin configuration (polarity).
- * return 0, or negative errno code
- */
- static int pwm_acts_freq_duty_set(const struct device *dev, u32_t chan,
- u32_t freq, u8_t duty, pwm_flags_t flags)
- {
- const struct pwm_acts_config *cfg = dev->config;
- struct acts_pwm_chan *pwm_chan;
- uint16_t reg_div_index;
- uint16_t reg_dutymax;
- uint16_t reg_duty;
- uint32_t reg_pwmclk = 0;
- uint32_t key;
- int ret;
- LOG_DBG("PWM@%d set frequency %d, duty %%%d", chan, freq, duty);
- if (chan >= cfg->chans) {
- LOG_ERR("invalid chan %d", chan);
- return -EINVAL;
- }
- if (duty > 100) {
- LOG_ERR("duty cycle is not valid");
- return -EINVAL;
- }
- if (pwm_acts_set_pinmux(dev, chan)) {
- LOG_ERR("set pwm pinmux error");
- return -EFAULT;
- }
- ret = convert_freq2pwmreg(PWM_CLK_CYCLES_PER_SEC, freq, duty,
- ®_div_index, ®_dutymax, ®_duty);
- if (ret < 0)
- return -EINVAL;
- key = irq_lock();
- switch (PWM_CLK_CYCLES_PER_SEC) {
- case BOARD_RC64M_FREQ:
- reg_pwmclk = CMU_PWMCLK_CLKSEL_CK64M;
- break;
- case BOARD_RC32K_FREQ:
- reg_pwmclk = CMU_PWMCLK_CLKSEL_32K;
- break;
- case BOARD_HOSC_FREQ:
- reg_pwmclk = CMU_PWMCLK_CLKSEL_HOSC;
- break;
- default:
- reg_pwmclk = CMU_PWMCLK_CLKSEL_HOSC;
- break;
- }
- sys_write32(reg_pwmclk | CMU_PWMCLK_CLKDIV(reg_div_index),
- PWM_CLK0_BASE + 4 * chan);
- pwm_chan = PWM_CHAN(cfg->base, chan);
- /* disable pwm */
- pwm_chan->ctrl = 0;
- /* setup pwm parameters */
- if (START_VOLTAGE_HIGH == flags)
- pwm_chan->ctrl = PWM_CTRL_POL_SEL_HIGH | PWM_CTRL_MODE_SEL_FIXED;
- else
- pwm_chan->ctrl = PWM_CTRL_MODE_SEL_FIXED;
- pwm_chan->duty_max = reg_dutymax;
- pwm_chan->duty = reg_duty;
- /* enable pwm */
- pwm_chan->ctrl |= (PWM_CTRL_CHANNEL_EN | PWM_CTRL_CHANNEL_START);
- irq_unlock(key);
- return 0;
- }
- /*
- * Get the clock rate (cycles per second) for a PWM pin.
- *
- * Parameters
- * dev: Pointer to PWM device structure
- * pwm: PWM port number
- * cycles: Pointer to the memory to store clock rate (cycles per second)
- *
- * return 0, or negative errno code
- */
- static int pwm_acts_get_cycles_per_sec(const struct device *dev, u32_t chan,
- u64_t *cycles)
- {
- const struct pwm_acts_config *cfg = dev->config;
- if (chan >= cfg->chans) {
- LOG_ERR("invalid pwm chan %d", chan);
- return -EINVAL;
- }
- *cycles = (u64_t)cfg->cycle;
- return 0;
- }
- static int pwm_acts_set_breath_mode(const struct device *dev, u32_t chan, pwm_breath_ctrl_t *ctrl)
- {
- const struct pwm_acts_config *cfg = dev->config;
- struct pwm_acts_data *data = dev->data;
- struct acts_pwm_chan *pwm_chan;
- u32_t period = PWM_PIN_CLK_PERIOD_USEC, qd, qu, high, low;
- pwm_breath_ctrl_t breath_ctrl = {0};
- if (!ctrl) {
- breath_ctrl.rise_time_ms = PWM_BREATH_RISE_TIME_DEFAULT;
- breath_ctrl.down_time_ms = PWM_BREATH_DOWN_TIME_DEFAULT;
- breath_ctrl.high_time_ms = PWM_BREATH_HIGH_TIME_DEFAULT;
- breath_ctrl.low_time_ms = PWM_BREATH_LOW_TIME_DEFAULT;
- } else {
- memcpy(&breath_ctrl, ctrl, sizeof(pwm_breath_ctrl_t));
- }
- LOG_INF("PWM@%d rise %dms, down %dms, high %dms, low %dms",
- chan, breath_ctrl.rise_time_ms, breath_ctrl.down_time_ms,
- breath_ctrl.high_time_ms, breath_ctrl.low_time_ms);
- if (chan >= cfg->chans) {
- LOG_ERR("invalid chan %d", chan);
- return -EINVAL;
- }
- if (pwm_acts_set_pinmux(dev, chan)) {
- LOG_DBG("set pwm pinmux error");
- return -EFAULT;
- }
- k_mutex_lock(&data->mutex, K_FOREVER);
- pwm_chan = PWM_CHAN(cfg->base, chan);
- /* disable pwm */
- pwm_chan->ctrl = 0;
- /* setup pwm parameters */
- pwm_chan->ctrl = PWM_CTRL_POL_SEL_HIGH | PWM_CTRL_MODE_SEL_BREATH;
- /* rise time T1 = QU x C x C x t; C=32, t=PWM_PIN_CLK_PERIOD_USEC */
- qu = breath_ctrl.rise_time_ms * 1000 / PWM_BREATH_MODE_DEFAULT_C / PWM_BREATH_MODE_DEFAULT_C;
- qu = (qu + period - 1) / period*3/2;
- /* down time T2 = QD x C x C x t; C=32, t=PWM_PIN_CLK_PERIOD_USEC */
- qd = breath_ctrl.down_time_ms * 1000 / PWM_BREATH_MODE_DEFAULT_C / PWM_BREATH_MODE_DEFAULT_C;
- qd = (qd + period - 1) / period*3/2;
- /* high level time T3 = H x C x t; C=32, t = PWM_PIN_CLK_PERIOD_USEC */
- high = breath_ctrl.high_time_ms * 1000 / PWM_BREATH_MODE_DEFAULT_C;
- high = (high + period - 1) / period*3/2;
- /* high level time T3 = L x C x t; C=32, t = PWM_PIN_CLK_PERIOD_USEC */
- low = breath_ctrl.low_time_ms * 1000 / PWM_BREATH_MODE_DEFAULT_C;
- low = (low + period - 1) / period*3/2;
- LOG_INF("QU:%d QD:%d high:%d low:%d", qu, qd, high, low);
- pwm_chan->c = PWM_BREATH_MODE_C(PWM_BREATH_MODE_DEFAULT_C);
- pwm_chan->q = PWM_BREATH_MODE_QU(qu) | PWM_BREATH_MODE_QD(qd);
- pwm_chan->h = PWM_BREATH_MODE_H(high);
- pwm_chan->l = PWM_BREATH_MODE_L(low);
- /* enable pwm */
- pwm_chan->ctrl |= (PWM_CTRL_CHANNEL_EN | PWM_CTRL_CHANNEL_START);
- k_mutex_unlock(&data->mutex);
- return 0;
- }
- static int pwm_acts_pin_stop(const struct device *dev, u32_t chan)
- {
- const struct pwm_acts_config *cfg = dev->config;
- //struct pwm_acts_data *data = dev->data;
- struct acts_pwm_chan *pwm_chan;
- if (chan >= cfg->chans) {
- LOG_ERR("invalid pwm chan %d", chan);
- return -EINVAL;
- }
- pwm_chan = PWM_CHAN(cfg->base, chan);
- /* disable pwm */
- pwm_chan->ctrl = 0;
- LOG_INF("PWM@%d pin stop", chan);
- return 0;
- }
- static int pwm_acts_pin_mfp_set(const struct device *dev, u32_t pwm, u32_t pin)
- {
- //const struct pwm_acts_config *cfg = dev->config;
- struct pwm_acts_data *data = dev->data;
- if(pwm_acts_check_chan(pwm, pin)) {
- LOG_ERR("invalid pwm %d: %d", pwm, pin);
- return -1;
- }
- if(data->pins_pwm_mfp[pwm].pin_num != 0)//this chan has been used
- pwm_acts_mfp(data->pins_pwm_mfp[pwm].pin_num, 0, false);
- data->pins_pwm_mfp[pwm].pin_num = pin;
- data->pins_pwm_mfp[pwm].mode = PWM_MFP;
- LOG_INF("PWM@%d pin mfp set", pin);
- return 0;
- }
- int pwm_acts_init(const struct device *dev)
- {
- const struct pwm_acts_config *cfg = dev->config;
- struct pwm_acts_data *data = dev->data;
- int i, chan;
- #ifdef CHIP_LEOPARD
- u16_t reg_div;
- #else
- u8_t clk_div;
- #endif
- struct board_pwm_pinmux_info pinmux_info;
- board_get_pwm_pinmux_info(&pinmux_info);
- memset(data->pins_pwm_mfp, 0xff, sizeof(data->pins_pwm_mfp));
- for (i = 0; i < pinmux_info.pins_num; i++) {
- chan = pinmux_info.pins_config[i].pin_chan;
- data->pins_pwm_mfp[chan].pin_num = pinmux_info.pins_config[i].pin_num;
- data->pins_pwm_mfp[chan].mode = pinmux_info.pins_config[i].mode;
- }
- #ifdef CHIP_LEOPARD
- /* enable pwm controller clock */
- acts_clock_peripheral_enable(cfg->clock0_id);
- acts_clock_peripheral_enable(cfg->clock1_id);
- acts_clock_peripheral_enable(cfg->clock2_id);
- acts_clock_peripheral_enable(cfg->clock3_id);
- #else
- /* enable pwm controller clock */
- acts_clock_peripheral_enable(cfg->clock_id);
- #endif
- /* reset pwm controller */
- acts_reset_peripheral(cfg->reset_id);
- #ifdef CHIP_LEOPARD
- /* clock source: 32Mhz, pwm clock fs 8KHz period 125us */
- reg_div = PWM_CLK_CYCLES_PER_SEC / PWM_PIN_CYCLES_PER_SEC;
- /* Segmental calculate reg val according div factor */
- if (reg_div < 256) {
- reg_div -= 1;
- } else if ((reg_div >= 256) && (reg_div < 384)) {/* div: 256 */
- reg_div = 255;
- } else if ((reg_div >= 384) && (reg_div < 768)) {/* div: 512 */
- reg_div = 256;
- } else if ((reg_div >= 768) && (reg_div < 1536)) {/* div: 1024 */
- reg_div = 257;
- } else if ((reg_div >= 1536) && (reg_div < 3072)) {/* div: 2048 */
- reg_div = 258;
- } else if ((reg_div >= 3072) && (reg_div < 6144)) {/* div: 4096 */
- reg_div = 259;
- } else if (reg_div >= 6144) {/* div: 8192 */
- reg_div = 260;
- }
- /* init PWM clock */
- for (i = 0; i < cfg->chans; i++)
- sys_write32(CMU_PWMCLK_CLKSEL_HOSC | CMU_PWMCLK_CLKDIV(reg_div), \
- cfg->pwmclk_reg + 4 * i);
- #else
- /* clock source: 16K, div= / 2, pwm clock fs 8KHz period 125us */
- clk_div = (PWM_CLK_CYCLES_PER_SEC / PWM_PIN_CYCLES_PER_SEC) - 1;
- /* init PWM clock */
- for (i = 0; i < cfg->chans; i++) {
- sys_write32(CMU_PWMCLK_CLKSEL_16K | CMU_PWMCLK_CLKDIV(clk_div), \
- cfg->pwmclk_reg + 4 * i);
- }
- #endif
- k_mutex_init(&data->mutex);
- if (cfg->flag_use_dma) {
- data->dma_dev = device_get_binding(cfg->dma_dev_name);
- if (!data->dma_dev) {
- LOG_ERR("Bind DMA device %s error", cfg->dma_dev_name);
- return -ENOENT;
- }
- data->program_pin = PWM_PROGRAM_PIN_INVALID;
- data->dma_chan = dma_request(data->dma_dev, 0xff);
- if(data->dma_chan < 0){
- LOG_ERR("dma-dev rxchan config err chan=%d\n", data->dma_chan);
- return -ENODEV;
- }
- }
- //sys_write32(sys_read32(0x40068000)|(1<<16), 0x40068000);
- return 0;
- }
- const struct pwm_driver_api pwm_acts_driver_api = {
- .pin_set = pwm_acts_pin_set,
- .get_cycles_per_sec = pwm_acts_get_cycles_per_sec,
- .set_breath = pwm_acts_set_breath_mode,
- .pin_mfp = pwm_acts_pin_mfp_set,
- // .set_program = pwm_acts_set_program_mode,
- .pin_stop = pwm_acts_pin_stop,
- .pin_set_freq_duty = pwm_acts_freq_duty_set,
- };
- static struct pwm_acts_data pwm_acts_data;
- static const struct pwm_acts_config pwm_acts_config = {
- .base = (uint32_t)PWM_REG_BASE,
- .pwmclk_reg = PWM_CLK0_BASE,
- .cycle = CONFIG_PWM_CYCLE,
- .chans = CONFIG_PWM_CHANS,
- #if CHIP_LEOPARD
- .clock0_id = CLOCK_ID_PWM0,
- .clock1_id = CLOCK_ID_PWM1,
- .clock2_id = CLOCK_ID_PWM2,
- .clock3_id = CLOCK_ID_PWM3,
- #else
- .clock_id = CLOCK_ID_PWM,
- #endif
- .reset_id = RESET_ID_PWM,
- .dma_dev_name = CONFIG_DMA_0_NAME,
- .txdma_id = CONFIG_PWM_DMA_CHAN,
- .flag_use_dma = CONFIG_PWM_USE_DMA,
- };
- #if IS_ENABLED(CONFIG_PWM)
- DEVICE_DEFINE(pwm_acts, CONFIG_PWM_NAME,
- pwm_acts_init, NULL,
- &pwm_acts_data, &pwm_acts_config,
- POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
- &pwm_acts_driver_api);
- #endif
|