]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/spi/arm/mxc/v2_0/src/mxc_spi.c
Initial revision
[karo-tx-redboot.git] / packages / devs / spi / arm / mxc / v2_0 / src / mxc_spi.c
1 //==========================================================================
2 //
3 //      mxc_spi.c
4 //
5 //      SPI support on Freescale MXC platforms
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    Kevin Zhang <k.zhang@freescale.com>
44 // Contributors:
45 // Date:         2006-08-24
46 // Purpose:
47 // Description:
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <redboot.h>
54 #include <stdlib.h>
55 #include <pkgconf/hal.h>
56 #include <cyg/hal/hal_arch.h>
57 #include <cyg/hal/hal_cache.h>
58 #include <cyg/hal/hal_io.h>
59
60 #include <cyg/hal/fsl_board.h>
61 #include <cyg/io/mxc_spi.h>
62
63 void clock_spi_enable(unsigned int spi_clk);
64
65 #undef MXC_SPI_DEBUG
66 //#define MXC_SPI_DEBUG
67
68 #ifdef MXC_SPI_DEBUG
69 #define diag_printf1    diag_printf
70 #else
71 #define diag_printf1(fmt,args...)
72 #endif
73
74 #if defined(MXC_SPI_VER_0_7) || defined(MXC_SPI_VER_0_4)
75 const unsigned int baud_rate_div[] = {
76     4, 8, 16, 32, 64, 128, 256, 512,
77 };
78
79 #elif defined(MXC_SPI_VER_XX)
80 const unsigned int baud_rate_div[] = {
81     3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
82 };
83
84 #else
85 #error No SPI version defined
86 #endif
87
88 const int BAUD_RATE_DIV_MAX = sizeof(baud_rate_div) / sizeof(unsigned int);
89
90 /*!
91  * It is for the master mode operation to exchange a single word with
92  * external device.
93  *
94  * @param   data        data to be transferred
95  * @param   base        base address of the spi module
96  *
97  * @return              the value received from the Rx register
98  */
99 unsigned int spi_xchg_single(unsigned int data, unsigned int base)
100 {
101     volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
102
103     hal_delay_us(100);
104
105     writel(data, base + SPI_TX_REG_OFF);
106
107     cfg_reg |= SPI_CTRL_REG_XCH_BIT;
108
109     writel(cfg_reg, base + SPI_CTRL_REG_OFF);
110
111     while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
112     }
113
114     return readl(base + SPI_RX_REG_OFF);
115 }
116
117 /*!
118  * Initialize and enable a spi module
119  *
120  * @param   base        base address of spi module (also assigned for SPIx_CLK)
121  * @param   baue        the desired data rate
122  * @param   ctrl_val    control register value EXCEPT the data rate
123  *
124  * @return              0 if successful; non-zero otherwise
125  */
126 int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
127 {
128     unsigned int clock = get_peri_clock(base);
129     int i, div = clock / baud;
130
131     clock_spi_enable(base);
132
133     diag_printf1("base=0x%x, baue=%d, ctrl_val=0x%x, div=%d, clock=%d\n",
134                 base, baud, ctrl_val, div, clock);
135
136     for (i = 0; i < BAUD_RATE_DIV_MAX; i++) {
137         if (div <= baud_rate_div[i]) {
138             break;
139         }
140     }
141     if (i == BAUD_RATE_DIV_MAX) {
142         diag_printf("Baud rate requested (%d) is too slow for spi(0x%x)\n",
143                     baud, base);
144         return -1;
145     }
146
147     // to adjust for differen spi versions
148     if (BAUD_RATE_DIV_MAX > 8) {
149         ctrl_val |= ((i + 1) << SPI_CTRL_REG_RATE_SH);
150     } else
151         ctrl_val |= (i << SPI_CTRL_REG_RATE_SH);
152
153
154     diag_printf1("ctrl_val=0x%x, i=%d, SPI_CTRL_REG_RATE_SH=%d\n",
155                 ctrl_val, i, SPI_CTRL_REG_RATE_SH);
156
157     writel(SPI_CTRL_EN, base + SPI_CTRL_REG_OFF);
158
159     writel(ctrl_val, base + SPI_CTRL_REG_OFF);
160
161     writel(0, base + SPI_INT_CTRL_REG_OFF);
162     diag_printf1("requested data rate is: %d, actual rate is: %d\n",
163                  baud, clock / baud_rate_div[i]);
164
165     return 0;
166 }
167
168 #ifdef PMIC_SPI_BASE
169 static void mxc_pmic_init(void)
170 {
171         volatile unsigned int rev_id;
172
173     spi_init(PMIC_SPI_BASE, 4000000,      // 4MHz data rate
174              SPI_CTRL_REG_BIT_COUNT32 |
175              SPI_CTRL_CS0 |
176              SPI_CTRL_SSPOL_HIGH |
177              SPI_CTRL_MODE_MASTER |
178              SPI_CTRL_EN
179              );
180
181     rev_id = pmic_reg(7, 0, 0);
182         diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
183     switch (rev_id & 0x1F) {
184     case 0x1:
185         diag_printf("1.0");
186         break;
187     case 0x9:
188         diag_printf("1.1");
189         break;
190     case 0xA:
191         diag_printf("1.2");
192         break;
193     case 0x10:
194         diag_printf("2.0");
195         break;
196     case 0x11:
197         diag_printf("2.1");
198         break;
199     case 0x18:
200         diag_printf("3.0");
201         break;
202     case 0x19:
203         diag_printf("3.1");
204         break;
205     case 0x1A:
206         diag_printf("3.2");
207         break;
208     case 0x2:
209         diag_printf("3.2A");
210         break;
211     case 0x1B:
212         diag_printf("3.3");
213         break;
214     case 0x1D:
215         diag_printf("3.5");
216         break;
217     default:
218         diag_printf("unknown");
219         break;
220     }
221     diag_printf("]\n");
222 }
223
224 RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
225
226 static void do_pmic(int argc, char *argv[]);
227 RedBoot_cmd("pmic",
228             "Read/Write internal PMIC register",
229             "<reg num> [value to be written]",
230             do_pmic
231            );
232
233 static void do_pmic(int argc,char *argv[])
234 {
235     unsigned int reg, temp, val = 0, write = 0;
236
237     if (argc == 1) {
238         diag_printf("\tRead:  pmic <reg num>\n");
239         diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
240         return;
241     }
242
243     if (!parse_num(*(&argv[1]), (unsigned long *)&reg, &argv[1], ":")) {
244         diag_printf("Error: Invalid parameter\n");
245         return;
246     }
247
248     if (argc == 3) {
249         if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
250             diag_printf("Error: Invalid parameter\n");
251             return;
252         }
253         write = 1;
254     }
255
256     temp = pmic_reg(reg, val, write);
257
258     diag_printf("\tval: 0x%08x\n\n", temp);
259 }
260
261 /*!
262  * To read/write to a PMIC register. For write, it does another read for the
263  * actual register value.
264  *
265  * @param   reg         register number inside the PMIC
266  * @param   val         data to be written to the register; don't care for read
267  * @param   write       0 for read; 1 for write
268  *
269  * @return              the actual data in the PMIC register
270  */
271 unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
272 {
273     unsigned int temp;
274
275     if (reg > 63 || write > 1 ) {
276         diag_printf("<reg num> = %d is invalide. Should be less then 63\n", reg);
277         return 0;
278     }
279     val = (write << 31) | (reg << 25) | (val & 0x00FFFFFF);
280     diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
281
282     temp = spi_xchg_single(val, PMIC_SPI_BASE);
283
284     if (write) {
285         val &= ~(1 << 31);
286         temp = spi_xchg_single(val, PMIC_SPI_BASE);
287     }
288
289     return temp;
290 }
291 #endif // PMIC_SPI_BASE