Przeglądaj źródła

[bsp/cvitek]add pwm driver (#8571)

flyingcys 1 rok temu
rodzic
commit
aa04a59805

+ 23 - 1
bsp/cvitek/c906_little/board/Kconfig

@@ -40,9 +40,31 @@ menu "General Drivers Configuration"
             default 32
         endif
 
-    menuconfig BSP_USING_ADC
+    config BSP_USING_ADC
         bool "Using ADC"
         select RT_USING_ADC
         default n
 
+    menuconfig BSP_USING_PWM
+        bool "Using PWM"
+        select RT_USING_PWM
+        default n
+
+        if BSP_USING_PWM
+            config BSP_USING_PWM0
+            bool "Enable PWM 0"
+            default n
+
+            config BSP_USING_PWM1
+            bool "Enable PWM 1"
+            default n
+
+            config BSP_USING_PWM2
+            bool "Enable PWM 2"
+            default n
+
+            config BSP_USING_PWM3
+            bool "Enable PWM 3"
+            default n
+        endif
 endmenu

+ 25 - 1
bsp/cvitek/cv1800b/board/Kconfig

@@ -32,9 +32,33 @@ menu "General Drivers Configuration"
 
         endif
         
-    menuconfig BSP_USING_ADC
+    config BSP_USING_ADC
         bool "Using ADC"
         select RT_USING_ADC
         default n
 
+    menuconfig BSP_USING_PWM
+        bool "Using PWM"
+        select RT_USING_PWM
+        default n
+
+        if BSP_USING_PWM
+            config BSP_USING_PWM0
+            bool "Enable PWM 0"
+            default n
+
+            config BSP_USING_PWM1
+            bool "Enable PWM 1"
+            default n
+
+            config BSP_USING_PWM2
+            bool "Enable PWM 2"
+            default n
+
+            config BSP_USING_PWM3
+            bool "Enable PWM 3"
+            default n
+            
+        endif
+
 endmenu

+ 3 - 0
bsp/cvitek/drivers/SConscript

@@ -18,6 +18,9 @@ if GetDepend('BSP_USING_I2C'):
 if GetDepend('BSP_USING_ADC'):
     src += ['drv_adc.c']
 
+if GetDepend('BSP_USING_PWM'):
+    src += ['drv_pwm.c']
+    CPPPATH += [cwd + r'/cv1800b/pwm']
 CPPDEFINES += ['-DCONFIG_64BIT']
 
 group = DefineGroup('drivers', src, depend = [''], CPPDEFINES = CPPDEFINES, CPPPATH = CPPPATH)

+ 266 - 0
bsp/cvitek/drivers/cv1800b/pwm/cvi_pwm.h

@@ -0,0 +1,266 @@
+#ifndef __CVI_PWM_H__
+#define __CVI_PWM_H__
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define     __IM     volatile const       /*! Defines 'read only' structure member permissions */
+#define     __OM     volatile             /*! Defines 'write only' structure member permissions */
+#define     __IOM    volatile             /*! Defines 'read / write' structure member permissions */
+
+#define CVI_PWM0_BASE               0x03060000
+#define CVI_PWM1_BASE               0x03061000
+#define CVI_PWM2_BASE               0x03062000
+#define CVI_PWM3_BASE               0x03063000
+
+typedef enum {
+    PWM_CHANNEL_0    = 0U,
+    PWM_CHANNEL_1,
+    PWM_CHANNEL_2,
+    PWM_CHANNEL_3,
+    PWM_CHANNEL_4,
+    PWM_CHANNEL_5,
+    PWM_CHANNEL_6,
+    PWM_CHANNEL_7,
+    PWM_CHANNEL_8,
+    PWM_CHANNEL_9,
+    PWM_CHANNEL_10,
+    PWM_CHANNEL_11,
+    PWM_CHANNEL_12,
+    PWM_CHANNEL_13,
+    PWM_CHANNEL_14,
+    PWM_CHANNEL_15,
+    PWM_CHANNEL_NUM
+} cvi_pwm_channel_t;
+
+
+struct cvi_pwm_regs_t {
+    uint32_t HLPERIOD0;
+    uint32_t PERIOD0;
+    uint32_t HLPERIOD1;
+    uint32_t PERIOD1;
+    uint32_t HLPERIOD2;
+    uint32_t PERIOD2;
+    uint32_t HLPERIOD3;
+    uint32_t PERIOD3;
+    uint32_t CAP_FREQNUM;
+    uint32_t CAP_FREQDATA;
+    uint32_t POLARITY;
+    uint32_t PWMSTART;
+    uint32_t PWMDONE;
+    uint32_t PWMUPDATE;
+    uint32_t PCOUNT0;
+    uint32_t PCOUNT1;
+    uint32_t PCOUNT2;
+    uint32_t PCOUNT3;
+    uint32_t PULSECOUNT0;
+    uint32_t PULSECOUNT1;
+    uint32_t PULSECOUNT2;
+    uint32_t PULSECOUNT3;
+    uint32_t SHIFTCOUNT0;
+    uint32_t SHIFTCOUNT1;
+    uint32_t SHIFTCOUNT2;
+    uint32_t SHIFTCOUNT3;
+    uint32_t SHIFTSTART;
+    uint32_t CAP_FREQEN;
+    uint32_t CAP_FREQDONE_NUM;
+    uint32_t PWM_OE;
+};
+
+
+static struct cvi_pwm_regs_t cv182x_pwm_reg = {
+    .HLPERIOD0 = 0x0,
+    .PERIOD0 = 0x4,
+    .HLPERIOD1 = 0x8,
+    .PERIOD1 = 0xc,
+    .HLPERIOD2 = 0x10,
+    .PERIOD2 = 0x14,
+    .HLPERIOD3 = 0x18,
+    .PERIOD3 = 0x1c,
+    .CAP_FREQNUM = 0x20,
+    .CAP_FREQDATA = 0x24,
+    .POLARITY = 0x40,
+    .PWMSTART = 0x44,
+    .PWMDONE = 0x48,
+    .PWMUPDATE = 0x4c,
+    .PCOUNT0 = 0x50,
+    .PCOUNT1 = 0x54,
+    .PCOUNT2 = 0x58,
+    .PCOUNT3 = 0x5c,
+    .PULSECOUNT0 = 0x60,
+    .PULSECOUNT1 = 0x64,
+    .PULSECOUNT2 = 0x68,
+    .PULSECOUNT3 = 0x6c,
+    .SHIFTCOUNT0 = 0x80,
+    .SHIFTCOUNT1 = 0x84,
+    .SHIFTCOUNT2 = 0x88,
+    .SHIFTCOUNT3 = 0x8c,
+    .SHIFTSTART = 0x90,
+    .CAP_FREQEN = 0x9c,
+    .CAP_FREQDONE_NUM = 0xC0,
+    .PWM_OE = 0xd0,
+};
+
+static struct cvi_pwm_regs_t *cvi_pwm_reg = &cv182x_pwm_reg;
+
+#define PWM_HLPERIOD0(reg_base)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD0))
+#define PWM_PERIOD0(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD0))
+#define PWM_HLPERIOD1(reg_base)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD1))
+#define PWM_PERIOD1(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD1))
+#define PWM_HLPERIOD2(reg_base)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD2))
+#define PWM_PERIOD2(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD2))
+#define PWM_HLPERIOD3(reg_base)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD3))
+#define PWM_PERIOD3(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD3))
+#define PWM_HLPERIODX(reg_base, _ch_)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD0 + (_ch_ << 3)))
+#define PWM_PERIODX(reg_base, _ch_)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD0 * (1 + (_ch_ << 1))))
+
+#define CAP_FREQNUM(reg_base, _ch_)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQNUM + _ch_ * 8))
+#define CAP_FREQDATA(reg_base, _ch_)       *((__IM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQDATA + _ch_ * 8))
+
+#define PWM_POLARITY(reg_base)      *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->POLARITY))
+#define PWM_PWMSTART(reg_base)      *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMSTART))
+#define PWM_PWMDONE(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMDONE))
+#define PWM_PWMUPDATE(reg_base)     *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMUPDATE))
+
+#define PWM_PCOUNT0(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT0))
+#define PWM_PCOUNT1(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT1))
+#define PWM_PCOUNT2(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT2))
+#define PWM_PCOUNT3(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT3))
+
+#define PWM_PULSECOUNT0(reg_base)       *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT0))
+#define PWM_PULSECOUNT1(reg_base)       *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT1))
+#define PWM_PULSECOUNT2(reg_base)       *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT2))
+#define PWM_PULSECOUNT3(reg_base)       *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT3))
+
+#define PWM_SHIFTCOUNT0(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT0))
+#define PWM_SHIFTCOUNT1(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT1))
+#define PWM_SHIFTCOUNT2(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT2))
+#define PWM_SHIFTCOUNT3(reg_base)       *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT3))
+#define PWM_SHIFTSTART(reg_base)        *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTSTART))
+
+#define CAP_FREQEN(reg_base)        *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQEN))
+#define CAP_FREQDONE_NUM(reg_base, _ch_)  *((__IM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQDONE_NUM + _ch_ * 4))
+
+#define PWM_PWM_OE(reg_base)        *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWM_OE))
+
+
+/*! PWM Configure Register,     offset: 0x00 */
+#define CVI_PWM_HIGH_PERIOD_Pos                         (0U)
+#define CVI_PWM_HIGH_PERIOD_Msk                         (0xffffffff)
+
+#define CVI_PWM_PERIOD_Pos                              (0U)
+#define CVI_PWM_PERIOD_Msk                              (0xffffffff)
+
+#define CVI_PWM_POLARITY_CH_Pos(_ch_)                     (_ch_)
+#define CVI_PWM_POLARITY_CH_Msk(_ch_)                     (1U << CVI_PWM_POLARITY_CH_Pos(_ch_))
+#define CVI_PWM_POLARITY_CH_HIGH(_ch_)                    CVI_PWM_POLARITY_CH_Msk(_ch_)
+
+#define CVI_PWM_START_CH_Pos(_ch_)                        (_ch_)
+#define CVI_PWM_START_CH_Msk(_ch_)                        (1U << CVI_PWM_START_CH_Pos(_ch_))
+#define CVI_PWM_START_CH_EN(_ch_)                         CVI_PWM_START_CH_Msk(_ch_)
+
+#define CVI_PWM_OUTPUT_CH_Pos(_ch_)                       (_ch_)
+#define CVI_PWM_OUTPUT_CH_Msk(_ch_)                       (1U << CVI_PWM_OUTPUT_CH_Pos(_ch_))
+#define CVI_PWM_OUTPUT_CH_EN(_ch_)                        CVI_PWM_OUTPUT_CH_Msk(_ch_)
+
+#define CVI_CAP_FREQNUM_CH_Pos                             (0U)
+#define CVI_CAP_FREQNUM_CH_Msk                             (0xffffffff)
+
+#define CVI_CAP_FREQEN_Pos(_ch_)                           (_ch_)
+#define CVI_CAP_FREQEN_Msk(_ch_)                           (1U << CVI_CAP_FREQEN_Pos(_ch_))
+#define CVI_CAP_FREQEN(_ch_)                                CVI_CAP_FREQEN_Msk(_ch_)
+
+#define CVI_CAP_FREQDONE_NUM_Poa                               (0U)
+#define CVI_CAP_FREQDONE_NUM_Msk                               (0xffffffff)
+
+#define CVI_CAP_FREQDATA_pos                                 (0U)
+#define CVI_CAP_FREQDATA_msk                                 (0xffffffff)
+
+static inline void cvi_pwm_set_high_period_ch(unsigned long reg_base, uint32_t ch, unsigned long long value)
+{
+    PWM_HLPERIODX(reg_base, ch) = value;
+}
+
+static inline unsigned long long cvi_pwm_get_high_period_ch(unsigned long reg_base, uint32_t ch)
+{
+    return PWM_HLPERIODX(reg_base, ch);
+}
+
+static inline void cvi_pwm_set_period_ch(unsigned long reg_base, uint32_t ch, unsigned long long value)
+{
+    PWM_PERIODX(reg_base, ch) = value;
+}
+
+static inline unsigned long long cvi_pwm_get_period_ch(unsigned long reg_base, uint32_t ch)
+{
+    return PWM_PERIODX(reg_base, ch);
+}
+
+static inline void cvi_pwm_set_polarity_high_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_POLARITY(reg_base) |= CVI_PWM_POLARITY_CH_HIGH(ch);
+}
+
+static inline void cvi_pwm_set_polarity_low_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_POLARITY(reg_base) &= ~CVI_PWM_POLARITY_CH_HIGH(ch);
+}
+
+static inline uint32_t cvi_pwm_get_polarity(unsigned long reg_base, uint32_t ch)
+{
+    return (PWM_POLARITY(reg_base) & CVI_PWM_POLARITY_CH_Msk(ch));
+}
+
+static inline void cvi_pwm_start_en_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_PWMSTART(reg_base) |= CVI_PWM_START_CH_EN(ch);
+}
+
+static inline void cvi_pwm_start_dis_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_PWMSTART(reg_base) &= ~CVI_PWM_START_CH_EN(ch);
+}
+
+static inline void cvi_pwm_output_en_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_PWM_OE(reg_base) |= CVI_PWM_OUTPUT_CH_EN(ch);
+}
+
+static inline void cvi_pwm_input_en_ch(unsigned long reg_base, uint32_t ch)
+{
+    PWM_PWM_OE(reg_base) &= ~CVI_PWM_OUTPUT_CH_EN(ch);
+}
+
+static inline void cvi_cap_set_freqnum_ch(unsigned long reg_base, uint32_t ch, uint32_t value)
+{
+    CAP_FREQNUM(reg_base, ch) = value;
+}
+
+static inline void cvi_cap_freq_en_ch(unsigned long reg_base, uint32_t ch)
+{
+    CAP_FREQEN(reg_base) |= CVI_CAP_FREQEN(ch);
+}
+
+static inline void cvi_cap_freq_dis_ch(unsigned long reg_base, uint32_t ch)
+{
+    CAP_FREQEN(reg_base) &= ~CVI_CAP_FREQEN(ch);
+}
+
+static inline uint32_t cvi_cap_get_freq_done_num_ch(unsigned long reg_base, uint32_t ch)
+{
+    return CAP_FREQDONE_NUM(reg_base, ch);
+}
+
+static inline uint32_t cvi_cap_get_freq_data_ch(unsigned long reg_base, uint32_t ch)
+{
+    return CAP_FREQDATA(reg_base, ch);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 212 - 0
bsp/cvitek/drivers/drv_pwm.c

@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024/02/19     flyingcys    first version
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "drv_pwm.h"
+
+#ifdef BSP_USING_PWM
+
+#define DBG_LEVEL   DBG_LOG
+#include <rtdbg.h>
+#define LOG_TAG "DRV.PWM"
+
+struct cvi_pwm_dev
+{
+    struct rt_device_pwm device;
+    const char *name;
+    rt_ubase_t reg_base;
+};
+
+static const uint64_t count_unit = 100000000;  // 100M count per second
+static const uint64_t NSEC_COUNT = 1000000000;  // ns
+
+static void cvi_pwm_set_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
+{
+    unsigned long long duty_clk, period_clk;
+
+    cvi_pwm_set_polarity_low_ch(reg_base, (cfg->channel & PWM_MAX_CH));
+
+    duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
+    cvi_pwm_set_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
+
+    period_clk = (cfg->period * count_unit) / NSEC_COUNT;
+    cvi_pwm_set_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
+
+    cvi_pwm_output_en_ch(reg_base, cfg->channel & PWM_MAX_CH);
+}
+
+static void cvi_pwm_get_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
+{
+    unsigned long long duty_clk, period_clk;
+
+    duty_clk = cvi_pwm_get_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
+    cfg->pulse = duty_clk * NSEC_COUNT / count_unit;
+
+    period_clk = cvi_pwm_get_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
+    cfg->period = period_clk * NSEC_COUNT / count_unit;
+}
+static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
+{
+    struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg;
+    struct cvi_pwm_dev *pwm_dev = (struct cvi_pwm_dev *)device->parent.user_data;
+    unsigned long long duty_clk, period_clk;
+    const uint64_t count_unit = 100000000;  // 100M count per second
+    const uint64_t NSEC_COUNT = 1000000000;  // ns
+
+    if (cfg->channel > PWM_MAX_CH)
+        return -RT_EINVAL;
+
+    switch (cmd)
+    {
+        case PWM_CMD_ENABLE:
+            cvi_pwm_start_en_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
+        break;
+
+        case PWM_CMD_DISABLE:
+            cvi_pwm_start_dis_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
+        break;
+
+        case PWM_CMD_SET:
+            cvi_pwm_set_config(pwm_dev->reg_base, cfg);
+        break;
+
+        case PWM_CMD_GET:
+            cvi_pwm_get_config(pwm_dev->reg_base, cfg);
+        break;
+
+        case PWM_CMD_SET_PERIOD:
+            period_clk = (cfg->period * count_unit) / NSEC_COUNT;
+            cvi_pwm_set_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
+        break;
+
+        case PWM_CMD_SET_PULSE:
+            duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
+            cvi_pwm_set_high_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
+        break;
+
+        default:
+        LOG_D("cmd: %x channel: %d period: %d pulse: %d", cmd, cfg->channel, cfg->period, cfg->pulse);
+        break;
+    }
+
+    return RT_EOK;
+}
+
+const static struct rt_pwm_ops cvi_pwm_ops =
+{
+    .control = &_pwm_control
+};
+
+static struct cvi_pwm_dev cvi_pwm[] =
+{
+#ifdef BSP_USING_PWM0
+    {
+        .name = "pwm0",
+        .reg_base = CVI_PWM0_BASE,
+    },
+#endif
+
+#ifdef BSP_USING_PWM1
+    {
+        .name = "pwm1",
+        .reg_base = CVI_PWM1_BASE,
+    },
+#endif
+
+#ifdef BSP_USING_PWM2
+    {
+        .name = "pwm2",
+        .reg_base = CVI_PWM2_BASE,
+    },
+#endif
+
+#ifdef BSP_USING_PWM3
+    {
+        .name = "pwm3",
+        .reg_base = CVI_PWM3_BASE,
+    },
+#endif
+};
+
+int rt_hw_pwm_init(void)
+{
+    int result = RT_EOK;
+    uint8_t i;
+
+    for (i = 0; i < sizeof(cvi_pwm) / sizeof(cvi_pwm[0]); i++)
+    {
+        result = rt_device_pwm_register(&cvi_pwm[i].device, cvi_pwm[i].name, &cvi_pwm_ops, &cvi_pwm[i]);
+        if (result != RT_EOK)
+        {
+            LOG_E("device %s register failed", cvi_pwm[i].name);
+            return -RT_ERROR;
+        }
+    }
+    return RT_EOK;
+#if 0
+#ifdef BSP_USING_PWM0
+    static struct cvi_pwm_dev cvi_pwm0;
+
+    cvi_pwm0.name = "pwm0";
+    cvi_pwm0.reg_base = CVI_PWM0_BASE;
+
+    result = rt_device_pwm_register(&cvi_pwm0.device, cvi_pwm0.name, &cvi_pwm_ops, &cvi_pwm0);
+    if (result != RT_EOK)
+    {
+        LOG_E("device %s register failed.", cvi_pwm0.name);
+        return result;
+    }
+#endif
+
+#ifdef BSP_USING_PWM1
+    static struct cvi_pwm_dev cvi_pwm1;
+    cvi_pwm1.name = "pwm1";
+    cvi_pwm1.reg_base = CVI_PWM1_BASE;
+
+    result = rt_device_pwm_register(&cvi_pwm1.device, cvi_pwm1.name, &cvi_pwm_ops, &cvi_pwm1);
+    if (result != RT_EOK)
+    {
+        LOG_E("device %s register failed.", cvi_pwm1.name);
+        return result;
+    }
+#endif
+
+#ifdef BSP_USING_PWM2
+    static struct cvi_pwm_dev cvi_pwm2;
+    cvi_pwm2.name = "pwm2";
+    cvi_pwm2.reg_base = CVI_PWM2_BASE;
+
+    result = rt_device_pwm_register(&cvi_pwm2.device, cvi_pwm2.name, &cvi_pwm_ops, &cvi_pwm2);
+    if (result != RT_EOK)
+    {
+        LOG_E("device %s register failed.", cvi_pwm2.name);
+        return result;
+    }
+#endif
+
+#ifdef BSP_USING_PWM3
+    static struct cvi_pwm_dev cvi_pwm3;
+    cvi_pwm3.name = "pwm3";
+    cvi_pwm3.reg_base = CVI_PWM3_BASE;
+
+    result = rt_device_pwm_register(&cvi_pwm3.device, cvi_pwm3.name, &cvi_pwm_ops, &cvi_pwm3);
+    if (result != RT_EOK)
+    {
+        LOG_E("device %s register failed.",  cvi_pwm3.name);
+        return result;
+    }
+#endif
+
+    return RT_EOK;
+#endif
+}
+INIT_BOARD_EXPORT(rt_hw_pwm_init);
+
+#endif /* BSP_USING_PWM */

+ 19 - 0
bsp/cvitek/drivers/drv_pwm.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024/02/19     flyingcys    first version
+ */
+#ifndef __DRV_PWM_H__
+#define __DRV_PWM_H__
+
+#include "cvi_pwm.h"
+
+#define PWM_MAX_CH          3
+
+int rt_hw_pwm_init(void);
+
+#endif /* __DRV_PWM_H__ */