xref: /rk3399_rockchip-uboot/drivers/spi/tegra20_sflash.c (revision 9694b724421b88acf7d553a55e4a43fa4e25e7be)
1ff1da6fbSAllen Martin /*
26b3a03e1SAllen Martin  * Copyright (c) 2010-2013 NVIDIA Corporation
3ff1da6fbSAllen Martin  * With help from the mpc8xxx SPI driver
4ff1da6fbSAllen Martin  * With more help from omap3_spi SPI driver
5ff1da6fbSAllen Martin  *
61a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
7ff1da6fbSAllen Martin  */
8ff1da6fbSAllen Martin 
9ff1da6fbSAllen Martin #include <common.h>
10fda6fac3SSimon Glass #include <dm.h>
11fda6fac3SSimon Glass #include <errno.h>
12ff1da6fbSAllen Martin #include <asm/io.h>
13ff1da6fbSAllen Martin #include <asm/gpio.h>
14ff1da6fbSAllen Martin #include <asm/arch/clock.h>
15ff1da6fbSAllen Martin #include <asm/arch/pinmux.h>
16ff1da6fbSAllen Martin #include <asm/arch-tegra/clk_rst.h>
17ff1da6fbSAllen Martin #include <spi.h>
18ff1da6fbSAllen Martin #include <fdtdec.h>
19fda6fac3SSimon Glass #include "tegra_spi.h"
20ff1da6fbSAllen Martin 
21ff1da6fbSAllen Martin DECLARE_GLOBAL_DATA_PTR;
22ff1da6fbSAllen Martin 
237a49ba6eSAllen Martin #define SPI_CMD_GO			(1 << 30)
247a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_SHIFT	26
257a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_MASK	(3 << SPI_CMD_ACTIVE_SCLK_SHIFT)
267a49ba6eSAllen Martin #define SPI_CMD_CK_SDA			(1 << 21)
277a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_SHIFT	18
287a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_MASK		(3 << SPI_CMD_ACTIVE_SDA_SHIFT)
297a49ba6eSAllen Martin #define SPI_CMD_CS_POL			(1 << 16)
307a49ba6eSAllen Martin #define SPI_CMD_TXEN			(1 << 15)
317a49ba6eSAllen Martin #define SPI_CMD_RXEN			(1 << 14)
327a49ba6eSAllen Martin #define SPI_CMD_CS_VAL			(1 << 13)
337a49ba6eSAllen Martin #define SPI_CMD_CS_SOFT			(1 << 12)
347a49ba6eSAllen Martin #define SPI_CMD_CS_DELAY		(1 << 9)
357a49ba6eSAllen Martin #define SPI_CMD_CS3_EN			(1 << 8)
367a49ba6eSAllen Martin #define SPI_CMD_CS2_EN			(1 << 7)
377a49ba6eSAllen Martin #define SPI_CMD_CS1_EN			(1 << 6)
387a49ba6eSAllen Martin #define SPI_CMD_CS0_EN			(1 << 5)
397a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH		(1 << 4)
407a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH_MASK		0x0000001F
417a49ba6eSAllen Martin 
427a49ba6eSAllen Martin #define SPI_STAT_BSY			(1 << 31)
437a49ba6eSAllen Martin #define SPI_STAT_RDY			(1 << 30)
447a49ba6eSAllen Martin #define SPI_STAT_RXF_FLUSH		(1 << 29)
457a49ba6eSAllen Martin #define SPI_STAT_TXF_FLUSH		(1 << 28)
467a49ba6eSAllen Martin #define SPI_STAT_RXF_UNR		(1 << 27)
477a49ba6eSAllen Martin #define SPI_STAT_TXF_OVF		(1 << 26)
487a49ba6eSAllen Martin #define SPI_STAT_RXF_EMPTY		(1 << 25)
497a49ba6eSAllen Martin #define SPI_STAT_RXF_FULL		(1 << 24)
507a49ba6eSAllen Martin #define SPI_STAT_TXF_EMPTY		(1 << 23)
517a49ba6eSAllen Martin #define SPI_STAT_TXF_FULL		(1 << 22)
527a49ba6eSAllen Martin #define SPI_STAT_SEL_TXRX_N		(1 << 16)
537a49ba6eSAllen Martin #define SPI_STAT_CUR_BLKCNT		(1 << 15)
547a49ba6eSAllen Martin 
557a49ba6eSAllen Martin #define SPI_TIMEOUT		1000
567a49ba6eSAllen Martin #define TEGRA_SPI_MAX_FREQ	52000000
577a49ba6eSAllen Martin 
587a49ba6eSAllen Martin struct spi_regs {
597a49ba6eSAllen Martin 	u32 command;	/* SPI_COMMAND_0 register  */
607a49ba6eSAllen Martin 	u32 status;	/* SPI_STATUS_0 register */
617a49ba6eSAllen Martin 	u32 rx_cmp;	/* SPI_RX_CMP_0 register  */
627a49ba6eSAllen Martin 	u32 dma_ctl;	/* SPI_DMA_CTL_0 register */
637a49ba6eSAllen Martin 	u32 tx_fifo;	/* SPI_TX_FIFO_0 register */
647a49ba6eSAllen Martin 	u32 rsvd[3];	/* offsets 0x14 to 0x1F reserved */
657a49ba6eSAllen Martin 	u32 rx_fifo;	/* SPI_RX_FIFO_0 register */
667a49ba6eSAllen Martin };
677a49ba6eSAllen Martin 
68fda6fac3SSimon Glass struct tegra20_sflash_priv {
697a49ba6eSAllen Martin 	struct spi_regs *regs;
70ff1da6fbSAllen Martin 	unsigned int freq;
71ff1da6fbSAllen Martin 	unsigned int mode;
72ff1da6fbSAllen Martin 	int periph_id;
736b3a03e1SAllen Martin 	int valid;
74fda6fac3SSimon Glass 	int last_transaction_us;
75ff1da6fbSAllen Martin };
76ff1da6fbSAllen Martin 
77fda6fac3SSimon Glass int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
78fda6fac3SSimon Glass 			   struct spi_cs_info *info)
79ff1da6fbSAllen Martin {
80ff1da6fbSAllen Martin 	/* Tegra20 SPI-Flash - only 1 device ('bus/cs') */
81fda6fac3SSimon Glass 	if (cs != 0)
82fda6fac3SSimon Glass 		return -ENODEV;
83ff1da6fbSAllen Martin 	else
84fda6fac3SSimon Glass 		return 0;
85ff1da6fbSAllen Martin }
86ff1da6fbSAllen Martin 
87fda6fac3SSimon Glass static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus)
88ff1da6fbSAllen Martin {
89fda6fac3SSimon Glass 	struct tegra_spi_platdata *plat = bus->platdata;
90fda6fac3SSimon Glass 	const void *blob = gd->fdt_blob;
91fda6fac3SSimon Glass 	int node = bus->of_offset;
92ff1da6fbSAllen Martin 
93fda6fac3SSimon Glass 	plat->base = fdtdec_get_addr(blob, node, "reg");
94fda6fac3SSimon Glass 	plat->periph_id = clock_decode_periph_id(blob, node);
95fda6fac3SSimon Glass 
96fda6fac3SSimon Glass 	if (plat->periph_id == PERIPH_ID_NONE) {
97fda6fac3SSimon Glass 		debug("%s: could not decode periph id %d\n", __func__,
98fda6fac3SSimon Glass 		      plat->periph_id);
99fda6fac3SSimon Glass 		return -FDT_ERR_NOTFOUND;
100ff1da6fbSAllen Martin 	}
101ff1da6fbSAllen Martin 
102fda6fac3SSimon Glass 	/* Use 500KHz as a suitable default */
103fda6fac3SSimon Glass 	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
104fda6fac3SSimon Glass 					500000);
105fda6fac3SSimon Glass 	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
106fda6fac3SSimon Glass 					"spi-deactivate-delay", 0);
107fda6fac3SSimon Glass 	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
108fda6fac3SSimon Glass 	      __func__, plat->base, plat->periph_id, plat->frequency,
109fda6fac3SSimon Glass 	      plat->deactivate_delay_us);
110fda6fac3SSimon Glass 
111fda6fac3SSimon Glass 	return 0;
112ff1da6fbSAllen Martin }
113ff1da6fbSAllen Martin 
114fda6fac3SSimon Glass static int tegra20_sflash_probe(struct udevice *bus)
115ff1da6fbSAllen Martin {
116fda6fac3SSimon Glass 	struct tegra_spi_platdata *plat = dev_get_platdata(bus);
117fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
118ff1da6fbSAllen Martin 
119fda6fac3SSimon Glass 	priv->regs = (struct spi_regs *)plat->base;
120fda6fac3SSimon Glass 
121fda6fac3SSimon Glass 	priv->last_transaction_us = timer_get_us();
122fda6fac3SSimon Glass 	priv->freq = plat->frequency;
123fda6fac3SSimon Glass 	priv->periph_id = plat->periph_id;
124fda6fac3SSimon Glass 
125fda6fac3SSimon Glass 	return 0;
126ff1da6fbSAllen Martin }
127ff1da6fbSAllen Martin 
128*9694b724SSimon Glass static int tegra20_sflash_claim_bus(struct udevice *dev)
129ff1da6fbSAllen Martin {
130*9694b724SSimon Glass 	struct udevice *bus = dev->parent;
131fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
132fda6fac3SSimon Glass 	struct spi_regs *regs = priv->regs;
133ff1da6fbSAllen Martin 	u32 reg;
134ff1da6fbSAllen Martin 
135ff1da6fbSAllen Martin 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
136fda6fac3SSimon Glass 	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
137fda6fac3SSimon Glass 			       priv->freq);
138ff1da6fbSAllen Martin 
139ff1da6fbSAllen Martin 	/* Clear stale status here */
140ff1da6fbSAllen Martin 	reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
141ff1da6fbSAllen Martin 		SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF;
142ff1da6fbSAllen Martin 	writel(reg, &regs->status);
14378f47b73SAllen Martin 	debug("%s: STATUS = %08x\n", __func__, readl(&regs->status));
144ff1da6fbSAllen Martin 
145ff1da6fbSAllen Martin 	/*
146ff1da6fbSAllen Martin 	 * Use sw-controlled CS, so we can clock in data after ReadID, etc.
147ff1da6fbSAllen Martin 	 */
148fda6fac3SSimon Glass 	reg = (priv->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
149fda6fac3SSimon Glass 	if (priv->mode & 2)
150ff1da6fbSAllen Martin 		reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT;
151ff1da6fbSAllen Martin 	clrsetbits_le32(&regs->command, SPI_CMD_ACTIVE_SCLK_MASK |
152ff1da6fbSAllen Martin 		SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg);
15378f47b73SAllen Martin 	debug("%s: COMMAND = %08x\n", __func__, readl(&regs->command));
154ff1da6fbSAllen Martin 
155ff1da6fbSAllen Martin 	/*
156ff1da6fbSAllen Martin 	 * SPI pins on Tegra20 are muxed - change pinmux later due to UART
157ff1da6fbSAllen Martin 	 * issue.
158ff1da6fbSAllen Martin 	 */
15970ad375eSStephen Warren 	pinmux_set_func(PMUX_PINGRP_GMD, PMUX_FUNC_SFLASH);
16070ad375eSStephen Warren 	pinmux_tristate_disable(PMUX_PINGRP_LSPI);
16170ad375eSStephen Warren 	pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_SFLASH);
162ff1da6fbSAllen Martin 
163ff1da6fbSAllen Martin 	return 0;
164ff1da6fbSAllen Martin }
165ff1da6fbSAllen Martin 
166fda6fac3SSimon Glass static void spi_cs_activate(struct udevice *dev)
167ff1da6fbSAllen Martin {
168fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
169fda6fac3SSimon Glass 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
170fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
171fda6fac3SSimon Glass 
172fda6fac3SSimon Glass 	/* If it's too soon to do another transaction, wait */
173fda6fac3SSimon Glass 	if (pdata->deactivate_delay_us &&
174fda6fac3SSimon Glass 	    priv->last_transaction_us) {
175fda6fac3SSimon Glass 		ulong delay_us;		/* The delay completed so far */
176fda6fac3SSimon Glass 		delay_us = timer_get_us() - priv->last_transaction_us;
177fda6fac3SSimon Glass 		if (delay_us < pdata->deactivate_delay_us)
178fda6fac3SSimon Glass 			udelay(pdata->deactivate_delay_us - delay_us);
179fda6fac3SSimon Glass 	}
180ff1da6fbSAllen Martin 
181ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 1 to get a 0 */
182fda6fac3SSimon Glass 	setbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
183ff1da6fbSAllen Martin }
184ff1da6fbSAllen Martin 
185fda6fac3SSimon Glass static void spi_cs_deactivate(struct udevice *dev)
186ff1da6fbSAllen Martin {
187fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
188fda6fac3SSimon Glass 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
189fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
190ff1da6fbSAllen Martin 
191ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 0 to get a 1 */
192fda6fac3SSimon Glass 	clrbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
193fda6fac3SSimon Glass 
194fda6fac3SSimon Glass 	/* Remember time of this transaction so we can honour the bus delay */
195fda6fac3SSimon Glass 	if (pdata->deactivate_delay_us)
196fda6fac3SSimon Glass 		priv->last_transaction_us = timer_get_us();
197ff1da6fbSAllen Martin }
198ff1da6fbSAllen Martin 
199fda6fac3SSimon Glass static int tegra20_sflash_xfer(struct udevice *dev, unsigned int bitlen,
200fda6fac3SSimon Glass 			     const void *data_out, void *data_in,
201fda6fac3SSimon Glass 			     unsigned long flags)
202ff1da6fbSAllen Martin {
203fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
204fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
205fda6fac3SSimon Glass 	struct spi_regs *regs = priv->regs;
206ff1da6fbSAllen Martin 	u32 reg, tmpdout, tmpdin = 0;
207ff1da6fbSAllen Martin 	const u8 *dout = data_out;
208ff1da6fbSAllen Martin 	u8 *din = data_in;
209ff1da6fbSAllen Martin 	int num_bytes;
210ff1da6fbSAllen Martin 	int ret;
211ff1da6fbSAllen Martin 
212fda6fac3SSimon Glass 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
213fda6fac3SSimon Glass 	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
214ff1da6fbSAllen Martin 	if (bitlen % 8)
215ff1da6fbSAllen Martin 		return -1;
216ff1da6fbSAllen Martin 	num_bytes = bitlen / 8;
217ff1da6fbSAllen Martin 
218ff1da6fbSAllen Martin 	ret = 0;
219ff1da6fbSAllen Martin 
220ff1da6fbSAllen Martin 	reg = readl(&regs->status);
221ff1da6fbSAllen Martin 	writel(reg, &regs->status);	/* Clear all SPI events via R/W */
222ff1da6fbSAllen Martin 	debug("spi_xfer entry: STATUS = %08x\n", reg);
223ff1da6fbSAllen Martin 
224ff1da6fbSAllen Martin 	reg = readl(&regs->command);
225ff1da6fbSAllen Martin 	reg |= SPI_CMD_TXEN | SPI_CMD_RXEN;
226ff1da6fbSAllen Martin 	writel(reg, &regs->command);
227ff1da6fbSAllen Martin 	debug("spi_xfer: COMMAND = %08x\n", readl(&regs->command));
228ff1da6fbSAllen Martin 
229ff1da6fbSAllen Martin 	if (flags & SPI_XFER_BEGIN)
230fda6fac3SSimon Glass 		spi_cs_activate(dev);
231ff1da6fbSAllen Martin 
232ff1da6fbSAllen Martin 	/* handle data in 32-bit chunks */
233ff1da6fbSAllen Martin 	while (num_bytes > 0) {
234ff1da6fbSAllen Martin 		int bytes;
235ff1da6fbSAllen Martin 		int is_read = 0;
236ff1da6fbSAllen Martin 		int tm, i;
237ff1da6fbSAllen Martin 
238ff1da6fbSAllen Martin 		tmpdout = 0;
239ff1da6fbSAllen Martin 		bytes = (num_bytes > 4) ?  4 : num_bytes;
240ff1da6fbSAllen Martin 
241ff1da6fbSAllen Martin 		if (dout != NULL) {
242ff1da6fbSAllen Martin 			for (i = 0; i < bytes; ++i)
243ff1da6fbSAllen Martin 				tmpdout = (tmpdout << 8) | dout[i];
244ff1da6fbSAllen Martin 		}
245ff1da6fbSAllen Martin 
246ff1da6fbSAllen Martin 		num_bytes -= bytes;
247ff1da6fbSAllen Martin 		if (dout)
248ff1da6fbSAllen Martin 			dout += bytes;
249ff1da6fbSAllen Martin 
250ff1da6fbSAllen Martin 		clrsetbits_le32(&regs->command, SPI_CMD_BIT_LENGTH_MASK,
251ff1da6fbSAllen Martin 				bytes * 8 - 1);
252ff1da6fbSAllen Martin 		writel(tmpdout, &regs->tx_fifo);
253ff1da6fbSAllen Martin 		setbits_le32(&regs->command, SPI_CMD_GO);
254ff1da6fbSAllen Martin 
255ff1da6fbSAllen Martin 		/*
256ff1da6fbSAllen Martin 		 * Wait for SPI transmit FIFO to empty, or to time out.
257ff1da6fbSAllen Martin 		 * The RX FIFO status will be read and cleared last
258ff1da6fbSAllen Martin 		 */
259ff1da6fbSAllen Martin 		for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
260ff1da6fbSAllen Martin 			u32 status;
261ff1da6fbSAllen Martin 
262ff1da6fbSAllen Martin 			status = readl(&regs->status);
263ff1da6fbSAllen Martin 
264ff1da6fbSAllen Martin 			/* We can exit when we've had both RX and TX activity */
265ff1da6fbSAllen Martin 			if (is_read && (status & SPI_STAT_TXF_EMPTY))
266ff1da6fbSAllen Martin 				break;
267ff1da6fbSAllen Martin 
268ff1da6fbSAllen Martin 			if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) !=
269ff1da6fbSAllen Martin 					SPI_STAT_RDY)
270ff1da6fbSAllen Martin 				tm++;
271ff1da6fbSAllen Martin 
272ff1da6fbSAllen Martin 			else if (!(status & SPI_STAT_RXF_EMPTY)) {
273ff1da6fbSAllen Martin 				tmpdin = readl(&regs->rx_fifo);
274ff1da6fbSAllen Martin 				is_read = 1;
275ff1da6fbSAllen Martin 
276ff1da6fbSAllen Martin 				/* swap bytes read in */
277ff1da6fbSAllen Martin 				if (din != NULL) {
278ff1da6fbSAllen Martin 					for (i = bytes - 1; i >= 0; --i) {
279ff1da6fbSAllen Martin 						din[i] = tmpdin & 0xff;
280ff1da6fbSAllen Martin 						tmpdin >>= 8;
281ff1da6fbSAllen Martin 					}
282ff1da6fbSAllen Martin 					din += bytes;
283ff1da6fbSAllen Martin 				}
284ff1da6fbSAllen Martin 			}
285ff1da6fbSAllen Martin 		}
286ff1da6fbSAllen Martin 
287ff1da6fbSAllen Martin 		if (tm >= SPI_TIMEOUT)
288ff1da6fbSAllen Martin 			ret = tm;
289ff1da6fbSAllen Martin 
290ff1da6fbSAllen Martin 		/* clear ACK RDY, etc. bits */
291ff1da6fbSAllen Martin 		writel(readl(&regs->status), &regs->status);
292ff1da6fbSAllen Martin 	}
293ff1da6fbSAllen Martin 
294ff1da6fbSAllen Martin 	if (flags & SPI_XFER_END)
295fda6fac3SSimon Glass 		spi_cs_deactivate(dev);
296ff1da6fbSAllen Martin 
297ff1da6fbSAllen Martin 	debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n",
298ff1da6fbSAllen Martin 		tmpdin, readl(&regs->status));
299ff1da6fbSAllen Martin 
300ff1da6fbSAllen Martin 	if (ret) {
301ff1da6fbSAllen Martin 		printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret);
302ff1da6fbSAllen Martin 		return -1;
303ff1da6fbSAllen Martin 	}
304ff1da6fbSAllen Martin 
305ff1da6fbSAllen Martin 	return 0;
306ff1da6fbSAllen Martin }
307fda6fac3SSimon Glass 
308fda6fac3SSimon Glass static int tegra20_sflash_set_speed(struct udevice *bus, uint speed)
309fda6fac3SSimon Glass {
310fda6fac3SSimon Glass 	struct tegra_spi_platdata *plat = bus->platdata;
311fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
312fda6fac3SSimon Glass 
313fda6fac3SSimon Glass 	if (speed > plat->frequency)
314fda6fac3SSimon Glass 		speed = plat->frequency;
315fda6fac3SSimon Glass 	priv->freq = speed;
316fda6fac3SSimon Glass 	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
317fda6fac3SSimon Glass 
318fda6fac3SSimon Glass 	return 0;
319fda6fac3SSimon Glass }
320fda6fac3SSimon Glass 
321fda6fac3SSimon Glass static int tegra20_sflash_set_mode(struct udevice *bus, uint mode)
322fda6fac3SSimon Glass {
323fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
324fda6fac3SSimon Glass 
325fda6fac3SSimon Glass 	priv->mode = mode;
326fda6fac3SSimon Glass 	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
327fda6fac3SSimon Glass 
328fda6fac3SSimon Glass 	return 0;
329fda6fac3SSimon Glass }
330fda6fac3SSimon Glass 
331fda6fac3SSimon Glass static const struct dm_spi_ops tegra20_sflash_ops = {
332fda6fac3SSimon Glass 	.claim_bus	= tegra20_sflash_claim_bus,
333fda6fac3SSimon Glass 	.xfer		= tegra20_sflash_xfer,
334fda6fac3SSimon Glass 	.set_speed	= tegra20_sflash_set_speed,
335fda6fac3SSimon Glass 	.set_mode	= tegra20_sflash_set_mode,
336fda6fac3SSimon Glass 	.cs_info	= tegra20_sflash_cs_info,
337fda6fac3SSimon Glass };
338fda6fac3SSimon Glass 
339fda6fac3SSimon Glass static const struct udevice_id tegra20_sflash_ids[] = {
340fda6fac3SSimon Glass 	{ .compatible = "nvidia,tegra20-sflash" },
341fda6fac3SSimon Glass 	{ }
342fda6fac3SSimon Glass };
343fda6fac3SSimon Glass 
344fda6fac3SSimon Glass U_BOOT_DRIVER(tegra20_sflash) = {
345fda6fac3SSimon Glass 	.name	= "tegra20_sflash",
346fda6fac3SSimon Glass 	.id	= UCLASS_SPI,
347fda6fac3SSimon Glass 	.of_match = tegra20_sflash_ids,
348fda6fac3SSimon Glass 	.ops	= &tegra20_sflash_ops,
349fda6fac3SSimon Glass 	.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
350fda6fac3SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
351fda6fac3SSimon Glass 	.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
352fda6fac3SSimon Glass 	.probe	= tegra20_sflash_probe,
353fda6fac3SSimon Glass };
354