[U-Boot] [PATCH] support spi gpio driver by control gpio bitbang

This patch adds basic support for spi mode 0~3 by control gpio bitbang. It uses several gpio pin and emulates spi chipselect signal, clock signal and sda signal as if spi controller generate spi signal.
Signed-off-by: Donghwa Lee <dh09.lee at samsung.com http://lists.denx.de/mailman/listinfo/u-boot>
--- drivers/spi/spi_gpio.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ include/spi.h | 27 +++++++++ 2 files changed, 180 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi_gpio.c
diff --git a/drivers/spi/spi_gpio.c b/drivers/spi/spi_gpio.c new file mode 100644 index 0000000..cce809e --- /dev/null +++ b/drivers/spi/spi_gpio.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * spi_gpio.c - SPI master driver using generic bitbanged GPIO + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <asm/arch/gpio.h> +#include <spi.h> + +static void spi_gpio_set_sck(struct spi_platform_data *spi, int is_on) +{ + gpio_set_value(spi->clk_bank, spi->clk_num, is_on); +} + +static void spi_gpio_set_mosi(struct spi_platform_data *spi, int is_on) +{ + gpio_set_value(spi->si_bank, spi->si_num, is_on); +} + +static void spi_gpio_chipselect(struct spi_platform_data *spi, + int cpol) +{ + gpio_set_value(spi->cs_bank, spi->cs_num, + !spi->cs_active); + + /* set initial clock polarity */ + if (cpol) + spi_gpio_set_sck(spi, spi->mode & SPI_CPOL); + + /* SPI is normally active-low */ + gpio_set_value(spi->cs_bank, spi->cs_num, + spi->cs_active); +} + +static void +spi_gpio_tx_cpha0(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int cpol, + unsigned int word, unsigned int bits) +{ + int i; + unsigned int data; + + data = (word << spi->word_len) + bits; + + spi_gpio_chipselect(spi, cpol); + + /* clock starts at inactive polarity */ + for (i = spi->word_len; i >= 0; i--) { + + /* data high or low */ + if ((data >> i) & 0x1) + spi_gpio_set_mosi(spi, 1); + else + spi_gpio_set_mosi(spi, 0); + + udelay(nsecs); + + spi_gpio_set_sck(spi, !cpol); + udelay(nsecs); + + spi_gpio_set_sck(spi, cpol); + } +} + +static void +spi_gpio_tx_cpha1(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int cpol, + unsigned int word, unsigned int bits) +{ + int i; + unsigned int data; + + data = (word << spi->word_len) + bits; + + spi_gpio_chipselect(spi, cpol); + + /* clock starts at inactive polarity */ + for (i = spi->word_len; i >= 0; i--) { + + /* setup MSB (to slave) on leading edge */ + spi_gpio_set_sck(spi, !cpol); + + /* data high or low */ + if ((data >> i) & 0x1) + spi_gpio_set_mosi(spi, 1); + else + spi_gpio_set_mosi(spi, 0); + + udelay(nsecs); + + spi_gpio_set_sck(spi, cpol); + udelay(nsecs); + } +} + +static void spi_gpio_tx_word_mode0(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int word, unsigned int bits) +{ + return spi_gpio_tx_cpha0(spi, nsecs, 0, word, bits); +} + +static void spi_gpio_tx_word_mode1(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int word, unsigned int bits) +{ + return spi_gpio_tx_cpha1(spi, nsecs, 0, word, bits); +} + +static void spi_gpio_tx_word_mode2(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int word, unsigned int bits) +{ + return spi_gpio_tx_cpha0(spi, nsecs, 1, word, bits); +} + +static void spi_gpio_tx_word_mode3(struct spi_platform_data *spi, + unsigned int nsecs, unsigned int word, unsigned int bits) +{ + return spi_gpio_tx_cpha1(spi, nsecs, 1, word, bits); +} + +void spi_gpio_write(struct spi_platform_data *spi, + unsigned int address, unsigned int command) +{ + switch (spi->mode) { + case SPI_MODE_0: + spi_gpio_tx_word_mode0(spi, + 1, address, command); + case SPI_MODE_1: + spi_gpio_tx_word_mode1(spi, + 1, address, command); + case SPI_MODE_2: + spi_gpio_tx_word_mode2(spi, + 1, address, command); + case SPI_MODE_3: + spi_gpio_tx_word_mode3(spi, + 1, address, command); + } +} diff --git a/include/spi.h b/include/spi.h index 320e50e..ef3f94d 100644 --- a/include/spi.h +++ b/include/spi.h @@ -62,6 +62,33 @@ struct spi_slave { unsigned int cs; };
+#define COMMAND_ONLY 0xFE +#define DATA_ONLY 0xFF +#define ACTIVE_LOW 0 +#define ACTIVE_HIGH 1 + + +struct spi_platform_data { + struct s5p_gpio_bank *cs_bank; + struct s5p_gpio_bank *clk_bank; + struct s5p_gpio_bank *si_bank; + struct s5p_gpio_bank *so_bank; + + unsigned int cs_num; + unsigned int clk_num; + unsigned int si_num; + unsigned int so_num; + + unsigned int mode; + unsigned int cs_active; + unsigned int word_len; + + unsigned int set_rev; +}; + +void spi_gpio_write(struct spi_platform_data *spi, + unsigned int address, unsigned int command); + /*----------------------------------------------------------------------- * Initialization, must be called once on start up. *

