Annotation of sys/arch/arm/s3c2xx0/s3c2410_spi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $NetBSD: s3c2410_spi.c,v 1.4 2005/12/11 12:16:51 christos Exp $ */
2:
3: /*
4: * Copyright (c) 2004 Genetec Corporation. All rights reserved.
5: * Written by Hiroyuki Bessho for Genetec Corporation.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of Genetec Corporation may not be used to endorse or
16: * promote products derived from this software without specific prior
17: * written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * Support S3C2410's SPI dirver.
34: * Real works are done by drivers attached to SPI ports.
35: */
36:
37: #include <sys/cdefs.h>
38: __KERNEL_RCSID(0, "$NetBSD: s3c2410_spi.c,v 1.4 2005/12/11 12:16:51 christos Exp $");
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/conf.h>
43:
44: #include <machine/bus.h>
45: #include <machine/cpu.h>
46:
47: #include <arm/s3c2xx0/s3c24x0var.h>
48: #include <arm/s3c2xx0/s3c24x0reg.h>
49: #include <arm/s3c2xx0/s3c2410reg.h>
50:
51: #include <arm/s3c2xx0/s3c24x0_spi.h>
52:
53: #include "locators.h"
54:
55: struct ssspi_softc {
56: struct device dev;
57:
58: bus_space_tag_t iot;
59: bus_space_handle_t ioh;
60: short index;
61: };
62:
63:
64: /* prototypes */
65: static int ssspi_match(struct device *, struct cfdata *, void *);
66: static void ssspi_attach(struct device *, struct device *, void *);
67: static int ssspi_search(struct device *, struct cfdata *,
68: const int *, void *);
69: static int ssspi_print(void *, const char *);
70:
71: /* attach structures */
72: CFATTACH_DECL(ssspi, sizeof(struct ssspi_softc), ssspi_match, ssspi_attach,
73: NULL, NULL);
74:
75:
76: static int
77: ssspi_print(void *aux, const char *name)
78: {
79: struct ssspi_attach_args *spia = aux;
80:
81: if (spia->spia_aux_intr != SSSPICF_INTR_DEFAULT)
82: printf(" intr %d", spia->spia_aux_intr);
83: return (UNCONF);
84: }
85:
86: int
87: ssspi_match(struct device *parent, struct cfdata *match, void *aux)
88: {
89: struct s3c2xx0_attach_args *sa = aux;
90:
91: /* S3C2410 have only two SPIs */
92: switch (sa->sa_index) {
93: case 0:
94: case 1:
95: break;
96: default:
97: return 0;
98: }
99:
100: return 1;
101: }
102:
103: void
104: ssspi_attach(struct device *parent, struct device *self, void *aux)
105: {
106: struct ssspi_softc *sc = (struct ssspi_softc*)self;
107: struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args *)aux;
108: bus_space_tag_t iot = sa->sa_iot;
109:
110: static bus_space_handle_t spi_ioh = 0;
111:
112: /* we map all registers for SPI0 and SPI1 at once, then
113: use subregions */
114: if (spi_ioh == 0) {
115: if (bus_space_map(iot, S3C2410_SPI0_BASE,
116: 2 * S3C24X0_SPI_SIZE,
117: 0, &spi_ioh)) {
118: aprint_error(": can't map registers\n");
119: return;
120: }
121: }
122:
123: aprint_normal("\n");
124:
125: sc->index = sa->sa_index;
126: sc->iot = iot;
127:
128: bus_space_subregion(iot, spi_ioh, sc->index == 0 ? 0 : S3C24X0_SPI_SIZE,
129: S3C24X0_SPI_SIZE, &sc->ioh);
130:
131: /*
132: * Attach child devices
133: */
134: config_search_ia(ssspi_search, self, "ssspi", NULL);
135: }
136:
137: int
138: ssspi_search(parent, cf, ldesc, aux)
139: struct device *parent;
140: struct cfdata *cf;
141: const int *ldesc;
142: void *aux;
143: {
144: struct ssspi_softc *sc = (struct ssspi_softc *)parent;
145: struct ssspi_attach_args spia;
146: static const unsigned char intr[] = { S3C24X0_INT_SPI0,
147: S3C2410_INT_SPI1 };
148:
149: KASSERT(sc->index == 0 || sc->index == 1);
150:
151: spia.spia_iot = sc->iot;
152: spia.spia_ioh = sc->ioh;
153: spia.spia_gpioh = s3c2xx0_softc->sc_gpio_ioh;
154: spia.spia_index = sc->index;
155: spia.spia_intr = intr[sc->index];
156: spia.spia_aux_intr = cf->cf_loc[SSSPICF_INTR];
157: spia.spia_dmat = s3c2xx0_softc->sc_dmat;
158:
159: if (config_match(parent, cf, &spia))
160: config_attach(parent, cf, &spia, ssspi_print);
161:
162: return 0;
163: }
164:
165: /*
166: * Intiialze SPI port. called by child devices.
167: */
168: int
169: s3c24x0_spi_setup(struct ssspi_softc *sc, uint32_t mode, int bps, int use_ss)
170: {
171: int pclk = s3c2xx0_softc->sc_pclk;
172: int prescaler;
173: uint32_t pgcon, pecon;
174: bus_space_handle_t gpioh = s3c2xx0_softc->sc_gpio_ioh;
175: bus_space_tag_t iot = sc->iot;
176:
177: if (bps > 1) {
178: prescaler = pclk / 2 / bps - 1;
179:
180: if (prescaler <= 0 || 0xff < prescaler)
181: return -1;
182: bus_space_write_1(sc->iot, sc->ioh, SPI_SPPRE, prescaler);
183: }
184:
185:
186: if (sc->index == 0) {
187: pecon = bus_space_read_4(iot, gpioh, GPIO_PECON);
188:
189: if (use_ss) {
190: pgcon = bus_space_read_4(iot, gpioh, GPIO_PGCON);
191: pgcon = GPIO_SET_FUNC(pgcon, 2, PCON_ALTFUN2);
192: bus_space_write_4(iot, gpioh, GPIO_PGCON, pgcon);
193: }
194:
195: pecon = GPIO_SET_FUNC(pecon, 11, PCON_ALTFUN2); /* SPIMISO0 */
196: pecon = GPIO_SET_FUNC(pecon, 12, PCON_ALTFUN2); /* SPIMOSI0 */
197: pecon = GPIO_SET_FUNC(pecon, 13, PCON_ALTFUN2); /* SPICL0 */
198:
199: bus_space_write_4(iot, gpioh, GPIO_PECON, pecon);
200: }
201: else {
202: pgcon = bus_space_read_4(iot, gpioh, GPIO_PGCON);
203:
204: if (use_ss)
205: pgcon = GPIO_SET_FUNC(pgcon, 3, PCON_ALTFUN2);
206:
207: pgcon = GPIO_SET_FUNC(pgcon, 5, PCON_ALTFUN2); /* SPIMISO1 */
208: pgcon = GPIO_SET_FUNC(pgcon, 6, PCON_ALTFUN2); /* SPIMOSI1 */
209: pgcon = GPIO_SET_FUNC(pgcon, 7, PCON_ALTFUN2); /* SPICLK1 */
210:
211: bus_space_write_4(iot, gpioh, GPIO_PGCON, pgcon);
212: }
213:
214: bus_space_write_4(iot, sc->ioh, SPI_SPCON, mode);
215:
216: return 0;
217: }
CVSweb