Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/s3c64xx', 'spi/topic...
authorMark Brown <broonie@kernel.org>
Fri, 26 Jan 2018 17:57:31 +0000 (17:57 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 26 Jan 2018 17:57:31 +0000 (17:57 +0000)
Documentation/devicetree/bindings/spi/sh-msiof.txt
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sirf.c
drivers/spi/spi-sun6i.c
include/linux/platform_data/spi-s3c64xx.h

index bdd8395..80710f0 100644 (file)
@@ -36,7 +36,21 @@ Required properties:
 
 Optional properties:
 - clocks               : Must contain a reference to the functional clock.
-- num-cs               : Total number of chip-selects (default is 1)
+- num-cs               : Total number of chip selects (default is 1).
+                        Up to 3 native chip selects are supported:
+                          0: MSIOF_SYNC
+                          1: MSIOF_SS1
+                          2: MSIOF_SS2
+                        Hardware limitations related to chip selects:
+                          - Native chip selects are always deasserted in
+                            between transfers that are part of the same
+                            message.  Use cs-gpios to work around this.
+                          - All slaves using native chip selects must use the
+                            same spi-cs-high configuration.  Use cs-gpios to
+                            work around this.
+                          - When using GPIO chip selects, at least one native
+                            chip select must be left unused, as it will be
+                            driven anyway.
 - dmas                 : Must contain a list of two references to DMA
                         specifiers, one for transmission, and one for
                         reception.
index 4cb515a..b0822d1 100644 (file)
@@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
         * different chip_info, release previously requested GPIO
         */
        if (chip->gpiod_cs) {
-               gpio_free(desc_to_gpio(chip->gpiod_cs));
+               gpiod_put(chip->gpiod_cs);
                chip->gpiod_cs = NULL;
        }
 
@@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi)
 
        if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
            chip->gpiod_cs)
-               gpio_free(desc_to_gpio(chip->gpiod_cs));
+               gpiod_put(chip->gpiod_cs);
 
        kfree(chip);
 }
index de7df20..baa3a9f 100644 (file)
@@ -1,17 +1,7 @@
-/*
- * Copyright (C) 2009 Samsung Electronics Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2009 Samsung Electronics Co., Ltd.
+//      Jaswinder Singh <jassi.brar@samsung.com>
 
 #include <linux/init.h>
 #include <linux/module.h>
index 06bc4b1..c5dcfb4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/dmaengine.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -55,9 +56,14 @@ struct sh_msiof_spi_priv {
        void *rx_dma_page;
        dma_addr_t tx_dma_addr;
        dma_addr_t rx_dma_addr;
+       unsigned short unused_ss;
+       bool native_cs_inited;
+       bool native_cs_high;
        bool slave_aborted;
 };
 
+#define MAX_SS 3       /* Maximum number of native chip selects */
+
 #define TMDR1  0x00    /* Transmit Mode Register 1 */
 #define TMDR2  0x04    /* Transmit Mode Register 2 */
 #define TMDR3  0x08    /* Transmit Mode Register 3 */
@@ -91,6 +97,8 @@ struct sh_msiof_spi_priv {
 #define MDR1_XXSTP      0x00000001 /* Transmission/Reception Stop on FIFO */
 /* TMDR1 */
 #define TMDR1_PCON      0x40000000 /* Transfer Signal Connection */
+#define TMDR1_SYNCCH_MASK 0xc000000 /* Synchronization Signal Channel Select */
+#define TMDR1_SYNCCH_SHIFT      26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */
 
 /* TMDR2 and RMDR2 */
 #define MDR2_BITLEN1(i)        (((i) - 1) << 24) /* Data Size (8-32 bits) */
@@ -324,7 +332,7 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
        return val;
 }
 
