]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/spi/mxc_spi.c
Merging Stelian Pop AT91 patches
[karo-tx-uboot.git] / drivers / spi / mxc_spi.c
1 /*
2  * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  *
19  */
20
21 #include <common.h>
22 #include <spi.h>
23 #include <asm/io.h>
24
25 #ifdef CONFIG_MX27
26 /* i.MX27 has a completely wrong register layout and register definitions in the
27  * datasheet, the correct one is in the Freescale's Linux driver */
28
29 #error "i.MX27 CSPI not supported due to drastic differences in register definisions" \
30 "See linux mxc_spi driver from Freescale for details."
31
32 #else
33
34 #define MXC_CSPIRXDATA          0x00
35 #define MXC_CSPITXDATA          0x04
36 #define MXC_CSPICTRL            0x08
37 #define MXC_CSPIINT             0x0C
38 #define MXC_CSPIDMA             0x10
39 #define MXC_CSPISTAT            0x14
40 #define MXC_CSPIPERIOD          0x18
41 #define MXC_CSPITEST            0x1C
42 #define MXC_CSPIRESET           0x00
43
44 #define MXC_CSPICTRL_EN         (1 << 0)
45 #define MXC_CSPICTRL_MODE       (1 << 1)
46 #define MXC_CSPICTRL_XCH        (1 << 2)
47 #define MXC_CSPICTRL_SMC        (1 << 3)
48 #define MXC_CSPICTRL_POL        (1 << 4)
49 #define MXC_CSPICTRL_PHA        (1 << 5)
50 #define MXC_CSPICTRL_SSCTL      (1 << 6)
51 #define MXC_CSPICTRL_SSPOL      (1 << 7)
52 #define MXC_CSPICTRL_CHIPSELECT(x)      (((x) & 0x3) << 24)
53 #define MXC_CSPICTRL_BITCOUNT(x)        (((x) & 0x1f) << 8)
54 #define MXC_CSPICTRL_DATARATE(x)        (((x) & 0x7) << 16)
55
56 #define MXC_CSPIPERIOD_32KHZ    (1 << 15)
57
58 static unsigned long spi_bases[] = {
59         0x43fa4000,
60         0x50010000,
61         0x53f84000,
62 };
63
64 static unsigned long spi_base;
65
66 #endif
67
68 spi_chipsel_type spi_chipsel[] = {
69         (spi_chipsel_type)0,
70         (spi_chipsel_type)1,
71         (spi_chipsel_type)2,
72         (spi_chipsel_type)3,
73 };
74 int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]);
75
76 static inline u32 reg_read(unsigned long addr)
77 {
78         return *(volatile unsigned long*)addr;
79 }
80
81 static inline void reg_write(unsigned long addr, u32 val)
82 {
83         *(volatile unsigned long*)addr = val;
84 }
85
86 static u32 spi_xchg_single(u32 data, int bitlen)
87 {
88
89         unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL);
90
91         if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {
92                 cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
93                         MXC_CSPICTRL_BITCOUNT(bitlen - 1);
94                 reg_write(spi_base + MXC_CSPICTRL, cfg_reg);
95         }
96
97         reg_write(spi_base + MXC_CSPITXDATA, data);
98
99         cfg_reg |= MXC_CSPICTRL_XCH;
100
101         reg_write(spi_base + MXC_CSPICTRL, cfg_reg);
102
103         while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)
104                 ;
105
106         return reg_read(spi_base + MXC_CSPIRXDATA);
107 }
108
109 int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
110 {
111         int n_blks = (bitlen + 31) / 32;
112         u32 *out_l, *in_l;
113         int i;
114
115         if ((int)dout & 3 || (int)din & 3) {
116                 printf("Error: unaligned buffers in: %p, out: %p\n", din, dout);
117                 return 1;
118         }
119
120         if (!spi_base)
121                 spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH);
122
123         for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;
124              i < n_blks;
125              i++, in_l++, out_l++, bitlen -= 32)
126                 *in_l = spi_xchg_single(*out_l, bitlen);
127
128         return 0;
129 }
130
131 void spi_init(void)
132 {
133 }
134
135 int spi_select(unsigned int bus, unsigned int dev, unsigned long mode)
136 {
137         unsigned int ctrl_reg;
138
139         if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) ||
140             dev > 3)
141                 return 1;
142
143         spi_base = spi_bases[bus];
144
145         ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) |
146                 MXC_CSPICTRL_BITCOUNT(31) |
147                 MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */
148                 MXC_CSPICTRL_EN |
149                 MXC_CSPICTRL_MODE;
150
151         if (mode & SPI_CPHA)
152                 ctrl_reg |= MXC_CSPICTRL_PHA;
153         if (!(mode & SPI_CPOL))
154                 ctrl_reg |= MXC_CSPICTRL_POL;
155         if (mode & SPI_CS_HIGH)
156                 ctrl_reg |= MXC_CSPICTRL_SSPOL;
157
158         reg_write(spi_base + MXC_CSPIRESET, 1);
159         udelay(1);
160         reg_write(spi_base + MXC_CSPICTRL, ctrl_reg);
161         reg_write(spi_base + MXC_CSPIPERIOD,
162                   MXC_CSPIPERIOD_32KHZ);
163         reg_write(spi_base + MXC_CSPIINT, 0);
164
165         return 0;
166 }