Re: [PATCH v3] gpio: pca953x: Add Maxim MAX7313 PWM support
From: Uwe Kleine-König
Date: Tue Nov 26 2019 - 08:12:58 EST
Hello Miquèl,
On Tue, Nov 26, 2019 at 12:15:14PM +0100, Miquel Raynal wrote:
> Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> wrote on Tue, 26 Nov
> 2019 11:49:20 +0100:
>
> > Hallo Miquel,
> >
> > On Tue, Nov 26, 2019 at 09:51:56AM +0100, Miquel Raynal wrote:
> > > > Also when switching from 0% to 50% you could prevent a glitch by
> > > > sticking to an unset blink phase 0 bit.
> > >
> > > You mean, when turning off the PWM, I should first change the intensity
> > > to 50%, then blink the phase, then change the intensity to 100%?
> > > (reversed logic when intensity > 0).
> >
> > No, that's not what I meant. Your hardware seems to have two different
> > "modes". One where you can set the intensity between 0 and 15/16, and
> > another where the intensity is between 1/16 and 16/16, right? Switching
>
> Right!
>
> > between these two results in a glitch and you use the first mode only
> > for intensity 0 and the second for the rest.
>
> Indeed.
>
> > If now you have to go from
> > 0 to 8/16 your driver does a mode switch while this isn't necessary.
>
> This is right but it complicates a bit the logic as intensity changes
> become stateful. If this is what you want, I can do it.
>
> >
> > I also wonder if a glitch can at least be made less likely, even when
> > going from 0% to 100%. You claimed that changing intensity was glitch
> > free (i.e. the currently running period is completed before the changed
> > setting has an effect). Does this hold also for changing the blink
> > phase?
>
> I honestly don't know, the datasheet does not tell anything about it.
So you don't have the equipment to test that?
> If I implement the above logic, glitches will be made less likely.
Sounds good.
> I could also add more logic to switch the blink state at the 50%
> whenever crossing this value but with the above logic added I think it
> becomes unreadable and error prone, the risks are not balanced with the
> benefits. Of course anyone can enhance the driver in the future.
I would just implement "lazy" switching. So switch if (and only if)
necessary.
> > > > > + mutex_unlock(&pwm->count_lock);
> > > > > +
> > > > > + gpiochip_free_own_desc(data->desc);
> > > > > +}
> > > > > +
> > > > > +static int max7313_pwm_apply(struct pwm_chip *pwm_chip,
> > > > > + struct pwm_device *pwm_device,
> > > > > + const struct pwm_state *state)
> > > > > +{
> > > > > + struct max7313_pwm_data *data = pwm_get_chip_data(pwm_device);
> > > > > + struct max7313_pwm *pwm = to_max7313_pwm(pwm_chip);
> > > > > + struct pca953x_chip *chip = to_pca953x(pwm);
> > > > > + unsigned int duty_cycle;
> > > > > +
> > > > > + if (state->period != PWM_PERIOD_NS ||
> > > > > + state->polarity != PWM_POLARITY_NORMAL)
> > > > > + return -EINVAL;
> > > >
> > > > The check for period is too strong. Anything bigger than PWM_PERIOD_NS
> > > > is acceptable, too. (The policy I'd like to see is: Provide the biggest
> > > > period possible not bigger than the requested policy.)
> > >
> > > I don't understand, what is this parameter supposed to mean? the period
> > > cannot be changed, it is ruled by an internal oscillator. In this case
> > > any period bigger than the actual period cannot be physically achieved.
> > > If we derive ratios with a bigger period than possible, why not
> > > allowing it for lower periods too?
> >
> > Yes, I understood that the period is fixed for your PWM. However
> > consider a consumer who would prefer a different period. If you decline
> > all requests unless state->period == PWM_PERIOD_NS the consumer has no
> > guide to determine that unless all periods are tested. If however asking
> > for period = 2s results in getting 31.25 ms this allows the consumer to
> > assume that no period setting between 2s and 31.25 ms is possible. And
> > so the usual policy to implement is as stated in my previous mail.
>
> I am not sure to follow you, here are two possible understandings:
>
> 1/ state->period > PWM_PERIOD_NS should not be refused, but in the end
> get_state should always return PWM_PERIOD_NS.
>
> 2/ I should always do the ratio between state->period and
> state->duty_cycle as long as state->period >= PWM_PERIOD_NS (In this
> case I still don't understand why I should refuse state->period <
> PWM_PERIOD_NS).
The first is the one I want. There are some strange corner cases, but
the policy is easy and also for other policies there are corner cases.
So in general you should do (when .enabled = true):
- use the requested polarity
- choose the biggest period not bigger than the requested one
- with the above period choose the biggest duty_cycle not bigger than
the requested one.
> > > > > + data->enabled = state->enabled;
> > > > > + data->duty_cycle = state->duty_cycle;
> > > >
> > > > Storing these is only to let .get_state yield the last set values,
> > > > right?
> > >
> > > I can't guess the duty_cycle/enabled state just by reading the
> > > hardware. For instance, I cannot represent a "40% duty with PWM
> > > disabled". Reading the hardware will not be able to know if the PWM
> > > is enabled or not and the duty_cycle will be read as 0.
> >
> > I interpret that as a "yes". IMHO it's a misconcept that a PWM driver
> > has to remember the duty cycle (and period) with enabled=false even
> > though this has no influence on the actual output in that state. I'd
> > like to get rid of .enabled in struct pwm_state completely, but Thierry
> > doesn't agree.
>
> I have no choice. Actually I don't understand why the core do not
> provide the 'last' duty cycle when enabled == false. It provides 0. So
> if I don't use the above trick here is what happens:
>
> echo 1 > enabled
> echo 50 > duty_cycle
> echo 0 > enabled
> echo 1 > enabled
> * duty_cycle is 0 while I expect it to be 50 *
IMHO this should be fixed in the framework. As I assume this is a bigger
discussion I suggest to keep the code as is and when at some point in
time we have the framework fixed, we simplify all drivers that can
benefit.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |