drivers/clocksource/timer-stm32-lp.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/timer-stm32-lp.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-stm32-lp.c
Extension
.c
Size
8181 bytes
Lines
293
Domain
Driver Families
Bucket
drivers/clocksource
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 stm32_lp_private {
	struct regmap *reg;
	struct clock_event_device clkevt;
	unsigned long period;
	u32 psc;
	struct device *dev;
	struct clk *clk;
	u32 version;
};

static struct stm32_lp_private*
to_priv(struct clock_event_device *clkevt)
{
	return container_of(clkevt, struct stm32_lp_private, clkevt);
}

static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
{
	struct stm32_lp_private *priv = to_priv(clkevt);

	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
	regmap_write(priv->reg, STM32_LPTIM_IER, 0);
	/* clear pending flags */
	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);

	return 0;
}

static int stm32mp25_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
{
	int ret;
	u32 val;

	regmap_read(priv->reg, STM32_LPTIM_CR, &val);
	if (!FIELD_GET(STM32_LPTIM_ENABLE, val)) {
		/* Enable LPTIMER to be able to write into IER and ARR registers */
		regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
		/*
		 * After setting the ENABLE bit, a delay of two counter clock cycles is needed
		 * before the LPTIM is actually enabled. For 32KHz rate, this makes approximately
		 * 62.5 micro-seconds, round it up.
		 */
		udelay(63);
	}
	/* set next event counter */
	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
	/* enable ARR interrupt */
	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);

	/* Poll DIEROK and ARROK to ensure register access has completed */
	ret = regmap_read_poll_timeout_atomic(priv->reg, STM32_LPTIM_ISR, val,
					      (val & STM32_LPTIM_DIEROK_ARROK) ==
					      STM32_LPTIM_DIEROK_ARROK,
					      10, 500);
	if (ret) {
		dev_err(priv->dev, "access to LPTIM timed out\n");
		/* Disable LPTIMER */
		regmap_write(priv->reg, STM32_LPTIM_CR, 0);
		return ret;
	}
	/* Clear DIEROK and ARROK flags */
	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_DIEROKCF_ARROKCF);

	return 0;
}

static void stm32_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
{
	/* disable LPTIMER to be able to write into IER register*/
	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
	/* enable ARR interrupt */
	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
	/* enable LPTIMER to be able to write into ARR register */
	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
	/* set next event counter */
	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
}

static int stm32_clkevent_lp_set_timer(unsigned long evt,
				       struct clock_event_device *clkevt,
				       int is_periodic)
{
	struct stm32_lp_private *priv = to_priv(clkevt);
	int ret;

	if (priv->version == STM32_LPTIM_VERR_23) {
		ret = stm32mp25_clkevent_lp_set_evt(priv, evt);
		if (ret)
			return ret;
	} else {

Annotation

Implementation Notes