drivers/clocksource/samsung_pwm_timer.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/samsung_pwm_timer.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/samsung_pwm_timer.c
Extension
.c
Size
12898 bytes
Lines
517
Domain
Driver Families
Bucket
drivers/clocksource
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

struct samsung_pwm_clocksource {
	void __iomem *base;
	const void __iomem *source_reg;
	unsigned int irq[SAMSUNG_PWM_NUM];
	struct samsung_pwm_variant variant;

	struct clk *timerclk;

	unsigned int event_id;
	unsigned int source_id;
	unsigned int tcnt_max;
	unsigned int tscaler_div;
	unsigned int tdiv;

	unsigned long clock_count_per_tick;
};

static struct samsung_pwm_clocksource pwm;

static void samsung_timer_set_prescale(unsigned int channel, u16 prescale)
{
	unsigned long flags;
	u8 shift = 0;
	u32 reg;

	if (channel >= 2)
		shift = TCFG0_PRESCALER1_SHIFT;

	spin_lock_irqsave(&samsung_pwm_lock, flags);

	reg = readl(pwm.base + REG_TCFG0);
	reg &= ~(TCFG0_PRESCALER_MASK << shift);
	reg |= (prescale - 1) << shift;
	writel(reg, pwm.base + REG_TCFG0);

	spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}

static void samsung_timer_set_divisor(unsigned int channel, u8 divisor)
{
	u8 shift = TCFG1_SHIFT(channel);
	unsigned long flags;
	u32 reg;
	u8 bits;

	bits = (fls(divisor) - 1) - pwm.variant.div_base;

	spin_lock_irqsave(&samsung_pwm_lock, flags);

	reg = readl(pwm.base + REG_TCFG1);
	reg &= ~(TCFG1_MUX_MASK << shift);
	reg |= bits << shift;
	writel(reg, pwm.base + REG_TCFG1);

	spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}

static void samsung_time_stop(unsigned int channel)
{
	unsigned long tcon;
	unsigned long flags;

	if (channel > 0)
		++channel;

	spin_lock_irqsave(&samsung_pwm_lock, flags);

	tcon = readl_relaxed(pwm.base + REG_TCON);
	tcon &= ~TCON_START(channel);
	writel_relaxed(tcon, pwm.base + REG_TCON);

	spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}

static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
{
	unsigned long tcon;
	unsigned long flags;
	unsigned int tcon_chan = channel;

	if (tcon_chan > 0)
		++tcon_chan;

	spin_lock_irqsave(&samsung_pwm_lock, flags);

	tcon = readl_relaxed(pwm.base + REG_TCON);

	tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan));
	tcon |= TCON_MANUALUPDATE(tcon_chan);

Annotation

Implementation Notes