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 fdt_gpio_state cs; 25 struct fdt_gpio_state sclk; 26 struct fdt_gpio_state mosi; 27 struct fdt_gpio_state 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 struct soft_spi_priv *priv = dev_get_priv(dev); 39 40 gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit); 41 42 return 0; 43 } 44 45 static int soft_spi_sda(struct udevice *dev, int bit) 46 { 47 struct soft_spi_platdata *plat = dev->platdata; 48 49 gpio_set_value(plat->mosi.gpio, bit); 50 51 return 0; 52 } 53 54 static int soft_spi_cs_activate(struct udevice *dev) 55 { 56 struct soft_spi_platdata *plat = dev->platdata; 57 struct soft_spi_priv *priv = dev_get_priv(dev); 58 59 gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH)); 60 gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL); 61 gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH); 62 63 return 0; 64 } 65 66 static int soft_spi_cs_deactivate(struct udevice *dev) 67 { 68 struct soft_spi_platdata *plat = dev->platdata; 69 struct soft_spi_priv *priv = dev_get_priv(dev); 70 71 gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH)); 72 73 return 0; 74 } 75 76 static int soft_spi_claim_bus(struct udevice *dev) 77 { 78 /* 79 * Make sure the SPI clock is in idle state as defined for 80 * this slave. 81 */ 82 return soft_spi_scl(dev, 0); 83 } 84 85 static int soft_spi_release_bus(struct udevice *dev) 86 { 87 /* Nothing to do */ 88 return 0; 89 } 90 91 /*----------------------------------------------------------------------- 92 * SPI transfer 93 * 94 * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks 95 * "bitlen" bits in the SPI MISO port. That's just the way SPI works. 96 * 97 * The source of the outgoing bits is the "dout" parameter and the 98 * destination of the input bits is the "din" parameter. Note that "dout" 99 * and "din" can point to the same memory location, in which case the 100 * input data overwrites the output data (since both are buffered by 101 * temporary variables, this is OK). 102 */ 103 static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen, 104 const void *dout, void *din, unsigned long flags) 105 { 106 struct soft_spi_priv *priv = dev_get_priv(dev); 107 struct soft_spi_platdata *plat = dev->platdata; 108 uchar tmpdin = 0; 109 uchar tmpdout = 0; 110 const u8 *txd = dout; 111 u8 *rxd = din; 112 int cpol = priv->mode & SPI_CPOL; 113 int cpha = priv->mode & SPI_CPHA; 114 unsigned int j; 115 116 debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", 117 dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, 118 bitlen); 119 120 if (flags & SPI_XFER_BEGIN) 121 soft_spi_cs_activate(dev); 122 123 for (j = 0; j < bitlen; j++) { 124 /* 125 * Check if it is time to work on a new byte. 126 */ 127 if ((j % 8) == 0) { 128 if (txd) 129 tmpdout = *txd++; 130 else 131 tmpdout = 0; 132 if (j != 0) { 133 if (rxd) 134 *rxd++ = tmpdin; 135 } 136 tmpdin = 0; 137 } 138 139 if (!cpha) 140 soft_spi_scl(dev, !cpol); 141 soft_spi_sda(dev, tmpdout & 0x80); 142 udelay(plat->spi_delay_us); 143 if (cpha) 144 soft_spi_scl(dev, !cpol); 145 else 146 soft_spi_scl(dev, cpol); 147 tmpdin <<= 1; 148 tmpdin |= gpio_get_value(plat->miso.gpio); 149 tmpdout <<= 1; 150 udelay(plat->spi_delay_us); 151 if (cpha) 152 soft_spi_scl(dev, cpol); 153 } 154 /* 155 * If the number of bits isn't a multiple of 8, shift the last 156 * bits over to left-justify them. Then store the last byte 157 * read in. 158 */ 159 if (rxd) { 160 if ((bitlen % 8) != 0) 161 tmpdin <<= 8 - (bitlen % 8); 162 *rxd++ = tmpdin; 163 } 164 165 if (flags & SPI_XFER_END) 166 soft_spi_cs_deactivate(dev); 167 168 return 0; 169 } 170 171 static int soft_spi_set_speed(struct udevice *dev, unsigned int speed) 172 { 173 /* Accept any speed */ 174 return 0; 175 } 176 177 static int soft_spi_set_mode(struct udevice *dev, unsigned int mode) 178 { 179 struct soft_spi_priv *priv = dev_get_priv(dev); 180 181 priv->mode = mode; 182 183 return 0; 184 } 185 186 static int soft_spi_child_pre_probe(struct udevice *dev) 187 { 188 struct spi_slave *slave = dev_get_parentdata(dev); 189 190 slave->dev = dev; 191 return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave); 192 } 193 194 static const struct dm_spi_ops soft_spi_ops = { 195 .claim_bus = soft_spi_claim_bus, 196 .release_bus = soft_spi_release_bus, 197 .xfer = soft_spi_xfer, 198 .set_speed = soft_spi_set_speed, 199 .set_mode = soft_spi_set_mode, 200 }; 201 202 static int soft_spi_ofdata_to_platdata(struct udevice *dev) 203 { 204 struct soft_spi_platdata *plat = dev->platdata; 205 const void *blob = gd->fdt_blob; 206 int node = dev->of_offset; 207 208 if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) || 209 fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) || 210 fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) || 211 fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso)) 212 return -EINVAL; 213 plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0); 214 215 return 0; 216 } 217 218 static int soft_spi_probe(struct udevice *dev) 219 { 220 struct spi_slave *slave = dev_get_parentdata(dev); 221 struct soft_spi_platdata *plat = dev->platdata; 222 223 gpio_request(plat->cs.gpio, "soft_spi_cs"); 224 gpio_request(plat->sclk.gpio, "soft_spi_sclk"); 225 gpio_request(plat->mosi.gpio, "soft_spi_mosi"); 226 gpio_request(plat->miso.gpio, "soft_spi_miso"); 227 228 gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL); 229 gpio_direction_output(plat->mosi.gpio, 1); 230 gpio_direction_input(plat->miso.gpio); 231 gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH)); 232 233 return 0; 234 } 235 236 static const struct udevice_id soft_spi_ids[] = { 237 { .compatible = "u-boot,soft-spi" }, 238 { } 239 }; 240 241 U_BOOT_DRIVER(soft_spi) = { 242 .name = "soft_spi", 243 .id = UCLASS_SPI, 244 .of_match = soft_spi_ids, 245 .ops = &soft_spi_ops, 246 .ofdata_to_platdata = soft_spi_ofdata_to_platdata, 247 .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), 248 .priv_auto_alloc_size = sizeof(struct soft_spi_priv), 249 .per_child_auto_alloc_size = sizeof(struct spi_slave), 250 .probe = soft_spi_probe, 251 .child_pre_probe = soft_spi_child_pre_probe, 252 }; 253