1 /* 2 * Altera SPI driver 3 * 4 * based on bfin_spi.c 5 * Copyright (c) 2005-2008 Analog Devices Inc. 6 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 #include <common.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <malloc.h> 14 #include <fdtdec.h> 15 #include <spi.h> 16 #include <asm/io.h> 17 18 #define ALTERA_SPI_STATUS_RRDY_MSK BIT(7) 19 #define ALTERA_SPI_CONTROL_SSO_MSK BIT(10) 20 21 #ifndef CONFIG_ALTERA_SPI_IDLE_VAL 22 #define CONFIG_ALTERA_SPI_IDLE_VAL 0xff 23 #endif 24 25 struct altera_spi_regs { 26 u32 rxdata; 27 u32 txdata; 28 u32 status; 29 u32 control; 30 u32 _reserved; 31 u32 slave_sel; 32 }; 33 34 struct altera_spi_platdata { 35 struct altera_spi_regs *regs; 36 }; 37 38 struct altera_spi_priv { 39 struct altera_spi_regs *regs; 40 }; 41 42 static void spi_cs_activate(struct udevice *dev, uint cs) 43 { 44 struct udevice *bus = dev->parent; 45 struct altera_spi_priv *priv = dev_get_priv(bus); 46 struct altera_spi_regs *const regs = priv->regs; 47 48 writel(1 << cs, ®s->slave_sel); 49 writel(ALTERA_SPI_CONTROL_SSO_MSK, ®s->control); 50 } 51 52 static void spi_cs_deactivate(struct udevice *dev) 53 { 54 struct udevice *bus = dev->parent; 55 struct altera_spi_priv *priv = dev_get_priv(bus); 56 struct altera_spi_regs *const regs = priv->regs; 57 58 writel(0, ®s->control); 59 writel(0, ®s->slave_sel); 60 } 61 62 static int altera_spi_claim_bus(struct udevice *dev) 63 { 64 struct udevice *bus = dev->parent; 65 struct altera_spi_priv *priv = dev_get_priv(bus); 66 struct altera_spi_regs *const regs = priv->regs; 67 68 writel(0, ®s->control); 69 writel(0, ®s->slave_sel); 70 71 return 0; 72 } 73 74 static int altera_spi_release_bus(struct udevice *dev) 75 { 76 struct udevice *bus = dev->parent; 77 struct altera_spi_priv *priv = dev_get_priv(bus); 78 struct altera_spi_regs *const regs = priv->regs; 79 80 writel(0, ®s->slave_sel); 81 82 return 0; 83 } 84 85 static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen, 86 const void *dout, void *din, unsigned long flags) 87 { 88 struct udevice *bus = dev->parent; 89 struct altera_spi_priv *priv = dev_get_priv(bus); 90 struct altera_spi_regs *const regs = priv->regs; 91 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); 92 93 /* assume spi core configured to do 8 bit transfers */ 94 unsigned int bytes = bitlen / 8; 95 const unsigned char *txp = dout; 96 unsigned char *rxp = din; 97 uint32_t reg, data, start; 98 99 debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, 100 bus->seq, slave_plat->cs, bitlen, bytes, flags); 101 102 if (bitlen == 0) 103 goto done; 104 105 if (bitlen % 8) { 106 flags |= SPI_XFER_END; 107 goto done; 108 } 109 110 /* empty read buffer */ 111 if (readl(®s->status) & ALTERA_SPI_STATUS_RRDY_MSK) 112 readl(®s->rxdata); 113 114 if (flags & SPI_XFER_BEGIN) 115 spi_cs_activate(dev, slave_plat->cs); 116 117 while (bytes--) { 118 if (txp) 119 data = *txp++; 120 else 121 data = CONFIG_ALTERA_SPI_IDLE_VAL; 122 123 debug("%s: tx:%x ", __func__, data); 124 writel(data, ®s->txdata); 125 126 start = get_timer(0); 127 while (1) { 128 reg = readl(®s->status); 129 if (reg & ALTERA_SPI_STATUS_RRDY_MSK) 130 break; 131 if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { 132 debug("%s: Transmission timed out!\n", __func__); 133 return -1; 134 } 135 } 136 137 data = readl(®s->rxdata); 138 if (rxp) 139 *rxp++ = data & 0xff; 140 141 debug("rx:%x\n", data); 142 } 143 144 done: 145 if (flags & SPI_XFER_END) 146 spi_cs_deactivate(dev); 147 148 return 0; 149 } 150 151 static int altera_spi_set_speed(struct udevice *bus, uint speed) 152 { 153 return 0; 154 } 155 156 static int altera_spi_set_mode(struct udevice *bus, uint mode) 157 { 158 return 0; 159 } 160 161 static int altera_spi_probe(struct udevice *bus) 162 { 163 struct altera_spi_platdata *plat = dev_get_platdata(bus); 164 struct altera_spi_priv *priv = dev_get_priv(bus); 165 166 priv->regs = plat->regs; 167 168 return 0; 169 } 170 171 static int altera_spi_ofdata_to_platdata(struct udevice *bus) 172 { 173 struct altera_spi_platdata *plat = dev_get_platdata(bus); 174 175 plat->regs = map_physmem(devfdt_get_addr(bus), 176 sizeof(struct altera_spi_regs), 177 MAP_NOCACHE); 178 179 return 0; 180 } 181 182 static const struct dm_spi_ops altera_spi_ops = { 183 .claim_bus = altera_spi_claim_bus, 184 .release_bus = altera_spi_release_bus, 185 .xfer = altera_spi_xfer, 186 .set_speed = altera_spi_set_speed, 187 .set_mode = altera_spi_set_mode, 188 /* 189 * cs_info is not needed, since we require all chip selects to be 190 * in the device tree explicitly 191 */ 192 }; 193 194 static const struct udevice_id altera_spi_ids[] = { 195 { .compatible = "altr,spi-1.0" }, 196 {} 197 }; 198 199 U_BOOT_DRIVER(altera_spi) = { 200 .name = "altera_spi", 201 .id = UCLASS_SPI, 202 .of_match = altera_spi_ids, 203 .ops = &altera_spi_ops, 204 .ofdata_to_platdata = altera_spi_ofdata_to_platdata, 205 .platdata_auto_alloc_size = sizeof(struct altera_spi_platdata), 206 .priv_auto_alloc_size = sizeof(struct altera_spi_priv), 207 .probe = altera_spi_probe, 208 }; 209