root/drivers/spi/spi-mpfs.c
// SPDX-License-Identifier: (GPL-2.0)
/*
 * Microchip CoreSPI SPI controller driver
 *
 * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
 *
 * Author: Daire McNamara <daire.mcnamara@microchip.com>
 * Author: Conor Dooley <conor.dooley@microchip.com>
 *
 */

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>

#define MAX_LEN                         (0xffff)
#define MAX_CS                          (1)
#define DEFAULT_FRAMESIZE               (8)
#define FIFO_DEPTH                      (32)
#define CLK_GEN_MODE1_MAX               (255)
#define CLK_GEN_MODE0_MAX               (15)
#define CLK_GEN_MIN                     (0)
#define MODE_X_MASK_SHIFT               (24)

#define CONTROL_ENABLE                  BIT(0)
#define CONTROL_MASTER                  BIT(1)
#define CONTROL_RX_DATA_INT             BIT(4)
#define CONTROL_TX_DATA_INT             BIT(5)
#define CONTROL_RX_OVER_INT             BIT(6)
#define CONTROL_TX_UNDER_INT            BIT(7)
#define CONTROL_SPO                     BIT(24)
#define CONTROL_SPH                     BIT(25)
#define CONTROL_SPS                     BIT(26)
#define CONTROL_FRAMEURUN               BIT(27)
#define CONTROL_CLKMODE                 BIT(28)
#define CONTROL_BIGFIFO                 BIT(29)
#define CONTROL_OENOFF                  BIT(30)
#define CONTROL_RESET                   BIT(31)

#define CONTROL_MODE_MASK               GENMASK(3, 2)
#define  MOTOROLA_MODE                  (0)
#define CONTROL_FRAMECNT_MASK           GENMASK(23, 8)
#define CONTROL_FRAMECNT_SHIFT          (8)

#define STATUS_ACTIVE                   BIT(14)
#define STATUS_SSEL                     BIT(13)
#define STATUS_FRAMESTART               BIT(12)
#define STATUS_TXFIFO_EMPTY_NEXT_READ   BIT(11)
#define STATUS_TXFIFO_EMPTY             BIT(10)
#define STATUS_TXFIFO_FULL_NEXT_WRITE   BIT(9)
#define STATUS_TXFIFO_FULL              BIT(8)
#define STATUS_RXFIFO_EMPTY_NEXT_READ   BIT(7)
#define STATUS_RXFIFO_EMPTY             BIT(6)
#define STATUS_RXFIFO_FULL_NEXT_WRITE   BIT(5)
#define STATUS_RXFIFO_FULL              BIT(4)
#define STATUS_TX_UNDERRUN              BIT(3)
#define STATUS_RX_OVERFLOW              BIT(2)
#define STATUS_RXDAT_RXED               BIT(1)
#define STATUS_TXDAT_SENT               BIT(0)

#define INT_TXDONE                      BIT(0)
#define INT_RXRDY                       BIT(1)
#define INT_RX_CHANNEL_OVERFLOW         BIT(2)
#define INT_TX_CHANNEL_UNDERRUN         BIT(3)

#define INT_ENABLE_MASK (CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)

#define REG_CONTROL             (0x00)
#define REG_FRAME_SIZE          (0x04)
#define  FRAME_SIZE_MASK        GENMASK(5, 0)
#define REG_STATUS              (0x08)
#define REG_INT_CLEAR           (0x0c)
#define REG_RX_DATA             (0x10)
#define REG_TX_DATA             (0x14)
#define REG_CLK_GEN             (0x18)
#define REG_SLAVE_SELECT        (0x1c)
#define  SSEL_MASK              GENMASK(7, 0)
#define  SSEL_DIRECT            BIT(8)
#define  SSELOUT_SHIFT          9
#define  SSELOUT                BIT(SSELOUT_SHIFT)
#define REG_MIS                 (0x20)
#define REG_RIS                 (0x24)
#define REG_CONTROL2            (0x28)
#define REG_COMMAND             (0x2c)
#define  COMMAND_CLRFRAMECNT    BIT(4)
#define  COMMAND_TXFIFORST              BIT(3)
#define  COMMAND_RXFIFORST              BIT(2)
#define REG_PKTSIZE             (0x30)
#define REG_CMD_SIZE            (0x34)
#define REG_HWSTATUS            (0x38)
#define REG_STAT8               (0x3c)
#define REG_CTRL2               (0x48)
#define REG_FRAMESUP            (0x50)

