177c42e80SAllen Martin /*
277c42e80SAllen Martin * NVIDIA Tegra SPI controller (T114 and later)
377c42e80SAllen Martin *
477c42e80SAllen Martin * Copyright (c) 2010-2013 NVIDIA Corporation
577c42e80SAllen Martin *
65b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0
777c42e80SAllen Martin */
877c42e80SAllen Martin
977c42e80SAllen Martin #include <common.h>
10fda6fac3SSimon Glass #include <dm.h>
1177c42e80SAllen Martin #include <asm/io.h>
1277c42e80SAllen Martin #include <asm/arch/clock.h>
1377c42e80SAllen Martin #include <asm/arch-tegra/clk_rst.h>
1477c42e80SAllen Martin #include <spi.h>
15fda6fac3SSimon Glass #include "tegra_spi.h"
1677c42e80SAllen Martin
1777c42e80SAllen Martin DECLARE_GLOBAL_DATA_PTR;
1877c42e80SAllen Martin
1977c42e80SAllen Martin /* COMMAND1 */
20f692248fSJagan Teki #define SPI_CMD1_GO BIT(31)
21f692248fSJagan Teki #define SPI_CMD1_M_S BIT(30)
2276538ec6SJagan Teki #define SPI_CMD1_MODE_MASK GENMASK(1, 0)
2377c42e80SAllen Martin #define SPI_CMD1_MODE_SHIFT 28
2476538ec6SJagan Teki #define SPI_CMD1_CS_SEL_MASK GENMASK(1, 0)
2577c42e80SAllen Martin #define SPI_CMD1_CS_SEL_SHIFT 26
26f692248fSJagan Teki #define SPI_CMD1_CS_POL_INACTIVE3 BIT(25)
27f692248fSJagan Teki #define SPI_CMD1_CS_POL_INACTIVE2 BIT(24)
28f692248fSJagan Teki #define SPI_CMD1_CS_POL_INACTIVE1 BIT(23)
29f692248fSJagan Teki #define SPI_CMD1_CS_POL_INACTIVE0 BIT(22)
30f692248fSJagan Teki #define SPI_CMD1_CS_SW_HW BIT(21)
31f692248fSJagan Teki #define SPI_CMD1_CS_SW_VAL BIT(20)
3276538ec6SJagan Teki #define SPI_CMD1_IDLE_SDA_MASK GENMASK(1, 0)
3377c42e80SAllen Martin #define SPI_CMD1_IDLE_SDA_SHIFT 18
34f692248fSJagan Teki #define SPI_CMD1_BIDIR BIT(17)
35f692248fSJagan Teki #define SPI_CMD1_LSBI_FE BIT(16)
36f692248fSJagan Teki #define SPI_CMD1_LSBY_FE BIT(15)
37f692248fSJagan Teki #define SPI_CMD1_BOTH_EN_BIT BIT(14)
38f692248fSJagan Teki #define SPI_CMD1_BOTH_EN_BYTE BIT(13)
39f692248fSJagan Teki #define SPI_CMD1_RX_EN BIT(12)
40f692248fSJagan Teki #define SPI_CMD1_TX_EN BIT(11)
41f692248fSJagan Teki #define SPI_CMD1_PACKED BIT(5)
4276538ec6SJagan Teki #define SPI_CMD1_BIT_LEN_MASK GENMASK(4, 0)
4377c42e80SAllen Martin #define SPI_CMD1_BIT_LEN_SHIFT 0
4477c42e80SAllen Martin
4577c42e80SAllen Martin /* COMMAND2 */
46f692248fSJagan Teki #define SPI_CMD2_TX_CLK_TAP_DELAY BIT(6)
4776538ec6SJagan Teki #define SPI_CMD2_TX_CLK_TAP_DELAY_MASK GENMASK(11, 6)
48f692248fSJagan Teki #define SPI_CMD2_RX_CLK_TAP_DELAY BIT(0)
4976538ec6SJagan Teki #define SPI_CMD2_RX_CLK_TAP_DELAY_MASK GENMASK(5, 0)
5077c42e80SAllen Martin
5177c42e80SAllen Martin /* TRANSFER STATUS */
52f692248fSJagan Teki #define SPI_XFER_STS_RDY BIT(30)
5377c42e80SAllen Martin
5477c42e80SAllen Martin /* FIFO STATUS */
55f692248fSJagan Teki #define SPI_FIFO_STS_CS_INACTIVE BIT(31)
56f692248fSJagan Teki #define SPI_FIFO_STS_FRAME_END BIT(30)
57f692248fSJagan Teki #define SPI_FIFO_STS_RX_FIFO_FLUSH BIT(15)
58f692248fSJagan Teki #define SPI_FIFO_STS_TX_FIFO_FLUSH BIT(14)
59f692248fSJagan Teki #define SPI_FIFO_STS_ERR BIT(8)
60f692248fSJagan Teki #define SPI_FIFO_STS_TX_FIFO_OVF BIT(7)
61f692248fSJagan Teki #define SPI_FIFO_STS_TX_FIFO_UNR BIT(6)
62f692248fSJagan Teki #define SPI_FIFO_STS_RX_FIFO_OVF BIT(5)
63f692248fSJagan Teki #define SPI_FIFO_STS_RX_FIFO_UNR BIT(4)
64f692248fSJagan Teki #define SPI_FIFO_STS_TX_FIFO_FULL BIT(3)
65f692248fSJagan Teki #define SPI_FIFO_STS_TX_FIFO_EMPTY BIT(2)
66f692248fSJagan Teki #define SPI_FIFO_STS_RX_FIFO_FULL BIT(1)
67f692248fSJagan Teki #define SPI_FIFO_STS_RX_FIFO_EMPTY BIT(0)
6877c42e80SAllen Martin
6977c42e80SAllen Martin #define SPI_TIMEOUT 1000
7077c42e80SAllen Martin #define TEGRA_SPI_MAX_FREQ 52000000
7177c42e80SAllen Martin
7277c42e80SAllen Martin struct spi_regs {
7377c42e80SAllen Martin u32 command1; /* 000:SPI_COMMAND1 register */
7477c42e80SAllen Martin u32 command2; /* 004:SPI_COMMAND2 register */
7577c42e80SAllen Martin u32 timing1; /* 008:SPI_CS_TIM1 register */
7677c42e80SAllen Martin u32 timing2; /* 00c:SPI_CS_TIM2 register */
7777c42e80SAllen Martin u32 xfer_status;/* 010:SPI_TRANS_STATUS register */
7877c42e80SAllen Martin u32 fifo_status;/* 014:SPI_FIFO_STATUS register */
7977c42e80SAllen Martin u32 tx_data; /* 018:SPI_TX_DATA register */
8077c42e80SAllen Martin u32 rx_data; /* 01c:SPI_RX_DATA register */
8177c42e80SAllen Martin u32 dma_ctl; /* 020:SPI_DMA_CTL register */
8277c42e80SAllen Martin u32 dma_blk; /* 024:SPI_DMA_BLK register */
8377c42e80SAllen Martin u32 rsvd[56]; /* 028-107 reserved */
8477c42e80SAllen Martin u32 tx_fifo; /* 108:SPI_FIFO1 register */
8577c42e80SAllen Martin u32 rsvd2[31]; /* 10c-187 reserved */
8677c42e80SAllen Martin u32 rx_fifo; /* 188:SPI_FIFO2 register */
8777c42e80SAllen Martin u32 spare_ctl; /* 18c:SPI_SPARE_CTRL register */
8877c42e80SAllen Martin };
8977c42e80SAllen Martin
90fda6fac3SSimon Glass struct tegra114_spi_priv {
9177c42e80SAllen Martin struct spi_regs *regs;
9277c42e80SAllen Martin unsigned int freq;
9377c42e80SAllen Martin unsigned int mode;
9477c42e80SAllen Martin int periph_id;
9577c42e80SAllen Martin int valid;
96fda6fac3SSimon Glass int last_transaction_us;
9777c42e80SAllen Martin };
9877c42e80SAllen Martin
tegra114_spi_ofdata_to_platdata(struct udevice * bus)99fda6fac3SSimon Glass static int tegra114_spi_ofdata_to_platdata(struct udevice *bus)
10077c42e80SAllen Martin {
101fda6fac3SSimon Glass struct tegra_spi_platdata *plat = bus->platdata;
102fda6fac3SSimon Glass
103*28a3e5a8SSimon Glass plat->base = dev_read_addr(bus);
104000f15faSSimon Glass plat->periph_id = clock_decode_periph_id(bus);
105fda6fac3SSimon Glass
106fda6fac3SSimon Glass if (plat->periph_id == PERIPH_ID_NONE) {
107fda6fac3SSimon Glass debug("%s: could not decode periph id %d\n", __func__,
108fda6fac3SSimon Glass plat->periph_id);
109fda6fac3SSimon Glass return -FDT_ERR_NOTFOUND;
11077c42e80SAllen Martin }
11177c42e80SAllen Martin
112fda6fac3SSimon Glass /* Use 500KHz as a suitable default */
113*28a3e5a8SSimon Glass plat->frequency = dev_read_u32_default(bus, "spi-max-frequency",
114fda6fac3SSimon Glass 500000);
115*28a3e5a8SSimon Glass plat->deactivate_delay_us = dev_read_u32_default(bus,
116fda6fac3SSimon Glass "spi-deactivate-delay", 0);
117fda6fac3SSimon Glass debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
118fda6fac3SSimon Glass __func__, plat->base, plat->periph_id, plat->frequency,
119fda6fac3SSimon Glass plat->deactivate_delay_us);
120fda6fac3SSimon Glass
12177c42e80SAllen Martin return 0;
12277c42e80SAllen Martin }
12377c42e80SAllen Martin
tegra114_spi_probe(struct udevice * bus)124fda6fac3SSimon Glass static int tegra114_spi_probe(struct udevice *bus)
12577c42e80SAllen Martin {
126fda6fac3SSimon Glass struct tegra_spi_platdata *plat = dev_get_platdata(bus);
127fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
128635c2515SSimon Glass struct spi_regs *regs;
12920edd1acSSimon Glass ulong rate;
13077c42e80SAllen Martin
131fda6fac3SSimon Glass priv->regs = (struct spi_regs *)plat->base;
132635c2515SSimon Glass regs = priv->regs;
13377c42e80SAllen Martin
134fda6fac3SSimon Glass priv->last_transaction_us = timer_get_us();
135fda6fac3SSimon Glass priv->freq = plat->frequency;
136fda6fac3SSimon Glass priv->periph_id = plat->periph_id;
137fda6fac3SSimon Glass
13820edd1acSSimon Glass /*
13920edd1acSSimon Glass * Change SPI clock to correct frequency, PLLP_OUT0 source, falling
14020edd1acSSimon Glass * back to the oscillator if that is too fast.
14120edd1acSSimon Glass */
14220edd1acSSimon Glass rate = clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
143635c2515SSimon Glass priv->freq);
14420edd1acSSimon Glass if (rate > priv->freq + 100000) {
14520edd1acSSimon Glass rate = clock_start_periph_pll(priv->periph_id, CLOCK_ID_OSC,
14620edd1acSSimon Glass priv->freq);
14720edd1acSSimon Glass if (rate != priv->freq) {
14820edd1acSSimon Glass printf("Warning: SPI '%s' requested clock %u, actual clock %lu\n",
14920edd1acSSimon Glass bus->name, priv->freq, rate);
15020edd1acSSimon Glass }
15120edd1acSSimon Glass }
1524a7b9ee1SSimon Glass udelay(plat->deactivate_delay_us);
15377c42e80SAllen Martin
15477c42e80SAllen Martin /* Clear stale status here */
15577c42e80SAllen Martin setbits_le32(®s->fifo_status,
15677c42e80SAllen Martin SPI_FIFO_STS_ERR |
15777c42e80SAllen Martin SPI_FIFO_STS_TX_FIFO_OVF |
15877c42e80SAllen Martin SPI_FIFO_STS_TX_FIFO_UNR |
15977c42e80SAllen Martin SPI_FIFO_STS_RX_FIFO_OVF |
16077c42e80SAllen Martin SPI_FIFO_STS_RX_FIFO_UNR |
16177c42e80SAllen Martin SPI_FIFO_STS_TX_FIFO_FULL |
16277c42e80SAllen Martin SPI_FIFO_STS_TX_FIFO_EMPTY |
16377c42e80SAllen Martin SPI_FIFO_STS_RX_FIFO_FULL |
16477c42e80SAllen Martin SPI_FIFO_STS_RX_FIFO_EMPTY);
16577c42e80SAllen Martin debug("%s: FIFO STATUS = %08x\n", __func__, readl(®s->fifo_status));
16677c42e80SAllen Martin
167635c2515SSimon Glass setbits_le32(&priv->regs->command1, SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW |
168635c2515SSimon Glass (priv->mode << SPI_CMD1_MODE_SHIFT) | SPI_CMD1_CS_SW_VAL);
16977c42e80SAllen Martin debug("%s: COMMAND1 = %08x\n", __func__, readl(®s->command1));
17077c42e80SAllen Martin
17177c42e80SAllen Martin return 0;
17277c42e80SAllen Martin }
17377c42e80SAllen Martin
174fda6fac3SSimon Glass /**
175fda6fac3SSimon Glass * Activate the CS by driving it LOW
176fda6fac3SSimon Glass *
177fda6fac3SSimon Glass * @param slave Pointer to spi_slave to which controller has to
178fda6fac3SSimon Glass * communicate with
179fda6fac3SSimon Glass */
spi_cs_activate(struct udevice * dev)180fda6fac3SSimon Glass static void spi_cs_activate(struct udevice *dev)
18177c42e80SAllen Martin {
182fda6fac3SSimon Glass struct udevice *bus = dev->parent;
183fda6fac3SSimon Glass struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
184fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
18577c42e80SAllen Martin
186fda6fac3SSimon Glass /* If it's too soon to do another transaction, wait */
187fda6fac3SSimon Glass if (pdata->deactivate_delay_us &&
188fda6fac3SSimon Glass priv->last_transaction_us) {
189fda6fac3SSimon Glass ulong delay_us; /* The delay completed so far */
190fda6fac3SSimon Glass delay_us = timer_get_us() - priv->last_transaction_us;
191fda6fac3SSimon Glass if (delay_us < pdata->deactivate_delay_us)
192fda6fac3SSimon Glass udelay(pdata->deactivate_delay_us - delay_us);
19377c42e80SAllen Martin }
19477c42e80SAllen Martin
195fda6fac3SSimon Glass clrbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
19677c42e80SAllen Martin }
19777c42e80SAllen Martin
198fda6fac3SSimon Glass /**
199fda6fac3SSimon Glass * Deactivate the CS by driving it HIGH
200fda6fac3SSimon Glass *
201fda6fac3SSimon Glass * @param slave Pointer to spi_slave to which controller has to
202fda6fac3SSimon Glass * communicate with
203fda6fac3SSimon Glass */
spi_cs_deactivate(struct udevice * dev)204fda6fac3SSimon Glass static void spi_cs_deactivate(struct udevice *dev)
20577c42e80SAllen Martin {
206fda6fac3SSimon Glass struct udevice *bus = dev->parent;
207fda6fac3SSimon Glass struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
208fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
209fda6fac3SSimon Glass
210fda6fac3SSimon Glass setbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
211fda6fac3SSimon Glass
212fda6fac3SSimon Glass /* Remember time of this transaction so we can honour the bus delay */
213fda6fac3SSimon Glass if (pdata->deactivate_delay_us)
214fda6fac3SSimon Glass priv->last_transaction_us = timer_get_us();
215fda6fac3SSimon Glass
216fda6fac3SSimon Glass debug("Deactivate CS, bus '%s'\n", bus->name);
217fda6fac3SSimon Glass }
218fda6fac3SSimon Glass
tegra114_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * data_out,void * data_in,unsigned long flags)219fda6fac3SSimon Glass static int tegra114_spi_xfer(struct udevice *dev, unsigned int bitlen,
220fda6fac3SSimon Glass const void *data_out, void *data_in,
221fda6fac3SSimon Glass unsigned long flags)
222fda6fac3SSimon Glass {
223fda6fac3SSimon Glass struct udevice *bus = dev->parent;
224fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
225fda6fac3SSimon Glass struct spi_regs *regs = priv->regs;
22677c42e80SAllen Martin u32 reg, tmpdout, tmpdin = 0;
22777c42e80SAllen Martin const u8 *dout = data_out;
22877c42e80SAllen Martin u8 *din = data_in;
22977c42e80SAllen Martin int num_bytes;
23077c42e80SAllen Martin int ret;
23177c42e80SAllen Martin
23277c42e80SAllen Martin debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
233fda6fac3SSimon Glass __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
23477c42e80SAllen Martin if (bitlen % 8)
23577c42e80SAllen Martin return -1;
23677c42e80SAllen Martin num_bytes = bitlen / 8;
23777c42e80SAllen Martin
23877c42e80SAllen Martin ret = 0;
23977c42e80SAllen Martin
240635c2515SSimon Glass if (flags & SPI_XFER_BEGIN)
241635c2515SSimon Glass spi_cs_activate(dev);
242635c2515SSimon Glass
24377c42e80SAllen Martin /* clear all error status bits */
24477c42e80SAllen Martin reg = readl(®s->fifo_status);
24577c42e80SAllen Martin writel(reg, ®s->fifo_status);
24677c42e80SAllen Martin
24777c42e80SAllen Martin clrsetbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL,
24877c42e80SAllen Martin SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
249fda6fac3SSimon Glass (spi_chip_select(dev) << SPI_CMD1_CS_SEL_SHIFT));
25077c42e80SAllen Martin
25177c42e80SAllen Martin /* set xfer size to 1 block (32 bits) */
25277c42e80SAllen Martin writel(0, ®s->dma_blk);
25377c42e80SAllen Martin
25477c42e80SAllen Martin /* handle data in 32-bit chunks */
25577c42e80SAllen Martin while (num_bytes > 0) {
25677c42e80SAllen Martin int bytes;
25777c42e80SAllen Martin int tm, i;
25877c42e80SAllen Martin
25977c42e80SAllen Martin tmpdout = 0;
26077c42e80SAllen Martin bytes = (num_bytes > 4) ? 4 : num_bytes;
26177c42e80SAllen Martin
26277c42e80SAllen Martin if (dout != NULL) {
26377c42e80SAllen Martin for (i = 0; i < bytes; ++i)
26477c42e80SAllen Martin tmpdout = (tmpdout << 8) | dout[i];
26577c42e80SAllen Martin dout += bytes;
26677c42e80SAllen Martin }
26777c42e80SAllen Martin
26877c42e80SAllen Martin num_bytes -= bytes;
26977c42e80SAllen Martin
27060acde43SYen Lin /* clear ready bit */
27160acde43SYen Lin setbits_le32(®s->xfer_status, SPI_XFER_STS_RDY);
27260acde43SYen Lin
27377c42e80SAllen Martin clrsetbits_le32(®s->command1,
27477c42e80SAllen Martin SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT,
27577c42e80SAllen Martin (bytes * 8 - 1) << SPI_CMD1_BIT_LEN_SHIFT);
27677c42e80SAllen Martin writel(tmpdout, ®s->tx_fifo);
27777c42e80SAllen Martin setbits_le32(®s->command1, SPI_CMD1_GO);
27877c42e80SAllen Martin
27977c42e80SAllen Martin /*
28077c42e80SAllen Martin * Wait for SPI transmit FIFO to empty, or to time out.
28177c42e80SAllen Martin * The RX FIFO status will be read and cleared last
28277c42e80SAllen Martin */
28360acde43SYen Lin for (tm = 0; tm < SPI_TIMEOUT; ++tm) {
28477c42e80SAllen Martin u32 fifo_status, xfer_status;
28577c42e80SAllen Martin
28677c42e80SAllen Martin xfer_status = readl(®s->xfer_status);
28777c42e80SAllen Martin if (!(xfer_status & SPI_XFER_STS_RDY))
28877c42e80SAllen Martin continue;
28977c42e80SAllen Martin
29060acde43SYen Lin fifo_status = readl(®s->fifo_status);
29177c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_ERR) {
29277c42e80SAllen Martin debug("%s: got a fifo error: ", __func__);
29377c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF)
29477c42e80SAllen Martin debug("tx FIFO overflow ");
29577c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_TX_FIFO_UNR)
29677c42e80SAllen Martin debug("tx FIFO underrun ");
29777c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_RX_FIFO_OVF)
29877c42e80SAllen Martin debug("rx FIFO overflow ");
29977c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_RX_FIFO_UNR)
30077c42e80SAllen Martin debug("rx FIFO underrun ");
30177c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_TX_FIFO_FULL)
30277c42e80SAllen Martin debug("tx FIFO full ");
30377c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY)
30477c42e80SAllen Martin debug("tx FIFO empty ");
30577c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_RX_FIFO_FULL)
30677c42e80SAllen Martin debug("rx FIFO full ");
30777c42e80SAllen Martin if (fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)
30877c42e80SAllen Martin debug("rx FIFO empty ");
30977c42e80SAllen Martin debug("\n");
31077c42e80SAllen Martin break;
31177c42e80SAllen Martin }
31277c42e80SAllen Martin
31377c42e80SAllen Martin if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) {
31477c42e80SAllen Martin tmpdin = readl(®s->rx_fifo);
31577c42e80SAllen Martin
31677c42e80SAllen Martin /* swap bytes read in */
31777c42e80SAllen Martin if (din != NULL) {
31877c42e80SAllen Martin for (i = bytes - 1; i >= 0; --i) {
31977c42e80SAllen Martin din[i] = tmpdin & 0xff;
32077c42e80SAllen Martin tmpdin >>= 8;
32177c42e80SAllen Martin }
32277c42e80SAllen Martin din += bytes;
32377c42e80SAllen Martin }
32460acde43SYen Lin
32560acde43SYen Lin /* We can exit when we've had both RX and TX */
32660acde43SYen Lin break;
32777c42e80SAllen Martin }
32877c42e80SAllen Martin }
32977c42e80SAllen Martin
33077c42e80SAllen Martin if (tm >= SPI_TIMEOUT)
33177c42e80SAllen Martin ret = tm;
33277c42e80SAllen Martin
33377c42e80SAllen Martin /* clear ACK RDY, etc. bits */
33477c42e80SAllen Martin writel(readl(®s->fifo_status), ®s->fifo_status);
33577c42e80SAllen Martin }
33677c42e80SAllen Martin
33777c42e80SAllen Martin if (flags & SPI_XFER_END)
338fda6fac3SSimon Glass spi_cs_deactivate(dev);
33977c42e80SAllen Martin
34077c42e80SAllen Martin debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
34177c42e80SAllen Martin __func__, tmpdin, readl(®s->fifo_status));
34277c42e80SAllen Martin
34377c42e80SAllen Martin if (ret) {
34477c42e80SAllen Martin printf("%s: timeout during SPI transfer, tm %d\n",
34577c42e80SAllen Martin __func__, ret);
34677c42e80SAllen Martin return -1;
34777c42e80SAllen Martin }
34877c42e80SAllen Martin
349fda6fac3SSimon Glass return ret;
350fda6fac3SSimon Glass }
351fda6fac3SSimon Glass
tegra114_spi_set_speed(struct udevice * bus,uint speed)352fda6fac3SSimon Glass static int tegra114_spi_set_speed(struct udevice *bus, uint speed)
353fda6fac3SSimon Glass {
354fda6fac3SSimon Glass struct tegra_spi_platdata *plat = bus->platdata;
355fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
356fda6fac3SSimon Glass
357fda6fac3SSimon Glass if (speed > plat->frequency)
358fda6fac3SSimon Glass speed = plat->frequency;
359fda6fac3SSimon Glass priv->freq = speed;
360fda6fac3SSimon Glass debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
361fda6fac3SSimon Glass
36277c42e80SAllen Martin return 0;
36377c42e80SAllen Martin }
364fda6fac3SSimon Glass
tegra114_spi_set_mode(struct udevice * bus,uint mode)365fda6fac3SSimon Glass static int tegra114_spi_set_mode(struct udevice *bus, uint mode)
366fda6fac3SSimon Glass {
367fda6fac3SSimon Glass struct tegra114_spi_priv *priv = dev_get_priv(bus);
368fda6fac3SSimon Glass
369fda6fac3SSimon Glass priv->mode = mode;
370fda6fac3SSimon Glass debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
371fda6fac3SSimon Glass
372fda6fac3SSimon Glass return 0;
373fda6fac3SSimon Glass }
374fda6fac3SSimon Glass
375fda6fac3SSimon Glass static const struct dm_spi_ops tegra114_spi_ops = {
376fda6fac3SSimon Glass .xfer = tegra114_spi_xfer,
377fda6fac3SSimon Glass .set_speed = tegra114_spi_set_speed,
378fda6fac3SSimon Glass .set_mode = tegra114_spi_set_mode,
379fda6fac3SSimon Glass /*
380fda6fac3SSimon Glass * cs_info is not needed, since we require all chip selects to be
381fda6fac3SSimon Glass * in the device tree explicitly
382fda6fac3SSimon Glass */
383fda6fac3SSimon Glass };
384fda6fac3SSimon Glass
385fda6fac3SSimon Glass static const struct udevice_id tegra114_spi_ids[] = {
386fda6fac3SSimon Glass { .compatible = "nvidia,tegra114-spi" },
387fda6fac3SSimon Glass { }
388fda6fac3SSimon Glass };
389fda6fac3SSimon Glass
390fda6fac3SSimon Glass U_BOOT_DRIVER(tegra114_spi) = {
391fda6fac3SSimon Glass .name = "tegra114_spi",
392fda6fac3SSimon Glass .id = UCLASS_SPI,
393fda6fac3SSimon Glass .of_match = tegra114_spi_ids,
394fda6fac3SSimon Glass .ops = &tegra114_spi_ops,
395fda6fac3SSimon Glass .ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
396fda6fac3SSimon Glass .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
397fda6fac3SSimon Glass .priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
398fda6fac3SSimon Glass .probe = tegra114_spi_probe,
399fda6fac3SSimon Glass };
400