FreeCalypso > hg > freecalypso-tools
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e7502631a0f9 |
---|---|
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 } |