1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Copyright(c) 2020, Du Huanpeng<548708880@qq.com>
7  *
8  */
9 
10 #include <rtthread.h>
11 #include <rtdevice.h>
12 #include <ls2k1000.h>
13 
14 #ifdef RT_USING_PWM
15 
16 #define PWM0_BASE   (0xFFFFFFFFBFe02000)
17 #define PWM1_BASE   (0xFFFFFFFFBFe02010)
18 #define PWM2_BASE   (0xFFFFFFFFBFe02020)
19 #define PWM3_BASE   (0xFFFFFFFFBFe02030)
20 
21 #define CTRL_EN     (1UL<<0)
22 #define CTRL_OE     (1UL<<3)
23 #define CTRL_SINGL  (1UL<<4)
24 #define CTRL_INTE   (1UL<<5)
25 #define CTRL_INT    (1UL<<6)
26 #define CTRL_RST    (1UL<<7)
27 #define CTRL_CAPTE  (1UL<<8)
28 #define CTRL_INVERT (1UL<<9)
29 #define CTRL_DZONE  (1UL<<10)
30 
31 struct loongson_pwm
32 {
33     rt_uint32_t __PAD0;
34     rt_uint32_t low_buffer;
35     rt_uint32_t full_buffer;
36     rt_uint32_t ctrl;
37 };
38 
loongson_pwm_enable(struct rt_device_pwm * device,int channel)39 rt_err_t loongson_pwm_enable(struct rt_device_pwm *device, int channel)
40 {
41     int **priv;
42     struct loongson_pwm *chip;
43     volatile rt_uint64_t *config0;
44     rt_uint64_t m;
45 
46     channel %= 4;
47 
48     config0 = (void *)GEN_CONFIG0_REG;
49     m = 1ULL << 12 << channel;
50     *config0 |= m;
51 
52     priv = device->parent.user_data;
53     chip = (void *)priv[channel];
54     chip->ctrl = CTRL_EN;
55 
56     return RT_EOK;
57 }
58 
loongson_pwm_disable(struct rt_device_pwm * device,int channel)59 rt_err_t loongson_pwm_disable(struct rt_device_pwm *device, int channel)
60 {
61     struct loongson_pwm **chip;
62     rt_uint64_t m;
63 
64     chip = device->parent.user_data;
65     channel %= 4;
66     chip[channel]->ctrl &= ~CTRL_EN;
67 
68     return RT_EOK;
69 }
70 
loongson_pwm_set(struct rt_device_pwm * device,int channel,rt_uint32_t period,rt_uint32_t pulse)71 rt_err_t loongson_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse)
72 {
73     struct loongson_pwm *chip;
74     rt_uint32_t **priv;
75 
76     priv = device->parent.user_data;
77     channel %= 4;
78     chip = (void *)priv[channel];
79 
80     chip->ctrl       &= ~CTRL_EN;
81     chip->full_buffer =  period;
82     chip->low_buffer  =  pulse;
83     chip->ctrl       |=  CTRL_EN;
84 
85     return RT_EOK;
86 }
87 
loongson_pwm_ioctl(struct rt_device_pwm * device,int cmd,void * arg)88 static rt_err_t loongson_pwm_ioctl(struct rt_device_pwm *device, int cmd, void *arg)
89 {
90     rt_err_t rc;
91     struct rt_pwm_configuration *cfg;
92 
93     cfg = (void *)arg;
94 
95     switch (cmd)
96     {
97     case PWM_CMD_ENABLE:
98         rc = loongson_pwm_enable(device, cfg->channel);
99         break;
100     case PWM_CMD_DISABLE:
101         rc = loongson_pwm_disable(device, cfg->channel);
102         break;
103     case PWM_CMD_SET:
104         rc = loongson_pwm_set(device, cfg->channel, cfg->period, cfg->pulse);
105         break;
106     case PWM_CMD_GET:
107         rc = -RT_ENOSYS;
108         break;
109     default:
110         rc = -RT_EINVAL;
111         break;
112     }
113     return rc;
114 }
115 
116 struct rt_pwm_ops loongson_pwm_ops =
117 {
118     .control = loongson_pwm_ioctl,
119 };
120 
121 struct rt_device_pwm loongson_pwm =
122 {
123     .ops = &loongson_pwm_ops,
124 };
125 
loongson_pwm_init(void)126 int loongson_pwm_init(void)
127 {
128     int rc = RT_EOK;
129     static rt_uint32_t *priv[] =
130     {
131         (void *)PWM0_BASE,
132         (void *)PWM1_BASE,
133         (void *)PWM2_BASE,
134         (void *)PWM3_BASE
135     };
136     rc = rt_device_pwm_register(&loongson_pwm, "pwm0", &loongson_pwm_ops, &priv);
137     return rc;
138 }
139 INIT_DEVICE_EXPORT(loongson_pwm_init);
140 
141 #endif /*RT_USING_PWM*/
142