aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch445
1 files changed, 445 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch
new file mode 100644
index 0000000..780459c
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0084-spi-core-Add-support-for-registering-SPI-slave-contr.patch
@@ -0,0 +1,445 @@
+From 069206bafab71d97d2c427ed664e7cbacbe0678c Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Fri, 17 Jun 2016 16:45:37 +0200
+Subject: [PATCH 2/7] spi: core: Add support for registering SPI slave
+ controllers
+
+Add support for registering SPI slave controllers using the existing SPI
+master framework:
+ - SPI slave controllers must use spi_alloc_slave() instead of
+ spi_alloc_master(), and should provide an additional callback
+ "slave_abort" to abort an ongoing SPI transfer request,
+ - SPI slave controllers are added to a new "spi_slave" device class,
+ - SPI slave handlers can be bound to the SPI slave device represented
+ by an SPI slave controller using a DT child node named "slave",
+ - Alternatively, (un)binding an SPI slave handler to the SPI slave
+ device represented by an SPI slave controller can be done by
+ (un)registering the slave device through a sysfs virtual file named
+ "slave".
+
+From the point of view of an SPI slave protocol handler, an SPI slave
+controller looks almost like an ordinary SPI master controller. The only
+exception is that a transfer request will block on the remote SPI
+master, and may be cancelled using spi_slave_abort().
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+---
+ drivers/spi/Kconfig | 14 +++-
+ drivers/spi/Makefile | 2 +
+ drivers/spi/spi.c | 179 ++++++++++++++++++++++++++++++++++++++++-------
+ include/linux/spi/spi.h | 35 +++++++--
+ 4 files changed, 201 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index fb418d5..8c97790 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -781,6 +781,18 @@ config SPI_TLE62X0
+
+ endif # SPI_MASTER
+
+-# (slave support would go here)
++#
++# SLAVE side ... listening to other SPI masters
++#
++
++config SPI_SLAVE
++ bool "SPI slave protocol handlers"
++ help
++ If your system has a slave-capable SPI controller, you can enable
++ slave protocol handlers.
++
++if SPI_SLAVE
++
++endif # SPI_SLAVE
+
+ endif # SPI
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index aa939d9..2428b0f 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -102,3 +102,5 @@ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
+ obj-$(CONFIG_SPI_XLP) += spi-xlp.o
+ obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
+ obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
++
++# SPI slave protocol handlers
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 838783c..a403e3a 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1513,15 +1513,6 @@ static int spi_master_initialize_queue(struct spi_master *master)
+ goto err_out;
+ }
+
+- /* Device address */
+- rc = of_property_read_u32(nc, "reg", &value);
+- if (rc) {
+- dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
+- nc->full_name, rc);
+- goto err_out;
+- }
+- spi->chip_select = value;
+-
+ /* Mode (clock phase/polarity/etc.) */
+ if (of_find_property(nc, "spi-cpha", NULL))
+ spi->mode |= SPI_CPHA;
+@@ -1571,6 +1562,24 @@ static int spi_master_initialize_queue(struct spi_master *master)
+ }
+ }
+
++ if (spi_controller_is_slave(master)) {
++ if (strcmp(nc->name, "slave")) {
++ dev_err(&master->dev, "%s is not called 'slave'\n",
++ nc->full_name);
++ return -EINVAL;
++ }
++ return 0;
++ }
++
++ /* Device address */
++ rc = of_property_read_u32(nc, "reg", &value);
++ if (rc) {
++ dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
++ nc->full_name, rc);
++ return rc;
++ }
++ spi->chip_select = value;
++
+ /* Device speed */
+ rc = of_property_read_u32(nc, "spi-max-frequency", &value);
+ if (rc) {
+@@ -1603,8 +1612,8 @@ static int spi_master_initialize_queue(struct spi_master *master)
+ * of_register_spi_devices() - Register child devices onto the SPI bus
+ * @master: Pointer to spi_master device
+ *
+- * Registers an spi_device for each child node of master node which has a 'reg'
+- * property.
++ * Registers an spi_device for each child node of controller node which
++ * represents a valid SPI slave.
+ */
+ static void of_register_spi_devices(struct spi_master *master)
+ {
+@@ -1771,28 +1780,129 @@ static void spi_master_release(struct device *dev)
+ .dev_groups = spi_master_groups,
+ };
+
++#ifdef CONFIG_SPI_SLAVE
++/**
++ * spi_slave_abort - abort the ongoing transfer request on an SPI slave
++ * controller
++ * @spi: device used for the current transfer
++ */
++int spi_slave_abort(struct spi_device *spi)
++{
++ struct spi_master *master = spi->master;
++
++ if (spi_controller_is_slave(master) && master->slave_abort)
++ return master->slave_abort(master);
++
++ return -ENOTSUPP;
++}
++EXPORT_SYMBOL_GPL(spi_slave_abort);
++
++static int match_true(struct device *dev, void *data)
++{
++ return 1;
++}
++
++static ssize_t spi_slave_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct spi_master *ctlr = container_of(dev, struct spi_master, dev);
++ struct device *child;
++
++ child = device_find_child(&ctlr->dev, NULL, match_true);
++ return sprintf(buf, "%s\n",
++ child ? to_spi_device(child)->modalias : NULL);
++}
++
++static ssize_t spi_slave_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ struct spi_master *ctlr = container_of(dev, struct spi_master, dev);
++ struct spi_device *spi;
++ struct device *child;
++ char name[32];
++ int rc;
++
++ rc = sscanf(buf, "%31s", name);
++ if (rc != 1 || !name[0])
++ return -EINVAL;
++
++ child = device_find_child(&ctlr->dev, NULL, match_true);
++ if (child) {
++ /* Remove registered slave */
++ device_unregister(child);
++ put_device(child);
++ }
++
++ if (strcmp(name, "(null)")) {
++ /* Register new slave */
++ spi = spi_alloc_device(ctlr);
++ if (!spi)
++ return -ENOMEM;
++
++ strlcpy(spi->modalias, name, sizeof(spi->modalias));
++
++ rc = spi_add_device(spi);
++ if (rc) {
++ spi_dev_put(spi);
++ return rc;
++ }
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(slave, 0644, spi_slave_show, spi_slave_store);
++
++static struct attribute *spi_slave_attrs[] = {
++ &dev_attr_slave.attr,
++ NULL,
++};
++
++static const struct attribute_group spi_slave_group = {
++ .attrs = spi_slave_attrs,
++};
++
++static const struct attribute_group *spi_slave_groups[] = {
++ &spi_master_statistics_group,
++ &spi_slave_group,
++ NULL,
++};
++
++static struct class spi_slave_class = {
++ .name = "spi_slave",
++ .owner = THIS_MODULE,
++ .dev_release = spi_master_release,
++ .dev_groups = spi_slave_groups,
++};
++#else
++extern struct class spi_slave_class; /* dummy */
++#endif
+
+ /**
+- * spi_alloc_master - allocate SPI master controller
++ * __spi_alloc_controller - allocate an SPI master or slave controller
+ * @dev: the controller, possibly using the platform_bus
+ * @size: how much zeroed driver-private data to allocate; the pointer to this
+ * memory is in the driver_data field of the returned device,
+ * accessible with spi_master_get_devdata().
++ * @slave: flag indicating whether to allocate an SPI master (false) or SPI
++ * slave (true) controller
+ * Context: can sleep
+ *
+- * This call is used only by SPI master controller drivers, which are the
++ * This call is used only by SPI controller drivers, which are the
+ * only ones directly touching chip registers. It's how they allocate
+ * an spi_master structure, prior to calling spi_register_master().
+ *
+ * This must be called from context that can sleep.
+ *
+- * The caller is responsible for assigning the bus number and initializing
+- * the master's methods before calling spi_register_master(); and (after errors
++ * The caller is responsible for assigning the bus number and initializing the
++ * controller's methods before calling spi_register_master(); and (after errors
+ * adding the device) calling spi_master_put() to prevent a memory leak.
+ *
+- * Return: the SPI master structure on success, else NULL.
++ * Return: the SPI controller structure on success, else NULL.
+ */
+-struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
++struct spi_master *__spi_alloc_controller(struct device *dev,
++ unsigned int size, bool slave)
+ {
+ struct spi_master *master;
+
+@@ -1806,14 +1916,18 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
+ device_initialize(&master->dev);
+ master->bus_num = -1;
+ master->num_chipselect = 1;
+- master->dev.class = &spi_master_class;
++ master->slave = slave;
++ if (IS_ENABLED(CONFIG_SPI_SLAVE) && slave)
++ master->dev.class = &spi_slave_class;
++ else
++ master->dev.class = &spi_master_class;
+ master->dev.parent = dev;
+ pm_suspend_ignore_children(&master->dev, true);
+ spi_master_set_devdata(master, &master[1]);
+
+ return master;
+ }
+-EXPORT_SYMBOL_GPL(spi_alloc_master);
++EXPORT_SYMBOL_GPL(__spi_alloc_controller);
+
+ #ifdef CONFIG_OF
+ static int of_spi_register_master(struct spi_master *master)
+@@ -1889,9 +2003,11 @@ int spi_register_master(struct spi_master *master)
+ if (!dev)
+ return -ENODEV;
+
+- status = of_spi_register_master(master);
+- if (status)
+- return status;
++ if (!spi_controller_is_slave(master)) {
++ status = of_spi_register_master(master);
++ if (status)
++ return status;
++ }
+
+ /* even if it's just one always-selected device, there must
+ * be at least one chipselect
+@@ -1928,8 +2044,9 @@ int spi_register_master(struct spi_master *master)
+ status = device_add(&master->dev);
+ if (status < 0)
+ goto done;
+- dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
+- dynamic ? " (dynamic)" : "");
++ dev_dbg(dev, "registered %s %s%s\n",
++ spi_controller_is_slave(master) ? "slave" : "master",
++ dev_name(&master->dev), dynamic ? " (dynamic)" : "");
+
+ /* If we're using a queued driver, start the queue */
+ if (master->transfer)
+@@ -3102,6 +3219,9 @@ static struct spi_master *of_find_spi_master_by_node(struct device_node *node)
+
+ dev = class_find_device(&spi_master_class, NULL, node,
+ __spi_of_master_match);
++ if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE))
++ dev = class_find_device(&spi_slave_class, NULL, node,
++ __spi_of_master_match);
+ if (!dev)
+ return NULL;
+
+@@ -3183,6 +3303,9 @@ static struct spi_master *acpi_spi_find_master_by_adev(struct acpi_device *adev)
+
+ dev = class_find_device(&spi_master_class, NULL, adev,
+ spi_acpi_master_match);
++ if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE))
++ dev = class_find_device(&spi_slave_class, NULL, adev,
++ spi_acpi_master_match);
+ if (!dev)
+ return NULL;
+
+@@ -3255,6 +3378,12 @@ static int __init spi_init(void)
+ if (status < 0)
+ goto err2;
+
++ if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
++ status = class_register(&spi_slave_class);
++ if (status < 0)
++ goto err3;
++ }
++
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
+ if (IS_ENABLED(CONFIG_ACPI))
+@@ -3262,6 +3391,8 @@ static int __init spi_init(void)
+
+ return 0;
+
++err3:
++ class_unregister(&spi_master_class);
+ err2:
+ bus_unregister(&spi_bus_type);
+ err1:
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 4b743ac..f9bbd33 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -28,8 +28,8 @@
+ struct spi_flash_read_message;
+
+ /*
+- * INTERFACES between SPI master-side drivers and SPI infrastructure.
+- * (There's no SPI slave support for Linux yet...)
++ * INTERFACES between SPI master-side drivers and SPI slave protocol handlers,
++ * and SPI infrastructure.
+ */
+ extern struct bus_type spi_bus_type;
+
+@@ -310,6 +310,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+ * @min_speed_hz: Lowest supported transfer speed
+ * @max_speed_hz: Highest supported transfer speed
+ * @flags: other constraints relevant to this driver
++ * @slave: indicates that this is an SPI slave controller
+ * @max_transfer_size: function that returns the max transfer size for
+ * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
+ * @max_message_size: function that returns the max message size for
+@@ -373,6 +374,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+ * @handle_err: the subsystem calls the driver to handle an error that occurs
+ * in the generic implementation of transfer_one_message().
+ * @unprepare_message: undo any work done by prepare_message().
++ * @slave_abort: abort the ongoing transfer request on an SPI slave controller
+ * @spi_flash_read: to support spi-controller hardwares that provide
+ * accelerated interface to read from flash devices.
+ * @flash_read_supported: spi device supports flash read
+@@ -443,6 +445,9 @@ struct spi_master {
+ #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */
+ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
+
++ /* flag indicating this is an SPI slave controller */
++ bool slave;
++
+ /*
+ * on some hardware transfer / message size may be constrained
+ * the limit may depend on device transfer settings
+@@ -535,6 +540,7 @@ struct spi_master {
+ struct spi_message *message);
+ int (*unprepare_message)(struct spi_master *master,
+ struct spi_message *message);
++ int (*slave_abort)(struct spi_master *spi);
+ int (*spi_flash_read)(struct spi_device *spi,
+ struct spi_flash_read_message *msg);
+ bool (*flash_read_supported)(struct spi_device *spi);
+@@ -589,6 +595,11 @@ static inline void spi_master_put(struct spi_master *master)
+ put_device(&master->dev);
+ }
+
++static inline bool spi_controller_is_slave(struct spi_master *ctlr)
++{
++ return IS_ENABLED(CONFIG_SPI_SLAVE) && ctlr->slave;
++}
++
+ /* PM calls that need to be issued by the driver */
+ extern int spi_master_suspend(struct spi_master *master);
+ extern int spi_master_resume(struct spi_master *master);
+@@ -599,8 +610,23 @@ static inline void spi_master_put(struct spi_master *master)
+ extern void spi_finalize_current_transfer(struct spi_master *master);
+
+ /* the spi driver core manages memory for the spi_master classdev */
+-extern struct spi_master *
+-spi_alloc_master(struct device *host, unsigned size);
++extern struct spi_master *__spi_alloc_controller(struct device *host,
++ unsigned int size, bool slave);
++
++static inline struct spi_master *spi_alloc_master(struct device *host,
++ unsigned int size)
++{
++ return __spi_alloc_controller(host, size, false);
++}
++
++static inline struct spi_master *spi_alloc_slave(struct device *host,
++ unsigned int size)
++{
++ if (!IS_ENABLED(CONFIG_SPI_SLAVE))
++ return NULL;
++
++ return __spi_alloc_controller(host, size, true);
++}
+
+ extern int spi_register_master(struct spi_master *master);
+ extern int devm_spi_register_master(struct device *dev,
+@@ -906,6 +932,7 @@ static inline void spi_message_free(struct spi_message *m)
+ extern int spi_async(struct spi_device *spi, struct spi_message *message);
+ extern int spi_async_locked(struct spi_device *spi,
+ struct spi_message *message);
++extern int spi_slave_abort(struct spi_device *spi);
+
+ static inline size_t
+ spi_max_message_size(struct spi_device *spi)
+--
+1.7.10.4