Unverified Commit 1a90aae3 authored by Gerhard Engleder's avatar Gerhard Engleder Committed by Mark Brown
Browse files

spi: spi-kspi2: Add KEBA SPI controller support



The KEBA SPI controller is found in the system FPGA of KEBA PLC devices.
It is used to connect the SPI flash chip of the FPGA and some SPI
devices.

It is a simple SPI controller with configurable speed. The hardware
supports only single byte transfers. There are no FIFOs or interrupts.

Signed-off-by: default avatarGerhard Engleder <eg@keba.com>
Link: https://patch.msgid.link/20241202194003.57679-1-gerhard@engleder-embedded.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 577f1cf7
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -542,6 +542,18 @@ config SPI_JCORE
	  This enables support for the SPI master controller in the J-Core
	  synthesizable, open source SoC.

config SPI_KSPI2
	tristate "Support for KEBA SPI master type 2 hardware"
	depends on HAS_IOMEM
	depends on KEBA_CP500 || COMPILE_TEST
	select AUXILIARY_BUS
	help
	  This driver supports KEBA SPI master type 2 FPGA implementation,
	  as found on CP500 devices for example.

	  This driver can also be built as a module. If so, the module
	  will be called spi-kspi2.

config SPI_LM70_LLP
	tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
	depends on PARPORT
+1 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_INTEL_PCI) += spi-intel-pci.o
obj-$(CONFIG_SPI_INTEL_PLATFORM)	+= spi-intel-platform.o
obj-$(CONFIG_SPI_LANTIQ_SSC)		+= spi-lantiq-ssc.o
obj-$(CONFIG_SPI_JCORE)			+= spi-jcore.o
obj-$(CONFIG_SPI_KSPI2)			+= spi-kspi2.o
obj-$(CONFIG_SPI_LJCA)			+= spi-ljca.o
obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
obj-$(CONFIG_SPI_LOONGSON_CORE)		+= spi-loongson-core.o
+431 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) KEBA Industrial Automation Gmbh 2024
 *
 * Driver for KEBA SPI host controller type 2 FPGA IP core
 */

#include <linux/iopoll.h>
#include <linux/misc/keba.h>
#include <linux/spi/spi.h>

#define KSPI2 "kspi2"

#define KSPI2_CLK_FREQ_REG	0x03
#define  KSPI2_CLK_FREQ_MASK	0x0f
#define  KSPI2_CLK_FREQ_62_5M	0x0
#define  KSPI2_CLK_FREQ_33_3M	0x1
#define  KSPI2_CLK_FREQ_125M	0x2
#define  KSPI2_CLK_FREQ_50M	0x3
#define  KSPI2_CLK_FREQ_100M	0x4

#define KSPI2_CONTROL_REG		0x04
#define  KSPI2_CONTROL_CLK_DIV_MAX	0x0f
#define  KSPI2_CONTROL_CLK_DIV_MASK	0x0f
#define  KSPI2_CONTROL_CPHA		0x10
#define  KSPI2_CONTROL_CPOL		0x20
#define  KSPI2_CONTROL_CLK_MODE_MASK	0x30
#define  KSPI2_CONTROL_INIT		KSPI2_CONTROL_CLK_DIV_MAX

#define KSPI2_STATUS_REG	0x08
#define  KSPI2_STATUS_IN_USE	0x01
#define  KSPI2_STATUS_BUSY	0x02

#define KSPI2_DATA_REG	0x0c

#define KSPI2_CS_NR_REG		0x10
#define  KSPI2_CS_NR_NONE	0xff

#define KSPI2_MODE_BITS	(SPI_CPHA | SPI_CPOL)
#define KSPI2_NUM_CS	255

#define KSPI2_SPEED_HZ_MIN(kspi)	(kspi->base_speed_hz / 65536)
#define KSPI2_SPEED_HZ_MAX(kspi)	(kspi->base_speed_hz / 2)

/* timeout is 10 times the time to transfer one byte at slowest clock */
#define KSPI2_XFER_TIMEOUT_US(kspi)	(USEC_PER_SEC / \
					 KSPI2_SPEED_HZ_MIN(kspi) * 8 * 10)

