1 /******************************************************************************
2 *                                                                             *
3 * License Agreement                                                           *
4 *                                                                             *
5 * Copyright (c) 2003 Altera Corporation, San Jose, California, USA.           *
6 * All rights reserved.                                                        *
7 *                                                                             *
8 * Permission is hereby granted, free of charge, to any person obtaining a     *
9 * copy of this software and associated documentation files (the "Software"),  *
10 * to deal in the Software without restriction, including without limitation   *
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
12 * and/or sell copies of the Software, and to permit persons to whom the       *
13 * Software is furnished to do so, subject to the following conditions:        *
14 *                                                                             *
15 * The above copyright notice and this permission notice shall be included in  *
16 * all copies or substantial portions of the Software.                         *
17 *                                                                             *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
24 * DEALINGS IN THE SOFTWARE.                                                   *
25 *                                                                             *
26 *                                                                             *
27 ******************************************************************************/
28 
29 #include "alt_types.h"
30 
31 #include "altera_avalon_spi_regs.h"
32 #include "altera_avalon_spi.h"
33 
34 /* This is a very simple routine which performs one SPI master transaction.
35  * It would be possible to implement a more efficient version using interrupts
36  * and sleeping threads but this is probably not worthwhile initially.
37  */
38 
alt_avalon_spi_command(alt_u32 base,alt_u32 slave,alt_u32 write_length,const alt_u8 * write_data,alt_u32 read_length,alt_u8 * read_data,alt_u32 flags)39 int alt_avalon_spi_command(alt_u32 base, alt_u32 slave,
40                            alt_u32 write_length, const alt_u8 * write_data,
41                            alt_u32 read_length, alt_u8 * read_data,
42                            alt_u32 flags)
43 {
44   const alt_u8 * write_end = write_data + write_length;
45   alt_u8 * read_end = read_data + read_length;
46 
47   alt_u32 write_zeros = read_length;
48   alt_u32 read_ignore = write_length;
49   alt_u32 status;
50 
51   /* We must not send more than two bytes to the target before it has
52    * returned any as otherwise it will overflow. */
53   /* Unfortunately the hardware does not seem to work with credits > 1,
54    * leave it at 1 for now. */
55   alt_32 credits = 1;
56 
57   /* Warning: this function is not currently safe if called in a multi-threaded
58    * environment, something above must perform locking to make it safe if more
59    * than one thread intends to use it.
60    */
61 
62   IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(base, 1 << slave);
63 
64   /* Set the SSO bit (force chipselect) only if the toggle flag is not set */
65   if ((flags & ALT_AVALON_SPI_COMMAND_TOGGLE_SS_N) == 0) {
66     IOWR_ALTERA_AVALON_SPI_CONTROL(base, ALTERA_AVALON_SPI_CONTROL_SSO_MSK);
67   }
68 
69   /*
70    * Discard any stale data present in the RXDATA register, in case
71    * previous communication was interrupted and stale data was left
72    * behind.
73    */
74   IORD_ALTERA_AVALON_SPI_RXDATA(base);
75 
76   /* Keep clocking until all the data has been processed. */
77   for ( ; ; )
78   {
79 
80     do
81     {
82       status = IORD_ALTERA_AVALON_SPI_STATUS(base);
83     }
84     while (((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0 || credits == 0) &&
85             (status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) == 0);
86 
87     if ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) != 0 && credits > 0)
88     {
89       credits--;
90 
91       if (write_data < write_end)
92         IOWR_ALTERA_AVALON_SPI_TXDATA(base, *write_data++);
93       else if (write_zeros > 0)
94       {
95         write_zeros--;
96         IOWR_ALTERA_AVALON_SPI_TXDATA(base, 0);
97       }
98       else
99         credits = -1024;
100     };
101 
102     if ((status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) != 0)
103     {
104       alt_u32 rxdata = IORD_ALTERA_AVALON_SPI_RXDATA(base);
105 
106       if (read_ignore > 0)
107         read_ignore--;
108       else
109         *read_data++ = (alt_u8)rxdata;
110       credits++;
111 
112       if (read_ignore == 0 && read_data == read_end)
113         break;
114     }
115 
116   }
117 
118   /* Wait until the interface has finished transmitting */
119   do
120   {
121     status = IORD_ALTERA_AVALON_SPI_STATUS(base);
122   }
123   while ((status & ALTERA_AVALON_SPI_STATUS_TMT_MSK) == 0);
124 
125   /* Clear SSO (release chipselect) unless the caller is going to
126    * keep using this chip
127    */
128   if ((flags & ALT_AVALON_SPI_COMMAND_MERGE) == 0)
129     IOWR_ALTERA_AVALON_SPI_CONTROL(base, 0);
130 
131   return read_length;
132 }
133