comparison target-utils/libbase/spidrv.c @ 991:5cff3579814c

target-utils: libbase factored out of libcommon The library dependency order is now strictly unidirectional
author Mychaela Falconia <falcon@ivan.Harhan.ORG>
date Wed, 30 Dec 2015 20:48:12 +0000
parents target-utils/libcommon/spidrv.c@e60aecf23970
children
comparison
equal deleted inserted replaced
990:2a867e5768e9 991:5cff3579814c
1 /* Driver for SPI Master Controller inside TI Calypso */
2 /* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */
3
4 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24 #include "types.h"
25
26 #define ASIC_CONF_REG (*(volatile u16 *) 0xFFFEF008)
27
28 struct spi_regs {
29 u16 reg_set1;
30 u16 reg_set2;
31 u16 reg_ctrl;
32 u16 reg_status;
33 u16 reg_tx_lsb;
34 u16 reg_tx_msb;
35 u16 reg_rx_lsb;
36 u16 reg_rx_msb;
37 };
38
39 #define SPI_REGS (*(volatile struct spi_regs *) 0xFFFE3000)
40
41 #define BASE_ADDR_SPI 0xfffe3000
42 #define SPI_REG(n) (BASE_ADDR_SPI+(n))
43
44 #define SPI_SET1_EN_CLK (1 << 0)
45 #define SPI_SET1_WR_IRQ_DIS (1 << 4)
46 #define SPI_SET1_RDWR_IRQ_DIS (1 << 5)
47
48 #define SPI_CTRL_RDWR (1 << 0)
49 #define SPI_CTRL_WR (1 << 1)
50 #define SPI_CTRL_NB_SHIFT 2
51 #define SPI_CTRL_AD_SHIFT 7
52
53 #define SPI_STATUS_RE (1 << 0) /* Read End */
54 #define SPI_STATUS_WE (1 << 1) /* Write End */
55
56 spi_init()
57 {
58 static int initdone;
59
60 if (initdone)
61 return(0);
62 ASIC_CONF_REG |= 0x6000;
63 SPI_REGS.reg_set1 = SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS |
64 SPI_SET1_RDWR_IRQ_DIS;
65 SPI_REGS.reg_set2 = 0x0001;
66 initdone = 1;
67 return(1);
68 }
69
70 spi_xfer(dev_idx, bitlen, dout, din)
71 void *dout, *din;
72 {
73 int bytes_per_xfer;
74 u16 reg_status, reg_ctrl = 0;
75 u32 tmp;
76
77 if (bitlen <= 0)
78 return 0;
79
80 if (bitlen > 32)
81 return -1;
82
83 if (dev_idx > 4)
84 return -1;
85
86 bytes_per_xfer = bitlen / 8;
87 if (bitlen % 8)
88 bytes_per_xfer ++;
89
90 reg_ctrl |= (bitlen - 1) << SPI_CTRL_NB_SHIFT;
91 reg_ctrl |= (dev_idx & 0x7) << SPI_CTRL_AD_SHIFT;
92
93 if (bitlen <= 8) {
94 tmp = *(u8 *)dout;
95 tmp <<= 24 + (8-bitlen); /* align to MSB */
96 } else if (bitlen <= 16) {
97 tmp = *(u16 *)dout;
98 tmp <<= 16 + (16-bitlen); /* align to MSB */
99 } else {
100 tmp = *(u32 *)dout;
101 tmp <<= (32-bitlen); /* align to MSB */
102 }
103
104 /* fill transmit registers */
105 SPI_REGS.reg_tx_msb = tmp >> 16;
106 SPI_REGS.reg_tx_lsb = tmp;
107
108 /* initiate transfer */
109 if (din)
110 reg_ctrl |= SPI_CTRL_RDWR;
111 else
112 reg_ctrl |= SPI_CTRL_WR;
113 SPI_REGS.reg_ctrl = reg_ctrl;
114
115 /* wait until the transfer is complete */
116 while (1) {
117 reg_status = SPI_REGS.reg_status;
118 if (din && (reg_status & SPI_STATUS_RE))
119 break;
120 else if (reg_status & SPI_STATUS_WE)
121 break;
122 }
123 /* FIXME: calibrate how much delay we really need (seven 13MHz cycles) */
124 osmo_delay_ms(1);
125
126 if (din) {
127 tmp = SPI_REGS.reg_rx_msb << 16;
128 tmp |= SPI_REGS.reg_rx_lsb;
129
130 if (bitlen <= 8)
131 *(u8 *)din = tmp & 0xff;
132 else if (bitlen <= 16)
133 *(u16 *)din = tmp & 0xffff;
134 else
135 *(u32 *)din = tmp;
136 }
137
138 return 0;
139 }