1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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 "stm32mp1_pwm.h"
17
18 #define HDF_LOG_TAG stm32mp1_pwm
19
20 struct Mp1xxPwm {
21 struct PwmDev dev;
22 TIM_HandleTypeDef stm32mp1;
23 volatile uint32_t *base;
24 struct Mp1xxPwmRegs *reg;
25 uint32_t pwmIomux[2];
26 };
27
GPIORemp(uint32_t port)28 static GPIO_TypeDef *GPIORemp(uint32_t port)
29 {
30 if (port > GPIO_Z) {
31 HDF_LOGE("%s: gpio remp stm32mp1 fail!", __func__);
32 return 0;
33 }
34 switch (port) {
35 case GPIO_A:
36 return OsalIoRemap(GPIOA_BASE, 0x400);
37 break;
38 case GPIO_B:
39 return OsalIoRemap(GPIOB_BASE, 0x400);
40 break;
41 case GPIO_C:
42 return OsalIoRemap(GPIOC_BASE, 0x400);
43 break;
44 case GPIO_D:
45 return OsalIoRemap(GPIOD_BASE, 0x400);
46 break;
47 case GPIO_E:
48 return OsalIoRemap(GPIOE_BASE, 0x400);
49 break;
50 case GPIO_F:
51 return OsalIoRemap(GPIOF_BASE, 0x400);
52 break;
53 case GPIO_G:
54 return OsalIoRemap(GPIOG_BASE, 0x400);
55 break;
56 case GPIO_H:
57 return OsalIoRemap(GPIOH_BASE, 0x400);
58 break;
59 case GPIO_I:
60 return OsalIoRemap(GPIOI_BASE, 0x400);
61 break;
62 case GPIO_J:
63 return OsalIoRemap(GPIOJ_BASE, 0x400);
64 break;
65 case GPIO_K:
66 return OsalIoRemap(GPIOK_BASE, 0x400);
67 break;
68 case GPIO_Z:
69 return OsalIoRemap(GPIOZ_BASE, 0x400);
70 break;
71
72 default:
73 break;
74 }
75 return 0;
76 }
77
Mp1xxPwmGpioSet(struct Mp1xxPwm * stm32mp1)78 static void Mp1xxPwmGpioSet(struct Mp1xxPwm *stm32mp1)
79 {
80 GPIO_InitTypeDef GPIO_Init = { 0 };
81 /* init gpio */
82 GPIO_Init.Mode = GPIO_MODE_AF_OD;
83 GPIO_Init.Pull = GPIO_PULLUP;
84 GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
85 GPIO_Init.Alternate = GPIO_AF2_TIM3;
86 GPIO_Init.Pin = 1 << stm32mp1->pwmIomux[1];
87 HAL_GPIO_Init(GPIORemp(stm32mp1->pwmIomux[0]), &GPIO_Init);
88 }
89
Mp1xxPwmRccConfig(uint32_t num)90 static void Mp1xxPwmRccConfig(uint32_t num)
91 {
92 RCC_PeriphCLKInitTypeDef TIMx_clock_source_config;
93 switch (num) {
94 case TIM_1:
95 __HAL_RCC_TIM1_CLK_ENABLE();
96 TIMx_clock_source_config.TIMG2PresSelection = RCC_TIMG2PRES_ACTIVATED;
97 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG2;
98 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
99 break;
100
101 case TIM_2:
102 __HAL_RCC_TIM2_CLK_ENABLE();
103 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
104 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
105 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
106 break;
107
108 case TIM_3:
109 __HAL_RCC_TIM3_CLK_ENABLE();
110 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
111 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
112 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
113 break;
114
115 case TIM_4:
116 __HAL_RCC_TIM4_CLK_ENABLE();
117 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
118 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
119 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
120 break;
121
122 case TIM_5:
123 __HAL_RCC_TIM5_CLK_ENABLE();
124 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
125 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
126 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
127 break;
128
129 case TIM_8:
130 __HAL_RCC_TIM8_CLK_ENABLE();
131 TIMx_clock_source_config.TIMG2PresSelection = RCC_TIMG2PRES_ACTIVATED;
132 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG2;
133 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
134 break;
135
136 case TIM_12:
137 __HAL_RCC_TIM12_CLK_ENABLE();
138 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
139 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
140 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
141 break;
142
143 case TIM_13:
144 __HAL_RCC_TIM13_CLK_ENABLE();
145 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
146 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
147 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
148 break;
149
150 case TIM_14:
151 __HAL_RCC_TIM14_CLK_ENABLE();
152 TIMx_clock_source_config.TIMG1PresSelection = RCC_TIMG1PRES_ACTIVATED;
153 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG1;
154 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
155 break;
156
157 case TIM_15:
158 __HAL_RCC_TIM15_CLK_ENABLE();
159 TIMx_clock_source_config.TIMG2PresSelection = RCC_TIMG2PRES_ACTIVATED;
160 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG2;
161 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
162 break;
163
164 case TIM_16:
165 __HAL_RCC_TIM16_CLK_ENABLE();
166 TIMx_clock_source_config.TIMG2PresSelection = RCC_TIMG2PRES_ACTIVATED;
167 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG2;
168 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
169 break;
170
171 case TIM_17:
172 __HAL_RCC_TIM17_CLK_ENABLE();
173 TIMx_clock_source_config.TIMG2PresSelection = RCC_TIMG2PRES_ACTIVATED;
174 TIMx_clock_source_config.PeriphClockSelection = RCC_PERIPHCLK_TIMG2;
175 HAL_RCCEx_PeriphCLKConfig(&TIMx_clock_source_config);
176 break;
177
178 default:
179 break;
180 }
181 }
182
HdfPwmSetConfig(struct PwmDev * pwm,struct PwmConfig * config)183 int32_t HdfPwmSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
184 {
185 struct Mp1xxPwm *stm32mp1 = (struct Mp1xxPwm *)pwm;
186 stm32mp1->reg->CR1 &= ~1; /* Counter disabled */
187 stm32mp1->reg->CR1 |= (1 << 7); /* Auto-reload preload enable, TIMx_ARR register is buffered */
188 stm32mp1->reg->CR1 |= (1 << 3); /* Counter stops counting at the next update event (clearing the bit CEN) */
189 stm32mp1->reg->CCMR2 |= (6 << 4); /* Output compare 3 mode, PWM mode 1 */
190 stm32mp1->reg->CCMR2 |= (1 << 3); /* Output compare 3 preload enable */
191 stm32mp1->reg->CCER |= (1 << 8); /* OC3 signal is output on the corresponding output pin */
192 stm32mp1->reg->CCER &= ~(1 << 9); /* output Polarity */
193 stm32mp1->reg->CCER |= ((config->polarity) << 9);
194 stm32mp1->reg->PSC = PWM_DEFAULT_PSC; /* prescaler 209, fre = 1MHz */
195 stm32mp1->reg->ARR = (config->period / PWM_DEFAULT_TICK) == 0 ? 0 : (config->period / PWM_DEFAULT_TICK - 1); /* period */
196 stm32mp1->reg->CCR3 = (config->duty / PWM_DEFAULT_TICK) == 0 ? 0 : (config->duty / PWM_DEFAULT_TICK - 1); /* duty */
197 stm32mp1->reg->CR1 |= config->status; /* disable/enable */
198 return HDF_SUCCESS;
199 }
200
HdfPwmOpen(struct PwmDev * pwm)201 int32_t HdfPwmOpen(struct PwmDev *pwm)
202 {
203 (void)pwm;
204 return HDF_SUCCESS;
205 }
206
HdfPwmClose(struct PwmDev * pwm)207 int32_t HdfPwmClose(struct PwmDev *pwm)
208 {
209 (void)pwm;
210 return HDF_SUCCESS;
211 }
212
213 struct PwmMethod g_pwmOps = {
214 .setConfig = HdfPwmSetConfig,
215 .open = HdfPwmOpen,
216 .close = HdfPwmClose
217 };
218
Mp1xxPwmPwmProbe(struct Mp1xxPwm * stm32mp1,struct HdfDeviceObject * obj)219 static int32_t Mp1xxPwmPwmProbe(struct Mp1xxPwm *stm32mp1, struct HdfDeviceObject *obj)
220 {
221 uint32_t tmp;
222 struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
223 if (iface == NULL || iface->GetUint32 == NULL || iface->GetUint32Array == NULL) {
224 HDF_LOGE("%s: face is invalid", __func__);
225 return HDF_FAILURE;
226 }
227
228 if (iface->GetUint32(obj->property, "num", &(stm32mp1->dev.num), 0) != HDF_SUCCESS) {
229 HDF_LOGE("%s: read num fail", __func__);
230 return HDF_FAILURE;
231 }
232
233 if (iface->GetUint32(obj->property, "base", &tmp, 0) != HDF_SUCCESS) {
234 HDF_LOGE("%s: read base fail", __func__);
235 return HDF_FAILURE;
236 }
237
238 if (iface->GetUint32Array(obj->property, "pwmIomux", stm32mp1->pwmIomux, 2, 0) != HDF_SUCCESS) {
239 HDF_LOGE("%s: read pwmIomux fail", __func__);
240 return HDF_FAILURE;
241 }
242
243 stm32mp1->base = OsalIoRemap(tmp, sizeof(struct Mp1xxPwmRegs));
244 if (stm32mp1->base == NULL) {
245 HDF_LOGE("%s: OsalIoRemap fail", __func__);
246 return HDF_FAILURE;
247 }
248
249 Mp1xxPwmRccConfig(stm32mp1->dev.num);
250 Mp1xxPwmGpioSet(stm32mp1);
251
252 stm32mp1->reg = (struct Mp1xxPwmRegs *)stm32mp1->base;
253 stm32mp1->dev.method = &g_pwmOps;
254 stm32mp1->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE;
255 stm32mp1->dev.cfg.period = PWM_DEFAULT_PERIOD;
256 stm32mp1->dev.cfg.polarity = PWM_NORMAL_POLARITY;
257 stm32mp1->dev.cfg.status = PWM_DISABLE_STATUS;
258 stm32mp1->dev.cfg.number = 0;
259 stm32mp1->dev.busy = false;
260
261 if (PwmDeviceAdd(obj, &(stm32mp1->dev)) != HDF_SUCCESS) {
262 OsalIoUnmap((void *)stm32mp1->base);
263 HDF_LOGE("%s: [PwmDeviceAdd] failed.", __func__);
264 return HDF_FAILURE;
265 }
266 HDF_LOGI("%s: success.", __func__);
267 return HDF_SUCCESS;
268 }
269
HdfPwmBind(struct HdfDeviceObject * obj)270 static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
271 {
272 (void)obj;
273 return HDF_SUCCESS;
274 }
275
HdfPwmInit(struct HdfDeviceObject * obj)276 static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
277 {
278 int ret;
279 struct Mp1xxPwm *stm32mp1 = NULL;
280
281 HDF_LOGI("%s: entry", __func__);
282 if (obj == NULL) {
283 HDF_LOGE("%s: obj is null", __func__);
284 return HDF_ERR_INVALID_OBJECT;
285 }
286 stm32mp1 = (struct Mp1xxPwm *)OsalMemCalloc(sizeof(*stm32mp1));
287 if (stm32mp1 == NULL) {
288 HDF_LOGE("%s: OsalMemCalloc stm32mp1 error", __func__);
289 return HDF_ERR_MALLOC_FAIL;
290 }
291
292 ret = Mp1xxPwmPwmProbe(stm32mp1, obj);
293 if (ret != HDF_SUCCESS) {
294 HDF_LOGE("%s: error probe, ret is %d", __func__, ret);
295 OsalMemFree(stm32mp1);
296 }
297 return ret;
298 }
299
HdfPwmRelease(struct HdfDeviceObject * obj)300 static void HdfPwmRelease(struct HdfDeviceObject *obj)
301 {
302 struct PwmDev *pwm = NULL;
303
304 HDF_LOGI("%s: entry", __func__);
305 if (obj == NULL) {
306 HDF_LOGE("%s: obj is null", __func__);
307 return;
308 }
309 pwm = (struct PwmDev *)obj->service;
310 if (pwm == NULL) {
311 HDF_LOGE("%s: pwm is null", __func__);
312 return;
313 }
314 PwmDeviceRemove(obj, pwm);
315 OsalMemFree(pwm);
316 }
317
318 struct HdfDriverEntry g_hdfPwm = {
319 .moduleVersion = 1,
320 .moduleName = "HDF_PLATFORM_PWM",
321 .Bind = HdfPwmBind,
322 .Init = HdfPwmInit,
323 .Release = HdfPwmRelease,
324 };
325
326 HDF_INIT(g_hdfPwm);
327