drivers/rtc/rtc-spear.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-spear.c
Extension
.c
Size
12746 bytes
Lines
493
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 spear_rtc_config {
	struct rtc_device *rtc;
	struct clk *clk;
	spinlock_t lock;
	void __iomem *ioaddr;
	unsigned int irq_wake;
};

static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
{
	unsigned int val;
	unsigned long flags;

	spin_lock_irqsave(&config->lock, flags);
	val = readl(config->ioaddr + STATUS_REG);
	val |= RTC_INT_MASK;
	writel(val, config->ioaddr + STATUS_REG);
	spin_unlock_irqrestore(&config->lock, flags);
}

static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config)
{
	unsigned int val;

	val = readl(config->ioaddr + CTRL_REG);
	if (!(val & INT_ENABLE)) {
		spear_rtc_clear_interrupt(config);
		val |= INT_ENABLE;
		writel(val, config->ioaddr + CTRL_REG);
	}
}

static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config)
{
	unsigned int val;

	val = readl(config->ioaddr + CTRL_REG);
	if (val & INT_ENABLE) {
		val &= ~INT_ENABLE;
		writel(val, config->ioaddr + CTRL_REG);
	}
}

static inline int is_write_complete(struct spear_rtc_config *config)
{
	int ret = 0;
	unsigned long flags;

	spin_lock_irqsave(&config->lock, flags);
	if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL)
		ret = -EIO;
	spin_unlock_irqrestore(&config->lock, flags);

	return ret;
}

static void rtc_wait_not_busy(struct spear_rtc_config *config)
{
	int status, count = 0;
	unsigned long flags;

	/* Assuming BUSY may stay active for 80 msec) */
	for (count = 0; count < 80; count++) {
		spin_lock_irqsave(&config->lock, flags);
		status = readl(config->ioaddr + STATUS_REG);
		spin_unlock_irqrestore(&config->lock, flags);
		if ((status & STATUS_BUSY) == 0)
			break;
		/* check status busy, after each msec */
		msleep(1);
	}
}

static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
{
	struct spear_rtc_config *config = dev_id;
	unsigned long events = 0;
	unsigned int irq_data;

	spin_lock(&config->lock);
	irq_data = readl(config->ioaddr + STATUS_REG);
	spin_unlock(&config->lock);

	if ((irq_data & RTC_INT_MASK)) {
		spear_rtc_clear_interrupt(config);
		events = RTC_IRQF | RTC_AF;
		rtc_update_irq(config->rtc, 1, events);
		return IRQ_HANDLED;
	} else
		return IRQ_NONE;

Annotation

Implementation Notes