-static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
+static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
                                      u32 cpol, u32 cpha,
                                      u32 tx_hi_z, u32 lsb_first, u32 cs_high)
 {
@@ -342,10 +350,13 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
        tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
        tmp |= lsb_first << MDR1_BITLSB_SHIFT;
        tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
-       if (spi_controller_is_slave(p->master))
+       if (spi_controller_is_slave(p->master)) {
                sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
-       else
-               sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+       } else {
+               sh_msiof_write(p, TMDR1,
+                              tmp | MDR1_TRMD | TMDR1_PCON |
+                              (ss < MAX_SS ? ss : 0) << TMDR1_SYNCCH_SHIFT);
+       }
        if (p->master->flags & SPI_MASTER_MUST_TX) {
                /* These bits are reserved if RX needs TX */
                tmp &= ~0x0000ffff;
@@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
 {
        struct device_node      *np = spi->master->dev.of_node;
        struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
-
-       pm_runtime_get_sync(&p->pdev->dev);
+       u32 clr, set, tmp;
 
        if (!np) {
                /*
@@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
                spi->cs_gpio = (uintptr_t)spi->controller_data;
        }
 
-       /* Configure pins before deasserting CS */
-       sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
-                                 !!(spi->mode & SPI_CPHA),
-                                 !!(spi->mode & SPI_3WIRE),
-                                 !!(spi->mode & SPI_LSB_FIRST),
-                                 !!(spi->mode & SPI_CS_HIGH));
+       if (gpio_is_valid(spi->cs_gpio)) {
+               gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+               return 0;
+       }
 
-       if (spi->cs_gpio >= 0)
-               gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+       if (spi_controller_is_slave(p->master))
+               return 0;
 
+       if (p->native_cs_inited &&
+           (p->native_cs_high == !!(spi->mode & SPI_CS_HIGH)))
+               return 0;
 
+       /* Configure native chip select mode/polarity early */
+       clr = MDR1_SYNCMD_MASK;
+       set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI;
+       if (spi->mode & SPI_CS_HIGH)
+               clr |= BIT(MDR1_SYNCAC_SHIFT);
+       else
+               set |= BIT(MDR1_SYNCAC_SHIFT);
+       pm_runtime_get_sync(&p->pdev->dev);
+       tmp = sh_msiof_read(p, TMDR1) & ~clr;
+       sh_msiof_write(p, TMDR1, tmp | set);
        pm_runtime_put(&p->pdev->dev);
-
+       p->native_cs_high = spi->mode & SPI_CS_HIGH;
+       p->native_cs_inited = true;
        return 0;
 }
 
@@ -560,13 +582,20 @@ static int sh_msiof_prepare_message(struct spi_master *master,
 {
        struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
        const struct spi_device *spi = msg->spi;
+       u32 ss, cs_high;
 
        /* Configure pins before asserting CS */
-       sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+       if (gpio_is_valid(spi->cs_gpio)) {
+               ss = p->unused_ss;
+               cs_high = p->native_cs_high;
+       } else {
+               ss = spi->chip_select;
+               cs_high = !!(spi->mode & SPI_CS_HIGH);
+       }
+       sh_msiof_spi_set_pin_regs(p, ss, !!(spi->mode & SPI_CPOL),
                                  !!(spi->mode & SPI_CPHA),
                                  !!(spi->mode & SPI_3WIRE),
-                                 !!(spi->mode & SPI_LSB_FIRST),
-                                 !!(spi->mode & SPI_CS_HIGH));
+                                 !!(spi->mode & SPI_LSB_FIRST), cs_high);
        return 0;
 }
 
@@ -922,9 +951,8 @@ static int sh_msiof_transfer_one(struct spi_master *master,
 
                ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
                if (ret == -EAGAIN) {
-                       pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
-                                    dev_driver_string(&p->pdev->dev),
-                                    dev_name(&p->pdev->dev));
+                       dev_warn_once(&p->pdev->dev,
+                               "DMA not available, falling back to PIO\n");
                        break;
                }
                if (ret)
@@ -1081,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
 }
 #endif
 
+static int sh_msiof_get_cs_gpios(struct sh_msiof_spi_priv *p)
+{
+       struct device *dev = &p->pdev->dev;
+       unsigned int used_ss_mask = 0;
+       unsigned int cs_gpios = 0;
+       unsigned int num_cs, i;
+       int ret;
+
+       ret = gpiod_count(dev, "cs");
+       if (ret <= 0)
+               return 0;
+
+       num_cs = max_t(unsigned int, ret, p->master->num_chipselect);
+       for (i = 0; i < num_cs; i++) {
+               struct gpio_desc *gpiod;
+
+               gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
+               if (!IS_ERR(gpiod)) {
+                       cs_gpios++;
+                       continue;
+               }
+
+               if (PTR_ERR(gpiod) != -ENOENT)
+                       return PTR_ERR(gpiod);
+
+               if (i >= MAX_SS) {
+                       dev_err(dev, "Invalid native chip select %d\n", i);
+                       return -EINVAL;
+               }
+               used_ss_mask |= BIT(i);
+       }
+       p->unused_ss = ffz(used_ss_mask);
+       if (cs_gpios && p->unused_ss >= MAX_SS) {
+               dev_err(dev, "No unused native chip select available\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
        enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr)
 {
@@ -1294,13 +1361,18 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
        if (p->info->rx_fifo_override)
                p->rx_fifo_size = p->info->rx_fifo_override;
 
+       /* Setup GPIO chip selects */
+       master->num_chipselect = p->info->num_chipselect;
+       ret = sh_msiof_get_cs_gpios(p);
+       if (ret)
+               goto err1;
+
        /* init master code */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
        master->flags = chipdata->master_flags;
        master->bus_num = pdev->id;
        master->dev.of_node = pdev->dev.of_node;
-       master->num_chipselect = p->info->num_chipselect;
        master->setup = sh_msiof_spi_setup;
        master->prepare_message = sh_msiof_prepare_message;
        master->slave_abort = sh_msiof_slave_abort;
index bbb1a27..f009d76 100644 (file)
@@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        struct sirfsoc_spi *sspi;
        struct spi_master *master;
        struct resource *mem_res;
-       struct sirf_spi_comp_data *spi_comp_data;
+       const struct sirf_spi_comp_data *spi_comp_data;
        int irq;
        int ret;
        const struct of_device_id *match;
@@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
        sspi = spi_master_get_devdata(master);
        sspi->fifo_full_offset = ilog2(sspi->fifo_size);
-       spi_comp_data = (struct sirf_spi_comp_data *)match->data;
+       spi_comp_data = match->data;
        sspi->regs = spi_comp_data->regs;
        sspi->type = spi_comp_data->type;
        sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1;
index fb38234..8533f4e 100644 (file)
@@ -541,7 +541,7 @@ err_free_master:
 
 static int sun6i_spi_remove(struct platform_device *pdev)
 {
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_force_suspend(&pdev->dev);
 
        return 0;
 }
index da79774..773daf7 100644 (file)
@@ -1,10 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
 /*
  * Copyright (C) 2009 Samsung Electronics Ltd.
  *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * 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 __SPI_S3C64XX_H