Dear Donghwa Lee,
2010/9/1 Donghwa Lee yiffie9819@gmail.com:
This patch adds basic support for spi mode 0~3 by control gpio bitbang. It uses several gpio pin and emulates spi chipselect signal, clock signal and sda signal as if spi controller generate spi signal.
Signed-off-by: Donghwa Lee <dh09.lee at samsung.com http://lists.denx.de/mailman/listinfo/u-boot>
Please fix your email address.
drivers/spi/spi_gpio.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ include/spi.h | 27 +++++++++ 2 files changed, 180 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi_gpio.c
Your patch is line wrapped and the tabs are stripped out. Please resubmit. And then, people would review your patch.
diff --git a/drivers/spi/spi_gpio.c b/drivers/spi/spi_gpio.c new file mode 100644 index 0000000..cce809e --- /dev/null +++ b/drivers/spi/spi_gpio.c @@ -0,0 +1,153 @@ +/*
- Copyright (C) 2010 Samsung Electronics
Please insert the name of author
- spi_gpio.c - SPI master driver using generic bitbanged GPIO
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
please remove this space
+#include <common.h> +#include <asm/arch/gpio.h> +#include <spi.h>
+static void spi_gpio_set_sck(struct spi_platform_data *spi, int is_on) +{
- gpio_set_value(spi->clk_bank, spi->clk_num, is_on);
+}
+static void spi_gpio_set_mosi(struct spi_platform_data *spi, int is_on) +{
- gpio_set_value(spi->si_bank, spi->si_num, is_on);
+}
+static void spi_gpio_chipselect(struct spi_platform_data *spi,
- int cpol)
+{
- gpio_set_value(spi->cs_bank, spi->cs_num,
- !spi->cs_active);
- /* set initial clock polarity */
- if (cpol)
- spi_gpio_set_sck(spi, spi->mode & SPI_CPOL);
- /* SPI is normally active-low */
- gpio_set_value(spi->cs_bank, spi->cs_num,
- spi->cs_active);
+}
+static void +spi_gpio_tx_cpha0(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int cpol,
- unsigned int word, unsigned int bits)
+{
- int i;
- unsigned int data;
- data = (word << spi->word_len) + bits;
- spi_gpio_chipselect(spi, cpol);
- /* clock starts at inactive polarity */
- for (i = spi->word_len; i >= 0; i--) {
- /* data high or low */
- if ((data >> i) & 0x1)
- spi_gpio_set_mosi(spi, 1);
- else
- spi_gpio_set_mosi(spi, 0);
- udelay(nsecs);
- spi_gpio_set_sck(spi, !cpol);
- udelay(nsecs);
- spi_gpio_set_sck(spi, cpol);
- }
+}
+static void +spi_gpio_tx_cpha1(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int cpol,
- unsigned int word, unsigned int bits)
+{
- int i;
- unsigned int data;
- data = (word << spi->word_len) + bits;
- spi_gpio_chipselect(spi, cpol);
- /* clock starts at inactive polarity */
- for (i = spi->word_len; i >= 0; i--) {
please remove this space
- /* setup MSB (to slave) on leading edge */
- spi_gpio_set_sck(spi, !cpol);
- /* data high or low */
- if ((data >> i) & 0x1)
- spi_gpio_set_mosi(spi, 1);
- else
- spi_gpio_set_mosi(spi, 0);
- udelay(nsecs);
- spi_gpio_set_sck(spi, cpol);
- udelay(nsecs);
- }
+}
+static void spi_gpio_tx_word_mode0(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int word, unsigned int bits)
+{
- return spi_gpio_tx_cpha0(spi, nsecs, 0, word, bits);
+}
+static void spi_gpio_tx_word_mode1(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int word, unsigned int bits)
+{
- return spi_gpio_tx_cpha1(spi, nsecs, 0, word, bits);
+}
+static void spi_gpio_tx_word_mode2(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int word, unsigned int bits)
+{
- return spi_gpio_tx_cpha0(spi, nsecs, 1, word, bits);
+}
+static void spi_gpio_tx_word_mode3(struct spi_platform_data *spi,
- unsigned int nsecs, unsigned int word, unsigned int bits)
+{
- return spi_gpio_tx_cpha1(spi, nsecs, 1, word, bits);
+}
+void spi_gpio_write(struct spi_platform_data *spi,
- unsigned int address, unsigned int command)
+{
- switch (spi->mode) {
- case SPI_MODE_0:
- spi_gpio_tx_word_mode0(spi,
- 1, address, command);
- case SPI_MODE_1:
- spi_gpio_tx_word_mode1(spi,
- 1, address, command);
- case SPI_MODE_2:
- spi_gpio_tx_word_mode2(spi,
- 1, address, command);
- case SPI_MODE_3:
- spi_gpio_tx_word_mode3(spi,
- 1, address, command);
- }
+} diff --git a/include/spi.h b/include/spi.h index 320e50e..ef3f94d 100644 --- a/include/spi.h +++ b/include/spi.h @@ -62,6 +62,33 @@ struct spi_slave { unsigned int cs; };
+#define COMMAND_ONLY 0xFE +#define DATA_ONLY 0xFF +#define ACTIVE_LOW 0 +#define ACTIVE_HIGH 1
please remove this space
+struct spi_platform_data {
- struct s5p_gpio_bank *cs_bank;
- struct s5p_gpio_bank *clk_bank;
- struct s5p_gpio_bank *si_bank;
- struct s5p_gpio_bank *so_bank;
Is it S5P SoC specific? It will be occur compiler errors at other SoCs.
- unsigned int cs_num;
- unsigned int clk_num;
- unsigned int si_num;
- unsigned int so_num;
- unsigned int mode;
- unsigned int cs_active;
- unsigned int word_len;
- unsigned int set_rev;
+};
+void spi_gpio_write(struct spi_platform_data *spi,
- unsigned int address, unsigned int command);
/*-----------------------------------------------------------------------
- Initialization, must be called once on start up.
-- 1.6.0.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Thanks Minkyu Kang
participants (2)
-
Donghwa Lee
-
Minkyu Kang