X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fspi%2Fsoft_spi.c;h=d23dc81a211edc865b516f07a1e8e3a45f9e4993;hb=ec5507707a1d1e84056a6c864338f95f6118d3ca;hp=5d22351290b6337280434cca41e2dd3372c504d2;hpb=c2120fbfbc4d1f6953228f86be8bdbf38bacfdab;p=karo-tx-uboot.git diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c index 5d22351290..d23dc81a21 100644 --- a/drivers/spi/soft_spi.c +++ b/drivers/spi/soft_spi.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2014 Google, Inc + * * (C) Copyright 2002 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. * @@ -9,94 +11,86 @@ */ #include +#include +#include +#include +#include #include +#include -#include +DECLARE_GLOBAL_DATA_PTR; -/*----------------------------------------------------------------------- - * Definitions - */ +struct soft_spi_platdata { + struct gpio_desc cs; + struct gpio_desc sclk; + struct gpio_desc mosi; + struct gpio_desc miso; + int spi_delay_us; + int flags; +}; -#ifdef DEBUG_SPI -#define PRINTD(fmt,args...) printf (fmt ,##args) -#else -#define PRINTD(fmt,args...) -#endif +#define SPI_MASTER_NO_RX BIT(0) +#define SPI_MASTER_NO_TX BIT(1) -struct soft_spi_slave { - struct spi_slave slave; +struct soft_spi_priv { unsigned int mode; }; -static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) +static int soft_spi_scl(struct udevice *dev, int bit) { - return container_of(slave, struct soft_spi_slave, slave); -} + struct udevice *bus = dev_get_parent(dev); + struct soft_spi_platdata *plat = dev_get_platdata(bus); -/*=====================================================================*/ -/* Public Functions */ -/*=====================================================================*/ + dm_gpio_set_value(&plat->sclk, bit); -/*----------------------------------------------------------------------- - * Initialization - */ -void spi_init (void) -{ -#ifdef SPI_INIT - volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; - - SPI_INIT; -#endif + return 0; } -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) +static int soft_spi_sda(struct udevice *dev, int bit) { - struct soft_spi_slave *ss; + struct udevice *bus = dev_get_parent(dev); + struct soft_spi_platdata *plat = dev_get_platdata(bus); - if (!spi_cs_is_valid(bus, cs)) - return NULL; + dm_gpio_set_value(&plat->mosi, bit); - ss = spi_alloc_slave(struct soft_spi_slave, bus, cs); - if (!ss) - return NULL; + return 0; +} - ss->mode = mode; +static int soft_spi_cs_activate(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct soft_spi_platdata *plat = dev_get_platdata(bus); - /* TODO: Use max_hz to limit the SCK rate */ + dm_gpio_set_value(&plat->cs, 0); + dm_gpio_set_value(&plat->sclk, 0); + dm_gpio_set_value(&plat->cs, 1); - return &ss->slave; + return 0; } -void spi_free_slave(struct spi_slave *slave) +static int soft_spi_cs_deactivate(struct udevice *dev) { - struct soft_spi_slave *ss = to_soft_spi(slave); + struct udevice *bus = dev_get_parent(dev); + struct soft_spi_platdata *plat = dev_get_platdata(bus); - free(ss); + dm_gpio_set_value(&plat->cs, 0); + + return 0; } -int spi_claim_bus(struct spi_slave *slave) +static int soft_spi_claim_bus(struct udevice *dev) { -#ifdef CONFIG_SYS_IMMR - volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; -#endif - struct soft_spi_slave *ss = to_soft_spi(slave); - /* * Make sure the SPI clock is in idle state as defined for * this slave. */ - if (ss->mode & SPI_CPOL) - SPI_SCL(1); - else - SPI_SCL(0); - - return 0; + return soft_spi_scl(dev, 0); } -void spi_release_bus(struct spi_slave *slave) +static int soft_spi_release_bus(struct udevice *dev) { /* Nothing to do */ + return 0; } /*----------------------------------------------------------------------- @@ -111,65 +105,155 @@ void spi_release_bus(struct spi_slave *slave) * input data overwrites the output data (since both are buffered by * temporary variables, this is OK). */ -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { -#ifdef CONFIG_SYS_IMMR - volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; -#endif - struct soft_spi_slave *ss = to_soft_spi(slave); + struct udevice *bus = dev_get_parent(dev); + struct soft_spi_priv *priv = dev_get_priv(bus); + struct soft_spi_platdata *plat = dev_get_platdata(bus); uchar tmpdin = 0; uchar tmpdout = 0; const u8 *txd = dout; u8 *rxd = din; - int cpol = ss->mode & SPI_CPOL; - int cpha = ss->mode & SPI_CPHA; + int cpha = priv->mode & SPI_CPHA; unsigned int j; - PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", - slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen); + debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", + dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, + bitlen); if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); + soft_spi_cs_activate(dev); - for(j = 0; j < bitlen; j++) { + for (j = 0; j < bitlen; j++) { /* * Check if it is time to work on a new byte. */ - if((j % 8) == 0) { - tmpdout = *txd++; - if(j != 0) { - *rxd++ = tmpdin; + if ((j % 8) == 0) { + if (txd) + tmpdout = *txd++; + else + tmpdout = 0; + if (j != 0) { + if (rxd) + *rxd++ = tmpdin; } tmpdin = 0; } if (!cpha) - SPI_SCL(!cpol); - SPI_SDA(tmpdout & 0x80); - SPI_DELAY; + soft_spi_scl(dev, 0); + if ((plat->flags & SPI_MASTER_NO_TX) == 0) + soft_spi_sda(dev, !!(tmpdout & 0x80)); + udelay(plat->spi_delay_us); if (cpha) - SPI_SCL(!cpol); + soft_spi_scl(dev, 0); else - SPI_SCL(cpol); + soft_spi_scl(dev, 1); tmpdin <<= 1; - tmpdin |= SPI_READ; + if ((plat->flags & SPI_MASTER_NO_RX) == 0) + tmpdin |= dm_gpio_get_value(&plat->miso); tmpdout <<= 1; - SPI_DELAY; + udelay(plat->spi_delay_us); if (cpha) - SPI_SCL(cpol); + soft_spi_scl(dev, 1); } /* * If the number of bits isn't a multiple of 8, shift the last * bits over to left-justify them. Then store the last byte * read in. */ - if((bitlen % 8) != 0) - tmpdin <<= 8 - (bitlen % 8); - *rxd++ = tmpdin; + if (rxd) { + if ((bitlen % 8) != 0) + tmpdin <<= 8 - (bitlen % 8); + *rxd++ = tmpdin; + } if (flags & SPI_XFER_END) - spi_cs_deactivate(slave); + soft_spi_cs_deactivate(dev); + + return 0; +} + +static int soft_spi_set_speed(struct udevice *dev, unsigned int speed) +{ + /* Accept any speed */ + return 0; +} + +static int soft_spi_set_mode(struct udevice *dev, unsigned int mode) +{ + struct soft_spi_priv *priv = dev_get_priv(dev); + + priv->mode = mode; + + return 0; +} + +static const struct dm_spi_ops soft_spi_ops = { + .claim_bus = soft_spi_claim_bus, + .release_bus = soft_spi_release_bus, + .xfer = soft_spi_xfer, + .set_speed = soft_spi_set_speed, + .set_mode = soft_spi_set_mode, +}; + +static int soft_spi_ofdata_to_platdata(struct udevice *dev) +{ + struct soft_spi_platdata *plat = dev->platdata; + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + + plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0); + + return 0; +} + +static int soft_spi_probe(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + struct soft_spi_platdata *plat = dev->platdata; + int cs_flags, clk_flags; + int ret; + + cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; + clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; + + if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs, + GPIOD_IS_OUT | cs_flags) || + gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk, + GPIOD_IS_OUT | clk_flags)) + return -EINVAL; + + ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + if (ret) + plat->flags |= SPI_MASTER_NO_TX; - return(0); + ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso, + GPIOD_IS_IN); + if (ret) + plat->flags |= SPI_MASTER_NO_RX; + + if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) == + (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) + return -EINVAL; + + return 0; } + +static const struct udevice_id soft_spi_ids[] = { + { .compatible = "spi-gpio" }, + { } +}; + +U_BOOT_DRIVER(soft_spi) = { + .name = "soft_spi", + .id = UCLASS_SPI, + .of_match = soft_spi_ids, + .ops = &soft_spi_ops, + .ofdata_to_platdata = soft_spi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), + .priv_auto_alloc_size = sizeof(struct soft_spi_priv), + .probe = soft_spi_probe, +};