[PATCH 1/3] drivers: base: add support for stmp-style devices
Arnd Bergmann
arnd at arndb.de
Wed Nov 16 12:44:19 EST 2011
On Wednesday 16 November 2011, Wolfram Sang wrote:
> Signed-off-by: Wolfram Sang <w.sang at pengutronix.de>
Introducing new core code definitely requires a long patch description.
How about copying the description from the introductory mail here?
> drivers/base/Kconfig | 3 ++
> drivers/base/Makefile | 1 +
> drivers/base/stmp_device.c | 80 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/stmp_device.h | 19 ++++++++++
> 4 files changed, 103 insertions(+), 0 deletions(-)
> create mode 100644 drivers/base/stmp_device.c
> create mode 100644 include/linux/stmp_device.h
I'm not convinced that drivers/base is the right place, but I also can't
think of anything better right now.
> diff --git a/drivers/base/stmp_device.c b/drivers/base/stmp_device.c
> +/*
> + * Clear the bit and poll it cleared. This is usually called with
> + * a reset address and mask being either SFTRST(bit 31) or CLKGATE
> + * (bit 30).
> + */
> +static int stmp_clear_poll_bit(void __iomem *addr, u32 mask)
> +{
> + int timeout = 0x400;
> +
> + writel(mask, addr + STMP_CLR_ADDR);
> + udelay(1);
> + while ((readl(addr) & mask) && --timeout)
> + /* nothing */;
> +
> + return !timeout;
> +}
For portable code, you should use cpu_relax() inside of the loop.
Is the udelay() actually necessary here?
> +int stmp_reset_block(void __iomem *reset_addr)
> +{
> + int ret;
> + int timeout = 0x400;
> +
> + /* clear and poll SFTRST */
> + ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST);
> + if (unlikely(ret))
> + goto error;
Please don't use likely()/unlikely() in code that is not very
performance sensitive. It will usually just increase the code size
but not actually have a measurable benefit.
> + /* clear CLKGATE */
> + writel(STMP_MODULE_CLKGATE, reset_addr + STMP_CLR_ADDR);
> +
> + /* set SFTRST to reset the block */
> + writel(STMP_MODULE_SFTRST, reset_addr + STMP_SET_ADDR);
> + udelay(1);
> +
> + /* poll CLKGATE becoming set */
> + while ((!(readl(reset_addr) & STMP_MODULE_CLKGATE)) && --timeout)
> + /* nothing */;
> + if (unlikely(!timeout))
> + goto error;
Since the run-time of a readl() may vary greatly, counting to 400
for a timeout seems completely arbitrary and unhelpful.
A better construct is
long timeout = jiffies + HZ / 10; /* wait for at most 100ms */
do {
...
} while (time_before(jiffies, timeout));
or the ktime equivalent of that if you are waiting for very short times.
> + /* clear and poll SFTRST */
> + ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_SFTRST);
> + if (unlikely(ret))
> + goto error;
> +
> + /* clear and poll CLKGATE */
> + ret = stmp_clear_poll_bit(reset_addr, STMP_MODULE_CLKGATE);
> + if (unlikely(ret))
> + goto error;
> +
> + return 0;
> +
> +error:
> + pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
> + return -ETIMEDOUT;
> +}
> +EXPORT_SYMBOL(stmp_reset_block);
EXPORT_SYMBOL_GPL?
> diff --git a/include/linux/stmp_device.h b/include/linux/stmp_device.h
> new file mode 100644
> index 0000000..330f8d8
> --- /dev/null
> +++ b/include/linux/stmp_device.h
> @@ -0,0 +1,19 @@
> +#ifndef __STMP_DEVICE_H__
> +#define __STMP_DEVICE_H__
> +
> +#define STMP_SET_ADDR 0x4
> +#define STMP_CLR_ADDR 0x8
> +#define STMP_TOG_ADDR 0xc
The register numbers should probably go into the implementation file,
they are not an interface.
> +extern int stmp_reset_block(void __iomem *);
> +#endif /* __STMP_DEVICE_H__ */
Arnd
More information about the linux-arm-kernel
mailing list