From 18eec557d0227425a04f1509b7c8ca8a1d24fb07 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Thu, 9 Sep 2010 09:19:06 -0300 Subject: [PATCH] Updated atusd driver for new hardware. Make use of the interrupt line. - tools/lib/atusd.c (spi_send_partial, spi_send): removed the old spi_send and renamed spi_send_partial to spi_send - tools/lib/atusd.c (atusd_cycle, spi_send, spi_recv, atusd_open): updated for removal of SLP_TR and split of MxSx into MOSI and MISO - tools/lib/atusd.c (atusd_reset_rf, atusd_open): added delays to precharge the capacitors - tools/lib/atusd.c (atusd_reset, spi_data_in, spi_data_out, spi_finish): removed functions for obsolete hardware features - tools/lib/atusd.c (atusd_reg_read): removed calls to removed functions - tools/lib/atusd.c (atusd_buf_write, atusd_buf_read, atusd_driver): new buffer read/write functions - tools/atspi-txrx/atspi-txrx.c (init_txrx): set the internal osciallator trim only in the USB version. Switch to the external oscillator in the uSD version. - tools/atspi-rssi/atspi-rssi.c (sweep), tools/atspi-txrx/atspi-txrx.c (set_channel): wait for the PLL to settle after setting the channel - tools/include/atspi.h, tools/lib/atspi.c (atspi_interrupt), tools/lib/driver.h (struct atspi_driver), tools/lib/atusd.c (atusd_interrupt): new function to poll the interrupt line - tools/atspi-txrx/atspi-txrx.c (receive): only read REG_IRQ_STATUS if there is a pending interrupt - tools/atspi-id/atspi-id.c (usage): print "usage:" as well - tools/Makefile (upload): upload the atspi tools to the Ben --- tools/Makefile | 5 ++ tools/atspi-id/atspi-id.c | 2 +- tools/atspi-rssi/atspi-rssi.c | 2 + tools/atspi-txrx/atspi-txrx.c | 11 +++ tools/include/atspi.h | 2 + tools/lib/atspi.c | 7 ++ tools/lib/atusd.c | 148 ++++++++++++++++------------------ tools/lib/driver.h | 1 + 8 files changed, 98 insertions(+), 80 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index ee3f1de..846e93f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,3 +15,8 @@ DIRS=atspi-id atspi-reset atspi-rssi atspi-trim atspi-txrx TARGET_ONLY_DIRS=lib include ../Makefile.recurse + +.PHONY: upload + +upload: + scp `for n in $(DIRS); do echo $$n/$$n; done` ben: diff --git a/tools/atspi-id/atspi-id.c b/tools/atspi-id/atspi-id.c index facca2a..f036054 100644 --- a/tools/atspi-id/atspi-id.c +++ b/tools/atspi-id/atspi-id.c @@ -127,7 +127,7 @@ static void show_info(struct atspi_dsc *dsc) static void usage(const char *name) { - fprintf(stderr, "%s\n", name); + fprintf(stderr, "usage: %s\n", name); exit(1); } diff --git a/tools/atspi-rssi/atspi-rssi.c b/tools/atspi-rssi/atspi-rssi.c index 238c03f..f75e31b 100644 --- a/tools/atspi-rssi/atspi-rssi.c +++ b/tools/atspi-rssi/atspi-rssi.c @@ -30,6 +30,8 @@ static void sweep(struct atspi_dsc *dsc) for (chan = 11; chan <= 26; chan++) { atspi_reg_write(dsc, REG_PHY_CC_CCA, chan); + /* 150 us, according to AVR2001 section 3.5 */ + usleep(1000); /* * No need to explicitly wait for the PPL lock - going USB-SPI * is pretty slow, leaving the transceiver plenty of time. diff --git a/tools/atspi-txrx/atspi-txrx.c b/tools/atspi-txrx/atspi-txrx.c index af38110..1e669a8 100644 --- a/tools/atspi-txrx/atspi-txrx.c +++ b/tools/atspi-txrx/atspi-txrx.c @@ -55,8 +55,12 @@ static struct atspi_dsc *init_txrx(int trim) atspi_reset_rf(dsc); atspi_reg_write(dsc, REG_TRX_STATE, TRX_CMD_TRX_OFF); +#ifdef HAVE_USB /* @@@ yeah, ugly */ atspi_reg_write(dsc, REG_XOSC_CTRL, (XTAL_MODE_INT << XTAL_MODE_SHIFT) | trim); +#else + atspi_reg_write(dsc, REG_XOSC_CTRL, XTAL_MODE_EXT << XTAL_MODE_SHIFT); +#endif atspi_reg_write(dsc, REG_TRX_CTRL_0, 0); /* disable CLKM */ return dsc; @@ -66,6 +70,11 @@ static struct atspi_dsc *init_txrx(int trim) static void set_channel(struct atspi_dsc *dsc, int channel) { atspi_reg_write(dsc, REG_PHY_CC_CCA, (1 << CCA_MODE_SHIFT) | channel); + /* + * 150 us, according to AVR2001 section 3.5. Note that we should just + * wait for the PPL_LOCK interrupt. + */ + usleep(1000); } @@ -93,6 +102,8 @@ static void receive(struct atspi_dsc *dsc) fprintf(stderr, "Ready.\n"); while (1) { + while (!atspi_interrupt(dsc)) + usleep(10); irq = atspi_reg_read(dsc, REG_IRQ_STATUS); if (atspi_error(dsc)) exit(1); diff --git a/tools/include/atspi.h b/tools/include/atspi.h index a60ceda..1663b55 100644 --- a/tools/include/atspi.h +++ b/tools/include/atspi.h @@ -36,4 +36,6 @@ uint8_t atspi_reg_read(struct atspi_dsc *dsc, uint8_t reg); void atspi_buf_write(struct atspi_dsc *dsc, const void *buf, int size); int atspi_buf_read(struct atspi_dsc *dsc, void *buf, int size); +int atspi_interrupt(struct atspi_dsc *dsc); + #endif /* !ATSPI_H */ diff --git a/tools/lib/atspi.c b/tools/lib/atspi.c index 9a7fe10..a4ad987 100644 --- a/tools/lib/atspi.c +++ b/tools/lib/atspi.c @@ -121,3 +121,10 @@ int atspi_buf_read(struct atspi_dsc *dsc, void *buf, int size) { return dsc->driver->buf_read(dsc->handle, buf, size); } + + +int atspi_interrupt(struct atspi_dsc *dsc) +{ + return + dsc->driver->interrupt ? dsc->driver->interrupt(dsc->handle) : 1; +} diff --git a/tools/lib/atusd.c b/tools/lib/atusd.c index d07963e..3383409 100644 --- a/tools/lib/atusd.c +++ b/tools/lib/atusd.c @@ -23,11 +23,11 @@ enum { - VDD_OFF = 1 << 6, /* VDD disable, PD06 */ - MxSx = 1 << 8, /* CMD, PD08 */ + VDD_OFF = 1 << 2, /* VDD disable, PD02 */ + MOSI = 1 << 8, /* CMD, PD08 */ CLK = 1 << 9, /* CLK, PD09 */ - SCLK = 1 << 10, /* DAT0, PD10 */ - SLP_TR = 1 << 11, /* DAT1, PD11 */ + MISO = 1 << 10, /* DAT0, PD10 */ + SCLK = 1 << 11, /* DAT1, PD11 */ IRQ = 1 << 12, /* DAT2, PD12 */ nSEL = 1 << 13, /* DAT3/CD, PD13 */ }; @@ -72,7 +72,7 @@ static void wait_for_power(void) { /* * Give power time to stabilize and the chip time to reset. - * Experiments show that even usleep(0) is long enough. + * Power takes about 2 ms to ramp up. We wait 10 ms to be sure. */ usleep(10*1000); } @@ -84,7 +84,7 @@ static void atusd_cycle(struct atusd_dsc *dsc) MSC_STRPCL = 1; /* drive all outputs low (including the MMC bus clock) */ - PDDATC = MxSx | CLK | SCLK | SLP_TR | nSEL; + PDDATC = MOSI | CLK | SCLK | nSEL; /* make the MMC bus clock a regular output */ PDFUNC = CLK; @@ -95,11 +95,11 @@ static void atusd_cycle(struct atusd_dsc *dsc) /* Power drains within about 20 ms. Wait 100 ms to be sure. */ usleep(100*1000); - /* drive nSS high */ - PDDATS = nSEL; + /* drive MOSI and nSS high */ + PDDATS = MOSI | nSEL; - /* supply power */ - PDDATC = VDD_OFF; + /* precharge the capacitors to avoid current surge */ + wait_for_power(); /* return the bus clock output to the MMC controller */ PDFUNS = CLK; @@ -107,30 +107,13 @@ static void atusd_cycle(struct atusd_dsc *dsc) /* start MMC clock output */ MSC_STRPCL = 2; + /* supply power */ + PDDATC = VDD_OFF; + wait_for_power(); } -#if 0 /* we probably won't need this anymore */ -static void atusd_reset(struct atusd_dsc *dsc) -{ - /* activate reset */ - PDDATS = SLP_TR; - PDDATC = nSEL; - - /* - * Data sheet says 625 ns, programmer's guide says 6 us. Whom do we - * trust ? - */ - usleep(6); - - /* release reset */ - PDDATS = nSEL; - PDDATC = SLP_TR; -} -#endif - - /* ----- Low-level SPI operations ------------------------------------------ */ @@ -146,35 +129,17 @@ static void spi_end(struct atusd_dsc *dsc) } -static void spi_data_in(struct atusd_dsc *dsc) -{ - PDDIRC = MxSx; -} - - -static void spi_data_out(struct atusd_dsc *dsc) -{ - PDDIRS = MxSx; -} - - - -/* - * Send a sequence of bytes but leave the clock high on the last bit, so that - * we can turn around the data line for reads. - */ - -static void spi_send_partial(struct atusd_dsc *dsc, uint8_t v) +static void spi_send(struct atusd_dsc *dsc, uint8_t v) { uint8_t mask; for (mask = 0x80; mask; mask >>= 1) { - PDDATC = SCLK; if (v & mask) - PDDATS = MxSx; + PDDATS = MOSI; else - PDDATC = MxSx; + PDDATC = MOSI; PDDATS = SCLK; + PDDATC = SCLK; } } @@ -185,29 +150,15 @@ static uint8_t spi_recv(struct atusd_dsc *dsc) uint8_t mask; for (mask = 0x80; mask; mask >>= 1) { - PDDATC = SCLK; - if (PDPIN & MxSx) + if (PDPIN & MISO) res |= mask; PDDATS = SCLK; + PDDATC = SCLK; } - PDDATC = SCLK; return res; } -static void spi_finish(struct atusd_dsc *dsc) -{ - PDDATC = SCLK; -} - - -static void spi_send(struct atusd_dsc *dsc, uint8_t v) -{ - spi_send_partial(dsc, v); - spi_finish(dsc); -} - - /* ----- Driver operations ------------------------------------------------- */ @@ -216,6 +167,7 @@ static void atusd_reset_rf(void *handle) struct atusd_dsc *dsc = handle; atusd_cycle(dsc); + wait_for_power(); } @@ -243,15 +195,18 @@ static void *atusd_open(void) /* set the output levels */ PDDATS = nSEL | VDD_OFF; - PDDATC = SCLK | SLP_TR; + PDDATC = SCLK; /* take the GPIOs away from the MMC controller */ - PDFUNC = MxSx | SCLK | SLP_TR | IRQ | nSEL; + PDFUNC = MOSI | MISO | SCLK | IRQ | nSEL; PDFUNS = CLK; /* set the pin directions */ - PDDIRC = IRQ; - PDDIRS = MxSx | CLK | SCLK | SLP_TR | nSEL; + PDDIRC = MISO | IRQ; + PDDIRS = MOSI | CLK | SCLK | nSEL; + + /* let capacitors precharge */ + wait_for_power(); /* enable power */ PDDATC = VDD_OFF; @@ -286,7 +241,7 @@ static void atusd_close(void *arg) PDDATS = VDD_OFF; /* make all MMC pins inputs */ - PDDIRC = MxSx | CLK | SCLK | SLP_TR | IRQ | nSEL; + PDDIRC = MOSI | MISO | CLK | SCLK | IRQ | nSEL; } @@ -307,16 +262,52 @@ static uint8_t atusd_reg_read(void *handle, uint8_t reg) uint8_t res; spi_begin(dsc); - spi_send_partial(dsc, AT86RF230_REG_READ| reg); - spi_data_in(dsc); + spi_send(dsc, AT86RF230_REG_READ | reg); res = spi_recv(dsc); - spi_finish(dsc); - spi_data_out(dsc); spi_end(dsc); return res; } +static void atusd_buf_write(void *handle, const void *buf, int size) +{ + struct atusd_dsc *dsc = handle; + + spi_begin(dsc); + spi_send(dsc, AT86RF230_BUF_WRITE); + spi_send(dsc, size); + while (size--) + spi_send(dsc, *(uint8_t *) buf++); + spi_end(dsc); +} + + +static int atusd_buf_read(void *handle, void *buf, int size) +{ + struct atusd_dsc *dsc = handle; + uint8_t len, i; + + spi_begin(dsc); + spi_send(dsc, AT86RF230_BUF_READ); + len = spi_recv(dsc); + len++; /* LQI */ + if (len > size) + len = size; + for (i = 0; i != len; i++) + *(uint8_t *) buf++ = spi_recv(dsc); + spi_end(dsc); + return len; +} + + +static int atusd_interrupt(void *handle) +{ + struct atusd_dsc *dsc = handle; + + return !!(PDPIN & IRQ); +} + + /* ----- Driver interface -------------------------------------------------- */ @@ -328,8 +319,7 @@ struct atspi_driver atusd_driver = { .reset_rf = atusd_reset_rf, .reg_write = atusd_reg_write, .reg_read = atusd_reg_read, -#if 0 .buf_write = atusd_buf_write, .buf_read = atusd_buf_read, -#endif + .interrupt = atusd_interrupt, }; diff --git a/tools/lib/driver.h b/tools/lib/driver.h index 5836525..35e0303 100644 --- a/tools/lib/driver.h +++ b/tools/lib/driver.h @@ -29,6 +29,7 @@ struct atspi_driver { uint8_t (*reg_read)(void *dsc, uint8_t reg); void (*buf_write)(void *dsc, const void *buf, int size); int (*buf_read)(void *dsc, void *buf, int size); + int (*interrupt)(void *dsc); }; #endif /* !DRIVER_H */