RE: [PATCH V4 2/5] pwm: Add i.MX TPM PWM driver support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, Uwe

Best Regards!
Anson Huang

> -----Original Message-----
> From: Uwe Kleine-König [mailto:u.kleine-koenig@xxxxxxxxxxxxxx]
> Sent: 2019年3月18日 16:08
> To: Anson Huang <anson.huang@xxxxxxx>
> Cc: thierry.reding@xxxxxxxxx; robh+dt@xxxxxxxxxx; mark.rutland@xxxxxxx;
> shawnguo@xxxxxxxxxx; s.hauer@xxxxxxxxxxxxxx; kernel@xxxxxxxxxxxxxx;
> festevam@xxxxxxxxx; linux@xxxxxxxxxxxxxxx; otavio@xxxxxxxxxxxxxxxx;
> stefan@xxxxxxxx; Leonard Crestez <leonard.crestez@xxxxxxx>;
> schnitzeltony@xxxxxxxxx; jan.tuerk@xxxxxxxxxxx; Robin Gong
> <yibin.gong@xxxxxxx>; linux-pwm@xxxxxxxxxxxxxxx;
> devicetree@xxxxxxxxxxxxxxx; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx; dl-linux-imx <linux-imx@xxxxxxx>
> Subject: Re: [PATCH V4 2/5] pwm: Add i.MX TPM PWM driver support
> 
> On Mon, Mar 18, 2019 at 07:41:02AM +0000, Anson Huang wrote:
> > Hi,Uwe
> > > > +	val &= ~PWM_IMX_TPM_SC_CMOD;
> > > > +	writel(val, tpm->base + PWM_IMX_TPM_SC);
> > >
> > > As this interrupts the output, please only do it if necessary.
> >
> > OK, will do it ONLY when it is enabled previously.
> 
> I think you only need to do that when the value actually changes.

OK, I will save the period/div count and ONLY do it when the value actually changes.

> 
> > > > +	/* set duty counter */
> > > > +	tmp = readl(tpm->base + PWM_IMX_TPM_MOD) &
> > > > +PWM_IMX_TPM_MOD_MOD_MASK;
> > >
> > > I recommend storing this value in driver data.
> >
> > NOT quite understand, as we did NOT use it in other places except the
> > get_state, just reading the register once should be OK there.
> 
> I had the impression it is used more than once. Will look again in the next
> iteration. But also note that shadowing the value might already be beneficial
> for a single call site as driver data might occupy more RAM than necessary
> anyhow and reading from RAM is faster than from the hardware's register.
> Probably this is not a fast path, so not worth the optimisation?!

OK, will save it in driver data and avoid accessing register again.

> 
> > > I wonder why MSA and MSB are two bits instead of making this a field
> > > of width 2 with 2b10 meaning PWM mode. But maybe it's just me not
> > > understanding the independent semantic of these two bits?
> >
> > I think making them a field makes more sense, but anyway we just
> > follow the RM.
> 
> If it makes the driver easier to understand (which I think it does) feel free to
> derivate from the RM. Just add a comment to the definition, then it's fine.

OK, I will change the register definition and a comment for it.

> 
> > > Reading the reference manual I'd say in PWM mode the semantic of
> > > ELSA and ELSB is:
> > >
> > > 	On counter reload set the output to ELSB
> > > 	On counter match set the output to ELSA
> > >
> > > Noting that in a comment would ease understanding the code here.
> >
> > I added below comment for PWM modes:
> >
> > 137         /*
> > 138          * set polarity (for edge-aligned PWM modes)
> > 139          *
> > 140          * CPWMS  MSB:MSA  ELSB:ELSA  Mode  Configuration
> > 141          * 0      10       10         PWM   High-true pulse
> > 142          * 0      10       00         PWM   Reserved
> > 143          * 0      10       01         PWM   Low-true pulse
> > 144          * 0      10       11         PWM   Reserved
> > 145          *
> > 146          * High-true pulse: clear output on counter match, set output on
> > 147          * counter reload, set output when counter first enabled or paused.
> > 148          *
> > 149          * Low-true pulse: set output on counter match, clear output on
> > 150          * counter reload, clear output when counter first enabled or
> paused.
> > 151          */
> 
> I stumbled over "high-true" and "low-true" in the RM, too. In my bubble this
> is an uncommon wording. I'd write instead:
> 
> 	/*
> 	 * set polarity
> 	 *
> 	 * ELSB:ELSA = 2b10 yields normal polarity behaviour, ELSB:ELSA
> 	 * = 2b01 yields inversed polarity. The other values are
> 	 * reserved.
> 	 */
> 
> And don't write about CPWM, MSA and MSB which are always used with
> fixed values anyhow in the driver.
> 

