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