Hi, Uwe Best Regards! Anson Huang > -----Original Message----- > From: Anson Huang > Sent: 2019年3月18日 18:08 > To: 'Uwe Kleine-König' <u.kleine-koenig@xxxxxxxxxxxxxx> > 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 > > 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. After further think, I added below tpm->period to save the current period settings, ONLY when the new period to be set is different from the current period, then the pwm_imx_tpm_config_counter() is called, so I think no need to care about the value changes, the value is always changed when pwm_imx_tpm_config_counter() is called. if (tpm->user_count != 1 && state->period != tpm->period) return -EBUSY; ret = pwm_imx_tpm_config_counter(chip, state->period); if (ret) return ret; > > > > > > > > + /* 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. Since all the functions in .apply function will need to access registers and these registers are shared by different channels, so I think the lock is necessary. Anson. > > > > > > > > + */ > > > > > + 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&data=02%7C01%7Canson.huang%40nxp.com%7C31 > > > d10d3f4a7c46eea9d708d6ab78d965%7C686ea1d3bc2b4c6fa92cd99c5c30163 > > > 5%7C0%7C0%7C636884932859808816&sdata=LD2D%2BwEhNKFllK2FaI > > Wvjttmre0YPV%2BXwv7sdvkZSpo%3D&reserved=0 |