11bf43b82SRajeshwari Shinde /*
21bf43b82SRajeshwari Shinde * (C) Copyright 2012 SAMSUNG Electronics
31bf43b82SRajeshwari Shinde * Padmavathi Venna <padma.v@samsung.com>
41bf43b82SRajeshwari Shinde *
51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
61bf43b82SRajeshwari Shinde */
71bf43b82SRajeshwari Shinde
81bf43b82SRajeshwari Shinde #include <common.h>
973186c94SSimon Glass #include <dm.h>
1073186c94SSimon Glass #include <errno.h>
111bf43b82SRajeshwari Shinde #include <malloc.h>
121bf43b82SRajeshwari Shinde #include <spi.h>
134d3acb9dSRajeshwari Shinde #include <fdtdec.h>
141bf43b82SRajeshwari Shinde #include <asm/arch/clk.h>
151bf43b82SRajeshwari Shinde #include <asm/arch/clock.h>
161bf43b82SRajeshwari Shinde #include <asm/arch/cpu.h>
171bf43b82SRajeshwari Shinde #include <asm/arch/gpio.h>
181bf43b82SRajeshwari Shinde #include <asm/arch/pinmux.h>
1977b55e8cSThomas Abraham #include <asm/arch/spi.h>
201bf43b82SRajeshwari Shinde #include <asm/io.h>
211bf43b82SRajeshwari Shinde
224d3acb9dSRajeshwari Shinde DECLARE_GLOBAL_DATA_PTR;
234d3acb9dSRajeshwari Shinde
2473186c94SSimon Glass struct exynos_spi_platdata {
251bf43b82SRajeshwari Shinde enum periph_id periph_id;
261bf43b82SRajeshwari Shinde s32 frequency; /* Default clock frequency, -1 for none */
271bf43b82SRajeshwari Shinde struct exynos_spi *regs;
288d203afdSRajeshwari Shinde uint deactivate_delay_us; /* Delay to wait after deactivate */
291bf43b82SRajeshwari Shinde };
301bf43b82SRajeshwari Shinde
3173186c94SSimon Glass struct exynos_spi_priv {
321bf43b82SRajeshwari Shinde struct exynos_spi *regs;
331bf43b82SRajeshwari Shinde unsigned int freq; /* Default frequency */
341bf43b82SRajeshwari Shinde unsigned int mode;
351bf43b82SRajeshwari Shinde enum periph_id periph_id; /* Peripheral ID for this device */
361bf43b82SRajeshwari Shinde unsigned int fifo_size;
37e4eaef89SRajeshwari Shinde int skip_preamble;
388d203afdSRajeshwari Shinde ulong last_transaction_us; /* Time of last transaction end */
391bf43b82SRajeshwari Shinde };
401bf43b82SRajeshwari Shinde
411bf43b82SRajeshwari Shinde /**
421bf43b82SRajeshwari Shinde * Flush spi tx, rx fifos and reset the SPI controller
431bf43b82SRajeshwari Shinde *
4473186c94SSimon Glass * @param regs Pointer to SPI registers
451bf43b82SRajeshwari Shinde */
spi_flush_fifo(struct exynos_spi * regs)4673186c94SSimon Glass static void spi_flush_fifo(struct exynos_spi *regs)
471bf43b82SRajeshwari Shinde {
481bf43b82SRajeshwari Shinde clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
491bf43b82SRajeshwari Shinde clrbits_le32(®s->ch_cfg, SPI_CH_RST);
501bf43b82SRajeshwari Shinde setbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
511bf43b82SRajeshwari Shinde }
521bf43b82SRajeshwari Shinde
spi_get_fifo_levels(struct exynos_spi * regs,int * rx_lvl,int * tx_lvl)531bf43b82SRajeshwari Shinde static void spi_get_fifo_levels(struct exynos_spi *regs,
541bf43b82SRajeshwari Shinde int *rx_lvl, int *tx_lvl)
551bf43b82SRajeshwari Shinde {
561bf43b82SRajeshwari Shinde uint32_t spi_sts = readl(®s->spi_sts);
571bf43b82SRajeshwari Shinde
581bf43b82SRajeshwari Shinde *rx_lvl = (spi_sts >> SPI_RX_LVL_OFFSET) & SPI_FIFO_LVL_MASK;
591bf43b82SRajeshwari Shinde *tx_lvl = (spi_sts >> SPI_TX_LVL_OFFSET) & SPI_FIFO_LVL_MASK;
601bf43b82SRajeshwari Shinde }
611bf43b82SRajeshwari Shinde
621bf43b82SRajeshwari Shinde /**
631bf43b82SRajeshwari Shinde * If there's something to transfer, do a software reset and set a
641bf43b82SRajeshwari Shinde * transaction size.
651bf43b82SRajeshwari Shinde *
661bf43b82SRajeshwari Shinde * @param regs SPI peripheral registers
671bf43b82SRajeshwari Shinde * @param count Number of bytes to transfer
68c4a79632SRajeshwari Shinde * @param step Number of bytes to transfer in each packet (1 or 4)
691bf43b82SRajeshwari Shinde */
spi_request_bytes(struct exynos_spi * regs,int count,int step)70c4a79632SRajeshwari Shinde static void spi_request_bytes(struct exynos_spi *regs, int count, int step)
711bf43b82SRajeshwari Shinde {
7273186c94SSimon Glass debug("%s: regs=%p, count=%d, step=%d\n", __func__, regs, count, step);
7373186c94SSimon Glass
74c4a79632SRajeshwari Shinde /* For word address we need to swap bytes */
75c4a79632SRajeshwari Shinde if (step == 4) {
76c4a79632SRajeshwari Shinde setbits_le32(®s->mode_cfg,
77c4a79632SRajeshwari Shinde SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
78c4a79632SRajeshwari Shinde count /= 4;
79c4a79632SRajeshwari Shinde setbits_le32(®s->swap_cfg, SPI_TX_SWAP_EN | SPI_RX_SWAP_EN |
80c4a79632SRajeshwari Shinde SPI_TX_BYTE_SWAP | SPI_RX_BYTE_SWAP |
81c4a79632SRajeshwari Shinde SPI_TX_HWORD_SWAP | SPI_RX_HWORD_SWAP);
82c4a79632SRajeshwari Shinde } else {
83c4a79632SRajeshwari Shinde /* Select byte access and clear the swap configuration */
84c4a79632SRajeshwari Shinde clrbits_le32(®s->mode_cfg,
85c4a79632SRajeshwari Shinde SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
86c4a79632SRajeshwari Shinde writel(0, ®s->swap_cfg);
87c4a79632SRajeshwari Shinde }
88c4a79632SRajeshwari Shinde
891bf43b82SRajeshwari Shinde assert(count && count < (1 << 16));
901bf43b82SRajeshwari Shinde setbits_le32(®s->ch_cfg, SPI_CH_RST);
911bf43b82SRajeshwari Shinde clrbits_le32(®s->ch_cfg, SPI_CH_RST);
92c4a79632SRajeshwari Shinde
931bf43b82SRajeshwari Shinde writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
941bf43b82SRajeshwari Shinde }
951bf43b82SRajeshwari Shinde
spi_rx_tx(struct exynos_spi_priv * priv,int todo,void ** dinp,void const ** doutp,unsigned long flags)9673186c94SSimon Glass static int spi_rx_tx(struct exynos_spi_priv *priv, int todo,
97e4eaef89SRajeshwari Shinde void **dinp, void const **doutp, unsigned long flags)
981bf43b82SRajeshwari Shinde {
9973186c94SSimon Glass struct exynos_spi *regs = priv->regs;
1001bf43b82SRajeshwari Shinde uchar *rxp = *dinp;
1011bf43b82SRajeshwari Shinde const uchar *txp = *doutp;
1021bf43b82SRajeshwari Shinde int rx_lvl, tx_lvl;
1031bf43b82SRajeshwari Shinde uint out_bytes, in_bytes;
104e4eaef89SRajeshwari Shinde int toread;
105e4eaef89SRajeshwari Shinde unsigned start = get_timer(0);
106e4eaef89SRajeshwari Shinde int stopping;
107c4a79632SRajeshwari Shinde int step;
1081bf43b82SRajeshwari Shinde
1091bf43b82SRajeshwari Shinde out_bytes = in_bytes = todo;
1101bf43b82SRajeshwari Shinde
11173186c94SSimon Glass stopping = priv->skip_preamble && (flags & SPI_XFER_END) &&
11273186c94SSimon Glass !(priv->mode & SPI_SLAVE);
113e4eaef89SRajeshwari Shinde
1141bf43b82SRajeshwari Shinde /*
115c4a79632SRajeshwari Shinde * Try to transfer words if we can. This helps read performance at
116c4a79632SRajeshwari Shinde * SPI clock speeds above about 20MHz.
117c4a79632SRajeshwari Shinde */
118c4a79632SRajeshwari Shinde step = 1;
119c4a79632SRajeshwari Shinde if (!((todo | (uintptr_t)rxp | (uintptr_t)txp) & 3) &&
12073186c94SSimon Glass !priv->skip_preamble)
121c4a79632SRajeshwari Shinde step = 4;
122c4a79632SRajeshwari Shinde
123c4a79632SRajeshwari Shinde /*
1241bf43b82SRajeshwari Shinde * If there's something to send, do a software reset and set a
1251bf43b82SRajeshwari Shinde * transaction size.
1261bf43b82SRajeshwari Shinde */
127c4a79632SRajeshwari Shinde spi_request_bytes(regs, todo, step);
1281bf43b82SRajeshwari Shinde
1291bf43b82SRajeshwari Shinde /*
1301bf43b82SRajeshwari Shinde * Bytes are transmitted/received in pairs. Wait to receive all the
1311bf43b82SRajeshwari Shinde * data because then transmission will be done as well.
1321bf43b82SRajeshwari Shinde */
133e4eaef89SRajeshwari Shinde toread = in_bytes;
134e4eaef89SRajeshwari Shinde
1351bf43b82SRajeshwari Shinde while (in_bytes) {
1361bf43b82SRajeshwari Shinde int temp;
1371bf43b82SRajeshwari Shinde
1381bf43b82SRajeshwari Shinde /* Keep the fifos full/empty. */
1391bf43b82SRajeshwari Shinde spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl);
140c4a79632SRajeshwari Shinde
141c4a79632SRajeshwari Shinde /*
142c4a79632SRajeshwari Shinde * Don't completely fill the txfifo, since we don't want our
143c4a79632SRajeshwari Shinde * rxfifo to overflow, and it may already contain data.
144c4a79632SRajeshwari Shinde */
14573186c94SSimon Glass while (tx_lvl < priv->fifo_size/2 && out_bytes) {
146c4a79632SRajeshwari Shinde if (!txp)
147c4a79632SRajeshwari Shinde temp = -1;
148c4a79632SRajeshwari Shinde else if (step == 4)
149c4a79632SRajeshwari Shinde temp = *(uint32_t *)txp;
150c4a79632SRajeshwari Shinde else
151c4a79632SRajeshwari Shinde temp = *txp;
1521bf43b82SRajeshwari Shinde writel(temp, ®s->tx_data);
153c4a79632SRajeshwari Shinde out_bytes -= step;
154c4a79632SRajeshwari Shinde if (txp)
155c4a79632SRajeshwari Shinde txp += step;
156c4a79632SRajeshwari Shinde tx_lvl += step;
1571bf43b82SRajeshwari Shinde }
158c4a79632SRajeshwari Shinde if (rx_lvl >= step) {
159c4a79632SRajeshwari Shinde while (rx_lvl >= step) {
1601bf43b82SRajeshwari Shinde temp = readl(®s->rx_data);
16173186c94SSimon Glass if (priv->skip_preamble) {
162e4eaef89SRajeshwari Shinde if (temp == SPI_PREAMBLE_END_BYTE) {
16373186c94SSimon Glass priv->skip_preamble = 0;
164e4eaef89SRajeshwari Shinde stopping = 0;
165e4eaef89SRajeshwari Shinde }
166e4eaef89SRajeshwari Shinde } else {
167c4a79632SRajeshwari Shinde if (rxp || stopping) {
168e76d2a81SAkshay Saraswat if (step == 4)
169e76d2a81SAkshay Saraswat *(uint32_t *)rxp = temp;
170e76d2a81SAkshay Saraswat else
171c4a79632SRajeshwari Shinde *rxp = temp;
172c4a79632SRajeshwari Shinde rxp += step;
1731bf43b82SRajeshwari Shinde }
174c4a79632SRajeshwari Shinde in_bytes -= step;
175c4a79632SRajeshwari Shinde }
176c4a79632SRajeshwari Shinde toread -= step;
177c4a79632SRajeshwari Shinde rx_lvl -= step;
178c4a79632SRajeshwari Shinde }
179e4eaef89SRajeshwari Shinde } else if (!toread) {
180e4eaef89SRajeshwari Shinde /*
181e4eaef89SRajeshwari Shinde * We have run out of input data, but haven't read
182e4eaef89SRajeshwari Shinde * enough bytes after the preamble yet. Read some more,
183e4eaef89SRajeshwari Shinde * and make sure that we transmit dummy bytes too, to
184e4eaef89SRajeshwari Shinde * keep things going.
185e4eaef89SRajeshwari Shinde */
186e4eaef89SRajeshwari Shinde assert(!out_bytes);
187e4eaef89SRajeshwari Shinde out_bytes = in_bytes;
188e4eaef89SRajeshwari Shinde toread = in_bytes;
189e4eaef89SRajeshwari Shinde txp = NULL;
190c4a79632SRajeshwari Shinde spi_request_bytes(regs, toread, step);
1911bf43b82SRajeshwari Shinde }
19273186c94SSimon Glass if (priv->skip_preamble && get_timer(start) > 100) {
193c7d50e7fSSimon Glass debug("SPI timeout: in_bytes=%d, out_bytes=%d, ",
194e4eaef89SRajeshwari Shinde in_bytes, out_bytes);
195c7d50e7fSSimon Glass return -ETIMEDOUT;
196e4eaef89SRajeshwari Shinde }
197e4eaef89SRajeshwari Shinde }
198e4eaef89SRajeshwari Shinde
1991bf43b82SRajeshwari Shinde *dinp = rxp;
2001bf43b82SRajeshwari Shinde *doutp = txp;
201e4eaef89SRajeshwari Shinde
202e4eaef89SRajeshwari Shinde return 0;
2031bf43b82SRajeshwari Shinde }
2041bf43b82SRajeshwari Shinde
2051bf43b82SRajeshwari Shinde /**
20673186c94SSimon Glass * Activate the CS by driving it LOW
2071bf43b82SRajeshwari Shinde *
2081bf43b82SRajeshwari Shinde * @param slave Pointer to spi_slave to which controller has to
2091bf43b82SRajeshwari Shinde * communicate with
2101bf43b82SRajeshwari Shinde */
spi_cs_activate(struct udevice * dev)21173186c94SSimon Glass static void spi_cs_activate(struct udevice *dev)
2121bf43b82SRajeshwari Shinde {
21373186c94SSimon Glass struct udevice *bus = dev->parent;
21473186c94SSimon Glass struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
21573186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
21673186c94SSimon Glass
21773186c94SSimon Glass /* If it's too soon to do another transaction, wait */
21873186c94SSimon Glass if (pdata->deactivate_delay_us &&
21973186c94SSimon Glass priv->last_transaction_us) {
22073186c94SSimon Glass ulong delay_us; /* The delay completed so far */
22173186c94SSimon Glass delay_us = timer_get_us() - priv->last_transaction_us;
22273186c94SSimon Glass if (delay_us < pdata->deactivate_delay_us)
22373186c94SSimon Glass udelay(pdata->deactivate_delay_us - delay_us);
22473186c94SSimon Glass }
22573186c94SSimon Glass
22673186c94SSimon Glass clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
22773186c94SSimon Glass debug("Activate CS, bus '%s'\n", bus->name);
22873186c94SSimon Glass priv->skip_preamble = priv->mode & SPI_PREAMBLE;
22973186c94SSimon Glass }
23073186c94SSimon Glass
23173186c94SSimon Glass /**
23273186c94SSimon Glass * Deactivate the CS by driving it HIGH
23373186c94SSimon Glass *
23473186c94SSimon Glass * @param slave Pointer to spi_slave to which controller has to
23573186c94SSimon Glass * communicate with
23673186c94SSimon Glass */
spi_cs_deactivate(struct udevice * dev)23773186c94SSimon Glass static void spi_cs_deactivate(struct udevice *dev)
23873186c94SSimon Glass {
23973186c94SSimon Glass struct udevice *bus = dev->parent;
24073186c94SSimon Glass struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
24173186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
24273186c94SSimon Glass
24373186c94SSimon Glass setbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
24473186c94SSimon Glass
24573186c94SSimon Glass /* Remember time of this transaction so we can honour the bus delay */
24673186c94SSimon Glass if (pdata->deactivate_delay_us)
24773186c94SSimon Glass priv->last_transaction_us = timer_get_us();
24873186c94SSimon Glass
24973186c94SSimon Glass debug("Deactivate CS, bus '%s'\n", bus->name);
25073186c94SSimon Glass }
25173186c94SSimon Glass
exynos_spi_ofdata_to_platdata(struct udevice * bus)25273186c94SSimon Glass static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
25373186c94SSimon Glass {
25473186c94SSimon Glass struct exynos_spi_platdata *plat = bus->platdata;
25573186c94SSimon Glass const void *blob = gd->fdt_blob;
256e160f7d4SSimon Glass int node = dev_of_offset(bus);
25773186c94SSimon Glass
258*a821c4afSSimon Glass plat->regs = (struct exynos_spi *)devfdt_get_addr(bus);
25973186c94SSimon Glass plat->periph_id = pinmux_decode_periph_id(blob, node);
26073186c94SSimon Glass
26173186c94SSimon Glass if (plat->periph_id == PERIPH_ID_NONE) {
26273186c94SSimon Glass debug("%s: Invalid peripheral ID %d\n", __func__,
26373186c94SSimon Glass plat->periph_id);
26473186c94SSimon Glass return -FDT_ERR_NOTFOUND;
26573186c94SSimon Glass }
26673186c94SSimon Glass
26773186c94SSimon Glass /* Use 500KHz as a suitable default */
26873186c94SSimon Glass plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
26973186c94SSimon Glass 500000);
27073186c94SSimon Glass plat->deactivate_delay_us = fdtdec_get_int(blob, node,
27173186c94SSimon Glass "spi-deactivate-delay", 0);
27273186c94SSimon Glass debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
27373186c94SSimon Glass __func__, plat->regs, plat->periph_id, plat->frequency,
27473186c94SSimon Glass plat->deactivate_delay_us);
27573186c94SSimon Glass
27673186c94SSimon Glass return 0;
27773186c94SSimon Glass }
27873186c94SSimon Glass
exynos_spi_probe(struct udevice * bus)27973186c94SSimon Glass static int exynos_spi_probe(struct udevice *bus)
28073186c94SSimon Glass {
28173186c94SSimon Glass struct exynos_spi_platdata *plat = dev_get_platdata(bus);
28273186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
28373186c94SSimon Glass
28473186c94SSimon Glass priv->regs = plat->regs;
28573186c94SSimon Glass if (plat->periph_id == PERIPH_ID_SPI1 ||
28673186c94SSimon Glass plat->periph_id == PERIPH_ID_SPI2)
28773186c94SSimon Glass priv->fifo_size = 64;
28873186c94SSimon Glass else
28973186c94SSimon Glass priv->fifo_size = 256;
29073186c94SSimon Glass
29173186c94SSimon Glass priv->skip_preamble = 0;
29273186c94SSimon Glass priv->last_transaction_us = timer_get_us();
29373186c94SSimon Glass priv->freq = plat->frequency;
29473186c94SSimon Glass priv->periph_id = plat->periph_id;
29573186c94SSimon Glass
29673186c94SSimon Glass return 0;
29773186c94SSimon Glass }
29873186c94SSimon Glass
exynos_spi_claim_bus(struct udevice * dev)2999694b724SSimon Glass static int exynos_spi_claim_bus(struct udevice *dev)
30073186c94SSimon Glass {
3019694b724SSimon Glass struct udevice *bus = dev->parent;
30273186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
30373186c94SSimon Glass
30473186c94SSimon Glass exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
30573186c94SSimon Glass spi_flush_fifo(priv->regs);
30673186c94SSimon Glass
30773186c94SSimon Glass writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
30873186c94SSimon Glass
30973186c94SSimon Glass return 0;
31073186c94SSimon Glass }
31173186c94SSimon Glass
exynos_spi_release_bus(struct udevice * dev)3129694b724SSimon Glass static int exynos_spi_release_bus(struct udevice *dev)
31373186c94SSimon Glass {
3149694b724SSimon Glass struct udevice *bus = dev->parent;
31573186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
31673186c94SSimon Glass
31773186c94SSimon Glass spi_flush_fifo(priv->regs);
31873186c94SSimon Glass
31973186c94SSimon Glass return 0;
32073186c94SSimon Glass }
32173186c94SSimon Glass
exynos_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)32273186c94SSimon Glass static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
32373186c94SSimon Glass const void *dout, void *din, unsigned long flags)
32473186c94SSimon Glass {
32573186c94SSimon Glass struct udevice *bus = dev->parent;
32673186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
3271bf43b82SRajeshwari Shinde int upto, todo;
3281bf43b82SRajeshwari Shinde int bytelen;
329e4eaef89SRajeshwari Shinde int ret = 0;
3301bf43b82SRajeshwari Shinde
3311bf43b82SRajeshwari Shinde /* spi core configured to do 8 bit transfers */
3321bf43b82SRajeshwari Shinde if (bitlen % 8) {
3331bf43b82SRajeshwari Shinde debug("Non byte aligned SPI transfer.\n");
3341bf43b82SRajeshwari Shinde return -1;
3351bf43b82SRajeshwari Shinde }
3361bf43b82SRajeshwari Shinde
3371bf43b82SRajeshwari Shinde /* Start the transaction, if necessary. */
3381bf43b82SRajeshwari Shinde if ((flags & SPI_XFER_BEGIN))
33973186c94SSimon Glass spi_cs_activate(dev);
3401bf43b82SRajeshwari Shinde
341c4a79632SRajeshwari Shinde /*
342c4a79632SRajeshwari Shinde * Exynos SPI limits each transfer to 65535 transfers. To keep
343c4a79632SRajeshwari Shinde * things simple, allow a maximum of 65532 bytes. We could allow
344c4a79632SRajeshwari Shinde * more in word mode, but the performance difference is small.
345c4a79632SRajeshwari Shinde */
3461bf43b82SRajeshwari Shinde bytelen = bitlen / 8;
347e4eaef89SRajeshwari Shinde for (upto = 0; !ret && upto < bytelen; upto += todo) {
348c4a79632SRajeshwari Shinde todo = min(bytelen - upto, (1 << 16) - 4);
34973186c94SSimon Glass ret = spi_rx_tx(priv, todo, &din, &dout, flags);
350e4eaef89SRajeshwari Shinde if (ret)
351e4eaef89SRajeshwari Shinde break;
3521bf43b82SRajeshwari Shinde }
3531bf43b82SRajeshwari Shinde
3541bf43b82SRajeshwari Shinde /* Stop the transaction, if necessary. */
35573186c94SSimon Glass if ((flags & SPI_XFER_END) && !(priv->mode & SPI_SLAVE)) {
35673186c94SSimon Glass spi_cs_deactivate(dev);
35773186c94SSimon Glass if (priv->skip_preamble) {
35873186c94SSimon Glass assert(!priv->skip_preamble);
359e4eaef89SRajeshwari Shinde debug("Failed to complete premable transaction\n");
360e4eaef89SRajeshwari Shinde ret = -1;
361e4eaef89SRajeshwari Shinde }
362e4eaef89SRajeshwari Shinde }
3631bf43b82SRajeshwari Shinde
364e4eaef89SRajeshwari Shinde return ret;
3651bf43b82SRajeshwari Shinde }
3661bf43b82SRajeshwari Shinde
exynos_spi_set_speed(struct udevice * bus,uint speed)36773186c94SSimon Glass static int exynos_spi_set_speed(struct udevice *bus, uint speed)
3681bf43b82SRajeshwari Shinde {
36973186c94SSimon Glass struct exynos_spi_platdata *plat = bus->platdata;
37073186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
37173186c94SSimon Glass int ret;
3721bf43b82SRajeshwari Shinde
37373186c94SSimon Glass if (speed > plat->frequency)
37473186c94SSimon Glass speed = plat->frequency;
37573186c94SSimon Glass ret = set_spi_clk(priv->periph_id, speed);
37673186c94SSimon Glass if (ret)
37773186c94SSimon Glass return ret;
37873186c94SSimon Glass priv->freq = speed;
37973186c94SSimon Glass debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
3804d3acb9dSRajeshwari Shinde
3814d3acb9dSRajeshwari Shinde return 0;
3824d3acb9dSRajeshwari Shinde }
3834d3acb9dSRajeshwari Shinde
exynos_spi_set_mode(struct udevice * bus,uint mode)38473186c94SSimon Glass static int exynos_spi_set_mode(struct udevice *bus, uint mode)
3854d3acb9dSRajeshwari Shinde {
38673186c94SSimon Glass struct exynos_spi_priv *priv = dev_get_priv(bus);
38773186c94SSimon Glass uint32_t reg;
3884d3acb9dSRajeshwari Shinde
38973186c94SSimon Glass reg = readl(&priv->regs->ch_cfg);
39073186c94SSimon Glass reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
3914d3acb9dSRajeshwari Shinde
39273186c94SSimon Glass if (mode & SPI_CPHA)
39373186c94SSimon Glass reg |= SPI_CH_CPHA_B;
3944d3acb9dSRajeshwari Shinde
39573186c94SSimon Glass if (mode & SPI_CPOL)
39673186c94SSimon Glass reg |= SPI_CH_CPOL_L;
3974d3acb9dSRajeshwari Shinde
39873186c94SSimon Glass writel(reg, &priv->regs->ch_cfg);
39973186c94SSimon Glass priv->mode = mode;
40073186c94SSimon Glass debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
4014d3acb9dSRajeshwari Shinde
4024d3acb9dSRajeshwari Shinde return 0;
4034d3acb9dSRajeshwari Shinde }
4044d3acb9dSRajeshwari Shinde
40573186c94SSimon Glass static const struct dm_spi_ops exynos_spi_ops = {
40673186c94SSimon Glass .claim_bus = exynos_spi_claim_bus,
40773186c94SSimon Glass .release_bus = exynos_spi_release_bus,
40873186c94SSimon Glass .xfer = exynos_spi_xfer,
40973186c94SSimon Glass .set_speed = exynos_spi_set_speed,
41073186c94SSimon Glass .set_mode = exynos_spi_set_mode,
41173186c94SSimon Glass /*
41273186c94SSimon Glass * cs_info is not needed, since we require all chip selects to be
41373186c94SSimon Glass * in the device tree explicitly
414f3424c55SHung-ying Tyan */
41573186c94SSimon Glass };
416f3424c55SHung-ying Tyan
41773186c94SSimon Glass static const struct udevice_id exynos_spi_ids[] = {
41873186c94SSimon Glass { .compatible = "samsung,exynos-spi" },
41973186c94SSimon Glass { }
42073186c94SSimon Glass };
421f3424c55SHung-ying Tyan
42273186c94SSimon Glass U_BOOT_DRIVER(exynos_spi) = {
42373186c94SSimon Glass .name = "exynos_spi",
42473186c94SSimon Glass .id = UCLASS_SPI,
42573186c94SSimon Glass .of_match = exynos_spi_ids,
42673186c94SSimon Glass .ops = &exynos_spi_ops,
42773186c94SSimon Glass .ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
42873186c94SSimon Glass .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
42973186c94SSimon Glass .priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
43073186c94SSimon Glass .probe = exynos_spi_probe,
43173186c94SSimon Glass };
432