Lines Matching +full:spi +full:- +full:tx +full:- +full:delay +full:- +full:us
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * MPC512x PSC in SPI mode driver.
7 * Hongjun Chen <hong-jun.chen@freescale.com>
21 #include <linux/delay.h>
23 #include <linux/spi/spi.h>
37 switch (mps->type) { \
39 struct mpc52xx_psc __iomem *psc = mps->psc; \
40 __ret = &psc->regname; \
44 struct mpc5125_psc __iomem *psc = mps->psc; \
45 __ret = &psc->regname; \
72 static int mpc512x_psc_spi_transfer_setup(struct spi_device *spi, in mpc512x_psc_spi_transfer_setup() argument
75 struct mpc512x_psc_spi_cs *cs = spi->controller_state; in mpc512x_psc_spi_transfer_setup()
77 cs->speed_hz = (t && t->speed_hz) in mpc512x_psc_spi_transfer_setup()
78 ? t->speed_hz : spi->max_speed_hz; in mpc512x_psc_spi_transfer_setup()
79 cs->bits_per_word = (t && t->bits_per_word) in mpc512x_psc_spi_transfer_setup()
80 ? t->bits_per_word : spi->bits_per_word; in mpc512x_psc_spi_transfer_setup()
81 cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8; in mpc512x_psc_spi_transfer_setup()
85 static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) in mpc512x_psc_spi_activate_cs() argument
87 struct mpc512x_psc_spi_cs *cs = spi->controller_state; in mpc512x_psc_spi_activate_cs()
88 struct mpc512x_psc_spi *mps = spi_controller_get_devdata(spi->controller); in mpc512x_psc_spi_activate_cs()
97 if (spi->mode & SPI_CPHA) in mpc512x_psc_spi_activate_cs()
102 if (spi->mode & SPI_CPOL) in mpc512x_psc_spi_activate_cs()
107 if (spi->mode & SPI_LSB_FIRST) in mpc512x_psc_spi_activate_cs()
115 speed = cs->speed_hz; in mpc512x_psc_spi_activate_cs()
118 bclkdiv = (mps->mclk_rate / speed) - 1; in mpc512x_psc_spi_activate_cs()
122 mps->bits_per_word = cs->bits_per_word; in mpc512x_psc_spi_activate_cs()
124 if (spi_get_csgpiod(spi, 0)) { in mpc512x_psc_spi_activate_cs()
126 gpiod_set_value(spi_get_csgpiod(spi, 0), 1); in mpc512x_psc_spi_activate_cs()
130 static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi) in mpc512x_psc_spi_deactivate_cs() argument
132 if (spi_get_csgpiod(spi, 0)) { in mpc512x_psc_spi_deactivate_cs()
134 gpiod_set_value(spi_get_csgpiod(spi, 0), 0); in mpc512x_psc_spi_deactivate_cs()
143 static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi, in mpc512x_psc_spi_transfer_rxtx() argument
146 struct mpc512x_psc_spi *mps = spi_controller_get_devdata(spi->controller); in mpc512x_psc_spi_transfer_rxtx()
147 struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; in mpc512x_psc_spi_transfer_rxtx()
148 size_t tx_len = t->len; in mpc512x_psc_spi_transfer_rxtx()
149 size_t rx_len = t->len; in mpc512x_psc_spi_transfer_rxtx()
150 u8 *tx_buf = (u8 *)t->tx_buf; in mpc512x_psc_spi_transfer_rxtx()
151 u8 *rx_buf = (u8 *)t->rx_buf; in mpc512x_psc_spi_transfer_rxtx()
153 if (!tx_buf && !rx_buf && t->len) in mpc512x_psc_spi_transfer_rxtx()
154 return -EINVAL; in mpc512x_psc_spi_transfer_rxtx()
164 * send the TX bytes in as large a chunk as possible in mpc512x_psc_spi_transfer_rxtx()
165 * but neither exceed the TX nor the RX FIFOs in mpc512x_psc_spi_transfer_rxtx()
167 fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz)); in mpc512x_psc_spi_transfer_rxtx()
169 fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz)); in mpc512x_psc_spi_transfer_rxtx()
170 fifosz -= in_be32(&fifo->rxcnt) + 1; in mpc512x_psc_spi_transfer_rxtx()
174 /* fill the TX FIFO */ in mpc512x_psc_spi_transfer_rxtx()
175 while (txcount-- > 0) { in mpc512x_psc_spi_transfer_rxtx()
177 if (tx_len == EOFBYTE && t->cs_change) in mpc512x_psc_spi_transfer_rxtx()
178 setbits32(&fifo->txcmd, in mpc512x_psc_spi_transfer_rxtx()
180 out_8(&fifo->txdata_8, data); in mpc512x_psc_spi_transfer_rxtx()
181 tx_len--; in mpc512x_psc_spi_transfer_rxtx()
184 /* have the ISR trigger when the TX FIFO is empty */ in mpc512x_psc_spi_transfer_rxtx()
185 reinit_completion(&mps->txisrdone); in mpc512x_psc_spi_transfer_rxtx()
186 out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); in mpc512x_psc_spi_transfer_rxtx()
187 out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); in mpc512x_psc_spi_transfer_rxtx()
188 wait_for_completion(&mps->txisrdone); in mpc512x_psc_spi_transfer_rxtx()
193 * iterate over the transfer's TX data length in mpc512x_psc_spi_transfer_rxtx()
196 * when the TX bytes were exhausted (that's at the very in mpc512x_psc_spi_transfer_rxtx()
206 * the FIFO while we read from it -- we'll return in mpc512x_psc_spi_transfer_rxtx()
208 * TX data in mpc512x_psc_spi_transfer_rxtx()
210 fifosz = in_be32(&fifo->rxcnt); in mpc512x_psc_spi_transfer_rxtx()
212 while (rxcount-- > 0) { in mpc512x_psc_spi_transfer_rxtx()
213 data = in_8(&fifo->rxdata_8); in mpc512x_psc_spi_transfer_rxtx()
216 rx_len--; in mpc512x_psc_spi_transfer_rxtx()
220 * come back later if there still is TX data to send, in mpc512x_psc_spi_transfer_rxtx()
221 * bail out of the RX drain loop if all of the TX data in mpc512x_psc_spi_transfer_rxtx()
231 * TX data transmission has completed while RX data in mpc512x_psc_spi_transfer_rxtx()
232 * is still pending -- that's a transient situation in mpc512x_psc_spi_transfer_rxtx()
238 * too long when running SPI at low speed in mpc512x_psc_spi_transfer_rxtx()
243 * times 10us and thus work at speeds as low as in mpc512x_psc_spi_transfer_rxtx()
253 * unknown inner delay in mpc512x_psc_spi_transfer_rxtx()
257 } while (--rxtries > 0); in mpc512x_psc_spi_transfer_rxtx()
263 rxcount = in_be32(&fifo->rxcnt); in mpc512x_psc_spi_transfer_rxtx()
264 dev_warn(&spi->dev, in mpc512x_psc_spi_transfer_rxtx()
275 while (in_be32(&fifo->rxcnt)) in mpc512x_psc_spi_transfer_rxtx()
276 in_8(&fifo->rxdata_8); in mpc512x_psc_spi_transfer_rxtx()
286 struct spi_device *spi; in mpc512x_psc_spi_msg_xfer() local
291 spi = m->spi; in mpc512x_psc_spi_msg_xfer()
294 list_for_each_entry(t, &m->transfers, transfer_list) { in mpc512x_psc_spi_msg_xfer()
295 status = mpc512x_psc_spi_transfer_setup(spi, t); in mpc512x_psc_spi_msg_xfer()
300 mpc512x_psc_spi_activate_cs(spi); in mpc512x_psc_spi_msg_xfer()
301 cs_change = t->cs_change; in mpc512x_psc_spi_msg_xfer()
303 status = mpc512x_psc_spi_transfer_rxtx(spi, t); in mpc512x_psc_spi_msg_xfer()
306 m->actual_length += t->len; in mpc512x_psc_spi_msg_xfer()
311 mpc512x_psc_spi_deactivate_cs(spi); in mpc512x_psc_spi_msg_xfer()
314 m->status = status; in mpc512x_psc_spi_msg_xfer()
315 if (m->complete) in mpc512x_psc_spi_msg_xfer()
316 m->complete(m->context); in mpc512x_psc_spi_msg_xfer()
319 mpc512x_psc_spi_deactivate_cs(spi); in mpc512x_psc_spi_msg_xfer()
321 mpc512x_psc_spi_transfer_setup(spi, NULL); in mpc512x_psc_spi_msg_xfer()
331 dev_dbg(&host->dev, "%s()\n", __func__); in mpc512x_psc_spi_prep_xfer_hw()
346 struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; in mpc512x_psc_spi_unprep_xfer_hw()
348 dev_dbg(&host->dev, "%s()\n", __func__); in mpc512x_psc_spi_unprep_xfer_hw()
352 out_be32(&fifo->tximr, 0); in mpc512x_psc_spi_unprep_xfer_hw()
357 static int mpc512x_psc_spi_setup(struct spi_device *spi) in mpc512x_psc_spi_setup() argument
359 struct mpc512x_psc_spi_cs *cs = spi->controller_state; in mpc512x_psc_spi_setup()
361 if (spi->bits_per_word % 8) in mpc512x_psc_spi_setup()
362 return -EINVAL; in mpc512x_psc_spi_setup()
367 return -ENOMEM; in mpc512x_psc_spi_setup()
369 spi->controller_state = cs; in mpc512x_psc_spi_setup()
372 cs->bits_per_word = spi->bits_per_word; in mpc512x_psc_spi_setup()
373 cs->speed_hz = spi->max_speed_hz; in mpc512x_psc_spi_setup()
378 static void mpc512x_psc_spi_cleanup(struct spi_device *spi) in mpc512x_psc_spi_cleanup() argument
380 kfree(spi->controller_state); in mpc512x_psc_spi_cleanup()
386 struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; in mpc512x_psc_spi_port_config()
401 out_be32(&fifo->tximr, 0); in mpc512x_psc_spi_port_config()
402 out_be32(&fifo->rximr, 0); in mpc512x_psc_spi_port_config()
405 /*out_be32(&fifo->txsz, 0x0fe00004);*/ in mpc512x_psc_spi_port_config()
406 /*out_be32(&fifo->rxsz, 0x0ff00004);*/ in mpc512x_psc_spi_port_config()
408 sicr = 0x01000000 | /* SIM = 0001 -- 8 bit */ in mpc512x_psc_spi_port_config()
409 0x00800000 | /* GenClk = 1 -- internal clk */ in mpc512x_psc_spi_port_config()
410 0x00008000 | /* SPI = 1 */ in mpc512x_psc_spi_port_config()
411 0x00004000 | /* MSTR = 1 -- SPI host */ in mpc512x_psc_spi_port_config()
412 0x00000800; /* UseEOF = 1 -- SS low until EOF */ in mpc512x_psc_spi_port_config()
419 bclkdiv = (mps->mclk_rate / speed) - 1; in mpc512x_psc_spi_port_config()
423 /* Set 2ms DTL delay */ in mpc512x_psc_spi_port_config()
428 out_be32(&fifo->rxalarm, 0xfff); in mpc512x_psc_spi_port_config()
429 out_be32(&fifo->txalarm, 0); in mpc512x_psc_spi_port_config()
431 /* Enable FIFO slices for Rx/Tx */ in mpc512x_psc_spi_port_config()
432 out_be32(&fifo->rxcmd, in mpc512x_psc_spi_port_config()
434 out_be32(&fifo->txcmd, in mpc512x_psc_spi_port_config()
437 mps->bits_per_word = 8; in mpc512x_psc_spi_port_config()
445 struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; in mpc512x_psc_spi_isr()
447 /* clear interrupt and wake up the rx/tx routine */ in mpc512x_psc_spi_isr()
448 if (in_be32(&fifo->txisr) & in mpc512x_psc_spi_isr()
449 in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) { in mpc512x_psc_spi_isr()
450 out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); in mpc512x_psc_spi_isr()
451 out_be32(&fifo->tximr, 0); in mpc512x_psc_spi_isr()
452 complete(&mps->txisrdone); in mpc512x_psc_spi_isr()
460 struct device *dev = &pdev->dev; in mpc512x_psc_spi_of_probe()
469 return -ENOMEM; in mpc512x_psc_spi_of_probe()
473 mps->type = (int)device_get_match_data(dev); in mpc512x_psc_spi_of_probe()
475 host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; in mpc512x_psc_spi_of_probe()
476 host->setup = mpc512x_psc_spi_setup; in mpc512x_psc_spi_of_probe()
477 host->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw; in mpc512x_psc_spi_of_probe()
478 host->transfer_one_message = mpc512x_psc_spi_msg_xfer; in mpc512x_psc_spi_of_probe()
479 host->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw; in mpc512x_psc_spi_of_probe()
480 host->use_gpio_descriptors = true; in mpc512x_psc_spi_of_probe()
481 host->cleanup = mpc512x_psc_spi_cleanup; in mpc512x_psc_spi_of_probe()
483 device_set_node(&host->dev, dev_fwnode(dev)); in mpc512x_psc_spi_of_probe()
488 mps->psc = tempp; in mpc512x_psc_spi_of_probe()
489 mps->fifo = in mpc512x_psc_spi_of_probe()
492 mps->irq = platform_get_irq(pdev, 0); in mpc512x_psc_spi_of_probe()
493 if (mps->irq < 0) in mpc512x_psc_spi_of_probe()
494 return mps->irq; in mpc512x_psc_spi_of_probe()
496 ret = devm_request_irq(dev, mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED, in mpc512x_psc_spi_of_probe()
497 "mpc512x-psc-spi", mps); in mpc512x_psc_spi_of_probe()
500 init_completion(&mps->txisrdone); in mpc512x_psc_spi_of_probe()
506 mps->mclk_rate = clk_get_rate(clk); in mpc512x_psc_spi_of_probe()
520 { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
521 { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
530 .name = "mpc512x-psc-spi",
537 MODULE_DESCRIPTION("MPC512x PSC SPI Driver");