From: Gabor Juhos Date: Tue, 15 Apr 2008 07:33:43 +0000 (+0000) Subject: move spi_gpio driver into the kernel, clean-up SPI modules X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=67fd9d7fba4f966a49012f02622f308b8cb2e7d7;p=openwrt%2Fstaging%2Fneocturne.git move spi_gpio driver into the kernel, clean-up SPI modules SVN-Revision: 10844 --- diff --git a/package/kernel/modules/other.mk b/package/kernel/modules/other.mk index b1f3c501a2..3872b3cfea 100644 --- a/package/kernel/modules/other.mk +++ b/package/kernel/modules/other.mk @@ -535,7 +535,7 @@ $(eval $(call KernelPackage,input-gpio-buttons)) define KernelPackage/mmc-spi SUBMENU:=$(OTHER_MENU) TITLE:=MMC/SD over SPI Support - DEPENDS:=@LINUX_2_6 + DEPENDS:=@LINUX_2_6 +kmod-mmc +kmod-spi +kmod-crc-itu-t +kmod-crc7 KCONFIG:=CONFIG_MMC_SPI FILES:=$(LINUX_DIR)/drivers/mmc/host/mmc_spi.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,90,mmc_spi) @@ -564,32 +564,22 @@ $(eval $(call KernelPackage,mmc-atmelmci)) define KernelPackage/spi SUBMENU:=$(OTHER_MENU) - TITLE:=Serial Peripheral Interface - DEPENDS:=@LINUX_2_6 +kmod-crc-itu-t +kmod-crc7 - KCONFIG:=CONFIG_SPI=y \ - CONFIG_MTD_DATAFLASH \ - CONFIG_MTD_M25P80 \ - CONFIG_SPI_AT25 \ - CONFIG_SPI_SPIDEV \ - CONFIG_SPI_TLE62X0 - FILES:= \ - $(LINUX_DIR)/drivers/spi/at25.$(LINUX_KMOD_SUFFIX) \ - $(LINUX_DIR)/drivers/spi/spidev.$(LINUX_KMOD_SUFFIX) \ - $(LINUX_DIR)/drivers/spi/tle62x0.$(LINUX_KMOD_SUFFIX) \ - $(LINUX_DIR)/drivers/mtd/devices/m25p80.$(LINUX_KMOD_SUFFIX) \ - $(LINUX_DIR)/drivers/mtd/devices/mtd_dataflash.$(LINUX_KMOD_SUFFIX) - AUTOLOAD:=$(call AutoLoad,90,spi) + TITLE:=Serial Peripheral Interface support + DEPENDS:=@LINUX_2_6 + KCONFIG:=\ + CONFIG_SPI=y \ + CONFIG_SPI_MASTER=y endef define KernelPackage/spi/description - This package contains the Serial Peripheral Interface driver + This package contains the Serial Peripheral Interface Master driver endef $(eval $(call KernelPackage,spi)) define KernelPackage/spi-bitbang SUBMENU:=$(OTHER_MENU) - TITLE:=Serial Peripheral Interface bitbanging + TITLE:=Serial Peripheral Interface bitbanging library DEPENDS:=@LINUX_2_6 +kmod-spi KCONFIG:=CONFIG_SPI_BITBANG FILES:=$(LINUX_DIR)/drivers/spi/spi_bitbang.$(LINUX_KMOD_SUFFIX) @@ -597,7 +587,38 @@ define KernelPackage/spi-bitbang endef define KernelPackage/spi-bitbang/description - This package contains the Serial Peripheral Interface bitbanging library + This package contains the SPI bitbanging library endef $(eval $(call KernelPackage,spi-bitbang)) + +define KernelPackage/spi-gpio + SUBMENU:=$(OTHER_MENU) + TITLE:=GPIO based bitbanging SPI controller + DEPENDS:=@LINUX_2_6 +kmod-spi-bitbang + KCONFIG:=CONFIG_SPI_GPIO + FILES:=$(LINUX_DIR)/drivers/spi/spi_gpio.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,92,spi_gpio) +endef + +define KernelPackage/spi-gpio/description + This package contains the GPIO based bitbanging SPI controller driver +endef + +$(eval $(call KernelPackage,spi-gpio)) + +define KernelPackage/spi-dev + SUBMENU:=$(OTHER_MENU) + TITLE:=User mode SPI device driver + DEPENDS:=@LINUX_2_6 +kmod-spi + KCONFIG:=CONFIG_SPI_SPIDEV + FILES:=$(LINUX_DIR)/drivers/spi/spidev.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,91,spidev) +endef + +define KernelPackage/spi-dev/description + This package contains the user mode SPI device driver +endef + +$(eval $(call KernelPackage,spi-dev)) + diff --git a/package/mmc_over_gpio/Makefile b/package/mmc_over_gpio/Makefile index 46847a50f6..42c666cd3c 100644 --- a/package/mmc_over_gpio/Makefile +++ b/package/mmc_over_gpio/Makefile @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. @@ -10,18 +10,17 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mmc-over-gpio -PKG_RELEASE:=1 +PKG_RELEASE:=2 include $(INCLUDE_DIR)/package.mk define KernelPackage/mmc-over-gpio SUBMENU:=Other modules - DEPENDS:=@LINUX_2_6 +kmod-spi +kmod-spi-bitbang +kmod-mmc +kmod-mmc-spi @!TARGET_x86 + DEPENDS:=@LINUX_2_6 +kmod-mmc-spi +kmod-spi-gpio @!TARGET_x86 TITLE:=MMC/SD card over GPIO support - FILES:=$(PKG_BUILD_DIR)/spi_gpio.$(LINUX_KMOD_SUFFIX) \ - $(PKG_BUILD_DIR)/mmc_over_spigpio.$(LINUX_KMOD_SUFFIX) - AUTOLOAD:=$(call AutoLoad,92,spi_gpio mmc_over_spigpio) + FILES:=$(PKG_BUILD_DIR)/mmc_over_spigpio.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,93,spi_gpio mmc_over_spigpio) endef define KernelPackage/mmc-over-gpio/description diff --git a/package/mmc_over_gpio/src/Makefile b/package/mmc_over_gpio/src/Makefile index d2258bb95f..b052c405ad 100644 --- a/package/mmc_over_gpio/src/Makefile +++ b/package/mmc_over_gpio/src/Makefile @@ -1,2 +1 @@ -obj-m += spi_gpio.o obj-m += mmc_over_spigpio.o diff --git a/package/mmc_over_gpio/src/linux/spi/spi_gpio.h b/package/mmc_over_gpio/src/linux/spi/spi_gpio.h deleted file mode 100644 index 8e7d4b189d..0000000000 --- a/package/mmc_over_gpio/src/linux/spi/spi_gpio.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * spi_gpio interface to platform code - * - * Copyright (c) 2008 Piotr Skamruk - * - * 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 -#include - - -/** 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; -}; - -#endif /* _LINUX_SPI_SPI_GPIO */ diff --git a/package/mmc_over_gpio/src/mmc_over_spigpio.c b/package/mmc_over_gpio/src/mmc_over_spigpio.c index 36dbd0f6a8..113b518a56 100644 --- a/package/mmc_over_gpio/src/mmc_over_spigpio.c +++ b/package/mmc_over_gpio/src/mmc_over_spigpio.c @@ -9,7 +9,7 @@ #include #include #include -#include "linux/spi/spi_gpio.h" //XXX +#include /* This is the maximum speed in Hz */ diff --git a/package/mmc_over_gpio/src/spi_gpio.c b/package/mmc_over_gpio/src/spi_gpio.c deleted file mode 100644 index 31048acc3f..0000000000 --- a/package/mmc_over_gpio/src/spi_gpio.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "linux/spi/spi_gpio.h" //XXX -#include - - -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 - -static u32 spi_gpio_txrx_mode0(struct spi_device *spi, - unsigned nsecs, u32 word, u8 bits) -{ - return bitbang_txrx_be_cpha0(spi, nsecs, 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, 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, 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, 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 __devexit 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", - .owner = THIS_MODULE, - }, - .probe = spi_gpio_probe, - .remove = __devexit_p(spi_gpio_remove), -}; - -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 "); -MODULE_AUTHOR("Michael Buesch"); -MODULE_DESCRIPTION("Platform independent GPIO bitbangling SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic-2.6/config-2.6.23 b/target/linux/generic-2.6/config-2.6.23 index 8d7a6cb3eb..3e755eb361 100644 --- a/target/linux/generic-2.6/config-2.6.23 +++ b/target/linux/generic-2.6/config-2.6.23 @@ -726,6 +726,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MOUSE_PC110PAD is not set CONFIG_MSDOS_FS=m CONFIG_MSDOS_PARTITION=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set # CONFIG_MTD_NAND is not set # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set CONFIG_MTD_ROOTFS_ROOT_DEV=y @@ -1386,6 +1388,8 @@ CONFIG_SOUND=m # CONFIG_SPARSEMEM_MANUAL is not set # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_TLE62X0 is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_SQUASHFS=y # CONFIG_SQUASHFS_EMBEDDED is not set diff --git a/target/linux/generic-2.6/config-2.6.24 b/target/linux/generic-2.6/config-2.6.24 index 688285582e..efd5d62a94 100644 --- a/target/linux/generic-2.6/config-2.6.24 +++ b/target/linux/generic-2.6/config-2.6.24 @@ -746,6 +746,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MOUSE_PC110PAD is not set CONFIG_MSDOS_FS=m CONFIG_MSDOS_PARTITION=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set # CONFIG_MTD_INTEL_VR_NOR is not set # CONFIG_MTD_NAND is not set # CONFIG_MTD_OOPS is not set @@ -1424,6 +1426,8 @@ CONFIG_SOUND=m # CONFIG_SPARSEMEM_MANUAL is not set # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_TLE62X0 is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_SQUASHFS=y # CONFIG_SQUASHFS_EMBEDDED is not set diff --git a/target/linux/generic-2.6/files/drivers/spi/spi_gpio.c b/target/linux/generic-2.6/files/drivers/spi/spi_gpio.c new file mode 100644 index 0000000000..31048acc3f --- /dev/null +++ b/target/linux/generic-2.6/files/drivers/spi/spi_gpio.c @@ -0,0 +1,242 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/spi/spi_gpio.h" //XXX +#include + + +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 + +static u32 spi_gpio_txrx_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 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, 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, 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, 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 __devexit 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", + .owner = THIS_MODULE, + }, + .probe = spi_gpio_probe, + .remove = __devexit_p(spi_gpio_remove), +}; + +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 "); +MODULE_AUTHOR("Michael Buesch"); +MODULE_DESCRIPTION("Platform independent GPIO bitbangling SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic-2.6/files/include/linux/spi/spi_gpio.h b/target/linux/generic-2.6/files/include/linux/spi/spi_gpio.h new file mode 100644 index 0000000000..8e7d4b189d --- /dev/null +++ b/target/linux/generic-2.6/files/include/linux/spi/spi_gpio.h @@ -0,0 +1,53 @@ +/* + * spi_gpio interface to platform code + * + * Copyright (c) 2008 Piotr Skamruk + * + * 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 +#include + + +/** 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; +}; + +#endif /* _LINUX_SPI_SPI_GPIO */ diff --git a/target/linux/generic-2.6/patches-2.6.23/921-gpio_spi_driver.patch b/target/linux/generic-2.6/patches-2.6.23/921-gpio_spi_driver.patch new file mode 100644 index 0000000000..aa4e6ee0ac --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.23/921-gpio_spi_driver.patch @@ -0,0 +1,28 @@ +Index: linux-2.6.23.16/drivers/spi/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/spi/Kconfig ++++ linux-2.6.23.16/drivers/spi/Kconfig +@@ -100,6 +100,11 @@ config SPI_BUTTERFLY + inexpensive battery powered microcontroller evaluation board. + This same cable can be used to flash new firmware. + ++config SPI_GPIO ++ tristate "GPIO API based bitbanging SPI controller" ++ depends on SPI_MASTER && GENERIC_GPIO && EXPERIMENTAL ++ select SPI_BITBANG ++ + config SPI_IMX + tristate "Freescale iMX SPI controller" + depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL +Index: linux-2.6.23.16/drivers/spi/Makefile +=================================================================== +--- linux-2.6.23.16.orig/drivers/spi/Makefile ++++ linux-2.6.23.16/drivers/spi/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx. + obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o + obj-$(CONFIG_SPI_AU1550) += au1550_spi.o + obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o ++obj-$(CONFIG_SPI_GPIO) += spi_gpio.o + obj-$(CONFIG_SPI_IMX) += spi_imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o + obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o diff --git a/target/linux/generic-2.6/patches-2.6.24/921-gpio_spi_driver.patch b/target/linux/generic-2.6/patches-2.6.24/921-gpio_spi_driver.patch new file mode 100644 index 0000000000..aa4e6ee0ac --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.24/921-gpio_spi_driver.patch @@ -0,0 +1,28 @@ +Index: linux-2.6.23.16/drivers/spi/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/spi/Kconfig ++++ linux-2.6.23.16/drivers/spi/Kconfig +@@ -100,6 +100,11 @@ config SPI_BUTTERFLY + inexpensive battery powered microcontroller evaluation board. + This same cable can be used to flash new firmware. + ++config SPI_GPIO ++ tristate "GPIO API based bitbanging SPI controller" ++ depends on SPI_MASTER && GENERIC_GPIO && EXPERIMENTAL ++ select SPI_BITBANG ++ + config SPI_IMX + tristate "Freescale iMX SPI controller" + depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL +Index: linux-2.6.23.16/drivers/spi/Makefile +=================================================================== +--- linux-2.6.23.16.orig/drivers/spi/Makefile ++++ linux-2.6.23.16/drivers/spi/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx. + obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o + obj-$(CONFIG_SPI_AU1550) += au1550_spi.o + obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o ++obj-$(CONFIG_SPI_GPIO) += spi_gpio.o + obj-$(CONFIG_SPI_IMX) += spi_imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o + obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o