1*c7fb772bSthorpej /* $NetBSD: zssp.c,v 1.15 2021/08/07 16:19:08 thorpej Exp $ */
2953d3b5bSober /* $OpenBSD: zaurus_ssp.c,v 1.6 2005/04/08 21:58:49 uwe Exp $ */
3953d3b5bSober
4953d3b5bSober /*
5953d3b5bSober * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
6953d3b5bSober *
7953d3b5bSober * Permission to use, copy, modify, and distribute this software for any
8953d3b5bSober * purpose with or without fee is hereby granted, provided that the above
9953d3b5bSober * copyright notice and this permission notice appear in all copies.
10953d3b5bSober *
11953d3b5bSober * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12953d3b5bSober * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13953d3b5bSober * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14953d3b5bSober * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15953d3b5bSober * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16953d3b5bSober * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17953d3b5bSober * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18953d3b5bSober */
19953d3b5bSober
20953d3b5bSober #include <sys/cdefs.h>
21*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: zssp.c,v 1.15 2021/08/07 16:19:08 thorpej Exp $");
22953d3b5bSober
23953d3b5bSober #include <sys/param.h>
24953d3b5bSober #include <sys/systm.h>
25953d3b5bSober #include <sys/device.h>
265410d577Sdyoung #include <sys/bus.h>
27953d3b5bSober
28953d3b5bSober #include <arm/xscale/pxa2x0reg.h>
29953d3b5bSober #include <arm/xscale/pxa2x0var.h>
30953d3b5bSober #include <arm/xscale/pxa2x0_gpio.h>
31953d3b5bSober
32953d3b5bSober #include <zaurus/dev/zsspvar.h>
33953d3b5bSober #include <zaurus/zaurus/zaurus_var.h>
34953d3b5bSober
35953d3b5bSober #define GPIO_ADS7846_CS_C3000 14 /* SSP SFRM */
36953d3b5bSober #define GPIO_MAX1111_CS_C3000 20
37953d3b5bSober #define GPIO_TG_CS_C3000 53
38533071c4Stsutsui #define GPIO_ADS7846_CS_C860 24 /* SSP SFRM */
39533071c4Stsutsui #define GPIO_MAX1111_CS_C860 20
40533071c4Stsutsui #define GPIO_TG_CS_C860 19
41953d3b5bSober
42fa07193fSnonaka #define SSCR0_ADS7846_C3000 0x06ab /* 12bit/Microwire/div by 7 */
43953d3b5bSober #define SSCR0_MAX1111 0x0387
44fa07193fSnonaka #define SSCR0_LZ9JG18 0x01ab
45533071c4Stsutsui #define SSCR0_ADS7846_C860 0x00ab /* 12bit/Microwire/div by 7 */
46533071c4Stsutsui
47533071c4Stsutsui struct zssp_ads7846 {
48533071c4Stsutsui u_int gpio;
49533071c4Stsutsui uint32_t sscr0;
50533071c4Stsutsui };
51533071c4Stsutsui struct zssp_max1111 {
52533071c4Stsutsui u_int gpio;
53533071c4Stsutsui uint32_t sscr0;
54533071c4Stsutsui };
55533071c4Stsutsui struct zssp_lz9jg18 {
56533071c4Stsutsui u_int gpio;
57533071c4Stsutsui uint32_t sscr0;
58533071c4Stsutsui int sclk_pin;
59533071c4Stsutsui int sfrm_pin;
60533071c4Stsutsui int txd_pin;
61533071c4Stsutsui int rxd_pin;
62533071c4Stsutsui };
63953d3b5bSober
64953d3b5bSober struct zssp_softc {
651a686006Snonaka device_t sc_dev;
66953d3b5bSober bus_space_tag_t sc_iot;
67953d3b5bSober bus_space_handle_t sc_ioh;
68533071c4Stsutsui bus_addr_t sc_ssp;
69533071c4Stsutsui struct zssp_ads7846 ads7846;
70533071c4Stsutsui struct zssp_max1111 max1111;
71533071c4Stsutsui struct zssp_lz9jg18 lz9jg18;
72953d3b5bSober };
73953d3b5bSober
741a686006Snonaka static int zssp_match(device_t, cfdata_t, void *);
751a686006Snonaka static void zssp_attach(device_t, device_t, void *);
766145ba81Stsutsui static int zssp_search(device_t, cfdata_t, const int *, void *);
776145ba81Stsutsui static int zssp_print(void *, const char *);
78953d3b5bSober
791a686006Snonaka CFATTACH_DECL_NEW(zssp, sizeof(struct zssp_softc),
80953d3b5bSober zssp_match, zssp_attach, NULL, NULL);
81953d3b5bSober
82fa07193fSnonaka static void zssp_init(void);
83c1b390d4Sdyoung static bool zssp_resume(device_t dv, const pmf_qual_t *);
84fa07193fSnonaka
85fa07193fSnonaka static struct zssp_softc *zssp_sc;
86fa07193fSnonaka
87953d3b5bSober static int
zssp_match(device_t parent,cfdata_t cf,void * aux)881a686006Snonaka zssp_match(device_t parent, cfdata_t cf, void *aux)
89953d3b5bSober {
90953d3b5bSober
91fa07193fSnonaka if (zssp_sc != NULL)
92fa07193fSnonaka return 0;
93953d3b5bSober return 1;
94953d3b5bSober }
95953d3b5bSober
96953d3b5bSober static void
zssp_attach(device_t parent,device_t self,void * aux)971a686006Snonaka zssp_attach(device_t parent, device_t self, void *aux)
98953d3b5bSober {
991a686006Snonaka struct zssp_softc *sc = device_private(self);
1001a686006Snonaka
1011a686006Snonaka sc->sc_dev = self;
1021a686006Snonaka zssp_sc = sc;
1031a686006Snonaka
1041a686006Snonaka aprint_normal("\n");
1051a686006Snonaka aprint_naive("\n");
106953d3b5bSober
107953d3b5bSober sc->sc_iot = &pxa2x0_bs_tag;
108533071c4Stsutsui if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
109533071c4Stsutsui sc->sc_ssp = PXA2X0_SSP1_BASE;
110533071c4Stsutsui sc->ads7846.gpio = GPIO_ADS7846_CS_C3000;
111533071c4Stsutsui sc->ads7846.sscr0 = SSCR0_ADS7846_C3000;
112533071c4Stsutsui sc->max1111.gpio = GPIO_MAX1111_CS_C3000;
113533071c4Stsutsui sc->max1111.sscr0 = SSCR0_MAX1111;
114533071c4Stsutsui sc->lz9jg18.gpio = GPIO_TG_CS_C3000;
115533071c4Stsutsui sc->lz9jg18.sscr0 = SSCR0_LZ9JG18;
116533071c4Stsutsui sc->lz9jg18.sclk_pin = 19;
117533071c4Stsutsui sc->lz9jg18.sfrm_pin = 14;
118533071c4Stsutsui sc->lz9jg18.txd_pin = 87;
119533071c4Stsutsui sc->lz9jg18.rxd_pin = 86;
120533071c4Stsutsui } else {
121533071c4Stsutsui sc->sc_ssp = PXA2X0_SSP_BASE;
122533071c4Stsutsui sc->ads7846.gpio = GPIO_ADS7846_CS_C860;
123533071c4Stsutsui sc->ads7846.sscr0 = SSCR0_ADS7846_C860;
124533071c4Stsutsui sc->max1111.gpio = GPIO_MAX1111_CS_C860;
125533071c4Stsutsui sc->max1111.sscr0 = SSCR0_MAX1111;
126533071c4Stsutsui sc->lz9jg18.gpio = GPIO_TG_CS_C860;
127533071c4Stsutsui sc->lz9jg18.sscr0 = SSCR0_LZ9JG18;
128533071c4Stsutsui sc->lz9jg18.sclk_pin = 23;
129533071c4Stsutsui sc->lz9jg18.sfrm_pin = 24;
130533071c4Stsutsui sc->lz9jg18.txd_pin = 25;
131533071c4Stsutsui sc->lz9jg18.rxd_pin = 26;
132533071c4Stsutsui }
133533071c4Stsutsui
134533071c4Stsutsui if (bus_space_map(sc->sc_iot, sc->sc_ssp, PXA2X0_SSP_SIZE,
135953d3b5bSober 0, &sc->sc_ioh)) {
1361a686006Snonaka aprint_error_dev(sc->sc_dev, "can't map bus space\n");
137953d3b5bSober return;
138953d3b5bSober }
139953d3b5bSober
140664df27bSnonaka if (!pmf_device_register(sc->sc_dev, NULL, zssp_resume))
141664df27bSnonaka aprint_error_dev(sc->sc_dev,
142664df27bSnonaka "couldn't establish power handler\n");
143953d3b5bSober
144953d3b5bSober zssp_init();
1456145ba81Stsutsui
1466145ba81Stsutsui /* Attach all devices */
1472685996bSthorpej config_search(self, NULL,
148*c7fb772bSthorpej CFARGS(.search = zssp_search));
1496145ba81Stsutsui }
1506145ba81Stsutsui
1516145ba81Stsutsui static int
zssp_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)1526145ba81Stsutsui zssp_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
1536145ba81Stsutsui {
1546145ba81Stsutsui struct zssp_attach_args aa;
1556145ba81Stsutsui
1566145ba81Stsutsui aa.zaa_name = cf->cf_name;
1576145ba81Stsutsui
1582685996bSthorpej if (config_probe(parent, cf, &aa))
159*c7fb772bSthorpej config_attach(parent, cf, &aa, zssp_print, CFARGS_NONE);
1606145ba81Stsutsui
1616145ba81Stsutsui return 0;
1626145ba81Stsutsui }
1636145ba81Stsutsui
1646145ba81Stsutsui static int
zssp_print(void * aux,const char * name)1656145ba81Stsutsui zssp_print(void *aux, const char *name)
1666145ba81Stsutsui {
1676145ba81Stsutsui
1686145ba81Stsutsui return UNCONF;
169953d3b5bSober }
170953d3b5bSober
171953d3b5bSober /*
172953d3b5bSober * Initialize the dedicated SSP unit and disable all chip selects.
173953d3b5bSober * This function is called with interrupts disabled.
174953d3b5bSober */
175953d3b5bSober static void
zssp_init(void)176953d3b5bSober zssp_init(void)
177953d3b5bSober {
178953d3b5bSober struct zssp_softc *sc;
179953d3b5bSober
1806145ba81Stsutsui if (__predict_false(zssp_sc == NULL)) {
1816145ba81Stsutsui aprint_error("%s: not configured.\n", __func__);
1826145ba81Stsutsui return;
1836145ba81Stsutsui }
184fa07193fSnonaka sc = zssp_sc;
185953d3b5bSober
186953d3b5bSober pxa2x0_clkman_config(CKEN_SSP, 1);
187953d3b5bSober
188533071c4Stsutsui bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, sc->lz9jg18.sscr0);
189953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR1, 0);
190953d3b5bSober
191533071c4Stsutsui pxa2x0_gpio_set_function(sc->ads7846.gpio, GPIO_OUT|GPIO_SET);
192533071c4Stsutsui pxa2x0_gpio_set_function(sc->max1111.gpio, GPIO_OUT|GPIO_SET);
193533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.gpio, GPIO_OUT|GPIO_SET);
194953d3b5bSober }
195953d3b5bSober
196664df27bSnonaka static bool
zssp_resume(device_t dv,const pmf_qual_t * qual)197c1b390d4Sdyoung zssp_resume(device_t dv, const pmf_qual_t *qual)
198953d3b5bSober {
199953d3b5bSober int s;
200953d3b5bSober
201953d3b5bSober s = splhigh();
202953d3b5bSober zssp_init();
203953d3b5bSober splx(s);
204664df27bSnonaka
205664df27bSnonaka return true;
206953d3b5bSober }
207953d3b5bSober
208953d3b5bSober /*
209953d3b5bSober * Transmit a single data word to one of the ICs, keep the chip selected
210953d3b5bSober * afterwards, and don't wait for data to be returned in SSDR. Interrupts
211953d3b5bSober * must be held off until zssp_ic_stop() gets called.
212953d3b5bSober */
213953d3b5bSober void
zssp_ic_start(int ic,uint32_t data)214953d3b5bSober zssp_ic_start(int ic, uint32_t data)
215953d3b5bSober {
216953d3b5bSober struct zssp_softc *sc;
217953d3b5bSober
2186145ba81Stsutsui if (__predict_false(zssp_sc == NULL)) {
2196145ba81Stsutsui aprint_error("%s: not configured.\n", __func__);
2206145ba81Stsutsui return;
2216145ba81Stsutsui }
222fa07193fSnonaka sc = zssp_sc;
223953d3b5bSober
224953d3b5bSober /* disable other ICs */
225953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
226953d3b5bSober if (ic != ZSSP_IC_ADS7846)
227533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
228953d3b5bSober if (ic != ZSSP_IC_LZ9JG18)
229533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
230953d3b5bSober if (ic != ZSSP_IC_MAX1111)
231533071c4Stsutsui pxa2x0_gpio_set_bit(sc->max1111.gpio);
232953d3b5bSober
233953d3b5bSober /* activate the chosen one */
234953d3b5bSober switch (ic) {
235953d3b5bSober case ZSSP_IC_ADS7846:
236953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
237533071c4Stsutsui sc->ads7846.sscr0);
238533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->ads7846.gpio);
239533071c4Stsutsui delay(1); /* ADS7846 Tcss = 100ns */
240953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, data);
241953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
242953d3b5bSober & SSSR_TNF) != SSSR_TNF)
243953d3b5bSober continue; /* poll */
244953d3b5bSober break;
245953d3b5bSober case ZSSP_IC_LZ9JG18:
246533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->lz9jg18.gpio);
247953d3b5bSober break;
248953d3b5bSober case ZSSP_IC_MAX1111:
249533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->max1111.gpio);
250953d3b5bSober break;
251953d3b5bSober }
252953d3b5bSober }
253953d3b5bSober
254953d3b5bSober /*
255953d3b5bSober * Read the last value from SSDR and deactivate all chip-selects.
256953d3b5bSober */
257953d3b5bSober uint32_t
zssp_ic_stop(int ic)258953d3b5bSober zssp_ic_stop(int ic)
259953d3b5bSober {
260953d3b5bSober struct zssp_softc *sc;
261953d3b5bSober uint32_t rv;
262953d3b5bSober
2636145ba81Stsutsui if (__predict_false(zssp_sc == NULL)) {
2646145ba81Stsutsui aprint_error("%s: not configured.\n", __func__);
2656145ba81Stsutsui return 0;
2666145ba81Stsutsui }
267fa07193fSnonaka sc = zssp_sc;
268953d3b5bSober
269953d3b5bSober switch (ic) {
270953d3b5bSober case ZSSP_IC_ADS7846:
271953d3b5bSober /* read result of last command */
272953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
273953d3b5bSober & SSSR_RNE) != SSSR_RNE)
274953d3b5bSober continue; /* poll */
275953d3b5bSober rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
276953d3b5bSober break;
277953d3b5bSober case ZSSP_IC_LZ9JG18:
278953d3b5bSober case ZSSP_IC_MAX1111:
279953d3b5bSober /* last value received is irrelevant or undefined */
280953d3b5bSober default:
281953d3b5bSober rv = 0;
282953d3b5bSober break;
283953d3b5bSober }
284953d3b5bSober
285533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
286533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
287533071c4Stsutsui pxa2x0_gpio_set_bit(sc->max1111.gpio);
288953d3b5bSober
289953d3b5bSober return rv;
290953d3b5bSober }
291953d3b5bSober
292953d3b5bSober /*
293953d3b5bSober * Activate one of the chip-select lines, transmit one word value in
294953d3b5bSober * each direction, and deactivate the chip-select again.
295953d3b5bSober */
296953d3b5bSober uint32_t
zssp_ic_send(int ic,uint32_t data)297953d3b5bSober zssp_ic_send(int ic, uint32_t data)
298953d3b5bSober {
299953d3b5bSober
300953d3b5bSober switch (ic) {
301953d3b5bSober case ZSSP_IC_MAX1111:
302953d3b5bSober return (zssp_read_max1111(data));
303953d3b5bSober case ZSSP_IC_ADS7846:
304953d3b5bSober return (zssp_read_ads7846(data));
305953d3b5bSober case ZSSP_IC_LZ9JG18:
306953d3b5bSober zssp_write_lz9jg18(data);
307953d3b5bSober return 0;
308953d3b5bSober default:
3095990ab68Snonaka aprint_error("zssp: zssp_ic_send: invalid IC %d\n", ic);
310953d3b5bSober return 0;
311953d3b5bSober }
312953d3b5bSober }
313953d3b5bSober
314953d3b5bSober int
zssp_read_max1111(uint32_t cmd)315953d3b5bSober zssp_read_max1111(uint32_t cmd)
316953d3b5bSober {
317953d3b5bSober struct zssp_softc *sc;
3182dfa5fffSnonaka int data[3];
3192dfa5fffSnonaka int voltage[3]; /* voltage[0]: dummy */
320953d3b5bSober int i;
321953d3b5bSober int s;
322953d3b5bSober
3236145ba81Stsutsui if (__predict_false(zssp_sc == NULL)) {
3246145ba81Stsutsui aprint_error("%s: not configured.\n", __func__);
3256145ba81Stsutsui return 0;
3266145ba81Stsutsui }
327fa07193fSnonaka sc = zssp_sc;
328953d3b5bSober
329953d3b5bSober s = splhigh();
330953d3b5bSober
331953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
332533071c4Stsutsui bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, sc->max1111.sscr0);
333953d3b5bSober
334533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
335533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
336533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->max1111.gpio);
337953d3b5bSober
338953d3b5bSober delay(1);
339953d3b5bSober
3402dfa5fffSnonaka memset(data, 0, sizeof(data));
3412dfa5fffSnonaka data[0] = cmd;
3422dfa5fffSnonaka for (i = 0; i < __arraycount(data); i++) {
3432dfa5fffSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, data[i]);
344953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
345953d3b5bSober & SSSR_TNF) != SSSR_TNF)
346953d3b5bSober continue; /* poll */
347953d3b5bSober /* XXX is this delay necessary? */
348953d3b5bSober delay(1);
349953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
350953d3b5bSober & SSSR_RNE) != SSSR_RNE)
351953d3b5bSober continue; /* poll */
352953d3b5bSober voltage[i] = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
353953d3b5bSober SSP_SSDR);
354953d3b5bSober }
355953d3b5bSober
356533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
357533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
358533071c4Stsutsui pxa2x0_gpio_set_bit(sc->max1111.gpio);
359953d3b5bSober
360953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
361953d3b5bSober
362953d3b5bSober splx(s);
363953d3b5bSober
364953d3b5bSober /* XXX no idea what this means, but it's what Linux would do. */
3652dfa5fffSnonaka if ((voltage[1] & 0xc0) != 0 || (voltage[2] & 0x3f) != 0)
3662dfa5fffSnonaka return -1;
3672dfa5fffSnonaka return ((voltage[1] << 2) & 0xfc) | ((voltage[2] >> 6) & 0x03);
368953d3b5bSober }
369953d3b5bSober
370953d3b5bSober /* XXX - only does CS_ADS7846 */
371953d3b5bSober uint32_t
zssp_read_ads7846(uint32_t cmd)372953d3b5bSober zssp_read_ads7846(uint32_t cmd)
373953d3b5bSober {
374953d3b5bSober struct zssp_softc *sc;
375953d3b5bSober uint32_t val;
376fa07193fSnonaka int s;
377953d3b5bSober
3786145ba81Stsutsui if (__predict_false(zssp_sc == NULL)) {
3796145ba81Stsutsui aprint_error("%s: not configured\n", __func__);
380953d3b5bSober return 0;
381953d3b5bSober }
382fa07193fSnonaka sc = zssp_sc;
383953d3b5bSober
384953d3b5bSober s = splhigh();
385fa07193fSnonaka
386953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
387533071c4Stsutsui bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, sc->ads7846.sscr0);
388953d3b5bSober
389533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
390533071c4Stsutsui pxa2x0_gpio_set_bit(sc->max1111.gpio);
391533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->ads7846.gpio);
392533071c4Stsutsui delay(1); /* ADS7846 Tcss = 100ns */
393953d3b5bSober
394953d3b5bSober bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
395953d3b5bSober
396953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
397953d3b5bSober & SSSR_TNF) != SSSR_TNF)
398953d3b5bSober continue; /* poll */
399953d3b5bSober
400953d3b5bSober delay(1);
401953d3b5bSober
402953d3b5bSober while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
403953d3b5bSober & SSSR_RNE) != SSSR_RNE)
404953d3b5bSober continue; /* poll */
405953d3b5bSober
406953d3b5bSober val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
407953d3b5bSober
408533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
409953d3b5bSober
410953d3b5bSober splx(s);
411953d3b5bSober
412953d3b5bSober return val;
413953d3b5bSober }
414953d3b5bSober
415953d3b5bSober void
zssp_write_lz9jg18(uint32_t data)416953d3b5bSober zssp_write_lz9jg18(uint32_t data)
417953d3b5bSober {
418533071c4Stsutsui struct zssp_softc *sc;
419533071c4Stsutsui int sclk_fn;
420533071c4Stsutsui int sfrm_fn;
421533071c4Stsutsui int txd_fn;
422533071c4Stsutsui int rxd_fn;
423953d3b5bSober int i;
424fa07193fSnonaka int s;
425953d3b5bSober
426533071c4Stsutsui KASSERT(zssp_sc != NULL);
427533071c4Stsutsui sc = zssp_sc;
428533071c4Stsutsui
429953d3b5bSober /* XXX this creates a DAC command from a backlight duty value. */
430953d3b5bSober data = 0x40 | (data & 0x1f);
431953d3b5bSober
432953d3b5bSober s = splhigh();
433953d3b5bSober
434533071c4Stsutsui sclk_fn = pxa2x0_gpio_get_function(sc->lz9jg18.sclk_pin);
435533071c4Stsutsui sfrm_fn = pxa2x0_gpio_get_function(sc->lz9jg18.sfrm_pin);
436533071c4Stsutsui txd_fn = pxa2x0_gpio_get_function(sc->lz9jg18.txd_pin);
437533071c4Stsutsui rxd_fn = pxa2x0_gpio_get_function(sc->lz9jg18.rxd_pin);
438953d3b5bSober
439533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.sfrm_pin, GPIO_OUT | GPIO_SET);
440533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.sclk_pin, GPIO_OUT | GPIO_CLR);
441533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.txd_pin, GPIO_OUT | GPIO_CLR);
442533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.rxd_pin, GPIO_IN);
443953d3b5bSober
444533071c4Stsutsui pxa2x0_gpio_set_bit(sc->max1111.gpio);
445533071c4Stsutsui pxa2x0_gpio_set_bit(sc->ads7846.gpio);
446533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->lz9jg18.gpio);
447953d3b5bSober
448953d3b5bSober delay(10);
449953d3b5bSober
450953d3b5bSober for (i = 0; i < 8; i++) {
451953d3b5bSober if (data & 0x80)
452533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.txd_pin);
453953d3b5bSober else
454533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->lz9jg18.txd_pin);
455953d3b5bSober delay(10);
456533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.sclk_pin);
457953d3b5bSober delay(10);
458533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->lz9jg18.sclk_pin);
459953d3b5bSober delay(10);
460953d3b5bSober data <<= 1;
461953d3b5bSober }
462953d3b5bSober
463533071c4Stsutsui pxa2x0_gpio_clear_bit(sc->lz9jg18.txd_pin);
464533071c4Stsutsui pxa2x0_gpio_set_bit(sc->lz9jg18.gpio);
465953d3b5bSober
466533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.sclk_pin, sclk_fn);
467533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.sfrm_pin, sfrm_fn);
468533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.txd_pin, txd_fn);
469533071c4Stsutsui pxa2x0_gpio_set_function(sc->lz9jg18.rxd_pin, rxd_fn);
470953d3b5bSober
471953d3b5bSober splx(s);
472953d3b5bSober }
473