Merge tag 'staging-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 May 2019 20:31:29 +0000 (13:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 May 2019 20:31:29 +0000 (13:31 -0700)
Pull staging / IIO driver updates from Greg KH:
 "Here is the big staging and iio driver update for 5.2-rc1.

  Lots of tiny fixes all over the staging and IIO driver trees here,
  along with some new IIO drivers.

  The "counter" subsystem was added in here as well, as it is needed by
  the IIO drivers and subsystem.

  Also we ended up deleting two drivers, making this pull request remove
  a few hundred thousand lines of code, always a nice thing to see. Both
  of the drivers removed have been replaced with "real" drivers in their
  various subsystem directories, and they will be coming to you from
  those locations during this merge window.

  There are some core vt/selection changes in here, that was due to some
  cleanups needed for the speakup fixes. Those have all been acked by
  the various subsystem maintainers (i.e. me), so those are ok.

  We also added a few new drivers, for some odd hardware, giving new
  developers plenty to work on with basic coding style cleanups to come
  in the near future.

  Other than that, nothing unusual here.

  All of these have been in linux-next for a while with no reported
  issues, other than an odd gcc warning for one of the new drivers that
  should be fixed up soon"

[ I fixed up the warning myself  - Linus ]

* tag 'staging-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (663 commits)
  staging: kpc2000: kpc_spi: Fix build error for {read,write}q
  Staging: rtl8192e: Remove extra space before break statement
  Staging: rtl8192u: ieee80211: Fix if-else indentation warning
  Staging: rtl8192u: ieee80211: Fix indentation errors by removing extra spaces
  staging: most: cdev: fix chrdev_region leak in mod_exit
  staging: wlan-ng: Fix improper SPDX comment style
  staging: rtl8192u: ieee80211: Resolve ERROR reported by checkpatch
  staging: vc04_services: bcm2835-camera: Compress two lines into one line
  staging: rtl8723bs: core: Use !x in place of NULL comparison.
  staging: rtl8723bs: core: Prefer using the BIT Macro.
  staging: fieldbus: anybus-s: fix wait_for_completion_timeout return handling
  staging: kpc2000: fix up build problems with readq()
  staging: rtlwifi: move remaining phydm .h files
  staging: rtlwifi: strip down phydm .h files
  staging: rtlwifi: delete the staging driver
  staging: fieldbus: anybus-s: rename bus id field to avoid confusion
  staging: fieldbus: anybus-s: keep device bus id in bus endianness
  Staging: sm750fb: Change *array into *const array
  staging: rtl8192u: ieee80211: Fix spelling mistake
  staging: rtl8192u: ieee80211: Replace bit shifting with BIT macro
  ...

14 files changed:
1  2 
Documentation/driver-api/index.rst
MAINTAINERS
drivers/iio/Kconfig
drivers/spi/spi-mt7621.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/comedi/drivers/ni_mio_common.c
drivers/staging/comedi/drivers/ni_tio.c
drivers/staging/erofs/super.c
drivers/staging/kpc2000/kpc_spi/spi_driver.c
drivers/staging/ks7010/ks_hostif.c
drivers/staging/pi433/pi433_if.c
drivers/staging/rtl8192e/rtllib_crypt_tkip.c
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c

index aa87075c78460a1c016d2621be87cb6426056e39,201247b7c1e8ae22c9124874bf654b60bb9b5538..d26308af60360b30f086a684affd0945e65a26f0
@@@ -56,7 -56,7 +56,8 @@@ available subsections can be seen below
     slimbus
     soundwire/index
     fpga/index
 +   acpi/index
+    generic-counter
  
  .. only::  subproject and html
  
