/* $OpenBSD: zaurus_ssp.c,v 1.5 2005/02/22 21:53:03 uwe Exp $ */ /* * Copyright (c) 2005 Uwe Stuehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #define GPIO_TG_CS_C3000 53 #define GPIO_MAX1111_CS_C3000 20 #define GPIO_ADS7846_CS_C3000 14 /* SSP SFRM */ #define SSCR0_LZ9JG18 0x01ab #define SSCR0_MAX1111 0x0387 struct zssp_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; }; int zssp_match(struct device *, void *, void *); void zssp_attach(struct device *, struct device *, void *); void zssp_init(void); void zssp_powerhook(int, void *); struct cfattach zssp_ca = { sizeof (struct zssp_softc), zssp_match, zssp_attach }; struct cfdriver zssp_cd = { NULL, "zssp", DV_DULL }; int zssp_match(struct device *parent, void *match, void *aux) { return 1; } void zssp_attach(struct device *parent, struct device *self, void *aux) { struct zssp_softc *sc = (struct zssp_softc *)self; sc->sc_iot = &pxa2x0_bs_tag; if (bus_space_map(sc->sc_iot, PXA2X0_SSP1_BASE, PXA2X0_SSP_SIZE, 0, &sc->sc_ioh)) { printf("can't map bus space\n"); return; } printf("\n"); zssp_init(); (void)powerhook_establish(zssp_powerhook, sc); } /* * Initialize the dedicated SSP unit and disable all chip selects. * This function is called with interrupts disabled. */ void zssp_init(void) { struct zssp_softc *sc; if (zssp_cd.cd_ndevs < 1 || zssp_cd.cd_devs[0] == NULL) { printf("zssp_read_max1111: not configured\n"); return; } sc = (struct zssp_softc *)zssp_cd.cd_devs[0]; pxa2x0_clkman_config(CKEN_SSP, 1); bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, SSCR0_LZ9JG18); bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR1, 0); pxa2x0_gpio_set_function(GPIO_TG_CS_C3000, GPIO_OUT|GPIO_SET); pxa2x0_gpio_set_function(GPIO_MAX1111_CS_C3000, GPIO_OUT|GPIO_SET); pxa2x0_gpio_set_function(GPIO_ADS7846_CS_C3000, GPIO_OUT|GPIO_SET); } int zssp_read_max1111(u_int32_t cmd) { struct zssp_softc *sc; int voltage[2]; int i; int s; if (zssp_cd.cd_ndevs < 1 || zssp_cd.cd_devs[0] == NULL) { printf("zssp_read_max1111: not configured\n"); return 0; } sc = (struct zssp_softc *)zssp_cd.cd_devs[0]; s = splhigh(); 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, SSCR0_MAX1111); pxa2x0_gpio_set_bit(GPIO_TG_CS_C3000); pxa2x0_gpio_set_bit(GPIO_ADS7846_CS_C3000); pxa2x0_gpio_clear_bit(GPIO_MAX1111_CS_C3000); delay(1); /* Send the command word and read a dummy word back. */ 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_TNF) != SSSR_TNF) /* poll */; /* XXX is this delay necessary? */ delay(1); while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE) != SSSR_RNE) /* poll */; i = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR); for (i = 0; i < 2; i++) { bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR, 0); while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_TNF) != SSSR_TNF) /* poll */; /* XXX again, is this delay necessary? */ delay(1); while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE) != SSSR_RNE) /* poll */; voltage[i] = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR); } pxa2x0_gpio_set_bit(GPIO_TG_CS_C3000); pxa2x0_gpio_set_bit(GPIO_ADS7846_CS_C3000); pxa2x0_gpio_set_bit(GPIO_MAX1111_CS_C3000); bus_space_write_4(sc->sc_iot, sc->sc_ioh, SSP_SSCR0, 0); /* XXX no idea what this means, but it's what Linux would do. */ if ((voltage[0] & 0xc0) != 0 || (voltage[1] & 0x3f) != 0) voltage[0] = -1; else voltage[0] = ((voltage[0] << 2) & 0xfc) | ((voltage[1] >> 6) & 0x03); splx(s); return voltage[0]; } /* XXX - only does CS_ADS7846 */ u_int32_t pxa2x0_ssp_read_val(u_int32_t cmd); u_int32_t pxa2x0_ssp_read_val(u_int32_t cmd) { struct zssp_softc *sc; sc = (struct zssp_softc *)zssp_cd.cd_devs[0]; unsigned int cr0; int s; u_int32_t val; if (zssp_cd.cd_ndevs < 1 || zssp_cd.cd_devs[0] == NULL) { printf("pxa2x0_ssp_read_val: not configured\n"); return 0; } sc = (struct zssp_softc *)zssp_cd.cd_devs[0]; s = splhigh(); if (1 /* C3000 */) { cr0 = 0x06ab; } else { cr0 = 0x00ab; } 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, cr0); pxa2x0_gpio_set_bit(GPIO_TG_CS_C3000); pxa2x0_gpio_set_bit(GPIO_MAX1111_CS_C3000); pxa2x0_gpio_clear_bit(GPIO_ADS7846_CS_C3000); 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_TNF) != SSSR_TNF) /* poll */; delay(1); while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSSR) & SSSR_RNE) != SSSR_RNE) /* poll */; val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SSP_SSDR); pxa2x0_gpio_set_bit(GPIO_ADS7846_CS_C3000); /* deselect */ splx(s); return val; } void zssp_write_lz9jg18(u_int32_t data) { int s; int sclk_pin, sclk_fn; int sfrm_pin, sfrm_fn; int txd_pin, txd_fn; int rxd_pin, rxd_fn; int i; /* XXX this creates a DAC command from a backlight duty value. */ data = 0x40 | (data & 0x1f); if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X) { /* C3000 */ sclk_pin = 19; sfrm_pin = 14; txd_pin = 87; rxd_pin = 86; } else { sclk_pin = 23; sfrm_pin = 24; txd_pin = 25; rxd_pin = 26; } s = splhigh(); sclk_fn = pxa2x0_gpio_get_function(sclk_pin); sfrm_fn = pxa2x0_gpio_get_function(sfrm_pin); txd_fn = pxa2x0_gpio_get_function(txd_pin); rxd_fn = pxa2x0_gpio_get_function(rxd_pin); pxa2x0_gpio_set_function(sfrm_pin, GPIO_OUT | GPIO_SET); pxa2x0_gpio_set_function(sclk_pin, GPIO_OUT | GPIO_CLR); pxa2x0_gpio_set_function(txd_pin, GPIO_OUT | GPIO_CLR); pxa2x0_gpio_set_function(rxd_pin, GPIO_IN); pxa2x0_gpio_set_bit(GPIO_MAX1111_CS_C3000); pxa2x0_gpio_set_bit(GPIO_ADS7846_CS_C3000); pxa2x0_gpio_clear_bit(GPIO_TG_CS_C3000); delay(10); for (i = 0; i < 8; i++) { if (data & 0x80) pxa2x0_gpio_set_bit(txd_pin); else pxa2x0_gpio_clear_bit(txd_pin); delay(10); pxa2x0_gpio_set_bit(sclk_pin); delay(10); pxa2x0_gpio_clear_bit(sclk_pin); delay(10); data <<= 1; } pxa2x0_gpio_clear_bit(txd_pin); pxa2x0_gpio_set_bit(GPIO_TG_CS_C3000); pxa2x0_gpio_set_function(sclk_pin, sclk_fn); pxa2x0_gpio_set_function(sfrm_pin, sfrm_fn); pxa2x0_gpio_set_function(txd_pin, txd_fn); pxa2x0_gpio_set_function(rxd_pin, rxd_fn); splx(s); } void zssp_powerhook(int why, void *arg) { int s; if (why == PWR_RESUME) { s = splhigh(); zssp_init(); splx(s); } }