Merge remote-tracking branches 'spi/topic/lp8841', 'spi/topic/msg', 'spi/topic/pl022...
authorMark Brown <broonie@kernel.org>
Fri, 11 Mar 2016 07:28:43 +0000 (14:28 +0700)
committerMark Brown <broonie@kernel.org>
Fri, 11 Mar 2016 07:28:43 +0000 (14:28 +0700)
1  2  3  4  5 
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi.c
include/linux/spi/spi.h

diff --combined drivers/spi/Kconfig
@@@@@@ -75,26 -75,11 -75,11 -75,11 -75,11 +75,26 @@@@@@ config SPI_ATME
          This selects a driver for the Atmel SPI Controller, present on
          many AT32 (AVR32) and AT91 (ARM) chips.
     
 ++++config SPI_AU1550
 ++++   tristate "Au1550/Au1200/Au1300 SPI Controller"
 ++++   depends on MIPS_ALCHEMY
 ++++   select SPI_BITBANG
 ++++   help
 ++++     If you say yes to this option, support will be included for the
 ++++     PSC SPI controller found on Au1550, Au1200 and Au1300 series.
 ++++
 ++++config SPI_AXI_SPI_ENGINE
 ++++   tristate "Analog Devices AXI SPI Engine controller"
 ++++   depends on HAS_IOMEM
 ++++   help
 ++++     This enables support for the Analog Devices AXI SPI Engine SPI controller.
 ++++     It is part of the SPI Engine framework that is used in some Analog Devices
 ++++     reference designs for FPGAs.
 ++++
     config SPI_BCM2835
        tristate "BCM2835 SPI controller"
        depends on GPIOLIB
        depends on ARCH_BCM2835 || COMPILE_TEST
 ----   depends on GPIOLIB
        help
          This selects a driver for the Broadcom BCM2835 SPI master.
     
     
     config SPI_BCM2835AUX
        tristate "BCM2835 SPI auxiliary controller"
 ----   depends on ARCH_BCM2835 || COMPILE_TEST
 ----   depends on GPIOLIB
 ++++   depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST
        help
          This selects a driver for the Broadcom BCM2835 SPI aux master.
     
@@@@@@ -132,6 -118,14 -118,14 -118,14 -118,14 +132,6 @@@@@@ config SPI_BFIN_SPOR
        help
          Enable support for a SPI bus via the Blackfin SPORT peripheral.
     
 ----config SPI_AU1550
 ----   tristate "Au1550/Au1200/Au1300 SPI Controller"
 ----   depends on MIPS_ALCHEMY
 ----   select SPI_BITBANG
 ----   help
 ----     If you say yes to this option, support will be included for the
 ----     PSC SPI controller found on Au1550, Au1200 and Au1300 series.
 ----
     config SPI_BCM53XX
        tristate "Broadcom BCM53xx SPI controller"
        depends on ARCH_BCM_5301X
@@@@@@ -203,23 -197,6 -197,6 -197,6 -197,6 +203,23 @@@@@@ config SPI_DAVINC
        help
          SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
     
 ++++config SPI_DESIGNWARE
 ++++   tristate "DesignWare SPI controller core support"
 ++++   help
 ++++     general driver for SPI controller core from DesignWare
 ++++
 ++++config SPI_DW_PCI
 ++++   tristate "PCI interface driver for DW SPI core"
 ++++   depends on SPI_DESIGNWARE && PCI
 ++++
 ++++config SPI_DW_MID_DMA
 ++++   bool "DMA support for DW SPI controller on Intel MID platform"
 ++++   depends on SPI_DW_PCI && DW_DMAC_PCI
 ++++
 ++++config SPI_DW_MMIO
 ++++   tristate "Memory-mapped io interface driver for DW SPI core"
 ++++   depends on SPI_DESIGNWARE
 ++++
     config SPI_DLN2
            tristate "Diolan DLN-2 USB SPI adapter"
            depends on MFD_DLN2
@@@@@@ -294,6 -271,16 -271,6 -271,6 -271,6 +294,16 @@@@@@ config SPI_LM70_LL
          which interfaces to an LM70 temperature sensor using
          a parallel port.
     
+ +++config SPI_LP8841_RTC
+ +++   tristate "ICP DAS LP-8841 SPI Controller for RTC"
+ +++   depends on MACH_PXA27X_DT || COMPILE_TEST
+ +++   help
+ +++     This driver provides an SPI master device to drive Maxim
+ +++     DS-1302 real time clock.
+ +++
+ +++     Say N here unless you plan to run the kernel on an ICP DAS
+ +++     LP-8x4x industrial computer.
+ +++
     config SPI_MPC52xx
        tristate "Freescale MPC52xx SPI (non-PSC) controller support"
        depends on PPC_MPC52xx
@@@@@@ -369,13 -356,6 -346,6 -346,6 -346,6 +379,13 @@@@@@ config SPI_MT65X
          say Y or M here.If you are not sure, say N.
          SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
     
 ++++config SPI_NUC900
 ++++   tristate "Nuvoton NUC900 series SPI"
 ++++   depends on ARCH_W90X900
 ++++   select SPI_BITBANG
 ++++   help
 ++++     SPI driver for Nuvoton NUC900 series ARM SoCs
 ++++
     config SPI_OC_TINY
        tristate "OpenCores tiny SPI"
        depends on GPIOLIB || COMPILE_TEST