diff --cc MAINTAINERS
Simple merge
Simple merge
index ae836114ee3d2786d48654796fc1cf3d32defdab,0000000000000000000000000000000000000000..ff85982464d2e9623a8d5e7109473ebaea01dd88
mode 100644,000000..100644
--- /dev/null
@@@ -1,421 -1,0 +1,416 @@@
-       struct mt7621_spi_ops   *ops;
 +// SPDX-License-Identifier: GPL-2.0
 +//
 +// spi-mt7621.c -- MediaTek MT7621 SPI controller driver
 +//
 +// Copyright (C) 2011 Sergiy <piratfm@gmail.com>
 +// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
 +// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
 +//
 +// Some parts are based on spi-orion.c:
 +//   Author: Shadi Ammouri <shadi@marvell.com>
 +//   Copyright (C) 2007-2008 Marvell Ltd.
 +
 +#include <linux/clk.h>
 +#include <linux/delay.h>
 +#include <linux/io.h>
 +#include <linux/module.h>
 +#include <linux/of_device.h>
 +#include <linux/reset.h>
 +#include <linux/spi/spi.h>
 +
 +#define DRIVER_NAME           "spi-mt7621"
 +
 +/* in usec */
 +#define RALINK_SPI_WAIT_MAX_LOOP 2000
 +
 +/* SPISTAT register bit field */
 +#define SPISTAT_BUSY          BIT(0)
 +
 +#define MT7621_SPI_TRANS      0x00
 +#define SPITRANS_BUSY         BIT(16)
 +
 +#define MT7621_SPI_OPCODE     0x04
 +#define MT7621_SPI_DATA0      0x08
 +#define MT7621_SPI_DATA4      0x18
 +#define SPI_CTL_TX_RX_CNT_MASK        0xff
 +#define SPI_CTL_START         BIT(8)
 +
 +#define MT7621_SPI_MASTER     0x28
 +#define MASTER_MORE_BUFMODE   BIT(2)
 +#define MASTER_FULL_DUPLEX    BIT(10)
 +#define MASTER_RS_CLK_SEL     GENMASK(27, 16)
 +#define MASTER_RS_CLK_SEL_SHIFT       16
 +#define MASTER_RS_SLAVE_SEL   GENMASK(31, 29)
 +
 +#define MT7621_SPI_MOREBUF    0x2c
 +#define MT7621_SPI_POLAR      0x38
 +#define MT7621_SPI_SPACE      0x3c
 +
 +#define MT7621_CPHA           BIT(5)
 +#define MT7621_CPOL           BIT(4)
 +#define MT7621_LSB_FIRST      BIT(3)
 +
 +struct mt7621_spi {
 +      struct spi_controller   *master;
 +      void __iomem            *base;
 +      unsigned int            sys_freq;
 +      unsigned int            speed;
 +      struct clk              *clk;
 +      int                     pending_write;
-               spi->max_speed_hz = (rs->sys_freq / 2);
 +};
 +
 +static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
 +{
 +      return spi_controller_get_devdata(spi->master);
 +}
 +
 +static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg)
 +{
 +      return ioread32(rs->base + reg);
 +}
 +
 +static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val)
 +{
 +      iowrite32(val, rs->base + reg);
 +}
 +
 +static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
 +{
 +      struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
 +      int cs = spi->chip_select;
 +      u32 polar = 0;
 +      u32 master;
 +
 +      /*
 +       * Select SPI device 7, enable "more buffer mode" and disable
 +       * full-duplex (only half-duplex really works on this chip
 +       * reliably)
 +       */
 +      master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
 +      master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE;
 +      master &= ~MASTER_FULL_DUPLEX;
 +      mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
 +
 +      rs->pending_write = 0;
 +
 +      if (enable)
 +              polar = BIT(cs);
 +      mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
 +}
 +
 +static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed)
 +{
 +      struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
 +      u32 rate;
 +      u32 reg;
 +
 +      dev_dbg(&spi->dev, "speed:%u\n", speed);
 +
 +      rate = DIV_ROUND_UP(rs->sys_freq, speed);
 +      dev_dbg(&spi->dev, "rate-1:%u\n", rate);
 +
 +      if (rate > 4097)
 +              return -EINVAL;
 +
 +      if (rate < 2)
 +              rate = 2;
 +
 +      reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
 +      reg &= ~MASTER_RS_CLK_SEL;
 +      reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT;
 +      rs->speed = speed;
 +
 +      reg &= ~MT7621_LSB_FIRST;
 +      if (spi->mode & SPI_LSB_FIRST)
 +              reg |= MT7621_LSB_FIRST;
 +
 +      /*
 +       * This SPI controller seems to be tested on SPI flash only and some
 +       * bits are swizzled under other SPI modes probably due to incorrect
 +       * wiring inside the silicon. Only mode 0 works correctly.
 +       */
 +      reg &= ~(MT7621_CPHA | MT7621_CPOL);
 +
 +      mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
 +
 +      return 0;
 +}
 +
 +static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
 +{
 +      int i;
 +
 +      for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
 +              u32 status;
 +
 +              status = mt7621_spi_read(rs, MT7621_SPI_TRANS);
 +              if ((status & SPITRANS_BUSY) == 0)
 +                      return 0;
 +              cpu_relax();
 +              udelay(1);
 +      }
 +
 +      return -ETIMEDOUT;
 +}
 +
 +static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
 +                                      int rx_len, u8 *buf)
 +{
 +      int tx_len;
 +
 +      /*
 +       * Combine with any pending write, and perform one or more half-duplex
 +       * transactions reading 'len' bytes. Data to be written is already in
 +       * MT7621_SPI_DATA.
 +       */
 +      tx_len = rs->pending_write;
 +      rs->pending_write = 0;
 +
 +      while (rx_len || tx_len) {
 +              int i;
 +              u32 val = (min(tx_len, 4) * 8) << 24;
 +              int rx = min(rx_len, 32);
 +
 +              if (tx_len > 4)
 +                      val |= (tx_len - 4) * 8;
 +              val |= (rx * 8) << 12;
 +              mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
 +
 +              tx_len = 0;
 +
 +              val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
 +              val |= SPI_CTL_START;
 +              mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
 +
 +              mt7621_spi_wait_till_ready(rs);
 +
 +              for (i = 0; i < rx; i++) {
 +                      if ((i % 4) == 0)
 +                              val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
 +                      *buf++ = val & 0xff;
 +                      val >>= 8;
 +              }
 +
 +              rx_len -= i;
 +      }
 +}
 +
 +static inline void mt7621_spi_flush(struct mt7621_spi *rs)
 +{
 +      mt7621_spi_read_half_duplex(rs, 0, NULL);
 +}
 +
 +static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs,
 +                                       int tx_len, const u8 *buf)
 +{
 +      int len = rs->pending_write;
 +      int val = 0;
 +
 +      if (len & 3) {
 +              val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3));
 +              if (len < 4) {
 +                      val <<= (4 - len) * 8;
 +                      val = swab32(val);
 +              }
 +      }
 +
 +      while (tx_len > 0) {
 +              if (len >= 36) {
 +                      rs->pending_write = len;
 +                      mt7621_spi_flush(rs);
 +                      len = 0;
 +              }
 +
 +              val |= *buf++ << (8 * (len & 3));
 +              len++;
 +              if ((len & 3) == 0) {
 +                      if (len == 4)
 +                              /* The byte-order of the opcode is weird! */
 +                              val = swab32(val);
 +                      mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val);
 +                      val = 0;
 +              }
 +              tx_len -= 1;
 +      }
 +
 +      if (len & 3) {
 +              if (len < 4) {
 +                      val = swab32(val);
 +                      val >>= (4 - len) * 8;
 +              }
 +              mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val);
 +      }
 +
 +      rs->pending_write = len;
 +}
 +
 +static int mt7621_spi_transfer_one_message(struct spi_controller *master,
 +                                         struct spi_message *m)
 +{
 +      struct mt7621_spi *rs = spi_controller_get_devdata(master);
 +      struct spi_device *spi = m->spi;
 +      unsigned int speed = spi->max_speed_hz;
 +      struct spi_transfer *t = NULL;
 +      int status = 0;
 +
 +      mt7621_spi_wait_till_ready(rs);
 +
 +      list_for_each_entry(t, &m->transfers, transfer_list)
 +              if (t->speed_hz < speed)
 +                      speed = t->speed_hz;
 +
 +      if (mt7621_spi_prepare(spi, speed)) {
 +              status = -EIO;
 +              goto msg_done;
 +      }
 +
 +      /* Assert CS */
 +      mt7621_spi_set_cs(spi, 1);
 +
 +      m->actual_length = 0;
 +      list_for_each_entry(t, &m->transfers, transfer_list) {
 +              if ((t->rx_buf) && (t->tx_buf)) {
 +                      /*
 +                       * This controller will shift some extra data out
 +                       * of spi_opcode if (mosi_bit_cnt > 0) &&
 +                       * (cmd_bit_cnt == 0). So the claimed full-duplex
 +                       * support is broken since we have no way to read
 +                       * the MISO value during that bit.
 +                       */
 +                      status = -EIO;
 +                      goto msg_done;
 +              } else if (t->rx_buf) {
 +                      mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
 +              } else if (t->tx_buf) {
 +                      mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
 +              }
 +              m->actual_length += t->len;
 +      }
 +
 +      /* Flush data and deassert CS */
 +      mt7621_spi_flush(rs);
 +      mt7621_spi_set_cs(spi, 0);
 +
 +msg_done:
 +      m->status = status;
 +      spi_finalize_current_message(master);
 +
 +      return 0;
 +}
 +
 +static int mt7621_spi_setup(struct spi_device *spi)
 +{
 +      struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
 +
 +      if ((spi->max_speed_hz == 0) ||
 +          (spi->max_speed_hz > (rs->sys_freq / 2)))
-       struct mt7621_spi_ops *ops;
++              spi->max_speed_hz = rs->sys_freq / 2;
 +
 +      if (spi->max_speed_hz < (rs->sys_freq / 4097)) {
 +              dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
 +                      spi->max_speed_hz);
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +
 +static const struct of_device_id mt7621_spi_match[] = {
 +      { .compatible = "ralink,mt7621-spi" },
 +      {},
 +};
 +MODULE_DEVICE_TABLE(of, mt7621_spi_match);
 +
 +static int mt7621_spi_probe(struct platform_device *pdev)
 +{
 +      const struct of_device_id *match;
 +      struct spi_controller *master;
 +      struct mt7621_spi *rs;
 +      void __iomem *base;
 +      struct resource *r;
 +      int status = 0;
 +      struct clk *clk;
-       ops = (struct mt7621_spi_ops *)match->data;
 +      int ret;
 +
 +      match = of_match_device(mt7621_spi_match, &pdev->dev);
 +      if (!match)
 +              return -EINVAL;
-       rs->ops = ops;
 +
 +      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      base = devm_ioremap_resource(&pdev->dev, r);
 +      if (IS_ERR(base))
 +              return PTR_ERR(base);
 +
 +      clk = devm_clk_get(&pdev->dev, NULL);
 +      if (IS_ERR(clk)) {
 +              dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
 +                      status);
 +              return PTR_ERR(clk);
 +      }
 +
 +      status = clk_prepare_enable(clk);
 +      if (status)
 +              return status;
 +
 +      master = spi_alloc_master(&pdev->dev, sizeof(*rs));
 +      if (!master) {
 +              dev_info(&pdev->dev, "master allocation failed\n");
 +              return -ENOMEM;
 +      }
 +
 +      master->mode_bits = SPI_LSB_FIRST;
 +      master->flags = SPI_CONTROLLER_HALF_DUPLEX;
 +      master->setup = mt7621_spi_setup;
 +      master->transfer_one_message = mt7621_spi_transfer_one_message;
 +      master->bits_per_word_mask = SPI_BPW_MASK(8);
 +      master->dev.of_node = pdev->dev.of_node;
 +      master->num_chipselect = 2;
 +
 +      dev_set_drvdata(&pdev->dev, master);
 +
 +      rs = spi_controller_get_devdata(master);
 +      rs->base = base;
 +      rs->clk = clk;
 +      rs->master = master;
 +      rs->sys_freq = clk_get_rate(rs->clk);
 +      rs->pending_write = 0;
 +      dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
 +
 +      ret = device_reset(&pdev->dev);
 +      if (ret) {
 +              dev_err(&pdev->dev, "SPI reset failed!\n");
 +              return ret;
 +      }
 +
 +      return devm_spi_register_controller(&pdev->dev, master);
 +}
 +
 +static int mt7621_spi_remove(struct platform_device *pdev)
 +{
 +      struct spi_controller *master;
 +      struct mt7621_spi *rs;
 +
 +      master = dev_get_drvdata(&pdev->dev);
 +      rs = spi_controller_get_devdata(master);
 +
 +      clk_disable_unprepare(rs->clk);
 +
 +      return 0;
 +}
 +
 +MODULE_ALIAS("platform:" DRIVER_NAME);
 +
 +static struct platform_driver mt7621_spi_driver = {
 +      .driver = {
 +              .name = DRIVER_NAME,
 +              .of_match_table = mt7621_spi_match,
 +      },
 +      .probe = mt7621_spi_probe,
 +      .remove = mt7621_spi_remove,
 +};
 +
 +module_platform_driver(mt7621_spi_driver);
 +
 +MODULE_DESCRIPTION("MT7621 SPI driver");
 +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
 +MODULE_LICENSE("GPL");
