summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/calypso/calypso_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/calypso/calypso_spi.c')
-rw-r--r--nuttx/arch/arm/src/calypso/calypso_spi.c95
1 files changed, 93 insertions, 2 deletions
diff --git a/nuttx/arch/arm/src/calypso/calypso_spi.c b/nuttx/arch/arm/src/calypso/calypso_spi.c
index cc20f2072..1158c7f2f 100644
--- a/nuttx/arch/arm/src/calypso/calypso_spi.c
+++ b/nuttx/arch/arm/src/calypso/calypso_spi.c
@@ -1,10 +1,12 @@
/****************************************************************************
- * calypso_spi.c
+ * arch/arm/src/calypso/calypso_spi.c
* SPI driver for TI Calypso
*
+ * Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>
* Copyright (C) 2011 Stefan Richter <ichgeh@l--putt.de>
*
- * All rights reserved.
+ * Part of this source code is derivated from Osmocom-BB project and was
+ * relicensed as BSD with permission from original authors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -38,6 +40,11 @@
#include <nuttx/config.h>
#include <nuttx/spi.h>
+#include <debug.h>
+
+#include "up_arch.h"
+#include "calypso_spi.h"
+
#warning "MOST OF SPI API IS INCOMPLETE! (Wrapper around Osmocom driver)"
extern void spi_init(void);
extern int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din);
@@ -127,6 +134,90 @@ static struct calypso_spidev_s g_spidev =
.nbits = 0,
};
+void spi_init(void)
+{
+ putreg16(SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS | SPI_SET1_RDWR_IRQ_DIS,
+ SPI_REG(REG_SET1));
+
+ putreg16(0x0001, SPI_REG(REG_SET2));
+}
+
+int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din)
+{
+ uint8_t bytes_per_xfer;
+ uint8_t reg_status, reg_ctrl = 0;
+ uint32_t tmp;
+
+ if (bitlen == 0)
+ return 0;
+
+ if (bitlen > 32)
+ return -1;
+
+ if (dev_idx > 4)
+ return -1;
+
+ bytes_per_xfer = bitlen / 8;
+ if (bitlen % 8)
+ bytes_per_xfer ++;
+
+ reg_ctrl |= (bitlen - 1) << SPI_CTRL_NB_SHIFT;
+ reg_ctrl |= (dev_idx & 0x7) << SPI_CTRL_AD_SHIFT;
+
+ if (bitlen <= 8) {
+ tmp = *(uint8_t *)dout;
+ tmp <<= 24 + (8-bitlen); /* align to MSB */
+ } else if (bitlen <= 16) {
+ tmp = *(uint16_t *)dout;
+ tmp <<= 16 + (16-bitlen); /* align to MSB */
+ } else {
+ tmp = *(uint32_t *)dout;
+ tmp <<= (32-bitlen); /* align to MSB */
+ }
+ dbg("spi_xfer(dev_idx=%u, bitlen=%u, data_out=0x%08x): ",
+ dev_idx, bitlen, tmp);
+
+ /* fill transmit registers */
+ putreg16(tmp >> 16, SPI_REG(REG_TX_MSB));
+ putreg16(tmp & 0xffff, SPI_REG(REG_TX_LSB));
+
+ /* initiate transfer */
+ if (din)
+ reg_ctrl |= SPI_CTRL_RDWR;
+ else
+ reg_ctrl |= SPI_CTRL_WR;
+ putreg16(reg_ctrl, SPI_REG(REG_CTRL));
+ dbg("reg_ctrl=0x%04x ", reg_ctrl);
+
+ /* wait until the transfer is complete */
+ while (1) {
+ reg_status = getreg16(SPI_REG(REG_STATUS));
+ dbg("status=0x%04x ", reg_status);
+ if (din && (reg_status & SPI_STATUS_RE))
+ break;
+ else if (reg_status & SPI_STATUS_WE)
+ break;
+ }
+ /* FIXME: calibrate how much delay we really need (seven 13MHz cycles) */
+ usleep(1000);
+
+ if (din) {
+ tmp = getreg16(SPI_REG(REG_RX_MSB)) << 16;
+ tmp |= getreg16(SPI_REG(REG_RX_LSB));
+ dbg("data_in=0x%08x ", tmp);
+
+ if (bitlen <= 8)
+ *(uint8_t *)din = tmp & 0xff;
+ else if (bitlen <= 16)
+ *(uint16_t *)din = tmp & 0xffff;
+ else
+ *(uint32_t *)din = tmp;
+ }
+ dbg('\n');
+
+ return 0;
+}
+
FAR struct spi_dev_s *up_spiinitialize(int port)
{
switch(port) {