@@@@@@ -445,10 -425,10 -415,10 -415,10 -415,6 +455,6 @@@@@@ config SPI_PPC4x
        help
          This selects a driver for the PPC4xx SPI Controller.
     
---- config SPI_PXA2XX_DMA
----    def_bool y
----    depends on SPI_PXA2XX
---- 
     config SPI_PXA2XX
        tristate "PXA2xx SSP SPI master"
        depends on (ARCH_PXA || PCI || ACPI)
@@@@@@ -677,10 -657,34 -647,34 -647,34 -643,34 +683,10 @@@@@@ config SPI_ZYNQMP_GQSP
        help
          Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
     
 ----config SPI_NUC900
 ----   tristate "Nuvoton NUC900 series SPI"
 ----   depends on ARCH_W90X900
 ----   select SPI_BITBANG
 ----   help
 ----     SPI driver for Nuvoton NUC900 series ARM SoCs
 ----
     #
     # Add new SPI master controllers in alphabetical order above this line
     #
     
 ----config SPI_DESIGNWARE
 ----   tristate "DesignWare SPI controller core support"
 ----   help
 ----     general driver for SPI controller core from DesignWare
 ----
 ----config SPI_DW_PCI
 ----   tristate "PCI interface driver for DW SPI core"
 ----   depends on SPI_DESIGNWARE && PCI
 ----
 ----config SPI_DW_MID_DMA
 ----   bool "DMA support for DW SPI controller on Intel MID platform"
 ----   depends on SPI_DW_PCI && DW_DMAC_PCI
 ----
 ----config SPI_DW_MMIO
 ----   tristate "Memory-mapped io interface driver for DW SPI core"
 ----   depends on SPI_DESIGNWARE
 ----
     #
     # There are lots of SPI device types, with sensors and memory
     # being probably the most widely used ones.
diff --combined drivers/spi/Makefile
@@@@@@ -15,7 -15,6 -15,6 -15,6 -15,6 +15,7 @@@@@@ obj-$(CONFIG_SPI_ALTERA)              += spi-altera
     obj-$(CONFIG_SPI_ATMEL)                    += spi-atmel.o
     obj-$(CONFIG_SPI_ATH79)                    += spi-ath79.o
     obj-$(CONFIG_SPI_AU1550)           += spi-au1550.o
 ++++obj-$(CONFIG_SPI_AXI_SPI_ENGINE)   += spi-axi-spi-engine.o
     obj-$(CONFIG_SPI_BCM2835)          += spi-bcm2835.o
     obj-$(CONFIG_SPI_BCM2835AUX)               += spi-bcm2835aux.o
     obj-$(CONFIG_SPI_BCM53XX)          += spi-bcm53xx.o
@@@@@@ -47,6 -46,7 -46,6 -46,6 -46,6 +47,7 @@@@@@ obj-$(CONFIG_SPI_GPIO)                        += spi-gpio.
     obj-$(CONFIG_SPI_IMG_SPFI)         += spi-img-spfi.o
     obj-$(CONFIG_SPI_IMX)                      += spi-imx.o
     obj-$(CONFIG_SPI_LM70_LLP)         += spi-lm70llp.o
+ +++obj-$(CONFIG_SPI_LP8841_RTC)               += spi-lp8841-rtc.o
     obj-$(CONFIG_SPI_MESON_SPIFC)              += spi-meson-spifc.o
     obj-$(CONFIG_SPI_MPC512x_PSC)              += spi-mpc512x-psc.o
     obj-$(CONFIG_SPI_MPC52xx_PSC)              += spi-mpc52xx-psc.o
@@@@@@ -63,8 -63,8 -62,8 -62,8 -62,7 +64,7 @@@@@@ obj-$(CONFIG_SPI_TI_QSPI)             += spi-ti-qs
     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_DMA)       += spi-pxa2xx-dma.o
++++ spi-pxa2xx-platform-objs           := spi-pxa2xx.o spi-pxa2xx-dma.o
     obj-$(CONFIG_SPI_PXA2XX)           += spi-pxa2xx-platform.o
     obj-$(CONFIG_SPI_PXA2XX_PCI)               += spi-pxa2xx-pci.o
     obj-$(CONFIG_SPI_QUP)                      += spi-qup.o
diff --combined drivers/spi/spi.c
@@@@@@ -144,6 -144,6 -144,8 -144,6 -144,6 +144,8 @@@@@@ SPI_STATISTICS_TRANSFER_BYTES_HISTO(14
     SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535");
     SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+");
     
++ ++SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
++ ++
     static struct attribute *spi_dev_attrs[] = {
        &dev_attr_modalias.attr,
        NULL,
@@@@@@ -181,6 -181,6 -183,7 -181,6 -181,6 +183,7 @@@@@@ static struct attribute *spi_device_sta
        &dev_attr_spi_device_transfer_bytes_histo14.attr,
        &dev_attr_spi_device_transfer_bytes_histo15.attr,
        &dev_attr_spi_device_transfer_bytes_histo16.attr,
++ ++   &dev_attr_spi_device_transfers_split_maxsize.attr,
        NULL,
     };
     
@@@@@@ -223,6 -223,6 -226,7 -223,6 -223,6 +226,7 @@@@@@ static struct attribute *spi_master_sta
        &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,
        NULL,
     };
     
