]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi-fsl-espi.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / spi / spi-fsl-espi.c
index 2c175b9495f7ee102a0d70a96f42fa730c019247..1d332e23f6ede6874e3a7c76329a9ab0ff67a751 100644 (file)
@@ -23,8 +23,6 @@
 #include <linux/pm_runtime.h>
 #include <sysdev/fsl_soc.h>
 
-#include "spi-fsl-lib.h"
-
 /* eSPI Controller registers */
 #define ESPI_SPMODE    0x00    /* eSPI mode register */
 #define ESPI_SPIE      0x04    /* eSPI event register */
 #define CSMODE_AFT(x)          ((x) << 8)
 #define CSMODE_CG(x)           ((x) << 3)
 
+#define FSL_ESPI_FIFO_SIZE     32
+#define FSL_ESPI_RXTHR         15
+
 /* Default mode/csmode for eSPI controller */
-#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR))
 #define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
                | CSMODE_AFT(0) | CSMODE_CG(1))
 
 
 #define AUTOSUSPEND_TIMEOUT 2000
 
-static inline u32 fsl_espi_read_reg(struct mpc8xxx_spi *mspi, int offset)
+struct fsl_espi {
+       struct device *dev;
+       void __iomem *reg_base;
+
+       struct list_head *m_transfers;
+       struct spi_transfer *tx_t;
+       unsigned int tx_pos;
+       bool tx_done;
+       struct spi_transfer *rx_t;
+       unsigned int rx_pos;
+       bool rx_done;
+
+       bool swab;
+       unsigned int rxskip;
+
+       spinlock_t lock;
+
+       u32 spibrg;             /* SPIBRG input clock */
+
+       struct completion done;
+};
+
+struct fsl_espi_cs {
+       u32 hw_mode;
+};
+
+static inline u32 fsl_espi_read_reg(struct fsl_espi *espi, int offset)
 {
-       return ioread32be(mspi->reg_base + offset);
+       return ioread32be(espi->reg_base + offset);
 }
 
-static inline u8 fsl_espi_read_reg8(struct mpc8xxx_spi *mspi, int offset)
+static inline u16 fsl_espi_read_reg16(struct fsl_espi *espi, int offset)
 {
-       return ioread8(mspi->reg_base + offset);
+       return ioread16be(espi->reg_base + offset);
 }
 
-static inline void fsl_espi_write_reg(struct mpc8xxx_spi *mspi, int offset,
-                                     u32 val)
+static inline u8 fsl_espi_read_reg8(struct fsl_espi *espi, int offset)
 {
-       iowrite32be(val, mspi->reg_base + offset);
+       return ioread8(espi->reg_base + offset);
 }
 
-static inline void fsl_espi_write_reg8(struct mpc8xxx_spi *mspi, int offset,
-                                      u8 val)
+static inline void fsl_espi_write_reg(struct fsl_espi *espi, int offset,
+                                     u32 val)
 {
-       iowrite8(val, mspi->reg_base + offset);
+       iowrite32be(val, espi->reg_base + offset);
 }
 
-static void fsl_espi_copy_to_buf(struct spi_message *m,
-                                struct mpc8xxx_spi *mspi)
+static inline void fsl_espi_write_reg16(struct fsl_espi *espi, int offset,
+                                       u16 val)
 {
-       struct spi_transfer *t;
-       u8 *buf = mspi->local_buf;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->tx_buf)
-                       memcpy(buf, t->tx_buf, t->len);
-               else
-                       memset(buf, 0, t->len);
-               buf += t->len;
-       }
+       iowrite16be(val, espi->reg_base + offset);
 }
 
