Skip to content

Commit 329db10

Browse files
hkallweitthierryreding
authored andcommitted
pwm: meson: make full use of common clock framework
Newer versions of the PWM block use a core clock with external mux, divider, and gate. These components either don't exist any longer in the PWM block, or they are bypassed. To minimize needed changes for supporting the new version, the internal divider and gate should be handled by CCF too. I didn't see a good way to split the patch, therefore it's somewhat bigger. What it does: - The internal mux is handled by CCF already. Register also internal divider and gate with CCF, so that we have one representation of the input clock: [mux] parent of [divider] parent of [gate] - Now that CCF selects an appropriate mux parent, we don't need the DT-provided default parent any longer. Accordingly we can also omit setting the mux parent directly in the driver. - Instead of manually handling the pre-div divider value, let CCF set the input clock. Targeted input clock frequency is 0xffff * 1/period for best precision. - For the "inverted pwm disabled" scenario target an input clock frequency of ULONG_MAX. This ensures that the remaining low pulses have minimum length. I don't have hw with the old PWM block, therefore I couldn't test this patch. With the not yet included extension for the new PWM block (channel->clk coming directly from get_clk(external_clk)) I didn't notice any problem. My system uses PWM for the CPU voltage regulator and for the SDIO 32kHz clock. Note: The clock gate in the old PWM block is permanently disabled. This seems to indicate that it's not used by the new PWM block. Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
1 parent 3bddf73 commit 329db10

1 file changed

Lines changed: 90 additions & 68 deletions

File tree

drivers/pwm/pwm-meson.c

Lines changed: 90 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
#define PWM_HIGH_MASK GENMASK(31, 16)
5050

5151
#define REG_MISC_AB 0x8
52-
#define MISC_B_CLK_EN BIT(23)
53-
#define MISC_A_CLK_EN BIT(15)
54-
#define MISC_CLK_DIV_MASK 0x7f
52+
#define MISC_B_CLK_EN_SHIFT 23
53+
#define MISC_A_CLK_EN_SHIFT 15
54+
#define MISC_CLK_DIV_WIDTH 7
5555
#define MISC_B_CLK_DIV_SHIFT 16
5656
#define MISC_A_CLK_DIV_SHIFT 8
5757
#define MISC_B_CLK_SEL_SHIFT 6
@@ -67,32 +67,33 @@ static struct meson_pwm_channel_data {
6767
u8 reg_offset;
6868
u8 clk_sel_shift;
6969
u8 clk_div_shift;
70-
u32 clk_en_mask;
70+
u8 clk_en_shift;
7171
u32 pwm_en_mask;
7272
} meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
7373
{
7474
.reg_offset = REG_PWM_A,
7575
.clk_sel_shift = MISC_A_CLK_SEL_SHIFT,
7676
.clk_div_shift = MISC_A_CLK_DIV_SHIFT,
77-
.clk_en_mask = MISC_A_CLK_EN,
77+
.clk_en_shift = MISC_A_CLK_EN_SHIFT,
7878
.pwm_en_mask = MISC_A_EN,
7979
},
8080
{
8181
.reg_offset = REG_PWM_B,
8282
.clk_sel_shift = MISC_B_CLK_SEL_SHIFT,
8383
.clk_div_shift = MISC_B_CLK_DIV_SHIFT,
84-
.clk_en_mask = MISC_B_CLK_EN,
84+
.clk_en_shift = MISC_B_CLK_EN_SHIFT,
8585
.pwm_en_mask = MISC_B_EN,
8686
}
8787
};
8888

8989
struct meson_pwm_channel {
90+
unsigned long rate;
9091
unsigned int hi;
9192
unsigned int lo;
92-
u8 pre_div;
9393

94-
struct clk *clk_parent;
9594
struct clk_mux mux;
95+
struct clk_divider div;
96+
struct clk_gate gate;
9697
struct clk *clk;
9798
};
9899

@@ -125,16 +126,6 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
125126
struct device *dev = chip->dev;
126127
int err;
127128