@@@@@@ -702,7 -702,6 -706,6 -702,6 -702,6 +706,7 @@@@@@ static int spi_map_buf(struct spi_maste
                       enum dma_data_direction dir)
     {
        const bool vmalloced_buf = is_vmalloc_addr(buf);
 ++++   unsigned int max_seg_size = dma_get_max_seg_size(dev);
        int desc_len;
        int sgs;
        struct page *vm_page;
        int i, ret;
     
        if (vmalloced_buf) {
 ----           desc_len = PAGE_SIZE;
 ++++           desc_len = min_t(int, max_seg_size, PAGE_SIZE);
                sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
        } else {
 ----           desc_len = master->max_dma_len;
 ++++           desc_len = min_t(int, max_seg_size, master->max_dma_len);
                sgs = DIV_ROUND_UP(len, desc_len);
        }
     
                        sg_set_buf(&sgt->sgl[i], sg_buf, min);
                }
     
 ----
                buf += min;
                len -= min;
        }
        if (msg->status && master->handle_err)
                master->handle_err(master, msg);
     
++ ++   spi_res_release(master, msg);
++ ++
        spi_finalize_current_message(master);
     
        return ret;
@@@@@@ -1047,7 -1047,6 -1053,6 -1047,6 -1047,6 +1053,7 @@@@@@ EXPORT_SYMBOL_GPL(spi_finalize_current_
      * __spi_pump_messages - function which processes spi message queue
      * @master: master to process queue for
      * @in_kthread: true if we are in the context of the message pump thread
 ++++ * @bus_locked: true if the bus mutex is held when calling this function
      *
      * This function checks if there is any spi message in the queue that
      * needs processing and if so call out to the driver to initialize hardware
      * inside spi_sync(); the queue extraction handling at the top of the
      * function should deal with this safely.
      */
 ----static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
 ++++static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
 ++++                           bool bus_locked)
     {
        unsigned long flags;
        bool was_busy = false;
                }
        }
     
 ++++   if (!bus_locked)
 ++++           mutex_lock(&master->bus_lock_mutex);
 ++++
        trace_spi_message_start(master->cur_msg);
     
        if (master->prepare_message) {
                                "failed to prepare message: %d\n", ret);
                        master->cur_msg->status = ret;
                        spi_finalize_current_message(master);
 ----                   return;
 ++++                   goto out;
                }
                master->cur_msg_prepared = true;
        }
        if (ret) {
                master->cur_msg->status = ret;
                spi_finalize_current_message(master);
 ----           return;
 ++++           goto out;
        }
     
        ret = master->transfer_one_message(master, master->cur_msg);
        if (ret) {
                dev_err(&master->dev,
                        "failed to transfer one message from queue\n");
 ----           return;
 ++++           goto out;
        }
 ++++
 ++++out:
 ++++   if (!bus_locked)
 ++++           mutex_unlock(&master->bus_lock_mutex);
 ++++
 ++++   /* Prod the scheduler in case transfer_one() was busy waiting */
 ++++   if (!ret)
 ++++           cond_resched();
     }
     
     /**
@@@@@@ -1203,7 -1190,7 -1196,7 -1190,7 -1190,7 +1209,7 @@@@@@ static void spi_pump_messages(struct kt
        struct spi_master *master =
                container_of(work, struct spi_master, pump_messages);
     
 ----   __spi_pump_messages(master, true);
 ++++   __spi_pump_messages(master, true, false);
     }
     
     static int spi_init_queue(struct spi_master *master)
@@@@@@ -1594,30 -1581,13 -1587,13 -1581,13 -1581,30 +1600,30 @@@@@@ static void of_register_spi_devices(str
     static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
     {
        struct spi_device *spi = data;
 +++    struct spi_master *master = spi->master;
     
        if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
                struct acpi_resource_spi_serialbus *sb;
     
                sb = &ares->data.spi_serial_bus;
                if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
 ---                    spi->chip_select = sb->device_selection;
 +++                    /*
 +++                     * ACPI DeviceSelection numbering is handled by the
 +++                     * host controller driver in Windows and can vary
 +++                     * from driver to driver. In Linux we always expect
 +++                     * 0 .. max - 1 so we need to ask the driver to
 +++                     * translate between the two schemes.
 +++                     */
 +++                    if (master->fw_translate_cs) {
 +++                            int cs = master->fw_translate_cs(master,
 +++                                            sb->device_selection);
 +++                            if (cs < 0)
 +++                                    return cs;
 +++                            spi->chip_select = cs;
 +++                    } else {
 +++                            spi->chip_select = sb->device_selection;
 +++                    }
 +++ 
                        spi->max_speed_hz = sb->connection_speed;
     
                        if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
