OpenCores
URL https://opencores.org/ocsvn/tiny_spi/tiny_spi/trunk

Subversion Repositories tiny_spi

[/] [tiny_spi/] [trunk/] [driver/] [u-boot/] [oc_tiny_spi.c] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 hippo5329
/*
2
 * Opencore tiny_spi driver
3
 *
4 9 hippo5329
 * http://opencores.org/project,tiny_spi
5
 *
6 5 hippo5329
 * based on bfin_spi.c
7
 * Copyright (c) 2005-2008 Analog Devices Inc.
8
 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
9
 *
10
 * Licensed under the GPL-2 or later.
11
 */
12 9 hippo5329
 
13 5 hippo5329
#include <common.h>
14
#include <asm/io.h>
15
#include <malloc.h>
16
#include <spi.h>
17
#include <asm/gpio.h>
18 9 hippo5329
 
19 5 hippo5329
#define TINY_SPI_RXDATA 0
20
#define TINY_SPI_TXDATA 4
21
#define TINY_SPI_STATUS 8
22
#define TINY_SPI_CONTROL 12
23
#define TINY_SPI_BAUD 16
24
 
25
#define TINY_SPI_STATUS_TXE 0x1
26
#define TINY_SPI_STATUS_TXR 0x2
27
 
28
struct tiny_spi_host {
29
        ulong base;
30
        uint freq;
31
        uint baudwidth;
32
};
33 9 hippo5329
static const struct tiny_spi_host tiny_spi_host_list[] =
34
        CONFIG_SYS_TINY_SPI_LIST;
35 5 hippo5329
 
36
struct tiny_spi_slave {
37
        struct spi_slave slave;
38 9 hippo5329
        const struct tiny_spi_host *host;
39 5 hippo5329
        uint mode;
40
        uint baud;
41
        uint flg;
42
};
43
#define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
44
 
45
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
46
{
47
        return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
48
}
49
 
50
void spi_cs_activate(struct spi_slave *slave)
51
{
52
        struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
53
        unsigned int cs = slave->cs;
54
        gpio_set_value(cs, tiny_spi->flg);
55
        debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
56
}
57
 
58
void spi_cs_deactivate(struct spi_slave *slave)
59
{
60
        struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
61
        unsigned int cs = slave->cs;
62
        gpio_set_value(cs, !tiny_spi->flg);
63
        debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
64
}
65
 
66
void spi_set_speed(struct spi_slave *slave, uint hz)
67
{
68
        struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
69 9 hippo5329
        const struct tiny_spi_host *host = tiny_spi->host;
70
        tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
71
                             (1 << host->baudwidth)) - 1;
72 5 hippo5329
        debug("%s: speed %u actual %u\n", __func__, hz,
73
              host->freq / ((tiny_spi->baud + 1) * 2));
74
}
75
 
76
void spi_init(void)
77
{
78
}
79
 
80
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
81
                                  unsigned int hz, unsigned int mode)
82
{
83
        struct tiny_spi_slave *tiny_spi;
84
 
85
        if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
86
                return NULL;
87
 
88
        tiny_spi = malloc(sizeof(*tiny_spi));
89
        if (!tiny_spi)
90
                return NULL;
91
        memset(tiny_spi, 0, sizeof(*tiny_spi));
92
 
93
        tiny_spi->slave.bus = bus;
94
        tiny_spi->slave.cs = cs;
95
        tiny_spi->host = &tiny_spi_host_list[bus];
96
        tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
97
        tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
98
        spi_set_speed(&tiny_spi->slave, hz);
99
 
100
        debug("%s: bus:%i cs:%i base:%lx\n", __func__,
101
                bus, cs, tiny_spi->host->base);
102
        return &tiny_spi->slave;
103
}
104
 
105
void spi_free_slave(struct spi_slave *slave)
106
{
107
        struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
108
        gpio_free(slave->cs);
109
        free(tiny_spi);
110
}
111
 
112
int spi_claim_bus(struct spi_slave *slave)
113
{
114
        struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
115 9 hippo5329
        const struct tiny_spi_host *host = tiny_spi->host;
116 5 hippo5329
        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
117
        gpio_direction_output(slave->cs, !tiny_spi->flg);
118
        writel(tiny_spi->mode, host->base + TINY_SPI_CONTROL);
119
        writel(tiny_spi->baud, host->base + TINY_SPI_BAUD);
120
        return 0;
121
}
122
 
123
void spi_release_bus(struct spi_slave *slave)
124
{
125
        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
126
}
127
 
128
#ifndef CONFIG_TINY_SPI_IDLE_VAL
129
# define CONFIG_TINY_SPI_IDLE_VAL 0xff
130
#endif
131
 
132
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
133
             void *din, unsigned long flags)
134
{
135 9 hippo5329
        const struct tiny_spi_host *host = to_tiny_spi_slave(slave)->host;
136 5 hippo5329
        const u8 *txp = dout;
137
        u8 *rxp = din;
138
        uint bytes = bitlen / 8;
139
        uint i;
140
 
141
        debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
142
                slave->bus, slave->cs, bitlen, bytes, flags);