OK.

> > > > +		/* disable channel */
> > > > +		writel(PWM_IMX_TPM_CnSC_CHF,
> > > > +			tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
> > >
> > > Clearing CHF doens't disable the channel as I read the manual.
> >
> > This write clears CHF as well as writing other bits 0, to disable the
> > output. Maybe I can explicitly clear MSA/MSB/ELSA/ELSB to avoid
> confusion.
> 
> Ah, I misinterpreted the value written.
> 
> > > > +static int pwm_imx_tpm_apply(struct pwm_chip *chip, struct
> pwm_device *pwm,
> > > > +			     struct pwm_state *state)
> > > > +{
> > > > +	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
> > > > +	struct pwm_state curstate;
> > > > +	u32 duty_cycle = state->duty_cycle;
> > > > +	int ret;
> > > > +
> > > > +	pwm_imx_tpm_get_state(chip, pwm, &curstate);
> > > > +
> > > > +	mutex_lock(&tpm->lock);
> > >
> > > What should this lock protect? Does it hurt if the state changes
> > > between pwm_imx_tpm_get_state releasing the lock and
> > > pwm_imx_tpm_apply taking it?
> >
> > The idea is to protect the share resourced by multiple channels, but I
> > think I can make the mutex_lock includes get_state and remove the lock in
> get_state function.
> A
> You might need it in .get_state to return a consistent state to the caller. In
> this case just introduce an unlocked variant of .get_state to share code
> between the two functions.
> 
> And BTW the question was honest. I'm not entirely sure that you need to
> hold the lock.

Agreed, if the different channel configuration ONLY access its own register, NOT
any shared registers, then I think this lock is unnecessary.

> 
> > > > +		 */
> > > > +		if (tpm->user_count != 1)
> > > > +			return -EBUSY;
> > >
> > > Ideally if say period = 37 is requested but currently we have period
> > > =
> > > 36 and configuring 37 would result in 36 anyhow, don't return EBUSY.
> >
> > I think here the protection is just for making sure that is there are
> > multiple users, period can NOT be changed, since all channels will be
> impacted.
> 
> I think you misunderstood what I intended to say here.
> 
> Consider that in the case that there is only a single PWM in use configuring
> for a period of 37 ns actually yields 36 ns because the hardware cannot
> provide 37 ns and 36 ns is the best match.
> 
> Then if a second user comes and requests 37 ns, the result here is, that the
> second user gets the -EBUSY. This is ridiculous however because the request
> is denied even though the period is already configured for the length that
> would be configured if the second user were the only one.

Ah, if I understand correctly, I think I can change it to, if second user try to set a period
different from first user, then return -EBUSY, otherwise, return success.

> 
> > > > +	tpm->chip.dev = &pdev->dev;
> > > > +	tpm->chip.ops = &imx_tpm_pwm_ops;
> > > > +	tpm->chip.base = -1;
> > > > +	tpm->chip.npwm = PWM_IMX_TPM_MAX_CHANNEL_NUM;
> > >
> > > This is wrong, as some only have 2 channels?
> >
> > I saw we can get channel number from register, will read register to
> > determine the channel number, but for the channel config and status
> > saved in struct, I will still use the MAX channel number to define the array.
> 
> Yeah, that is sensible.

I will resend V5 patch set, since there are some mis-understanding for previous comments.

Thanks,
Anson.

> 
> Best regards
> Uwe
> 
> --
> Pengutronix e.K.                           | Uwe Kleine-König            |
> Industrial Linux Solutions                 |
> https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.p
> engutronix.de%2F&amp;data=02%7C01%7Canson.huang%40nxp.com%7C31
> d10d3f4a7c46eea9d708d6ab78d965%7C686ea1d3bc2b4c6fa92cd99c5c30163
> 5%7C0%7C0%7C636884932859808816&amp;sdata=LD2D%2BwEhNKFllK2FaI
> Wvjttmre0YPV%2BXwv7sdvkZSpo%3D&amp;reserved=0  |




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux