1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a666f39eSSimon Glass /*
3a666f39eSSimon Glass * (C) Copyright 2002
4a666f39eSSimon Glass * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
5a666f39eSSimon Glass *
6a666f39eSSimon Glass * Influenced by code from:
7a666f39eSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8a666f39eSSimon Glass */
9a666f39eSSimon Glass
10a666f39eSSimon Glass #include <common.h>
11a666f39eSSimon Glass #include <spi.h>
12a666f39eSSimon Glass
13a666f39eSSimon Glass #include <malloc.h>
14a666f39eSSimon Glass
15a666f39eSSimon Glass /*-----------------------------------------------------------------------
16a666f39eSSimon Glass * Definitions
17a666f39eSSimon Glass */
18a666f39eSSimon Glass
19a666f39eSSimon Glass #ifdef DEBUG_SPI
20a666f39eSSimon Glass #define PRINTD(fmt,args...) printf (fmt ,##args)
21a666f39eSSimon Glass #else
22a666f39eSSimon Glass #define PRINTD(fmt,args...)
23a666f39eSSimon Glass #endif
24a666f39eSSimon Glass
25a666f39eSSimon Glass struct soft_spi_slave {
26a666f39eSSimon Glass struct spi_slave slave;
27a666f39eSSimon Glass unsigned int mode;
28a666f39eSSimon Glass };
29a666f39eSSimon Glass
to_soft_spi(struct spi_slave * slave)30a666f39eSSimon Glass static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
31a666f39eSSimon Glass {
32a666f39eSSimon Glass return container_of(slave, struct soft_spi_slave, slave);
33a666f39eSSimon Glass }
34a666f39eSSimon Glass
35a666f39eSSimon Glass /*=====================================================================*/
36a666f39eSSimon Glass /* Public Functions */
37a666f39eSSimon Glass /*=====================================================================*/
38a666f39eSSimon Glass
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)39a666f39eSSimon Glass struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
40a666f39eSSimon Glass unsigned int max_hz, unsigned int mode)
41a666f39eSSimon Glass {
42a666f39eSSimon Glass struct soft_spi_slave *ss;
43a666f39eSSimon Glass
44a666f39eSSimon Glass if (!spi_cs_is_valid(bus, cs))
45a666f39eSSimon Glass return NULL;
46a666f39eSSimon Glass
47a666f39eSSimon Glass ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
48a666f39eSSimon Glass if (!ss)
49a666f39eSSimon Glass return NULL;
50a666f39eSSimon Glass
51a666f39eSSimon Glass ss->mode = mode;
52a666f39eSSimon Glass
53a666f39eSSimon Glass /* TODO: Use max_hz to limit the SCK rate */
54a666f39eSSimon Glass
55a666f39eSSimon Glass return &ss->slave;
56a666f39eSSimon Glass }
57a666f39eSSimon Glass
spi_free_slave(struct spi_slave * slave)58a666f39eSSimon Glass void spi_free_slave(struct spi_slave *slave)
59a666f39eSSimon Glass {
60a666f39eSSimon Glass struct soft_spi_slave *ss = to_soft_spi(slave);
61a666f39eSSimon Glass
62a666f39eSSimon Glass free(ss);
63a666f39eSSimon Glass }
64a666f39eSSimon Glass
spi_claim_bus(struct spi_slave * slave)65a666f39eSSimon Glass int spi_claim_bus(struct spi_slave *slave)
66a666f39eSSimon Glass {
67a666f39eSSimon Glass #ifdef CONFIG_SYS_IMMR
68a666f39eSSimon Glass volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
69a666f39eSSimon Glass #endif
70a666f39eSSimon Glass struct soft_spi_slave *ss = to_soft_spi(slave);
71a666f39eSSimon Glass
72a666f39eSSimon Glass /*
73a666f39eSSimon Glass * Make sure the SPI clock is in idle state as defined for
74a666f39eSSimon Glass * this slave.
75a666f39eSSimon Glass */
76a666f39eSSimon Glass if (ss->mode & SPI_CPOL)
77a666f39eSSimon Glass SPI_SCL(1);
78a666f39eSSimon Glass else
79a666f39eSSimon Glass SPI_SCL(0);
80a666f39eSSimon Glass
81a666f39eSSimon Glass return 0;
82a666f39eSSimon Glass }
83a666f39eSSimon Glass
spi_release_bus(struct spi_slave * slave)84a666f39eSSimon Glass void spi_release_bus(struct spi_slave *slave)
85a666f39eSSimon Glass {
86a666f39eSSimon Glass /* Nothing to do */
87a666f39eSSimon Glass }
88a666f39eSSimon Glass
89a666f39eSSimon Glass /*-----------------------------------------------------------------------
90a666f39eSSimon Glass * SPI transfer
91a666f39eSSimon Glass *
92a666f39eSSimon Glass * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
93a666f39eSSimon Glass * "bitlen" bits in the SPI MISO port. That's just the way SPI works.
94a666f39eSSimon Glass *
95a666f39eSSimon Glass * The source of the outgoing bits is the "dout" parameter and the
96a666f39eSSimon Glass * destination of the input bits is the "din" parameter. Note that "dout"
97a666f39eSSimon Glass * and "din" can point to the same memory location, in which case the
98a666f39eSSimon Glass * input data overwrites the output data (since both are buffered by
99a666f39eSSimon Glass * temporary variables, this is OK).
100a666f39eSSimon Glass */
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)101a666f39eSSimon Glass int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
102a666f39eSSimon Glass const void *dout, void *din, unsigned long flags)
103a666f39eSSimon Glass {
104a666f39eSSimon Glass #ifdef CONFIG_SYS_IMMR
105a666f39eSSimon Glass volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
106a666f39eSSimon Glass #endif
107a666f39eSSimon Glass struct soft_spi_slave *ss = to_soft_spi(slave);
108a666f39eSSimon Glass uchar tmpdin = 0;
109a666f39eSSimon Glass uchar tmpdout = 0;
110a666f39eSSimon Glass const u8 *txd = dout;
111a666f39eSSimon Glass u8 *rxd = din;
112a666f39eSSimon Glass int cpol = ss->mode & SPI_CPOL;
113a666f39eSSimon Glass int cpha = ss->mode & SPI_CPHA;
114a666f39eSSimon Glass unsigned int j;
115a666f39eSSimon Glass
116a666f39eSSimon Glass PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
117a666f39eSSimon Glass slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
118a666f39eSSimon Glass
119a666f39eSSimon Glass if (flags & SPI_XFER_BEGIN)
120a666f39eSSimon Glass spi_cs_activate(slave);
121a666f39eSSimon Glass
122a666f39eSSimon Glass for(j = 0; j < bitlen; j++) {
123a666f39eSSimon Glass /*
124a666f39eSSimon Glass * Check if it is time to work on a new byte.
125a666f39eSSimon Glass */
126a666f39eSSimon Glass if ((j % 8) == 0) {
127a666f39eSSimon Glass if (txd)
128a666f39eSSimon Glass tmpdout = *txd++;
129a666f39eSSimon Glass else
130a666f39eSSimon Glass tmpdout = 0;
131a666f39eSSimon Glass if(j != 0) {
132a666f39eSSimon Glass if (rxd)
133a666f39eSSimon Glass *rxd++ = tmpdin;
134a666f39eSSimon Glass }
135a666f39eSSimon Glass tmpdin = 0;
136a666f39eSSimon Glass }
137a666f39eSSimon Glass
138a666f39eSSimon Glass if (!cpha)
139a666f39eSSimon Glass SPI_SCL(!cpol);
140a666f39eSSimon Glass SPI_SDA(tmpdout & 0x80);
141a666f39eSSimon Glass SPI_DELAY;
142a666f39eSSimon Glass if (cpha)
143a666f39eSSimon Glass SPI_SCL(!cpol);
144a666f39eSSimon Glass else
145a666f39eSSimon Glass SPI_SCL(cpol);
146a666f39eSSimon Glass tmpdin <<= 1;
147a666f39eSSimon Glass tmpdin |= SPI_READ;
148a666f39eSSimon Glass tmpdout <<= 1;
149a666f39eSSimon Glass SPI_DELAY;
150a666f39eSSimon Glass if (cpha)
151a666f39eSSimon Glass SPI_SCL(cpol);
152a666f39eSSimon Glass }
153a666f39eSSimon Glass /*
154a666f39eSSimon Glass * If the number of bits isn't a multiple of 8, shift the last
155a666f39eSSimon Glass * bits over to left-justify them. Then store the last byte
156a666f39eSSimon Glass * read in.
157a666f39eSSimon Glass */
158a666f39eSSimon Glass if (rxd) {
159a666f39eSSimon Glass if ((bitlen % 8) != 0)
160a666f39eSSimon Glass tmpdin <<= 8 - (bitlen % 8);
161a666f39eSSimon Glass *rxd++ = tmpdin;
162a666f39eSSimon Glass }
163a666f39eSSimon Glass
164a666f39eSSimon Glass if (flags & SPI_XFER_END)
165a666f39eSSimon Glass spi_cs_deactivate(slave);
166a666f39eSSimon Glass
167a666f39eSSimon Glass return(0);
168a666f39eSSimon Glass }
169