-static void fsl_espi_copy_from_buf(struct spi_message *m,
-                                  struct mpc8xxx_spi *mspi)
+static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset,
+                                      u8 val)
 {
-       struct spi_transfer *t;
-       u8 *buf = mspi->local_buf;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->rx_buf)
-                       memcpy(t->rx_buf, buf, t->len);
-               buf += t->len;
-       }
+       iowrite8(val, espi->reg_base + offset);
 }
 
 static int fsl_espi_check_message(struct spi_message *m)
 {
-       struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master);
+       struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
        struct spi_transfer *t, *first;
 
        if (m->frame_length > SPCOM_TRANLEN_MAX) {
-               dev_err(mspi->dev, "message too long, size is %u bytes\n",
+               dev_err(espi->dev, "message too long, size is %u bytes\n",
                        m->frame_length);
                return -EMSGSIZE;
        }
 
        first = list_first_entry(&m->transfers, struct spi_transfer,
                                 transfer_list);
+
        list_for_each_entry(t, &m->transfers, transfer_list) {
                if (first->bits_per_word != t->bits_per_word ||
                    first->speed_hz != t->speed_hz) {
-                       dev_err(mspi->dev, "bits_per_word/speed_hz should be the same for all transfers\n");
+                       dev_err(espi->dev, "bits_per_word/speed_hz should be the same for all transfers\n");
                        return -EINVAL;
                }
        }
 
+       /* ESPI supports MSB-first transfers for word size 8 / 16 only */
+       if (!(m->spi->mode & SPI_LSB_FIRST) && first->bits_per_word != 8 &&
+           first->bits_per_word != 16) {
+               dev_err(espi->dev,
+                       "MSB-first transfer not supported for wordsize %u\n",
+                       first->bits_per_word);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
-static void fsl_espi_change_mode(struct spi_device *spi)
+static unsigned int fsl_espi_check_rxskip_mode(struct spi_message *m)
 {
-       struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
-       struct spi_mpc8xxx_cs *cs = spi->controller_state;
-       u32 tmp;
-       unsigned long flags;
-
-       /* Turn off IRQs locally to minimize time that SPI is disabled. */
-       local_irq_save(flags);
-
-       /* Turn off SPI unit prior changing mode */
-       tmp = fsl_espi_read_reg(mspi, ESPI_SPMODE);
-       fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp & ~SPMODE_ENABLE);
-       fsl_espi_write_reg(mspi, ESPI_SPMODEx(spi->chip_select),
-                             cs->hw_mode);
-       fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp);
-
-       local_irq_restore(flags);
+       struct spi_transfer *t;
+       unsigned int i = 0, rxskip = 0;
+
+       /*
+        * prerequisites for ESPI rxskip mode:
+        * - message has two transfers
+        * - first transfer is a write and second is a read
+        *
+        * In addition the current low-level transfer mechanism requires
+        * that the rxskip bytes fit into the TX FIFO. Else the transfer
+        * would hang because after the first FSL_ESPI_FIFO_SIZE bytes
+        * the TX FIFO isn't re-filled.
+        */
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (i == 0) {
+                       if (!t->tx_buf || t->rx_buf ||
+                           t->len > FSL_ESPI_FIFO_SIZE)
+                               return 0;
+                       rxskip = t->len;
+               } else if (i == 1) {
+                       if (t->tx_buf || !t->rx_buf)
+                               return 0;
+               }
+               i++;
+       }
+
+       return i == 2 ? rxskip : 0;
 }
 
-static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
+static void fsl_espi_fill_tx_fifo(struct fsl_espi *espi, u32 events)
 {
-       u32 data;
-       u16 data_h;
-       u16 data_l;
-       const u32 *tx = mpc8xxx_spi->tx;
+       u32 tx_fifo_avail;
+       unsigned int tx_left;
+       const void *tx_buf;
+
+       /* if events is zero transfer has not started and tx fifo is empty */
+       tx_fifo_avail = events ? SPIE_TXCNT(events) :  FSL_ESPI_FIFO_SIZE;
+start:
+       tx_left = espi->tx_t->len - espi->tx_pos;
+       tx_buf = espi->tx_t->tx_buf;
+       while (tx_fifo_avail >= min(4U, tx_left) && tx_left) {
+               if (tx_left >= 4) {
+                       if (!tx_buf)
+                               fsl_espi_write_reg(espi, ESPI_SPITF, 0);
+                       else if (espi->swab)
+                               fsl_espi_write_reg(espi, ESPI_SPITF,
+                                       swahb32p(tx_buf + espi->tx_pos));
+                       else
+                               fsl_espi_write_reg(espi, ESPI_SPITF,
+                                       *(u32 *)(tx_buf + espi->tx_pos));
+                       espi->tx_pos += 4;
+                       tx_left -= 4;
+                       tx_fifo_avail -= 4;
+               } else if (tx_left >= 2 && tx_buf && espi->swab) {
+                       fsl_espi_write_reg16(espi, ESPI_SPITF,
+                                       swab16p(tx_buf + espi->tx_pos));
+                       espi->tx_pos += 2;
+                       tx_left -= 2;
+                       tx_fifo_avail -= 2;
+               } else {
+                       if (!tx_buf)
+                               fsl_espi_write_reg8(espi, ESPI_SPITF, 0);
+                       else
+                               fsl_espi_write_reg8(espi, ESPI_SPITF,
+                                       *(u8 *)(tx_buf + espi->tx_pos));
+                       espi->tx_pos += 1;
+                       tx_left -= 1;
+                       tx_fifo_avail -= 1;
+               }
+       }
 
-       if (!tx)
-               return 0;
+       if (!tx_left) {
+               /* Last transfer finished, in rxskip mode only one is needed */
+               if (list_is_last(&espi->tx_t->transfer_list,
+                   espi->m_transfers) || espi->rxskip) {
+                       espi->tx_done = true;
+                       return;
+               }
+               espi->tx_t = list_next_entry(espi->tx_t, transfer_list);
+               espi->tx_pos = 0;
+               /* continue with next transfer if tx fifo is not full */
+               if (tx_fifo_avail)
+                       goto start;
+       }
+}
 
