Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af211211 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/fix/bcm2835', 'spi/fix/bitbang',...

Merge remote-tracking branches 'spi/fix/bcm2835', 'spi/fix/bitbang', 'spi/fix/img-spfi', 'spi/fix/omap2-mcspi', 'spi/fix/orion' and 'spi/fix/xilinx' into spi-linus
Loading
Loading
Loading
Loading
+29 −9
Original line number Diff line number Diff line
@@ -480,7 +480,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
					 struct spi_device *spi,
					 struct spi_transfer *tfr,
					 u32 cs,
					 unsigned long xfer_time_us)
					 unsigned long long xfer_time_us)
{
	struct bcm2835_spi *bs = spi_master_get_devdata(master);
	unsigned long timeout;
@@ -531,7 +531,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
{
	struct bcm2835_spi *bs = spi_master_get_devdata(master);
	unsigned long spi_hz, clk_hz, cdiv;
	unsigned long spi_used_hz, xfer_time_us;
	unsigned long spi_used_hz;
	unsigned long long xfer_time_us;
	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

	/* set clock */
@@ -553,13 +554,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
	spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
	bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);

	/* handle all the modes */
	/* handle all the 3-wire mode */
	if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
		cs |= BCM2835_SPI_CS_REN;
	if (spi->mode & SPI_CPOL)
		cs |= BCM2835_SPI_CS_CPOL;
	if (spi->mode & SPI_CPHA)
		cs |= BCM2835_SPI_CS_CPHA;
	else
		cs &= ~BCM2835_SPI_CS_REN;

	/* for gpio_cs set dummy CS so that no HW-CS get changed
	 * we can not run this in bcm2835_spi_set_cs, as it does
@@ -575,9 +574,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
	bs->rx_len = tfr->len;

	/* calculate the estimated time in us the transfer runs */
	xfer_time_us = tfr->len
	xfer_time_us = (unsigned long long)tfr->len
		* 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
		* 1000000 / spi_used_hz;
		* 1000000;
	do_div(xfer_time_us, spi_used_hz);

	/* for short requests run polling*/
	if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
@@ -592,6 +592,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
	return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
}

static int bcm2835_spi_prepare_message(struct spi_master *master,
				       struct spi_message *msg)
{
	struct spi_device *spi = msg->spi;
	struct bcm2835_spi *bs = spi_master_get_devdata(master);
	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

	cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);

	if (spi->mode & SPI_CPOL)
		cs |= BCM2835_SPI_CS_CPOL;
	if (spi->mode & SPI_CPHA)
		cs |= BCM2835_SPI_CS_CPHA;

	bcm2835_wr(bs, BCM2835_SPI_CS, cs);

	return 0;
}

static void bcm2835_spi_handle_err(struct spi_master *master,
				   struct spi_message *msg)
{
@@ -739,6 +758,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
	master->set_cs = bcm2835_spi_set_cs;
	master->transfer_one = bcm2835_spi_transfer_one;
	master->handle_err = bcm2835_spi_handle_err;
	master->prepare_message = bcm2835_spi_prepare_message;
	master->dev.of_node = pdev->dev.of_node;

	bs = spi_master_get_devdata(master);
+2 −2
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
{
	/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */

	bool oldbit = !(word & 1);
	u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
	/* clock starts at inactive polarity */
	for (word <<= (32 - bits); likely(bits); bits--) {

@@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
{
	/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */

	bool oldbit = !(word & (1 << 31));
	u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
	/* clock starts at inactive polarity */
	for (word <<= (32 - bits); likely(bits); bits--) {

+46 −13
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@ struct img_spfi {
	bool rx_dma_busy;
};

struct img_spfi_device_data {
	bool gpio_requested;
};

static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{
	return readl(spfi->regs + reg);
@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master,
		cpu_relax();
	}

	ret = spfi_wait_all_done(spfi);
	if (ret < 0)
		return ret;

	if (rx_bytes > 0 || tx_bytes > 0) {
		dev_err(spfi->dev, "PIO transfer timed out\n");
		return -ETIMEDOUT;
	}

	ret = spfi_wait_all_done(spfi);
	if (ret < 0)
		return ret;

	return 0;
}

@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master,

static int img_spfi_setup(struct spi_device *spi)
{
	int ret;
	int ret = -EINVAL;
	struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);

	ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
	if (!spfi_data) {
		spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
		if (!spfi_data)
			return -ENOMEM;
		spfi_data->gpio_requested = false;
		spi_set_ctldata(spi, spfi_data);
	}
	if (!spfi_data->gpio_requested) {
		ret = gpio_request_one(spi->cs_gpio,
				       (spi->mode & SPI_CS_HIGH) ?
				       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
				       dev_name(&spi->dev));
		if (ret)
			dev_err(&spi->dev, "can't request chipselect gpio %d\n",
				spi->cs_gpio);
		else
			spfi_data->gpio_requested = true;
	} else {
		if (gpio_is_valid(spi->cs_gpio)) {
			int mode = ((spi->mode & SPI_CS_HIGH) ?
				    GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);

			ret = gpio_direction_output(spi->cs_gpio, mode);
			if (ret)
				dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
					spi->cs_gpio, ret);
		}
	}
	return ret;
}

static void img_spfi_cleanup(struct spi_device *spi)
{
	struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);

	if (spfi_data) {
		if (spfi_data->gpio_requested)
			gpio_free(spi->cs_gpio);
		kfree(spfi_data);
		spi_set_ctldata(spi, NULL);
	}
}

static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
+10 −0
Original line number Diff line number Diff line
@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)

