Message ID | 20181212220922.18759-13-paul@crapouillou.net (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Paul Burton |
Headers | show |
Series | Ingenic TCU patchset v8 | expand |
On Wed, Dec 12, 2018 at 11:09:07PM +0100, Paul Cercueil wrote: > The TCU channels 0 and 1 were previously reserved for system tasks, and > thus unavailable for PWM. > > The driver will now only allow a PWM channel to be requested if memory > resources corresponding to the register area of the channel were > supplied to the driver. This allows the TCU channels to be reserved for > system tasks from within the devicetree. > > Signed-off-by: Paul Cercueil <paul@crapouillou.net> While there is someone caring for this driver I'd like to complete (a bit) my picture about the different capabilities and specialities of the supported PWMs. So I have a few questions: Is there a publicly available reference manual for this device? (If yes, adding a link to the driver would be great.) jz4740_pwm_config looks as if the currently running period isn't completed before the new config is in effect. Is that correct? If yes, can this be fixed? A similar question for set_polarity: Does setting the JZ_TIMER_CTRL_PWM_ACTIVE_LOW bit in the control register take effect immediately or is this shadowed until the next period starts? How does the device's output behave after the PWM is disabled? Does it complete the currently running period? How does the output behave then? (active/inactive/high/low/high-z?) > @@ -42,11 +68,7 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) > char clk_name[16]; > int ret; > > - /* > - * Timers 0 and 1 are used for system tasks, so they are unavailable > - * for use as PWMs. > - */ > - if (pwm->hwpwm < 2) > + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) > return -EBUSY; Maybe EBUSY isn't the best choice here. If the needed register space for the requested pwm is not included in the memory resources provided to the device I'd prefer ENXIO or ENODEV. > snprintf(clk_name, sizeof(clk_name), "timer%u", pwm->hwpwm); > @@ -208,6 +230,12 @@ static int jz4740_pwm_probe(struct platform_device *pdev) > return -EINVAL; > } > > + jz4740->parent_res = platform_get_resource( > + to_platform_device(dev->parent), > + IORESOURCE_MEM, 0); > + if (!jz4740->parent_res) > + return -EINVAL; > + > jz4740->chip.dev = dev; > jz4740->chip.ops = &jz4740_pwm_ops; > jz4740->chip.npwm = NUM_PWM; Thanks Uwe
Hi, Le jeu. 13 déc. 2018 à 10:18, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> a écrit : > On Wed, Dec 12, 2018 at 11:09:07PM +0100, Paul Cercueil wrote: >> The TCU channels 0 and 1 were previously reserved for system tasks, >> and >> thus unavailable for PWM. >> >> The driver will now only allow a PWM channel to be requested if >> memory >> resources corresponding to the register area of the channel were >> supplied to the driver. This allows the TCU channels to be reserved >> for >> system tasks from within the devicetree. >> >> Signed-off-by: Paul Cercueil <paul@crapouillou.net> > > While there is someone caring for this driver I'd like to complete (a > bit) my picture about the different capabilities and specialities of > the > supported PWMs. So I have a few questions: > > Is there a publicly available reference manual for this device? (If > yes, adding a link to the driver would be great.) I have them here: https://zcrc.me/~paul/jz_docs/ > jz4740_pwm_config looks as if the currently running period isn't > completed before the new config is in effect. Is that correct? If yes, > can this be fixed? A similar question for set_polarity: Does setting > the > JZ_TIMER_CTRL_PWM_ACTIVE_LOW bit in the control register take effect > immediately or is this shadowed until the next period starts? I don't really know. We only use this driver for a rumble motor and backlight. Somebody would have to check with a logic analyzer. > How does the device's output behave after the PWM is disabled? > Does it complete the currently running period? How does the output > behave then? (active/inactive/high/low/high-z?) There's a bit to toggle between "graceful" shutdown (bit clear) and "abrupt" shutdown (bit set). TCSR bit 9. I think that graceful shutdown will complete the running period, then keep the level active. Abrupt shutdown will keep the current level of the line. >> @@ -42,11 +68,7 @@ static int jz4740_pwm_request(struct pwm_chip >> *chip, struct pwm_device *pwm) >> char clk_name[16]; >> int ret; >> >> - /* >> - * Timers 0 and 1 are used for system tasks, so they are >> unavailable >> - * for use as PWMs. >> - */ >> - if (pwm->hwpwm < 2) >> + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) >> return -EBUSY; > > Maybe EBUSY isn't the best choice here. If the needed register space > for > the requested pwm is not included in the memory resources provided to > the device I'd prefer ENXIO or ENODEV. The idea was that if we don't get the register space we need, that means the channel is used for something else, hence the EBUSY. Should I switch it to ENXIO? >> snprintf(clk_name, sizeof(clk_name), "timer%u", pwm->hwpwm); >> @@ -208,6 +230,12 @@ static int jz4740_pwm_probe(struct >> platform_device *pdev) >> return -EINVAL; >> } >> >> + jz4740->parent_res = platform_get_resource( >> + to_platform_device(dev->parent), >> + IORESOURCE_MEM, 0); >> + if (!jz4740->parent_res) >> + return -EINVAL; >> + >> jz4740->chip.dev = dev; >> jz4740->chip.ops = &jz4740_pwm_ops; >> jz4740->chip.npwm = NUM_PWM; > > Thanks > Uwe > > -- > Pengutronix e.K. | Uwe Kleine-König > | > Industrial Linux Solutions | > http://www.pengutronix.de/ |
On Thu, Dec 13, 2018 at 02:58:31PM +0100, Paul Cercueil wrote: > Hi, > > Le jeu. 13 déc. 2018 à 10:18, Uwe Kleine-König > <u.kleine-koenig@pengutronix.de> a écrit : > > On Wed, Dec 12, 2018 at 11:09:07PM +0100, Paul Cercueil wrote: > > > The TCU channels 0 and 1 were previously reserved for system tasks, > > > and > > > thus unavailable for PWM. > > > > > > The driver will now only allow a PWM channel to be requested if > > > memory > > > resources corresponding to the register area of the channel were > > > supplied to the driver. This allows the TCU channels to be reserved > > > for > > > system tasks from within the devicetree. > > > > > > Signed-off-by: Paul Cercueil <paul@crapouillou.net> > > > > While there is someone caring for this driver I'd like to complete (a > > bit) my picture about the different capabilities and specialities of the > > supported PWMs. So I have a few questions: > > > > Is there a publicly available reference manual for this device? (If > > yes, adding a link to the driver would be great.) > > I have them here: https://zcrc.me/~paul/jz_docs/ Is this link good enough to add it to the driver? From a quick view I'd say this is another pwm implementation that gets active on pwm_disable(). Can you confirm this? > > jz4740_pwm_config looks as if the currently running period isn't > > completed before the new config is in effect. Is that correct? If yes, > > can this be fixed? A similar question for set_polarity: Does setting the > > JZ_TIMER_CTRL_PWM_ACTIVE_LOW bit in the control register take effect > > immediately or is this shadowed until the next period starts? > > I don't really know. We only use this driver for a rumble motor and > backlight. > Somebody would have to check with a logic analyzer. depending on the possible timings you might also be able to test this e.g. by setting: duty_cycle=1ms, period=5s and then duty_cycle=5s, period=5s . If the implementation is right your display should be dark for nearly 5 seconds. (And the second call to pwm_apply should also block until the display is on.) > > How does the device's output behave after the PWM is disabled? > > Does it complete the currently running period? How does the output > > behave then? (active/inactive/high/low/high-z?) > > There's a bit to toggle between "graceful" shutdown (bit clear) and "abrupt" > shutdown (bit set). TCSR bit 9. I think that graceful shutdown will complete > the running period, then keep the level active. Abrupt shutdown will keep > the > current level of the line. Can you confirm the things you think above? I'd like to have them eventually documented in the driver. > > > @@ -42,11 +68,7 @@ static int jz4740_pwm_request(struct pwm_chip > > > *chip, struct pwm_device *pwm) > > > char clk_name[16]; > > > int ret; > > > > > > - /* > > > - * Timers 0 and 1 are used for system tasks, so they are > > > unavailable > > > - * for use as PWMs. > > > - */ > > > - if (pwm->hwpwm < 2) > > > + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) > > > return -EBUSY; > > > > Maybe EBUSY isn't the best choice here. If the needed register space for > > the requested pwm is not included in the memory resources provided to > > the device I'd prefer ENXIO or ENODEV. > > The idea was that if we don't get the register space we need, that means > the channel is used for something else, hence the EBUSY. Should I switch > it to ENXIO? I understand your reasoning, but I think it's misleading. If I get -EBUSY from a PWM driver I'd start searching for another user of said resource. With ENXIO or ENODEV it's more obvious that the driver isn't responsible for the resource that was requested. Best regards Uwe
Hi, Le jeu. 13 déc. 2018 à 21:32, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> a écrit : > On Thu, Dec 13, 2018 at 02:58:31PM +0100, Paul Cercueil wrote: >> Hi, >> >> Le jeu. 13 déc. 2018 à 10:18, Uwe Kleine-König >> <u.kleine-koenig@pengutronix.de> a écrit : >> > On Wed, Dec 12, 2018 at 11:09:07PM +0100, Paul Cercueil wrote: >> > > The TCU channels 0 and 1 were previously reserved for system >> tasks, >> > > and >> > > thus unavailable for PWM. >> > > >> > > The driver will now only allow a PWM channel to be requested if >> > > memory >> > > resources corresponding to the register area of the channel >> were >> > > supplied to the driver. This allows the TCU channels to be >> reserved >> > > for >> > > system tasks from within the devicetree. >> > > >> > > Signed-off-by: Paul Cercueil <paul@crapouillou.net> >> > >> > While there is someone caring for this driver I'd like to >> complete (a >> > bit) my picture about the different capabilities and specialities >> of the >> > supported PWMs. So I have a few questions: >> > >> > Is there a publicly available reference manual for this device? >> (If >> > yes, adding a link to the driver would be great.) >> >> I have them here: https://zcrc.me/~paul/jz_docs/ > > Is this link good enough to add it to the driver? From a quick view > I'd > say this is another pwm implementation that gets active on > pwm_disable(). > Can you confirm this? It's my website, so if these get moved, I can update the link. What do you mean it gets active on pwm_disable()? If pwm_disable() gets called the PWM line goes back to inactive state, which is what it should do. >> > jz4740_pwm_config looks as if the currently running period isn't >> > completed before the new config is in effect. Is that correct? If >> yes, >> > can this be fixed? A similar question for set_polarity: Does >> setting the >> > JZ_TIMER_CTRL_PWM_ACTIVE_LOW bit in the control register take >> effect >> > immediately or is this shadowed until the next period starts? >> >> I don't really know. We only use this driver for a rumble motor and >> backlight. >> Somebody would have to check with a logic analyzer. > > depending on the possible timings you might also be able to test this > e.g. by setting: > > duty_cycle=1ms, period=5s > > and then > > duty_cycle=5s, period=5s > > . If the implementation is right your display should be dark for > nearly > 5 seconds. (And the second call to pwm_apply should also block until > the > display is on.) So it switches to full ON as soon as I set the duty cycle to 5s. Same for the polarity, it is updated as soon as the register is written. So the registers are not shadowed. >> > How does the device's output behave after the PWM is disabled? >> > Does it complete the currently running period? How does the output >> > behave then? (active/inactive/high/low/high-z?) >> >> There's a bit to toggle between "graceful" shutdown (bit clear) and >> "abrupt" >> shutdown (bit set). TCSR bit 9. I think that graceful shutdown will >> complete >> the running period, then keep the level active. Abrupt shutdown >> will keep >> the >> current level of the line. > > Can you confirm the things you think above? I'd like to have them > eventually documented in the driver. From what I can see, with "abrupt" shutdown the line will always return to its inactive state (be it low or high, depending on the polarity). Setting this bit to "graceful" shutdown, the only difference is that the hardware will keep its current state, active or inactive. That's why we use the "abrupt" shutdown in the PWM driver. >> > > @@ -42,11 +68,7 @@ static int jz4740_pwm_request(struct >> pwm_chip >> > > *chip, struct pwm_device *pwm) >> > > char clk_name[16]; >> > > int ret; >> > > >> > > - /* >> > > - * Timers 0 and 1 are used for system tasks, so they are >> > > unavailable >> > > - * for use as PWMs. >> > > - */ >> > > - if (pwm->hwpwm < 2) >> > > + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) >> > > return -EBUSY; >> > >> > Maybe EBUSY isn't the best choice here. If the needed register >> space for >> > the requested pwm is not included in the memory resources >> provided to >> > the device I'd prefer ENXIO or ENODEV. >> >> The idea was that if we don't get the register space we need, that >> means >> the channel is used for something else, hence the EBUSY. Should I >> switch >> it to ENXIO? > > I understand your reasoning, but I think it's misleading. If I get > -EBUSY from a PWM driver I'd start searching for another user of said > resource. With ENXIO or ENODEV it's more obvious that the driver isn't > responsible for the resource that was requested. OK. > Best regards > Uwe > > -- > Pengutronix e.K. | Uwe Kleine-König > | > Industrial Linux Solutions | > http://www.pengutronix.de/ |
Hello Paul, On Sun, Dec 16, 2018 at 02:36:03PM +0100, Paul Cercueil wrote: > Le jeu. 13 déc. 2018 à 21:32, Uwe Kleine-König > <u.kleine-koenig@pengutronix.de> a écrit : > > On Thu, Dec 13, 2018 at 02:58:31PM +0100, Paul Cercueil wrote: > > > Hi, > > > > > > Le jeu. 13 déc. 2018 à 10:18, Uwe Kleine-König > > > <u.kleine-koenig@pengutronix.de> a écrit : > > > > On Wed, Dec 12, 2018 at 11:09:07PM +0100, Paul Cercueil wrote: > > > > > The TCU channels 0 and 1 were previously reserved for system > > > tasks, > > > > > and > > > > > thus unavailable for PWM. > > > > > > > > > > The driver will now only allow a PWM channel to be requested if > > > > > memory > > > > > resources corresponding to the register area of the channel > > > were > > > > > supplied to the driver. This allows the TCU channels to be > > > reserved > > > > > for > > > > > system tasks from within the devicetree. > > > > > > > > > > Signed-off-by: Paul Cercueil <paul@crapouillou.net> > > > > > > > > While there is someone caring for this driver I'd like to > > > complete (a > > > > bit) my picture about the different capabilities and specialities > > > of the > > > > supported PWMs. So I have a few questions: > > > > > > > > Is there a publicly available reference manual for this device? > > > (If > > > > yes, adding a link to the driver would be great.) > > > > > > I have them here: https://zcrc.me/~paul/jz_docs/ > > > > Is this link good enough to add it to the driver? From a quick view I'd > > say this is another pwm implementation that gets active on > > pwm_disable(). > > Can you confirm this? > > It's my website, so if these get moved, I can update the link. > > What do you mean it gets active on pwm_disable()? If pwm_disable() gets > called the PWM line goes back to inactive state, which is what it > should do. The register description for TCSRn.PWM_EN reads: 1: PWM pin output enable 0: PWM pin output disable, and the PWM pin will be set to the initial level according to INITL As I read the manual (but that differes from the driver) you should use INITL=1 for an uninverted PWM such that the period starts with the output being 1. And with that I'd expect that the output goes high on disable. Given that the driver inverts this and sets INITL (called JZ_TIMER_CTRL_PWM_ACTIVE_LOW in the driver) for an inverted pwm that behaviour is ok. With this approach the bug is not the level when pwm_disable was called but that the period doesn't start with the active part of the period. > > > > jz4740_pwm_config looks as if the currently running period isn't > > > > completed before the new config is in effect. Is that correct? If > > > yes, > > > > can this be fixed? A similar question for set_polarity: Does > > > setting the > > > > JZ_TIMER_CTRL_PWM_ACTIVE_LOW bit in the control register take > > > effect > > > > immediately or is this shadowed until the next period starts? > > > > > > I don't really know. We only use this driver for a rumble motor and > > > backlight. > > > Somebody would have to check with a logic analyzer. > > > > depending on the possible timings you might also be able to test this > > e.g. by setting: > > > > duty_cycle=1ms, period=5s > > > > and then > > > > duty_cycle=5s, period=5s > > > > . If the implementation is right your display should be dark for nearly > > 5 seconds. (And the second call to pwm_apply should also block until the > > display is on.) > > So it switches to full ON as soon as I set the duty cycle to 5s. Same for > the polarity, it is updated as soon as the register is written. So the > registers are not shadowed. Then I think the right thing to do is to gracefully disable the hardware on a duty/period change first to ensure the currently running period is completed before the next configuration gets active. > > > > How does the device's output behave after the PWM is disabled? > > > > Does it complete the currently running period? How does the output > > > > behave then? (active/inactive/high/low/high-z?) > > > > > > There's a bit to toggle between "graceful" shutdown (bit clear) and > > > "abrupt" > > > shutdown (bit set). TCSR bit 9. I think that graceful shutdown will > > > complete > > > the running period, then keep the level active. Abrupt shutdown > > > will keep > > > the > > > current level of the line. > > > > Can you confirm the things you think above? I'd like to have them > > eventually documented in the driver. > > From what I can see, with "abrupt" shutdown the line will always return to > its inactive state (be it low or high, depending on the polarity). Setting > this bit to "graceful" shutdown, the only difference is that the hardware > will keep its current state, active or inactive. That's why we use the > "abrupt" shutdown in the PWM driver. That sounds backwards from your last mail and the reference manual. As I read the manual "graceful" means the period is completed until FULL matches. And I understand "aprupt" as "immediatly freeze". If this is the case the names in the manual are well chosen. For the pwm framework the intended behaviour is the graceful one. (For both, disable and duty/period change.) Best regards Uwe
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 6b865c14f789..7b12e5628f4f 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -28,6 +28,7 @@ struct jz4740_pwm_chip { struct pwm_chip chip; struct clk *clks[NUM_PWM]; struct regmap *map; + struct resource *parent_res; }; static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) @@ -35,6 +36,31 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) return container_of(chip, struct jz4740_pwm_chip, chip); } +static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz, unsigned int chn) +{ + struct platform_device *pdev = to_platform_device(jz->chip.dev); + struct resource chn_res, *res; + unsigned int i; + + chn_res.start = jz->parent_res->start + TCU_REG_TDFRc(chn); + chn_res.end = chn_res.start + TCU_CHANNEL_STRIDE - 1; + chn_res.flags = IORESOURCE_MEM; + + /* + * Walk the list of resources, find if there's one that contains the + * registers for the requested TCU channel + */ + for (i = 0; ; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) + break; + if (resource_contains(res, &chn_res)) + return true; + } + + return false; +} + static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct jz4740_pwm_chip *jz = to_jz4740(chip); @@ -42,11 +68,7 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) char clk_name[16]; int ret; - /* - * Timers 0 and 1 are used for system tasks, so they are unavailable - * for use as PWMs. - */ - if (pwm->hwpwm < 2) + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) return -EBUSY; snprintf(clk_name, sizeof(clk_name), "timer%u", pwm->hwpwm); @@ -208,6 +230,12 @@ static int jz4740_pwm_probe(struct platform_device *pdev) return -EINVAL; } + jz4740->parent_res = platform_get_resource( + to_platform_device(dev->parent), + IORESOURCE_MEM, 0); + if (!jz4740->parent_res) + return -EINVAL; + jz4740->chip.dev = dev; jz4740->chip.ops = &jz4740_pwm_ops; jz4740->chip.npwm = NUM_PWM;
The TCU channels 0 and 1 were previously reserved for system tasks, and thus unavailable for PWM. The driver will now only allow a PWM channel to be requested if memory resources corresponding to the register area of the channel were supplied to the driver. This allows the TCU channels to be reserved for system tasks from within the devicetree. Signed-off-by: Paul Cercueil <paul@crapouillou.net> --- Notes: v6: New patch v7: No change v8: ingenic_tcu_[request,release]_channel are dropped. We now use the memory resources provided to the driver to detect whether or not we are allowed to use the TCU channel. drivers/pwm/pwm-jz4740.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-)