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 5

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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