[BACK]Return to jmcu.c CVS log [TXT][DIR] Up to [local] / sys / arch / jornada / dev

File: [local] / sys / arch / jornada / dev / jmcu.c (download)

Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:09:01 2008 UTC (16 years, 3 months ago) by nbrk
Branch: OPENBSD_4_2_BASE
CVS Tags: jornada-partial-support-wip
Changes since 1.1: +0 -0 lines

Import of OpenBSD 4.2 release kernel tree with initial code to support 
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO

Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)

/*	$Id: jmcu.c,v 1.1.1.1 2008/03/04 16:09:01 nbrk Exp $	*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/endian.h>

#include <machine/intr.h>
#include <machine/bus.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>

#include <dev/spivar.h>

#include <jornada/dev/jmcu_cmd.h>

#include <arm/sa11x0/sa11x0_var.h>
#include <arm/sa11x0/sa11x0_reg.h>
#include <arm/sa11x0/sa11x0_gpiovar.h>

#include <jornada/dev/jmcu_kbdmap.h>

#define JMCU_KBD_GPIOINTR	0
#define JMCU_TS_GPIOINTR	15

#define JMCU_KBD_NEVENTS	8

struct jmcu_softc {
	struct device	sc_dev;

	struct spi_bus	*sc_bus;
	void	*sc_spisc;

	uint8_t	sc_kbdeventsbuf[JMCU_KBD_NEVENTS];
	uint8_t	sc_kbdeventsnum;
};

struct jmcu_softc *jmcu_sc;
struct wskbd_mapdata jmcukbd_keymapdata = {
        jmcukbd_keydesctab,   
        KB_US,
};

/*
 * Prototypes.
 */
int	jmcu_match(struct device *parent, void *cf, void *aux);
void	jmcu_attach(struct device *parent, struct device *self, void *aux);
int	jmcu_kbdintr(void *arg);
int	jmcu_touchintr(void *arg);
void	jmcukbd_cngetc(void *v, u_int *type, int *data);
void	jmcukbd_enqueue(struct jmcu_softc *sc, uint8_t keycode);
void	jmcukbd_dequeue(struct jmcu_softc *sc, uint8_t *keycodep);
void	jmcukbd_getcodes(struct jmcu_softc *sc, int block);
void	jmcubatt_status(struct jmcu_softc *sc);

/*
 * Autoconf glue.
 */
struct cfattach	jmcu_ca = {
	sizeof(struct jmcu_softc), jmcu_match, jmcu_attach, NULL, NULL
};

struct cfdriver	jmcu_cd = {
	NULL,
	"jmcu",
	DV_DULL
};

/*
 * Console ops.
 */
struct wskbd_consops jmcukbd_consops = {
	jmcukbd_cngetc,
	NULL, /* pollc */
	NULL /* bell */
};


int
jmcu_match(struct device *parent, void *cf, void *aux)
{
	return (1);
}

void
jmcu_attach(struct device *parent, struct device *self, void *aux)
{
	struct jmcu_softc *sc = (struct jmcu_softc *)self;
	struct spibus_attach_args *sba = aux;
	struct wskbddev_attach_args	wda;

	sc->sc_bus = sba->sba_bus;
	sc->sc_spisc = sba->sba_spisc;

	printf(": Jornada MCU\n");

	jmcu_sc = sc;

	/* XXX */
	jmcubatt_status(sc);

	sa11x0_gpio_intr_establish(JMCU_KBD_GPIOINTR, IST_EDGE_FALLING, IPL_TTY, jmcu_kbdintr, sc, "jmcukbd");
	sa11x0_gpio_intr_establish(JMCU_TS_GPIOINTR, IST_EDGE_FALLING, IPL_TTY, jmcu_touchintr, sc, "jmcutouch");

	wskbd_cnattach(&jmcukbd_consops, sc, &jmcukbd_keymapdata);

	wda.console = 1;
	wda.keymap = &jmcukbd_keymapdata;
	wda.accessops = NULL; //jmcukbd_accessops;
	wda.accesscookie = sc;

	config_found(self, &wda, wskbddevprint);

	return;
}

