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