1623b6386SSimon Glass /* 2623b6386SSimon Glass * Copyright (c) 2014 Google, Inc 3623b6386SSimon Glass * 4623b6386SSimon Glass * (C) Copyright 2002 5623b6386SSimon Glass * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 6623b6386SSimon Glass * 7623b6386SSimon Glass * Influenced by code from: 8623b6386SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9623b6386SSimon Glass * 10623b6386SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 11623b6386SSimon Glass */ 12623b6386SSimon Glass 13623b6386SSimon Glass #include <common.h> 14623b6386SSimon Glass #include <dm.h> 15623b6386SSimon Glass #include <errno.h> 16623b6386SSimon Glass #include <fdtdec.h> 17623b6386SSimon Glass #include <malloc.h> 18623b6386SSimon Glass #include <spi.h> 19623b6386SSimon Glass #include <asm/gpio.h> 20623b6386SSimon Glass 21623b6386SSimon Glass DECLARE_GLOBAL_DATA_PTR; 22623b6386SSimon Glass 23623b6386SSimon Glass struct soft_spi_platdata { 24050fb909SSimon Glass struct gpio_desc cs; 25050fb909SSimon Glass struct gpio_desc sclk; 26050fb909SSimon Glass struct gpio_desc mosi; 27050fb909SSimon Glass struct gpio_desc miso; 28623b6386SSimon Glass int spi_delay_us; 29*102412c4SPeng Fan int flags; 30623b6386SSimon Glass }; 31623b6386SSimon Glass 32*102412c4SPeng Fan #define SPI_MASTER_NO_RX BIT(0) 33*102412c4SPeng Fan #define SPI_MASTER_NO_TX BIT(1) 34*102412c4SPeng Fan 35623b6386SSimon Glass struct soft_spi_priv { 36623b6386SSimon Glass unsigned int mode; 37623b6386SSimon Glass }; 38623b6386SSimon Glass 39623b6386SSimon Glass static int soft_spi_scl(struct udevice *dev, int bit) 40623b6386SSimon Glass { 41b6d54d52SPeng Fan struct udevice *bus = dev_get_parent(dev); 42b6d54d52SPeng Fan struct soft_spi_platdata *plat = dev_get_platdata(bus); 43623b6386SSimon Glass 44050fb909SSimon Glass dm_gpio_set_value(&plat->sclk, bit); 45623b6386SSimon Glass 46623b6386SSimon Glass return 0; 47623b6386SSimon Glass } 48623b6386SSimon Glass 49623b6386SSimon Glass static int soft_spi_sda(struct udevice *dev, int bit) 50623b6386SSimon Glass { 51b6d54d52SPeng Fan struct udevice *bus = dev_get_parent(dev); 52b6d54d52SPeng Fan struct soft_spi_platdata *plat = dev_get_platdata(bus); 53623b6386SSimon Glass 54050fb909SSimon Glass dm_gpio_set_value(&plat->mosi, bit); 55623b6386SSimon Glass 56623b6386SSimon Glass return 0; 57623b6386SSimon Glass } 58623b6386SSimon Glass 59623b6386SSimon Glass static int soft_spi_cs_activate(struct udevice *dev) 60623b6386SSimon Glass { 61b6d54d52SPeng Fan struct udevice *bus = dev_get_parent(dev); 62b6d54d52SPeng Fan struct soft_spi_platdata *plat = dev_get_platdata(bus); 63623b6386SSimon Glass 64050fb909SSimon Glass dm_gpio_set_value(&plat->cs, 0); 65050fb909SSimon Glass dm_gpio_set_value(&plat->sclk, 0); 66050fb909SSimon Glass dm_gpio_set_value(&plat->cs, 1); 67623b6386SSimon Glass 68623b6386SSimon Glass return 0; 69623b6386SSimon Glass } 70623b6386SSimon Glass 71623b6386SSimon Glass static int soft_spi_cs_deactivate(struct udevice *dev) 72623b6386SSimon Glass { 73b6d54d52SPeng Fan struct udevice *bus = dev_get_parent(dev); 74b6d54d52SPeng Fan struct soft_spi_platdata *plat = dev_get_platdata(bus); 75623b6386SSimon Glass 76050fb909SSimon Glass dm_gpio_set_value(&plat->cs, 0); 77623b6386SSimon Glass 78623b6386SSimon Glass return 0; 79623b6386SSimon Glass } 80623b6386SSimon Glass 81623b6386SSimon Glass static int soft_spi_claim_bus(struct udevice *dev) 82623b6386SSimon Glass { 83623b6386SSimon Glass /* 84623b6386SSimon Glass * Make sure the SPI clock is in idle state as defined for 85623b6386SSimon Glass * this slave. 86623b6386SSimon Glass */ 87623b6386SSimon Glass return soft_spi_scl(dev, 0); 88623b6386SSimon Glass } 89623b6386SSimon Glass 90623b6386SSimon Glass static int soft_spi_release_bus(struct udevice *dev) 91623b6386SSimon Glass { 92623b6386SSimon Glass /* Nothing to do */ 93623b6386SSimon Glass return 0; 94623b6386SSimon Glass } 95623b6386SSimon Glass 96623b6386SSimon Glass /*----------------------------------------------------------------------- 97623b6386SSimon Glass * SPI transfer 98623b6386SSimon Glass * 99623b6386SSimon Glass * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks 100623b6386SSimon Glass * "bitlen" bits in the SPI MISO port. That's just the way SPI works. 101623b6386SSimon Glass * 102623b6386SSimon Glass * The source of the outgoing bits is the "dout" parameter and the 103623b6386SSimon Glass * destination of the input bits is the "din" parameter. Note that "dout" 104623b6386SSimon Glass * and "din" can point to the same memory location, in which case the 105623b6386SSimon Glass * input data overwrites the output data (since both are buffered by 106623b6386SSimon Glass * temporary variables, this is OK). 107623b6386SSimon Glass */ 108623b6386SSimon Glass static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, 109623b6386SSimon Glass const void *dout, void *din, unsigned long flags) 110623b6386SSimon Glass { 111b6d54d52SPeng Fan struct udevice *bus = dev_get_parent(dev); 112b6d54d52SPeng Fan struct soft_spi_priv *priv = dev_get_priv(bus); 113b6d54d52SPeng Fan struct soft_spi_platdata *plat = dev_get_platdata(bus); 114623b6386SSimon Glass uchar tmpdin = 0; 115623b6386SSimon Glass uchar tmpdout = 0; 116623b6386SSimon Glass const u8 *txd = dout; 117623b6386SSimon Glass u8 *rxd = din; 118623b6386SSimon Glass int cpha = priv->mode & SPI_CPHA; 119623b6386SSimon Glass unsigned int j; 120623b6386SSimon Glass 121623b6386SSimon Glass debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", 122623b6386SSimon Glass dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, 123623b6386SSimon Glass bitlen); 124623b6386SSimon Glass 125623b6386SSimon Glass if (flags & SPI_XFER_BEGIN) 126623b6386SSimon Glass soft_spi_cs_activate(dev); 127623b6386SSimon Glass 128623b6386SSimon Glass for (j = 0; j < bitlen; j++) { 129623b6386SSimon Glass /* 130623b6386SSimon Glass * Check if it is time to work on a new byte. 131623b6386SSimon Glass */ 132623b6386SSimon Glass if ((j % 8) == 0) { 133623b6386SSimon Glass if (txd) 134623b6386SSimon Glass tmpdout = *txd++; 135623b6386SSimon Glass else 136623b6386SSimon Glass tmpdout = 0; 137623b6386SSimon Glass if (j != 0) { 138623b6386SSimon Glass if (rxd) 139623b6386SSimon Glass *rxd++ = tmpdin; 140623b6386SSimon Glass } 141623b6386SSimon Glass tmpdin = 0; 142623b6386SSimon Glass } 143623b6386SSimon Glass 144623b6386SSimon Glass if (!cpha) 145050fb909SSimon Glass soft_spi_scl(dev, 0); 146*102412c4SPeng Fan if ((plat->flags & SPI_MASTER_NO_TX) == 0) 147b6d54d52SPeng Fan soft_spi_sda(dev, !!(tmpdout & 0x80)); 148623b6386SSimon Glass udelay(plat->spi_delay_us); 149623b6386SSimon Glass if (cpha) 150050fb909SSimon Glass soft_spi_scl(dev, 0); 151623b6386SSimon Glass else 152050fb909SSimon Glass soft_spi_scl(dev, 1); 153623b6386SSimon Glass tmpdin <<= 1; 154*102412c4SPeng Fan if ((plat->flags & SPI_MASTER_NO_RX) == 0) 155050fb909SSimon Glass tmpdin |= dm_gpio_get_value(&plat->miso); 156623b6386SSimon Glass tmpdout <<= 1; 157623b6386SSimon Glass udelay(plat->spi_delay_us); 158623b6386SSimon Glass if (cpha) 159050fb909SSimon Glass soft_spi_scl(dev, 1); 160623b6386SSimon Glass } 161623b6386SSimon Glass /* 162623b6386SSimon Glass * If the number of bits isn't a multiple of 8, shift the last 163623b6386SSimon Glass * bits over to left-justify them. Then store the last byte 164623b6386SSimon Glass * read in. 165623b6386SSimon Glass */ 166623b6386SSimon Glass if (rxd) { 167623b6386SSimon Glass if ((bitlen % 8) != 0) 168623b6386SSimon Glass tmpdin <<= 8 - (bitlen % 8); 169623b6386SSimon Glass *rxd++ = tmpdin; 170623b6386SSimon Glass } 171623b6386SSimon Glass 172623b6386SSimon Glass if (flags & SPI_XFER_END) 173623b6386SSimon Glass soft_spi_cs_deactivate(dev); 174623b6386SSimon Glass 175623b6386SSimon Glass return 0; 176623b6386SSimon Glass } 177623b6386SSimon Glass 178623b6386SSimon Glass static int soft_spi_set_speed(struct udevice *dev, unsigned int speed) 179623b6386SSimon Glass { 180623b6386SSimon Glass /* Accept any speed */ 181623b6386SSimon Glass return 0; 182623b6386SSimon Glass } 183623b6386SSimon Glass 184623b6386SSimon Glass static int soft_spi_set_mode(struct udevice *dev, unsigned int mode) 185623b6386SSimon Glass { 186623b6386SSimon Glass struct soft_spi_priv *priv = dev_get_priv(dev); 187623b6386SSimon Glass 188623b6386SSimon Glass priv->mode = mode; 189623b6386SSimon Glass 190623b6386SSimon Glass return 0; 191623b6386SSimon Glass } 192623b6386SSimon Glass 193623b6386SSimon Glass static const struct dm_spi_ops soft_spi_ops = { 194623b6386SSimon Glass .claim_bus = soft_spi_claim_bus, 195623b6386SSimon Glass .release_bus = soft_spi_release_bus, 196623b6386SSimon Glass .xfer = soft_spi_xfer, 197623b6386SSimon Glass .set_speed = soft_spi_set_speed, 198623b6386SSimon Glass .set_mode = soft_spi_set_mode, 199623b6386SSimon Glass }; 200623b6386SSimon Glass 201623b6386SSimon Glass static int soft_spi_ofdata_to_platdata(struct udevice *dev) 202623b6386SSimon Glass { 203623b6386SSimon Glass struct soft_spi_platdata *plat = dev->platdata; 204623b6386SSimon Glass const void *blob = gd->fdt_blob; 205623b6386SSimon Glass int node = dev->of_offset; 206623b6386SSimon Glass 207623b6386SSimon Glass plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0); 208623b6386SSimon Glass 209623b6386SSimon Glass return 0; 210623b6386SSimon Glass } 211623b6386SSimon Glass 212623b6386SSimon Glass static int soft_spi_probe(struct udevice *dev) 213623b6386SSimon Glass { 214bcbe3d15SSimon Glass struct spi_slave *slave = dev_get_parent_priv(dev); 215623b6386SSimon Glass struct soft_spi_platdata *plat = dev->platdata; 216050fb909SSimon Glass int cs_flags, clk_flags; 217*102412c4SPeng Fan int ret; 218623b6386SSimon Glass 219050fb909SSimon Glass cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; 220050fb909SSimon Glass clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; 221*102412c4SPeng Fan 222*102412c4SPeng Fan if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs, 223050fb909SSimon Glass GPIOD_IS_OUT | cs_flags) || 224*102412c4SPeng Fan gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk, 225*102412c4SPeng Fan GPIOD_IS_OUT | clk_flags)) 226*102412c4SPeng Fan return -EINVAL; 227*102412c4SPeng Fan 228*102412c4SPeng Fan ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi, 229*102412c4SPeng Fan GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 230*102412c4SPeng Fan if (ret) 231*102412c4SPeng Fan plat->flags |= SPI_MASTER_NO_TX; 232*102412c4SPeng Fan 233*102412c4SPeng Fan ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso, 234*102412c4SPeng Fan GPIOD_IS_IN); 235*102412c4SPeng Fan if (ret) 236*102412c4SPeng Fan plat->flags |= SPI_MASTER_NO_RX; 237*102412c4SPeng Fan 238*102412c4SPeng Fan if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) == 239*102412c4SPeng Fan (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) 240050fb909SSimon Glass return -EINVAL; 241623b6386SSimon Glass 242623b6386SSimon Glass return 0; 243623b6386SSimon Glass } 244623b6386SSimon Glass 245623b6386SSimon Glass static const struct udevice_id soft_spi_ids[] = { 246*102412c4SPeng Fan { .compatible = "spi-gpio" }, 247623b6386SSimon Glass { } 248623b6386SSimon Glass }; 249623b6386SSimon Glass 250623b6386SSimon Glass U_BOOT_DRIVER(soft_spi) = { 251623b6386SSimon Glass .name = "soft_spi", 252623b6386SSimon Glass .id = UCLASS_SPI, 253623b6386SSimon Glass .of_match = soft_spi_ids, 254623b6386SSimon Glass .ops = &soft_spi_ops, 255623b6386SSimon Glass .ofdata_to_platdata = soft_spi_ofdata_to_platdata, 256623b6386SSimon Glass .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), 257623b6386SSimon Glass .priv_auto_alloc_size = sizeof(struct soft_spi_priv), 258623b6386SSimon Glass .probe = soft_spi_probe, 259623b6386SSimon Glass }; 260