143
        if (bitlen == 0)
144
                goto done;
145
 
146
        /* assume to do 8 bits transfers */
147
        if (bitlen % 8) {
148
                flags |= SPI_XFER_END;
149
                goto done;
150
        }
151
 
152
        if (flags & SPI_XFER_BEGIN)
153
                spi_cs_activate(slave);
154
 
155
        /* we need to tighten the transfer loop */
156
        if (txp && rxp) {
157
                writeb(*txp++, host->base + TINY_SPI_TXDATA);
158
                if (bytes > 1) {
159
                        writeb(*txp++, host->base + TINY_SPI_TXDATA);
160
                        for (i = 2; i < bytes; i++) {
161
                                u8 rx, tx = *txp++;
162
                                while (!(readb(host->base + TINY_SPI_STATUS) &
163 9 hippo5329
                                         TINY_SPI_STATUS_TXR))
164
                                        ;
165 5 hippo5329
                                rx = readb(host->base + TINY_SPI_TXDATA);
166
                                writeb(tx, host->base + TINY_SPI_TXDATA);
167
                                *rxp++ = rx;
168
                        }
169
                        while (!(readb(host->base + TINY_SPI_STATUS) &
170 9 hippo5329
                                 TINY_SPI_STATUS_TXR))
171
                                ;
172 5 hippo5329
                        *rxp++ = readb(host->base + TINY_SPI_TXDATA);
173
                }
174
                while (!(readb(host->base + TINY_SPI_STATUS) &
175 9 hippo5329
                         TINY_SPI_STATUS_TXE))
176
                        ;
177 5 hippo5329
                *rxp++ = readb(host->base + TINY_SPI_RXDATA);
178
        } else if (rxp) {
179
                writeb(CONFIG_TINY_SPI_IDLE_VAL, host->base + TINY_SPI_TXDATA);
180
                if (bytes > 1) {
181
                        writeb(CONFIG_TINY_SPI_IDLE_VAL,
182
                               host->base + TINY_SPI_TXDATA);
183
                        for (i = 2; i < bytes; i++) {
184
                                u8 rx;
185
                                while (!(readb(host->base + TINY_SPI_STATUS) &
186 9 hippo5329
                                         TINY_SPI_STATUS_TXR))
187
                                        ;
188 5 hippo5329
                                rx = readb(host->base + TINY_SPI_TXDATA);
189
                                writeb(CONFIG_TINY_SPI_IDLE_VAL,
190
                                       host->base + TINY_SPI_TXDATA);
191
                                *rxp++ = rx;
192
                        }
193
                        while (!(readb(host->base + TINY_SPI_STATUS) &
194 9 hippo5329
                                 TINY_SPI_STATUS_TXR))
195
                                ;
196 5 hippo5329
                        *rxp++ = readb(host->base + TINY_SPI_TXDATA);
197
                }
198
                while (!(readb(host->base + TINY_SPI_STATUS) &
199 9 hippo5329
                         TINY_SPI_STATUS_TXE))
200
                        ;
201 5 hippo5329
                *rxp++ = readb(host->base + TINY_SPI_RXDATA);
202
        } else if (txp) {
203
                writeb(*txp++, host->base + TINY_SPI_TXDATA);
204
                if (bytes > 1) {
205
                        writeb(*txp++, host->base + TINY_SPI_TXDATA);
206
                        for (i = 2; i < bytes; i++) {
207
                                u8 tx = *txp++;
208
                                while (!(readb(host->base + TINY_SPI_STATUS) &
209 9 hippo5329
                                         TINY_SPI_STATUS_TXR))
210
                                        ;
211 5 hippo5329
                                writeb(tx, host->base + TINY_SPI_TXDATA);
212
                        }
213
                }
214
                while (!(readb(host->base + TINY_SPI_STATUS) &
215 9 hippo5329
                         TINY_SPI_STATUS_TXE))
216
                        ;
217 5 hippo5329
        } else {
218
                writeb(CONFIG_TINY_SPI_IDLE_VAL, host->base + TINY_SPI_TXDATA);
219
                if (bytes > 1) {
220
                        writeb(CONFIG_TINY_SPI_IDLE_VAL,
221
                               host->base + TINY_SPI_TXDATA);
222
                        for (i = 2; i < bytes; i++) {
223
                                while (!(readb(host->base + TINY_SPI_STATUS) &
224 9 hippo5329
                                         TINY_SPI_STATUS_TXR))
225
                                        ;
226 5 hippo5329
                                writeb(CONFIG_TINY_SPI_IDLE_VAL,
227
                                       host->base + TINY_SPI_TXDATA);
228
                        }
229
                }
230
                while (!(readb(host->base + TINY_SPI_STATUS) &
231 9 hippo5329
                         TINY_SPI_STATUS_TXE))
232
                        ;
233 5 hippo5329
        }
234
 
235
 done:
236
        if (flags & SPI_XFER_END)
237
                spi_cs_deactivate(slave);
238
 
239
        return 0;
240
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.