@@@@@@ -2043,6 -2013,6 -2019,336 -2013,6 -2030,6 +2049,336 @@@@@@ struct spi_master *spi_busnum_to_master
     }
     EXPORT_SYMBOL_GPL(spi_busnum_to_master);
     
++ ++/*-------------------------------------------------------------------------*/
++ ++
++ ++/* Core methods for SPI resource management */
++ ++
++ ++/**
++ ++ * spi_res_alloc - allocate a spi resource that is life-cycle managed
++ ++ *                 during the processing of a spi_message while using
++ ++ *                 spi_transfer_one
++ ++ * @spi:     the spi device for which we allocate memory
++ ++ * @release: the release code to execute for this resource
++ ++ * @size:    size to alloc and return
++ ++ * @gfp:     GFP allocation flags
++ ++ *
++ ++ * Return: the pointer to the allocated data
++ ++ *
++ ++ * This may get enhanced in the future to allocate from a memory pool
++ ++ * of the @spi_device or @spi_master to avoid repeated allocations.
++ ++ */
++ ++void *spi_res_alloc(struct spi_device *spi,
++ ++               spi_res_release_t release,
++ ++               size_t size, gfp_t gfp)
++ ++{
++ ++   struct spi_res *sres;
++ ++
++ ++   sres = kzalloc(sizeof(*sres) + size, gfp);
++ ++   if (!sres)
++ ++           return NULL;
++ ++
++ ++   INIT_LIST_HEAD(&sres->entry);
++ ++   sres->release = release;
++ ++
++ ++   return sres->data;
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_res_alloc);
++ ++
++ ++/**
++ ++ * spi_res_free - free an spi resource
++ ++ * @res: pointer to the custom data of a resource
++ ++ *
++ ++ */
++ ++void spi_res_free(void *res)
++ ++{
++ ++   struct spi_res *sres = container_of(res, struct spi_res, data);
++ ++
++ ++   if (!res)
++ ++           return;
++ ++
++ ++   WARN_ON(!list_empty(&sres->entry));
++ ++   kfree(sres);
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_res_free);
++ ++
++ ++/**
++ ++ * spi_res_add - add a spi_res to the spi_message
++ ++ * @message: the spi message
++ ++ * @res:     the spi_resource
++ ++ */
++ ++void spi_res_add(struct spi_message *message, void *res)
++ ++{
++ ++   struct spi_res *sres = container_of(res, struct spi_res, data);
++ ++
++ ++   WARN_ON(!list_empty(&sres->entry));
++ ++   list_add_tail(&sres->entry, &message->resources);
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_res_add);
++ ++
++ ++/**
++ ++ * spi_res_release - release all spi resources for this message
++ ++ * @master:  the @spi_master
++ ++ * @message: the @spi_message
++ ++ */
++ ++void spi_res_release(struct spi_master *master,
++ ++                struct spi_message *message)
++ ++{
++ ++   struct spi_res *res;
++ ++
++ ++   while (!list_empty(&message->resources)) {
++ ++           res = list_last_entry(&message->resources,
++ ++                                 struct spi_res, entry);
++ ++
++ ++           if (res->release)
++ ++                   res->release(master, message, res->data);
++ ++
++ ++           list_del(&res->entry);
++ ++
++ ++           kfree(res);
++ ++   }
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_res_release);
++ ++
++ ++/*-------------------------------------------------------------------------*/
++ ++
++ ++/* Core methods for spi_message alterations */
++ ++
++ ++static void __spi_replace_transfers_release(struct spi_master *master,
++ ++                                       struct spi_message *msg,
++ ++                                       void *res)
++ ++{
++ ++   struct spi_replaced_transfers *rxfer = res;
++ ++   size_t i;
++ ++
++ ++   /* call extra callback if requested */
++ ++   if (rxfer->release)
++ ++           rxfer->release(master, msg, res);
++ ++
++ ++   /* insert replaced transfers back into the message */
++ ++   list_splice(&rxfer->replaced_transfers, rxfer->replaced_after);
++ ++
++ ++   /* remove the formerly inserted entries */
++ ++   for (i = 0; i < rxfer->inserted; i++)
++ ++           list_del(&rxfer->inserted_transfers[i].transfer_list);
++ ++}
++ ++
++ ++/**
++ ++ * spi_replace_transfers - replace transfers with several transfers
++ ++ *                         and register change with spi_message.resources
++ ++ * @msg:           the spi_message we work upon
++ ++ * @xfer_first:    the first spi_transfer we want to replace
++ ++ * @remove:        number of transfers to remove
++ ++ * @insert:        the number of transfers we want to insert instead
++ ++ * @release:       extra release code necessary in some circumstances
++ ++ * @extradatasize: extra data to allocate (with alignment guarantees
++ ++ *                 of struct @spi_transfer)
++ ++ * @gfp:           gfp flags
++ ++ *
++ ++ * Returns: pointer to @spi_replaced_transfers,
++ ++ *          PTR_ERR(...) in case of errors.
++ ++ */
++ ++struct spi_replaced_transfers *spi_replace_transfers(
++ ++   struct spi_message *msg,
++ ++   struct spi_transfer *xfer_first,
++ ++   size_t remove,
++ ++   size_t insert,
++ ++   spi_replaced_release_t release,
++ ++   size_t extradatasize,
++ ++   gfp_t gfp)
++ ++{
++ ++   struct spi_replaced_transfers *rxfer;
++ ++   struct spi_transfer *xfer;
++ ++   size_t i;
++ ++
++ ++   /* allocate the structure using spi_res */
++ ++   rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release,
++ ++                         insert * sizeof(struct spi_transfer)
++ ++                         + sizeof(struct spi_replaced_transfers)
++ ++                         + extradatasize,
++ ++                         gfp);
++ ++   if (!rxfer)
++ ++           return ERR_PTR(-ENOMEM);
++ ++
++ ++   /* the release code to invoke before running the generic release */
++ ++   rxfer->release = release;
++ ++
++ ++   /* assign extradata */
++ ++   if (extradatasize)
++ ++           rxfer->extradata =
++ ++                   &rxfer->inserted_transfers[insert];
++ ++
++ ++   /* init the replaced_transfers list */
++ ++   INIT_LIST_HEAD(&rxfer->replaced_transfers);
++ ++
++ ++   /* assign the list_entry after which we should reinsert
++ ++    * the @replaced_transfers - it may be spi_message.messages!
++ ++    */
++ ++   rxfer->replaced_after = xfer_first->transfer_list.prev;
++ ++
++ ++   /* remove the requested number of transfers */
++ ++   for (i = 0; i < remove; i++) {
++ ++           /* if the entry after replaced_after it is msg->transfers
++ ++            * then we have been requested to remove more transfers
++ ++            * than are in the list
++ ++            */
++ ++           if (rxfer->replaced_after->next == &msg->transfers) {
++ ++                   dev_err(&msg->spi->dev,
++ ++                           "requested to remove more spi_transfers than are available\n");
++ ++                   /* insert replaced transfers back into the message */
++ ++                   list_splice(&rxfer->replaced_transfers,
++ ++                               rxfer->replaced_after);
++ ++
++ ++                   /* free the spi_replace_transfer structure */
++ ++                   spi_res_free(rxfer);
++ ++
++ ++                   /* and return with an error */
++ ++                   return ERR_PTR(-EINVAL);
++ ++           }
++ ++
++ ++           /* remove the entry after replaced_after from list of
++ ++            * transfers and add it to list of replaced_transfers
++ ++            */
++ ++           list_move_tail(rxfer->replaced_after->next,
++ ++                          &rxfer->replaced_transfers);
++ ++   }
++ ++
++ ++   /* create copy of the given xfer with identical settings
++ ++    * based on the first transfer to get removed
++ ++    */
++ ++   for (i = 0; i < insert; i++) {
++ ++           /* we need to run in reverse order */
++ ++           xfer = &rxfer->inserted_transfers[insert - 1 - i];
++ ++
++ ++           /* copy all spi_transfer data */
++ ++           memcpy(xfer, xfer_first, sizeof(*xfer));
++ ++
++ ++           /* add to list */
++ ++           list_add(&xfer->transfer_list, rxfer->replaced_after);
++ ++
++ ++           /* clear cs_change and delay_usecs for all but the last */
++ ++           if (i) {
++ ++                   xfer->cs_change = false;
++ ++                   xfer->delay_usecs = 0;
++ ++           }
++ ++   }
++ ++
++ ++   /* set up inserted */
++ ++   rxfer->inserted = insert;
++ ++
++ ++   /* and register it with spi_res/spi_message */
++ ++   spi_res_add(msg, rxfer);
++ ++
++ ++   return rxfer;
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_replace_transfers);
++ ++
++ ++static int __spi_split_transfer_maxsize(struct spi_master *master,
++ ++                                   struct spi_message *msg,
++ ++                                   struct spi_transfer **xferp,
++ ++                                   size_t maxsize,
++ ++                                   gfp_t gfp)
++ ++{
++ ++   struct spi_transfer *xfer = *xferp, *xfers;
++ ++   struct spi_replaced_transfers *srt;
++ ++   size_t offset;
++ ++   size_t count, i;
++ ++
++ ++   /* warn once about this fact that we are splitting a transfer */
++ ++   dev_warn_once(&msg->spi->dev,
++ ++                 "spi_transfer of length %i exceed max length of %zu - needed to split transfers\n",
++ ++                 xfer->len, maxsize);
++ ++
++ ++   /* calculate how many we have to replace */
++ ++   count = DIV_ROUND_UP(xfer->len, maxsize);
++ ++
++ ++   /* create replacement */
++ ++   srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, gfp);
++ ++   if (IS_ERR(srt))
++ ++           return PTR_ERR(srt);
++ ++   xfers = srt->inserted_transfers;
++ ++
++ ++   /* now handle each of those newly inserted spi_transfers
++ ++    * note that the replacements spi_transfers all are preset
++ ++    * to the same values as *xferp, so tx_buf, rx_buf and len
++ ++    * are all identical (as well as most others)
++ ++    * so we just have to fix up len and the pointers.
++ ++    *
++ ++    * this also includes support for the depreciated
++ ++    * spi_message.is_dma_mapped interface
++ ++    */
++ ++
++ ++   /* the first transfer just needs the length modified, so we
++ ++    * run it outside the loop
++ ++    */
++ ++   xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
++ ++
++ ++   /* all the others need rx_buf/tx_buf also set */
++ ++   for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
++ ++           /* update rx_buf, tx_buf and dma */
++ ++           if (xfers[i].rx_buf)
++ ++                   xfers[i].rx_buf += offset;
++ ++           if (xfers[i].rx_dma)
++ ++                   xfers[i].rx_dma += offset;
++ ++           if (xfers[i].tx_buf)
++ ++                   xfers[i].tx_buf += offset;
++ ++           if (xfers[i].tx_dma)
++ ++                   xfers[i].tx_dma += offset;
++ ++
++ ++           /* update length */
++ ++           xfers[i].len = min(maxsize, xfers[i].len - offset);
++ ++   }
++ ++
++ ++   /* we set up xferp to the last entry we have inserted,
++ ++    * so that we skip those already split transfers
++ ++    */
++ ++   *xferp = &xfers[count - 1];
++ ++
++ ++   /* increment statistics counters */
++ ++   SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,
++ ++                                  transfers_split_maxsize);
++ ++   SPI_STATISTICS_INCREMENT_FIELD(&msg->spi->statistics,
++ ++                                  transfers_split_maxsize);
++ ++
++ ++   return 0;
++ ++}
++ ++
++ ++/**
++ ++ * spi_split_tranfers_maxsize - split spi transfers into multiple transfers
++ ++ *                              when an individual transfer exceeds a
++ ++ *                              certain size
++ ++ * @master:    the @spi_master for this transfer
++ ++ * @msg:   the @spi_message to transform
++ ++ * @maxsize:  the maximum when to apply this
++ ++ * @gfp: GFP allocation flags
++ ++ *
++ ++ * Return: status of transformation
++ ++ */
++ ++int spi_split_transfers_maxsize(struct spi_master *master,
++ ++                           struct spi_message *msg,
++ ++                           size_t maxsize,
++ ++                           gfp_t gfp)
++ ++{
++ ++   struct spi_transfer *xfer;
++ ++   int ret;
++ ++
++ ++   /* iterate over the transfer_list,
++ ++    * but note that xfer is advanced to the last transfer inserted
++ ++    * to avoid checking sizes again unnecessarily (also xfer does
++ ++    * potentiall belong to a different list by the time the
++ ++    * replacement has happened
++ ++    */
++ ++   list_for_each_entry(xfer, &msg->transfers, transfer_list) {
++ ++           if (xfer->len > maxsize) {
++ ++                   ret = __spi_split_transfer_maxsize(
++ ++                           master, msg, &xfer, maxsize, gfp);
++ ++                   if (ret)
++ ++                           return ret;
++ ++           }
++ ++   }
++ ++
++ ++   return 0;
++ ++}
++ ++EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
     
     /*-------------------------------------------------------------------------*/
     
