drivers/rtc/rtc-atcrtc100.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-atcrtc100.c
Extension
.c
Size
10338 bytes
Lines
382
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 atcrtc_dev {
	struct rtc_device	*rtc_dev;
	struct regmap		*regmap;
	struct work_struct	rtc_work;
	unsigned int		alarm_irq;
	bool			alarm_en;
};

static const struct regmap_config atcrtc_regmap_config = {
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
	.max_register = RTC_TRIM,
	.cache_type = REGCACHE_NONE,
};

/**
 * atcrtc_check_write_done - Wait for RTC registers to be synchronized.
 * @rtc: Pointer to the atcrtc_dev structure.
 *
 * The WriteDone bit in the status register indicates the synchronization
 * progress of RTC register updates. This bit is cleared to zero whenever
 * any RTC control register (Counter, Alarm, Control, etc.) is written.
 * It returns to one only after all previous updates have been fully
 * synchronized to the RTC clock domain. This function polls the WriteDone
 * bit with a timeout to ensure the device is ready for the next operation.
 *
 * Return: 0 on success, or -EBUSY on timeout.
 */
static int atcrtc_check_write_done(struct atcrtc_dev *rtc)
{
	unsigned int val;

	/*
	 * Using read_poll_timeout is more efficient than a manual loop
	 * with usleep_range.
	 */
	return regmap_read_poll_timeout(rtc->regmap, RTC_STA, val,
					val & WRITE_DONE,
					ATCRTC_TIMEOUT_USLEEP_MIN,
					ATCRTC_TIMEOUT_US);
}

static irqreturn_t atcrtc_alarm_isr(int irq, void *dev)
{
	struct atcrtc_dev *rtc = dev;
	unsigned int status;

	regmap_read(rtc->regmap, RTC_STA, &status);
	if (status & ALARM_INT) {
		regmap_write(rtc->regmap, RTC_STA, ALARM_INT);
		rtc->alarm_en = false;
		schedule_work(&rtc->rtc_work);
		rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
		return IRQ_HANDLED;
	}
	return IRQ_NONE;
}

static int atcrtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
	struct atcrtc_dev *rtc = dev_get_drvdata(dev);
	unsigned int mask;
	int ret;

	ret = atcrtc_check_write_done(rtc);
	if (ret)
		return ret;

	mask = ALARM_WAKEUP | ALARM_INT;
	regmap_update_bits(rtc->regmap, RTC_CR, mask, enable ? mask : 0);

	return 0;
}

static void atcrtc_alarm_clear(struct work_struct *work)
{
	struct atcrtc_dev *rtc =
		container_of(work, struct atcrtc_dev, rtc_work);
	int ret;

	rtc_lock(rtc->rtc_dev);

	if (!rtc->alarm_en) {
		ret = atcrtc_check_write_done(rtc);
		if (ret)
			dev_info(&rtc->rtc_dev->dev,
				 "failed to sync before clearing alarm: %d\n",
				 ret);
		else

Annotation

Implementation Notes