Revert "kernel: remove long obsolete gpio spi controller driver patch"
This reverts commit 9e62a7668c.
			
			
This commit is contained in:
		| @@ -43,6 +43,22 @@ endef | ||||
| $(eval $(call KernelPackage,spi-bitbang)) | ||||
|  | ||||
|  | ||||
| define KernelPackage/spi-gpio-old | ||||
|   SUBMENU:=$(SPI_MENU) | ||||
|   TITLE:=Old GPIO based bitbanging SPI controller (DEPRECATED) | ||||
|   DEPENDS:=@GPIO_SUPPORT +kmod-spi-bitbang | ||||
|   KCONFIG:=CONFIG_SPI_GPIO_OLD | ||||
|   FILES:=$(LINUX_DIR)/drivers/spi/spi_gpio_old.ko | ||||
|   AUTOLOAD:=$(call AutoProbe,spi_gpio_old) | ||||
| endef | ||||
|  | ||||
| define KernelPackage/spi-gpio-old/description | ||||
|  This package contains the GPIO based bitbanging SPI controller driver | ||||
| endef | ||||
|  | ||||
| $(eval $(call KernelPackage,spi-gpio-old)) | ||||
|  | ||||
|  | ||||
| define KernelPackage/spi-gpio | ||||
|   SUBMENU:=$(SPI_MENU) | ||||
|   TITLE:=GPIO-based bitbanging SPI Master | ||||
|   | ||||
| @@ -3784,6 +3784,7 @@ CONFIG_SND_VERBOSE_PROCFS=y | ||||
| # CONFIG_SPI_FSL_ESPI is not set | ||||
| # CONFIG_SPI_FSL_SPI is not set | ||||
| # CONFIG_SPI_GPIO is not set | ||||
| # CONFIG_SPI_GPIO_OLD is not set | ||||
| # CONFIG_SPI_LM70_LLP is not set | ||||
| # CONFIG_SPI_MASTER is not set | ||||
| # CONFIG_SPI_MPC52xx is not set | ||||
|   | ||||
| @@ -3938,6 +3938,7 @@ CONFIG_SND_VERBOSE_PROCFS=y | ||||
| # CONFIG_SPI_FSL_ESPI is not set | ||||
| # CONFIG_SPI_FSL_SPI is not set | ||||
| # CONFIG_SPI_GPIO is not set | ||||
| # CONFIG_SPI_GPIO_OLD is not set | ||||
| # CONFIG_SPI_IMG_SPFI is not set | ||||
| # CONFIG_SPI_LM70_LLP is not set | ||||
| # CONFIG_SPI_MASTER is not set | ||||
|   | ||||
| @@ -3942,6 +3942,7 @@ CONFIG_SND_VERBOSE_PROCFS=y | ||||
| # CONFIG_SPI_FSL_ESPI is not set | ||||
| # CONFIG_SPI_FSL_SPI is not set | ||||
| # CONFIG_SPI_GPIO is not set | ||||
| # CONFIG_SPI_GPIO_OLD is not set | ||||
| # CONFIG_SPI_IMG_SPFI is not set | ||||
| # CONFIG_SPI_LM70_LLP is not set | ||||
| # CONFIG_SPI_MASTER is not set | ||||
|   | ||||
							
								
								
									
										373
									
								
								target/linux/generic/patches-3.18/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								target/linux/generic/patches-3.18/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | ||||
