code:
/* $OpenBSD: exgpio.c,v 1.2 2015/05/27 00:06:14 jsg Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/evcount.h>

#include <arm/cpufunc.h>

#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <machine/intr.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/exgpiovar.h>

/* Exynos5 registers */
#define GPIO_BANK_SIZE		0x20
#define GPIO_BANK(x)		(GPIO_BANK_SIZE * ((x) / 8))
#define GPIO_CON(x)		(GPIO_BANK(x) + 0x00)
#define GPIO_DAT(x)		(GPIO_BANK(x) + 0x04)
#define GPIO_PULL(x)		(GPIO_BANK(x) + 0x08)
#define GPIO_DRV(x)		(GPIO_BANK(x) + 0x0c)
#define GPIO_PDN_CON(x)		(GPIO_BANK(x) + 0x10)
#define GPIO_PDN_PULL(x)	(GPIO_BANK(x) + 0x14)

/* bits and bytes */
#define GPIO_PIN(x)		((x) % 8)
#define GPIO_CON_INPUT(x)	(0x0 << (GPIO_PIN(x) << 2))
#define GPIO_CON_OUTPUT(x)	(0x1 << (GPIO_PIN(x) << 2))
#define GPIO_CON_IRQ(x)		(0xf << (GPIO_PIN(x) << 2))
#define GPIO_CON_MASK(x)	(0xf << (GPIO_PIN(x) << 2))
#define GPIO_DAT_SET(x)		(0x1 << (GPIO_PIN(x) << 0))
#define GPIO_DAT_MASK(x)	(0x1 << (GPIO_PIN(x) << 0))
#define GPIO_PULL_NONE(x)	(0x0 << (GPIO_PIN(x) << 1))
#define GPIO_PULL_DOWN(x)	(0x1 << (GPIO_PIN(x) << 1))
#define GPIO_PULL_UP(x)		(0x3 << (GPIO_PIN(x) << 1))
#define GPIO_PULL_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))
#define GPIO_DRV_1X(x)		(0x0 << (GPIO_PIN(x) << 1))
#define GPIO_DRV_2X(x)		(0x1 << (GPIO_PIN(x) << 1))
#define GPIO_DRV_3X(x)		(0x2 << (GPIO_PIN(x) << 1))
#define GPIO_DRV_4X(x)		(0x3 << (GPIO_PIN(x) << 1))
#define GPIO_DRV_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))

#define GPIO_PINS_PER_BANK	8

struct exgpio_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	int			sc_ngpio;
	unsigned int (*sc_get_bit)(struct exgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_set_bit)(struct exgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_clear_bit)(struct exgpio_softc *sc,
	    unsigned int gpio);
	void (*sc_set_dir)(struct exgpio_softc *sc,
	    unsigned int gpio, unsigned int dir);
};

int exgpio_match(struct device *parent, void *v, void *aux);
void exgpio_attach(struct device *parent, struct device *self, void *args);

struct exgpio_softc *exgpio_pin_to_inst(unsigned int);
unsigned int exgpio_pin_to_offset(unsigned int);
unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int);
void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int);
void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int);
void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int);
unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int);

struct cfattach	exgpio_ca = {
	sizeof (struct exgpio_softc), NULL, exgpio_attach
};
struct cfattach	exgpio_fdt_ca = {
	sizeof (struct exgpio_softc), exgpio_match, exgpio_attach
};

struct cfdriver exgpio_cd = {
	NULL, "exgpio", DV_DULL
};

int
exgpio_match(struct device *parent, void *v, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node))
		return 1;
#endif

	return 0;
}

void
exgpio_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct exgpio_softc *sc = (struct exgpio_softc *) self;
	struct armv7mem mem;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK;

	sc->sc_get_bit  = exgpio_v5_get_bit;
	sc->sc_set_bit = exgpio_v5_set_bit;
	sc->sc_clear_bit = exgpio_v5_clear_bit;
	sc->sc_set_dir = exgpio_v5_set_dir;

	printf("\n");

	/* XXX - IRQ */
	/* XXX - SYSCONFIG */
	/* XXX - CTRL */
	/* XXX - DEBOUNCE */
}

struct exgpio_softc *
exgpio_pin_to_inst(unsigned int gpio)
{
	int i;

	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
	{
		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
		if (gpio < sc->sc_ngpio)
			return sc;
		else
			gpio -= sc->sc_ngpio;
	}

	return NULL;
}

unsigned int
exgpio_pin_to_offset(unsigned int gpio)
{
	int i;

	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
	{
		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
		if (gpio < sc->sc_ngpio)
			return gpio;
		else
			gpio -= sc->sc_ngpio;
	}

	return 0;
}

unsigned int
exgpio_get_bit(unsigned int gpio)
{
	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);

	return sc->sc_get_bit(sc, gpio);
}

void
exgpio_set_bit(unsigned int gpio)
{
	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);

	sc->sc_set_bit(sc, gpio);
}

void
exgpio_clear_bit(unsigned int gpio)
{
	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);

	sc->sc_clear_bit(sc, gpio);
}
void
exgpio_set_dir(unsigned int gpio, unsigned int dir)
{
	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);

	sc->sc_set_dir(sc, gpio, dir);
}

unsigned int
exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	gpio = exgpio_pin_to_offset(gpio);
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));

	return !!(val & GPIO_DAT_SET(gpio));
}

void
exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	gpio = exgpio_pin_to_offset(gpio);
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
		val | GPIO_DAT_SET(gpio));
}

void
exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio)
{
	u_int32_t val;

	gpio = exgpio_pin_to_offset(gpio);
	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
		val & ~GPIO_DAT_MASK(gpio));
}

void
exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir)
{
	int s;
	u_int32_t val;

	gpio = exgpio_pin_to_offset(gpio);
	s = splhigh();

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
	val &= ~GPIO_CON_OUTPUT(gpio);
	if (dir == EXGPIO_DIR_OUT)
		val |= GPIO_CON_OUTPUT(gpio);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val);

	splx(s);
}

unsigned int
exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio)
{
	int s;
	u_int32_t val;

	gpio = exgpio_pin_to_offset(gpio);
	s = splhigh();

	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
	if (val & GPIO_CON_OUTPUT(gpio))
		val = EXGPIO_DIR_OUT;
	else
		val = EXGPIO_DIR_IN;

	splx(s);
	return val;
}


code:
/* $OpenBSD: exgpiovar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef EXGPIOVAR_H
#define EXGPIOVAR_H

#define EXGPIO_DIR_IN	0
#define EXGPIO_DIR_OUT	1

unsigned int exgpio_get_function(unsigned int gpio, unsigned int fn);
void exgpio_set_function(unsigned int gpio, unsigned int fn);
unsigned int exgpio_get_bit(unsigned int gpio);
void exgpio_set_bit(unsigned int gpio);
void exgpio_clear_bit(unsigned int gpio);
void exgpio_set_dir(unsigned int gpio, unsigned int dir);

/* interrupts */
void exgpio_clear_intr(unsigned int gpio);
void exgpio_intr_mask(unsigned int gpio);
void exgpio_intr_unmask(unsigned int gpio);
void exgpio_intr_level(unsigned int gpio, unsigned int level);
void *exgpio_intr_establish(unsigned int gpio, int level, int spl,
    int (*func)(void *), void *arg, char *name);
void exgpio_intr_disestablish(void *cookie);

#endif /* EXGPIOVAR_H */

license: unknown


code:
/*
 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif

#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/exgpiovar.h>
#include <armv7/exynos/exiicvar.h>
#include <armv7/exynos/exclockvar.h>

/* registers */
#define I2C_CON				0x00	/* control register */
#define I2C_STAT			0x04	/* control/status register */
#define I2C_ADD				0x08	/* address register */
#define I2C_DS				0x0C	/* transmit/receive data shift register */
#define I2C_LC				0x10	/* multi-master line control register */

/* bits and bytes */
#define I2C_CON_TXCLKVAL_MASK		(0xf << 0) /* tx clock = i2cclk / (i2ccon[3:0] + 1) */
#define I2C_CON_INTPENDING		(0x1 << 4) /* 0 = no interrupt pending/clear, 1 = pending */
#define I2C_CON_TXRX_INT		(0x1 << 5) /* enable/disable */
#define I2C_CON_TXCLKSRC_16		(0x0 << 6) /* i2clk = fpclk/16 */
#define I2C_CON_TXCLKSRC_512		(0x1 << 6) /* i2clk = fpclk/512 */
#define I2C_CON_ACK			(0x1 << 7)
#define I2C_STAT_LAST_RVCD_BIT		(0x1 << 0) /* last received bit 0 => ack, 1 => no ack */
#define I2C_STAT_ADDR_ZERO_FLAG		(0x1 << 1) /* 0 => start/stop cond. detected, 1 => received slave addr 0xb */
#define I2C_STAT_ADDR_SLAVE_ZERO_FLAG	(0x1 << 2) /* 0 => start/stop cond. detected, 1 => received slave addr matches i2cadd */
#define I2C_STAT_ARBITRATION		(0x1 << 3) /* 0 => successul, 1 => failed */
#define I2C_STAT_SERIAL_OUTPUT		(0x1 << 4) /* 0 => disable tx/rx, 1 => enable tx/rx */
#define I2C_STAT_BUSY_SIGNAL		(0x1 << 5) /* 0 => not busy / stop signal generation, 1 => busy / start signal generation */
#define I2C_STAT_MODE_SEL_SLAVE_RX	(0x0 << 6) /* slave receive mode */
#define I2C_STAT_MODE_SEL_SLAVE_TX	(0x1 << 6) /* slave transmit mode */
#define I2C_STAT_MODE_SEL_MASTER_RX	(0x2 << 6) /* master receive mode */
#define I2C_STAT_MODE_SEL_MASTER_TX	(0x3 << 6) /* master transmit */
#define I2C_ADD_SLAVE_ADDR(x)		(((x) & 0x7f) << 1)
#define I2C_DS_DATA_SHIFT(x)		(((x) & 0xff) << 0)

#define I2C_ACK				0
#define I2C_NACK			1
#define I2C_TIMEOUT			2

struct exiic_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_size_t		sc_ios;
	void			*sc_ih;
	int			unit;

	struct rwlock		sc_buslock;
	struct i2c_controller	i2c_tag;

	uint16_t		frequency;
	uint16_t		intr_status;
};

int exiic_match(struct device *parent, void *v, void *aux);
void exiic_attach(struct device *, struct device *, void *);
int exiic_detach(struct device *, int);
void exiic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
void exiic_setspeed(struct exiic_softc *, int);
int exiic_intr(void *);
int exiic_wait_intr(struct exiic_softc *, int, int);
int exiic_wait_state(struct exiic_softc *, uint32_t, uint32_t, uint32_t);
int exiic_start(struct exiic_softc *, int, int, void *, int);

void exiic_xfer_start(struct exiic_softc *);
int exiic_xfer_wait(struct exiic_softc *);
int exiic_i2c_acquire_bus(void *, int);
void exiic_i2c_release_bus(void *, int);
int exiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
    void *, size_t, int);

#define HREAD4(sc, reg)							\
	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val)						\
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))

struct cfattach exiic_ca = {
	sizeof(struct exiic_softc), NULL, exiic_attach, exiic_detach
};
struct cfattach exiic_fdt_ca = {
	sizeof(struct exiic_softc), exiic_match, exiic_attach, exiic_detach
};

struct cfdriver exiic_cd = {
	NULL, "exiic", DV_DULL
};

int
exiic_match(struct device *parent, void *v, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,s3c2440-i2c", aa->aa_node))
		return 1;
#endif

	return 0;
}

