LKML Archive on lore.kernel.org help / color / mirror / Atom feed
* [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller @ 2014-12-08 12:53 Lee Jones 2014-12-08 12:53 ` [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' " Lee Jones ` (4 more replies) 0 siblings, 5 replies; 9+ messages in thread From: Lee Jones @ 2014-12-08 12:53 UTC (permalink / raw) To: linux-arm-kernel, linux-kernel Cc: lee.jones, kernel, broonie, linux-spi, devicetree This is a new driver which controls the SPI component of ST's Synchronous Serial Controller (SSC). v2 => v3: - Fixes Patrice's review comments - Removed COMPILE_TEST (at least until Will Deacon's patch lands) v1 => v2: - New, more specific CONFIG symbol - Increased Runtime PM functionality - Make use of new Pinctrl API - Convert from SPI Bitbang => Transfer One - Omit functionality which Core can handle - Removal of *cough* debug code Lee Jones (4): spi: Add new driver for STMicroelectronics' SPI Controller spi: st: Provide Device Tree binding documentation ARM: sti: Provide DT nodes for SSC[0..4] ARM: sti: Provide DT nodes for SBC SSC[0..2] Documentation/devicetree/bindings/spi/spi-st.txt | 40 ++ arch/arm/boot/dts/stih407.dtsi | 85 ++++ drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/spi-st-ssc4.c | 509 +++++++++++++++++++++++ 5 files changed, 642 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-st.txt create mode 100644 drivers/spi/spi-st-ssc4.c -- 1.9.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' SPI Controller 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones @ 2014-12-08 12:53 ` Lee Jones 2014-12-08 13:12 ` [STLinux Kernel] " Patrice Chotard 2014-12-08 12:53 ` [PATCH v3 2/4] spi: st: Provide Device Tree binding documentation Lee Jones ` (3 subsequent siblings) 4 siblings, 1 reply; 9+ messages in thread From: Lee Jones @ 2014-12-08 12:53 UTC (permalink / raw) To: linux-arm-kernel, linux-kernel Cc: lee.jones, kernel, broonie, linux-spi, devicetree This patch adds support for the SPI portion of ST's SSC device. Signed-off-by: Lee Jones <lee.jones@linaro.org> --- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/spi-st-ssc4.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 517 insertions(+) create mode 100644 drivers/spi/spi-st-ssc4.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 84e7c9e..0d42362 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -488,6 +488,13 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_ST_SSC4 + tristate "STMicroelectronics SPI SSC-based driver" + depends on ARCH_STI + help + STMicroelectronics SoCs support for SPI. If you say yes to + this option, support will be included for the SSC driven SPI. + config SPI_SUN4I tristate "Allwinner A10 SoCs SPI controller" depends on ARCH_SUNXI || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 78f24ca..c38e28c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c new file mode 100644 index 0000000..3fd3e85 --- /dev/null +++ b/drivers/spi/spi-st-ssc4.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2008-2014 STMicroelectronics Limited + * + * Author: Angus Clark <Angus.Clark@st.com> + * Patrice Chotard <patrice.chotard@st.com> + * Lee Jones <lee.jones@linaro.org> + * + * SPI master mode controller driver, used in STMicroelectronics devices. + * + * May be copied or modified under the terms of the GNU General Public + * License Version 2.0 only. See linux/COPYING for more information. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> + +/* SSC registers */ +#define SSC_BRG 0x000 +#define SSC_TBUF 0x004 +#define SSC_RBUF 0x008 +#define SSC_CTL 0x00C +#define SSC_IEN 0x010 +#define SSC_I2C 0x018 + +/* SSC Control */ +#define SSC_CTL_DATA_WIDTH_9 0x8 +#define SSC_CTL_DATA_WIDTH_MSK 0xf +#define SSC_CTL_BM 0xf +#define SSC_CTL_HB BIT(4) +#define SSC_CTL_PH BIT(5) +#define SSC_CTL_PO BIT(6) +#define SSC_CTL_SR BIT(7) +#define SSC_CTL_MS BIT(8) +#define SSC_CTL_EN BIT(9) +#define SSC_CTL_LPB BIT(10) +#define SSC_CTL_EN_TX_FIFO BIT(11) +#define SSC_CTL_EN_RX_FIFO BIT(12) +#define SSC_CTL_EN_CLST_RX BIT(13) + +/* SSC Interrupt Enable */ +#define SSC_IEN_TEEN BIT(2) + +#define FIFO_SIZE 8 + +struct spi_st { + /* SSC SPI Controller */ + void __iomem *base; + struct clk *clk; + struct device *dev; + + /* SSC SPI current transaction */ + const u8 *tx_ptr; + u8 *rx_ptr; + u16 bytes_per_word; + unsigned int words_remaining; + unsigned int baud; + struct completion done; +}; + +static int spi_st_clk_enable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return 0; + + return clk_prepare_enable(spi_st->clk); +} + +static void spi_st_clk_disable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return; + + clk_disable_unprepare(spi_st->clk); +} + +/* Load the TX FIFO */ +static void ssc_write_tx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + if (spi_st->tx_ptr) { + if (spi_st->bytes_per_word == 1) { + word = *spi_st->tx_ptr++; + } else { + word = *spi_st->tx_ptr++; + word = *spi_st->tx_ptr++ | (word << 8); + } + } + writel_relaxed(word, spi_st->base + SSC_TBUF); + } +} + +/* Read the RX FIFO */ +static void ssc_read_rx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + word = readl_relaxed(spi_st->base + SSC_RBUF); + + if (spi_st->rx_ptr) { + if (spi_st->bytes_per_word == 1) { + *spi_st->rx_ptr++ = (uint8_t)word; + } else { + *spi_st->rx_ptr++ = (word >> 8); + *spi_st->rx_ptr++ = word & 0xff; + } + } + } + spi_st->words_remaining -= count; +} + +static int spi_st_transfer_one(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) +{ + struct spi_st *spi_st = spi_master_get_devdata(master); + uint32_t ctl = 0; + + /* Setup transfer */ + spi_st->tx_ptr = t->tx_buf; + spi_st->rx_ptr = t->rx_buf; + + if (spi->bits_per_word > 8) { + /* + * Anything greater than 8 bits-per-word requires 2 + * bytes-per-word in the RX/TX buffers + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + } else if (spi->bits_per_word == 8 && !(t->len & 0x1)) { + /* + * If transfer is even-length, and 8 bits-per-word, then + * implement as half-length 16 bits-per-word transfer + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + /* Set SSC_CTL to 16 bits-per-word */ + ctl = readl_relaxed(spi_st->base + SSC_CTL); + writel_relaxed((ctl | 0xf), spi_st->base + SSC_CTL); + + readl_relaxed(spi_st->base + SSC_RBUF); + + } else { + spi_st->bytes_per_word = 1; + spi_st->words_remaining = t->len; + } + + reinit_completion(&spi_st->done); + + /* Start transfer by writing to the TX FIFO */ + ssc_write_tx_fifo(spi_st); + writel_relaxed(SSC_IEN_TEEN, spi_st->base + SSC_IEN); + + /* Wait for transfer to complete */ + wait_for_completion(&spi_st->done); + + /* Restore SSC_CTL if necessary */ + if (ctl) + writel_relaxed(ctl, spi_st->base + SSC_CTL); + + spi_finalize_current_transfer(spi->master); + + return t->len; +} + +static void spi_st_cleanup(struct spi_device *spi) +{ + int cs = spi->cs_gpio; + + if (gpio_is_valid(cs)) + devm_gpio_free(&spi->dev, cs); +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) +static int spi_st_setup(struct spi_device *spi) +{ + struct spi_st *spi_st = spi_master_get_devdata(spi->master); + u32 spi_st_clk, sscbrg, var; + u32 hz = spi->max_speed_hz; + int cs = spi->cs_gpio; + int ret; + + if (spi->mode & ~MODEBITS) { + dev_err(&spi->dev, "unsupported mode bits 0x%x\n", + spi->mode & ~MODEBITS); + return -EINVAL; + } + + if (!hz) { + dev_err(&spi->dev, "max_speed_hz unspecified\n"); + return -EINVAL; + } + + if (!gpio_is_valid(cs)) { + dev_err(&spi->dev, "%d is not a valid gpio\n", cs); + return -EINVAL; + } + + if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) { + dev_err(&spi->dev, "could not request gpio:%d\n", cs); + return -EINVAL; + } + + ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + if (ret) + return ret; + + spi_st_clk = clk_get_rate(spi_st->clk); + + /* Set SSC_BRF */ + sscbrg = spi_st_clk / (2 * hz); + if (sscbrg < 0x07 || sscbrg > BIT(16)) { + dev_err(&spi->dev, + "baudrate %d outside valid range %d\n", sscbrg, hz); + return -EINVAL; + } + + spi_st->baud = spi_st_clk / (2 * sscbrg); + if (sscbrg == BIT(16)) /* 16-bit counter wraps */ + sscbrg = 0x0; + + writel_relaxed(sscbrg, spi_st->base + SSC_BRG); + + dev_dbg(&spi->dev, + "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n", + hz, spi_st->baud, sscbrg); + + /* Set SSC_CTL and enable SSC */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_MS; + + if (spi->mode & SPI_CPOL) + var |= SSC_CTL_PO; + else + var &= ~SSC_CTL_PO; + + if (spi->mode & SPI_CPHA) + var |= SSC_CTL_PH; + else + var &= ~SSC_CTL_PH; + + if ((spi->mode & SPI_LSB_FIRST) == 0) + var |= SSC_CTL_HB; + else + var &= ~SSC_CTL_HB; + + if (spi->mode & SPI_LOOP) + var |= SSC_CTL_LPB; + else + var &= ~SSC_CTL_LPB; + + var &= ~SSC_CTL_DATA_WIDTH_MSK; + var |= (spi->bits_per_word - 1); + + var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO; + var |= SSC_CTL_EN; + + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Clear the status register */ + readl_relaxed(spi_st->base + SSC_RBUF); + + return 0; +} + +/* Interrupt fired when TX shift register becomes empty */ +static irqreturn_t spi_st_irq(int irq, void *dev_id) +{ + struct spi_st *spi_st = (struct spi_st *)dev_id; + + /* Read RX FIFO */ + ssc_read_rx_fifo(spi_st); + + /* Fill TX FIFO */ + if (spi_st->words_remaining) { + ssc_write_tx_fifo(spi_st); + } else { + /* TX/RX complete */ + writel_relaxed(0x0, spi_st->base + SSC_IEN); + /* + * read SSC_IEN to ensure that this bit is set + * before re-enabling interrupt + */ + readl(spi_st->base + SSC_IEN); + complete(&spi_st->done); + } + + return IRQ_HANDLED; +} + +static int spi_st_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct resource *res; + struct spi_st *spi_st; + int irq, ret = 0; + u32 var; + + master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); + if (!master) + return -ENOMEM; + + master->dev.of_node = np; + master->mode_bits = MODEBITS; + master->setup = spi_st_setup; + master->cleanup = spi_st_cleanup; + master->transfer_one = spi_st_transfer_one; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->auto_runtime_pm = true; + master->bus_num = pdev->id; + spi_st = spi_master_get_devdata(master); + + spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); + if (IS_ERR(spi_st->clk)) { + dev_err(&pdev->dev, "Unable to request clock\n"); + return PTR_ERR(spi_st->clk); + } + + ret = spi_st_clk_enable(spi_st); + if (ret) + return ret; + + init_completion(&spi_st->done); + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + spi_st->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spi_st->base)) { + ret = PTR_ERR(spi_st->base); + goto clk_disable; + } + + /* Disable I2C and Reset SSC */ + writel_relaxed(0x0, spi_st->base + SSC_I2C); + var = readw_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + udelay(1); + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Set SSC into slave mode before reconfiguring PIO pins */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_MS; + writel_relaxed(var, spi_st->base + SSC_CTL); + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + dev_err(&pdev->dev, "IRQ missing or invalid\n"); + ret = -EINVAL; + goto clk_disable; + } + + ret = devm_request_irq(&pdev->dev, irq, spi_st_irq, 0, + pdev->name, spi_st); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq %d\n", irq); + goto clk_disable; + } + + /* by default the device is on */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + platform_set_drvdata(pdev, master); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "Failed to register master\n"); + goto clk_disable; + } + + return 0; + +clk_disable: + spi_st_clk_disable(spi_st); + + return ret; +} + +static int spi_st_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + spi_st_clk_disable(spi_st); + + pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int spi_st_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + writel_relaxed(0, spi_st->base + SSC_IEN); + pinctrl_pm_select_sleep_state(dev); + + spi_st_clk_disable(spi_st); + + return 0; +} + +static int spi_st_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + int ret; + + ret = spi_st_clk_enable(spi_st); + pinctrl_pm_select_default_state(dev); + + return ret; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int spi_st_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + return pm_runtime_force_suspend(dev); +} + +static int spi_st_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_resume(master); + if (ret) + return ret; + + return pm_runtime_force_resume(dev); +} +#endif + +static const struct dev_pm_ops spi_st_pm = { + SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) + SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) +}; + +static struct of_device_id stm_spi_match[] = { + { .compatible = "st,comms-ssc4-spi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm_spi_match); + +static struct platform_driver spi_st_driver = { + .driver = { + .name = "spi-st", + .pm = &spi_st_pm, + .of_match_table = of_match_ptr(stm_spi_match), + }, + .probe = spi_st_probe, + .remove = spi_st_remove, +}; +module_platform_driver(spi_st_driver); + +MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>"); +MODULE_DESCRIPTION("STM SSC SPI driver"); +MODULE_LICENSE("GPL v2"); -- 1.9.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [STLinux Kernel] [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' SPI Controller 2014-12-08 12:53 ` [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' " Lee Jones @ 2014-12-08 13:12 ` Patrice Chotard 0 siblings, 0 replies; 9+ messages in thread From: Patrice Chotard @ 2014-12-08 13:12 UTC (permalink / raw) To: Lee Jones, linux-arm-kernel, linux-kernel Cc: devicetree, broonie, kernel, linux-spi Hi Lee Acked-by: Patrice Chotard <patrice.chotard@st.com> Thanks On 12/08/2014 01:53 PM, Lee Jones wrote: > This patch adds support for the SPI portion of ST's SSC device. > > Signed-off-by: Lee Jones <lee.jones@linaro.org> > --- > drivers/spi/Kconfig | 7 + > drivers/spi/Makefile | 1 + > drivers/spi/spi-st-ssc4.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 517 insertions(+) > create mode 100644 drivers/spi/spi-st-ssc4.c > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 84e7c9e..0d42362 100644 > --- a/drivers/spi/Kconfig > +++ b/drivers/spi/Kconfig > @@ -488,6 +488,13 @@ config SPI_SIRF > help > SPI driver for CSR SiRFprimaII SoCs > > +config SPI_ST_SSC4 > + tristate "STMicroelectronics SPI SSC-based driver" > + depends on ARCH_STI > + help > + STMicroelectronics SoCs support for SPI. If you say yes to > + this option, support will be included for the SSC driven SPI. > + > config SPI_SUN4I > tristate "Allwinner A10 SoCs SPI controller" > depends on ARCH_SUNXI || COMPILE_TEST > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index 78f24ca..c38e28c 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o > obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o > obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o > obj-$(CONFIG_SPI_SIRF) += spi-sirf.o > +obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o > obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o > obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o > obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o > diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c > new file mode 100644 > index 0000000..3fd3e85 > --- /dev/null > +++ b/drivers/spi/spi-st-ssc4.c > @@ -0,0 +1,509 @@ > +/* > + * Copyright (c) 2008-2014 STMicroelectronics Limited > + * > + * Author: Angus Clark <Angus.Clark@st.com> > + * Patrice Chotard <patrice.chotard@st.com> > + * Lee Jones <lee.jones@linaro.org> > + * > + * SPI master mode controller driver, used in STMicroelectronics devices. > + * > + * May be copied or modified under the terms of the GNU General Public > + * License Version 2.0 only. See linux/COPYING for more information. > + */ > + > +#include <linux/clk.h> > +#include <linux/delay.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/of_gpio.h> > +#include <linux/of_irq.h> > +#include <linux/pm_runtime.h> > +#include <linux/spi/spi.h> > +#include <linux/spi/spi_bitbang.h> > + > +/* SSC registers */ > +#define SSC_BRG 0x000 > +#define SSC_TBUF 0x004 > +#define SSC_RBUF 0x008 > +#define SSC_CTL 0x00C > +#define SSC_IEN 0x010 > +#define SSC_I2C 0x018 > + > +/* SSC Control */ > +#define SSC_CTL_DATA_WIDTH_9 0x8 > +#define SSC_CTL_DATA_WIDTH_MSK 0xf > +#define SSC_CTL_BM 0xf > +#define SSC_CTL_HB BIT(4) > +#define SSC_CTL_PH BIT(5) > +#define SSC_CTL_PO BIT(6) > +#define SSC_CTL_SR BIT(7) > +#define SSC_CTL_MS BIT(8) > +#define SSC_CTL_EN BIT(9) > +#define SSC_CTL_LPB BIT(10) > +#define SSC_CTL_EN_TX_FIFO BIT(11) > +#define SSC_CTL_EN_RX_FIFO BIT(12) > +#define SSC_CTL_EN_CLST_RX BIT(13) > + > +/* SSC Interrupt Enable */ > +#define SSC_IEN_TEEN BIT(2) > + > +#define FIFO_SIZE 8 > + > +struct spi_st { > + /* SSC SPI Controller */ > + void __iomem *base; > + struct clk *clk; > + struct device *dev; > + > + /* SSC SPI current transaction */ > + const u8 *tx_ptr; > + u8 *rx_ptr; > + u16 bytes_per_word; > + unsigned int words_remaining; > + unsigned int baud; > + struct completion done; > +}; > + > +static int spi_st_clk_enable(struct spi_st *spi_st) > +{ > + /* > + * Current platforms use one of the core clocks for SPI and I2C. > + * If we attempt to disable the clock, the system will hang. > + * > + * TODO: Remove this when platform supports power domains. > + */ > + return 0; > + > + return clk_prepare_enable(spi_st->clk); > +} > + > +static void spi_st_clk_disable(struct spi_st *spi_st) > +{ > + /* > + * Current platforms use one of the core clocks for SPI and I2C. > + * If we attempt to disable the clock, the system will hang. > + * > + * TODO: Remove this when platform supports power domains. > + */ > + return; > + > + clk_disable_unprepare(spi_st->clk); > +} > + > +/* Load the TX FIFO */ > +static void ssc_write_tx_fifo(struct spi_st *spi_st) > +{ > + unsigned int count, i; > + uint32_t word = 0; > + > + if (spi_st->words_remaining > FIFO_SIZE) > + count = FIFO_SIZE; > + else > + count = spi_st->words_remaining; > + > + for (i = 0; i < count; i++) { > + if (spi_st->tx_ptr) { > + if (spi_st->bytes_per_word == 1) { > + word = *spi_st->tx_ptr++; > + } else { > + word = *spi_st->tx_ptr++; > + word = *spi_st->tx_ptr++ | (word << 8); > + } > + } > + writel_relaxed(word, spi_st->base + SSC_TBUF); > + } > +} > + > +/* Read the RX FIFO */ > +static void ssc_read_rx_fifo(struct spi_st *spi_st) > +{ > + unsigned int count, i; > + uint32_t word = 0; > + > + if (spi_st->words_remaining > FIFO_SIZE) > + count = FIFO_SIZE; > + else > + count = spi_st->words_remaining; > + > + for (i = 0; i < count; i++) { > + word = readl_relaxed(spi_st->base + SSC_RBUF); > + > + if (spi_st->rx_ptr) { > + if (spi_st->bytes_per_word == 1) { > + *spi_st->rx_ptr++ = (uint8_t)word; > + } else { > + *spi_st->rx_ptr++ = (word >> 8); > + *spi_st->rx_ptr++ = word & 0xff; > + } > + } > + } > + spi_st->words_remaining -= count; > +} > + > +static int spi_st_transfer_one(struct spi_master *master, > + struct spi_device *spi, struct spi_transfer *t) > +{ > + struct spi_st *spi_st = spi_master_get_devdata(master); > + uint32_t ctl = 0; > + > + /* Setup transfer */ > + spi_st->tx_ptr = t->tx_buf; > + spi_st->rx_ptr = t->rx_buf; > + > + if (spi->bits_per_word > 8) { > + /* > + * Anything greater than 8 bits-per-word requires 2 > + * bytes-per-word in the RX/TX buffers > + */ > + spi_st->bytes_per_word = 2; > + spi_st->words_remaining = t->len / 2; > + > + } else if (spi->bits_per_word == 8 && !(t->len & 0x1)) { > + /* > + * If transfer is even-length, and 8 bits-per-word, then > + * implement as half-length 16 bits-per-word transfer > + */ > + spi_st->bytes_per_word = 2; > + spi_st->words_remaining = t->len / 2; > + > + /* Set SSC_CTL to 16 bits-per-word */ > + ctl = readl_relaxed(spi_st->base + SSC_CTL); > + writel_relaxed((ctl | 0xf), spi_st->base + SSC_CTL); > + > + readl_relaxed(spi_st->base + SSC_RBUF); > + > + } else { > + spi_st->bytes_per_word = 1; > + spi_st->words_remaining = t->len; > + } > + > + reinit_completion(&spi_st->done); > + > + /* Start transfer by writing to the TX FIFO */ > + ssc_write_tx_fifo(spi_st); > + writel_relaxed(SSC_IEN_TEEN, spi_st->base + SSC_IEN); > + > + /* Wait for transfer to complete */ > + wait_for_completion(&spi_st->done); > + > + /* Restore SSC_CTL if necessary */ > + if (ctl) > + writel_relaxed(ctl, spi_st->base + SSC_CTL); > + > + spi_finalize_current_transfer(spi->master); > + > + return t->len; > +} > + > +static void spi_st_cleanup(struct spi_device *spi) > +{ > + int cs = spi->cs_gpio; > + > + if (gpio_is_valid(cs)) > + devm_gpio_free(&spi->dev, cs); > +} > + > +/* the spi->mode bits understood by this driver: */ > +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) > +static int spi_st_setup(struct spi_device *spi) > +{ > + struct spi_st *spi_st = spi_master_get_devdata(spi->master); > + u32 spi_st_clk, sscbrg, var; > + u32 hz = spi->max_speed_hz; > + int cs = spi->cs_gpio; > + int ret; > + > + if (spi->mode & ~MODEBITS) { > + dev_err(&spi->dev, "unsupported mode bits 0x%x\n", > + spi->mode & ~MODEBITS); > + return -EINVAL; > + } > + > + if (!hz) { > + dev_err(&spi->dev, "max_speed_hz unspecified\n"); > + return -EINVAL; > + } > + > + if (!gpio_is_valid(cs)) { > + dev_err(&spi->dev, "%d is not a valid gpio\n", cs); > + return -EINVAL; > + } > + > + if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) { > + dev_err(&spi->dev, "could not request gpio:%d\n", cs); > + return -EINVAL; > + } > + > + ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); > + if (ret) > + return ret; > + > + spi_st_clk = clk_get_rate(spi_st->clk); > + > + /* Set SSC_BRF */ > + sscbrg = spi_st_clk / (2 * hz); > + if (sscbrg < 0x07 || sscbrg > BIT(16)) { > + dev_err(&spi->dev, > + "baudrate %d outside valid range %d\n", sscbrg, hz); > + return -EINVAL; > + } > + > + spi_st->baud = spi_st_clk / (2 * sscbrg); > + if (sscbrg == BIT(16)) /* 16-bit counter wraps */ > + sscbrg = 0x0; > + > + writel_relaxed(sscbrg, spi_st->base + SSC_BRG); > + > + dev_dbg(&spi->dev, > + "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n", > + hz, spi_st->baud, sscbrg); > + > + /* Set SSC_CTL and enable SSC */ > + var = readl_relaxed(spi_st->base + SSC_CTL); > + var |= SSC_CTL_MS; > + > + if (spi->mode & SPI_CPOL) > + var |= SSC_CTL_PO; > + else > + var &= ~SSC_CTL_PO; > + > + if (spi->mode & SPI_CPHA) > + var |= SSC_CTL_PH; > + else > + var &= ~SSC_CTL_PH; > + > + if ((spi->mode & SPI_LSB_FIRST) == 0) > + var |= SSC_CTL_HB; > + else > + var &= ~SSC_CTL_HB; > + > + if (spi->mode & SPI_LOOP) > + var |= SSC_CTL_LPB; > + else > + var &= ~SSC_CTL_LPB; > + > + var &= ~SSC_CTL_DATA_WIDTH_MSK; > + var |= (spi->bits_per_word - 1); > + > + var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO; > + var |= SSC_CTL_EN; > + > + writel_relaxed(var, spi_st->base + SSC_CTL); > + > + /* Clear the status register */ > + readl_relaxed(spi_st->base + SSC_RBUF); > + > + return 0; > +} > + > +/* Interrupt fired when TX shift register becomes empty */ > +static irqreturn_t spi_st_irq(int irq, void *dev_id) > +{ > + struct spi_st *spi_st = (struct spi_st *)dev_id; > + > + /* Read RX FIFO */ > + ssc_read_rx_fifo(spi_st); > + > + /* Fill TX FIFO */ > + if (spi_st->words_remaining) { > + ssc_write_tx_fifo(spi_st); > + } else { > + /* TX/RX complete */ > + writel_relaxed(0x0, spi_st->base + SSC_IEN); > + /* > + * read SSC_IEN to ensure that this bit is set > + * before re-enabling interrupt > + */ > + readl(spi_st->base + SSC_IEN); > + complete(&spi_st->done); > + } > + > + return IRQ_HANDLED; > +} > + > +static int spi_st_probe(struct platform_device *pdev) > +{ > + struct device_node *np = pdev->dev.of_node; > + struct spi_master *master; > + struct resource *res; > + struct spi_st *spi_st; > + int irq, ret = 0; > + u32 var; > + > + master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); > + if (!master) > + return -ENOMEM; > + > + master->dev.of_node = np; > + master->mode_bits = MODEBITS; > + master->setup = spi_st_setup; > + master->cleanup = spi_st_cleanup; > + master->transfer_one = spi_st_transfer_one; > + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); > + master->auto_runtime_pm = true; > + master->bus_num = pdev->id; > + spi_st = spi_master_get_devdata(master); > + > + spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); > + if (IS_ERR(spi_st->clk)) { > + dev_err(&pdev->dev, "Unable to request clock\n"); > + return PTR_ERR(spi_st->clk); > + } > + > + ret = spi_st_clk_enable(spi_st); > + if (ret) > + return ret; > + > + init_completion(&spi_st->done); > + > + /* Get resources */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + spi_st->base = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(spi_st->base)) { > + ret = PTR_ERR(spi_st->base); > + goto clk_disable; > + } > + > + /* Disable I2C and Reset SSC */ > + writel_relaxed(0x0, spi_st->base + SSC_I2C); > + var = readw_relaxed(spi_st->base + SSC_CTL); > + var |= SSC_CTL_SR; > + writel_relaxed(var, spi_st->base + SSC_CTL); > + > + udelay(1); > + var = readl_relaxed(spi_st->base + SSC_CTL); > + var &= ~SSC_CTL_SR; > + writel_relaxed(var, spi_st->base + SSC_CTL); > + > + /* Set SSC into slave mode before reconfiguring PIO pins */ > + var = readl_relaxed(spi_st->base + SSC_CTL); > + var &= ~SSC_CTL_MS; > + writel_relaxed(var, spi_st->base + SSC_CTL); > + > + irq = irq_of_parse_and_map(np, 0); > + if (!irq) { > + dev_err(&pdev->dev, "IRQ missing or invalid\n"); > + ret = -EINVAL; > + goto clk_disable; > + } > + > + ret = devm_request_irq(&pdev->dev, irq, spi_st_irq, 0, > + pdev->name, spi_st); > + if (ret) { > + dev_err(&pdev->dev, "Failed to request irq %d\n", irq); > + goto clk_disable; > + } > + > + /* by default the device is on */ > + pm_runtime_set_active(&pdev->dev); > + pm_runtime_enable(&pdev->dev); > + > + platform_set_drvdata(pdev, master); > + > + ret = devm_spi_register_master(&pdev->dev, master); > + if (ret) { > + dev_err(&pdev->dev, "Failed to register master\n"); > + goto clk_disable; > + } > + > + return 0; > + > +clk_disable: > + spi_st_clk_disable(spi_st); > + > + return ret; > +} > + > +static int spi_st_remove(struct platform_device *pdev) > +{ > + struct spi_master *master = platform_get_drvdata(pdev); > + struct spi_st *spi_st = spi_master_get_devdata(master); > + > + spi_st_clk_disable(spi_st); > + > + pinctrl_pm_select_sleep_state(&pdev->dev); > + > + return 0; > +} > + > +#ifdef CONFIG_PM > +static int spi_st_runtime_suspend(struct device *dev) > +{ > + struct spi_master *master = dev_get_drvdata(dev); > + struct spi_st *spi_st = spi_master_get_devdata(master); > + > + writel_relaxed(0, spi_st->base + SSC_IEN); > + pinctrl_pm_select_sleep_state(dev); > + > + spi_st_clk_disable(spi_st); > + > + return 0; > +} > + > +static int spi_st_runtime_resume(struct device *dev) > +{ > + struct spi_master *master = dev_get_drvdata(dev); > + struct spi_st *spi_st = spi_master_get_devdata(master); > + int ret; > + > + ret = spi_st_clk_enable(spi_st); > + pinctrl_pm_select_default_state(dev); > + > + return ret; > +} > +#endif > + > +#ifdef CONFIG_PM_SLEEP > +static int spi_st_suspend(struct device *dev) > +{ > + struct spi_master *master = dev_get_drvdata(dev); > + int ret; > + > + ret = spi_master_suspend(master); > + if (ret) > + return ret; > + > + return pm_runtime_force_suspend(dev); > +} > + > +static int spi_st_resume(struct device *dev) > +{ > + struct spi_master *master = dev_get_drvdata(dev); > + int ret; > + > + ret = spi_master_resume(master); > + if (ret) > + return ret; > + > + return pm_runtime_force_resume(dev); > +} > +#endif > + > +static const struct dev_pm_ops spi_st_pm = { > + SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) > + SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) > +}; > + > +static struct of_device_id stm_spi_match[] = { > + { .compatible = "st,comms-ssc4-spi", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, stm_spi_match); > + > +static struct platform_driver spi_st_driver = { > + .driver = { > + .name = "spi-st", > + .pm = &spi_st_pm, > + .of_match_table = of_match_ptr(stm_spi_match), > + }, > + .probe = spi_st_probe, > + .remove = spi_st_remove, > +}; > +module_platform_driver(spi_st_driver); > + > +MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>"); > +MODULE_DESCRIPTION("STM SSC SPI driver"); > +MODULE_LICENSE("GPL v2"); ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/4] spi: st: Provide Device Tree binding documentation 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones 2014-12-08 12:53 ` [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' " Lee Jones @ 2014-12-08 12:53 ` Lee Jones 2014-12-08 12:53 ` [PATCH v3 3/4] ARM: sti: Provide DT nodes for SSC[0..4] Lee Jones ` (2 subsequent siblings) 4 siblings, 0 replies; 9+ messages in thread From: Lee Jones @ 2014-12-08 12:53 UTC (permalink / raw) To: linux-arm-kernel, linux-kernel Cc: lee.jones, kernel, broonie, linux-spi, devicetree This patch adds DT documentation for the SPI portion of ST's SSC device. Signed-off-by: Lee Jones <lee.jones@linaro.org> --- Documentation/devicetree/bindings/spi/spi-st.txt | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-st.txt diff --git a/Documentation/devicetree/bindings/spi/spi-st.txt b/Documentation/devicetree/bindings/spi/spi-st.txt new file mode 100644 index 0000000..fe54959 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-st.txt @@ -0,0 +1,40 @@ +STMicroelectronics SSC (SPI) Controller +--------------------------------------- + +Required properties: +- compatible : "st,comms-ssc4-spi" +- reg : Offset and length of the device's register set +- interrupts : The interrupt specifier +- clock-names : Must contain "ssc" +- clocks : Must contain an entry for each name in clock-names + See ../clk/* +- pinctrl-names : Uses "default", can use "sleep" if provided + See ../pinctrl/pinctrl-binding.txt + +Optional properties: +- cs-gpios : List of GPIO chip selects + See ../spi/spi-bus.txt + +Child nodes represent devices on the SPI bus + See ../spi/spi-bus.txt + +Example: + spi@9840000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9840000 0x110>; + interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + pinctrl-0 = <&pinctrl_spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&pio17 5 0>; + #address-cells = <1>; + #size-cells = <0>; + + st95hf@0{ + compatible = "st,st95hf"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + }; + }; -- 1.9.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/4] ARM: sti: Provide DT nodes for SSC[0..4] 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones 2014-12-08 12:53 ` [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' " Lee Jones 2014-12-08 12:53 ` [PATCH v3 2/4] spi: st: Provide Device Tree binding documentation Lee Jones @ 2014-12-08 12:53 ` Lee Jones 2014-12-08 12:53 ` [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] Lee Jones 2014-12-08 13:22 ` [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Arnd Bergmann 4 siblings, 0 replies; 9+ messages in thread From: Lee Jones @ 2014-12-08 12:53 UTC (permalink / raw) To: linux-arm-kernel, linux-kernel Cc: lee.jones, kernel, broonie, linux-spi, devicetree The Synchronous Serial Controller is used to provide SPI. Signed-off-by: Lee Jones <lee.jones@linaro.org> --- arch/arm/boot/dts/stih407.dtsi | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi index 50637f5..90bc090 100644 --- a/arch/arm/boot/dts/stih407.dtsi +++ b/arch/arm/boot/dts/stih407.dtsi @@ -275,5 +275,59 @@ status = "disabled"; }; + + spi@9840000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9840000 0x110>; + interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + pinctrl-0 = <&pinctrl_spi0_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi@9841000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9841000 0x110>; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + + status = "disabled"; + }; + + spi@9842000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9842000 0x110>; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + + status = "disabled"; + }; + + spi@9843000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9843000 0x110>; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + + status = "disabled"; + }; + + spi@9844000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9844000 0x110>; + interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + + status = "disabled"; + }; }; }; -- 1.9.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones ` (2 preceding siblings ...) 2014-12-08 12:53 ` [PATCH v3 3/4] ARM: sti: Provide DT nodes for SSC[0..4] Lee Jones @ 2014-12-08 12:53 ` Lee Jones 2014-12-08 13:15 ` [STLinux Kernel] " Peter Griffin 2014-12-08 13:22 ` [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Arnd Bergmann 4 siblings, 1 reply; 9+ messages in thread From: Lee Jones @ 2014-12-08 12:53 UTC (permalink / raw) To: linux-arm-kernel, linux-kernel Cc: lee.jones, kernel, broonie, linux-spi, devicetree The Synchronous Serial Controller is used to provide SPI. These are the ports which are located on the Stand-By Controller (SBC). Signed-off-by: Lee Jones <lee.jones@linaro.org> --- arch/arm/boot/dts/stih407.dtsi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi index 90bc090..80e2407 100644 --- a/arch/arm/boot/dts/stih407.dtsi +++ b/arch/arm/boot/dts/stih407.dtsi @@ -329,5 +329,36 @@ status = "disabled"; }; + + /* SBC SSC */ + spi@9540000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9540000 0x110>; + interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_sysin>; + clock-names = "ssc"; + + status = "disabled"; + }; + + spi@9541000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9541000 0x110>; + interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_sysin>; + clock-names = "ssc"; + + status = "disabled"; + }; + + spi@9542000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9542000 0x110>; + interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_sysin>; + clock-names = "ssc"; + + status = "disabled"; + }; }; }; -- 1.9.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [STLinux Kernel] [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] 2014-12-08 12:53 ` [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] Lee Jones @ 2014-12-08 13:15 ` Peter Griffin 0 siblings, 0 replies; 9+ messages in thread From: Peter Griffin @ 2014-12-08 13:15 UTC (permalink / raw) To: Lee Jones Cc: linux-arm-kernel, linux-kernel, devicetree, broonie, kernel, linux-spi Hi Lee, On Mon, 08 Dec 2014, Lee Jones wrote: > The Synchronous Serial Controller is used to provide SPI. > > These are the ports which are located on the Stand-By Controller (SBC). After my series which adds stih410 SoC support, these nodes should now live in the common stih407-family.dtsi file (common to both SoC's). regards, Peter. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones ` (3 preceding siblings ...) 2014-12-08 12:53 ` [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] Lee Jones @ 2014-12-08 13:22 ` Arnd Bergmann 2014-12-08 13:53 ` [STLinux Kernel] " Maxime Coquelin 4 siblings, 1 reply; 9+ messages in thread From: Arnd Bergmann @ 2014-12-08 13:22 UTC (permalink / raw) To: Lee Jones Cc: linux-arm-kernel, linux-kernel, kernel, broonie, linux-spi, devicetree On Monday 08 December 2014 12:53:30 Lee Jones wrote: > This is a new driver which controls the SPI component of ST's > Synchronous Serial Controller (SSC). > How does this related to the i2c driver for drivers/i2c/busses/i2c-st.c? Could you have the same piece of hardware do one or the other mode depending on pin configuration, or is each instance hardwired to a particular mode? Is there any code worth sharing between the two drivers? Arnd ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [STLinux Kernel] [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller 2014-12-08 13:22 ` [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Arnd Bergmann @ 2014-12-08 13:53 ` Maxime Coquelin 0 siblings, 0 replies; 9+ messages in thread From: Maxime Coquelin @ 2014-12-08 13:53 UTC (permalink / raw) To: Arnd Bergmann, Lee Jones Cc: devicetree, kernel, linux-kernel, linux-spi, broonie, linux-arm-kernel On 12/08/2014 02:22 PM, Arnd Bergmann wrote: > On Monday 08 December 2014 12:53:30 Lee Jones wrote: >> This is a new driver which controls the SPI component of ST's >> Synchronous Serial Controller (SSC). >> > How does this related to the i2c driver for drivers/i2c/busses/i2c-st.c? > Could you have the same piece of hardware do one or the other mode > depending on pin configuration, or is each instance hardwired to > a particular mode? This is the same IP, that can be configured either in SPI or I2C. > > Is there any code worth sharing between the two drivers? No, except a couple of registers, they are managed in a ways. The way it is used, a single SSC instance can only be used either in SPI or I2C mode on a board, so I think it wouldn't make sense to create a MFD driver to manage it. Kr, Maxime > > Arnd > > _______________________________________________ > Kernel mailing list > Kernel@stlinux.com > http://www.stlinux.com/mailman/listinfo/kernel ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2014-12-08 13:54 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-12-08 12:53 [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Lee Jones 2014-12-08 12:53 ` [PATCH v3 1/4] spi: Add new driver for STMicroelectronics' " Lee Jones 2014-12-08 13:12 ` [STLinux Kernel] " Patrice Chotard 2014-12-08 12:53 ` [PATCH v3 2/4] spi: st: Provide Device Tree binding documentation Lee Jones 2014-12-08 12:53 ` [PATCH v3 3/4] ARM: sti: Provide DT nodes for SSC[0..4] Lee Jones 2014-12-08 12:53 ` [PATCH v3 4/4] ARM: sti: Provide DT nodes for SBC SSC[0..2] Lee Jones 2014-12-08 13:15 ` [STLinux Kernel] " Peter Griffin 2014-12-08 13:22 ` [PATCH v3 0/4] spi: st: New driver for ST's SPI Controller Arnd Bergmann 2014-12-08 13:53 ` [STLinux Kernel] " Maxime Coquelin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).