@@@@@@ -2381,46 -2351,6 -2687,6 -2351,6 -2368,6 +2717,46 @@@@@@ int spi_async_locked(struct spi_device 
     EXPORT_SYMBOL_GPL(spi_async_locked);
     
     
 ++++int spi_flash_read(struct spi_device *spi,
 ++++              struct spi_flash_read_message *msg)
 ++++
 ++++{
 ++++   struct spi_master *master = spi->master;
 ++++   int ret;
 ++++
 ++++   if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
 ++++        msg->addr_nbits == SPI_NBITS_DUAL) &&
 ++++       !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
 ++++           return -EINVAL;
 ++++   if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
 ++++        msg->addr_nbits == SPI_NBITS_QUAD) &&
 ++++       !(spi->mode & SPI_TX_QUAD))
 ++++           return -EINVAL;
 ++++   if (msg->data_nbits == SPI_NBITS_DUAL &&
 ++++       !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
 ++++           return -EINVAL;
 ++++   if (msg->data_nbits == SPI_NBITS_QUAD &&
 ++++       !(spi->mode &  SPI_RX_QUAD))
 ++++           return -EINVAL;
 ++++
 ++++   if (master->auto_runtime_pm) {
 ++++           ret = pm_runtime_get_sync(master->dev.parent);
 ++++           if (ret < 0) {
 ++++                   dev_err(&master->dev, "Failed to power device: %d\n",
 ++++                           ret);
 ++++                   return ret;
 ++++           }
 ++++   }
 ++++   mutex_lock(&master->bus_lock_mutex);
 ++++   ret = master->spi_flash_read(spi, msg);
 ++++   mutex_unlock(&master->bus_lock_mutex);
 ++++   if (master->auto_runtime_pm)
 ++++           pm_runtime_put(master->dev.parent);
 ++++
 ++++   return ret;
 ++++}
 ++++EXPORT_SYMBOL_GPL(spi_flash_read);
 ++++
     /*-------------------------------------------------------------------------*/
     
     /* Utility methods for SPI master protocol drivers, layered on
@@@@@@ -2484,7 -2414,7 -2750,7 -2414,7 -2431,7 +2820,7 @@@@@@ static int __spi_sync(struct spi_devic
                                                       spi_sync_immediate);
                        SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
                                                       spi_sync_immediate);
 ----                   __spi_pump_messages(master, false);
 ++++                   __spi_pump_messages(master, false, bus_locked);
                }
     
                wait_for_completion(&done);
diff --combined include/linux/spi/spi.h
     struct dma_chan;
     struct spi_master;
     struct spi_transfer;
 ++++struct spi_flash_read_message;
     
     /*
      * INTERFACES between SPI master-side drivers and SPI infrastructure.
@@@@@@ -54,6 -53,6 -53,10 -53,6 -53,6 +54,10 @@@@@@ extern struct bus_type spi_bus_type
      *
      * @transfer_bytes_histo:
      *                 transfer bytes histogramm
++ ++ *
++ ++ * @transfers_split_maxsize:
++ ++ *                 number of transfers that have been split because of
++ ++ *                 maxsize limit
      */
     struct spi_statistics {
        spinlock_t              lock; /* lock for the whole structure */
     
     #define SPI_STATISTICS_HISTO_SIZE 17
        unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];
