xref: /openbmc/u-boot/drivers/spi/omap3_spi.c (revision c6af2e7d)
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_AM33XX
177 	/*
178 	 * The reference design on AM33xx has D0 and D1 wired up opposite
179 	 * of how it has been done on previous platforms.  We assume that
180 	 * custom hardware will also follow this convention.
181 	 */
182 	conf &= OMAP3_MCSPI_CHCONF_DPE0;
183 	conf |= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
184 #else
185 	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
186 	conf |= OMAP3_MCSPI_CHCONF_DPE0;
187 #endif
188 
189 	/* wordlength */
190 	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
191 	conf |= (WORD_LEN - 1) << 7;
192 
193 	/* set chipselect polarity; manage with FORCE */
194 	if (!(ds->mode & SPI_CS_HIGH))
195 		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
196 	else
197 		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
198 
199 	/* set clock divisor */
200 	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
201 	conf |= div << 2;
202 
203 	/* set SPI mode 0..3 */
204 	if (ds->mode & SPI_CPOL)
205 		conf |= OMAP3_MCSPI_CHCONF_POL;
206 	else
207 		conf &= ~OMAP3_MCSPI_CHCONF_POL;
208 	if (ds->mode & SPI_CPHA)
209 		conf |= OMAP3_MCSPI_CHCONF_PHA;
210 	else
211 		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
212 
213 	/* Transmit & receive mode */
214 	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
215 
216 	writel(conf, &ds->regs->channel[ds->slave.cs].chconf);
217 
218 	return 0;
219 }
220 
221 void spi_release_bus(struct spi_slave *slave)
222 {
223 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
224 
225 	/* Reset the SPI hardware */
226 	spi_reset(ds);
227 }
228 
229 int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
230 		    unsigned long flags)
231 {
232 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
233 	int i;
234 	int timeout = SPI_WAIT_TIMEOUT;
235 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
236 
237 	if (flags & SPI_XFER_BEGIN)
238 		writel(OMAP3_MCSPI_CHCTRL_EN,
239 		       &ds->regs->channel[ds->slave.cs].chctrl);
240 
241 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
242 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
243 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
244 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
245 
246 	for (i = 0; i < len; i++) {
247 		/* wait till TX register is empty (TXS == 1) */
248 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
249 			 OMAP3_MCSPI_CHSTAT_TXS)) {
250 			if (--timeout <= 0) {
251 				printf("SPI TXS timed out, status=0x%08x\n",
252 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
253 				return -1;
254 			}
255 		}
256 		/* Write the data */
257 		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
258 	}
259 
260 	if (flags & SPI_XFER_END) {
261 		/* wait to finish of transfer */
262 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
263 			 OMAP3_MCSPI_CHSTAT_EOT));
264 
265 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
266 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
267 
268 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
269 	}
270 	return 0;
271 }
272 
273 int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
274 		   unsigned long flags)
275 {
276 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
277 	int i;
278 	int timeout = SPI_WAIT_TIMEOUT;
279 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
280 
281 	if (flags & SPI_XFER_BEGIN)
282 		writel(OMAP3_MCSPI_CHCTRL_EN,
283 		       &ds->regs->channel[ds->slave.cs].chctrl);
284 
285 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
286 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
287 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
288 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
289 
290 	writel(0, &ds->regs->channel[ds->slave.cs].tx);
291 
292 	for (i = 0; i < len; i++) {
293 		/* Wait till RX register contains data (RXS == 1) */
294 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
295 			 OMAP3_MCSPI_CHSTAT_RXS)) {
296 			if (--timeout <= 0) {
297 				printf("SPI RXS timed out, status=0x%08x\n",
298 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
299 				return -1;
300 			}
301 		}
302 		/* Read the data */
303 		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
304 	}
305 
306 	if (flags & SPI_XFER_END) {
307 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
308 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
309 
310 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
311 	}
312 
313 	return 0;
314 }
315 
316 /*McSPI Transmit Receive Mode*/
317 int omap3_spi_txrx(struct spi_slave *slave,
318 		unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
319 {
320 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
321 	int timeout = SPI_WAIT_TIMEOUT;
322 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
323 	int irqstatus = readl(&ds->regs->irqstatus);
324 	int i=0;
325 
326 	/*Enable SPI channel*/
327 	if (flags & SPI_XFER_BEGIN)
328 		writel(OMAP3_MCSPI_CHCTRL_EN,
329 		       &ds->regs->channel[ds->slave.cs].chctrl);
330 
331 	/*set TRANSMIT-RECEIVE Mode*/
332 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
333 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
334 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
335 
336 	/*Shift in and out 1 byte at time*/
337 	for (i=0; i < len; i++){
338 		/* Write: wait for TX empty (TXS == 1)*/
339 		irqstatus |= (1<< (4*(ds->slave.bus)));
340 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
341 			 OMAP3_MCSPI_CHSTAT_TXS)) {
342 			if (--timeout <= 0) {
343 				printf("SPI TXS timed out, status=0x%08x\n",
344 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
345 				return -1;
346 			}
347 		}
348 		/* Write the data */
349 		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
350 
351 		/*Read: wait for RX containing data (RXS == 1)*/
352 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
353 			 OMAP3_MCSPI_CHSTAT_RXS)) {
354 			if (--timeout <= 0) {
355 				printf("SPI RXS timed out, status=0x%08x\n",
356 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
357 				return -1;
358 			}
359 		}
360 		/* Read the data */
361 		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
362 	}
363 
364 	/*if transfer must be terminated disable the channel*/
365 	if (flags & SPI_XFER_END) {
366 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
367 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
368 
369 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
370 	}
371 
372 	return 0;
373 }
374 
375 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
376 	     const void *dout, void *din, unsigned long flags)
377 {
378 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
379 	unsigned int	len;
380 	const u8	*txp = dout;
381 	u8		*rxp = din;
382 	int ret = -1;
383 
384 	if (bitlen % 8)
385 		return -1;
386 
387 	len = bitlen / 8;
388 
389 	if (bitlen == 0) {	 /* only change CS */
390 		int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
391 
392 		if (flags & SPI_XFER_BEGIN) {
393 			writel(OMAP3_MCSPI_CHCTRL_EN,
394 			       &ds->regs->channel[ds->slave.cs].chctrl);
395 			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
396 			writel(chconf,
397 			       &ds->regs->channel[ds->slave.cs].chconf);
398 		}
399 		if (flags & SPI_XFER_END) {
400 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
401 			writel(chconf,
402 			       &ds->regs->channel[ds->slave.cs].chconf);
403 			writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
404 		}
405 		ret = 0;
406 	} else {
407 		if (dout != NULL && din != NULL)
408 			ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
409 		else if (dout != NULL)
410 			ret = omap3_spi_write(slave, len, txp, flags);
411 		else if (din != NULL)
412 			ret = omap3_spi_read(slave, len, rxp, flags);
413 	}
414 	return ret;
415 }
416 
417 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
418 {
419 	return 1;
420 }
421 
422 void spi_cs_activate(struct spi_slave *slave)
423 {
424 }
425 
426 void spi_cs_deactivate(struct spi_slave *slave)
427 {
428 }
429