drivers/leds/leds-sun50i-a100.c

Source file repositories/reference/linux-study-clean/drivers/leds/leds-sun50i-a100.c

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-sun50i-a100.c
Extension
.c
Size
15742 bytes
Lines
574
Domain
Driver Families
Bucket
drivers/leds
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 sun50i_a100_ledc_led {
	struct led_classdev_mc mc_cdev;
	struct mc_subled subled_info[LEDC_CHANNELS_PER_LED];
	u32 addr;
};

#define to_ledc_led(mc) container_of(mc, struct sun50i_a100_ledc_led, mc_cdev)

struct sun50i_a100_ledc_timing {
	u32 t0h_ns;
	u32 t0l_ns;
	u32 t1h_ns;
	u32 t1l_ns;
	u32 treset_ns;
};

struct sun50i_a100_ledc {
	struct device *dev;
	void __iomem *base;
	struct clk *bus_clk;
	struct clk *mod_clk;
	struct reset_control *reset;

	u32 *buffer;
	struct dma_chan *dma_chan;
	dma_addr_t dma_handle;
	unsigned int pio_length;
	unsigned int pio_offset;

	spinlock_t lock;
	unsigned int next_length;
	bool xfer_active;

	u32 format;
	struct sun50i_a100_ledc_timing timing;

	u32 max_addr;
	u32 num_leds;
	struct sun50i_a100_ledc_led leds[] __counted_by(num_leds);
};

static int sun50i_a100_ledc_dma_xfer(struct sun50i_a100_ledc *priv, unsigned int length)
{
	struct dma_async_tx_descriptor *desc;
	dma_cookie_t cookie;

	desc = dmaengine_prep_slave_single(priv->dma_chan, priv->dma_handle,
					   LEDS_TO_BYTES(length), DMA_MEM_TO_DEV, 0);
	if (!desc)
		return -ENOMEM;

	cookie = dmaengine_submit(desc);
	if (dma_submit_error(cookie))
		return -EIO;

	dma_async_issue_pending(priv->dma_chan);

	return 0;
}

static void sun50i_a100_ledc_pio_xfer(struct sun50i_a100_ledc *priv, unsigned int fifo_used)
{
	unsigned int burst, length, offset;
	u32 control;

	length = priv->pio_length;
	offset = priv->pio_offset;
	burst  = min(length, LEDC_FIFO_DEPTH - fifo_used);

	iowrite32_rep(priv->base + LEDC_DATA_REG, priv->buffer + offset, burst);

	if (burst < length) {
		priv->pio_length = length - burst;
		priv->pio_offset = offset + burst;

		if (!offset) {
			control = readl(priv->base + LEDC_INT_CTRL_REG);
			control |= LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
			writel(control, priv->base + LEDC_INT_CTRL_REG);
		}
	} else {
		/* Disable the request IRQ once all data is written. */
		control = readl(priv->base + LEDC_INT_CTRL_REG);
		control &= ~LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
		writel(control, priv->base + LEDC_INT_CTRL_REG);
	}
}

static void sun50i_a100_ledc_start_xfer(struct sun50i_a100_ledc *priv, unsigned int length)
{

Annotation

Implementation Notes