// SPDX-License-Identifier: GPL-2.0-or-later /* * Cadence SPI controller driver (host and target mode) * * Copyright (C) 2008 - 2014 Xilinx, Inc. * * based on Blackfin On-Chip SPI Driver (spi_bfin5xx.c) */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> #include <linux/spi/spi.h> /* Name of this driver */ #define CDNS_SPI_NAME … /* Register offset definitions */ #define CDNS_SPI_CR … #define CDNS_SPI_ISR … #define CDNS_SPI_IER … #define CDNS_SPI_IDR … #define CDNS_SPI_IMR … #define CDNS_SPI_ER … #define CDNS_SPI_DR … #define CDNS_SPI_TXD … #define CDNS_SPI_RXD … #define CDNS_SPI_SICR … #define CDNS_SPI_THLD … #define SPI_AUTOSUSPEND_TIMEOUT … /* * SPI Configuration Register bit Masks * * This register contains various control bits that affect the operation * of the SPI controller */ #define CDNS_SPI_CR_MANSTRT … #define CDNS_SPI_CR_CPHA … #define CDNS_SPI_CR_CPOL … #define CDNS_SPI_CR_SSCTRL … #define CDNS_SPI_CR_PERI_SEL … #define CDNS_SPI_CR_BAUD_DIV … #define CDNS_SPI_CR_MSTREN … #define CDNS_SPI_CR_MANSTRTEN … #define CDNS_SPI_CR_SSFORCE … #define CDNS_SPI_CR_BAUD_DIV_4 … #define CDNS_SPI_CR_DEFAULT … /* * SPI Configuration Register - Baud rate and target select * * These are the values used in the calculation of baud rate divisor and * setting the target select. */ #define CDNS_SPI_BAUD_DIV_MAX … #define CDNS_SPI_BAUD_DIV_MIN … #define CDNS_SPI_BAUD_DIV_SHIFT … #define CDNS_SPI_SS_SHIFT … #define CDNS_SPI_SS0 … #define CDNS_SPI_NOSS … /* * SPI Interrupt Registers bit Masks * * All the four interrupt registers (Status/Mask/Enable/Disable) have the same * bit definitions. */ #define CDNS_SPI_IXR_TXOW … #define CDNS_SPI_IXR_MODF … #define CDNS_SPI_IXR_RXNEMTY … #define CDNS_SPI_IXR_DEFAULT … #define CDNS_SPI_IXR_TXFULL … #define CDNS_SPI_IXR_ALL … /* * SPI Enable Register bit Masks * * This register is used to enable or disable the SPI controller */ #define CDNS_SPI_ER_ENABLE … #define CDNS_SPI_ER_DISABLE … /* Default number of chip select lines */ #define CDNS_SPI_DEFAULT_NUM_CS … /** * struct cdns_spi - This definition defines spi driver instance * @regs: Virtual address of the SPI controller registers * @ref_clk: Pointer to the peripheral clock * @pclk: Pointer to the APB clock * @clk_rate: Reference clock frequency, taken from @ref_clk * @speed_hz: Current SPI bus clock speed in Hz * @txbuf: Pointer to the TX buffer * @rxbuf: Pointer to the RX buffer * @tx_bytes: Number of bytes left to transfer * @rx_bytes: Number of bytes requested * @dev_busy: Device busy flag * @is_decoded_cs: Flag for decoder property set or not * @tx_fifo_depth: Depth of the TX FIFO * @rstc: Optional reset control for SPI controller */ struct cdns_spi { … }; /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { … } static inline void cdns_spi_write(struct cdns_spi *xspi, u32 offset, u32 val) { … } /** * cdns_spi_init_hw - Initialize the hardware and configure the SPI controller * @xspi: Pointer to the cdns_spi structure * @is_target: Flag to indicate target or host mode * * On reset the SPI controller is configured to target or host mode. * In host mode baud rate divisor is set to 4, threshold value for TX FIFO * not full interrupt is set to 1 and size of the word to be transferred as 8 bit. * * This function initializes the SPI controller to disable and clear all the * interrupts, enable manual target select and manual start, deselect all the * chip select lines, and enable the SPI controller. */ static void cdns_spi_init_hw(struct cdns_spi *xspi, bool is_target) { … } /** * cdns_spi_chipselect - Select or deselect the chip select line * @spi: Pointer to the spi_device structure * @is_high: Select(0) or deselect (1) the chip select line */ static void cdns_spi_chipselect(struct spi_device *spi, bool is_high) { … } /** * cdns_spi_config_clock_mode - Sets clock polarity and phase * @spi: Pointer to the spi_device structure * * Sets the requested clock polarity and phase. */ static void cdns_spi_config_clock_mode(struct spi_device *spi) { … } /** * cdns_spi_config_clock_freq - Sets clock frequency * @spi: Pointer to the spi_device structure * @transfer: Pointer to the spi_transfer structure which provides * information about next transfer setup parameters * * Sets the requested clock frequency. * Note: If the requested frequency is not an exact match with what can be * obtained using the prescalar value the driver sets the clock frequency which * is lower than the requested frequency (maximum lower) for the transfer. If * the requested frequency is higher or lower than that is supported by the SPI * controller the driver will set the highest or lowest frequency supported by * controller. */ static void cdns_spi_config_clock_freq(struct spi_device *spi, struct spi_transfer *transfer) { … } /** * cdns_spi_setup_transfer - Configure SPI controller for specified transfer * @spi: Pointer to the spi_device structure * @transfer: Pointer to the spi_transfer structure which provides * information about next transfer setup parameters * * Sets the operational mode of SPI controller for the next SPI transfer and * sets the requested clock frequency. * * Return: Always 0 */ static int cdns_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *transfer) { … } /** * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO * @xspi: Pointer to the cdns_spi structure * @ntx: Number of bytes to pack into the TX FIFO * @nrx: Number of bytes to drain from the RX FIFO */ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) { … } /** * cdns_spi_irq - Interrupt service routine of the SPI controller * @irq: IRQ number * @dev_id: Pointer to the xspi structure * * This function handles TX empty and Mode Fault interrupts only. * On TX empty interrupt this function reads the received data from RX FIFO and * fills the TX FIFO if there is any data remaining to be transferred. * On Mode Fault interrupt this function indicates that transfer is completed, * the SPI subsystem will identify the error as the remaining bytes to be * transferred is non-zero. * * Return: IRQ_HANDLED when handled; IRQ_NONE otherwise. */ static irqreturn_t cdns_spi_irq(int irq, void *dev_id) { … } static int cdns_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) { … } /** * cdns_transfer_one - Initiates the SPI transfer * @ctlr: Pointer to spi_controller structure * @spi: Pointer to the spi_device structure * @transfer: Pointer to the spi_transfer structure which provides * information about next transfer parameters * * This function in host mode fills the TX FIFO, starts the SPI transfer and * returns a positive transfer count so that core will wait for completion. * This function in target mode fills the TX FIFO and wait for transfer trigger. * * Return: Number of bytes transferred in the last transfer */ static int cdns_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *transfer) { … } /** * cdns_prepare_transfer_hardware - Prepares hardware for transfer. * @ctlr: Pointer to the spi_controller structure which provides * information about the controller. * * This function enables SPI host controller. * * Return: 0 always */ static int cdns_prepare_transfer_hardware(struct spi_controller *ctlr) { … } /** * cdns_unprepare_transfer_hardware - Relaxes hardware after transfer * @ctlr: Pointer to the spi_controller structure which provides * information about the controller. * * This function disables the SPI host controller when no target selected. * This function flush out if any pending data in FIFO. * * Return: 0 always */ static int cdns_unprepare_transfer_hardware(struct spi_controller *ctlr) { … } /** * cdns_spi_detect_fifo_depth - Detect the FIFO depth of the hardware * @xspi: Pointer to the cdns_spi structure * * The depth of the TX FIFO is a synthesis configuration parameter of the SPI * IP. The FIFO threshold register is sized so that its maximum value can be the * FIFO size - 1. This is used to detect the size of the FIFO. */ static void cdns_spi_detect_fifo_depth(struct cdns_spi *xspi) { … } /** * cdns_target_abort - Abort target transfer * @ctlr: Pointer to the spi_controller structure * * This function abort target transfer if there any transfer timeout. * * Return: 0 always */ static int cdns_target_abort(struct spi_controller *ctlr) { … } /** * cdns_spi_probe - Probe method for the SPI driver * @pdev: Pointer to the platform_device structure * * This function initializes the driver data structures and the hardware. * * Return: 0 on success and error value on error */ static int cdns_spi_probe(struct platform_device *pdev) { … } /** * cdns_spi_remove - Remove method for the SPI driver * @pdev: Pointer to the platform_device structure * * This function is called if a device is physically removed from the system or * if the driver module is being unloaded. It frees all resources allocated to * the device. */ static void cdns_spi_remove(struct platform_device *pdev) { … } /** * cdns_spi_suspend - Suspend method for the SPI driver * @dev: Address of the platform_device structure * * This function disables the SPI controller and * changes the driver state to "suspend" * * Return: 0 on success and error value on error */ static int __maybe_unused cdns_spi_suspend(struct device *dev) { … } /** * cdns_spi_resume - Resume method for the SPI driver * @dev: Address of the platform_device structure * * This function changes the driver state to "ready" * * Return: 0 on success and error value on error */ static int __maybe_unused cdns_spi_resume(struct device *dev) { … } /** * cdns_spi_runtime_resume - Runtime resume method for the SPI driver * @dev: Address of the platform_device structure * * This function enables the clocks * * Return: 0 on success and error value on error */ static int __maybe_unused cdns_spi_runtime_resume(struct device *dev) { … } /** * cdns_spi_runtime_suspend - Runtime suspend method for the SPI driver * @dev: Address of the platform_device structure * * This function disables the clocks * * Return: Always 0 */ static int __maybe_unused cdns_spi_runtime_suspend(struct device *dev) { … } static const struct dev_pm_ops cdns_spi_dev_pm_ops = …; static const struct of_device_id cdns_spi_of_match[] = …; MODULE_DEVICE_TABLE(of, cdns_spi_of_match); /* cdns_spi_driver - This structure defines the SPI subsystem platform driver */ static struct platform_driver cdns_spi_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;