1*2388feefSnonaka /* $NetBSD: wzero3_ssp.c,v 1.5 2012/01/21 19:44:29 nonaka Exp $ */
22f41d35dSnonaka
3*2388feefSnonaka /*-
4*2388feefSnonaka * Copyright (C) 2010 NONAKA Kimihiro <nonaka@netbsd.org>
52f41d35dSnonaka * All rights reserved.
62f41d35dSnonaka *
72f41d35dSnonaka * Redistribution and use in source and binary forms, with or without
82f41d35dSnonaka * modification, are permitted provided that the following conditions
92f41d35dSnonaka * are met:
102f41d35dSnonaka * 1. Redistributions of source code must retain the above copyright
112f41d35dSnonaka * notice, this list of conditions and the following disclaimer.
122f41d35dSnonaka * 2. Redistributions in binary form must reproduce the above copyright
132f41d35dSnonaka * notice, this list of conditions and the following disclaimer in the
142f41d35dSnonaka * documentation and/or other materials provided with the distribution.
152f41d35dSnonaka *
16*2388feefSnonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*2388feefSnonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*2388feefSnonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*2388feefSnonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*2388feefSnonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*2388feefSnonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*2388feefSnonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*2388feefSnonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*2388feefSnonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*2388feefSnonaka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262f41d35dSnonaka */
272f41d35dSnonaka
282f41d35dSnonaka #include <sys/cdefs.h>
29*2388feefSnonaka __KERNEL_RCSID(0, "$NetBSD: wzero3_ssp.c,v 1.5 2012/01/21 19:44:29 nonaka Exp $");
302f41d35dSnonaka
312f41d35dSnonaka #include <sys/param.h>
322f41d35dSnonaka #include <sys/systm.h>
332f41d35dSnonaka #include <sys/device.h>
342f41d35dSnonaka #include <sys/mutex.h>
352f41d35dSnonaka #include <sys/pmf.h>
362f41d35dSnonaka #include <sys/bus.h>
372f41d35dSnonaka
382f41d35dSnonaka #include <machine/bootinfo.h>
392f41d35dSnonaka #include <machine/platid.h>
402f41d35dSnonaka #include <machine/platid_mask.h>
412f41d35dSnonaka
422f41d35dSnonaka #include <arm/xscale/pxa2x0reg.h>
432f41d35dSnonaka #include <arm/xscale/pxa2x0var.h>
442f41d35dSnonaka #include <arm/xscale/pxa2x0_gpio.h>
452f41d35dSnonaka
462f41d35dSnonaka #include <hpcarm/dev/wzero3_reg.h>
472f41d35dSnonaka #include <hpcarm/dev/wzero3_sspvar.h>
482f41d35dSnonaka
4912cd5caeSnonaka #define WS003SH_SSCR0_MAX1233 0x0000048f /* 16bit/SPI/div by 5 */
5012cd5caeSnonaka #define WS007SH_SSCR0_ADS7846 0x000006ab /* 12bit/Microwire/div by 7 */
514071f150Snonaka #define WS011SH_SSCR0_AK4184_TP 0x0010068f /* 32bit/SPI/div by 7 */
529f093235Snonaka #define WS011SH_SSCR0_AK4184_KEYPAD 0x0000068f /* 16bit/SPI/div by 7 */
532f41d35dSnonaka
5412cd5caeSnonaka struct wzero3ssp_model;
552f41d35dSnonaka struct wzero3ssp_softc {
562f41d35dSnonaka device_t sc_dev;
572f41d35dSnonaka bus_space_tag_t sc_iot;
582f41d35dSnonaka bus_space_handle_t sc_ioh;
592f41d35dSnonaka kmutex_t sc_mtx;
6012cd5caeSnonaka const struct wzero3ssp_model *sc_model;
612f41d35dSnonaka };
622f41d35dSnonaka
632f41d35dSnonaka static int wzero3ssp_match(device_t, cfdata_t, void *);
642f41d35dSnonaka static void wzero3ssp_attach(device_t, device_t, void *);
652f41d35dSnonaka
662f41d35dSnonaka CFATTACH_DECL_NEW(wzero3ssp, sizeof(struct wzero3ssp_softc),
672f41d35dSnonaka wzero3ssp_match, wzero3ssp_attach, NULL, NULL);
682f41d35dSnonaka
692f41d35dSnonaka static void wzero3ssp_init(struct wzero3ssp_softc *);
702f41d35dSnonaka static bool wzero3ssp_resume(device_t dv, const pmf_qual_t *);
7112cd5caeSnonaka static uint32_t wzero3ssp_read_ads7846(struct wzero3ssp_softc *, uint32_t);
7212cd5caeSnonaka static uint32_t wzero3ssp_read_max1233(struct wzero3ssp_softc *, uint32_t,
7312cd5caeSnonaka uint32_t);
749f093235Snonaka static uint32_t wzero3ssp_read_ak4184_tp(struct wzero3ssp_softc *, uint32_t);
759f093235Snonaka static uint16_t wzero3ssp_read_ak4184_keypad(struct wzero3ssp_softc *, uint32_t,
769f093235Snonaka uint32_t);
772f41d35dSnonaka
782f41d35dSnonaka static struct wzero3ssp_softc *wzero3ssp_sc;
792f41d35dSnonaka
802f41d35dSnonaka static const struct wzero3ssp_model {
812f41d35dSnonaka platid_mask_t *platid;
8212cd5caeSnonaka u_long sspaddr;
832f41d35dSnonaka } wzero3ssp_table[] = {
842f41d35dSnonaka /* WS003SH */
852f41d35dSnonaka {
862f41d35dSnonaka &platid_mask_MACH_SHARP_WZERO3_WS003SH,
8712cd5caeSnonaka PXA2X0_SSP2_BASE,
882f41d35dSnonaka },
892f41d35dSnonaka /* WS004SH */
902f41d35dSnonaka {
912f41d35dSnonaka &platid_mask_MACH_SHARP_WZERO3_WS004SH,
9212cd5caeSnonaka PXA2X0_SSP2_BASE,
932f41d35dSnonaka },
942f41d35dSnonaka /* WS007SH */
952f41d35dSnonaka {
962f41d35dSnonaka &platid_mask_MACH_SHARP_WZERO3_WS007SH,
9712cd5caeSnonaka PXA2X0_SSP1_BASE,
982f41d35dSnonaka },
992f41d35dSnonaka /* WS011SH */
1002f41d35dSnonaka {
1012f41d35dSnonaka &platid_mask_MACH_SHARP_WZERO3_WS011SH,
10212cd5caeSnonaka PXA2X0_SSP1_BASE,
1032f41d35dSnonaka },
10412cd5caeSnonaka #if 0
1052f41d35dSnonaka /* WS0020H */
1062f41d35dSnonaka {
1072f41d35dSnonaka &platid_mask_MACH_SHARP_WZERO3_WS020SH,
10812cd5caeSnonaka PXA2X0_SSP1_BASE,
1092f41d35dSnonaka },
1102f41d35dSnonaka #endif
1112f41d35dSnonaka {
11212cd5caeSnonaka NULL, 0,
1132f41d35dSnonaka },
1142f41d35dSnonaka };
1152f41d35dSnonaka
1162f41d35dSnonaka static const struct wzero3ssp_model *
wzero3ssp_lookup(void)1172f41d35dSnonaka wzero3ssp_lookup(void)
1182f41d35dSnonaka {
1192f41d35dSnonaka const struct wzero3ssp_model *model;
1202f41d35dSnonaka
1212f41d35dSnonaka for (model = wzero3ssp_table; model->platid != NULL; model++) {
1222f41d35dSnonaka if (platid_match(&platid, model->platid)) {
1232f41d35dSnonaka return model;
1242f41d35dSnonaka }
1252f41d35dSnonaka }
1262f41d35dSnonaka return NULL;
1272f41d35dSnonaka }
1282f41d35dSnonaka
1292f41d35dSnonaka static int
wzero3ssp_match(device_t parent,cfdata_t cf,void * aux)1302f41d35dSnonaka wzero3ssp_match(device_t parent, cfdata_t cf, void *aux)
1312f41d35dSnonaka {
1322f41d35dSnonaka
1332f41d35dSnonaka if (strcmp(cf->cf_name, "wzero3ssp") != 0)
1342f41d35dSnonaka return 0;
1352f41d35dSnonaka if (wzero3ssp_lookup() == NULL)
1362f41d35dSnonaka return 0;
1372f41d35dSnonaka if (wzero3ssp_sc != NULL)
1382f41d35dSnonaka return 0;
1392f41d35dSnonaka return 1;
1402f41d35dSnonaka }
1412f41d35dSnonaka
1422f41d35dSnonaka static void
wzero3ssp_attach(device_t parent,device_t self,void * aux)1432f41d35dSnonaka wzero3ssp_attach(device_t parent, device_t self, void *aux)
1442f41d35dSnonaka {
1452f41d35dSnonaka struct wzero3ssp_softc *sc = device_private(self);
1462f41d35dSnonaka
1472f41d35dSnonaka sc->sc_dev = self;
1482f41d35dSnonaka wzero3ssp_sc = sc;
1492f41d35dSnonaka
1502f41d35dSnonaka aprint_normal("\n");
1512f41d35dSnonaka aprint_naive("\n");
1522f41d35dSnonaka
15312cd5caeSnonaka sc->sc_model = wzero3ssp_lookup();
15412cd5caeSnonaka if (sc->sc_model == NULL) {
15512cd5caeSnonaka aprint_error_dev(self, "unknown model\n");
15612cd5caeSnonaka return;
15712cd5caeSnonaka }
15812cd5caeSnonaka
1592f41d35dSnonaka mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_TTY);
1602f41d35dSnonaka
1612f41d35dSnonaka sc->sc_iot = &pxa2x0_bs_tag;
16212cd5caeSnonaka if (bus_space_map(sc->sc_iot, sc->sc_model->sspaddr, PXA2X0_SSP_SIZE, 0,
1632f41d35dSnonaka &sc->sc_ioh)) {
1642f41d35dSnonaka aprint_error_dev(sc->sc_dev, "can't map bus space\n");
1652f41d35dSnonaka return;
1662f41d35dSnonaka }
1672f41d35dSnonaka
1682f41d35dSnonaka if (!pmf_device_register(sc->sc_dev, NULL, wzero3ssp_resume))
1692f41d35dSnonaka aprint_error_dev(sc->sc_dev,
1702f41d35dSnonaka "couldn't establish power handler\n");
1712f41d35dSnonaka
1722f41d35dSnonaka wzero3ssp_init(sc);
1732f41d35dSnonaka }
1742f41d35dSnonaka
1752f41d35dSnonaka /*
1762f41d35dSnonaka * Initialize the dedicated SSP unit and disable all chip selects.
1772f41d35dSnonaka * This function is called with interrupts disabled.
1782f41d35dSnonaka */
1792f41d35dSnonaka static void
wzero3ssp_init(struct wzero3ssp_softc * sc)1802f41d35dSnonaka wzero3ssp_init(struct wzero3ssp_softc *sc)
1812f41d35dSnonaka {
1822f41d35dSnonaka
18312cd5caeSnonaka if (sc->sc_model->sspaddr == PXA2X0_SSP1_BASE)
18412cd5caeSnonaka pxa2x0_clkman_config(CKEN_SSP2, 1);
18512cd5caeSnonaka else if (sc->sc_model->sspaddr == PXA2X0_SSP2_BASE)
18612cd5caeSnonaka pxa2x0_clkman_config(CKEN_SSP3, 1);
1872f41d35dSnonaka
1882f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
1892f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR1, 0);
1902f41d35dSnonaka
19112cd5caeSnonaka /* XXX */
19212cd5caeSnonaka if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS003SH)
19312cd5caeSnonaka || platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS004SH)) {
19412cd5caeSnonaka pxa2x0_gpio_set_function(39/*GPIO_WS003SH_XXX*/,
19512cd5caeSnonaka GPIO_OUT|GPIO_SET);
19612cd5caeSnonaka pxa2x0_gpio_set_function(GPIO_WS003SH_MAX1233_CS,
19712cd5caeSnonaka GPIO_OUT|GPIO_SET);
19812cd5caeSnonaka }
19912cd5caeSnonaka if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH)) {
20012cd5caeSnonaka pxa2x0_gpio_set_function(GPIO_WS007SH_ADS7846_CS,
20112cd5caeSnonaka GPIO_OUT|GPIO_SET);
20212cd5caeSnonaka }
2034071f150Snonaka if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH)) {
2044071f150Snonaka pxa2x0_gpio_set_function(GPIO_WS011SH_AK4184_CS,
2054071f150Snonaka GPIO_OUT|GPIO_SET);
2064071f150Snonaka }
2072f41d35dSnonaka }
2082f41d35dSnonaka
2092f41d35dSnonaka static bool
wzero3ssp_resume(device_t dv,const pmf_qual_t * qual)2102f41d35dSnonaka wzero3ssp_resume(device_t dv, const pmf_qual_t *qual)
2112f41d35dSnonaka {
2122f41d35dSnonaka struct wzero3ssp_softc *sc = device_private(dv);
2132f41d35dSnonaka
2142f41d35dSnonaka mutex_enter(&sc->sc_mtx);
2152f41d35dSnonaka wzero3ssp_init(sc);
2162f41d35dSnonaka mutex_exit(&sc->sc_mtx);
2172f41d35dSnonaka
2182f41d35dSnonaka return true;
2192f41d35dSnonaka }
2202f41d35dSnonaka
2212f41d35dSnonaka /*
2222f41d35dSnonaka * Transmit a single data word to one of the ICs, keep the chip selected
2232f41d35dSnonaka * afterwards, and don't wait for data to be returned in SSDR. Interrupts
2242f41d35dSnonaka * must be held off until wzero3ssp_ic_stop() gets called.
2252f41d35dSnonaka */
2262f41d35dSnonaka void
wzero3ssp_ic_start(int ic,uint32_t cmd)2272f41d35dSnonaka wzero3ssp_ic_start(int ic, uint32_t cmd)
2282f41d35dSnonaka {
2292f41d35dSnonaka struct wzero3ssp_softc *sc;
2302f41d35dSnonaka
2312f41d35dSnonaka KASSERT(wzero3ssp_sc != NULL);
2322f41d35dSnonaka sc = wzero3ssp_sc;
2332f41d35dSnonaka
2342f41d35dSnonaka mutex_enter(&sc->sc_mtx);
2352f41d35dSnonaka
2362f41d35dSnonaka /* disable other ICs */
2372f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
2384071f150Snonaka if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH)) {
2392f41d35dSnonaka if (ic != WZERO3_SSP_IC_ADS7846)
2402f41d35dSnonaka pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
2414071f150Snonaka }
2424071f150Snonaka if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH)) {
2439f093235Snonaka if (ic != WZERO3_SSP_IC_AK4184_TP
2449f093235Snonaka && ic != WZERO3_SSP_IC_AK4184_KEYPAD)
2454071f150Snonaka pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
2464071f150Snonaka }
2472f41d35dSnonaka
2482f41d35dSnonaka /* activate the chosen one */
2492f41d35dSnonaka switch (ic) {
2502f41d35dSnonaka case WZERO3_SSP_IC_ADS7846:
2512f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
2522f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
2532f41d35dSnonaka WS007SH_SSCR0_ADS7846);
2542f41d35dSnonaka pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
2552f41d35dSnonaka bus_space_write_1(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
2562f41d35dSnonaka while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
2572f41d35dSnonaka & SSSR_TNF) != SSSR_TNF)
2582f41d35dSnonaka continue; /* poll */
2592f41d35dSnonaka break;
2609f093235Snonaka case WZERO3_SSP_IC_AK4184_TP:
2614071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
2624071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
2634071f150Snonaka WS011SH_SSCR0_AK4184_TP);
2644071f150Snonaka pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
2654071f150Snonaka (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
2664071f150Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
2674071f150Snonaka & SSSR_TNF))
2684071f150Snonaka continue; /* poll */
2694071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd << 16);
2704071f150Snonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
2714071f150Snonaka & SSSR_BUSY)
2724071f150Snonaka continue; /* poll */
2734071f150Snonaka break;
27412cd5caeSnonaka case WZERO3_SSP_IC_MAX1233:
2759f093235Snonaka case WZERO3_SSP_IC_AK4184_KEYPAD:
27612cd5caeSnonaka case WZERO3_SSP_IC_NUM:
27712cd5caeSnonaka default:
27812cd5caeSnonaka break;
2792f41d35dSnonaka }
2802f41d35dSnonaka }
2812f41d35dSnonaka
2822f41d35dSnonaka /*
2832f41d35dSnonaka * Read the last value from SSDR and deactivate all chip-selects.
2842f41d35dSnonaka */
2852f41d35dSnonaka uint32_t
wzero3ssp_ic_stop(int ic)2862f41d35dSnonaka wzero3ssp_ic_stop(int ic)
2872f41d35dSnonaka {
2882f41d35dSnonaka struct wzero3ssp_softc *sc;
2892f41d35dSnonaka uint32_t rv;
2902f41d35dSnonaka
2912f41d35dSnonaka KASSERT(wzero3ssp_sc != NULL);
2922f41d35dSnonaka sc = wzero3ssp_sc;
2932f41d35dSnonaka
2942f41d35dSnonaka switch (ic) {
2952f41d35dSnonaka case WZERO3_SSP_IC_ADS7846:
2962f41d35dSnonaka /* read result of last command */
2972f41d35dSnonaka while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
2982f41d35dSnonaka & SSSR_RNE) != SSSR_RNE)
2992f41d35dSnonaka continue; /* poll */
3002f41d35dSnonaka rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
30112cd5caeSnonaka pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
3022f41d35dSnonaka break;
3039f093235Snonaka case WZERO3_SSP_IC_AK4184_TP:
3044071f150Snonaka /* read result of last command */
3054071f150Snonaka while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
3064071f150Snonaka & SSSR_RNE) != SSSR_RNE)
3074071f150Snonaka continue; /* poll */
3084071f150Snonaka rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
3094071f150Snonaka pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
3104071f150Snonaka break;
31112cd5caeSnonaka case WZERO3_SSP_IC_MAX1233:
3129f093235Snonaka case WZERO3_SSP_IC_AK4184_KEYPAD:
31312cd5caeSnonaka case WZERO3_SSP_IC_NUM:
3142f41d35dSnonaka default:
3152f41d35dSnonaka rv = 0;
3162f41d35dSnonaka break;
3172f41d35dSnonaka }
3182f41d35dSnonaka
3192f41d35dSnonaka mutex_exit(&sc->sc_mtx);
3202f41d35dSnonaka
3212f41d35dSnonaka return rv;
3222f41d35dSnonaka }
3232f41d35dSnonaka
3242f41d35dSnonaka /*
3252f41d35dSnonaka * Activate one of the chip-select lines, transmit one word value in
3262f41d35dSnonaka * each direction, and deactivate the chip-select again.
3272f41d35dSnonaka */
3282f41d35dSnonaka uint32_t
wzero3ssp_ic_send(int ic,uint32_t data,uint32_t data2)32912cd5caeSnonaka wzero3ssp_ic_send(int ic, uint32_t data, uint32_t data2)
3302f41d35dSnonaka {
33112cd5caeSnonaka struct wzero3ssp_softc *sc;
33212cd5caeSnonaka
33312cd5caeSnonaka if (wzero3ssp_sc == NULL) {
33412cd5caeSnonaka aprint_error("%s: not configured\n", __func__);
33512cd5caeSnonaka return 0;
33612cd5caeSnonaka }
33712cd5caeSnonaka sc = wzero3ssp_sc;
3382f41d35dSnonaka
3392f41d35dSnonaka switch (ic) {
3402f41d35dSnonaka case WZERO3_SSP_IC_ADS7846:
34112cd5caeSnonaka return wzero3ssp_read_ads7846(sc, data);
34212cd5caeSnonaka case WZERO3_SSP_IC_MAX1233:
34312cd5caeSnonaka return wzero3ssp_read_max1233(sc, data, data2);
3449f093235Snonaka case WZERO3_SSP_IC_AK4184_TP:
3459f093235Snonaka return wzero3ssp_read_ak4184_tp(sc, data);
3469f093235Snonaka case WZERO3_SSP_IC_AK4184_KEYPAD:
3479f093235Snonaka return wzero3ssp_read_ak4184_keypad(sc, data, data2);
34812cd5caeSnonaka case WZERO3_SSP_IC_NUM:
3492f41d35dSnonaka default:
35012cd5caeSnonaka aprint_error("%s: invalid IC %d\n", __func__, ic);
3512f41d35dSnonaka return 0;
3522f41d35dSnonaka }
3532f41d35dSnonaka }
3542f41d35dSnonaka
3552f41d35dSnonaka static uint32_t
wzero3ssp_read_ads7846(struct wzero3ssp_softc * sc,uint32_t cmd)35612cd5caeSnonaka wzero3ssp_read_ads7846(struct wzero3ssp_softc *sc, uint32_t cmd)
3572f41d35dSnonaka {
3582f41d35dSnonaka uint32_t rv;
3592f41d35dSnonaka
3602f41d35dSnonaka mutex_enter(&sc->sc_mtx);
3612f41d35dSnonaka
3622f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
3632f41d35dSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
3642f41d35dSnonaka WS007SH_SSCR0_ADS7846);
3652f41d35dSnonaka
3662f41d35dSnonaka pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
3672f41d35dSnonaka
3682f41d35dSnonaka /* send cmd */
36912cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
3702f41d35dSnonaka continue; /* poll */
37112cd5caeSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
37212cd5caeSnonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
37312cd5caeSnonaka continue; /* poll */
37412cd5caeSnonaka
37512cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
3762f41d35dSnonaka continue; /* poll */
3772f41d35dSnonaka rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
3782f41d35dSnonaka
3792f41d35dSnonaka pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
3802f41d35dSnonaka
3812f41d35dSnonaka mutex_exit(&sc->sc_mtx);
3822f41d35dSnonaka
3832f41d35dSnonaka return rv;
3842f41d35dSnonaka }
38512cd5caeSnonaka
38612cd5caeSnonaka static uint32_t
wzero3ssp_read_max1233(struct wzero3ssp_softc * sc,uint32_t cmd,uint32_t data)38712cd5caeSnonaka wzero3ssp_read_max1233(struct wzero3ssp_softc *sc, uint32_t cmd, uint32_t data)
38812cd5caeSnonaka {
38912cd5caeSnonaka uint32_t rv;
39012cd5caeSnonaka
39112cd5caeSnonaka mutex_enter(&sc->sc_mtx);
39212cd5caeSnonaka
39312cd5caeSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
39412cd5caeSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
39512cd5caeSnonaka WS003SH_SSCR0_MAX1233);
39612cd5caeSnonaka
39712cd5caeSnonaka pxa2x0_gpio_set_bit(39/*GPIO_WS003SH_XXX*/);
39812cd5caeSnonaka pxa2x0_gpio_clear_bit(GPIO_WS003SH_MAX1233_CS);
39912cd5caeSnonaka
40012cd5caeSnonaka /* send cmd */
40112cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
40212cd5caeSnonaka continue; /* poll */
40312cd5caeSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
40412cd5caeSnonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
40512cd5caeSnonaka continue; /* poll */
40612cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
40712cd5caeSnonaka continue; /* poll */
40812cd5caeSnonaka (void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
40912cd5caeSnonaka
41012cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
41112cd5caeSnonaka continue; /* poll */
41212cd5caeSnonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, data);
41312cd5caeSnonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
41412cd5caeSnonaka continue; /* poll */
41512cd5caeSnonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
41612cd5caeSnonaka continue; /* poll */
41712cd5caeSnonaka rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
41812cd5caeSnonaka
41912cd5caeSnonaka pxa2x0_gpio_set_bit(GPIO_WS003SH_MAX1233_CS);
42012cd5caeSnonaka
42112cd5caeSnonaka mutex_exit(&sc->sc_mtx);
42212cd5caeSnonaka
42312cd5caeSnonaka return rv;
42412cd5caeSnonaka }
4254071f150Snonaka
4264071f150Snonaka static uint32_t
wzero3ssp_read_ak4184_tp(struct wzero3ssp_softc * sc,uint32_t cmd)4279f093235Snonaka wzero3ssp_read_ak4184_tp(struct wzero3ssp_softc *sc, uint32_t cmd)
4284071f150Snonaka {
4294071f150Snonaka uint32_t rv;
4304071f150Snonaka
4314071f150Snonaka mutex_enter(&sc->sc_mtx);
4324071f150Snonaka
4334071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
4344071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
4354071f150Snonaka WS011SH_SSCR0_AK4184_TP);
4364071f150Snonaka
4374071f150Snonaka pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
4384071f150Snonaka
4399f093235Snonaka /* clear rx fifo */
4404071f150Snonaka (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
4414071f150Snonaka
4424071f150Snonaka /* send cmd */
4434071f150Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
4444071f150Snonaka continue; /* poll */
4454071f150Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd << 16);
4464071f150Snonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
4474071f150Snonaka continue; /* poll */
4484071f150Snonaka
4494071f150Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
4504071f150Snonaka continue; /* poll */
4514071f150Snonaka rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
4524071f150Snonaka
4534071f150Snonaka pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
4544071f150Snonaka
4554071f150Snonaka mutex_exit(&sc->sc_mtx);
4564071f150Snonaka
4574071f150Snonaka return rv;
4584071f150Snonaka }
4599f093235Snonaka
4609f093235Snonaka static uint16_t
wzero3ssp_read_ak4184_keypad(struct wzero3ssp_softc * sc,uint32_t cmd,uint32_t data)4619f093235Snonaka wzero3ssp_read_ak4184_keypad(struct wzero3ssp_softc *sc, uint32_t cmd,
4629f093235Snonaka uint32_t data)
4639f093235Snonaka {
4649f093235Snonaka uint16_t rv;
4659f093235Snonaka
4669f093235Snonaka mutex_enter(&sc->sc_mtx);
4679f093235Snonaka
4689f093235Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
4699f093235Snonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
4709f093235Snonaka WS011SH_SSCR0_AK4184_KEYPAD);
4719f093235Snonaka
4729f093235Snonaka pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
4739f093235Snonaka
4749f093235Snonaka /* clear rx fifo */
4759f093235Snonaka (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
4769f093235Snonaka
4779f093235Snonaka /* send cmd */
4789f093235Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
4799f093235Snonaka continue; /* poll */
4809f093235Snonaka bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR, (uint16_t)cmd);
4819f093235Snonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
4829f093235Snonaka continue; /* poll */
4839f093235Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
4849f093235Snonaka continue; /* poll */
4859f093235Snonaka (void) bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
4869f093235Snonaka
4879f093235Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
4889f093235Snonaka continue; /* poll */
4899f093235Snonaka bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR, (uint16_t)data);
4909f093235Snonaka while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
4919f093235Snonaka continue; /* poll */
4929f093235Snonaka while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
4939f093235Snonaka continue; /* poll */
4949f093235Snonaka rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
4959f093235Snonaka
4969f093235Snonaka pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
4979f093235Snonaka
4989f093235Snonaka mutex_exit(&sc->sc_mtx);
4999f093235Snonaka
5009f093235Snonaka return rv;
5019f093235Snonaka }
502