2 * Opencore tiny_spi driver
4 * http://opencores.org/project,tiny_spi
7 * Copyright (c) 2005-2008 Analog Devices Inc.
8 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
10 * SPDX-License-Identifier: GPL-2.0+
19 #define TINY_SPI_STATUS_TXE 0x1
20 #define TINY_SPI_STATUS_TXR 0x2
22 struct tiny_spi_regs
{
23 unsigned rxdata
; /* Rx data reg */
24 unsigned txdata
; /* Tx data reg */
25 unsigned status
; /* Status reg */
26 unsigned control
; /* Control reg */
27 unsigned baud
; /* Baud reg */
30 struct tiny_spi_host
{
35 static const struct tiny_spi_host tiny_spi_host_list
[] =
36 CONFIG_SYS_TINY_SPI_LIST
;
38 struct tiny_spi_slave
{
39 struct spi_slave slave
;
40 const struct tiny_spi_host
*host
;
45 #define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
47 int spi_cs_is_valid(unsigned int bus
, unsigned int cs
)
49 return bus
< ARRAY_SIZE(tiny_spi_host_list
) && gpio_is_valid(cs
);
52 void spi_cs_activate(struct spi_slave
*slave
)
54 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
55 unsigned int cs
= slave
->cs
;
57 gpio_set_value(cs
, tiny_spi
->flg
);
58 debug("%s: SPI_CS_GPIO:%x\n", __func__
, gpio_get_value(cs
));
61 void spi_cs_deactivate(struct spi_slave
*slave
)
63 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
64 unsigned int cs
= slave
->cs
;
66 gpio_set_value(cs
, !tiny_spi
->flg
);
67 debug("%s: SPI_CS_GPIO:%x\n", __func__
, gpio_get_value(cs
));
70 void spi_set_speed(struct spi_slave
*slave
, uint hz
)
72 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
73 const struct tiny_spi_host
*host
= tiny_spi
->host
;
75 tiny_spi
->baud
= min(DIV_ROUND_UP(host
->freq
, hz
* 2),
76 (1 << host
->baudwidth
)) - 1;
77 debug("%s: speed %u actual %u\n", __func__
, hz
,
78 host
->freq
/ ((tiny_spi
->baud
+ 1) * 2));
85 struct spi_slave
*spi_setup_slave(unsigned int bus
, unsigned int cs
,
86 unsigned int hz
, unsigned int mode
)
88 struct tiny_spi_slave
*tiny_spi
;
90 if (!spi_cs_is_valid(bus
, cs
) || gpio_request(cs
, "tiny_spi"))
93 tiny_spi
= spi_alloc_slave(struct tiny_spi_slave
, bus
, cs
);
97 tiny_spi
->host
= &tiny_spi_host_list
[bus
];
98 tiny_spi
->mode
= mode
& (SPI_CPOL
| SPI_CPHA
);
99 tiny_spi
->flg
= mode
& SPI_CS_HIGH
? 1 : 0;
100 spi_set_speed(&tiny_spi
->slave
, hz
);
102 debug("%s: bus:%i cs:%i base:%lx\n", __func__
,
103 bus
, cs
, tiny_spi
->host
->base
);
104 return &tiny_spi
->slave
;
107 void spi_free_slave(struct spi_slave
*slave
)
109 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
111 gpio_free(slave
->cs
);
115 int spi_claim_bus(struct spi_slave
*slave
)
117 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
118 struct tiny_spi_regs
*regs
= (void *)tiny_spi
->host
->base
;
120 debug("%s: bus:%i cs:%i\n", __func__
, slave
->bus
, slave
->cs
);
121 gpio_direction_output(slave
->cs
, !tiny_spi
->flg
);
122 writel(tiny_spi
->mode
, ®s
->control
);
123 writel(tiny_spi
->baud
, ®s
->baud
);
127 void spi_release_bus(struct spi_slave
*slave
)
129 debug("%s: bus:%i cs:%i\n", __func__
, slave
->bus
, slave
->cs
);
132 #ifndef CONFIG_TINY_SPI_IDLE_VAL
133 # define CONFIG_TINY_SPI_IDLE_VAL 0xff
136 int spi_xfer(struct spi_slave
*slave
, unsigned int bitlen
, const void *dout
,
137 void *din
, unsigned long flags
)
139 struct tiny_spi_slave
*tiny_spi
= to_tiny_spi_slave(slave
);
140 struct tiny_spi_regs
*regs
= (void *)tiny_spi
->host
->base
;
141 const u8
*txp
= dout
;
143 uint bytes
= bitlen
/ 8;
146 debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__
,
147 slave
->bus
, slave
->cs
, bitlen
, bytes
, flags
);
151 /* assume to do 8 bits transfers */
153 flags
|= SPI_XFER_END
;
157 if (flags
& SPI_XFER_BEGIN
)
158 spi_cs_activate(slave
);
160 /* we need to tighten the transfer loop */
162 writeb(*txp
++, ®s
->txdata
);
164 writeb(*txp
++, ®s
->txdata
);
165 for (i
= 2; i
< bytes
; i
++) {
167 while (!(readb(®s
->status
) &
168 TINY_SPI_STATUS_TXR
))
170 rx
= readb(®s
->txdata
);
171 writeb(tx
, ®s
->txdata
);
174 while (!(readb(®s
->status
) &
175 TINY_SPI_STATUS_TXR
))
177 *rxp
++ = readb(®s
->txdata
);
179 while (!(readb(®s
->status
) &
180 TINY_SPI_STATUS_TXE
))
182 *rxp
++ = readb(®s
->rxdata
);
184 writeb(CONFIG_TINY_SPI_IDLE_VAL
, ®s
->txdata
);
186 writeb(CONFIG_TINY_SPI_IDLE_VAL
,
188 for (i
= 2; i
< bytes
; i
++) {
190 while (!(readb(®s
->status
) &
191 TINY_SPI_STATUS_TXR
))
193 rx
= readb(®s
->txdata
);
194 writeb(CONFIG_TINY_SPI_IDLE_VAL
,
198 while (!(readb(®s
->status
) &
199 TINY_SPI_STATUS_TXR
))
201 *rxp
++ = readb(®s
->txdata
);
203 while (!(readb(®s
->status
) &
204 TINY_SPI_STATUS_TXE
))
206 *rxp
++ = readb(®s
->rxdata
);
208 writeb(*txp
++, ®s
->txdata
);
210 writeb(*txp
++, ®s
->txdata
);
211 for (i
= 2; i
< bytes
; i
++) {
213 while (!(readb(®s
->status
) &
214 TINY_SPI_STATUS_TXR
))
216 writeb(tx
, ®s
->txdata
);
219 while (!(readb(®s
->status
) &
220 TINY_SPI_STATUS_TXE
))
223 writeb(CONFIG_TINY_SPI_IDLE_VAL
, ®s
->txdata
);
225 writeb(CONFIG_TINY_SPI_IDLE_VAL
,
227 for (i
= 2; i
< bytes
; i
++) {
228 while (!(readb(®s
->status
) &
229 TINY_SPI_STATUS_TXR
))
231 writeb(CONFIG_TINY_SPI_IDLE_VAL
,
235 while (!(readb(®s
->status
) &
236 TINY_SPI_STATUS_TXE
))
241 if (flags
& SPI_XFER_END
)
242 spi_cs_deactivate(slave
);