All of lore.kernel.org
 help / color / mirror / Atom feed
From: Baruch Siach <baruch@tkos.co.il>
To: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
Cc: Thierry Reding <thierry.reding@gmail.com>,
	Lee Jones <lee.jones@linaro.org>, Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Balaji Prakash J <bjagadee@codeaurora.org>,
	Rob Herring <robh+dt@kernel.org>,
	Robert Marko <robert.marko@sartura.hr>,
	linux-pwm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-msm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v4 1/3] pwm: driver for qualcomm ipq6018 pwm block
Date: Wed, 07 Jul 2021 07:58:01 +0300	[thread overview]
Message-ID: <875yxmg1pi.fsf@tarshish> (raw)
In-Reply-To: <20210705072055.5mvux5h6zdewzabz@pengutronix.de>

Hi Uwe,

Thanks for taking the time to review this patch. I have a few comment
below.

On Mon, Jul 05 2021, Uwe Kleine-König wrote:
> On Sun, Jun 27, 2021 at 08:24:04AM +0300, Baruch Siach wrote:
>> +/*
>> + * Enable bit is set to enable output toggling in pwm device.
>> + * Update bit is set to reflect the changed divider and high duration
>> + * values in register.
>> + */
>> +#define PWM_ENABLE		0x80000000
>> +#define PWM_UPDATE		0x40000000
>> +
>> +/* The frequency range supported is 1Hz to 100MHz */
>> +#define MIN_PERIOD_NS	10
>> +#define MAX_PERIOD_NS	1000000000
>
> Please use a driver prefix for these defines.

I take this to refer also to the defines below, right?

>> +
>> +/*
>> + * The max value specified for each field is based on the number of bits
>> + * in the pwm control register for that field
>> + */
>> +#define MAX_PWM_CFG		0xFFFF
>> +
>> +#define PWM_CTRL_HI_SHIFT	16
>> +
>> +#define PWM_CFG_REG0 0 /*PWM_DIV PWM_HI*/
>> +#define PWM_CFG_REG1 1 /*ENABLE UPDATE PWM_PRE_DIV*/

...

>> +static void config_div_and_duty(struct pwm_device *pwm, int pre_div,
>> +			unsigned long long pwm_div, unsigned long period_ns,
>> +			unsigned long long duty_ns)
>
> Please also use a consistent prefix for function names.
>
> I suggest to use u64 for some of the parameters. While this doesn't
> change anything, it is cleaner as the caller passes variables of this
> type.

Actually for pre_div and pwm_div the caller passes int values. I agree
this is inconsistent.

...

