drivers/spi/spi-sifive.c
Source file repositories/reference/linux-study-clean/drivers/spi/spi-sifive.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/spi/spi-sifive.c- Extension
.c- Size
- 13593 bytes
- Lines
- 465
- Domain
- Driver Families
- Bucket
- drivers/spi
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk.hlinux/module.hlinux/interrupt.hlinux/of.hlinux/platform_device.hlinux/spi/spi.hlinux/io.hlinux/log2.h
Detected Declarations
struct sifive_spifunction sifive_spi_writefunction sifive_spi_readfunction sifive_spi_initfunction sifive_spi_prepare_messagefunction sifive_spi_set_csfunction sifive_spi_prep_transferfunction sifive_spi_irqfunction sifive_spi_waitfunction sifive_spi_txfunction sifive_spi_rxfunction sifive_spi_transfer_onefunction sifive_spi_probefunction sifive_spi_removefunction sifive_spi_suspendfunction sifive_spi_resume
Annotated Snippet
struct sifive_spi {
void __iomem *regs; /* virt. address of control registers */
struct clk *clk; /* bus clock */
unsigned int fifo_depth; /* fifo depth in words */
u32 cs_inactive; /* level of the CS pins when inactive */
struct completion done; /* wake-up from interrupt */
};
static void sifive_spi_write(struct sifive_spi *spi, int offset, u32 value)
{
iowrite32(value, spi->regs + offset);
}
static u32 sifive_spi_read(struct sifive_spi *spi, int offset)
{
return ioread32(spi->regs + offset);
}
static void sifive_spi_init(struct sifive_spi *spi)
{
/* Watermark interrupts are disabled by default */
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
/* Default watermark FIFO threshold values */
sifive_spi_write(spi, SIFIVE_SPI_REG_TXMARK, 1);
sifive_spi_write(spi, SIFIVE_SPI_REG_RXMARK, 0);
/* Set CS/SCK Delays and Inactive Time to defaults */
sifive_spi_write(spi, SIFIVE_SPI_REG_DELAY0,
SIFIVE_SPI_DELAY0_CSSCK(1) |
SIFIVE_SPI_DELAY0_SCKCS(1));
sifive_spi_write(spi, SIFIVE_SPI_REG_DELAY1,
SIFIVE_SPI_DELAY1_INTERCS(1) |
SIFIVE_SPI_DELAY1_INTERXFR(0));
/* Exit specialized memory-mapped SPI flash mode */
sifive_spi_write(spi, SIFIVE_SPI_REG_FCTRL, 0);
}
static int
sifive_spi_prepare_message(struct spi_controller *host, struct spi_message *msg)
{
struct sifive_spi *spi = spi_controller_get_devdata(host);
struct spi_device *device = msg->spi;
/* Update the chip select polarity */
if (device->mode & SPI_CS_HIGH)
spi->cs_inactive &= ~BIT(spi_get_chipselect(device, 0));
else
spi->cs_inactive |= BIT(spi_get_chipselect(device, 0));
sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, spi->cs_inactive);
/* Select the correct device */
sifive_spi_write(spi, SIFIVE_SPI_REG_CSID, spi_get_chipselect(device, 0));
/* Set clock mode */
sifive_spi_write(spi, SIFIVE_SPI_REG_SCKMODE,
device->mode & SIFIVE_SPI_SCKMODE_MODE_MASK);
return 0;
}
static void sifive_spi_set_cs(struct spi_device *device, bool is_high)
{
struct sifive_spi *spi = spi_controller_get_devdata(device->controller);
/* Reverse polarity is handled by SCMR/CPOL. Not inverted CS. */
if (device->mode & SPI_CS_HIGH)
is_high = !is_high;
sifive_spi_write(spi, SIFIVE_SPI_REG_CSMODE, is_high ?
SIFIVE_SPI_CSMODE_MODE_AUTO :
SIFIVE_SPI_CSMODE_MODE_HOLD);
}
static int
sifive_spi_prep_transfer(struct sifive_spi *spi, struct spi_device *device,
struct spi_transfer *t)
{
u32 cr;
unsigned int mode;
/* Calculate and program the clock rate */
cr = DIV_ROUND_UP(clk_get_rate(spi->clk) >> 1, t->speed_hz) - 1;
cr &= SIFIVE_SPI_SCKDIV_DIV_MASK;
sifive_spi_write(spi, SIFIVE_SPI_REG_SCKDIV, cr);
mode = max_t(unsigned int, t->rx_nbits, t->tx_nbits);
/* Set frame format */
Annotation
- Immediate include surface: `linux/clk.h`, `linux/module.h`, `linux/interrupt.h`, `linux/of.h`, `linux/platform_device.h`, `linux/spi/spi.h`, `linux/io.h`, `linux/log2.h`.
- Detected declarations: `struct sifive_spi`, `function sifive_spi_write`, `function sifive_spi_read`, `function sifive_spi_init`, `function sifive_spi_prepare_message`, `function sifive_spi_set_cs`, `function sifive_spi_prep_transfer`, `function sifive_spi_irq`, `function sifive_spi_wait`, `function sifive_spi_tx`.
- Atlas domain: Driver Families / drivers/spi.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.