drivers/rtc/rtc-ftrtc010.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-ftrtc010.c
Extension
.c
Size
5657 bytes
Lines
220
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 ftrtc010_rtc {
	void __iomem		*rtc_base;
	int			rtc_irq;
	struct clk		*pclk;
	struct clk		*extclk;
};

enum ftrtc010_rtc_offsets {
	FTRTC010_RTC_SECOND		= 0x00,
	FTRTC010_RTC_MINUTE		= 0x04,
	FTRTC010_RTC_HOUR		= 0x08,
	FTRTC010_RTC_DAYS		= 0x0C,
	FTRTC010_RTC_ALARM_SECOND	= 0x10,
	FTRTC010_RTC_ALARM_MINUTE	= 0x14,
	FTRTC010_RTC_ALARM_HOUR		= 0x18,
	FTRTC010_RTC_RECORD		= 0x1C,
	FTRTC010_RTC_CR			= 0x20,
};

static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev)
{
	return IRQ_HANDLED;
}

/*
 * Looks like the RTC in the Gemini SoC is (totaly) broken
 * We can't read/write directly the time from RTC registers.
 * We must do some "offset" calculation to get the real time
 *
 * This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
 * the same thing, without the rtc-lib.c calls.
 */

static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);

	u32 days, hour, min, sec, offset;
	timeu64_t time;

	sec  = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
	min  = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
	hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
	days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
	offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);

	time = offset + days * 86400 + hour * 3600 + min * 60 + sec;

	rtc_time64_to_tm(time, tm);

	return 0;
}

static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
	u32 sec, min, hour, day, offset;
	timeu64_t time;

	time = rtc_tm_to_time64(tm);

	sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
	min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
	hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
	day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);

	offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);

	writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
	writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);

	return 0;
}

static const struct rtc_class_ops ftrtc010_rtc_ops = {
	.read_time     = ftrtc010_rtc_read_time,
	.set_time      = ftrtc010_rtc_set_time,
};

static int ftrtc010_rtc_probe(struct platform_device *pdev)
{
	u32 days, hour, min, sec;
	struct ftrtc010_rtc *rtc;
	struct device *dev = &pdev->dev;
	struct resource *res;
	struct rtc_device *rtc_dev;
	int ret;

	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
	if (unlikely(!rtc))

Annotation

Implementation Notes