diff options
Diffstat (limited to 'drivers/pwm/pwm-stm32.c')
-rw-r--r-- | drivers/pwm/pwm-stm32.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 2708212933f7..ed3961b7b938 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c | |||
@@ -25,6 +25,7 @@ struct stm32_pwm { | |||
25 | struct regmap *regmap; | 25 | struct regmap *regmap; |
26 | u32 max_arr; | 26 | u32 max_arr; |
27 | bool have_complementary_output; | 27 | bool have_complementary_output; |
28 | u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */ | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct stm32_breakinput { | 31 | struct stm32_breakinput { |
@@ -62,6 +63,178 @@ static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value) | |||
62 | return -EINVAL; | 63 | return -EINVAL; |
63 | } | 64 | } |
64 | 65 | ||
66 | #define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P) | ||
67 | #define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E) | ||
68 | #define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P) | ||
69 | #define TIM_CCER_CC34E (TIM_CCER_CC3E | TIM_CCER_CC4E) | ||
70 | |||
71 | /* | ||
72 | * Capture using PWM input mode: | ||
73 | * ___ ___ | ||
74 | * TI[1, 2, 3 or 4]: ........._| |________| | ||
75 | * ^0 ^1 ^2 | ||
76 | * . . . | ||
77 | * . . XXXXX | ||
78 | * . . XXXXX | | ||
79 | * . XXXXX . | | ||
80 | * XXXXX . . | | ||
81 | * COUNTER: ______XXXXX . . . |_XXX | ||
82 | * start^ . . . ^stop | ||
83 | * . . . . | ||
84 | * v v . v | ||
85 | * v | ||
86 | * CCR1/CCR3: tx..........t0...........t2 | ||
87 | * CCR2/CCR4: tx..............t1......... | ||
88 | * | ||
89 | * DMA burst transfer: | | | ||
90 | * v v | ||
91 | * DMA buffer: { t0, tx } { t2, t1 } | ||
92 | * DMA done: ^ | ||
93 | * | ||
94 | * 0: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3 | ||
95 | * + DMA transfer CCR[1/3] & CCR[2/4] values (t0, tx: doesn't care) | ||
96 | * 1: IC2/4 snapchot on falling edge: counter value -> CCR2/CCR4 | ||
97 | * 2: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3 | ||
98 | * + DMA transfer CCR[1/3] & CCR[2/4] values (t2, t1) | ||
99 | * | ||
100 | * DMA done, compute: | ||
101 | * - Period = t2 - t0 | ||
102 | * - Duty cycle = t1 - t0 | ||
103 | */ | ||
104 | static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, | ||
105 | unsigned long tmo_ms, u32 *raw_prd, | ||
106 | u32 *raw_dty) | ||
107 | { | ||
108 | struct device *parent = priv->chip.dev->parent; | ||
109 | enum stm32_timers_dmas dma_id; | ||
110 | u32 ccen, ccr; | ||
111 | int ret; | ||
112 | |||
113 | /* Ensure registers have been updated, enable counter and capture */ | ||
114 | regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); | ||
115 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); | ||
116 | |||
117 | /* Use cc1 or cc3 DMA resp for PWM input channels 1 & 2 or 3 & 4 */ | ||
118 | dma_id = pwm->hwpwm < 2 ? STM32_TIMERS_DMA_CH1 : STM32_TIMERS_DMA_CH3; | ||
119 | ccen = pwm->hwpwm < 2 ? TIM_CCER_CC12E : TIM_CCER_CC34E; | ||
120 | ccr = pwm->hwpwm < 2 ? TIM_CCR1 : TIM_CCR3; | ||
121 | regmap_update_bits(priv->regmap, TIM_CCER, ccen, ccen); | ||
122 | |||
123 | /* | ||
124 | * Timer DMA burst mode. Request 2 registers, 2 bursts, to get both | ||
125 | * CCR1 & CCR2 (or CCR3 & CCR4) on each capture event. | ||
126 | * We'll get two capture snapchots: { CCR1, CCR2 }, { CCR1, CCR2 } | ||
127 | * or { CCR3, CCR4 }, { CCR3, CCR4 } | ||
128 | */ | ||
129 | ret = stm32_timers_dma_burst_read(parent, priv->capture, dma_id, ccr, 2, | ||
130 | 2, tmo_ms); | ||
131 | if (ret) | ||
132 | goto stop; | ||
133 | |||
134 | /* Period: t2 - t0 (take care of counter overflow) */ | ||
135 | if (priv->capture[0] <= priv->capture[2]) | ||
136 | *raw_prd = priv->capture[2] - priv->capture[0]; | ||
137 | else | ||
138 | *raw_prd = priv->max_arr - priv->capture[0] + priv->capture[2]; | ||
139 | |||
140 | /* Duty cycle capture requires at least two capture units */ | ||
141 | if (pwm->chip->npwm < 2) | ||
142 | *raw_dty = 0; | ||
143 | else if (priv->capture[0] <= priv->capture[3]) | ||
144 | *raw_dty = priv->capture[3] - priv->capture[0]; | ||
145 | else | ||
146 | *raw_dty = priv->max_arr - priv->capture[0] + priv->capture[3]; | ||
147 | |||
148 | if (*raw_dty > *raw_prd) { | ||
149 | /* | ||
150 | * Race beetween PWM input and DMA: it may happen | ||
151 | * falling edge triggers new capture on TI2/4 before DMA | ||
152 | * had a chance to read CCR2/4. It means capture[1] | ||
153 | * contains period + duty_cycle. So, subtract period. | ||
154 | */ | ||
155 | *raw_dty -= *raw_prd; | ||
156 | } | ||
157 | |||
158 | stop: | ||
159 | regmap_update_bits(priv->regmap, TIM_CCER, ccen, 0); | ||
160 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, | ||
166 | struct pwm_capture *result, unsigned long tmo_ms) | ||
167 | { | ||
168 | struct stm32_pwm *priv = to_stm32_pwm_dev(chip); | ||
169 | unsigned long long prd, div, dty; | ||
170 | unsigned long rate; | ||
171 | unsigned int psc = 0; | ||
172 | u32 raw_prd, raw_dty; | ||
173 | int ret = 0; | ||
174 | |||
175 | mutex_lock(&priv->lock); | ||
176 | |||
177 | if (active_channels(priv)) { | ||
178 | ret = -EBUSY; | ||
179 | goto unlock; | ||
180 | } | ||
181 | |||
182 | ret = clk_enable(priv->clk); | ||
183 | if (ret) { | ||
184 | dev_err(priv->chip.dev, "failed to enable counter clock\n"); | ||
185 | goto unlock; | ||
186 | } | ||
187 | |||
188 | rate = clk_get_rate(priv->clk); | ||
189 | if (!rate) { | ||
190 | ret = -EINVAL; | ||
191 | goto clk_dis; | ||
192 | } | ||
193 | |||
194 | /* prescaler: fit timeout window provided by upper layer */ | ||
195 | div = (unsigned long long)rate * (unsigned long long)tmo_ms; | ||
196 | do_div(div, MSEC_PER_SEC); | ||
197 | prd = div; | ||
198 | while ((div > priv->max_arr) && (psc < MAX_TIM_PSC)) { | ||
199 | psc++; | ||
200 | div = prd; | ||
201 | do_div(div, psc + 1); | ||
202 | } | ||
203 | regmap_write(priv->regmap, TIM_ARR, priv->max_arr); | ||
204 | regmap_write(priv->regmap, TIM_PSC, psc); | ||
205 | |||
206 | /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ | ||
207 | regmap_update_bits(priv->regmap, | ||
208 | pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, | ||
209 | TIM_CCMR_CC1S | TIM_CCMR_CC2S, pwm->hwpwm & 0x1 ? | ||
210 | TIM_CCMR_CC1S_TI2 | TIM_CCMR_CC2S_TI2 : | ||
211 | TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC2S_TI1); | ||
212 | |||
213 | /* Capture period on IC1/3 rising edge, duty cycle on IC2/4 falling. */ | ||
214 | regmap_update_bits(priv->regmap, TIM_CCER, pwm->hwpwm < 2 ? | ||
215 | TIM_CCER_CC12P : TIM_CCER_CC34P, pwm->hwpwm < 2 ? | ||
216 | TIM_CCER_CC2P : TIM_CCER_CC4P); | ||
217 | |||
218 | ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty); | ||
219 | if (ret) | ||
220 | goto stop; | ||
221 | |||
222 | prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC; | ||
223 | result->period = DIV_ROUND_UP_ULL(prd, rate); | ||
224 | dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC; | ||
225 | result->duty_cycle = DIV_ROUND_UP_ULL(dty, rate); | ||
226 | stop: | ||
227 | regmap_write(priv->regmap, TIM_CCER, 0); | ||
228 | regmap_write(priv->regmap, pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, 0); | ||
229 | regmap_write(priv->regmap, TIM_PSC, 0); | ||
230 | clk_dis: | ||
231 | clk_disable(priv->clk); | ||
232 | unlock: | ||
233 | mutex_unlock(&priv->lock); | ||
234 | |||
235 | return ret; | ||
236 | } | ||
237 | |||
65 | static int stm32_pwm_config(struct stm32_pwm *priv, int ch, | 238 | static int stm32_pwm_config(struct stm32_pwm *priv, int ch, |
66 | int duty_ns, int period_ns) | 239 | int duty_ns, int period_ns) |
67 | { | 240 | { |
@@ -230,6 +403,9 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm, | |||
230 | static const struct pwm_ops stm32pwm_ops = { | 403 | static const struct pwm_ops stm32pwm_ops = { |
231 | .owner = THIS_MODULE, | 404 | .owner = THIS_MODULE, |
232 | .apply = stm32_pwm_apply_locked, | 405 | .apply = stm32_pwm_apply_locked, |
406 | #if IS_ENABLED(CONFIG_DMA_ENGINE) | ||
407 | .capture = stm32_pwm_capture, | ||
408 | #endif | ||
233 | }; | 409 | }; |
234 | 410 | ||
235 | static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, | 411 | static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, |