[PATCH 2/2] MFD: mc13xxx workaround SPI hardware bug on i.Mx
Marc Reilly
marc at cpdesign.com.au
Wed May 30 19:47:29 EDT 2012
Hi Philipe,
Thanks for fixing this.
Acked-by: Marc Reilly <marc at cpdesign.com.au>
Cheers,
Marc
(Some real trivial spelling corrections inline below. I'd ignore them unless
you do a V2)
On Tuesday, May 29, 2012 07:06:29 PM Philippe Rétornaz wrote:
> The MC13xxx PMIC is mainly used on i.Mx SoC. On thoses SoC the SPI
s/thoses/these
> hardware will deassert CS line as soon as the SPI FIFO is empty.
> The MC13xxx hardware is very sensitive to CS line change as it
> corrupts the transfert if CS is deasserted in the middle of a register
s/transfert/transfer
> read or write.
> It is not possible to use the CS line as a GPIO on some SoC, so we
> need to workaround this by implementing a single SPI transfer to
> access the PMIC.
>
> Signed-off-by: Philippe Rétornaz <philippe.retornaz at epfl.ch>
> ---
> drivers/mfd/mc13xxx-spi.c | 65
> ++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 64
> insertions(+), 1 deletions(-)
>
> diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c
> index 5d1969f..03df422 100644
> --- a/drivers/mfd/mc13xxx-spi.c
> +++ b/drivers/mfd/mc13xxx-spi.c
> @@ -54,6 +54,67 @@ static struct regmap_config mc13xxx_regmap_spi_config =
> { .max_register = MC13XXX_NUMREGS,
>
> .cache_type = REGCACHE_NONE,
> + .use_single_rw = 1,
> +};
> +
> +static int mc13xxx_spi_read(void *context, const void *reg, size_t
> reg_size, + void *val, size_t val_size)
> +{
> + unsigned char w[4] = { *((unsigned char *) reg), 0, 0, 0};
> + unsigned char r[4];
> + unsigned char *p = val;
> + struct device *dev = context;
> + struct spi_device *spi = to_spi_device(dev);
> + struct spi_transfer t = {
> + .tx_buf = w,
> + .rx_buf = r,
> + .len = 4,
> + };
> +
> + struct spi_message m;
> + int ret;
> +
> + if (val_size != 3 || reg_size != 1)
> + return -ENOTSUPP;
> +
> + spi_message_init(&m);
> + spi_message_add_tail(&t, &m);
> + ret = spi_sync(spi, &m);
> +
> + memcpy(p, &r[1], 3);
> +
> + return ret;
> +}
> +
> +static int mc13xxx_spi_write(void *context, const void *data, size_t
> count) +{
> + struct device *dev = context;
> + struct spi_device *spi = to_spi_device(dev);
> +
> + if (count != 4)
> + return -ENOTSUPP;
> +
> + return spi_write(spi, data, count);
> +}
> +
> +/*
> + * We cannot use regmap-spi generic bus implementation here.
> + * The MC13783 chip will get corrupted if CS signal is deasserted
> + * and on i.Mx31 SoC (the target SoC for MC13783 PMIC) the SPI controller
> + * has the following errata (DSPhl22960):
> + * "The CSPI negates SS when the FIFO becomes empty with
> + * SSCTL= 0. Software cannot guarantee that the FIFO will not
> + * drain because of higher priority interrupts and the
> + * non-realtime characteristics of the operating system. As a
> + * result, the SS will negate before all of the data has been
> + * transferred to/from the peripheral."
> + * We workaround this by accessing the SPI controller with a
> + * single transfert.
s/transfert/transfer
> + */
> +
> +static struct regmap_bus regmap_mc13xxx_bus = {
> + .write = mc13xxx_spi_write,
> + .read = mc13xxx_spi_read,
> };
>
> static int mc13xxx_spi_probe(struct spi_device *spi)
> @@ -78,7 +139,9 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
> mc13xxx->dev = &spi->dev;
> mutex_init(&mc13xxx->lock);
>
> - mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
> + mc13xxx->regmap = regmap_init(&spi->dev, ®map_mc13xxx_bus, &spi->dev,
> + &mc13xxx_regmap_spi_config);
> +
> if (IS_ERR(mc13xxx->regmap)) {
> ret = PTR_ERR(mc13xxx->regmap);
> dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
More information about the linux-arm-kernel
mailing list