-       data = *tx++ << mpc8xxx_spi->tx_shift;
-       data_l = data & 0xffff;
-       data_h = (data >> 16) & 0xffff;
-       swab16s(&data_l);
-       swab16s(&data_h);
-       data = data_h | data_l;
+static void fsl_espi_read_rx_fifo(struct fsl_espi *espi, u32 events)
+{
+       u32 rx_fifo_avail = SPIE_RXCNT(events);
+       unsigned int rx_left;
+       void *rx_buf;
+
+start:
+       rx_left = espi->rx_t->len - espi->rx_pos;
+       rx_buf = espi->rx_t->rx_buf;
+       while (rx_fifo_avail >= min(4U, rx_left) && rx_left) {
+               if (rx_left >= 4) {
+                       u32 val = fsl_espi_read_reg(espi, ESPI_SPIRF);
+
+                       if (rx_buf && espi->swab)
+                               *(u32 *)(rx_buf + espi->rx_pos) = swahb32(val);
+                       else if (rx_buf)
+                               *(u32 *)(rx_buf + espi->rx_pos) = val;
+                       espi->rx_pos += 4;
+                       rx_left -= 4;
+                       rx_fifo_avail -= 4;
+               } else if (rx_left >= 2 && rx_buf && espi->swab) {
+                       u16 val = fsl_espi_read_reg16(espi, ESPI_SPIRF);
+
+                       *(u16 *)(rx_buf + espi->rx_pos) = swab16(val);
+                       espi->rx_pos += 2;
+                       rx_left -= 2;
+                       rx_fifo_avail -= 2;
+               } else {
+                       u8 val = fsl_espi_read_reg8(espi, ESPI_SPIRF);
+
+                       if (rx_buf)
+                               *(u8 *)(rx_buf + espi->rx_pos) = val;
+                       espi->rx_pos += 1;
+                       rx_left -= 1;
+                       rx_fifo_avail -= 1;
+               }
+       }
 
-       mpc8xxx_spi->tx = tx;
-       return data;
+       if (!rx_left) {
+               if (list_is_last(&espi->rx_t->transfer_list,
+                   espi->m_transfers)) {
+                       espi->rx_done = true;
+                       return;
+               }
+               espi->rx_t = list_next_entry(espi->rx_t, transfer_list);
+               espi->rx_pos = 0;
+               /* continue with next transfer if rx fifo is not empty */
+               if (rx_fifo_avail)
+                       goto start;
+       }
 }
 
 static void fsl_espi_setup_transfer(struct spi_device *spi,
                                        struct spi_transfer *t)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_espi *espi = spi_master_get_devdata(spi->master);
        int bits_per_word = t ? t->bits_per_word : spi->bits_per_word;
-       u32 hz = t ? t->speed_hz : spi->max_speed_hz;
-       u8 pm;
-       struct spi_mpc8xxx_cs *cs = spi->controller_state;
-
-       cs->rx_shift = 0;
-       cs->tx_shift = 0;
-       cs->get_rx = mpc8xxx_spi_rx_buf_u32;
-       cs->get_tx = mpc8xxx_spi_tx_buf_u32;
-       if (bits_per_word <= 8) {
-               cs->rx_shift = 8 - bits_per_word;
-       } else {
-               cs->rx_shift = 16 - bits_per_word;
-               if (spi->mode & SPI_LSB_FIRST)
-                       cs->get_tx = fsl_espi_tx_buf_lsb;
-       }
-
-       mpc8xxx_spi->rx_shift = cs->rx_shift;
-       mpc8xxx_spi->tx_shift = cs->tx_shift;
-       mpc8xxx_spi->get_rx = cs->get_rx;
-       mpc8xxx_spi->get_tx = cs->get_tx;
+       u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz;
+       struct fsl_espi_cs *cs = spi_get_ctldata(spi);
+       u32 hw_mode_old = cs->hw_mode;
 
        /* mask out bits we are going to set */
        cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF));
 
        cs->hw_mode |= CSMODE_LEN(bits_per_word - 1);
 
