wzero3_ssp.c revision 1.1 1 /* $NetBSD: wzero3_ssp.c,v 1.1 2010/05/09 10:40:00 nonaka Exp $ */
2
3 /*
4 * Copyright (c) 2010 NONAKA Kimihiro <nonaka (at) netbsd.org>
5 * All rights reserved.
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wzero3_ssp.c,v 1.1 2010/05/09 10:40:00 nonaka Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/mutex.h>
36 #include <sys/pmf.h>
37 #include <sys/bus.h>
38
39 #include <machine/bootinfo.h>
40 #include <machine/platid.h>
41 #include <machine/platid_mask.h>
42
43 #include <arm/xscale/pxa2x0reg.h>
44 #include <arm/xscale/pxa2x0var.h>
45 #include <arm/xscale/pxa2x0_gpio.h>
46
47 #include <hpcarm/dev/wzero3_reg.h>
48 #include <hpcarm/dev/wzero3_sspvar.h>
49
50 #define WS007SH_SSCR0_ADS7846 0x06ab /* 12bit/Microwire/div by 7 */
51
52 struct wzero3ssp_softc {
53 device_t sc_dev;
54 bus_space_tag_t sc_iot;
55 bus_space_handle_t sc_ioh;
56 kmutex_t sc_mtx;
57 };
58
59 static int wzero3ssp_match(device_t, cfdata_t, void *);
60 static void wzero3ssp_attach(device_t, device_t, void *);
61
62 CFATTACH_DECL_NEW(wzero3ssp, sizeof(struct wzero3ssp_softc),
63 wzero3ssp_match, wzero3ssp_attach, NULL, NULL);
64
65 static void wzero3ssp_init(struct wzero3ssp_softc *);
66 static bool wzero3ssp_resume(device_t dv, const pmf_qual_t *);
67 static uint32_t wzero3ssp_read_ads7846(uint32_t);
68
69 static struct wzero3ssp_softc *wzero3ssp_sc;
70
71 static const struct wzero3ssp_model {
72 platid_mask_t *platid;
73 } wzero3ssp_table[] = {
74 #if 0
75 /* WS003SH */
76 {
77 &platid_mask_MACH_SHARP_WZERO3_WS003SH,
78 },
79 /* WS004SH */
80 {
81 &platid_mask_MACH_SHARP_WZERO3_WS004SH,
82 },
83 #endif
84 /* WS007SH */
85 {
86 &platid_mask_MACH_SHARP_WZERO3_WS007SH,
87 },
88 #if 0
89 /* WS011SH */
90 {
91 &platid_mask_MACH_SHARP_WZERO3_WS011SH,
92 },
93 /* WS0020H */
94 {
95 &platid_mask_MACH_SHARP_WZERO3_WS020SH,
96 },
97 #endif
98 {
99 NULL,
100 },
101 };
102
103 static const struct wzero3ssp_model *
104 wzero3ssp_lookup(void)
105 {
106 const struct wzero3ssp_model *model;
107
108 for (model = wzero3ssp_table; model->platid != NULL; model++) {
109 if (platid_match(&platid, model->platid)) {
110 return model;
111 }
112 }
113 return NULL;
114 }
115
116 static int
117 wzero3ssp_match(device_t parent, cfdata_t cf, void *aux)
118 {
119
120 if (strcmp(cf->cf_name, "wzero3ssp") != 0)
121 return 0;
122 if (wzero3ssp_lookup() == NULL)
123 return 0;
124 if (wzero3ssp_sc != NULL)
125 return 0;
126 return 1;
127 }
128
129 static void
130 wzero3ssp_attach(device_t parent, device_t self, void *aux)
131 {
132 struct wzero3ssp_softc *sc = device_private(self);
133
134 sc->sc_dev = self;
135 wzero3ssp_sc = sc;
136
137 aprint_normal("\n");
138 aprint_naive("\n");
139
140 mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_TTY);
141
142 sc->sc_iot = &pxa2x0_bs_tag;
143 if (bus_space_map(sc->sc_iot, PXA2X0_SSP1_BASE, PXA2X0_SSP_SIZE, 0,
144 &sc->sc_ioh)) {
145 aprint_error_dev(sc->sc_dev, "can't map bus space\n");
146 return;
147 }
148
149 if (!pmf_device_register(sc->sc_dev, NULL, wzero3ssp_resume))
150 aprint_error_dev(sc->sc_dev,
151 "couldn't establish power handler\n");
152
153 wzero3ssp_init(sc);
154 }
155
156 /*
157 * Initialize the dedicated SSP unit and disable all chip selects.
158 * This function is called with interrupts disabled.
159 */
160 static void
161 wzero3ssp_init(struct wzero3ssp_softc *sc)
162 {
163
164 pxa2x0_clkman_config(CKEN_SSP, 1);
165
166 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
167 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR1, 0);
168
169 pxa2x0_gpio_set_function(GPIO_WS007SH_ADS7846_CS, GPIO_OUT|GPIO_SET);
170 }
171
172 static bool
173 wzero3ssp_resume(device_t dv, const pmf_qual_t *qual)
174 {
175 struct wzero3ssp_softc *sc = device_private(dv);
176
177 mutex_enter(&sc->sc_mtx);
178 wzero3ssp_init(sc);
179 mutex_exit(&sc->sc_mtx);
180
181 return true;
182 }
183
184 /*
185 * Transmit a single data word to one of the ICs, keep the chip selected
186 * afterwards, and don't wait for data to be returned in SSDR. Interrupts
187 * must be held off until wzero3ssp_ic_stop() gets called.
188 */
189 void
190 wzero3ssp_ic_start(int ic, uint32_t cmd)
191 {
192 struct wzero3ssp_softc *sc;
193
194 KASSERT(wzero3ssp_sc != NULL);
195 sc = wzero3ssp_sc;
196
197 mutex_enter(&sc->sc_mtx);
198
199 /* disable other ICs */
200 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
201 if (ic != WZERO3_SSP_IC_ADS7846)
202 pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
203
204 /* activate the chosen one */
205 switch (ic) {
206 case WZERO3_SSP_IC_ADS7846:
207 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
208 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
209 WS007SH_SSCR0_ADS7846);
210 pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
211 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
212 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
213 & SSSR_TNF) != SSSR_TNF)
214 continue; /* poll */
215 break;
216 }
217 }
218
219 /*
220 * Read the last value from SSDR and deactivate all chip-selects.
221 */
222 uint32_t
223 wzero3ssp_ic_stop(int ic)
224 {
225 struct wzero3ssp_softc *sc;
226 uint32_t rv;
227
228 KASSERT(wzero3ssp_sc != NULL);
229 sc = wzero3ssp_sc;
230
231 switch (ic) {
232 case WZERO3_SSP_IC_ADS7846:
233 /* read result of last command */
234 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
235 & SSSR_RNE) != SSSR_RNE)
236 continue; /* poll */
237 rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
238 break;
239 default:
240 rv = 0;
241 break;
242 }
243
244 pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
245
246 mutex_exit(&sc->sc_mtx);
247
248 return rv;
249 }
250
251 /*
252 * Activate one of the chip-select lines, transmit one word value in
253 * each direction, and deactivate the chip-select again.
254 */
255 uint32_t
256 wzero3ssp_ic_send(int ic, uint32_t data)
257 {
258
259 switch (ic) {
260 case WZERO3_SSP_IC_ADS7846:
261 return wzero3ssp_read_ads7846(data);
262 default:
263 aprint_error("wzero3ssp: wzero3ssp_ic_send: invalid IC %d\n", ic);
264 return 0;
265 }
266 }
267
268 static uint32_t
269 wzero3ssp_read_ads7846(uint32_t cmd)
270 {
271 struct wzero3ssp_softc *sc;
272 uint32_t rv;
273
274 if (wzero3ssp_sc == NULL) {
275 printf("wzero3ssp_read_ads7846: not configured\n");
276 return 0;
277 }
278 sc = wzero3ssp_sc;
279
280 mutex_enter(&sc->sc_mtx);
281
282 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
283 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
284 WS007SH_SSCR0_ADS7846);
285
286 pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
287
288 /* send cmd */
289 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
290 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
291 & SSSR_TNF) != SSSR_TNF)
292 continue; /* poll */
293 delay(1);
294 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
295 & SSSR_RNE) != SSSR_RNE)
296 continue; /* poll */
297 rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
298
299 pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
300
301 mutex_exit(&sc->sc_mtx);
302
303 return rv;
304 }
305