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,
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,
85 #error No SPI version defined
88 const int BAUD_RATE_DIV_MAX = sizeof(baud_rate_div) / sizeof(unsigned int);
91 * It is for the master mode operation to exchange a single word with
94 * @param data data to be transferred
95 * @param base base address of the spi module
97 * @return the value received from the Rx register
99 unsigned int spi_xchg_single(unsigned int data, unsigned int base)
101 volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
105 writel(data, base + SPI_TX_REG_OFF);
107 cfg_reg |= SPI_CTRL_REG_XCH_BIT;
109 writel(cfg_reg, base + SPI_CTRL_REG_OFF);
111 while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
114 return readl(base + SPI_RX_REG_OFF);
118 * Initialize and enable a spi module
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
124 * @return 0 if successful; non-zero otherwise
126 int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
128 unsigned int clock = get_peri_clock(base);
129 int i, div = clock / baud;
131 clock_spi_enable(base);
133 diag_printf1("base=0x%x, baue=%d, ctrl_val=0x%x, div=%d, clock=%d\n",
134 base, baud, ctrl_val, div, clock);
136 for (i = 0; i < BAUD_RATE_DIV_MAX; i++) {
137 if (div <= baud_rate_div[i]) {
141 if (i == BAUD_RATE_DIV_MAX) {
142 diag_printf("Baud rate requested (%d) is too slow for spi(0x%x)\n",
147 // to adjust for differen spi versions
148 if (BAUD_RATE_DIV_MAX > 8) {
149 ctrl_val |= ((i + 1) << SPI_CTRL_REG_RATE_SH);
151 ctrl_val |= (i << SPI_CTRL_REG_RATE_SH);
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);
157 writel(SPI_CTRL_EN, base + SPI_CTRL_REG_OFF);
159 writel(ctrl_val, base + SPI_CTRL_REG_OFF);
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]);
169 static void mxc_pmic_init(void)
171 volatile unsigned int rev_id;
173 spi_init(PMIC_SPI_BASE, 4000000, // 4MHz data rate
174 SPI_CTRL_REG_BIT_COUNT32 |
176 SPI_CTRL_SSPOL_HIGH |
177 SPI_CTRL_MODE_MASTER |
181 rev_id = pmic_reg(7, 0, 0);
182 diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
183 switch (rev_id & 0x1F) {
218 diag_printf("unknown");
224 RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
226 static void do_pmic(int argc, char *argv[]);
228 "Read/Write internal PMIC register",
229 "<reg num> [value to be written]",
233 static void do_pmic(int argc,char *argv[])
235 unsigned int reg, temp, val = 0, write = 0;
238 diag_printf("\tRead: pmic <reg num>\n");
239 diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
243 if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
244 diag_printf("Error: Invalid parameter\n");
249 if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
250 diag_printf("Error: Invalid parameter\n");
256 temp = pmic_reg(reg, val, write);
258 diag_printf("\tval: 0x%08x\n\n", temp);
262 * To read/write to a PMIC register. For write, it does another read for the
263 * actual register value.
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
269 * @return the actual data in the PMIC register
271 unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
275 if (reg > 63 || write > 1 ) {
276 diag_printf("<reg num> = %d is invalide. Should be less then 63\n", reg);
279 val = (write << 31) | (reg << 25) | (val & 0x00FFFFFF);
280 diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
282 temp = spi_xchg_single(val, PMIC_SPI_BASE);
286 temp = spi_xchg_single(val, PMIC_SPI_BASE);
291 #endif // PMIC_SPI_BASE