xref: /openbmc/u-boot/drivers/spi/omap3_spi.c (revision e0a0cbf2)
1 /*
2  * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
3  *
4  * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
5  * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
6  *
7  * Copyright (C) 2007 Atmel Corporation
8  *
9  * Parts taken from linux/drivers/spi/omap2_mcspi.c
10  * Copyright (C) 2005, 2006 Nokia Corporation
11  *
12  * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com>
13  *
14  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30  * MA 02111-1307 USA
31  *
32  */
33 
34 #include <common.h>
35 #include <spi.h>
36 #include <malloc.h>
37 #include <asm/io.h>
38 #include "omap3_spi.h"
39 
40 #define WORD_LEN	8
41 #define SPI_WAIT_TIMEOUT 3000000;
42 
43 static void spi_reset(struct omap3_spi_slave *ds)
44 {
45 	unsigned int tmp;
46 
47 	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig);
48 	do {
49 		tmp = readl(&ds->regs->sysstatus);
50 	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
51 
52 	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
53 				 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
54 				 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
55 				 &ds->regs->sysconfig);
56 
57 	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable);
58 }
59 
60 void spi_init()
61 {
62 	/* do nothing */
63 }
64 
65 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
66 				  unsigned int max_hz, unsigned int mode)
67 {
68 	struct omap3_spi_slave	*ds;
69 
70 	ds = malloc(sizeof(struct omap3_spi_slave));
71 	if (!ds) {
72 		printf("SPI error: malloc of SPI structure failed\n");
73 		return NULL;
74 	}
75 
76 	/*
77 	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
78 	 * with different number of chip selects (CS, channels):
79 	 * McSPI1 has 4 CS (bus 0, cs 0 - 3)
80 	 * McSPI2 has 2 CS (bus 1, cs 0 - 1)
81 	 * McSPI3 has 2 CS (bus 2, cs 0 - 1)
82 	 * McSPI4 has 1 CS (bus 3, cs 0)
83 	 */
84 
85 	switch (bus) {
86 	case 0:
87 		ds->regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
88 		break;
89 #ifdef OMAP3_MCSPI2_BASE
90 	case 1:
91 		ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
92 		break;
93 #endif
94 #ifdef OMAP3_MCSPI3_BASE
95 	case 2:
96 		ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
97 		break;
98 #endif
99 #ifdef OMAP3_MCSPI4_BASE
100 	case 3:
101 		ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
102 		break;
103 #endif
104 	default:
105 		printf("SPI error: unsupported bus %i. \
106 			Supported busses 0 - 3\n", bus);
107 		return NULL;
108 	}
109 	ds->slave.bus = bus;
110 
111 	if (((bus == 0) && (cs > 3)) ||
112 			((bus == 1) && (cs > 1)) ||
113 			((bus == 2) && (cs > 1)) ||
114 			((bus == 3) && (cs > 0))) {
115 		printf("SPI error: unsupported chip select %i \
116 			on bus %i\n", cs, bus);
117 		return NULL;
118 	}
119 	ds->slave.cs = cs;
120 
121 	if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
122 		printf("SPI error: unsupported frequency %i Hz. \
123 			Max frequency is 48 Mhz\n", max_hz);
124 		return NULL;
125 	}
126 	ds->freq = max_hz;
127 
128 	if (mode > SPI_MODE_3) {
129 		printf("SPI error: unsupported SPI mode %i\n", mode);
130 		return NULL;
131 	}
132 	ds->mode = mode;
133 
134 	return &ds->slave;
135 }
136 
137 void spi_free_slave(struct spi_slave *slave)
138 {
139 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
140 
141 	free(ds);
142 }
143 
144 int spi_claim_bus(struct spi_slave *slave)
145 {
146 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
147 	unsigned int conf, div = 0;
148 
149 	/* McSPI global module configuration */
150 
151 	/*
152 	 * setup when switching from (reset default) slave mode
153 	 * to single-channel master mode
154 	 */
155 	spi_reset(ds);
156 	conf = readl(&ds->regs->modulctrl);
157 	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
158 	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
159 	writel(conf, &ds->regs->modulctrl);
160 
161 	/* McSPI individual channel configuration */
162 
163 	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
164 	if (ds->freq) {
165 		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
166 					 > ds->freq)
167 			div++;
168 	} else
169 		div = 0xC;
170 
171 	conf = readl(&ds->regs->channel[ds->slave.cs].chconf);
172 
173 	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
174 	 * REVISIT: this controller could support SPI_3WIRE mode.
175 	 */
176 #ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
177 	/*
178 	 * Some boards have D0 wired as MOSI / D1 as MISO instead of
179 	 * The normal D0 as MISO / D1 as MOSI.
180 	 */
181 	conf &= ~OMAP3_MCSPI_CHCONF_DPE0;
182 	conf |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
183 #else
184 	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
185 	conf |= OMAP3_MCSPI_CHCONF_DPE0;
186 #endif
187 
188 	/* wordlength */
189 	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
190 	conf |= (WORD_LEN - 1) << 7;
191 
192 	/* set chipselect polarity; manage with FORCE */
193 	if (!(ds->mode & SPI_CS_HIGH))
194 		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
195 	else
196 		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
197 
198 	/* set clock divisor */
199 	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
200 	conf |= div << 2;
201 
202 	/* set SPI mode 0..3 */
203 	if (ds->mode & SPI_CPOL)
204 		conf |= OMAP3_MCSPI_CHCONF_POL;
205 	else
206 		conf &= ~OMAP3_MCSPI_CHCONF_POL;
207 	if (ds->mode & SPI_CPHA)
208 		conf |= OMAP3_MCSPI_CHCONF_PHA;
209 	else
210 		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
211 
212 	/* Transmit & receive mode */
213 	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
214 
215 	writel(conf, &ds->regs->channel[ds->slave.cs].chconf);
216 
217 	return 0;
218 }
219 
220 void spi_release_bus(struct spi_slave *slave)
221 {
222 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
223 
224 	/* Reset the SPI hardware */
225 	spi_reset(ds);
226 }
227 
228 int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
229 		    unsigned long flags)
230 {
231 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
232 	int i;
233 	int timeout = SPI_WAIT_TIMEOUT;
234 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
235 
236 	if (flags & SPI_XFER_BEGIN)
237 		writel(OMAP3_MCSPI_CHCTRL_EN,
238 		       &ds->regs->channel[ds->slave.cs].chctrl);
239 
240 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
241 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
242 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
243 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
244 
245 	for (i = 0; i < len; i++) {
246 		/* wait till TX register is empty (TXS == 1) */
247 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
248 			 OMAP3_MCSPI_CHSTAT_TXS)) {
249 			if (--timeout <= 0) {
250 				printf("SPI TXS timed out, status=0x%08x\n",
251 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
252 				return -1;
253 			}
254 		}
255 		/* Write the data */
256 		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
257 	}
258 
259 	if (flags & SPI_XFER_END) {
260 		/* wait to finish of transfer */
261 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
262 			 OMAP3_MCSPI_CHSTAT_EOT));
263 
264 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
265 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
266 
267 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
268 	}
269 	return 0;
270 }
271 
272 int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
273 		   unsigned long flags)
274 {
275 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
276 	int i;
277 	int timeout = SPI_WAIT_TIMEOUT;
278 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
279 
280 	if (flags & SPI_XFER_BEGIN)
281 		writel(OMAP3_MCSPI_CHCTRL_EN,
282 		       &ds->regs->channel[ds->slave.cs].chctrl);
283 
284 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
285 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
286 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
287 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
288 
289 	writel(0, &ds->regs->channel[ds->slave.cs].tx);
290 
291 	for (i = 0; i < len; i++) {
292 		/* Wait till RX register contains data (RXS == 1) */
293 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
294 			 OMAP3_MCSPI_CHSTAT_RXS)) {
295 			if (--timeout <= 0) {
296 				printf("SPI RXS timed out, status=0x%08x\n",
297 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
298 				return -1;
299 			}
300 		}
301 		/* Read the data */
302 		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
303 	}
304 
305 	if (flags & SPI_XFER_END) {
306 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
307 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
308 
309 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
310 	}
311 
312 	return 0;
313 }
314 
315 /*McSPI Transmit Receive Mode*/
316 int omap3_spi_txrx(struct spi_slave *slave,
317 		unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
318 {
319 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
320 	int timeout = SPI_WAIT_TIMEOUT;
321 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
322 	int irqstatus = readl(&ds->regs->irqstatus);
323 	int i=0;
324 
325 	/*Enable SPI channel*/
326 	if (flags & SPI_XFER_BEGIN)
327 		writel(OMAP3_MCSPI_CHCTRL_EN,
328 		       &ds->regs->channel[ds->slave.cs].chctrl);
329 
330 	/*set TRANSMIT-RECEIVE Mode*/
331 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
332 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
333 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
334 
335 	/*Shift in and out 1 byte at time*/
336 	for (i=0; i < len; i++){
337 		/* Write: wait for TX empty (TXS == 1)*/
338 		irqstatus |= (1<< (4*(ds->slave.bus)));
339 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
340 			 OMAP3_MCSPI_CHSTAT_TXS)) {
341 			if (--timeout <= 0) {
342 				printf("SPI TXS timed out, status=0x%08x\n",
343 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
344 				return -1;
345 			}
346 		}
347 		/* Write the data */
348 		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
349 
350 		/*Read: wait for RX containing data (RXS == 1)*/
351 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
352 			 OMAP3_MCSPI_CHSTAT_RXS)) {
353 			if (--timeout <= 0) {
354 				printf("SPI RXS timed out, status=0x%08x\n",
355 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
356 				return -1;
357 			}
358 		}
359 		/* Read the data */
360 		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
361 	}
362 
363 	/*if transfer must be terminated disable the channel*/
364 	if (flags & SPI_XFER_END) {
365 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
366 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
367 
368 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
369 	}
370 
371 	return 0;
372 }
373 
374 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
375 	     const void *dout, void *din, unsigned long flags)
376 {
377 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
378 	unsigned int	len;
379 	const u8	*txp = dout;
380 	u8		*rxp = din;
381 	int ret = -1;
382 
383 	if (bitlen % 8)
384 		return -1;
385 
386 	len = bitlen / 8;
387 
388 	if (bitlen == 0) {	 /* only change CS */
389 		int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
390 
391 		if (flags & SPI_XFER_BEGIN) {
392 			writel(OMAP3_MCSPI_CHCTRL_EN,
393 			       &ds->regs->channel[ds->slave.cs].chctrl);
394 			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
395 			writel(chconf,
396 			       &ds->regs->channel[ds->slave.cs].chconf);
397 		}
398 		if (flags & SPI_XFER_END) {
399 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
400 			writel(chconf,
401 			       &ds->regs->channel[ds->slave.cs].chconf);
402 			writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
403 		}
404 		ret = 0;
405 	} else {
406 		if (dout != NULL && din != NULL)
407 			ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
408 		else if (dout != NULL)
409 			ret = omap3_spi_write(slave, len, txp, flags);
410 		else if (din != NULL)
411 			ret = omap3_spi_read(slave, len, rxp, flags);
412 	}
413 	return ret;
414 }
415 
416 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
417 {
418 	return 1;
419 }
420 
421 void spi_cs_activate(struct spi_slave *slave)
422 {
423 }
424 
425 void spi_cs_deactivate(struct spi_slave *slave)
426 {
427 }
428