drivers/rtc/rtc-mxc_v2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-mxc_v2.c
Extension
.c
Size
10175 bytes
Lines
392
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 mxc_rtc_data {
	struct rtc_device *rtc;
	void __iomem *ioaddr;
	struct clk *clk;
	spinlock_t lock; /* protects register access */
	int irq;
};

/*
 * This function does write synchronization for writes to the lp srtc block.
 * To take care of the asynchronous CKIL clock, all writes from the IP domain
 * will be synchronized to the CKIL domain.
 * The caller should hold the pdata->lock
 */
static void mxc_rtc_sync_lp_locked(struct device *dev, void __iomem *ioaddr)
{
	unsigned int i;

	/* Wait for 3 CKIL cycles */
	for (i = 0; i < 3; i++) {
		const u32 count = readl(ioaddr + SRTC_LPSCLR);
		unsigned int timeout = REG_READ_TIMEOUT;

		while ((readl(ioaddr + SRTC_LPSCLR)) == count) {
			if (!--timeout) {
				dev_err_once(dev, "SRTC_LPSCLR stuck! Check your hw.\n");
				return;
			}
		}
	}
}

/* This function is the RTC interrupt service routine. */
static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
{
	struct device *dev = dev_id;
	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
	void __iomem *ioaddr = pdata->ioaddr;
	u32 lp_status;
	u32 lp_cr;

	spin_lock(&pdata->lock);
	if (clk_enable(pdata->clk)) {
		spin_unlock(&pdata->lock);
		return IRQ_NONE;
	}

	lp_status = readl(ioaddr + SRTC_LPSR);
	lp_cr = readl(ioaddr + SRTC_LPCR);

	/* update irq data & counter */
	if (lp_status & SRTC_LPSR_ALP) {
		if (lp_cr & SRTC_LPCR_ALP)
			rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF);

		/* disable further lp alarm interrupts */
		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
	}

	/* Update interrupt enables */
	writel(lp_cr, ioaddr + SRTC_LPCR);

	/* clear interrupt status */
	writel(lp_status, ioaddr + SRTC_LPSR);

	mxc_rtc_sync_lp_locked(dev, ioaddr);
	clk_disable(pdata->clk);
	spin_unlock(&pdata->lock);
	return IRQ_HANDLED;
}

/*
 * Enable clk and aquire spinlock
 * @return  0 if successful; non-zero otherwise.
 */
static int mxc_rtc_lock(struct mxc_rtc_data *const pdata)
{
	int ret;

	spin_lock_irq(&pdata->lock);
	ret = clk_enable(pdata->clk);
	if (ret) {
		spin_unlock_irq(&pdata->lock);
		return ret;
	}
	return 0;
}

static int mxc_rtc_unlock(struct mxc_rtc_data *const pdata)
{

Annotation

Implementation Notes