++ ++
++ ++   unsigned long transfers_split_maxsize;
     };
     
     void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
@@@@@@ -304,8 -303,6 -309,6 -303,6 -303,6 +310,8 @@@@@@ static inline void spi_unregister_drive
      * @min_speed_hz: Lowest supported transfer speed
      * @max_speed_hz: Highest supported transfer speed
      * @flags: other constraints relevant to this driver
 ++++ * @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.
      * @bus_lock_spinlock: spinlock for SPI bus locking
      * @bus_lock_mutex: mutex for SPI bus locking
      * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
      * @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().
 ++++ * @spi_flash_read: to support spi-controller hardwares that provide
 ++++ *                  accelerated interface to read from flash devices.
      * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
      * number. Any individual value may be -ENOENT for CS lines that
      * are not GPIOs (driven by the SPI controller itself).
      * @dma_rx: DMA receive channel
      * @dummy_rx: dummy receive buffer for full-duplex devices
      * @dummy_tx: dummy transmit buffer for full-duplex devices
 +++  * @fw_translate_cs: If the boot firmware uses different numbering scheme
 +++  * what Linux expects, this optional hook can be used to translate
 +++  * between the two.
      *
      * Each SPI master controller can communicate with one or more @spi_device
      * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@@@@@ -521,8 -513,6 -519,6 -513,6 -516,6 +527,8 @@@@@@ struct spi_master 
                               struct spi_message *message);
        int (*unprepare_message)(struct spi_master *master,
                                 struct spi_message *message);
 ++++   int (*spi_flash_read)(struct  spi_device *spi,
 ++++                         struct spi_flash_read_message *msg);
     
        /*
         * These hooks are for drivers that use a generic implementation
        /* dummy data for full duplex devices */
        void                    *dummy_rx;
        void                    *dummy_tx;
 +++ 
 +++    int (*fw_translate_cs)(struct spi_master *master, unsigned cs);
     };
     
     static inline void *spi_master_get_devdata(struct spi_master *master)
