diff options
author | Mark Brown <broonie@kernel.org> | 2017-07-03 16:21:05 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-07-03 16:21:05 +0100 |
commit | 9d540b0d4964603798efdccae90cab8ac06c8bf4 (patch) | |
tree | 3ecf8c3779f1c99578cd64068121478895b05408 /drivers/spi | |
parent | 096bf6b7f4fcc2fe486f61526b888034a7059342 (diff) | |
parent | 8caab75fd2c2a92667cbb1cd315720bede3feaa9 (diff) |
Merge remote-tracking branch 'spi/topic/master' into spi-next
Diffstat (limited to 'drivers/spi')
-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 |
5 files changed, 987 insertions, 542 deletions
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_DEVICE); } return 0; } #else /* !CONFIG_HAS_DMA */ -static inline int spi_map_buf(struct spi_master *master, - struct device *dev, struct sg_table *sgt, - void *buf, size_t len, +static inline 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) { return -EINVAL; } -static inline void spi_unmap_buf(struct spi_master *master, +static inline void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, struct sg_table *sgt, enum dma_data_direction dir) { } -static inline int __spi_map_msg(struct spi_master *master, +static inline int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { return 0; } -static inline int __spi_unmap_msg(struct spi_master *master, +static inline int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) { return 0; } #endif /* !CONFIG_HAS_DMA */ -static inline int spi_unmap_msg(struct spi_master *master, +static inline int spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) { struct spi_transfer *xfer; @@ -934,63 +933,63 @@ static inline int spi_unmap_msg(struct spi_master *master, * Restore the original value of tx_buf or rx_buf if they are * NULL. */ - if (xfer->tx_buf == master->dummy_tx) + if (xfer->tx_buf == ctlr->dummy_tx) xfer->tx_buf = NULL; - if (xfer->rx_buf == master->dummy_rx) + if (xfer->rx_buf == ctlr->dummy_rx) xfer->rx_buf = NULL; } - return __spi_unmap_msg(master, msg); + return __spi_unmap_msg(ctlr, msg); } -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 spi_transfer *xfer; void *tmp; unsigned int max_tx, max_rx; - if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { + if (ctlr->flags & (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX)) { max_tx = 0; max_rx = 0; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if ((master->flags & SPI_MASTER_MUST_TX) && + if ((ctlr->flags & SPI_CONTROLLER_MUST_TX) && !xfer->tx_buf) max_tx = max(xfer->len, max_tx); - if ((master->flags & SPI_MASTER_MUST_RX) && + if ((ctlr->flags & SPI_CONTROLLER_MUST_RX) && !xfer->rx_buf) max_rx = max(xfer->len, max_rx); } if (max_tx) { - tmp = krealloc(master->dummy_tx, max_tx, + tmp = krealloc(ctlr->dummy_tx, max_tx, GFP_KERNEL | GFP_DMA); if (!tmp) return -ENOMEM; - master->dummy_tx = tmp; + ctlr->dummy_tx = tmp; memset(tmp, 0, max_tx); } if (max_rx) { - tmp = krealloc(master->dummy_rx, max_rx, + tmp = krealloc(ctlr->dummy_rx, max_rx, GFP_KERNEL | GFP_DMA); if (!tmp) return -ENOMEM; - master->dummy_rx = tmp; + ctlr->dummy_rx = tmp; } if (max_tx || max_rx) { list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!xfer->tx_buf) - xfer->tx_buf = master->dummy_tx; + xfer->tx_buf = ctlr->dummy_tx; if (!xfer->rx_buf) - xfer->rx_buf = master->dummy_rx; + xfer->rx_buf = ctlr->dummy_rx; } } } - return __spi_map_msg(master, msg); + return __spi_map_msg(ctlr, msg); } /* @@ -1000,14 +999,14 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg) * drivers which implement a transfer_one() operation. It provides * standard handling of delays and chip select management. */ -static int spi_transfer_one_message(struct spi_master *master, +static int spi_transfer_one_message(struct spi_controller *ctlr, struct spi_message *msg) { struct spi_transfer *xfer; bool keep_cs = false; int ret = 0; unsigned long long ms = 1; - struct spi_statistics *statm = &master->statistics; + struct spi_statistics *statm = &ctlr->statistics; struct spi_statistics *stats = &msg->spi->statistics; spi_set_cs(msg->spi, true); @@ -1018,13 +1017,13 @@ static int spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { trace_spi_transfer_start(msg, xfer); - spi_statistics_add_transfer_stats(statm, xfer, master); - spi_statistics_add_transfer_stats(stats, xfer, master); + spi_statistics_add_transfer_stats(statm, xfer, ctlr); + spi_statistics_add_transfer_stats(stats, xfer, ctlr); if (xfer->tx_buf || xfer->rx_buf) { - reinit_completion(&master->xfer_completion); + reinit_completion(&ctlr->xfer_completion); - ret = master->transfer_one(master, msg->spi, xfer); + ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { SPI_STATISTICS_INCREMENT_FIELD(statm, errors); @@ -1044,7 +1043,7 @@ static int spi_transfer_one_message(struct spi_master *master, if (ms > UINT_MAX) ms = UINT_MAX; - ms = wait_for_completion_timeout(&master->xfer_completion, + ms = wait_for_completion_timeout(&ctlr->xfer_completion, msecs_to_jiffies(ms)); } @@ -1099,33 +1098,33 @@ out: if (msg->status == -EINPROGRESS) msg->status = ret; - if (msg->status && master->handle_err) - master->handle_err(master, msg); + if (msg->status && ctlr->handle_err) + ctlr->handle_err(ctlr, msg); - spi_res_release(master, msg); + spi_res_release(ctlr, msg); - spi_finalize_current_message(master); + spi_finalize_current_message(ctlr); return ret; } /** * spi_finalize_current_transfer - report completion of a transfer - * @master: the master reporting completion + * @ctlr: the controller reporting completion * * Called by SPI drivers using the core transfer_one_message() * implementation to notify it that the current interrupt driven * transfer has finished and the next one may be scheduled. */ -void spi_finalize_current_transfer(struct spi_master *master) +void spi_finalize_current_transfer(struct spi_controller *ctlr) { - complete(&master->xfer_completion); + complete(&ctlr->xfer_completion); } EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); /** * __spi_pump_messages - function which processes spi message queue - * @master: master to process queue for + * @ctlr: controller to process queue for * @in_kthread: true if we are in the context of the message pump thread * * This function checks if there is any spi message in the queue that |