drivers/rtc/rtc-ac100.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-ac100.c
Extension
.c
Size
17470 bytes
Lines
643
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 ac100_clkout {
	struct clk_hw hw;
	struct regmap *regmap;
	u8 offset;
};

#define to_ac100_clkout(_hw) container_of(_hw, struct ac100_clkout, hw)

#define AC100_RTC_32K_NAME	"ac100-rtc-32k"
#define AC100_RTC_32K_RATE	32768
#define AC100_CLKOUT_NUM	3

static const char * const ac100_clkout_names[AC100_CLKOUT_NUM] = {
	"ac100-cko1-rtc",
	"ac100-cko2-rtc",
	"ac100-cko3-rtc",
};

struct ac100_rtc_dev {
	struct rtc_device *rtc;
	struct device *dev;
	struct regmap *regmap;
	int irq;
	unsigned long alarm;

	struct clk_hw *rtc_32k_clk;
	struct ac100_clkout clks[AC100_CLKOUT_NUM];
	struct clk_hw_onecell_data *clk_data;
};

/*
 * Clock controls for 3 clock output pins
 */

static const struct clk_div_table ac100_clkout_prediv[] = {
	{ .val = 0, .div = 1 },
	{ .val = 1, .div = 2 },
	{ .val = 2, .div = 4 },
	{ .val = 3, .div = 8 },
	{ .val = 4, .div = 16 },
	{ .val = 5, .div = 32 },
	{ .val = 6, .div = 64 },
	{ .val = 7, .div = 122 },
	{ },
};

/* Abuse the fact that one parent is 32768 Hz, and the other is 4 MHz */
static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw,
					      unsigned long prate)
{
	struct ac100_clkout *clk = to_ac100_clkout(hw);
	unsigned int reg, div;

	regmap_read(clk->regmap, clk->offset, &reg);

	/* Handle pre-divider first */
	if (prate != AC100_RTC_32K_RATE) {
		div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) &
			((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1);
		prate = divider_recalc_rate(hw, prate, div,
					    ac100_clkout_prediv, 0,
					    AC100_CLKOUT_PRE_DIV_WIDTH);
	}

	div = (reg >> AC100_CLKOUT_DIV_SHIFT) &
		(BIT(AC100_CLKOUT_DIV_WIDTH) - 1);
	return divider_recalc_rate(hw, prate, div, NULL,
				   CLK_DIVIDER_POWER_OF_TWO,
				   AC100_CLKOUT_DIV_WIDTH);
}

static int ac100_clkout_determine_rate(struct clk_hw *hw,
				       struct clk_rate_request *req)
{
	int i, ret, num_parents = clk_hw_get_num_parents(hw);
	struct clk_hw *best_parent = NULL;
	unsigned long best = 0;

	for (i = 0; i < num_parents; i++) {
		struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
		unsigned long prate;

		/*
		 * The clock has two parents, one is a fixed clock which is
		 * internally registered by the ac100 driver. The other parent
		 * is a clock from the codec side of the chip, which we
		 * properly declare and reference in the devicetree and is
		 * not implemented in any driver right now.
		 * If the clock core looks for the parent of that second
		 * missing clock, it can't find one that is registered and

Annotation

Implementation Notes