-       if ((mpc8xxx_spi->spibrg / hz) > 64) {
+       pm = DIV_ROUND_UP(espi->spibrg, hz * 4) - 1;
+
+       if (pm > 15) {
                cs->hw_mode |= CSMODE_DIV16;
-               pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 16 * 4);
-
-               WARN_ONCE(pm > 33, "%s: Requested speed is too low: %d Hz. "
-                         "Will use %d Hz instead.\n", dev_name(&spi->dev),
-                               hz, mpc8xxx_spi->spibrg / (4 * 16 * (32 + 1)));
-               if (pm > 33)
-                       pm = 33;
-       } else {
-               pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 4);
+               pm = DIV_ROUND_UP(espi->spibrg, hz * 16 * 4) - 1;
        }
-       if (pm)
-               pm--;
-       if (pm < 2)
-               pm = 2;
 
        cs->hw_mode |= CSMODE_PM(pm);
 
-       fsl_espi_change_mode(spi);
+       /* don't write the mode register if the mode doesn't change */
+       if (cs->hw_mode != hw_mode_old)
+               fsl_espi_write_reg(espi, ESPI_SPMODEx(spi->chip_select),
+                                  cs->hw_mode);
 }
 
 static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-       u32 word;
+       struct fsl_espi *espi = spi_master_get_devdata(spi->master);
+       unsigned int rx_len = t->len;
+       u32 mask, spcom;
        int ret;
 
-       mpc8xxx_spi->len = t->len;
-       mpc8xxx_spi->count = roundup(t->len, 4) / 4;
-
-       mpc8xxx_spi->tx = t->tx_buf;
-       mpc8xxx_spi->rx = t->rx_buf;
-
-       reinit_completion(&mpc8xxx_spi->done);
+       reinit_completion(&espi->done);
 
        /* Set SPCOM[CS] and SPCOM[TRANLEN] field */
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM,
-               (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+       spcom = SPCOM_CS(spi->chip_select);
+       spcom |= SPCOM_TRANLEN(t->len - 1);
+
+       /* configure RXSKIP mode */
+       if (espi->rxskip) {
+               spcom |= SPCOM_RXSKIP(espi->rxskip);
+               rx_len = t->len - espi->rxskip;
+               if (t->rx_nbits == SPI_NBITS_DUAL)
+                       spcom |= SPCOM_DO;
+       }
+
+       fsl_espi_write_reg(espi, ESPI_SPCOM, spcom);
 
-       /* enable rx ints */
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
+       /* enable interrupts */
+       mask = SPIM_DON;
+       if (rx_len > FSL_ESPI_FIFO_SIZE)
+               mask |= SPIM_RXT;
+       fsl_espi_write_reg(espi, ESPI_SPIM, mask);
 
-       /* transmit word */
-       word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, word);
+       /* Prevent filling the fifo from getting interrupted */
+       spin_lock_irq(&espi->lock);
+       fsl_espi_fill_tx_fifo(espi, 0);
+       spin_unlock_irq(&espi->lock);
 
        /* Won't hang up forever, SPI bus sometimes got lost interrupts... */
-       ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
+       ret = wait_for_completion_timeout(&espi->done, 2 * HZ);
        if (ret == 0)
-               dev_err(mpc8xxx_spi->dev,
-                       "Transaction hanging up (left %d bytes)\n",
-                       mpc8xxx_spi->count);
+               dev_err(espi->dev, "Transfer timed out!\n");
 
        /* disable rx ints */
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
+       fsl_espi_write_reg(espi, ESPI_SPIM, 0);
 
-       return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0;
+       return ret == 0 ? -ETIMEDOUT : 0;
 }
 
 static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
 {
-       struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master);
+       struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
        struct spi_device *spi = m->spi;
        int ret;
 
-       fsl_espi_copy_to_buf(m, mspi);
+       /* In case of LSB-first and bits_per_word > 8 byte-swap all words */
+       espi->swab = spi->mode & SPI_LSB_FIRST && trans->bits_per_word > 8;
+
+       espi->m_transfers = &m->transfers;
+       espi->tx_t = list_first_entry(&m->transfers, struct spi_transfer,
+                                     transfer_list);
+       espi->tx_pos = 0;
+       espi->tx_done = false;
+       espi->rx_t = list_first_entry(&m->transfers, struct spi_transfer,
+                                     transfer_list);
+       espi->rx_pos = 0;
+       espi->rx_done = false;
+
+       espi->rxskip = fsl_espi_check_rxskip_mode(m);
+       if (trans->rx_nbits == SPI_NBITS_DUAL && !espi->rxskip) {
+               dev_err(espi->dev, "Dual output mode requires RXSKIP mode!\n");
+               return -EINVAL;
+       }
+
+       /* In RXSKIP mode skip first transfer for reads */
+       if (espi->rxskip)
+               espi->rx_t = list_next_entry(espi->rx_t, transfer_list);
+
        fsl_espi_setup_transfer(spi, trans);
 
        ret = fsl_espi_bufs(spi, trans);
