xref: /openbmc/u-boot/drivers/spi/davinci_spi.c (revision 9450ab2ba8d720bd9f73bccc0af2e2b5a2c2aaf1)
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