xref: /rk3399_rockchip-uboot/drivers/spi/altera_spi.c (revision e7b1e452ff7e1d06a6ceebd441fca4597cdf1c84)
1661ba140SThomas Chou /*
2661ba140SThomas Chou  * Altera SPI driver
3661ba140SThomas Chou  *
4661ba140SThomas Chou  * based on bfin_spi.c
5661ba140SThomas Chou  * Copyright (c) 2005-2008 Analog Devices Inc.
6661ba140SThomas Chou  * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
7661ba140SThomas Chou  *
8*e7b1e452SJagannadha Sutradharudu Teki  * SPDX-License-Identifier:	GPL-2.0+
9661ba140SThomas Chou  */
10661ba140SThomas Chou #include <common.h>
11661ba140SThomas Chou #include <asm/io.h>
12661ba140SThomas Chou #include <malloc.h>
13661ba140SThomas Chou #include <spi.h>
14661ba140SThomas Chou 
15661ba140SThomas Chou #define ALTERA_SPI_RXDATA	0
16661ba140SThomas Chou #define ALTERA_SPI_TXDATA	4
17661ba140SThomas Chou #define ALTERA_SPI_STATUS	8
18661ba140SThomas Chou #define ALTERA_SPI_CONTROL	12
19661ba140SThomas Chou #define ALTERA_SPI_SLAVE_SEL	20
20661ba140SThomas Chou 
21661ba140SThomas Chou #define ALTERA_SPI_STATUS_ROE_MSK	(0x8)
22661ba140SThomas Chou #define ALTERA_SPI_STATUS_TOE_MSK	(0x10)
23661ba140SThomas Chou #define ALTERA_SPI_STATUS_TMT_MSK	(0x20)
24661ba140SThomas Chou #define ALTERA_SPI_STATUS_TRDY_MSK	(0x40)
25661ba140SThomas Chou #define ALTERA_SPI_STATUS_RRDY_MSK	(0x80)
26661ba140SThomas Chou #define ALTERA_SPI_STATUS_E_MSK	(0x100)
27661ba140SThomas Chou 
28661ba140SThomas Chou #define ALTERA_SPI_CONTROL_IROE_MSK	(0x8)
29661ba140SThomas Chou #define ALTERA_SPI_CONTROL_ITOE_MSK	(0x10)
30661ba140SThomas Chou #define ALTERA_SPI_CONTROL_ITRDY_MSK	(0x40)
31661ba140SThomas Chou #define ALTERA_SPI_CONTROL_IRRDY_MSK	(0x80)
32661ba140SThomas Chou #define ALTERA_SPI_CONTROL_IE_MSK	(0x100)
33661ba140SThomas Chou #define ALTERA_SPI_CONTROL_SSO_MSK	(0x400)
34661ba140SThomas Chou 
35661ba140SThomas Chou #ifndef CONFIG_SYS_ALTERA_SPI_LIST
36661ba140SThomas Chou #define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE }
37661ba140SThomas Chou #endif
38661ba140SThomas Chou 
39661ba140SThomas Chou static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST;
40661ba140SThomas Chou 
41661ba140SThomas Chou struct altera_spi_slave {
42661ba140SThomas Chou 	struct spi_slave slave;
43661ba140SThomas Chou 	ulong base;
44661ba140SThomas Chou };
45661ba140SThomas Chou #define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave)
46661ba140SThomas Chou 
47661ba140SThomas Chou __attribute__((weak))
48661ba140SThomas Chou int spi_cs_is_valid(unsigned int bus, unsigned int cs)
49661ba140SThomas Chou {
50661ba140SThomas Chou 	return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32;
51661ba140SThomas Chou }
52661ba140SThomas Chou 
53661ba140SThomas Chou __attribute__((weak))
54661ba140SThomas Chou void spi_cs_activate(struct spi_slave *slave)
55661ba140SThomas Chou {
56661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
57661ba140SThomas Chou 	writel(1 << slave->cs, altspi->base + ALTERA_SPI_SLAVE_SEL);
58661ba140SThomas Chou 	writel(ALTERA_SPI_CONTROL_SSO_MSK, altspi->base + ALTERA_SPI_CONTROL);
59661ba140SThomas Chou }
60661ba140SThomas Chou 
61661ba140SThomas Chou __attribute__((weak))
62661ba140SThomas Chou void spi_cs_deactivate(struct spi_slave *slave)
63661ba140SThomas Chou {
64661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
65661ba140SThomas Chou 	writel(0, altspi->base + ALTERA_SPI_CONTROL);
66661ba140SThomas Chou 	writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
67661ba140SThomas Chou }
68661ba140SThomas Chou 
69661ba140SThomas Chou void spi_init(void)
70661ba140SThomas Chou {
71661ba140SThomas Chou }
72661ba140SThomas Chou 
73df8f1252SThomas Chou void spi_set_speed(struct spi_slave *slave, uint hz)
74df8f1252SThomas Chou {
75df8f1252SThomas Chou 	/* altera spi core does not support programmable speed */
76df8f1252SThomas Chou }
77df8f1252SThomas Chou 
78661ba140SThomas Chou struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
79661ba140SThomas Chou 				  unsigned int max_hz, unsigned int mode)
80661ba140SThomas Chou {
81661ba140SThomas Chou 	struct altera_spi_slave *altspi;
82661ba140SThomas Chou 
83661ba140SThomas Chou 	if (!spi_cs_is_valid(bus, cs))
84661ba140SThomas Chou 		return NULL;
85661ba140SThomas Chou 
86d3504feeSSimon Glass 	altspi = spi_alloc_slave(struct altera_spi_slave, bus, cs);
87661ba140SThomas Chou 	if (!altspi)
88661ba140SThomas Chou 		return NULL;
89661ba140SThomas Chou 
90661ba140SThomas Chou 	altspi->base = altera_spi_base_list[bus];
91661ba140SThomas Chou 	debug("%s: bus:%i cs:%i base:%lx\n", __func__,
92661ba140SThomas Chou 		bus, cs, altspi->base);
93661ba140SThomas Chou 
94661ba140SThomas Chou 	return &altspi->slave;
95661ba140SThomas Chou }
96661ba140SThomas Chou 
97661ba140SThomas Chou void spi_free_slave(struct spi_slave *slave)
98661ba140SThomas Chou {
99661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
100661ba140SThomas Chou 	free(altspi);
101661ba140SThomas Chou }
102661ba140SThomas Chou 
103661ba140SThomas Chou int spi_claim_bus(struct spi_slave *slave)
104661ba140SThomas Chou {
105661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
106661ba140SThomas Chou 
107661ba140SThomas Chou 	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
108661ba140SThomas Chou 	writel(0, altspi->base + ALTERA_SPI_CONTROL);
109661ba140SThomas Chou 	writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
110661ba140SThomas Chou 	return 0;
111661ba140SThomas Chou }
112661ba140SThomas Chou 
113661ba140SThomas Chou void spi_release_bus(struct spi_slave *slave)
114661ba140SThomas Chou {
115661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
116661ba140SThomas Chou 
117661ba140SThomas Chou 	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
118661ba140SThomas Chou 	writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
119661ba140SThomas Chou }
120661ba140SThomas Chou 
121661ba140SThomas Chou #ifndef CONFIG_ALTERA_SPI_IDLE_VAL
122661ba140SThomas Chou # define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
123661ba140SThomas Chou #endif
124661ba140SThomas Chou 
125661ba140SThomas Chou int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
126661ba140SThomas Chou 	     void *din, unsigned long flags)
127661ba140SThomas Chou {
128661ba140SThomas Chou 	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
129661ba140SThomas Chou 	/* assume spi core configured to do 8 bit transfers */
130661ba140SThomas Chou 	uint bytes = bitlen / 8;
131661ba140SThomas Chou 	const uchar *txp = dout;
132661ba140SThomas Chou 	uchar *rxp = din;
133661ba140SThomas Chou 
134661ba140SThomas Chou 	debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
135661ba140SThomas Chou 		slave->bus, slave->cs, bitlen, bytes, flags);
136661ba140SThomas Chou 	if (bitlen == 0)
137661ba140SThomas Chou 		goto done;
138661ba140SThomas Chou 
139661ba140SThomas Chou 	if (bitlen % 8) {
140661ba140SThomas Chou 		flags |= SPI_XFER_END;
141661ba140SThomas Chou 		goto done;
142661ba140SThomas Chou 	}
143661ba140SThomas Chou 
144661ba140SThomas Chou 	/* empty read buffer */
145661ba140SThomas Chou 	if (readl(altspi->base + ALTERA_SPI_STATUS) &
146661ba140SThomas Chou 	    ALTERA_SPI_STATUS_RRDY_MSK)
147661ba140SThomas Chou 		readl(altspi->base + ALTERA_SPI_RXDATA);
148661ba140SThomas Chou 	if (flags & SPI_XFER_BEGIN)
149661ba140SThomas Chou 		spi_cs_activate(slave);
150661ba140SThomas Chou 
151661ba140SThomas Chou 	while (bytes--) {
152661ba140SThomas Chou 		uchar d = txp ? *txp++ : CONFIG_ALTERA_SPI_IDLE_VAL;
153661ba140SThomas Chou 		debug("%s: tx:%x ", __func__, d);
154661ba140SThomas Chou 		writel(d, altspi->base + ALTERA_SPI_TXDATA);
155661ba140SThomas Chou 		while (!(readl(altspi->base + ALTERA_SPI_STATUS) &
156661ba140SThomas Chou 			 ALTERA_SPI_STATUS_RRDY_MSK))
157661ba140SThomas Chou 			;
158661ba140SThomas Chou 		d = readl(altspi->base + ALTERA_SPI_RXDATA);
159661ba140SThomas Chou 		if (rxp)
160661ba140SThomas Chou 			*rxp++ = d;
161661ba140SThomas Chou 		debug("rx:%x\n", d);
162661ba140SThomas Chou 	}
163661ba140SThomas Chou  done:
164661ba140SThomas Chou 	if (flags & SPI_XFER_END)
165661ba140SThomas Chou 		spi_cs_deactivate(slave);
166661ba140SThomas Chou 
167661ba140SThomas Chou 	return 0;
168661ba140SThomas Chou }
169