@@ -310,19 +434,13 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
        if (trans->delay_usecs)
                udelay(trans->delay_usecs);
 
-       fsl_espi_setup_transfer(spi, NULL);
-
-       if (!ret)
-               fsl_espi_copy_from_buf(m, mspi);
-
        return ret;
 }
 
 static int fsl_espi_do_one_msg(struct spi_master *master,
                               struct spi_message *m)
 {
-       struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master);
-       unsigned int delay_usecs = 0;
+       unsigned int delay_usecs = 0, rx_nbits = 0;
        struct spi_transfer *t, trans = {};
        int ret;
 
@@ -333,6 +451,8 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
        list_for_each_entry(t, &m->transfers, transfer_list) {
                if (t->delay_usecs > delay_usecs)
                        delay_usecs = t->delay_usecs;
+               if (t->rx_nbits > rx_nbits)
+                       rx_nbits = t->rx_nbits;
        }
 
        t = list_first_entry(&m->transfers, struct spi_transfer,
@@ -342,8 +462,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
        trans.speed_hz = t->speed_hz;
        trans.bits_per_word = t->bits_per_word;
        trans.delay_usecs = delay_usecs;
-       trans.tx_buf = mspi->local_buf;
-       trans.rx_buf = mspi->local_buf;
+       trans.rx_nbits = rx_nbits;
 
        if (trans.len)
                ret = fsl_espi_trans(m, &trans);
@@ -360,12 +479,9 @@ out:
 
 static int fsl_espi_setup(struct spi_device *spi)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi;
+       struct fsl_espi *espi;
        u32 loop_mode;
-       struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
-
-       if (!spi->max_speed_hz)
-               return -EINVAL;
+       struct fsl_espi_cs *cs = spi_get_ctldata(spi);
 
        if (!cs) {
                cs = kzalloc(sizeof(*cs), GFP_KERNEL);
@@ -374,12 +490,11 @@ static int fsl_espi_setup(struct spi_device *spi)
                spi_set_ctldata(spi, cs);
        }
 
-       mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       espi = spi_master_get_devdata(spi->master);
 
-       pm_runtime_get_sync(mpc8xxx_spi->dev);
+       pm_runtime_get_sync(espi->dev);
 
-       cs->hw_mode = fsl_espi_read_reg(mpc8xxx_spi,
-                                          ESPI_SPMODEx(spi->chip_select));
+       cs->hw_mode = fsl_espi_read_reg(espi, ESPI_SPMODEx(spi->chip_select));
        /* mask out bits we are going to set */
        cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
                         | CSMODE_REV);
@@ -392,115 +507,74 @@ static int fsl_espi_setup(struct spi_device *spi)
                cs->hw_mode |= CSMODE_REV;
 
        /* Handle the loop mode */
-       loop_mode = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE);
+       loop_mode = fsl_espi_read_reg(espi, ESPI_SPMODE);
        loop_mode &= ~SPMODE_LOOP;
        if (spi->mode & SPI_LOOP)
                loop_mode |= SPMODE_LOOP;
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, loop_mode);
+       fsl_espi_write_reg(espi, ESPI_SPMODE, loop_mode);
 
        fsl_espi_setup_transfer(spi, NULL);
 
-       pm_runtime_mark_last_busy(mpc8xxx_spi->dev);
-       pm_runtime_put_autosuspend(mpc8xxx_spi->dev);
+       pm_runtime_mark_last_busy(espi->dev);
+       pm_runtime_put_autosuspend(espi->dev);
 
        return 0;
 }
 
 static void fsl_espi_cleanup(struct spi_device *spi)
 {
-       struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
+       struct fsl_espi_cs *cs = spi_get_ctldata(spi);
 
        kfree(cs);
        spi_set_ctldata(spi, NULL);
 }
 