#define KSPI2_INUSE_SLEEP_US	(2 * USEC_PER_MSEC)
#define KSPI2_INUSE_TIMEOUT_US	(10 * USEC_PER_SEC)

struct kspi2 {
	struct keba_spi_auxdev *auxdev;
	void __iomem *base;
	struct spi_controller *host;

	u32 base_speed_hz; /* SPI base clock frequency in HZ */
	u8 control_shadow;

	struct spi_device **device;
	int device_size;
};

static int kspi2_inuse_lock(struct kspi2 *kspi)
{
	u8 sts;
	int ret;

	/*
	 * The SPI controller has an IN_USE bit for locking access to the
	 * controller. This enables the use of the SPI controller by other none
	 * Linux processors.
	 *
	 * If the SPI controller is free, then the first read returns
	 * IN_USE == 0. After that the SPI controller is locked and further
	 * reads of IN_USE return 1.
	 *
	 * The SPI controller is unlocked by writing 1 into IN_USE.
	 *
	 * The IN_USE bit acts as a hardware semaphore for the SPI controller.
	 * Poll for semaphore, but sleep while polling to free the CPU.
	 */
	ret = readb_poll_timeout(kspi->base + KSPI2_STATUS_REG,
				 sts, (sts & KSPI2_STATUS_IN_USE) == 0,
				 KSPI2_INUSE_SLEEP_US, KSPI2_INUSE_TIMEOUT_US);
	if (ret != 0)
		dev_warn(&kspi->auxdev->auxdev.dev, "%s err!\n", __func__);

	return ret;
}

static void kspi2_inuse_unlock(struct kspi2 *kspi)
{
	/* unlock the controller by writing 1 into IN_USE */
	iowrite8(KSPI2_STATUS_IN_USE, kspi->base + KSPI2_STATUS_REG);
}

static int kspi2_prepare_hardware(struct spi_controller *host)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);

	/* lock hardware semaphore before actual use of controller */
	return kspi2_inuse_lock(kspi);
}

static int kspi2_unprepare_hardware(struct spi_controller *host)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);

	/* unlock hardware semaphore after actual use of controller */
	kspi2_inuse_unlock(kspi);

	return 0;
}

static u8 kspi2_calc_minimal_divider(struct kspi2 *kspi, u32 max_speed_hz)
{
	u8 div;

	/*
	 * Divider values 2, 4, 8, 16, ..., 65536 are possible. They are coded
	 * as 0, 1, 2, 3, ..., 15 in the CONTROL_CLK_DIV bit.
	 */
	for (div = 0; div < KSPI2_CONTROL_CLK_DIV_MAX; div++) {
		if ((kspi->base_speed_hz >> (div + 1)) <= max_speed_hz)
			return div;
	}

	/* return divider for slowest clock if loop fails to find one */
	return KSPI2_CONTROL_CLK_DIV_MAX;
}

static void kspi2_write_control_reg(struct kspi2 *kspi, u8 val, u8 mask)
{
	/* write control register only when necessary to improve performance */
	if (val != (kspi->control_shadow & mask)) {
		kspi->control_shadow = (kspi->control_shadow & ~mask) | val;
		iowrite8(kspi->control_shadow, kspi->base + KSPI2_CONTROL_REG);
	}
}

static int kspi2_txrx_byte(struct kspi2 *kspi, u8 tx, u8 *rx)
{
	u8 sts;
	int ret;

	/* start transfer by writing TX byte */
	iowrite8(tx, kspi->base + KSPI2_DATA_REG);

	/* wait till finished (BUSY == 0) */
	ret = readb_poll_timeout(kspi->base + KSPI2_STATUS_REG,
				 sts, (sts & KSPI2_STATUS_BUSY) == 0,
				 0, KSPI2_XFER_TIMEOUT_US(kspi));
	if (ret != 0)
		return ret;

	/* read RX byte */
	if (rx)
		*rx = ioread8(kspi->base + KSPI2_DATA_REG);

	return 0;
}

static int kspi2_process_transfer(struct kspi2 *kspi, struct spi_transfer *t)
{
	u8 tx = 0;
	u8 rx;
	int i;
	int ret;

	for (i = 0; i < t->len; i++) {
		if (t->tx_buf)
			tx = ((const u8 *)t->tx_buf)[i];

		ret = kspi2_txrx_byte(kspi, tx, &rx);
		if (ret)
			return ret;

		if (t->rx_buf)
			((u8 *)t->rx_buf)[i] = rx;
	}

	return 0;
}

