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

Commit 38ab18ca authored by Daniel Mack's avatar Daniel Mack Committed by Mark Brown
Browse files

spi: spi-gpio: Add DT bindings



This patch adds DT bindings to the spi-gpio driver and some
documentation about how to use it.

Signed-off-by: default avatarDaniel Mack <zonque@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 161c2dd3
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
SPI-GPIO devicetree bindings

Required properties:

 - compatible: should be set to "spi-gpio"
 - #address-cells: should be set to <0x1>
 - ranges
 - gpio-sck: GPIO spec for the SCK line to use
 - gpio-miso: GPIO spec for the MISO line to use
 - gpio-mosi: GPIO spec for the MOSI line to use
 - cs-gpios: GPIOs to use for chipselect lines
 - num-chipselects: number of chipselect lines

Example:

	spi {
		compatible = "spi-gpio";
		#address-cells = <0x1>;
		ranges;

		gpio-sck = <&gpio 95 0>;
		gpio-miso = <&gpio 98 0>;
		gpio-mosi = <&gpio 97 0>;
		cs-gpios = <&gpio 125 0>;
		num-chipselects = <1>;

		/* clients */
	};
+96 −3
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>

#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -232,13 +234,27 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)

static int spi_gpio_setup(struct spi_device *spi)
{
	unsigned int		cs = (unsigned int) spi->controller_data;
	unsigned int		cs;
	int			status = 0;
	struct spi_gpio		*spi_gpio = spi_to_spi_gpio(spi);
	struct device_node	*np = spi->master->dev.of_node;

	if (spi->bits_per_word > 32)
		return -EINVAL;

	if (np) {
		/*
		 * In DT environments, the CS GPIOs have already been
		 * initialized from the "cs-gpios" property of the node.
		 */
		cs = spi_gpio->cs_gpios[spi->chip_select];
	} else {
		/*
		 * ... otherwise, take it from spi->controller_data
		 */
		cs = (unsigned int) spi->controller_data;
	}

	if (!spi->controller_state) {
		if (cs != SPI_GPIO_NO_CHIPSELECT) {
			status = gpio_request(cs, dev_name(&spi->dev));
@@ -250,6 +266,7 @@ static int spi_gpio_setup(struct spi_device *spi)
	}
	if (!status) {
		status = spi_bitbang_setup(spi);
		/* in case it was initialized from static board data */
		spi_gpio->cs_gpios[spi->chip_select] = cs;
	}

@@ -326,6 +343,55 @@ spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label,
	return value;
}

#ifdef CONFIG_OF
static struct of_device_id spi_gpio_dt_ids[] = {
	{ .compatible = "spi-gpio" },
	{}
};
MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);

static int spi_gpio_probe_dt(struct platform_device *pdev)
{
	int ret;
	u32 tmp;
	struct spi_gpio_platform_data	*pdata;
	struct device_node *np = pdev->dev.of_node;
	const struct of_device_id *of_id =
			of_match_device(spi_gpio_dt_ids, &pdev->dev);

	if (!of_id)
		return 0;

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	pdata->sck = of_get_named_gpio(np, "gpio-sck", 0);
	pdata->miso = of_get_named_gpio(np, "gpio-miso", 0);
	pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0);

	ret = of_property_read_u32(np, "num-chipselects", &tmp);
	if (ret < 0) {
		dev_err(&pdev->dev, "num-chipselects property not found\n");
		goto error_free;
	}

	pdata->num_chipselect = tmp;
	pdev->dev.platform_data = pdata;

	return 1;

error_free:
	devm_kfree(&pdev->dev, pdata);
	return ret;
}
#else
static inline int spi_probe_dt(struct platform_device *)
{
	return 0;
}
#endif

static int __devinit spi_gpio_probe(struct platform_device *pdev)
{
	int				status;
@@ -333,6 +399,13 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev)
	struct spi_gpio			*spi_gpio;
	struct spi_gpio_platform_data	*pdata;
	u16 master_flags = 0;
	bool use_of = 0;

	status = spi_gpio_probe_dt(pdev);
	if (status < 0)
		return status;
	if (status > 0)
		use_of = 1;

	pdata = pdev->dev.platform_data;
#ifdef GENERIC_BITBANG
@@ -362,6 +435,23 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev)
	master->num_chipselect = SPI_N_CHIPSEL;
	master->setup = spi_gpio_setup;
	master->cleanup = spi_gpio_cleanup;
#ifdef CONFIG_OF
	master->dev.of_node = pdev->dev.of_node;

	if (use_of) {
		int i;
		struct device_node *np = pdev->dev.of_node;

		/*
		 * In DT environments, take the CS GPIO from the "cs-gpios"
		 * property of the node.
		 */

		for (i = 0; i < SPI_N_CHIPSEL; i++)
			spi_gpio->cs_gpios[i] =
				of_get_named_gpio(np, "cs-gpios", i);
	}
#endif

	spi_gpio->bitbang.master = spi_master_get(master);
	spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
@@ -422,8 +512,11 @@ static int __devexit spi_gpio_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:" DRIVER_NAME);

static struct platform_driver spi_gpio_driver = {
	.driver.name	= DRIVER_NAME,
	.driver.owner	= THIS_MODULE,
	.driver = {
		.name	= DRIVER_NAME,
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(spi_gpio_dt_ids),
	},
	.probe		= spi_gpio_probe,
	.remove		= __devexit_p(spi_gpio_remove),
};