-static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
 {
-       /* We need handle RX first */
-       if (events & SPIE_RNE) {
-               u32 rx_data, tmp;
-               u8 rx_data_8;
-               int rx_nr_bytes = 4;
-               int ret;
-
-               /* Spin until RX is done */
-               if (SPIE_RXCNT(events) < min(4, mspi->len)) {
-                       ret = spin_event_timeout(
-                               !(SPIE_RXCNT(events =
-                               fsl_espi_read_reg(mspi, ESPI_SPIE)) <
-                                               min(4, mspi->len)),
-                                               10000, 0); /* 10 msec */
-                       if (!ret)
-                               dev_err(mspi->dev,
-                                        "tired waiting for SPIE_RXCNT\n");
-               }
+       if (!espi->rx_done)
+               fsl_espi_read_rx_fifo(espi, events);
 
-               if (mspi->len >= 4) {
-                       rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF);
-               } else if (mspi->len <= 0) {
-                       dev_err(mspi->dev,
-                               "unexpected RX(SPIE_RNE) interrupt occurred,\n"
-                               "(local rxlen %d bytes, reg rxlen %d bytes)\n",
-                               min(4, mspi->len), SPIE_RXCNT(events));
-                       rx_nr_bytes = 0;
-               } else {
-                       rx_nr_bytes = mspi->len;
-                       tmp = mspi->len;
-                       rx_data = 0;
-                       while (tmp--) {
-                               rx_data_8 = fsl_espi_read_reg8(mspi,
-                                                              ESPI_SPIRF);
-                               rx_data |= (rx_data_8 << (tmp * 8));
-                       }
-
-                       rx_data <<= (4 - mspi->len) * 8;
-               }
+       if (!espi->tx_done)
+               fsl_espi_fill_tx_fifo(espi, events);
 
-               mspi->len -= rx_nr_bytes;
+       if (!espi->tx_done || !espi->rx_done)
+               return;
 
-               if (rx_nr_bytes && mspi->rx)
-                       mspi->get_rx(rx_data, mspi);
-       }
+       /* we're done, but check for errors before returning */
+       events = fsl_espi_read_reg(espi, ESPI_SPIE);
 
-       if (!(events & SPIE_TNF)) {
-               int ret;
-
-               /* spin until TX is done */
-               ret = spin_event_timeout(((events = fsl_espi_read_reg(
-                               mspi, ESPI_SPIE)) & SPIE_TNF), 1000, 0);
-               if (!ret) {
-                       dev_err(mspi->dev, "tired waiting for SPIE_TNF\n");
-                       complete(&mspi->done);
-                       return;
-               }
-       }
+       if (!(events & SPIE_DON))
+               dev_err(espi->dev,
+                       "Transfer done but SPIE_DON isn't set!\n");
 
-       mspi->count -= 1;
-       if (mspi->count) {
-               u32 word = mspi->get_tx(mspi);
+       if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE)
+               dev_err(espi->dev, "Transfer done but rx/tx fifo's aren't empty!\n");
 
-               fsl_espi_write_reg(mspi, ESPI_SPITF, word);
-       } else {
-               complete(&mspi->done);
-       }
+       complete(&espi->done);
 }
 
 static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
 {
-       struct mpc8xxx_spi *mspi = context_data;
+       struct fsl_espi *espi = context_data;
        u32 events;
 
+       spin_lock(&espi->lock);
+
        /* Get interrupt events(tx/rx) */
-       events = fsl_espi_read_reg(mspi, ESPI_SPIE);
-       if (!events)
+       events = fsl_espi_read_reg(espi, ESPI_SPIE);
+       if (!events) {
+               spin_unlock(&espi->lock);
                return IRQ_NONE;
+       }
 
-       dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events);
+       dev_vdbg(espi->dev, "%s: events %x\n", __func__, events);
 
-       fsl_espi_cpu_irq(mspi, events);
+       fsl_espi_cpu_irq(espi, events);
 
        /* Clear the events */
-       fsl_espi_write_reg(mspi, ESPI_SPIE, events);
+       fsl_espi_write_reg(espi, ESPI_SPIE, events);
+
+       spin_unlock(&espi->lock);
 
        return IRQ_HANDLED;
 }
@@ -509,12 +583,12 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
 static int fsl_espi_runtime_suspend(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+       struct fsl_espi *espi = spi_master_get_devdata(master);
        u32 regval;
 
-       regval = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE);
+       regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
        regval &= ~SPMODE_ENABLE;
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval);
+       fsl_espi_write_reg(espi, ESPI_SPMODE, regval);
 
        return 0;
 }
@@ -522,12 +596,12 @@ static int fsl_espi_runtime_suspend(struct device *dev)
 static int fsl_espi_runtime_resume(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+       struct fsl_espi *espi = spi_master_get_devdata(master);
        u32 regval;
 
-       regval = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE);
+       regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
        regval |= SPMODE_ENABLE;
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval);
+       fsl_espi_write_reg(espi, ESPI_SPMODE, regval);
 
        return 0;
 }
