1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <drv/pwm.h>
6 #include <aos/pwm_csi.h>
7 #include "device.h"
8 #include "objects.h"
9 #include "pinmap.h"
10 
11 #define BIT_PWM_TIM_IDX_FLAG BIT(7)
12 #define BIT_PWM_TIM_IDX_SHIFT 7
13 #define PWM_TIMER 5
14 
15 /* Table elements express the pin to PWM channel number, they are:
16  * {pinName, km0_pin2chan, km4_pin2chan}
17  */
18 const u32 csi_pin2chan[18][2] = {
19     { PA_12, 0 },
20     { PA_13, 1 },
21     { PA_23, 2 },
22     { PA_24, 3 },
23     { PA_25, 4 },
24     { PA_26, 5 },
25     { PA_28, 6 },
26     { PA_30, 7 },
27     { PB_4, 8 },
28     { PB_5, 9 },
29     { PB_18, 10 },
30     { PB_19, 11 },
31     { PB_20, 12 },
32     { PB_21, 13 },
33     { PB_22, 14 },
34     { PB_23, 15 },
35     { PB_24, 16 },
36     { PB_25, 17 } // this channel also can be PB_7
37 };
38 
39 RTIM_TypeDef *CSI_PWM_TIM[2] = { TIM5, TIMM05 };
40 
41 u8 csi_km4_ch_start[18] = { 0 };
42 
csi_pwm_init(csi_pwm_t * pwm,uint32_t idx)43 csi_error_t csi_pwm_init(csi_pwm_t *pwm, uint32_t idx)
44 {
45     if (!pwm)
46         return CSI_ERROR;
47 
48     if (idx != 0) {
49         return CSI_ERROR;
50     }
51     pwm->priv = (TIM_CCInitTypeDef *)malloc(sizeof(TIM_CCInitTypeDef));
52     pwm->dev.idx = idx << BIT_PWM_TIM_IDX_SHIFT;
53 
54     return CSI_OK;
55 }
56 
csi_pwm_uninit(csi_pwm_t * pwm)57 void csi_pwm_uninit(csi_pwm_t *pwm)
58 {
59     uint32_t pwm_chan = pwm->dev.idx & (~BIT_PWM_TIM_IDX_FLAG);
60     uint8_t pwm_tim_idx = pwm->dev.idx >> BIT_PWM_TIM_IDX_SHIFT;
61 
62     if (csi_km4_ch_start[pwm_chan]) {
63         csi_km4_ch_start[pwm_chan] = 0;
64         RTIM_CCxCmd(CSI_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
65 
66         /* stop timer5 if no pwm channels starts */
67         for (pwm_chan = 0; pwm_chan < 18; pwm_chan++) {
68             if (csi_km4_ch_start[pwm_chan]) {
69                 return;
70             }
71         }
72         RTIM_Cmd(CSI_PWM_TIM[pwm_tim_idx], DISABLE);
73     }
74 
75     if (pwm && pwm->priv) {
76         free(pwm->priv);
77         pwm->priv = NULL;
78     }
79 }
80 
csi_pwm_out_config(csi_pwm_t * pwm,uint32_t channel,uint32_t period_us,uint32_t pulse_width_us,csi_pwm_polarity_t polarity)81 csi_error_t csi_pwm_out_config(csi_pwm_t *pwm, uint32_t channel, uint32_t period_us,
82                                 uint32_t pulse_width_us, csi_pwm_polarity_t polarity)
83 {
84     uint32_t arr, tmp, ccrx;
85     uint32_t period;
86     float pulse, value, dc;
87     uint8_t pwm_tim_idx = pwm->dev.idx >> BIT_PWM_TIM_IDX_SHIFT;
88     TIM_CCInitTypeDef *TIM_CCInitStruct = (TIM_CCInitTypeDef *)pwm->priv;
89     u32 csi_prescaler = 0;
90 
91     if (channel > 18) {
92         return CSI_ERROR;
93     }
94 
95     RTIM_CCStructInit(TIM_CCInitStruct);
96     RTIM_CCxInit(CSI_PWM_TIM[pwm_tim_idx], TIM_CCInitStruct, channel);
97     RTIM_CCxCmd(CSI_PWM_TIM[pwm_tim_idx], channel, TIM_CCx_Enable);
98 
99     PinName pin = csi_pin2chan[channel][0];
100 
101     if (pwm_tim_idx) {
102         Pinmux_Config(pin, PINMUX_FUNCTION_PWM_LP);
103     } else {
104         Pinmux_Config(pin, PINMUX_FUNCTION_PWM_HS);
105     }
106     pwm->dev.idx |= channel;
107     csi_km4_ch_start[channel] = 1;
108 
109     tmp = period_us * 40 / (csi_prescaler + 1);
110     /*
111      *  psr is 8bits
112     */
113     if (tmp > 0x10000) {
114         csi_prescaler = period_us * 40 / 0x10000;
115         if (csi_prescaler > 0xff) {
116             csi_prescaler = 0xff;
117         }
118         RTIM_PrescalerConfig(CSI_PWM_TIM[pwm_tim_idx], csi_prescaler, TIM_PSCReloadMode_Update);
119     }
120     /*
121      *     arr is 16bits
122     */
123 
124     /*
125      * 40M oscilator  range:2HZ-2KHZ?
126     */
127     arr = period_us * 40 / (csi_prescaler + 1) - 1;
128     if (arr > 0xffff) {
129         arr = 0xffff;
130     }
131     RTIM_ChangePeriod(CSI_PWM_TIM[pwm_tim_idx], arr);
132 
133     ccrx = (u32)((period_us - pulse_width_us) * 40 / (csi_prescaler + 1)) & 0x0000ffff;
134     RTIM_CCRxSet(CSI_PWM_TIM[pwm_tim_idx], ccrx, channel);
135 
136     if (0 == polarity)
137         RTIM_CCxPolarityConfig(CSI_PWM_TIM[pwm_tim_idx], TIM_CCPolarity_Low, channel);
138     else
139         RTIM_CCxPolarityConfig(CSI_PWM_TIM[pwm_tim_idx], TIM_CCPolarity_High, channel);
140     return CSI_OK;
141 }
142 
csi_pwm_out_start(csi_pwm_t * pwm,uint32_t channel)143 csi_error_t csi_pwm_out_start(csi_pwm_t *pwm, uint32_t channel)
144 {
145     uint32_t pwm_chan = channel;
146     uint8_t pwm_tim_idx = pwm->dev.idx >> BIT_PWM_TIM_IDX_SHIFT;
147 
148     RTIM_CCxCmd(CSI_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Enable);
149     return CSI_OK;
150 }
151 
csi_pwm_out_stop(csi_pwm_t * pwm,uint32_t channel)152 void csi_pwm_out_stop(csi_pwm_t *pwm, uint32_t channel)
153 {
154     uint32_t pwm_chan = channel;
155     uint8_t pwm_tim_idx = pwm->dev.idx >> BIT_PWM_TIM_IDX_SHIFT;
156 
157     RTIM_CCxCmd(CSI_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
158 }
pwm_csi_init(void)159 static int pwm_csi_init(void)
160 {
161     csi_error_t ret;
162     static aos_pwm_csi_t pwm_csi_dev[CONFIG_PWM_NUM];
163     int idx = 0, i;
164     RTIM_TimeBaseInitTypeDef TIM_InitStruct;
165     RTIM_TimeBaseStructInit(&TIM_InitStruct);
166     TIM_InitStruct.TIM_Idx = PWM_TIMER;
167     RTIM_TimeBaseInit(CSI_PWM_TIM[idx], &TIM_InitStruct, TIMER5_IRQ, NULL, (u32)&TIM_InitStruct);
168     RTIM_Cmd(CSI_PWM_TIM[idx], ENABLE);
169     for (i = 0; i < CONFIG_PWM_NUM; i++) {
170         ret = csi_pwm_init(&(pwm_csi_dev[i].csi_pwm), idx);
171         pwm_csi_dev[i].csi_pwm.dev.idx |= (i) & (~BIT_PWM_TIM_IDX_FLAG);
172         if (ret != CSI_OK) {
173             return ret;
174         }
175         pwm_csi_dev[i].aos_pwm.dev.id = i;
176         ret =  aos_pwm_csi_register(&(pwm_csi_dev[i]));
177         if  (ret != CSI_OK) {
178             return ret;
179         }
180     }
181     return 0;
182 }
183 
184 LEVEL1_DRIVER_ENTRY(pwm_csi_init)
185