drivers/spi/spi-amlogic-spisg.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-amlogic-spisg.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-amlogic-spisg.c
Extension
.c
Size
23836 bytes
Lines
881
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct spisg_sg_link {
#define LINK_ADDR_VALID		BIT(0)
#define LINK_ADDR_EOC		BIT(1)
#define LINK_ADDR_IRQ		BIT(2)
#define LINK_ADDR_ACT		GENMASK(5, 3)
#define LINK_ADDR_RING		BIT(6)
#define LINK_ADDR_LEN		GENMASK(31, 8)
	u32			addr;
	u32			addr1;
};

struct spisg_descriptor {
	u32				cfg_start;
	u32				cfg_bus;
	u64				tx_paddr;
	u64				rx_paddr;
};

struct spisg_descriptor_extra {
	struct spisg_sg_link		*tx_ccsg;
	struct spisg_sg_link		*rx_ccsg;
	int				tx_ccsg_len;
	int				rx_ccsg_len;
};

struct spisg_device {
	struct spi_controller		*controller;
	struct platform_device		*pdev;
	struct regmap			*map;
	struct clk			*core;
	struct clk			*pclk;
	struct clk			*sclk;
	struct clk_div_table		*tbl;
	struct completion		completion;
	u32				status;
	u32				speed_hz;
	u32				effective_speed_hz;
	u32				bytes_per_word;
	u32				cfg_spi;
	u32				cfg_start;
	u32				cfg_bus;
};

static int spi_delay_to_sclk(u32 slck_speed_hz, struct spi_delay *delay)
{
	s32 ns;

	if (!delay)
		return 0;

	if (delay->unit == SPI_DELAY_UNIT_SCK)
		return delay->value;

	ns = spi_delay_to_ns(delay, NULL);
	if (ns < 0)
		return 0;

	return DIV_ROUND_UP_ULL(slck_speed_hz * ns, NSEC_PER_SEC);
}

static inline u32 aml_spisg_sem_down_read(struct spisg_device *spisg)
{
	u32 ret;

	regmap_read(spisg->map, SPISG_REG_CFG_READY, &ret);
	if (ret)
		regmap_write(spisg->map, SPISG_REG_CFG_READY, 0);

	return ret;
}

static inline void aml_spisg_sem_up_write(struct spisg_device *spisg)
{
	regmap_write(spisg->map, SPISG_REG_CFG_READY, 1);
}

static int aml_spisg_set_speed(struct spisg_device *spisg, uint speed_hz)
{
	u32 cfg_bus;

	if (!speed_hz || speed_hz == spisg->speed_hz)
		return 0;

	spisg->speed_hz = speed_hz;
	clk_set_rate(spisg->sclk, speed_hz);
	/* Store the div for the descriptor mode */
	regmap_read(spisg->map, SPISG_REG_CFG_BUS, &cfg_bus);
	spisg->cfg_bus &= ~CFG_CLK_DIV;
	spisg->cfg_bus |= cfg_bus & CFG_CLK_DIV;
	spisg->effective_speed_hz = clk_get_rate(spisg->sclk);

Annotation

Implementation Notes