xref: /openbmc/u-boot/drivers/spi/omap3_spi.c (revision 4f9a5b06)
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 	case 1:
90 		ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
91 		break;
92 	case 2:
93 		ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
94 		break;
95 	case 3:
96 		ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
97 		break;
98 	default:
99 		printf("SPI error: unsupported bus %i. \
100 			Supported busses 0 - 3\n", bus);
101 		return NULL;
102 	}
103 	ds->slave.bus = bus;
104 
105 	if (((bus == 0) && (cs > 3)) ||
106 			((bus == 1) && (cs > 1)) ||
107 			((bus == 2) && (cs > 1)) ||
108 			((bus == 3) && (cs > 0))) {
109 		printf("SPI error: unsupported chip select %i \
110 			on bus %i\n", cs, bus);
111 		return NULL;
112 	}
113 	ds->slave.cs = cs;
114 
115 	if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
116 		printf("SPI error: unsupported frequency %i Hz. \
117 			Max frequency is 48 Mhz\n", max_hz);
118 		return NULL;
119 	}
120 	ds->freq = max_hz;
121 
122 	if (mode > SPI_MODE_3) {
123 		printf("SPI error: unsupported SPI mode %i\n", mode);
124 		return NULL;
125 	}
126 	ds->mode = mode;
127 
128 	return &ds->slave;
129 }
130 
131 void spi_free_slave(struct spi_slave *slave)
132 {
133 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
134 
135 	free(ds);
136 }
137 
138 int spi_claim_bus(struct spi_slave *slave)
139 {
140 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
141 	unsigned int conf, div = 0;
142 
143 	/* McSPI global module configuration */
144 
145 	/*
146 	 * setup when switching from (reset default) slave mode
147 	 * to single-channel master mode
148 	 */
149 	spi_reset(ds);
150 	conf = readl(&ds->regs->modulctrl);
151 	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
152 	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
153 	writel(conf, &ds->regs->modulctrl);
154 
155 	/* McSPI individual channel configuration */
156 
157 	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
158 	if (ds->freq) {
159 		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
160 					 > ds->freq)
161 			div++;
162 	} else
163 		div = 0xC;
164 
165 	conf = readl(&ds->regs->channel[ds->slave.cs].chconf);
166 
167 	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
168 	 * REVISIT: this controller could support SPI_3WIRE mode.
169 	 */
170 	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
171 	conf |= OMAP3_MCSPI_CHCONF_DPE0;
172 
173 	/* wordlength */
174 	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
175 	conf |= (WORD_LEN - 1) << 7;
176 
177 	/* set chipselect polarity; manage with FORCE */
178 	if (!(ds->mode & SPI_CS_HIGH))
179 		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
180 	else
181 		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
182 
183 	/* set clock divisor */
184 	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
185 	conf |= div << 2;
186 
187 	/* set SPI mode 0..3 */
188 	if (ds->mode & SPI_CPOL)
189 		conf |= OMAP3_MCSPI_CHCONF_POL;
190 	else
191 		conf &= ~OMAP3_MCSPI_CHCONF_POL;
192 	if (ds->mode & SPI_CPHA)
193 		conf |= OMAP3_MCSPI_CHCONF_PHA;
194 	else
195 		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
196 
197 	/* Transmit & receive mode */
198 	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
199 
200 	writel(conf, &ds->regs->channel[ds->slave.cs].chconf);
201 
202 	return 0;
203 }
204 
205 void spi_release_bus(struct spi_slave *slave)
206 {
207 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
208 
209 	/* Reset the SPI hardware */
210 	spi_reset(ds);
211 }
212 
213 int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
214 		    unsigned long flags)
215 {
216 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
217 	int i;
218 	int timeout = SPI_WAIT_TIMEOUT;
219 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
220 
221 	if (flags & SPI_XFER_BEGIN)
222 		writel(OMAP3_MCSPI_CHCTRL_EN,
223 		       &ds->regs->channel[ds->slave.cs].chctrl);
224 
225 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
226 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
227 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
228 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
229 
230 	for (i = 0; i < len; i++) {
231 		/* wait till TX register is empty (TXS == 1) */
232 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
233 			 OMAP3_MCSPI_CHSTAT_TXS)) {
234 			if (--timeout <= 0) {
235 				printf("SPI TXS timed out, status=0x%08x\n",
236 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
237 				return -1;
238 			}
239 		}
240 		/* Write the data */
241 		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
242 	}
243 
244 	if (flags & SPI_XFER_END) {
245 		/* wait to finish of transfer */
246 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
247 			 OMAP3_MCSPI_CHSTAT_EOT));
248 
249 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
250 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
251 
252 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
253 	}
254 	return 0;
255 }
256 
257 int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
258 		   unsigned long flags)
259 {
260 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
261 	int i;
262 	int timeout = SPI_WAIT_TIMEOUT;
263 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
264 
265 	if (flags & SPI_XFER_BEGIN)
266 		writel(OMAP3_MCSPI_CHCTRL_EN,
267 		       &ds->regs->channel[ds->slave.cs].chctrl);
268 
269 	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
270 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
271 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
272 	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
273 
274 	writel(0, &ds->regs->channel[ds->slave.cs].tx);
275 
276 	for (i = 0; i < len; i++) {
277 		/* Wait till RX register contains data (RXS == 1) */
278 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
279 			 OMAP3_MCSPI_CHSTAT_RXS)) {
280 			if (--timeout <= 0) {
281 				printf("SPI RXS timed out, status=0x%08x\n",
282 				       readl(&ds->regs->channel[ds->slave.cs].chstat));
283 				return -1;
284 			}
285 		}
286 		/* Read the data */
287 		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
288 	}
289 
290 	if (flags & SPI_XFER_END) {
291 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
292 		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
293 
294 		writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
295 	}
296 
297 	return 0;
298 }
299 
300 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
301 	     const void *dout, void *din, unsigned long flags)
302 {
303 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
304 	unsigned int	len;
305 	const u8	*txp = dout;
306 	u8		*rxp = din;
307 	int ret = -1;
308 
309 	if (bitlen % 8)
310 		return -1;
311 
312 	len = bitlen / 8;
313 
314 	if (bitlen == 0) {	 /* only change CS */
315 		int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
316 
317 		if (flags & SPI_XFER_BEGIN) {
318 			writel(OMAP3_MCSPI_CHCTRL_EN,
319 			       &ds->regs->channel[ds->slave.cs].chctrl);
320 			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
321 			writel(chconf,
322 			       &ds->regs->channel[ds->slave.cs].chconf);
323 		}
324 		if (flags & SPI_XFER_END) {
325 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
326 			writel(chconf,
327 			       &ds->regs->channel[ds->slave.cs].chconf);
328 			writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
329 		}
330 		ret = 0;
331 	} else {
332 		if (dout != NULL)
333 			ret = omap3_spi_write(slave, len, txp, flags);
334 
335 		if (din != NULL)
336 			ret = omap3_spi_read(slave, len, rxp, flags);
337 	}
338 	return ret;
339 }
340 
341 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
342 {
343 	return 1;
344 }
345 
346 void spi_cs_activate(struct spi_slave *slave)
347 {
348 }
349 
350 void spi_cs_deactivate(struct spi_slave *slave)
351 {
352 }
353