1 //==========================================================================
5 // SPI support on Freescale MXC platforms
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.
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.
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
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.
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.
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.
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####
43 // Author(s): Kevin Zhang <k.zhang@freescale.com>
49 //####DESCRIPTIONEND####
51 //==========================================================================
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>
60 #include <cyg/hal/fsl_board.h>
61 #include <cyg/io/mxc_spi.h>
63 void clock_spi_enable(unsigned int spi_clk);
66 //#define MXC_SPI_DEBUG
69 #define diag_printf1 diag_printf
71 #define diag_printf1(fmt,args...)
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,
78 static int version = 1;
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,
83 static int version = 2;
84 #elif defined(MXC_SPI_VER_2_3)
85 const unsigned int baud_rate_div[] = {
86 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
88 static int version = 3;
90 #error No SPI version defined
93 const int BAUD_RATE_DIV_MAX = sizeof(baud_rate_div) / sizeof(unsigned int);
96 * Initialize and enable a spi module
98 * @param base base address of spi module (also assigned for SPIx_CLK)
99 * @param baue the desired data rate
100 * @param ctrl_val control register value EXCEPT the data rate
102 * @return 0 if successful; non-zero otherwise
104 int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
106 unsigned int clock = get_peri_clock(base);
107 int i, div = clock / baud;
109 clock_spi_enable(base);
111 diag_printf1("base=0x%x, baue=%d, ctrl_val=0x%x, div=%d, clock=%d\n",
112 base, baud, ctrl_val, div, clock);
114 for (i = 0; i < BAUD_RATE_DIV_MAX; i++) {
115 if (div <= baud_rate_div[i]) {
119 if (i == BAUD_RATE_DIV_MAX) {
120 diag_printf("Baud rate requested (%d) is too slow for spi(0x%x)\n",
125 // to adjust for differen spi versions
127 ctrl_val |= ((i + 1) << SPI_CTRL_REG_RATE_SH);
129 ctrl_val |= (i << SPI_CTRL_REG_RATE_SH);
132 diag_printf1("ctrl_val=0x%x, i=%d, SPI_CTRL_REG_RATE_SH=%d\n",
133 ctrl_val, i, SPI_CTRL_REG_RATE_SH);
135 /* Reinitialize the control register */
136 writel(0, base + SPI_CTRL_REG_OFF);
137 writel(SPI_CTRL_EN, base + SPI_CTRL_REG_OFF);
139 writel(ctrl_val, base + SPI_CTRL_REG_OFF);
141 writel(0, base + SPI_INT_CTRL_REG_OFF);
142 diag_printf1("requested data rate is: %d, actual rate is: %d\n",
143 baud, clock / baud_rate_div[i]);
150 * It is for the master mode operation to exchange a single word with
153 * @param data data to be transferred
154 * @param base base address of the spi module
156 * @return the value received from the Rx register
158 unsigned int spi_xchg_single(unsigned int data, unsigned int base)
160 volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
162 #if defined(MXC_SPI_VER_2_3)
163 int ss_num = (PMIC_SPI_CHIP_SELECT_NO >> 18) & 0x3;
164 volatile unsigned int pol_reg = readl(base + SPI_CONFIG_REG_OFF);
165 pol_reg &= ~(1 << (12 + ss_num));
166 /* Activate the SS signal */
167 pol_reg |= PMIC_SPI_SS_POL;
168 writel(pol_reg, base + SPI_CONFIG_REG_OFF);
173 writel(data, base + SPI_TX_REG_OFF);
175 cfg_reg |= SPI_CTRL_REG_XCH_BIT;
177 writel(cfg_reg, base + SPI_CTRL_REG_OFF);
179 while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
182 #if defined(MXC_SPI_VER_2_3)
183 pol_reg &= ~(1 << (12 + ss_num));
184 pol_reg |= (~PMIC_SPI_SS_POL) & (1 << (12 + ss_num));
185 /* Deactivate the SS signal */
186 writel(PMIC_SPI_SS_POL, base + SPI_CONFIG_REG_OFF);
189 return readl(base + SPI_RX_REG_OFF);
192 static void mxc_pmic_init(void)
194 volatile unsigned int rev_id;
197 #if defined(MXC_SPI_VER_2_3)
198 ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_MODE_MASTER_0 | SPI_CTRL_EN;
200 ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_SSPOL_HIGH |
201 SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
203 /* Activate the SS signal */
204 ctrl |= PMIC_SPI_CHIP_SELECT_NO;
205 spi_init(PMIC_SPI_BASE, 6000000, // 4MHz data rate
208 rev_id = pmic_reg(7, 0, 0);
209 diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
210 switch (rev_id & 0x1F) {
245 diag_printf("unknown");
251 RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
253 static void do_pmic(int argc, char *argv[]);
255 "Read/Write internal PMIC register",
256 "<reg num> [value to be written]",
260 static void do_pmic(int argc,char *argv[])
262 unsigned int reg, temp, val = 0, write = 0;
265 diag_printf("\tRead: pmic <reg num>\n");
266 diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
270 if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
271 diag_printf("Error: Invalid parameter\n");
276 if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
277 diag_printf("Error: Invalid parameter\n");
283 temp = pmic_reg(reg, val, write);
285 diag_printf("\tval: 0x%08x\n\n", temp);
289 * To read/write to a PMIC register. For write, it does another read for the
290 * actual register value.
292 * @param reg register number inside the PMIC
293 * @param val data to be written to the register; don't care for read
294 * @param write 0 for read; 1 for write
296 * @return the actual data in the PMIC register
298 unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
302 if (reg > 63 || write > 1 ) {
303 diag_printf("<reg num> = %d is invalide. Should be less then 63\n", reg);
306 val = (write << 31) | (reg << 25) | (val & 0x00FFFFFF);
307 diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
309 temp = spi_xchg_single(val, PMIC_SPI_BASE);
313 temp = spi_xchg_single(val, PMIC_SPI_BASE);
318 #endif // PMIC_SPI_BASE
322 unsigned int spi_cpld_xchg_single(unsigned int data, unsigned int data1, unsigned int base)
324 volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
327 /* Activate the SS signal */
328 cfg_reg |= CPLD_SPI_CHIP_SELECT_NO;
329 writel(cfg_reg, CPLD_SPI_BASE + SPI_CTRL_REG_OFF);
332 writel(data, base + SPI_TX_REG_OFF);
333 writel(data1, base + SPI_TX_REG_OFF);
335 cfg_reg |= SPI_CTRL_REG_XCH_BIT;
336 writel(cfg_reg, base + SPI_CTRL_REG_OFF);
338 while ((((cfg_reg = readl(base + SPI_TEST_REG_OFF)) &
339 SPI_TEST_REG_RXCNT_MASK) >> SPI_TEST_REG_RXCNT_OFFSET) != 2) {
342 /* Deactivate the SS signal */
343 cfg_reg = readl(base + SPI_CTRL_REG_OFF);
344 cfg_reg &= ~SPI_CTRL_CS_MASK;
345 writel(cfg_reg, base + SPI_CTRL_REG_OFF);
347 /* Read from RX FIFO, second entry contains the data */
348 temp = readl(base + SPI_RX_REG_OFF);
349 temp = readl(base + SPI_RX_REG_OFF);
350 return ((temp >> 6) & 0xffff);
353 static void mxc_cpld_spi_init(void)
357 ctrl = SPI_CTRL_REG_BIT_COUNT46 | CPLD_SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
359 spi_init(CPLD_SPI_BASE, 18000000, // 54MHz data rate
363 RedBoot_init(mxc_cpld_spi_init, RedBoot_INIT_PRIO(102));
365 static void do_cpld(int argc, char *argv[]);
367 RedBoot_cmd("spi_cpld",
368 "Read/Write 16-bit internal CPLD register over CSPI",
369 "<reg num> [16-bit value to be written]",
373 static void do_cpld(int argc,char *argv[])
375 unsigned int reg, temp, val = 0, read = 1;
378 diag_printf("\tRead: spi_cpld <reg num>\n");
379 diag_printf("\tWrite: spi_cpld <reg num> <value to be written>\n");
383 if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
384 diag_printf("Error: Invalid parameter\n");
389 if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
390 diag_printf("Error: Invalid parameter\n");
396 temp = cpld_reg(reg, val, read);
398 diag_printf("\tval: 0x%04x\n\n", temp);
402 * To read/write to a CPLD register.
404 * @param reg register number inside the CPLD
405 * @param val data to be written to the register; don't care for read
406 * @param read 0 for write; 1 for read
408 * @return the actual data in the CPLD register
410 unsigned int cpld_reg_xfer(unsigned int reg, unsigned int val, unsigned int read)
412 unsigned int local_val1, local_val2;
416 local_val1 = (read << 13) | ((reg & 0x0001FFFF) >> 5) | 0x00001000;
418 //local_val1 = (read << 22) | (reg << 4) | 0x00200004;
420 local_val2 = ( ((reg & 0x0000001F) << 27) | 0x0200001f);
423 //local_val1 = (read << 22) | (reg << 4) | 0x00200007;
424 //local_val2 = ((val & 0xFFFF) << 6) | 0x00400027;
425 local_val2 = ( ((reg & 0x0000001F) << 27) | ((val & 0x0000FFFF) << 6) | 0x03C00027);
429 diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
430 return spi_cpld_xchg_single(local_val1, local_val2, CPLD_SPI_BASE);
434 * To read/write to a CPLD register. For write, it does another read for the
435 * actual register value.
437 * @param reg register number inside the CPLD
438 * @param val data to be written to the register; don't care for read
439 * @param read 0 for write; 1 for read
441 * @return the actual data in the CPLD register
443 unsigned int cpld_reg(unsigned int reg, unsigned int val, unsigned int read)
447 if (reg > 0x20068 || read > 1 ) {
448 diag_printf("<reg num> = %x is invalid. Should be less then 0x20068\n", reg);
452 temp = cpld_reg_xfer(reg, val, read);
453 diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
456 temp = cpld_reg_xfer(reg, val, 1);
462 #endif // CPLD_SPI_BASE