Skip to content

Commit 6b28fb6

Browse files
lokeshvutlathierryreding
authored andcommitted
pwm: omap-dmtimer: Implement .apply callback
Implement .apply callback and drop the legacy callbacks(enable, disable, config, set_polarity). In .apply() check for the current hardware status before changing the PWM configuration. Signed-off-by: Lokesh Vutla <[email protected]> Tested-by: Tony Lindgren <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent e793eef commit 6b28fb6

File tree

1 file changed

+129
-51
lines changed

1 file changed

+129
-51
lines changed

drivers/pwm/pwm-omap-dmtimer.c

Lines changed: 129 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
* can get updated as below based on the current timer counter:
2727
* - period for current cycle = current_period + new period
2828
* - 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.
2934
*/
3035

3136
#include <linux/clk.h>
@@ -46,8 +51,18 @@
4651
#define DM_TIMER_LOAD_MIN 0xfffffffe
4752
#define DM_TIMER_MAX 0xffffffff
4853

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+
*/
4963
struct pwm_omap_dmtimer_chip {
5064
struct pwm_chip chip;
65+
/* Mutex to protect pwm apply state */
5166
struct mutex mutex;
5267
struct omap_dm_timer *dm_timer;
5368
const struct omap_dm_timer_ops *pdata;
@@ -60,11 +75,22 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
6075
return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
6176
}
6277

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+
*/
6385
static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
6486
{
6587
return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
6688
}
6789

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+
*/
6894
static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
6995
{
7096
/*
@@ -82,64 +108,73 @@ static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
82108
omap->pdata->start(omap->dm_timer);
83109
}
84110

85-
static int pwm_omap_dmtimer_enable(struct pwm_chip *chip,
86-
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)
87118
{
88-
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
119+
u32 status;
89120

90-
mutex_lock(&omap->mutex);
91-
omap->pdata->set_pwm(omap->dm_timer,
92-
pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED,
93-
true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
94-
true);
95-
96-
pwm_omap_dmtimer_start(omap);
97-
mutex_unlock(&omap->mutex);
121+
status = omap->pdata->get_pwm_status(omap->dm_timer);
98122

99-
return 0;
123+
return !!(status & OMAP_TIMER_CTRL_ST);
100124
}
101125

102-
static void pwm_omap_dmtimer_disable(struct pwm_chip *chip,
103-
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)
104133
{
105-
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
134+
u32 status;
106135

107-
mutex_lock(&omap->mutex);
108-
omap->pdata->stop(omap->dm_timer);
109-
mutex_unlock(&omap->mutex);
136+
status = omap->pdata->get_pwm_status(omap->dm_timer);
137+
138+
return !!(status & OMAP_TIMER_CTRL_SCPWM);
110139
}
111140

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+
*/
112151
static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
113152
struct pwm_device *pwm,
114153
int duty_ns, int period_ns)
115154
{
116155
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
117156
u32 period_cycles, duty_cycles;
118157
u32 load_value, match_value;
119-
struct clk *fclk;
120158
unsigned long clk_rate;
159+
struct clk *fclk;
121160

122161
dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
123162
duty_ns, period_ns);
124163

125-
mutex_lock(&omap->mutex);
126164
if (duty_ns == pwm_get_duty_cycle(pwm) &&
127-
period_ns == pwm_get_period(pwm)) {
128-
/* No change - don't cause any transients. */
129-
mutex_unlock(&omap->mutex);
165+
period_ns == pwm_get_period(pwm))
130166
return 0;
131-
}
132167

133168
fclk = omap->pdata->get_fclk(omap->dm_timer);
134169
if (!fclk) {
135170
dev_err(chip->dev, "invalid pmtimer fclk\n");
136-
goto err_einval;
171+
return -EINVAL;
137172
}
138173

139174
clk_rate = clk_get_rate(fclk);
140175
if (!clk_rate) {
141176
dev_err(chip->dev, "invalid pmtimer fclk rate\n");
142-
goto err_einval;
177+
return -EINVAL;
143178
}
144179

145180
dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
@@ -167,7 +202,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
167202
dev_info(chip->dev,
168203
"period %d ns too short for clock rate %lu Hz\n",
169204
period_ns, clk_rate);
170-
goto err_einval;
205+
return -EINVAL;
171206
}
172207

173208
if (duty_cycles < 1) {
@@ -199,55 +234,97 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
199234
dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
200235
load_value, load_value, match_value, match_value);
201236

202-
mutex_unlock(&omap->mutex);
203-
204237
return 0;
205-
206-
err_einval:
207-
mutex_unlock(&omap->mutex);
208-
209-
return -EINVAL;
210238
}
211239

212-
static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
213-
struct pwm_device *pwm,
214-
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)
215249
{
216250
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
251+
bool enabled;
252+
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);
217257

218-
/*
219-
* PWM core will not call set_polarity while PWM is enabled so it's
220-
* safe to reconfigure the timer here without stopping it first.
221-
*/
222-
mutex_lock(&omap->mutex);
223258
omap->pdata->set_pwm(omap->dm_timer,
224259
polarity == PWM_POLARITY_INVERSED,
225260
true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
226261
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:
227307
mutex_unlock(&omap->mutex);
228308

229-
return 0;
309+
return ret;
230310
}
231311

232312
static const struct pwm_ops pwm_omap_dmtimer_ops = {
233-
.enable = pwm_omap_dmtimer_enable,
234-
.disable = pwm_omap_dmtimer_disable,
235-
.config = pwm_omap_dmtimer_config,
236-
.set_polarity = pwm_omap_dmtimer_set_polarity,
313+
.apply = pwm_omap_dmtimer_apply,
237314
.owner = THIS_MODULE,
238315
};
239316

240317
static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
241318
{
242319
struct device_node *np = pdev->dev.of_node;
243-
struct device_node *timer;
244-
struct platform_device *timer_pdev;
245-
struct pwm_omap_dmtimer_chip *omap;
246320
struct dmtimer_platform_data *timer_pdata;
247321
const struct omap_dm_timer_ops *pdata;
322+
struct platform_device *timer_pdev;
323+
struct pwm_omap_dmtimer_chip *omap;
248324
struct omap_dm_timer *dm_timer;
249-
u32 v;
325+
struct device_node *timer;
250326
int ret = 0;
327+
u32 v;
251328

252329
timer = of_parse_phandle(np, "ti,timers", 0);
253330
if (!timer)
@@ -280,6 +357,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
280357
!pdata->set_load ||
281358
!pdata->set_match ||
282359
!pdata->set_pwm ||
360+
!pdata->get_pwm_status ||
283361
!pdata->set_prescaler ||
284362
!pdata->write_counter) {
285363
dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");

0 commit comments

Comments
 (0)