1 /**************************************************************************//**
2  * @file
3  * @brief SPI implementation of Board Control interface
4  *        This implementation use the USART2 SPI interface to control board
5  *        control registers. It works
6  * @author Energy Micro AS
7  * @version 2.0.1
8  ******************************************************************************
9  * @section License
10  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
11  *******************************************************************************
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute it
15  * freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software.
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  * 3. This notice may not be removed or altered from any source distribution.
22  * 4. The source and compiled code may only be used on Energy Micro "EFM32"
23  *    microcontrollers and "EFR4" radios.
24  *
25  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
26  * obligation to support this Software. Energy Micro AS is providing the
27  * Software "AS IS", with no express or implied warranties of any kind,
28  * including, but not limited to, any implied warranties of merchantability
29  * or fitness for any particular purpose or warranties against infringement
30  * of any proprietary rights of a third party.
31  *
32  * Energy Micro AS will not be liable for any consequential, incidental, or
33  * special damages, or any other relief, or for any claim by any third party,
34  * arising from your use of this Software.
35  *
36  *****************************************************************************/
37 
38 /***************************************************************************//**
39  * @addtogroup BSP
40  * @{
41  ******************************************************************************/
42 
43 #include <stdio.h>
44 #include "efm32.h"
45 #include "em_usart.h"
46 #include "em_gpio.h"
47 #include "em_cmu.h"
48 #include "dvk.h"
49 #include "dvk_bcregisters.h"
50 
51 #ifdef _EFM32_TINY_FAMILY
52 
53 /* USART used for SPI access */
54 #define USART_USED                USART0
55 #define USART_CLK                 cmuClock_USART0
56 
57 /* GPIO pins used, please refer to DVK user guide. */
58 #define PIN_SPIBUS_CONNECT        13
59 #define PORT_SPIBUS_CONNECT       gpioPortC
60 #define PIN_SPI_TX                10
61 #define PORT_SPI_TX               gpioPortE
62 #define PIN_SPI_RX                11
63 #define PORT_SPI_RX               gpioPortE
64 #define PIN_SPI_CLK               12
65 #define PORT_SPI_CLK              gpioPortE
66 #define PIN_SPI_CS                13
67 #define PORT_SPI_CS               gpioPortE
68 
69 #else
70 
71 /* USART used for SPI access */
72 #define USART_USED                USART2
73 #define USART_CLK                 cmuClock_USART2
74 
75 /* GPIO pins used, please refer to DVK user guide. */
76 #define PIN_SPIBUS_CONNECT        13
77 #define PORT_SPIBUS_CONNECT       gpioPortC
78 #define PIN_EBIBUS_CONNECT        12
79 #define PORT_EBIBUS_CONNECT       gpioPortC
80 #define PIN_SPI_TX                2
81 #define PORT_SPI_TX               gpioPortC
82 #define PIN_SPI_RX                3
83 #define PORT_SPI_RX               gpioPortC
84 #define PIN_SPI_CLK               4
85 #define PORT_SPI_CLK              gpioPortC
86 #define PIN_SPI_CS                5
87 #define PORT_SPI_CS               gpioPortC
88 
89 #endif
90 
91 static volatile uint16_t *lastAddr = NULL;
92 
93 /**************************************************************************//**
94  * @brief  Initializes SPI interface for access to FPGA registers
95  *         for board control
96  *****************************************************************************/
spiInit(void)97 static void spiInit(void)
98 {
99   USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
100 
101   /* Enable module clocks */
102   CMU_ClockEnable(cmuClock_GPIO, true);
103   CMU_ClockEnable(cmuClock_HFPER, true);
104   CMU_ClockEnable(USART_CLK, true);
105 
106   /* Configure SPI bus connect pins, DOUT set to 0, disable EBI */
107   GPIO_PinModeSet(PORT_SPIBUS_CONNECT, PIN_SPIBUS_CONNECT, gpioModePushPull, 0);
108   GPIO_PinModeSet(PORT_EBIBUS_CONNECT, PIN_EBIBUS_CONNECT, gpioModePushPull, 1);
109 
110   /* Configure SPI pins */
111   GPIO_PinModeSet(PORT_SPI_TX, PIN_SPI_TX, gpioModePushPull, 0);
112   GPIO_PinModeSet(PORT_SPI_RX, PIN_SPI_RX, gpioModePushPull, 0);
113   GPIO_PinModeSet(PORT_SPI_CLK, PIN_SPI_CLK, gpioModePushPull, 0);
114   /* Keep CS high to not activate slave */
115   GPIO_PinModeSet(PORT_SPI_CS, PIN_SPI_CS, gpioModePushPull, 1);
116 
117   /* Configure to use SPI master with manual CS */
118   /* For now, configure SPI for worst case 32MHz clock in order to work for all */
119   /* configurations. */
120   init.refFreq = 32000000;
121   init.baudrate = 7000000;
122   USART_InitSync(USART_USED, &init);
123 
124   /* Enable pins at default location */
125   USART_USED->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_CLKPEN;
126 }
127 
128 /**************************************************************************//**
129  * @brief  Disables GPIO pins and USART from FPGA register access
130  *****************************************************************************/
spiDisable(void)131 static void spiDisable(void)
132 {
133   USART_Reset(USART_USED);
134 
135   /* Disable LCD_SELECT */
136   GPIO_PinModeSet(gpioPortD, 13, gpioModeDisabled, 0);
137 
138   /* Disable SPI pins */
139   GPIO_PinModeSet(PORT_SPIBUS_CONNECT, 13, gpioModeDisabled, 0);
140   GPIO_PinModeSet(PORT_SPIBUS_CONNECT, 12, gpioModeDisabled, 0);
141   GPIO_PinModeSet(PORT_SPI_TX, PIN_SPI_TX, gpioModeDisabled, 0);
142   GPIO_PinModeSet(PORT_SPI_RX, PIN_SPI_RX, gpioModeDisabled, 0);
143   GPIO_PinModeSet(PORT_SPI_CLK, PIN_SPI_CLK, gpioModeDisabled, 0);
144   GPIO_PinModeSet(PORT_SPI_CS, PIN_SPI_CS, gpioModeDisabled, 0);
145 
146   /* Disable USART clock - we can't disable GPIO or HFPER as we don't know who else
147    * might be using it */
148   CMU_ClockEnable(USART_CLK, false);
149 }
150 
151 /**************************************************************************//**
152  * @brief  Perform SPI Transfer
153  *****************************************************************************/
spiAccess(uint8_t spiaddr,uint8_t rw,uint16_t spidata)154 static uint16_t spiAccess(uint8_t spiaddr, uint8_t rw, uint16_t spidata)
155 {
156   uint16_t      tmp;
157 
158   GPIO_PinOutClear(PORT_SPI_CS, PIN_SPI_CS);
159 
160   /* For every byte sent, one is received */
161 
162   /* Write SPI address */
163   USART_Tx(USART_USED, (spiaddr & 0x3) | rw << 3);
164   /* Just ignore data read back */
165   USART_Rx(USART_USED);
166 
167   /* SPI data LSB */
168   USART_Tx(USART_USED, spidata & 0xFF);
169   tmp = (uint16_t)USART_Rx(USART_USED);
170 
171   /* SPI data MSB */
172   USART_Tx(USART_USED, spidata >> 8);
173   tmp |= (uint16_t)USART_Rx(USART_USED) << 8;
174 
175   GPIO_PinOutSet(PORT_SPI_CS, PIN_SPI_CS);
176 
177   return tmp;
178 }
179 
180 /**************************************************************************//**
181  * @brief  Performs SPI write to FPGA register
182  * @param spiadr Address of register
183  * @param spidata Data to write
184  *****************************************************************************/
spiWrite(uint8_t spiadr,uint16_t spidata)185 static void spiWrite(uint8_t spiadr, uint16_t spidata)
186 {
187   spiAccess(spiadr, 0, spidata);
188 }
189 
190 /**************************************************************************//**
191  * @brief  Performs SPI read from FPGA register
192  * @param spiadr Address of register
193  * @param spidata Dummy data
194  *****************************************************************************/
spiRead(uint8_t spiadr,uint16_t spidata)195 static uint16_t spiRead(uint8_t spiadr, uint16_t spidata)
196 {
197   return spiAccess(spiadr, 1, spidata);
198 }
199 
200 /**************************************************************************//**
201  * @brief  Initializes DVK register access
202 *  @return true on success, false on failure
203  *****************************************************************************/
DVK_SPI_init(void)204 bool DVK_SPI_init(void)
205 {
206   uint16_t spiMagic;
207 
208   spiInit();
209   /* Read "board control Magic" register to verify SPI is up and running */
210   /*  if not FPGA is configured to be in EBI mode  */
211 
212   spiMagic = DVK_SPI_readRegister(BC_MAGIC);
213   if(spiMagic != BC_MAGIC_VALUE)
214   {
215     return false;
216   }
217   else
218   {
219     return true;
220   }
221 }
222 
223 /**************************************************************************//**
224  * @brief  Disable and free up resources used by SPI board control access
225  *****************************************************************************/
DVK_SPI_disable(void)226 void DVK_SPI_disable(void)
227 {
228   spiDisable();
229 }
230 
231 /**************************************************************************//**
232  * @brief  Perform read from DVK board control register
233  * @param  addr Address of register to read from
234  *****************************************************************************/
DVK_SPI_readRegister(volatile uint16_t * addr)235 uint16_t DVK_SPI_readRegister(volatile uint16_t *addr)
236 {
237   uint16_t data;
238 
239   if (addr != lastAddr)
240   {
241     spiWrite(0x00, 0xFFFF & ((uint32_t) addr));             /*LSBs of address*/
242     spiWrite(0x01, 0xFF & ((uint32_t) addr >> 16));         /*MSBs of address*/
243     spiWrite(0x02, (0x0C000000 & (uint32_t) addr) >> 26);   /*Chip select*/
244   }
245   /* Read twice */
246   data     = spiRead(0x03, 0);
247   data     = spiRead(0x03, 0);
248   lastAddr = addr;
249   return data;
250 }
251 
252 /**************************************************************************//**
253  * @brief  Perform write to DVK board control register
254  * @param addr Address of register to write to
255  * @param data 16-bit to  write into register
256  *****************************************************************************/
DVK_SPI_writeRegister(volatile uint16_t * addr,uint16_t data)257 void DVK_SPI_writeRegister(volatile uint16_t *addr, uint16_t data)
258 {
259   if (addr != lastAddr)
260   {
261     spiWrite(0x00, 0xFFFF & ((uint32_t) addr));             /*LSBs of address*/
262     spiWrite(0x01, 0xFF & ((uint32_t) addr >> 16));         /*MSBs of address*/
263     spiWrite(0x02, (0x0C000000 & (uint32_t) addr) >> 26);   /*Chip select*/
264   }
265   spiWrite(0x03, data);                                     /*Data*/
266   lastAddr = addr;
267 }
268 
269 /** @} (end group BSP) */
270