X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fspi%2Fspi-uclass.c;h=247abfa72ba1c28f904bd8df846df2e17464e441;hb=fe34b6a4845476208ca7d19a35179e56bebf3877;hp=13c6b77d73df350f943b1dd3c77ce8c7e0fef0c3;hpb=1fba907f9a8d178eee960294ecffc8ee8bc6b00d;p=u-boot diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 13c6b77d73..247abfa72b 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -45,45 +44,46 @@ static int spi_set_speed_mode(struct udevice *bus, int speed, int mode) return 0; } -int spi_claim_bus(struct spi_slave *slave) +int dm_spi_claim_bus(struct udevice *dev) { - struct udevice *dev = slave->dev; struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); - struct dm_spi_bus *spi = bus->uclass_priv; + struct dm_spi_bus *spi = dev_get_uclass_priv(bus); + struct spi_slave *slave = dev_get_parent_priv(dev); int speed; int ret; speed = slave->max_hz; if (spi->max_hz) { if (speed) - speed = min(speed, spi->max_hz); + speed = min(speed, (int)spi->max_hz); else speed = spi->max_hz; } if (!speed) speed = 100000; - ret = spi_set_speed_mode(bus, speed, slave->mode); - if (ret) - return ret; + if (speed != slave->speed) { + ret = spi_set_speed_mode(bus, speed, slave->mode); + if (ret) + return ret; + slave->speed = speed; + } - return ops->claim_bus ? ops->claim_bus(bus) : 0; + return ops->claim_bus ? ops->claim_bus(dev) : 0; } -void spi_release_bus(struct spi_slave *slave) +void dm_spi_release_bus(struct udevice *dev) { - struct udevice *dev = slave->dev; struct udevice *bus = dev->parent; struct dm_spi_ops *ops = spi_get_ops(bus); if (ops->release_bus) - ops->release_bus(bus); + ops->release_bus(dev); } -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +int dm_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { - struct udevice *dev = slave->dev; struct udevice *bus = dev->parent; if (bus->uclass->uc_drv->id != UCLASS_SPI) @@ -92,55 +92,102 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags); } -int spi_post_bind(struct udevice *dev) +int spi_claim_bus(struct spi_slave *slave) +{ + return dm_spi_claim_bus(slave->dev); +} + +void spi_release_bus(struct spi_slave *slave) +{ + dm_spi_release_bus(slave->dev); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); + return dm_spi_xfer(slave->dev, bitlen, dout, din, flags); } -int spi_post_probe(struct udevice *dev) +static int spi_child_post_bind(struct udevice *dev) { - struct dm_spi_bus *spi = dev->uclass_priv; + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); - spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + if (dev->of_offset == -1) + return 0; + + return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat); +} + +static int spi_post_probe(struct udevice *bus) +{ + struct dm_spi_bus *spi = dev_get_uclass_priv(bus); + + spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset, "spi-max-frequency", 0); +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct dm_spi_ops *ops = spi_get_ops(bus); + + + if (ops->claim_bus) + ops->claim_bus += gd->reloc_off; + if (ops->release_bus) + ops->release_bus += gd->reloc_off; + if (ops->set_wordlen) + ops->set_wordlen += gd->reloc_off; + if (ops->xfer) + ops->xfer += gd->reloc_off; + if (ops->set_speed) + ops->set_speed += gd->reloc_off; + if (ops->set_mode) + ops->set_mode += gd->reloc_off; + if (ops->cs_info) + ops->cs_info += gd->reloc_off; +#endif + + return 0; +} + +static int spi_child_pre_probe(struct udevice *dev) +{ + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); + struct spi_slave *slave = dev_get_parent_priv(dev); + + /* + * This is needed because we pass struct spi_slave around the place + * instead slave->dev (a struct udevice). So we have to have some + * way to access the slave udevice given struct spi_slave. Once we + * change the SPI API to use udevice instead of spi_slave, we can + * drop this. + */ + slave->dev = dev; + + slave->max_hz = plat->max_hz; + slave->mode = plat->mode; + slave->mode_rx = plat->mode_rx; + slave->wordlen = SPI_DEFAULT_WORDLEN; + return 0; } int spi_chip_select(struct udevice *dev) { - struct spi_slave *slave = dev_get_parentdata(dev); + struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); - return slave ? slave->cs : -ENOENT; + return plat ? plat->cs : -ENOENT; } -/** - * spi_find_chip_select() - Find the slave attached to chip select - * - * @bus: SPI bus to search - * @cs: Chip select to look for - * @devp: Returns the slave device if found - * @return 0 if found, -ENODEV on error - */ -static int spi_find_chip_select(struct udevice *bus, int cs, - struct udevice **devp) +int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) { struct udevice *dev; for (device_find_first_child(bus, &dev); dev; device_find_next_child(&dev)) { - struct spi_slave store; - struct spi_slave *slave = dev_get_parentdata(dev); + struct dm_spi_slave_platdata *plat; - if (!slave) { - slave = &store; - spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, - slave); - } - debug("%s: slave=%p, cs=%d\n", __func__, slave, - slave ? slave->cs : -1); - if (slave && slave->cs == cs) { + plat = dev_get_parent_platdata(dev); + debug("%s: plat=%p, cs=%d\n", __func__, plat, plat->cs); + if (plat->cs == cs) { *devp = dev; return 0; } @@ -197,27 +244,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) return -ENODEV; } -int spi_bind_device(struct udevice *bus, int cs, const char *drv_name, - const char *dev_name, struct udevice **devp) -{ - struct driver *drv; - int ret; - - drv = lists_driver_lookup_name(drv_name); - if (!drv) { - printf("Cannot find driver '%s'\n", drv_name); - return -ENOENT; - } - ret = device_bind(bus, drv, dev_name, NULL, -1, devp); - if (ret) { - printf("Cannot create device named '%s' (err=%d)\n", - dev_name, ret); - return ret; - } - - return 0; -} - int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, struct udevice **devp) { @@ -245,7 +271,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, struct udevice **busp, struct spi_slave **devp) { struct udevice *bus, *dev; - struct spi_slave *slave; + struct dm_spi_slave_platdata *plat; bool created = false; int ret; @@ -264,9 +290,13 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, if (ret == -ENODEV && drv_name) { debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", __func__, dev_name, busnum, cs, drv_name); - ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev); + ret = device_bind_driver(bus, drv_name, dev_name, &dev); if (ret) return ret; + plat = dev_get_parent_platdata(dev); + plat->cs = cs; + plat->max_hz = speed; + plat->mode = mode; created = true; } else if (ret) { printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs, @@ -275,36 +305,33 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, } if (!device_active(dev)) { - slave = (struct spi_slave *)calloc(1, - sizeof(struct spi_slave)); - if (!slave) { - ret = -ENOMEM; - goto err; - } + struct spi_slave *slave; - ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, - slave); + ret = device_probe(dev); if (ret) goto err; - slave->cs = cs; + slave = dev_get_parent_priv(dev); slave->dev = dev; - ret = device_probe_child(dev, slave); - free(slave); - if (ret) - goto err; } + plat = dev_get_parent_platdata(dev); + if (!speed) { + speed = plat->max_hz; + mode = plat->mode; + } ret = spi_set_speed_mode(bus, speed, mode); if (ret) goto err; *busp = bus; - *devp = dev_get_parentdata(dev); + *devp = dev_get_parent_priv(dev); debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp); return 0; err: + debug("%s: Error path, created=%d, device '%s'\n", __func__, + created, dev->name); if (created) { device_remove(dev); device_unbind(dev); @@ -326,7 +353,7 @@ struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, ret = device_get_child_by_of_offset(bus, node, &dev); if (ret) return NULL; - return dev_get_parentdata(dev); + return dev_get_parent_priv(dev); } /* Compatibility function - to be removed */ @@ -351,22 +378,59 @@ void spi_free_slave(struct spi_slave *slave) slave->dev = NULL; } -int spi_ofdata_to_platdata(const void *blob, int node, - struct spi_slave *spi) +int spi_slave_ofdata_to_platdata(const void *blob, int node, + struct dm_spi_slave_platdata *plat) { - int mode = 0; + int mode = 0, mode_rx = 0; + int value; - spi->cs = fdtdec_get_int(blob, node, "reg", -1); - spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0); + plat->cs = fdtdec_get_int(blob, node, "reg", -1); + plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0); if (fdtdec_get_bool(blob, node, "spi-cpol")) mode |= SPI_CPOL; if (fdtdec_get_bool(blob, node, "spi-cpha")) mode |= SPI_CPHA; if (fdtdec_get_bool(blob, node, "spi-cs-high")) mode |= SPI_CS_HIGH; + if (fdtdec_get_bool(blob, node, "spi-3wire")) + mode |= SPI_3WIRE; if (fdtdec_get_bool(blob, node, "spi-half-duplex")) mode |= SPI_PREAMBLE; - spi->mode = mode; + + /* Device DUAL/QUAD mode */ + value = fdtdec_get_uint(blob, node, "spi-tx-bus-width", 1); + switch (value) { + case 1: + break; + case 2: + mode |= SPI_TX_DUAL; + break; + case 4: + mode |= SPI_TX_QUAD; + break; + default: + error("spi-tx-bus-width %d not supported\n", value); + break; + } + + plat->mode = mode; + + value = fdtdec_get_uint(blob, node, "spi-rx-bus-width", 1); + switch (value) { + case 1: + break; + case 2: + mode_rx |= SPI_RX_DUAL; + break; + case 4: + mode_rx |= SPI_RX_QUAD; + break; + default: + error("spi-rx-bus-width %d not supported\n", value); + break; + } + + plat->mode_rx = mode_rx; return 0; } @@ -374,9 +438,15 @@ int spi_ofdata_to_platdata(const void *blob, int node, UCLASS_DRIVER(spi) = { .id = UCLASS_SPI, .name = "spi", - .post_bind = spi_post_bind, + .flags = DM_UC_FLAG_SEQ_ALIAS, + .post_bind = dm_scan_fdt_dev, .post_probe = spi_post_probe, + .child_pre_probe = spi_child_pre_probe, .per_device_auto_alloc_size = sizeof(struct dm_spi_bus), + .per_child_auto_alloc_size = sizeof(struct spi_slave), + .per_child_platdata_auto_alloc_size = + sizeof(struct dm_spi_slave_platdata), + .child_post_bind = spi_child_post_bind, }; UCLASS_DRIVER(spi_generic) = {