• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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