diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2015-05-06 21:36:13 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2015-05-06 21:36:13 +0200 |
commit | 67e4e8c056b1df440b44ff2af785f89de36883da (patch) | |
tree | 294f83f475c36eea1f768153479efe2f370ef8c5 /drivers/spi | |
parent | 3975737a7d48b3c767f60be994d55884321d45f9 (diff) | |
parent | 094d25ea9d7aece2a15d4be3a5df81e2ecfe79a9 (diff) | |
download | barebox-67e4e8c056b1df440b44ff2af785f89de36883da.tar.gz barebox-67e4e8c056b1df440b44ff2af785f89de36883da.tar.xz |
Merge branch 'for-next/mvebu'
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 4 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/ath79_spi.c | 2 | ||||
-rw-r--r-- | drivers/spi/gpio_spi.c | 240 | ||||
-rw-r--r-- | drivers/spi/spi-bitbang-txrx.h | 2 |
5 files changed, 247 insertions, 2 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e4fa6a2d94..738b88ea5e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -18,6 +18,10 @@ config DRIVER_SPI_ATMEL bool "Atmel (AT91) SPI Master driver" depends on ARCH_AT91 +config DRIVER_SPI_GPIO + bool "GPIO SPI Master driver" + depends on GPIOLIB + config DRIVER_SPI_IMX bool "i.MX SPI Master driver" depends on ARCH_IMX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7469479c31..7481966585 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_SPI) += spi.o obj-$(CONFIG_DRIVER_SPI_ATH79) += ath79_spi.o +obj-$(CONFIG_DRIVER_SPI_GPIO) += gpio_spi.o obj-$(CONFIG_DRIVER_SPI_IMX) += imx_spi.o obj-$(CONFIG_DRIVER_SPI_MVEBU) += mvebu_spi.o obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c index d9ab269da7..4d71eba695 100644 --- a/drivers/spi/ath79_spi.c +++ b/drivers/spi/ath79_spi.c @@ -100,6 +100,8 @@ static inline u32 getmiso(struct spi_device *spi) return !!((ath79_spi_rr(sc, AR71XX_SPI_REG_RDS) & 1)); } +#define spidelay(nsecs) udelay(nsecs/1000) + #include "spi-bitbang-txrx.h" static inline void ath79_spi_chipselect(struct ath79_spi *sp, int chipselect) diff --git a/drivers/spi/gpio_spi.c b/drivers/spi/gpio_spi.c new file mode 100644 index 0000000000..4ea545a282 --- /dev/null +++ b/drivers/spi/gpio_spi.c @@ -0,0 +1,240 @@ +/* + * SPI master driver using generic bitbanged GPIO + * + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * + * Based on Linux driver + * Copyright (C) 2006,2008 David Brownell + * + * 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. + */ + +#include <common.h> +#include <driver.h> +#include <errno.h> +#include <gpio.h> +#include <init.h> +#include <io.h> +#include <malloc.h> +#include <of_gpio.h> +#include <spi/spi.h> +#include <spi/spi_gpio.h> + +struct gpio_spi { + struct spi_master master; + struct gpio_spi_pdata *data; +}; + +#define priv_from_spi_device(s) container_of(s->master, struct gpio_spi, master) + +static inline void setsck(const struct spi_device *spi, int is_on) +{ + struct gpio_spi *priv = priv_from_spi_device(spi); + gpio_set_value(priv->data->sck, is_on); +} + +static inline void setmosi(const struct spi_device *spi, int is_on) +{ + struct gpio_spi *priv = priv_from_spi_device(spi); + if (!gpio_is_valid(priv->data->mosi)) + return; + gpio_set_value(priv->data->mosi, is_on); +} + +static inline int getmiso(const struct spi_device *spi) +{ + struct gpio_spi *priv = priv_from_spi_device(spi); + if (!gpio_is_valid(priv->data->miso)) + return 1; + return !!gpio_get_value(priv->data->miso); +} + +#define spidelay(nsecs) do { } while (0) + +#include "spi-bitbang-txrx.h" + +static int gpio_spi_set_cs(struct spi_device *spi, bool en) +{ + struct gpio_spi *priv = priv_from_spi_device(spi); + + if (!gpio_is_valid(priv->data->cs[spi->chip_select])) + return 0; + + gpio_set_value(priv->data->cs[spi->chip_select], + (spi->mode & SPI_CS_HIGH) ? en : !en); + + return 0; +} + +static inline u32 gpio_spi_txrx_word(struct spi_device *spi, unsigned nsecs, + u32 word, u8 bits) +{ + int cpol = !!(spi->mode & SPI_CPOL); + if (spi->mode & SPI_CPHA) + return bitbang_txrx_be_cpha1(spi, nsecs, cpol, word, bits); + else + return bitbang_txrx_be_cpha0(spi, nsecs, cpol, word, bits); +} + +static int gpio_spi_transfer_one(struct spi_device *spi, struct spi_transfer *t) +{ + bool read = (t->rx_buf) ? true : false; + u32 word = 0; + int n; + + for (n = 0; n < t->len; n++) { + if (!read) + word = ((const u8 *)t->tx_buf)[n]; + word = gpio_spi_txrx_word(spi, 0, word, 8); + if (read) + ((u8 *)t->rx_buf)[n] = word & 0xff; + } + + return 0; +} + +static int gpio_spi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct spi_transfer *t; + int ret; + + ret = gpio_spi_set_cs(spi, true); + if (ret) + return ret; + + list_for_each_entry(t, &msg->transfers, transfer_list) { + ret = gpio_spi_transfer_one(spi, t); + if (ret) + return ret; + msg->actual_length += t->len; + } + + ret = gpio_spi_set_cs(spi, false); + if (ret) + return ret; + + return 0; +} + +static int gpio_spi_setup(struct spi_device *spi) +{ + if (spi->bits_per_word != 8) { + dev_err(spi->master->dev, "master does not support %d bits per word\n", + spi->bits_per_word); + return -EINVAL; + } + + return 0; +} + +static int gpio_spi_of_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct gpio_spi_pdata *pdata; + int n, sck; + + if (!IS_ENABLED(CONFIG_OFDEVICE) || dev->platform_data) + return 0; + + sck = of_get_named_gpio(np, "gpio-sck", 0); + if (sck == -EPROBE_DEFER) + return sck; + if (!gpio_is_valid(sck)) { + dev_err(dev, "missing mandatory SCK gpio\n"); + return sck; + } + + pdata = xzalloc(sizeof(*pdata)); + pdata->sck = sck; + pdata->num_cs = MAX_CHIPSELECT; + + pdata->miso = of_get_named_gpio(np, "gpio-miso", 0); + if (!gpio_is_valid(pdata->miso)) + pdata->miso = SPI_GPIO_NO_MISO; + + pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0); + if (!gpio_is_valid(pdata->mosi)) + pdata->mosi = SPI_GPIO_NO_MOSI; + + for (n = 0; n < MAX_CHIPSELECT; n++) { + pdata->cs[n] = of_get_named_gpio(np, "cs-gpios", n); + if (!gpio_is_valid(pdata->cs[n])) + pdata->cs[n] = SPI_GPIO_NO_CS; + } + + dev->platform_data = pdata; + + return 0; +} + +static int gpio_spi_probe(struct device_d *dev) +{ + struct gpio_spi *priv; + struct gpio_spi_pdata *pdata; + struct spi_master *master; + int n, ret; + + ret = gpio_spi_of_probe(dev); + if (ret) + return ret; + pdata = dev->platform_data; + + ret = gpio_request_one(pdata->sck, GPIOF_DIR_OUT, "spi-sck"); + if (ret) + return ret; + + if (pdata->miso != SPI_GPIO_NO_MISO) { + ret = gpio_request_one(pdata->miso, GPIOF_DIR_IN, "spi-miso"); + if (ret) + return ret; + } + + if (pdata->mosi != SPI_GPIO_NO_MOSI) { + ret = gpio_request_one(pdata->mosi, GPIOF_DIR_OUT, "spi-mosi"); + if (ret) + return ret; + } + + for (n = 0; n < pdata->num_cs; n++) { + char *cs_name; + + if (!gpio_is_valid(pdata->cs[n])) + continue; + + cs_name = asprintf("spi-cs%d", n); + ret = gpio_request_one(pdata->cs[n], GPIOF_DIR_OUT, cs_name); + if (ret) + return ret; + } + + priv = xzalloc(sizeof(*priv)); + priv->data = pdata; + master = &priv->master; + master->dev = dev; + master->bus_num = dev->id; + master->setup = gpio_spi_setup; + master->transfer = gpio_spi_transfer; + master->num_chipselect = priv->data->num_cs; + + return spi_register_master(&priv->master); +} + +static struct of_device_id __maybe_unused gpio_spi_dt_ids[] = { + { .compatible = "spi-gpio", }, + { } +}; + +static struct driver_d gpio_spi_driver = { + .name = "gpio-spi", + .probe = gpio_spi_probe, + .of_compatible = DRV_OF_COMPAT(gpio_spi_dt_ids), +}; +device_platform_driver(gpio_spi_driver); diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h index 4c74d4e0c5..078ab8c6c0 100644 --- a/drivers/spi/spi-bitbang-txrx.h +++ b/drivers/spi/spi-bitbang-txrx.h @@ -42,8 +42,6 @@ * particular CPU clock rate. */ -#define spidelay(nsecs) udelay(nsecs/1000) - static inline u32 bitbang_txrx_be_cpha0(struct spi_device *spi, unsigned nsecs, unsigned cpol, |