xref: /rk3399_rockchip-uboot/drivers/spi/fsl_dspi.c (revision 1490eb89f4697b02cfb8f826d2f5eaf37edcbd47)
1a8919371SHaikun.Wang@freescale.com /*
2a8919371SHaikun.Wang@freescale.com  * (C) Copyright 2000-2003
3a8919371SHaikun.Wang@freescale.com  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4a8919371SHaikun.Wang@freescale.com  *
5a8919371SHaikun.Wang@freescale.com  * Copyright (C) 2004-2009, 2015 Freescale Semiconductor, Inc.
6a8919371SHaikun.Wang@freescale.com  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
7a8919371SHaikun.Wang@freescale.com  * Chao Fu (B44548@freescale.com)
8a8919371SHaikun.Wang@freescale.com  * Haikun Wang (B53464@freescale.com)
9a8919371SHaikun.Wang@freescale.com  *
10a8919371SHaikun.Wang@freescale.com  * SPDX-License-Identifier:	GPL-2.0+
11a8919371SHaikun.Wang@freescale.com  */
12*4af0d7e8SSimon Glass 
13*4af0d7e8SSimon Glass #include <common.h>
14a8919371SHaikun.Wang@freescale.com #include <dm.h>
15a8919371SHaikun.Wang@freescale.com #include <errno.h>
16a8919371SHaikun.Wang@freescale.com #include <common.h>
17a8919371SHaikun.Wang@freescale.com #include <spi.h>
18a8919371SHaikun.Wang@freescale.com #include <malloc.h>
19a8919371SHaikun.Wang@freescale.com #include <asm/io.h>
20a8919371SHaikun.Wang@freescale.com #include <fdtdec.h>
21a8919371SHaikun.Wang@freescale.com #ifndef CONFIG_M68K
22a8919371SHaikun.Wang@freescale.com #include <asm/arch/clock.h>
23a8919371SHaikun.Wang@freescale.com #endif
24a8919371SHaikun.Wang@freescale.com #include <fsl_dspi.h>
25a8919371SHaikun.Wang@freescale.com 
26a8919371SHaikun.Wang@freescale.com DECLARE_GLOBAL_DATA_PTR;
27a8919371SHaikun.Wang@freescale.com 
28a8919371SHaikun.Wang@freescale.com /* fsl_dspi_platdata flags */
2929e6abd9SJagan Teki #define DSPI_FLAG_REGMAP_ENDIAN_BIG	BIT(0)
30a8919371SHaikun.Wang@freescale.com 
31a8919371SHaikun.Wang@freescale.com /* idle data value */
32a8919371SHaikun.Wang@freescale.com #define DSPI_IDLE_VAL			0x0
33a8919371SHaikun.Wang@freescale.com 
34a8919371SHaikun.Wang@freescale.com /* max chipselect signals number */
35a8919371SHaikun.Wang@freescale.com #define FSL_DSPI_MAX_CHIPSELECT		6
36a8919371SHaikun.Wang@freescale.com 
37a8919371SHaikun.Wang@freescale.com /* default SCK frequency, unit: HZ */
38a8919371SHaikun.Wang@freescale.com #define FSL_DSPI_DEFAULT_SCK_FREQ	10000000
39a8919371SHaikun.Wang@freescale.com 
40a8919371SHaikun.Wang@freescale.com /* tx/rx data wait timeout value, unit: us */
41a8919371SHaikun.Wang@freescale.com #define DSPI_TXRX_WAIT_TIMEOUT		1000000
42a8919371SHaikun.Wang@freescale.com 
43a8919371SHaikun.Wang@freescale.com /* CTAR register pre-configure value */
44a8919371SHaikun.Wang@freescale.com #define DSPI_CTAR_DEFAULT_VALUE		(DSPI_CTAR_TRSZ(7) | \
45a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PCSSCK_1CLK | \
46a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PASC(0) | \
47a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PDT(0) | \
48a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_CSSCK(0) | \
49a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_ASC(0) | \
50a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_DT(0))
51a8919371SHaikun.Wang@freescale.com 
52a8919371SHaikun.Wang@freescale.com /* CTAR register pre-configure mask */
53a8919371SHaikun.Wang@freescale.com #define DSPI_CTAR_SET_MODE_MASK		(DSPI_CTAR_TRSZ(15) | \
54a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PCSSCK(3) | \
55a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PASC(3) | \
56a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_PDT(3) | \
57a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_CSSCK(15) | \
58a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_ASC(15) | \
59a8919371SHaikun.Wang@freescale.com 					DSPI_CTAR_DT(15))
60a8919371SHaikun.Wang@freescale.com 
61a8919371SHaikun.Wang@freescale.com /**
62a8919371SHaikun.Wang@freescale.com  * struct fsl_dspi_platdata - platform data for Freescale DSPI
63a8919371SHaikun.Wang@freescale.com  *
64a8919371SHaikun.Wang@freescale.com  * @flags: Flags for DSPI DSPI_FLAG_...
65a8919371SHaikun.Wang@freescale.com  * @speed_hz: Default SCK frequency
66a8919371SHaikun.Wang@freescale.com  * @num_chipselect: Number of DSPI chipselect signals
67a8919371SHaikun.Wang@freescale.com  * @regs_addr: Base address of DSPI registers
68a8919371SHaikun.Wang@freescale.com  */
69a8919371SHaikun.Wang@freescale.com struct fsl_dspi_platdata {
70a8919371SHaikun.Wang@freescale.com 	uint flags;
71a8919371SHaikun.Wang@freescale.com 	uint speed_hz;
72a8919371SHaikun.Wang@freescale.com 	uint num_chipselect;
73a8919371SHaikun.Wang@freescale.com 	fdt_addr_t regs_addr;
74a8919371SHaikun.Wang@freescale.com };
75a8919371SHaikun.Wang@freescale.com 
76a8919371SHaikun.Wang@freescale.com /**
77a8919371SHaikun.Wang@freescale.com  * struct fsl_dspi_priv - private data for Freescale DSPI
78a8919371SHaikun.Wang@freescale.com  *
79a8919371SHaikun.Wang@freescale.com  * @flags: Flags for DSPI DSPI_FLAG_...
80a8919371SHaikun.Wang@freescale.com  * @mode: SPI mode to use for slave device (see SPI mode flags)
81a8919371SHaikun.Wang@freescale.com  * @mcr_val: MCR register configure value
82a8919371SHaikun.Wang@freescale.com  * @bus_clk: DSPI input clk frequency
83a8919371SHaikun.Wang@freescale.com  * @speed_hz: Default SCK frequency
84a8919371SHaikun.Wang@freescale.com  * @charbit: How many bits in every transfer
85a8919371SHaikun.Wang@freescale.com  * @num_chipselect: Number of DSPI chipselect signals
86a8919371SHaikun.Wang@freescale.com  * @ctar_val: CTAR register configure value of per chipselect slave device
87a8919371SHaikun.Wang@freescale.com  * @regs: Point to DSPI register structure for I/O access
88a8919371SHaikun.Wang@freescale.com  */
89a8919371SHaikun.Wang@freescale.com struct fsl_dspi_priv {
90a8919371SHaikun.Wang@freescale.com 	uint flags;
91a8919371SHaikun.Wang@freescale.com 	uint mode;
92a8919371SHaikun.Wang@freescale.com 	uint mcr_val;
93a8919371SHaikun.Wang@freescale.com 	uint bus_clk;
94a8919371SHaikun.Wang@freescale.com 	uint speed_hz;
95a8919371SHaikun.Wang@freescale.com 	uint charbit;
96a8919371SHaikun.Wang@freescale.com 	uint num_chipselect;
97a8919371SHaikun.Wang@freescale.com 	uint ctar_val[FSL_DSPI_MAX_CHIPSELECT];
98a8919371SHaikun.Wang@freescale.com 	struct dspi *regs;
99a8919371SHaikun.Wang@freescale.com };
100a8919371SHaikun.Wang@freescale.com 
101a8919371SHaikun.Wang@freescale.com #ifndef CONFIG_DM_SPI
102a8919371SHaikun.Wang@freescale.com struct fsl_dspi {
103a8919371SHaikun.Wang@freescale.com 	struct spi_slave slave;
104a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv priv;
105a8919371SHaikun.Wang@freescale.com };
106a8919371SHaikun.Wang@freescale.com #endif
107a8919371SHaikun.Wang@freescale.com 
cpu_dspi_port_conf(void)108a8919371SHaikun.Wang@freescale.com __weak void cpu_dspi_port_conf(void)
109a8919371SHaikun.Wang@freescale.com {
110a8919371SHaikun.Wang@freescale.com }
111a8919371SHaikun.Wang@freescale.com 
cpu_dspi_claim_bus(uint bus,uint cs)112a8919371SHaikun.Wang@freescale.com __weak int cpu_dspi_claim_bus(uint bus, uint cs)
113a8919371SHaikun.Wang@freescale.com {
114a8919371SHaikun.Wang@freescale.com 	return 0;
115a8919371SHaikun.Wang@freescale.com }
116a8919371SHaikun.Wang@freescale.com 
cpu_dspi_release_bus(uint bus,uint cs)117a8919371SHaikun.Wang@freescale.com __weak void cpu_dspi_release_bus(uint bus, uint cs)
118a8919371SHaikun.Wang@freescale.com {
119a8919371SHaikun.Wang@freescale.com }
120a8919371SHaikun.Wang@freescale.com 
dspi_read32(uint flags,uint * addr)121a8919371SHaikun.Wang@freescale.com static uint dspi_read32(uint flags, uint *addr)
122a8919371SHaikun.Wang@freescale.com {
123a8919371SHaikun.Wang@freescale.com 	return flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
124a8919371SHaikun.Wang@freescale.com 		in_be32(addr) : in_le32(addr);
125a8919371SHaikun.Wang@freescale.com }
126a8919371SHaikun.Wang@freescale.com 
dspi_write32(uint flags,uint * addr,uint val)127a8919371SHaikun.Wang@freescale.com static void dspi_write32(uint flags, uint *addr, uint val)
128a8919371SHaikun.Wang@freescale.com {
129a8919371SHaikun.Wang@freescale.com 	flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ?
130a8919371SHaikun.Wang@freescale.com 		out_be32(addr, val) : out_le32(addr, val);
131a8919371SHaikun.Wang@freescale.com }
132a8919371SHaikun.Wang@freescale.com 
dspi_halt(struct fsl_dspi_priv * priv,u8 halt)133a8919371SHaikun.Wang@freescale.com static void dspi_halt(struct fsl_dspi_priv *priv, u8 halt)
134a8919371SHaikun.Wang@freescale.com {
135a8919371SHaikun.Wang@freescale.com 	uint mcr_val;
136a8919371SHaikun.Wang@freescale.com 
137a8919371SHaikun.Wang@freescale.com 	mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
138a8919371SHaikun.Wang@freescale.com 
139a8919371SHaikun.Wang@freescale.com 	if (halt)
140a8919371SHaikun.Wang@freescale.com 		mcr_val |= DSPI_MCR_HALT;
141a8919371SHaikun.Wang@freescale.com 	else
142a8919371SHaikun.Wang@freescale.com 		mcr_val &= ~DSPI_MCR_HALT;
143a8919371SHaikun.Wang@freescale.com 
144a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
145a8919371SHaikun.Wang@freescale.com }
146a8919371SHaikun.Wang@freescale.com 
fsl_dspi_init_mcr(struct fsl_dspi_priv * priv,uint cfg_val)147a8919371SHaikun.Wang@freescale.com static void fsl_dspi_init_mcr(struct fsl_dspi_priv *priv, uint cfg_val)
148a8919371SHaikun.Wang@freescale.com {
149a8919371SHaikun.Wang@freescale.com 	/* halt DSPI module */
150a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 1);
151a8919371SHaikun.Wang@freescale.com 
152a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->mcr, cfg_val);
153a8919371SHaikun.Wang@freescale.com 
154a8919371SHaikun.Wang@freescale.com 	/* resume module */
155a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 0);
156a8919371SHaikun.Wang@freescale.com 
157a8919371SHaikun.Wang@freescale.com 	priv->mcr_val = cfg_val;
158a8919371SHaikun.Wang@freescale.com }
159a8919371SHaikun.Wang@freescale.com 
fsl_dspi_cfg_cs_active_state(struct fsl_dspi_priv * priv,uint cs,uint state)160a8919371SHaikun.Wang@freescale.com static void fsl_dspi_cfg_cs_active_state(struct fsl_dspi_priv *priv,
161a8919371SHaikun.Wang@freescale.com 		uint cs, uint state)
162a8919371SHaikun.Wang@freescale.com {
163a8919371SHaikun.Wang@freescale.com 	uint mcr_val;
164a8919371SHaikun.Wang@freescale.com 
165a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 1);
166a8919371SHaikun.Wang@freescale.com 
167a8919371SHaikun.Wang@freescale.com 	mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
168a8919371SHaikun.Wang@freescale.com 	if (state & SPI_CS_HIGH)
169a8919371SHaikun.Wang@freescale.com 		/* CSx inactive state is low */
170a8919371SHaikun.Wang@freescale.com 		mcr_val &= ~DSPI_MCR_PCSIS(cs);
171a8919371SHaikun.Wang@freescale.com 	else
172a8919371SHaikun.Wang@freescale.com 		/* CSx inactive state is high */
173a8919371SHaikun.Wang@freescale.com 		mcr_val |= DSPI_MCR_PCSIS(cs);
174a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
175a8919371SHaikun.Wang@freescale.com 
176a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 0);
177a8919371SHaikun.Wang@freescale.com }
178a8919371SHaikun.Wang@freescale.com 
fsl_dspi_cfg_ctar_mode(struct fsl_dspi_priv * priv,uint cs,uint mode)179a8919371SHaikun.Wang@freescale.com static int fsl_dspi_cfg_ctar_mode(struct fsl_dspi_priv *priv,
180a8919371SHaikun.Wang@freescale.com 		uint cs, uint mode)
181a8919371SHaikun.Wang@freescale.com {
182a8919371SHaikun.Wang@freescale.com 	uint bus_setup;
183a8919371SHaikun.Wang@freescale.com 
184a8919371SHaikun.Wang@freescale.com 	bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
185a8919371SHaikun.Wang@freescale.com 
186a8919371SHaikun.Wang@freescale.com 	bus_setup &= ~DSPI_CTAR_SET_MODE_MASK;
187a8919371SHaikun.Wang@freescale.com 	bus_setup |= priv->ctar_val[cs];
188a8919371SHaikun.Wang@freescale.com 	bus_setup &= ~(DSPI_CTAR_CPOL | DSPI_CTAR_CPHA | DSPI_CTAR_LSBFE);
189a8919371SHaikun.Wang@freescale.com 
190a8919371SHaikun.Wang@freescale.com 	if (mode & SPI_CPOL)
191a8919371SHaikun.Wang@freescale.com 		bus_setup |= DSPI_CTAR_CPOL;
192a8919371SHaikun.Wang@freescale.com 	if (mode & SPI_CPHA)
193a8919371SHaikun.Wang@freescale.com 		bus_setup |= DSPI_CTAR_CPHA;
194a8919371SHaikun.Wang@freescale.com 	if (mode & SPI_LSB_FIRST)
195a8919371SHaikun.Wang@freescale.com 		bus_setup |= DSPI_CTAR_LSBFE;
196a8919371SHaikun.Wang@freescale.com 
197a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
198a8919371SHaikun.Wang@freescale.com 
199a8919371SHaikun.Wang@freescale.com 	priv->charbit =
200a8919371SHaikun.Wang@freescale.com 		((dspi_read32(priv->flags, &priv->regs->ctar[0]) &
201a8919371SHaikun.Wang@freescale.com 		  DSPI_CTAR_TRSZ(15)) == DSPI_CTAR_TRSZ(15)) ? 16 : 8;
202a8919371SHaikun.Wang@freescale.com 
203a8919371SHaikun.Wang@freescale.com 	return 0;
204a8919371SHaikun.Wang@freescale.com }
205a8919371SHaikun.Wang@freescale.com 
fsl_dspi_clr_fifo(struct fsl_dspi_priv * priv)206a8919371SHaikun.Wang@freescale.com static void fsl_dspi_clr_fifo(struct fsl_dspi_priv *priv)
207a8919371SHaikun.Wang@freescale.com {
208a8919371SHaikun.Wang@freescale.com 	uint mcr_val;
209a8919371SHaikun.Wang@freescale.com 
210a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 1);
211a8919371SHaikun.Wang@freescale.com 	mcr_val = dspi_read32(priv->flags, &priv->regs->mcr);
212a8919371SHaikun.Wang@freescale.com 	/* flush RX and TX FIFO */
213a8919371SHaikun.Wang@freescale.com 	mcr_val |= (DSPI_MCR_CTXF | DSPI_MCR_CRXF);
214a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
215a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 0);
216a8919371SHaikun.Wang@freescale.com }
217a8919371SHaikun.Wang@freescale.com 
dspi_tx(struct fsl_dspi_priv * priv,u32 ctrl,u16 data)218a8919371SHaikun.Wang@freescale.com static void dspi_tx(struct fsl_dspi_priv *priv, u32 ctrl, u16 data)
219a8919371SHaikun.Wang@freescale.com {
220a8919371SHaikun.Wang@freescale.com 	int timeout = DSPI_TXRX_WAIT_TIMEOUT;
221a8919371SHaikun.Wang@freescale.com 
222a8919371SHaikun.Wang@freescale.com 	/* wait for empty entries in TXFIFO or timeout */
223a8919371SHaikun.Wang@freescale.com 	while (DSPI_SR_TXCTR(dspi_read32(priv->flags, &priv->regs->sr)) >= 4 &&
224a8919371SHaikun.Wang@freescale.com 			timeout--)
225a8919371SHaikun.Wang@freescale.com 		udelay(1);
226a8919371SHaikun.Wang@freescale.com 
227a8919371SHaikun.Wang@freescale.com 	if (timeout >= 0)
228a8919371SHaikun.Wang@freescale.com 		dspi_write32(priv->flags, &priv->regs->tfr, (ctrl | data));
229a8919371SHaikun.Wang@freescale.com 	else
230a8919371SHaikun.Wang@freescale.com 		debug("dspi_tx: waiting timeout!\n");
231a8919371SHaikun.Wang@freescale.com }
232a8919371SHaikun.Wang@freescale.com 
dspi_rx(struct fsl_dspi_priv * priv)233a8919371SHaikun.Wang@freescale.com static u16 dspi_rx(struct fsl_dspi_priv *priv)
234a8919371SHaikun.Wang@freescale.com {
235a8919371SHaikun.Wang@freescale.com 	int timeout = DSPI_TXRX_WAIT_TIMEOUT;
236a8919371SHaikun.Wang@freescale.com 
237a8919371SHaikun.Wang@freescale.com 	/* wait for valid entries in RXFIFO or timeout */
238a8919371SHaikun.Wang@freescale.com 	while (DSPI_SR_RXCTR(dspi_read32(priv->flags, &priv->regs->sr)) == 0 &&
239a8919371SHaikun.Wang@freescale.com 			timeout--)
240a8919371SHaikun.Wang@freescale.com 		udelay(1);
241a8919371SHaikun.Wang@freescale.com 
242a8919371SHaikun.Wang@freescale.com 	if (timeout >= 0)
243a8919371SHaikun.Wang@freescale.com 		return (u16)DSPI_RFR_RXDATA(
244a8919371SHaikun.Wang@freescale.com 				dspi_read32(priv->flags, &priv->regs->rfr));
245a8919371SHaikun.Wang@freescale.com 	else {
246a8919371SHaikun.Wang@freescale.com 		debug("dspi_rx: waiting timeout!\n");
247a8919371SHaikun.Wang@freescale.com 		return (u16)(~0);
248a8919371SHaikun.Wang@freescale.com 	}
249a8919371SHaikun.Wang@freescale.com }
250a8919371SHaikun.Wang@freescale.com 
dspi_xfer(struct fsl_dspi_priv * priv,uint cs,unsigned int bitlen,const void * dout,void * din,unsigned long flags)251a8919371SHaikun.Wang@freescale.com static int dspi_xfer(struct fsl_dspi_priv *priv, uint cs, unsigned int bitlen,
252a8919371SHaikun.Wang@freescale.com 		const void *dout, void *din, unsigned long flags)
253a8919371SHaikun.Wang@freescale.com {
254a8919371SHaikun.Wang@freescale.com 	u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
255a8919371SHaikun.Wang@freescale.com 	u8 *spi_rd = NULL, *spi_wr = NULL;
256a8919371SHaikun.Wang@freescale.com 	static u32 ctrl;
257a8919371SHaikun.Wang@freescale.com 	uint len = bitlen >> 3;
258a8919371SHaikun.Wang@freescale.com 
259a8919371SHaikun.Wang@freescale.com 	if (priv->charbit == 16) {
260a8919371SHaikun.Wang@freescale.com 		bitlen >>= 1;
261a8919371SHaikun.Wang@freescale.com 		spi_wr16 = (u16 *)dout;
262a8919371SHaikun.Wang@freescale.com 		spi_rd16 = (u16 *)din;
263a8919371SHaikun.Wang@freescale.com 	} else {
264a8919371SHaikun.Wang@freescale.com 		spi_wr = (u8 *)dout;
265a8919371SHaikun.Wang@freescale.com 		spi_rd = (u8 *)din;
266a8919371SHaikun.Wang@freescale.com 	}
267a8919371SHaikun.Wang@freescale.com 
268a8919371SHaikun.Wang@freescale.com 	if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
269a8919371SHaikun.Wang@freescale.com 		ctrl |= DSPI_TFR_CONT;
270a8919371SHaikun.Wang@freescale.com 
271a8919371SHaikun.Wang@freescale.com 	ctrl = ctrl & DSPI_TFR_CONT;
272a8919371SHaikun.Wang@freescale.com 	ctrl = ctrl | DSPI_TFR_CTAS(0) | DSPI_TFR_PCS(cs);
273a8919371SHaikun.Wang@freescale.com 
274a8919371SHaikun.Wang@freescale.com 	if (len > 1) {
275a8919371SHaikun.Wang@freescale.com 		int tmp_len = len - 1;
276a8919371SHaikun.Wang@freescale.com 		while (tmp_len--) {
277a8919371SHaikun.Wang@freescale.com 			if (dout != NULL) {
278a8919371SHaikun.Wang@freescale.com 				if (priv->charbit == 16)
279a8919371SHaikun.Wang@freescale.com 					dspi_tx(priv, ctrl, *spi_wr16++);
280a8919371SHaikun.Wang@freescale.com 				else
281a8919371SHaikun.Wang@freescale.com 					dspi_tx(priv, ctrl, *spi_wr++);
282a8919371SHaikun.Wang@freescale.com 				dspi_rx(priv);
283a8919371SHaikun.Wang@freescale.com 			}
284a8919371SHaikun.Wang@freescale.com 
285a8919371SHaikun.Wang@freescale.com 			if (din != NULL) {
286a8919371SHaikun.Wang@freescale.com 				dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
287a8919371SHaikun.Wang@freescale.com 				if (priv->charbit == 16)
288a8919371SHaikun.Wang@freescale.com 					*spi_rd16++ = dspi_rx(priv);
289a8919371SHaikun.Wang@freescale.com 				else
290a8919371SHaikun.Wang@freescale.com 					*spi_rd++ = dspi_rx(priv);
291a8919371SHaikun.Wang@freescale.com 			}
292a8919371SHaikun.Wang@freescale.com 		}
293a8919371SHaikun.Wang@freescale.com 
294a8919371SHaikun.Wang@freescale.com 		len = 1;	/* remaining byte */
295a8919371SHaikun.Wang@freescale.com 	}
296a8919371SHaikun.Wang@freescale.com 
297a8919371SHaikun.Wang@freescale.com 	if ((flags & SPI_XFER_END) == SPI_XFER_END)
298a8919371SHaikun.Wang@freescale.com 		ctrl &= ~DSPI_TFR_CONT;
299a8919371SHaikun.Wang@freescale.com 
300a8919371SHaikun.Wang@freescale.com 	if (len) {
301a8919371SHaikun.Wang@freescale.com 		if (dout != NULL) {
302a8919371SHaikun.Wang@freescale.com 			if (priv->charbit == 16)
303a8919371SHaikun.Wang@freescale.com 				dspi_tx(priv, ctrl, *spi_wr16);
304a8919371SHaikun.Wang@freescale.com 			else
305a8919371SHaikun.Wang@freescale.com 				dspi_tx(priv, ctrl, *spi_wr);
306a8919371SHaikun.Wang@freescale.com 			dspi_rx(priv);
307a8919371SHaikun.Wang@freescale.com 		}
308a8919371SHaikun.Wang@freescale.com 
309a8919371SHaikun.Wang@freescale.com 		if (din != NULL) {
310a8919371SHaikun.Wang@freescale.com 			dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
311a8919371SHaikun.Wang@freescale.com 			if (priv->charbit == 16)
312a8919371SHaikun.Wang@freescale.com 				*spi_rd16 = dspi_rx(priv);
313a8919371SHaikun.Wang@freescale.com 			else
314a8919371SHaikun.Wang@freescale.com 				*spi_rd = dspi_rx(priv);
315a8919371SHaikun.Wang@freescale.com 		}
316a8919371SHaikun.Wang@freescale.com 	} else {
317a8919371SHaikun.Wang@freescale.com 		/* dummy read */
318a8919371SHaikun.Wang@freescale.com 		dspi_tx(priv, ctrl, DSPI_IDLE_VAL);
319a8919371SHaikun.Wang@freescale.com 		dspi_rx(priv);
320a8919371SHaikun.Wang@freescale.com 	}
321a8919371SHaikun.Wang@freescale.com 
322a8919371SHaikun.Wang@freescale.com 	return 0;
323a8919371SHaikun.Wang@freescale.com }
324a8919371SHaikun.Wang@freescale.com 
325a8919371SHaikun.Wang@freescale.com /**
326a8919371SHaikun.Wang@freescale.com  * Calculate the divide value between input clk frequency and expected SCK frequency
327a8919371SHaikun.Wang@freescale.com  * Formula: SCK = (clkrate/pbr) x ((1+dbr)/br)
328a8919371SHaikun.Wang@freescale.com  * Dbr: use default value 0
329a8919371SHaikun.Wang@freescale.com  *
330a8919371SHaikun.Wang@freescale.com  * @pbr: return Baud Rate Prescaler value
331a8919371SHaikun.Wang@freescale.com  * @br: return Baud Rate Scaler value
332a8919371SHaikun.Wang@freescale.com  * @speed_hz: expected SCK frequency
333a8919371SHaikun.Wang@freescale.com  * @clkrate: input clk frequency
334a8919371SHaikun.Wang@freescale.com  */
fsl_dspi_hz_to_spi_baud(int * pbr,int * br,int speed_hz,uint clkrate)335a8919371SHaikun.Wang@freescale.com static int fsl_dspi_hz_to_spi_baud(int *pbr, int *br,
336a8919371SHaikun.Wang@freescale.com 		int speed_hz, uint clkrate)
337a8919371SHaikun.Wang@freescale.com {
338a8919371SHaikun.Wang@freescale.com 	/* Valid baud rate pre-scaler values */
339a8919371SHaikun.Wang@freescale.com 	int pbr_tbl[4] = {2, 3, 5, 7};
340a8919371SHaikun.Wang@freescale.com 	int brs[16] = {2, 4, 6, 8,
341a8919371SHaikun.Wang@freescale.com 		16, 32, 64, 128,
342a8919371SHaikun.Wang@freescale.com 		256, 512, 1024, 2048,
343a8919371SHaikun.Wang@freescale.com 		4096, 8192, 16384, 32768};
344a8919371SHaikun.Wang@freescale.com 	int temp, i = 0, j = 0;
345a8919371SHaikun.Wang@freescale.com 
346a8919371SHaikun.Wang@freescale.com 	temp = clkrate / speed_hz;
347a8919371SHaikun.Wang@freescale.com 
348a8919371SHaikun.Wang@freescale.com 	for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
349a8919371SHaikun.Wang@freescale.com 		for (j = 0; j < ARRAY_SIZE(brs); j++) {
350a8919371SHaikun.Wang@freescale.com 			if (pbr_tbl[i] * brs[j] >= temp) {
351a8919371SHaikun.Wang@freescale.com 				*pbr = i;
352a8919371SHaikun.Wang@freescale.com 				*br = j;
353a8919371SHaikun.Wang@freescale.com 				return 0;
354a8919371SHaikun.Wang@freescale.com 			}
355a8919371SHaikun.Wang@freescale.com 		}
356a8919371SHaikun.Wang@freescale.com 
357a8919371SHaikun.Wang@freescale.com 	debug("Can not find valid baud rate,speed_hz is %d, ", speed_hz);
358a8919371SHaikun.Wang@freescale.com 	debug("clkrate is %d, we use the max prescaler value.\n", clkrate);
359a8919371SHaikun.Wang@freescale.com 
360a8919371SHaikun.Wang@freescale.com 	*pbr = ARRAY_SIZE(pbr_tbl) - 1;
361a8919371SHaikun.Wang@freescale.com 	*br =  ARRAY_SIZE(brs) - 1;
362a8919371SHaikun.Wang@freescale.com 	return -EINVAL;
363a8919371SHaikun.Wang@freescale.com }
364a8919371SHaikun.Wang@freescale.com 
fsl_dspi_cfg_speed(struct fsl_dspi_priv * priv,uint speed)365a8919371SHaikun.Wang@freescale.com static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed)
366a8919371SHaikun.Wang@freescale.com {
367a8919371SHaikun.Wang@freescale.com 	int ret;
368a8919371SHaikun.Wang@freescale.com 	uint bus_setup;
369a8919371SHaikun.Wang@freescale.com 	int best_i, best_j, bus_clk;
370a8919371SHaikun.Wang@freescale.com 
371a8919371SHaikun.Wang@freescale.com 	bus_clk = priv->bus_clk;
372a8919371SHaikun.Wang@freescale.com 
373a8919371SHaikun.Wang@freescale.com 	debug("DSPI set_speed: expected SCK speed %u, bus_clk %u.\n",
374a8919371SHaikun.Wang@freescale.com 	      speed, bus_clk);
375a8919371SHaikun.Wang@freescale.com 
376a8919371SHaikun.Wang@freescale.com 	bus_setup = dspi_read32(priv->flags, &priv->regs->ctar[0]);
377a8919371SHaikun.Wang@freescale.com 	bus_setup &= ~(DSPI_CTAR_DBR | DSPI_CTAR_PBR(0x3) | DSPI_CTAR_BR(0xf));
378a8919371SHaikun.Wang@freescale.com 
379a8919371SHaikun.Wang@freescale.com 	ret = fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
380a8919371SHaikun.Wang@freescale.com 	if (ret) {
381a8919371SHaikun.Wang@freescale.com 		speed = priv->speed_hz;
382a8919371SHaikun.Wang@freescale.com 		debug("DSPI set_speed use default SCK rate %u.\n", speed);
383a8919371SHaikun.Wang@freescale.com 		fsl_dspi_hz_to_spi_baud(&best_i, &best_j, speed, bus_clk);
384a8919371SHaikun.Wang@freescale.com 	}
385a8919371SHaikun.Wang@freescale.com 
386a8919371SHaikun.Wang@freescale.com 	bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
387a8919371SHaikun.Wang@freescale.com 	dspi_write32(priv->flags, &priv->regs->ctar[0], bus_setup);
388a8919371SHaikun.Wang@freescale.com 
389a8919371SHaikun.Wang@freescale.com 	priv->speed_hz = speed;
390a8919371SHaikun.Wang@freescale.com 
391a8919371SHaikun.Wang@freescale.com 	return 0;
392a8919371SHaikun.Wang@freescale.com }
393a8919371SHaikun.Wang@freescale.com #ifndef CONFIG_DM_SPI
spi_init(void)394a8919371SHaikun.Wang@freescale.com void spi_init(void)
395a8919371SHaikun.Wang@freescale.com {
396a8919371SHaikun.Wang@freescale.com 	/* Nothing to do */
397a8919371SHaikun.Wang@freescale.com }
398a8919371SHaikun.Wang@freescale.com 
spi_cs_is_valid(unsigned int bus,unsigned int cs)399a8919371SHaikun.Wang@freescale.com int spi_cs_is_valid(unsigned int bus, unsigned int cs)
400a8919371SHaikun.Wang@freescale.com {
401a8919371SHaikun.Wang@freescale.com 	if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
402a8919371SHaikun.Wang@freescale.com 		return 1;
403a8919371SHaikun.Wang@freescale.com 	else
404a8919371SHaikun.Wang@freescale.com 		return 0;
405a8919371SHaikun.Wang@freescale.com }
406a8919371SHaikun.Wang@freescale.com 
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)407a8919371SHaikun.Wang@freescale.com struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
408a8919371SHaikun.Wang@freescale.com 				  unsigned int max_hz, unsigned int mode)
409a8919371SHaikun.Wang@freescale.com {
410a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi *dspi;
411a8919371SHaikun.Wang@freescale.com 	uint mcr_cfg_val;
412a8919371SHaikun.Wang@freescale.com 
413a8919371SHaikun.Wang@freescale.com 	dspi = spi_alloc_slave(struct fsl_dspi, bus, cs);
414a8919371SHaikun.Wang@freescale.com 	if (!dspi)
415a8919371SHaikun.Wang@freescale.com 		return NULL;
416a8919371SHaikun.Wang@freescale.com 
417a8919371SHaikun.Wang@freescale.com 	cpu_dspi_port_conf();
418a8919371SHaikun.Wang@freescale.com 
419a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_FSL_DSPI_BE
420a8919371SHaikun.Wang@freescale.com 	dspi->priv.flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
421a8919371SHaikun.Wang@freescale.com #endif
422a8919371SHaikun.Wang@freescale.com 
423a8919371SHaikun.Wang@freescale.com 	dspi->priv.regs = (struct dspi *)MMAP_DSPI;
424a8919371SHaikun.Wang@freescale.com 
425a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_M68K
426a8919371SHaikun.Wang@freescale.com 	dspi->priv.bus_clk = gd->bus_clk;
427a8919371SHaikun.Wang@freescale.com #else
428a8919371SHaikun.Wang@freescale.com 	dspi->priv.bus_clk = mxc_get_clock(MXC_DSPI_CLK);
429a8919371SHaikun.Wang@freescale.com #endif
430a8919371SHaikun.Wang@freescale.com 	dspi->priv.speed_hz = FSL_DSPI_DEFAULT_SCK_FREQ;
431a8919371SHaikun.Wang@freescale.com 
432a8919371SHaikun.Wang@freescale.com 	/* default: all CS signals inactive state is high */
433a8919371SHaikun.Wang@freescale.com 	mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
434a8919371SHaikun.Wang@freescale.com 		DSPI_MCR_CRXF | DSPI_MCR_CTXF;
435a8919371SHaikun.Wang@freescale.com 	fsl_dspi_init_mcr(&dspi->priv, mcr_cfg_val);
436a8919371SHaikun.Wang@freescale.com 
437a8919371SHaikun.Wang@freescale.com 	for (i = 0; i < FSL_DSPI_MAX_CHIPSELECT; i++)
438a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[i] = DSPI_CTAR_DEFAULT_VALUE;
439a8919371SHaikun.Wang@freescale.com 
440a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR0
441a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 0)
442a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[0] = CONFIG_SYS_DSPI_CTAR0;
443a8919371SHaikun.Wang@freescale.com #endif
444a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR1
445a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 1)
446a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[1] = CONFIG_SYS_DSPI_CTAR1;
447a8919371SHaikun.Wang@freescale.com #endif
448a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR2
449a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 2)
450a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[2] = CONFIG_SYS_DSPI_CTAR2;
451a8919371SHaikun.Wang@freescale.com #endif
452a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR3
453a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 3)
454a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[3] = CONFIG_SYS_DSPI_CTAR3;
455a8919371SHaikun.Wang@freescale.com #endif
456a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR4
457a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 4)
458a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[4] = CONFIG_SYS_DSPI_CTAR4;
459a8919371SHaikun.Wang@freescale.com #endif
460a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR5
461a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 5)
462a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[5] = CONFIG_SYS_DSPI_CTAR5;
463a8919371SHaikun.Wang@freescale.com #endif
464a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR6
465a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 6)
466a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[6] = CONFIG_SYS_DSPI_CTAR6;
467a8919371SHaikun.Wang@freescale.com #endif
468a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_DSPI_CTAR7
469a8919371SHaikun.Wang@freescale.com 	if (FSL_DSPI_MAX_CHIPSELECT > 7)
470a8919371SHaikun.Wang@freescale.com 		dspi->priv.ctar_val[7] = CONFIG_SYS_DSPI_CTAR7;
471a8919371SHaikun.Wang@freescale.com #endif
472a8919371SHaikun.Wang@freescale.com 
473a8919371SHaikun.Wang@freescale.com 	fsl_dspi_cfg_speed(&dspi->priv, max_hz);
474a8919371SHaikun.Wang@freescale.com 
475a8919371SHaikun.Wang@freescale.com 	/* configure transfer mode */
476a8919371SHaikun.Wang@freescale.com 	fsl_dspi_cfg_ctar_mode(&dspi->priv, cs, mode);
477a8919371SHaikun.Wang@freescale.com 
478a8919371SHaikun.Wang@freescale.com 	/* configure active state of CSX */
479a8919371SHaikun.Wang@freescale.com 	fsl_dspi_cfg_cs_active_state(&dspi->priv, cs, mode);
480a8919371SHaikun.Wang@freescale.com 
481a8919371SHaikun.Wang@freescale.com 	return &dspi->slave;
482a8919371SHaikun.Wang@freescale.com }
483a8919371SHaikun.Wang@freescale.com 
spi_free_slave(struct spi_slave * slave)484a8919371SHaikun.Wang@freescale.com void spi_free_slave(struct spi_slave *slave)
485a8919371SHaikun.Wang@freescale.com {
486a8919371SHaikun.Wang@freescale.com 	free(slave);
487a8919371SHaikun.Wang@freescale.com }
488a8919371SHaikun.Wang@freescale.com 
spi_claim_bus(struct spi_slave * slave)489a8919371SHaikun.Wang@freescale.com int spi_claim_bus(struct spi_slave *slave)
490a8919371SHaikun.Wang@freescale.com {
491a8919371SHaikun.Wang@freescale.com 	uint sr_val;
492a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
493a8919371SHaikun.Wang@freescale.com 
494a8919371SHaikun.Wang@freescale.com 	cpu_dspi_claim_bus(slave->bus, slave->cs);
495a8919371SHaikun.Wang@freescale.com 
496a8919371SHaikun.Wang@freescale.com 	fsl_dspi_clr_fifo(&dspi->priv);
497a8919371SHaikun.Wang@freescale.com 
498a8919371SHaikun.Wang@freescale.com 	/* check module TX and RX status */
499a8919371SHaikun.Wang@freescale.com 	sr_val = dspi_read32(dspi->priv.flags, &dspi->priv.regs->sr);
500a8919371SHaikun.Wang@freescale.com 	if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
501a8919371SHaikun.Wang@freescale.com 		debug("DSPI RX/TX not ready!\n");
502a8919371SHaikun.Wang@freescale.com 		return -EIO;
503a8919371SHaikun.Wang@freescale.com 	}
504a8919371SHaikun.Wang@freescale.com 
505a8919371SHaikun.Wang@freescale.com 	return 0;
506a8919371SHaikun.Wang@freescale.com }
507a8919371SHaikun.Wang@freescale.com 
spi_release_bus(struct spi_slave * slave)508a8919371SHaikun.Wang@freescale.com void spi_release_bus(struct spi_slave *slave)
509a8919371SHaikun.Wang@freescale.com {
510a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
511a8919371SHaikun.Wang@freescale.com 
512a8919371SHaikun.Wang@freescale.com 	dspi_halt(&dspi->priv, 1);
513a8919371SHaikun.Wang@freescale.com 	cpu_dspi_release_bus(slave->bus.slave->cs);
514a8919371SHaikun.Wang@freescale.com }
515a8919371SHaikun.Wang@freescale.com 
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)516a8919371SHaikun.Wang@freescale.com int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
517a8919371SHaikun.Wang@freescale.com 	     void *din, unsigned long flags)
518a8919371SHaikun.Wang@freescale.com {
519a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi *dspi = (struct fsl_dspi *)slave;
520a8919371SHaikun.Wang@freescale.com 	return dspi_xfer(&dspi->priv, slave->cs, bitlen, dout, din, flags);
521a8919371SHaikun.Wang@freescale.com }
522a8919371SHaikun.Wang@freescale.com #else
fsl_dspi_child_pre_probe(struct udevice * dev)523a8919371SHaikun.Wang@freescale.com static int fsl_dspi_child_pre_probe(struct udevice *dev)
524a8919371SHaikun.Wang@freescale.com {
525a8919371SHaikun.Wang@freescale.com 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
526a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv = dev_get_priv(dev->parent);
527a8919371SHaikun.Wang@freescale.com 
528a8919371SHaikun.Wang@freescale.com 	if (slave_plat->cs >= priv->num_chipselect) {
529a8919371SHaikun.Wang@freescale.com 		debug("DSPI invalid chipselect number %d(max %d)!\n",
530a8919371SHaikun.Wang@freescale.com 		      slave_plat->cs, priv->num_chipselect - 1);
531a8919371SHaikun.Wang@freescale.com 		return -EINVAL;
532a8919371SHaikun.Wang@freescale.com 	}
533a8919371SHaikun.Wang@freescale.com 
534a8919371SHaikun.Wang@freescale.com 	priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE;
535a8919371SHaikun.Wang@freescale.com 
536a8919371SHaikun.Wang@freescale.com 	debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n",
537a8919371SHaikun.Wang@freescale.com 	      slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
538a8919371SHaikun.Wang@freescale.com 
539a8919371SHaikun.Wang@freescale.com 	return 0;
540a8919371SHaikun.Wang@freescale.com }
541a8919371SHaikun.Wang@freescale.com 
fsl_dspi_probe(struct udevice * bus)542a8919371SHaikun.Wang@freescale.com static int fsl_dspi_probe(struct udevice *bus)
543a8919371SHaikun.Wang@freescale.com {
544a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_platdata *plat = dev_get_platdata(bus);
545a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv = dev_get_priv(bus);
546a8919371SHaikun.Wang@freescale.com 	struct dm_spi_bus *dm_spi_bus;
547a8919371SHaikun.Wang@freescale.com 	uint mcr_cfg_val;
548a8919371SHaikun.Wang@freescale.com 
549a8919371SHaikun.Wang@freescale.com 	dm_spi_bus = bus->uclass_priv;
550a8919371SHaikun.Wang@freescale.com 
551a8919371SHaikun.Wang@freescale.com 	/* cpu speical pin muxing configure */
552a8919371SHaikun.Wang@freescale.com 	cpu_dspi_port_conf();
553a8919371SHaikun.Wang@freescale.com 
554a8919371SHaikun.Wang@freescale.com 	/* get input clk frequency */
555a8919371SHaikun.Wang@freescale.com 	priv->regs = (struct dspi *)plat->regs_addr;
556a8919371SHaikun.Wang@freescale.com 	priv->flags = plat->flags;
557a8919371SHaikun.Wang@freescale.com #ifdef CONFIG_M68K
558a8919371SHaikun.Wang@freescale.com 	priv->bus_clk = gd->bus_clk;
559a8919371SHaikun.Wang@freescale.com #else
560a8919371SHaikun.Wang@freescale.com 	priv->bus_clk = mxc_get_clock(MXC_DSPI_CLK);
561a8919371SHaikun.Wang@freescale.com #endif
562a8919371SHaikun.Wang@freescale.com 	priv->num_chipselect = plat->num_chipselect;
563a8919371SHaikun.Wang@freescale.com 	priv->speed_hz = plat->speed_hz;
564a8919371SHaikun.Wang@freescale.com 	/* frame data length in bits, default 8bits */
565a8919371SHaikun.Wang@freescale.com 	priv->charbit = 8;
566a8919371SHaikun.Wang@freescale.com 
567a8919371SHaikun.Wang@freescale.com 	dm_spi_bus->max_hz = plat->speed_hz;
568a8919371SHaikun.Wang@freescale.com 
569a8919371SHaikun.Wang@freescale.com 	/* default: all CS signals inactive state is high */
570a8919371SHaikun.Wang@freescale.com 	mcr_cfg_val = DSPI_MCR_MSTR | DSPI_MCR_PCSIS_MASK |
571a8919371SHaikun.Wang@freescale.com 		DSPI_MCR_CRXF | DSPI_MCR_CTXF;
572a8919371SHaikun.Wang@freescale.com 	fsl_dspi_init_mcr(priv, mcr_cfg_val);
573a8919371SHaikun.Wang@freescale.com 
574a8919371SHaikun.Wang@freescale.com 	debug("%s probe done, bus-num %d.\n", bus->name, bus->seq);
575a8919371SHaikun.Wang@freescale.com 
576a8919371SHaikun.Wang@freescale.com 	return 0;
577a8919371SHaikun.Wang@freescale.com }
578a8919371SHaikun.Wang@freescale.com 
fsl_dspi_claim_bus(struct udevice * dev)579a8919371SHaikun.Wang@freescale.com static int fsl_dspi_claim_bus(struct udevice *dev)
580a8919371SHaikun.Wang@freescale.com {
581a8919371SHaikun.Wang@freescale.com 	uint sr_val;
582a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv;
583a8919371SHaikun.Wang@freescale.com 	struct udevice *bus = dev->parent;
584a8919371SHaikun.Wang@freescale.com 	struct dm_spi_slave_platdata *slave_plat =
585a8919371SHaikun.Wang@freescale.com 		dev_get_parent_platdata(dev);
586a8919371SHaikun.Wang@freescale.com 
587a8919371SHaikun.Wang@freescale.com 	priv = dev_get_priv(bus);
588a8919371SHaikun.Wang@freescale.com 
589fc0b5948SRobert P. J. Day 	/* processor special preparation work */
590a8919371SHaikun.Wang@freescale.com 	cpu_dspi_claim_bus(bus->seq, slave_plat->cs);
591a8919371SHaikun.Wang@freescale.com 
592a8919371SHaikun.Wang@freescale.com 	/* configure transfer mode */
593a8919371SHaikun.Wang@freescale.com 	fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs, priv->mode);
594a8919371SHaikun.Wang@freescale.com 
595a8919371SHaikun.Wang@freescale.com 	/* configure active state of CSX */
596a8919371SHaikun.Wang@freescale.com 	fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs,
597a8919371SHaikun.Wang@freescale.com 				     priv->mode);
598a8919371SHaikun.Wang@freescale.com 
599a8919371SHaikun.Wang@freescale.com 	fsl_dspi_clr_fifo(priv);
600a8919371SHaikun.Wang@freescale.com 
601a8919371SHaikun.Wang@freescale.com 	/* check module TX and RX status */
602a8919371SHaikun.Wang@freescale.com 	sr_val = dspi_read32(priv->flags, &priv->regs->sr);
603a8919371SHaikun.Wang@freescale.com 	if ((sr_val & DSPI_SR_TXRXS) != DSPI_SR_TXRXS) {
604a8919371SHaikun.Wang@freescale.com 		debug("DSPI RX/TX not ready!\n");
605a8919371SHaikun.Wang@freescale.com 		return -EIO;
606a8919371SHaikun.Wang@freescale.com 	}
607a8919371SHaikun.Wang@freescale.com 
608a8919371SHaikun.Wang@freescale.com 	return 0;
609a8919371SHaikun.Wang@freescale.com }
610a8919371SHaikun.Wang@freescale.com 
fsl_dspi_release_bus(struct udevice * dev)611a8919371SHaikun.Wang@freescale.com static int fsl_dspi_release_bus(struct udevice *dev)
612a8919371SHaikun.Wang@freescale.com {
613a8919371SHaikun.Wang@freescale.com 	struct udevice *bus = dev->parent;
614a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv = dev_get_priv(bus);
615a8919371SHaikun.Wang@freescale.com 	struct dm_spi_slave_platdata *slave_plat =
616a8919371SHaikun.Wang@freescale.com 		dev_get_parent_platdata(dev);
617a8919371SHaikun.Wang@freescale.com 
618a8919371SHaikun.Wang@freescale.com 	/* halt module */
619a8919371SHaikun.Wang@freescale.com 	dspi_halt(priv, 1);
620a8919371SHaikun.Wang@freescale.com 
621a8919371SHaikun.Wang@freescale.com 	/* processor special release work */
622a8919371SHaikun.Wang@freescale.com 	cpu_dspi_release_bus(bus->seq, slave_plat->cs);
623a8919371SHaikun.Wang@freescale.com 
624a8919371SHaikun.Wang@freescale.com 	return 0;
625a8919371SHaikun.Wang@freescale.com }
626a8919371SHaikun.Wang@freescale.com 
627a8919371SHaikun.Wang@freescale.com /**
628a8919371SHaikun.Wang@freescale.com  * This function doesn't do anything except help with debugging
629a8919371SHaikun.Wang@freescale.com  */
fsl_dspi_bind(struct udevice * bus)630a8919371SHaikun.Wang@freescale.com static int fsl_dspi_bind(struct udevice *bus)
631a8919371SHaikun.Wang@freescale.com {
632a8919371SHaikun.Wang@freescale.com 	debug("%s assigned req_seq %d.\n", bus->name, bus->req_seq);
633a8919371SHaikun.Wang@freescale.com 	return 0;
634a8919371SHaikun.Wang@freescale.com }
635a8919371SHaikun.Wang@freescale.com 
fsl_dspi_ofdata_to_platdata(struct udevice * bus)636a8919371SHaikun.Wang@freescale.com static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
637a8919371SHaikun.Wang@freescale.com {
638a8919371SHaikun.Wang@freescale.com 	fdt_addr_t addr;
639a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_platdata *plat = bus->platdata;
640a8919371SHaikun.Wang@freescale.com 	const void *blob = gd->fdt_blob;
641e160f7d4SSimon Glass 	int node = dev_of_offset(bus);
642a8919371SHaikun.Wang@freescale.com 
643a8919371SHaikun.Wang@freescale.com 	if (fdtdec_get_bool(blob, node, "big-endian"))
644a8919371SHaikun.Wang@freescale.com 		plat->flags |= DSPI_FLAG_REGMAP_ENDIAN_BIG;
645a8919371SHaikun.Wang@freescale.com 
646a8919371SHaikun.Wang@freescale.com 	plat->num_chipselect =
647a8919371SHaikun.Wang@freescale.com 		fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT);
648a8919371SHaikun.Wang@freescale.com 
649a821c4afSSimon Glass 	addr = devfdt_get_addr(bus);
650a8919371SHaikun.Wang@freescale.com 	if (addr == FDT_ADDR_T_NONE) {
651a8919371SHaikun.Wang@freescale.com 		debug("DSPI: Can't get base address or size\n");
652a8919371SHaikun.Wang@freescale.com 		return -ENOMEM;
653a8919371SHaikun.Wang@freescale.com 	}
654a8919371SHaikun.Wang@freescale.com 	plat->regs_addr = addr;
655a8919371SHaikun.Wang@freescale.com 
656a8919371SHaikun.Wang@freescale.com 	plat->speed_hz = fdtdec_get_int(blob,
657a8919371SHaikun.Wang@freescale.com 			node, "spi-max-frequency", FSL_DSPI_DEFAULT_SCK_FREQ);
658a8919371SHaikun.Wang@freescale.com 
659fdb9f349SYork Sun 	debug("DSPI: regs=%pa, max-frequency=%d, endianess=%s, num-cs=%d\n",
660fdb9f349SYork Sun 	      &plat->regs_addr, plat->speed_hz,
661a8919371SHaikun.Wang@freescale.com 	      plat->flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le",
662a8919371SHaikun.Wang@freescale.com 	      plat->num_chipselect);
663a8919371SHaikun.Wang@freescale.com 
664a8919371SHaikun.Wang@freescale.com 	return 0;
665a8919371SHaikun.Wang@freescale.com }
666a8919371SHaikun.Wang@freescale.com 
fsl_dspi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)667a8919371SHaikun.Wang@freescale.com static int fsl_dspi_xfer(struct udevice *dev, unsigned int bitlen,
668a8919371SHaikun.Wang@freescale.com 		const void *dout, void *din, unsigned long flags)
669a8919371SHaikun.Wang@freescale.com {
670a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv;
671a8919371SHaikun.Wang@freescale.com 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
672a8919371SHaikun.Wang@freescale.com 	struct udevice *bus;
673a8919371SHaikun.Wang@freescale.com 
674a8919371SHaikun.Wang@freescale.com 	bus = dev->parent;
675a8919371SHaikun.Wang@freescale.com 	priv = dev_get_priv(bus);
676a8919371SHaikun.Wang@freescale.com 
677a8919371SHaikun.Wang@freescale.com 	return dspi_xfer(priv, slave_plat->cs, bitlen, dout, din, flags);
678a8919371SHaikun.Wang@freescale.com }
679a8919371SHaikun.Wang@freescale.com 
fsl_dspi_set_speed(struct udevice * bus,uint speed)680a8919371SHaikun.Wang@freescale.com static int fsl_dspi_set_speed(struct udevice *bus, uint speed)
681a8919371SHaikun.Wang@freescale.com {
682a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv = dev_get_priv(bus);
683a8919371SHaikun.Wang@freescale.com 
684a8919371SHaikun.Wang@freescale.com 	return fsl_dspi_cfg_speed(priv, speed);
685a8919371SHaikun.Wang@freescale.com }
686a8919371SHaikun.Wang@freescale.com 
fsl_dspi_set_mode(struct udevice * bus,uint mode)687a8919371SHaikun.Wang@freescale.com static int fsl_dspi_set_mode(struct udevice *bus, uint mode)
688a8919371SHaikun.Wang@freescale.com {
689a8919371SHaikun.Wang@freescale.com 	struct fsl_dspi_priv *priv = dev_get_priv(bus);
690a8919371SHaikun.Wang@freescale.com 
691a8919371SHaikun.Wang@freescale.com 	debug("DSPI set_mode: mode 0x%x.\n", mode);
692a8919371SHaikun.Wang@freescale.com 
693a8919371SHaikun.Wang@freescale.com 	/*
694a8919371SHaikun.Wang@freescale.com 	 * We store some chipselect special configure value in priv->ctar_val,
695a8919371SHaikun.Wang@freescale.com 	 * and we can't get the correct chipselect number here,
696a8919371SHaikun.Wang@freescale.com 	 * so just store mode value.
697a8919371SHaikun.Wang@freescale.com 	 * Do really configuration when claim_bus.
698a8919371SHaikun.Wang@freescale.com 	 */
699a8919371SHaikun.Wang@freescale.com 	priv->mode = mode;
700a8919371SHaikun.Wang@freescale.com 
701a8919371SHaikun.Wang@freescale.com 	return 0;
702a8919371SHaikun.Wang@freescale.com }
703a8919371SHaikun.Wang@freescale.com 
704a8919371SHaikun.Wang@freescale.com static const struct dm_spi_ops fsl_dspi_ops = {
705a8919371SHaikun.Wang@freescale.com 	.claim_bus	= fsl_dspi_claim_bus,
706a8919371SHaikun.Wang@freescale.com 	.release_bus	= fsl_dspi_release_bus,
707a8919371SHaikun.Wang@freescale.com 	.xfer		= fsl_dspi_xfer,
708a8919371SHaikun.Wang@freescale.com 	.set_speed	= fsl_dspi_set_speed,
709a8919371SHaikun.Wang@freescale.com 	.set_mode	= fsl_dspi_set_mode,
710a8919371SHaikun.Wang@freescale.com };
711a8919371SHaikun.Wang@freescale.com 
712a8919371SHaikun.Wang@freescale.com static const struct udevice_id fsl_dspi_ids[] = {
713a8919371SHaikun.Wang@freescale.com 	{ .compatible = "fsl,vf610-dspi" },
714a8919371SHaikun.Wang@freescale.com 	{ }
715a8919371SHaikun.Wang@freescale.com };
716a8919371SHaikun.Wang@freescale.com 
717a8919371SHaikun.Wang@freescale.com U_BOOT_DRIVER(fsl_dspi) = {
718a8919371SHaikun.Wang@freescale.com 	.name	= "fsl_dspi",
719a8919371SHaikun.Wang@freescale.com 	.id	= UCLASS_SPI,
720a8919371SHaikun.Wang@freescale.com 	.of_match = fsl_dspi_ids,
721a8919371SHaikun.Wang@freescale.com 	.ops	= &fsl_dspi_ops,
722a8919371SHaikun.Wang@freescale.com 	.ofdata_to_platdata = fsl_dspi_ofdata_to_platdata,
723a8919371SHaikun.Wang@freescale.com 	.platdata_auto_alloc_size = sizeof(struct fsl_dspi_platdata),
724a8919371SHaikun.Wang@freescale.com 	.priv_auto_alloc_size = sizeof(struct fsl_dspi_priv),
725a8919371SHaikun.Wang@freescale.com 	.probe	= fsl_dspi_probe,
726a8919371SHaikun.Wang@freescale.com 	.child_pre_probe = fsl_dspi_child_pre_probe,
727a8919371SHaikun.Wang@freescale.com 	.bind = fsl_dspi_bind,
728a8919371SHaikun.Wang@freescale.com };
729a8919371SHaikun.Wang@freescale.com #endif
730