drivers/mfd/stm32-timers.c

Source file repositories/reference/linux-study-clean/drivers/mfd/stm32-timers.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/stm32-timers.c
Extension
.c
Size
9814 bytes
Lines
369
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (IS_ERR(ddata->dma.chans[i])) {
			/* Save the first error code to return */
			if (PTR_ERR(ddata->dma.chans[i]) != -ENODEV && !ret)
				ret = PTR_ERR(ddata->dma.chans[i]);

			ddata->dma.chans[i] = NULL;
		}
	}

	return ret;
}

static void stm32_timers_dma_remove(struct device *dev,
				    struct stm32_timers *ddata)
{
	int i;

	for (i = STM32_TIMERS_DMA_CH1; i < STM32_TIMERS_MAX_DMAS; i++)
		if (ddata->dma.chans[i])
			dma_release_channel(ddata->dma.chans[i]);
}

static const char * const stm32_timers_irq_name[STM32_TIMERS_MAX_IRQS] = {
	"brk", "up", "trg-com", "cc"
};

static int stm32_timers_irq_probe(struct platform_device *pdev,
				  struct stm32_timers *ddata)
{
	int i, ret;

	/*
	 * STM32 Timer may have either:
	 * - a unique global interrupt line
	 * - four dedicated interrupt lines that may be handled separately.
	 * Optionally get them here, to be used by child devices.
	 */
	ret = platform_get_irq_byname_optional(pdev, "global");
	if (ret < 0 && ret != -ENXIO) {
		return ret;
	} else if (ret != -ENXIO) {
		ddata->irq[STM32_TIMERS_IRQ_GLOBAL_BRK] = ret;
		ddata->nr_irqs = 1;
		return 0;
	}

	for (i = 0; i < STM32_TIMERS_MAX_IRQS; i++) {
		ret = platform_get_irq_byname_optional(pdev, stm32_timers_irq_name[i]);
		if (ret < 0 && ret != -ENXIO) {
			return ret;
		} else if (ret != -ENXIO) {
			ddata->irq[i] = ret;
			ddata->nr_irqs++;
		}
	}

	if (ddata->nr_irqs && ddata->nr_irqs != STM32_TIMERS_MAX_IRQS) {
		dev_err(&pdev->dev, "Invalid number of IRQs %d\n", ddata->nr_irqs);
		return -EINVAL;
	}

	return 0;
}

static int stm32_timers_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct stm32_timers *ddata;
	struct resource *res;
	void __iomem *mmio;
	int ret;

	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
	if (!ddata)
		return -ENOMEM;

	mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
	if (IS_ERR(mmio))
		return PTR_ERR(mmio);

	/* Timer physical addr for DMA */
	ddata->dma.phys_base = res->start;

	ddata->regmap = devm_regmap_init_mmio_clk(dev, "int", mmio,
						  &stm32_timers_regmap_cfg);
	if (IS_ERR(ddata->regmap))
		return PTR_ERR(ddata->regmap);

	ddata->clk = devm_clk_get(dev, NULL);
	if (IS_ERR(ddata->clk))

Annotation

Implementation Notes