Port-arm archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
SPI support on OMAP
Hi port-arm,
I am trying to implement the SPI bus driver on OMAP, in order to
implement the touchscreen driver on the Nokia N900 (TSC2005). I think I
am getting close, but kind of stuck at the moment - I would therefore
welcome feedback already.
During my latest tests I got the following error:
=== BEGIN PASTE ===
panic: kernel diagnostic assertion "!cpu_intr_p()" failed: file
".../sys/kern/kern_condvar.c", line 142
=== END PASTE ===
I still have no functional keypad driver to obtain a backtrace, but I
suppose this is triggered within spi_wait() whenever a transfer is
started. I'll welcome an explanation of the issue here :/
Anyway, I am attaching both drivers in their current state to this mail
(work in progress). omap2_spi.c and omap2_spireg.h should both be in
sys/arch/arm/omap, while tsc2005.c and tsc2005reg.h go in sys/dev/spi.
They also require the following changes to compile:
sys/arch/arm/omap/files.omap2:
=== BEGIN PASTE ===
# OMAP2 SPI controllers
device omapspi: spibus
attach omapspi at obio with omap2_spi
file arch/arm/omap/omap2_spi.c (omap2 | omap3) & omapspi
=== END PASTE
sys/arch/evbarm/conf/N900: (or whichever other OMAP kernel)
=== BEGIN PASTE ===
# SPI devices
omapspi0 at obio0 addr 0x48098000 size 0x1000 intr 65
omapspi1 at obio0 addr 0x4809a000 size 0x1000 intr 66
omapspi2 at obio0 addr 0x480b8000 size 0x1000 intr 91
omapspi3 at obio0 addr 0x480ba000 size 0x1000 intr 48
spi* at omapspi?
# Touchscreen
tsc2005ts0 at spi0 slave 0 intr 196
=== END PASTE ===
sys/dev/spi/files.spi:
=== BEGIN PASTE ===
# TSC2005 touchscreen
device tsc2005ts: wsmousedev
attach tsc2005ts at spi
file dev/spi/tsc2005.c tsc2005ts
=== END PASTE ===
I am also using the patch that I posted earlier on current-users@ (to
let tsc2005 interrupt on the GPIO bus).
Cheers,
--
khorben
/* $NetBSD$ */
/*
* Copyright (c) 2013 Pierre Pronchery <khorben%defora.org@localhost>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");
#include "opt_omap.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#if 0
#include <sys/conf.h>
#endif
#include <sys/bus.h>
#if 0
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/mutex.h>
#endif
#include <dev/spi/spivar.h>
#include <arm/omap/omap2_obiovar.h>
#include <arm/omap/omap2_reg.h>
#include <arm/omap/omap2_spireg.h>
#define OMAP2_MCSPI_MAX_CHANNELS 4
struct omap2_spi_channel {
SIMPLEQ_HEAD(,spi_transfer) queue;
struct spi_transfer *transfer;
struct spi_chunk *wchunk;
struct spi_chunk *rchunk;
bool running;
};
struct omap2_spi_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
void *sc_intr;
struct spi_controller sc_spi;
struct omap2_spi_channel sc_channels[OMAP2_MCSPI_MAX_CHANNELS];
};
#define SPI_READ_REG(sc, reg) \
bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
#define SPI_WRITE_REG(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
static int omap2_spi_match(device_t, cfdata_t, void *);
static void omap2_spi_attach(device_t, device_t, void *);
static int omap2_spi_configure(void *, int, int, int);
static int omap2_spi_transfer(void *, struct spi_transfer *);
static void omap2_spi_start(struct omap2_spi_softc * const, int);
static void omap2_spi_stop(struct omap2_spi_softc * const, int);
static int omap2_spi_intr(void *v);
static int omap2_spi_reset(struct omap2_spi_softc * const);
static void omap2_spi_send(struct omap2_spi_softc * const, int);
static void omap2_spi_recv(struct omap2_spi_softc * const, int);
CFATTACH_DECL_NEW(omap2_spi, sizeof(struct omap2_spi_softc),
omap2_spi_match, omap2_spi_attach, NULL, NULL);
static int
omap2_spi_match(device_t parent, cfdata_t match, void *opaque)
{
struct obio_attach_args *obio = opaque;
#if defined(OMAP_3430) || defined(OMAP_3530)
if (obio->obio_addr == SPI1_BASE_3530 ||
obio->obio_addr == SPI2_BASE_3530 ||
obio->obio_addr == SPI3_BASE_3530 ||
obio->obio_addr == SPI4_BASE_3530)
return 1;
#endif
return 0;
}
static void
omap2_spi_attach(device_t parent, device_t self, void *opaque)
{
struct omap2_spi_softc *sc = device_private(self);
struct obio_attach_args *obio = opaque;
int nslaves;
uint32_t rev;
struct spibus_attach_args sba;
int i;
aprint_naive("\n");
sc->sc_dev = self;
sc->sc_iot = obio->obio_iot;
#if defined(OMAP_3430) || defined(OMAP_3530)
switch (obio->obio_addr) {
case SPI1_BASE_3530:
nslaves = 4;
break;
case SPI2_BASE_3530:
case SPI3_BASE_3530:
nslaves = 2;
break;
case SPI4_BASE_3530:
nslaves = 1;
break;
default:
return;
}
#endif
if (bus_space_map(obio->obio_iot, obio->obio_addr, obio->obio_size, 0,
&sc->sc_ioh) != 0) {
aprint_error(": couldn't map address space\n");
return;
}
rev = SPI_READ_REG(sc, OMAP2_MCSPI_REVISION);
aprint_normal(": rev %u.%u\n",
(unsigned int)((rev & OMAP2_MCSPI_REV_MAJ_MASK)
>> OMAP2_MCSPI_REV_MAJ_SHIFT),
(unsigned int)((rev & OMAP2_MCSPI_REV_MIN_MASK)
>> OMAP2_MCSPI_REV_MIN_SHIFT));
omap2_spi_reset(sc);
if (obio->obio_intr < 0) {
sc->sc_intr = NULL;
} else {
sc->sc_intr = intr_establish(obio->obio_intr, IPL_BIO,
IST_LEVEL, omap2_spi_intr, sc);
if (sc->sc_intr == NULL) {
aprint_error_dev(self,
"couldn't establish interrupt\n");
}
}
sc->sc_spi.sct_cookie = sc;
sc->sc_spi.sct_configure = omap2_spi_configure;
sc->sc_spi.sct_transfer = omap2_spi_transfer;
sc->sc_spi.sct_nslaves = nslaves;
/* initialize the channels */
for (i = 0; i < nslaves; i++) {
SIMPLEQ_INIT(&sc->sc_channels[i].queue);
}
sba.sba_controller = &sc->sc_spi;
config_found_ia(self, "spibus", &sba, spibus_print);
}
static int
omap2_spi_configure(void *cookie, int slave, int mode, int speed)
{
struct omap2_spi_softc *sc = cookie;
uint32_t conf = 0;
uint32_t div;
if (slave >= sc->sc_spi.sct_nslaves)
return EINVAL;
if (speed <= 0)
return EINVAL;
/* set the speed */
/* XXX implement lower speeds */
if (speed <= 187500)
div = 0x8;
else if (speed <= 375000)
div = 0x7;
else if (speed <= 750000)
div = 0x6;
else if (speed <= 1500000)
div = 0x5;
else if (speed <= 3000000)
div = 0x4;
else if (speed <= 6000000)
div = 0x3;
else if (speed <= 12000000)
div = 0x2;
else if (speed <= 24000000)
div = 0x1;
else
div = 0;
conf |= (div << OMAP2_MCSPI_CHXCONF_CLKD_SHIFT);
/* set the word size to 8 bits */
conf &= ~OMAP2_MCSPI_CHXCONF_WL;
conf |= (0x7 << OMAP2_MCSPI_CHXCONF_WL_SHIFT);
/* disable the FIFO */
conf &= ~OMAP2_MCSPI_CHXCONF_FFER;
conf &= ~OMAP2_MCSPI_CHXCONF_FFEW;
switch (mode) {
case SPI_MODE_0:
break;
case SPI_MODE_1:
conf |= OMAP2_MCSPI_CHXCONF_PHA;
break;
case SPI_MODE_2:
conf |= OMAP2_MCSPI_CHXCONF_POL;
break;
case SPI_MODE_3:
conf |= OMAP2_MCSPI_CHXCONF_POL
| OMAP2_MCSPI_CHXCONF_PHA;
break;
default:
return EINVAL;
}
SPI_WRITE_REG(sc, OMAP2_MCSPI_CHXCONF(slave), conf);
return 0;
}
static int
omap2_spi_transfer(void *cookie, struct spi_transfer *st)
{
struct omap2_spi_softc *sc = cookie;
int s;
int channel;
channel = st->st_slave;
s = splbio();
spi_transq_enqueue(&sc->sc_channels[channel].queue, st);
omap2_spi_start(sc, channel);
splx(s);
return 0;
}
static void
omap2_spi_start(struct omap2_spi_softc * const sc, int channel)
{
struct omap2_spi_channel *chan;
struct spi_transfer *st;
uint32_t enableval = 0;
uint32_t ctrlreg;
uint32_t ctrlval;
uint32_t u32;
chan = &sc->sc_channels[channel];
if (chan->running)
return;
if ((st = spi_transq_first(&chan->queue)) == NULL)
return;
spi_transq_dequeue(&chan->queue);
chan->running = true;
KASSERT(chan->transfer == NULL);
chan->transfer = st;
chan->rchunk = chan->wchunk = st->st_chunks;
switch (channel) {
case 0:
enableval = OMAP2_MCSPI_IRQENABLE_RX0_FULL
| OMAP2_MCSPI_IRQENABLE_TX0_UNDERFLOW
| OMAP2_MCSPI_IRQENABLE_TX0_EMPTY;
break;
case 1:
enableval = OMAP2_MCSPI_IRQENABLE_RX1_FULL
| OMAP2_MCSPI_IRQENABLE_TX1_UNDERFLOW
| OMAP2_MCSPI_IRQENABLE_TX1_EMPTY;
break;
case 2:
enableval = OMAP2_MCSPI_IRQENABLE_RX2_FULL
| OMAP2_MCSPI_IRQENABLE_TX2_UNDERFLOW
| OMAP2_MCSPI_IRQENABLE_TX2_EMPTY;
break;
case 3:
enableval = OMAP2_MCSPI_IRQENABLE_RX3_FULL
| OMAP2_MCSPI_IRQENABLE_TX3_UNDERFLOW
| OMAP2_MCSPI_IRQENABLE_TX3_EMPTY;
break;
}
/* enable interrupts */
u32 = SPI_READ_REG(sc, OMAP2_MCSPI_IRQENABLE);
SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQENABLE, u32 | enableval);
/* start the channel */
ctrlreg = OMAP2_MCSPI_CHXCTRL(channel);
u32 = SPI_READ_REG(sc, ctrlreg);
ctrlval = OMAP2_MCSPI_CHXCTRL_EN;
SPI_WRITE_REG(sc, ctrlreg, u32 | ctrlval);
}
static void
omap2_spi_stop(struct omap2_spi_softc * const sc, int channel)
{
struct omap2_spi_channel *chan;
uint32_t ctrlreg;
uint32_t u32;
chan = &sc->sc_channels[channel];
chan->running = false;
/* stop the channel */
ctrlreg = OMAP2_MCSPI_CHXCTRL(channel);
u32 = SPI_READ_REG(sc, ctrlreg);
u32 &= ~OMAP2_MCSPI_CHXCTRL_EN;
SPI_WRITE_REG(sc, ctrlreg, u32);
}
static int
omap2_spi_intr(void *v)
{
struct omap2_spi_softc *sc = v;
int i;
struct omap2_spi_channel *chan;
struct spi_transfer *st;
uint32_t status;
uint32_t u32;
uint32_t tx_empty = 0;
uint32_t rx_full = 0;
/* reset the channel status bits */
status = SPI_READ_REG(sc, OMAP2_MCSPI_IRQSTATUS);
u32 = 0;
/* check every channel */
for (i = 0; i < sc->sc_spi.sct_nslaves; i++) {
chan = &sc->sc_channels[i];
switch (i) {
case 0:
u32 |= OMAP2_MCSPI_IRQSTATUS_RX0_OVERFLOW
| OMAP2_MCSPI_IRQSTATUS_RX0_FULL
| OMAP2_MCSPI_IRQSTATUS_TX0_UNDERFLOW
| OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY;
tx_empty = status
& OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY;
rx_full = status
& OMAP2_MCSPI_IRQSTATUS_RX0_FULL;
break;
case 1:
u32 |= OMAP2_MCSPI_IRQSTATUS_RX1_FULL
| OMAP2_MCSPI_IRQSTATUS_TX1_UNDERFLOW
| OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY;
tx_empty = status
& OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY;
rx_full = status
& OMAP2_MCSPI_IRQSTATUS_RX1_FULL;
break;
case 2:
u32 |= OMAP2_MCSPI_IRQSTATUS_RX2_FULL
| OMAP2_MCSPI_IRQSTATUS_TX2_UNDERFLOW
| OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY;
tx_empty = status
& OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY;
rx_full = status
& OMAP2_MCSPI_IRQSTATUS_RX2_FULL;
break;
case 3:
u32 |= OMAP2_MCSPI_IRQSTATUS_RX3_FULL
| OMAP2_MCSPI_IRQSTATUS_TX3_UNDERFLOW
| OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY;
tx_empty = status
& OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY;
rx_full = status
& OMAP2_MCSPI_IRQSTATUS_RX3_FULL;
break;
}
if (tx_empty && chan->wchunk != NULL) {
omap2_spi_send(sc, i);
}
if (rx_full) {
omap2_spi_recv(sc, i);
}
if (chan->wchunk == NULL && chan->rchunk == NULL) {
st = chan->transfer;
chan->transfer = NULL;
KASSERT(st != NULL);
spi_done(st, 0);
spi_transq_dequeue(&chan->queue);
if ((st = spi_transq_first(&chan->queue)) == NULL)
omap2_spi_stop(sc, i);
else
chan->transfer = st;
}
}
/* acknowledge the interrupt */
SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQSTATUS, u32);
return 1;
}
static int
omap2_spi_reset(struct omap2_spi_softc * const sc)
{
int retry;
uint32_t status;
int i;
/* proceed to a software reset */
SPI_WRITE_REG(sc, OMAP2_MCSPI_SYSCONFIG,
OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
/* poll until the reset is done */
retry = 1000;
status = SPI_READ_REG(sc, OMAP2_MCSPI_SYSSTATUS);
while ((status & OMAP2_MCSPI_SYSSTATUS_RESETDONE) == 0) {
if (--retry == 0)
return EBUSY;
delay(1000);
status = SPI_READ_REG(sc, OMAP2_MCSPI_SYSSTATUS);
}
/* disable every channel available */
for (i = 0; i < sc->sc_spi.sct_nslaves; i++) {
SPI_WRITE_REG(sc, OMAP2_MCSPI_CHXCTRL(i), 0);
}
/* disable and clear all interrupts */
SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQENABLE, 0);
SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQSTATUS, 0x1777f);
/* set the module in master and multichannel mode */
SPI_WRITE_REG(sc, OMAP2_MCSPI_MODULCTRL, 0);
return 0;
}
static void
omap2_spi_send(struct omap2_spi_softc * const sc, int channel)
{
struct spi_chunk *chunk;
const uint32_t stat = OMAP2_MCSPI_CHXSTAT(channel);
uint32_t u32;
uint32_t data;
if ((chunk = sc->sc_channels[channel].wchunk) == NULL)
return;
if (chunk->chunk_wresid) {
u32 = SPI_READ_REG(sc, stat);
if ((u32 & OMAP2_MCSPI_CHXSTAT_TXS) == 0)
return;
if (chunk->chunk_wptr) {
data = *chunk->chunk_wptr++;
SPI_WRITE_REG(sc, OMAP2_MCSPI_TX(channel), data);
}
}
if (chunk->chunk_wresid-- == 0) {
sc->sc_channels[channel].wchunk
= sc->sc_channels[channel].wchunk->chunk_next;
}
}
static void
omap2_spi_recv(struct omap2_spi_softc * const sc, int channel)
{
struct spi_chunk *chunk;
const uint32_t stat = OMAP2_MCSPI_CHXSTAT(channel);
uint32_t u32;
uint32_t data;
if ((chunk = sc->sc_channels[channel].rchunk) == NULL)
return;
if (chunk->chunk_rresid) {
u32 = SPI_READ_REG(sc, stat);
if ((u32 & OMAP2_MCSPI_CHXSTAT_RXS) == 0)
return;
data = SPI_READ_REG(sc, OMAP2_MCSPI_RX(channel));
if (chunk->chunk_rptr) {
*chunk->chunk_rptr++ = data & 0xff;
}
}
if (chunk->chunk_rresid-- == 0) {
sc->sc_channels[channel].rchunk
= sc->sc_channels[channel].rchunk->chunk_next;
}
}
/* $NetBSD$ */
/*
* Copyright (c) 2013 Pierre Pronchery <khorben%defora.org@localhost>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _OMAP2_SPIREG_H
#define _OMAP2_SPIREG_H
/*
* Multichannel SPI Controller registers
*/
#define OMAP2_MCSPI_REVISION 0x00
#define OMAP2_MCSPI_REV_MAJ_MASK __BITS(4,7)
#define OMAP2_MCSPI_REV_MAJ_SHIFT 4
#define OMAP2_MCSPI_REV_MIN_MASK __BITS(0,3)
#define OMAP2_MCSPI_REV_MIN_SHIFT 0
#define OMAP2_MCSPI_SYSCONFIG 0x10
#define OMAP2_MCSPI_SYSCONFIG_CLOCKACTIVITY __BITS(8,9)
#define OMAP2_MCSPI_SYSCONFIG_SIDLEMODE __BITS(3,4)
#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP __BIT(2)
#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET __BIT(1)
#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE __BIT(0)
#define OMAP2_MCSPI_SYSSTATUS 0x14
#define OMAP2_MCSPI_SYSSTATUS_RESETDONE __BIT(0)
#define OMAP2_MCSPI_IRQSTATUS 0x18
#define OMAP2_MCSPI_IRQSTATUS_EOW __BIT(16)
#define OMAP2_MCSPI_IRQSTATUS_RX3_FULL __BIT(14)
#define OMAP2_MCSPI_IRQSTATUS_TX3_UNDERFLOW __BIT(13)
#define OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY __BIT(12)
#define OMAP2_MCSPI_IRQSTATUS_RX2_FULL __BIT(10)
#define OMAP2_MCSPI_IRQSTATUS_TX2_UNDERFLOW __BIT(9)
#define OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY __BIT(8)
#define OMAP2_MCSPI_IRQSTATUS_RX1_FULL __BIT(6)
#define OMAP2_MCSPI_IRQSTATUS_TX1_UNDERFLOW __BIT(5)
#define OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY __BIT(4)
#define OMAP2_MCSPI_IRQSTATUS_RX0_OVERFLOW __BIT(3)
#define OMAP2_MCSPI_IRQSTATUS_RX0_FULL __BIT(2)
#define OMAP2_MCSPI_IRQSTATUS_TX0_UNDERFLOW __BIT(1)
#define OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY __BIT(0)
#define OMAP2_MCSPI_IRQENABLE 0x1c
#define OMAP2_MCSPI_IRQENABLE_EOWKE __BIT(17)
#define OMAP2_MCSPI_IRQENABLE_WKE __BIT(16)
#define OMAP2_MCSPI_IRQENABLE_RX3_FULL __BIT(14)
#define OMAP2_MCSPI_IRQENABLE_TX3_UNDERFLOW __BIT(13)
#define OMAP2_MCSPI_IRQENABLE_TX3_EMPTY __BIT(12)
#define OMAP2_MCSPI_IRQENABLE_RX2_FULL __BIT(10)
#define OMAP2_MCSPI_IRQENABLE_TX2_UNDERFLOW __BIT(9)
#define OMAP2_MCSPI_IRQENABLE_TX2_EMPTY __BIT(8)
#define OMAP2_MCSPI_IRQENABLE_RX1_FULL __BIT(6)
#define OMAP2_MCSPI_IRQENABLE_TX1_UNDERFLOW __BIT(5)
#define OMAP2_MCSPI_IRQENABLE_TX1_EMPTY __BIT(4)
#define OMAP2_MCSPI_IRQENABLE_RX0_OVERFLOW __BIT(3)
#define OMAP2_MCSPI_IRQENABLE_RX0_FULL __BIT(2)
#define OMAP2_MCSPI_IRQENABLE_TX0_UNDERFLOW __BIT(1)
#define OMAP2_MCSPI_IRQENABLE_TX0_EMPTY __BIT(0)
#define OMAP2_MCSPI_WAKEUPENABLE 0x20
#define OMAP2_MCSPI_SYST 0x24
#define OMAP2_MCSPI_SYST_SSB __BIT(11)
#define OMAP2_MCSPI_SYST_SPIENDIR __BIT(10)
#define OMAP2_MCSPI_SYST_SPIDATDIR1 __BIT(9)
#define OMAP2_MCSPI_SYST_SPIDATDIR0 __BIT(8)
#define OMAP2_MCSPI_SYST_WAKD __BIT(7)
#define OMAP2_MCSPI_SYST_SPICLK __BIT(6)
#define OMAP2_MCSPI_SYST_SPIDAT_1 __BIT(5)
#define OMAP2_MCSPI_SYST_SPIDAT_0 __BIT(4)
#define OMAP2_MCSPI_SYST_SPIEN_3 __BIT(3)
#define OMAP2_MCSPI_SYST_SPIEN_2 __BIT(2)
#define OMAP2_MCSPI_SYST_SPIEN_1 __BIT(1)
#define OMAP2_MCSPI_SYST_SPIEN_0 __BIT(0)
#define OMAP2_MCSPI_MODULCTRL 0x28
#define OMAP2_MCSPI_MODULCTRL_SYSTEM_TEST __BIT(3)
#define OMAP2_MCSPI_MODULCTRL_MS __BIT(2)
#define OMAP2_MCSPI_MODULCTRL_SINGLE __BIT(0)
#define OMAP2_MCSPI_CHXCONF(channel) (0x2c + (channel * 0x14))
#define OMAP2_MCSPI_CH0CONF OMAP2_MCSPI_CHXCONF(0)
#define OMAP2_MCSPI_CH1CONF OMAP2_MCSPI_CHXCONF(1)
#define OMAP2_MCSPI_CH2CONF OMAP2_MCSPI_CHXCONF(2)
#define OMAP2_MCSPI_CH3CONF OMAP2_MCSPI_CH0CONF(3)
#define OMAP2_MCSPI_CHXCONF_FFER __BIT(28)
#define OMAP2_MCSPI_CHXCONF_FFEW __BIT(27)
#define OMAP2_MCSPI_CHXCONF_TCS __BITS(25,26)
#define OMAP2_MCSPI_CHXCONF_SBE __BIT(23)
#define OMAP2_MCSPI_CHXCONF_TRM __BITS(12,13)
#define OMAP2_MCSPI_CHXCONF_TRM_SHIFT 12
#define OMAP2_MCSPI_CHXCONF_WL __BITS(7,11)
#define OMAP2_MCSPI_CHXCONF_WL_SHIFT 7
#define OMAP2_MCSPI_CHXCONF_EPOL __BIT(6)
#define OMAP2_MCSPI_CHXCONF_CLKD __BITS(2,5)
#define OMAP2_MCSPI_CHXCONF_CLKD_SHIFT 2
#define OMAP2_MCSPI_CHXCONF_POL __BIT(1)
#define OMAP2_MCSPI_CHXCONF_PHA __BIT(0)
#define OMAP2_MCSPI_CHXSTAT(channel) (0x30 + ((channel) * 0x14))
#define OMAP2_MCSPI_CH0STAT OMAP2_MCSPI_CHXSTAT(0)
#define OMAP2_MCSPI_CH1STAT OMAP2_MCSPI_CHXSTAT(1)
#define OMAP2_MCSPI_CH2STAT OMAP2_MCSPI_CHXSTAT(2)
#define OMAP2_MCSPI_CH3STAT OMAP2_MCSPI_CHXSTAT(3)
# define OMAP2_MCSPI_CHXSTAT_EOT __BIT(2)
# define OMAP2_MCSPI_CHXSTAT_TXS __BIT(1)
# define OMAP2_MCSPI_CHXSTAT_RXS __BIT(0)
#define OMAP2_MCSPI_CHXCTRL(channel) (0x34 + ((channel) * 0x14))
#define OMAP2_MCSPI_CH0CTRL OMAP2_MCSPI_CHXCTRL(0)
#define OMAP2_MCSPI_CH1CTRL OMAP2_MCSPI_CHXCTRL(1)
#define OMAP2_MCSPI_CH2CTRL OMAP2_MCSPI_CHXCTRL(2)
#define OMAP2_MCSPI_CH3CTRL OMAP2_MCSPI_CHXCTRL(3)
#define OMAP2_MCSPI_CHXCTRL_EN __BIT(0)
#define OMAP2_MCSPI_TX(channel) (0x38 + ((channel) * 0x14))
#define OMAP2_MCSPI_TX0 OMAP2_MCSPI_TX(0)
#define OMAP2_MCSPI_TX1 OMAP2_MCSPI_TX(1)
#define OMAP2_MCSPI_TX2 OMAP2_MCSPI_TX(2)
#define OMAP2_MCSPI_TX3 OMAP2_MCSPI_TX(3)
#define OMAP2_MCSPI_RX(channel) (0x3c + (channel * 0x14))
#define OMAP2_MCSPI_RX0 OMAP2_MCSPI_RX(0)
#define OMAP2_MCSPI_RX1 OMAP2_MCSPI_RX(1)
#define OMAP2_MCSPI_RX2 OMAP2_MCSPI_RX(2)
#define OMAP2_MCSPI_RX3 OMAP2_MCSPI_RX(3)
#define OMAP2_MCSPI_XFERLEVEL 0x7c
#define OMAP2_MCSPI_XFERLEVEL_WCNT __BITS(16,31)
#define OMAP2_MCSPI_XFERLEVEL_AFL __BITS(8,13)
#define OMAP2_MCSPI_XFERLEVEL_AEL __BITS(0,5)
#endif /* !_OMAP2_SPIREG_H */
/* $NetBSD$ */
/*
* Copyright (c) 2013 Pierre Pronchery <khorben%defora.org@localhost>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Texas Instruments Touch Screen Controller:
* - 2005
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");
#include <sys/param.h>
#include <sys/device.h>
#include <dev/spi/spivar.h>
#include <dev/spi/tsc2005reg.h>
/* variables */
struct tsc2005_softc {
device_t sc_dev;
struct spi_handle *sc_spi;
void * sc_intr;
};
static int tsc2005_match(device_t, cfdata_t, void *);
static void tsc2005_attach(device_t, device_t, void *);
static int tsc2005_detach(device_t, int);
static int tsc2005_reset(struct tsc2005_softc *);
static int tsc2005_intr(void *);
static int tsc2005_read_reg(struct tsc2005_softc *, int, uint16_t *);
#if 0
static int tsc2005_write_reg(struct tsc2005_softc *, int, uint16_t);
#endif
CFATTACH_DECL_NEW(tsc2005ts, sizeof(struct tsc2005_softc),
tsc2005_match, tsc2005_attach, tsc2005_detach, NULL);
static int
tsc2005_match(device_t parent, cfdata_t match, void *aux)
{
struct spi_attach_args *sa = aux;
spi_configure(sa->sa_handle, SPI_MODE_0, 6000000);
return 1;
}
static void
tsc2005_attach(device_t parent, device_t self, void *aux)
{
struct tsc2005_softc *sc = device_private(self);
struct spi_attach_args *sa = aux;
sc->sc_dev = self;
sc->sc_spi = sa->sa_handle;
aprint_normal(": TSC2005 touchscreen\n");
aprint_naive(": TSC2005 touchscreen\n");
tsc2005_reset(sc);
sc->sc_intr = intr_establish(sa->sa_intr, IPL_BIO, IST_LEVEL_LOW,
tsc2005_intr, sc);
if (sc->sc_intr == NULL) {
aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n");
}
if (!pmf_device_register(sc->sc_dev, NULL, NULL)) {
aprint_error_dev(sc->sc_dev,
"couldn't establish power handler\n");
}
}
static int
tsc2005_detach(device_t self, int flags)
{
struct tsc2005_softc *sc = device_private(self);
if (sc->sc_intr) {
intr_disestablish(sc->sc_intr);
}
pmf_device_deregister(self);
return 0;
}
static int
tsc2005_reset(struct tsc2005_softc *sc)
{
uint8_t u8;
aprint_normal_dev(sc->sc_dev, "%s()\n", __func__);
/* send a Control Byte 1 with the SWRST bit set */
u8 = 0x82;
spi_send(sc->sc_spi, sizeof(u8), &u8);
/* send a Control Byte 1 with the SWRST bit unset */
u8 = 0x80;
spi_send(sc->sc_spi, sizeof(u8), &u8);
return 0;
}
static int
tsc2005_intr(void *v)
{
struct tsc2005_softc *sc = v;
uint16_t status;
uint16_t x;
uint16_t y;
uint16_t z;
tsc2005_read_reg(sc, TSC2005_REG_STATUS, &status);
tsc2005_read_reg(sc, TSC2005_REG_X, &x);
tsc2005_read_reg(sc, TSC2005_REG_Y, &y);
tsc2005_read_reg(sc, TSC2005_REG_Z1, &z);
aprint_normal_dev(sc->sc_dev, "X: %u, Y:%u, Z:%u\n", x, y, z);
return 0;
}
static int
tsc2005_read_reg(struct tsc2005_softc *sc, int reg, uint16_t *data)
{
uint8_t buf[2];
buf[0] = reg << 3 | 1;
spi_send_recv(sc->sc_spi, sizeof(buf), buf, sizeof(buf), buf);
memcpy(data, buf, sizeof(data));
return 0;
}
#if 0
static int
tsc2005_write_reg(struct tsc2005_softc *sc, int reg, uint16_t data)
{
uint8_t buf[3];
buf[0] = reg << 3;
memcpy(&buf[1], &data, sizeof(data));
return spi_send(sc->sc_spi, sizeof(buf), buf);
}
#endif
/* $NetBSD$ */
/*
* Copyright (c) 2013 Pierre Pronchery <khorben%defora.org@localhost>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_SPI_TSC2005REG_H_
#define _DEV_SPI_TSC2005REG_H_
/*
* Texas Instruments Touch Screen Controller:
* - 2005
*/
#define TSC2005_REG_X 0x00
#define TSC2005_REG_Y 0x01
#define TSC2005_REG_Z1 0x02
#define TSC2005_REG_Z2 0x03
#define TSC2005_REG_AUX 0x04
#define TSC2005_REG_TEMP1 0x05
#define TSC2005_REG_TEMP2 0x06
#define TSC2005_REG_STATUS 0x07
#define TSC2005_REG_AUX_HIGH 0x08
#define TSC2005_REG_AUX_LOW 0x09
#define TSC2005_REG_TEMP_HIGH 0x0a
#define TSC2005_REG_TEMP_LOW 0x0b
#define TSC2005_REG_CFR0 0x0c
#define TSC2005_REG_CFR1 0x0d
#define TSC2005_REG_CFR2 0x0e
#define TSC2005_REG_CFSS 0x0f
#endif /* _DEV_SPI_SPIVAR_H_ */
Home |
Main Index |
Thread Index |
Old Index