| THIS CODE IS DEPRECATED. | ||||
|  | ||||
| Please use the new mainline SPI-GPIO driver, as of 2.6.29. | ||||
|  | ||||
| --mb | ||||
|  | ||||
|  | ||||
|  | ||||
| --- | ||||
|  drivers/spi/Kconfig              |    9 + | ||||
|  drivers/spi/Makefile             |    1  | ||||
|  drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++ | ||||
|  include/linux/spi/spi_gpio_old.h |   73 +++++++++++ | ||||
|  4 files changed, 334 insertions(+) | ||||
|  | ||||
| --- /dev/null | ||||
| +++ b/include/linux/spi/spi_gpio_old.h | ||||
| @@ -0,0 +1,73 @@ | ||||
| +/* | ||||
| + * spi_gpio interface to platform code | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| +#ifndef _LINUX_SPI_SPI_GPIO | ||||
| +#define _LINUX_SPI_SPI_GPIO | ||||
| + | ||||
| +#include <linux/types.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| + | ||||
| + | ||||
| +/** | ||||
| + * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. | ||||
| + * | ||||
| + * This structure holds information about a GPIO-based SPI device. | ||||
| + * | ||||
| + * @pin_clk: The GPIO pin number of the CLOCK pin. | ||||
| + * | ||||
| + * @pin_miso: The GPIO pin number of the MISO pin. | ||||
| + * | ||||
| + * @pin_mosi: The GPIO pin number of the MOSI pin. | ||||
| + * | ||||
| + * @pin_cs: The GPIO pin number of the CHIPSELECT pin. | ||||
| + * | ||||
| + * @cs_activelow: If true, the chip is selected when the CS line is low. | ||||
| + * | ||||
| + * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. | ||||
| + *                Note that doing no delay is not standards compliant, | ||||
| + *                but it might be needed to speed up transfers on some | ||||
| + *                slow embedded machines. | ||||
| + * | ||||
| + * @boardinfo_setup: This callback is called after the | ||||
| + *                   SPI master device was registered, but before the | ||||
| + *                   device is registered. | ||||
| + * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). | ||||
| + */ | ||||
| +struct spi_gpio_platform_data { | ||||
| +	unsigned int pin_clk; | ||||
| +	unsigned int pin_miso; | ||||
| +	unsigned int pin_mosi; | ||||
| +	unsigned int pin_cs; | ||||
| +	bool cs_activelow; | ||||
| +	bool no_spi_delay; | ||||
| +	int (*boardinfo_setup)(struct spi_board_info *bi, | ||||
| +			       struct spi_master *master, | ||||
| +			       void *data); | ||||
| +	void *boardinfo_setup_data; | ||||
| +}; | ||||
| + | ||||
| +/** | ||||
| + * SPI_GPIO_PLATDEV_NAME - The platform device name string. | ||||
| + * | ||||
| + * The name string that has to be used for platform_device_alloc | ||||
| + * when allocating a spi-gpio device. | ||||
| + */ | ||||
| +#define SPI_GPIO_PLATDEV_NAME	"spi-gpio" | ||||
| + | ||||
| +/** | ||||
| + * spi_gpio_next_id - Get another platform device ID number. | ||||
| + * | ||||
| + * This returns the next platform device ID number that has to be used | ||||
| + * for platform_device_alloc. The ID is opaque and should not be used for | ||||
| + * anything else. | ||||
| + */ | ||||
| +int spi_gpio_next_id(void); | ||||
| + | ||||
| +#endif /* _LINUX_SPI_SPI_GPIO */ | ||||
| --- /dev/null | ||||
| +++ b/drivers/spi/spi_gpio_old.c | ||||
| @@ -0,0 +1,251 @@ | ||||
| +/* | ||||
| + * Bitbanging SPI bus driver using GPIO API | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * based on spi_s3c2410_gpio.c | ||||
| + *   Copyright (c) 2006 Ben Dooks | ||||
| + *   Copyright (c) 2006 Simtec Electronics | ||||
| + * and on i2c-gpio.c | ||||
| + *   Copyright (C) 2007 Atmel Corporation | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| + | ||||
| +#include <linux/kernel.h> | ||||
| +#include <linux/init.h> | ||||
| +#include <linux/delay.h> | ||||
| +#include <linux/spinlock.h> | ||||
| +#include <linux/workqueue.h> | ||||
| +#include <linux/module.h> | ||||
| +#include <linux/platform_device.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| +#include <linux/spi/spi_bitbang.h> | ||||
| +#include <linux/spi/spi_gpio_old.h> | ||||
| +#include <linux/gpio.h> | ||||
| +#include <asm/atomic.h> | ||||
| + | ||||
| + | ||||
| +struct spi_gpio { | ||||
| +	struct spi_bitbang bitbang; | ||||
| +	struct spi_gpio_platform_data *info; | ||||
| +	struct platform_device *pdev; | ||||
| +	struct spi_board_info bi; | ||||
| +}; | ||||
| + | ||||
| + | ||||
| +static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) | ||||
| +{ | ||||
| +	return dev->controller_data; | ||||
| +} | ||||
| + | ||||
| +static inline void setsck(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_clk, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline void setmosi(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline u32 getmiso(struct spi_device *dev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	return gpio_get_value(sp->info->pin_miso) ? 1 : 0; | ||||
| +} | ||||
| + | ||||
| +static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (!sp->info->no_spi_delay) | ||||
| +		ndelay(nsecs); | ||||
| +} | ||||
| + | ||||
| +#define spidelay(nsecs) do {					\ | ||||
| +	/* Steal the spi_device pointer from our caller.	\ | ||||
| +	 * The bitbang-API should probably get fixed here... */	\ | ||||
| +	do_spidelay(spi, nsecs);				\ | ||||
| +  } while (0) | ||||
| + | ||||
| +#define EXPAND_BITBANG_TXRX | ||||
| +#include "spi-bitbang-txrx.h" | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode0(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode1(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode2(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode3(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static void spi_gpio_chipselect(struct spi_device *dev, int on) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (sp->info->cs_activelow) | ||||
| +		on = !on; | ||||
| +	gpio_set_value(sp->info->pin_cs, on ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_probe(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_master *master; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_device *spidev; | ||||
| +	int err; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	if (!pdata) | ||||
| +		return -ENXIO; | ||||
| + | ||||
| +	err = -ENOMEM; | ||||
| +	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); | ||||
| +	if (!master) | ||||
| +		goto err_alloc_master; | ||||
| + | ||||
| +	sp = spi_master_get_devdata(master); | ||||
| +	platform_set_drvdata(pdev, sp); | ||||
| +	sp->info = pdata; | ||||
| + | ||||
| +	err = gpio_request(pdata->pin_clk, "spi_clock"); | ||||
| +	if (err) | ||||
| +		goto err_request_clk; | ||||
| +	err = gpio_request(pdata->pin_mosi, "spi_mosi"); | ||||
| +	if (err) | ||||
| +		goto err_request_mosi; | ||||
| +	err = gpio_request(pdata->pin_miso, "spi_miso"); | ||||
| +	if (err) | ||||
| +		goto err_request_miso; | ||||
| +	err = gpio_request(pdata->pin_cs, "spi_cs"); | ||||
| +	if (err) | ||||
| +		goto err_request_cs; | ||||
| + | ||||
| +	sp->bitbang.master = spi_master_get(master); | ||||
| +	sp->bitbang.master->bus_num = -1; | ||||
| +	sp->bitbang.master->num_chipselect = 1; | ||||
| +	sp->bitbang.chipselect = spi_gpio_chipselect; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; | ||||
| + | ||||
| +	gpio_direction_output(pdata->pin_clk, 0); | ||||
| +	gpio_direction_output(pdata->pin_mosi, 0); | ||||
| +	gpio_direction_output(pdata->pin_cs, | ||||
| +			      pdata->cs_activelow ? 1 : 0); | ||||
| +	gpio_direction_input(pdata->pin_miso); | ||||
| + | ||||
| +	err = spi_bitbang_start(&sp->bitbang); | ||||
| +	if (err) | ||||
| +		goto err_no_bitbang; | ||||
| +	err = pdata->boardinfo_setup(&sp->bi, master, | ||||
| +				     pdata->boardinfo_setup_data); | ||||
| +	if (err) | ||||
| +		goto err_bi_setup; | ||||
| +	sp->bi.controller_data = sp; | ||||
| +	spidev = spi_new_device(master, &sp->bi); | ||||
| +	if (!spidev) | ||||
| +		goto err_new_dev; | ||||
| + | ||||
| +	return 0; | ||||
| + | ||||
| +err_new_dev: | ||||
| +err_bi_setup: | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +err_no_bitbang: | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +err_request_cs: | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +err_request_miso: | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +err_request_mosi: | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +err_request_clk: | ||||
| +	kfree(master); | ||||
| + | ||||
| +err_alloc_master: | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_remove(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	sp = platform_get_drvdata(pdev); | ||||
| + | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static struct platform_driver spi_gpio_driver = { | ||||
| +	.driver		= { | ||||
| +		.name	= SPI_GPIO_PLATDEV_NAME, | ||||
| +		.owner	= THIS_MODULE, | ||||
| +	}, | ||||
| +	.probe		= spi_gpio_probe, | ||||
| +	.remove		= spi_gpio_remove, | ||||
| +}; | ||||
| + | ||||
| +int spi_gpio_next_id(void) | ||||
| +{ | ||||
| +	static atomic_t counter = ATOMIC_INIT(-1); | ||||
| + | ||||
| +	return atomic_inc_return(&counter); | ||||
| +} | ||||
| +EXPORT_SYMBOL(spi_gpio_next_id); | ||||
| + | ||||
| +static int __init spi_gpio_init(void) | ||||
| +{ | ||||
| +	int err; | ||||
| + | ||||
| +	err = platform_driver_register(&spi_gpio_driver); | ||||
| +	if (err) | ||||
| +		printk(KERN_ERR "spi-gpio: register failed: %d\n", err); | ||||
| + | ||||
| +	return err; | ||||
| +} | ||||
| +module_init(spi_gpio_init); | ||||
| + | ||||
| +static void __exit spi_gpio_exit(void) | ||||
| +{ | ||||
| +	platform_driver_unregister(&spi_gpio_driver); | ||||
| +} | ||||
| +module_exit(spi_gpio_exit); | ||||
| + | ||||
| +MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>"); | ||||
| +MODULE_AUTHOR("Michael Buesch"); | ||||
| +MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); | ||||
| +MODULE_LICENSE("GPL v2"); | ||||
| --- a/drivers/spi/Kconfig | ||||
| +++ b/drivers/spi/Kconfig | ||||
| @@ -225,6 +225,15 @@ config SPI_GPIO | ||||
|  	  GPIO operations, you should be able to leverage that for better | ||||
|  	  speed with a custom version of this driver; see the source code. | ||||
|   | ||||
| +config SPI_GPIO_OLD | ||||
| +	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" | ||||
| +	depends on SPI_MASTER && GPIOLIB | ||||
| +	select SPI_BITBANG | ||||
| +	help | ||||
| +	  This code is deprecated. Please use the new mainline SPI-GPIO driver. | ||||
| + | ||||
| +	  If unsure, say N. | ||||
| + | ||||
|  config SPI_IMX | ||||
|  	tristate "Freescale i.MX SPI controllers" | ||||
|  	depends on ARCH_MXC || COMPILE_TEST | ||||
| --- a/drivers/spi/Makefile | ||||
| +++ b/drivers/spi/Makefile | ||||
| @@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li | ||||
|  obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o | ||||
|  obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o | ||||
|  obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o | ||||
| +obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o | ||||
|  obj-$(CONFIG_SPI_IMX)			+= spi-imx.o | ||||
|  obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o | ||||
|  obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mpc512x-psc.o | ||||
							
								
								
									
										373
									
								
								target/linux/generic/patches-4.1/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								target/linux/generic/patches-4.1/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | ||||
| THIS CODE IS DEPRECATED. | ||||
|  | ||||
| Please use the new mainline SPI-GPIO driver, as of 2.6.29. | ||||
|  | ||||
| --mb | ||||
|  | ||||
|  | ||||
|  | ||||
| --- | ||||
|  drivers/spi/Kconfig              |    9 + | ||||
|  drivers/spi/Makefile             |    1  | ||||
|  drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++ | ||||
|  include/linux/spi/spi_gpio_old.h |   73 +++++++++++ | ||||
|  4 files changed, 334 insertions(+) | ||||
|  | ||||
| --- /dev/null | ||||
| +++ b/include/linux/spi/spi_gpio_old.h | ||||
| @@ -0,0 +1,73 @@ | ||||
| +/* | ||||
| + * spi_gpio interface to platform code | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| +#ifndef _LINUX_SPI_SPI_GPIO | ||||
| +#define _LINUX_SPI_SPI_GPIO | ||||
| + | ||||
| +#include <linux/types.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| + | ||||
| + | ||||
| +/** | ||||
| + * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. | ||||
| + * | ||||
| + * This structure holds information about a GPIO-based SPI device. | ||||
| + * | ||||
| + * @pin_clk: The GPIO pin number of the CLOCK pin. | ||||
| + * | ||||
| + * @pin_miso: The GPIO pin number of the MISO pin. | ||||
| + * | ||||
| + * @pin_mosi: The GPIO pin number of the MOSI pin. | ||||
| + * | ||||
| + * @pin_cs: The GPIO pin number of the CHIPSELECT pin. | ||||
| + * | ||||
| + * @cs_activelow: If true, the chip is selected when the CS line is low. | ||||
| + * | ||||
| + * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. | ||||
| + *                Note that doing no delay is not standards compliant, | ||||
| + *                but it might be needed to speed up transfers on some | ||||
| + *                slow embedded machines. | ||||
| + * | ||||
| + * @boardinfo_setup: This callback is called after the | ||||
| + *                   SPI master device was registered, but before the | ||||
| + *                   device is registered. | ||||
| + * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). | ||||
| + */ | ||||
| +struct spi_gpio_platform_data { | ||||
| +	unsigned int pin_clk; | ||||
| +	unsigned int pin_miso; | ||||
| +	unsigned int pin_mosi; | ||||
| +	unsigned int pin_cs; | ||||
| +	bool cs_activelow; | ||||
| +	bool no_spi_delay; | ||||
| +	int (*boardinfo_setup)(struct spi_board_info *bi, | ||||
| +			       struct spi_master *master, | ||||
| +			       void *data); | ||||
| +	void *boardinfo_setup_data; | ||||
| +}; | ||||
| + | ||||
| +/** | ||||
| + * SPI_GPIO_PLATDEV_NAME - The platform device name string. | ||||
| + * | ||||
| + * The name string that has to be used for platform_device_alloc | ||||
| + * when allocating a spi-gpio device. | ||||
| + */ | ||||
| +#define SPI_GPIO_PLATDEV_NAME	"spi-gpio" | ||||
| + | ||||
| +/** | ||||
| + * spi_gpio_next_id - Get another platform device ID number. | ||||
| + * | ||||
| + * This returns the next platform device ID number that has to be used | ||||
| + * for platform_device_alloc. The ID is opaque and should not be used for | ||||
| + * anything else. | ||||
| + */ | ||||
| +int spi_gpio_next_id(void); | ||||
| + | ||||
| +#endif /* _LINUX_SPI_SPI_GPIO */ | ||||
| --- /dev/null | ||||
| +++ b/drivers/spi/spi_gpio_old.c | ||||
| @@ -0,0 +1,251 @@ | ||||
| +/* | ||||
| + * Bitbanging SPI bus driver using GPIO API | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * based on spi_s3c2410_gpio.c | ||||
| + *   Copyright (c) 2006 Ben Dooks | ||||
| + *   Copyright (c) 2006 Simtec Electronics | ||||
| + * and on i2c-gpio.c | ||||
| + *   Copyright (C) 2007 Atmel Corporation | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| + | ||||
| +#include <linux/kernel.h> | ||||
| +#include <linux/init.h> | ||||
| +#include <linux/delay.h> | ||||
| +#include <linux/spinlock.h> | ||||
| +#include <linux/workqueue.h> | ||||
| +#include <linux/module.h> | ||||
| +#include <linux/platform_device.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| +#include <linux/spi/spi_bitbang.h> | ||||
| +#include <linux/spi/spi_gpio_old.h> | ||||
| +#include <linux/gpio.h> | ||||
| +#include <asm/atomic.h> | ||||
| + | ||||
| + | ||||
| +struct spi_gpio { | ||||
| +	struct spi_bitbang bitbang; | ||||
| +	struct spi_gpio_platform_data *info; | ||||
| +	struct platform_device *pdev; | ||||
| +	struct spi_board_info bi; | ||||
| +}; | ||||
| + | ||||
| + | ||||
| +static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) | ||||
| +{ | ||||
| +	return dev->controller_data; | ||||
| +} | ||||
| + | ||||
| +static inline void setsck(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_clk, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline void setmosi(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline u32 getmiso(struct spi_device *dev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	return gpio_get_value(sp->info->pin_miso) ? 1 : 0; | ||||
| +} | ||||
| + | ||||
| +static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (!sp->info->no_spi_delay) | ||||
| +		ndelay(nsecs); | ||||
| +} | ||||
| + | ||||
| +#define spidelay(nsecs) do {					\ | ||||
| +	/* Steal the spi_device pointer from our caller.	\ | ||||
| +	 * The bitbang-API should probably get fixed here... */	\ | ||||
| +	do_spidelay(spi, nsecs);				\ | ||||
| +  } while (0) | ||||
| + | ||||
| +#define EXPAND_BITBANG_TXRX | ||||
| +#include "spi-bitbang-txrx.h" | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode0(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode1(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode2(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode3(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static void spi_gpio_chipselect(struct spi_device *dev, int on) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (sp->info->cs_activelow) | ||||
| +		on = !on; | ||||
| +	gpio_set_value(sp->info->pin_cs, on ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_probe(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_master *master; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_device *spidev; | ||||
| +	int err; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	if (!pdata) | ||||
| +		return -ENXIO; | ||||
| + | ||||
| +	err = -ENOMEM; | ||||
| +	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); | ||||
| +	if (!master) | ||||
| +		goto err_alloc_master; | ||||
| + | ||||
| +	sp = spi_master_get_devdata(master); | ||||
| +	platform_set_drvdata(pdev, sp); | ||||
| +	sp->info = pdata; | ||||
| + | ||||
| +	err = gpio_request(pdata->pin_clk, "spi_clock"); | ||||
| +	if (err) | ||||
| +		goto err_request_clk; | ||||
| +	err = gpio_request(pdata->pin_mosi, "spi_mosi"); | ||||
| +	if (err) | ||||
| +		goto err_request_mosi; | ||||
| +	err = gpio_request(pdata->pin_miso, "spi_miso"); | ||||
| +	if (err) | ||||
| +		goto err_request_miso; | ||||
| +	err = gpio_request(pdata->pin_cs, "spi_cs"); | ||||
| +	if (err) | ||||
| +		goto err_request_cs; | ||||
| + | ||||
| +	sp->bitbang.master = spi_master_get(master); | ||||
| +	sp->bitbang.master->bus_num = -1; | ||||
| +	sp->bitbang.master->num_chipselect = 1; | ||||
| +	sp->bitbang.chipselect = spi_gpio_chipselect; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; | ||||
| + | ||||
| +	gpio_direction_output(pdata->pin_clk, 0); | ||||
| +	gpio_direction_output(pdata->pin_mosi, 0); | ||||
| +	gpio_direction_output(pdata->pin_cs, | ||||
| +			      pdata->cs_activelow ? 1 : 0); | ||||
| +	gpio_direction_input(pdata->pin_miso); | ||||
| + | ||||
| +	err = spi_bitbang_start(&sp->bitbang); | ||||
| +	if (err) | ||||
| +		goto err_no_bitbang; | ||||
| +	err = pdata->boardinfo_setup(&sp->bi, master, | ||||
| +				     pdata->boardinfo_setup_data); | ||||
| +	if (err) | ||||
| +		goto err_bi_setup; | ||||
| +	sp->bi.controller_data = sp; | ||||
| +	spidev = spi_new_device(master, &sp->bi); | ||||
| +	if (!spidev) | ||||
| +		goto err_new_dev; | ||||
| + | ||||
| +	return 0; | ||||
| + | ||||
| +err_new_dev: | ||||
| +err_bi_setup: | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +err_no_bitbang: | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +err_request_cs: | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +err_request_miso: | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +err_request_mosi: | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +err_request_clk: | ||||
| +	kfree(master); | ||||
| + | ||||
| +err_alloc_master: | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_remove(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	sp = platform_get_drvdata(pdev); | ||||
| + | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static struct platform_driver spi_gpio_driver = { | ||||
| +	.driver		= { | ||||
| +		.name	= SPI_GPIO_PLATDEV_NAME, | ||||
| +		.owner	= THIS_MODULE, | ||||
| +	}, | ||||
| +	.probe		= spi_gpio_probe, | ||||
| +	.remove		= spi_gpio_remove, | ||||
| +}; | ||||
| + | ||||
| +int spi_gpio_next_id(void) | ||||
| +{ | ||||
| +	static atomic_t counter = ATOMIC_INIT(-1); | ||||
| + | ||||
| +	return atomic_inc_return(&counter); | ||||
| +} | ||||
| +EXPORT_SYMBOL(spi_gpio_next_id); | ||||
| + | ||||
| +static int __init spi_gpio_init(void) | ||||
| +{ | ||||
| +	int err; | ||||
| + | ||||
| +	err = platform_driver_register(&spi_gpio_driver); | ||||
| +	if (err) | ||||
| +		printk(KERN_ERR "spi-gpio: register failed: %d\n", err); | ||||
| + | ||||
| +	return err; | ||||
| +} | ||||
| +module_init(spi_gpio_init); | ||||
| + | ||||
| +static void __exit spi_gpio_exit(void) | ||||
| +{ | ||||
| +	platform_driver_unregister(&spi_gpio_driver); | ||||
| +} | ||||
| +module_exit(spi_gpio_exit); | ||||
| + | ||||
| +MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>"); | ||||
| +MODULE_AUTHOR("Michael Buesch"); | ||||
| +MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); | ||||
| +MODULE_LICENSE("GPL v2"); | ||||
| --- a/drivers/spi/Kconfig | ||||
| +++ b/drivers/spi/Kconfig | ||||
| @@ -242,6 +242,15 @@ config SPI_IMG_SPFI | ||||
|  	  This enables support for the SPFI master controller found on | ||||
|  	  IMG SoCs. | ||||
|   | ||||
| +config SPI_GPIO_OLD | ||||
| +	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" | ||||
| +	depends on SPI_MASTER && GPIOLIB | ||||
| +	select SPI_BITBANG | ||||
| +	help | ||||
| +	  This code is deprecated. Please use the new mainline SPI-GPIO driver. | ||||
| + | ||||
| +	  If unsure, say N. | ||||
| + | ||||
|  config SPI_IMX | ||||
|  	tristate "Freescale i.MX SPI controllers" | ||||
|  	depends on ARCH_MXC || COMPILE_TEST | ||||
| --- a/drivers/spi/Makefile | ||||
| +++ b/drivers/spi/Makefile | ||||
| @@ -41,6 +41,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li | ||||
|  obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o | ||||
|  obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o | ||||
|  obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o | ||||
| +obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o | ||||
|  obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o | ||||
|  obj-$(CONFIG_SPI_IMX)			+= spi-imx.o | ||||
|  obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o | ||||
							
								
								
									
										373
									
								
								target/linux/generic/patches-4.4/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								target/linux/generic/patches-4.4/862-gpio_spi_driver.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | ||||
| THIS CODE IS DEPRECATED. | ||||
|  | ||||
| Please use the new mainline SPI-GPIO driver, as of 2.6.29. | ||||
|  | ||||
| --mb | ||||
|  | ||||
|  | ||||
|  | ||||
| --- | ||||
|  drivers/spi/Kconfig              |    9 + | ||||
|  drivers/spi/Makefile             |    1  | ||||
|  drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++ | ||||
|  include/linux/spi/spi_gpio_old.h |   73 +++++++++++ | ||||
|  4 files changed, 334 insertions(+) | ||||
|  | ||||
| --- /dev/null | ||||
| +++ b/include/linux/spi/spi_gpio_old.h | ||||
| @@ -0,0 +1,73 @@ | ||||
| +/* | ||||
| + * spi_gpio interface to platform code | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| +#ifndef _LINUX_SPI_SPI_GPIO | ||||
| +#define _LINUX_SPI_SPI_GPIO | ||||
| + | ||||
| +#include <linux/types.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| + | ||||
| + | ||||
| +/** | ||||
| + * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. | ||||
| + * | ||||
| + * This structure holds information about a GPIO-based SPI device. | ||||
| + * | ||||
| + * @pin_clk: The GPIO pin number of the CLOCK pin. | ||||
| + * | ||||
| + * @pin_miso: The GPIO pin number of the MISO pin. | ||||
| + * | ||||
| + * @pin_mosi: The GPIO pin number of the MOSI pin. | ||||
| + * | ||||
| + * @pin_cs: The GPIO pin number of the CHIPSELECT pin. | ||||
| + * | ||||
| + * @cs_activelow: If true, the chip is selected when the CS line is low. | ||||
| + * | ||||
| + * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. | ||||
| + *                Note that doing no delay is not standards compliant, | ||||
| + *                but it might be needed to speed up transfers on some | ||||
| + *                slow embedded machines. | ||||
| + * | ||||
| + * @boardinfo_setup: This callback is called after the | ||||
| + *                   SPI master device was registered, but before the | ||||
| + *                   device is registered. | ||||
| + * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). | ||||
| + */ | ||||
| +struct spi_gpio_platform_data { | ||||
| +	unsigned int pin_clk; | ||||
| +	unsigned int pin_miso; | ||||
| +	unsigned int pin_mosi; | ||||
| +	unsigned int pin_cs; | ||||
| +	bool cs_activelow; | ||||
| +	bool no_spi_delay; | ||||
| +	int (*boardinfo_setup)(struct spi_board_info *bi, | ||||
| +			       struct spi_master *master, | ||||
| +			       void *data); | ||||
| +	void *boardinfo_setup_data; | ||||
| +}; | ||||
| + | ||||
| +/** | ||||
| + * SPI_GPIO_PLATDEV_NAME - The platform device name string. | ||||
| + * | ||||
| + * The name string that has to be used for platform_device_alloc | ||||
| + * when allocating a spi-gpio device. | ||||
| + */ | ||||
| +#define SPI_GPIO_PLATDEV_NAME	"spi-gpio" | ||||
| + | ||||
| +/** | ||||
| + * spi_gpio_next_id - Get another platform device ID number. | ||||
| + * | ||||
| + * This returns the next platform device ID number that has to be used | ||||
| + * for platform_device_alloc. The ID is opaque and should not be used for | ||||
| + * anything else. | ||||
| + */ | ||||
| +int spi_gpio_next_id(void); | ||||
| + | ||||
| +#endif /* _LINUX_SPI_SPI_GPIO */ | ||||
| --- /dev/null | ||||
| +++ b/drivers/spi/spi_gpio_old.c | ||||
| @@ -0,0 +1,251 @@ | ||||
| +/* | ||||
| + * Bitbanging SPI bus driver using GPIO API | ||||
| + * | ||||
| + * Copyright (c) 2008 Piotr Skamruk | ||||
| + * Copyright (c) 2008 Michael Buesch | ||||
| + * | ||||
| + * based on spi_s3c2410_gpio.c | ||||
| + *   Copyright (c) 2006 Ben Dooks | ||||
| + *   Copyright (c) 2006 Simtec Electronics | ||||
| + * and on i2c-gpio.c | ||||
| + *   Copyright (C) 2007 Atmel Corporation | ||||
| + * | ||||
| + * This program is free software; you can redistribute it and/or modify | ||||
| + * it under the terms of the GNU General Public License version 2 as | ||||
| + * published by the Free Software Foundation. | ||||
| + */ | ||||
| + | ||||
| +#include <linux/kernel.h> | ||||
| +#include <linux/init.h> | ||||
| +#include <linux/delay.h> | ||||
| +#include <linux/spinlock.h> | ||||
| +#include <linux/workqueue.h> | ||||
| +#include <linux/module.h> | ||||
| +#include <linux/platform_device.h> | ||||
| +#include <linux/spi/spi.h> | ||||
| +#include <linux/spi/spi_bitbang.h> | ||||
| +#include <linux/spi/spi_gpio_old.h> | ||||
| +#include <linux/gpio.h> | ||||
| +#include <asm/atomic.h> | ||||
| + | ||||
| + | ||||
| +struct spi_gpio { | ||||
| +	struct spi_bitbang bitbang; | ||||
| +	struct spi_gpio_platform_data *info; | ||||
| +	struct platform_device *pdev; | ||||
| +	struct spi_board_info bi; | ||||
| +}; | ||||
| + | ||||
| + | ||||
| +static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) | ||||
| +{ | ||||
| +	return dev->controller_data; | ||||
| +} | ||||
| + | ||||
| +static inline void setsck(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_clk, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline void setmosi(struct spi_device *dev, int val) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static inline u32 getmiso(struct spi_device *dev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| +	return gpio_get_value(sp->info->pin_miso) ? 1 : 0; | ||||
| +} | ||||
| + | ||||
| +static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (!sp->info->no_spi_delay) | ||||
| +		ndelay(nsecs); | ||||
| +} | ||||
| + | ||||
| +#define spidelay(nsecs) do {					\ | ||||
| +	/* Steal the spi_device pointer from our caller.	\ | ||||
| +	 * The bitbang-API should probably get fixed here... */	\ | ||||
| +	do_spidelay(spi, nsecs);				\ | ||||
| +  } while (0) | ||||
| + | ||||
| +#define EXPAND_BITBANG_TXRX | ||||
| +#include "spi-bitbang-txrx.h" | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode0(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode1(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode2(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static u32 spi_gpio_txrx_mode3(struct spi_device *spi, | ||||
| +			       unsigned nsecs, u32 word, u8 bits) | ||||
| +{ | ||||
| +	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); | ||||
| +} | ||||
| + | ||||
| +static void spi_gpio_chipselect(struct spi_device *dev, int on) | ||||
| +{ | ||||
| +	struct spi_gpio *sp = spidev_to_sg(dev); | ||||
| + | ||||
| +	if (sp->info->cs_activelow) | ||||
| +		on = !on; | ||||
| +	gpio_set_value(sp->info->pin_cs, on ? 1 : 0); | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_probe(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_master *master; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_device *spidev; | ||||
| +	int err; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	if (!pdata) | ||||
| +		return -ENXIO; | ||||
| + | ||||
| +	err = -ENOMEM; | ||||
| +	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); | ||||
| +	if (!master) | ||||
| +		goto err_alloc_master; | ||||
| + | ||||
| +	sp = spi_master_get_devdata(master); | ||||
| +	platform_set_drvdata(pdev, sp); | ||||
| +	sp->info = pdata; | ||||
| + | ||||
| +	err = gpio_request(pdata->pin_clk, "spi_clock"); | ||||
| +	if (err) | ||||
| +		goto err_request_clk; | ||||
| +	err = gpio_request(pdata->pin_mosi, "spi_mosi"); | ||||
| +	if (err) | ||||
| +		goto err_request_mosi; | ||||
| +	err = gpio_request(pdata->pin_miso, "spi_miso"); | ||||
| +	if (err) | ||||
| +		goto err_request_miso; | ||||
| +	err = gpio_request(pdata->pin_cs, "spi_cs"); | ||||
| +	if (err) | ||||
| +		goto err_request_cs; | ||||
| + | ||||
| +	sp->bitbang.master = spi_master_get(master); | ||||
| +	sp->bitbang.master->bus_num = -1; | ||||
| +	sp->bitbang.master->num_chipselect = 1; | ||||
| +	sp->bitbang.chipselect = spi_gpio_chipselect; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; | ||||
| +	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; | ||||
| + | ||||
| +	gpio_direction_output(pdata->pin_clk, 0); | ||||
| +	gpio_direction_output(pdata->pin_mosi, 0); | ||||
| +	gpio_direction_output(pdata->pin_cs, | ||||
| +			      pdata->cs_activelow ? 1 : 0); | ||||
| +	gpio_direction_input(pdata->pin_miso); | ||||
| + | ||||
| +	err = spi_bitbang_start(&sp->bitbang); | ||||
| +	if (err) | ||||
| +		goto err_no_bitbang; | ||||
| +	err = pdata->boardinfo_setup(&sp->bi, master, | ||||
| +				     pdata->boardinfo_setup_data); | ||||
| +	if (err) | ||||
| +		goto err_bi_setup; | ||||
| +	sp->bi.controller_data = sp; | ||||
| +	spidev = spi_new_device(master, &sp->bi); | ||||
| +	if (!spidev) | ||||
| +		goto err_new_dev; | ||||
| + | ||||
| +	return 0; | ||||
| + | ||||
| +err_new_dev: | ||||
| +err_bi_setup: | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +err_no_bitbang: | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +err_request_cs: | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +err_request_miso: | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +err_request_mosi: | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +err_request_clk: | ||||
| +	kfree(master); | ||||
| + | ||||
| +err_alloc_master: | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
| +static int spi_gpio_remove(struct platform_device *pdev) | ||||
| +{ | ||||
| +	struct spi_gpio *sp; | ||||
| +	struct spi_gpio_platform_data *pdata; | ||||
| + | ||||
| +	pdata = pdev->dev.platform_data; | ||||
| +	sp = platform_get_drvdata(pdev); | ||||
| + | ||||
| +	gpio_free(pdata->pin_clk); | ||||
| +	gpio_free(pdata->pin_mosi); | ||||
| +	gpio_free(pdata->pin_miso); | ||||
| +	gpio_free(pdata->pin_cs); | ||||
| +	spi_bitbang_stop(&sp->bitbang); | ||||
| +	spi_master_put(sp->bitbang.master); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static struct platform_driver spi_gpio_driver = { | ||||
| +	.driver		= { | ||||
| +		.name	= SPI_GPIO_PLATDEV_NAME, | ||||
| +		.owner	= THIS_MODULE, | ||||
| +	}, | ||||
| +	.probe		= spi_gpio_probe, | ||||
| +	.remove		= spi_gpio_remove, | ||||
| +}; | ||||
| + | ||||
| +int spi_gpio_next_id(void) | ||||
| +{ | ||||
| +	static atomic_t counter = ATOMIC_INIT(-1); | ||||
| + | ||||
| +	return atomic_inc_return(&counter); | ||||
| +} | ||||
| +EXPORT_SYMBOL(spi_gpio_next_id); | ||||
| + | ||||
| +static int __init spi_gpio_init(void) | ||||
| +{ | ||||
| +	int err; | ||||
| + | ||||
| +	err = platform_driver_register(&spi_gpio_driver); | ||||
| +	if (err) | ||||
| +		printk(KERN_ERR "spi-gpio: register failed: %d\n", err); | ||||
| + | ||||
| +	return err; | ||||
| +} | ||||
| +module_init(spi_gpio_init); | ||||
| + | ||||
| +static void __exit spi_gpio_exit(void) | ||||
| +{ | ||||
| +	platform_driver_unregister(&spi_gpio_driver); | ||||
| +} | ||||
| +module_exit(spi_gpio_exit); | ||||
| + | ||||
| +MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>"); | ||||
| +MODULE_AUTHOR("Michael Buesch"); | ||||
| +MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); | ||||
| +MODULE_LICENSE("GPL v2"); | ||||
| --- a/drivers/spi/Kconfig | ||||
| +++ b/drivers/spi/Kconfig | ||||
| @@ -254,6 +254,15 @@ config SPI_IMG_SPFI | ||||
|  	  This enables support for the SPFI master controller found on | ||||
|  	  IMG SoCs. | ||||
|   | ||||
| +config SPI_GPIO_OLD | ||||
| +	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" | ||||
| +	depends on SPI_MASTER && GPIOLIB | ||||
| +	select SPI_BITBANG | ||||
| +	help | ||||
| +	  This code is deprecated. Please use the new mainline SPI-GPIO driver. | ||||
| + | ||||
| +	  If unsure, say N. | ||||
| + | ||||
|  config SPI_IMX | ||||
|  	tristate "Freescale i.MX SPI controllers" | ||||
|  	depends on ARCH_MXC || COMPILE_TEST | ||||
| --- a/drivers/spi/Makefile | ||||
| +++ b/drivers/spi/Makefile | ||||
| @@ -42,6 +42,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li | ||||
|  obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o | ||||
|  obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o | ||||
|  obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o | ||||
| +obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o | ||||
|  obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o | ||||
|  obj-$(CONFIG_SPI_IMX)			+= spi-imx.o | ||||
|  obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o | ||||
| @@ -13,7 +13,7 @@ Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> | ||||
|  | ||||
| --- a/drivers/spi/Kconfig | ||||
| +++ b/drivers/spi/Kconfig | ||||
| @@ -346,6 +346,13 @@ config SPI_MT65XX | ||||
| @@ -355,6 +355,13 @@ config SPI_MT65XX | ||||
|  	  say Y or M here.If you are not sure, say N. | ||||
|  	  SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. | ||||
|   | ||||
| @@ -29,8 +29,8 @@ Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> | ||||
|  	depends on GPIOLIB || COMPILE_TEST | ||||
| --- a/drivers/spi/Makefile | ||||
| +++ b/drivers/spi/Makefile | ||||
| @@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-sp | ||||
|  obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o | ||||
| @@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o | ||||
|  obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o | ||||
|  obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o | ||||
|  obj-$(CONFIG_SPI_IMX)			+= spi-imx.o | ||||
| +obj-$(CONFIG_SPI_LANTIQ)		+= spi-lantiq.o | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau