drivers/spi/spi-orion.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-orion.c
Extension
.c
Size
21807 bytes
Lines
860
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 orion_spi_dev {
	enum orion_spi_type	typ;
	/*
	 * min_divisor and max_hz should be exclusive, the only we can
	 * have both is for managing the armada-370-spi case with old
	 * device tree
	 */
	unsigned long		max_hz;
	unsigned int		min_divisor;
	unsigned int		max_divisor;
	u32			prescale_mask;
	bool			is_errata_50mhz_ac;
};

struct orion_direct_acc {
	void __iomem		*vaddr;
	u32			size;
};

struct orion_child_options {
	struct orion_direct_acc direct_access;
};

struct orion_spi {
	struct spi_controller	*host;
	void __iomem		*base;
	struct clk              *clk;
	struct clk              *axi_clk;
	const struct orion_spi_dev *devdata;
	struct device		*dev;

	struct orion_child_options	child[ORION_NUM_CHIPSELECTS];
};

#ifdef CONFIG_PM
static int orion_spi_runtime_suspend(struct device *dev);
static int orion_spi_runtime_resume(struct device *dev);
#endif

static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
{
	return orion_spi->base + reg;
}

static inline void
orion_spi_setbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
{
	void __iomem *reg_addr = spi_reg(orion_spi, reg);
	u32 val;

	val = readl(reg_addr);
	val |= mask;
	writel(val, reg_addr);
}

static inline void
orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
{
	void __iomem *reg_addr = spi_reg(orion_spi, reg);
	u32 val;

	val = readl(reg_addr);
	val &= ~mask;
	writel(val, reg_addr);
}

static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
	u32 tclk_hz;
	u32 rate;
	u32 prescale;
	u32 reg;
	struct orion_spi *orion_spi;
	const struct orion_spi_dev *devdata;

	orion_spi = spi_controller_get_devdata(spi->controller);
	devdata = orion_spi->devdata;

	tclk_hz = clk_get_rate(orion_spi->clk);

	if (devdata->typ == ARMADA_SPI) {
		/*
		 * Given the core_clk (tclk_hz) and the target rate (speed) we
		 * determine the best values for SPR (in [0 .. 15]) and SPPR (in
		 * [0..7]) such that
		 *
		 * 	core_clk / (SPR * 2 ** SPPR)
		 *
		 * is as big as possible but not bigger than speed.
		 */

Annotation

Implementation Notes