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