Simple merge
index 19c0a25ff98b5ade77755d59066ff2f3b6486b46,7da52e87c9a5531d5f224f6b4e968a3acea89cad..dc3da72b3ff9b1d7af07531af40c7420968721cf
@@@ -43,9 -42,9 +42,8 @@@ obj-$(CONFIG_PI433)           += pi433
  obj-$(CONFIG_PCI_MT7621)      += mt7621-pci/
  obj-$(CONFIG_PCI_MT7621_PHY)  += mt7621-pci-phy/
  obj-$(CONFIG_PINCTRL_RT2880)  += mt7621-pinctrl/
 -obj-$(CONFIG_SPI_MT7621)      += mt7621-spi/
  obj-$(CONFIG_SOC_MT7621)      += mt7621-dma/
  obj-$(CONFIG_DMA_RALINK)      += ralink-gdma/
- obj-$(CONFIG_MTK_MMC)         += mt7621-mmc/
  obj-$(CONFIG_SOC_MT7621)      += mt7621-dts/
  obj-$(CONFIG_STAGING_GASKET_FRAMEWORK)        += gasket/
  obj-$(CONFIG_XIL_AXIS_FIFO)   += axis-fifo/
Simple merge
index 0000000000000000000000000000000000000000,3ace4e5c12847ef270f6a279dd7ff8392688bd6b..86df16547a92ccb6b492ec765acace194f5ea84a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,507 +1,507 @@@
 -        unsigned char pha       : 1; /* spim_clk Phase      */
 -        unsigned char pol       : 1; /* spim_clk Polarity   */
 -        unsigned char epol      : 1; /* spim_csx Polarity   */
 -        unsigned char dpe       : 1; /* Transmission Enable */
 -        unsigned char wl        : 5; /* Word Length         */
 -        unsigned char           : 3;
 -        unsigned char trm       : 2; /* TxRx Mode           */
 -        unsigned char cs        : 4; /* Chip Select         */
 -        unsigned char wcnt      : 7; /* Word Count          */
 -        unsigned char ffen      : 1; /* FIFO Enable         */
 -        unsigned char spi_en    : 1; /* SPI Enable          */
 -        unsigned char           : 5;
