Skip to content

Commit 9921640

Browse files
committed
bsp: k230: add pwm driver
Signed-off-by: Wang Chen <[email protected]>
1 parent 8af201e commit 9921640

File tree

3 files changed

+318
-0
lines changed

3 files changed

+318
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# RT-Thread building script for component
2+
3+
from building import *
4+
5+
cwd = GetCurrentDir()
6+
src = Glob('*.c') + Glob('*.S')
7+
CPPPATH = [cwd]
8+
9+
group = DefineGroup('PWM', src, depend = ['RT_USING_PWM'], CPPPATH = CPPPATH)
10+
11+
objs = [group]
12+
13+
list = os.listdir(cwd)
14+
15+
for item in list:
16+
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
17+
objs = objs + SConscript(os.path.join(item, 'SConscript'))
18+
19+
Return('objs')
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
2+
*
3+
* Redistribution and use in source and binary forms, with or without
4+
* modification, are permitted provided that the following conditions are met:
5+
* 1. Redistributions of source code must retain the above copyright
6+
* notice, this list of conditions and the following disclaimer.
7+
* 2. Redistributions in binary form must reproduce the above copyright
8+
* notice, this list of conditions and the following disclaimer in the
9+
* documentation and/or other materials provided with the distribution.
10+
*
11+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
12+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
16+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
#include <rtthread.h>
26+
#include <rtdevice.h>
27+
#include "riscv_io.h"
28+
#include "board.h"
29+
#include "ioremap.h"
30+
#include <rtdbg.h>
31+
#include <stdbool.h>
32+
#include "sysctl_clk.h"
33+
#include "drv_pwm.h"
34+
#include <sys/ioctl.h>
35+
static struct rt_device_pwm kd_pwm;
36+
kd_pwm_t *reg_pwm;
37+
38+
static int check_channel(int channel)
39+
{
40+
if (channel < 0 || channel > 5)
41+
{
42+
LOG_E("channel %d is not valid\n", channel);
43+
return -RT_ERROR;
44+
}
45+
return channel;
46+
}
47+
48+
static int pwm_start(kd_pwm_t *reg, int channel)
49+
{
50+
int ret;
51+
ret = check_channel(channel);
52+
if (ret < 0)
53+
return ret;
54+
55+
if (channel > 2)
56+
{
57+
reg = (kd_pwm_t *)((void*)reg + 0x40);
58+
}
59+
reg->pwmcfg |= (1 << 12); //default always mode
60+
return ret;
61+
}
62+
63+
static int pwm_stop(kd_pwm_t *reg, int channel)
64+
{
65+
int ret;
66+
ret = check_channel(channel);
67+
if (ret < 0)
68+
return ret;
69+
70+
if (channel > 2)
71+
{
72+
reg = (kd_pwm_t *)((void*)reg + 0x40);
73+
}
74+
reg->pwmcfg &= ~(1 << 12);
75+
76+
return ret;
77+
}
78+
79+
static rt_err_t kd_pwm_get(kd_pwm_t *reg, rt_uint8_t channel, struct rt_pwm_configuration *configuration)
80+
{
81+
int ret;
82+
uint64_t pulse, period;
83+
uint32_t pwm_pclock, pwmscale;
84+
85+
ret = check_channel(channel);
86+
if (ret < 0)
87+
return ret;
88+
89+
pwm_pclock = sysctl_clk_get_leaf_freq(SYSCTL_CLK_PWM_PCLK_GATE);
90+
91+
if (channel > 2)
92+
reg = (kd_pwm_t *)((void*)reg + 0x40);
93+
94+
pwmscale = reg->pwmcfg & 0xf;
95+
pwm_pclock >>= pwmscale;
96+
period = reg->pwmcmp0;
97+
period = period * NSEC_PER_SEC / pwm_pclock;
98+
pulse = *((&reg->pwmcmp1) + (channel % 3));
99+
pulse = pulse * NSEC_PER_SEC / pwm_pclock;
100+
101+
configuration->period = period;
102+
configuration->pulse = pulse;
103+
104+
return RT_EOK;
105+
}
106+
107+
static int kd_pwm_set(kd_pwm_t *reg, int channel, struct rt_pwm_configuration *configuration)
108+
{
109+
int ret;
110+
uint64_t pulse, period, pwmcmpx_max;
111+
uint32_t pwm_pclock, pwmscale = 0;
112+
113+
ret = check_channel(channel);
114+
if (ret < 0)
115+
return ret;
116+
117+
pwm_pclock = sysctl_clk_get_leaf_freq(SYSCTL_CLK_PWM_PCLK_GATE);
118+
pulse = (uint64_t)configuration->pulse * pwm_pclock / NSEC_PER_SEC;
119+
period = (uint64_t)configuration->period * pwm_pclock / NSEC_PER_SEC;
120+
if (pulse > period)
121+
return -RT_EINVAL;
122+
123+
if (channel > 2)
124+
reg = (kd_pwm_t *)((void*)reg + 0x40);
125+
126+
/* 计算占空比 */
127+
pwmcmpx_max = (1 << 16) - 1;
128+
if (period > ((1 << (15 + 16)) - 1LL))
129+
return -RT_EINVAL;
130+
131+
while ((period >> pwmscale) > pwmcmpx_max)
132+
pwmscale++;
133+
if (pwmscale > 0xf)
134+
return -RT_EINVAL;
135+
136+
reg->pwmcfg |= (1 << 9); //default always mode
137+
reg->pwmcfg &= (~0xf);
138+
reg->pwmcfg |= pwmscale; //scale
139+
reg->pwmcmp0 = (period >> pwmscale);
140+
*((&reg->pwmcmp1) + (channel % 3)) = reg->pwmcmp0 - (pulse >> pwmscale);
141+
142+
return RT_EOK;
143+
}
144+
145+
static rt_err_t kd_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
146+
{
147+
struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
148+
rt_uint32_t channel = 0;
149+
int ret;
150+
151+
kd_pwm_t *reg = (kd_pwm_t *)(device->parent.user_data);
152+
channel = configuration->channel;
153+
154+
switch (cmd)
155+
{
156+
case PWM_CMD_ENABLE:
157+
case KD_PWM_CMD_ENABLE:
158+
ret = pwm_start(reg, channel);
159+
if (ret < 0)
160+
return -RT_ERROR;
161+
else
162+
return RT_EOK;
163+
case PWM_CMD_DISABLE:
164+
case KD_PWM_CMD_DISABLE:
165+
ret = pwm_stop(reg, channel);
166+
if (ret < 0)
167+
return -RT_ERROR;
168+
else
169+
return RT_EOK;
170+
case PWM_CMD_SET:
171+
case KD_PWM_CMD_SET:
172+
kd_pwm_set(reg, channel, configuration);
173+
break;
174+
case PWM_CMD_GET:
175+
case KD_PWM_CMD_GET:
176+
kd_pwm_get(reg, channel, configuration);
177+
break;
178+
default:
179+
return -RT_EINVAL;
180+
}
181+
182+
return RT_EOK;
183+
}
184+
185+
static struct rt_pwm_ops drv_ops =
186+
{
187+
kd_pwm_control
188+
};
189+
190+
int rt_hw_pwm_init(void)
191+
{
192+
reg_pwm = (kd_pwm_t *)rt_ioremap((void *)PWM_BASE_ADDR, PWM_IO_SIZE);
193+
kd_pwm.ops = &drv_ops;
194+
rt_device_pwm_register(&kd_pwm, "pwm", &drv_ops, (void *)reg_pwm);
195+
#ifndef RT_FASTBOOT
196+
rt_kprintf("pwm driver register OK\n");
197+
#endif
198+
return RT_EOK;
199+
}
200+
INIT_DEVICE_EXPORT(rt_hw_pwm_init);
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
2+
*
3+
* Redistribution and use in source and binary forms, with or without
4+
* modification, are permitted provided that the following conditions are met:
5+
* 1. Redistributions of source code must retain the above copyright
6+
* notice, this list of conditions and the following disclaimer.
7+
* 2. Redistributions in binary form must reproduce the above copyright
8+
* notice, this list of conditions and the following disclaimer in the
9+
* documentation and/or other materials provided with the distribution.
10+
*
11+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
12+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
13+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
16+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
#ifndef DRV_PWM_H__
26+
#define DRV_PWM_H__
27+
#include <stdint.h>
28+
29+
#define KD_PWM_CMD_ENABLE _IOW('P', 0, int)
30+
#define KD_PWM_CMD_DISABLE _IOW('P', 1, int)
31+
#define KD_PWM_CMD_SET _IOW('P', 2, int)
32+
#define KD_PWM_CMD_GET _IOW('P', 3, int)
33+
#define NSEC_PER_SEC 1000000000L
34+
35+
36+
/**
37+
* @brief pwm channel
38+
* channel 0 ----> pwm0
39+
* channel 1 ----> pwm1
40+
* channel 2 ----> pwm2
41+
* channel 3 ----> pwm3
42+
* channel 4 ----> pwm4
43+
* channel 5 ----> pwm5
44+
*/
45+
46+
47+
typedef struct
48+
{
49+
volatile uint32_t pwmcfg; /* 0x00 */
50+
volatile uint32_t reserved0;
51+
volatile uint32_t pwmcount; /* 0x08 */
52+
volatile uint32_t reserved1;
53+
volatile uint32_t pwms; /* 0x10 */
54+
volatile uint32_t reserved2;
55+
volatile uint32_t reserved3;
56+
volatile uint32_t reserved4;
57+
volatile uint32_t pwmcmp0; /* 0x20 */
58+
volatile uint32_t pwmcmp1; /* 0x24 */
59+
volatile uint32_t pwmcmp2; /* 0x28 */
60+
volatile uint32_t pwmcmp3; /* 0x2c */
61+
} kd_pwm_t;
62+
63+
typedef struct
64+
{
65+
uint32_t scale : 4;
66+
uint32_t reserve: 4;
67+
uint32_t sticky : 1;
68+
uint32_t zerocmp : 1;
69+
uint32_t deglitch : 1;
70+
uint32_t reserve1 : 1;
71+
uint32_t enalways : 1;
72+
uint32_t enoneshot : 1;
73+
uint32_t reserve2 : 2;
74+
uint32_t cmp0center : 1;
75+
uint32_t cmp1center : 1;
76+
uint32_t cmp2center : 1;
77+
uint32_t cmp3center : 1;
78+
uint32_t reserve3 : 4;
79+
uint32_t cmp0gang : 1;
80+
uint32_t cmp1gang : 1;
81+
uint32_t cmp2gang : 1;
82+
uint32_t cmp3gang : 1;
83+
uint32_t cmp0ip : 1;
84+
uint32_t cmp1ip : 1;
85+
uint32_t cmp2ip : 1;
86+
uint32_t cmp3ip : 1;
87+
} pwm_cfg_t;
88+
89+
typedef struct
90+
{
91+
pwm_cfg_t cfg;
92+
uint32_t freq;
93+
uint32_t cmp0_val;
94+
double cmp1_duty;
95+
double cmp2_duty;
96+
double cmp3_duty;
97+
} pwm_param_t;
98+
99+
#endif

0 commit comments

Comments
 (0)