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@xxxxxxxxxxxxxxx> --- 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(-) 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; -- 2.11.0