void
exiic_attach(struct device *parent, struct device *self, void *args)
{
	struct exiic_softc *sc = (struct exiic_softc *)self;
	struct armv7_attach_args *aa = args;
	struct armv7mem mem;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		static int unit = 0;

		sc->unit = unit++;
		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
		sc->unit = aa->aa_dev->unit;
	}
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);
	sc->sc_ios = mem.size;

#if 0
	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_BIO,
	    exiic_intr, sc, sc->sc_dev.dv_xname);
#endif

	printf("\n");

	rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);

	struct i2cbus_attach_args iba;

	sc->i2c_tag.ic_cookie = sc;
	sc->i2c_tag.ic_acquire_bus = exiic_i2c_acquire_bus;
	sc->i2c_tag.ic_release_bus = exiic_i2c_release_bus;
	sc->i2c_tag.ic_exec = exiic_i2c_exec;

	bzero(&iba, sizeof iba);
	iba.iba_name = "iic";
	iba.iba_tag = &sc->i2c_tag;
	iba.iba_bus_scan = exiic_bus_scan;
	iba.iba_bus_scan_arg = sc;
	config_found(&sc->sc_dev, &iba, NULL);
}

void
exiic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
{
	struct exiic_softc *sc = (struct exiic_softc *)arg;
	struct i2c_attach_args ia;

	/* XXX: We currently only attach cros-ec on I2C4.  We'll use FDT later. */
	if (sc->unit != 4)
		return;

	char *name = "crosec";
	int addr = 0x1e;

	memset(&ia, 0, sizeof(ia));
	ia.ia_tag = iba->iba_tag;
	ia.ia_addr = addr;
	ia.ia_size = 1;
	ia.ia_name = name;
	config_found(self, &ia, iicbus_print);

	name = "tps65090";
	addr = 0x48;

	memset(&ia, 0, sizeof(ia));
	ia.ia_tag = iba->iba_tag;
	ia.ia_addr = addr;
	ia.ia_size = 1;
	ia.ia_name = name;
	config_found(self, &ia, iicbus_print);
}

void
exiic_setspeed(struct exiic_softc *sc, int speed)
{
	if (!sc->frequency) {
		uint32_t freq, div = 0, pres = 16;
		freq = exclock_get_i2cclk();

		/* calculate prescaler and divisor values */
		if ((freq / pres / (16 + 1)) > speed)
			/* set prescaler to 512 */
			pres = 512;

		while ((freq / pres / (div + 1)) > speed)
			div++;

		/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
		sc->frequency = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
	}

	HWRITE4(sc, I2C_CON, sc->frequency);
}

#if 0
int
exiic_intr(void *arg)
{
	struct exiic_softc *sc = arg;
	u_int16_t status;
	int rc = 0;

	status = HREAD4(sc, I2C_CON);

	if (ISSET(status, I2C_CON_INTPENDING)) {
		/* we do not acknowledge the interrupt here */
		rc = 1;

		sc->intr_status |= status;
		wakeup(&sc->intr_status);
	}

	return (rc);
}

int
exiic_wait_intr(struct exiic_softc *sc, int mask, int timo)
{
	int status;
	int s;

	s = splbio();

	status = sc->intr_status & mask;
	while (status == 0) {
		if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
		    == EWOULDBLOCK) {
			break;
		}
		status = sc->intr_status & mask;
	}
	status = sc->intr_status & mask;
	sc->intr_status &= ~status;

	splx(s);
	return status;
}
#endif

int
exiic_wait_state(struct exiic_softc *sc, uint32_t reg, uint32_t mask, uint32_t value)
{
	uint32_t state;
	int timeout;
	state = HREAD4(sc, reg);
	for (timeout = 1000; timeout > 0; timeout--) {
		if (((state = HREAD4(sc, reg)) & mask) == value)
			return 0;
		delay(1000);
	}
	return ETIMEDOUT;
}

int
exiic_i2c_acquire_bus(void *cookie, int flags)
{
	struct exiic_softc *sc = cookie;
	int ret = rw_enter(&sc->sc_buslock, RW_WRITE);

	if (!ret) {
		/* set speed to 100 Kbps */
		exiic_setspeed(sc, 100);

		/* STOP */
		HWRITE4(sc, I2C_STAT, 0);
		HWRITE4(sc, I2C_ADD, 0);
		HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
				    | I2C_STAT_SERIAL_OUTPUT);
	}

	return ret;
}

void
exiic_i2c_release_bus(void *cookie, int flags)
{
	struct exiic_softc *sc = cookie;

	(void) rw_exit(&sc->sc_buslock);
}

int
exiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t _addr,
    const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags)
{
	struct exiic_softc *sc = cookie;
	uint32_t ret = 0;
	u_int8_t addr = 0;
	int i = 0;

	addr = (_addr & 0x7f) << 1;

	/* clock gating */
	//exccm_enable_i2c(sc->unit);

	if (exiic_wait_state(sc, I2C_STAT, I2C_STAT_BUSY_SIGNAL, 0)) {
		printf("%s: busy\n", __func__);
		return (EIO);
	}

	/* acknowledge generation */
	HSET4(sc, I2C_CON, I2C_CON_ACK);

	/* Send the slave-address */
	HWRITE4(sc, I2C_DS, addr);
	if (!I2C_OP_READ_P(op) || (cmdbuf && cmdlen))
		HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
				    | I2C_STAT_SERIAL_OUTPUT
				    | I2C_STAT_BUSY_SIGNAL);
	else
		HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
				    | I2C_STAT_SERIAL_OUTPUT
				    | I2C_STAT_BUSY_SIGNAL);

	ret = exiic_xfer_wait(sc);
	if (ret != I2C_ACK)
		goto fail;

	/* transmit commands */
	if (cmdbuf && cmdlen) {
		for (i = 0; i < cmdlen; i++) {
			HWRITE4(sc, I2C_DS, ((uint8_t *)cmdbuf)[i]);
			exiic_xfer_start(sc);
			ret = exiic_xfer_wait(sc);
			if (ret != I2C_ACK)
				goto fail;
		}
	}

	if (I2C_OP_READ_P(op)) {
		if (cmdbuf && cmdlen) {
			/* write slave chip address again for actual read */
			HWRITE4(sc, I2C_DS, addr);

			/* restart */
			HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
					    | I2C_STAT_SERIAL_OUTPUT
					    | I2C_STAT_BUSY_SIGNAL);
			exiic_xfer_start(sc);
			ret = exiic_xfer_wait(sc);
			if (ret != I2C_ACK)
				goto fail;
		}

		for (i = 0; i < datalen && ret == I2C_ACK; i++) {
			/* disable ACK for final read */
			if (i == datalen - 1)
				HCLR4(sc, I2C_CON, I2C_CON_ACK);
			exiic_xfer_start(sc);
			ret = exiic_xfer_wait(sc);
			((uint8_t *)databuf)[i] = HREAD4(sc, I2C_DS);
		}
		if (ret == I2C_NACK)
			ret = I2C_ACK; /* Normal terminated read. */
	} else {
		for (i = 0; i < datalen && ret == I2C_ACK; i++) {
			HWRITE4(sc, I2C_DS, ((uint8_t *)databuf)[i]);
			exiic_xfer_start(sc);
			ret = exiic_xfer_wait(sc);
		}
	}

fail:
	/* send STOP */
	if (op & I2C_OP_READ_WITH_STOP) {
		HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
				    | I2C_STAT_SERIAL_OUTPUT);
		exiic_xfer_start(sc);
	}

	return ret;
}

void
exiic_xfer_start(struct exiic_softc *sc)
{
	HCLR4(sc, I2C_CON, I2C_CON_INTPENDING);
}

int
exiic_xfer_wait(struct exiic_softc *sc)
{
	if (!exiic_wait_state(sc, I2C_CON, I2C_CON_INTPENDING,
					   I2C_CON_INTPENDING))
		return (HREAD4(sc, I2C_STAT) & I2C_STAT_LAST_RVCD_BIT) ?
			I2C_NACK : I2C_ACK;
	else
		return I2C_TIMEOUT;
}

int
exiic_detach(struct device *self, int flags)
{
	struct exiic_softc *sc = (struct exiic_softc *)self;

	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
	return 0;
}


code:
/*
 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef EXIICVAR_H
#define EXIICVAR_H

#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/rwlock.h>

#include <dev/i2c/i2cvar.h>

#endif


code:
/* $OpenBSD: exmct.c,v 1.2 2015/05/27 00:06:14 jsg Exp $ */
/*
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <arm/cpufunc.h>
#include <machine/intr.h>
#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/armv7/armv7var.h>

/* registers */
#define MCT_CTRL	0x240
#define MCT_WRITE_STAT	0x24C

/* bits and bytes */
#define MCT_CTRL_START	(1 << 8)

struct exmct_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

struct exmct_softc *exmct_sc;

int exmct_match(struct device *parent, void *v, void *aux);
void exmct_attach(struct device *parent, struct device *self, void *args);
void exmct_stop(void);
void exmct_reset(void);

struct cfattach	exmct_ca = {
	sizeof (struct exmct_softc), NULL, exmct_attach
};
struct cfattach	exmct_fdt_ca = {
	sizeof (struct exmct_softc), exmct_match, exmct_attach
};

struct cfdriver exmct_cd = {
	NULL, "exmct", DV_DULL
};

int
exmct_match(struct device *parent, void *v, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,exynos4210-mct", aa->aa_node))
		return 1;
#endif

	return 0;
}

void
exmct_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct exmct_softc *sc = (struct exmct_softc *) self;
	struct armv7mem mem;
	uint32_t i, mask, reg;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	printf("\n");

	exmct_sc = sc;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MCT_CTRL,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MCT_CTRL) | MCT_CTRL_START);

	mask = (1 << 16);

	/* Wait 10 times until written value is applied */
	for (i = 0; i < 10; i++) {
		reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MCT_WRITE_STAT);
		if (reg & mask) {
			bus_space_write_4(sc->sc_iot, sc->sc_ioh,
			    MCT_WRITE_STAT, mask);
			return;
		}
		cpufunc_nullop();
	}

	/* NOTREACHED */

	panic("%s: Can't enable timer!", __func__);
}


code:
/* $OpenBSD: expower.c,v 1.2 2015/05/27 00:06:14 jsg Exp $ */
/*
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/expowervar.h>

/* registers */
#define POWER_PHY_CTRL				0x708

/* bits and bytes */
#define POWER_PHY_CTRL_USB_HOST_EN		(1 << 0)

#define HREAD4(sc, reg)							\
	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val)						\
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))

struct expower_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

struct expower_softc *expower_sc;

int expower_match(struct device *parent, void *v, void *aux);
void expower_attach(struct device *parent, struct device *self, void *args);

struct cfattach	expower_ca = {
	sizeof (struct expower_softc), NULL, expower_attach
};
struct cfattach	expower_fdt_ca = {
	sizeof (struct expower_softc), expower_match, expower_attach
};

struct cfdriver expower_cd = {
	NULL, "expower", DV_DULL
};

int
expower_match(struct device *parent, void *v, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,exynos5250-pmu", aa->aa_node))
		return 1;
#endif

	return 0;
}

void
expower_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct expower_softc *sc = (struct expower_softc *) self;
	struct armv7mem mem;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	printf("\n");

	expower_sc = sc;
}

void
expower_usbhost_phy_ctrl(int on)
{
	struct expower_softc *sc = expower_sc;

	if (on)
		HSET4(sc, POWER_PHY_CTRL, POWER_PHY_CTRL_USB_HOST_EN);
	else
		HCLR4(sc, POWER_PHY_CTRL, POWER_PHY_CTRL_USB_HOST_EN);
}


code:
/* $OpenBSD: expowervar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
/*
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef EXPOWERVAR_H
#define EXPOWERVAR_H

void expower_usbhost_phy_ctrl(int);

#endif /* EXPOWERVAR_H */


