xref: /OK3568_Linux_fs/u-boot/drivers/spi/mpc8xx_spi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2001 Navin Boppuri / Prashant Patel
3*4882a593Smuzhiyun  *	<nboppuri@trinetcommunication.com>,
4*4882a593Smuzhiyun  *	<pmpatel@trinetcommunication.com>
5*4882a593Smuzhiyun  * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
6*4882a593Smuzhiyun  * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun  * MPC8xx CPM SPI interface.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Parts of this code are probably not portable and/or specific to
15*4882a593Smuzhiyun  * the board which I used for the tests. Please send fixes/complaints
16*4882a593Smuzhiyun  * to wd@denx.de
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <common.h>
21*4882a593Smuzhiyun #include <mpc8xx.h>
22*4882a593Smuzhiyun #include <asm/cpm_8xx.h>
23*4882a593Smuzhiyun #include <linux/ctype.h>
24*4882a593Smuzhiyun #include <malloc.h>
25*4882a593Smuzhiyun #include <post.h>
26*4882a593Smuzhiyun #include <serial.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define SPI_EEPROM_WREN		0x06
29*4882a593Smuzhiyun #define SPI_EEPROM_RDSR		0x05
30*4882a593Smuzhiyun #define SPI_EEPROM_READ		0x03
31*4882a593Smuzhiyun #define SPI_EEPROM_WRITE	0x02
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* ---------------------------------------------------------------
34*4882a593Smuzhiyun  * Offset for initial SPI buffers in DPRAM:
35*4882a593Smuzhiyun  * We need a 520 byte scratch DPRAM area to use at an early stage.
36*4882a593Smuzhiyun  * It is used between the two initialization calls (spi_init_f()
37*4882a593Smuzhiyun  * and spi_init_r()).
38*4882a593Smuzhiyun  * The value 0xb00 makes it far enough from the start of the data
39*4882a593Smuzhiyun  * area (as well as from the stack pointer).
40*4882a593Smuzhiyun  * --------------------------------------------------------------- */
41*4882a593Smuzhiyun #ifndef	CONFIG_SYS_SPI_INIT_OFFSET
42*4882a593Smuzhiyun #define	CONFIG_SYS_SPI_INIT_OFFSET	0xB00
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define CPM_SPI_BASE_RX	CPM_SPI_BASE
46*4882a593Smuzhiyun #define CPM_SPI_BASE_TX	(CPM_SPI_BASE + sizeof(cbd_t))
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* -------------------
49*4882a593Smuzhiyun  * Function prototypes
50*4882a593Smuzhiyun  * ------------------- */
51*4882a593Smuzhiyun ssize_t spi_xfer(size_t);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /* -------------------
54*4882a593Smuzhiyun  * Variables
55*4882a593Smuzhiyun  * ------------------- */
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define MAX_BUFFER	0x104
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* ----------------------------------------------------------------------
60*4882a593Smuzhiyun  * Initially we place the RX and TX buffers at a fixed location in DPRAM!
61*4882a593Smuzhiyun  * ---------------------------------------------------------------------- */
62*4882a593Smuzhiyun static uchar *rxbuf =
63*4882a593Smuzhiyun 	(uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
64*4882a593Smuzhiyun 			[CONFIG_SYS_SPI_INIT_OFFSET];
65*4882a593Smuzhiyun static uchar *txbuf =
66*4882a593Smuzhiyun 	(uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
67*4882a593Smuzhiyun 			[CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun /* **************************************************************************
70*4882a593Smuzhiyun  *
71*4882a593Smuzhiyun  *  Function:    spi_init_f
72*4882a593Smuzhiyun  *
73*4882a593Smuzhiyun  *  Description: Init SPI-Controller (ROM part)
74*4882a593Smuzhiyun  *
75*4882a593Smuzhiyun  *  return:      ---
76*4882a593Smuzhiyun  *
77*4882a593Smuzhiyun  * *********************************************************************** */
spi_init_f(void)78*4882a593Smuzhiyun void spi_init_f(void)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
81*4882a593Smuzhiyun 	cpm8xx_t __iomem *cp = &immr->im_cpm;
82*4882a593Smuzhiyun 	spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
83*4882a593Smuzhiyun 	cbd_t __iomem *tbdf, *rbdf;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	/* Disable relocation */
86*4882a593Smuzhiyun 	out_be16(&spi->spi_rpbase, 0);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /* 1 */
89*4882a593Smuzhiyun 	/* ------------------------------------------------
90*4882a593Smuzhiyun 	 * Initialize Port B SPI pins -> page 34-8 MPC860UM
91*4882a593Smuzhiyun 	 * (we are only in Master Mode !)
92*4882a593Smuzhiyun 	 * ------------------------------------------------ */
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* --------------------------------------------
95*4882a593Smuzhiyun 	 * GPIO or per. Function
96*4882a593Smuzhiyun 	 * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
97*4882a593Smuzhiyun 	 * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
98*4882a593Smuzhiyun 	 * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
99*4882a593Smuzhiyun 	 * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
100*4882a593Smuzhiyun 	 * -------------------------------------------- */
101*4882a593Smuzhiyun 	clrsetbits_be32(&cp->cp_pbpar, 0x00000001, 0x0000000E);	/* set  bits */
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	/* ----------------------------------------------
104*4882a593Smuzhiyun 	 * In/Out or per. Function 0/1
105*4882a593Smuzhiyun 	 * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
106*4882a593Smuzhiyun 	 * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
107*4882a593Smuzhiyun 	 * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
108*4882a593Smuzhiyun 	 * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
109*4882a593Smuzhiyun 	 * ---------------------------------------------- */
110*4882a593Smuzhiyun 	setbits_be32(&cp->cp_pbdir, 0x0000000F);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	/* ----------------------------------------------
113*4882a593Smuzhiyun 	 * open drain or active output
114*4882a593Smuzhiyun 	 * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
115*4882a593Smuzhiyun 	 * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
116*4882a593Smuzhiyun 	 * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
117*4882a593Smuzhiyun 	 * PBODR[31] = 0 [0x00000001] -> active output GPIO OUT: CS for PCUE/CCM
118*4882a593Smuzhiyun 	 * ---------------------------------------------- */
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	clrsetbits_be16(&cp->cp_pbodr, 0x00000007, 0x00000008);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* Initialize the parameter ram.
123*4882a593Smuzhiyun 	 * We need to make sure many things are initialized to zero
124*4882a593Smuzhiyun 	 */
125*4882a593Smuzhiyun 	out_be32(&spi->spi_rstate, 0);
126*4882a593Smuzhiyun 	out_be32(&spi->spi_rdp, 0);
127*4882a593Smuzhiyun 	out_be16(&spi->spi_rbptr, 0);
128*4882a593Smuzhiyun 	out_be16(&spi->spi_rbc, 0);
129*4882a593Smuzhiyun 	out_be32(&spi->spi_rxtmp, 0);
130*4882a593Smuzhiyun 	out_be32(&spi->spi_tstate, 0);
131*4882a593Smuzhiyun 	out_be32(&spi->spi_tdp, 0);
132*4882a593Smuzhiyun 	out_be16(&spi->spi_tbptr, 0);
133*4882a593Smuzhiyun 	out_be16(&spi->spi_tbc, 0);
134*4882a593Smuzhiyun 	out_be32(&spi->spi_txtmp, 0);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /* 3 */
137*4882a593Smuzhiyun 	/* Set up the SPI parameters in the parameter ram */
138*4882a593Smuzhiyun 	out_be16(&spi->spi_rbase, CPM_SPI_BASE_RX);
139*4882a593Smuzhiyun 	out_be16(&spi->spi_tbase, CPM_SPI_BASE_TX);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/***********IMPORTANT******************/
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/*
144*4882a593Smuzhiyun 	 * Setting transmit and receive buffer descriptor pointers
145*4882a593Smuzhiyun 	 * initially to rbase and tbase. Only the microcode patches
146*4882a593Smuzhiyun 	 * documentation talks about initializing this pointer. This
147*4882a593Smuzhiyun 	 * is missing from the sample I2C driver. If you dont
148*4882a593Smuzhiyun 	 * initialize these pointers, the kernel hangs.
149*4882a593Smuzhiyun 	 */
150*4882a593Smuzhiyun 	out_be16(&spi->spi_rbptr, CPM_SPI_BASE_RX);
151*4882a593Smuzhiyun 	out_be16(&spi->spi_tbptr, CPM_SPI_BASE_TX);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /* 4 */
154*4882a593Smuzhiyun 	/* Init SPI Tx + Rx Parameters */
155*4882a593Smuzhiyun 	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
156*4882a593Smuzhiyun 		;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) |
159*4882a593Smuzhiyun 			       CPM_CR_FLG);
160*4882a593Smuzhiyun 	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
161*4882a593Smuzhiyun 		;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun /* 5 */
164*4882a593Smuzhiyun 	/* Set SDMA configuration register */
165*4882a593Smuzhiyun 	out_be32(&immr->im_siu_conf.sc_sdcr, 0x0001);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /* 6 */
168*4882a593Smuzhiyun 	/* Set to big endian. */
169*4882a593Smuzhiyun 	out_8(&spi->spi_tfcr, SMC_EB);
170*4882a593Smuzhiyun 	out_8(&spi->spi_rfcr, SMC_EB);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /* 7 */
173*4882a593Smuzhiyun 	/* Set maximum receive size. */
174*4882a593Smuzhiyun 	out_be16(&spi->spi_mrblr, MAX_BUFFER);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun /* 8 + 9 */
177*4882a593Smuzhiyun 	/* tx and rx buffer descriptors */
178*4882a593Smuzhiyun 	tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
179*4882a593Smuzhiyun 	rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	clrbits_be16(&tbdf->cbd_sc, BD_SC_READY);
182*4882a593Smuzhiyun 	clrbits_be16(&rbdf->cbd_sc, BD_SC_EMPTY);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	/* Set the bd's rx and tx buffer address pointers */
185*4882a593Smuzhiyun 	out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf);
186*4882a593Smuzhiyun 	out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun /* 10 + 11 */
189*4882a593Smuzhiyun 	out_8(&cp->cp_spim, 0);			/* Mask  all SPI events */
190*4882a593Smuzhiyun 	out_8(&cp->cp_spie, SPI_EMASK);		/* Clear all SPI events	*/
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun /* **************************************************************************
196*4882a593Smuzhiyun  *
197*4882a593Smuzhiyun  *  Function:    spi_init_r
198*4882a593Smuzhiyun  *
199*4882a593Smuzhiyun  *  Description: Init SPI-Controller (RAM part) -
200*4882a593Smuzhiyun  *		 The malloc engine is ready and we can move our buffers to
201*4882a593Smuzhiyun  *		 normal RAM
202*4882a593Smuzhiyun  *
203*4882a593Smuzhiyun  *  return:      ---
204*4882a593Smuzhiyun  *
205*4882a593Smuzhiyun  * *********************************************************************** */
spi_init_r(void)206*4882a593Smuzhiyun void spi_init_r(void)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
209*4882a593Smuzhiyun 	cpm8xx_t __iomem *cp = &immr->im_cpm;
210*4882a593Smuzhiyun 	spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
211*4882a593Smuzhiyun 	cbd_t __iomem *tbdf, *rbdf;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	/* Disable relocation */
214*4882a593Smuzhiyun 	out_be16(&spi->spi_rpbase, 0);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	/* tx and rx buffer descriptors */
217*4882a593Smuzhiyun 	tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
218*4882a593Smuzhiyun 	rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/* Allocate memory for RX and TX buffers */
221*4882a593Smuzhiyun 	rxbuf = (uchar *)malloc(MAX_BUFFER);
222*4882a593Smuzhiyun 	txbuf = (uchar *)malloc(MAX_BUFFER);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf);
225*4882a593Smuzhiyun 	out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	return;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun /****************************************************************************
231*4882a593Smuzhiyun  *  Function:    spi_write
232*4882a593Smuzhiyun  **************************************************************************** */
spi_write(uchar * addr,int alen,uchar * buffer,int len)233*4882a593Smuzhiyun ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	int i;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	memset(rxbuf, 0, MAX_BUFFER);
238*4882a593Smuzhiyun 	memset(txbuf, 0, MAX_BUFFER);
239*4882a593Smuzhiyun 	*txbuf = SPI_EEPROM_WREN;		/* write enable		*/
240*4882a593Smuzhiyun 	spi_xfer(1);
241*4882a593Smuzhiyun 	memcpy(txbuf, addr, alen);
242*4882a593Smuzhiyun 	*txbuf = SPI_EEPROM_WRITE;		/* WRITE memory array	*/
243*4882a593Smuzhiyun 	memcpy(alen + txbuf, buffer, len);
244*4882a593Smuzhiyun 	spi_xfer(alen + len);
245*4882a593Smuzhiyun 						/* ignore received data	*/
246*4882a593Smuzhiyun 	for (i = 0; i < 1000; i++) {
247*4882a593Smuzhiyun 		*txbuf = SPI_EEPROM_RDSR;	/* read status		*/
248*4882a593Smuzhiyun 		txbuf[1] = 0;
249*4882a593Smuzhiyun 		spi_xfer(2);
250*4882a593Smuzhiyun 		if (!(rxbuf[1] & 1))
251*4882a593Smuzhiyun 			break;
252*4882a593Smuzhiyun 		udelay(1000);
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 	if (i >= 1000)
255*4882a593Smuzhiyun 		printf("*** spi_write: Time out while writing!\n");
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return len;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun /****************************************************************************
261*4882a593Smuzhiyun  *  Function:    spi_read
262*4882a593Smuzhiyun  **************************************************************************** */
spi_read(uchar * addr,int alen,uchar * buffer,int len)263*4882a593Smuzhiyun ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	memset(rxbuf, 0, MAX_BUFFER);
266*4882a593Smuzhiyun 	memset(txbuf, 0, MAX_BUFFER);
267*4882a593Smuzhiyun 	memcpy(txbuf, addr, alen);
268*4882a593Smuzhiyun 	*txbuf = SPI_EEPROM_READ;		/* READ memory array	*/
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/*
271*4882a593Smuzhiyun 	 * There is a bug in 860T (?) that cuts the last byte of input
272*4882a593Smuzhiyun 	 * if we're reading into DPRAM. The solution we choose here is
273*4882a593Smuzhiyun 	 * to always read len+1 bytes (we have one extra byte at the
274*4882a593Smuzhiyun 	 * end of the buffer).
275*4882a593Smuzhiyun 	 */
276*4882a593Smuzhiyun 	spi_xfer(alen + len + 1);
277*4882a593Smuzhiyun 	memcpy(buffer, alen + rxbuf, len);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	return len;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun /****************************************************************************
283*4882a593Smuzhiyun  *  Function:    spi_xfer
284*4882a593Smuzhiyun  **************************************************************************** */
spi_xfer(size_t count)285*4882a593Smuzhiyun ssize_t spi_xfer(size_t count)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
288*4882a593Smuzhiyun 	cpm8xx_t __iomem *cp = &immr->im_cpm;
289*4882a593Smuzhiyun 	spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
290*4882a593Smuzhiyun 	cbd_t __iomem *tbdf, *rbdf;
291*4882a593Smuzhiyun 	int tm;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* Disable relocation */
294*4882a593Smuzhiyun 	out_be16(&spi->spi_rpbase, 0);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
297*4882a593Smuzhiyun 	rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/* Set CS for device */
300*4882a593Smuzhiyun 	clrbits_be32(&cp->cp_pbdat, 0x0001);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	/* Setting tx bd status and data length */
303*4882a593Smuzhiyun 	out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP);
304*4882a593Smuzhiyun 	out_be16(&tbdf->cbd_datlen, count);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* Setting rx bd status and data length */
307*4882a593Smuzhiyun 	out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
308*4882a593Smuzhiyun 	out_be16(&rbdf->cbd_datlen, 0);	 /* rx length has no significance */
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	clrsetbits_be16(&cp->cp_spmode, ~SPMODE_LOOP, SPMODE_REV | SPMODE_MSTR |
311*4882a593Smuzhiyun 			SPMODE_EN | SPMODE_LEN(8) | SPMODE_PM(0x8));
312*4882a593Smuzhiyun 	out_8(&cp->cp_spim, 0);		/* Mask  all SPI events */
313*4882a593Smuzhiyun 	out_8(&cp->cp_spie, SPI_EMASK);	/* Clear all SPI events	*/
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* start spi transfer */
316*4882a593Smuzhiyun 	setbits_8(&cp->cp_spcom, SPI_STR);		/* Start transmit */
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* --------------------------------
319*4882a593Smuzhiyun 	 * Wait for SPI transmit to get out
320*4882a593Smuzhiyun 	 * or time out (1 second = 1000 ms)
321*4882a593Smuzhiyun 	 * -------------------------------- */
322*4882a593Smuzhiyun 	for (tm = 0; tm < 1000; ++tm) {
323*4882a593Smuzhiyun 		if (in_8(&cp->cp_spie) & SPI_TXB)	/* Tx Buffer Empty */
324*4882a593Smuzhiyun 			break;
325*4882a593Smuzhiyun 		if ((in_be16(&tbdf->cbd_sc) & BD_SC_READY) == 0)
326*4882a593Smuzhiyun 			break;
327*4882a593Smuzhiyun 		udelay(1000);
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 	if (tm >= 1000)
330*4882a593Smuzhiyun 		printf("*** spi_xfer: Time out while xferring to/from SPI!\n");
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Clear CS for device */
333*4882a593Smuzhiyun 	setbits_be32(&cp->cp_pbdat, 0x0001);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return count;
336*4882a593Smuzhiyun }
337