linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
To: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>,
	"Mark Brown" <broonie@kernel.org>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Heiko Stuebner <heiko@sntech.de>,
	devicetree@vger.kernel.org,
	Linus Walleij <linus.walleij@linaro.org>,
	Thierry Reding <thierry.reding@gmail.com>,
	Sam Ravnborg <sam@ravnborg.org>,
	linux-rtc@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>,
	Fabio Estevam <festevam@gmail.com>,
	Daniel Palmer <daniel@0x0f.com>,
	Andy Shevchenko <andy.shevchenko@gmail.com>,
	Andreas Kemnade <andreas@kemnade.info>,
	NXP Linux Team <linux-imx@nxp.com>,
	linux-pwm@vger.kernel.org, Stephan Gerhold <stephan@gerhold.net>,
	allen <allen.chen@ite.com.tw>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Lubomir Rintel <lkundrak@v3.sk>, Rob Herring <robh+dt@kernel.org>,
	Lee Jones <lee.jones@linaro.org>,
	linux-arm-kernel@lists.infradead.org,
	Alessandro Zummo <a.zummo@towertech.it>,
	linux-kernel@vger.kernel.org,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
	Josua Mayer <josua.mayer@jm0.eu>, Shawn Guo <shawnguo@kernel.org>,
	"David S. Miller" <davem@davemloft.net>
Subject: Re: [PATCH v4 4/7] pwm: ntxec: Add driver for PWM function in Netronix EC
Date: Fri, 27 Nov 2020 08:11:05 +0100	[thread overview]
Message-ID: <20201127071105.k2rb4iykeqevbao5@pengutronix.de> (raw)
In-Reply-To: <20201126231931.GE456020@latitude>

[-- Attachment #1: Type: text/plain, Size: 6745 bytes --]

Hello Jonathan,

On Fri, Nov 27, 2020 at 12:19:31AM +0100, Jonathan Neuschäfer wrote:
> On Tue, Nov 24, 2020 at 09:20:19AM +0100, Uwe Kleine-König wrote:
> > On Sun, Nov 22, 2020 at 11:27:36PM +0100, Jonathan Neuschäfer wrote:
> [...]
> > > +/*
> > > + * The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are
> > > + * measured in this unit.
> > > + */
> > > +#define TIME_BASE_NS 125
> > > +
> > > +/*
> > > + * The maximum input value (in nanoseconds) is determined by the time base and
> > > + * the range of the hardware registers that hold the converted value.
> > > + * It fits into 32 bits, so we can do our calculations in 32 bits as well.
> > > + */
> > > +#define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff)
> > > +
> > > +static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
> > > +			   const struct pwm_state *state)
> > > +{
> > > +	struct ntxec_pwm *priv = pwmchip_to_priv(pwm_dev->chip);
> > > +	unsigned int duty = state->duty_cycle;
> > > +	unsigned int period = state->period;
> > 
> > state->duty_cycle and state->period are u64, so you're losing
> > information here. Consider state->duty_cycle = 0x100000001 and
> > state->period = 0x200000001.
> 
> Oh, good point, I didn't notice the truncation.
> 
> The reason I picked unsigned int was to avoid a 64-bit division;
> I suppose I can do something like this:
> 
>     period = (u32)period / TIME_BASE_NS;
>     duty = (u32)duty / TIME_BASE_NS;

You can do that after you checked period > MAX_PERIOD_NS below, yes.
Something like:

	if (state->polarity != PWM_POLARITY_NORMAL)
		return -EINVAL;

	if (state->period > MAX_PERIOD_NS) {
		period = MAX_PERIOD_NS;
	else
		period = state->period;

	if (state->duty_cycle > period)
		duty_cycle = period;
	else
		duty_cycle = state->duty_cycle;

should work with even keeping the local variables as unsigned int.

> > > +	int res = 0;
> > > +
> > > +	if (state->polarity != PWM_POLARITY_NORMAL)
> > > +		return -EINVAL;
> > > +
> > > +	if (period > MAX_PERIOD_NS) {
> > > +		period = MAX_PERIOD_NS;
> > > +
> > > +		if (duty > period)
> > > +			duty = period;
> > > +	}
> > > +
> > > +	period /= TIME_BASE_NS;
> > > +	duty /= TIME_BASE_NS;
> > > +
> > > +	res = regmap_write(priv->ec->regmap, NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8));
> > > +	if (res)
> > > +		return res;
> > 
> > I wonder if you can add some logic to the regmap in the mfd driver such
> > that ntxec_reg8 isn't necessary for all users.
> 
> I think that would involve:
> 
> 1. adding custom register access functions to the regmap, which decide
>    based on the register number whether a register needs 8-bit or 16-bit
>    access. So far I have avoided information about registers into the
>    main driver, when the registers are only used in the sub-drivers.
> 
> or
> 
> 2. switching the regmap configuration to little endian, which would be
>    advantageous for 8-bit registers, inconsequential for 16-bit
>    registers that consist of independent high and low halves, and wrong
>    for the 16-bit registers 0x41, which reads the battery voltage ADC
>    value. It is also different from how the vendor kernel treats 16-bit
>    registers.
> 
> Perhaps there is another option that I haven't considered yet.

I don't know enough about regmap to teach you something here. But maybe
Mark has an idea. (I promoted him from Cc: to To:, maybe he will
notice.)

> > > +	res = regmap_write(priv->ec->regmap, NTXEC_REG_PERIOD_LOW, ntxec_reg8(period));
> > > +	if (res)
> > > +		return res;
> > > +
> > > +	res = regmap_write(priv->ec->regmap, NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8));
> > > +	if (res)
> > > +		return res;
> > > +
> > > +	res = regmap_write(priv->ec->regmap, NTXEC_REG_DUTY_LOW, ntxec_reg8(duty));
> > > +	if (res)
> > > +		return res;
> > 
> > I think I already asked, but I don't remember the reply: What happens to
> > the output between these writes? A comment here about this would be
> > suitable.
> 
> I will add something like the following:
> 
> /*
>  * Changes to the period and duty cycle take effect as soon as the
>  * corresponding low byte is written, so the hardware may be configured
>  * to an inconsistent state after the period is written and before the
>  * duty cycle is fully written. If, in such a case, the old duty cycle
>  * is longer than the new period, the EC will output 100% for a moment.
>  */

