xref: /netbsd-src/sys/arch/hpcarm/dev/wzero3_ssp.c (revision 2388feef6162e5f55bc0fbaaa9d32d8dfc8354a3)
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