static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{
	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
	u32 l;

	/* The controller handles the inverted chip selects
@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
		enable = !enable;

	if (spi->controller_state) {
		int err = pm_runtime_get_sync(mcspi->dev);
		if (err < 0) {
			dev_err(mcspi->dev, "failed to get sync: %d\n", err);
			return;
		}

		l = mcspi_cached_chconf0(spi);

		if (enable)
@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
			l |= OMAP2_MCSPI_CHCONF_FORCE;

		mcspi_write_chconf0(spi, l);

		pm_runtime_mark_last_busy(mcspi->dev);
		pm_runtime_put_autosuspend(mcspi->dev);
	}
}

+53 −1
Original line number Diff line number Diff line
@@ -41,6 +41,11 @@
#define ORION_SPI_DATA_OUT_REG		0x08
#define ORION_SPI_DATA_IN_REG		0x0c
#define ORION_SPI_INT_CAUSE_REG		0x10
#define ORION_SPI_TIMING_PARAMS_REG	0x18

#define ORION_SPI_TMISO_SAMPLE_MASK	(0x3 << 6)
#define ORION_SPI_TMISO_SAMPLE_1	(1 << 6)
#define ORION_SPI_TMISO_SAMPLE_2	(2 << 6)

#define ORION_SPI_MODE_CPOL		(1 << 11)
#define ORION_SPI_MODE_CPHA		(1 << 12)
@@ -70,6 +75,7 @@ struct orion_spi_dev {
	unsigned int		min_divisor;
	unsigned int		max_divisor;
	u32			prescale_mask;
	bool			is_errata_50mhz_ac;
};

struct orion_spi {
@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi)
	writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
}

static void
orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
{
	u32 reg;
	struct orion_spi *orion_spi;

	orion_spi = spi_master_get_devdata(spi->master);

	/*
	 * Erratum description: (Erratum NO. FE-9144572) The device
	 * SPI interface supports frequencies of up to 50 MHz.
	 * However, due to this erratum, when the device core clock is
	 * 250 MHz and the SPI interfaces is configured for 50MHz SPI
	 * clock and CPOL=CPHA=1 there might occur data corruption on
	 * reads from the SPI device.
	 * Erratum Workaround:
	 * Work in one of the following configurations:
	 * 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
	 * Register".
	 * 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
	 * Register" before setting the interface.
	 */
	reg = readl(spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
	reg &= ~ORION_SPI_TMISO_SAMPLE_MASK;

	if (clk_get_rate(orion_spi->clk) == 250000000 &&
			speed == 50000000 && spi->mode & SPI_CPOL &&
			spi->mode & SPI_CPHA)
		reg |= ORION_SPI_TMISO_SAMPLE_2;
	else
		reg |= ORION_SPI_TMISO_SAMPLE_1; /* This is the default value */

	writel(reg, spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
}

/*
 * called only when no transfer is active on the bus
 */
@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)

	orion_spi_mode_set(spi);

	if (orion_spi->devdata->is_errata_50mhz_ac)
		orion_spi_50mhz_ac_timing_erratum(spi, speed);

	rc = orion_spi_baudrate_set(spi, speed);
	if (rc)
		return rc;
@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = {
	.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
};

static const struct orion_spi_dev armada_380_spi_dev_data = {
	.typ = ARMADA_SPI,
	.max_hz = 50000000,
	.max_divisor = 1920,
	.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
	.is_errata_50mhz_ac = true,
};

static const struct of_device_id orion_spi_of_match_table[] = {
	{
		.compatible = "marvell,orion-spi",
@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = {
	},
	{
		.compatible = "marvell,armada-380-spi",
		.data = &armada_xp_spi_dev_data,
		.data = &armada_380_spi_dev_data,
	},
	{
		.compatible = "marvell,armada-390-spi",
Loading