int
jmcu_kbdintr(void *arg)
{
	struct jmcu_softc *sc = arg;
	printf("%s: jmcu_kbdintr\n", sc->sc_dev.dv_xname);

	return(0);
}

int
jmcu_touchintr(void *arg)
{
	struct jmcu_softc *sc = arg;
	printf("%s: jmcu_touchintr\n", sc->sc_dev.dv_xname);

	return(0);
}

void
jmcukbd_cngetc(void *v, u_int *type, int *data)
{
	struct jmcu_softc *sc = v;
	uint8_t	ourdata;

	printf("jmcukbd_cngetc:\n");

	if (sc->sc_kbdeventsnum == 0)
		jmcukbd_getcodes(sc, 1);	/* note that we've passed blocking flag */

	jmcukbd_dequeue(sc, &ourdata);

	*data = ourdata & 0x7f;
	*type = ourdata & 0x80 ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
}

void
jmcukbd_getcodes(struct jmcu_softc *sc, int block)
{
	int	nkeys;
	uint8_t keycode;

	/* wake up the MCU */
	sa11x0_gpio_clear_bit(25);

	spi_acquire(sc->sc_spisc);

	do {
		/* ask mcu about how many keypress events are there; should get TXDUMMY here */
		if (spi_shift_1(sc->sc_spisc, JMCU_CMD_GETKEYCODES) != JMCU_CMD_TXDUMMY)
		printf("%s: WARNING, no txdummy received\n", sc->sc_dev.dv_xname);

		nkeys = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	} while(nkeys == 0 && block);

	while (nkeys) {
		keycode = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
		jmcukbd_enqueue(sc, keycode);

		nkeys--;
	}
	spi_release(sc->sc_spisc);

	/* park off the MCU */
	sa11x0_gpio_set_bit(25);
}

void
jmcukbd_enqueue(struct jmcu_softc *sc, uint8_t keycode)
{
	if (sc->sc_kbdeventsnum >= JMCU_KBD_NEVENTS) {
		printf("%s: WARNING, event queue is full; keycode 0x%x will be discarded\n", sc->sc_dev.dv_xname, keycode);
		return;
	}

	sc->sc_kbdeventsbuf[sc->sc_kbdeventsnum] = keycode;
	sc->sc_kbdeventsnum++;
}

void
jmcukbd_dequeue(struct jmcu_softc *sc, uint8_t *keycodep)
{
	if (sc->sc_kbdeventsnum < 1) {
		printf("%s: WARNING, event queue is empty\n", sc->sc_dev.dv_xname);
		return;
	}

	sc->sc_kbdeventsnum--;
	*keycodep = sc->sc_kbdeventsbuf[sc->sc_kbdeventsnum];
}

void
jmcubatt_status(struct jmcu_softc *sc)
{
	uint16_t	mainbatt;
	uint16_t	backbatt;
	uint8_t	fraction;

	/* wake up the MCU */
	sa11x0_gpio_clear_bit(25);

	spi_acquire(sc->sc_spisc);
	spi_shift_1(sc->sc_spisc, JMCU_CMD_GETBATTERYDATA);
	mainbatt = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	backbatt = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	fraction = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	spi_release(sc->sc_spisc);

	/* park off the MCU */
	sa11x0_gpio_set_bit(25);

	/* fraction[0:1] is mainbatt[8:9]; fraction[2:3] is backbatt[8:9] */
	mainbatt |= (uint16_t)((fraction & 0x03) << 8);
	backbatt |= (uint16_t)((fraction & 0xc0) << 6);

	printf("%s: battery status: main %d, backup %d\n", sc->sc_dev.dv_xname, mainbatt, backbatt);
}