>> +static int ipq_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
>> +			 const struct pwm_state *state)
>> +{
>> +	struct ipq_pwm_chip *ipq_chip = to_ipq_pwm_chip(chip);
>> +	unsigned long freq;
>> +	int pre_div, close_pre_div, close_pwm_div;
>> +	int pwm_div;
>> +	long long diff;
>> +	unsigned long rate = clk_get_rate(ipq_chip->clk);
>> +	unsigned long min_diff = rate;
>> +	uint64_t fin_ps;
>> +	u64 period_ns, duty_ns;
>> +
>> +	if (state->period < MIN_PERIOD_NS)
>> +		return -ERANGE;
>
> MIN_PERIOD_NS depends on clk_get_rate(ipq_chip->clk), doesn't it?

probe sets this clock to the fixed 100MHz rate (CLK_SRC_FREQ). Would you
prefer to derive MIN_PERIOD_NS from CLK_SRC_FREQ?

>> +	period_ns = min_t(u64, state->period, MAX_PERIOD_NS);
>> +	duty_ns = min_t(u64, state->duty_cycle, period_ns);
>
> If you define MAX_PERIOD_NS as (u64)1000000000 you can just use min().
>
>> +
>> +	/* freq in Hz for period in nano second*/
>
> Space before the closing */ please
>
>> +	freq = div64_u64(NSEC_PER_SEC, period_ns);
>> +	fin_ps = div64_u64(NSEC_PER_SEC * 1000ULL, rate);
>> +	close_pre_div = MAX_PWM_CFG;
>> +	close_pwm_div = MAX_PWM_CFG;
>> +
>> +	for (pre_div = 0; pre_div <= MAX_PWM_CFG; pre_div++) {
>> +		pwm_div = DIV64_U64_ROUND_CLOSEST(period_ns * 1000,
>> +						  fin_ps * (pre_div + 1));
>> +		pwm_div--;
>> +		if (pwm_div < 0 || pwm_div > MAX_PWM_CFG)
>> +			continue;
>> +
>> +		diff = ((uint64_t)freq * (pre_div + 1) * (pwm_div + 1))
>> +			- (uint64_t)rate;
>> +
>> +		if (diff < 0) /* period larger than requested */
>> +			continue;
>> +		if (diff == 0) { /* bingo */
>> +			close_pre_div = pre_div;
>> +			close_pwm_div = pwm_div;
>> +			break;
>> +		}
>> +		if (diff < min_diff) {
>> +			min_diff = diff;
>> +			close_pre_div = pre_div;
>> +			close_pwm_div = pwm_div;
>> +		}
>
> I didn't check deeply, but I assume this calculation can be done more
> efficiently.

The thing is that we have two dividers to play with. I can't think of a
cleaner way to find the best match for a given target frequency.

> Also I wonder if DIV64_U64_ROUND_CLOSEST is right. When you implement
> a .get_state() callback (which usually helps me to understand how the
> hardware works) I'm willing to take a closer look.

Thanks,
baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -

WARNING: multiple messages have this Message-ID (diff)
From: Baruch Siach <baruch@tkos.co.il>
To: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
Cc: Thierry Reding <thierry.reding@gmail.com>,
	Lee Jones <lee.jones@linaro.org>, Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Balaji Prakash J <bjagadee@codeaurora.org>,
	Rob Herring <robh+dt@kernel.org>,
	Robert Marko <robert.marko@sartura.hr>,
	linux-pwm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-msm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v4 1/3] pwm: driver for qualcomm ipq6018 pwm block
Date: Wed, 07 Jul 2021 07:58:01 +0300	[thread overview]
Message-ID: <875yxmg1pi.fsf@tarshish> (raw)
In-Reply-To: <20210705072055.5mvux5h6zdewzabz@pengutronix.de>

Hi Uwe,

Thanks for taking the time to review this patch. I have a few comment
below.

On Mon, Jul 05 2021, Uwe Kleine-König wrote:
> On Sun, Jun 27, 2021 at 08:24:04AM +0300, Baruch Siach wrote:
>> +/*
>> + * Enable bit is set to enable output toggling in pwm device.
>> + * Update bit is set to reflect the changed divider and high duration
>> + * values in register.
>> + */
>> +#define PWM_ENABLE		0x80000000
>> +#define PWM_UPDATE		0x40000000
>> +
>> +/* The frequency range supported is 1Hz to 100MHz */
>> +#define MIN_PERIOD_NS	10
>> +#define MAX_PERIOD_NS	1000000000
>
> Please use a driver prefix for these defines.

I take this to refer also to the defines below, right?

>> +
>> +/*
>> + * The max value specified for each field is based on the number of bits
>> + * in the pwm control register for that field
>> + */
>> +#define MAX_PWM_CFG		0xFFFF
>> +
>> +#define PWM_CTRL_HI_SHIFT	16
>> +
>> +#define PWM_CFG_REG0 0 /*PWM_DIV PWM_HI*/
>> +#define PWM_CFG_REG1 1 /*ENABLE UPDATE PWM_PRE_DIV*/

...

>> +static void config_div_and_duty(struct pwm_device *pwm, int pre_div,
>> +			unsigned long long pwm_div, unsigned long period_ns,
>> +			unsigned long long duty_ns)
>
> Please also use a consistent prefix for function names.
>
> I suggest to use u64 for some of the parameters. While this doesn't
> change anything, it is cleaner as the caller passes variables of this
> type.

Actually for pre_div and pwm_div the caller passes int values. I agree
this is inconsistent.

...

>> +static int ipq_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
>> +			 const struct pwm_state *state)
>> +{
>> +	struct ipq_pwm_chip *ipq_chip = to_ipq_pwm_chip(chip);
>> +	unsigned long freq;
>> +	int pre_div, close_pre_div, close_pwm_div;
>> +	int pwm_div;
>> +	long long diff;
>> +	unsigned long rate = clk_get_rate(ipq_chip->clk);
>> +	unsigned long min_diff = rate;
>> +	uint64_t fin_ps;
>> +	u64 period_ns, duty_ns;
>> +
>> +	if (state->period < MIN_PERIOD_NS)
>> +		return -ERANGE;
>
> MIN_PERIOD_NS depends on clk_get_rate(ipq_chip->clk), doesn't it?

probe sets this clock to the fixed 100MHz rate (CLK_SRC_FREQ). Would you
prefer to derive MIN_PERIOD_NS from CLK_SRC_FREQ?

>> +	period_ns = min_t(u64, state->period, MAX_PERIOD_NS);
>> +	duty_ns = min_t(u64, state->duty_cycle, period_ns);
>
> If you define MAX_PERIOD_NS as (u64)1000000000 you can just use min().
>
>> +
>> +	/* freq in Hz for period in nano second*/
>
> Space before the closing */ please
>
>> +	freq = div64_u64(NSEC_PER_SEC, period_ns);
>> +	fin_ps = div64_u64(NSEC_PER_SEC * 1000ULL, rate);
>> +	close_pre_div = MAX_PWM_CFG;
>> +	close_pwm_div = MAX_PWM_CFG;
>> +
>> +	for (pre_div = 0; pre_div <= MAX_PWM_CFG; pre_div++) {
>> +		pwm_div = DIV64_U64_ROUND_CLOSEST(period_ns * 1000,
>> +						  fin_ps * (pre_div + 1));
>> +		pwm_div--;
>> +		if (pwm_div < 0 || pwm_div > MAX_PWM_CFG)
>> +			continue;
>> +
>> +		diff = ((uint64_t)freq * (pre_div + 1) * (pwm_div + 1))
>> +			- (uint64_t)rate;
>> +
>> +		if (diff < 0) /* period larger than requested */
>> +			continue;
>> +		if (diff == 0) { /* bingo */
>> +			close_pre_div = pre_div;
>> +			close_pwm_div = pwm_div;
>> +			break;
>> +		}
>> +		if (diff < min_diff) {
>> +			min_diff = diff;
>> +			close_pre_div = pre_div;
>> +			close_pwm_div = pwm_div;
>> +		}
>
> I didn't check deeply, but I assume this calculation can be done more
> efficiently.

The thing is that we have two dividers to play with. I can't think of a
cleaner way to find the best match for a given target frequency.

> Also I wonder if DIV64_U64_ROUND_CLOSEST is right. When you implement
> a .get_state() callback (which usually helps me to understand how the
> hardware works) I'm willing to take a closer look.

Thanks,
baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-07-07  4:58 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-27  5:24 [PATCH v4 1/3] pwm: driver for qualcomm ipq6018 pwm block Baruch Siach
2021-06-27  5:24 ` Baruch Siach
2021-06-27  5:24 ` [PATCH v4 2/3] dt-bindings: pwm: add IPQ6018 binding Baruch Siach
2021-06-27  5:24   ` Baruch Siach
2021-06-27  5:24 ` [PATCH v4 3/3] arm64: dts: ipq6018: add pwm node Baruch Siach
2021-06-27  5:24   ` Baruch Siach
2021-07-05  7:20 ` [PATCH v4 1/3] pwm: driver for qualcomm ipq6018 pwm block Uwe Kleine-König
2021-07-05  7:20   ` Uwe Kleine-König
2021-07-07  4:58   ` Baruch Siach [this message]
2021-07-07  4:58     ` Baruch Siach
2021-07-07  5:42     ` Uwe Kleine-König
2021-07-07  5:42       ` Uwe Kleine-König

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=875yxmg1pi.fsf@tarshish \
    --to=baruch@tkos.co.il \
    --cc=agross@kernel.org \
    --cc=bjagadee@codeaurora.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lee.jones@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=robert.marko@sartura.hr \
    --cc=robh+dt@kernel.org \
    --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.