diff options
Diffstat (limited to 'drivers/spi')
| -rw-r--r-- | drivers/spi/spi-armada-3700.c | 143 | ||||
| -rw-r--r-- | drivers/spi/spi-bcm-qspi.c | 9 | ||||
| -rw-r--r-- | drivers/spi/spi-stm32.c | 4 | ||||
| -rw-r--r-- | drivers/spi/spi.c | 13 | 
4 files changed, 63 insertions, 106 deletions
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 6c7d7a460689..568e1c65aa82 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -99,11 +99,6 @@  /* A3700_SPI_IF_TIME_REG */  #define A3700_SPI_CLK_CAPT_EDGE		BIT(7) -/* Flags and macros for struct a3700_spi */ -#define A3700_INSTR_CNT			1 -#define A3700_ADDR_CNT			3 -#define A3700_DUMMY_CNT			1 -  struct a3700_spi {  	struct spi_master *master;  	void __iomem *base; @@ -117,9 +112,6 @@ struct a3700_spi {  	u8 byte_len;  	u32 wait_mask;  	struct completion done; -	u32 addr_cnt; -	u32 instr_cnt; -	size_t hdr_cnt;  };  static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset) @@ -161,7 +153,7 @@ static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi,  }  static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, -				  unsigned int pin_mode) +				  unsigned int pin_mode, bool receiving)  {  	u32 val; @@ -177,6 +169,9 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,  		break;  	case SPI_NBITS_QUAD:  		val |= A3700_SPI_DATA_PIN1; +		/* RX during address reception uses 4-pin */ +		if (receiving) +			val |= A3700_SPI_ADDR_PIN;  		break;  	default:  		dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode); @@ -392,7 +387,8 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)  	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); -	return true; +	/* Timeout was reached */ +	return false;  }  static bool a3700_spi_transfer_wait(struct spi_device *spi, @@ -446,59 +442,43 @@ static void a3700_spi_set_cs(struct spi_device *spi, bool enable)  static void a3700_spi_header_set(struct a3700_spi *a3700_spi)  { -	u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0; +	unsigned int addr_cnt;  	u32 val = 0;  	/* Clear the header registers */  	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0);  	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0);  	spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0); +	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);  	/* Set header counters */  	if (a3700_spi->tx_buf) { -		if (a3700_spi->buf_len <= a3700_spi->instr_cnt) { -			instr_cnt = a3700_spi->buf_len; -		} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt + -						  a3700_spi->addr_cnt)) { -			instr_cnt = a3700_spi->instr_cnt; -			addr_cnt = a3700_spi->buf_len - instr_cnt; -		} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) { -			instr_cnt = a3700_spi->instr_cnt; -			addr_cnt = a3700_spi->addr_cnt; -			/* Need to handle the normal write case with 1 byte -			 * data -			 */ -			if (!a3700_spi->tx_buf[instr_cnt + addr_cnt]) -				dummy_cnt = a3700_spi->buf_len - instr_cnt - -					    addr_cnt; -		} -		val |= ((instr_cnt & A3700_SPI_INSTR_CNT_MASK) -			<< A3700_SPI_INSTR_CNT_BIT); -		val |= ((addr_cnt & A3700_SPI_ADDR_CNT_MASK) -			<< A3700_SPI_ADDR_CNT_BIT); -		val |= ((dummy_cnt & A3700_SPI_DUMMY_CNT_MASK) -			<< A3700_SPI_DUMMY_CNT_BIT); -	} -	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val); +		/* +		 * when tx data is not 4 bytes aligned, there will be unexpected +		 * bytes out of SPI output register, since it always shifts out +		 * as whole 4 bytes. This might cause incorrect transaction with +		 * some devices. To avoid that, use SPI header count feature to +		 * transfer up to 3 bytes of data first, and then make the rest +		 * of data 4-byte aligned. +		 */ +		addr_cnt = a3700_spi->buf_len % 4; +		if (addr_cnt) { +			val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK) +				<< A3700_SPI_ADDR_CNT_BIT; +			spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val); -	/* Update the buffer length to be transferred */ -	a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt); +			/* Update the buffer length to be transferred */ +			a3700_spi->buf_len -= addr_cnt; -	/* Set Instruction */ -	val = 0; -	while (instr_cnt--) { -		val = (val << 8) | a3700_spi->tx_buf[0]; -		a3700_spi->tx_buf++; -	} -	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, val); - -	/* Set Address */ -	val = 0; -	while (addr_cnt--) { -		val = (val << 8) | a3700_spi->tx_buf[0]; -		a3700_spi->tx_buf++; +			/* transfer 1~3 bytes through address count */ +			val = 0; +			while (addr_cnt--) { +				val = (val << 8) | a3700_spi->tx_buf[0]; +				a3700_spi->tx_buf++; +			} +			spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val); +		}  	} -	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);  }  static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi) @@ -512,35 +492,12 @@ static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)  static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)  {  	u32 val; -	int i = 0;  	while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) { -		val = 0; -		if (a3700_spi->buf_len >= 4) { -			val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf); -			spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); - -			a3700_spi->buf_len -= 4; -			a3700_spi->tx_buf += 4; -		} else { -			/* -			 * If the remained buffer length is less than 4-bytes, -			 * we should pad the write buffer with all ones. So that -			 * it avoids overwrite the unexpected bytes following -			 * the last one. -			 */ -			val = GENMASK(31, 0); -			while (a3700_spi->buf_len) { -				val &= ~(0xff << (8 * i)); -				val |= *a3700_spi->tx_buf++ << (8 * i); -				i++; -				a3700_spi->buf_len--; - -				spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, -					     val); -			} -			break; -		} +		val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf); +		spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); +		a3700_spi->buf_len -= 4; +		a3700_spi->tx_buf += 4;  	}  	return 0; @@ -645,15 +602,18 @@ static int a3700_spi_transfer_one(struct spi_master *master,  	a3700_spi->rx_buf  = xfer->rx_buf;  	a3700_spi->buf_len = xfer->len; -	/* SPI transfer headers */ -	a3700_spi_header_set(a3700_spi); -  	if (xfer->tx_buf)  		nbits = xfer->tx_nbits;  	else if (xfer->rx_buf)  		nbits = xfer->rx_nbits; -	a3700_spi_pin_mode_set(a3700_spi, nbits); +	a3700_spi_pin_mode_set(a3700_spi, nbits, xfer->rx_buf ? true : false); + +	/* Flush the FIFOs */ +	a3700_spi_fifo_flush(a3700_spi); + +	/* Transfer first bytes of data when buffer is not 4-byte aligned */ +	a3700_spi_header_set(a3700_spi);  	if (xfer->rx_buf) {  		/* Set read data length */ @@ -733,16 +693,11 @@ static int a3700_spi_transfer_one(struct spi_master *master,  				dev_err(&spi->dev, "wait wfifo empty timed out\n");  				return -ETIMEDOUT;  			} -		} else { -			/* -			 * If the instruction in SPI_INSTR does not require data -			 * to be written to the SPI device, wait until SPI_RDY -			 * is 1 for the SPI interface to be in idle. -			 */ -			if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) { -				dev_err(&spi->dev, "wait xfer ready timed out\n"); -				return -ETIMEDOUT; -			} +		} + +		if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) { +			dev_err(&spi->dev, "wait xfer ready timed out\n"); +			return -ETIMEDOUT;  		}  		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); @@ -834,10 +789,6 @@ static int a3700_spi_probe(struct platform_device *pdev)  	memset(spi, 0, sizeof(struct a3700_spi));  	spi->master = master; -	spi->instr_cnt = A3700_INSTR_CNT; -	spi->addr_cnt = A3700_ADDR_CNT; -	spi->hdr_cnt = A3700_INSTR_CNT + A3700_ADDR_CNT + -		       A3700_DUMMY_CNT;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	spi->base = devm_ioremap_resource(dev, res); diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 6ef6c44f39f5..a172ab299e80 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1250,7 +1250,7 @@ int bcm_qspi_probe(struct platform_device *pdev,  			goto qspi_probe_err;  		}  	} else { -		goto qspi_probe_err; +		goto qspi_resource_err;  	}  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi"); @@ -1272,7 +1272,7 @@ int bcm_qspi_probe(struct platform_device *pdev,  		qspi->base[CHIP_SELECT]  = devm_ioremap_resource(dev, res);  		if (IS_ERR(qspi->base[CHIP_SELECT])) {  			ret = PTR_ERR(qspi->base[CHIP_SELECT]); -			goto qspi_probe_err; +			goto qspi_resource_err;  		}  	} @@ -1280,7 +1280,7 @@ int bcm_qspi_probe(struct platform_device *pdev,  				GFP_KERNEL);  	if (!qspi->dev_ids) {  		ret = -ENOMEM; -		goto qspi_probe_err; +		goto qspi_resource_err;  	}  	for (val = 0; val < num_irqs; val++) { @@ -1369,8 +1369,9 @@ qspi_reg_err:  	bcm_qspi_hw_uninit(qspi);  	clk_disable_unprepare(qspi->clk);  qspi_probe_err: -	spi_master_put(master);  	kfree(qspi->dev_ids); +qspi_resource_err: +	spi_master_put(master);  	return ret;  }  /* probe function to be called by SoC specific platform driver probe */ diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 680cdf549506..ba9743fa2326 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -263,8 +263,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz)  	 * no need to check it there.  	 * However, we need to ensure the following calculations.  	 */ -	if ((div < SPI_MBR_DIV_MIN) && -	    (div > SPI_MBR_DIV_MAX)) +	if (div < SPI_MBR_DIV_MIN || +	    div > SPI_MBR_DIV_MAX)  		return -EINVAL;  	/* Determine the first power of 2 greater than or equal to div */ diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6e65524cbfd9..e8b5a5e21b2e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -45,7 +45,6 @@  #define CREATE_TRACE_POINTS  #include <trace/events/spi.h> -#define SPI_DYN_FIRST_BUS_NUM 0  static DEFINE_IDR(spi_master_idr); @@ -2086,7 +2085,7 @@ int spi_register_controller(struct spi_controller *ctlr)  	struct device		*dev = ctlr->dev.parent;  	struct boardinfo	*bi;  	int			status = -ENODEV; -	int			id; +	int			id, first_dynamic;  	if (!dev)  		return -ENODEV; @@ -2116,9 +2115,15 @@ int spi_register_controller(struct spi_controller *ctlr)  		}  	}  	if (ctlr->bus_num < 0) { +		first_dynamic = of_alias_get_highest_id("spi"); +		if (first_dynamic < 0) +			first_dynamic = 0; +		else +			first_dynamic++; +  		mutex_lock(&board_lock); -		id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0, -			       GFP_KERNEL); +		id = idr_alloc(&spi_master_idr, ctlr, first_dynamic, +			       0, GFP_KERNEL);  		mutex_unlock(&board_lock);  		if (WARN(id < 0, "couldn't get idr"))  			return id;  | 
