Commit 78f47b7353ebe1f243203dcc1ce0a2a374c08a40
Committed by
Tom Warren
1 parent
6b3a03e112
Exists in
master
and in
54 other branches
spi: add common fdt SPI driver interface
Add a common interface to fdt based SPI drivers. Each driver is represented by a table entry in fdt_spi_drivers[]. If there are multiple SPI drivers in the table, the first driver to return success from spi_init() will be registered as the SPI driver. Signed-off-by: Allen Martin <amartin@nvidia.com> Signed-off-by: Tom Warren <twarren@nvidia.com> Reviewed-by: Stephen Warren <swarren@nvidia.com>
Showing 8 changed files with 224 additions and 46 deletions Side-by-side Diff
arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
... | ... | @@ -27,5 +27,16 @@ |
27 | 27 | |
28 | 28 | #include <asm/types.h> |
29 | 29 | |
30 | +int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs); | |
31 | +struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs, | |
32 | + unsigned int max_hz, unsigned int mode); | |
33 | +void tegra20_spi_free_slave(struct spi_slave *slave); | |
34 | +int tegra20_spi_init(int *node_list, int count); | |
35 | +int tegra20_spi_claim_bus(struct spi_slave *slave); | |
36 | +void tegra20_spi_cs_activate(struct spi_slave *slave); | |
37 | +void tegra20_spi_cs_deactivate(struct spi_slave *slave); | |
38 | +int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
39 | + const void *data_out, void *data_in, unsigned long flags); | |
40 | + | |
30 | 41 | #endif /* _TEGRA20_SPI_H_ */ |
arch/arm/include/asm/arch-tegra20/tegra20_slink.h
... | ... | @@ -27,5 +27,16 @@ |
27 | 27 | |
28 | 28 | #include <asm/types.h> |
29 | 29 | |
30 | +int tegra30_spi_init(int *node_list, int count); | |
31 | +int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs); | |
32 | +struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs, | |
33 | + unsigned int max_hz, unsigned int mode); | |
34 | +void tegra30_spi_free_slave(struct spi_slave *slave); | |
35 | +int tegra30_spi_claim_bus(struct spi_slave *slave); | |
36 | +void tegra30_spi_cs_activate(struct spi_slave *slave); | |
37 | +void tegra30_spi_cs_deactivate(struct spi_slave *slave); | |
38 | +int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
39 | + const void *data_out, void *data_in, unsigned long flags); | |
40 | + | |
30 | 41 | #endif /* _TEGRA30_SPI_H_ */ |
board/nvidia/common/board.c
drivers/spi/Makefile
... | ... | @@ -46,6 +46,7 @@ |
46 | 46 | COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o |
47 | 47 | COBJS-$(CONFIG_SH_SPI) += sh_spi.o |
48 | 48 | COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o |
49 | +COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o | |
49 | 50 | COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o |
50 | 51 | COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o |
51 | 52 | COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o |
drivers/spi/fdt_spi.c
1 | +/* | |
2 | + * Common fdt based SPI driver front end | |
3 | + * | |
4 | + * Copyright (c) 2013 NVIDIA Corporation | |
5 | + * | |
6 | + * See file CREDITS for list of people who contributed to this | |
7 | + * project. | |
8 | + * | |
9 | + * This software is licensed under the terms of the GNU General Public | |
10 | + * License version 2, as published by the Free Software Foundation, and | |
11 | + * may be copied, distributed, and modified under those terms. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <malloc.h> | |
26 | +#include <asm/io.h> | |
27 | +#include <asm/gpio.h> | |
28 | +#include <asm/arch/clock.h> | |
29 | +#include <asm/arch-tegra/clk_rst.h> | |
30 | +#include <asm/arch-tegra20/tegra20_sflash.h> | |
31 | +#include <asm/arch-tegra20/tegra20_slink.h> | |
32 | +#include <spi.h> | |
33 | +#include <fdtdec.h> | |
34 | + | |
35 | +DECLARE_GLOBAL_DATA_PTR; | |
36 | + | |
37 | +struct fdt_spi_driver { | |
38 | + int compat; | |
39 | + int max_ctrls; | |
40 | + int (*init)(int *node_list, int count); | |
41 | + int (*claim_bus)(struct spi_slave *slave); | |
42 | + int (*release_bus)(struct spi_slave *slave); | |
43 | + int (*cs_is_valid)(unsigned int bus, unsigned int cs); | |
44 | + struct spi_slave *(*setup_slave)(unsigned int bus, unsigned int cs, | |
45 | + unsigned int max_hz, unsigned int mode); | |
46 | + void (*free_slave)(struct spi_slave *slave); | |
47 | + void (*cs_activate)(struct spi_slave *slave); | |
48 | + void (*cs_deactivate)(struct spi_slave *slave); | |
49 | + int (*xfer)(struct spi_slave *slave, unsigned int bitlen, | |
50 | + const void *data_out, void *data_in, unsigned long flags); | |
51 | +}; | |
52 | + | |
53 | +static struct fdt_spi_driver fdt_spi_drivers[] = { | |
54 | +#ifdef CONFIG_TEGRA20_SFLASH | |
55 | + { | |
56 | + .compat = COMPAT_NVIDIA_TEGRA20_SFLASH, | |
57 | + .max_ctrls = 1, | |
58 | + .init = tegra20_spi_init, | |
59 | + .claim_bus = tegra20_spi_claim_bus, | |
60 | + .cs_is_valid = tegra20_spi_cs_is_valid, | |
61 | + .setup_slave = tegra20_spi_setup_slave, | |
62 | + .free_slave = tegra20_spi_free_slave, | |
63 | + .cs_activate = tegra20_spi_cs_activate, | |
64 | + .cs_deactivate = tegra20_spi_cs_deactivate, | |
65 | + .xfer = tegra20_spi_xfer, | |
66 | + }, | |
67 | +#endif | |
68 | +#ifdef CONFIG_TEGRA20_SLINK | |
69 | + { | |
70 | + .compat = COMPAT_NVIDIA_TEGRA20_SLINK, | |
71 | + .max_ctrls = CONFIG_TEGRA_SLINK_CTRLS, | |
72 | + .init = tegra30_spi_init, | |
73 | + .claim_bus = tegra30_spi_claim_bus, | |
74 | + .cs_is_valid = tegra30_spi_cs_is_valid, | |
75 | + .setup_slave = tegra30_spi_setup_slave, | |
76 | + .free_slave = tegra30_spi_free_slave, | |
77 | + .cs_activate = tegra30_spi_cs_activate, | |
78 | + .cs_deactivate = tegra30_spi_cs_deactivate, | |
79 | + .xfer = tegra30_spi_xfer, | |
80 | + }, | |
81 | +#endif | |
82 | +}; | |
83 | + | |
84 | +static struct fdt_spi_driver *driver; | |
85 | + | |
86 | +int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
87 | +{ | |
88 | + if (!driver) | |
89 | + return 0; | |
90 | + else if (!driver->cs_is_valid) | |
91 | + return 1; | |
92 | + else | |
93 | + return driver->cs_is_valid(bus, cs); | |
94 | +} | |
95 | + | |
96 | +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
97 | + unsigned int max_hz, unsigned int mode) | |
98 | +{ | |
99 | + if (!driver || !driver->setup_slave) | |
100 | + return NULL; | |
101 | + | |
102 | + return driver->setup_slave(bus, cs, max_hz, mode); | |
103 | +} | |
104 | + | |
105 | +void spi_free_slave(struct spi_slave *slave) | |
106 | +{ | |
107 | + if (driver && driver->free_slave) | |
108 | + return driver->free_slave(slave); | |
109 | +} | |
110 | + | |
111 | +static int spi_init_driver(struct fdt_spi_driver *driver) | |
112 | +{ | |
113 | + int count; | |
114 | + int node_list[driver->max_ctrls]; | |
115 | + | |
116 | + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", | |
117 | + driver->compat, | |
118 | + node_list, | |
119 | + driver->max_ctrls); | |
120 | + return driver->init(node_list, count); | |
121 | +} | |
122 | + | |
123 | +void spi_init(void) | |
124 | +{ | |
125 | + int i; | |
126 | + | |
127 | + for (i = 0; i < ARRAY_SIZE(fdt_spi_drivers); i++) { | |
128 | + driver = &fdt_spi_drivers[i]; | |
129 | + if (!spi_init_driver(driver)) | |
130 | + break; | |
131 | + } | |
132 | + if (i == ARRAY_SIZE(fdt_spi_drivers)) | |
133 | + driver = NULL; | |
134 | +} | |
135 | + | |
136 | +int spi_claim_bus(struct spi_slave *slave) | |
137 | +{ | |
138 | + if (!driver) | |
139 | + return 1; | |
140 | + if (!driver->claim_bus) | |
141 | + return 0; | |
142 | + | |
143 | + return driver->claim_bus(slave); | |
144 | +} | |
145 | + | |
146 | +void spi_release_bus(struct spi_slave *slave) | |
147 | +{ | |
148 | + if (driver && driver->release_bus) | |
149 | + driver->release_bus(slave); | |
150 | +} | |
151 | + | |
152 | +void spi_cs_activate(struct spi_slave *slave) | |
153 | +{ | |
154 | + if (driver && driver->cs_activate) | |
155 | + driver->cs_activate(slave); | |
156 | +} | |
157 | + | |
158 | +void spi_cs_deactivate(struct spi_slave *slave) | |
159 | +{ | |
160 | + if (driver && driver->cs_deactivate) | |
161 | + driver->cs_deactivate(slave); | |
162 | +} | |
163 | + | |
164 | +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
165 | + const void *data_out, void *data_in, unsigned long flags) | |
166 | +{ | |
167 | + if (!driver || !driver->xfer) | |
168 | + return -1; | |
169 | + | |
170 | + return driver->xfer(slave, bitlen, data_out, data_in, flags); | |
171 | +} |
drivers/spi/tegra20_sflash.c
... | ... | @@ -101,7 +101,7 @@ |
101 | 101 | return container_of(slave, struct tegra_spi_slave, slave); |
102 | 102 | } |
103 | 103 | |
104 | -int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
104 | +int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
105 | 105 | { |
106 | 106 | /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */ |
107 | 107 | if (bus != 0 || cs != 0) |
... | ... | @@ -110,8 +110,8 @@ |
110 | 110 | return 1; |
111 | 111 | } |
112 | 112 | |
113 | -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
114 | - unsigned int max_hz, unsigned int mode) | |
113 | +struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs, | |
114 | + unsigned int max_hz, unsigned int mode) | |
115 | 115 | { |
116 | 116 | struct tegra_spi_slave *spi; |
117 | 117 | |
118 | 118 | |
119 | 119 | |
120 | 120 | |
... | ... | @@ -151,25 +151,20 @@ |
151 | 151 | return &spi->slave; |
152 | 152 | } |
153 | 153 | |
154 | -void spi_free_slave(struct spi_slave *slave) | |
154 | +void tegra20_spi_free_slave(struct spi_slave *slave) | |
155 | 155 | { |
156 | 156 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
157 | 157 | |
158 | 158 | free(spi); |
159 | 159 | } |
160 | 160 | |
161 | -void spi_init(void) | |
161 | +int tegra20_spi_init(int *node_list, int count) | |
162 | 162 | { |
163 | 163 | struct tegra_spi_ctrl *ctrl; |
164 | 164 | int i; |
165 | 165 | int node = 0; |
166 | - int count; | |
167 | - int node_list[1]; | |
166 | + int found = 0; | |
168 | 167 | |
169 | - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", | |
170 | - COMPAT_NVIDIA_TEGRA20_SFLASH, | |
171 | - node_list, | |
172 | - 1); | |
173 | 168 | for (i = 0; i < count; i++) { |
174 | 169 | ctrl = &spi_ctrls[i]; |
175 | 170 | node = node_list[i]; |
176 | 171 | |
177 | 172 | |
... | ... | @@ -193,13 +188,15 @@ |
193 | 188 | continue; |
194 | 189 | } |
195 | 190 | ctrl->valid = 1; |
191 | + found = 1; | |
196 | 192 | |
197 | 193 | debug("%s: found controller at %p, freq = %u, periph_id = %d\n", |
198 | 194 | __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); |
199 | 195 | } |
196 | + return !found; | |
200 | 197 | } |
201 | 198 | |
202 | -int spi_claim_bus(struct spi_slave *slave) | |
199 | +int tegra20_spi_claim_bus(struct spi_slave *slave) | |
203 | 200 | { |
204 | 201 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
205 | 202 | struct spi_regs *regs = spi->ctrl->regs; |
... | ... | @@ -213,7 +210,7 @@ |
213 | 210 | reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ |
214 | 211 | SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF; |
215 | 212 | writel(reg, ®s->status); |
216 | - debug("spi_init: STATUS = %08x\n", readl(®s->status)); | |
213 | + debug("%s: STATUS = %08x\n", __func__, readl(®s->status)); | |
217 | 214 | |
218 | 215 | /* |
219 | 216 | * Use sw-controlled CS, so we can clock in data after ReadID, etc. |
... | ... | @@ -223,7 +220,7 @@ |
223 | 220 | reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; |
224 | 221 | clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | |
225 | 222 | SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); |
226 | - debug("spi_init: COMMAND = %08x\n", readl(®s->command)); | |
223 | + debug("%s: COMMAND = %08x\n", __func__, readl(®s->command)); | |
227 | 224 | |
228 | 225 | /* |
229 | 226 | * SPI pins on Tegra20 are muxed - change pinmux later due to UART |
230 | 227 | |
... | ... | @@ -236,18 +233,8 @@ |
236 | 233 | return 0; |
237 | 234 | } |
238 | 235 | |
239 | -void spi_release_bus(struct spi_slave *slave) | |
236 | +void tegra20_spi_cs_activate(struct spi_slave *slave) | |
240 | 237 | { |
241 | - /* | |
242 | - * We can't release UART_DISABLE and set pinmux to UART4 here since | |
243 | - * some code (e,g, spi_flash_probe) uses printf() while the SPI | |
244 | - * bus is held. That is arguably bad, but it has the advantage of | |
245 | - * already being in the source tree. | |
246 | - */ | |
247 | -} | |
248 | - | |
249 | -void spi_cs_activate(struct spi_slave *slave) | |
250 | -{ | |
251 | 238 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
252 | 239 | struct spi_regs *regs = spi->ctrl->regs; |
253 | 240 | |
... | ... | @@ -255,7 +242,7 @@ |
255 | 242 | setbits_le32(®s->command, SPI_CMD_CS_VAL); |
256 | 243 | } |
257 | 244 | |
258 | -void spi_cs_deactivate(struct spi_slave *slave) | |
245 | +void tegra20_spi_cs_deactivate(struct spi_slave *slave) | |
259 | 246 | { |
260 | 247 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
261 | 248 | struct spi_regs *regs = spi->ctrl->regs; |
... | ... | @@ -264,7 +251,7 @@ |
264 | 251 | clrbits_le32(®s->command, SPI_CMD_CS_VAL); |
265 | 252 | } |
266 | 253 | |
267 | -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
254 | +int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
268 | 255 | const void *data_out, void *data_in, unsigned long flags) |
269 | 256 | { |
270 | 257 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
drivers/spi/tegra20_slink.c
... | ... | @@ -107,7 +107,7 @@ |
107 | 107 | return container_of(slave, struct tegra_spi_slave, slave); |
108 | 108 | } |
109 | 109 | |
110 | -int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
110 | +int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
111 | 111 | { |
112 | 112 | if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid) |
113 | 113 | return 0; |
... | ... | @@ -115,7 +115,7 @@ |
115 | 115 | return 1; |
116 | 116 | } |
117 | 117 | |
118 | -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
118 | +struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs, | |
119 | 119 | unsigned int max_hz, unsigned int mode) |
120 | 120 | { |
121 | 121 | struct tegra_spi_slave *spi; |
122 | 122 | |
123 | 123 | |
124 | 124 | |
... | ... | @@ -159,25 +159,20 @@ |
159 | 159 | return &spi->slave; |
160 | 160 | } |
161 | 161 | |
162 | -void spi_free_slave(struct spi_slave *slave) | |
162 | +void tegra30_spi_free_slave(struct spi_slave *slave) | |
163 | 163 | { |
164 | 164 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
165 | 165 | |
166 | 166 | free(spi); |
167 | 167 | } |
168 | 168 | |
169 | -void spi_init(void) | |
169 | +int tegra30_spi_init(int *node_list, int count) | |
170 | 170 | { |
171 | 171 | struct tegra_spi_ctrl *ctrl; |
172 | 172 | int i; |
173 | 173 | int node = 0; |
174 | - int count; | |
175 | - int node_list[CONFIG_TEGRA_SLINK_CTRLS]; | |
174 | + int found = 0; | |
176 | 175 | |
177 | - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", | |
178 | - COMPAT_NVIDIA_TEGRA20_SLINK, | |
179 | - node_list, | |
180 | - CONFIG_TEGRA_SLINK_CTRLS); | |
181 | 176 | for (i = 0; i < count; i++) { |
182 | 177 | ctrl = &spi_ctrls[i]; |
183 | 178 | node = node_list[i]; |
184 | 179 | |
185 | 180 | |
... | ... | @@ -201,13 +196,15 @@ |
201 | 196 | continue; |
202 | 197 | } |
203 | 198 | ctrl->valid = 1; |
199 | + found = 1; | |
204 | 200 | |
205 | 201 | debug("%s: found controller at %p, freq = %u, periph_id = %d\n", |
206 | 202 | __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); |
207 | 203 | } |
204 | + return !found; | |
208 | 205 | } |
209 | 206 | |
210 | -int spi_claim_bus(struct spi_slave *slave) | |
207 | +int tegra30_spi_claim_bus(struct spi_slave *slave) | |
211 | 208 | { |
212 | 209 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
213 | 210 | struct spi_regs *regs = spi->ctrl->regs; |
214 | 211 | |
... | ... | @@ -232,12 +229,8 @@ |
232 | 229 | return 0; |
233 | 230 | } |
234 | 231 | |
235 | -void spi_release_bus(struct spi_slave *slave) | |
232 | +void tegra30_spi_cs_activate(struct spi_slave *slave) | |
236 | 233 | { |
237 | -} | |
238 | - | |
239 | -void spi_cs_activate(struct spi_slave *slave) | |
240 | -{ | |
241 | 234 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
242 | 235 | struct spi_regs *regs = spi->ctrl->regs; |
243 | 236 | |
... | ... | @@ -245,7 +238,7 @@ |
245 | 238 | setbits_le32(®s->command, SLINK_CMD_CS_VAL); |
246 | 239 | } |
247 | 240 | |
248 | -void spi_cs_deactivate(struct spi_slave *slave) | |
241 | +void tegra30_spi_cs_deactivate(struct spi_slave *slave) | |
249 | 242 | { |
250 | 243 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
251 | 244 | struct spi_regs *regs = spi->ctrl->regs; |
... | ... | @@ -254,7 +247,7 @@ |
254 | 247 | clrbits_le32(®s->command, SLINK_CMD_CS_VAL); |
255 | 248 | } |
256 | 249 | |
257 | -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
250 | +int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
258 | 251 | const void *data_out, void *data_in, unsigned long flags) |
259 | 252 | { |
260 | 253 | struct tegra_spi_slave *spi = to_tegra_spi(slave); |
include/configs/tegra-common-post.h