xref: /openbmc/u-boot/drivers/spi/ath79_spi.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2b85dc460SWills Wang /*
3b85dc460SWills Wang  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
4b85dc460SWills Wang  */
5b85dc460SWills Wang 
6b85dc460SWills Wang #include <common.h>
7b85dc460SWills Wang #include <spi.h>
8b85dc460SWills Wang #include <dm.h>
9b85dc460SWills Wang #include <div64.h>
10b85dc460SWills Wang #include <errno.h>
11b85dc460SWills Wang #include <asm/io.h>
12b85dc460SWills Wang #include <asm/addrspace.h>
13b85dc460SWills Wang #include <asm/types.h>
14b85dc460SWills Wang #include <dm/pinctrl.h>
15b85dc460SWills Wang #include <mach/ar71xx_regs.h>
16b85dc460SWills Wang 
17b85dc460SWills Wang /* CLOCK_DIVIDER = 3 (SPI clock = 200 / 8 ~ 25 MHz) */
18b85dc460SWills Wang #define ATH79_SPI_CLK_DIV(x)           (((x) >> 1) - 1)
19b85dc460SWills Wang #define ATH79_SPI_RRW_DELAY_FACTOR     12000
20b85dc460SWills Wang #define ATH79_SPI_MHZ                  (1000 * 1000)
21b85dc460SWills Wang 
22b85dc460SWills Wang struct ath79_spi_priv {
23b85dc460SWills Wang 	void __iomem *regs;
24b85dc460SWills Wang 	u32 rrw_delay;
25b85dc460SWills Wang };
26b85dc460SWills Wang 
spi_cs_activate(struct udevice * dev)27b85dc460SWills Wang static void spi_cs_activate(struct udevice *dev)
28b85dc460SWills Wang {
29b85dc460SWills Wang 	struct udevice *bus = dev_get_parent(dev);
30b85dc460SWills Wang 	struct ath79_spi_priv *priv = dev_get_priv(bus);
31b85dc460SWills Wang 
32b85dc460SWills Wang 	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
33b85dc460SWills Wang 	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
34b85dc460SWills Wang }
35b85dc460SWills Wang 
spi_cs_deactivate(struct udevice * dev)36b85dc460SWills Wang static void spi_cs_deactivate(struct udevice *dev)
37b85dc460SWills Wang {
38b85dc460SWills Wang 	struct udevice *bus = dev_get_parent(dev);
39b85dc460SWills Wang 	struct ath79_spi_priv *priv = dev_get_priv(bus);
40b85dc460SWills Wang 
41b85dc460SWills Wang 	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
42b85dc460SWills Wang 	writel(0, priv->regs + AR71XX_SPI_REG_FS);
43b85dc460SWills Wang }
44b85dc460SWills Wang 
ath79_spi_claim_bus(struct udevice * dev)45b85dc460SWills Wang static int ath79_spi_claim_bus(struct udevice *dev)
46b85dc460SWills Wang {
47b85dc460SWills Wang 	return 0;
48b85dc460SWills Wang }
49b85dc460SWills Wang 
ath79_spi_release_bus(struct udevice * dev)50b85dc460SWills Wang static int ath79_spi_release_bus(struct udevice *dev)
51b85dc460SWills Wang {
52b85dc460SWills Wang 	return 0;
53b85dc460SWills Wang }
54b85dc460SWills Wang 
ath79_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)55b85dc460SWills Wang static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen,
56b85dc460SWills Wang 		const void *dout, void *din, unsigned long flags)
57b85dc460SWills Wang {
58b85dc460SWills Wang 	struct udevice *bus = dev_get_parent(dev);
59b85dc460SWills Wang 	struct ath79_spi_priv *priv = dev_get_priv(bus);
60b85dc460SWills Wang 	struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
61b85dc460SWills Wang 	u8 *rx = din;
62b85dc460SWills Wang 	const u8 *tx = dout;
63b85dc460SWills Wang 	u8 curbyte, curbitlen, restbits;
64b85dc460SWills Wang 	u32 bytes = bitlen / 8;
65b85dc460SWills Wang 	u32 out, in;
66b85dc460SWills Wang 	u64 tick;
67b85dc460SWills Wang 
68b85dc460SWills Wang 	if (flags & SPI_XFER_BEGIN)
69b85dc460SWills Wang 		spi_cs_activate(dev);
70b85dc460SWills Wang 
71b85dc460SWills Wang 	restbits = (bitlen % 8);
72b85dc460SWills Wang 	if (restbits)
73b85dc460SWills Wang 		bytes++;
74b85dc460SWills Wang 
75b85dc460SWills Wang 	out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs));
76b85dc460SWills Wang 	while (bytes > 0) {
77b85dc460SWills Wang 		bytes--;
78b85dc460SWills Wang 		curbyte = 0;
79b85dc460SWills Wang 		if (tx)
80b85dc460SWills Wang 			curbyte = *tx++;
81b85dc460SWills Wang 
82b85dc460SWills Wang 		if (restbits && !bytes) {
83b85dc460SWills Wang 			curbitlen = restbits;
84b85dc460SWills Wang 			curbyte <<= 8 - restbits;
85b85dc460SWills Wang 		} else {
86b85dc460SWills Wang 			curbitlen = 8;
87b85dc460SWills Wang 		}
88b85dc460SWills Wang 
89b85dc460SWills Wang 		for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) {
90b85dc460SWills Wang 			if (curbyte & 0x80)
91b85dc460SWills Wang 				out |= AR71XX_SPI_IOC_DO;
92b85dc460SWills Wang 			else
93b85dc460SWills Wang 				out &= ~(AR71XX_SPI_IOC_DO);
94b85dc460SWills Wang 
95b85dc460SWills Wang 			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
96b85dc460SWills Wang 
97b85dc460SWills Wang 			/* delay for low level */
98b85dc460SWills Wang 			if (priv->rrw_delay) {
99b85dc460SWills Wang 				tick = get_ticks() + priv->rrw_delay;
100b85dc460SWills Wang 				while (get_ticks() < tick)
101b85dc460SWills Wang 					/*NOP*/;
102b85dc460SWills Wang 			}
103b85dc460SWills Wang 
104b85dc460SWills Wang 			writel(out | AR71XX_SPI_IOC_CLK,
105b85dc460SWills Wang 			       priv->regs + AR71XX_SPI_REG_IOC);
106b85dc460SWills Wang 
107b85dc460SWills Wang 			/* delay for high level */
108b85dc460SWills Wang 			if (priv->rrw_delay) {
109b85dc460SWills Wang 				tick = get_ticks() + priv->rrw_delay;
110b85dc460SWills Wang 				while (get_ticks() < tick)
111b85dc460SWills Wang 					/*NOP*/;
112b85dc460SWills Wang 			}
113b85dc460SWills Wang 
114b85dc460SWills Wang 			curbyte <<= 1;
115b85dc460SWills Wang 		}
116b85dc460SWills Wang 
117b85dc460SWills Wang 		if (!bytes)
118b85dc460SWills Wang 			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
119b85dc460SWills Wang 
120b85dc460SWills Wang 		in = readl(priv->regs + AR71XX_SPI_REG_RDS);
121b85dc460SWills Wang 		if (rx) {
122b85dc460SWills Wang 			if (restbits && !bytes)
123b85dc460SWills Wang 				*rx++ = (in << (8 - restbits));
124b85dc460SWills Wang 			else
125b85dc460SWills Wang 				*rx++ = in;
126b85dc460SWills Wang 		}
127b85dc460SWills Wang 	}
128b85dc460SWills Wang 
129b85dc460SWills Wang 	if (flags & SPI_XFER_END)
130b85dc460SWills Wang 		spi_cs_deactivate(dev);
131b85dc460SWills Wang 
132b85dc460SWills Wang 	return 0;
133b85dc460SWills Wang }
134b85dc460SWills Wang 
135b85dc460SWills Wang 
ath79_spi_set_speed(struct udevice * bus,uint speed)136b85dc460SWills Wang static int ath79_spi_set_speed(struct udevice *bus, uint speed)
137b85dc460SWills Wang {
138b85dc460SWills Wang 	struct ath79_spi_priv *priv = dev_get_priv(bus);
139b85dc460SWills Wang 	u32 val, div = 0;
140b85dc460SWills Wang 	u64 time;
141b85dc460SWills Wang 
142b85dc460SWills Wang 	if (speed)
143b85dc460SWills Wang 		div = get_bus_freq(0) / speed;
144b85dc460SWills Wang 
145b85dc460SWills Wang 	if (div > 63)
146b85dc460SWills Wang 		div = 63;
147b85dc460SWills Wang 
148b85dc460SWills Wang 	if (div < 5)
149b85dc460SWills Wang 		div = 5;
150b85dc460SWills Wang 
151b85dc460SWills Wang 	/* calculate delay */
152b85dc460SWills Wang 	time = get_tbclk();
153b85dc460SWills Wang 	do_div(time, speed / 2);
154b85dc460SWills Wang 	val = get_bus_freq(0) / ATH79_SPI_MHZ;
155b85dc460SWills Wang 	val = ATH79_SPI_RRW_DELAY_FACTOR / val;
156b85dc460SWills Wang 	if (time > val)
157b85dc460SWills Wang 		priv->rrw_delay = time - val + 1;
158b85dc460SWills Wang 	else
159b85dc460SWills Wang 		priv->rrw_delay = 0;
160b85dc460SWills Wang 
161b85dc460SWills Wang 	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
162b85dc460SWills Wang 	clrsetbits_be32(priv->regs + AR71XX_SPI_REG_CTRL,
163b85dc460SWills Wang 			AR71XX_SPI_CTRL_DIV_MASK,
164b85dc460SWills Wang 			ATH79_SPI_CLK_DIV(div));
165b85dc460SWills Wang 	writel(0, priv->regs + AR71XX_SPI_REG_FS);
166b85dc460SWills Wang 	return 0;
167b85dc460SWills Wang }
168b85dc460SWills Wang 
ath79_spi_set_mode(struct udevice * bus,uint mode)169b85dc460SWills Wang static int ath79_spi_set_mode(struct udevice *bus, uint mode)
170b85dc460SWills Wang {
171b85dc460SWills Wang 	return 0;
172b85dc460SWills Wang }
173b85dc460SWills Wang 
ath79_spi_probe(struct udevice * bus)174b85dc460SWills Wang static int ath79_spi_probe(struct udevice *bus)
175b85dc460SWills Wang {
176b85dc460SWills Wang 	struct ath79_spi_priv *priv = dev_get_priv(bus);
177b85dc460SWills Wang 	fdt_addr_t addr;
178b85dc460SWills Wang 
179a821c4afSSimon Glass 	addr = devfdt_get_addr(bus);
180b85dc460SWills Wang 	if (addr == FDT_ADDR_T_NONE)
181b85dc460SWills Wang 		return -EINVAL;
182b85dc460SWills Wang 
183b85dc460SWills Wang 	priv->regs = map_physmem(addr,
184b85dc460SWills Wang 				 AR71XX_SPI_SIZE,
185b85dc460SWills Wang 				 MAP_NOCACHE);
186b85dc460SWills Wang 
187b85dc460SWills Wang 	/* Init SPI Hardware, disable remap, set clock */
188b85dc460SWills Wang 	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
189b85dc460SWills Wang 	writel(AR71XX_SPI_CTRL_RD | ATH79_SPI_CLK_DIV(8),
190b85dc460SWills Wang 	       priv->regs + AR71XX_SPI_REG_CTRL);
191b85dc460SWills Wang 	writel(0, priv->regs + AR71XX_SPI_REG_FS);
192b85dc460SWills Wang 
193b85dc460SWills Wang 	return 0;
194b85dc460SWills Wang }
195b85dc460SWills Wang 
ath79_cs_info(struct udevice * bus,uint cs,struct spi_cs_info * info)196b85dc460SWills Wang static int ath79_cs_info(struct udevice *bus, uint cs,
197b85dc460SWills Wang 			   struct spi_cs_info *info)
198b85dc460SWills Wang {
199b85dc460SWills Wang 	/* Always allow activity on CS 0/1/2 */
200b85dc460SWills Wang 	if (cs >= 3)
201b85dc460SWills Wang 		return -ENODEV;
202b85dc460SWills Wang 
203b85dc460SWills Wang 	return 0;
204b85dc460SWills Wang }
205b85dc460SWills Wang 
206b85dc460SWills Wang static const struct dm_spi_ops ath79_spi_ops = {
207b85dc460SWills Wang 	.claim_bus  = ath79_spi_claim_bus,
208b85dc460SWills Wang 	.release_bus    = ath79_spi_release_bus,
209b85dc460SWills Wang 	.xfer       = ath79_spi_xfer,
210b85dc460SWills Wang 	.set_speed  = ath79_spi_set_speed,
211b85dc460SWills Wang 	.set_mode   = ath79_spi_set_mode,
212b85dc460SWills Wang 	.cs_info    = ath79_cs_info,
213b85dc460SWills Wang };
214b85dc460SWills Wang 
215b85dc460SWills Wang static const struct udevice_id ath79_spi_ids[] = {
216b85dc460SWills Wang 	{ .compatible = "qca,ar7100-spi" },
217b85dc460SWills Wang 	{}
218b85dc460SWills Wang };
219b85dc460SWills Wang 
220b85dc460SWills Wang U_BOOT_DRIVER(ath79_spi) = {
221b85dc460SWills Wang 	.name   = "ath79_spi",
222b85dc460SWills Wang 	.id = UCLASS_SPI,
223b85dc460SWills Wang 	.of_match = ath79_spi_ids,
224b85dc460SWills Wang 	.ops    = &ath79_spi_ops,
225b85dc460SWills Wang 	.priv_auto_alloc_size = sizeof(struct ath79_spi_priv),
226b85dc460SWills Wang 	.probe  = ath79_spi_probe,
227b85dc460SWills Wang };
228