diff options
Diffstat (limited to 'drivers/spi/spi-gpio.c')
| -rw-r--r-- | drivers/spi/spi-gpio.c | 99 | 
1 files changed, 96 insertions, 3 deletions
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index ff7263ce12c..aed16159584 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -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 @@ done:  	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),  };  |