static int kspi2_setup_transfer(struct kspi2 *kspi,
				 struct spi_device *spi,
				 struct spi_transfer *t)
{
	u32 max_speed_hz = spi->max_speed_hz;
	u8 clk_div;

	/*
	 * spi_device (spi) has default parameters. Some of these can be
	 * overwritten by parameters in spi_transfer (t).
	 */
	if (t->bits_per_word && ((t->bits_per_word % 8) != 0)) {
		dev_err(&spi->dev, "Word width %d not supported!\n",
			t->bits_per_word);

		return -EINVAL;
	}

	if (t->speed_hz && (t->speed_hz < max_speed_hz))
		max_speed_hz = t->speed_hz;

	clk_div = kspi2_calc_minimal_divider(kspi, max_speed_hz);
	kspi2_write_control_reg(kspi, clk_div, KSPI2_CONTROL_CLK_DIV_MASK);

	return 0;
}

static int kspi2_transfer_one(struct spi_controller *host,
			      struct spi_device *spi,
			      struct spi_transfer *t)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);
	int ret;

	ret = kspi2_setup_transfer(kspi, spi, t);
	if (ret != 0)
		return ret;

	if (t->len) {
		ret = kspi2_process_transfer(kspi, t);
		if (ret != 0)
			return ret;
	}

	return 0;
}

static void kspi2_set_cs(struct spi_device *spi, bool enable)
{
	struct spi_controller *host = spi->controller;
	struct kspi2 *kspi = spi_controller_get_devdata(host);

	/* controller is using active low chip select signals by design */
	if (!enable)
		iowrite8(spi_get_chipselect(spi, 0), kspi->base + KSPI2_CS_NR_REG);
	else
		iowrite8(KSPI2_CS_NR_NONE, kspi->base + KSPI2_CS_NR_REG);
}

static int kspi2_prepare_message(struct spi_controller *host,
				 struct spi_message *msg)
{
	struct kspi2 *kspi = spi_controller_get_devdata(host);
	struct spi_device *spi = msg->spi;
	u8 mode = 0;

	/* setup SPI clock phase and polarity */
	if (spi->mode & SPI_CPHA)
		mode |= KSPI2_CONTROL_CPHA;
	if (spi->mode & SPI_CPOL)
		mode |= KSPI2_CONTROL_CPOL;
	kspi2_write_control_reg(kspi, mode, KSPI2_CONTROL_CLK_MODE_MASK);

	return 0;
}

static int kspi2_setup(struct spi_device *spi)
{
	struct kspi2 *kspi = spi_controller_get_devdata(spi->controller);

	/*
	 * Check only parameters. Actual setup is done in kspi2_prepare_message
	 * and directly before the SPI transfer starts.
	 */

	if (spi->mode & ~KSPI2_MODE_BITS) {
		dev_err(&spi->dev, "Mode %d not supported!\n", spi->mode);

		return -EINVAL;
	}

	if ((spi->bits_per_word % 8) != 0) {
		dev_err(&spi->dev, "Word width %d not supported!\n",
			spi->bits_per_word);

		return -EINVAL;
	}

	if ((spi->max_speed_hz == 0) ||
	    (spi->max_speed_hz > KSPI2_SPEED_HZ_MAX(kspi)))
		spi->max_speed_hz = KSPI2_SPEED_HZ_MAX(kspi);

	if (spi->max_speed_hz < KSPI2_SPEED_HZ_MIN(kspi)) {
		dev_err(&spi->dev, "Requested speed of %d Hz is too low!\n",
			spi->max_speed_hz);

		return -EINVAL;
	}

	return 0;
}

static void kspi2_unregister_devices(struct kspi2 *kspi)
{
	int i;

	for (i = 0; i < kspi->device_size; i++) {
		struct spi_device *device = kspi->device[i];

		if (device)
			spi_unregister_device(device);
	}
}

