xref: /rk3399_rockchip-uboot/drivers/spi/tegra20_sflash.c (revision 000f15fa15c57d2d2f5a1a1d2ea233edbff6461e)
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 
23f692248fSJagan Teki #define SPI_CMD_GO			BIT(30)
247a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_SHIFT	26
257a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_MASK	(3 << SPI_CMD_ACTIVE_SCLK_SHIFT)
26f692248fSJagan Teki #define SPI_CMD_CK_SDA			BIT(21)
277a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_SHIFT	18
287a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_MASK		(3 << SPI_CMD_ACTIVE_SDA_SHIFT)
29f692248fSJagan Teki #define SPI_CMD_CS_POL			BIT(16)
30f692248fSJagan Teki #define SPI_CMD_TXEN			BIT(15)
31f692248fSJagan Teki #define SPI_CMD_RXEN			BIT(14)
32f692248fSJagan Teki #define SPI_CMD_CS_VAL			BIT(13)
33f692248fSJagan Teki #define SPI_CMD_CS_SOFT			BIT(12)
34f692248fSJagan Teki #define SPI_CMD_CS_DELAY		BIT(9)
35f692248fSJagan Teki #define SPI_CMD_CS3_EN			BIT(8)
36f692248fSJagan Teki #define SPI_CMD_CS2_EN			BIT(7)
37f692248fSJagan Teki #define SPI_CMD_CS1_EN			BIT(6)
38f692248fSJagan Teki #define SPI_CMD_CS0_EN			BIT(5)
39f692248fSJagan Teki #define SPI_CMD_BIT_LENGTH		BIT(4)
4076538ec6SJagan Teki #define SPI_CMD_BIT_LENGTH_MASK		GENMASK(4, 0)
417a49ba6eSAllen Martin 
42f692248fSJagan Teki #define SPI_STAT_BSY			BIT(31)
43f692248fSJagan Teki #define SPI_STAT_RDY			BIT(30)
44f692248fSJagan Teki #define SPI_STAT_RXF_FLUSH		BIT(29)
45f692248fSJagan Teki #define SPI_STAT_TXF_FLUSH		BIT(28)
46f692248fSJagan Teki #define SPI_STAT_RXF_UNR		BIT(27)
47f692248fSJagan Teki #define SPI_STAT_TXF_OVF		BIT(26)
48f692248fSJagan Teki #define SPI_STAT_RXF_EMPTY		BIT(25)
49f692248fSJagan Teki #define SPI_STAT_RXF_FULL		BIT(24)
50f692248fSJagan Teki #define SPI_STAT_TXF_EMPTY		BIT(23)
51f692248fSJagan Teki #define SPI_STAT_TXF_FULL		BIT(22)
52f692248fSJagan Teki #define SPI_STAT_SEL_TXRX_N		BIT(16)
53f692248fSJagan Teki #define SPI_STAT_CUR_BLKCNT		BIT(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 
tegra20_sflash_cs_info(struct udevice * bus,unsigned int cs,struct spi_cs_info * info)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 
tegra20_sflash_ofdata_to_platdata(struct udevice * bus)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;
91e160f7d4SSimon Glass 	int node = dev_of_offset(bus);
92ff1da6fbSAllen Martin 
93a821c4afSSimon Glass 	plat->base = devfdt_get_addr(bus);
94*000f15faSSimon Glass 	plat->periph_id = clock_decode_periph_id(bus);
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 
tegra20_sflash_probe(struct udevice * bus)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 
1254832c7f5SStephen Warren 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
1264832c7f5SStephen Warren 	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
1274832c7f5SStephen Warren 			       priv->freq);
1284832c7f5SStephen Warren 
129fda6fac3SSimon Glass 	return 0;
130ff1da6fbSAllen Martin }
131ff1da6fbSAllen Martin 
tegra20_sflash_claim_bus(struct udevice * dev)1329694b724SSimon Glass static int tegra20_sflash_claim_bus(struct udevice *dev)
133ff1da6fbSAllen Martin {
1349694b724SSimon Glass 	struct udevice *bus = dev->parent;
135fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
136fda6fac3SSimon Glass 	struct spi_regs *regs = priv->regs;
137ff1da6fbSAllen Martin 	u32 reg;
138ff1da6fbSAllen Martin 
139ff1da6fbSAllen Martin 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
140fda6fac3SSimon Glass 	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
141fda6fac3SSimon Glass 			       priv->freq);
142ff1da6fbSAllen Martin 
143ff1da6fbSAllen Martin 	/* Clear stale status here */
144ff1da6fbSAllen Martin 	reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
145ff1da6fbSAllen Martin 		SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF;
146ff1da6fbSAllen Martin 	writel(reg, &regs->status);
14778f47b73SAllen Martin 	debug("%s: STATUS = %08x\n", __func__, readl(&regs->status));
148ff1da6fbSAllen Martin 
149ff1da6fbSAllen Martin 	/*
150ff1da6fbSAllen Martin 	 * Use sw-controlled CS, so we can clock in data after ReadID, etc.
151ff1da6fbSAllen Martin 	 */
152fda6fac3SSimon Glass 	reg = (priv->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
153fda6fac3SSimon Glass 	if (priv->mode & 2)
154ff1da6fbSAllen Martin 		reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT;
155ff1da6fbSAllen Martin 	clrsetbits_le32(&regs->command, SPI_CMD_ACTIVE_SCLK_MASK |
156ff1da6fbSAllen Martin 		SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg);
15778f47b73SAllen Martin 	debug("%s: COMMAND = %08x\n", __func__, readl(&regs->command));
158ff1da6fbSAllen Martin 
159ff1da6fbSAllen Martin 	/*
160ff1da6fbSAllen Martin 	 * SPI pins on Tegra20 are muxed - change pinmux later due to UART
161ff1da6fbSAllen Martin 	 * issue.
162ff1da6fbSAllen Martin 	 */
16370ad375eSStephen Warren 	pinmux_set_func(PMUX_PINGRP_GMD, PMUX_FUNC_SFLASH);
16470ad375eSStephen Warren 	pinmux_tristate_disable(PMUX_PINGRP_LSPI);
16570ad375eSStephen Warren 	pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_SFLASH);
166ff1da6fbSAllen Martin 
167ff1da6fbSAllen Martin 	return 0;
168ff1da6fbSAllen Martin }
169ff1da6fbSAllen Martin 
spi_cs_activate(struct udevice * dev)170fda6fac3SSimon Glass static void spi_cs_activate(struct udevice *dev)
171ff1da6fbSAllen Martin {
172fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
173fda6fac3SSimon Glass 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
174fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
175fda6fac3SSimon Glass 
176fda6fac3SSimon Glass 	/* If it's too soon to do another transaction, wait */
177fda6fac3SSimon Glass 	if (pdata->deactivate_delay_us &&
178fda6fac3SSimon Glass 	    priv->last_transaction_us) {
179fda6fac3SSimon Glass 		ulong delay_us;		/* The delay completed so far */
180fda6fac3SSimon Glass 		delay_us = timer_get_us() - priv->last_transaction_us;
181fda6fac3SSimon Glass 		if (delay_us < pdata->deactivate_delay_us)
182fda6fac3SSimon Glass 			udelay(pdata->deactivate_delay_us - delay_us);
183fda6fac3SSimon Glass 	}
184ff1da6fbSAllen Martin 
185ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 1 to get a 0 */
186fda6fac3SSimon Glass 	setbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
187ff1da6fbSAllen Martin }
188ff1da6fbSAllen Martin 
spi_cs_deactivate(struct udevice * dev)189fda6fac3SSimon Glass static void spi_cs_deactivate(struct udevice *dev)
190ff1da6fbSAllen Martin {
191fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
192fda6fac3SSimon Glass 	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
193fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
194ff1da6fbSAllen Martin 
195ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 0 to get a 1 */
196fda6fac3SSimon Glass 	clrbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
197fda6fac3SSimon Glass 
198fda6fac3SSimon Glass 	/* Remember time of this transaction so we can honour the bus delay */
199fda6fac3SSimon Glass 	if (pdata->deactivate_delay_us)
200fda6fac3SSimon Glass 		priv->last_transaction_us = timer_get_us();
201ff1da6fbSAllen Martin }
202ff1da6fbSAllen Martin 
tegra20_sflash_xfer(struct udevice * dev,unsigned int bitlen,const void * data_out,void * data_in,unsigned long flags)203fda6fac3SSimon Glass static int tegra20_sflash_xfer(struct udevice *dev, unsigned int bitlen,
204fda6fac3SSimon Glass 			     const void *data_out, void *data_in,
205fda6fac3SSimon Glass 			     unsigned long flags)
206ff1da6fbSAllen Martin {
207fda6fac3SSimon Glass 	struct udevice *bus = dev->parent;
208fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
209fda6fac3SSimon Glass 	struct spi_regs *regs = priv->regs;
210ff1da6fbSAllen Martin 	u32 reg, tmpdout, tmpdin = 0;
211ff1da6fbSAllen Martin 	const u8 *dout = data_out;
212ff1da6fbSAllen Martin 	u8 *din = data_in;
213ff1da6fbSAllen Martin 	int num_bytes;
214ff1da6fbSAllen Martin 	int ret;
215ff1da6fbSAllen Martin 
216fda6fac3SSimon Glass 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
217fda6fac3SSimon Glass 	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
218ff1da6fbSAllen Martin 	if (bitlen % 8)
219ff1da6fbSAllen Martin 		return -1;
220ff1da6fbSAllen Martin 	num_bytes = bitlen / 8;
221ff1da6fbSAllen Martin 
222ff1da6fbSAllen Martin 	ret = 0;
223ff1da6fbSAllen Martin 
224ff1da6fbSAllen Martin 	reg = readl(&regs->status);
225ff1da6fbSAllen Martin 	writel(reg, &regs->status);	/* Clear all SPI events via R/W */
226ff1da6fbSAllen Martin 	debug("spi_xfer entry: STATUS = %08x\n", reg);
227ff1da6fbSAllen Martin 
228ff1da6fbSAllen Martin 	reg = readl(&regs->command);
229ff1da6fbSAllen Martin 	reg |= SPI_CMD_TXEN | SPI_CMD_RXEN;
230ff1da6fbSAllen Martin 	writel(reg, &regs->command);
231ff1da6fbSAllen Martin 	debug("spi_xfer: COMMAND = %08x\n", readl(&regs->command));
232ff1da6fbSAllen Martin 
233ff1da6fbSAllen Martin 	if (flags & SPI_XFER_BEGIN)
234fda6fac3SSimon Glass 		spi_cs_activate(dev);
235ff1da6fbSAllen Martin 
236ff1da6fbSAllen Martin 	/* handle data in 32-bit chunks */
237ff1da6fbSAllen Martin 	while (num_bytes > 0) {
238ff1da6fbSAllen Martin 		int bytes;
239ff1da6fbSAllen Martin 		int is_read = 0;
240ff1da6fbSAllen Martin 		int tm, i;
241ff1da6fbSAllen Martin 
242ff1da6fbSAllen Martin 		tmpdout = 0;
243ff1da6fbSAllen Martin 		bytes = (num_bytes > 4) ?  4 : num_bytes;
244ff1da6fbSAllen Martin 
245ff1da6fbSAllen Martin 		if (dout != NULL) {
246ff1da6fbSAllen Martin 			for (i = 0; i < bytes; ++i)
247ff1da6fbSAllen Martin 				tmpdout = (tmpdout << 8) | dout[i];
248ff1da6fbSAllen Martin 		}
249ff1da6fbSAllen Martin 
250ff1da6fbSAllen Martin 		num_bytes -= bytes;
251ff1da6fbSAllen Martin 		if (dout)
252ff1da6fbSAllen Martin 			dout += bytes;
253ff1da6fbSAllen Martin 
254ff1da6fbSAllen Martin 		clrsetbits_le32(&regs->command, SPI_CMD_BIT_LENGTH_MASK,
255ff1da6fbSAllen Martin 				bytes * 8 - 1);
256ff1da6fbSAllen Martin 		writel(tmpdout, &regs->tx_fifo);
257ff1da6fbSAllen Martin 		setbits_le32(&regs->command, SPI_CMD_GO);
258ff1da6fbSAllen Martin 
259ff1da6fbSAllen Martin 		/*
260ff1da6fbSAllen Martin 		 * Wait for SPI transmit FIFO to empty, or to time out.
261ff1da6fbSAllen Martin 		 * The RX FIFO status will be read and cleared last
262ff1da6fbSAllen Martin 		 */
263ff1da6fbSAllen Martin 		for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
264ff1da6fbSAllen Martin 			u32 status;
265ff1da6fbSAllen Martin 
266ff1da6fbSAllen Martin 			status = readl(&regs->status);
267ff1da6fbSAllen Martin 
268ff1da6fbSAllen Martin 			/* We can exit when we've had both RX and TX activity */
269ff1da6fbSAllen Martin 			if (is_read && (status & SPI_STAT_TXF_EMPTY))
270ff1da6fbSAllen Martin 				break;
271ff1da6fbSAllen Martin 
272ff1da6fbSAllen Martin 			if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) !=
273ff1da6fbSAllen Martin 					SPI_STAT_RDY)
274ff1da6fbSAllen Martin 				tm++;
275ff1da6fbSAllen Martin 
276ff1da6fbSAllen Martin 			else if (!(status & SPI_STAT_RXF_EMPTY)) {
277ff1da6fbSAllen Martin 				tmpdin = readl(&regs->rx_fifo);
278ff1da6fbSAllen Martin 				is_read = 1;
279ff1da6fbSAllen Martin 
280ff1da6fbSAllen Martin 				/* swap bytes read in */
281ff1da6fbSAllen Martin 				if (din != NULL) {
282ff1da6fbSAllen Martin 					for (i = bytes - 1; i >= 0; --i) {
283ff1da6fbSAllen Martin 						din[i] = tmpdin & 0xff;
284ff1da6fbSAllen Martin 						tmpdin >>= 8;
285ff1da6fbSAllen Martin 					}
286ff1da6fbSAllen Martin 					din += bytes;
287ff1da6fbSAllen Martin 				}
288ff1da6fbSAllen Martin 			}
289ff1da6fbSAllen Martin 		}
290ff1da6fbSAllen Martin 
291ff1da6fbSAllen Martin 		if (tm >= SPI_TIMEOUT)
292ff1da6fbSAllen Martin 			ret = tm;
293ff1da6fbSAllen Martin 
294ff1da6fbSAllen Martin 		/* clear ACK RDY, etc. bits */
295ff1da6fbSAllen Martin 		writel(readl(&regs->status), &regs->status);
296ff1da6fbSAllen Martin 	}
297ff1da6fbSAllen Martin 
298ff1da6fbSAllen Martin 	if (flags & SPI_XFER_END)
299fda6fac3SSimon Glass 		spi_cs_deactivate(dev);
300ff1da6fbSAllen Martin 
301ff1da6fbSAllen Martin 	debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n",
302ff1da6fbSAllen Martin 		tmpdin, readl(&regs->status));
303ff1da6fbSAllen Martin 
304ff1da6fbSAllen Martin 	if (ret) {
305ff1da6fbSAllen Martin 		printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret);
306ff1da6fbSAllen Martin 		return -1;
307ff1da6fbSAllen Martin 	}
308ff1da6fbSAllen Martin 
309ff1da6fbSAllen Martin 	return 0;
310ff1da6fbSAllen Martin }
311fda6fac3SSimon Glass 
tegra20_sflash_set_speed(struct udevice * bus,uint speed)312fda6fac3SSimon Glass static int tegra20_sflash_set_speed(struct udevice *bus, uint speed)
313fda6fac3SSimon Glass {
314fda6fac3SSimon Glass 	struct tegra_spi_platdata *plat = bus->platdata;
315fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
316fda6fac3SSimon Glass 
317fda6fac3SSimon Glass 	if (speed > plat->frequency)
318fda6fac3SSimon Glass 		speed = plat->frequency;
319fda6fac3SSimon Glass 	priv->freq = speed;
320fda6fac3SSimon Glass 	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
321fda6fac3SSimon Glass 
322fda6fac3SSimon Glass 	return 0;
323fda6fac3SSimon Glass }
324fda6fac3SSimon Glass 
tegra20_sflash_set_mode(struct udevice * bus,uint mode)325fda6fac3SSimon Glass static int tegra20_sflash_set_mode(struct udevice *bus, uint mode)
326fda6fac3SSimon Glass {
327fda6fac3SSimon Glass 	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
328fda6fac3SSimon Glass 
329fda6fac3SSimon Glass 	priv->mode = mode;
330fda6fac3SSimon Glass 	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
331fda6fac3SSimon Glass 
332fda6fac3SSimon Glass 	return 0;
333fda6fac3SSimon Glass }
334fda6fac3SSimon Glass 
335fda6fac3SSimon Glass static const struct dm_spi_ops tegra20_sflash_ops = {
336fda6fac3SSimon Glass 	.claim_bus	= tegra20_sflash_claim_bus,
337fda6fac3SSimon Glass 	.xfer		= tegra20_sflash_xfer,
338fda6fac3SSimon Glass 	.set_speed	= tegra20_sflash_set_speed,
339fda6fac3SSimon Glass 	.set_mode	= tegra20_sflash_set_mode,
340fda6fac3SSimon Glass 	.cs_info	= tegra20_sflash_cs_info,
341fda6fac3SSimon Glass };
342fda6fac3SSimon Glass 
343fda6fac3SSimon Glass static const struct udevice_id tegra20_sflash_ids[] = {
344fda6fac3SSimon Glass 	{ .compatible = "nvidia,tegra20-sflash" },
345fda6fac3SSimon Glass 	{ }
346fda6fac3SSimon Glass };
347fda6fac3SSimon Glass 
348fda6fac3SSimon Glass U_BOOT_DRIVER(tegra20_sflash) = {
349fda6fac3SSimon Glass 	.name	= "tegra20_sflash",
350fda6fac3SSimon Glass 	.id	= UCLASS_SPI,
351fda6fac3SSimon Glass 	.of_match = tegra20_sflash_ids,
352fda6fac3SSimon Glass 	.ops	= &tegra20_sflash_ops,
353fda6fac3SSimon Glass 	.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
354fda6fac3SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
355fda6fac3SSimon Glass 	.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
356fda6fac3SSimon Glass 	.probe	= tegra20_sflash_probe,
357fda6fac3SSimon Glass };
358