hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/pwm/pwm-omap-dmtimer.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2015 Neil Armstrong <narmstrong@baylibre.com>
34 * Copyright (c) 2014 Joachim Eastwood <manabian@gmail.com>
....@@ -7,13 +8,29 @@
78 *
89 * Also based on pwm-samsung.c
910 *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * version 2 as published by the Free Software Foundation.
13
- *
1411 * Description:
1512 * This file is the core OMAP support for the generic, Linux
16
- * PWM driver / controller, using the OMAP's dual-mode timers.
13
+ * PWM driver / controller, using the OMAP's dual-mode timers
14
+ * with a timer counter that goes up. When it overflows it gets
15
+ * reloaded with the load value and the pwm output goes up.
16
+ * When counter matches with match register, the output goes down.
17
+ * Reference Manual: https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
18
+ *
19
+ * Limitations:
20
+ * - When PWM is stopped, timer counter gets stopped immediately. This
21
+ * doesn't allow the current PWM period to complete and stops abruptly.
22
+ * - When PWM is running and changing both duty cycle and period,
23
+ * we cannot prevent in software that the output might produce
24
+ * a period with mixed settings. Especially when period/duty_cyle
25
+ * is updated while the pwm pin is high, current pwm period/duty_cycle
26
+ * can get updated as below based on the current timer counter:
27
+ * - period for current cycle = current_period + new period
28
+ * - duty_cycle for current period = current period + new duty_cycle.
29
+ * - PWM OMAP DM timer cannot change the polarity when pwm is active. When
30
+ * user requests a change in polarity when in active state:
31
+ * - PWM is stopped abruptly(without completing the current cycle)
32
+ * - Polarity is changed
33
+ * - A fresh cycle is started.
1734 */
1835
1936 #include <linux/clk.h>
....@@ -23,8 +40,8 @@
2340 #include <linux/mutex.h>
2441 #include <linux/of.h>
2542 #include <linux/of_platform.h>
43
+#include <clocksource/timer-ti-dm.h>
2644 #include <linux/platform_data/dmtimer-omap.h>
27
-#include <linux/platform_data/pwm_omap_dmtimer.h>
2845 #include <linux/platform_device.h>
2946 #include <linux/pm_runtime.h>
3047 #include <linux/pwm.h>
....@@ -34,10 +51,20 @@
3451 #define DM_TIMER_LOAD_MIN 0xfffffffe
3552 #define DM_TIMER_MAX 0xffffffff
3653
54
+/**
55
+ * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
56
+ * corresponding to omap dmtimer.
57
+ * @chip: PWM chip structure representing PWM controller
58
+ * @mutex: Mutex to protect pwm apply state
59
+ * @dm_timer: Pointer to omap dm timer.
60
+ * @pdata: Pointer to omap dm timer ops.
61
+ * @dm_timer_pdev: Pointer to omap dm timer platform device
62
+ */
3763 struct pwm_omap_dmtimer_chip {
3864 struct pwm_chip chip;
65
+ /* Mutex to protect pwm apply state */
3966 struct mutex mutex;
40
- pwm_omap_dmtimer *dm_timer;
67
+ struct omap_dm_timer *dm_timer;
4168 const struct omap_dm_timer_ops *pdata;
4269 struct platform_device *dm_timer_pdev;
4370 };
....@@ -48,11 +75,22 @@
4875 return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
4976 }
5077
78
+/**
79
+ * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
80
+ * @clk_rate: pwm timer clock rate
81
+ * @ns: time frame in nano seconds.
82
+ *
83
+ * Return number of clock cycles in a given period(ins ns).
84
+ */
5185 static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
5286 {
5387 return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
5488 }
5589
90
+/**
91
+ * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
92
+ * @omap: Pointer to pwm omap dm timer chip
93
+ */
5694 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
5795 {
5896 /*
....@@ -70,28 +108,46 @@
70108 omap->pdata->start(omap->dm_timer);
71109 }
72110
73
-static int pwm_omap_dmtimer_enable(struct pwm_chip *chip,
74
- struct pwm_device *pwm)
111
+/**
112
+ * pwm_omap_dmtimer_is_enabled() - Detect if the pwm is enabled.
113
+ * @omap: Pointer to pwm omap dm timer chip
114
+ *
115
+ * Return true if pwm is enabled else false.
116
+ */
117
+static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap)
75118 {
76
- struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
119
+ u32 status;
77120
78
- mutex_lock(&omap->mutex);
79
- pwm_omap_dmtimer_start(omap);
80
- mutex_unlock(&omap->mutex);
121
+ status = omap->pdata->get_pwm_status(omap->dm_timer);
81122
82
- return 0;
123
+ return !!(status & OMAP_TIMER_CTRL_ST);
83124 }
84125
85
-static void pwm_omap_dmtimer_disable(struct pwm_chip *chip,
86
- struct pwm_device *pwm)
126
+/**
127
+ * pwm_omap_dmtimer_polarity() - Detect the polarity of pwm.
128
+ * @omap: Pointer to pwm omap dm timer chip
129
+ *
130
+ * Return the polarity of pwm.
131
+ */
132
+static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap)
87133 {
88
- struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
134
+ u32 status;
89135
90
- mutex_lock(&omap->mutex);
91
- omap->pdata->stop(omap->dm_timer);
92
- mutex_unlock(&omap->mutex);
136
+ status = omap->pdata->get_pwm_status(omap->dm_timer);
137
+
138
+ return !!(status & OMAP_TIMER_CTRL_SCPWM);
93139 }
94140
141
+/**
142
+ * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer
143
+ * @chip: Pointer to PWM controller
144
+ * @pwm: Pointer to PWM channel
145
+ * @duty_ns: New duty cycle in nano seconds
146
+ * @period_ns: New period in nano seconds
147
+ *
148
+ * Return 0 if successfully changed the period/duty_cycle else appropriate
149
+ * error.
150
+ */
95151 static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
96152 struct pwm_device *pwm,
97153 int duty_ns, int period_ns)
....@@ -99,31 +155,26 @@
99155 struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
100156 u32 period_cycles, duty_cycles;
101157 u32 load_value, match_value;
102
- struct clk *fclk;
103158 unsigned long clk_rate;
104
- bool timer_active;
159
+ struct clk *fclk;
105160
106161 dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
107162 duty_ns, period_ns);
108163
109
- mutex_lock(&omap->mutex);
110164 if (duty_ns == pwm_get_duty_cycle(pwm) &&
111
- period_ns == pwm_get_period(pwm)) {
112
- /* No change - don't cause any transients. */
113
- mutex_unlock(&omap->mutex);
165
+ period_ns == pwm_get_period(pwm))
114166 return 0;
115
- }
116167
117168 fclk = omap->pdata->get_fclk(omap->dm_timer);
118169 if (!fclk) {
119170 dev_err(chip->dev, "invalid pmtimer fclk\n");
120
- goto err_einval;
171
+ return -EINVAL;
121172 }
122173
123174 clk_rate = clk_get_rate(fclk);
124175 if (!clk_rate) {
125176 dev_err(chip->dev, "invalid pmtimer fclk rate\n");
126
- goto err_einval;
177
+ return -EINVAL;
127178 }
128179
129180 dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
....@@ -151,7 +202,7 @@
151202 dev_info(chip->dev,
152203 "period %d ns too short for clock rate %lu Hz\n",
153204 period_ns, clk_rate);
154
- goto err_einval;
205
+ return -EINVAL;
155206 }
156207
157208 if (duty_cycles < 1) {
....@@ -177,79 +228,103 @@
177228 load_value = (DM_TIMER_MAX - period_cycles) + 1;
178229 match_value = load_value + duty_cycles - 1;
179230
180
- /*
181
- * We MUST stop the associated dual-mode timer before attempting to
182
- * write its registers, but calls to omap_dm_timer_start/stop must
183
- * be balanced so check if timer is active before calling timer_stop.
184
- */
185
- timer_active = pm_runtime_active(&omap->dm_timer_pdev->dev);
186
- if (timer_active)
187
- omap->pdata->stop(omap->dm_timer);
188
-
189
- omap->pdata->set_load(omap->dm_timer, true, load_value);
231
+ omap->pdata->set_load(omap->dm_timer, load_value);
190232 omap->pdata->set_match(omap->dm_timer, true, match_value);
191233
192234 dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
193235 load_value, load_value, match_value, match_value);
194236
195
- omap->pdata->set_pwm(omap->dm_timer,
196
- pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED,
197
- true,
198
- PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
199
-
200
- /* If config was called while timer was running it must be reenabled. */
201
- if (timer_active)
202
- pwm_omap_dmtimer_start(omap);
203
-
204
- mutex_unlock(&omap->mutex);
205
-
206237 return 0;
207
-
208
-err_einval:
209
- mutex_unlock(&omap->mutex);
210
-
211
- return -EINVAL;
212238 }
213239
214
-static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
215
- struct pwm_device *pwm,
216
- enum pwm_polarity polarity)
240
+/**
241
+ * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer.
242
+ * @chip: Pointer to PWM controller
243
+ * @pwm: Pointer to PWM channel
244
+ * @polarity: New pwm polarity to be set
245
+ */
246
+static void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
247
+ struct pwm_device *pwm,
248
+ enum pwm_polarity polarity)
217249 {
218250 struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
251
+ bool enabled;
219252
220
- /*
221
- * PWM core will not call set_polarity while PWM is enabled so it's
222
- * safe to reconfigure the timer here without stopping it first.
223
- */
224
- mutex_lock(&omap->mutex);
253
+ /* Disable the PWM before changing the polarity. */
254
+ enabled = pwm_omap_dmtimer_is_enabled(omap);
255
+ if (enabled)
256
+ omap->pdata->stop(omap->dm_timer);
257
+
225258 omap->pdata->set_pwm(omap->dm_timer,
226
- polarity == PWM_POLARITY_INVERSED,
227
- true,
228
- PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
259
+ polarity == PWM_POLARITY_INVERSED,
260
+ true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
261
+ true);
262
+
263
+ if (enabled)
264
+ pwm_omap_dmtimer_start(omap);
265
+}
266
+
267
+/**
268
+ * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer.
269
+ * @chip: Pointer to PWM controller
270
+ * @pwm: Pointer to PWM channel
271
+ * @state: New state to apply
272
+ *
273
+ * Return 0 if successfully changed the state else appropriate error.
274
+ */
275
+static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
276
+ struct pwm_device *pwm,
277
+ const struct pwm_state *state)
278
+{
279
+ struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
280
+ int ret = 0;
281
+
282
+ mutex_lock(&omap->mutex);
283
+
284
+ if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
285
+ omap->pdata->stop(omap->dm_timer);
286
+ goto unlock_mutex;
287
+ }
288
+
289
+ if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
290
+ pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity);
291
+
292
+ ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
293
+ state->period);
294
+ if (ret)
295
+ goto unlock_mutex;
296
+
297
+ if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
298
+ omap->pdata->set_pwm(omap->dm_timer,
299
+ state->polarity == PWM_POLARITY_INVERSED,
300
+ true,
301
+ OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
302
+ true);
303
+ pwm_omap_dmtimer_start(omap);
304
+ }
305
+
306
+unlock_mutex:
229307 mutex_unlock(&omap->mutex);
230308
231
- return 0;
309
+ return ret;
232310 }
233311
234312 static const struct pwm_ops pwm_omap_dmtimer_ops = {
235
- .enable = pwm_omap_dmtimer_enable,
236
- .disable = pwm_omap_dmtimer_disable,
237
- .config = pwm_omap_dmtimer_config,
238
- .set_polarity = pwm_omap_dmtimer_set_polarity,
313
+ .apply = pwm_omap_dmtimer_apply,
239314 .owner = THIS_MODULE,
240315 };
241316
242317 static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
243318 {
244319 struct device_node *np = pdev->dev.of_node;
245
- struct device_node *timer;
246
- struct platform_device *timer_pdev;
247
- struct pwm_omap_dmtimer_chip *omap;
248320 struct dmtimer_platform_data *timer_pdata;
249321 const struct omap_dm_timer_ops *pdata;
250
- pwm_omap_dmtimer *dm_timer;
251
- u32 v;
322
+ struct platform_device *timer_pdev;
323
+ struct pwm_omap_dmtimer_chip *omap;
324
+ struct omap_dm_timer *dm_timer;
325
+ struct device_node *timer;
252326 int ret = 0;
327
+ u32 v;
253328
254329 timer = of_parse_phandle(np, "ti,timers", 0);
255330 if (!timer)
....@@ -282,6 +357,7 @@
282357 !pdata->set_load ||
283358 !pdata->set_match ||
284359 !pdata->set_pwm ||
360
+ !pdata->get_pwm_status ||
285361 !pdata->set_prescaler ||
286362 !pdata->write_counter) {
287363 dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");