drivers/rtc/rtc-ds1307.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-ds1307.c
Extension
.c
Size
51336 bytes
Lines
2039
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 ds1307 {
	enum ds_type		type;
	struct device		*dev;
	struct regmap		*regmap;
	const char		*name;
	struct rtc_device	*rtc;
#ifdef CONFIG_COMMON_CLK
	struct clk_hw		clks[2];
#endif
};

struct chip_desc {
	unsigned		alarm:1;
	u16			nvram_offset;
	u16			nvram_size;
	u8			offset; /* register's offset */
	u8			century_reg;
	u8			century_enable_bit;
	u8			century_bit;
	u8			bbsqi_bit;
	irq_handler_t		irq_handler;
	const struct rtc_class_ops *rtc_ops;
	u16			trickle_charger_reg;
	u8			(*do_trickle_setup)(struct ds1307 *, u32,
						    bool);
	/* Does the RTC require trickle-resistor-ohms to select the value of
	 * the resistor between Vcc and Vbackup?
	 */
	bool			requires_trickle_resistor;
	/* Some RTC's batteries and supercaps were charged by default, others
	 * allow charging but were not configured previously to do so.
	 * Remember this behavior to stay backwards compatible.
	 */
	bool			charge_default;
};

static const struct chip_desc chips[last_ds_type];

static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
	struct ds1307	*ds1307 = dev_get_drvdata(dev);
	int		tmp, ret;
	const struct chip_desc *chip = &chips[ds1307->type];
	u8 regs[7];

	if (ds1307->type == rx_8130) {
		unsigned int regflag;
		ret = regmap_read(ds1307->regmap, RX8130_REG_FLAG, &regflag);
		if (ret) {
			dev_err(dev, "%s error %d\n", "read", ret);
			return ret;
		}

		if (regflag & RX8130_REG_FLAG_VLF) {
			dev_warn_once(dev, "oscillator failed, set time!\n");
			return -EINVAL;
		}
	}

	/* read the RTC date and time registers all at once */
	ret = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
			       sizeof(regs));
	if (ret) {
		dev_err(dev, "%s error %d\n", "read", ret);
		return ret;
	}

	dev_dbg(dev, "%s: %7ph\n", "read", regs);

	/* if oscillator fail bit is set, no data can be trusted */
	if (ds1307->type == m41t0 &&
	    regs[DS1307_REG_MIN] & M41T0_BIT_OF) {
		dev_warn_once(dev, "oscillator failed, set time!\n");
		return -EINVAL;
	} else if (ds1307->type == mcp794xx &&
	    !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_OSCRUN)) {
		dev_warn_once(dev, "oscillator failed, set time!\n");
		return -EINVAL;
	}

	tmp = regs[DS1307_REG_SECS];
	switch (ds1307->type) {
	case ds_1307:
	case m41t0:
	case m41t00:
	case m41t11:
		if (tmp & DS1307_BIT_CH)
			return -EINVAL;
		break;
	case ds_1308:

Annotation

Implementation Notes