drivers/rtc/rtc-pcf8523.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-pcf8523.c
Extension
.c
Size
12497 bytes
Lines
524
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 pcf8523 {
	struct rtc_device *rtc;
	struct regmap *regmap;
};

static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node *node)
{
	u32 load, value = 0;

	load = 12500;
	of_property_read_u32(node, "quartz-load-femtofarads", &load);

	switch (load) {
	default:
		dev_warn(&pcf8523->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500",
			 load);
		fallthrough;
	case 12500:
		value = PCF8523_CONTROL1_CAP_SEL;
		break;
	case 7000:
		break;
	}

	return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
				  PCF8523_CONTROL1_CAP_SEL, value);
}

static irqreturn_t pcf8523_irq(int irq, void *dev_id)
{
	struct pcf8523 *pcf8523 = dev_id;
	u32 value;
	int err;

	err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value);
	if (err < 0)
		return IRQ_HANDLED;

	if (value & PCF8523_CONTROL2_AF) {
		value &= ~PCF8523_CONTROL2_AF;
		regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, value);
		rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF);

		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}

static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
	u8 regs[10];
	int err;

	err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs,
			       sizeof(regs));
	if (err < 0)
		return err;

	if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS))
		return -EINVAL;

	tm->tm_sec = bcd2bin(regs[3] & 0x7f);
	tm->tm_min = bcd2bin(regs[4] & 0x7f);
	tm->tm_hour = bcd2bin(regs[5] & 0x3f);
	tm->tm_mday = bcd2bin(regs[6] & 0x3f);
	tm->tm_wday = regs[7] & 0x7;
	tm->tm_mon = bcd2bin(regs[8] & 0x1f) - 1;
	tm->tm_year = bcd2bin(regs[9]) + 100;

	return 0;
}

static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
	u8 regs[7];
	int err;

	err = regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1,
				 PCF8523_CONTROL1_STOP, PCF8523_CONTROL1_STOP);
	if (err < 0)
		return err;

	/* This will purposely overwrite PCF8523_SECONDS_OS */
	regs[0] = bin2bcd(tm->tm_sec);
	regs[1] = bin2bcd(tm->tm_min);
	regs[2] = bin2bcd(tm->tm_hour);
	regs[3] = bin2bcd(tm->tm_mday);

Annotation

Implementation Notes