@@ -538,96 +612,105 @@ static size_t fsl_espi_max_message_size(struct spi_device *spi)
        return SPCOM_TRANLEN_MAX;
 }
 
+static void fsl_espi_init_regs(struct device *dev, bool initial)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct fsl_espi *espi = spi_master_get_devdata(master);
+       struct device_node *nc;
+       u32 csmode, cs, prop;
+       int ret;
+
+       /* SPI controller initializations */
+       fsl_espi_write_reg(espi, ESPI_SPMODE, 0);
+       fsl_espi_write_reg(espi, ESPI_SPIM, 0);
+       fsl_espi_write_reg(espi, ESPI_SPCOM, 0);
+       fsl_espi_write_reg(espi, ESPI_SPIE, 0xffffffff);
+
+       /* Init eSPI CS mode register */
+       for_each_available_child_of_node(master->dev.of_node, nc) {
+               /* get chip select */
+               ret = of_property_read_u32(nc, "reg", &cs);
+               if (ret || cs >= master->num_chipselect)
+                       continue;
+
+               csmode = CSMODE_INIT_VAL;
+
+               /* check if CSBEF is set in device tree */
+               ret = of_property_read_u32(nc, "fsl,csbef", &prop);
+               if (!ret) {
+                       csmode &= ~(CSMODE_BEF(0xf));
+                       csmode |= CSMODE_BEF(prop);
+               }
+
+               /* check if CSAFT is set in device tree */
+               ret = of_property_read_u32(nc, "fsl,csaft", &prop);
+               if (!ret) {
+                       csmode &= ~(CSMODE_AFT(0xf));
+                       csmode |= CSMODE_AFT(prop);
+               }
+
+               fsl_espi_write_reg(espi, ESPI_SPMODEx(cs), csmode);
+
+               if (initial)
+                       dev_info(dev, "cs=%u, init_csmode=0x%x\n", cs, csmode);
+       }
+
+       /* Enable SPI interface */
+       fsl_espi_write_reg(espi, ESPI_SPMODE, SPMODE_INIT_VAL | SPMODE_ENABLE);
+}
+
 static int fsl_espi_probe(struct device *dev, struct resource *mem,
-                         unsigned int irq)
+                         unsigned int irq, unsigned int num_cs)
 {
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
        struct spi_master *master;
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       struct device_node *nc;
-       const __be32 *prop;
-       u32 regval, csmode;
-       int i, len, ret;
+       struct fsl_espi *espi;
+       int ret;
 
-       master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
+       master = spi_alloc_master(dev, sizeof(struct fsl_espi));
        if (!master)
                return -ENOMEM;
 
        dev_set_drvdata(dev, master);
 
-       mpc8xxx_spi_probe(dev, mem, irq);
-
+       master->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+                           SPI_LSB_FIRST | SPI_LOOP;
+       master->dev.of_node = dev->of_node;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
        master->setup = fsl_espi_setup;
        master->cleanup = fsl_espi_cleanup;
        master->transfer_one_message = fsl_espi_do_one_msg;
        master->auto_runtime_pm = true;
        master->max_message_size = fsl_espi_max_message_size;
+       master->num_chipselect = num_cs;
 
-       mpc8xxx_spi = spi_master_get_devdata(master);
+       espi = spi_master_get_devdata(master);
+       spin_lock_init(&espi->lock);
 
-       mpc8xxx_spi->local_buf =
-               devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL);
-       if (!mpc8xxx_spi->local_buf) {
-               ret = -ENOMEM;
+       espi->dev = dev;
+       espi->spibrg = fsl_get_sys_freq();
+       if (espi->spibrg == -1) {
+               dev_err(dev, "Can't get sys frequency!\n");
+               ret = -EINVAL;
                goto err_probe;
        }
+       /* determined by clock divider fields DIV16/PM in register SPMODEx */
+       master->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
+       master->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
 
-       mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
-       if (IS_ERR(mpc8xxx_spi->reg_base)) {
-               ret = PTR_ERR(mpc8xxx_spi->reg_base);
+       init_completion(&espi->done);
+
+       espi->reg_base = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(espi->reg_base)) {
+               ret = PTR_ERR(espi->reg_base);
                goto err_probe;
        }
 
        /* Register for SPI Interrupt */
-       ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq,
-                         0, "fsl_espi", mpc8xxx_spi);
+       ret = devm_request_irq(dev, irq, fsl_espi_irq, 0, "fsl_espi", espi);
        if (ret)
                goto err_probe;
 
