#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wzero3_ssp.c,v 1.5 2012/01/21 19:44:29 nonaka Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/mutex.h>
#include <sys/pmf.h>
#include <sys/bus.h>
#include <machine/bootinfo.h>
#include <machine/platid.h>
#include <machine/platid_mask.h>
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_gpio.h>
#include <hpcarm/dev/wzero3_reg.h>
#include <hpcarm/dev/wzero3_sspvar.h>
#define WS003SH_SSCR0_MAX1233 0x0000048f
#define WS007SH_SSCR0_ADS7846 0x000006ab
#define WS011SH_SSCR0_AK4184_TP 0x0010068f
#define WS011SH_SSCR0_AK4184_KEYPAD 0x0000068f
struct wzero3ssp_model;
struct wzero3ssp_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
kmutex_t sc_mtx;
const struct wzero3ssp_model *sc_model;
};
static int wzero3ssp_match(device_t, cfdata_t, void *);
static void wzero3ssp_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(wzero3ssp, sizeof(struct wzero3ssp_softc),
wzero3ssp_match, wzero3ssp_attach, NULL, NULL);
static void wzero3ssp_init(struct wzero3ssp_softc *);
static bool wzero3ssp_resume(device_t dv, const pmf_qual_t *);
static uint32_t wzero3ssp_read_ads7846(struct wzero3ssp_softc *, uint32_t);
static uint32_t wzero3ssp_read_max1233(struct wzero3ssp_softc *, uint32_t,
uint32_t);
static uint32_t wzero3ssp_read_ak4184_tp(struct wzero3ssp_softc *, uint32_t);
static uint16_t wzero3ssp_read_ak4184_keypad(struct wzero3ssp_softc *, uint32_t,
uint32_t);
static struct wzero3ssp_softc *wzero3ssp_sc;
static const struct wzero3ssp_model {
platid_mask_t *platid;
u_long sspaddr;
} wzero3ssp_table[] = {
{
&platid_mask_MACH_SHARP_WZERO3_WS003SH,
PXA2X0_SSP2_BASE,
},
{
&platid_mask_MACH_SHARP_WZERO3_WS004SH,
PXA2X0_SSP2_BASE,
},
{
&platid_mask_MACH_SHARP_WZERO3_WS007SH,
PXA2X0_SSP1_BASE,
},
{
&platid_mask_MACH_SHARP_WZERO3_WS011SH,
PXA2X0_SSP1_BASE,
},
#if 0
{
&platid_mask_MACH_SHARP_WZERO3_WS020SH,
PXA2X0_SSP1_BASE,
},
#endif
{
NULL, 0,
},
};
static const struct wzero3ssp_model *
wzero3ssp_lookup(void)
{
const struct wzero3ssp_model *model;
for (model = wzero3ssp_table; model->platid != NULL; model++) {
if (platid_match(&platid, model->platid)) {
return model;
}
}
return NULL;
}
static int
wzero3ssp_match(device_t parent, cfdata_t cf, void *aux)
{
if (strcmp(cf->cf_name, "wzero3ssp") != 0)
return 0;
if (wzero3ssp_lookup() == NULL)
return 0;
if (wzero3ssp_sc != NULL)
return 0;
return 1;
}
static void
wzero3ssp_attach(device_t parent, device_t self, void *aux)
{
struct wzero3ssp_softc *sc = device_private(self);
sc->sc_dev = self;
wzero3ssp_sc = sc;
aprint_normal("\n");
aprint_naive("\n");
sc->sc_model = wzero3ssp_lookup();
if (sc->sc_model == NULL) {
aprint_error_dev(self, "unknown model\n");
return;
}
mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_TTY);
sc->sc_iot = &pxa2x0_bs_tag;
if (bus_space_map(sc->sc_iot, sc->sc_model->sspaddr, PXA2X0_SSP_SIZE, 0,
&sc->sc_ioh)) {
aprint_error_dev(sc->sc_dev, "can't map bus space\n");
return;
}
if (!pmf_device_register(sc->sc_dev, NULL, wzero3ssp_resume))
aprint_error_dev(sc->sc_dev,
"couldn't establish power handler\n");
wzero3ssp_init(sc);
}
static void
wzero3ssp_init(struct wzero3ssp_softc *sc)
{
if (sc->sc_model->sspaddr == PXA2X0_SSP1_BASE)
pxa2x0_clkman_config(CKEN_SSP2, 1);
else if (sc->sc_model->sspaddr == PXA2X0_SSP2_BASE)
pxa2x0_clkman_config(CKEN_SSP3, 1);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR1, 0);
if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS003SH)
|| platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS004SH)) {
pxa2x0_gpio_set_function(39,
GPIO_OUT|GPIO_SET);
pxa2x0_gpio_set_function(GPIO_WS003SH_MAX1233_CS,
GPIO_OUT|GPIO_SET);
}
if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH)) {
pxa2x0_gpio_set_function(GPIO_WS007SH_ADS7846_CS,
GPIO_OUT|GPIO_SET);
}
if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH)) {
pxa2x0_gpio_set_function(GPIO_WS011SH_AK4184_CS,
GPIO_OUT|GPIO_SET);
}
}
static bool
wzero3ssp_resume(device_t dv, const pmf_qual_t *qual)
{
struct wzero3ssp_softc *sc = device_private(dv);
mutex_enter(&sc->sc_mtx);
wzero3ssp_init(sc);
mutex_exit(&sc->sc_mtx);
return true;
}
void
wzero3ssp_ic_start(int ic, uint32_t cmd)
{
struct wzero3ssp_softc *sc;
KASSERT(wzero3ssp_sc != NULL);
sc = wzero3ssp_sc;
mutex_enter(&sc->sc_mtx);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH)) {
if (ic != WZERO3_SSP_IC_ADS7846)
pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
}
if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH)) {
if (ic != WZERO3_SSP_IC_AK4184_TP
&& ic != WZERO3_SSP_IC_AK4184_KEYPAD)
pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
}
switch (ic) {
case WZERO3_SSP_IC_ADS7846:
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS007SH_SSCR0_ADS7846);
pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
& SSSR_TNF) != SSSR_TNF)
continue;
break;
case WZERO3_SSP_IC_AK4184_TP:
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS011SH_SSCR0_AK4184_TP);
pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
& SSSR_TNF))
continue;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd << 16);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
& SSSR_BUSY)
continue;
break;
case WZERO3_SSP_IC_MAX1233:
case WZERO3_SSP_IC_AK4184_KEYPAD:
case WZERO3_SSP_IC_NUM:
default:
break;
}
}
uint32_t
wzero3ssp_ic_stop(int ic)
{
struct wzero3ssp_softc *sc;
uint32_t rv;
KASSERT(wzero3ssp_sc != NULL);
sc = wzero3ssp_sc;
switch (ic) {
case WZERO3_SSP_IC_ADS7846:
while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
& SSSR_RNE) != SSSR_RNE)
continue;
rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
break;
case WZERO3_SSP_IC_AK4184_TP:
while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR)
& SSSR_RNE) != SSSR_RNE)
continue;
rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
break;
case WZERO3_SSP_IC_MAX1233:
case WZERO3_SSP_IC_AK4184_KEYPAD:
case WZERO3_SSP_IC_NUM:
default:
rv = 0;
break;
}
mutex_exit(&sc->sc_mtx);
return rv;
}
uint32_t
wzero3ssp_ic_send(int ic, uint32_t data, uint32_t data2)
{
struct wzero3ssp_softc *sc;
if (wzero3ssp_sc == NULL) {
aprint_error("%s: not configured\n", __func__);
return 0;
}
sc = wzero3ssp_sc;
switch (ic) {
case WZERO3_SSP_IC_ADS7846:
return wzero3ssp_read_ads7846(sc, data);
case WZERO3_SSP_IC_MAX1233:
return wzero3ssp_read_max1233(sc, data, data2);
case WZERO3_SSP_IC_AK4184_TP:
return wzero3ssp_read_ak4184_tp(sc, data);
case WZERO3_SSP_IC_AK4184_KEYPAD:
return wzero3ssp_read_ak4184_keypad(sc, data, data2);
case WZERO3_SSP_IC_NUM:
default:
aprint_error("%s: invalid IC %d\n", __func__, ic);
return 0;
}
}
static uint32_t
wzero3ssp_read_ads7846(struct wzero3ssp_softc *sc, uint32_t cmd)
{
uint32_t rv;
mutex_enter(&sc->sc_mtx);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS007SH_SSCR0_ADS7846);
pxa2x0_gpio_clear_bit(GPIO_WS007SH_ADS7846_CS);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS007SH_ADS7846_CS);
mutex_exit(&sc->sc_mtx);
return rv;
}
static uint32_t
wzero3ssp_read_max1233(struct wzero3ssp_softc *sc, uint32_t cmd, uint32_t data)
{
uint32_t rv;
mutex_enter(&sc->sc_mtx);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS003SH_SSCR0_MAX1233);
pxa2x0_gpio_set_bit(39);
pxa2x0_gpio_clear_bit(GPIO_WS003SH_MAX1233_CS);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
(void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, data);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS003SH_MAX1233_CS);
mutex_exit(&sc->sc_mtx);
return rv;
}
static uint32_t
wzero3ssp_read_ak4184_tp(struct wzero3ssp_softc *sc, uint32_t cmd)
{
uint32_t rv;
mutex_enter(&sc->sc_mtx);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS011SH_SSCR0_AK4184_TP);
pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, cmd << 16);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
mutex_exit(&sc->sc_mtx);
return rv;
}
static uint16_t
wzero3ssp_read_ak4184_keypad(struct wzero3ssp_softc *sc, uint32_t cmd,
uint32_t data)
{
uint16_t rv;
mutex_enter(&sc->sc_mtx);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0,
WS011SH_SSCR0_AK4184_KEYPAD);
pxa2x0_gpio_clear_bit(GPIO_WS011SH_AK4184_CS);
(void) bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR, (uint16_t)cmd);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
(void) bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF))
continue;
bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR, (uint16_t)data);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_BUSY)
continue;
while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE))
continue;
rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSP_SSDR);
pxa2x0_gpio_set_bit(GPIO_WS011SH_AK4184_CS);
mutex_exit(&sc->sc_mtx);
return rv;
}