From: Paul Cercueil <paul@crapouillou.net>
To: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
Cc: Thierry Reding <thierry.reding@gmail.com>,
od@zcrc.me, linux-pwm@vger.kernel.org,
linux-kernel@vger.kernel.org,
Mathieu Malaterre <malat@debian.org>,
Artur Rojek <contact@artur-rojek.eu>
Subject: Re: [PATCH v2 1/3] pwm: jz4740: Use clocks from TCU driver
Date: Sun, 17 Nov 2019 23:58:43 +0100 [thread overview]
Message-ID: <1574031523.3.0@crapouillou.net> (raw)
In-Reply-To: <20191117202028.4chgjv2kulyyq2eu@pengutronix.de>
Hi Uwe,
Le dim., nov. 17, 2019 at 21:20, Uwe Kleine-König
<u.kleine-koenig@pengutronix.de> a écrit :
> On Sat, Nov 16, 2019 at 06:36:11PM +0100, Paul Cercueil wrote:
>> The ingenic-timer "TCU" driver provides us with clocks, that can be
>> (un)gated, reparented or reclocked from devicetree, instead of
>> having
>> these settings hardcoded in this driver.
>>
>> While this driver is devicetree-compatible, it is never (as of now)
>> probed from devicetree, so this change does not introduce a ABI
>> problem
>> with current devicetree files.
>>
>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>> Tested-by: Mathieu Malaterre <malat@debian.org>
>> Tested-by: Artur Rojek <contact@artur-rojek.eu>
>> ---
>>
>> Notes:
>> v2: This patch is now before the patch introducing regmap, so
>> the code
>> has changed a bit.
>>
>> drivers/pwm/Kconfig | 1 +
>> drivers/pwm/pwm-jz4740.c | 45
>> ++++++++++++++++++++++++++++------------
>> 2 files changed, 33 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
>> index e3a2518503ed..e998e5cb01b0 100644
>> --- a/drivers/pwm/Kconfig
>> +++ b/drivers/pwm/Kconfig
>> @@ -225,6 +225,7 @@ config PWM_IMX_TPM
>> config PWM_JZ4740
>> tristate "Ingenic JZ47xx PWM support"
>> depends on MACH_INGENIC
>> + depends on COMMON_CLK
>> help
>> Generic PWM framework driver for Ingenic JZ47xx based
>> machines.
>> diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
>> index 9d78cc21cb12..fd83644f9323 100644
>> --- a/drivers/pwm/pwm-jz4740.c
>> +++ b/drivers/pwm/pwm-jz4740.c
>> @@ -24,7 +24,6 @@
>>
>> struct jz4740_pwm_chip {
>> struct pwm_chip chip;
>> - struct clk *clk;
>
> What is the motivation to go away from this approach to store the
> clock?
It's actually not the same clock. Instead of obtaining "ext" clock from
the probe, we obtain "timerX" clocks (X being the PWM channel) from the
request callback.
>> };
>>
>> static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip
>> *chip)
>> @@ -34,6 +33,11 @@ static inline struct jz4740_pwm_chip
>> *to_jz4740(struct pwm_chip *chip)
>>
>> static int jz4740_pwm_request(struct pwm_chip *chip, struct
>> pwm_device *pwm)
>> {
>> + struct jz4740_pwm_chip *jz = to_jz4740(chip);
>> + struct clk *clk;
>> + char clk_name[16];
>> + int ret;
>> +
>> /*
>> * Timers 0 and 1 are used for system tasks, so they are
>> unavailable
>> * for use as PWMs.
>> @@ -41,16 +45,31 @@ static int jz4740_pwm_request(struct pwm_chip
>> *chip, struct pwm_device *pwm)
>> if (pwm->hwpwm < 2)
>> return -EBUSY;
>>
>> - jz4740_timer_start(pwm->hwpwm);
>> + snprintf(clk_name, sizeof(clk_name), "timer%u", pwm->hwpwm);
>> +
>> + clk = clk_get(chip->dev, clk_name);
>> + if (IS_ERR(clk))
>
> if (PTR_ERR(clk) != -EPROBE_DEFER)
> dev_err(chip->dev, "Failed to get clock: %pe\n", clk);
Never heard about that %pe. Will do that.
>
>> + return PTR_ERR(clk);
>> +
>> + ret = clk_prepare_enable(clk);
>> + if (ret) {
>> + clk_put(clk);
>> + return ret;
>> + }
>> +
>> + pwm_set_chip_data(pwm, clk);
>>
>> return 0;
>> }
>>
>> static void jz4740_pwm_free(struct pwm_chip *chip, struct
>> pwm_device *pwm)
>> {
>> + struct clk *clk = pwm_get_chip_data(pwm);
>> +
>> jz4740_timer_set_ctrl(pwm->hwpwm, 0);
>
> What is the purpose of this call? I would have expected that all these
> would go away when converting to the clk stuff?!
Some go away in patch [1/3] as they are clock-related, this one will go
away in patch [2/3] when the driver is converted to use regmap.
>
>> - jz4740_timer_stop(pwm->hwpwm);
>> + clk_disable_unprepare(clk);
>> + clk_put(clk);
>> }
>>
>> static int jz4740_pwm_enable(struct pwm_chip *chip, struct
>> pwm_device *pwm)
>> @@ -91,17 +110,21 @@ static int jz4740_pwm_apply(struct pwm_chip
>> *chip, struct pwm_device *pwm,
>> const struct pwm_state *state)
>> {
>> struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
>> + struct clk *clk = pwm_get_chip_data(pwm),
>> + *parent_clk = clk_get_parent(clk);
>> + unsigned long rate, period, duty;
>> unsigned long long tmp;
>> - unsigned long period, duty;
>> unsigned int prescaler = 0;
>> uint16_t ctrl;
>>
>> - tmp = (unsigned long long)clk_get_rate(jz4740->clk) *
>> state->period;
>> + rate = clk_get_rate(parent_clk);
>
> Why is it the parent's rate that is relevant here?
We calculate the divider to be used for the "timerX" clock, so we need
to know the parent clock.
>> + tmp = (unsigned long long)rate * state->period;
>> do_div(tmp, 1000000000);
>> period = tmp;
>>
>> while (period > 0xffff && prescaler < 6) {
>> period >>= 2;
>> + rate >>= 2;
>> ++prescaler;
>> }
>>
>> @@ -117,14 +140,14 @@ static int jz4740_pwm_apply(struct pwm_chip
>> *chip, struct pwm_device *pwm,
>>
>> jz4740_pwm_disable(chip, pwm);
>>
>> + clk_set_rate(clk, rate);
>
> This function's return code must be checked.
In practice this will never fail, but OK, will do.
Cheers,
-Paul
>
>> jz4740_timer_set_count(pwm->hwpwm, 0);
>> jz4740_timer_set_duty(pwm->hwpwm, duty);
>> jz4740_timer_set_period(pwm->hwpwm, period);
>>
>> - ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT
>> |
>> - JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
>> -
>> - jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
>> + ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
>> + ctrl |= JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
>>
>> switch (state->polarity) {
>> case PWM_POLARITY_NORMAL:
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-König
> |
> Industrial Linux Solutions |
> https://www.pengutronix.de/ |
next prev parent reply other threads:[~2019-11-17 22:58 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-16 17:36 [PATCH v2 0/3] pwm: jz4740: Update to use TCU clocks/regmap Paul Cercueil
2019-11-16 17:36 ` [PATCH v2 1/3] pwm: jz4740: Use clocks from TCU driver Paul Cercueil
2019-11-17 20:20 ` Uwe Kleine-König
2019-11-17 22:58 ` Paul Cercueil [this message]
2019-11-18 7:15 ` Uwe Kleine-König
2019-11-18 10:55 ` Paul Cercueil
2019-11-18 11:19 ` Uwe Kleine-König
2019-11-18 13:42 ` Paul Cercueil
2020-02-11 16:25 ` Uwe Kleine-König
2019-11-16 17:36 ` [PATCH v2 2/3] pwm: jz4740: Obtain regmap from parent node Paul Cercueil
2019-11-16 17:36 ` [PATCH v2 3/3] pwm: jz4740: Allow selection of PWM channels 0 and 1 Paul Cercueil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1574031523.3.0@crapouillou.net \
--to=paul@crapouillou.net \
--cc=contact@artur-rojek.eu \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=malat@debian.org \
--cc=od@zcrc.me \
--cc=thierry.reding@gmail.com \
--cc=u.kleine-koenig@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.