code:
/* $OpenBSD: exsysreg.c,v 1.2 2015/05/27 00:06:14 jsg Exp $ */
/*
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/exsysregvar.h>

/* registers */
#define SYSREG_USB20PHY_CFG			0x230

/* bits and bytes */
#define SYSREG_USB20PHY_CFG_HOST_LINK_EN	(1 << 0)

#define HREAD4(sc, reg)							\
	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val)						\
	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits)						\
	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))

struct exsysreg_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

struct exsysreg_softc *exsysreg_sc;

int exsysreg_match(struct device *parent, void *v, void *aux);
void exsysreg_attach(struct device *parent, struct device *self, void *args);

struct cfattach	exsysreg_ca = {
	sizeof (struct exsysreg_softc), NULL, exsysreg_attach
};
struct cfattach	exsysreg_fdt_ca = {
	sizeof (struct exsysreg_softc), exsysreg_match, exsysreg_attach
};

struct cfdriver exsysreg_cd = {
	NULL, "exsysreg", DV_DULL
};

int
exsysreg_match(struct device *parent, void *v, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,exynos5-sysreg", aa->aa_node))
		return 1;
#endif

	return 0;
}

void
exsysreg_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct exsysreg_softc *sc = (struct exsysreg_softc *) self;
	struct armv7mem mem;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);
		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;
	} else
#endif
	{
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	printf("\n");

	exsysreg_sc = sc;
}

void
exsysreg_usbhost_mode(int on)
{
	struct exsysreg_softc *sc = exsysreg_sc;

	if (on)
		HSET4(sc, SYSREG_USB20PHY_CFG, SYSREG_USB20PHY_CFG_HOST_LINK_EN);
	else
		HCLR4(sc, SYSREG_USB20PHY_CFG, SYSREG_USB20PHY_CFG_HOST_LINK_EN);
}


code:
/* $OpenBSD: exsysregvar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
/*
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#ifndef EXSYSREGVAR_H
#define EXSYSREGVAR_H

void exsysreg_usbhost_mode(int);

#endif /* EXSYSREGVAR_H */


code:
/* $OpenBSD: exuart.c,v 1.2 2015/05/27 00:06:14 jsg Exp $ */
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/uio.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/select.h>
#include <sys/kernel.h>

#include <dev/cons.h>

#ifdef DDB
#include <ddb/db_var.h>
#endif

#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif
#include <armv7/exynos/exuartreg.h>
#include <armv7/exynos/exuartvar.h>
#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/exclockvar.h>

#define DEVUNIT(x)      (minor(x) & 0x7f)
#define DEVCUA(x)       (minor(x) & 0x80)

struct exuart_softc {
	struct device	sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ioh;
	struct soft_intrhand *sc_si;
	void *sc_irq;
	struct tty	*sc_tty;
	struct timeout	sc_diag_tmo;
	struct timeout	sc_dtr_tmo;
	int		sc_fifo;
	int		sc_overflows;
	int		sc_floods;
	int		sc_errors;
	int		sc_halt;
	u_int32_t	sc_ulcon;
	u_int32_t	sc_ucon;
	u_int32_t	sc_ufcon;
	u_int32_t	sc_umcon;
	u_int8_t	sc_hwflags;
#define COM_HW_NOIEN    0x01
#define COM_HW_FIFO     0x02
#define COM_HW_SIR      0x20
#define COM_HW_CONSOLE  0x40
#define COM_HW_KGDB     0x80
	u_int8_t	sc_swflags;
#define COM_SW_SOFTCAR  0x01
#define COM_SW_CLOCAL   0x02
#define COM_SW_CRTSCTS  0x04
#define COM_SW_MDMBUF   0x08
#define COM_SW_PPS      0x10

	u_int8_t	sc_initialize;
	u_int8_t	sc_cua;
	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
#define EXUART_IBUFSIZE 128
#define EXUART_IHIGHWATER 100
	u_int16_t		sc_ibufs[2][EXUART_IBUFSIZE];
};

int     exuartprobe(struct device *parent, void *self, void *aux);
int     exuartprobe_fdt(struct device *parent, void *self, void *aux);
void    exuartattach(struct device *parent, struct device *self, void *aux);

void exuartcnprobe(struct consdev *cp);
void exuartcnprobe(struct consdev *cp);
void exuartcninit(struct consdev *cp);
int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
    tcflag_t cflag);
int exuartcngetc(dev_t dev);
void exuartcnputc(dev_t dev, int c);
void exuartcnpollc(dev_t dev, int on);
int  exuart_param(struct tty *tp, struct termios *t);
void exuart_start(struct tty *);
void exuart_pwroff(struct exuart_softc *sc);
void exuart_diag(void *arg);
void exuart_raisedtr(void *arg);
void exuart_softint(void *arg);
struct exuart_softc *exuart_sc(dev_t dev);

int exuart_intr(void *);

/* XXX - we imitate 'com' serial ports and take over their entry points */
/* XXX: These belong elsewhere */
cdev_decl(exuart);

struct cfdriver exuart_cd = {
	NULL, "exuart", DV_TTY
};

struct cfattach exuart_ca = {
	sizeof(struct exuart_softc), exuartprobe, exuartattach
};
struct cfattach exuart_fdt_ca = {
	sizeof(struct exuart_softc), exuartprobe_fdt, exuartattach
};

bus_space_tag_t	exuartconsiot;
bus_space_handle_t exuartconsioh;
bus_addr_t	exuartconsaddr;
tcflag_t	exuartconscflag = TTYDEF_CFLAG;
int		exuartdefaultrate = B115200;

int
exuartprobe(struct device *parent, void *self, void *aux)
{
	return 1;
}

int
exuartprobe_fdt(struct device *parent, void *self, void *aux)
{
#if NFDT > 0
	struct armv7_attach_args *aa = aux;

	if (fdt_node_compatible("samsung,exynos4210-uart", aa->aa_node))
		return 1;
#endif

	return 0;
}

struct cdevsw exuartdev =
	cdev_tty_init(3/*XXX NEXUART */ ,exuart);		/* 12: serial port */

void
exuartattach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct exuart_softc *sc = (struct exuart_softc *) self;
	struct armv7mem mem;
	int irq;

	sc->sc_iot = aa->aa_iot;
#if NFDT > 0
	if (aa->aa_node) {
		struct fdt_memory fdtmem;
		uint32_t ints[3];

		if (fdt_get_memory_address(aa->aa_node, 0, &fdtmem))
			panic("%s: could not extract memory data from FDT",
			    __func__);

		/* TODO: Add interrupt FDT API. */
		if (fdt_node_property_ints(aa->aa_node, "interrupts",
		    ints, 3) != 3)
			panic("%s: could not extract interrupt data from FDT",
			    __func__);

		mem.addr = fdtmem.addr;
		mem.size = fdtmem.size;

		irq = ints[1];
	} else
#endif
	{
		irq = aa->aa_dev->irq[0];
		mem.addr = aa->aa_dev->mem[0].addr;
		mem.size = aa->aa_dev->mem[0].size;
	}

	sc->sc_irq = arm_intr_establish(irq, IPL_TTY,
	    exuart_intr, sc, sc->sc_dev.dv_xname);
	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	if (mem.addr == exuartconsaddr)
		printf(" console");

	timeout_set(&sc->sc_diag_tmo, exuart_diag, sc);
	timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc);
	sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc);

	if(sc->sc_si == NULL)
		panic("%s: can't establish soft interrupt.",
		    sc->sc_dev.dv_xname);

	printf("\n");
}

int
exuart_intr(void *arg)
{
#if 0
	struct exuart_softc *sc = arg;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp = sc->sc_tty;
	u_int32_t reg;
	u_int16_t *p;
	u_int16_t c;

	sr1 = bus_space_read_2(iot, ioh, EXUART_USR1);
	if (ISSET(sr1, EXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) {
		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
		if (sc->sc_halt > 0)
			wakeup(&tp->t_outq);
		(*linesw[tp->t_line].l_start)(tp);
	}

	if (sc->sc_tty == NULL)
		return(0);

	if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR))
		return 0;

	p = sc->sc_ibufp;

	while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) {
		c = bus_space_read_1(iot, ioh, EXUART_URXH);
		if (p >= sc->sc_ibufend) {
			sc->sc_floods++;
			if (sc->sc_errors++ == 0)
				timeout_add(&sc->sc_diag_tmo, 60 * hz);
		} else {
			*p++ = c;
			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
				/* XXX */
				//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
				//bus_space_write_2(iot, ioh, EXUART_UCR3,
				//    sc->sc_ucr3);

		}
		/* XXX - msr stuff ? */
	}
	sc->sc_ibufp = p;

	softintr_schedule(sc->sc_si);
#endif

	return 1;
}

int
exuart_param(struct tty *tp, struct termios *t)
{
	struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	int ospeed = t->c_ospeed;
	int error;
	tcflag_t oldcflag;

	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
		return EINVAL;

	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
		SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE);
		break;
	case CS6:
		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX);
		break;
	case CS7:
		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN);
		break;
	case CS8:
		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
		SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT);
		break;
	}

	CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK);
	if (ISSET(t->c_cflag, PARENB)) {
		if (ISSET(t->c_cflag, PARODD))
			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD);
		else
			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN);
	}

	if (ISSET(t->c_cflag, CSTOPB))
		SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO);
	else
		CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE);

	bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon);

	if (ospeed == 0) {
		/* lower dtr */
	}

	if (ospeed != 0) {
		while (ISSET(tp->t_state, TS_BUSY)) {
			++sc->sc_halt;
			error = ttysleep(tp, &tp->t_outq,
			    TTOPRI | PCATCH, "exuartprm", 0);
			--sc->sc_halt;
			if (error) {
				exuart_start(tp);
				return (error);
			}
		}
		/* set speed */
	}

	/* setup fifo */

	/* When not using CRTSCTS, RTS follows DTR. */
	/* sc->sc_dtr = MCR_DTR; */

	/* and copy to tty */
	tp->t_ispeed = t->c_ispeed;
	tp->t_ospeed = t->c_ospeed;
	oldcflag = tp->t_cflag;
	tp->t_cflag = t->c_cflag;

        /*
	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
	 * stop the device.
	 */
	 /* XXX */

	exuart_start(tp);

	return 0;
}

void
exuart_start(struct tty *tp)
{
        struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	int s;
	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY)) {
		splx(s);
		return;
	}
	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
		goto stopped;
#ifdef DAMNFUCKSHIT
	/* clear to send (IE the RTS pin on this shit) is not directly \
	 * readable - skip check for now
	 */
	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS))
		goto stopped;
#endif
	if (tp->t_outq.c_cc <= tp->t_lowat) {
		if (ISSET(tp->t_state, TS_ASLEEP)) {
			CLR(tp->t_state, TS_ASLEEP);
			wakeup(&tp->t_outq);
		}
		if (tp->t_outq.c_cc == 0)
			goto stopped;
		selwakeup(&tp->t_wsel);
	}
	SET(tp->t_state, TS_BUSY);

#if 0
	if (!ISSET(sc->sc_ucr1, EXUART_CR1_TXMPTYEN)) {
		SET(sc->sc_ucr1, EXUART_CR1_TXMPTYEN);
		bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
	}
#endif

	{
		u_char buf[32];
		int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
		int i;
		for (i = 0; i < n; i++)
			bus_space_write_1(iot, ioh, EXUART_UTXH, buf[i]);
	}
	splx(s);
	return;
stopped:
#if 0
	if (ISSET(sc->sc_ucr1, )) {
		CLR(sc->sc_ucr1, EXUART_CR1_TXMPTYEN);
		bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
	}
