drivers/media/pci/netup_unidvb/netup_unidvb_spi.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
Extension
.c
Size
6070 bytes
Lines
241
Domain
Driver Families
Bucket
drivers/media
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct netup_spi_regs {
	__u8	data[1024];
	__le16	control_stat;
	__le16	clock_divider;
} __packed __aligned(1);

struct netup_spi {
	struct device			*dev;
	struct spi_controller		*ctlr;
	struct netup_spi_regs __iomem	*regs;
	u8 __iomem			*mmio;
	spinlock_t			lock;
	wait_queue_head_t		waitq;
	enum netup_spi_state		state;
};

static char netup_spi_name[64] = "fpga";

static struct mtd_partition netup_spi_flash_partitions = {
	.name = netup_spi_name,
	.size = 0x1000000, /* 16MB */
	.offset = 0,
	.mask_flags = MTD_CAP_ROM
};

static struct flash_platform_data spi_flash_data = {
	.name = "netup0_m25p128",
	.parts = &netup_spi_flash_partitions,
	.nr_parts = 1,
};

static struct spi_board_info netup_spi_board = {
	.modalias = "m25p128",
	.max_speed_hz = 11000000,
	.chip_select = 0,
	.mode = SPI_MODE_0,
	.platform_data = &spi_flash_data,
};

irqreturn_t netup_spi_interrupt(struct netup_spi *spi)
{
	u16 reg;
	unsigned long flags;

	if (!spi)
		return IRQ_NONE;

	spin_lock_irqsave(&spi->lock, flags);
	reg = readw(&spi->regs->control_stat);
	if (!(reg & NETUP_SPI_CTRL_IRQ)) {
		spin_unlock_irqrestore(&spi->lock, flags);
		dev_dbg(&spi->ctlr->dev,
			"%s(): not mine interrupt\n", __func__);
		return IRQ_NONE;
	}
	writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
	reg = readw(&spi->regs->control_stat);
	writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
	spi->state = SPI_STATE_DONE;
	wake_up(&spi->waitq);
	spin_unlock_irqrestore(&spi->lock, flags);
	dev_dbg(&spi->ctlr->dev,
		"%s(): SPI interrupt handled\n", __func__);
	return IRQ_HANDLED;
}

static int netup_spi_transfer(struct spi_controller *ctlr,
			      struct spi_message *msg)
{
	struct netup_spi *spi = spi_controller_get_devdata(ctlr);
	struct spi_transfer *t;
	int result = 0;
	u32 tr_size;

	/* reset CS */
	writew(NETUP_SPI_CTRL_LAST_CS, &spi->regs->control_stat);
	writew(0, &spi->regs->control_stat);
	list_for_each_entry(t, &msg->transfers, transfer_list) {
		tr_size = t->len;
		while (tr_size) {
			u32 frag_offset = t->len - tr_size;
			u32 frag_size = (tr_size > sizeof(spi->regs->data)) ?
					sizeof(spi->regs->data) : tr_size;
			int frag_last = 0;

			if (list_is_last(&t->transfer_list,
					&msg->transfers) &&
					frag_offset + frag_size == t->len) {
				frag_last = 1;
			}

Annotation

Implementation Notes