xref: /rk3399_rockchip-uboot/drivers/spi/exynos_spi.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
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(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
491bf43b82SRajeshwari Shinde 	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
501bf43b82SRajeshwari Shinde 	setbits_le32(&regs->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(&regs->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(&regs->mode_cfg,
77c4a79632SRajeshwari Shinde 			     SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
78c4a79632SRajeshwari Shinde 		count /= 4;
79c4a79632SRajeshwari Shinde 		setbits_le32(&regs->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(&regs->mode_cfg,
85c4a79632SRajeshwari Shinde 			     SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
86c4a79632SRajeshwari Shinde 		writel(0, &regs->swap_cfg);
87c4a79632SRajeshwari Shinde 	}
88c4a79632SRajeshwari Shinde 
891bf43b82SRajeshwari Shinde 	assert(count && count < (1 << 16));
901bf43b82SRajeshwari Shinde 	setbits_le32(&regs->ch_cfg, SPI_CH_RST);
911bf43b82SRajeshwari Shinde 	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
92c4a79632SRajeshwari Shinde 
931bf43b82SRajeshwari Shinde 	writel(count | SPI_PACKET_CNT_EN, &regs->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, &regs->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(&regs->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