diff mbox series

[v2,1/3] spi: Add driver_override SPI device attribute

Message ID 20180920191759.17781-2-tpiepho@impinj.com (mailing list archive)
State Accepted
Commit 5039563e7c25eccd7fec1de6706011009d1c5665
Headers show
Series device tree spidev solution - driver_override for SPI | expand

Commit Message

Trent Piepho Sept. 20, 2018, 7:18 p.m. UTC
This attribute works the same was as the identically named attribute
for PCI, AMBA, and platform devices.  For reference, see:

commit 3cf385713460 ("ARM: 8256/1: driver coamba: add device binding
path 'driver_override'")
commit 3d713e0e382e ("driver core: platform: add device binding path
'driver_override'")
commit 782a985d7af2 ("PCI: Introduce new device binding path using
pci_dev.driver_override")

If the name of a driver is written to this attribute, then the device
will bind to the named driver and only the named driver.

The device will bind to the driver even if the driver does not list the
device in its id table.  This behavior is different than the driver's
bind attribute, which only allows binding to devices that are listed as
supported by the driver.

It can be used to bind a generic driver, like spidev, to a device.

Signed-off-by: Trent Piepho <tpiepho@impinj.com>
---
 drivers/spi/spi.c       | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/spi/spi.h |  1 +
 2 files changed, 52 insertions(+)

Comments

Jan Kundrát Sept. 20, 2018, 9:38 p.m. UTC | #1
On čtvrtek 20. září 2018 21:18:32 CEST, Trent Piepho wrote:
> This attribute works the same was as the identically named attribute
> for PCI, AMBA, and platform devices.  For reference, see:
>
> commit 3cf385713460 ("ARM: 8256/1: driver coamba: add device binding
> path 'driver_override'")
> commit 3d713e0e382e ("driver core: platform: add device binding path
> 'driver_override'")
> commit 782a985d7af2 ("PCI: Introduce new device binding path using
> pci_dev.driver_override")
>
> If the name of a driver is written to this attribute, then the device
> will bind to the named driver and only the named driver.
>
> The device will bind to the driver even if the driver does not list the
> device in its id table.  This behavior is different than the driver's
> bind attribute, which only allows binding to devices that are listed as
> supported by the driver.
>
> It can be used to bind a generic driver, like spidev, to a device.
>
> Signed-off-by: Trent Piepho <tpiepho@impinj.com>

Reviewed-by: Jan Kundrát <jan.kundrat@cesnet.cz>
Tested-by: Jan Kundrát <jan.kundrat@cesnet.cz>

This very neatly fixes the problem I was having at 
https://patchwork.kernel.org/patch/10558889/ . Thanks!

Cheers,
Jan
Geert Uytterhoeven Sept. 24, 2018, 7:59 a.m. UTC | #2
On Thu, Sep 20, 2018 at 9:18 PM Trent Piepho <tpiepho@impinj.com> wrote:
> This attribute works the same was as the identically named attribute
> for PCI, AMBA, and platform devices.  For reference, see:
>
> commit 3cf385713460 ("ARM: 8256/1: driver coamba: add device binding
> path 'driver_override'")
> commit 3d713e0e382e ("driver core: platform: add device binding path
> 'driver_override'")
> commit 782a985d7af2 ("PCI: Introduce new device binding path using
> pci_dev.driver_override")
>
> If the name of a driver is written to this attribute, then the device
> will bind to the named driver and only the named driver.
>
> The device will bind to the driver even if the driver does not list the
> device in its id table.  This behavior is different than the driver's
> bind attribute, which only allows binding to devices that are listed as
> supported by the driver.
>
> It can be used to bind a generic driver, like spidev, to a device.
>
> Signed-off-by: Trent Piepho <tpiepho@impinj.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert
diff mbox series

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 03833924ca6c..823fc130248b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -60,6 +60,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 +78,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 +204,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 +352,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;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 7bb36145e2ba..d90e55029704 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -168,6 +168,7 @@  struct spi_device {
 	void			*controller_state;
 	void			*controller_data;
 	char			modalias[SPI_NAME_SIZE];
+	const char		*driver_override;
 	int			cs_gpio;	/* chip select gpio */
 
 	/* the statistics */