]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
53736baa | 2 | /* |
77b8d048 JT |
3 | * Copyright (C) 2016 Jagan Teki <[email protected]> |
4 | * Christophe Ricard <[email protected]> | |
5 | * | |
53736baa DB |
6 | * Copyright (C) 2010 Dirk Behme <[email protected]> |
7 | * | |
8 | * Driver for McSPI controller on OMAP3. Based on davinci_spi.c | |
9 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | |
10 | * | |
11 | * Copyright (C) 2007 Atmel Corporation | |
12 | * | |
13 | * Parts taken from linux/drivers/spi/omap2_mcspi.c | |
14 | * Copyright (C) 2005, 2006 Nokia Corporation | |
15 | * | |
16 | * Modified by Ruslan Araslanov <[email protected]> | |
53736baa DB |
17 | */ |
18 | ||
19 | #include <common.h> | |
77b8d048 | 20 | #include <dm.h> |
53736baa DB |
21 | #include <spi.h> |
22 | #include <malloc.h> | |
401d1c4f | 23 | #include <asm/global_data.h> |
53736baa | 24 | #include <asm/io.h> |
cd93d625 | 25 | #include <linux/bitops.h> |
41cf3cb3 | 26 | #include <omap3_spi.h> |
53736baa | 27 | |
77b8d048 JT |
28 | DECLARE_GLOBAL_DATA_PTR; |
29 | ||
5f89a15e MH |
30 | struct omap2_mcspi_platform_config { |
31 | unsigned int regs_offset; | |
32 | }; | |
33 | ||
77b8d048 | 34 | struct omap3_spi_priv { |
682c1723 | 35 | struct mcspi *regs; |
77b8d048 | 36 | unsigned int cs; |
682c1723 JT |
37 | unsigned int freq; |
38 | unsigned int mode; | |
77b8d048 JT |
39 | unsigned int wordlen; |
40 | unsigned int pin_dir:1; | |
f3f83ad4 VR |
41 | |
42 | bool bus_claimed; | |
682c1723 JT |
43 | }; |
44 | ||
77b8d048 | 45 | static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val) |
682c1723 | 46 | { |
77b8d048 | 47 | writel(val, &priv->regs->channel[priv->cs].chconf); |
cc1182be | 48 | /* Flash post writes to make immediate effect */ |
77b8d048 | 49 | readl(&priv->regs->channel[priv->cs].chconf); |
cc1182be | 50 | } |
51 | ||
77b8d048 | 52 | static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable) |
cc1182be | 53 | { |
77b8d048 | 54 | writel(enable, &priv->regs->channel[priv->cs].chctrl); |
93e14596 | 55 | /* Flash post writes to make immediate effect */ |
77b8d048 | 56 | readl(&priv->regs->channel[priv->cs].chctrl); |
53736baa DB |
57 | } |
58 | ||
77b8d048 | 59 | static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len, |
03661d85 | 60 | const void *txp, unsigned long flags) |
53736baa | 61 | { |
611c9ba2 | 62 | ulong start; |
77b8d048 JT |
63 | int i, chconf; |
64 | ||
65 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | |
53736baa | 66 | |
cc1182be | 67 | /* Enable the channel */ |
77b8d048 | 68 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
53736baa | 69 | |
5753d09b | 70 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
77b8d048 | 71 | chconf |= (priv->wordlen - 1) << 7; |
53736baa DB |
72 | chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; |
73 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 | 74 | omap3_spi_write_chconf(priv, chconf); |
53736baa DB |
75 | |
76 | for (i = 0; i < len; i++) { | |
77 | /* wait till TX register is empty (TXS == 1) */ | |
611c9ba2 | 78 | start = get_timer(0); |
77b8d048 | 79 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
53736baa | 80 | OMAP3_MCSPI_CHSTAT_TXS)) { |
611c9ba2 | 81 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
53736baa | 82 | printf("SPI TXS timed out, status=0x%08x\n", |
77b8d048 | 83 | readl(&priv->regs->channel[priv->cs].chstat)); |
53736baa DB |
84 | return -1; |
85 | } | |
86 | } | |
87 | /* Write the data */ | |
77b8d048 JT |
88 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; |
89 | if (priv->wordlen > 16) | |
5753d09b | 90 | writel(((u32 *)txp)[i], tx); |
77b8d048 | 91 | else if (priv->wordlen > 8) |
5753d09b NK |
92 | writel(((u16 *)txp)[i], tx); |
93 | else | |
94 | writel(((u8 *)txp)[i], tx); | |
53736baa DB |
95 | } |
96 | ||
93e14596 | 97 | /* wait to finish of transfer */ |
77b8d048 JT |
98 | while ((readl(&priv->regs->channel[priv->cs].chstat) & |
99 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) != | |
100 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) | |
101 | ; | |
cc1182be | 102 | |
103 | /* Disable the channel otherwise the next immediate RX will get affected */ | |
77b8d048 | 104 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
cc1182be | 105 | |
53736baa | 106 | if (flags & SPI_XFER_END) { |
53736baa DB |
107 | |
108 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 | 109 | omap3_spi_write_chconf(priv, chconf); |
53736baa DB |
110 | } |
111 | return 0; | |
112 | } | |
113 | ||
77b8d048 | 114 | static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len, |
03661d85 | 115 | void *rxp, unsigned long flags) |
53736baa | 116 | { |
77b8d048 | 117 | int i, chconf; |
611c9ba2 | 118 | ulong start; |
77b8d048 JT |
119 | |
120 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | |
53736baa | 121 | |
cc1182be | 122 | /* Enable the channel */ |
77b8d048 | 123 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
53736baa | 124 | |
5753d09b | 125 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
77b8d048 | 126 | chconf |= (priv->wordlen - 1) << 7; |
53736baa DB |
127 | chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; |
128 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 | 129 | omap3_spi_write_chconf(priv, chconf); |
53736baa | 130 | |
77b8d048 | 131 | writel(0, &priv->regs->channel[priv->cs].tx); |
53736baa DB |
132 | |
133 | for (i = 0; i < len; i++) { | |
611c9ba2 | 134 | start = get_timer(0); |
53736baa | 135 | /* Wait till RX register contains data (RXS == 1) */ |
77b8d048 | 136 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
53736baa | 137 | OMAP3_MCSPI_CHSTAT_RXS)) { |
611c9ba2 | 138 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
53736baa | 139 | printf("SPI RXS timed out, status=0x%08x\n", |
77b8d048 | 140 | readl(&priv->regs->channel[priv->cs].chstat)); |
53736baa DB |
141 | return -1; |
142 | } | |
143 | } | |
cc1182be | 144 | |
d466f620 | 145 | /* Disable the channel to prevent further receiving */ |
77b8d048 JT |
146 | if (i == (len - 1)) |
147 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | |
cc1182be | 148 | |
53736baa | 149 | /* Read the data */ |
77b8d048 JT |
150 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; |
151 | if (priv->wordlen > 16) | |
5753d09b | 152 | ((u32 *)rxp)[i] = readl(rx); |
77b8d048 | 153 | else if (priv->wordlen > 8) |
5753d09b NK |
154 | ((u16 *)rxp)[i] = (u16)readl(rx); |
155 | else | |
156 | ((u8 *)rxp)[i] = (u8)readl(rx); | |
53736baa DB |
157 | } |
158 | ||
159 | if (flags & SPI_XFER_END) { | |
160 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 | 161 | omap3_spi_write_chconf(priv, chconf); |
53736baa DB |
162 | } |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
08b5ab07 | 167 | /*McSPI Transmit Receive Mode*/ |
77b8d048 | 168 | static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len, |
03661d85 | 169 | const void *txp, void *rxp, unsigned long flags) |
08b5ab07 | 170 | { |
611c9ba2 | 171 | ulong start; |
77b8d048 JT |
172 | int chconf, i = 0; |
173 | ||
174 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | |
08b5ab07 | 175 | |
176 | /*Enable SPI channel*/ | |
77b8d048 | 177 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
08b5ab07 | 178 | |
179 | /*set TRANSMIT-RECEIVE Mode*/ | |
5753d09b | 180 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
77b8d048 | 181 | chconf |= (priv->wordlen - 1) << 7; |
08b5ab07 | 182 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
77b8d048 | 183 | omap3_spi_write_chconf(priv, chconf); |
08b5ab07 | 184 | |
185 | /*Shift in and out 1 byte at time*/ | |
186 | for (i=0; i < len; i++){ | |
187 | /* Write: wait for TX empty (TXS == 1)*/ | |
611c9ba2 | 188 | start = get_timer(0); |
77b8d048 | 189 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
08b5ab07 | 190 | OMAP3_MCSPI_CHSTAT_TXS)) { |
611c9ba2 | 191 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
08b5ab07 | 192 | printf("SPI TXS timed out, status=0x%08x\n", |
77b8d048 | 193 | readl(&priv->regs->channel[priv->cs].chstat)); |
08b5ab07 | 194 | return -1; |
195 | } | |
196 | } | |
197 | /* Write the data */ | |
77b8d048 JT |
198 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; |
199 | if (priv->wordlen > 16) | |
5753d09b | 200 | writel(((u32 *)txp)[i], tx); |
77b8d048 | 201 | else if (priv->wordlen > 8) |
5753d09b NK |
202 | writel(((u16 *)txp)[i], tx); |
203 | else | |
204 | writel(((u8 *)txp)[i], tx); | |
08b5ab07 | 205 | |
206 | /*Read: wait for RX containing data (RXS == 1)*/ | |
611c9ba2 | 207 | start = get_timer(0); |
77b8d048 | 208 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
08b5ab07 | 209 | OMAP3_MCSPI_CHSTAT_RXS)) { |
611c9ba2 | 210 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
08b5ab07 | 211 | printf("SPI RXS timed out, status=0x%08x\n", |
77b8d048 | 212 | readl(&priv->regs->channel[priv->cs].chstat)); |
08b5ab07 | 213 | return -1; |
214 | } | |
215 | } | |
216 | /* Read the data */ | |
77b8d048 JT |
217 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; |
218 | if (priv->wordlen > 16) | |
5753d09b | 219 | ((u32 *)rxp)[i] = readl(rx); |
77b8d048 | 220 | else if (priv->wordlen > 8) |
5753d09b NK |
221 | ((u16 *)rxp)[i] = (u16)readl(rx); |
222 | else | |
223 | ((u8 *)rxp)[i] = (u8)readl(rx); | |
08b5ab07 | 224 | } |
cc1182be | 225 | /* Disable the channel */ |
77b8d048 | 226 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
08b5ab07 | 227 | |
228 | /*if transfer must be terminated disable the channel*/ | |
229 | if (flags & SPI_XFER_END) { | |
230 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 | 231 | omap3_spi_write_chconf(priv, chconf); |
08b5ab07 | 232 | } |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
77b8d048 JT |
237 | static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen, |
238 | const void *dout, void *din, unsigned long flags) | |
53736baa | 239 | { |
53736baa | 240 | unsigned int len; |
53736baa DB |
241 | int ret = -1; |
242 | ||
77b8d048 JT |
243 | if (priv->wordlen < 4 || priv->wordlen > 32) { |
244 | printf("omap3_spi: invalid wordlen %d\n", priv->wordlen); | |
5753d09b NK |
245 | return -1; |
246 | } | |
247 | ||
77b8d048 | 248 | if (bitlen % priv->wordlen) |
53736baa DB |
249 | return -1; |
250 | ||
77b8d048 | 251 | len = bitlen / priv->wordlen; |
53736baa DB |
252 | |
253 | if (bitlen == 0) { /* only change CS */ | |
77b8d048 | 254 | int chconf = readl(&priv->regs->channel[priv->cs].chconf); |
53736baa DB |
255 | |
256 | if (flags & SPI_XFER_BEGIN) { | |
77b8d048 | 257 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
53736baa | 258 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
77b8d048 | 259 | omap3_spi_write_chconf(priv, chconf); |
53736baa DB |
260 | } |
261 | if (flags & SPI_XFER_END) { | |
262 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | |
77b8d048 JT |
263 | omap3_spi_write_chconf(priv, chconf); |
264 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | |
53736baa DB |
265 | } |
266 | ret = 0; | |
267 | } else { | |
08b5ab07 | 268 | if (dout != NULL && din != NULL) |
77b8d048 | 269 | ret = omap3_spi_txrx(priv, len, dout, din, flags); |
08b5ab07 | 270 | else if (dout != NULL) |
77b8d048 | 271 | ret = omap3_spi_write(priv, len, dout, flags); |
08b5ab07 | 272 | else if (din != NULL) |
77b8d048 | 273 | ret = omap3_spi_read(priv, len, din, flags); |
53736baa DB |
274 | } |
275 | return ret; | |
276 | } | |
277 | ||
77b8d048 JT |
278 | static void _omap3_spi_set_speed(struct omap3_spi_priv *priv) |
279 | { | |
280 | uint32_t confr, div = 0; | |
281 | ||
282 | confr = readl(&priv->regs->channel[priv->cs].chconf); | |
283 | ||
284 | /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ | |
285 | if (priv->freq) { | |
286 | while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) | |
287 | > priv->freq) | |
288 | div++; | |
289 | } else { | |
290 | div = 0xC; | |
291 | } | |
292 | ||
293 | /* set clock divisor */ | |
294 | confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; | |
295 | confr |= div << 2; | |
296 | ||
297 | omap3_spi_write_chconf(priv, confr); | |
298 | } | |
299 | ||
300 | static void _omap3_spi_set_mode(struct omap3_spi_priv *priv) | |
301 | { | |
302 | uint32_t confr; | |
303 | ||
304 | confr = readl(&priv->regs->channel[priv->cs].chconf); | |
305 | ||
306 | /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS | |
307 | * REVISIT: this controller could support SPI_3WIRE mode. | |
308 | */ | |
309 | if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { | |
310 | confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); | |
311 | confr |= OMAP3_MCSPI_CHCONF_DPE0; | |
312 | } else { | |
313 | confr &= ~OMAP3_MCSPI_CHCONF_DPE0; | |
314 | confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1; | |
315 | } | |
316 | ||
317 | /* set SPI mode 0..3 */ | |
318 | confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA); | |
319 | if (priv->mode & SPI_CPHA) | |
320 | confr |= OMAP3_MCSPI_CHCONF_PHA; | |
321 | if (priv->mode & SPI_CPOL) | |
322 | confr |= OMAP3_MCSPI_CHCONF_POL; | |
323 | ||
324 | /* set chipselect polarity; manage with FORCE */ | |
325 | if (!(priv->mode & SPI_CS_HIGH)) | |
326 | confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ | |
327 | else | |
328 | confr &= ~OMAP3_MCSPI_CHCONF_EPOL; | |
329 | ||
330 | /* Transmit & receive mode */ | |
331 | confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; | |
332 | ||
333 | omap3_spi_write_chconf(priv, confr); | |
334 | } | |
335 | ||
336 | static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) | |
337 | { | |
338 | unsigned int confr; | |
339 | ||
340 | /* McSPI individual channel configuration */ | |
b8b88e6a | 341 | confr = readl(&priv->regs->channel[priv->cs].chconf); |
77b8d048 JT |
342 | |
343 | /* wordlength */ | |
344 | confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK; | |
345 | confr |= (priv->wordlen - 1) << 7; | |
346 | ||
347 | omap3_spi_write_chconf(priv, confr); | |
348 | } | |
349 | ||
fb93bd8d | 350 | static void spi_reset(struct omap3_spi_priv *priv) |
77b8d048 JT |
351 | { |
352 | unsigned int tmp; | |
353 | ||
fb93bd8d | 354 | writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &priv->regs->sysconfig); |
77b8d048 | 355 | do { |
fb93bd8d | 356 | tmp = readl(&priv->regs->sysstatus); |
77b8d048 JT |
357 | } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); |
358 | ||
359 | writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | | |
360 | OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | | |
fb93bd8d | 361 | OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, &priv->regs->sysconfig); |
77b8d048 | 362 | |
fb93bd8d JP |
363 | writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &priv->regs->wakeupenable); |
364 | ||
365 | /* | |
366 | * Set the same default mode for each channel, especially CS polarity | |
367 | * which must be common for all SPI slaves before any transfer. | |
368 | */ | |
369 | for (priv->cs = 0 ; priv->cs < OMAP4_MCSPI_CHAN_NB ; priv->cs++) | |
370 | _omap3_spi_set_mode(priv); | |
371 | priv->cs = 0; | |
77b8d048 JT |
372 | } |
373 | ||
374 | static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv) | |
375 | { | |
376 | unsigned int conf; | |
77b8d048 JT |
377 | /* |
378 | * setup when switching from (reset default) slave mode | |
379 | * to single-channel master mode | |
380 | */ | |
381 | conf = readl(&priv->regs->modulctrl); | |
382 | conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); | |
383 | conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; | |
384 | ||
385 | writel(conf, &priv->regs->modulctrl); | |
f3f83ad4 VR |
386 | |
387 | priv->bus_claimed = true; | |
77b8d048 JT |
388 | } |
389 | ||
77b8d048 JT |
390 | static int omap3_spi_claim_bus(struct udevice *dev) |
391 | { | |
392 | struct udevice *bus = dev->parent; | |
393 | struct omap3_spi_priv *priv = dev_get_priv(bus); | |
8a8d24bd | 394 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
77b8d048 JT |
395 | |
396 | priv->cs = slave_plat->cs; | |
f3f83ad4 VR |
397 | if (!priv->freq) |
398 | priv->freq = slave_plat->max_hz; | |
b1d2b529 | 399 | |
77b8d048 | 400 | _omap3_spi_claim_bus(priv); |
f3f83ad4 VR |
401 | _omap3_spi_set_speed(priv); |
402 | _omap3_spi_set_mode(priv); | |
77b8d048 JT |
403 | |
404 | return 0; | |
405 | } | |
406 | ||
407 | static int omap3_spi_release_bus(struct udevice *dev) | |
408 | { | |
409 | struct udevice *bus = dev->parent; | |
410 | struct omap3_spi_priv *priv = dev_get_priv(bus); | |
411 | ||
c0eaffa0 | 412 | writel(OMAP3_MCSPI_MODULCTRL_MS, &priv->regs->modulctrl); |
77b8d048 | 413 | |
f3f83ad4 VR |
414 | priv->bus_claimed = false; |
415 | ||
77b8d048 JT |
416 | return 0; |
417 | } | |
418 | ||
419 | static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) | |
420 | { | |
421 | struct udevice *bus = dev->parent; | |
422 | struct omap3_spi_priv *priv = dev_get_priv(bus); | |
8a8d24bd | 423 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
77b8d048 JT |
424 | |
425 | priv->cs = slave_plat->cs; | |
426 | priv->wordlen = wordlen; | |
427 | _omap3_spi_set_wordlen(priv); | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
432 | static int omap3_spi_probe(struct udevice *dev) | |
433 | { | |
434 | struct omap3_spi_priv *priv = dev_get_priv(dev); | |
c69cda25 | 435 | struct omap3_spi_plat *plat = dev_get_plat(dev); |
77b8d048 | 436 | |
afd4f15a FA |
437 | priv->regs = plat->regs; |
438 | priv->pin_dir = plat->pin_dir; | |
77b8d048 | 439 | priv->wordlen = SPI_DEFAULT_WORDLEN; |
c0eaffa0 | 440 | |
fb93bd8d | 441 | spi_reset(priv); |
c0eaffa0 | 442 | |
77b8d048 JT |
443 | return 0; |
444 | } | |
445 | ||
446 | static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen, | |
447 | const void *dout, void *din, unsigned long flags) | |
448 | { | |
449 | struct udevice *bus = dev->parent; | |
450 | struct omap3_spi_priv *priv = dev_get_priv(bus); | |
451 | ||
452 | return _spi_xfer(priv, bitlen, dout, din, flags); | |
453 | } | |
454 | ||
b2b41d27 | 455 | static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed) |
77b8d048 | 456 | { |
84807922 | 457 | |
9cddf70e HS |
458 | struct omap3_spi_priv *priv = dev_get_priv(dev); |
459 | ||
460 | priv->freq = speed; | |
f3f83ad4 VR |
461 | if (priv->bus_claimed) |
462 | _omap3_spi_set_speed(priv); | |
84807922 | 463 | |
77b8d048 JT |
464 | return 0; |
465 | } | |
466 | ||
b2b41d27 | 467 | static int omap3_spi_set_mode(struct udevice *dev, uint mode) |
77b8d048 | 468 | { |
9cddf70e HS |
469 | struct omap3_spi_priv *priv = dev_get_priv(dev); |
470 | ||
471 | priv->mode = mode; | |
84807922 | 472 | |
f3f83ad4 VR |
473 | if (priv->bus_claimed) |
474 | _omap3_spi_set_mode(priv); | |
84807922 | 475 | |
77b8d048 JT |
476 | return 0; |
477 | } | |
478 | ||
479 | static const struct dm_spi_ops omap3_spi_ops = { | |
480 | .claim_bus = omap3_spi_claim_bus, | |
481 | .release_bus = omap3_spi_release_bus, | |
482 | .set_wordlen = omap3_spi_set_wordlen, | |
483 | .xfer = omap3_spi_xfer, | |
484 | .set_speed = omap3_spi_set_speed, | |
485 | .set_mode = omap3_spi_set_mode, | |
486 | /* | |
487 | * cs_info is not needed, since we require all chip selects to be | |
488 | * in the device tree explicitly | |
489 | */ | |
490 | }; | |
491 | ||
414cc151 | 492 | #if CONFIG_IS_ENABLED(OF_REAL) |
5f89a15e MH |
493 | static struct omap2_mcspi_platform_config omap2_pdata = { |
494 | .regs_offset = 0, | |
495 | }; | |
496 | ||
497 | static struct omap2_mcspi_platform_config omap4_pdata = { | |
498 | .regs_offset = OMAP4_MCSPI_REG_OFFSET, | |
499 | }; | |
500 | ||
d1998a9f | 501 | static int omap3_spi_of_to_plat(struct udevice *dev) |
afd4f15a FA |
502 | { |
503 | struct omap2_mcspi_platform_config *data = | |
504 | (struct omap2_mcspi_platform_config *)dev_get_driver_data(dev); | |
c69cda25 | 505 | struct omap3_spi_plat *plat = dev_get_plat(dev); |
afd4f15a FA |
506 | |
507 | plat->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset); | |
508 | ||
509 | if (dev_read_bool(dev, "ti,pindir-d0-out-d1-in")) | |
510 | plat->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; | |
511 | else | |
512 | plat->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT; | |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
77b8d048 | 517 | static const struct udevice_id omap3_spi_ids[] = { |
5f89a15e MH |
518 | { .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata }, |
519 | { .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata }, | |
77b8d048 JT |
520 | { } |
521 | }; | |
afd4f15a | 522 | #endif |
77b8d048 JT |
523 | U_BOOT_DRIVER(omap3_spi) = { |
524 | .name = "omap3_spi", | |
525 | .id = UCLASS_SPI, | |
afd4f15a | 526 | .flags = DM_FLAG_PRE_RELOC, |
414cc151 | 527 | #if CONFIG_IS_ENABLED(OF_REAL) |
77b8d048 | 528 | .of_match = omap3_spi_ids, |
d1998a9f | 529 | .of_to_plat = omap3_spi_of_to_plat, |
caa4daa2 | 530 | .plat_auto = sizeof(struct omap3_spi_plat), |
afd4f15a | 531 | #endif |
77b8d048 JT |
532 | .probe = omap3_spi_probe, |
533 | .ops = &omap3_spi_ops, | |
41575d8e | 534 | .priv_auto = sizeof(struct omap3_spi_priv), |
77b8d048 | 535 | }; |