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