// 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 #include #include #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 "); MODULE_DESCRIPTION("KEBA SPI host controller driver"); MODULE_LICENSE("GPL");