最近正在做个项目 用2440上的gpio模拟spi总线。
2.6.32.2内核里有spi_gpio的驱动,但是似乎没有实现同一总线上多个设备的片选。
于是自己实现了一种解决方法,实际使用下来是可行的。
在这里分享一下,望各位大侠不吝指教。
From 14f975c9cfaabcecc52feaba86e44438b79afaa9 Mon Sep 17 00:00:00 2001
From: wangtt <
wtt_usst@163.com>
Date: Wed, 14 Mar 2012 13:21:25 +0800
Subject: [PATCH] enable spi gpio
---
arch/arm/mach-s3c2410/include/mach/spi-gpio.h | 3 +-
arch/arm/mach-s3c2440/mach-mini2440.c | 96 ++++++++++++++++++++++++-
arch/arm/plat-s3c24xx/Kconfig | 2 +-
drivers/spi/spi_s3c24xx_gpio.c | 13 +++-
4 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
index 980a099..e189024 100755
--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
@@ -17,11 +17,12 @@ struct s3c2410_spigpio_info {
unsigned long pin_clk;
unsigned long pin_mosi;
unsigned long pin_miso;
+ unsigned long *pin_cs_array;
int num_chipselect;
int bus_num;
- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
+ void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs, int chip_select_id);
};
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c
index 775750f..9a055d3 100755
--- a/arch/arm/mach-s3c2440/mach-mini2440.c
+++ b/arch/arm/mach-s3c2440/mach-mini2440.c
@@ -42,6 +42,7 @@
#include <linux/mtd/partitions.h>
#include <linux/dm9000.h>
#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>//WTT ADD
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -51,10 +52,14 @@
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
#include <mach/regs-lcd.h>
#include <mach/leds-gpio.h>
#include <mach/idle.h>
#include <mach/fb.h>
+#include <mach/spi-gpio.h>//WTT ADD
+#include <mach/spi.h>//WTT ADD
+#include <../mach-s3c2410/include/mach/spi.h>
#include <plat/regs-serial.h>
#include <plat/iic.h>
@@ -265,6 +270,89 @@ static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
#endif
+/*WTT ADD*/
+/* SPI GPIO BUS1 */
+unsigned long spi_spio_bus1_cs_array[] = {
+ S3C2410_GPF(1), //chip select = 0, AD9833 HIGH SPEED
+ S3C2410_GPF(3), //chip select = 1, AD9833 LOW SPEED
+ S3C2410_GPF(5), //chip select = 2, AD5160
+};
+
+static void gpio_spi1_chipselect(struct s3c2410_spigpio_info *spi, int cs, int chip_select_id)
+{
+ if(chip_select_id >= spi->num_chipselect)
+ {
+ printk("***** WTT DEBUG %s: chip_select_id %d is over spi->num_chipselect %d\n",__func__,chip_select_id,spi->num_chipselect);
+ return;
+ }
+ printk("***** WTT DEBUG %s: chip_select_id %d\n",__func__,chip_select_id);
+ s3c2410_gpio_setpin(spi_spio_bus1_cs_array[chip_select_id], cs ? 0 : 1);
+}
+
+static struct s3c2410_spigpio_info gpio_spi1_info = {
+ .bus_num = 1,
+ .pin_clk = S3C2440_GPJ0,
+ .pin_mosi = S3C2440_GPJ3,
+ .pin_cs_array = spi_spio_bus1_cs_array,
+ .num_chipselect = ARRAY_SIZE(spi_spio_bus1_cs_array), //bus total chips num, eg:'4' is for four devices on this bus
+ .chip_select = gpio_spi1_chipselect,
+};
+
+static struct platform_device gpio_spi1= {
+ .name = "spi_s3c24xx_gpio",
+ .id = 1,
+ .num_resources = 0,
+ .dev.platform_data = &gpio_spi1_info,
+};
+
+static struct spi_board_info __initdata spi1_slave_devs[] = {
+ [0] = {
+ .modalias = "ad9833_spi",
+ .bus_num = 1,
+ .chip_select = 0, //every chip id on this bus
+ //value must below s3c2410_spigpio_info->num_chipselect
+ .mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */
+ .max_speed_hz = 100000,
+ //.platform_data = &jive_lcm_config,
+ },
+ [1] = {
+ .modalias = "ad9833_spi",
+ .bus_num = 1,
+ .chip_select = 1, //every chip id on this bus
+ //value must below s3c2410_spigpio_info->num_chipselect
+ .mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */
+ .max_speed_hz = 100000,
+ }
+};
+
+/* SPI bus0 support */
+static struct s3c2410_spi_info spi0_data = {
+ .pin_cs = S3C2410_GPF(2),
+ .num_cs = 2, //bus total chips num
+ .bus_num = 0,
+ .set_cs = NULL,
+ .gpio_setup = s3c24xx_spi_gpiocfg_bus0_gpe11_12_13,
+// void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
+// void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
+};
+
+static struct spi_board_info __initdata spi0_slave_devs[] = {
+ [0] = {
+ .modalias = "spidev",
+ .bus_num = 0, //every chip id on this bus,value must below spi_board_info->num_cs
+ .chip_select = 0,
+ .mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */
+ .max_speed_hz = 100000,
+ //.platform_data = &jive_lcm_config,
+ }, {
+ .modalias = "tlc357x",
+ .bus_num = 0,
+ .chip_select = 1, //every chip id on this bus,value must below spi_board_info->num_cs
+ .mode = SPI_MODE_0, // CPOL=0, CPHA=0
+ .max_speed_hz = 100000,
+ },
+};
+/*WTT ADD*/
static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = {
.l3_clk = S3C2410_GPB(4),
.l3_data = S3C2410_GPB(3),
@@ -386,6 +474,8 @@ static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
+ &s3c_device_spi0,//WTT ADD
+ &gpio_spi1,//WTT ADD
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
@@ -407,6 +497,11 @@ static void __init mini2440_machine_init(void)
s3c24xx_fb_set_platdata(&mini2440_fb_info);
#endif
s3c_i2c0_set_platdata(NULL);
+ spi_register_board_info(spi0_slave_devs, ARRAY_SIZE(spi0_slave_devs));//WTT ADD
+ s3c_device_spi0.dev.platform_data = &spi0_data;//WTT ADD
+
+ spi_register_board_info(spi1_slave_devs, ARRAY_SIZE(spi1_slave_devs));//WTT ADD
+ gpio_spi1.dev.platform_data = &gpio_spi1_info;//WTT ADD
s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
@@ -426,4 +521,3 @@ MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")
.init_machine = mini2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
-
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 6d302bf..a53a05b 100755
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -129,7 +129,7 @@ config S3C24XX_ADC
# SPI default pin configuration code
config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
- bool
+ bool "S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13"
help
SPI GPIO configuration code for BUS0 when connected to
GPE11, GPE12 and GPE13.
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index bbf9371..6f51fba 100755
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -23,6 +23,7 @@
#include <linux/spi/spi_bitbang.h>
#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
#include <mach/spi-gpio.h>
#include <mach/hardware.h>
@@ -92,7 +93,7 @@ static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
if (sg->info && sg->info->chip_select)
- (sg->info->chip_select)(sg->info, value);
+ (sg->info->chip_select)(sg->info, value, dev->chip_select);
}
static int s3c2410_spigpio_probe(struct platform_device *dev)
@@ -101,6 +102,7 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
+ int cur_pin = 0;
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
if (master == NULL) {
@@ -132,14 +134,19 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
s3c2410_gpio_setpin(info->pin_clk, 0);
s3c2410_gpio_cfgpin(info->pin_clk, S3C2410_GPIO_OUTPUT);
- if (info->pin_mosi < S3C2410_GPH10) {
+ if (info->pin_mosi < S3C2443_GPJ13) {
s3c2410_gpio_setpin(info->pin_mosi, 0);
s3c2410_gpio_cfgpin(info->pin_mosi, S3C2410_GPIO_OUTPUT);
}
- if (info->pin_miso != S3C2410_GPA0 && info->pin_miso < S3C2410_GPH10)
+ if (info->pin_miso != S3C2410_GPA0 && info->pin_miso < S3C2443_GPJ13)
s3c2410_gpio_cfgpin(info->pin_miso, S3C2410_GPIO_INPUT);
+ for(cur_pin = 0;cur_pin < info->num_chipselect; cur_pin++)
+ {
+ if (info->pin_cs_array[cur_pin] != S3C2410_GPA0 && info->pin_cs_array[cur_pin] < S3C2443_GPJ13)
+ s3c2410_gpio_cfgpin(info->pin_cs_array[cur_pin], S3C2410_GPIO_OUTPUT);
+ }
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
goto err_no_bitbang;
--
1.7.4.2.406
[ 此帖被jbx在2012-03-14 16:02重新编辑 ]