• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <hi_stdlib.h>
17 #include <hi_sem.h>
18 
19 #include "pwm_drv.h"
20 
21 #define CLKEN1_PWM5     10
22 #define CLKEN1_PWM_BUS  6
23 #define CLKEN1_PWM      5
24 #define CLKEN1_PWM4     4
25 #define CLKEN1_PWM3     3
26 #define CLKEN1_PWM2     2
27 #define CLKEN1_PWM1     1
28 #define CLKEN1_PWM0     0
29 #define CLKEN1_PWM_ALL  ((1 << (CLKEN1_PWM0)) | (1 << (CLKEN1_PWM1)) | (1 << (CLKEN1_PWM2)) | (1 << (CLKEN1_PWM3)) | \
30                         (1 << (CLKEN1_PWM4)) | (1 << (CLKEN1_PWM5)))
31 
hi_pwm_init(hi_pwm_port port)32 hi_u32 hi_pwm_init(hi_pwm_port port)
33 {
34     hi_u32 ret;
35     pwm_ctl *ctrl = HI_NULL;
36     hi_u16 reg_val;
37 
38     if (pwm_check_port(port) != HI_ERR_SUCCESS) {
39         return HI_ERR_PWM_INVALID_PARAMETER;
40     }
41     ctrl = pwm_get_ctl(port);
42     if (ctrl->is_init == HI_FALSE) {
43         hi_reg_read16(CLDO_CTL_CLKEN1_REG, reg_val);
44         switch (port) {
45             case HI_PWM_PORT_PWM0:
46                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
47                 reg_val |= 1 << CLKEN1_PWM0;
48                 break;
49             case HI_PWM_PORT_PWM1:
50                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
51                 reg_val |= 1 << CLKEN1_PWM1;
52                 break;
53             case HI_PWM_PORT_PWM2:
54                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
55                 reg_val |= 1 << CLKEN1_PWM2;
56                 break;
57             case HI_PWM_PORT_PWM3:
58                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
59                 reg_val |= 1 << CLKEN1_PWM3;
60                 break;
61             case HI_PWM_PORT_PWM4:
62                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
63                 reg_val |= 1 << CLKEN1_PWM4;
64                 break;
65             default:
66                 ret = hi_sem_bcreate(&(ctrl->pwm_sem), HI_SEM_ONE);
67                 reg_val |= 1 << CLKEN1_PWM5;
68                 break;
69         }
70 
71         if (ret == HI_ERR_SUCCESS) {
72             ctrl->is_init = HI_TRUE;
73             reg_val |= (1 << CLKEN1_PWM_BUS) | (1 << CLKEN1_PWM);
74             hi_reg_write16(CLDO_CTL_CLKEN1_REG, reg_val); /* enable pwmx clk bus */
75         }
76     } else {
77         ret = HI_ERR_SUCCESS; /* HI_ERR_PWM_INITILIZATION_ALREADY return success */
78     }
79     return ret;
80 }
81 
pwm_deinit_clken(hi_pwm_port port)82 hi_void pwm_deinit_clken(hi_pwm_port port)
83 {
84     hi_u16 reg_val;
85     if (pwm_check_port(port) != HI_ERR_SUCCESS) {
86         return;
87     }
88     hi_reg_read16(CLDO_CTL_CLKEN1_REG, reg_val);
89     if (port == HI_PWM_PORT_PWM5) {
90         reg_val &= ~(1 << CLKEN1_PWM5);
91     } else {
92         reg_val &= ~(1 << (hi_u16)port);
93     }
94     if ((reg_val & CLKEN1_PWM_ALL) == 0) { /* if all channels are free, then close pwm bus and clk_pwm */
95         reg_val &= ~((1 << CLKEN1_PWM_BUS) | (1 << CLKEN1_PWM));
96     }
97     hi_reg_write16(CLDO_CTL_CLKEN1_REG, reg_val); /* disable pwmx clk bus */
98 }
99 
hi_pwm_deinit(hi_pwm_port port)100 hi_u32 hi_pwm_deinit(hi_pwm_port port)
101 {
102     hi_u32 ret;
103     pwm_ctl *ctrl = HI_NULL;
104 
105     if (pwm_check_port(port) != HI_ERR_SUCCESS) {
106         return HI_ERR_PWM_INVALID_PARAMETER;
107     }
108     ctrl = pwm_get_ctl(port);
109     if (ctrl->is_init == HI_TRUE) {
110         ret = hi_sem_delete(ctrl->pwm_sem);
111         if (ret == HI_ERR_SUCCESS) {
112             (hi_void)memset_s(ctrl, sizeof(pwm_ctl), 0, sizeof(pwm_ctl));
113             pwm_deinit_clken(port);
114         }
115     } else {
116         ret = HI_ERR_SUCCESS;
117     }
118     return ret;
119 }
120 
hi_pwm_set_clock(hi_pwm_clk_source clk_type)121 hi_u32 hi_pwm_set_clock(hi_pwm_clk_source clk_type)
122 {
123     if (clk_type >= PWM_CLK_MAX) {
124         return HI_ERR_PWM_INVALID_PARAMETER;
125     }
126 
127     if (clk_type == PWM_CLK_160M) {
128         hi_reg_clrbit(CLDO_CTL_CLK_SEL_REG, 0);
129     } else {
130         hi_reg_setbit(CLDO_CTL_CLK_SEL_REG, 0);
131     }
132 
133     return HI_ERR_SUCCESS;
134 }
135 
pwm_set_enable(hi_pwm_port port,hi_bool flag)136 static hi_void pwm_set_enable(hi_pwm_port port, hi_bool flag)
137 {
138     if (flag == HI_TRUE) {
139         /* enable */
140         hi_reg_setbit(pwm_en_reg(pwm_base_addr(port)), 0);
141     } else {
142         /* disable */
143         hi_reg_clrbit(pwm_en_reg(pwm_base_addr(port)), 0);
144     }
145 }
146 
pwm_set_freq(hi_pwm_port port,hi_u16 freq)147 static hi_void pwm_set_freq(hi_pwm_port port, hi_u16 freq)
148 {
149     hi_reg_setbits(pwm_freq_reg(pwm_base_addr(port)), 0, 16, freq);  /* base_addr 16 */
150 }
151 
pwm_set_duty(hi_pwm_port port,hi_u16 duty)152 static hi_void pwm_set_duty(hi_pwm_port port, hi_u16 duty)
153 {
154     hi_reg_setbits(pwm_duty_reg(pwm_base_addr(port)), 0, 16, duty);  /* base_addr 16 */
155 }
156 
pwm_take_effect(hi_pwm_port port)157 static hi_void pwm_take_effect(hi_pwm_port port)
158 {
159     hi_reg_setbit(pwm_start_reg(pwm_base_addr(port)), 0);
160 }
161 
hi_pwm_start(hi_pwm_port port,hi_u16 duty,hi_u16 freq)162 hi_u32 hi_pwm_start(hi_pwm_port port, hi_u16 duty, hi_u16 freq)
163 {
164     hi_u32 ret;
165 
166     if ((pwm_check_port(port) != HI_ERR_SUCCESS) || (duty == 0) || (freq == 0)
167         || (duty > freq)) {
168         return HI_ERR_PWM_INVALID_PARAMETER;
169     }
170     if (pwm_is_init(port) == HI_FALSE) {
171         return HI_ERR_PWM_NO_INIT;
172     }
173     ret = pwm_lock(port);
174     if (ret != HI_ERR_SUCCESS) {
175         return ret;
176     }
177     pwm_set_enable(port, HI_TRUE);
178     pwm_set_freq(port, freq);
179     pwm_set_duty(port, duty);
180     pwm_take_effect(port);
181     return pwm_unlock(port);
182 }
183 
hi_pwm_stop(hi_pwm_port port)184 hi_u32 hi_pwm_stop(hi_pwm_port port)
185 {
186     hi_u32 ret;
187 
188     if (pwm_check_port(port) != HI_ERR_SUCCESS) {
189         return HI_ERR_PWM_INVALID_PARAMETER;
190     }
191     if (pwm_is_init(port) == HI_FALSE) {
192         return HI_ERR_PWM_NO_INIT;
193     }
194 
195     ret = pwm_lock(port);
196     if (ret != HI_ERR_SUCCESS) {
197         return ret;
198     }
199     pwm_set_enable(port, HI_FALSE);
200     pwm_take_effect(port);
201     return pwm_unlock(port);
202 }
203 
pwm_check_port(hi_pwm_port port)204 hi_u32 pwm_check_port(hi_pwm_port port)
205 {
206     if (port >= HI_PWM_PORT_MAX) {
207         return HI_ERR_PWM_INVALID_PARAMETER;
208     }
209     return HI_ERR_SUCCESS;
210 }
211