@@@@@@ -594,6 -582,6 -588,37 -582,6 -587,6 +600,37 @@@@@@ extern void spi_unregister_master(struc
     
     extern struct spi_master *spi_busnum_to_master(u16 busnum);
     
++ ++/*
++ ++ * SPI resource management while processing a SPI message
++ ++ */
++ ++
++ ++/**
++ ++ * struct spi_res - spi resource management structure
++ ++ * @entry:   list entry
++ ++ * @release: release code called prior to freeing this resource
++ ++ * @data:    extra data allocated for the specific use-case
++ ++ *
++ ++ * this is based on ideas from devres, but focused on life-cycle
++ ++ * management during spi_message processing
++ ++ */
++ ++typedef void (*spi_res_release_t)(struct spi_master *master,
++ ++                             struct spi_message *msg,
++ ++                             void *res);
++ ++struct spi_res {
++ ++   struct list_head        entry;
++ ++   spi_res_release_t       release;
++ ++   unsigned long long      data[]; /* guarantee ull alignment */
++ ++};
++ ++
++ ++extern void *spi_res_alloc(struct spi_device *spi,
++ ++                      spi_res_release_t release,
++ ++                      size_t size, gfp_t gfp);
++ ++extern void spi_res_add(struct spi_message *message, void *res);
++ ++extern void spi_res_free(void *res);
++ ++
++ ++extern void spi_res_release(struct spi_master *master,
++ ++                       struct spi_message *message);
++ ++
     /*---------------------------------------------------------------------------*/
     
     /*
@@@@@@ -732,6 -720,6 -757,7 -720,6 -725,6 +769,7 @@@@@@ struct spi_transfer 
      * @status: zero for success, else negative errno
      * @queue: for use by whichever driver currently owns the message
      * @state: for use by whichever driver currently owns the message
++ ++ * @resources: for resource management when the spi message is processed
      *
      * A @spi_message is used to execute an atomic sequence of data transfers,
      * each represented by a struct spi_transfer.  The sequence is "atomic"
@@@@@@ -778,11 -766,11 -804,15 -766,11 -771,11 +816,15 @@@@@@ struct spi_message 
         */
        struct list_head        queue;
        void                    *state;
++ ++
++ ++   /* list of spi_res reources when the spi message is processed */
++ ++   struct list_head        resources;
     };
     
     static inline void spi_message_init_no_memset(struct spi_message *m)
     {
        INIT_LIST_HEAD(&m->transfers);
++ ++   INIT_LIST_HEAD(&m->resources);
     }
     
     static inline void spi_message_init(struct spi_message *m)
