[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1574074556.3.0@crapouillou.net>
Date: Mon, 18 Nov 2019 11:55:56 +0100
From: Paul Cercueil <paul@...pouillou.net>
To: Uwe Kleine-König
<u.kleine-koenig@...gutronix.de>
Cc: Thierry Reding <thierry.reding@...il.com>, od@...c.me,
linux-pwm@...r.kernel.org, linux-kernel@...r.kernel.org,
Mathieu Malaterre <malat@...ian.org>,
Artur Rojek <contact@...ur-rojek.eu>, kernel@...gutronix.de
Subject: Re: [PATCH v2 1/3] pwm: jz4740: Use clocks from TCU driver
Hi Uwe,
Le lun., nov. 18, 2019 at 08:15, Uwe Kleine-König
<u.kleine-koenig@...gutronix.de> a écrit :
> Hello Paul,
>
> On Sun, Nov 17, 2019 at 11:58:43PM +0100, Paul Cercueil wrote:
>> Le dim., nov. 17, 2019 at 21:20, Uwe Kleine-König
>> <u.kleine-koenig@...gutronix.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@...pouillou.net>
>> > > Tested-by: Mathieu Malaterre <malat@...ian.org>
>> > > Tested-by: Artur Rojek <contact@...ur-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.
>
> Before you used driver data and container_of to get it, now you used
> pwm_set_chip_data. I wondered why you changed the approach to store
> data. That the actual data is different now is another thing (and
> obviously ok).
Thierry suggested it: https://lkml.org/lkml/2019/3/4/486
>
>> > > };
>> > >
>> > > 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.
>
> Yeah, that's new and IMHO quite nice.
>
>> > > + 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.
>
> I'd like to understand what it does. Judging from the name I expect
> this
> is somehow related to the clock stuff and so I wonder if the
> conversion
> to the clk API is as complete as it should be.
It clears the PWM channel's CTRL register. That's the register used for
instance to enable the PWM function of a TCU channel.
>
>> > > - 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.
>
> Then the approach here is wrong. You should not assume anything about
> the internal details of the clock, that's the task of the clock
> driver.
> As a consumer of the clock just request a rate (or use clk_round_rate
> to
> find a good setting first) and use that.
Totally agreed. I wanted to do that, but you were fighting tooth and
nails against my patch "Improve algorithm of clock calculation",
remember?
-Paul
Powered by blists - more mailing lists