struct mpfs_spi {
        void __iomem *regs;
        struct clk *clk;
        const u8 *tx_buf;
        u8 *rx_buf;
        u32 clk_gen; /* divider for spi output clock generated by the controller */
        u32 clk_mode;
        u32 pending_slave_select;
        int irq;
        int tx_len;
        int rx_len;
        int n_bytes;
};

static inline u32 mpfs_spi_read(struct mpfs_spi *spi, unsigned int reg)
{
        return readl(spi->regs + reg);
}

static inline void mpfs_spi_write(struct mpfs_spi *spi, unsigned int reg, u32 val)
{
        writel(val, spi->regs + reg);
}

static inline void mpfs_spi_disable(struct mpfs_spi *spi)
{
        u32 control = mpfs_spi_read(spi, REG_CONTROL);

        control &= ~CONTROL_ENABLE;

        mpfs_spi_write(spi, REG_CONTROL, control);
}

static inline void mpfs_spi_read_fifo(struct mpfs_spi *spi, int fifo_max)
{
        for (int i = 0; i < fifo_max; i++) {
                u32 data;

                while (mpfs_spi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)
                        ;

                data = mpfs_spi_read(spi, REG_RX_DATA);

                spi->rx_len -= spi->n_bytes;

                if (!spi->rx_buf)
                        continue;

                if (spi->n_bytes == 4)
                        *((u32 *)spi->rx_buf) = data;
                else if (spi->n_bytes == 2)
                        *((u16 *)spi->rx_buf) = data;
                else
                        *spi->rx_buf = data;

                spi->rx_buf += spi->n_bytes;
        }
}

static void mpfs_spi_enable_ints(struct mpfs_spi *spi)
{
        u32 control = mpfs_spi_read(spi, REG_CONTROL);

        control |= INT_ENABLE_MASK;
        mpfs_spi_write(spi, REG_CONTROL, control);
}

static void mpfs_spi_disable_ints(struct mpfs_spi *spi)
{
        u32 control = mpfs_spi_read(spi, REG_CONTROL);

        control &= ~INT_ENABLE_MASK;
        mpfs_spi_write(spi, REG_CONTROL, control);
}

static inline void mpfs_spi_set_xfer_size(struct mpfs_spi *spi, int len)
{
        u32 control;
        u32 lenpart;
        u32 frames = mpfs_spi_read(spi, REG_FRAMESUP);

        /*
         * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking
         * a shortcut requires an explicit clear.
         */
        if (frames == len) {
                mpfs_spi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT);
                return;
        }

        /*
         * The lower 16 bits of the frame count are stored in the control reg
         * for legacy reasons, but the upper 16 written to a different register:
         * FRAMESUP. While both the upper and lower bits can be *READ* from the
         * FRAMESUP register, writing to the lower 16 bits is (supposedly) a NOP.
         *
         * The driver used to disable the controller while modifying the frame
         * count, and mask off the lower 16 bits of len while writing to
         * FRAMES_UP. When the driver was changed to disable the controller as
         * infrequently as possible, it was discovered that the logic of
         * lenpart = len & 0xffff_0000
         * write(REG_FRAMESUP, lenpart)
         * would actually write zeros into the lower 16 bits on an mpfs250t-es,
         * despite documentation stating these bits were read-only.
         * Writing len unmasked into FRAMES_UP ensures those bits aren't zeroed
         * on an mpfs250t-es and will be a NOP for the lower 16 bits on hardware
         * that matches the documentation.
         */
        lenpart = len & 0xffff;
        control = mpfs_spi_read(spi, REG_CONTROL);
        control &= ~CONTROL_FRAMECNT_MASK;
        control |= lenpart << CONTROL_FRAMECNT_SHIFT;
        mpfs_spi_write(spi, REG_CONTROL, control);
        mpfs_spi_write(spi, REG_FRAMESUP, len);
}