#endif
	splx(s);
}

void
exuart_pwroff(struct exuart_softc *sc)
{
}

void
exuart_diag(void *arg)
{
	struct exuart_softc *sc = arg;
	int overflows, floods;
	int s;

	s = spltty();
	sc->sc_errors = 0;
	overflows = sc->sc_overflows;
	sc->sc_overflows = 0;
	floods = sc->sc_floods;
	sc->sc_floods = 0;
	splx(s);
	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
	    sc->sc_dev.dv_xname,
	    overflows, overflows == 1 ? "" : "s",
	    floods, floods == 1 ? "" : "s");
}

void
exuart_raisedtr(void *arg)
{
	//struct exuart_softc *sc = arg;

	//SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
	//bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3);
}

void
exuart_softint(void *arg)
{
	struct exuart_softc *sc = arg;
	struct tty *tp;
	u_int16_t *ibufp;
	u_int16_t *ibufend;
	int c;
	int err;
	int s;

	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
		return;

	tp = sc->sc_tty;
	s = spltty();

	ibufp = sc->sc_ibuf;
	ibufend = sc->sc_ibufp;

	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
		splx(s);
		return;
	}

	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
	sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
	sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;

#if 0
	if (ISSET(tp->t_cflag, CRTSCTS) &&
	    !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) {
		/* XXX */
		SET(sc->sc_ucr3, EXUART_CR3_DSR);
		bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3,
		    sc->sc_ucr3);
	}
#endif

	splx(s);

	while (ibufp < ibufend) {
		c = *ibufp++;
		if (ISSET(c, EXUART_UERSTAT_OVERRUN)) {
			sc->sc_overflows++;
			if (sc->sc_errors++ == 0)
				timeout_add(&sc->sc_diag_tmo, 60 * hz);
		}
		/* This is ugly, but fast. */

		err = 0;
		if (ISSET(c, EXUART_UERSTAT_PARITY))
			err |= TTY_PE;
		if (ISSET(c, EXUART_UERSTAT_FRAME))
			err |= TTY_FE;
		c = (c & 0xff) | err;
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
}

int
exuartopen(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct exuart_softc *sc;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	struct tty *tp;
	int s;
	int error = 0;

	if (unit >= exuart_cd.cd_ndevs)
		return ENXIO;
	sc = exuart_cd.cd_devs[unit];
	if (sc == NULL)
		return ENXIO;

	s = spltty();
	if (sc->sc_tty == NULL)
		tp = sc->sc_tty = ttymalloc(0);
	else
		tp = sc->sc_tty;

	splx(s);

	tp->t_oproc = exuart_start;
	tp->t_param = exuart_param;
	tp->t_dev = dev;

	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		SET(tp->t_state, TS_WOPEN);
		ttychars(tp);
		tp->t_iflag = TTYDEF_IFLAG;
		tp->t_oflag = TTYDEF_OFLAG;

		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
			tp->t_cflag = exuartconscflag;
		else
			tp->t_cflag = TTYDEF_CFLAG;
		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
			SET(tp->t_cflag, CLOCAL);
		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
			SET(tp->t_cflag, CRTSCTS);
		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
			SET(tp->t_cflag, MDMBUF);
		tp->t_lflag = TTYDEF_LFLAG;
		tp->t_ispeed = tp->t_ospeed = exuartdefaultrate;

		s = spltty();

		sc->sc_initialize = 1;
		exuart_param(tp, &tp->t_termios);
		ttsetwater(tp);
		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
		sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
		sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;

		iot = sc->sc_iot;
		ioh = sc->sc_ioh;

		sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON);
		sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON);
		sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON);
		sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON);

#if 0
		/* interrupt after one char on tx/rx */
		/* reference frequency divider: 1 */
		bus_space_write_2(iot, ioh, EXUART_UFCR,
		    1 << EXUART_FCR_TXTL_SH |
		    5 << EXUART_FCR_RFDIV_SH |
		    1 << EXUART_FCR_RXTL_SH);

		bus_space_write_2(iot, ioh, EXUART_UBIR,
		    (exuartdefaultrate / 100) - 1);

		/* formula: clk / (rfdiv * 1600) */
		bus_space_write_2(iot, ioh, EXUART_UBMR,
		    (exccm_get_uartclk() * 1000) / 1600);

		SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN);
		SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN);
		bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
		bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2);

		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
		SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
		bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
#endif

		SET(tp->t_state, TS_CARR_ON); /* XXX */

	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
		return EBUSY;
	else
		s = spltty();

	if (DEVCUA(dev)) {
		if (ISSET(tp->t_state, TS_ISOPEN)) {
			splx(s);
			return EBUSY;
		}
		sc->sc_cua = 1;
	} else {
		/* tty (not cua) device; wait for carrier if necessary */
		if (ISSET(flag, O_NONBLOCK)) {
			if (sc->sc_cua) {
				/* Opening TTY non-blocking... but the CUA is busy */
				splx(s);
				return EBUSY;
			}
		} else {
			while (sc->sc_cua ||
			    (!ISSET(tp->t_cflag, CLOCAL) &&
				!ISSET(tp->t_state, TS_CARR_ON))) {
				SET(tp->t_state, TS_WOPEN);
				error = ttysleep(tp, &tp->t_rawq,
				    TTIPRI | PCATCH, ttopen, 0);
				/*
				 * If TS_WOPEN has been reset, that means the
				 * cua device has been closed.  We don't want
				 * to fail in that case,
				 * so just go around again.
				 */
				if (error && ISSET(tp->t_state, TS_WOPEN)) {
					CLR(tp->t_state, TS_WOPEN);
					if (!sc->sc_cua && !ISSET(tp->t_state,
					    TS_ISOPEN))
						exuart_pwroff(sc);
					splx(s);
					return error;
				}
			}
		}
	}
	splx(s);
	return (*linesw[tp->t_line].l_open)(dev,tp,p);
}

int
exuartclose(dev_t dev, int flag, int mode, struct proc *p)
{
	int unit = DEVUNIT(dev);
	struct exuart_softc *sc = exuart_cd.cd_devs[unit];
	//bus_space_tag_t iot = sc->sc_iot;
	//bus_space_handle_t ioh = sc->sc_ioh;
	struct tty *tp = sc->sc_tty;
	int s;

	/* XXX This is for cons.c. */
	if (!ISSET(tp->t_state, TS_ISOPEN))
		return 0;

	(*linesw[tp->t_line].l_close)(tp, flag, p);
	s = spltty();
	if (ISSET(tp->t_state, TS_WOPEN)) {
		/* tty device is waiting for carrier; drop dtr then re-raise */
		//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
		//bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
		timeout_add(&sc->sc_dtr_tmo, hz * 2);
	} else {
		/* no one else waiting; turn off the uart */
		exuart_pwroff(sc);
	}
	CLR(tp->t_state, TS_BUSY | TS_FLUSH);

	sc->sc_cua = 0;
	splx(s);
	ttyclose(tp);

	return 0;
}

int
exuartread(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = exuarttty(dev);
	if (tty == NULL)
		return ENODEV;

	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
}

int
exuartwrite(dev_t dev, struct uio *uio, int flag)
{
	struct tty *tty;

	tty = exuarttty(dev);
	if (tty == NULL)
		return ENODEV;

	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
}

int
exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct exuart_softc *sc;
	struct tty *tp;
	int error;

	sc = exuart_sc(dev);
	if (sc == NULL)
		return (ENODEV);

	tp = sc->sc_tty;
	if (tp == NULL)
		return (ENXIO);

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	switch(cmd) {
	case TIOCSBRK:
		/* */
		break;

	case TIOCCBRK:
		/* */
		break;

	case TIOCSDTR:
#if 0
		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
#endif
		break;

	case TIOCCDTR:
#if 0
		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
#endif
		break;

	case TIOCMSET:
#if 0
		(void) clmctl(dev, *(int *) data, DMSET);
#endif
		break;

	case TIOCMBIS:
#if 0
		(void) clmctl(dev, *(int *) data, DMBIS);
#endif
		break;

	case TIOCMBIC:
#if 0
		(void) clmctl(dev, *(int *) data, DMBIC);
#endif
		break;

        case TIOCMGET:
#if 0
		*(int *)data = clmctl(dev, 0, DMGET);
#endif
		break;

	case TIOCGFLAGS:
#if 0
		*(int *)data = cl->cl_swflags;
#endif
		break;

	case TIOCSFLAGS:
		error = suser(p, 0);
		if (error != 0)
			return(EPERM);

#if 0
		cl->cl_swflags = *(int *)data;
		cl->cl_swflags &= /* only allow valid flags */
		    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
#endif
		break;
	default:
		return (ENOTTY);
	}

	return 0;
}

int
exuartstop(struct tty *tp, int flag)
{
	return 0;
}

struct tty *
exuarttty(dev_t dev)
{
	int unit;
	struct exuart_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= exuart_cd.cd_ndevs)
		return NULL;
	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
	if (sc == NULL)
		return NULL;
	return sc->sc_tty;
}

struct exuart_softc *
exuart_sc(dev_t dev)
{
	int unit;
	struct exuart_softc *sc;
	unit = DEVUNIT(dev);
	if (unit >= exuart_cd.cd_ndevs)
		return NULL;
	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
	return sc;
}

/* serial console */
void
exuartcnprobe(struct consdev *cp)
{
	cp->cn_dev = makedev(12 /* XXX */, 0);
	cp->cn_pri = CN_MIDPRI;
}

void
exuartcninit(struct consdev *cp)
{
}

int
exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
{
	static struct consdev exuartcons = {
		NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL,
		NODEV, CN_MIDPRI
	};

	if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh))
			return ENOMEM;

	cn_tab = &exuartcons;
	cn_tab->cn_dev = makedev(12 /* XXX */, 0);
	cdevsw[12] = exuartdev; 	/* KLUDGE */

	exuartconsiot = iot;
	exuartconsaddr = iobase;
	exuartconscflag = cflag;

	return 0;
}

int
exuartcngetc(dev_t dev)
{
	int c;
	int s;
	s = splhigh();
	while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
	    EXUART_UTRSTAT_RXBREADY) == 0 &&
	      (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
	    (EXUART_UFSTAT_RX_FIFO_CNT_MASK|EXUART_UFSTAT_RX_FIFO_FULL)) == 0)
		;
	c = bus_space_read_1(exuartconsiot, exuartconsioh, EXUART_URXH);
	splx(s);
	return c;
}

