Merge remote-tracking branch 'spi/topic/of' into spi-next
[linux-2.6-block.git] / drivers / spi / spi.c
index be73d236919f067a9ad5be3123024ff1f417a22f..6ca59406b0b7a5bbe965833cb7e5fa8d86b388dd 100644 (file)
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * SPI init/core code
  *
  * Copyright (C) 2005 David Brownell
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
- *
- * 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 <linux/kernel.h>
@@ -60,6 +51,7 @@ static void spidev_release(struct device *dev)
                spi->controller->cleanup(spi);
 
        spi_controller_put(spi->controller);
+       kfree(spi->driver_override);
        kfree(spi);
 }
 
@@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 }
 static DEVICE_ATTR_RO(modalias);
 
+static ssize_t driver_override_store(struct device *dev,
+                                    struct device_attribute *a,
+                                    const char *buf, size_t count)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       const char *end = memchr(buf, '\n', count);
+       const size_t len = end ? end - buf : count;
+       const char *driver_override, *old;
+
+       /* We need to keep extra room for a newline when displaying value */
+       if (len >= (PAGE_SIZE - 1))
+               return -EINVAL;
+
+       driver_override = kstrndup(buf, len, GFP_KERNEL);
+       if (!driver_override)
+               return -ENOMEM;
+
+       device_lock(dev);
+       old = spi->driver_override;
+       if (len) {
+               spi->driver_override = driver_override;
+       } else {
+               /* Emptry string, disable driver override */
+               spi->driver_override = NULL;
+               kfree(driver_override);
+       }
+       device_unlock(dev);
+       kfree(old);
+
+       return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+                                   struct device_attribute *a, char *buf)
+{
+       const struct spi_device *spi = to_spi_device(dev);
+       ssize_t len;
+
+       device_lock(dev);
+       len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
+       device_unlock(dev);
+       return len;
+}
+static DEVICE_ATTR_RW(driver_override);
+
 #define SPI_STATISTICS_ATTRS(field, file)                              \
 static ssize_t spi_controller_##field##_show(struct device *dev,       \
                                             struct device_attribute *attr, \
@@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
 
 static struct attribute *spi_dev_attrs[] = {
        &dev_attr_modalias.attr,
+       &dev_attr_driver_override.attr,
        NULL,
 };
 
@@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
        const struct spi_device *spi = to_spi_device(dev);
        const struct spi_driver *sdrv = to_spi_driver(drv);
 
+       /* Check override first, and if set, only use the named driver */
+       if (spi->driver_override)
+               return strcmp(spi->driver_override, drv->name) == 0;
+
        /* Attempt an OF style match */
        if (of_driver_match_device(dev, drv))
                return 1;
@@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
                enable = !enable;
 
        if (gpio_is_valid(spi->cs_gpio)) {
-               gpio_set_value(spi->cs_gpio, !enable);
+               /* Honour the SPI_NO_CS flag */
+               if (!(spi->mode & SPI_NO_CS))
+                       gpio_set_value(spi->cs_gpio, !enable);
                /* Some SPI masters need both GPIO CS & slave_select */
                if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
                    spi->controller->set_cs)
@@ -2143,8 +2187,17 @@ int spi_register_controller(struct spi_controller *ctlr)
         */
        if (ctlr->num_chipselect == 0)
                return -EINVAL;
-       /* allocate dynamic bus number using Linux idr */
-       if ((ctlr->bus_num < 0) && ctlr->dev.of_node) {
+       if (ctlr->bus_num >= 0) {
+               /* devices with a fixed bus num must check-in with the num */
+               mutex_lock(&board_lock);
+               id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
+                       ctlr->bus_num + 1, GFP_KERNEL);
+               mutex_unlock(&board_lock);
+               if (WARN(id < 0, "couldn't get idr"))
+                       return id == -ENOSPC ? -EBUSY : id;
+               ctlr->bus_num = id;
+       } else if (ctlr->dev.of_node) {
+               /* allocate dynamic bus number using Linux idr */
                id = of_alias_get_id(ctlr->dev.of_node, "spi");
                if (id >= 0) {
                        ctlr->bus_num = id;
@@ -2832,11 +2885,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                return -EINVAL;
 
        /* If an SPI controller does not support toggling the CS line on each
-        * transfer (indicated by the SPI_CS_WORD flag), we can emulate it by
+        * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
+        * for the CS line, we can emulate the CS-per-word hardware function by
         * splitting transfers into one-word transfers and ensuring that
         * cs_change is set for each transfer.
         */
-       if ((spi->mode & SPI_CS_WORD) && !(ctlr->mode_bits & SPI_CS_WORD)) {
+       if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
+                                         gpio_is_valid(spi->cs_gpio))) {
                size_t maxsize;
                int ret;
 
@@ -3343,20 +3398,23 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
 
 /*-------------------------------------------------------------------------*/
 
-#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+#if IS_ENABLED(CONFIG_OF)
 static int __spi_of_device_match(struct device *dev, void *data)
 {
        return dev->of_node == data;
 }
 
 /* must call put_device() when done with returned spi_device device */
-static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
+struct spi_device *of_find_spi_device_by_node(struct device_node *node)
 {
        struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
                                                __spi_of_device_match);
        return dev ? to_spi_device(dev) : NULL;
 }
+EXPORT_SYMBOL_GPL(of_find_spi_device_by_node);
+#endif /* IS_ENABLED(CONFIG_OF) */
 
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
 static int __spi_of_controller_match(struct device *dev, const void *data)
 {
        return dev->of_node == data;