FreeCalypso > hg > freecalypso-tools
diff target-utils/libbase/spidrv.c @ 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 11 Jun 2016 00:13:35 +0000 |
parents | |
children | 3d73d4d3527f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/spidrv.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,139 @@ +/* Driver for SPI Master Controller inside TI Calypso */ +/* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */ + +/* (C) 2010 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "types.h" + +#define ASIC_CONF_REG (*(volatile u16 *) 0xFFFEF008) + +struct spi_regs { + u16 reg_set1; + u16 reg_set2; + u16 reg_ctrl; + u16 reg_status; + u16 reg_tx_lsb; + u16 reg_tx_msb; + u16 reg_rx_lsb; + u16 reg_rx_msb; +}; + +#define SPI_REGS (*(volatile struct spi_regs *) 0xFFFE3000) + +#define BASE_ADDR_SPI 0xfffe3000 +#define SPI_REG(n) (BASE_ADDR_SPI+(n)) + +#define SPI_SET1_EN_CLK (1 << 0) +#define SPI_SET1_WR_IRQ_DIS (1 << 4) +#define SPI_SET1_RDWR_IRQ_DIS (1 << 5) + +#define SPI_CTRL_RDWR (1 << 0) +#define SPI_CTRL_WR (1 << 1) +#define SPI_CTRL_NB_SHIFT 2 +#define SPI_CTRL_AD_SHIFT 7 + +#define SPI_STATUS_RE (1 << 0) /* Read End */ +#define SPI_STATUS_WE (1 << 1) /* Write End */ + +spi_init() +{ + static int initdone; + + if (initdone) + return(0); + ASIC_CONF_REG |= 0x6000; + SPI_REGS.reg_set1 = SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS | + SPI_SET1_RDWR_IRQ_DIS; + SPI_REGS.reg_set2 = 0x0001; + initdone = 1; + return(1); +} + +spi_xfer(dev_idx, bitlen, dout, din) + void *dout, *din; +{ + int bytes_per_xfer; + u16 reg_status, reg_ctrl = 0; + u32 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 = *(u8 *)dout; + tmp <<= 24 + (8-bitlen); /* align to MSB */ + } else if (bitlen <= 16) { + tmp = *(u16 *)dout; + tmp <<= 16 + (16-bitlen); /* align to MSB */ + } else { + tmp = *(u32 *)dout; + tmp <<= (32-bitlen); /* align to MSB */ + } + + /* fill transmit registers */ + SPI_REGS.reg_tx_msb = tmp >> 16; + SPI_REGS.reg_tx_lsb = tmp; + + /* initiate transfer */ + if (din) + reg_ctrl |= SPI_CTRL_RDWR; + else + reg_ctrl |= SPI_CTRL_WR; + SPI_REGS.reg_ctrl = reg_ctrl; + + /* wait until the transfer is complete */ + while (1) { + reg_status = SPI_REGS.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) */ + osmo_delay_ms(1); + + if (din) { + tmp = SPI_REGS.reg_rx_msb << 16; + tmp |= SPI_REGS.reg_rx_lsb; + + if (bitlen <= 8) + *(u8 *)din = tmp & 0xff; + else if (bitlen <= 16) + *(u16 *)din = tmp & 0xffff; + else + *(u32 *)din = tmp; + } + + return 0; +}