@@@@@@ -866,6 -854,6 -896,60 -854,6 -859,6 +908,60 @@@@@@ spi_max_transfer_size(struct spi_devic
     
     /*---------------------------------------------------------------------------*/
     
++ ++/* SPI transfer replacement methods which make use of spi_res */
++ ++
++ ++struct spi_replaced_transfers;
++ ++typedef void (*spi_replaced_release_t)(struct spi_master *master,
++ ++                                  struct spi_message *msg,
++ ++                                  struct spi_replaced_transfers *res);
++ ++/**
++ ++ * struct spi_replaced_transfers - structure describing the spi_transfer
++ ++ *                                 replacements that have occurred
++ ++ *                                 so that they can get reverted
++ ++ * @release:            some extra release code to get executed prior to
++ ++ *                      relasing this structure
++ ++ * @extradata:          pointer to some extra data if requested or NULL
++ ++ * @replaced_transfers: transfers that have been replaced and which need
++ ++ *                      to get restored
++ ++ * @replaced_after:     the transfer after which the @replaced_transfers
++ ++ *                      are to get re-inserted
++ ++ * @inserted:           number of transfers inserted
++ ++ * @inserted_transfers: array of spi_transfers of array-size @inserted,
++ ++ *                      that have been replacing replaced_transfers
++ ++ *
++ ++ * note: that @extradata will point to @inserted_transfers[@inserted]
++ ++ * if some extra allocation is requested, so alignment will be the same
++ ++ * as for spi_transfers
++ ++ */
++ ++struct spi_replaced_transfers {
++ ++   spi_replaced_release_t release;
++ ++   void *extradata;
++ ++   struct list_head replaced_transfers;
++ ++   struct list_head *replaced_after;
++ ++   size_t inserted;
++ ++   struct spi_transfer inserted_transfers[];
++ ++};
++ ++
++ ++extern struct spi_replaced_transfers *spi_replace_transfers(
++ ++   struct spi_message *msg,
++ ++   struct spi_transfer *xfer_first,
++ ++   size_t remove,
++ ++   size_t insert,
++ ++   spi_replaced_release_t release,
++ ++   size_t extradatasize,
++ ++   gfp_t gfp);
++ ++
++ ++/*---------------------------------------------------------------------------*/
++ ++
++ ++/* SPI transfer transformation methods */
++ ++
++ ++extern int spi_split_transfers_maxsize(struct spi_master *master,
++ ++                                  struct spi_message *msg,
++ ++                                  size_t maxsize,
++ ++                                  gfp_t gfp);
++ ++
++ ++/*---------------------------------------------------------------------------*/
++ ++
     /* All these synchronous SPI transfer routines are utilities layered
      * over the core async transfer primitive.  Here, "synchronous" means
      * they will sleep uninterruptibly until the async transfer completes.
@@@@@@ -1031,42 -1019,6 -1115,6 -1019,6 -1024,6 +1127,42 @@@@@@ static inline ssize_t spi_w8r16be(struc
        return be16_to_cpu(result);
     }
     
 ++++/**
 ++++ * struct spi_flash_read_message - flash specific information for
 ++++ * spi-masters that provide accelerated flash read interfaces
 ++++ * @buf: buffer to read data
 ++++ * @from: offset within the flash from where data is to be read
 ++++ * @len: length of data to be read
 ++++ * @retlen: actual length of data read
 ++++ * @read_opcode: read_opcode to be used to communicate with flash
 ++++ * @addr_width: number of address bytes
 ++++ * @dummy_bytes: number of dummy bytes
 ++++ * @opcode_nbits: number of lines to send opcode
 ++++ * @addr_nbits: number of lines to send address
 ++++ * @data_nbits: number of lines for data
 ++++ */
 ++++struct spi_flash_read_message {
 ++++   void *buf;
 ++++   loff_t from;
 ++++   size_t len;
 ++++   size_t retlen;
 ++++   u8 read_opcode;
 ++++   u8 addr_width;
 ++++   u8 dummy_bytes;
 ++++   u8 opcode_nbits;
 ++++   u8 addr_nbits;
 ++++   u8 data_nbits;
 ++++};
 ++++
 ++++/* SPI core interface for flash read support */
 ++++static inline bool spi_flash_read_supported(struct spi_device *spi)
 ++++{
 ++++   return spi->master->spi_flash_read ? true : false;
 ++++}
 ++++
 ++++int spi_flash_read(struct spi_device *spi,
 ++++              struct spi_flash_read_message *msg);
 ++++
     /*---------------------------------------------------------------------------*/
     
     /*