[PATCH 5/5] SPI S3C64XX: SPI Controller driver for S3C64XX

Grant Likely grant.likely at secretlab.ca
Thu Nov 26 02:40:58 EST 2009


On Wed, Nov 25, 2009 at 11:48 PM, Jassi Brar <jassi.brar at samsung.com> wrote:
> Added S3C64XX SPI controller driver.
>
> Each SPI controller has exactly one CS line and as such doesn't
> provide for multi-cs. We implement a workaround to support
> multi-cs by _not_ configuring the mux'ed CS pin for each SPI
> controller. The CS mechanism is assumed to be fully machine
> specific - the driver doesn't even assume some GPIO pin is used
> to control the CS.
>
> The driver selects between DMA and POLLING mode depending upon
> the xfer size - DMA mode for xfers bigger than FIFO size, POLLING
> mode otherwise.
>
> The driver has been designed to be capable of running SoCs since
> s3c64xx and till date, for that reason some of the register fields
> have been passed via, SoC specific, platform data.
>
> Signed-off-by: Jassi Brar <jassi.brar at samsung.com>
> ---
>  drivers/spi/Kconfig       |    7 +
>  drivers/spi/Makefile      |    1 +
>  drivers/spi/spi_s3c64xx.c | 1033 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/spi_s3c64xx.h |  189 +++++++++

This is in the drivers/spi tree, but depends on the arch/arm stuff
from the first 4 patches.  Will need to decide which tree to merge
this driver though.

I won't review patches 1-4, but I've got a few comments for this
patch.  Mostly minor stuff.  I don't seen anything on quick review
that jumps out at me as bad.

> +
> +#include "spi_s3c64xx.h"

First, why the separate header file?  It doesn't look like there are
any external users of the header file data.  Please merge it into the
top of the .c file.

> +
> +static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
> +       .name = "s3c64xx-spi-dma",
> +};
> +
> +#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
> +
> +static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
> +{
> +       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
> +       unsigned long loops;
> +       u32 val;
> +
> +       val = readl(sdd->regs + S3C64XX_SPI_CH_CFG);
> +       val |= S3C64XX_SPI_CH_SW_RST;
> +       val &= ~S3C64XX_SPI_CH_HS_EN;
> +       writel(val, sdd->regs + S3C64XX_SPI_CH_CFG);
> +
> +       /* Flush TxFIFO*/
> +       loops = msecs_to_loops(1);
> +       do {
> +               val = readl(sdd->regs + S3C64XX_SPI_STATUS);
> +       } while (TX_FIFO_LVL(val, sci) && loops--);

nasty spin.  Can you sleep here instead?  How much time do you project
is needed to flush the fifo.  It is a worthwhile question to ask on
the other spin loops through this file.

> +static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
> +                                               struct spi_device *spi)
> +{
> +       struct s3c64xx_spi_csinfo *cs;
> +
> +       if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
> +               if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
> +                       /* Deselect the last toggled device */
> +                       cs = sdd->tgl_spi->controller_data;
> +                       if (sdd->tgl_spi->mode & SPI_CS_HIGH)
> +                               cs->set_level(0);
> +                       else
> +                               cs->set_level(1);
> +               }
> +               sdd->tgl_spi = NULL;
> +       }
> +
> +       cs = spi->controller_data;
> +       if (spi->mode & SPI_CS_HIGH)
> +               cs->set_level(1);
> +       else
> +               cs->set_level(0);

cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0) perhaps?

> +
> +       S3C64XX_SPI_ACT(sdd);
> +}
[...]
> +static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
> +                                               struct spi_device *spi)
> +{
> +       struct s3c64xx_spi_csinfo *cs;
> +
> +       S3C64XX_SPI_DEACT(sdd);
> +
> +       if (sdd->tgl_spi == spi)
> +               sdd->tgl_spi = NULL;
> +
> +       cs = spi->controller_data;
> +       if (spi->mode & SPI_CS_HIGH)
> +               cs->set_level(0);
> +       else
> +               cs->set_level(1);

ditto here.

g.



More information about the linux-arm-kernel mailing list