new file mode 100644
@@ -0,0 +1,35 @@
+GPIO-based SPI Chip Select Mux for Barco Orka board
+
+This binding describes a SPI bus multiplexer that uses GPIOs to route the SPI
+chip select signals.
+
+ MOSI /--------------------------------+--------+--------+--------\
+ MISO |/------------------------------+|-------+|-------+|-------\|
+ SCL ||/----------------------------+||------+||------+||------\||
+ ||| ||| ||| ||| |||
+ +------------+ ||| ||| ||| |||
+ | SoC ||| | +-+++-+ +-+++-+ +-+++-+ +-+++-+
+ | ||| | | dev | | dev | | dev | | dev |
+ | +--+++-+ | CS-X +------+\ +--+--+ +--+--+ +--+--+ +--+--+
+ | | SPI +-|-------+ Mux |\\ CS-0 | | | |
+ | +------+ | +--++--+\\\-------/ CS-1 | | |
+ | | || \\\----------------/ CS-2 | |
+ | +------+ | || \\-------------------------/ CS-3 |
+ | | GPIO +-|----------/| \----------------------------------/
+ | | +-|-----------/
+ | +------+ |
+ +------------+
+
+Required properties:
+* Standard SPI mux properties. See spi-mux.txt in this directory.
+- compatible: "barco,orka-spi-mux-gpio"
+- gpios: list of gpios used to control the muxer
+
+Whenever an access is made to a child device, the value set in the revelant
+node's reg property is interpreted as a bitmask defining the state of the gpio
+pins, with the least significant bit defining the state of first gpio, the next
+bit the state of the second gpio and so forth. The node's reg property is also
+used by the core SPI code as the (virtual) chip select in this case.
+
+Example: see spi-mux.txt in this directory, which uses an example with this
+specific SPI mux.
new file mode 100644
@@ -0,0 +1,106 @@
+Common SPI multiplexer properties.
+
+This binding describes a SPI bus multiplexer to route the SPI chip select
+signals. This can be used when you need more devices than the SPI controller
+has chip selects available. An example setup is shown in ASCII art; the actual
+setting of the multiplexer to a channel needs to be done by a specific SPI mux
+driver. See barco-orka-spi-mux-gpio.txt for a concrete example.
+
+ MOSI /--------------------------------+--------+--------+--------\
+ MISO |/------------------------------+|-------+|-------+|-------\|
+ SCL ||/----------------------------+||------+||------+||------\||
+ ||| ||| ||| ||| |||
+ +------------+ ||| ||| ||| |||
+ | SoC ||| | +-+++-+ +-+++-+ +-+++-+ +-+++-+
+ | ||| | | dev | | dev | | dev | | dev |
+ | +--+++-+ | CS-X +------+\ +--+--+ +--+--+ +--+--+ +--+--+
+ | | SPI +-|-------+ Mux |\\ CS-0 | | | |
+ | +------+ | +--+---+\\\-------/ CS-1 | | |
+ | | | \\\----------------/ CS-2 | |
+ | +------+ | | \\-------------------------/ CS-3 |
+ | | ? +-|----------/ \----------------------------------/
+ | +------+ |
+ +------------+
+
+Required properties:
+- #address-cells: <1> (as for any SPI master device)
+- #size-cells: <0> (as for any SPI master device)
+- reg: chip select of the mux on the parent SPI master
+- spi-max-frequency: the maximum frequency allowed for any devices on this mux
+* SPI child nodes, as if the mux is a real spi master
+
+Optional properties:
+- Other properties specific to the multiplexer/switch hardware.
+
+A new SPI bus will be created. Then for each child node, a SPI device is
+created, with a virtual chip select on this bus according to the reg property.
+
+The property spi-max-frequency is conceptually not needed, as each child node
+holds the maximum frequency specific to that device. However, the SPI core code
+wants every device in the tree to specify a maximum frequency. So because the
+mux is a device to a parent SPI master, you need to set a maximum frequency.
+It's best to set this high, as the driver will take the minimum of this value
+and the child's maximum frequency value when doing a transfer to that child
+device.
+
+Example:
+ /*
+ * An SPI mux on chip select 1 of the spi1 peripheral controller of an
+ * am33xx soc. Chip select 0 is taken by another device, and the mux is
+ * on chip select 1. Behind the mux are 4 devices which are defined as
+ * if the spi-mux is a master. The specific mux implementation used is
+ * barco,orka-spi-mux-gpio
+ */
+
+ spi1 {
+ compatible = "ti,omap4-mcspi";
+ status = "enabled";
+
+ spi-flash@0 {
+ compatible = "m25p40";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ };
+
+ spi-mux {
+ compatible = "barco,orka-spi-mux-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+ spi-max-frequency = <100000000>;
+
+ gpios = <&gpio2 30 0 &gpio2 31 0>;
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "sst,sst25vf016b";
+ spi-max-frequency = <40000000>;
+ reg = <0>;
+ };
+
+ spi-device@1 {
+ compatible = "spidev";
+ reg = <1>;
+ spi-max-frequency = <10000000>;
+ };
+
+ spi-flash@2 {
+ compatible = "winbond,w25q32";
+ reg = <2>;
+ spi-max-frequency = <20000000>;
+ };
+
+ mc13892@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mc13892";
+ spi-max-frequency = <6000000>;
+ reg = <3>;
+
+ /* more settings... */
+ }
+
+ };
+ };
@@ -55,14 +55,13 @@ comment "SPI Master Controller Drivers"
config SPI_ALTERA
tristate "Altera SPI Controller"
- depends on GENERIC_HARDIRQS
select SPI_BITBANG
help
This is the driver for the Altera SPI Controller.
config SPI_ATH79
tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver"
- depends on ATH79 && GPIOLIB
+ depends on ATH79 && GENERIC_GPIO
select SPI_BITBANG
help
This enables support for the SPI controller present on the
@@ -75,17 +74,6 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
-config SPI_BCM2835
- tristate "BCM2835 SPI controller"
- depends on ARCH_BCM2835
- help
- This selects a driver for the Broadcom BCM2835 SPI master.
-
- The BCM2835 contains two types of SPI master controller; the
- "universal SPI master", and the regular SPI controller. This driver
- is for the regular SPI controller. Slave mode operation is not also
- not supported.
-
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN
@@ -100,7 +88,7 @@ config SPI_BFIN_SPORT
config SPI_AU1550
tristate "Au1550/Au1200/Au1300 SPI Controller"
- depends on MIPS_ALCHEMY
+ depends on MIPS_ALCHEMY && EXPERIMENTAL
select SPI_BITBANG
help
If you say yes to this option, support will be included for the
@@ -175,7 +163,7 @@ config SPI_FALCON
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
- depends on GPIOLIB
+ depends on GENERIC_GPIO
select SPI_BITBANG
help
This simple GPIO bitbanging SPI master uses the arch-neutral GPIO
@@ -200,7 +188,7 @@ config SPI_IMX
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
- depends on PARPORT
+ depends on PARPORT && EXPERIMENTAL
select SPI_BITBANG
help
This driver supports the NS LM70 LLP Evaluation Board,
@@ -216,7 +204,7 @@ config SPI_MPC52xx
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
- depends on PPC_MPC52xx
+ depends on PPC_MPC52xx && EXPERIMENTAL
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
@@ -230,23 +218,16 @@ config SPI_MPC512x_PSC
config SPI_FSL_LIB
tristate
- depends on OF
-
-config SPI_FSL_CPM
- tristate
depends on FSL_SOC
config SPI_FSL_SPI
- bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
- depends on OF
+ bool "Freescale SPI controller"
+ depends on FSL_SOC
select SPI_FSL_LIB
- select SPI_FSL_CPM if FSL_SOC
help
This enables using the Freescale SPI controllers in master mode.
MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
- This also enables using the Aeroflex Gaisler GRLIB SPI controller in
- master mode.
config SPI_FSL_ESPI
bool "Freescale eSPI controller"
@@ -259,7 +240,7 @@ config SPI_FSL_ESPI
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
- depends on GPIOLIB
+ depends on GENERIC_GPIO
select SPI_BITBANG
help
This is the driver for OpenCores tiny SPI master controller.
@@ -292,8 +273,8 @@ config SPI_OMAP_100K
OMAP SPI 100K master controller for omap7xx boards.
config SPI_ORION
- tristate "Orion SPI master"
- depends on PLAT_ORION
+ tristate "Orion SPI master (EXPERIMENTAL)"
+ depends on PLAT_ORION && EXPERIMENTAL
help
This enables using the SPI master controller on the Orion chips.
@@ -316,20 +297,9 @@ config SPI_PPC4xx
help
This selects a driver for the PPC4xx SPI Controller.
-config SPI_PXA2XX_PXADMA
- bool "PXA2xx SSP legacy PXA DMA API support"
- depends on SPI_PXA2XX && ARCH_PXA
- help
- Enable PXA private legacy DMA API support. Note that this is
- deprecated in favor of generic DMA engine API.
-
-config SPI_PXA2XX_DMA
- def_bool y
- depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA
-
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS
+ depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
select PXA_SSP if ARCH_PXA
help
This enables using a PXA2xx or Sodaville SSP port as a SPI master
@@ -337,7 +307,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI
- def_tristate SPI_PXA2XX && PCI
+ def_bool SPI_PXA2XX && X86_32 && PCI
config SPI_RSPI
tristate "Renesas RSPI controller"
@@ -347,7 +317,7 @@ config SPI_RSPI
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
- depends on ARCH_S3C24XX
+ depends on ARCH_S3C24XX && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
@@ -416,14 +386,6 @@ config SPI_MXS
help
SPI driver for Freescale MXS devices.
-config SPI_TEGRA114
- tristate "NVIDIA Tegra114 SPI Controller"
- depends on ARCH_TEGRA && TEGRA20_APB_DMA
- help
- SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
- is different than the older SoCs SPI controller and also register interface
- get changed with this controller.
-
config SPI_TEGRA20_SFLASH
tristate "Nvidia Tegra20 Serial flash Controller"
depends on ARCH_TEGRA
@@ -457,7 +419,7 @@ config SPI_TOPCLIFF_PCH
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
- depends on GPIOLIB && CPU_TX49XX
+ depends on GENERIC_GPIO && CPU_TX49XX
help
SPI driver for Toshiba TXx9 MIPS SoCs
@@ -470,7 +432,7 @@ config SPI_XCOMM
config SPI_XILINX
tristate "Xilinx SPI controller common module"
- depends on HAS_IOMEM
+ depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
@@ -482,7 +444,7 @@ config SPI_XILINX
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
- depends on ARCH_W90X900
+ depends on ARCH_W90X900 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Nuvoton NUC900 series ARM SoCs
@@ -508,6 +470,31 @@ config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE && HAVE_CLK
+comment "SPI Multiplexer support"
+
+config SPI_MUX
+ tristate "SPI multiplexer support"
+ help
+ This adds support for SPI multiplexers. The mux will be accessible as
+ an extra master bus, the devices behind the mux will appear to be
+ chip selects on this master bus. It is still neccessary to select one
+ or more specific mux drivers.
+
+config SPI_BARCO_ORKA_MUX_GPIO
+ tristate "SPI mux support for the barco orka board, GPIO based"
+ depends on GENERIC_GPIO
+ depends on SPI_MUX
+ help
+ This adds support for the SPI mux on the Orka board from Barco. The
+ mux is a simple GPIO based multiplexer where the chip select is
+ interpreted as a bitmask defining the state of the gpio pins, with
+ the least significant bit defining the state of first gpio, the next
+ bit the state of the second gpio and so forth.
+
+#
+# Add new SPI multiplexer drivers in alphabetical order above this line
+#
+
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
@@ -516,6 +503,7 @@ comment "SPI Protocol Masters"
config SPI_SPIDEV
tristate "User mode SPI device driver support"
+ depends on EXPERIMENTAL
help
This supports user mode SPI protocol drivers.
@@ -8,13 +8,13 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
# config declarations into driver model code
obj-$(CONFIG_SPI_MASTER) += spi.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
+obj-$(CONFIG_SPI_MUX) += spi-mux.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
-obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
@@ -29,7 +29,6 @@ obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
-obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
@@ -49,10 +48,7 @@ obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
-spi-pxa2xx-platform-objs := spi-pxa2xx.o
-spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
-spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
-obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
+obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
@@ -65,7 +61,6 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
-obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
@@ -74,3 +69,6 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
+
+#SPI mux drivers
+obj-$(CONFIG_SPI_BARCO_ORKA_MUX_GPIO) += spi-barco-orka-mux-gpio.o
new file mode 100644
@@ -0,0 +1,142 @@
+/*
+ * SPI multiplexer driver using GPIO API for Barco Orka board
+ *
+ * Dries Van Puymbroeck <Dries.VanPuymbroeck@barco.com>
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mux.h>
+
+/**
+ * DOC: Driver description
+ *
+ * This driver supports the mux on the Barco Orka board. The MUX can set up 2^n
+ * channels, where n is the number of GPIO's connected to set the MUX. The chip
+ * select of the child devices will be interpreted as a bitmask for the GPIO's,
+ * with the least significant bit defining the state of first gpio, the next
+ * bit the state of the second gpio and so forth.
+ */
+
+/**
+ * struct barco_orka_spi_mux_gpio - the basic barco_orka_spi_mux_gpio structure
+ * @gpios: Array of GPIO numbers used to control MUX
+ * @n_gpios: Number of GPIOs used to control MUX
+ */
+struct barco_orka_spi_mux_gpio {
+ unsigned int *gpios;
+ int n_gpios;
+};
+
+static int barco_orka_spi_mux_gpio_select(void *mux_dev, u8 chip_select)
+{
+ struct barco_orka_spi_mux_gpio *mux =
+ (struct barco_orka_spi_mux_gpio *)mux_dev;
+ int i;
+
+ for (i = 0; i < mux->n_gpios; i++) {
+ gpio_set_value(mux->gpios[i],
+ chip_select & (1 << i));
+ }
+
+ return 0;
+}
+
+static int barco_orka_spi_mux_gpio_probe(struct spi_device *spi)
+{
+ struct barco_orka_spi_mux_gpio *mux;
+ struct device_node *np;
+ int ret = 0, i;
+ u16 num_chipselect;
+
+ mux = devm_kzalloc(&spi->dev, sizeof(*mux), GFP_KERNEL);
+ if (mux == NULL) {
+ dev_err(&spi->dev, "Failed to allocate driver struct\n");
+ return -ENOMEM;
+ }
+
+ np = spi->dev.of_node;
+ if (!np)
+ return -ENODEV;
+
+ mux->n_gpios = of_gpio_named_count(np, "gpios");
+ if (mux->n_gpios < 0) {
+ dev_err(&spi->dev, "Missing gpios property in the DT.\n");
+ return -EINVAL;
+ }
+
+ mux->gpios = devm_kzalloc(&spi->dev,
+ sizeof(*mux->gpios) * mux->n_gpios,
+ GFP_KERNEL);
+ if (!mux->gpios) {
+ dev_err(&spi->dev, "Cannot allocate gpios array");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < mux->n_gpios; i++)
+ mux->gpios[i] = of_get_named_gpio(np, "gpios", i);
+
+ for (i = 0; i < mux->n_gpios; i++) {
+ devm_gpio_request(&spi->dev, mux->gpios[i],
+ "barco-orka-spi-mux-gpio");
+ gpio_direction_output(mux->gpios[i], 0);
+ }
+
+ /* the mux can have 2 ^ <nr_gpio_used_for_muxing> chip selects */
+ num_chipselect = 1 << mux->n_gpios;
+
+ ret = spi_add_mux(spi, mux, num_chipselect,
+ barco_orka_spi_mux_gpio_select);
+ return ret;
+}
+
+static int barco_orka_spi_mux_gpio_remove(struct spi_device *spi)
+{
+ spi_del_mux(spi);
+ return 0;
+}
+
+static const struct of_device_id barco_orka_spi_mux_gpio_of_match[] = {
+ { .compatible = "barco,orka-spi-mux-gpio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, barco_orka_spi_mux_gpio_of_match);
+
+static struct spi_driver barco_orka_spi_mux_gpio_driver = {
+ .probe = barco_orka_spi_mux_gpio_probe,
+ .remove = barco_orka_spi_mux_gpio_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "barco,orka-spi-mux-gpio",
+ .of_match_table = barco_orka_spi_mux_gpio_of_match,
+ },
+};
+
+module_spi_driver(barco_orka_spi_mux_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO-based SPI multiplexer driver for Barco Orka");
+MODULE_AUTHOR("Dries Van Puymbroeck <Dries.VanPuymbroeck@barco.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:barco,orka-spi-mux-gpio");
new file mode 100644
@@ -0,0 +1,219 @@
+/*
+ * SPI multiplexer core driver
+ *
+ * Dries Van Puymbroeck <Dries.VanPuymbroeck@barco.com>
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mux.h>
+
+#define SPI_MUX_NO_CS ((unsigned)-1)
+
+/**
+ * DOC: Driver description
+ *
+ * This driver supports a MUX on an SPI bus. This can be useful when you need
+ * more chip selects than the hardware peripherals support, or than are
+ * available in a particular board setup.
+ *
+ * The driver will create an additional master bus. Devices added under the mux
+ * will be handled as 'chip selects' on the mux bus.
+ *
+ * This is just the core mux driver, you will need an aditional mux-specific
+ * driver which needs to implement the spi_mux_select callback to set the mux.
+ */
+
+/**
+ * struct spi_mux_priv - the basic spi_mux structure
+ * @spi_device: pointer to the device struct attached to the parent
+ * spi master
+ * @current_cs: The current chip select set in the mux
+ * @child_mesg_complete: The mux replaces the complete callback in the child's
+ * message to its own callback; this field is used by the
+ * driver to store the child's callback during a transfer
+ * @child_mesg_context: Used to store the child's context to the callback
+ * @child_mesg_dev: Used to store the spi_device pointer to the child
+ * @spi_mux_select: Callback to the specific mux implementation to set the
+ * mux to a chip select
+ * @mux_dev: Data passed to spi_mux_select callback and returned
+ * with spi_del_mux
+ */
+struct spi_mux_priv {
+ struct spi_device *spi;
+ unsigned current_cs;
+
+ void (*child_mesg_complete)(void *context);
+ void *child_mesg_context;
+ struct spi_device *child_mesg_dev;
+
+ int (*spi_mux_select)(void *mux_dev, u8 chip_select);
+ void *mux_dev;
+};
+
+/* should not get called when the parent master is doing a transfer */
+static int spi_mux_setup_mux(struct spi_device *spi)
+{
+ struct spi_mux_priv *priv = spi_master_get_devdata(spi->master);
+ int ret = 0;
+
+ if (priv->current_cs != spi->chip_select) {
+ dev_dbg(&priv->spi->dev,
+ "setting up the mux for cs %d\n",
+ spi->chip_select);
+
+ /* copy the child device's settings except for the cs */
+ priv->spi->max_speed_hz = spi->max_speed_hz;
+ priv->spi->mode = spi->mode;
+ priv->spi->bits_per_word = spi->bits_per_word;
+
+ ret = priv->spi_mux_select(priv->mux_dev, spi->chip_select);
+ if (ret)
+ return ret;
+
+ priv->current_cs = spi->chip_select;
+ }
+
+ return ret;
+}
+
+static int spi_mux_setup(struct spi_device *spi)
+{
+ struct spi_mux_priv *priv = spi_master_get_devdata(spi->master);
+
+ /*
+ * can be called multiple times, won't do a valid setup now but we will
+ * change the settings when we do a transfer (necessary because we
+ * can't predict from which device it will be anyway)
+ */
+ return spi_setup(priv->spi);
+}
+
+static void spi_mux_complete_cb(void *context)
+{
+ struct spi_mux_priv *priv = (struct spi_mux_priv *)context;
+ struct spi_master *master = spi_get_drvdata(priv->spi);
+ struct spi_message *m = master->cur_msg;
+
+ m->complete = priv->child_mesg_complete;
+ m->context = priv->child_mesg_context;
+ m->spi = priv->child_mesg_dev;
+ spi_finalize_current_message(master);
+}
+
+static int spi_mux_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_mux_priv *priv = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ int ret = 0;
+
+ ret = spi_mux_setup_mux(spi);
+ if (ret)
+ return ret;
+
+ /*
+ * Replace the complete callback, context and spi_device with our own
+ * pointers. Save originals
+ */
+ priv->child_mesg_complete = m->complete;
+ priv->child_mesg_context = m->context;
+ priv->child_mesg_dev = m->spi;
+
+ m->complete = spi_mux_complete_cb;
+ m->context = priv;
+ m->spi = priv->spi;
+
+ /* do the transfer */
+ ret = spi_async(priv->spi, m);
+ return ret;
+}
+
+int spi_add_mux(struct spi_device *spi, void *mux_dev, u16 num_chipselect,
+ int (*spi_mux_select)(void *mux_dev, u8 chip_select))
+{
+ struct spi_master *master;
+ struct spi_mux_priv *priv;
+ int ret = 0;
+
+ master = spi_alloc_master(&spi->dev, sizeof(*priv));
+ if (master == NULL) {
+ dev_dbg(&spi->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(&spi->dev, master);
+ priv = spi_master_get_devdata(master);
+ priv->spi = spi;
+ priv->spi_mux_select = spi_mux_select;
+ priv->mux_dev = mux_dev;
+
+ priv->current_cs = SPI_MUX_NO_CS;
+ ret = priv->spi_mux_select(priv->mux_dev, priv->current_cs);
+ if (ret)
+ goto err_mux_select;
+
+ /* supported modes are the same as our parent's */
+ master->mode_bits = spi->master->mode_bits;
+
+ master->setup = spi_mux_setup;
+ master->transfer_one_message = spi_mux_transfer_one_message;
+ master->num_chipselect = num_chipselect;
+ master->dev.of_node = spi->dev.of_node;
+
+ /*
+ * when we register our mux as an spi master, it will parse the
+ * the children of this node and add them as devices.
+ * So we don't need to parse the child nodes here.
+ */
+ ret = spi_register_master(master);
+ if (ret < 0)
+ goto err_register_master;
+
+ return ret;
+
+err_mux_select:
+err_register_master:
+ spi_master_put(master);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_add_mux);
+
+void spi_del_mux(struct spi_device *spi)
+{
+ struct spi_master *master = spi_get_drvdata(spi);
+
+ spi_unregister_master(master);
+ spi_master_put(master);
+}
+EXPORT_SYMBOL_GPL(spi_del_mux);
+
+void *spi_get_mux_dev(struct spi_device *spi)
+{
+ struct spi_master *master = spi_get_drvdata(spi);
+ struct spi_mux_priv *priv = spi_master_get_devdata(master);
+ return priv->mux_dev;
+}
+EXPORT_SYMBOL_GPL(spi_get_mux_dev);
+
+MODULE_DESCRIPTION("SPI multiplexer core functions");
+MODULE_AUTHOR("Dries Van Puymbroeck <Dries.VanPuymbroeck@barco.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:spi-mux");
new file mode 100644
@@ -0,0 +1,58 @@
+/*
+ * SPI multiplexer core driver
+ *
+ * Dries Van Puymbroeck <Dries.VanPuymbroeck@barco.com>
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses>
+ */
+
+#ifndef _LINUX_SPI_MUX_H
+#define _LINUX_SPI_MUX_H
+
+#ifdef __KERNEL__
+
+/**
+ * spi_add_mux: - create a SPI bus on a multiplexed bus segment.
+ * @spi: the SPI device struct attached to the parent SPI controller
+ * @mux_dev: pointer to the mux's implementation-dependent data
+ * @num_chipselect: maximum number of chip selects on this mux
+ * @spi_mux_select: callback function to set the mux to a specified chip select
+ *
+ * Description: adds a mux on the chip select of @spi
+ * Return: 0 if success, err otherwise
+ */
+extern int spi_add_mux(struct spi_device *spi,
+ void *mux_dev,
+ u16 num_chipselect,
+ int (*spi_mux_select)(void *mux_dev, u8 chip_select));
+
+/**
+ * spi_del_mux: - delete a SPI mutliplexer previously added by spi_add_mux
+ * @spi: the SPI device struct attached to the parent SPI controller
+ *
+ * Description: deletes the mux on the chip select of @spi
+ */
+extern void spi_del_mux(struct spi_device *spi);
+
+/**
+ * spi_get_mux_dev: - get pointer to the mux's implementation-dependent data
+ * @spi: the SPI device struct attached to the parent SPI controller
+ *
+ * Return: the mux_dev pointer passed in spi_add_mux
+ */
+extern void *spi_get_mux_dev(struct spi_device *spi);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SPI_MUX_H */