drivers/rtc/rtc-mt2712.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-mt2712.c
Extension
.c
Size
11351 bytes
Lines
414
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 mt2712_rtc {
	struct rtc_device	*rtc;
	void __iomem		*base;
	int			irq;
	u8			irq_wake_enabled;
	u8			powerlost;
};

static inline u32 mt2712_readl(struct mt2712_rtc *mt2712_rtc, u32 reg)
{
	return readl(mt2712_rtc->base + reg);
}

static inline void mt2712_writel(struct mt2712_rtc *mt2712_rtc,
				 u32 reg, u32 val)
{
	writel(val, mt2712_rtc->base + reg);
}

static void mt2712_rtc_write_trigger(struct mt2712_rtc *mt2712_rtc)
{
	unsigned long timeout = jiffies + HZ / 10;

	mt2712_writel(mt2712_rtc, MT2712_WRTGR, 1);
	while (1) {
		if (!(mt2712_readl(mt2712_rtc, MT2712_BBPU)
					& MT2712_BBPU_CBUSY))
			break;

		if (time_after(jiffies, timeout)) {
			dev_err(&mt2712_rtc->rtc->dev,
				"%s time out!\n", __func__);
			break;
		}
		cpu_relax();
	}
}

static void mt2712_rtc_writeif_unlock(struct mt2712_rtc *mt2712_rtc)
{
	mt2712_writel(mt2712_rtc, MT2712_PROT, MT2712_PROT_UNLOCK1);
	mt2712_rtc_write_trigger(mt2712_rtc);
	mt2712_writel(mt2712_rtc, MT2712_PROT, MT2712_PROT_UNLOCK2);
	mt2712_rtc_write_trigger(mt2712_rtc);
}

static irqreturn_t rtc_irq_handler_thread(int irq, void *data)
{
	struct mt2712_rtc *mt2712_rtc = data;
	u16 irqsta;

	/* Clear interrupt */
	irqsta = mt2712_readl(mt2712_rtc, MT2712_IRQ_STA);
	if (irqsta & MT2712_IRQ_STA_AL) {
		rtc_update_irq(mt2712_rtc->rtc, 1, RTC_IRQF | RTC_AF);
		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}

static void __mt2712_rtc_read_time(struct mt2712_rtc *mt2712_rtc,
				   struct rtc_time *tm, int *sec)
{
	tm->tm_sec  = mt2712_readl(mt2712_rtc, MT2712_TC_SEC)
			& MT2712_SEC_MASK;
	tm->tm_min  = mt2712_readl(mt2712_rtc, MT2712_TC_MIN)
			& MT2712_MIN_MASK;
	tm->tm_hour = mt2712_readl(mt2712_rtc, MT2712_TC_HOU)
			& MT2712_HOU_MASK;
	tm->tm_mday = mt2712_readl(mt2712_rtc, MT2712_TC_DOM)
			& MT2712_DOM_MASK;
	tm->tm_mon  = (mt2712_readl(mt2712_rtc, MT2712_TC_MTH) - 1)
			& MT2712_MTH_MASK;
	tm->tm_year = (mt2712_readl(mt2712_rtc, MT2712_TC_YEA) + 100)
			& MT2712_YEA_MASK;

	*sec = mt2712_readl(mt2712_rtc, MT2712_TC_SEC) & MT2712_SEC_MASK;
}

static int mt2712_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct mt2712_rtc *mt2712_rtc = dev_get_drvdata(dev);
	int sec;

	if (mt2712_rtc->powerlost)
		return -EINVAL;

	do {
		__mt2712_rtc_read_time(mt2712_rtc, tm, &sec);

Annotation

Implementation Notes