blob: a1c307059c3ee5993630eca3fb446c246ebdb584 [file] [log] [blame]
Prafulla Wadaskar1fd6a9b2009-05-30 01:13:33 +05301/*
2 * (C) Copyright 2009
3 * Marvell Semiconductor <www.marvell.com>
4 * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
5 *
6 * Derived from drivers/spi/mpc8xxx_spi.c
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 * MA 02110-1301 USA
25 */
26
27#include <common.h>
28#include <malloc.h>
29#include <spi.h>
30#include <asm/arch/kirkwood.h>
31#include <asm/arch/spi.h>
32#include <asm/arch/mpp.h>
33
34static struct kwspi_registers *spireg = (struct kwspi_registers *)KW_SPI_BASE;
35
36struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
37 unsigned int max_hz, unsigned int mode)
38{
39 struct spi_slave *slave;
40 u32 data;
41 u32 kwspi_mpp_config[] = {
42 MPP0_GPIO,
43 MPP7_SPI_SCn,
44 0
45 };
46
47 if (!spi_cs_is_valid(bus, cs))
48 return NULL;
49
50 slave = malloc(sizeof(struct spi_slave));
51 if (!slave)
52 return NULL;
53
54 slave->bus = bus;
55 slave->cs = cs;
56
57 writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
58
59 /* calculate spi clock prescaller using max_hz */
60 data = ((CONFIG_SYS_TCLK / 2) / max_hz) & KWSPI_CLKPRESCL_MASK;
61 data |= 0x10;
62
63 /* program spi clock prescaller using max_hz */
64 writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
65 debug("data = 0x%08x \n", data);
66
67 writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause);
68 writel(KWSPI_IRQMASK, spireg->irq_mask);
69
70 /* program mpp registers to select SPI_CSn */
71 if (cs) {
72 kwspi_mpp_config[0] = MPP0_GPIO;
73 kwspi_mpp_config[1] = MPP7_SPI_SCn;
74 } else {
75 kwspi_mpp_config[0] = MPP0_SPI_SCn;
76 kwspi_mpp_config[1] = MPP7_GPO;
77 }
78 kirkwood_mpp_conf(kwspi_mpp_config);
79
80 return slave;
81}
82
83void spi_free_slave(struct spi_slave *slave)
84{
85 free(slave);
86}
87
88int spi_claim_bus(struct spi_slave *slave)
89{
90 return 0;
91}
92
93void spi_release_bus(struct spi_slave *slave)
94{
95}
96
97#ifndef CONFIG_SPI_CS_IS_VALID
98/*
99 * you can define this function board specific
100 * define above CONFIG in board specific config file and
101 * provide the function in board specific src file
102 */
103int spi_cs_is_valid(unsigned int bus, unsigned int cs)
104{
105 return (bus == 0 && (cs == 0 || cs == 1));
106}
107#endif
108
109void spi_cs_activate(struct spi_slave *slave)
110{
111 writel(readl(&spireg->ctrl) | KWSPI_IRQUNMASK, &spireg->ctrl);
112}
113
114void spi_cs_deactivate(struct spi_slave *slave)
115{
116 writel(readl(&spireg->ctrl) & KWSPI_IRQMASK, &spireg->ctrl);
117}
118
119int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
120 void *din, unsigned long flags)
121{
122 unsigned int tmpdout, tmpdin;
123 int tm, isread = 0;
124
125 debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
126 slave->bus, slave->cs, dout, din, bitlen);
127
128 if (flags & SPI_XFER_BEGIN)
129 spi_cs_activate(slave);
130
131 /*
132 * handle data in 8-bit chunks
133 * TBD: 2byte xfer mode to be enabled
134 */
135 writel(((readl(&spireg->cfg) & ~KWSPI_XFERLEN_MASK) |
136 KWSPI_XFERLEN_1BYTE), &spireg->cfg);
137
138 while (bitlen > 4) {
139 debug("loopstart bitlen %d\n", bitlen);
140 tmpdout = 0;
141
142 /* Shift data so it's msb-justified */
143 if (dout)
144 tmpdout = *(u32 *) dout & 0x0ff;
145
146 writel(~KWSPI_SMEMRDIRQ, &spireg->irq_cause);
147 writel(tmpdout, &spireg->dout); /* Write the data out */
148 debug("*** spi_xfer: ... %08x written, bitlen %d\n",
149 tmpdout, bitlen);
150
151 /*
152 * Wait for SPI transmit to get out
153 * or time out (1 second = 1000 ms)
154 * The NE event must be read and cleared first
155 */
156 for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
157 if (readl(&spireg->irq_cause) & KWSPI_SMEMRDIRQ) {
158 isread = 1;
159 tmpdin = readl(&spireg->din);
160 debug
161 ("spi_xfer: din %08x..%08x read\n",
162 din, tmpdin);
163
164 if (din) {
165 *((u8 *) din) = (u8) tmpdin;
166 din += 1;
167 }
168 if (dout)
169 dout += 1;
170 bitlen -= 8;
171 }
172 if (isread)
173 break;
174 }
175 if (tm >= KWSPI_TIMEOUT)
176 printf("*** spi_xfer: Time out during SPI transfer\n");
177
178 debug("loopend bitlen %d\n", bitlen);
179 }
180
181 if (flags & SPI_XFER_END)
182 spi_cs_deactivate(slave);
183
184 return 0;
185}