+ // SPDX-License-Identifier: GPL-2.0+
+ /*
+  * KP2000 SPI controller driver
+  *
+  * Copyright (C) 2014-2018 Daktronics
+  * Author: Matt Sickler <matt.sickler@daktronics.com>
+  * Very loosely based on spi-omap2-mcspi.c
+  */
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/io-64-nonatomic-lo-hi.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
+ #include <linux/delay.h>
+ #include <linux/platform_device.h>
+ #include <linux/err.h>
+ #include <linux/clk.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/gcd.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/partitions.h>
+ #include "../kpc.h"
+ #include "spi_parts.h"
+ /***************
+  * SPI Defines *
+  ***************/
+ #define KP_SPI_REG_CONFIG 0x0 /* 0x00 */
+ #define KP_SPI_REG_STATUS 0x1 /* 0x08 */
+ #define KP_SPI_REG_FFCTRL 0x2 /* 0x10 */
+ #define KP_SPI_REG_TXDATA 0x3 /* 0x18 */
+ #define KP_SPI_REG_RXDATA 0x4 /* 0x20 */
+ #define KP_SPI_CLK           48000000
+ #define KP_SPI_MAX_FIFODEPTH 64
+ #define KP_SPI_MAX_FIFOWCNT  0xFFFF
+ #define KP_SPI_REG_CONFIG_TRM_TXRX 0
+ #define KP_SPI_REG_CONFIG_TRM_RX   1
+ #define KP_SPI_REG_CONFIG_TRM_TX   2
+ #define KP_SPI_REG_STATUS_RXS   0x01
+ #define KP_SPI_REG_STATUS_TXS   0x02
+ #define KP_SPI_REG_STATUS_EOT   0x04
+ #define KP_SPI_REG_STATUS_TXFFE 0x10
+ #define KP_SPI_REG_STATUS_TXFFF 0x20
+ #define KP_SPI_REG_STATUS_RXFFE 0x40
+ #define KP_SPI_REG_STATUS_RXFFF 0x80
+ /******************
+  * SPI Structures *
+  ******************/
+ struct kp_spi {
+       struct spi_master  *master;
+       u64 __iomem        *base;
+       unsigned long       phys;
+       struct device      *dev;
+       int                 fifo_depth;
+       unsigned int        pin_dir:1;
+ };
+ struct kp_spi_controller_state {
+     void __iomem   *base;
+     unsigned long   phys;
+     unsigned char   chip_select;
+     int             word_len;
+     s64             conf_cache;
+ };
+ union kp_spi_config {
+     /* use this to access individual elements */
+     struct __attribute__((packed)) spi_config_bitfield {
 -        unsigned char rx    :  1; /* Rx Status       */
 -        unsigned char tx    :  1; /* Tx Status       */
 -        unsigned char eo    :  1; /* End of Transfer */
 -        unsigned char       :  1;
 -        unsigned char txffe :  1; /* Tx FIFO Empty   */
 -        unsigned char txfff :  1; /* Tx FIFO Full    */
 -        unsigned char rxffe :  1; /* Rx FIFO Empty   */
 -        unsigned char rxfff :  1; /* Rx FIFO Full    */
 -        unsigned int        : 24;
++        unsigned int pha       : 1; /* spim_clk Phase      */
++        unsigned int pol       : 1; /* spim_clk Polarity   */
++        unsigned int epol      : 1; /* spim_csx Polarity   */
++        unsigned int dpe       : 1; /* Transmission Enable */
++        unsigned int wl        : 5; /* Word Length         */
++        unsigned int           : 3;
++        unsigned int trm       : 2; /* TxRx Mode           */
++        unsigned int cs        : 4; /* Chip Select         */
++        unsigned int wcnt      : 7; /* Word Count          */
++        unsigned int ffen      : 1; /* FIFO Enable         */
++        unsigned int spi_en    : 1; /* SPI Enable          */
++        unsigned int           : 5;
+     } bitfield;
+     /* use this to grab the whole register */
+     u32 reg;
+ };
+ union kp_spi_status {
+     struct __attribute__((packed)) spi_status_bitfield {
 -        unsigned char ffstart :  1; /* FIFO Start */
 -        unsigned int          : 31;
++        unsigned int rx    :  1; /* Rx Status       */
++        unsigned int tx    :  1; /* Tx Status       */
++        unsigned int eo    :  1; /* End of Transfer */
++        unsigned int       :  1;
++        unsigned int txffe :  1; /* Tx FIFO Empty   */
++        unsigned int txfff :  1; /* Tx FIFO Full    */
++        unsigned int rxffe :  1; /* Rx FIFO Empty   */
++        unsigned int rxfff :  1; /* Rx FIFO Full    */
++        unsigned int       : 24;
+     } bitfield;
+     u32 reg;
+ };
+ union kp_spi_ffctrl {
+     struct __attribute__((packed)) spi_ffctrl_bitfield {
++        unsigned int ffstart :  1; /* FIFO Start */
++        unsigned int         : 31;
+     } bitfield;
+     u32 reg;
+ };
+ /***************
+  * SPI Helpers *
+  ***************/
+ static inline int
+ kp_spi_bytes_per_word(int word_len)
+ {
+     if (word_len <= 8){
+         return 1;
+     }
+     else if (word_len <= 16) {
+         return 2;
+     }
+     else { /* word_len <= 32 */
+         return 4;
+     }
+ }
+ static inline u64
+ kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx)
+ {
+     u64 __iomem *addr = cs->base;
+     u64 val;
+     addr += idx;
+     if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0)){
+         return cs->conf_cache;
+     }
+     val = readq((void*)addr);
+     return val;
+ }
+ static inline void
+ kp_spi_write_reg(struct kp_spi_controller_state *cs, int idx, u64 val)
+ {
+     u64 __iomem *addr = cs->base;
+     addr += idx;
+     writeq(val, (void*)addr);
+     if (idx == KP_SPI_REG_CONFIG)
+         cs->conf_cache = val;
+ }
+ static int
+ kp_spi_wait_for_reg_bit(struct kp_spi_controller_state *cs, int idx, unsigned long bit)
+ {
+     unsigned long timeout;
+     timeout = jiffies + msecs_to_jiffies(1000);
+     while (!(kp_spi_read_reg(cs, idx) & bit)) {
+         if (time_after(jiffies, timeout)) {
+             if (!(kp_spi_read_reg(cs, idx) & bit)) {
+                 return -ETIMEDOUT;
+             } else {
+                 return 0;
+             }
+         }
+         cpu_relax();
+     }
+     return 0;
+ }
+ static unsigned
+ kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer)
+ {
+     struct kp_spi_controller_state *cs = spidev->controller_state;
+     unsigned int count = transfer->len;
+     unsigned int c = count;
+     
+     int i;
+     u8 *rx       = transfer->rx_buf;
+     const u8 *tx = transfer->tx_buf;
+     int processed = 0;
+     
+     if (tx) {
+         for (i = 0 ; i < c ; i++) {
+             char val = *tx++;
+             
+             if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_TXS) < 0) {
+                 goto out;
+             }
+             
+             kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val);
+             processed++;
+         }
+     }
+     else if(rx) {
+         for (i = 0 ; i < c ; i++) {
+             char test=0;
+             
+             kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, 0x00);
+             
+             if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_RXS) < 0) {
+                 goto out;
+             }
+             
+             test = kp_spi_read_reg(cs, KP_SPI_REG_RXDATA);
+             *rx++ = test;
+             processed++;
+         }
+     }
+     
+     if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
+         //TODO: Figure out how to abort transaction??  This has never happened in practice though...
+     }
+     
+  out:
+     return processed;
+ }
+ /*****************
+  * SPI Functions *
+  *****************/
+ static int
+ kp_spi_setup(struct spi_device *spidev)
+ {
+     union kp_spi_config sc;
+     struct kp_spi *kpspi = spi_master_get_devdata(spidev->master);
+     struct kp_spi_controller_state *cs;
+     
+     /* setup controller state */
+     cs = spidev->controller_state;
+     if (!cs) {
+         cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+         if(!cs) {
+             return -ENOMEM;
+         }
+         cs->base = kpspi->base;
+         cs->phys = kpspi->phys;
+         cs->chip_select = spidev->chip_select;
+         cs->word_len = spidev->bits_per_word;
+         cs->conf_cache = -1;
+         spidev->controller_state = cs;
+     }
+     
+     /* set config register */
+     sc.bitfield.wl = spidev->bits_per_word - 1;
+     sc.bitfield.cs = spidev->chip_select;
+     sc.bitfield.spi_en = 0;
+     sc.bitfield.trm = 0;
+     sc.bitfield.ffen = 0;
+     kp_spi_write_reg(spidev->controller_state, KP_SPI_REG_CONFIG, sc.reg);
+     return 0;
+ }
+ static int
+ kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
+ {
+     struct kp_spi_controller_state *cs;
+     struct spi_device   *spidev;
+     struct kp_spi       *kpspi;
+     struct spi_transfer *transfer;
+     union kp_spi_config sc;
+     int status = 0;
+     
+     spidev = m->spi;
+     kpspi = spi_master_get_devdata(master);
+     m->actual_length = 0;
+     m->status = 0;
+     
+     cs = spidev->controller_state;
+     
+     /* reject invalid messages and transfers */
+     if (list_empty(&m->transfers)) {
+         return -EINVAL;
+     }
+     
+     /* validate input */
+     list_for_each_entry(transfer, &m->transfers, transfer_list) {
+         const void *tx_buf = transfer->tx_buf;
+         void       *rx_buf = transfer->rx_buf;
+         unsigned    len = transfer->len;
+         
+         if (transfer->speed_hz > KP_SPI_CLK || (len && !(rx_buf || tx_buf))) {
+             dev_dbg(kpspi->dev, "  transfer: %d Hz, %d %s%s, %d bpw\n",
+                     transfer->speed_hz,
+                     len,
+                     tx_buf ? "tx" : "",
+                     rx_buf ? "rx" : "",
+                     transfer->bits_per_word);
+             dev_dbg(kpspi->dev, "  transfer -EINVAL\n");
+             return -EINVAL;
+         }
+         if (transfer->speed_hz && (transfer->speed_hz < (KP_SPI_CLK >> 15))) {
+             dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n",
+                     transfer->speed_hz,
+                     KP_SPI_CLK >> 15);
+             dev_dbg(kpspi->dev, "  speed_hz -EINVAL\n");
+             return -EINVAL;
+         }
+     }
+     
+     /* assert chip select to start the sequence*/
+     sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+     sc.bitfield.spi_en = 1;
+     kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+     
+     /* work */
+     if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
+         dev_info(kpspi->dev, "EOT timed out\n");
+         goto out;
+     }
+     
+     /* do the transfers for this message */
+     list_for_each_entry(transfer, &m->transfers, transfer_list) {
+         if (transfer->tx_buf == NULL && transfer->rx_buf == NULL && transfer->len) {
+             status = -EINVAL;
+             break;
+         }
+         
+         /* transfer */
+         if (transfer->len) {
+             unsigned int word_len = spidev->bits_per_word;
+             unsigned count;
+             
+             /* set up the transfer... */
+             sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+             
+             /* ...direction */
+             if (transfer->tx_buf) {
+                 sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_TX;
+             }
+             else if (transfer->rx_buf) {
+                 sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_RX;
+             }
+             
+             /* ...word length */
+             if (transfer->bits_per_word) {
+                 word_len = transfer->bits_per_word;
+             }
+             cs->word_len = word_len;
+             sc.bitfield.wl = word_len-1;
+             
+             /* ...chip select */
+             sc.bitfield.cs = spidev->chip_select;
+             
+             /* ...and write the new settings */
+             kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+             
+             /* do the transfer */
+             count = kp_spi_txrx_pio(spidev, transfer);
+             m->actual_length += count;
+             
+             if (count != transfer->len) {
+                 status = -EIO;
+                 break;
+             }
+         }
+         
+         if (transfer->delay_usecs) {
+             udelay(transfer->delay_usecs);
+         }
+     }
+     
+     /* de-assert chip select to end the sequence */
+     sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+     sc.bitfield.spi_en = 0;
+     kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+     
+  out:
+     /* done work */
+     spi_finalize_current_message(master);
+     return 0;
+ }
+ static void
+ kp_spi_cleanup(struct spi_device *spidev)
+ {
+     struct kp_spi_controller_state *cs = spidev->controller_state;
+     if (cs) {
+         kfree(cs);
+     }
+ }
+ /******************
+  * Probe / Remove *
+  ******************/
+ static int
+ kp_spi_probe(struct platform_device *pldev)
+ {
+     struct kpc_core_device_platdata *drvdata;
+     struct spi_master *master;
+     struct kp_spi *kpspi;
+     struct resource *r;
+     int status = 0;
+     int i;
+     drvdata = pldev->dev.platform_data;
+     if (!drvdata){
+         dev_err(&pldev->dev, "kp_spi_probe: platform_data is NULL!\n");
+         return -ENODEV;
+     }
+     
+     master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
+     if (master == NULL) {
+         dev_err(&pldev->dev, "kp_spi_probe: master allocation failed\n");
+         return -ENOMEM;
+     }
+     
+     /* set up the spi functions */
+     master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+     master->bits_per_word_mask = (unsigned int)SPI_BPW_RANGE_MASK(4, 32);
+     master->setup = kp_spi_setup;
+     master->transfer_one_message = kp_spi_transfer_one_message;
+     master->cleanup = kp_spi_cleanup;
+     
+     platform_set_drvdata(pldev, master);
+     
+     kpspi = spi_master_get_devdata(master);
+     kpspi->master = master;
+     kpspi->dev = &pldev->dev;
+     
+     master->num_chipselect = 4;
+     if (pldev->id != -1) {
+         master->bus_num = pldev->id;
+     }
+     kpspi->pin_dir = 0;
+     
+     r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+     if (r == NULL) {
+         dev_err(&pldev->dev, "kp_spi_probe: Unable to get platform resources\n");
+         status = -ENODEV;
+         goto free_master;
+     }
+     
+     kpspi->phys = (unsigned long)ioremap_nocache(r->start, resource_size(r));
+     kpspi->base = (u64 __iomem *)kpspi->phys;
+     
+     status = spi_register_master(master);
+     if (status < 0) {
+         dev_err(&pldev->dev, "Unable to register SPI device\n");
+         goto free_master;
+     }
+     
+     /* register the slave boards */
+     #define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \
+         for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \
+             spi_new_device(master, &(table[i])); \
+         }
+     
+     switch ((drvdata->card_id & 0xFFFF0000) >> 16){
+         case PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0:
+             NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(p2kr0_board_info);
+             break;
+         default:
+             dev_err(&pldev->dev, "Unknown hardware, cant know what partition table to use!\n");
+             goto free_master;
+             break;
+     }
+     
+     return status;
+  free_master:
+     spi_master_put(master);
+     return status;
+ }
+ static int
+ kp_spi_remove(struct platform_device *pldev)
+ {
+     struct spi_master * master = platform_get_drvdata(pldev);
+     spi_unregister_master(master);
+     return 0;
+ }
+ static struct platform_driver kp_spi_driver = {
+     .driver = {
+         .name =     KP_DRIVER_NAME_SPI,
+     },
+     .probe =    kp_spi_probe,
+     .remove =   kp_spi_remove,
+ };
+ module_platform_driver(kp_spi_driver);
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS("platform:kp_spi");
Simple merge
Simple merge