drivers/rtc/rtc-msm6242.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-msm6242.c
Extension
.c
Size
6769 bytes
Lines
229
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 msm6242_priv {
	u32 __iomem *regs;
	struct rtc_device *rtc;
};

static inline unsigned int msm6242_read(struct msm6242_priv *priv,
				       unsigned int reg)
{
	return __raw_readl(&priv->regs[reg]) & 0xf;
}

static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
				unsigned int reg)
{
	__raw_writel(val, &priv->regs[reg]);
}

static void msm6242_lock(struct msm6242_priv *priv)
{
	int cnt = 5;

	msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);

	while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) {
		msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
		udelay(70);
		msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);
		cnt--;
	}

	if (!cnt)
		pr_warn("timed out waiting for RTC (0x%x)\n",
			msm6242_read(priv, MSM6242_CD));
}

static void msm6242_unlock(struct msm6242_priv *priv)
{
	msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
}

static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
{
	struct msm6242_priv *priv = dev_get_drvdata(dev);

	msm6242_lock(priv);

	tm->tm_sec  = msm6242_read(priv, MSM6242_SECOND10) * 10 +
		      msm6242_read(priv, MSM6242_SECOND1);
	tm->tm_min  = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
		      msm6242_read(priv, MSM6242_MINUTE1);
	tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) &
		       MSM6242_HOUR10_HR_MASK) * 10 +
		      msm6242_read(priv, MSM6242_HOUR1);
	tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
		      msm6242_read(priv, MSM6242_DAY1);
	tm->tm_wday = msm6242_read(priv, MSM6242_WEEK);
	tm->tm_mon  = msm6242_read(priv, MSM6242_MONTH10) * 10 +
		      msm6242_read(priv, MSM6242_MONTH1) - 1;
	tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 +
		      msm6242_read(priv, MSM6242_YEAR1);
	if (tm->tm_year <= 69)
		tm->tm_year += 100;

	if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) {
		unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) &
				  MSM6242_HOUR10_PM;
		if (!pm && tm->tm_hour == 12)
			tm->tm_hour = 0;
		else if (pm && tm->tm_hour != 12)
			tm->tm_hour += 12;
	}

	msm6242_unlock(priv);

	return 0;
}

static int msm6242_set_time(struct device *dev, struct rtc_time *tm)
{
	struct msm6242_priv *priv = dev_get_drvdata(dev);

	msm6242_lock(priv);

	msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10);
	msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1);
	msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10);
	msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1);
	if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)
		msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
	else if (tm->tm_hour >= 12)

Annotation

Implementation Notes