text: // 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"
  
  static struct mtd_partition p2kr0_spi0_parts[] = {
  	{ .name = "SLOT_0",	.size = 7798784,		.offset = 0,                },
  	{ .name = "SLOT_1",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "SLOT_2",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "SLOT_3",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "CS0_EXTRA",	.size = MTDPART_SIZ_FULL,	.offset = MTDPART_OFS_NXTBLK},
  };
  
  static struct mtd_partition p2kr0_spi1_parts[] = {
  	{ .name = "SLOT_4",	.size = 7798784,		.offset = 0,                },
  	{ .name = "SLOT_5",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "SLOT_6",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "SLOT_7",	.size = 7798784,		.offset = MTDPART_OFS_NXTBLK},
  	{ .name = "CS1_EXTRA",	.size = MTDPART_SIZ_FULL,	.offset = MTDPART_OFS_NXTBLK},
  };
  
  static struct flash_platform_data p2kr0_spi0_pdata = {
  	.name =		"SPI0",
  	.nr_parts =	ARRAY_SIZE(p2kr0_spi0_parts),
  	.parts =	p2kr0_spi0_parts,
  };
  static struct flash_platform_data p2kr0_spi1_pdata = {
  	.name =		"SPI1",
  	.nr_parts =	ARRAY_SIZE(p2kr0_spi1_parts),
  	.parts =	p2kr0_spi1_parts,
  };
  
  static struct spi_board_info p2kr0_board_info[] = {
  	{
  		.modalias =		"n25q256a11",
  		.bus_num =		1,
  		.chip_select =		0,
  		.mode =			SPI_MODE_0,
  		.platform_data =	&p2kr0_spi0_pdata
  	},
  	{
  		.modalias =		"n25q256a11",
  		.bus_num =		1,
  		.chip_select =		1,
  		.mode =			SPI_MODE_0,
  		.platform_data =	&p2kr0_spi1_pdata
  	},
  };
  
  /***************
   * 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;
  	struct device      *dev;
  };
  
  struct kp_spi_controller_state {
  	void __iomem   *base;
  	s64             conf_cache;
  };
  
  union kp_spi_config {
  	/* use this to access individual elements */
  	struct __packed spi_config_bitfield {
  		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 __packed spi_status_bitfield {
  		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 __packed spi_ffctrl_bitfield {
  		unsigned int ffstart :  1; /* FIFO Start */
  		unsigned int         : 31;
  	} bitfield;
  	u32 reg;
  };
  
  /***************
   * SPI Helpers *
   ***************/
  	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(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, 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;
  	int res;
  	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++;
  
  			res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
  						      KP_SPI_REG_STATUS_TXS);
  			if (res < 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);
  			res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
  						      KP_SPI_REG_STATUS_RXS);
  			if (res < 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??
  		//Ths 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->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 int 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 && !transfer->rx_buf &&
  		    transfer->len) {
  			status = -EINVAL;
  			goto error;
  		}
  
  		/* transfer */
  		if (transfer->len) {
  			unsigned int word_len = spidev->bits_per_word;
  			unsigned int 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;
  			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;
  				goto error;
  			}
  		}
  
  		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;
  
  error:
  	m->status = status;
  	return status;
  }
  
  	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, "%s: platform_data is NULL\n", __func__);
  		return -ENODEV;
  	}
  
  	master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
  	if (!master) {
  		dev_err(&pldev->dev, "%s: master allocation failed\n",
  			__func__);
  		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;
  
  	r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
  	if (!r) {
  		dev_err(&pldev->dev, "%s: Unable to get platform resources\n",
  			__func__);
  		status = -ENODEV;
  		goto free_master;
  	}
  
  	kpspi->base = devm_ioremap_nocache(&pldev->dev, r->start,
  					   resource_size(r));
  
  	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;
  	}
  
  	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");
  