xref: /rk3399_rockchip-uboot/drivers/spi/davinci_spi.c (revision e6d2fbf70acb57e778e9be2f30df15c344c37902)
18ed58856SSekhar Nori /*
28ed58856SSekhar Nori  * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
38ed58856SSekhar Nori  *
48ed58856SSekhar Nori  * Driver for SPI controller on DaVinci. Based on atmel_spi.c
58ed58856SSekhar Nori  * by Atmel Corporation
68ed58856SSekhar Nori  *
78ed58856SSekhar Nori  * Copyright (C) 2007 Atmel Corporation
88ed58856SSekhar Nori  *
91a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
108ed58856SSekhar Nori  */
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>
16*e6d2fbf7SJagan Teki 
17*e6d2fbf7SJagan Teki struct davinci_spi_regs {
18*e6d2fbf7SJagan Teki 	dv_reg	gcr0;		/* 0x00 */
19*e6d2fbf7SJagan Teki 	dv_reg	gcr1;		/* 0x04 */
20*e6d2fbf7SJagan Teki 	dv_reg	int0;		/* 0x08 */
21*e6d2fbf7SJagan Teki 	dv_reg	lvl;		/* 0x0c */
22*e6d2fbf7SJagan Teki 	dv_reg	flg;		/* 0x10 */
23*e6d2fbf7SJagan Teki 	dv_reg	pc0;		/* 0x14 */
24*e6d2fbf7SJagan Teki 	dv_reg	pc1;		/* 0x18 */
25*e6d2fbf7SJagan Teki 	dv_reg	pc2;		/* 0x1c */
26*e6d2fbf7SJagan Teki 	dv_reg	pc3;		/* 0x20 */
27*e6d2fbf7SJagan Teki 	dv_reg	pc4;		/* 0x24 */
28*e6d2fbf7SJagan Teki 	dv_reg	pc5;		/* 0x28 */
29*e6d2fbf7SJagan Teki 	dv_reg	rsvd[3];
30*e6d2fbf7SJagan Teki 	dv_reg	dat0;		/* 0x38 */
31*e6d2fbf7SJagan Teki 	dv_reg	dat1;		/* 0x3c */
32*e6d2fbf7SJagan Teki 	dv_reg	buf;		/* 0x40 */
33*e6d2fbf7SJagan Teki 	dv_reg	emu;		/* 0x44 */
34*e6d2fbf7SJagan Teki 	dv_reg	delay;		/* 0x48 */
35*e6d2fbf7SJagan Teki 	dv_reg	def;		/* 0x4c */
36*e6d2fbf7SJagan Teki 	dv_reg	fmt0;		/* 0x50 */
37*e6d2fbf7SJagan Teki 	dv_reg	fmt1;		/* 0x54 */
38*e6d2fbf7SJagan Teki 	dv_reg	fmt2;		/* 0x58 */
39*e6d2fbf7SJagan Teki 	dv_reg	fmt3;		/* 0x5c */
40*e6d2fbf7SJagan Teki 	dv_reg	intvec0;	/* 0x60 */
41*e6d2fbf7SJagan Teki 	dv_reg	intvec1;	/* 0x64 */
42*e6d2fbf7SJagan Teki };
43*e6d2fbf7SJagan Teki 
44*e6d2fbf7SJagan Teki #define BIT(x)			(1 << (x))
45*e6d2fbf7SJagan Teki 
46*e6d2fbf7SJagan Teki /* SPIGCR0 */
47*e6d2fbf7SJagan Teki #define SPIGCR0_SPIENA_MASK	0x1
48*e6d2fbf7SJagan Teki #define SPIGCR0_SPIRST_MASK	0x0
49*e6d2fbf7SJagan Teki 
50*e6d2fbf7SJagan Teki /* SPIGCR0 */
51*e6d2fbf7SJagan Teki #define SPIGCR1_CLKMOD_MASK	BIT(1)
52*e6d2fbf7SJagan Teki #define SPIGCR1_MASTER_MASK	BIT(0)
53*e6d2fbf7SJagan Teki #define SPIGCR1_SPIENA_MASK	BIT(24)
54*e6d2fbf7SJagan Teki 
55*e6d2fbf7SJagan Teki /* SPIPC0 */
56*e6d2fbf7SJagan Teki #define SPIPC0_DIFUN_MASK	BIT(11)		/* SIMO */
57*e6d2fbf7SJagan Teki #define SPIPC0_DOFUN_MASK	BIT(10)		/* SOMI */
58*e6d2fbf7SJagan Teki #define SPIPC0_CLKFUN_MASK	BIT(9)		/* CLK */
59*e6d2fbf7SJagan Teki #define SPIPC0_EN0FUN_MASK	BIT(0)
60*e6d2fbf7SJagan Teki 
61*e6d2fbf7SJagan Teki /* SPIFMT0 */
62*e6d2fbf7SJagan Teki #define SPIFMT_SHIFTDIR_SHIFT	20
63*e6d2fbf7SJagan Teki #define SPIFMT_POLARITY_SHIFT	17
64*e6d2fbf7SJagan Teki #define SPIFMT_PHASE_SHIFT	16
65*e6d2fbf7SJagan Teki #define SPIFMT_PRESCALE_SHIFT	8
66*e6d2fbf7SJagan Teki 
67*e6d2fbf7SJagan Teki /* SPIDAT1 */
68*e6d2fbf7SJagan Teki #define SPIDAT1_CSHOLD_SHIFT	28
69*e6d2fbf7SJagan Teki #define SPIDAT1_CSNR_SHIFT	16
70*e6d2fbf7SJagan Teki 
71*e6d2fbf7SJagan Teki /* SPIDELAY */
72*e6d2fbf7SJagan Teki #define SPI_C2TDELAY_SHIFT	24
73*e6d2fbf7SJagan Teki #define SPI_T2CDELAY_SHIFT	16
74*e6d2fbf7SJagan Teki 
75*e6d2fbf7SJagan Teki /* SPIBUF */
76*e6d2fbf7SJagan Teki #define SPIBUF_RXEMPTY_MASK	BIT(31)
77*e6d2fbf7SJagan Teki #define SPIBUF_TXFULL_MASK	BIT(29)
78*e6d2fbf7SJagan Teki 
79*e6d2fbf7SJagan Teki /* SPIDEF */
80*e6d2fbf7SJagan Teki #define SPIDEF_CSDEF0_MASK	BIT(0)
81*e6d2fbf7SJagan Teki 
82*e6d2fbf7SJagan Teki #define SPI0_BUS		0
83*e6d2fbf7SJagan Teki #define SPI0_BASE		CONFIG_SYS_SPI_BASE
84*e6d2fbf7SJagan Teki /*
85*e6d2fbf7SJagan Teki  * Define default SPI0_NUM_CS as 1 for existing platforms that uses this
86*e6d2fbf7SJagan Teki  * driver. Platform can configure number of CS using CONFIG_SYS_SPI0_NUM_CS
87*e6d2fbf7SJagan Teki  * if more than one CS is supported and by defining CONFIG_SYS_SPI0.
88*e6d2fbf7SJagan Teki  */
89*e6d2fbf7SJagan Teki #ifndef CONFIG_SYS_SPI0
90*e6d2fbf7SJagan Teki #define SPI0_NUM_CS		1
91*e6d2fbf7SJagan Teki #else
92*e6d2fbf7SJagan Teki #define SPI0_NUM_CS		CONFIG_SYS_SPI0_NUM_CS
93*e6d2fbf7SJagan Teki #endif
94*e6d2fbf7SJagan Teki 
95*e6d2fbf7SJagan Teki /*
96*e6d2fbf7SJagan Teki  * define CONFIG_SYS_SPI1 when platform has spi-1 device (bus #1) and
97*e6d2fbf7SJagan Teki  * CONFIG_SYS_SPI1_NUM_CS defines number of CS on this bus
98*e6d2fbf7SJagan Teki  */
99*e6d2fbf7SJagan Teki #ifdef CONFIG_SYS_SPI1
100*e6d2fbf7SJagan Teki #define SPI1_BUS		1
101*e6d2fbf7SJagan Teki #define SPI1_NUM_CS		CONFIG_SYS_SPI1_NUM_CS
102*e6d2fbf7SJagan Teki #define SPI1_BASE		CONFIG_SYS_SPI1_BASE
103*e6d2fbf7SJagan Teki #endif
104*e6d2fbf7SJagan Teki 
105*e6d2fbf7SJagan Teki /*
106*e6d2fbf7SJagan Teki  * define CONFIG_SYS_SPI2 when platform has spi-2 device (bus #2) and
107*e6d2fbf7SJagan Teki  * CONFIG_SYS_SPI2_NUM_CS defines number of CS on this bus
108*e6d2fbf7SJagan Teki  */
109*e6d2fbf7SJagan Teki #ifdef CONFIG_SYS_SPI2
110*e6d2fbf7SJagan Teki #define SPI2_BUS		2
111*e6d2fbf7SJagan Teki #define SPI2_NUM_CS		CONFIG_SYS_SPI2_NUM_CS
112*e6d2fbf7SJagan Teki #define SPI2_BASE		CONFIG_SYS_SPI2_BASE
113*e6d2fbf7SJagan Teki #endif
114*e6d2fbf7SJagan Teki 
115*e6d2fbf7SJagan Teki struct davinci_spi_slave {
116*e6d2fbf7SJagan Teki 	struct spi_slave slave;
117*e6d2fbf7SJagan Teki 	struct davinci_spi_regs *regs;
118*e6d2fbf7SJagan Teki 	unsigned int freq;
119*e6d2fbf7SJagan Teki };
120*e6d2fbf7SJagan Teki 
121*e6d2fbf7SJagan Teki static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
122*e6d2fbf7SJagan Teki {
123*e6d2fbf7SJagan Teki 	return container_of(slave, struct davinci_spi_slave, slave);
124*e6d2fbf7SJagan Teki }
1258ed58856SSekhar Nori 
1268ed58856SSekhar Nori void spi_init()
1278ed58856SSekhar Nori {
1288ed58856SSekhar Nori 	/* do nothing */
1298ed58856SSekhar Nori }
1308ed58856SSekhar Nori 
1318ed58856SSekhar Nori struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
1328ed58856SSekhar Nori 			unsigned int max_hz, unsigned int mode)
1338ed58856SSekhar Nori {
1348ed58856SSekhar Nori 	struct davinci_spi_slave	*ds;
1358ed58856SSekhar Nori 
1368ed58856SSekhar Nori 	if (!spi_cs_is_valid(bus, cs))
1378ed58856SSekhar Nori 		return NULL;
1388ed58856SSekhar Nori 
139d3504feeSSimon Glass 	ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
1408ed58856SSekhar Nori 	if (!ds)
1418ed58856SSekhar Nori 		return NULL;
1428ed58856SSekhar Nori 
1432bcdf84dSKaricheri, Muralidharan 	switch (bus) {
1442bcdf84dSKaricheri, Muralidharan 	case SPI0_BUS:
1452bcdf84dSKaricheri, Muralidharan 		ds->regs = (struct davinci_spi_regs *)SPI0_BASE;
1462bcdf84dSKaricheri, Muralidharan 		break;
1472bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI1
1482bcdf84dSKaricheri, Muralidharan 	case SPI1_BUS:
1497a4861faSAxel Lin 		ds->regs = (struct davinci_spi_regs *)SPI1_BASE;
1502bcdf84dSKaricheri, Muralidharan 		break;
1512bcdf84dSKaricheri, Muralidharan #endif
1522bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI2
1532bcdf84dSKaricheri, Muralidharan 	case SPI2_BUS:
1542bcdf84dSKaricheri, Muralidharan 		ds->regs = (struct davinci_spi_regs *)SPI2_BASE;
1552bcdf84dSKaricheri, Muralidharan 		break;
1562bcdf84dSKaricheri, Muralidharan #endif
1572bcdf84dSKaricheri, Muralidharan 	default: /* Invalid bus number */
1582bcdf84dSKaricheri, Muralidharan 		return NULL;
1592bcdf84dSKaricheri, Muralidharan 	}
1602bcdf84dSKaricheri, Muralidharan 
1618ed58856SSekhar Nori 	ds->freq = max_hz;
1628ed58856SSekhar Nori 
1638ed58856SSekhar Nori 	return &ds->slave;
1648ed58856SSekhar Nori }
1658ed58856SSekhar Nori 
1668ed58856SSekhar Nori void spi_free_slave(struct spi_slave *slave)
1678ed58856SSekhar Nori {
1688ed58856SSekhar Nori 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
1698ed58856SSekhar Nori 
1708ed58856SSekhar Nori 	free(ds);
1718ed58856SSekhar Nori }
1728ed58856SSekhar Nori 
1738ed58856SSekhar Nori int spi_claim_bus(struct spi_slave *slave)
1748ed58856SSekhar Nori {
1758ed58856SSekhar Nori 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
17677436d66SNick Thompson 	unsigned int scalar;
1778ed58856SSekhar Nori 
1788ed58856SSekhar Nori 	/* Enable the SPI hardware */
1798ed58856SSekhar Nori 	writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
1808ed58856SSekhar Nori 	udelay(1000);
1818ed58856SSekhar Nori 	writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
1828ed58856SSekhar Nori 
1838ed58856SSekhar Nori 	/* Set master mode, powered up and not activated */
1848ed58856SSekhar Nori 	writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
1858ed58856SSekhar Nori 
1868ed58856SSekhar Nori 	/* CS, CLK, SIMO and SOMI are functional pins */
1872bcdf84dSKaricheri, Muralidharan 	writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
1888ed58856SSekhar Nori 		SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
1898ed58856SSekhar Nori 
1908ed58856SSekhar Nori 	/* setup format */
1918ed58856SSekhar Nori 	scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
1928ed58856SSekhar Nori 
1938ed58856SSekhar Nori 	/*
1948ed58856SSekhar Nori 	 * Use following format:
1958ed58856SSekhar Nori 	 *   character length = 8,
1968ed58856SSekhar Nori 	 *   clock signal delayed by half clk cycle,
1978ed58856SSekhar Nori 	 *   clock low in idle state - Mode 0,
1988ed58856SSekhar Nori 	 *   MSB shifted out first
1998ed58856SSekhar Nori 	 */
2008ed58856SSekhar Nori 	writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
2018ed58856SSekhar Nori 		(1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
2028ed58856SSekhar Nori 
2038ed58856SSekhar Nori 	/*
2048ed58856SSekhar Nori 	 * Including a minor delay. No science here. Should be good even with
2058ed58856SSekhar Nori 	 * no delay
2068ed58856SSekhar Nori 	 */
2078ed58856SSekhar Nori 	writel((50 << SPI_C2TDELAY_SHIFT) |
2088ed58856SSekhar Nori 		(50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
2098ed58856SSekhar Nori 
2108ed58856SSekhar Nori 	/* default chip select register */
2118ed58856SSekhar Nori 	writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
2128ed58856SSekhar Nori 
2138ed58856SSekhar Nori 	/* no interrupts */
2148ed58856SSekhar Nori 	writel(0, &ds->regs->int0);
2158ed58856SSekhar Nori 	writel(0, &ds->regs->lvl);
2168ed58856SSekhar Nori 
2178ed58856SSekhar Nori 	/* enable SPI */
21877436d66SNick Thompson 	writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
2198ed58856SSekhar Nori 
2208ed58856SSekhar Nori 	return 0;
2218ed58856SSekhar Nori }
2228ed58856SSekhar Nori 
2238ed58856SSekhar Nori void spi_release_bus(struct spi_slave *slave)
2248ed58856SSekhar Nori {
2258ed58856SSekhar Nori 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
2268ed58856SSekhar Nori 
2278ed58856SSekhar Nori 	/* Disable the SPI hardware */
2288ed58856SSekhar Nori 	writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
2298ed58856SSekhar Nori }
2308ed58856SSekhar Nori 
23177436d66SNick Thompson /*
23277436d66SNick Thompson  * This functions needs to act like a macro to avoid pipeline reloads in the
23377436d66SNick Thompson  * loops below. Use always_inline. This gains us about 160KiB/s and the bloat
23477436d66SNick Thompson  * appears to be zero bytes (da830).
23577436d66SNick Thompson  */
23677436d66SNick Thompson __attribute__((always_inline))
23777436d66SNick Thompson static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data)
23877436d66SNick Thompson {
23977436d66SNick Thompson 	u32	buf_reg_val;
24077436d66SNick Thompson 
24177436d66SNick Thompson 	/* send out data */
24277436d66SNick Thompson 	writel(data, &ds->regs->dat1);
24377436d66SNick Thompson 
24477436d66SNick Thompson 	/* wait for the data to clock in/out */
24577436d66SNick Thompson 	while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK)
24677436d66SNick Thompson 		;
24777436d66SNick Thompson 
24877436d66SNick Thompson 	return buf_reg_val;
24977436d66SNick Thompson }
25077436d66SNick Thompson 
25177436d66SNick Thompson static int davinci_spi_read(struct spi_slave *slave, unsigned int len,
25277436d66SNick Thompson 			    u8 *rxp, unsigned long flags)
25377436d66SNick Thompson {
25477436d66SNick Thompson 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
25577436d66SNick Thompson 	unsigned int data1_reg_val;
25677436d66SNick Thompson 
25777436d66SNick Thompson 	/* enable CS hold, CS[n] and clear the data bits */
25877436d66SNick Thompson 	data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
25977436d66SNick Thompson 			 (slave->cs << SPIDAT1_CSNR_SHIFT));
26077436d66SNick Thompson 
26177436d66SNick Thompson 	/* wait till TXFULL is deasserted */
26277436d66SNick Thompson 	while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
26377436d66SNick Thompson 		;
26477436d66SNick Thompson 
26577436d66SNick Thompson 	/* preload the TX buffer to avoid clock starvation */
26677436d66SNick Thompson 	writel(data1_reg_val, &ds->regs->dat1);
26777436d66SNick Thompson 
26877436d66SNick Thompson 	/* keep reading 1 byte until only 1 byte left */
26977436d66SNick Thompson 	while ((len--) > 1)
27077436d66SNick Thompson 		*rxp++ = davinci_spi_xfer_data(ds, data1_reg_val);
27177436d66SNick Thompson 
27277436d66SNick Thompson 	/* clear CS hold when we reach the end */
27377436d66SNick Thompson 	if (flags & SPI_XFER_END)
27477436d66SNick Thompson 		data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
27577436d66SNick Thompson 
27677436d66SNick Thompson 	/* read the last byte */
27777436d66SNick Thompson 	*rxp = davinci_spi_xfer_data(ds, data1_reg_val);
27877436d66SNick Thompson 
27977436d66SNick Thompson 	return 0;
28077436d66SNick Thompson }
28177436d66SNick Thompson 
28277436d66SNick Thompson static int davinci_spi_write(struct spi_slave *slave, unsigned int len,
28377436d66SNick Thompson 			     const u8 *txp, unsigned long flags)
28477436d66SNick Thompson {
28577436d66SNick Thompson 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
28677436d66SNick Thompson 	unsigned int data1_reg_val;
28777436d66SNick Thompson 
28877436d66SNick Thompson 	/* enable CS hold and clear the data bits */
28977436d66SNick Thompson 	data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
29077436d66SNick Thompson 			 (slave->cs << SPIDAT1_CSNR_SHIFT));
29177436d66SNick Thompson 
29277436d66SNick Thompson 	/* wait till TXFULL is deasserted */
29377436d66SNick Thompson 	while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
29477436d66SNick Thompson 		;
29577436d66SNick Thompson 
29677436d66SNick Thompson 	/* preload the TX buffer to avoid clock starvation */
29777436d66SNick Thompson 	if (len > 2) {
29877436d66SNick Thompson 		writel(data1_reg_val | *txp++, &ds->regs->dat1);
29977436d66SNick Thompson 		len--;
30077436d66SNick Thompson 	}
30177436d66SNick Thompson 
30277436d66SNick Thompson 	/* keep writing 1 byte until only 1 byte left */
30377436d66SNick Thompson 	while ((len--) > 1)
30477436d66SNick Thompson 		davinci_spi_xfer_data(ds, data1_reg_val | *txp++);
30577436d66SNick Thompson 
30677436d66SNick Thompson 	/* clear CS hold when we reach the end */
30777436d66SNick Thompson 	if (flags & SPI_XFER_END)
30877436d66SNick Thompson 		data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
30977436d66SNick Thompson 
31077436d66SNick Thompson 	/* write the last byte */
31177436d66SNick Thompson 	davinci_spi_xfer_data(ds, data1_reg_val | *txp);
31277436d66SNick Thompson 
31377436d66SNick Thompson 	return 0;
31477436d66SNick Thompson }
31577436d66SNick Thompson 
31677436d66SNick Thompson #ifndef CONFIG_SPI_HALF_DUPLEX
31777436d66SNick Thompson static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
31877436d66SNick Thompson 				  u8 *rxp, const u8 *txp, unsigned long flags)
31977436d66SNick Thompson {
32077436d66SNick Thompson 	struct davinci_spi_slave *ds = to_davinci_spi(slave);
32177436d66SNick Thompson 	unsigned int data1_reg_val;
32277436d66SNick Thompson 
32377436d66SNick Thompson 	/* enable CS hold and clear the data bits */
32477436d66SNick Thompson 	data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
32577436d66SNick Thompson 			 (slave->cs << SPIDAT1_CSNR_SHIFT));
32677436d66SNick Thompson 
32777436d66SNick Thompson 	/* wait till TXFULL is deasserted */
32877436d66SNick Thompson 	while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
32977436d66SNick Thompson 		;
33077436d66SNick Thompson 
33177436d66SNick Thompson 	/* keep reading and writing 1 byte until only 1 byte left */
33277436d66SNick Thompson 	while ((len--) > 1)
33377436d66SNick Thompson 		*rxp++ = davinci_spi_xfer_data(ds, data1_reg_val | *txp++);
33477436d66SNick Thompson 
33577436d66SNick Thompson 	/* clear CS hold when we reach the end */
33677436d66SNick Thompson 	if (flags & SPI_XFER_END)
33777436d66SNick Thompson 		data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
33877436d66SNick Thompson 
33977436d66SNick Thompson 	/* read and write the last byte */
34077436d66SNick Thompson 	*rxp = davinci_spi_xfer_data(ds, data1_reg_val | *txp);
34177436d66SNick Thompson 
34277436d66SNick Thompson 	return 0;
34377436d66SNick Thompson }
34477436d66SNick Thompson #endif
34577436d66SNick Thompson 
3468ed58856SSekhar Nori int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
3478ed58856SSekhar Nori 	     const void *dout, void *din, unsigned long flags)
3488ed58856SSekhar Nori {
34977436d66SNick Thompson 	unsigned int len;
3508ed58856SSekhar Nori 
3518ed58856SSekhar Nori 	if (bitlen == 0)
3528ed58856SSekhar Nori 		/* Finish any previously submitted transfers */
3538ed58856SSekhar Nori 		goto out;
3548ed58856SSekhar Nori 
3558ed58856SSekhar Nori 	/*
3568ed58856SSekhar Nori 	 * It's not clear how non-8-bit-aligned transfers are supposed to be
3578ed58856SSekhar Nori 	 * represented as a stream of bytes...this is a limitation of
3588ed58856SSekhar Nori 	 * the current SPI interface - here we terminate on receiving such a
3598ed58856SSekhar Nori 	 * transfer request.
3608ed58856SSekhar Nori 	 */
3618ed58856SSekhar Nori 	if (bitlen % 8) {
3628ed58856SSekhar Nori 		/* Errors always terminate an ongoing transfer */
3638ed58856SSekhar Nori 		flags |= SPI_XFER_END;
3648ed58856SSekhar Nori 		goto out;
3658ed58856SSekhar Nori 	}
3668ed58856SSekhar Nori 
3678ed58856SSekhar Nori 	len = bitlen / 8;
3688ed58856SSekhar Nori 
36977436d66SNick Thompson 	if (!dout)
37077436d66SNick Thompson 		return davinci_spi_read(slave, len, din, flags);
37177436d66SNick Thompson 	else if (!din)
37277436d66SNick Thompson 		return davinci_spi_write(slave, len, dout, flags);
37377436d66SNick Thompson #ifndef CONFIG_SPI_HALF_DUPLEX
37477436d66SNick Thompson 	else
37577436d66SNick Thompson 		return davinci_spi_read_write(slave, len, din, dout, flags);
376dce6538fSNick Thompson #else
377dce6538fSNick Thompson 	printf("SPI full duplex transaction requested with "
378dce6538fSNick Thompson 	       "CONFIG_SPI_HALF_DUPLEX defined.\n");
379dce6538fSNick Thompson 	flags |= SPI_XFER_END;
38077436d66SNick Thompson #endif
3818ed58856SSekhar Nori 
3828ed58856SSekhar Nori out:
3838ed58856SSekhar Nori 	if (flags & SPI_XFER_END) {
38477436d66SNick Thompson 		u8 dummy = 0;
38577436d66SNick Thompson 		davinci_spi_write(slave, 1, &dummy, flags);
3868ed58856SSekhar Nori 	}
3878ed58856SSekhar Nori 	return 0;
3888ed58856SSekhar Nori }
3898ed58856SSekhar Nori 
3908ed58856SSekhar Nori int spi_cs_is_valid(unsigned int bus, unsigned int cs)
3918ed58856SSekhar Nori {
3922bcdf84dSKaricheri, Muralidharan 	int ret = 0;
3932bcdf84dSKaricheri, Muralidharan 
3942bcdf84dSKaricheri, Muralidharan 	switch (bus) {
3952bcdf84dSKaricheri, Muralidharan 	case SPI0_BUS:
3962bcdf84dSKaricheri, Muralidharan 		if (cs < SPI0_NUM_CS)
3972bcdf84dSKaricheri, Muralidharan 			ret = 1;
3982bcdf84dSKaricheri, Muralidharan 		break;
3992bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI1
4002bcdf84dSKaricheri, Muralidharan 	case SPI1_BUS:
4012bcdf84dSKaricheri, Muralidharan 		if (cs < SPI1_NUM_CS)
4022bcdf84dSKaricheri, Muralidharan 			ret = 1;
4032bcdf84dSKaricheri, Muralidharan 		break;
4042bcdf84dSKaricheri, Muralidharan #endif
4052bcdf84dSKaricheri, Muralidharan #ifdef CONFIG_SYS_SPI2
4062bcdf84dSKaricheri, Muralidharan 	case SPI2_BUS:
4072bcdf84dSKaricheri, Muralidharan 		if (cs < SPI2_NUM_CS)
4082bcdf84dSKaricheri, Muralidharan 			ret = 1;
4092bcdf84dSKaricheri, Muralidharan 		break;
4102bcdf84dSKaricheri, Muralidharan #endif
4112bcdf84dSKaricheri, Muralidharan 	default:
4122bcdf84dSKaricheri, Muralidharan 		/* Invalid bus number. Do nothing */
4132bcdf84dSKaricheri, Muralidharan 		break;
4142bcdf84dSKaricheri, Muralidharan 	}
4152bcdf84dSKaricheri, Muralidharan 	return ret;
4168ed58856SSekhar Nori }
4178ed58856SSekhar Nori 
4188ed58856SSekhar Nori void spi_cs_activate(struct spi_slave *slave)
4198ed58856SSekhar Nori {
4208ed58856SSekhar Nori 	/* do nothing */
4218ed58856SSekhar Nori }
4228ed58856SSekhar Nori 
4238ed58856SSekhar Nori void spi_cs_deactivate(struct spi_slave *slave)
4248ed58856SSekhar Nori {
4258ed58856SSekhar Nori 	/* do nothing */
4268ed58856SSekhar Nori }
427