static inline void mpfs_spi_write_fifo(struct mpfs_spi *spi, int fifo_max)
{
        int i = 0;

        mpfs_spi_set_xfer_size(spi, fifo_max);

        while ((i < fifo_max) && !(mpfs_spi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
                u32 word;

                if (spi->n_bytes == 4)
                        word = spi->tx_buf ? *((u32 *)spi->tx_buf) : 0xaa;
                else if (spi->n_bytes == 2)
                        word = spi->tx_buf ? *((u16 *)spi->tx_buf) : 0xaa;
                else
                        word = spi->tx_buf ? *spi->tx_buf : 0xaa;

                mpfs_spi_write(spi, REG_TX_DATA, word);
                if (spi->tx_buf)
                        spi->tx_buf += spi->n_bytes;
                i++;
        }

        spi->tx_len -= i * spi->n_bytes;
}

static inline void mpfs_spi_set_framesize(struct mpfs_spi *spi, int bt)
{
        u32 frame_size = mpfs_spi_read(spi, REG_FRAME_SIZE);
        u32 control;

        if ((frame_size & FRAME_SIZE_MASK) == bt)
                return;

        /*
         * Disable the SPI controller. Writes to the frame size have
         * no effect when the controller is enabled.
         */
        control = mpfs_spi_read(spi, REG_CONTROL);
        control &= ~CONTROL_ENABLE;
        mpfs_spi_write(spi, REG_CONTROL, control);

        mpfs_spi_write(spi, REG_FRAME_SIZE, bt);

        control |= CONTROL_ENABLE;
        mpfs_spi_write(spi, REG_CONTROL, control);
}

static void mpfs_spi_set_cs(struct spi_device *spi, bool disable)
{
        u32 reg;
        struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);

        reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
        reg &= ~BIT(spi_get_chipselect(spi, 0));
        reg |= !disable << spi_get_chipselect(spi, 0);
        mspi->pending_slave_select = reg;

        /*
         * Only deassert chip select immediately. Writing to some registers
         * requires the controller to be disabled, which results in the
         * output pins being tristated and can cause the SCLK and MOSI lines
         * to transition. Therefore asserting the chip select is deferred
         * until just before writing to the TX FIFO, to ensure the device
         * doesn't see any spurious clock transitions whilst CS is enabled.
         */
        if (((spi->mode & SPI_CS_HIGH) == 0) == disable)
                mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
}

static int mpfs_spi_setup(struct spi_device *spi)
{
        struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);
        u32 reg;

        if (spi_is_csgpiod(spi))
                return 0;

        /*
         * Active high targets need to be specifically set to their inactive
         * states during probe by adding them to the "control group" & thus
         * driving their select line low.
         */
        if (spi->mode & SPI_CS_HIGH) {
                reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
                reg |= BIT(spi_get_chipselect(spi, 0));
                mspi->pending_slave_select = reg;
                mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
        }
        return 0;
}

static void mpfs_spi_init(struct spi_controller *host, struct mpfs_spi *spi)
{
        unsigned long clk_hz;
        u32 control = mpfs_spi_read(spi, REG_CONTROL);

        control &= ~CONTROL_ENABLE;
        mpfs_spi_write(spi, REG_CONTROL, control);

        control |= CONTROL_MASTER;
        control &= ~CONTROL_MODE_MASK;
        control |= MOTOROLA_MODE;

        /*
         * The controller must be configured so that it doesn't remove Chip
         * Select until the entire message has been transferred, even if at
         * some points TX FIFO becomes empty.
         *
         * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames
         * for the 8 bit transfers that this driver uses.
         */
        control |= CONTROL_SPS | CONTROL_BIGFIFO;

        mpfs_spi_write(spi, REG_CONTROL, control);

        mpfs_spi_set_framesize(spi, DEFAULT_FRAMESIZE);

        /* max. possible spi clock rate is the apb clock rate */
        clk_hz = clk_get_rate(spi->clk);
        host->max_speed_hz = clk_hz;

        mpfs_spi_enable_ints(spi);

        /*
         * It is required to enable direct mode, otherwise control over the chip
         * select is relinquished to the hardware. SSELOUT is enabled too so we
         * can deal with active high targets.
         */
        spi->pending_slave_select = SSELOUT | SSEL_DIRECT;
        mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);

        control = mpfs_spi_read(spi, REG_CONTROL);

        control &= ~CONTROL_RESET;
        control |= CONTROL_ENABLE;

        mpfs_spi_write(spi, REG_CONTROL, control);
}

