diff options
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-bus.txt | 76 | ||||
-rw-r--r-- | Documentation/spi/spi-summary | 27 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 26 | ||||
-rw-r--r-- | drivers/spi/Makefile | 4 | ||||
-rw-r--r-- | drivers/spi/spi-slave-system-control.c | 154 | ||||
-rw-r--r-- | drivers/spi/spi-slave-time.c | 129 | ||||
-rw-r--r-- | drivers/spi/spi.c | 1216 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 217 | ||||
-rw-r--r-- | include/trace/events/spi.h | 26 |
9 files changed, 1201 insertions, 674 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt index 4b1d6e74c744..1f6e86f787ef 100644 --- a/Documentation/devicetree/bindings/spi/spi-bus.txt +++ b/Documentation/devicetree/bindings/spi/spi-bus.txt @@ -1,17 +1,23 @@ SPI (Serial Peripheral Interface) busses -SPI busses can be described with a node for the SPI master device -and a set of child nodes for each SPI slave on the bus. For this -discussion, it is assumed that the system's SPI controller is in -SPI master mode. This binding does not describe SPI controllers -in slave mode. +SPI busses can be described with a node for the SPI controller device +and a set of child nodes for each SPI slave on the bus. The system's SPI +controller may be described for use in SPI master mode or in SPI slave mode, +but not for both at the same time. -The SPI master node requires the following properties: +The SPI controller node requires the following properties: +- compatible - Name of SPI bus controller following generic names + recommended practice. + +In master mode, the SPI controller node requires the following additional +properties: - #address-cells - number of cells required to define a chip select address on the SPI bus. - #size-cells - should be zero. -- compatible - name of SPI bus controller following generic names - recommended practice. + +In slave mode, the SPI controller node requires one additional property: +- spi-slave - Empty property. + No other properties are required in the SPI bus node. It is assumed that a driver for an SPI bus device will understand that it is an SPI bus. However, the binding does not attempt to define the specific method for @@ -21,7 +27,7 @@ assumption that board specific platform code will be used to manage chip selects. Individual drivers can define additional properties to support describing the chip select layout. -Optional properties: +Optional properties (master mode only): - cs-gpios - gpios chip select. - num-cs - total number of chipselects. @@ -41,28 +47,36 @@ cs1 : native cs2 : &gpio1 1 0 cs3 : &gpio1 2 0 -SPI slave nodes must be children of the SPI master node and can -contain the following properties. -- reg - (required) chip select address of device. -- compatible - (required) name of SPI device following generic names - recommended practice. -- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz. -- spi-cpol - (optional) Empty property indicating device requires - inverse clock polarity (CPOL) mode. -- spi-cpha - (optional) Empty property indicating device requires - shifted clock phase (CPHA) mode. -- spi-cs-high - (optional) Empty property indicating device requires - chip select active high. -- spi-3wire - (optional) Empty property indicating device requires - 3-wire mode. -- spi-lsb-first - (optional) Empty property indicating device requires - LSB first mode. -- spi-tx-bus-width - (optional) The bus width (number of data wires) that is - used for MOSI. Defaults to 1 if not present. -- spi-rx-bus-width - (optional) The bus width (number of data wires) that is - used for MISO. Defaults to 1 if not present. -- spi-rx-delay-us - (optional) Microsecond delay after a read transfer. -- spi-tx-delay-us - (optional) Microsecond delay after a write transfer. + +SPI slave nodes must be children of the SPI controller node. + +In master mode, one or more slave nodes (up to the number of chip selects) can +be present. Required properties are: +- compatible - Name of SPI device following generic names recommended + practice. +- reg - Chip select address of device. +- spi-max-frequency - Maximum SPI clocking speed of device in Hz. + +In slave mode, the (single) slave node is optional. +If present, it must be called "slave". Required properties are: +- compatible - Name of SPI device following generic names recommended + practice. + +All slave nodes can contain the following optional properties: +- spi-cpol - Empty property indicating device requires inverse clock + polarity (CPOL) mode. +- spi-cpha - Empty property indicating device requires shifted clock + phase (CPHA) mode. +- spi-cs-high - Empty property indicating device requires chip select + active high. +- spi-3wire - Empty property indicating device requires 3-wire mode. +- spi-lsb-first - Empty property indicating device requires LSB first mode. +- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI. + Defaults to 1 if not present. +- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO. + Defaults to 1 if not present. +- spi-rx-delay-us - Microsecond delay after a read transfer. +- spi-tx-delay-us - Microsecond delay after a write transfer. Some SPI controllers and devices support Dual and Quad SPI transfer mode. It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4 diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index d1824b399b2d..1721c1b570c3 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -62,8 +62,8 @@ chips described as using "three wire" signaling: SCK, data, nCSx. (That data line is sometimes called MOMI or SISO.) Microcontrollers often support both master and slave sides of the SPI -protocol. This document (and Linux) currently only supports the master -side of SPI interactions. +protocol. This document (and Linux) supports both the master and slave +sides of SPI interactions. Who uses it? On what kinds of systems? @@ -154,9 +154,8 @@ control audio interfaces, present touchscreen sensors as input interfaces, or monitor temperature and voltage levels during industrial processing. And those might all be sharing the same controller driver. -A "struct spi_device" encapsulates the master-side interface between -those two types of driver. At this writing, Linux has no slave side -programming interface. +A "struct spi_device" encapsulates the controller-side interface between +those two types of drivers. There is a minimal core of SPI programming interfaces, focussing on using the driver model to connect controller and protocol drivers using @@ -177,10 +176,24 @@ shows up in sysfs in several locations: /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices /sys/class/spi_master/spiB ... symlink (or actual device node) to - a logical node which could hold class related state for the - controller managing bus "B". All spiB.* devices share one + a logical node which could hold class related state for the SPI + master controller managing bus "B". All spiB.* devices share one physical SPI bus segment, with SCLK, MOSI, and MISO. + /sys/devices/.../CTLR/slave ... virtual file for (un)registering the + slave device for an SPI slave controller. + Writing the driver name of an SPI slave handler to this file + registers the slave device; writing "(null)" unregisters the slave + device. + Reading from this file shows the name of the slave device ("(null)" + if not registered). + + /sys/class/spi_slave/spiB ... symlink (or actual device node) to + a logical node which could hold class related state for the SPI + slave controller on bus "B". When registered, a single spiB.* + device is present here, possible sharing the physical SPI bus + segment with other SPI slave devices. + Note that the actual location of the controller's class state depends on whether you enabled CONFIG_SYSFS_DEPRECATED or not. At this time, the only class-specific state is the bus number ("B" in "spiB"), so diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 097883362036..82cd818aa062 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -785,6 +785,30 @@ 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 + +config SPI_SLAVE_TIME + tristate "SPI slave handler reporting boot up time" + help + SPI slave handler responding with the time of reception of the last + SPI message. + +config SPI_SLAVE_SYSTEM_CONTROL + tristate "SPI slave handler controlling system state" + help + SPI slave handler to allow remote control of system reboot, power + off, halt, and suspend. + +endif # SPI_SLAVE endif # SPI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b375a7a89216..1d7923e8c63b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -105,3 +105,7 @@ 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 +obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o +obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) += spi-slave-system-control.o diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c new file mode 100644 index 000000000000..c0257e937995 --- /dev/null +++ b/drivers/spi/spi-slave-system-control.c @@ -0,0 +1,154 @@ +/* + * SPI slave handler controlling system state + * + * This SPI slave handler allows remote control of system reboot, power off, + * halt, and suspend. + * + * Copyright (C) 2016-2017 Glider bvba + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote + * system): + * + * # reboot='\x7c\x50' + * # poweroff='\x71\x3f' + * # halt='\x38\x76' + * # suspend='\x1b\x1b' + * # spidev_test -D /dev/spidev2.0 -p $suspend # or $reboot, $poweroff, $halt + */ + +#include <linux/completion.h> +#include <linux/module.h> +#include <linux/reboot.h> +#include <linux/suspend.h> +#include <linux/spi/spi.h> + +/* + * The numbers are chosen to display something human-readable on two 7-segment + * displays connected to two 74HC595 shift registers + */ +#define CMD_REBOOT 0x7c50 /* rb */ +#define CMD_POWEROFF 0x713f /* OF */ +#define CMD_HALT 0x3876 /* HL */ +#define CMD_SUSPEND 0x1b1b /* ZZ */ + +struct spi_slave_system_control_priv { + struct spi_device *spi; + struct completion finished; + struct spi_transfer xfer; + struct spi_message msg; + __be16 cmd; +}; + +static +int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv); + +static void spi_slave_system_control_complete(void *arg) +{ + struct spi_slave_system_control_priv *priv = arg; + u16 cmd; + int ret; + + if (priv->msg.status) + goto terminate; + + cmd = be16_to_cpu(priv->cmd); + switch (cmd) { + case CMD_REBOOT: + dev_info(&priv->spi->dev, "Rebooting system...\n"); + kernel_restart(NULL); + + case CMD_POWEROFF: + dev_info(&priv->spi->dev, "Powering off system...\n"); + kernel_power_off(); + break; + + case CMD_HALT: + dev_info(&priv->spi->dev, "Halting system...\n"); + kernel_halt(); + break; + + case CMD_SUSPEND: + dev_info(&priv->spi->dev, "Suspending system...\n"); + pm_suspend(PM_SUSPEND_MEM); + break; + + default: + dev_warn(&priv->spi->dev, "Unknown command 0x%x\n", cmd); + break; + } + + ret = spi_slave_system_control_submit(priv); + if (ret) + goto terminate; + + return; + +terminate: + dev_info(&priv->spi->dev, "Terminating\n"); + complete(&priv->finished); +} + +static +int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv) +{ + int ret; + + spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1); + + priv->msg.complete = spi_slave_system_control_complete; + priv->msg.context = priv; + + ret = spi_async(priv->spi, &priv->msg); + if (ret) + dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret); + + return ret; +} + +static int spi_slave_system_control_probe(struct spi_device *spi) +{ + struct spi_slave_system_control_priv *priv; + int ret; + + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->spi = spi; + init_completion(&priv->finished); + priv->xfer.rx_buf = &priv->cmd; + priv->xfer.len = sizeof(priv->cmd); + + ret = spi_slave_system_control_submit(priv); + if (ret) + return ret; + + spi_set_drvdata(spi, priv); + return 0; +} + +static int spi_slave_system_control_remove(struct spi_device *spi) +{ + struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi); + + spi_slave_abort(spi); + wait_for_completion(&priv->finished); + return 0; +} + +static struct spi_driver spi_slave_system_control_driver = { + .driver = { + .name = "spi-slave-system-control", + }, + .probe = spi_slave_system_control_probe, + .remove = spi_slave_system_control_remove, +}; +module_spi_driver(spi_slave_system_control_driver); + +MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); +MODULE_DESCRIPTION("SPI slave handler controlling system state"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-slave-time.c b/drivers/spi/spi-slave-time.c new file mode 100644 index 000000000000..f2e07a392d68 --- /dev/null +++ b/drivers/spi/spi-slave-time.c @@ -0,0 +1,129 @@ +/* + * SPI slave handler reporting uptime at reception of previous SPI message + * + * This SPI slave handler sends the time of reception of the last SPI message + * as two 32-bit unsigned integers in binary format and in network byte order, + * representing the number of seconds and fractional seconds (in microseconds) + * since boot up. + * + * Copyright (C) 2016-2017 Glider bvba + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote + * system): + * + * # spidev_test -D /dev/spidev2.0 -p dummy-8B + * spi mode: 0x0 + * bits per word: 8 + * max speed: 500000 Hz (500 KHz) + * RX | 00 00 04 6D 00 09 5B BB ... + * ^^^^^ ^^^^^^^^ + * seconds microseconds + */ + +#include <linux/completion.h> +#include <linux/module.h> +#include <linux/sched/clock.h> +#include <linux/spi/spi.h> + + +struct spi_slave_time_priv { + struct spi_device *spi; + struct completion finished; + struct spi_transfer xfer; + struct spi_message msg; + __be32 buf[2]; +}; + +static int spi_slave_time_submit(struct spi_slave_time_priv *priv); + +static void spi_slave_time_complete(void *arg) +{ + struct spi_slave_time_priv *priv = arg; + int ret; + + ret = priv->msg.status; + if (ret) + goto terminate; + + ret = spi_slave_time_submit(priv); + if (ret) + goto terminate; + + return; + +terminate: + dev_info(&priv->spi->dev, "Terminating\n"); + complete(&priv->finished); +} + +static int spi_slave_time_submit(struct spi_slave_time_priv *priv) +{ + u32 rem_us; + int ret; + u64 ts; + + ts = local_clock(); + rem_us = do_div(ts, 1000000000) / 1000; + + priv->buf[0] = cpu_to_be32(ts); + priv->buf[1] = cpu_to_be32(rem_us); + + spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1); + + priv->msg.complete = spi_slave_time_complete; + priv->msg.context = priv; + + ret = spi_async(priv->spi, &priv->msg); + if (ret) + dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret); + + return ret; +} + +static int spi_slave_time_probe(struct spi_device *spi) +{ + struct spi_slave_time_priv *priv; + int ret; + + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->spi = spi; + init_completion(&priv->finished); + priv->xfer.tx_buf = priv->buf; + priv->xfer.len = sizeof(priv->buf); + + ret = spi_slave_time_submit(priv); + if (ret) + return ret; + + spi_set_drvdata(spi, priv); + return 0; +} + +static int spi_slave_time_remove(struct spi_device *spi) +{ + struct spi_slave_time_priv *priv = spi_get_drvdata(spi); + + spi_slave_abort(spi); + wait_for_completion(&priv->finished); + return 0; +} + +static struct spi_driver spi_slave_time_driver = { + .driver = { + .name = "spi-slave-time", + }, + .probe = spi_slave_time_probe, + .remove = spi_slave_time_remove, +}; +module_spi_driver(spi_slave_time_driver); + +MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); +MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6f87fec409b5..4fcbb0aa71d3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -48,11 +48,11 @@ static void spidev_release(struct device *dev) { struct spi_device *spi = to_spi_device(dev); - /* spi masters may cleanup for released devices */ - if (spi->master->cleanup) - spi->master->cleanup(spi); + /* spi controllers may cleanup for released devices */ + if (spi->controller->cleanup) + spi->controller->cleanup(spi); - spi_master_put(spi->master); + spi_controller_put(spi->controller); kfree(spi); } @@ -71,17 +71,17 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) static DEVICE_ATTR_RO(modalias); #define SPI_STATISTICS_ATTRS(field, file) \ -static ssize_t spi_master_##field##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ +static ssize_t spi_controller_##field##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - struct spi_master *master = container_of(dev, \ - struct spi_master, dev); \ - return spi_statistics_##field##_show(&master->statistics, buf); \ + struct spi_controller *ctlr = container_of(dev, \ + struct spi_controller, dev); \ + return spi_statistics_##field##_show(&ctlr->statistics, buf); \ } \ -static struct device_attribute dev_attr_spi_master_##field = { \ +static struct device_attribute dev_attr_spi_controller_##field = { \ .attr = { .name = file, .mode = 0444 }, \ - .show = spi_master_##field##_show, \ + .show = spi_controller_##field##_show, \ }; \ static ssize_t spi_device_##field##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -201,51 +201,51 @@ static const struct attribute_group *spi_dev_groups[] = { NULL, }; -static struct attribute *spi_master_statistics_attrs[] = { - &dev_attr_spi_master_messages.attr, - &dev_attr_spi_master_transfers.attr, - &dev_attr_spi_master_errors.attr, - &dev_attr_spi_master_timedout.attr, - &dev_attr_spi_master_spi_sync.attr, - &dev_attr_spi_master_spi_sync_immediate.attr, - &dev_attr_spi_master_spi_async.attr, - &dev_attr_spi_master_bytes.attr, - &dev_attr_spi_master_bytes_rx.attr, - &dev_attr_spi_master_bytes_tx.attr, - &dev_attr_spi_master_transfer_bytes_histo0.attr, - &dev_attr_spi_master_transfer_bytes_histo1.attr, - &dev_attr_spi_master_transfer_bytes_histo2.attr, - &dev_attr_spi_master_transfer_bytes_histo3.attr, - &dev_attr_spi_master_transfer_bytes_histo4.attr, - &dev_attr_spi_master_transfer_bytes_histo5.attr, - &dev_attr_spi_master_transfer_bytes_histo6.attr, - &dev_attr_spi_master_transfer_bytes_histo7.attr, - &dev_attr_spi_master_transfer_bytes_histo8.attr, - &dev_attr_spi_master_transfer_bytes_histo9.attr, - &dev_attr_spi_master_transfer_bytes_histo10.attr, - &dev_attr_spi_master_transfer_bytes_histo11.attr, - &dev_attr_spi_master_transfer_bytes_histo12.attr, - &dev_attr_spi_master_transfer_bytes_histo13.attr, - &dev_attr_spi_master_transfer_bytes_histo14.attr, - &dev_attr_spi_master_transfer_bytes_histo15.attr, - &dev_attr_spi_master_transfer_bytes_histo16.attr, - &dev_attr_spi_master_transfers_split_maxsize.attr, +static struct attribute *spi_controller_statistics_attrs[] = { + &dev_attr_spi_controller_messages.attr, + &dev_attr_spi_controller_transfers.attr, + &dev_attr_spi_controller_errors.attr, + &dev_attr_spi_controller_timedout.attr, + &dev_attr_spi_controller_spi_sync.attr, + &dev_attr_spi_controller_spi_sync_immediate.attr, + &dev_attr_spi_controller_spi_async.attr, + &dev_attr_spi_controller_bytes.attr, + &dev_attr_spi_controller_bytes_rx.attr, + &dev_attr_spi_controller_bytes_tx.attr, + &dev_attr_spi_controller_transfer_bytes_histo0.attr, + &dev_attr_spi_controller_transfer_bytes_histo1.attr, + &dev_attr_spi_controller_transfer_bytes_histo2.attr, + &dev_attr_spi_controller_transfer_bytes_histo3.attr, + &dev_attr_spi_controller_transfer_bytes_histo4.attr, + &dev_attr_spi_controller_transfer_bytes_histo5.attr, + &dev_attr_spi_controller_transfer_bytes_histo6.attr, + &dev_attr_spi_controller_transfer_bytes_histo7.attr, + &dev_attr_spi_controller_transfer_bytes_histo8.attr, + &dev_attr_spi_controller_transfer_bytes_histo9.attr, + &dev_attr_spi_controller_transfer_bytes_histo10.attr, + &dev_attr_spi_controller_transfer_bytes_histo11.attr, + &dev_attr_spi_controller_transfer_bytes_histo12.attr, + &dev_attr_spi_controller_transfer_bytes_histo13.attr, + &dev_attr_spi_controller_transfer_bytes_histo14.attr, + &dev_attr_spi_controller_transfer_bytes_histo15.attr, + &dev_attr_spi_controller_transfer_bytes_histo16.attr, + &dev_attr_spi_controller_transfers_split_maxsize.attr, NULL, }; -static const struct attribute_group spi_master_statistics_group = { +static const struct attribute_group spi_controller_statistics_group = { .name = "statistics", - .attrs = spi_master_statistics_attrs, + .attrs = spi_controller_statistics_attrs, }; static const struct attribute_group *spi_master_groups[] = { - &spi_master_statistics_group, + &spi_controller_statistics_group, NULL, }; void spi_statistics_add_transfer_stats(struct spi_statistics *stats, struct spi_transfer *xfer, - struct spi_master *master) + struct spi_controller *ctlr) { unsigned long flags; int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; @@ -260,10 +260,10 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats, stats->bytes += xfer->len; if ((xfer->tx_buf) && - (xfer->tx_buf != master->dummy_tx)) + (xfer->tx_buf != ctlr->dummy_tx)) stats->bytes_tx += xfer->len; if ((xfer->rx_buf) && - (xfer->rx_buf != master->dummy_rx)) + (xfer->rx_buf != ctlr->dummy_rx)) stats->bytes_rx += xfer->len; spin_unlock_irqrestore(&stats->lock, flags); @@ -405,7 +405,7 @@ EXPORT_SYMBOL_GPL(__spi_register_driver); /*-------------------------------------------------------------------------*/ /* SPI devices should normally not be created by SPI device drivers; that - * would make them board-specific. Similarly with SPI master drivers. + * would make them board-specific. Similarly with SPI controller drivers. * Device registration normally goes into like arch/.../mach.../board-YYY.c * with other readonly (flashable) information about mainboard devices. */ @@ -416,17 +416,17 @@ struct boardinfo { }; static LIST_HEAD(board_list); -static LIST_HEAD(spi_master_list); +static LIST_HEAD(spi_controller_list); /* * Used to protect add/del opertion for board_info list and - * spi_master list, and their matching process + * spi_controller list, and their matching process */ static DEFINE_MUTEX(board_lock); /** * spi_alloc_device - Allocate a new SPI device - * @master: Controller to which device is connected + * @ctlr: Controller to which device is connected * Context: can sleep * * Allows a driver to allocate and initialize a spi_device without @@ -435,27 +435,27 @@ static DEFINE_MUTEX(board_lock); * spi_add_device() on it. * * Caller is responsible to call spi_add_device() on the returned - * spi_device structure to add it to the SPI master. If the caller + * spi_device structure to add it to the SPI controller. If the caller * needs to discard the spi_device without adding it, then it should * call spi_dev_put() on it. * * Return: a pointer to the new device, or NULL. */ -struct spi_device *spi_alloc_device(struct spi_master *master) +struct spi_device *spi_alloc_device(struct spi_controller *ctlr) { struct spi_device *spi; - if (!spi_master_get(master)) + if (!spi_controller_get(ctlr)) return NULL; spi = kzalloc(sizeof(*spi), GFP_KERNEL); if (!spi) { - spi_master_put(master); + spi_controller_put(ctlr); return NULL; } - spi->master = master; - spi->dev.parent = &master->dev; + spi->master = spi->controller = ctlr; + spi->dev.parent = &ctlr->dev; spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; spi->cs_gpio = -ENOENT; @@ -476,7 +476,7 @@ static void spi_dev_set_name(struct spi_device *spi) return; } - dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev), + dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev), spi->chip_select); } @@ -485,7 +485,7 @@ static int spi_dev_check(struct device *dev, void *data) struct spi_device *spi = to_spi_device(dev); struct spi_device *new_spi = data; - if (spi->master == new_spi->master && + if (spi->controller == new_spi->controller && spi->chip_select == new_spi->chip_select) return -EBUSY; return 0; @@ -503,15 +503,14 @@ static int spi_dev_check(struct device *dev, void *data) int spi_add_device(struct spi_device *spi) { static DEFINE_MUTEX(spi_add_lock); - struct spi_master *master = spi->master; - struct device *dev = master->dev.parent; + struct spi_controller *ctlr = spi->controller; + struct device *dev = ctlr->dev.parent; int status; /* Chipselects are numbered 0..max; validate. */ - if (spi->chip_select >= master->num_chipselect) { - dev_err(dev, "cs%d >= max %d\n", - spi->chip_select, - master->num_chipselect); + if (spi->chip_select >= ctlr->num_chipselect) { + dev_err(dev, "cs%d >= max %d\n", spi->chip_select, + ctlr->num_chipselect); return -EINVAL; } @@ -531,8 +530,8 @@ int spi_add_device(struct spi_device *spi) goto done; } - if (master->cs_gpios) - spi->cs_gpio = master->cs_gpios[spi->chip_select]; + if (ctlr->cs_gpios) + spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; /* Drivers may modify this initial i/o setup, but will * normally rely on the device being setup. Devices @@ -561,7 +560,7 @@ EXPORT_SYMBOL_GPL(spi_add_device); /** * spi_new_device - instantiate one new SPI device - * @master: Controller to which device is connected + * @ctlr: Controller to which device is connected * @chip: Describes the SPI device * Context: can sleep * @@ -573,7 +572,7 @@ EXPORT_SYMBOL_GPL(spi_add_device); * * Return: the new device, or NULL. */ -struct spi_device *spi_new_device(struct spi_master *master, +struct spi_device *spi_new_device(struct spi_controller *ctlr, struct spi_board_info *chip) { struct spi_device *proxy; @@ -586,7 +585,7 @@ struct spi_device *spi_new_device(struct spi_master *master, * suggests syslogged diagnostics are best here (ugh). */ - proxy = spi_alloc_device(master); + proxy = spi_alloc_device(ctlr); if (!proxy) return NULL; @@ -604,7 +603,7 @@ struct spi_device *spi_new_device(struct spi_master *master, if (chip->properties) { status = device_add_properties(&proxy->dev, chip->properties); if (status) { - dev_err(&master->dev, + dev_err(&ctlr->dev, "failed to add properties to '%s': %d\n", chip->modalias, status); goto err_dev_put; @@ -631,7 +630,7 @@ EXPORT_SYMBOL_GPL(spi_new_device); * @spi: spi_device to unregister * * Start making the passed SPI device vanish. Normally this would be handled - * by spi_unregister_master(). + * by spi_unregister_controller(). */ void spi_unregister_device(struct spi_device *spi) { @@ -648,17 +647,17 @@ void spi_unregister_device(struct spi_device *spi) } EXPORT_SYMBOL_GPL(spi_unregister_device); -static void spi_match_master_to_boardinfo(struct spi_master *master, - struct spi_board_info *bi) +static void spi_match_controller_to_boardinfo(struct spi_controller *ctlr, + struct spi_board_info *bi) { struct spi_device *dev; - if (master->bus_num != bi->bus_num) + if (ctlr->bus_num != bi->bus_num) return; - dev = spi_new_device(master, bi); + dev = spi_new_device(ctlr, bi); if (!dev) - dev_err(master->dev.parent, "can't create new device for %s\n", + dev_err(ctlr->dev.parent, "can't create new device for %s\n", bi->modalias); } @@ -697,7 +696,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) return -ENOMEM; for (i = 0; i < n; i++, bi++, info++) { - struct spi_master *master; + struct spi_controller *ctlr; memcpy(&bi->board_info, info, sizeof(*info)); if (info->properties) { @@ -709,8 +708,9 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) mutex_lock(&board_lock); list_add_tail(&bi->list, &board_list); - list_for_each_entry(master, &spi_master_list, list) - spi_match_master_to_boardinfo(master, &bi->board_info); + list_for_each_entry(ctlr, &spi_controller_list, list) + spi_match_controller_to_boardinfo(ctlr, + &bi->board_info); mutex_unlock(&board_lock); } @@ -727,16 +727,16 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (gpio_is_valid(spi->cs_gpio)) { gpio_set_value(spi->cs_gpio, !enable); /* Some SPI masters need both GPIO CS & slave_select */ - if ((spi->master->flags & SPI_MASTER_GPIO_SS) && - spi->master->set_cs) - spi->master->set_cs(spi, !enable); - } else if (spi->master->set_cs) { - spi->master->set_cs(spi, !enable); + if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && + spi->controller->set_cs) + spi->controller->set_cs(spi, !enable); + } else if (spi->controller->set_cs) { + spi->controller->set_cs(spi, !enable); } } #ifdef CONFIG_HAS_DMA -static int spi_map_buf(struct spi_master *master, struct device *dev, +static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, struct sg_table *sgt, void *buf, size_t len, enum dma_data_direction dir) { @@ -761,7 +761,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, desc_len = min_t(int, max_seg_size, PAGE_SIZE); sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); } else if (virt_addr_valid(buf)) { - desc_len = min_t(int, max_seg_size, master->max_dma_len); + desc_len = min_t(int, max_seg_size, ctlr->max_dma_len); sgs = DIV_ROUND_UP(len, desc_len); } else { return -EINVAL; @@ -811,7 +811,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, return 0; } -static void spi_unmap_buf(struct spi_master *master, struct device *dev, +static void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, struct sg_table *sgt, enum dma_data_direction dir) { if (sgt->orig_nents) { @@ -820,31 +820,31 @@ static void spi_unmap_buf(struct spi_master *master, struct device *dev, } } -static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) +static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { struct device *tx_dev, *rx_dev; struct spi_transfer *xfer; int ret; - if (!master->can_dma) + if (!ctlr->can_dma) return 0; - if (master->dma_tx) - tx_dev = master->dma_tx->device->dev; + if (ctlr->dma_tx) + tx_dev = ctlr->dma_tx->device->dev; else - tx_dev = master->dev.parent; + tx_dev = ctlr->dev.parent; - if (master->dma_rx) - rx_dev = master->dma_rx->device->dev; + if (ctlr->dma_rx) + rx_dev = ctlr->dma_rx->device->dev; else - rx_dev = master->dev.parent; + rx_dev = ctlr->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!master->can_dma(master, msg->spi, xfer)) + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) continue; if (xfer->tx_buf != NULL) { - ret = spi_map_buf(master, tx_dev, &xfer->tx_sg, + ret = spi_map_buf(ctlr, tx_dev, &xfer->tx_sg, (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE); if (ret != 0) @@ -852,79 +852,78 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) } if (xfer->rx_buf != NULL) { - ret = spi_map_buf(master, rx_dev, &xfer->rx_sg, + ret = spi_map_buf(ctlr, rx_dev, &xfer->rx_sg, xfer->rx_buf, xfer->len, DMA_FROM_DEVICE); if (ret != 0) { - spi_unmap_buf(master, tx_dev, &xfer->tx_sg, + spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); return ret; } } } - master->cur_msg_mapped = true; + ctlr->cur_msg_mapped = true; return 0; } -static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) +static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) { struct spi_transfer *xfer; struct device *tx_dev, *rx_dev; - if (!master->cur_msg_mapped || !master->can_dma) + if (!ctlr->cur_msg_mapped || !ctlr->can_dma) return 0; - if (master->dma_tx) - tx_dev = master->dma_tx->device->dev; + if (ctlr->dma_tx) + tx_dev = ctlr->dma_tx->device->dev; else - tx_dev = master->dev.parent; + tx_dev = ctlr->dev.parent; - if (master->dma_rx) - rx_dev = master->dma_rx->device->dev; + if (ctlr->dma_rx) + rx_dev = ctlr->dma_rx->device->dev; else - rx_dev = master->dev.parent; + rx_dev = ctlr->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!master->can_dma(master, msg->spi, xfer)) + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) continue; - spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + spi_unmap_buf(ctlr, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_D |