void
exuartcnputc(dev_t dev, int c)
{
	int s;
	s = splhigh();
	bus_space_write_1(exuartconsiot, exuartconsioh, EXUART_UTXH, (uint8_t)c);
	while((bus_space_read_2(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
	    EXUART_UTRSTAT_TXBEMPTY) != 0 &&
	      (bus_space_read_2(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
	    (EXUART_UFSTAT_TX_FIFO_CNT_MASK|EXUART_UFSTAT_TX_FIFO_FULL)) != 0)
		;
	splx(s);
}

void
exuartcnpollc(dev_t dev, int on)
{
}


code:
/*
 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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.
 */

#define	EXUART_ULCON				0x00
#define		EXUART_ULCON_WORD_FIVE			(0x0 << 0)
#define		EXUART_ULCON_WORD_SIX			(0x1 << 0)
#define		EXUART_ULCON_WORD_SEVEN			(0x2 << 0)
#define		EXUART_ULCON_WORD_EIGHT			(0x3 << 0)
#define		EXUART_ULCON_WORD_MASK			(0x3 << 0)
#define		EXUART_ULCON_STOP_ONE			(0x0 << 2)
#define		EXUART_ULCON_STOP_TWO			(0x1 << 2)
#define		EXUART_ULCON_PARITY_NONE		(0x0 << 3)
#define		EXUART_ULCON_PARITY_ODD			(0x4 << 3)
#define		EXUART_ULCON_PARITY_EVEN		(0x5 << 3)
#define		EXUART_ULCON_PARITY_FORCED1		(0x6 << 3)
#define		EXUART_ULCON_PARITY_FORCED0		(0x7 << 3)
#define		EXUART_ULCON_PARITY_MASK		(0x7 << 3)
#define		EXUART_ULCON_INFRARED			(0x1 << 6)
#define	EXUART_UCON				0x04
#define		EXUART_UCON_RX_IRQORPOLL		(0x1 << 0)
#define		EXUART_UCON_RX_DMA			(0x2 << 0)
#define		EXUART_UCON_TX_IRQORPOLL		(0x1 << 2)
#define		EXUART_UCON_TX_DMA			(0x2 << 2)
#define		EXUART_UCON_SEND_BREAK			(0x1 << 4)
#define		EXUART_UCON_LOOPBACK_MODE		(0x1 << 5)
#define		EXUART_UCON_RX_ERR_STS_INT		(0x1 << 6)
#define		EXUART_UCON_RX_TIMEOUT			(0x1 << 7)
#define		EXUART_UCON_RX_INT_TYPE_PULSE		(0x0 << 8)
#define		EXUART_UCON_RX_INT_TYPE_LEVEL		(0x1 << 8)
#define		EXUART_UCON_TX_INT_TYPE_PULSE		(0x0 << 9)
#define		EXUART_UCON_TX_INT_TYPE_LEVEL		(0x1 << 9)
#define		EXUART_UCON_RX_TIMEOUT_DMA_SUSPEND	(0x1 << 10)
#define		EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO	(0x1 << 11)
#define		EXUART_UCON_RX_TIMEOUT_INTERVAL(x)	(((x) & 0xf) << 12) /* 8 * (x + a) frame time */
#define		EXUART_UCON_RX_DMA_BURST_1B		(0x0 << 16)
#define		EXUART_UCON_RX_DMA_BURST_4B		(0x1 << 16)
#define		EXUART_UCON_RX_DMA_BURST_8B		(0x2 << 16)
#define		EXUART_UCON_RX_DMA_BURST_16B		(0x3 << 16)
#define		EXUART_UCON_TX_DMA_BURST_1B		(0x0 << 20)
#define		EXUART_UCON_TX_DMA_BURST_4B		(0x1 << 20)
#define		EXUART_UCON_TX_DMA_BURST_8B		(0x2 << 20)
#define		EXUART_UCON_TX_DMA_BURST_16B		(0x3 << 20)
#define	EXUART_UFCON				0x08
#define		EXUART_UFCON_FIFO_ENABLE		(0x1 << 0)
#define		EXUART_UFCON_RX_FIFO_RESET		(0x1 << 1)
#define		EXUART_UFCON_TX_FIFO_RESET		(0x1 << 2)
#define		EXUART_UFCON_RX_FIFO_TRIGGER_LEVEL	(((x) & 0x7) << 4)
#define		EXUART_UFCON_TX_FIFO_TRIGGER_LEVEL	(((x) & 0x7) << 8)
#define	EXUART_UMCON				0x0c
#define		EXUART_UMCON_RTS			(0x1 << 0)
#define		EXUART_UMCON_MODEM_INT_EN		(0x1 << 3)
#define		EXUART_UMCON_AUTO_FLOW_CONTROL		(0x1 << 4)
#define		EXUART_UMCON_RTS_TRIGGER_LEVEL		(((x) & 0x7) << 5)
#define	EXUART_UTRSTAT				0x10
#define		EXUART_UTRSTAT_RXBREADY			(0x1 << 0)
#define		EXUART_UTRSTAT_TXBEMPTY			(0x1 << 1)
#define		EXUART_UTRSTAT_TXEMPTY			(0x1 << 2)
#define		EXUART_UTRSTAT_RX_TIMEOUT_STSCLR	(0x1 << 3)
#define		EXUART_UTRSTAT_RX_DMA_FSM_STS(x)	(((x) >> 8) & 0xf)
#define		EXUART_UTRSTAT_TX_DMA_FSM_STS(x)	(((x) >> 12) & 0xf)
#define		EXUART_UTRSTAT_RX_FIFO_CNT_TIMEOUT(x)	(((x) >> 16) & 0xff)
#define	EXUART_UERSTAT				0x14
#define		EXUART_UERSTAT_OVERRUN			(0x1 << 0)
#define		EXUART_UERSTAT_PARITY			(0x1 << 1)
#define		EXUART_UERSTAT_FRAME			(0x1 << 2)
#define		EXUART_UERSTAT_BREAK			(0x1 << 3)
#define	EXUART_UFSTAT				0x18
#define		EXUART_UFSTAT_RX_FIFO_CNT(x)		(((x) >> 0) & 0xff) /* 0 when full */
#define		EXUART_UFSTAT_RX_FIFO_CNT_MASK		(0xff << 0) /* 0 when full */
#define		EXUART_UFSTAT_RX_FIFO_FULL		(0x1 << 8)
#define		EXUART_UFSTAT_RX_FIFO_ERROR		(0x1 << 9)
#define		EXUART_UFSTAT_TX_FIFO_CNT(x)		(((x) >> 16) & 0xff) /* 0 when full */
#define		EXUART_UFSTAT_TX_FIFO_CNT_MASK		(0xff << 16) /* 0 when full */
#define		EXUART_UFSTAT_TX_FIFO_FULL		(0x1 << 24)
#define	EXUART_UMSTAT				0x1c
#define		EXUART_UMSTAT_CTS			(0x1 << 0)
#define		EXUART_UMSTAT_DELTA_CTS			(0x1 << 4)
#define	EXUART_UTXH				0x20
#define	EXUART_URXH				0x24
#define	EXUART_UBRDIV				0x28
#define		EXUART_UBRDIV_SEL(x)			(((x) & 0xffff) << 0)
#define	EXUART_UFRACVAL				0x2c
#define		EXUART_UFRACVAL_SEL(x)			(((x) & 0xf) << 0)
#define	EXUART_UINTP				0x30
#define		EXUART_UINTP_RXD			(0x1 << 0)
#define		EXUART_UINTP_ERROR			(0x1 << 1)
#define		EXUART_UINTP_TXD			(0x1 << 2)
#define		EXUART_UINTP_MODEM			(0x1 << 3)
#define	EXUART_UINTS				0x34
#define		EXUART_UINTS_RXD			(0x1 << 0)
#define		EXUART_UINTS_ERROR			(0x1 << 1)
#define		EXUART_UINTS_TXD			(0x1 << 2)
#define		EXUART_UINTS_MODEM			(0x1 << 3)
#define	EXUART_UINTM				0x38
#define		EXUART_UINTM_RXD			(0x1 << 0)
#define		EXUART_UINTM_ERROR			(0x1 << 1)
#define		EXUART_UINTM_TXD			(0x1 << 2)
#define		EXUART_UINTM_MODEM			(0x1 << 3)


code:
/*
 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
 *
 * 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.
 */

int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
    tcflag_t cflag);


code:
/* $OpenBSD: exynos.c,v 1.8 2015/07/17 17:33:50 jsg Exp $ */
/*
 * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com>
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/bus.h>
#if NFDT > 0
#include <machine/fdt.h>
#endif

#include <armv7/armv7/armv7var.h>

int	exynos_match(struct device *, void *, void *);
void	exynos4_init();
void	exynos5_init();

struct cfattach exynos_ca = {
	sizeof(struct armv7_softc), exynos_match, armv7_attach, NULL,
	config_activate_children
};

struct cfdriver exynos_cd = {
	NULL, "exynos", DV_DULL
};

struct board_dev chromebook_devs[] = {
	{ "exmct",	0 },
	{ "exdog",	0 },
	{ "exclock",	0 },
	{ "expower",	0 },
	{ "exsysreg",	0 },
//	{ "exuart",	1 },
	{ "exgpio",	0 },
	{ "exgpio",	1 },
	{ "exgpio",	2 },
	{ "exgpio",	3 },
	{ "exgpio",	4 },
	{ "exgpio",	5 },
	{ "exehci",	0 },
	{ "exiic",	4 },
//	{ "exesdhc",	2 },
//	{ "exesdhc",	3 },
	{ "exdisplay",	0 },
	{ NULL,		0 }
};

/* Samsung Mobile NURI board */
struct board_dev nuri_devs[] = {
	{ "exmct",	0 },
	{ "exdog",	0 },
//	{ "exclock",	0 },
	{ "expower",	0 },
	{ "exsysreg",	0 },
//	{ "exuart",	0 },
	{ "exuart",	1 },
	{ "exuart",	2 },
	{ "exuart",	3 },
	{ "exgpio",	0 },
	{ "exgpio",	1 },
	{ "exgpio",	2 },
	{ "exgpio",	3 },
	{ "exgpio",	4 },
	{ "exgpio",	5 },
//	{ "exehci",	0 },
	{ "exiic",	0 },
//	{ "exesdhc",	2 },
	{ NULL,		0 }
};

/*
 * S5PC210/Exynos4210 reference board
 * has a LAN9215 (emulated in qemu as LAN9118)
 */
struct board_dev smdkc210_devs[] = {
	{ "exmct",	0 },
	{ "exdog",	0 },
//	{ "exclock",	0 },
	{ "expower",	0 },
	{ "exsysreg",	0 },
//	{ "exuart",	0 },
	{ "exuart",	1 },
	{ "exuart",	2 },
	{ "exuart",	3 },
	{ "exgpio",	0 },
	{ "exgpio",	1 },
	{ "exgpio",	2 },
	{ "exgpio",	3 },
	{ "exgpio",	4 },
	{ "exgpio",	5 },
//	{ "exehci",	0 },
	{ "exiic",	0 },
//	{ "exesdhc",	2 },
	{ NULL,		0 }
};

struct armv7_board exynos_boards[] = {
	{
		BOARD_ID_EXYNOS5_CHROMEBOOK,
		"Exynos 5 Chromebook",
		chromebook_devs,
		exynos5_init,
	},
	{
		BOARD_ID_EXYNOS4_NURI,
		"Samsung NURI",
		nuri_devs,
		exynos4_init,
	},
	{
		BOARD_ID_EXYNOS4_SMDKC210,
		"Samsung SMDKC210",
		smdkc210_devs,
		exynos4_init,
	},
	{ 0, NULL, NULL, NULL },
};

struct board_dev *
exynos_board_devs(void)
{
	int i;

	for (i = 0; exynos_boards[i].name != NULL; i++) {
		if (exynos_boards[i].board_id == board_id)
			return (exynos_boards[i].devs);
	}
	return (NULL);
}

void
exynos_board_init(void)
{
	int i;

	for (i = 0; exynos_boards[i].name != NULL; i++) {
		if (exynos_boards[i].board_id == board_id) {
			exynos_boards[i].init();
			break;
		}
	}
}

const char *
exynos_board_name(void)
{
	int i;

	for (i = 0; exynos_boards[i].name != NULL; i++) {
		if (exynos_boards[i].board_id == board_id) {
			return (exynos_boards[i].name);
			break;
		}
	}
	return (NULL);
}

int
exynos_match(struct device *parent, void *cfdata, void *aux)
{
#if NFDT > 0
	/* If we're running with fdt, do not attach. */
	/* XXX: Find a better way. */
	if (fdt_next_node(0))
		return (0);
#endif

	return (exynos_board_devs() != NULL);
}


code:
/*	$OpenBSD: exynos4.c,v 1.2 2015/07/15 21:09:40 jsg Exp $	*/
/*
 * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
 * Copyright (c) 2012 Patrick Wildt <patrick@blueri.se>
 *
 * 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <arch/arm/armv7/armv7var.h>

#include <armv7/armv7/armv7var.h>

/* IRQs are defined without the 32 cpu IRQs */

#define MCT_ADDR	0x10050000
#define MCT_SIZE	0x800

#define WD_ADDR		0x10060000
#define WD_SIZE		0x400
#define WD_IRQ		43

#define CLOCK_ADDR	0x10030000
#define CLOCK_SIZE	0x20000

#define POWER_ADDR	0x10020000
#define POWER_SIZE	0x4000

#define SYSREG_ADDR	0x10010000
#define SYSREG_SIZE	0x400

#define GIC_CPU_ADDR	0x10480000
#define GIC_CPU_SIZE	0x10000
#define GIC_DIST_ADDR	0x10490000
#define GIC_DIST_SIZE	0x10000

#define UARTx_SIZE	0x100
#define UART1_ADDR	0x13800000
#define UART2_ADDR	0x13810000
#define UART3_ADDR	0x13820000
#define UART4_ADDR	0x13830000
#define UART5_ADDR	0x13840000

#define UART1_IRQ	52
#define UART2_IRQ	53
#define UART3_IRQ	54
#define UART4_IRQ	55
#define UART5_IRQ	56

#define USB_EHCI_ADDR	0x12580000
#define USB_OHCI_ADDR	0x12590000
#define USB_PHY_ADDR	0x125b0000
#define USBx_SIZE	0x1000

#define USB_IRQ		70

#define GPIO1_ADDR	0x11400000
#define GPIO1_SIZE	0x280
#define GPIO2_ADDR	0x11400C00
#define GPIO2_SIZE	0x80
#define GPIO3_ADDR	0x13400000
#define GPIO3_SIZE	0x120
#define GPIO4_ADDR	0x10D10000
#define GPIO4_SIZE	0x80
#define GPIO5_ADDR	0x10D100C0
#define GPIO5_SIZE	0x20
#define GPIO6_ADDR	0x03860000
#define GPIO6_SIZE	0x20

#define I2Cx_SIZE	0x100
#define I2C1_ADDR	0x13860000
#define I2C2_ADDR	0x13870000
#define I2C3_ADDR	0x13880000
#define I2C4_ADDR	0x13890000
#define I2C5_ADDR	0x138a0000
#define I2C6_ADDR	0x138b0000
#define I2C7_ADDR	0x138c0000
#define I2C8_ADDR	0x138d0000

#define I2C1_IRQ	58
#define I2C2_IRQ	59
#define I2C3_IRQ	60
#define I2C4_IRQ	61
#define I2C5_IRQ	62
#define I2C6_IRQ	63
#define I2C7_IRQ	64
#define I2C8_IRQ	65

#define ESDHCx_SIZE	0x1000
#define ESDHC1_ADDR	0x12510000
#define ESDHC2_ADDR	0x12520000
#define ESDHC3_ADDR	0x12530000
#define ESDHC4_ADDR	0x12540000

#define ESDHC1_IRQ	73
#define ESDHC2_IRQ	74
#define ESDHC3_IRQ	75
#define ESDHC4_IRQ	76
#define SDMMC_IRQ	77

struct armv7_dev exynos4_devs[] = {

	/*
	 * Multi-Core Timer
	 */
	{ .name = "exmct",
	  .unit = 0,
	  .mem = {
	    { MCT_ADDR, MCT_SIZE },
	  },
	},

	/*
	 * Watchdog Timer
	 */
	{ .name = "exdog",
	  .unit = 0,
	  .mem = {
	    { WD_ADDR, WD_SIZE },
	  },
	},

	/*
	 * Clock
	 */
	{ .name = "exclock",
	  .unit = 0,
	  .mem = {
	    { CLOCK_ADDR, CLOCK_SIZE },
	  },
	},

	/*
	 * Power
	 */
	{ .name = "expower",
	  .unit = 0,
	  .mem = {
	    { POWER_ADDR, POWER_SIZE },
	  },
	},

	/*
	 * Sysreg
	 */
	{ .name = "exsysreg",
	  .unit = 0,
	  .mem = {
	    { SYSREG_ADDR, SYSREG_SIZE },
	  },
	},

	/*
	 * UART
	 */
	{ .name = "exuart",
	  .unit = 0,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART1_IRQ }
	},
	{ .name = "exuart",
	  .unit = 1,
	  .mem = { { UART2_ADDR, UARTx_SIZE } },
	  .irq = { UART2_IRQ }
	},
	{ .name = "exuart",
	  .unit = 2,
	  .mem = { { UART3_ADDR, UARTx_SIZE } },
	  .irq = { UART3_IRQ }
	},
	{ .name = "exuart",
	  .unit = 3,
	  .mem = { { UART4_ADDR, UARTx_SIZE } },
	  .irq = { UART4_IRQ }
	},
	{ .name = "exuart",
	  .unit = 4,
	  .mem = { { UART5_ADDR, UARTx_SIZE } },
	  .irq = { UART5_IRQ }
	},

	/*
	 * GPIO
	 */
	{ .name = "exgpio",
	  .unit = 0,
	  .mem = { { GPIO1_ADDR, GPIO1_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 1,
	  .mem = { { GPIO2_ADDR, GPIO2_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 2,
	  .mem = { { GPIO3_ADDR, GPIO3_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 3,
	  .mem = { { GPIO4_ADDR, GPIO4_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 4,
	  .mem = { { GPIO5_ADDR, GPIO5_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 5,
	  .mem = { { GPIO6_ADDR, GPIO6_SIZE } },
	},

	/*
	 * I2C
	 */
	{ .name = "exiic",
	  .unit = 0,
	  .mem = { { I2C1_ADDR, I2Cx_SIZE } },
	  .irq = { I2C1_IRQ },
	},

	{ .name = "exiic",
	  .unit = 1,
	  .mem = { { I2C2_ADDR, I2Cx_SIZE } },
	  .irq = { I2C2_IRQ },
	},

	{ .name = "exiic",
	  .unit = 2,
	  .mem = { { I2C3_ADDR, I2Cx_SIZE } },
	  .irq = { I2C3_IRQ },
	},

	{ .name = "exiic",
	  .unit = 3,
	  .mem = { { I2C4_ADDR, I2Cx_SIZE } },
	  .irq = { I2C4_IRQ },
	},

	{ .name = "exiic",
	  .unit = 4,
	  .mem = { { I2C5_ADDR, I2Cx_SIZE } },
	  .irq = { I2C5_IRQ },
	},

	{ .name = "exiic",
	  .unit = 5,
	  .mem = { { I2C6_ADDR, I2Cx_SIZE } },
	  .irq = { I2C6_IRQ },
	},

	{ .name = "exiic",
	  .unit = 6,
	  .mem = { { I2C7_ADDR, I2Cx_SIZE } },
	  .irq = { I2C7_IRQ },
	},

	{ .name = "exiic",
	  .unit = 7,
	  .mem = { { I2C8_ADDR, I2Cx_SIZE } },
	  .irq = { I2C8_IRQ },
	},

	/*
	 * ESDHC
	 */
	{ .name = "exesdhc",
	  .unit = 0,
	  .mem = { { ESDHC1_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC1_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 1,
	  .mem = { { ESDHC2_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC2_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 2,
	  .mem = { { ESDHC3_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC3_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 3,
	  .mem = { { ESDHC4_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC4_IRQ },
	},

	/*
	 * USB
	 */
	{ .name = "exehci",
	  .unit = 0,
	  .mem = {
	    { USB_EHCI_ADDR, USBx_SIZE },
	    { USB_PHY_ADDR, USBx_SIZE },
	  },
	  .irq = { USB_IRQ }
	},

	/* Terminator */
	{ .name = NULL,
	  .unit = 0
	}
};

extern paddr_t gic_dist_base, gic_cpu_base, gic_dist_size, gic_cpu_size;

void
exynos4_init(void)
{
	armv7_set_devs(exynos4_devs);

	gic_dist_base = GIC_DIST_ADDR;
	gic_dist_size = GIC_DIST_SIZE;
	gic_cpu_base = GIC_CPU_ADDR;
	gic_cpu_size = GIC_CPU_SIZE;
}


code:
/* $OpenBSD: exynos5.c,v 1.4 2015/07/17 17:33:50 jsg Exp $ */
/*
 * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
 * Copyright (c) 2012 Patrick Wildt <patrick@blueri.se>
 *
 * 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <arch/arm/armv7/armv7var.h>

#include <armv7/armv7/armv7var.h>

/* XXX ??? */
/* IRQs are defined without the 32 cpu IRQs */

#define MCT_ADDR	0x101c0000
#define MCT_SIZE	0x1000

#define WD_ADDR		0x101d0000
#define WD_SIZE		0x400

#define CLOCK_ADDR	0x10010000
#define CLOCK_SIZE	0x5000

#define POWER_ADDR	0x10040000
#define POWER_SIZE	0x1000

#define SYSREG_ADDR	0x10050000
#define SYSREG_SIZE	0x1000

#define GIC_DIST_ADDR	0x10481000
#define GIC_DIST_SIZE	0x1000
#define GIC_CPU_ADDR	0x10482000
#define GIC_CPU_SIZE	0x1000

#define UARTx_SIZE	0x100
#define UART1_ADDR	0x12c00000
#define UART2_ADDR	0x12c10000
#define UART3_ADDR	0x12c20000
#define UART4_ADDR	0x12c30000

#define UART1_IRQ	51
#define UART2_IRQ	52
#define UART3_IRQ	53
#define UART4_IRQ	54

#define USB_EHCI_ADDR	0x12110000
#define USB_PHY_ADDR	0x12130000
#define USBx_SIZE	0x1000

#define USB_IRQ		71

#define GPIO1_ADDR	0x11400000
#define GPIO1_SIZE	0x280
#define GPIO2_ADDR	0x11400C00
#define GPIO2_SIZE	0x80
#define GPIO3_ADDR	0x13400000
#define GPIO3_SIZE	0x120
#define GPIO4_ADDR	0x10D10000
#define GPIO4_SIZE	0x80
#define GPIO5_ADDR	0x10D100C0
#define GPIO5_SIZE	0x20
#define GPIO6_ADDR	0x03860000
#define GPIO6_SIZE	0x20

#define I2Cx_SIZE	0x100
#define I2C1_ADDR	0x12c60000
#define I2C2_ADDR	0x12c70000
#define I2C3_ADDR	0x12c80000
#define I2C4_ADDR	0x12c90000
#define I2C5_ADDR	0x12ca0000
#define I2C6_ADDR	0x12cb0000
#define I2C7_ADDR	0x12cc0000
#define I2C8_ADDR	0x12cd0000

#define I2C1_IRQ	56
#define I2C2_IRQ	57
#define I2C3_IRQ	58
#define I2C4_IRQ	59
#define I2C5_IRQ	60
#define I2C6_IRQ	61
#define I2C7_IRQ	62
#define I2C8_IRQ	63

#define ESDHCx_SIZE	0x1000
#define ESDHC1_ADDR	0x12200000
#define ESDHC2_ADDR	0x12210000
#define ESDHC3_ADDR	0x12220000
#define ESDHC4_ADDR	0x12230000

#define ESDHC1_IRQ	75
#define ESDHC2_IRQ	76
#define ESDHC3_IRQ	77
#define ESDHC4_IRQ	78

#define PCIE_REG_ADDR	0x01ffc000
#define PCIE_REG_SIZE	0x4000
#define PCIE_MAP_ADDR	0x01000000
#define PCIE_MAP_SIZE	0xffc000

#define PCIE_IRQ0	120
#define PCIE_IRQ1	121
#define PCIE_IRQ2	122
#define PCIE_IRQ3	123

#define EXDISPLAY_ADDR	0xbfc00000
#define EXDISPLAY_SIZE	0x202000

struct armv7_dev exynos5_devs[] = {

	/*
	 * Multi-Core Timer
	 */
	{ .name = "exmct",
	  .unit = 0,
	  .mem = {
	    { MCT_ADDR, MCT_SIZE },
	  },
	},

	/*
	 * Watchdog Timer
	 */
	{ .name = "exdog",
	  .unit = 0,
	  .mem = {
	    { WD_ADDR, WD_SIZE },
	  },
	},

	/*
	 * Clock
	 */
	{ .name = "exclock",
	  .unit = 0,
	  .mem = {
	    { CLOCK_ADDR, CLOCK_SIZE },
	  },
	},

	/*
	 * Power
	 */
	{ .name = "expower",
	  .unit = 0,
	  .mem = {
	    { POWER_ADDR, POWER_SIZE },
	  },
	},

	/*
	 * Sysreg
	 */
	{ .name = "exsysreg",
	  .unit = 0,
	  .mem = {
	    { SYSREG_ADDR, SYSREG_SIZE },
	  },
	},

	/*
	 * UART
	 */
	{ .name = "exuart",
	  .unit = 0,
	  .mem = { { UART1_ADDR, UARTx_SIZE } },
	  .irq = { UART1_IRQ }
	},
	{ .name = "exuart",
	  .unit = 1,
	  .mem = { { UART2_ADDR, UARTx_SIZE } },
	  .irq = { UART2_IRQ }
	},
	{ .name = "exuart",
	  .unit = 2,
	  .mem = { { UART3_ADDR, UARTx_SIZE } },
	  .irq = { UART3_IRQ }
	},
	{ .name = "exuart",
	  .unit = 3,
	  .mem = { { UART4_ADDR, UARTx_SIZE } },
	  .irq = { UART4_IRQ }
	},

	/*
	 * GPIO
	 */
	{ .name = "exgpio",
	  .unit = 0,
	  .mem = { { GPIO1_ADDR, GPIO1_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 1,
	  .mem = { { GPIO2_ADDR, GPIO2_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 2,
	  .mem = { { GPIO3_ADDR, GPIO3_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 3,
	  .mem = { { GPIO4_ADDR, GPIO4_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 4,
	  .mem = { { GPIO5_ADDR, GPIO5_SIZE } },
	},

	{ .name = "exgpio",
	  .unit = 5,
	  .mem = { { GPIO6_ADDR, GPIO6_SIZE } },
	},

	/*
	 * I2C
	 */
	{ .name = "exiic",
	  .unit = 0,
	  .mem = { { I2C1_ADDR, I2Cx_SIZE } },
	  .irq = { I2C1_IRQ },
	},

	{ .name = "exiic",
	  .unit = 1,
	  .mem = { { I2C2_ADDR, I2Cx_SIZE } },
	  .irq = { I2C2_IRQ },
	},

	{ .name = "exiic",
	  .unit = 2,
	  .mem = { { I2C3_ADDR, I2Cx_SIZE } },
	  .irq = { I2C3_IRQ },
	},

	{ .name = "exiic",
	  .unit = 3,
	  .mem = { { I2C4_ADDR, I2Cx_SIZE } },
	  .irq = { I2C4_IRQ },
	},

	{ .name = "exiic",
	  .unit = 4,
	  .mem = { { I2C5_ADDR, I2Cx_SIZE } },
	  .irq = { I2C5_IRQ },
	},

	{ .name = "exiic",
	  .unit = 5,
	  .mem = { { I2C6_ADDR, I2Cx_SIZE } },
	  .irq = { I2C6_IRQ },
	},

	{ .name = "exiic",
	  .unit = 6,
	  .mem = { { I2C7_ADDR, I2Cx_SIZE } },
	  .irq = { I2C7_IRQ },
	},

	{ .name = "exiic",
	  .unit = 7,
	  .mem = { { I2C8_ADDR, I2Cx_SIZE } },
	  .irq = { I2C8_IRQ },
	},

	/*
	 * ESDHC
	 */
	{ .name = "exesdhc",
	  .unit = 0,
	  .mem = { { ESDHC1_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC1_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 1,
	  .mem = { { ESDHC2_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC2_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 2,
	  .mem = { { ESDHC3_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC3_IRQ },
	},

	{ .name = "exesdhc",
	  .unit = 3,
	  .mem = { { ESDHC4_ADDR, ESDHCx_SIZE } },
	  .irq = { ESDHC4_IRQ },
	},

	/*
	 * USB
	 */
	{ .name = "exehci",
	  .unit = 0,
	  .mem = {
	    { USB_EHCI_ADDR, USBx_SIZE },
	    { USB_PHY_ADDR, USBx_SIZE },
	  },
	  .irq = { USB_IRQ }
	},

	{ .name = "exdisplay",
	  .unit = 0,
	  .mem = { { EXDISPLAY_ADDR, EXDISPLAY_SIZE } },
	},

	/* Terminator */
	{ .name = NULL,
	  .unit = 0
	}
};

extern paddr_t gic_dist_base, gic_cpu_base, gic_dist_size, gic_cpu_size;

void
exynos5_init(void)
{
	armv7_set_devs(exynos5_devs);

	gic_dist_base = GIC_DIST_ADDR;
	gic_dist_size = GIC_DIST_SIZE;
	gic_cpu_base = GIC_CPU_ADDR;
	gic_cpu_size = GIC_CPU_SIZE;
}


code:
/*	$OpenBSD: exynos_machdep.c,v 1.5 2015/06/07 16:54:16 jsg Exp $	*/
/*
 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 "fdt.h"

#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/termios.h>

#include <machine/bus.h>

#if NFDT > 0
#include <machine/fdt.h>
#endif

#include <arm/cortex/smc.h>
#include <arm/armv7/armv7var.h>
#include <armv7/armv7/armv7var.h>
#include <armv7/exynos/exdisplayvar.h>
#include <armv7/exynos/exuartvar.h>
#include <armv7/armv7/armv7_machdep.h>

extern void exdog_reset(void);
extern char *exynos_board_name(void);
extern struct board_dev *exynos_board_devs(void);
extern void exynos_board_init(void);
extern int comcnspeed;
extern int comcnmode;

static void
exynos_platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
    uint32_t op, uint32_t val)
{
	bus_space_write_4(iot, ioh, off, val);
}

static void
exynos_platform_init_cons(void)
{
	paddr_t paddr;
	size_t size;

	switch (board_id) {
	case BOARD_ID_EXYNOS5_CHROMEBOOK:
#if NFDT > 0
		void *node;
		node = fdt_find_node("/framebuffer");
		if (node != NULL) {
			uint32_t *mem;
			if (fdt_node_property(node, "reg", (char **)&mem) >= 2*sizeof(uint32_t)) {
				paddr = betoh32(*mem++);
				size = betoh32(*mem);
			}
		}
#else
		paddr = 0xbfc00000;
		size = 0x202000;
#endif
		exdisplay_cnattach(&armv7_bs_tag, paddr, size);
		break;
	case BOARD_ID_EXYNOS4_SMDKC210:
	case BOARD_ID_EXYNOS4_NURI:
		paddr = 0x13800000;
		exuartcnattach(&armv7_bs_tag, paddr, comcnspeed, comcnmode);
		break;
	default:
		printf("board type %x unknown", board_id);
		return;
		/* XXX - HELP */
	}
}

static void
exynos_platform_watchdog_reset(void)
{
	exdog_reset();
}

static void
exynos_platform_powerdown(void)
{

}

const char *
exynos_platform_board_name(void)
{
	return (exynos_board_name());
}

static void
exynos_platform_disable_l2_if_needed(void)
{

}

void
exynos_platform_board_init(void)
{
	exynos_board_init();
}

struct armv7_platform exynos_platform = {
	.boot_name = "OpenBSD/exynos",
	.board_name = exynos_platform_board_name,
	.board_init = exynos_platform_board_init,
	.smc_write = exynos_platform_smc_write,
	.init_cons = exynos_platform_init_cons,
	.watchdog_reset = exynos_platform_watchdog_reset,
	.powerdown = exynos_platform_powerdown,
	.disable_l2_if_needed = exynos_platform_disable_l2_if_needed,
};

struct armv7_platform *
exynos_platform_match(void)
{
	struct board_dev *devs;

	devs = exynos_board_devs();
	if (devs == NULL)
		return (NULL);

	exynos_platform.devs = devs;
	return (&exynos_platform);
}


code:
#	$OpenBSD: files.exynos,v 1.2 2015/06/07 16:54:16 jsg Exp $

define exynos {}
device exynos: exynos
attach exynos at mainbus
file	arch/armv7/exynos/exynos_machdep.c	exynos	needs-flag
file	arch/armv7/exynos/exynos.c		exynos
file	arch/armv7/exynos/exynos4.c		exynos
file	arch/armv7/exynos/exynos5.c		exynos

# serial ports
device exuart
attach	exuart at exynos
attach	exuart at fdt with exuart_fdt
file	arch/armv7/exynos/exuart.c		exuart | exuart_fdt

device exdisplay: wsemuldisplaydev, rasops16
attach exdisplay at exynos
attach exdisplay at fdt with exdisplay_fdt
file	arch/armv7/exynos/exdisplay.c		exdisplay | exdisplay_fdt

device exclock
attach exclock at exynos
attach exclock at fdt with exclock_fdt
file	arch/armv7/exynos/exclock.c		exclock | exclock_fdt

device expower
attach expower at exynos
attach expower at fdt with expower_fdt
file	arch/armv7/exynos/expower.c		expower | expower_fdt

device exsysreg
attach exsysreg at exynos
attach exsysreg at fdt with exsysreg_fdt
file	arch/armv7/exynos/exsysreg.c		exsysreg | exsysreg_fdt

device exmct
attach exmct at exynos
attach exmct at fdt with exmct_fdt
file	arch/armv7/exynos/exmct.c		exmct | exiomuxc_fdt

device exdog
attach exdog at exynos
attach exdog at fdt with exdog_fdt
file	arch/armv7/exynos/exdog.c		exdog | exdog_fdt

device exgpio
attach exgpio at exynos
attach exgpio at fdt with exgpio_fdt
file	arch/armv7/exynos/exgpio.c		exgpio | exgpio_fdt

device	exiic: i2cbus
attach	exiic at exynos
attach	exiic at fdt with exiic_fdt
file	arch/armv7/exynos/exiic.c		exiic | exiic_fdt

device exehci {}
attach exehci at exynos with exehci
attach exehci at fdt with exehci_fdt
attach ehci at exehci with ehci_ex
file	arch/armv7/exynos/exehci.c		exehci | exehci_fdt

device exesdhc: sdmmcbus
attach exesdhc at exynos
attach exesdhc at fdt with exesdhc_fdt
file	arch/armv7/exynos/exesdhc.c		exesdhc | exesdhc_fdt

device	crosec: wskbddev
attach	crosec at i2c
file	arch/armv7/exynos/crosec.c		crosec
file	arch/armv7/exynos/crosec_kbd.c		crosec

device	tpspmic
attach	tpspmic at i2c
file	arch/armv7/exynos/tps65090.c		tpspmic


code:
/* $OpenBSD: tps65090.c,v 1.2 2015/07/19 02:41:39 bmercer Exp $ */
/*
 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>
#include <sys/malloc.h>

#include <dev/i2c/i2cvar.h>

#define	REG_IRQ1		0x00
#define	REG_IRQ2		0x01
#define	REG_IRQ1MASK		0x02
#define	REG_IRQ2MASK		0x03
#define	REG_CG_CTRL0		0x04
#define	 REG_CG_CTRL0_ENC_MASK		(1 << 0)
#define	REG_CG_CTRL1		0x05
#define	REG_CG_CTRL2		0x06
#define	REG_CG_CTRL3		0x07
#define	REG_CG_CTRL4		0x08
#define	REG_CG_CTRL5		0x09
#define	REG_CG_STATUS1		0x0a
#define	REG_CG_STATUS2		0x0b
#define	REG_DCDC1_CTRL		0x0c
#define	REG_DCDC2_CTRL		0x0d
#define	REG_DCDC3_CTRL		0x0e
#define	REG_FET1_CTRL		0x0f
#define	REG_FET2_CTRL		0x10
#define	REG_FET3_CTRL		0x11
#define	REG_FET4_CTRL		0x12
#define	REG_FET5_CTRL		0x13
#define	REG_FET6_CTRL		0x14
#define	REG_FET7_CTRL		0x15
#define	REG_FETx_CTRL(x)	(0x0e + (x))
#define	 REG_FETx_CTRL_ENFET		(1 << 0) /* Enable FET */
#define	 REG_FETx_CTRL_ADENFET		(1 << 1) /* Enable output auto discharge */
#define	 REG_FETx_CTRL_WAIT		(3 << 2) /* Overcurrent timeout max */
#define	 REG_FETx_CTRL_PGFET		(1 << 4) /* Power good for FET status */
#define	 REG_FETx_CTRL_TOFET		(1 << 7) /* Timeout, startup, overload */
#define	REG_AD_CTRL		0x16
#define	REG_AD_OUT1		0x17
#define	REG_AD_OUT2		0x18

#define	NFET			7

#ifdef DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif

struct tps65090_softc {
	struct device		sc_dev;
	i2c_tag_t sc_tag;
	i2c_addr_t sc_addr;
};

struct tps65090_softc *tps65090_sc;

int	tps65090_match(struct device *, void *, void *);
void	tps65090_attach(struct device *, struct device *, void *);

int	tps65090_read_reg(struct tps65090_softc *, uint8_t);
void	tps65090_write_reg(struct tps65090_softc *, uint8_t, uint8_t);
int	tps65090_fet_set(int, int);
int	tps65090_fet_get(int);
void	tps65090_fet_enable(int);
void	tps65090_fet_disable(int);
int	tps65090_get_charging(void);
void	tps65090_set_charging(int);

struct cfattach tpspmic_ca = {
	sizeof(struct tps65090_softc), tps65090_match, tps65090_attach
};

struct cfdriver tpspmic_cd = {
	NULL, "tpspmic", DV_DULL
};

int
tps65090_match(struct device *parent, void *match, void *aux)
{
	struct i2c_attach_args *ia = aux;

	if (strcmp(ia->ia_name, "tps65090") == 0)
		return (1);
	return (0);
}

void
tps65090_attach(struct device *parent, struct device *self, void *aux)
{
	struct tps65090_softc *sc = (struct tps65090_softc *)self;
	struct i2c_attach_args *ia = aux;

	sc->sc_tag = ia->ia_tag;
	sc->sc_addr = ia->ia_addr;
	tps65090_sc = sc;

	printf("\n");
}

/*
 * FET1: Backlight on the Chromebook
 * FET6: LCD panel on the Chromebook
 */
void
tps65090_fet_enable(int fet)
{
	int i;

	if (fet < 1 || fet > NFET)
		return;

	for (i = 0; i < 10; i++) {
		if (!tps65090_fet_set(fet, 1))
			break;

		if (i != 9)
			tps65090_fet_set(fet, 0);
	}
}

void
tps65090_fet_disable(int fet)
{
	if (fet < 1 || fet > NFET)
		return;

	tps65090_fet_set(fet, 0);
}

int
tps65090_fet_set(int fet, int set)
{
	struct tps65090_softc *sc = tps65090_sc;
	int i;
	uint8_t val, check;

	val = REG_FETx_CTRL_ADENFET | REG_FETx_CTRL_WAIT;
	if (set)
		val |= REG_FETx_CTRL_ENFET;

	tps65090_write_reg(sc, REG_FETx_CTRL(fet), val);
	for (i = 0; i < 5; i++) {
		check = tps65090_read_reg(sc, REG_FETx_CTRL(fet));

		/* FET state correct? */
		if (!!(check & REG_FETx_CTRL_PGFET) == set)
			return 0;

		/* Timeout, don't need to try again. */
		if (check & REG_FETx_CTRL_TOFET)
			break;

		delay(1000);
	}

	return -1;
}

int
tps65090_fet_get(int fet)
{
	struct tps65090_softc *sc = tps65090_sc;
	uint8_t val = tps65090_read_reg(sc, REG_FETx_CTRL(fet));
	return val & REG_FETx_CTRL_ENFET;
}

int
tps65090_get_charging()
{
	struct tps65090_softc *sc = tps65090_sc;
	uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
	return val & REG_CG_CTRL0_ENC_MASK;
}

void
tps65090_set_charging(int set)
{
	struct tps65090_softc *sc = tps65090_sc;
	uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
	if (set)
		val |= REG_CG_CTRL0_ENC_MASK;
	else
		val &= REG_CG_CTRL0_ENC_MASK;
	tps65090_write_reg(sc, REG_CG_CTRL0, val);
}

int
tps65090_read_reg(struct tps65090_softc *sc, uint8_t cmd)
{
	uint8_t val;

	iic_acquire_bus(sc->sc_tag, 0);
	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
	    sc->sc_addr, &cmd, 1, &val, 1, 0);
	iic_release_bus(sc->sc_tag, 0);

	return val;
}

void
tps65090_write_reg(struct tps65090_softc *sc, uint8_t cmd, uint8_t val)
{
	iic_acquire_bus(sc->sc_tag, 0);
	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
	    sc->sc_addr, &cmd, 1, &val, 1, 0);
	iic_release_bus(sc->sc_tag, 0);
}


code:
#	$OpenBSD: files.imx,v 1.3 2015/05/15 15:35:43 jsg Exp $

define imx {}
device imx: imx
attach imx at mainbus
file	arch/armv7/imx/imx_machdep.c		imx	needs-flag
file	arch/armv7/imx/imx.c			imx
file	arch/armv7/imx/imx6.c

# serial ports
device imxuart
attach	imxuart at imx
file	arch/armv7/imx/imxuart.c		imxuart

device imxccm
attach imxccm at imx
file	arch/armv7/imx/imxccm.c		imxccm

device imxiomuxc
attach imxiomuxc at imx
file	arch/armv7/imx/imxiomuxc.c	imxiomuxc

device imxdog
attach imxdog at imx
file	arch/armv7/imx/imxdog.c		imxdog

device imxocotp
attach imxocotp at imx
file	arch/armv7/imx/imxocotp.c		imxocotp

device imxgpio
attach imxgpio at imx
file	arch/armv7/imx/imxgpio.c		imxgpio

device	imxiic: i2cbus
attach	imxiic at imx
file	arch/armv7/imx/imxiic.c		imxiic

device imxenet: ether, ifnet, mii, ifmedia
attach imxenet at imx
file	arch/armv7/imx/imxenet.c		imxenet

attach ehci at imx with imxehci
file	arch/armv7/imx/imxehci.c		imxehci

device imxesdhc: sdmmcbus
attach imxesdhc at imx
file	arch/armv7/imx/imxesdhc.c		imxesdhc

attach ahci at imx with imxahci
file	arch/armv7/imx/imxahci.c		imxahci


code:
/* $OpenBSD: imx.c,v 1.8 2015/05/20 00:14:55 jsg Exp $ */
/*
 * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com>
 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
 *
 * 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 <sys/param.h>
#include <sys/systm.h>

#include <machine/bus.h>

#include <armv7/armv7/armv7var.h>

int	imx_match(struct device *, void *, void *);
void	imx6_init();

struct cfattach imx_ca = {
	sizeof(struct armv7_softc), imx_match, armv7_attach, NULL,
	config_activate_children
};

struct cfdriver imx_cd = {
	NULL, "imx", DV_DULL
};

struct board_dev hummingboard_devs[] = {
	{ "imxocotp",	0 },
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxuart",	0 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	1 },
	{ "ehci",	0 },
	{ "ehci",	1 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev phyflex_imx6_devs[] = {
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxocotp",	0 },
	{ "imxuart",	3 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	1 },
	{ "imxesdhc",	2 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev sabrelite_devs[] = {
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxocotp",	0 },
	{ "imxuart",	1 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	2 },
	{ "imxesdhc",	3 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev sabresd_devs[] = {
	{ "imxocotp",	0 },
	{ "imxccm",	0 },
	{ "imxtemp",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxuart",	0 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	1 },
	{ "imxesdhc",	2 },
	{ "imxesdhc",	3 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev udoo_devs[] = {
	{ "imxocotp",	0 },
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxuart",	1 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	2 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev utilite_devs[] = {
	{ "imxocotp",	0 },
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxuart",	3 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	2 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev novena_devs[] = {
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxocotp",	0 },
	{ "imxuart",	1 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxesdhc",	1 },
	{ "imxesdhc",	2 },
	{ "ehci",	0 },
	{ "imxenet",	0 },
	{ "ahci",	0 },
	{ NULL,		0 }
};

struct board_dev wandboard_devs[] = {
	{ "imxccm",	0 },
	{ "imxiomuxc",	0 },
	{ "imxdog",	0 },
	{ "imxocotp",	0 },
	{ "imxuart",	0 },
	{ "imxgpio",	0 },
	{ "imxgpio",	1 },
	{ "imxgpio",	2 },
	{ "imxgpio",	3 },
	{ "imxgpio",	4 },
	{ "imxgpio",	5 },
	{ "imxgpio",	6 },
	{ "imxenet",	0 },
	{ "imxesdhc",	2 },
	{ "imxesdhc",	0 },
	{ "ehci",	0 },
	{ "ahci",	0 },	/* only on quad, afaik. */
	{ NULL,		0 }
};

struct armv7_board imx_boards[] = {
	{
		BOARD_ID_IMX6_CUBOXI,
		"SolidRun CuBox-i",
		hummingboard_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_HUMMINGBOARD,
		"SolidRun HummingBoard",
		hummingboard_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_PHYFLEX,
		"Phytec phyFLEX-i.MX6",
		phyflex_imx6_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_SABRELITE,
		"Freescale i.MX6 SABRE Lite",
		sabrelite_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_SABRESD,
		"Freescale i.MX6 SABRE SD",
		sabresd_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_UDOO,
		"Udoo i.MX6",
		udoo_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_UTILITE,
		"CompuLab Utilite",
		utilite_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_NOVENA,
		"Kosagi Novena",
		novena_devs,
		imx6_init,
	},
	{
		BOARD_ID_IMX6_WANDBOARD,
		"Wandboard i.MX6",
		wandboard_devs,
		imx6_init,
	},
	{ 0, NULL, NULL, NULL },
};

struct board_dev *
imx_board_devs(void)
{
	int i;

	for (i = 0; imx_boards[i].name != NULL; i++) {
		if (imx_boards[i].board_id == board_id)
			return (imx_boards[i].devs);
	}
	return (NULL);
}

void
imx_board_init(void)
{
	int i;

	for (i = 0; imx_boards[i].name != NULL; i++) {
		if (imx_boards[i].board_id == board_id) {
			imx_boards[i].init();
			break;
		}
	}
}

const char *
imx_board_name(void)
{
	int i;

	for (i = 0; imx_boards[i].name != NULL; i++) {
		if (imx_boards[i].board_id == board_id) {
			return (imx_boards[i].name);
			break;
		}
	}
	return (NULL);
}

int
imx_match(struct device *parent, void *cfdata, void *aux)
{
	return (imx_board_devs() != NULL);
}