static inline void mpfs_spi_set_clk_gen(struct mpfs_spi *spi)
{
        u32 control;

        control = mpfs_spi_read(spi, REG_CONTROL);
        if (spi->clk_mode)
                control |= CONTROL_CLKMODE;
        else
                control &= ~CONTROL_CLKMODE;

        mpfs_spi_write(spi, REG_CLK_GEN, spi->clk_gen);
        mpfs_spi_write(spi, REG_CONTROL, control);
}

static inline void mpfs_spi_set_mode(struct mpfs_spi *spi, unsigned int mode)
{
        u32 mode_val;
        u32 control = mpfs_spi_read(spi, REG_CONTROL);

        switch (mode & SPI_MODE_X_MASK) {
        case SPI_MODE_0:
                mode_val = 0;
                break;
        case SPI_MODE_1:
                mode_val = CONTROL_SPH;
                break;
        case SPI_MODE_2:
                mode_val = CONTROL_SPO;
                break;
        case SPI_MODE_3:
                mode_val = CONTROL_SPH | CONTROL_SPO;
                break;
        }

        /*
         * Disable the SPI controller. Writes to the frame protocol have
         * no effect when the controller is enabled.
         */

        control &= ~CONTROL_ENABLE;
        mpfs_spi_write(spi, REG_CONTROL, control);

        control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
        control |= mode_val;

        mpfs_spi_write(spi, REG_CONTROL, control);

        control |= CONTROL_ENABLE;
        mpfs_spi_write(spi, REG_CONTROL, control);
}

static irqreturn_t mpfs_spi_interrupt(int irq, void *dev_id)
{
        struct spi_controller *host = dev_id;
        struct mpfs_spi *spi = spi_controller_get_devdata(host);
        u32 intfield = mpfs_spi_read(spi, REG_MIS) & 0xf;
        bool finalise = false;

        /* Interrupt line may be shared and not for us at all */
        if (intfield == 0)
                return IRQ_NONE;

        if (intfield & INT_RX_CHANNEL_OVERFLOW) {
                mpfs_spi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
                finalise = true;
                dev_err(&host->dev,
                        "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__,
                        spi->rx_len, spi->tx_len);
        }

        if (intfield & INT_TX_CHANNEL_UNDERRUN) {
                mpfs_spi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN);
                finalise = true;
                dev_err(&host->dev,
                        "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__,
                        spi->rx_len, spi->tx_len);
        }

        if (finalise)
                spi_finalize_current_transfer(host);

        return IRQ_HANDLED;
}

static int mpfs_spi_calculate_clkgen(struct mpfs_spi *spi,
                                     unsigned long target_hz)
{
        unsigned long clk_hz, spi_hz, clk_gen;

        clk_hz = clk_get_rate(spi->clk);
        if (!clk_hz)
                return -EINVAL;
        spi_hz = min(target_hz, clk_hz);

        /*
         * There are two possible clock modes for the controller generated
         * clock's division ratio:
         * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15.
         * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255.
         * First try mode 1, fall back to 0 and if we have tried both modes and
         * we /still/ can't get a good setting, we then throw the toys out of
         * the pram and give up
         * clk_gen is the register name for the clock divider on MPFS.
         */
        clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1;
        if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) {
                clk_gen = DIV_ROUND_UP(clk_hz, spi_hz);
                clk_gen = fls(clk_gen) - 1;

                if (clk_gen > CLK_GEN_MODE0_MAX)
                        return -EINVAL;

                spi->clk_mode = 0;
        } else {
                spi->clk_mode = 1;
        }

        spi->clk_gen = clk_gen;
        return 0;
}

static int mpfs_spi_transfer_one(struct spi_controller *host,
                                 struct spi_device *spi_dev,
                                 struct spi_transfer *xfer)
{
        struct mpfs_spi *spi = spi_controller_get_devdata(host);
        int ret;

