[PATCH v3 2/2] gpio: ixp4xx: Handle clock output on pin 14 and 15

Andy Shevchenko andy at kernel.org
Mon Sep 25 00:18:50 PDT 2023


On Sat, Sep 23, 2023 at 06:02:29PM +0200, Linus Walleij wrote:
> This makes it possible to provide basic clock output on pins
> 14 and 15. The clocks are typically used by random electronics,
> not modeled in the device tree, so they just need to be provided
> on request.
> 
> In order to not disturb old systems that require that the
> hardware defaults are kept in the clock setting bits, we only
> manipulate these if either device tree property is present.
> Once we know a device needs one of the clocks we can set it
> in the device tree.

Given that cover letter implicitly explains why not PPS,
Reviewed-by: Andy Shevchenko <andy at kernel.org>

Also see below.

...

>  	if (of_machine_is_compatible("dlink,dsm-g600-a") ||
>  	    of_machine_is_compatible("iom,nas-100d"))
> -		__raw_writel(0x0, g->base + IXP4XX_REG_GPCLK);
> +		val = 0;
> +	else
> +		val = __raw_readl(g->base + IXP4XX_REG_GPCLK);
> +
> +	/*
> +	 * If either clock output is enabled explicitly in the device tree
> +	 * we take full control of the clock by masking off all bits for
> +	 * the clock control and selectively enabling them. Otherwise
> +	 * we leave the hardware default settings.
> +	 *
> +	 * Enable clock outputs with default timings of requested clock.
> +	 * If you need control over TC and DC, add these to the device
> +	 * tree bindings and use them here.
> +	 */
> +	clk_14 = of_property_read_bool(np, "intel,ixp4xx-gpio14-clkout");
> +	clk_15 = of_property_read_bool(np, "intel,ixp4xx-gpio15-clkout");
> +	if (clk_14 || clk_15) {
> +		val &= ~(IXP4XX_GPCLK_MUX14 | IXP4XX_GPCLK_MUX15);
> +		val &= ~IXP4XX_GPCLK_CLK0_MASK;
> +		val &= ~IXP4XX_GPCLK_CLK1_MASK;
> +		if (clk_14) {
> +			val |= (0 << IXP4XX_GPCLK_CLK0DC_SHIFT);
> +			val |= (1 << IXP4XX_GPCLK_CLK0TC_SHIFT);
> +			val |= IXP4XX_GPCLK_MUX14;
> +		}
> +
> +		if (clk_15) {
> +			val |= (0 << IXP4XX_GPCLK_CLK1DC_SHIFT);
> +			val |= (1 << IXP4XX_GPCLK_CLK1TC_SHIFT);
> +			val |= IXP4XX_GPCLK_MUX15;
> +		}
> +	}
> +
> +	__raw_writel(val, g->base + IXP4XX_REG_GPCLK);

Can be optimized this way (not insisting, though):

	/*
	 * If either clock output is enabled explicitly in the device tree
	 * we take full control of the clock by masking off all bits for
	 * the clock control and selectively enabling them. Otherwise
	 * we leave the hardware default settings.
	 *
	 * Enable clock outputs with default timings of requested clock.
	 * If you need control over TC and DC, add these to the device
	 * tree bindings and use them here.
	 */
	clk_14 = of_property_read_bool(np, "intel,ixp4xx-gpio14-clkout");
	clk_15 = of_property_read_bool(np, "intel,ixp4xx-gpio15-clkout");

	if (of_machine_is_compatible("dlink,dsm-g600-a") ||
	    of_machine_is_compatible("iom,nas-100d")) {
		val = 0;
	} else {
		val = __raw_readl(g->base + IXP4XX_REG_GPCLK);
		if (clk_14 || clk_15) {

I'm wondering if it's fine to have them both to be cleared if not defined?
I.o.w. does it meant that appearance of one of the properties (to be set)
implies the other (to be not set)?

			val &= ~(IXP4XX_GPCLK_MUX14 | IXP4XX_GPCLK_MUX15);
			val &= ~IXP4XX_GPCLK_CLK0_MASK;
			val &= ~IXP4XX_GPCLK_CLK1_MASK;
		}
	}

	if (clk_14) {

		val |= (0 << IXP4XX_GPCLK_CLK0DC_SHIFT);

Wondering why you simply can't replace this...

		val |= (1 << IXP4XX_GPCLK_CLK0TC_SHIFT);
		val |= IXP4XX_GPCLK_MUX14;
	}

	if (clk_15) {
		val |= (0 << IXP4XX_GPCLK_CLK1DC_SHIFT);

...and this by a comment?

		val |= (1 << IXP4XX_GPCLK_CLK1TC_SHIFT);
		val |= IXP4XX_GPCLK_MUX15;
	}

	__raw_writel(val, g->base + IXP4XX_REG_GPCLK);

-- 
With Best Regards,
Andy Shevchenko





More information about the linux-arm-kernel mailing list