1 /* 2 * Copyright (c) 2014 Google, Inc 3 * 4 * (C) Copyright 2002 5 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 6 * 7 * Influenced by code from: 8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 13 #include <common.h> 14 #include <dm.h> 15 #include <errno.h> 16 #include <fdtdec.h> 17 #include <malloc.h> 18 #include <spi.h> 19 #include <asm/gpio.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 struct soft_spi_platdata { 24 struct gpio_desc cs; 25 struct gpio_desc sclk; 26 struct gpio_desc mosi; 27 struct gpio_desc miso; 28 int spi_delay_us; 29 }; 30 31 struct soft_spi_priv { 32 unsigned int mode; 33 }; 34 35 static int soft_spi_scl(struct udevice *dev, int bit) 36 { 37 struct soft_spi_platdata *plat = dev->platdata; 38 39 dm_gpio_set_value(&plat->sclk, bit); 40 41 return 0; 42 } 43 44 static int soft_spi_sda(struct udevice *dev, int bit) 45 { 46 struct soft_spi_platdata *plat = dev->platdata; 47 48 dm_gpio_set_value(&plat->mosi, bit); 49 50 return 0; 51 } 52 53 static int soft_spi_cs_activate(struct udevice *dev) 54 { 55 struct soft_spi_platdata *plat = dev->platdata; 56 57 dm_gpio_set_value(&plat->cs, 0); 58 dm_gpio_set_value(&plat->sclk, 0); 59 dm_gpio_set_value(&plat->cs, 1); 60 61 return 0; 62 } 63 64 static int soft_spi_cs_deactivate(struct udevice *dev) 65 { 66 struct soft_spi_platdata *plat = dev->platdata; 67 68 dm_gpio_set_value(&plat->cs, 0); 69 70 return 0; 71 } 72 73 static int soft_spi_claim_bus(struct udevice *dev) 74 { 75 /* 76 * Make sure the SPI clock is in idle state as defined for 77 * this slave. 78 */ 79 return soft_spi_scl(dev, 0); 80 } 81 82 static int soft_spi_release_bus(struct udevice *dev) 83 { 84 /* Nothing to do */ 85 return 0; 86 } 87 88 /*----------------------------------------------------------------------- 89 * SPI transfer 90 * 91 * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks 92 * "bitlen" bits in the SPI MISO port. That's just the way SPI works. 93 * 94 * The source of the outgoing bits is the "dout" parameter and the 95 * destination of the input bits is the "din" parameter. Note that "dout" 96 * and "din" can point to the same memory location, in which case the 97 * input data overwrites the output data (since both are buffered by 98 * temporary variables, this is OK). 99 */ 100 static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, 101 const void *dout, void *din, unsigned long flags) 102 { 103 struct soft_spi_priv *priv = dev_get_priv(dev); 104 struct soft_spi_platdata *plat = dev->platdata; 105 uchar tmpdin = 0; 106 uchar tmpdout = 0; 107 const u8 *txd = dout; 108 u8 *rxd = din; 109 int cpha = priv->mode & SPI_CPHA; 110 unsigned int j; 111 112 debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", 113 dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, 114 bitlen); 115 116 if (flags & SPI_XFER_BEGIN) 117 soft_spi_cs_activate(dev); 118 119 for (j = 0; j < bitlen; j++) { 120 /* 121 * Check if it is time to work on a new byte. 122 */ 123 if ((j % 8) == 0) { 124 if (txd) 125 tmpdout = *txd++; 126 else 127 tmpdout = 0; 128 if (j != 0) { 129 if (rxd) 130 *rxd++ = tmpdin; 131 } 132 tmpdin = 0; 133 } 134 135 if (!cpha) 136 soft_spi_scl(dev, 0); 137 soft_spi_sda(dev, tmpdout & 0x80); 138 udelay(plat->spi_delay_us); 139 if (cpha) 140 soft_spi_scl(dev, 0); 141 else 142 soft_spi_scl(dev, 1); 143 tmpdin <<= 1; 144 tmpdin |= dm_gpio_get_value(&plat->miso); 145 tmpdout <<= 1; 146 udelay(plat->spi_delay_us); 147 if (cpha) 148 soft_spi_scl(dev, 1); 149 } 150 /* 151 * If the number of bits isn't a multiple of 8, shift the last 152 * bits over to left-justify them. Then store the last byte 153 * read in. 154 */ 155 if (rxd) { 156 if ((bitlen % 8) != 0) 157 tmpdin <<= 8 - (bitlen % 8); 158 *rxd++ = tmpdin; 159 } 160 161 if (flags & SPI_XFER_END) 162 soft_spi_cs_deactivate(dev); 163 164 return 0; 165 } 166 167 static int soft_spi_set_speed(struct udevice *dev, unsigned int speed) 168 { 169 /* Accept any speed */ 170 return 0; 171 } 172 173 static int soft_spi_set_mode(struct udevice *dev, unsigned int mode) 174 { 175 struct soft_spi_priv *priv = dev_get_priv(dev); 176 177 priv->mode = mode; 178 179 return 0; 180 } 181 182 static const struct dm_spi_ops soft_spi_ops = { 183 .claim_bus = soft_spi_claim_bus, 184 .release_bus = soft_spi_release_bus, 185 .xfer = soft_spi_xfer, 186 .set_speed = soft_spi_set_speed, 187 .set_mode = soft_spi_set_mode, 188 }; 189 190 static int soft_spi_ofdata_to_platdata(struct udevice *dev) 191 { 192 struct soft_spi_platdata *plat = dev->platdata; 193 const void *blob = gd->fdt_blob; 194 int node = dev->of_offset; 195 196 plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0); 197 198 return 0; 199 } 200 201 static int soft_spi_probe(struct udevice *dev) 202 { 203 struct spi_slave *slave = dev_get_parentdata(dev); 204 struct soft_spi_platdata *plat = dev->platdata; 205 int cs_flags, clk_flags; 206 207 cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; 208 clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; 209 if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs, 210 GPIOD_IS_OUT | cs_flags) || 211 gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk, 212 GPIOD_IS_OUT | clk_flags) || 213 gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi, 214 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) || 215 gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso, 216 GPIOD_IS_IN)) 217 return -EINVAL; 218 219 return 0; 220 } 221 222 static const struct udevice_id soft_spi_ids[] = { 223 { .compatible = "u-boot,soft-spi" }, 224 { } 225 }; 226 227 U_BOOT_DRIVER(soft_spi) = { 228 .name = "soft_spi", 229 .id = UCLASS_SPI, 230 .of_match = soft_spi_ids, 231 .ops = &soft_spi_ops, 232 .ofdata_to_platdata = soft_spi_ofdata_to_platdata, 233 .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), 234 .priv_auto_alloc_size = sizeof(struct soft_spi_priv), 235 .probe = soft_spi_probe, 236 }; 237