        ret = mpfs_spi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz);
        if (ret) {
                dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz);
                return ret;
        }

        mpfs_spi_set_clk_gen(spi);

        spi->tx_buf = xfer->tx_buf;
        spi->rx_buf = xfer->rx_buf;
        spi->tx_len = xfer->len;
        spi->rx_len = xfer->len;
        spi->n_bytes = roundup_pow_of_two(DIV_ROUND_UP(xfer->bits_per_word, BITS_PER_BYTE));

        mpfs_spi_set_framesize(spi, xfer->bits_per_word);

        mpfs_spi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST);

        mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);

        while (spi->tx_len) {
                int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);

                mpfs_spi_write_fifo(spi, fifo_max);
                mpfs_spi_read_fifo(spi, fifo_max);
        }

        spi_finalize_current_transfer(host);
        return 1;
}

static int mpfs_spi_prepare_message(struct spi_controller *host,
                                    struct spi_message *msg)
{
        struct spi_device *spi_dev = msg->spi;
        struct mpfs_spi *spi = spi_controller_get_devdata(host);

        mpfs_spi_set_mode(spi, spi_dev->mode);

        return 0;
}

static int mpfs_spi_probe(struct platform_device *pdev)
{
        struct spi_controller *host;
        struct mpfs_spi *spi;
        struct resource *res;
        u32 num_cs;
        int ret = 0;

        host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi));
        if (!host)
                return dev_err_probe(&pdev->dev, -ENOMEM,
                                     "unable to allocate host for SPI controller\n");

        platform_set_drvdata(pdev, host);

        if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
                num_cs = MAX_CS;

        host->num_chipselect = num_cs;
        host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        host->use_gpio_descriptors = true;
        host->setup = mpfs_spi_setup;
        host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        host->transfer_one = mpfs_spi_transfer_one;
        host->prepare_message = mpfs_spi_prepare_message;
        host->set_cs = mpfs_spi_set_cs;

        spi = spi_controller_get_devdata(host);

        spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(spi->regs))
                return PTR_ERR(spi->regs);

        spi->irq = platform_get_irq(pdev, 0);
        if (spi->irq < 0)
                return spi->irq;

        ret = devm_request_irq(&pdev->dev, spi->irq, mpfs_spi_interrupt,
                               IRQF_SHARED, dev_name(&pdev->dev), host);
        if (ret)
                return dev_err_probe(&pdev->dev, ret,
                                     "could not request irq\n");

        spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
        if (IS_ERR(spi->clk))
                return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
                                     "could not get clk\n");

        mpfs_spi_init(host, spi);

        ret = devm_spi_register_controller(&pdev->dev, host);
        if (ret) {
                mpfs_spi_disable_ints(spi);
                mpfs_spi_disable(spi);
                return dev_err_probe(&pdev->dev, ret,
                                     "unable to register host for SPI controller\n");
        }

        dev_info(&pdev->dev, "Registered SPI controller %d\n", host->bus_num);

        return 0;
}

static void mpfs_spi_remove(struct platform_device *pdev)
{
        struct spi_controller *host  = platform_get_drvdata(pdev);
        struct mpfs_spi *spi = spi_controller_get_devdata(host);

        mpfs_spi_disable_ints(spi);
        mpfs_spi_disable(spi);
}

#define MICROCHIP_SPI_PM_OPS (NULL)

/*
 * Platform driver data structure
 */

#if defined(CONFIG_OF)
static const struct of_device_id mpfs_spi_dt_ids[] = {
        { .compatible = "microchip,mpfs-spi" },
        { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mpfs_spi_dt_ids);
#endif

static struct platform_driver mpfs_spi_driver = {
        .probe = mpfs_spi_probe,
        .driver = {
                .name = "microchip-spi",
                .pm = MICROCHIP_SPI_PM_OPS,
                .of_match_table = of_match_ptr(mpfs_spi_dt_ids),
        },
        .remove = mpfs_spi_remove,
};
module_platform_driver(mpfs_spi_driver);
MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");
MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
MODULE_LICENSE("GPL");