Is the value pair taken over by hardware atomically? That is, is it
really "will" in your last line, or only "might". (E.g. when changing
from duty_cycle, period = 1000, 2000 to 500, 800 and a new cycle begins
after reducing period, the new duty_cycle is probably written before the
counter reaches 500. Do we get a 100% cycle here?)

Other than that the info is fine. Make sure to point this out in the
Limitations paragraph at the top of the driver please, too.

> > > +	.apply = ntxec_pwm_apply,
> > 
> > /*
> >  * The current state cannot be read out, so there is no .get_state
> >  * callback.
> >  */
> > 
> > Hmm, at least you could provice a .get_state() callback that reports the
> > setting that was actually implemented for in the last call to .apply()?
> 
> Yes... I see two options:
> 
> 1. Caching the state in the driver's private struct. I'm not completely
>    convinced of the value, given that the information is mostly
>    available in the PWM core already (except for the adjustments that
>    the driver makes).
> 
> 2. Writing the adjusted state back into pwm_dev->state (via pwm_set_*).
>    This seems a bit dirty.

2. isn't a good option. Maybe regmap caches this stuff anyhow for 1. (or
can be made doing that)?

> > @Thierry: Do you have concerns here? Actually it would be more effective
> > to have a callback (like .apply()) that modfies its pwm_state
> > accordingly. (Some drivers did that in the past, but I changed that to
> > get an uniform behaviour in 71523d1812aca61e32e742e87ec064e3d8c615e1.)
> > The downside is that people have to understand that concept to properly
> > use it. I'm torn about the right approach.
> 
> General guidance for such cases when the state can't be read back from
> the hardware would be appreciated.

Yes, improving the documentation would be great here. Thierry, can you
please comment on
https://lore.kernel.org/r/20191209213233.29574-2-u.kleine-koenig@pengutronix.de
which I'm waiting on before describing our understanding in more detail.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2020-11-27  7:11 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-22 22:27 [PATCH v4 0/7] Netronix embedded controller driver for Kobo and Tolino ebook readers Jonathan Neuschäfer
2020-11-22 22:27 ` [PATCH v4 1/7] dt-bindings: Add vendor prefix for Netronix, Inc Jonathan Neuschäfer
2020-11-22 22:27 ` [PATCH v4 2/7] dt-bindings: mfd: Add binding for Netronix embedded controller Jonathan Neuschäfer
2020-11-22 22:27 ` [PATCH v4 3/7] mfd: Add base driver " Jonathan Neuschäfer
2020-12-02 13:05   ` Lee Jones
2020-12-02 13:06     ` Lee Jones
2020-12-02 14:00     ` Jonathan Neuschäfer
2020-12-02 15:09       ` Lee Jones
2020-12-02 17:11         ` Jonathan Neuschäfer
2020-11-22 22:27 ` [PATCH v4 4/7] pwm: ntxec: Add driver for PWM function in Netronix EC Jonathan Neuschäfer
2020-11-24  8:20   ` Uwe Kleine-König
2020-11-26 23:19     ` Jonathan Neuschäfer
2020-11-27  7:11       ` Uwe Kleine-König [this message]
2020-11-27 11:08         ` Thierry Reding
2020-11-27 14:23           ` Uwe Kleine-König
2020-11-29 17:59             ` Jonathan Neuschäfer
2020-11-29 17:48         ` Jonathan Neuschäfer
2020-11-22 22:27 ` [PATCH v4 5/7] rtc: New driver for RTC in Netronix embedded controller Jonathan Neuschäfer
2020-11-22 23:10   ` Alexandre Belloni
2020-11-23 21:31     ` Jonathan Neuschäfer
2020-11-23 21:34       ` Mark Brown
2020-11-23 21:38       ` Alexandre Belloni
2020-11-22 22:27 ` [PATCH v4 6/7] MAINTAINERS: Add entry for " Jonathan Neuschäfer
2020-11-23  0:09 ` [PATCH v4 7/7] ARM: dts: imx50-kobo-aura: Add " Jonathan Neuschäfer

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=20201127071105.k2rb4iykeqevbao5@pengutronix.de \
    --to=u.kleine-koenig@pengutronix.de \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=allen.chen@ite.com.tw \
    --cc=andreas@kemnade.info \
    --cc=andy.shevchenko@gmail.com \
    --cc=arnd@arndb.de \
    --cc=broonie@kernel.org \
    --cc=daniel@0x0f.com \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=festevam@gmail.com \
    --cc=heiko.stuebner@theobroma-systems.com \
    --cc=heiko@sntech.de \
    --cc=j.neuschaefer@gmx.net \
    --cc=josua.mayer@jm0.eu \
    --cc=kernel@pengutronix.de \
    --cc=lee.jones@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=lkundrak@v3.sk \
    --cc=mchehab+huawei@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=sam@ravnborg.org \
    --cc=shawnguo@kernel.org \
    --cc=stephan@gerhold.net \
    --cc=thierry.reding@gmail.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).