128-
if (channel->clk_parent) {
129-
err = clk_set_parent(channel->clk, channel->clk_parent);
130-
if (err < 0) {
131-
dev_err(dev, "failed to set parent %s for %s: %d\n",
132-
__clk_get_name(channel->clk_parent),
133-
__clk_get_name(channel->clk), err);
134-
return err;
135-
}
136-
}
137-
138129
err = clk_prepare_enable(channel->clk);
139130
if (err < 0) {
140131
dev_err(dev, "failed to enable clock %s: %d\n",
@@ -157,9 +148,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
157148
const struct pwm_state *state)
158149
{
159150
struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
160-
unsigned int pre_div, cnt, duty_cnt;
151+
unsigned int cnt, duty_cnt;
161152
unsigned long fin_freq;
162-
u64 duty, period;
153+
u64 duty, period, freq;
163154

164155
duty = state->duty_cycle;
165156
period = state->period;
@@ -173,48 +164,43 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
173164
if (state->polarity == PWM_POLARITY_INVERSED)
174165
duty = period - duty;
175166

176-
fin_freq = clk_get_rate(channel->clk);
167+
freq = div64_u64(NSEC_PER_SEC * 0xffffULL, period);
168+
if (freq > ULONG_MAX)
169+
freq = ULONG_MAX;
170+
171+
fin_freq = clk_round_rate(channel->clk, freq);
177172
if (fin_freq == 0) {
178173
dev_err(meson->chip.dev, "invalid source clock frequency\n");
179174
return -EINVAL;
180175
}
181176

182177
dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
183178

184-
pre_div = div64_u64(fin_freq * period, NSEC_PER_SEC * 0xffffLL);
185-
if (pre_div > MISC_CLK_DIV_MASK) {
186-
dev_err(meson->chip.dev, "unable to get period pre_div\n");
187-
return -EINVAL;
188-
}
189-
190-
cnt = div64_u64(fin_freq * period, NSEC_PER_SEC * (pre_div + 1));
179+
cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
191180
if (cnt > 0xffff) {
192181
dev_err(meson->chip.dev, "unable to get period cnt\n");
193182
return -EINVAL;
194183
}
195184

196-
dev_dbg(meson->chip.dev, "period=%llu pre_div=%u cnt=%u\n", period,
197-
pre_div, cnt);
185+
dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt);
198186

199187
if (duty == period) {
200-
channel->pre_div = pre_div;
201188
channel->hi = cnt;
202189
channel->lo = 0;
203190
} else if (duty == 0) {
204-
channel->pre_div = pre_div;
205191
channel->hi = 0;
206192
channel->lo = cnt;
207193
} else {
208-
duty_cnt = div64_u64(fin_freq * duty, NSEC_PER_SEC * (pre_div + 1));
194+
duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
209195

210-
dev_dbg(meson->chip.dev, "duty=%llu pre_div=%u duty_cnt=%u\n",
211-
duty, pre_div, duty_cnt);
196+
dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
212197

213-
channel->pre_div = pre_div;
214198
channel->hi = duty_cnt;
215199
channel->lo = cnt - duty_cnt;
216200
}
217201

202+
channel->rate = fin_freq;
203+
218204
return 0;
219205
}
220206

@@ -224,16 +210,15 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
224210
struct meson_pwm_channel_data *channel_data;
225211
unsigned long flags;
226212
u32 value;
213+
int err;
227214

228215
channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
229216

230-
spin_lock_irqsave(&meson->lock, flags);
217+
err = clk_set_rate(channel->clk, channel->rate);
218+
if (err)
219+
dev_err(meson->chip.dev, "setting clock rate failed\n");
231220

232-
value = readl(meson->base + REG_MISC_AB);
233-
value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift);
234-
value |= channel->pre_div << channel_data->clk_div_shift;
235-
value |= channel_data->clk_en_mask;
236-
writel(value, meson->base + REG_MISC_AB);
221+
spin_lock_irqsave(&meson->lock, flags);
237222

238223
value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) |
239224
FIELD_PREP(PWM_LOW_MASK, channel->lo);
@@ -272,16 +257,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
272257
/*
273258
* This IP block revision doesn't have an "always high"
274259
* setting which we can use for "inverted disabled".
275-
* Instead we achieve this using the same settings
276-
* that we use a pre_div of 0 (to get the shortest
277-
* possible duration for one "count") and
278-
* "period == duty_cycle". This results in a signal
260+
* Instead we achieve this by setting mux parent with
261+
* highest rate and minimum divider value, resulting
262+
* in the shortest possible duration for one "count"
263+
* and "period == duty_cycle". This results in a signal
279264
* which is LOW for one "count", while being HIGH for
280265
* the rest of the (so the signal is HIGH for slightly
281266
* less than 100% of the period, but this is the best
282267
* we can achieve).
283268
*/
284-
channel->pre_div = 0;
269+
channel->rate = ULONG_MAX;
285270
channel->hi = ~0;
286271
channel->lo = 0;
287272

@@ -300,13 +285,12 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
300285
return 0;
301286
}
302287

303-
static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip,
304-
struct pwm_device *pwm, u32 cnt)
288+
static u64 meson_pwm_cnt_to_ns(struct pwm_chip *chip, struct pwm_device *pwm,
289+
u32 cnt)
305290
{
306291
struct meson_pwm *meson = to_meson_pwm(chip);
307292
struct meson_pwm_channel *channel;
308293
unsigned long fin_freq;
309-
u32 fin_ns;
310294

311295
/* to_meson_pwm() can only be used after .get_state() is called */
312296
channel = &meson->channels[pwm->hwpwm];
@@ -315,9 +299,7 @@ static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip,
315299
if (fin_freq == 0)
316300
return 0;
317301

318-
fin_ns = div_u64(NSEC_PER_SEC, fin_freq);
319-
320-
return cnt * fin_ns * (channel->pre_div + 1);
302+
return div64_ul(NSEC_PER_SEC * (u64)cnt, fin_freq);
321303
}
322304

