drivers/rtc/rtc-renesas-rtca3.c

Source file repositories/reference/linux-study-clean/drivers/rtc/rtc-renesas-rtca3.c

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-renesas-rtca3.c
Extension
.c
Size
25481 bytes
Lines
897
Domain
Driver Families
Bucket
drivers/rtc
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 rtca3_ppb_per_cycle {
	int ten_sec;
	int sixty_sec;
};

/**
 * struct rtca3_priv - RTCA3 private data structure
 * @base: base address
 * @rtc_dev: RTC device
 * @rstc: reset control
 * @set_alarm_completion: alarm setup completion
 * @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step)
 * @lock: device lock
 * @ppb: ppb per cycle for each the available adjustment modes
 * @wakeup_irq: wakeup IRQ
 */
struct rtca3_priv {
	void __iomem *base;
	struct rtc_device *rtc_dev;
	struct reset_control *rstc;
	struct completion set_alarm_completion;
	atomic_t alrm_sstep;
	spinlock_t lock;
	struct rtca3_ppb_per_cycle ppb;
	int wakeup_irq;
};

static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val)
{
	u8 tmp;

	tmp = readb(priv->base + off);
	tmp &= ~mask;
	tmp |= (val & mask);
	writeb(tmp, priv->base + off);
}

static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv)
{
	u8 val, pending;

	val = readb(priv->base + RTCA3_RSR);
	pending = val & RTCA3_RSR_AF;
	writeb(val & ~pending, priv->base + RTCA3_RSR);

	if (pending)
		rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);

	return pending;
}

static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id)
{
	struct rtca3_priv *priv = dev_id;
	u8 pending;

	guard(spinlock)(&priv->lock);

	pending = rtca3_alarm_handler_helper(priv);

	return IRQ_RETVAL(pending);
}

static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id)
{
	struct rtca3_priv *priv = dev_id;
	u8 val, pending;

	guard(spinlock)(&priv->lock);

	val = readb(priv->base + RTCA3_RSR);
	pending = val & RTCA3_RSR_PF;

	if (pending) {
		writeb(val & ~pending, priv->base + RTCA3_RSR);

		if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) {
			/* Alarm setup in progress. */
			atomic_dec(&priv->alrm_sstep);

			if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) {
				/*
				 * We got 2 * 1/64 periodic interrupts. Disable
				 * interrupt and let alarm setup continue.
				 */
				rtca3_byte_update_bits(priv, RTCA3_RCR1,
						       RTCA3_RCR1_PIE, 0);
				readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val,
							  !(val & RTCA3_RCR1_PIE),
							  10, RTCA3_DEFAULT_TIMEOUT_US);

Annotation

Implementation Notes