-       if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
-               mpc8xxx_spi->rx_shift = 16;
-               mpc8xxx_spi->tx_shift = 24;
-       }
-
-       /* SPI controller initializations */
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIE, 0xffffffff);
-
-       /* Init eSPI CS mode register */
-       for_each_available_child_of_node(master->dev.of_node, nc) {
-               /* get chip select */
-               prop = of_get_property(nc, "reg", &len);
-               if (!prop || len < sizeof(*prop))
-                       continue;
-               i = be32_to_cpup(prop);
-               if (i < 0 || i >= pdata->max_chipselect)
-                       continue;
-
-               csmode = CSMODE_INIT_VAL;
-               /* check if CSBEF is set in device tree */
-               prop = of_get_property(nc, "fsl,csbef", &len);
-               if (prop && len >= sizeof(*prop)) {
-                       csmode &= ~(CSMODE_BEF(0xf));
-                       csmode |= CSMODE_BEF(be32_to_cpup(prop));
-               }
-               /* check if CSAFT is set in device tree */
-               prop = of_get_property(nc, "fsl,csaft", &len);
-               if (prop && len >= sizeof(*prop)) {
-                       csmode &= ~(CSMODE_AFT(0xf));
-                       csmode |= CSMODE_AFT(be32_to_cpup(prop));
-               }
-               fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(i), csmode);
-
-               dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode);
-       }
-
-       /* Enable SPI interface */
-       regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
-
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval);
+       fsl_espi_init_regs(dev, true);
 
        pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT);
        pm_runtime_use_autosuspend(dev);
@@ -639,8 +722,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
        if (ret < 0)
                goto err_pm;
 
-       dev_info(dev, "at 0x%p (irq = %d)\n", mpc8xxx_spi->reg_base,
-                mpc8xxx_spi->irq);
+       dev_info(dev, "at 0x%p (irq = %u)\n", espi->reg_base, irq);
 
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
@@ -659,20 +741,16 @@ err_probe:
 static int of_fsl_espi_get_chipselects(struct device *dev)
 {
        struct device_node *np = dev->of_node;
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
-       const u32 *prop;
-       int len;
+       u32 num_cs;
+       int ret;
 
-       prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
-       if (!prop || len < sizeof(*prop)) {
+       ret = of_property_read_u32(np, "fsl,espi-num-chipselects", &num_cs);
+       if (ret) {
                dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
-               return -EINVAL;
+               return 0;
        }
 
-       pdata->max_chipselect = *prop;
-       pdata->cs_control = NULL;
-
-       return 0;
+       return num_cs;
 }
 
 static int of_fsl_espi_probe(struct platform_device *ofdev)
@@ -680,16 +758,17 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
        struct device *dev = &ofdev->dev;
        struct device_node *np = ofdev->dev.of_node;
        struct resource mem;
-       unsigned int irq;
+       unsigned int irq, num_cs;
        int ret;
 
-       ret = of_mpc8xxx_spi_probe(ofdev);
-       if (ret)
-               return ret;
+       if (of_property_read_bool(np, "mode")) {
+               dev_err(dev, "mode property is not supported on ESPI!\n");
+               return -EINVAL;
+       }
 
-       ret = of_fsl_espi_get_chipselects(dev);
-       if (ret)
-               return ret;
+       num_cs = of_fsl_espi_get_chipselects(dev);
+       if (!num_cs)
+               return -EINVAL;
 
        ret = of_address_to_resource(np, 0, &mem);
        if (ret)
@@ -699,7 +778,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
        if (!irq)
                return -EINVAL;
 
-       return fsl_espi_probe(dev, &mem, irq);
+       return fsl_espi_probe(dev, &mem, irq, num_cs);
 }
 
 static int of_fsl_espi_remove(struct platform_device *dev)
@@ -721,38 +800,15 @@ static int of_fsl_espi_suspend(struct device *dev)
                return ret;
        }
 
-       ret = pm_runtime_force_suspend(dev);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return pm_runtime_force_suspend(dev);
 }
 
 static int of_fsl_espi_resume(struct device *dev)
 {
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
        struct spi_master *master = dev_get_drvdata(dev);
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       u32 regval;
-       int i, ret;
-
-       mpc8xxx_spi = spi_master_get_devdata(master);
-
-       /* SPI controller initializations */
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, 0);
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIE, 0xffffffff);
-
-       /* Init eSPI CS mode register */
-       for (i = 0; i < pdata->max_chipselect; i++)
-               fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(i),
-                                     CSMODE_INIT_VAL);
-
-       /* Enable SPI interface */
-       regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+       int ret;
 
-       fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval);
+       fsl_espi_init_regs(dev, false);
 
        ret = pm_runtime_force_resume(dev);
        if (ret < 0)