183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
28ed58856SSekhar Nori /*
38ed58856SSekhar Nori * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
48ed58856SSekhar Nori *
58ed58856SSekhar Nori * Driver for SPI controller on DaVinci. Based on atmel_spi.c
68ed58856SSekhar Nori * by Atmel Corporation
78ed58856SSekhar Nori *
88ed58856SSekhar Nori * Copyright (C) 2007 Atmel Corporation
98ed58856SSekhar Nori */
10ff6e31d3SJagan Teki
118ed58856SSekhar Nori #include <common.h>
128ed58856SSekhar Nori #include <spi.h>
138ed58856SSekhar Nori #include <malloc.h>
148ed58856SSekhar Nori #include <asm/io.h>
158ed58856SSekhar Nori #include <asm/arch/hardware.h>
16192bb756SVignesh R #include <dm.h>
17*ba3c22bfSJagan Teki #include <dm/platform_data/spi_davinci.h>
18e6d2fbf7SJagan Teki
19e6d2fbf7SJagan Teki /* SPIGCR0 */
20e6d2fbf7SJagan Teki #define SPIGCR0_SPIENA_MASK 0x1
21e6d2fbf7SJagan Teki #define SPIGCR0_SPIRST_MASK 0x0
22e6d2fbf7SJagan Teki
23e6d2fbf7SJagan Teki /* SPIGCR0 */
24e6d2fbf7SJagan Teki #define SPIGCR1_CLKMOD_MASK BIT(1)
25e6d2fbf7SJagan Teki #define SPIGCR1_MASTER_MASK BIT(0)
26e6d2fbf7SJagan Teki #define SPIGCR1_SPIENA_MASK BIT(24)
27e6d2fbf7SJagan Teki
28e6d2fbf7SJagan Teki /* SPIPC0 */
29e6d2fbf7SJagan Teki #define SPIPC0_DIFUN_MASK BIT(11) /* SIMO */
30e6d2fbf7SJagan Teki #define SPIPC0_DOFUN_MASK BIT(10) /* SOMI */
31e6d2fbf7SJagan Teki #define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
32e6d2fbf7SJagan Teki #define SPIPC0_EN0FUN_MASK BIT(0)
33e6d2fbf7SJagan Teki
34e6d2fbf7SJagan Teki /* SPIFMT0 */
35e6d2fbf7SJagan Teki #define SPIFMT_SHIFTDIR_SHIFT 20
36e6d2fbf7SJagan Teki #define SPIFMT_POLARITY_SHIFT 17
37e6d2fbf7SJagan Teki #define SPIFMT_PHASE_SHIFT 16
38e6d2fbf7SJagan Teki #define SPIFMT_PRESCALE_SHIFT 8
39e6d2fbf7SJagan Teki
40e6d2fbf7SJagan Teki /* SPIDAT1 */
41e6d2fbf7SJagan Teki #define SPIDAT1_CSHOLD_SHIFT 28
42e6d2fbf7SJagan Teki #define SPIDAT1_CSNR_SHIFT 16
43e6d2fbf7SJagan Teki
44e6d2fbf7SJagan Teki /* SPIDELAY */
45e6d2fbf7SJagan Teki #define SPI_C2TDELAY_SHIFT 24
46e6d2fbf7SJagan Teki #define SPI_T2CDELAY_SHIFT 16
47e6d2fbf7SJagan Teki
48e6d2fbf7SJagan Teki /* SPIBUF */
49e6d2fbf7SJagan Teki #define SPIBUF_RXEMPTY_MASK BIT(31)
50e6d2fbf7SJagan Teki #define SPIBUF_TXFULL_MASK BIT(29)
51e6d2fbf7SJagan Teki
52e6d2fbf7SJagan Teki /* SPIDEF */
53e6d2fbf7SJagan Teki #define SPIDEF_CSDEF0_MASK BIT(0)
54e6d2fbf7SJagan Teki
55192bb756SVignesh R #ifndef CONFIG_DM_SPI
56e6d2fbf7SJagan Teki #define SPI0_BUS 0
57e6d2fbf7SJagan Teki #define SPI0_BASE CONFIG_SYS_SPI_BASE
58e6d2fbf7SJagan Teki /*
59e6d2fbf7SJagan Teki * Define default SPI0_NUM_CS as 1 for existing platforms that uses this
60e6d2fbf7SJagan Teki * driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
61e6d2fbf7SJagan Teki * if more than one CS is supported and by defining CONFIG_SYS_SPI0.
62e6d2fbf7SJagan Teki */
63e6d2fbf7SJagan Teki #ifndef CONFIG_SYS_SPI0
64e6d2fbf7SJagan Teki #define SPI0_NUM_CS 1
65e6d2fbf7SJagan Teki #else
66e6d2fbf7SJagan Teki #define SPI0_NUM_CS CONFIG_SYS_SPI0_NUM_CS
67e6d2fbf7SJagan Teki #endif
68e6d2fbf7SJagan Teki
69e6d2fbf7SJagan Teki /*
70e6d2fbf7SJagan Teki * define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
71e6d2fbf7SJagan Teki * CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
72e6d2fbf7SJagan Teki */
73e6d2fbf7SJagan Teki #ifdef CONFIG_SYS_SPI1
74e6d2fbf7SJagan Teki #define SPI1_BUS 1
75e6d2fbf7SJagan Teki #define SPI1_NUM_CS CONFIG_SYS_SPI1_NUM_CS
76e6d2fbf7SJagan Teki #define SPI1_BASE CONFIG_SYS_SPI1_BASE
77e6d2fbf7SJagan Teki #endif
78e6d2fbf7SJagan Teki
79e6d2fbf7SJagan Teki /*
80e6d2fbf7SJagan Teki * define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
81e6d2fbf7SJagan Teki * CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
82e6d2fbf7SJagan Teki */
83e6d2fbf7SJagan Teki #ifdef CONFIG_SYS_SPI2
84e6d2fbf7SJagan Teki #define SPI2_BUS 2
85e6d2fbf7SJagan Teki #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
86e6d2fbf7SJagan Teki #define SPI2_BASE CONFIG_SYS_SPI2_BASE
87e6d2fbf7SJagan Teki #endif
88192bb756SVignesh R #endif
89192bb756SVignesh R
90192bb756SVignesh R DECLARE_GLOBAL_DATA_PTR;
91e6d2fbf7SJagan Teki
92ff6e31d3SJagan Teki /* davinci spi register set */
93ff6e31d3SJagan Teki struct davinci_spi_regs {
94ff6e31d3SJagan Teki dv_reg gcr0; /* 0x00 */
95ff6e31d3SJagan Teki dv_reg gcr1; /* 0x04 */
96ff6e31d3SJagan Teki dv_reg int0; /* 0x08 */
97ff6e31d3SJagan Teki dv_reg lvl; /* 0x0c */
98ff6e31d3SJagan Teki dv_reg flg; /* 0x10 */
99ff6e31d3SJagan Teki dv_reg pc0; /* 0x14 */
100ff6e31d3SJagan Teki dv_reg pc1; /* 0x18 */
101ff6e31d3SJagan Teki dv_reg pc2; /* 0x1c */
102ff6e31d3SJagan Teki dv_reg pc3; /* 0x20 */
103ff6e31d3SJagan Teki dv_reg pc4; /* 0x24 */
104ff6e31d3SJagan Teki dv_reg pc5; /* 0x28 */
105ff6e31d3SJagan Teki dv_reg rsvd[3];
106ff6e31d3SJagan Teki dv_reg dat0; /* 0x38 */
107ff6e31d3SJagan Teki dv_reg dat1; /* 0x3c */
108ff6e31d3SJagan Teki dv_reg buf; /* 0x40 */
109ff6e31d3SJagan Teki dv_reg emu; /* 0x44 */
110ff6e31d3SJagan Teki dv_reg delay; /* 0x48 */
111ff6e31d3SJagan Teki dv_reg def; /* 0x4c */
112ff6e31d3SJagan Teki dv_reg fmt0; /* 0x50 */
113ff6e31d3SJagan Teki dv_reg fmt1; /* 0x54 */
114ff6e31d3SJagan Teki dv_reg fmt2; /* 0x58 */
115ff6e31d3SJagan Teki dv_reg fmt3; /* 0x5c */
116ff6e31d3SJagan Teki dv_reg intvec0; /* 0x60 */
117ff6e31d3SJagan Teki dv_reg intvec1; /* 0x64 */
118ff6e31d3SJagan Teki };
119ff6e31d3SJagan Teki
120ff6e31d3SJagan Teki /* davinci spi slave */
121e6d2fbf7SJagan Teki struct davinci_spi_slave {
122192bb756SVignesh R #ifndef CONFIG_DM_SPI
123e6d2fbf7SJagan Teki struct spi_slave slave;
124192bb756SVignesh R #endif
125e6d2fbf7SJagan Teki struct davinci_spi_regs *regs;
126192bb756SVignesh R unsigned int freq; /* current SPI bus frequency */
127192bb756SVignesh R unsigned int mode; /* current SPI mode used */
128192bb756SVignesh R u8 num_cs; /* total no. of CS available */
129192bb756SVignesh R u8 cur_cs; /* CS of current slave */
130192bb756SVignesh R bool half_duplex; /* true, if master is half-duplex only */
131e6d2fbf7SJagan Teki };
132e6d2fbf7SJagan Teki
13377436d66SNick Thompson /*
13477436d66SNick Thompson * This functions needs to act like a macro to avoid pipeline reloads in the
13577436d66SNick Thompson * loops below. Use always_inline. This gains us about 160KiB/s and the bloat
13677436d66SNick Thompson * appears to be zero bytes (da830).
13777436d66SNick Thompson */
13877436d66SNick Thompson __attribute__((always_inline))
davinci_spi_xfer_data(struct davinci_spi_slave * ds,u32 data)13977436d66SNick Thompson static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data)
14077436d66SNick Thompson {
14177436d66SNick Thompson u32 buf_reg_val;
14277436d66SNick Thompson
14377436d66SNick Thompson /* send out data */
14477436d66SNick Thompson writel(data, &ds->regs->dat1);
14577436d66SNick Thompson
14677436d66SNick Thompson /* wait for the data to clock in/out */
14777436d66SNick Thompson while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK)
14877436d66SNick Thompson ;
14977436d66SNick Thompson
15077436d66SNick Thompson return buf_reg_val;
15177436d66SNick Thompson }
15277436d66SNick Thompson
davinci_spi_read(struct davinci_spi_slave * ds,unsigned int len,u8 * rxp,unsigned long flags)153192bb756SVignesh R static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len,
15477436d66SNick Thompson u8 *rxp, unsigned long flags)
15577436d66SNick Thompson {
15677436d66SNick Thompson unsigned int data1_reg_val;
15777436d66SNick Thompson
15877436d66SNick Thompson /* enable CS hold, CS[n] and clear the data bits */
15977436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
160192bb756SVignesh R (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
16177436d66SNick Thompson
16277436d66SNick Thompson /* wait till TXFULL is deasserted */
16377436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
16477436d66SNick Thompson ;
16577436d66SNick Thompson
16677436d66SNick Thompson /* preload the TX buffer to avoid clock starvation */
16777436d66SNick Thompson writel(data1_reg_val, &ds->regs->dat1);
16877436d66SNick Thompson
16977436d66SNick Thompson /* keep reading 1 byte until only 1 byte left */
17077436d66SNick Thompson while ((len--) > 1)
17177436d66SNick Thompson *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val);
17277436d66SNick Thompson
17377436d66SNick Thompson /* clear CS hold when we reach the end */
17477436d66SNick Thompson if (flags & SPI_XFER_END)
17577436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
17677436d66SNick Thompson
17777436d66SNick Thompson /* read the last byte */
17877436d66SNick Thompson *rxp = davinci_spi_xfer_data(ds, data1_reg_val);
17977436d66SNick Thompson
18077436d66SNick Thompson return 0;
18177436d66SNick Thompson }
18277436d66SNick Thompson
davinci_spi_write(struct davinci_spi_slave * ds,unsigned int len,const u8 * txp,unsigned long flags)183192bb756SVignesh R static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len,
18477436d66SNick Thompson const u8 *txp, unsigned long flags)
18577436d66SNick Thompson {
18677436d66SNick Thompson unsigned int data1_reg_val;
18777436d66SNick Thompson
18877436d66SNick Thompson /* enable CS hold and clear the data bits */
18977436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
190192bb756SVignesh R (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
19177436d66SNick Thompson
19277436d66SNick Thompson /* wait till TXFULL is deasserted */
19377436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
19477436d66SNick Thompson ;
19577436d66SNick Thompson
19677436d66SNick Thompson /* preload the TX buffer to avoid clock starvation */
19777436d66SNick Thompson if (len > 2) {
19877436d66SNick Thompson writel(data1_reg_val | *txp++, &ds->regs->dat1);
19977436d66SNick Thompson len--;
20077436d66SNick Thompson }
20177436d66SNick Thompson
20277436d66SNick Thompson /* keep writing 1 byte until only 1 byte left */
20377436d66SNick Thompson while ((len--) > 1)
20477436d66SNick Thompson davinci_spi_xfer_data(ds, data1_reg_val | *txp++);
20577436d66SNick Thompson
20677436d66SNick Thompson /* clear CS hold when we reach the end */
20777436d66SNick Thompson if (flags & SPI_XFER_END)
20877436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
20977436d66SNick Thompson
21077436d66SNick Thompson /* write the last byte */
21177436d66SNick Thompson davinci_spi_xfer_data(ds, data1_reg_val | *txp);
21277436d66SNick Thompson
21377436d66SNick Thompson return 0;
21477436d66SNick Thompson }
21577436d66SNick Thompson
davinci_spi_read_write(struct davinci_spi_slave * ds,unsigned int len,u8 * rxp,const u8 * txp,unsigned long flags)216192bb756SVignesh R static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned
217192bb756SVignesh R int len, u8 *rxp, const u8 *txp,
218192bb756SVignesh R unsigned long flags)
21977436d66SNick Thompson {
22077436d66SNick Thompson unsigned int data1_reg_val;
22177436d66SNick Thompson
22277436d66SNick Thompson /* enable CS hold and clear the data bits */
22377436d66SNick Thompson data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
224192bb756SVignesh R (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
22577436d66SNick Thompson
22677436d66SNick Thompson /* wait till TXFULL is deasserted */
22777436d66SNick Thompson while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
22877436d66SNick Thompson ;
22977436d66SNick Thompson
23077436d66SNick Thompson /* keep reading and writing 1 byte until only 1 byte left */
23177436d66SNick Thompson while ((len--) > 1)
23277436d66SNick Thompson *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val | *txp++);
23377436d66SNick Thompson
23477436d66SNick Thompson /* clear CS hold when we reach the end */
23577436d66SNick Thompson if (flags & SPI_XFER_END)
23677436d66SNick Thompson data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
23777436d66SNick Thompson
23877436d66SNick Thompson /* read and write the last byte */
23977436d66SNick Thompson *rxp = davinci_spi_xfer_data(ds, data1_reg_val | *txp);
24077436d66SNick Thompson
24177436d66SNick Thompson return 0;
24277436d66SNick Thompson }
243192bb756SVignesh R
244192bb756SVignesh R
__davinci_spi_claim_bus(struct davinci_spi_slave * ds,int cs)245192bb756SVignesh R static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs)
246192bb756SVignesh R {
247192bb756SVignesh R unsigned int mode = 0, scalar;
248192bb756SVignesh R
249192bb756SVignesh R /* Enable the SPI hardware */
250192bb756SVignesh R writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
251192bb756SVignesh R udelay(1000);
252192bb756SVignesh R writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
253192bb756SVignesh R
254192bb756SVignesh R /* Set master mode, powered up and not activated */
255192bb756SVignesh R writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
256192bb756SVignesh R
257192bb756SVignesh R /* CS, CLK, SIMO and SOMI are functional pins */
258192bb756SVignesh R writel(((1 << cs) | SPIPC0_CLKFUN_MASK |
259192bb756SVignesh R SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
260192bb756SVignesh R
261192bb756SVignesh R /* setup format */
262192bb756SVignesh R scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
263192bb756SVignesh R
264192bb756SVignesh R /*
265192bb756SVignesh R * Use following format:
266192bb756SVignesh R * character length = 8,
267192bb756SVignesh R * MSB shifted out first
268192bb756SVignesh R */
269192bb756SVignesh R if (ds->mode & SPI_CPOL)
270192bb756SVignesh R mode |= SPI_CPOL;
271192bb756SVignesh R if (!(ds->mode & SPI_CPHA))
272192bb756SVignesh R mode |= SPI_CPHA;
273192bb756SVignesh R writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
274192bb756SVignesh R (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
275192bb756SVignesh R
276192bb756SVignesh R /*
277192bb756SVignesh R * Including a minor delay. No science here. Should be good even with
278192bb756SVignesh R * no delay
279192bb756SVignesh R */
280192bb756SVignesh R writel((50 << SPI_C2TDELAY_SHIFT) |
281192bb756SVignesh R (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
282192bb756SVignesh R
283192bb756SVignesh R /* default chip select register */
284192bb756SVignesh R writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
285192bb756SVignesh R
286192bb756SVignesh R /* no interrupts */
287192bb756SVignesh R writel(0, &ds->regs->int0);
288192bb756SVignesh R writel(0, &ds->regs->lvl);
289192bb756SVignesh R
290192bb756SVignesh R /* enable SPI */
291192bb756SVignesh R writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
292192bb756SVignesh R
293192bb756SVignesh R return 0;
294192bb756SVignesh R }
295192bb756SVignesh R
__davinci_spi_release_bus(struct davinci_spi_slave * ds)296192bb756SVignesh R static int __davinci_spi_release_bus(struct davinci_spi_slave *ds)
297192bb756SVignesh R {
298192bb756SVignesh R /* Disable the SPI hardware */
299192bb756SVignesh R writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
300192bb756SVignesh R
301192bb756SVignesh R return 0;
302192bb756SVignesh R }
303192bb756SVignesh R
__davinci_spi_xfer(struct davinci_spi_slave * ds,unsigned int bitlen,const void * dout,void * din,unsigned long flags)304192bb756SVignesh R static int __davinci_spi_xfer(struct davinci_spi_slave *ds,
305192bb756SVignesh R unsigned int bitlen, const void *dout, void *din,
306192bb756SVignesh R unsigned long flags)
307192bb756SVignesh R {
308192bb756SVignesh R unsigned int len;
309192bb756SVignesh R
310192bb756SVignesh R if (bitlen == 0)
311192bb756SVignesh R /* Finish any previously submitted transfers */
312192bb756SVignesh R goto out;
313192bb756SVignesh R
314192bb756SVignesh R /*
315192bb756SVignesh R * It's not clear how non-8-bit-aligned transfers are supposed to be
316192bb756SVignesh R * represented as a stream of bytes...this is a limitation of
317192bb756SVignesh R * the current SPI interface - here we terminate on receiving such a
318192bb756SVignesh R * transfer request.
319192bb756SVignesh R */
320192bb756SVignesh R if (bitlen % 8) {
321192bb756SVignesh R /* Errors always terminate an ongoing transfer */
322192bb756SVignesh R flags |= SPI_XFER_END;
323192bb756SVignesh R goto out;
324192bb756SVignesh R }
325192bb756SVignesh R
326192bb756SVignesh R len = bitlen / 8;
327192bb756SVignesh R
328192bb756SVignesh R if (!dout)
329192bb756SVignesh R return davinci_spi_read(ds, len, din, flags);
330192bb756SVignesh R if (!din)
331192bb756SVignesh R return davinci_spi_write(ds, len, dout, flags);
332192bb756SVignesh R if (!ds->half_duplex)
333192bb756SVignesh R return davinci_spi_read_write(ds, len, din, dout, flags);
334192bb756SVignesh R
335192bb756SVignesh R printf("SPI full duplex not supported\n");
336192bb756SVignesh R flags |= SPI_XFER_END;
337192bb756SVignesh R
338192bb756SVignesh R out:
339192bb756SVignesh R if (flags & SPI_XFER_END) {
340192bb756SVignesh R u8 dummy = 0;
341192bb756SVignesh R davinci_spi_write(ds, 1, &dummy, flags);
342192bb756SVignesh R }
343192bb756SVignesh R return 0;
344192bb756SVignesh R }
345192bb756SVignesh R
346192bb756SVignesh R #ifndef CONFIG_DM_SPI
347192bb756SVignesh R
to_davinci_spi(struct spi_slave * slave)348192bb756SVignesh R static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
349192bb756SVignesh R {
350192bb756SVignesh R return container_of(slave, struct davinci_spi_slave, slave);
351192bb756SVignesh R }
35277436d66SNick Thompson
spi_cs_is_valid(unsigned int bus,unsigned int cs)353ff6e31d3SJagan Teki int spi_cs_is_valid(unsigned int bus, unsigned int cs)
354ff6e31d3SJagan Teki {
355ff6e31d3SJagan Teki int ret = 0;
356ff6e31d3SJagan Teki
357ff6e31d3SJagan Teki switch (bus) {
358ff6e31d3SJagan Teki case SPI0_BUS:
359ff6e31d3SJagan Teki if (cs < SPI0_NUM_CS)
360ff6e31d3SJagan Teki ret = 1;
361ff6e31d3SJagan Teki break;
362ff6e31d3SJagan Teki #ifdef CONFIG_SYS_SPI1
363ff6e31d3SJagan Teki case SPI1_BUS:
364ff6e31d3SJagan Teki if (cs < SPI1_NUM_CS)
365ff6e31d3SJagan Teki ret = 1;
366ff6e31d3SJagan Teki break;
367ff6e31d3SJagan Teki #endif
368ff6e31d3SJagan Teki #ifdef CONFIG_SYS_SPI2
369ff6e31d3SJagan Teki case SPI2_BUS:
370ff6e31d3SJagan Teki if (cs < SPI2_NUM_CS)
371ff6e31d3SJagan Teki ret = 1;
372ff6e31d3SJagan Teki break;
373ff6e31d3SJagan Teki #endif
374ff6e31d3SJagan Teki default:
375ff6e31d3SJagan Teki /* Invalid bus number. Do nothing */
376ff6e31d3SJagan Teki break;
377ff6e31d3SJagan Teki }
378ff6e31d3SJagan Teki return ret;
379ff6e31d3SJagan Teki }
380ff6e31d3SJagan Teki
spi_cs_activate(struct spi_slave * slave)381ff6e31d3SJagan Teki void spi_cs_activate(struct spi_slave *slave)
382ff6e31d3SJagan Teki {
383ff6e31d3SJagan Teki /* do nothing */
384ff6e31d3SJagan Teki }
385ff6e31d3SJagan Teki
spi_cs_deactivate(struct spi_slave * slave)386ff6e31d3SJagan Teki void spi_cs_deactivate(struct spi_slave *slave)
387ff6e31d3SJagan Teki {
388ff6e31d3SJagan Teki /* do nothing */
389ff6e31d3SJagan Teki }
390ff6e31d3SJagan Teki
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)391ff6e31d3SJagan Teki struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
392ff6e31d3SJagan Teki unsigned int max_hz, unsigned int mode)
393ff6e31d3SJagan Teki {
394ff6e31d3SJagan Teki struct davinci_spi_slave *ds;
395ff6e31d3SJagan Teki
396ff6e31d3SJagan Teki if (!spi_cs_is_valid(bus, cs))
397ff6e31d3SJagan Teki return NULL;
398ff6e31d3SJagan Teki
399ff6e31d3SJagan Teki ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
400ff6e31d3SJagan Teki if (!ds)
401ff6e31d3SJagan Teki return NULL;
402ff6e31d3SJagan Teki
403ff6e31d3SJagan Teki switch (bus) {
404ff6e31d3SJagan Teki case SPI0_BUS:
405ff6e31d3SJagan Teki ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
406ff6e31d3SJagan Teki break;
407ff6e31d3SJagan Teki #ifdef CONFIG_SYS_SPI1
408ff6e31d3SJagan Teki case SPI1_BUS:
409ff6e31d3SJagan Teki ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
410ff6e31d3SJagan Teki break;
411ff6e31d3SJagan Teki #endif
412ff6e31d3SJagan Teki #ifdef CONFIG_SYS_SPI2
413ff6e31d3SJagan Teki case SPI2_BUS:
414ff6e31d3SJagan Teki ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
415ff6e31d3SJagan Teki break;
416ff6e31d3SJagan Teki #endif
417ff6e31d3SJagan Teki default: /* Invalid bus number */
418ff6e31d3SJagan Teki return NULL;
419ff6e31d3SJagan Teki }
420ff6e31d3SJagan Teki
421ff6e31d3SJagan Teki ds->freq = max_hz;
422192bb756SVignesh R ds->mode = mode;
423ff6e31d3SJagan Teki
424ff6e31d3SJagan Teki return &ds->slave;
425ff6e31d3SJagan Teki }
426ff6e31d3SJagan Teki
spi_free_slave(struct spi_slave * slave)427ff6e31d3SJagan Teki void spi_free_slave(struct spi_slave *slave)
428ff6e31d3SJagan Teki {
429ff6e31d3SJagan Teki struct davinci_spi_slave *ds = to_davinci_spi(slave);
430ff6e31d3SJagan Teki
431ff6e31d3SJagan Teki free(ds);
432ff6e31d3SJagan Teki }
433ff6e31d3SJagan Teki
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)434192bb756SVignesh R int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
435192bb756SVignesh R const void *dout, void *din, unsigned long flags)
436192bb756SVignesh R {
437192bb756SVignesh R struct davinci_spi_slave *ds = to_davinci_spi(slave);
438192bb756SVignesh R
439192bb756SVignesh R ds->cur_cs = slave->cs;
440192bb756SVignesh R
441192bb756SVignesh R return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
442192bb756SVignesh R }
443192bb756SVignesh R
spi_claim_bus(struct spi_slave * slave)444ff6e31d3SJagan Teki int spi_claim_bus(struct spi_slave *slave)
445ff6e31d3SJagan Teki {
446ff6e31d3SJagan Teki struct davinci_spi_slave *ds = to_davinci_spi(slave);
447ff6e31d3SJagan Teki
448192bb756SVignesh R #ifdef CONFIG_SPI_HALF_DUPLEX
449192bb756SVignesh R ds->half_duplex = true;
450192bb756SVignesh R #else
451192bb756SVignesh R ds->half_duplex = false;
452192bb756SVignesh R #endif
453192bb756SVignesh R return __davinci_spi_claim_bus(ds, ds->slave.cs);
454ff6e31d3SJagan Teki }
455ff6e31d3SJagan Teki
spi_release_bus(struct spi_slave * slave)456ff6e31d3SJagan Teki void spi_release_bus(struct spi_slave *slave)
457ff6e31d3SJagan Teki {
458ff6e31d3SJagan Teki struct davinci_spi_slave *ds = to_davinci_spi(slave);
459ff6e31d3SJagan Teki
460192bb756SVignesh R __davinci_spi_release_bus(ds);
461ff6e31d3SJagan Teki }
462ff6e31d3SJagan Teki
463dce6538fSNick Thompson #else
davinci_spi_set_speed(struct udevice * bus,uint max_hz)464192bb756SVignesh R static int davinci_spi_set_speed(struct udevice *bus, uint max_hz)
465192bb756SVignesh R {
466192bb756SVignesh R struct davinci_spi_slave *ds = dev_get_priv(bus);
4678ed58856SSekhar Nori
468192bb756SVignesh R debug("%s speed %u\n", __func__, max_hz);
469192bb756SVignesh R if (max_hz > CONFIG_SYS_SPI_CLK / 2)
470192bb756SVignesh R return -EINVAL;
471192bb756SVignesh R
472192bb756SVignesh R ds->freq = max_hz;
473192bb756SVignesh R
4748ed58856SSekhar Nori return 0;
4758ed58856SSekhar Nori }
476192bb756SVignesh R
davinci_spi_set_mode(struct udevice * bus,uint mode)477192bb756SVignesh R static int davinci_spi_set_mode(struct udevice *bus, uint mode)
478192bb756SVignesh R {
479192bb756SVignesh R struct davinci_spi_slave *ds = dev_get_priv(bus);
480192bb756SVignesh R
481192bb756SVignesh R debug("%s mode %u\n", __func__, mode);
482192bb756SVignesh R ds->mode = mode;
483192bb756SVignesh R
484192bb756SVignesh R return 0;
485192bb756SVignesh R }
486192bb756SVignesh R
davinci_spi_claim_bus(struct udevice * dev)487192bb756SVignesh R static int davinci_spi_claim_bus(struct udevice *dev)
488192bb756SVignesh R {
489192bb756SVignesh R struct dm_spi_slave_platdata *slave_plat =
490192bb756SVignesh R dev_get_parent_platdata(dev);
491192bb756SVignesh R struct udevice *bus = dev->parent;
492192bb756SVignesh R struct davinci_spi_slave *ds = dev_get_priv(bus);
493192bb756SVignesh R
494192bb756SVignesh R if (slave_plat->cs >= ds->num_cs) {
495192bb756SVignesh R printf("Invalid SPI chipselect\n");
496192bb756SVignesh R return -EINVAL;
497192bb756SVignesh R }
498192bb756SVignesh R ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
499192bb756SVignesh R
500192bb756SVignesh R return __davinci_spi_claim_bus(ds, slave_plat->cs);
501192bb756SVignesh R }
502192bb756SVignesh R
davinci_spi_release_bus(struct udevice * dev)503192bb756SVignesh R static int davinci_spi_release_bus(struct udevice *dev)
504192bb756SVignesh R {
505192bb756SVignesh R struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
506192bb756SVignesh R
507192bb756SVignesh R return __davinci_spi_release_bus(ds);
508192bb756SVignesh R }
509192bb756SVignesh R
davinci_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)510192bb756SVignesh R static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen,
511192bb756SVignesh R const void *dout, void *din,
512192bb756SVignesh R unsigned long flags)
513192bb756SVignesh R {
514192bb756SVignesh R struct dm_spi_slave_platdata *slave =
515192bb756SVignesh R dev_get_parent_platdata(dev);
516192bb756SVignesh R struct udevice *bus = dev->parent;
517192bb756SVignesh R struct davinci_spi_slave *ds = dev_get_priv(bus);
518192bb756SVignesh R
519192bb756SVignesh R if (slave->cs >= ds->num_cs) {
520192bb756SVignesh R printf("Invalid SPI chipselect\n");
521192bb756SVignesh R return -EINVAL;
522192bb756SVignesh R }
523192bb756SVignesh R ds->cur_cs = slave->cs;
524192bb756SVignesh R
525192bb756SVignesh R return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
526192bb756SVignesh R }
527192bb756SVignesh R
528192bb756SVignesh R static const struct dm_spi_ops davinci_spi_ops = {
529192bb756SVignesh R .claim_bus = davinci_spi_claim_bus,
530192bb756SVignesh R .release_bus = davinci_spi_release_bus,
531192bb756SVignesh R .xfer = davinci_spi_xfer,
532192bb756SVignesh R .set_speed = davinci_spi_set_speed,
533192bb756SVignesh R .set_mode = davinci_spi_set_mode,
534192bb756SVignesh R };
535192bb756SVignesh R
davinci_spi_probe(struct udevice * bus)536*ba3c22bfSJagan Teki static int davinci_spi_probe(struct udevice *bus)
537*ba3c22bfSJagan Teki {
538*ba3c22bfSJagan Teki struct davinci_spi_slave *ds = dev_get_priv(bus);
539*ba3c22bfSJagan Teki struct davinci_spi_platdata *plat = bus->platdata;
540*ba3c22bfSJagan Teki ds->regs = plat->regs;
541*ba3c22bfSJagan Teki ds->num_cs = plat->num_cs;
542*ba3c22bfSJagan Teki
543*ba3c22bfSJagan Teki return 0;
544*ba3c22bfSJagan Teki }
545*ba3c22bfSJagan Teki
546*ba3c22bfSJagan Teki #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
davinci_ofdata_to_platadata(struct udevice * bus)547*ba3c22bfSJagan Teki static int davinci_ofdata_to_platadata(struct udevice *bus)
548*ba3c22bfSJagan Teki {
549*ba3c22bfSJagan Teki struct davinci_spi_platdata *plat = bus->platdata;
550*ba3c22bfSJagan Teki fdt_addr_t addr;
551*ba3c22bfSJagan Teki
552*ba3c22bfSJagan Teki addr = devfdt_get_addr(bus);
553*ba3c22bfSJagan Teki if (addr == FDT_ADDR_T_NONE)
554*ba3c22bfSJagan Teki return -EINVAL;
555*ba3c22bfSJagan Teki
556*ba3c22bfSJagan Teki plat->regs = (struct davinci_spi_regs *)addr;
557*ba3c22bfSJagan Teki plat->num_cs = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), "num-cs", 4);
558*ba3c22bfSJagan Teki
559*ba3c22bfSJagan Teki return 0;
560*ba3c22bfSJagan Teki }
561*ba3c22bfSJagan Teki
562192bb756SVignesh R static const struct udevice_id davinci_spi_ids[] = {
563192bb756SVignesh R { .compatible = "ti,keystone-spi" },
564192bb756SVignesh R { .compatible = "ti,dm6441-spi" },
565ab0ac272SAdam Ford { .compatible = "ti,da830-spi" },
566192bb756SVignesh R { }
567192bb756SVignesh R };
568*ba3c22bfSJagan Teki #endif
569192bb756SVignesh R
570192bb756SVignesh R U_BOOT_DRIVER(davinci_spi) = {
571192bb756SVignesh R .name = "davinci_spi",
572192bb756SVignesh R .id = UCLASS_SPI,
573*ba3c22bfSJagan Teki #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
574192bb756SVignesh R .of_match = davinci_spi_ids,
575192bb756SVignesh R .ofdata_to_platdata = davinci_ofdata_to_platadata,
576*ba3c22bfSJagan Teki .platdata_auto_alloc_size = sizeof(struct davinci_spi_platdata),
577*ba3c22bfSJagan Teki #endif
578192bb756SVignesh R .probe = davinci_spi_probe,
579*ba3c22bfSJagan Teki .ops = &davinci_spi_ops,
580*ba3c22bfSJagan Teki .priv_auto_alloc_size = sizeof(struct davinci_spi_slave),
581192bb756SVignesh R };
582192bb756SVignesh R #endif
583