drivers/rtc/rtc-pm8xxx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-pm8xxx.c
Extension
.c
Size
16044 bytes
Lines
690
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 pm8xxx_rtc_regs {
	unsigned int ctrl;
	unsigned int write;
	unsigned int read;
	unsigned int alarm_ctrl;
	unsigned int alarm_ctrl2;
	unsigned int alarm_rw;
	unsigned int alarm_en;
};

struct qcom_uefi_rtc_info {
	__le32	offset_gps;
	u8	reserved[8];
} __packed;

/**
 * struct pm8xxx_rtc -  RTC driver internal structure
 * @rtc:		RTC device
 * @regmap:		regmap used to access registers
 * @allow_set_time:	whether the time can be set
 * @use_uefi:		use UEFI variable as fallback for offset
 * @alarm_irq:		alarm irq number
 * @regs:		register description
 * @dev:		device structure
 * @rtc_info:		qcom uefi rtc-info structure
 * @nvmem_cell:		nvmem cell for offset
 * @offset:		offset from epoch in seconds
 * @offset_dirty:	offset needs to be stored on shutdown
 */
struct pm8xxx_rtc {
	struct rtc_device *rtc;
	struct regmap *regmap;
	bool allow_set_time;
	bool use_uefi;
	int alarm_irq;
	const struct pm8xxx_rtc_regs *regs;
	struct device *dev;
	struct qcom_uefi_rtc_info rtc_info;
	struct nvmem_cell *nvmem_cell;
	u32 offset;
	bool offset_dirty;
};

#ifdef CONFIG_EFI

MODULE_IMPORT_NS("EFIVAR");

#define QCOM_UEFI_NAME	L"RTCInfo"
#define QCOM_UEFI_GUID	EFI_GUID(0x882f8c2b, 0x9646, 0x435f, \
				 0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd)
#define QCOM_UEFI_ATTRS	(EFI_VARIABLE_NON_VOLATILE | \
			 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
			 EFI_VARIABLE_RUNTIME_ACCESS)

static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
{
	struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
	unsigned long size = sizeof(*rtc_info);
	struct device *dev = rtc_dd->dev;
	efi_status_t status;
	u32 offset_gps;
	int rc;

	rc = efivar_lock();
	if (rc)
		return rc;

	status = efivar_get_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID, NULL,
				     &size, rtc_info);
	efivar_unlock();

	if (status != EFI_SUCCESS) {
		dev_dbg(dev, "failed to read UEFI offset: %lu\n", status);
		return efi_status_to_err(status);
	}

	if (size != sizeof(*rtc_info)) {
		dev_dbg(dev, "unexpected UEFI structure size %lu\n", size);
		return -EINVAL;
	}

	dev_dbg(dev, "uefi_rtc_info = %*ph\n", (int)size, rtc_info);

	/* Convert from GPS to Unix time offset */
	offset_gps = le32_to_cpu(rtc_info->offset_gps);
	rtc_dd->offset = offset_gps + (u32)RTC_TIMESTAMP_EPOCH_GPS;

	return 0;
}

Annotation

Implementation Notes