atmel_spi now support dt along with platform data, respective boards need to switch into dm for the same.
Signed-off-by: Jagan Teki <ja...@amarulasolutions.com> --- drivers/spi/atmel_spi.c | 294 +++++++---------------------------- include/dm/platform_data/spi_atmel.h | 17 ++ 2 files changed, 69 insertions(+), 242 deletions(-) create mode 100644 include/dm/platform_data/spi_atmel.h diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 8010ab434c..0bd395bb4a 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -12,240 +12,31 @@ #include <wait_bit.h> #include <asm/io.h> - #include <asm/arch/clk.h> #include <asm/arch/hardware.h> -#ifdef CONFIG_DM_SPI #include <asm/arch/at91_spi.h> -#endif -#ifdef CONFIG_DM_GPIO #include <asm/gpio.h> -#endif + +#include <dm/platform_data/spi_atmel.h> #include "atmel_spi.h" DECLARE_GLOBAL_DATA_PTR; -#ifndef CONFIG_DM_SPI - -static int spi_has_wdrbt(struct atmel_spi_slave *slave) -{ - unsigned int ver; - - ver = spi_readl(slave, VERSION); - - return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); -} - -void spi_init() -{ - -} - -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) -{ - struct atmel_spi_slave *as; - unsigned int scbr; - u32 csrx; - void *regs; - - if (!spi_cs_is_valid(bus, cs)) - return NULL; - - switch (bus) { - case 0: - regs = (void *)ATMEL_BASE_SPI0; - break; -#ifdef ATMEL_BASE_SPI1 - case 1: - regs = (void *)ATMEL_BASE_SPI1; - break; -#endif -#ifdef ATMEL_BASE_SPI2 - case 2: - regs = (void *)ATMEL_BASE_SPI2; - break; -#endif -#ifdef ATMEL_BASE_SPI3 - case 3: - regs = (void *)ATMEL_BASE_SPI3; - break; -#endif - default: - return NULL; - } - - - scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; - if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) - /* Too low max SCK rate */ - return NULL; - if (scbr < 1) - scbr = 1; - - csrx = ATMEL_SPI_CSRx_SCBR(scbr); - csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); - if (!(mode & SPI_CPHA)) - csrx |= ATMEL_SPI_CSRx_NCPHA; - if (mode & SPI_CPOL) - csrx |= ATMEL_SPI_CSRx_CPOL; - - as = spi_alloc_slave(struct atmel_spi_slave, bus, cs); - if (!as) - return NULL; - - as->regs = regs; - as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS - | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); - if (spi_has_wdrbt(as)) - as->mr |= ATMEL_SPI_MR_WDRBT; - - spi_writel(as, CSR(cs), csrx); - - return &as->slave; -} - -void spi_free_slave(struct spi_slave *slave) -{ - struct atmel_spi_slave *as = to_atmel_spi(slave); - - free(as); -} - -int spi_claim_bus(struct spi_slave *slave) -{ - struct atmel_spi_slave *as = to_atmel_spi(slave); - - /* Enable the SPI hardware */ - spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); - - /* - * Select the slave. This should set SCK to the correct - * initial state, etc. - */ - spi_writel(as, MR, as->mr); - - return 0; -} - -void spi_release_bus(struct spi_slave *slave) -{ - struct atmel_spi_slave *as = to_atmel_spi(slave); - - /* Disable the SPI hardware */ - spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); -} - -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) -{ - struct atmel_spi_slave *as = to_atmel_spi(slave); - unsigned int len_tx; - unsigned int len_rx; - unsigned int len; - u32 status; - const u8 *txp = dout; - u8 *rxp = din; - u8 value; - - if (bitlen == 0) - /* Finish any previously submitted transfers */ - goto out; - - /* - * TODO: The controller can do non-multiple-of-8 bit - * transfers, but this driver currently doesn't support it. - * - * It's also not clear how such transfers are supposed to be - * represented as a stream of bytes...this is a limitation of - * the current SPI interface. - */ - if (bitlen % 8) { - /* Errors always terminate an ongoing transfer */ - flags |= SPI_XFER_END; - goto out; - } - - len = bitlen / 8; - - /* - * The controller can do automatic CS control, but it is - * somewhat quirky, and it doesn't really buy us much anyway - * in the context of U-Boot. - */ - if (flags & SPI_XFER_BEGIN) { - spi_cs_activate(slave); - /* - * sometimes the RDR is not empty when we get here, - * in theory that should not happen, but it DOES happen. - * Read it here to be on the safe side. - * That also clears the OVRES flag. Required if the - * following loop exits due to OVRES! - */ - spi_readl(as, RDR); - } - - for (len_tx = 0, len_rx = 0; len_rx < len; ) { - status = spi_readl(as, SR); - - if (status & ATMEL_SPI_SR_OVRES) - return -1; - - if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { - if (txp) - value = *txp++; - else - value = 0; - spi_writel(as, TDR, value); - len_tx++; - } - if (status & ATMEL_SPI_SR_RDRF) { - value = spi_readl(as, RDR); - if (rxp) - *rxp++ = value; - len_rx++; - } - } - -out: - if (flags & SPI_XFER_END) { - /* - * Wait until the transfer is completely done before - * we deactivate CS. - */ - do { - status = spi_readl(as, SR); - } while (!(status & ATMEL_SPI_SR_TXEMPTY)); - - spi_cs_deactivate(slave); - } - - return 0; -} - -#else - -#define MAX_CS_COUNT 4 - -struct atmel_spi_platdata { - struct at91_spi *regs; -}; - struct atmel_spi_priv { + struct at91_spi *regs; unsigned int freq; /* Default frequency */ unsigned int mode; ulong bus_clk_rate; - struct gpio_desc cs_gpios[MAX_CS_COUNT]; + struct gpio_desc *cs_gpios; }; static int atmel_spi_claim_bus(struct udevice *dev) { struct udevice *bus = dev_get_parent(dev); - struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); struct atmel_spi_priv *priv = dev_get_priv(bus); - struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - struct at91_spi *reg_base = bus_plat->regs; + struct dm_spi_slave_platdata *slave_plat = + dev_get_parent_platdata(dev); u32 cs = slave_plat->cs; u32 freq = priv->freq; u32 scbr, csrx, mode; @@ -265,16 +56,16 @@ static int atmel_spi_claim_bus(struct udevice *dev) if (priv->mode & SPI_CPOL) csrx |= ATMEL_SPI_CSRx_CPOL; - writel(csrx, ®_base->csr[cs]); + writel(csrx, &priv->regs->csr[cs]); mode = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS | ATMEL_SPI_MR_WDRBT | ATMEL_SPI_MR_PCS(~(1 << cs)); - writel(mode, ®_base->mr); + writel(mode, &priv->regs->mr); - writel(ATMEL_SPI_CR_SPIEN, ®_base->cr); + writel(ATMEL_SPI_CR_SPIEN, &priv->regs->cr); return 0; } @@ -282,9 +73,9 @@ static int atmel_spi_claim_bus(struct udevice *dev) static int atmel_spi_release_bus(struct udevice *dev) { struct udevice *bus = dev_get_parent(dev); - struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); + struct atmel_spi_priv *priv = dev_get_priv(bus); - writel(ATMEL_SPI_CR_SPIDIS, &bus_plat->regs->cr); + writel(ATMEL_SPI_CR_SPIDIS, &priv->regs->cr); return 0; } @@ -319,8 +110,7 @@ static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev_get_parent(dev); - struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); - struct at91_spi *reg_base = bus_plat->regs; + struct atmel_spi_priv *priv = dev_get_priv(bus); u32 len_tx, len_rx, len; u32 status; @@ -362,11 +152,11 @@ static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, * That also clears the OVRES flag. Required if the * following loop exits due to OVRES! */ - readl(®_base->rdr); + readl(&priv->regs->rdr); } for (len_tx = 0, len_rx = 0; len_rx < len; ) { - status = readl(®_base->sr); + status = readl(&priv->regs->sr); if (status & ATMEL_SPI_SR_OVRES) return -1; @@ -376,12 +166,12 @@ static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, value = *txp++; else value = 0; - writel(value, ®_base->tdr); + writel(value, &priv->regs->tdr); len_tx++; } if (status & ATMEL_SPI_SR_RDRF) { - value = readl(®_base->rdr); + value = readl(&priv->regs->rdr); if (rxp) *rxp++ = value; len_rx++; @@ -394,7 +184,7 @@ out: * Wait until the transfer is completely done before * we deactivate CS. */ - wait_for_bit_le32(®_base->sr, + wait_for_bit_le32(&priv->regs->sr, ATMEL_SPI_SR_TXEMPTY, true, 1000, false); atmel_spi_cs_deactivate(dev); @@ -461,23 +251,17 @@ static int atmel_spi_enable_clk(struct udevice *bus) static int atmel_spi_probe(struct udevice *bus) { - struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); + struct atmel_spi_platdata *plat = dev_get_platdata(bus); struct atmel_spi_priv *priv = dev_get_priv(bus); int i, ret; + priv->regs = plat->regs; + priv->cs_gpios = plat->cs_gpios; + ret = atmel_spi_enable_clk(bus); if (ret) return ret; - - bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus); - - ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios, - ARRAY_SIZE(priv->cs_gpios), 0); - if (ret < 0) { - pr_err("Can't get %s gpios! Error: %d", bus->name, ret); - return ret; - } - + for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { if (!dm_gpio_is_valid(&priv->cs_gpios[i])) continue; @@ -486,7 +270,30 @@ static int atmel_spi_probe(struct udevice *bus) GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); } - writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr); + writel(ATMEL_SPI_CR_SWRST, &priv->regs->cr); + + return 0; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static int atmel_ofdata_to_platadata(struct udevice *bus) +{ + struct atmel_spi_platdata *plat = bus->platdata; + fdt_addr_t addr; + int ret; + + addr = devfdt_get_addr(bus); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->regs = (struct at91_spi *)addr; + + ret = gpio_request_list_by_name(bus, "cs-gpios", plat->cs_gpios, + ARRAY_SIZE(plat->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s gpios! Error: %d", bus->name, ret); + return ret; + } return 0; } @@ -495,14 +302,17 @@ static const struct udevice_id atmel_spi_ids[] = { { .compatible = "atmel,at91rm9200-spi" }, { } }; +#endif U_BOOT_DRIVER(atmel_spi) = { .name = "atmel_spi", .id = UCLASS_SPI, +#if CONFIG_IS_ENABLED(OF_CONTROL) .of_match = atmel_spi_ids, - .ops = &atmel_spi_ops, + .ofdata_to_platdata = atmel_ofdata_to_platadata, .platdata_auto_alloc_size = sizeof(struct atmel_spi_platdata), - .priv_auto_alloc_size = sizeof(struct atmel_spi_priv), +#endif .probe = atmel_spi_probe, + .ops = &atmel_spi_ops, + .priv_auto_alloc_size = sizeof(struct atmel_spi_priv), }; -#endif diff --git a/include/dm/platform_data/spi_atmel.h b/include/dm/platform_data/spi_atmel.h new file mode 100644 index 0000000000..a5bb5665a3 --- /dev/null +++ b/include/dm/platform_data/spi_atmel.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Jagan Teki <ja...@amarulasolutions.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __spi_atmel_h +#define __spi_atmel_h + +#define MAX_CS_COUNT 4 + +struct atmel_spi_platdata { + struct at91_spi *regs; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; +}; + +#endif /* __spi_atmel_h */ -- 2.14.3 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot