spi: Add Freescale QuadSpi driver
PATCH 2/2 spi: Add Freescale QuadSpi driver
Add QuadSpi driver for Freescale's Quad Spi controller. This controller is designed for serial flash access.
This driver has been tested on vf610-twr board with m25p80 type chips. The hardware has no support for other types of spi peripherals. Chip select control is handled via Serial Flash Address Register.
--- drivers/spi/Kconfig | 5 + drivers/spi/Makefile | 1 + drivers/spi/spi-fsl-quadspi.c | 595 ++++++++++++++++++++++++++++++++++++++++++ drivers/spi/spi-fsl-quadspi.h | 167 ++++++++++++ 4 files changed, 768 insertions(+) create mode 100644 drivers/spi/spi-fsl-quadspi.c create mode 100644 drivers/spi/spi-fsl-quadspi.h
drivers/spi/Kconfig +5 -0
@@ -198,6 +198,11 @@ config SPI_IMX This enables using the Freescale i.MX SPI controllers in master mode. +config SPI_FSL_QUADSPI + tristate "Freescale Quad SPI controller" + help + This enables support for the Quad SPI controller in master mode. + config SPI_LM70_LLP tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" depends on PARPORT
drivers/spi/Makefile +1 -0
@@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMX) += spi-imx.o +obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-quadspi.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
drivers/spi/spi-fsl-quadspi.c new file +595 -0
595 lines not on this page · raw message
drivers/spi/spi-fsl-quadspi.h new file +167 -0
167 lines not on this page · raw message
Signature · 1 line
1.8.0
PATCH 2/2 spi: Add Freescale QuadSpi driver
Quoted 8 lines · Xiaochun Li
Add QuadSpi driver for Freescale's Quad Spi controller. This controller is designed for serial flash access.
This driver has been tested on vf610-twr board with m25p80 type chips. The hardware has no support for other types of spi peripherals. Chip select control is handled via Serial Flash Address Register.Signed-off-by Alison Wang <[email protected]>Signed-off-by Xiaochun Li <[email protected]>
Quoted 8 lines
--- drivers/spi/Kconfig | 5 + drivers/spi/Makefile | 1 + drivers/spi/spi-fsl-quadspi.c | 595 ++++++++++++++++++++++++++++++++++++++++++ drivers/spi/spi-fsl-quadspi.h | 167 ++++++++++++ 4 files changed, 768 insertions(+) create mode 100644 drivers/spi/spi-fsl-quadspi.c create mode 100644 drivers/spi/spi-fsl-quadspi.h
There should be a binding doc along with the patch. Check Documentation/devicetree/bindings/spi/ for examples.
drivers/spi/Kconfig config SPI_IMX · line 202
Quoted 11 lines
drivers/spi/Kconfig +2
-0@@ -198,6 +198,11 @@ config SPI_IMX This enables using the Freescale i.MX SPI controllers in master mode. +config SPI_FSL_QUADSPI + tristate "Freescale Quad SPI controller"
I see indentation problem here, probably because you're using spaces here.
Quoted 42 lines
drivers/spi/Kconfig +3
-0+ help + This enables support for the Quad SPI controller in master mode. + config SPI_LM70_LLP tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" depends on PARPORTdrivers/spi/Makefile +1
-0@@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMX) += spi-imx.o +obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-quadspi.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.odrivers/spi/spi-fsl-quadspi.c new file +18
-0@@ -0,0 +1,595 @@ +/* +* Freescale Quad SPI driver. +* +* Copyright 2012-2013 Freescale Semiconductor, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/delay.h>
drivers/spi/spi-fsl-quadspi.c line 28
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/spi/spi.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/timer.h> +#include <linux/jiffies.h> + +#include "spi-fsl-quadspi.h"
If the header is only used by this file, we do not have to have the header. It's always easier to search definitions in a single file than in two.
drivers/spi/spi-fsl-quadspi.c line 30
Quoted 2 lines
drivers/spi/spi-fsl-quadspi.c new file +2
-0+ +static inline unsigned int fsl_qspi_check_status (struct fsl_qspi *fsl_qspi)
fsl_qspi_check_busy() could be a better name.
drivers/spi/spi-fsl-quadspi.c line 43
Quoted 13 lines
drivers/spi/spi-fsl-quadspi.c new file +13
-0+{ +return readl (fsl_qspi->iobase +QUADSPI_SR ) &QSPI_SR_BUSY_MASK ; +} + +static inline unsigned int fsl_qspi_check_txfull (struct fsl_qspi *fsl_qspi) +{ +return readl (fsl_qspi->iobase +QUADSPI_SR ) &QSPI_SR_TXFULL_MASK ; +} + +static void wait_do_timer (unsigned long arg) +{ +struct fsl_qspi *fsl_qspi = (struct fsl_qspi *)(arg); + fsl_qspi->timeout =1 ;
I expect "true" to be used here, since timeout is defined as bool and "false" is used in probe() for initialization.
Quoted 8 lines
drivers/spi/spi-fsl-quadspi.c new file +8
-0+} + +static irqreturn_t fsl_qspi_irq_handler (int this_irq,void *dev_id) +{ +struct fsl_qspi *fsl_qspi = dev_id; +u32 reg_fr =readl (fsl_qspi->iobase +QUADSPI_FR ); + +/* clear interrupt */
drivers/spi/spi-fsl-quadspi.c line 61
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+writel (reg_fr, fsl_qspi->iobase +QUADSPI_FR ); +if (reg_fr &QSPI_FR_TFF_MASK ) +wake_up (&fsl_qspi->waitq); + +return IRQ_HANDLED ; +} + +static void set_lut (struct fsl_qspi *fsl_qspi) +{ +u32 lut_base;
Have a blank line here.
Quoted 23 lines
drivers/spi/spi-fsl-quadspi.c new file +23
-0+/* Unlock the LUT */ +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY ); +writel (QSPI_LCKCR_UNLOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); + +/* SEQID 1 - Write enable */ + lut_base =WEN_SEQID *4 ; +writel (OPRND0 (0x6 ) |PAD0 (0x0 ) |INSTR0 (CMD ), + fsl_qspi->iobase +QUADSPI_LUT (lut_base)); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +1 )); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +2 )); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +3 )); + +/* SEQID 3 - Read Status */ + lut_base =READSTATU_SEQID *4 ; +writel (OPRND0 (0x05 ) |PAD0 (0x0 ) |INSTR0 (CMD ) | +OPRND1 (0x1 ) |PAD1 (0x0 ) |INSTR1 (READ ), + fsl_qspi->iobase +QUADSPI_LUT (lut_base)); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +1 )); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +2 )); +writel (0x0 , fsl_qspi->iobase +QUADSPI_LUT (lut_base +3 )); + +/* Lock the LUT */ +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY );
drivers/spi/spi-fsl-quadspi.c line 94
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+writel (QSPI_LCKCR_LOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); +} + +static void waiting_for_end (struct fsl_qspi *fsl_qspi, +u32 current_bit,u32 bitvalue,u32 timeout) +{ +u32 reg, status_reg; + + fsl_qspi->wait_timer.expires = jiffies + timeout; +add_timer (&fsl_qspi->wait_timer);
Shouldn't we always initialize timeout to be false when adding the timer? Otherwise, once we get one timeout event, we will timeout all the time?
drivers/spi/spi-fsl-quadspi.c line 102
Quoted 8 lines
drivers/spi/spi-fsl-quadspi.c new file +8
-0+ + status_reg = !bitvalue << current_bit; +while ((status_reg & (0x1 << current_bit)) != bitvalue << current_bit) { +if (fsl_qspi->timeout) { +dev_err (fsl_qspi->dev,"tired waiting for end status\n" ); +break ; + } + writel((READSTATU_SEQID << QSPI_IPCR_SEQID_SHIFT) | 1,
There are so many bit filed definitions, and no one for this magic "1"?
Quoted 290 lines
drivers/spi/spi-fsl-quadspi.c new file +290
-0+ fsl_qspi->iobase + QUADSPI_IPCR); +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + + reg =readl (fsl_qspi->iobase +QUADSPI_RBSR ); +if (reg &QSPI_RBSR_RDBFL_MASK ) + status_reg =readl (fsl_qspi->iobase + +QUADSPI_RBDR ); + +writel (readl (fsl_qspi->iobase +QUADSPI_MCR ) | +QSPI_MCR_CLR_RXF_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); + } +del_timer (&fsl_qspi->wait_timer); +} + +static void set_send_lut (struct fsl_qspi *fsl_qspi,u8 opr, +u32 num_of_trans,u32 len) +{ +u32 lut[4 ], lut_base; + +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY ); +writel (QSPI_LCKCR_UNLOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); + + lut[0 ] =OPRND0 (opr) |PAD0 (0x0 ) |INSTR0 (CMD ); + lut[1 ] =0 ; + lut[2 ] =0 ; + lut[3 ] =0 ; + +if (len >1 ) + lut[0 ] = lut[0 ] |OPRND1 (ADDR24BIT ) |PAD1 (0x0 ) |INSTR1 (ADDR ); +if (num_of_trans >1 ) + lut[1 ] =OPRND0 (TX_BUFFER_SIZE ) |PAD0 (0x0 ) |INSTR0 (WRITE ); + lut_base =TX_SEQID *4 ; +writel (lut[0 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base)); +writel (lut[1 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +1 )); +writel (lut[2 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +2 )); +writel (lut[3 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +3 )); + +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY ); +writel (QSPI_LCKCR_LOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); +} + +static void set_receive_lut (struct fsl_qspi *fsl_qspi,u8 opr, +u32 num_of_tran,u32 len,u32 tx_len) +{ +u32 lut[4 ], lut_base; + +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY ); +writel (QSPI_LCKCR_UNLOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); + + lut[0 ] =OPRND0 (opr) |PAD0 (0x0 ) |INSTR0 (CMD ); + lut[1 ] =OPRND0 (ADDR24BIT ) |PAD0 (0x0 ) |INSTR0 (ADDR ); + lut[2 ] =0 ; + lut[3 ] =0 ; + +if (tx_len >1 ) { + len =RX_BUFFER_SIZE ; + lut[0 ] = lut[0 ] |OPRND1 (ADDR24BIT ) |PAD1 (0x0 ) |INSTR1 (ADDR ); + lut[1 ] =OPRND0 (len) |PAD0 (0x0 ) |INSTR0 (READ ); + }else { + lut[0 ] = lut[0 ] |OPRND1 (len) |PAD1 (0x0 ) |INSTR1 (READ ); + } + lut_base =RX_SEQID *4 ; +writel (lut[0 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base)); +writel (lut[1 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +1 )); +writel (lut[2 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +2 )); +writel (lut[3 ], fsl_qspi->iobase +QUADSPI_LUT (lut_base +3 )); + +writel (KEY_VALUE , fsl_qspi->iobase +QUADSPI_LUTKEY ); +writel (QSPI_LCKCR_LOCK , fsl_qspi->iobase +QUADSPI_LCKCR ); +} + +static void fsl_qspi_do_rx (struct fsl_qspi *fsl_qspi,u32 position, +u32 count,u32 *rxbuf) +{ +u32 tmp, i, size; + + position +=PSP_QSPI0_MEMMAP_BASE ; + +while (count >0 ) { +writel (position, fsl_qspi->iobase +QUADSPI_SFAR ); + size = (count >RX_BUFFER_SIZE ) ? +RX_BUFFER_SIZE : count; + +writel (RX_SEQID <<QSPI_IPCR_SEQID_SHIFT | size, + fsl_qspi->iobase +QUADSPI_IPCR ); +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + + position += size; + count -= size; + + i =0 ; +while ((RX_BUFFER_SIZE >= size) && (size >0 )) { + tmp =readl (fsl_qspi->iobase +QUADSPI_RBDR + + i *4 ); + *rxbuf =endian_change_32bit (tmp); + rxbuf++; + size -=4 ; + i++; + } + +writel (readl (fsl_qspi->iobase +QUADSPI_MCR ) | +QSPI_MCR_CLR_RXF_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); + } +} + +static void fsl_qspi_do_tx (struct fsl_qspi *fsl_qspi, +u32 position,u32 count,const u32 *txbuf) +{ +u32 tmp, i, j, size, tx_size; + + position +=PSP_QSPI0_MEMMAP_BASE ; + +while (count >0 ) { +writel (position, fsl_qspi->iobase +QUADSPI_SFAR ); + +writel ((WEN_SEQID <<QSPI_IPCR_SEQID_SHIFT ) |0 , + fsl_qspi->iobase +QUADSPI_IPCR ); +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + +waiting_for_end (fsl_qspi,WRITE_ENABLE_BIT , +VALID_WRITE_ENABLE_BIT ,WRITE_ENABLE_TIMEOUT ); + +writel (position, fsl_qspi->iobase +QUADSPI_SFAR ); + tx_size = (count >TX_BUFFER_SIZE ) ? +TX_BUFFER_SIZE : count; + + position += tx_size; + count -= tx_size; + + size = (tx_size +3 ) /4 ; + i = (size >16 ) ?16 : size; +for (j =0 ; j < i; j++) { + tmp =endian_change_32bit (*txbuf); +writel (tmp, fsl_qspi->iobase +QUADSPI_TBDR ); + txbuf++; + } + +writel (TX_SEQID <<QSPI_IPCR_SEQID_SHIFT | tx_size, + fsl_qspi->iobase +QUADSPI_IPCR ); + +for (j = i; j < size; j++) { +wait_event (fsl_qspi->waitq, + !fsl_qspi_check_txfull (fsl_qspi)); + tmp =endian_change_32bit (*txbuf); +writel (tmp, fsl_qspi->iobase +QUADSPI_TBDR ); + txbuf++; + } + +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + +waiting_for_end (fsl_qspi,STATUS_BIT , +VALID_STATUS_BIT ,READ_STATUS_TIMEOUT ); + } +} + +static void fsl_qspi_do_tx_cmd (struct fsl_qspi *fsl_qspi, +u32 position) +{ + position +=PSP_QSPI0_MEMMAP_BASE ; +writel (position, fsl_qspi->iobase +QUADSPI_SFAR ); + +writel ((TX_SEQID <<QSPI_IPCR_SEQID_SHIFT ) |0 , + fsl_qspi->iobase +QUADSPI_IPCR ); + +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + +waiting_for_end (fsl_qspi,STATUS_BIT , +VALID_STATUS_BIT ,READ_STATUS_TIMEOUT ); +} + +static void fsl_qspi_write_trans (struct spi_master *master, +struct spi_message *msg,u32 num) +{ +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); +struct spi_transfer *xfer; +u8 opr =0 ; +loff_t pos =0 ; +int status =0 ; +u32 mcr_reg, trans_counter =0 ; + +list_for_each_entry (xfer, &msg->transfers, transfer_list) { + +if (xfer->tx_buf && trans_counter ==0 ) { + opr = *(u8 *)xfer->tx_buf; +if (xfer->len >1 ) + pos = *(u32 *)xfer->tx_buf &POS_LOCATION_MASK ; + + msg->actual_length += xfer->len; +set_send_lut (fsl_qspi, opr, num, xfer->len); + } + + mcr_reg =readl (fsl_qspi->iobase +QUADSPI_MCR ); +writel (QSPI_MCR_CLR_RXF_MASK |QSPI_MCR_CLR_TXF_MASK |QSPI_MCR_RESERVED_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); +writel (QSPI_RBCT_WMRK_MASK |QSPI_RBCT_RXBRD_USEIPS , + fsl_qspi->iobase +QUADSPI_RBCT ); + +if (xfer->tx_buf && num >1 && trans_counter >0 ) { +fsl_qspi_do_tx (fsl_qspi,endian_change_32bit (pos), + xfer->len, xfer->tx_buf); + msg->actual_length += xfer->len; + }else if (xfer->tx_buf && (num ==1 ) && (trans_counter ==0 )) { +fsl_qspi_do_tx_cmd (fsl_qspi,endian_change_32bit (pos)); + } +writel (mcr_reg, fsl_qspi->iobase +QUADSPI_MCR ); + +if (xfer->delay_usecs) +udelay (xfer->delay_usecs); + + trans_counter++; + } + + msg->status = status; +spi_finalize_current_message (master); +} + +static void fsl_qspi_read_trans (struct spi_master *master, +struct spi_message *msg,u32 num) +{ +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); +struct spi_transfer *xfer; +u32 tx_len =0 , trans_counter =0 , mcr_reg; +u8 opr =0 ; +loff_t pos =0 ; +int status =0 ; + +list_for_each_entry (xfer, &msg->transfers, transfer_list) { + +writel (QSPI_RBCT_WMRK_MASK |QSPI_RBCT_RXBRD_USEIPS , + fsl_qspi->iobase +QUADSPI_RBCT ); + +if (xfer->tx_buf && trans_counter ==0 ) { + opr = *(u8 *)xfer->tx_buf; +if (xfer->len >1 ) + pos = *(u32 *)xfer->tx_buf &POS_LOCATION_MASK ; +else + pos =0 ; + tx_len = xfer->len; + } + +if (xfer->rx_buf && trans_counter >0 ) { +set_receive_lut (fsl_qspi, opr, num, xfer->len, tx_len); + + mcr_reg =readl (fsl_qspi->iobase +QUADSPI_MCR ); +writel (QSPI_MCR_CLR_RXF_MASK | +QSPI_MCR_CLR_TXF_MASK |QSPI_MCR_RESERVED_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); + +fsl_qspi_do_rx (fsl_qspi,endian_change_32bit (pos), + xfer->len, xfer->rx_buf); + +writel (mcr_reg, fsl_qspi->iobase +QUADSPI_MCR ); + } + +if (xfer->delay_usecs) +udelay (xfer->delay_usecs); + msg->actual_length += xfer->len; + + trans_counter++; + } + + msg->status = status; +spi_finalize_current_message (master); +} + +static int fsl_qspi_do_one_msg (struct spi_master *master, +struct spi_message *m) +{ +struct spi_transfer *t; +u8 *rx_buf =NULL ; +unsigned int xfer_num =0 ; +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); + +writel (INT_TFIE , fsl_qspi->iobase +QUADSPI_RSER ); + +list_for_each_entry (t, &m->transfers, transfer_list) { +if (t->rx_buf) + rx_buf = t->rx_buf; + xfer_num++; + } + +if (!rx_buf) +fsl_qspi_write_trans (master, m, xfer_num); +else +fsl_qspi_read_trans (master, m, xfer_num); + +return m->status; +}
drivers/spi/spi-fsl-quadspi.c line 402
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+ +static int fsl_qspi_setup (struct spi_device *spi) +{ +u32 reg_val, smpr_val, seq_id; +struct fsl_qspi *fsl_qspi; + + fsl_qspi =spi_master_get_devdata (spi->master); + +if ((spi->bits_per_word <8 ) || (spi->bits_per_word >16 )) { + dev_dbg(&spi->dev, "%d bits per word is not supported\n",
dev_err
drivers/spi/spi-fsl-quadspi.c line 408
Quoted 6 lines
drivers/spi/spi-fsl-quadspi.c new file +6
-0+ spi->bits_per_word); +return -EINVAL ; + } + +if (spi->chip_select >= spi->master->num_chipselect) { + dev_dbg(&spi->dev, "%d chip select is out of range\n",
Ditto
Quoted 48 lines
drivers/spi/spi-fsl-quadspi.c new file +48
-0+ spi->chip_select); +return -EINVAL ; + } + +writel (QSPI_MCR_RESERVED_MASK |QSPI_MCR_MDIS_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); + + reg_val =readl (fsl_qspi->iobase +QUADSPI_SMPR ); + +writel (reg_val & ~(QSPI_SMPR_FSDLY_MASK + |QSPI_SMPR_FSPHS_MASK + |QSPI_SMPR_HSENA_MASK ), + fsl_qspi->iobase +QUADSPI_SMPR ); + +writel (QSPI_MCR_RESERVED_MASK , fsl_qspi->iobase +QUADSPI_MCR ); + +writel (TPADA |PSP_QSPI0_MEMMAP_BASE , + fsl_qspi->iobase +QUADSPI_SFA1AD ); +writel (TPADA |PSP_QSPI0_MEMMAP_BASE , + fsl_qspi->iobase +QUADSPI_SFA2AD ); +writel (TPADB |PSP_QSPI0_MEMMAP_BASE , + fsl_qspi->iobase +QUADSPI_SFB1AD ); +writel (TPADB |PSP_QSPI0_MEMMAP_BASE , + fsl_qspi->iobase +QUADSPI_SFB2AD ); + +set_lut (fsl_qspi); + + reg_val =0 ; + reg_val |=QSPI_MCR_RESERVED_MASK ; + smpr_val =readl (fsl_qspi->iobase +QUADSPI_SMPR ); + smpr_val &= ~QSPI_SMPR_DDRSMP_MASK ; +writel (smpr_val, fsl_qspi->iobase +QUADSPI_SMPR ); + reg_val &= ~QSPI_MCR_DDR_EN_MASK ; +writel (reg_val, fsl_qspi->iobase +QUADSPI_MCR ); + + seq_id =0 ; + reg_val =readl (fsl_qspi->iobase +QUADSPI_BFGENCR ); + reg_val &= ~QSPI_BFGENCR_SEQID_MASK ; + reg_val |= (seq_id <<QSPI_BFGENCR_SEQID_SHIFT ); + reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK ; +writel (reg_val, fsl_qspi->iobase +QUADSPI_BFGENCR ); + +return 0 ; +} + +static int fsl_qspi_probe (struct platform_device *pdev) +{ +struct device_node *np = pdev->dev.of_node;
drivers/spi/spi-fsl-quadspi.c line 466
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+struct spi_master *master; +struct fsl_qspi *fsl_qspi; +struct resource *res; +int ret, num_cs, status =0 ; +struct clk *gate; + +if (!np) { +dev_err (&pdev->dev,"can't get the platform data\n" ); +return -EINVAL ; + }
The driver supports DT probe only. We can not get here at all if the np is NULL. The check is meaningless.
drivers/spi/spi-fsl-quadspi.c line 472
Quoted 6 lines
drivers/spi/spi-fsl-quadspi.c new file +6
-0+ + ret =of_property_read_u32 (np,"fsl,spi-num-chipselects" , &num_cs); +if (ret <0 ) { +dev_err (&pdev->dev,"can't get the spi-mum-chipselects\n" ); +return ret; + }
If you move the block somewhere after spi_alloc_master() call, you can use master->num_chipselect directly, and save one local variable and one assignment.
drivers/spi/spi-fsl-quadspi.c line 476
Quoted 4 lines
drivers/spi/spi-fsl-quadspi.c new file +4
-0+ + master =spi_alloc_master (&pdev->dev,sizeof (*fsl_qspi)); +if (master ==NULL ) { +dev_dbg (&pdev->dev,"spi_alloc_master failed\n" );
It hits an error condition. We should use dev_err().
drivers/spi/spi-fsl-quadspi.c line 487
Quoted 11 lines
drivers/spi/spi-fsl-quadspi.c new file +11
-0+return -ENOMEM ; + } + + fsl_qspi =spi_master_get_devdata (master); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) { +dev_dbg (&pdev->dev,"platform_get_resource failed\n" ); + status = -ENXIO ; + goto fail0; + }
devm_ioremap_resource() covers the error checking, so we can save it. Check kerenldoc of function devm_ioremap_resource() for usage example.
drivers/spi/spi-fsl-quadspi.c line 492
Quoted 5 lines
drivers/spi/spi-fsl-quadspi.c new file +5
-0+ + fsl_qspi->iobase =devm_ioremap_resource (&pdev->dev, res); +if (!fsl_qspi->iobase) { +dev_dbg (&pdev->dev,"ioremap failed\n" ); + status = -ENOMEM ;
We should return the error code returned by devm_ioremap_resource(). Again, check usage example in devm_ioremap_resource kerenldoc.
Nit, we generally name the variable used for return as "ret".
drivers/spi/spi-fsl-quadspi.c line 493
Quoted 1 line
drivers/spi/spi-fsl-quadspi.c new file +1
-0+ goto fail0;
Can we name the label in a meaningful way, like out_put_master or something?
drivers/spi/spi-fsl-quadspi.c line 499
Quoted 6 lines
drivers/spi/spi-fsl-quadspi.c new file +6
-0+ } + + gate =devm_clk_get (&pdev->dev,"qspi_en" ); +if (IS_ERR (gate)) { +dev_dbg (&pdev->dev,"clk_get failed\n" ); + status =PTR_ERR (fsl_qspi->clk);
Shouldn't be PTR_ERR(gate)? Also why it can be a local variable while the "qspi" clk below is a member variable of fsl_qspi.
drivers/spi/spi-fsl-quadspi.c line 502
Quoted 3 lines
drivers/spi/spi-fsl-quadspi.c new file +3
-0+ goto fail0; + } +clk_prepare_enable (gate);
The function call can fail. Error check?
drivers/spi/spi-fsl-quadspi.c line 512
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+ + fsl_qspi->clk =devm_clk_get (&pdev->dev,"qspi" ); +if (IS_ERR (fsl_qspi->clk)) { +dev_dbg (&pdev->dev,"clk_get failed\n" ); + status =PTR_ERR (fsl_qspi->clk); + goto fail1; + } +clk_prepare_enable (fsl_qspi->clk); + + fsl_qspi->irq =platform_get_irq (pdev,0 );
It seems to me that the "irq" can simply be a local variable?
drivers/spi/spi-fsl-quadspi.c line 515
Quoted 3 lines
drivers/spi/spi-fsl-quadspi.c new file +3
-0+if (fsl_qspi->irq <0 ) { +dev_dbg (&pdev->dev,"platform_get_irq failed\n" ); + status = -ENXIO ;
fsl_qspi->irq is just the error code we should return here.
Quoted 22 lines
drivers/spi/spi-fsl-quadspi.c new file +22
-0+ goto fail2; + } + + status =devm_request_irq (&pdev->dev, fsl_qspi->irq, + fsl_qspi_irq_handler,0 , pdev->name, fsl_qspi); +if (status) { +dev_dbg (&pdev->dev,"request_irq failed\n" ); + goto fail2; + } + +init_timer (&fsl_qspi->wait_timer); + fsl_qspi->wait_timer.function = &wait_do_timer; + fsl_qspi->wait_timer.data = (unsigned long )fsl_qspi; + fsl_qspi->timeout = false; + +init_waitqueue_head (&fsl_qspi->waitq); + fsl_qspi->dev = &pdev->dev; + + master->bus_num = pdev->id; + master->num_chipselect = num_cs; + master->dev.of_node = pdev->dev.of_node; +
drivers/spi/spi-fsl-quadspi.c line 547
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+ master->setup = fsl_qspi_setup; + master->transfer_one_message = fsl_qspi_do_one_msg; +platform_set_drvdata (pdev, master); + + status =spi_register_master (master); +if (status) { +dev_dbg (&pdev->dev,"spi_register_master failed\n" ); + goto fail2; + } +dev_info (&pdev->dev,"QuadSpi bus driver\n" );
Nit: I'm more comfortable with spelling it "QuadSPI", which is how Reference Manual spells.
drivers/spi/spi-fsl-quadspi.c line 558
Quoted 11 lines
drivers/spi/spi-fsl-quadspi.c new file +11
-0+ +return 0 ; + +fail2: +clk_disable_unprepare (fsl_qspi->clk); +fail1: +clk_disable_unprepare (gate); +fail0: +spi_master_put (master); + +dev_dbg (&pdev->dev,"Fsl QuadSpi probe failed\n" );
Nit: Either "FSL" or "Freescale" looks better than "Fsl" to me.
Quoted 11 lines
drivers/spi/spi-fsl-quadspi.c new file +11
-0+ +return status; +} + +static int fsl_qspi_remove (struct platform_device *pdev) +{ +struct spi_master *master =platform_get_drvdata (pdev); +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); + +/* disable the hardware */ +writel (0x0 , fsl_qspi->iobase +QUADSPI_MCR );
drivers/spi/spi-fsl-quadspi.c line 579
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+writel (0x0 , fsl_qspi->iobase +QUADSPI_RSER ); + +clk_disable_unprepare (fsl_qspi->clk); +spi_master_put (master); + +return 0 ; +} + +static struct of_device_id fsl_qspi_dt_ids[] = { + { .compatible ="fsl,vf610-qspi" , .data =NULL , },
.data has been initialized to NULL.
Quoted 27 lines
drivers/spi/spi-fsl-quadspi.c new file +16
-0+ {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, fsl_qspi_dt_ids); + +static struct platform_driver fsl_qspi_driver = { + .driver.name =DRIVER_NAME , + .driver.of_match_table = fsl_qspi_dt_ids, + .driver.owner =THIS_MODULE , + .probe = fsl_qspi_probe, + .remove = fsl_qspi_remove, +}; +module_platform_driver (fsl_qspi_driver); + +MODULE_DESCRIPTION ("Freescale QuadSPI Controller Driver" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_ALIAS ("platform:" DRIVER_NAME );drivers/spi/spi-fsl-quadspi.h new file +5
-0@@ -0,0 +1,167 @@ +/* +* Freescale Quad SPI driver. +* +* Copyright 2012-2013 Freescale Semiconductor, Inc. +*
drivers/spi/spi-fsl-quadspi.h line 15
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.h new file +10
-0+* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +*/ + +#ifndef __SPI_FSL_QSPI_H__ +#define __SPI_FSL_QSPI_H__ + +#define DRIVER_NAME "fsl-qspi"
I'm not strong on this. But I think it would be better if we have the driver name matches file name. Considering the abbr qspi is already used in the compatible string, we may name all the files and definitions in "qspi" (you already did this expect file names and register names below.) It makes some sense to me since even hardware spec uses this abbr somewhere.
Quad SPI can still be used as the formal name of the block in Kconfig help text, binding doc etc.
drivers/spi/spi-fsl-quadspi.h line 18
Quoted 3 lines
drivers/spi/spi-fsl-quadspi.h new file +3
-0+ +/* Quad SPI Controller*/ +#define QUADSPI_MCR (0x00)
No need of parentheses for such constant.
Quoted 113 lines
drivers/spi/spi-fsl-quadspi.h new file +113
-0+#define QUADSPI_IPCR (0x08) +#define QUADSPI_BFGENCR (0x20) +#define QUADSPI_SFAR (0x100) +#define QUADSPI_SMPR (0x108) +#define QUADSPI_RBSR (0x10c) +#define QUADSPI_RBCT (0x110) +#define QUADSPI_TBSR (0x150) +#define QUADSPI_TBDR (0x154) +#define QUADSPI_SR (0x15c) +#define QUADSPI_FR (0x160) +#define QUADSPI_SFA1AD (0x180) +#define QUADSPI_SFA2AD (0x184) +#define QUADSPI_SFB1AD (0x188) +#define QUADSPI_SFB2AD (0x18c) +#define QUADSPI_RBDR (0x200) +#define QUADSPI_LUTKEY (0x300) +#define QUADSPI_LCKCR (0x304) +#define QUADSPI_RSER (0x164) +#define KEY_VALUE (0x5AF05AF0) +#define QUADSPI_LUT (x) (0x310 + (x) * 4) + +#define INT_TFIE (0x1 << 0) +#define TPADA (0x1 << 24) +#define TPADB (0x1 << 25) + +/* Field definitions for LCKCR */ +#define QSPI_LCKCR_LOCK (0x1) +#define QSPI_LCKCR_UNLOCK (0x2) + +/* Field definitions for RBSR */ +#define QSPI_RBSR_RDBFL_SHIFT (8) +#define QSPI_RBSR_RDBFL_MASK (0x3F << QSPI_RBSR_RDBFL_SHIFT) + +/* Field definitions for RBCT */ +#define QSPI_RBCT_WMRK_MASK (0x1F) +#define QSPI_RBCT_RXBRD_SHIFT (8) +#define QSPI_RBCT_RXBRD_USEIPS (0x1 << QSPI_RBCT_RXBRD_SHIFT) + +/* Field definitions for MCR */ +#define QSPI_MCR_MDIS_SHIFT (14) +#define QSPI_MCR_MDIS_MASK (1 << QSPI_MCR_MDIS_SHIFT) +#define QSPI_MCR_CLR_TXF_SHIFT (11) +#define QSPI_MCR_CLR_TXF_MASK (1 << QSPI_MCR_CLR_TXF_SHIFT) +#define QSPI_MCR_CLR_RXF_SHIFT (10) +#define QSPI_MCR_CLR_RXF_MASK (1 << QSPI_MCR_CLR_RXF_SHIFT) +#define QSPI_MCR_DDR_EN_SHIFT (7) +#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT) +#define QSPI_MCR_RESERVED_SHIFT (16) +#define QSPI_MCR_RESERVED_MASK (0xF << QSPI_MCR_RESERVED_SHIFT) + +/* Field definitions for SMPR */ +#define QSPI_SMPR_DDRSMP_SHIFT (16) +#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT) +#define QSPI_SMPR_FSDLY_SHIFT (6) +#define QSPI_SMPR_FSDLY_MASK (1 << QSPI_SMPR_FSDLY_SHIFT) +#define QSPI_SMPR_FSPHS_SHIFT (5) +#define QSPI_SMPR_FSPHS_MASK (1 << QSPI_SMPR_FSPHS_SHIFT) +#define QSPI_SMPR_HSENA_SHIFT (0) +#define QSPI_SMPR_HSENA_MASK (1 << QSPI_SMPR_HSENA_SHIFT) + +/* Field definitions for BFGENCR */ +#define QSPI_BFGENCR_PAR_EN_SHIFT (16) +#define QSPI_BFGENCR_PAR_EN_MASK (1 << (QSPI_BFGENCR_PAR_EN_SHIFT)) +#define QSPI_BFGENCR_SEQID_SHIFT (12) +#define QSPI_BFGENCR_SEQID_MASK (0xF << QSPI_BFGENCR_SEQID_SHIFT) + +/* Field definitions for SR */ +#define QSPI_SR_TXFULL_SHIFT (27) +#define QSPI_SR_TXFULL_MASK (1 << QSPI_SR_TXFULL_SHIFT) +#define QSPI_SR_AHBTRN_SHIFT (6) +#define QSPI_SR_AHBTRN_MASK (1 << QSPI_SR_AHBTRN_SHIFT) +#define QSPI_SR_AHB_ACC_SHIFT (2) +#define QSPI_SR_AHB_ACC_MASK (1 << QSPI_SR_AHB_ACC_SHIFT) +#define QSPI_SR_IP_ACC_SHIFT (1) +#define QSPI_SR_IP_ACC_MASK (1 << QSPI_SR_IP_ACC_SHIFT) +#define QSPI_SR_BUSY_SHIFT (0) +#define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT) + +/* Field definitions for FR */ +#define QSPI_FR_TFF_MASK (0x1) + +/* Seqid */ +#define WEN_SEQID (1) +#define READSTATU_SEQID (3) +#define TX_SEQID (8) +#define RX_SEQID (9) + +/* Field definitions for IPCR */ +#define QSPI_IPCR_SEQID_SHIFT (24) +#define QSPI_IPCR_SEQID_MASK (0xF << QSPI_IPCR_SEQID_SHIFT) +#define OPRND0_SHIFT (0) +#define OPRND0 (x) ((x) << (OPRND0_SHIFT)) +#define PAD0_SHIFT (8) +#define PAD0 (x) ((x) << (PAD0_SHIFT)) +#define INSTR0_SHIFT (10) +#define INSTR0 (x) ((x) << (INSTR0_SHIFT)) +#define OPRND1_SHIFT (16) +#define OPRND1 (x) ((x) << (OPRND1_SHIFT)) +#define PAD1_SHIFT (24) +#define PAD1 (x) ((x) << (PAD1_SHIFT)) +#define INSTR1_SHIFT (26) +#define INSTR1 (x) ((x) << (INSTR1_SHIFT)) + +/* instruction set */ +#define CMD (1) +#define ADDR (2) +#define ADDR24BIT (0x18) +#define DUMMY (3) +#define MODE (4) +#define MODE2 (5) +#define MODE4 (6) +#define READ (7) +#define WRITE (8)
drivers/spi/spi-fsl-quadspi.h line 141
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.h new file +10
-0+#define JMP_ON_CS (9) +#define ADDR_DDR (10) +#define MODE_DDR (11) +#define MODE2_DDR (12) +#define MODE4_DDR (13) + +#define endian_change_32bit (A ) ((((u32)(A) & 0xFF000000) >> 24) | \ + (((u32)(A) & 0x00FF0000) >> 8) | \ + (((u32)(A) & 0x0000FF00) << 8) | \ + (((u32)(A) & 0x000000FF) << 24))
The macros defined in include/linux/byteorder/generic.h can help, I think.
Shawn
Quoted 30 lines
drivers/spi/spi-fsl-quadspi.h new file +26
-0+ +#define PSP_QSPI0_MEMMAP_BASE (0x20000000) +#define RX_BUFFER_SIZE (0x80) +#define TX_BUFFER_SIZE (0x40) +#define POS_LOCATION_MASK (0xFFFFFF00) +#define STATUS_BIT (24) +#define VALID_STATUS_BIT (0) +#define READ_STATUS_TIMEOUT (5000) +#define WRITE_ENABLE_BIT (25) +#define VALID_WRITE_ENABLE_BIT (1) +#define WRITE_ENABLE_TIMEOUT (10) + +struct fsl_qspi { +void __iomem *iobase; +int irq; +struct clk *clk; +u32 quad_mode; +u32 select_cs; +struct device *dev; + +wait_queue_head_t waitq; +struct timer_list wait_timer; +bool timeout; +}; + +#endif Signature · 1 line
1.8.0
PATCH 2/2 spi: Add Freescale QuadSpi driver
In reply to Xiaochun LiQuoted 5 lines · Xiaochun Li
Add QuadSpi driver for Freescale's Quad Spi controller. This controller is designed for serial flash access.
This driver has been tested on vf610-twr board with m25p80 type chips. The hardware has no support for other types of spi peripherals. Chip select control is handled via Serial Flash Address Register.
This really needs serious rework. If possible find someone in your company who can help you with this driver.
drivers/spi/spi-fsl-quadspi.c line 33
Quoted 4 lines
drivers/spi/spi-fsl-quadspi.c new file +4
-0+static inline unsigned int fsl_qspi_check_status (struct fsl_qspi *fsl_qspi) +{ +return readl (fsl_qspi->iobase +QUADSPI_SR ) &QSPI_SR_BUSY_MASK ; +}
What does a function calles check_status return? Does it return "Yes, I'm busy" or does it return "Yes, I'm idle". Use fsl_qspi_is_busy or fsl_qspi_is_idle instead.
Quoted 5 lines
drivers/spi/spi-fsl-quadspi.c new file +5
-0+static irqreturn_t fsl_qspi_irq_handler (int this_irq,void *dev_id) +{ +struct fsl_qspi *fsl_qspi = dev_id; +u32 reg_fr =readl (fsl_qspi->iobase +QUADSPI_FR ); +
drivers/spi/spi-fsl-quadspi.c line 60
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+/* clear interrupt */ +writel (reg_fr, fsl_qspi->iobase +QUADSPI_FR ); +if (reg_fr &QSPI_FR_TFF_MASK ) +wake_up (&fsl_qspi->waitq); + +return IRQ_HANDLED ; +} + +static void set_lut (struct fsl_qspi *fsl_qspi) +{
Consistently add a fsl_qspi_ namespace to all functions in this driver.
Quoted 19 lines
drivers/spi/spi-fsl-quadspi.c new file +19
-0+static void waiting_for_end (struct fsl_qspi *fsl_qspi, +u32 current_bit,u32 bitvalue,u32 timeout) +{ +u32 reg, status_reg; + + fsl_qspi->wait_timer.expires = jiffies + timeout; +add_timer (&fsl_qspi->wait_timer); + + status_reg = !bitvalue << current_bit; +while ((status_reg & (0x1 << current_bit)) != bitvalue << current_bit) { +if (fsl_qspi->timeout) { +dev_err (fsl_qspi->dev,"tired waiting for end status\n" ); +break ; + } +writel ((READSTATU_SEQID <<QSPI_IPCR_SEQID_SHIFT ) |1 , + fsl_qspi->iobase +QUADSPI_IPCR ); +wait_event (fsl_qspi->waitq, !fsl_qspi_check_status (fsl_qspi)); + + reg =readl (fsl_qspi->iobase +QUADSPI_RBSR );
drivers/spi/spi-fsl-quadspi.c line 116
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+if (reg &QSPI_RBSR_RDBFL_MASK ) + status_reg =readl (fsl_qspi->iobase + +QUADSPI_RBDR ); + +writel (readl (fsl_qspi->iobase +QUADSPI_MCR ) | +QSPI_MCR_CLR_RXF_MASK , + fsl_qspi->iobase +QUADSPI_MCR ); + } +del_timer (&fsl_qspi->wait_timer); +}
What the hell are you doing here??
You have interrupts. Use them! Interrupts are for triggering actions, not for polling until they happen. The driver logic is completely wrong.
Each wait_event possibly deadlocks the driver. Don't do this. Also each wait_event is either unnecessary in this context or means that there is an interrupt. I lost track how many wait_events you have in your execution path, but get rid of them all.
drivers/spi/spi-fsl-quadspi.c line 332
Quoted 12 lines
drivers/spi/spi-fsl-quadspi.c new file +12
-0+static void fsl_qspi_read_trans (struct spi_master *master, +struct spi_message *msg,u32 num) +{ +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); +struct spi_transfer *xfer; +u32 tx_len =0 , trans_counter =0 , mcr_reg; +u8 opr =0 ; +loff_t pos =0 ; +int status =0 ; + +list_for_each_entry (xfer, &msg->transfers, transfer_list) { +
Why do you have two function which both iterate over all transfers of a message?
To clean this up start with a function which handles one transfer. Then add one function which iterates over all transfers and calls the transfer function.
Then, since your hardware doesn't seem to be able to handle spi messages directly you should probably use the bitbanging helpers instead of implementing a master directly.
drivers/spi/spi-fsl-quadspi.c line 346
Quoted 3 lines
drivers/spi/spi-fsl-quadspi.c new file +3
-0+ +if (xfer->rx_buf && trans_counter >0 ) { +set_receive_lut (fsl_qspi, opr, num, xfer->len, tx_len);
set_receive_lut is not at all interested in the number of transfers. What it wants to know is whether this transfer is the last one of a message...
drivers/spi/spi-fsl-quadspi.c line 383
Quoted 11 lines
drivers/spi/spi-fsl-quadspi.c new file +11
-0+struct spi_transfer *t; +u8 *rx_buf =NULL ; +unsigned int xfer_num =0 ; +struct fsl_qspi *fsl_qspi =spi_master_get_devdata (master); + +writel (INT_TFIE , fsl_qspi->iobase +QUADSPI_RSER ); + +list_for_each_entry (t, &m->transfers, transfer_list) { +if (t->rx_buf) + rx_buf = t->rx_buf; + xfer_num++;
...which means that you no longer have to count the number of transfers here.
drivers/spi/spi-fsl-quadspi.c line 389
Quoted 6 lines
drivers/spi/spi-fsl-quadspi.c new file +6
-0+ } + +if (!rx_buf) +fsl_qspi_write_trans (master, m, xfer_num); +else +fsl_qspi_read_trans (master, m, xfer_num);
There shouldn't be any need to distinguish between messages with no read transfers and messages with at least one read transfer. Get rid of this.
Quoted 12 lines
drivers/spi/spi-fsl-quadspi.c new file +12
-0+ +return m->status; +} + +static int fsl_qspi_setup (struct spi_device *spi) +{ +u32 reg_val, smpr_val, seq_id; +struct fsl_qspi *fsl_qspi; + + fsl_qspi =spi_master_get_devdata (spi->master); + +if ((spi->bits_per_word <8 ) || (spi->bits_per_word >16 )) {
drivers/spi/spi-fsl-quadspi.c line 411
Quoted 10 lines
drivers/spi/spi-fsl-quadspi.c new file +10
-0+dev_dbg (&spi->dev,"%d bits per word is not supported\n" , + spi->bits_per_word); +return -EINVAL ; + } + +if (spi->chip_select >= spi->master->num_chipselect) { +dev_dbg (&spi->dev,"%d chip select is out of range\n" , + spi->chip_select); +return -EINVAL ; + }
This will never happen. The spi core checks this in spi_add_device.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |