view target-utils/libcommon/spidrv.c @ 814:1c0c8f93bd60
aci: psa_util.c done
author
Space Falcon <falcon@ivan.Harhan.ORG>
date
Sun, 05 Apr 2015 08:09:28 +0000 (2015-04-05)
parents
e60aecf23970
children
line source
+ − /* 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;
+ − }