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

Commit d9c73bb8 authored by Baruch Siach's avatar Baruch Siach Committed by Mark Brown
Browse files

spi: dw: add support for gpio controlled chip select



Also, use this opportunity to let spi_chip_sel() handle chip-select
deactivation as well.

Signed-off-by: default avatarBaruch Siach <baruch@tkos.co.il>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 20e5ea19
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/spi/spi.h>
#include <linux/scatterlist.h>
#include <linux/module.h>
#include <linux/of_gpio.h>

#include "spi-dw.h"

@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
	dws->num_cs = 4;
	dws->max_freq = clk_get_rate(dwsmmio->clk);

	if (pdev->dev.of_node) {
		int i;

		for (i = 0; i < dws->num_cs; i++) {
			int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
					"cs-gpios", i);

			if (cs_gpio == -EPROBE_DEFER) {
				ret = cs_gpio;
				goto out;
			}

			if (gpio_is_valid(cs_gpio)) {
				ret = devm_gpio_request(&pdev->dev, cs_gpio,
						dev_name(&pdev->dev));
				if (ret)
					goto out;
			}
		}
	}

	ret = dw_spi_add_host(&pdev->dev, dws);
	if (ret)
		goto out;
+12 −6
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>

#include "spi-dw.h"

@@ -36,9 +37,6 @@
#define DONE_STATE	((void *)2)
#define ERROR_STATE	((void *)-1)

#define MRST_SPI_DEASSERT	0
#define MRST_SPI_ASSERT		1

/* Slave spi_dev related */
struct chip_data {
	u16 cr0;
@@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws)
	last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
					transfer_list);

	if (!last_transfer->cs_change && dws->cs_control)
		dws->cs_control(MRST_SPI_DEASSERT);
	if (!last_transfer->cs_change)
		spi_chip_sel(dws, dws->cur_msg->spi, 0);

	spi_finalize_current_message(dws->master);
}
@@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data)
			dw_writew(dws, DW_SPI_CTRL0, cr0);

		spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
		spi_chip_sel(dws, spi->chip_select);
		spi_chip_sel(dws, spi, 1);

		/* Set the interrupt mask, for poll mode just disable all int */
		spi_mask_intr(dws, 0xff);
@@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi)
{
	struct dw_spi_chip *chip_info = NULL;
	struct chip_data *chip;
	int ret;

	/* Only alloc on first setup */
	chip = spi_get_ctldata(spi);
@@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi)
			| (spi->mode  << SPI_MODE_OFFSET)
			| (chip->tmode << SPI_TMOD_OFFSET);

	if (gpio_is_valid(spi->cs_gpio)) {
		ret = gpio_direction_output(spi->cs_gpio,
				!(spi->mode & SPI_CS_HIGH));
		if (ret)
			return ret;
	}

	return 0;
}

+11 −5
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <linux/io.h>
#include <linux/scatterlist.h>
#include <linux/gpio.h>

/* Register offsets */
#define DW_SPI_CTRL0			0x00
@@ -178,14 +179,19 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
	dw_writel(dws, DW_SPI_BAUDR, div);
}

static inline void spi_chip_sel(struct dw_spi *dws, u16 cs)
static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi,
		int active)
{
	if (cs > dws->num_cs)
		return;
	u16 cs = spi->chip_select;
	int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
		!(spi->mode & SPI_CS_HIGH);

	if (dws->cs_control)
		dws->cs_control(1);
		dws->cs_control(active);
	if (gpio_is_valid(spi->cs_gpio))
		gpio_set_value(spi->cs_gpio, gpio_val);

	if (active)
		dw_writel(dws, DW_SPI_SER, 1 << cs);
}