323305
static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -326,7 +308,7 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
326308
struct meson_pwm *meson = to_meson_pwm(chip);
327309
struct meson_pwm_channel_data *channel_data;
328310
struct meson_pwm_channel *channel;
329-
u32 value, tmp;
311+
u32 value;
330312

331313
if (!state)
332314
return 0;
@@ -335,15 +317,9 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
335317
channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
336318

337319
value = readl(meson->base + REG_MISC_AB);
338-
339-
tmp = channel_data->pwm_en_mask | channel_data->clk_en_mask;
340-
state->enabled = (value & tmp) == tmp;
341-
342-
tmp = value >> channel_data->clk_div_shift;
343-
channel->pre_div = FIELD_GET(MISC_CLK_DIV_MASK, tmp);
320+
state->enabled = value & channel_data->pwm_en_mask;
344321

345322
value = readl(meson->base + channel_data->reg_offset);
346-
347323
channel->lo = FIELD_GET(PWM_LOW_MASK, value);
348324
channel->hi = FIELD_GET(PWM_HIGH_MASK, value);
349325

@@ -473,6 +449,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
473449

474450
for (i = 0; i < meson->chip.npwm; i++) {
475451
struct meson_pwm_channel *channel = &meson->channels[i];
452+
struct clk_parent_data div_parent = {}, gate_parent = {};
476453
struct clk_init_data init = {};
477454

478455
snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i);
@@ -492,18 +469,63 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
492469
channel->mux.table = NULL;
493470
channel->mux.hw.init = &init;
494471

495-
channel->clk = devm_clk_register(dev, &channel->mux.hw);
496-
if (IS_ERR(channel->clk)) {
497-
err = PTR_ERR(channel->clk);
472+
err = devm_clk_hw_register(dev, &channel->mux.hw);
473+
if (err) {
474+
dev_err(dev, "failed to register %s: %d\n", name, err);
475+
return err;
476+
}
477+
478+
snprintf(name, sizeof(name), "%s#div%u", dev_name(dev), i);
479+
480+
init.name = name;
481+
init.ops = &clk_divider_ops;
482+
init.flags = CLK_SET_RATE_PARENT;
483+
div_parent.index = -1;
484+
div_parent.hw = &channel->mux.hw;
485+
init.parent_data = &div_parent;
486+
init.num_parents = 1;
487+
488+
channel->div.reg = meson->base + REG_MISC_AB;
489+
channel->div.shift = meson_pwm_per_channel_data[i].clk_div_shift;
490+
channel->div.width = MISC_CLK_DIV_WIDTH;
491+
channel->div.hw.init = &init;
492+
channel->div.flags = 0;
493+
channel->div.lock = &meson->lock;
494+
495+
err = devm_clk_hw_register(dev, &channel->div.hw);
496+
if (err) {
498497
dev_err(dev, "failed to register %s: %d\n", name, err);
499498
return err;
500499
}
501500

502-
snprintf(name, sizeof(name), "clkin%u", i);
501+
snprintf(name, sizeof(name), "%s#gate%u", dev_name(dev), i);
503502

504-
channel->clk_parent = devm_clk_get_optional(dev, name);
505-
if (IS_ERR(channel->clk_parent))
506-
return PTR_ERR(channel->clk_parent);
503+
init.name = name;
504+
init.ops = &clk_gate_ops;
505+
init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
506+
gate_parent.index = -1;
507+
gate_parent.hw = &channel->div.hw;
508+
init.parent_data = &gate_parent;
509+
init.num_parents = 1;
510+
511+
channel->gate.reg = meson->base + REG_MISC_AB;
512+
channel->gate.bit_idx = meson_pwm_per_channel_data[i].clk_en_shift;
513+
channel->gate.hw.init = &init;
514+
channel->gate.flags = 0;
515+
channel->gate.lock = &meson->lock;
516+
517+
err = devm_clk_hw_register(dev, &channel->gate.hw);
518+
if (err) {
519+
dev_err(dev, "failed to register %s: %d\n", name, err);
520+
return err;
521+
}
522+
523+
channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL);
524+
if (IS_ERR(channel->clk)) {
525+
err = PTR_ERR(channel->clk);
526+
dev_err(dev, "failed to register %s: %d\n", name, err);
527+
return err;
528+
}
507529
}
508530

509531
return 0;

0 commit comments

Comments
 (0)