blob: ad9e490faa9f0475542682615c2cdbcb2cbcde5d [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasut7f8a5582011-11-08 23:18:14 +00002/*
3 * Freescale i.MX28 SPI driver
4 *
Lukasz Majewski5faaf092019-06-19 17:31:07 +02005 * Copyright (C) 2019 DENX Software Engineering
6 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
7 *
Marek Vasut7f8a5582011-11-08 23:18:14 +00008 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
9 * on behalf of DENX Software Engineering GmbH
10 *
Marek Vasut7f8a5582011-11-08 23:18:14 +000011 * NOTE: This driver only supports the SPI-controller chipselects,
12 * GPIO driven chipselects are not supported.
13 */
14
Jagan Tekib4669c42020-05-25 23:31:59 +053015#include <dm.h>
16#include <dt-structs.h>
Simon Glass63334482019-11-14 12:57:39 -070017#include <cpu_func.h>
Jagan Tekib4669c42020-05-25 23:31:59 +053018#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060019#include <log.h>
Marek Vasut7f8a5582011-11-08 23:18:14 +000020#include <malloc.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060021#include <memalign.h>
Marek Vasut7f8a5582011-11-08 23:18:14 +000022#include <spi.h>
Simon Glass274e0b02020-05-10 11:39:56 -060023#include <asm/cache.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060024#include <linux/bitops.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090025#include <linux/errno.h>
Marek Vasut7f8a5582011-11-08 23:18:14 +000026#include <asm/io.h>
27#include <asm/arch/clock.h>
28#include <asm/arch/imx-regs.h>
29#include <asm/arch/sys_proto.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020030#include <asm/mach-imx/dma.h>
Marek Vasut7f8a5582011-11-08 23:18:14 +000031
32#define MXS_SPI_MAX_TIMEOUT 1000000
33#define MXS_SPI_PORT_OFFSET 0x2000
Fabio Estevamd7bc6b02012-04-23 08:30:50 +000034#define MXS_SSP_CHIPSELECT_MASK 0x00300000
35#define MXS_SSP_CHIPSELECT_SHIFT 20
Marek Vasut7f8a5582011-11-08 23:18:14 +000036
Marek Vasut23697f62012-07-09 00:48:33 +000037#define MXSSSP_SMALL_TRANSFER 512
38
Jagan Tekib4669c42020-05-25 23:31:59 +053039/* Base numbers of i.MX2[38] clk for ssp0 IP block */
40#define MXS_SSP_IMX23_CLKID_SSP0 33
41#define MXS_SSP_IMX28_CLKID_SSP0 46
Lukasz Majewski6be06562019-09-05 09:54:58 +020042
Simon Glassb75b15b2020-12-03 16:55:23 -070043struct mxs_spi_plat {
Lukasz Majewski6be06562019-09-05 09:54:58 +020044#if CONFIG_IS_ENABLED(OF_PLATDATA)
Walter Lozano69358932020-07-23 00:22:04 -030045 struct dtd_fsl_imx23_spi dtplat;
Lukasz Majewski6be06562019-09-05 09:54:58 +020046#endif
Lukasz Majewski5faaf092019-06-19 17:31:07 +020047 s32 frequency; /* Default clock frequency, -1 for none */
48 fdt_addr_t base; /* SPI IP block base address */
49 int num_cs; /* Number of CSes supported */
50 int dma_id; /* ID of the DMA channel */
51 int clk_id; /* ID of the SSP clock */
52};
Marek Vasut7f8a5582011-11-08 23:18:14 +000053
Lukasz Majewski5faaf092019-06-19 17:31:07 +020054struct mxs_spi_priv {
55 struct mxs_ssp_regs *regs;
56 unsigned int dma_channel;
57 unsigned int max_freq;
58 unsigned int clk_id;
59 unsigned int mode;
60};
Marek Vasut7f8a5582011-11-08 23:18:14 +000061
Jagan Tekib4669c42020-05-25 23:31:59 +053062static void mxs_spi_start_xfer(struct mxs_ssp_regs *ssp_regs)
63{
64 writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_set);
65 writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_clr);
66}
67
68static void mxs_spi_end_xfer(struct mxs_ssp_regs *ssp_regs)
69{
70 writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_clr);
71 writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_set);
72}
73
Lukasz Majewski5faaf092019-06-19 17:31:07 +020074static int mxs_spi_xfer_pio(struct mxs_spi_priv *priv,
75 char *data, int length, int write,
76 unsigned long flags)
77{
78 struct mxs_ssp_regs *ssp_regs = priv->regs;
Marek Vasut955d92f2012-07-09 00:48:31 +000079
Marek Vasut7f8a5582011-11-08 23:18:14 +000080 if (flags & SPI_XFER_BEGIN)
81 mxs_spi_start_xfer(ssp_regs);
82
Marek Vasut036b7bd2012-07-09 00:48:32 +000083 while (length--) {
Marek Vasut7f8a5582011-11-08 23:18:14 +000084 /* We transfer 1 byte */
Marek Vasutbf372e32013-02-23 02:42:59 +000085#if defined(CONFIG_MX23)
86 writel(SSP_CTRL0_XFER_COUNT_MASK, &ssp_regs->hw_ssp_ctrl0_clr);
87 writel(1, &ssp_regs->hw_ssp_ctrl0_set);
88#elif defined(CONFIG_MX28)
Marek Vasut7f8a5582011-11-08 23:18:14 +000089 writel(1, &ssp_regs->hw_ssp_xfer_size);
Marek Vasutbf372e32013-02-23 02:42:59 +000090#endif
Marek Vasut7f8a5582011-11-08 23:18:14 +000091
Marek Vasut036b7bd2012-07-09 00:48:32 +000092 if ((flags & SPI_XFER_END) && !length)
Marek Vasut7f8a5582011-11-08 23:18:14 +000093 mxs_spi_end_xfer(ssp_regs);
94
Marek Vasut955d92f2012-07-09 00:48:31 +000095 if (write)
Marek Vasut7f8a5582011-11-08 23:18:14 +000096 writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_clr);
97 else
98 writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_set);
99
100 writel(SSP_CTRL0_RUN, &ssp_regs->hw_ssp_ctrl0_set);
101
Otavio Salvadorcbf0bf22012-08-13 09:53:12 +0000102 if (mxs_wait_mask_set(&ssp_regs->hw_ssp_ctrl0_reg,
Marek Vasut7f8a5582011-11-08 23:18:14 +0000103 SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
104 printf("MXS SPI: Timeout waiting for start\n");
Fabio Estevam8e57ca22012-03-18 17:23:35 +0000105 return -ETIMEDOUT;
Marek Vasut7f8a5582011-11-08 23:18:14 +0000106 }
107
Marek Vasut955d92f2012-07-09 00:48:31 +0000108 if (write)
109 writel(*data++, &ssp_regs->hw_ssp_data);
Marek Vasut7f8a5582011-11-08 23:18:14 +0000110
111 writel(SSP_CTRL0_DATA_XFER, &ssp_regs->hw_ssp_ctrl0_set);
112
Marek Vasut955d92f2012-07-09 00:48:31 +0000113 if (!write) {
Otavio Salvadorcbf0bf22012-08-13 09:53:12 +0000114 if (mxs_wait_mask_clr(&ssp_regs->hw_ssp_status_reg,
Marek Vasut7f8a5582011-11-08 23:18:14 +0000115 SSP_STATUS_FIFO_EMPTY, MXS_SPI_MAX_TIMEOUT)) {
116 printf("MXS SPI: Timeout waiting for data\n");
Fabio Estevam8e57ca22012-03-18 17:23:35 +0000117 return -ETIMEDOUT;
Marek Vasut7f8a5582011-11-08 23:18:14 +0000118 }
119
Marek Vasut955d92f2012-07-09 00:48:31 +0000120 *data = readl(&ssp_regs->hw_ssp_data);
121 data++;
Marek Vasut7f8a5582011-11-08 23:18:14 +0000122 }
123
Otavio Salvadorcbf0bf22012-08-13 09:53:12 +0000124 if (mxs_wait_mask_clr(&ssp_regs->hw_ssp_ctrl0_reg,
Marek Vasut7f8a5582011-11-08 23:18:14 +0000125 SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
126 printf("MXS SPI: Timeout waiting for finish\n");
Fabio Estevam8e57ca22012-03-18 17:23:35 +0000127 return -ETIMEDOUT;
Marek Vasut7f8a5582011-11-08 23:18:14 +0000128 }
129 }
130
131 return 0;
Marek Vasut036b7bd2012-07-09 00:48:32 +0000132}
133
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200134static int mxs_spi_xfer_dma(struct mxs_spi_priv *priv,
135 char *data, int length, int write,
136 unsigned long flags)
137{ struct mxs_ssp_regs *ssp_regs = priv->regs;
Marek Vasut7f4d0142012-08-21 16:17:27 +0000138 const int xfer_max_sz = 0xff00;
139 const int desc_count = DIV_ROUND_UP(length, xfer_max_sz) + 1;
Marek Vasut7f4d0142012-08-21 16:17:27 +0000140 struct mxs_dma_desc *dp;
141 uint32_t ctrl0;
Marek Vasut23697f62012-07-09 00:48:33 +0000142 uint32_t cache_data_count;
Marek Vasut87737992012-08-31 16:07:59 +0000143 const uint32_t dstart = (uint32_t)data;
Marek Vasut23697f62012-07-09 00:48:33 +0000144 int dmach;
Marek Vasut7f4d0142012-08-21 16:17:27 +0000145 int tl;
Marek Vasut45edc5d2012-08-31 16:08:00 +0000146 int ret = 0;
Marek Vasut7f4d0142012-08-21 16:17:27 +0000147
Marek Vasutbf372e32013-02-23 02:42:59 +0000148#if defined(CONFIG_MX23)
149 const int mxs_spi_pio_words = 1;
150#elif defined(CONFIG_MX28)
151 const int mxs_spi_pio_words = 4;
152#endif
153
Marek Vasut7f4d0142012-08-21 16:17:27 +0000154 ALLOC_CACHE_ALIGN_BUFFER(struct mxs_dma_desc, desc, desc_count);
Marek Vasut23697f62012-07-09 00:48:33 +0000155
Marek Vasut7f4d0142012-08-21 16:17:27 +0000156 memset(desc, 0, sizeof(struct mxs_dma_desc) * desc_count);
157
158 ctrl0 = readl(&ssp_regs->hw_ssp_ctrl0);
159 ctrl0 |= SSP_CTRL0_DATA_XFER;
Marek Vasut23697f62012-07-09 00:48:33 +0000160
161 if (flags & SPI_XFER_BEGIN)
162 ctrl0 |= SSP_CTRL0_LOCK_CS;
Marek Vasut23697f62012-07-09 00:48:33 +0000163 if (!write)
164 ctrl0 |= SSP_CTRL0_READ;
165
Marek Vasut23697f62012-07-09 00:48:33 +0000166 if (length % ARCH_DMA_MINALIGN)
167 cache_data_count = roundup(length, ARCH_DMA_MINALIGN);
168 else
169 cache_data_count = length;
170
Marek Vasut87737992012-08-31 16:07:59 +0000171 /* Flush data to DRAM so DMA can pick them up */
Marek Vasut7f4d0142012-08-21 16:17:27 +0000172 if (write)
Marek Vasut87737992012-08-31 16:07:59 +0000173 flush_dcache_range(dstart, dstart + cache_data_count);
174
175 /* Invalidate the area, so no writeback into the RAM races with DMA */
176 invalidate_dcache_range(dstart, dstart + cache_data_count);
Marek Vasut23697f62012-07-09 00:48:33 +0000177
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200178 dmach = priv->dma_channel;
Marek Vasut23697f62012-07-09 00:48:33 +0000179
Marek Vasut7f4d0142012-08-21 16:17:27 +0000180 dp = desc;
181 while (length) {
182 dp->address = (dma_addr_t)dp;
183 dp->cmd.address = (dma_addr_t)data;
Marek Vasut23697f62012-07-09 00:48:33 +0000184
Marek Vasut7f4d0142012-08-21 16:17:27 +0000185 /*
186 * This is correct, even though it does indeed look insane.
187 * I hereby have to, wholeheartedly, thank Freescale Inc.,
188 * for always inventing insane hardware and keeping me busy
189 * and employed ;-)
190 */
191 if (write)
192 dp->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ;
193 else
194 dp->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE;
195
196 /*
197 * The DMA controller can transfer large chunks (64kB) at
198 * time by setting the transfer length to 0. Setting tl to
199 * 0x10000 will overflow below and make .data contain 0.
200 * Otherwise, 0xff00 is the transfer maximum.
201 */
202 if (length >= 0x10000)
203 tl = 0x10000;
204 else
205 tl = min(length, xfer_max_sz);
206
207 dp->cmd.data |=
Marek Vasut45edc5d2012-08-31 16:08:00 +0000208 ((tl & 0xffff) << MXS_DMA_DESC_BYTES_OFFSET) |
Marek Vasutbf372e32013-02-23 02:42:59 +0000209 (mxs_spi_pio_words << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
Marek Vasut7f4d0142012-08-21 16:17:27 +0000210 MXS_DMA_DESC_HALT_ON_TERMINATE |
211 MXS_DMA_DESC_TERMINATE_FLUSH;
Marek Vasut7f4d0142012-08-21 16:17:27 +0000212
213 data += tl;
214 length -= tl;
215
Marek Vasut45edc5d2012-08-31 16:08:00 +0000216 if (!length) {
217 dp->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM;
218
219 if (flags & SPI_XFER_END) {
220 ctrl0 &= ~SSP_CTRL0_LOCK_CS;
221 ctrl0 |= SSP_CTRL0_IGNORE_CRC;
222 }
223 }
224
225 /*
Marek Vasutbf372e32013-02-23 02:42:59 +0000226 * Write CTRL0, CMD0, CMD1 and XFER_SIZE registers in
227 * case of MX28, write only CTRL0 in case of MX23 due
228 * to the difference in register layout. It is utterly
Marek Vasut45edc5d2012-08-31 16:08:00 +0000229 * essential that the XFER_SIZE register is written on
230 * a per-descriptor basis with the same size as is the
231 * descriptor!
232 */
233 dp->cmd.pio_words[0] = ctrl0;
Marek Vasutbf372e32013-02-23 02:42:59 +0000234#ifdef CONFIG_MX28
Marek Vasut45edc5d2012-08-31 16:08:00 +0000235 dp->cmd.pio_words[1] = 0;
236 dp->cmd.pio_words[2] = 0;
237 dp->cmd.pio_words[3] = tl;
Marek Vasutbf372e32013-02-23 02:42:59 +0000238#endif
Marek Vasut45edc5d2012-08-31 16:08:00 +0000239
Marek Vasut7f4d0142012-08-21 16:17:27 +0000240 mxs_dma_desc_append(dmach, dp);
241
242 dp++;
243 }
244
Marek Vasut23697f62012-07-09 00:48:33 +0000245 if (mxs_dma_go(dmach))
Marek Vasut45edc5d2012-08-31 16:08:00 +0000246 ret = -EINVAL;
Marek Vasut23697f62012-07-09 00:48:33 +0000247
248 /* The data arrived into DRAM, invalidate cache over them */
Marek Vasut87737992012-08-31 16:07:59 +0000249 if (!write)
250 invalidate_dcache_range(dstart, dstart + cache_data_count);
Marek Vasut23697f62012-07-09 00:48:33 +0000251
Marek Vasut45edc5d2012-08-31 16:08:00 +0000252 return ret;
Marek Vasut23697f62012-07-09 00:48:33 +0000253}
254
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200255int mxs_spi_xfer(struct udevice *dev, unsigned int bitlen,
256 const void *dout, void *din, unsigned long flags)
257{
258 struct udevice *bus = dev_get_parent(dev);
259 struct mxs_spi_priv *priv = dev_get_priv(bus);
260 struct mxs_ssp_regs *ssp_regs = priv->regs;
Marek Vasut036b7bd2012-07-09 00:48:32 +0000261 int len = bitlen / 8;
262 char dummy;
263 int write = 0;
264 char *data = NULL;
Marek Vasut23697f62012-07-09 00:48:33 +0000265 int dma = 1;
Marek Vasut23697f62012-07-09 00:48:33 +0000266
Marek Vasut036b7bd2012-07-09 00:48:32 +0000267 if (bitlen == 0) {
268 if (flags & SPI_XFER_END) {
269 din = (void *)&dummy;
270 len = 1;
271 } else
272 return 0;
273 }
274
275 /* Half-duplex only */
276 if (din && dout)
277 return -EINVAL;
278 /* No data */
279 if (!din && !dout)
280 return 0;
281
282 if (dout) {
283 data = (char *)dout;
284 write = 1;
285 } else if (din) {
286 data = (char *)din;
287 write = 0;
288 }
289
Marek Vasut23697f62012-07-09 00:48:33 +0000290 /*
291 * Check for alignment, if the buffer is aligned, do DMA transfer,
292 * PIO otherwise. This is a temporary workaround until proper bounce
293 * buffer is in place.
294 */
295 if (dma) {
296 if (((uint32_t)data) & (ARCH_DMA_MINALIGN - 1))
297 dma = 0;
298 if (((uint32_t)len) & (ARCH_DMA_MINALIGN - 1))
299 dma = 0;
300 }
301
302 if (!dma || (len < MXSSSP_SMALL_TRANSFER)) {
303 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200304 return mxs_spi_xfer_pio(priv, data, len, write, flags);
Marek Vasut23697f62012-07-09 00:48:33 +0000305 } else {
306 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200307 return mxs_spi_xfer_dma(priv, data, len, write, flags);
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200308 }
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200309}
310
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200311static int mxs_spi_probe(struct udevice *bus)
312{
Simon Glassb75b15b2020-12-03 16:55:23 -0700313 struct mxs_spi_plat *plat = dev_get_plat(bus);
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200314 struct mxs_spi_priv *priv = dev_get_priv(bus);
315 int ret;
316
317 debug("%s: probe\n", __func__);
Lukasz Majewski6be06562019-09-05 09:54:58 +0200318
319#if CONFIG_IS_ENABLED(OF_PLATDATA)
Walter Lozano69358932020-07-23 00:22:04 -0300320 struct dtd_fsl_imx23_spi *dtplat = &plat->dtplat;
Lukasz Majewski6be06562019-09-05 09:54:58 +0200321 struct phandle_1_arg *p1a = &dtplat->clocks[0];
322
323 priv->regs = (struct mxs_ssp_regs *)dtplat->reg[0];
324 priv->dma_channel = dtplat->dmas[1];
325 priv->clk_id = p1a->arg[0];
326 priv->max_freq = dtplat->spi_max_frequency;
327 plat->num_cs = dtplat->num_cs;
328
329 debug("OF_PLATDATA: regs: 0x%x max freq: %d clkid: %d\n",
330 (unsigned int)priv->regs, priv->max_freq, priv->clk_id);
331#else
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200332 priv->regs = (struct mxs_ssp_regs *)plat->base;
333 priv->max_freq = plat->frequency;
334
335 priv->dma_channel = plat->dma_id;
336 priv->clk_id = plat->clk_id;
Lukasz Majewski6be06562019-09-05 09:54:58 +0200337#endif
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200338
Lukasz Majewski35223a62019-09-05 09:54:57 +0200339 mxs_reset_block(&priv->regs->hw_ssp_ctrl0_reg);
340
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200341 ret = mxs_dma_init_channel(priv->dma_channel);
342 if (ret) {
343 printf("%s: DMA init channel error %d\n", __func__, ret);
344 return ret;
345 }
346
347 return 0;
348}
349
350static int mxs_spi_claim_bus(struct udevice *dev)
351{
352 struct udevice *bus = dev_get_parent(dev);
353 struct mxs_spi_priv *priv = dev_get_priv(bus);
354 struct mxs_ssp_regs *ssp_regs = priv->regs;
355 int cs = spi_chip_select(dev);
356
357 /*
358 * i.MX28 supports up to 3 CS (SSn0, SSn1, SSn2)
359 * To set them it uses following tuple (WAIT_FOR_IRQ,WAIT_FOR_CMD),
360 * where:
361 *
362 * WAIT_FOR_IRQ is bit 21 of HW_SSP_CTRL0
363 * WAIT_FOR_CMD is bit 20 (#defined as MXS_SSP_CHIPSELECT_SHIFT here) of
364 * HW_SSP_CTRL0
365 * SSn0 b00
366 * SSn1 b01
367 * SSn2 b10 (which require setting WAIT_FOR_IRQ)
368 *
369 * However, for now i.MX28 SPI driver will support up till 2 CSes
370 * (SSn0, and SSn1).
371 */
372
373 /* Ungate SSP clock and set active CS */
374 clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
375 BIT(MXS_SSP_CHIPSELECT_SHIFT) |
376 SSP_CTRL0_CLKGATE, (cs << MXS_SSP_CHIPSELECT_SHIFT));
377
378 return 0;
379}
380
381static int mxs_spi_release_bus(struct udevice *dev)
382{
383 struct udevice *bus = dev_get_parent(dev);
384 struct mxs_spi_priv *priv = dev_get_priv(bus);
385 struct mxs_ssp_regs *ssp_regs = priv->regs;
386
387 /* Gate SSP clock */
388 setbits_le32(&ssp_regs->hw_ssp_ctrl0, SSP_CTRL0_CLKGATE);
389
390 return 0;
391}
392
393static int mxs_spi_set_speed(struct udevice *bus, uint speed)
394{
395 struct mxs_spi_priv *priv = dev_get_priv(bus);
396#ifdef CONFIG_MX28
397 int clkid = priv->clk_id - MXS_SSP_IMX28_CLKID_SSP0;
398#else /* CONFIG_MX23 */
399 int clkid = priv->clk_id - MXS_SSP_IMX23_CLKID_SSP0;
400#endif
401 if (speed > priv->max_freq)
402 speed = priv->max_freq;
403
404 debug("%s speed: %u [Hz] clkid: %d\n", __func__, speed, clkid);
405 mxs_set_ssp_busclock(clkid, speed / 1000);
406
407 return 0;
408}
409
410static int mxs_spi_set_mode(struct udevice *bus, uint mode)
411{
412 struct mxs_spi_priv *priv = dev_get_priv(bus);
413 struct mxs_ssp_regs *ssp_regs = priv->regs;
414 u32 reg;
415
416 priv->mode = mode;
417 debug("%s: mode 0x%x\n", __func__, mode);
418
419 reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
420 reg |= (priv->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
421 reg |= (priv->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
422 writel(reg, &ssp_regs->hw_ssp_ctrl1);
423
424 /* Single bit SPI support */
425 writel(SSP_CTRL0_BUS_WIDTH_ONE_BIT, &ssp_regs->hw_ssp_ctrl0);
426
427 return 0;
428}
429
430static const struct dm_spi_ops mxs_spi_ops = {
431 .claim_bus = mxs_spi_claim_bus,
432 .release_bus = mxs_spi_release_bus,
433 .xfer = mxs_spi_xfer,
434 .set_speed = mxs_spi_set_speed,
435 .set_mode = mxs_spi_set_mode,
436 /*
437 * cs_info is not needed, since we require all chip selects to be
438 * in the device tree explicitly
439 */
440};
441
Simon Glass3580f6d2021-08-07 07:24:03 -0600442#if CONFIG_IS_ENABLED(OF_REAL)
Simon Glassaad29ae2020-12-03 16:55:21 -0700443static int mxs_of_to_plat(struct udevice *bus)
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200444{
Simon Glass95588622020-12-22 19:30:28 -0700445 struct mxs_spi_plat *plat = dev_get_plat(bus);
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200446 u32 prop[2];
447 int ret;
448
449 plat->base = dev_read_addr(bus);
450 plat->frequency =
451 dev_read_u32_default(bus, "spi-max-frequency", 40000000);
452 plat->num_cs = dev_read_u32_default(bus, "num-cs", 2);
453
454 ret = dev_read_u32_array(bus, "dmas", prop, ARRAY_SIZE(prop));
455 if (ret) {
456 printf("%s: Reading 'dmas' property failed!\n", __func__);
457 return ret;
458 }
459 plat->dma_id = prop[1];
460
461 ret = dev_read_u32_array(bus, "clocks", prop, ARRAY_SIZE(prop));
462 if (ret) {
463 printf("%s: Reading 'clocks' property failed!\n", __func__);
464 return ret;
465 }
466 plat->clk_id = prop[1];
467
468 debug("%s: base=0x%x, max-frequency=%d num-cs=%d dma_id=%d clk_id=%d\n",
469 __func__, (uint)plat->base, plat->frequency, plat->num_cs,
470 plat->dma_id, plat->clk_id);
471
472 return 0;
473}
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200474
475static const struct udevice_id mxs_spi_ids[] = {
476 { .compatible = "fsl,imx23-spi" },
477 { .compatible = "fsl,imx28-spi" },
478 { }
479};
Lukasz Majewski6be06562019-09-05 09:54:58 +0200480#endif
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200481
Walter Lozano2901ac62020-06-25 01:10:04 -0300482U_BOOT_DRIVER(fsl_imx23_spi) = {
Lukasz Majewski6be06562019-09-05 09:54:58 +0200483 .name = "fsl_imx23_spi",
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200484 .id = UCLASS_SPI,
Simon Glass3580f6d2021-08-07 07:24:03 -0600485#if CONFIG_IS_ENABLED(OF_REAL)
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200486 .of_match = mxs_spi_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700487 .of_to_plat = mxs_of_to_plat,
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200488#endif
Simon Glassb75b15b2020-12-03 16:55:23 -0700489 .plat_auto = sizeof(struct mxs_spi_plat),
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200490 .ops = &mxs_spi_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700491 .priv_auto = sizeof(struct mxs_spi_priv),
Lukasz Majewski5faaf092019-06-19 17:31:07 +0200492 .probe = mxs_spi_probe,
493};
Walter Lozano48e5b042020-06-25 01:10:06 -0300494
Simon Glassdf65db82020-12-28 20:34:57 -0700495DM_DRIVER_ALIAS(fsl_imx23_spi, fsl_imx28_spi)