static int kspi2_register_devices(struct kspi2 *kspi)
{
	struct spi_board_info *info = kspi->auxdev->info;
	int i;

	/* register all known SPI devices */
	for (i = 0; i < kspi->auxdev->info_size; i++) {
		struct spi_device *device = spi_new_device(kspi->host, &info[i]);

		if (!device) {
			kspi2_unregister_devices(kspi);

			return -ENODEV;
		}
		kspi->device[i] = device;
	}

	return 0;
}

static void kspi2_init(struct kspi2 *kspi)
{
	iowrite8(KSPI2_CONTROL_INIT, kspi->base + KSPI2_CONTROL_REG);
	kspi->control_shadow = KSPI2_CONTROL_INIT;

	iowrite8(KSPI2_CS_NR_NONE, kspi->base + KSPI2_CS_NR_REG);
}

static int kspi2_probe(struct auxiliary_device *auxdev,
		       const struct auxiliary_device_id *id)
{
	struct device *dev = &auxdev->dev;
	struct spi_controller *host;
	struct kspi2 *kspi;
	u8 clk_reg;
	int ret;

	host = devm_spi_alloc_host(dev, sizeof(struct kspi2));
	if (!host)
		return -ENOMEM;
	kspi = spi_controller_get_devdata(host);
	kspi->auxdev = container_of(auxdev, struct keba_spi_auxdev, auxdev);
	kspi->host = host;
	kspi->device = devm_kcalloc(dev, kspi->auxdev->info_size,
				    sizeof(*kspi->device), GFP_KERNEL);
	if (!kspi->device)
		return -ENOMEM;
	kspi->device_size = kspi->auxdev->info_size;
	auxiliary_set_drvdata(auxdev, kspi);

	kspi->base = devm_ioremap_resource(dev, &kspi->auxdev->io);
	if (IS_ERR(kspi->base))
		return PTR_ERR(kspi->base);

	/* read the SPI base clock frequency */
	clk_reg = ioread8(kspi->base + KSPI2_CLK_FREQ_REG);
	switch (clk_reg & KSPI2_CLK_FREQ_MASK) {
	case KSPI2_CLK_FREQ_62_5M:
		kspi->base_speed_hz = 62500000; break;
	case KSPI2_CLK_FREQ_33_3M:
		kspi->base_speed_hz = 33333333; break;
	case KSPI2_CLK_FREQ_125M:
		kspi->base_speed_hz = 125000000; break;
	case KSPI2_CLK_FREQ_50M:
		kspi->base_speed_hz = 50000000; break;
	case KSPI2_CLK_FREQ_100M:
		kspi->base_speed_hz = 100000000; break;
	default:
		dev_err(dev, "Undefined SPI base clock frequency!\n");
		return -ENODEV;
	}

	kspi2_init(kspi);

	host->bus_num = -1;
	host->num_chipselect = KSPI2_NUM_CS;
	host->mode_bits = KSPI2_MODE_BITS;
	host->setup = kspi2_setup;
	host->prepare_transfer_hardware = kspi2_prepare_hardware;
	host->unprepare_transfer_hardware = kspi2_unprepare_hardware;
	host->prepare_message = kspi2_prepare_message;
	host->set_cs = kspi2_set_cs;
	host->transfer_one = kspi2_transfer_one;
	ret = devm_spi_register_controller(dev, host);
	if (ret) {
		dev_err(dev, "Failed to register host (%d)!\n", ret);
		return ret;
	}

	ret = kspi2_register_devices(kspi);
	if (ret) {
		dev_err(dev, "Failed to register devices (%d)!\n", ret);
		return ret;
	}

	return 0;
}

static void kspi2_remove(struct auxiliary_device *auxdev)
{
	struct kspi2 *kspi = auxiliary_get_drvdata(auxdev);

	kspi2_unregister_devices(kspi);
}

static const struct auxiliary_device_id kspi2_devtype_aux[] = {
	{ .name = "keba.spi" },
	{ },
};
MODULE_DEVICE_TABLE(auxiliary, kspi2_devtype_aux);

static struct auxiliary_driver kspi2_driver_aux = {
	.name = KSPI2,
	.id_table = kspi2_devtype_aux,
	.probe = kspi2_probe,
	.remove = kspi2_remove,
};
module_auxiliary_driver(kspi2_driver_aux);

MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>");
MODULE_DESCRIPTION("KEBA SPI host controller driver");
MODULE_LICENSE("GPL");