drivers/clk/clk-si544.c

Source file repositories/reference/linux-study-clean/drivers/clk/clk-si544.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/clk-si544.c
Extension
.c
Size
12628 bytes
Lines
510
Domain
Driver Families
Bucket
drivers/clk
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 clk_si544 {
	struct clk_hw hw;
	struct regmap *regmap;
	struct i2c_client *i2c_client;
	unsigned long  max_freq;
};
#define to_clk_si544(_hw)	container_of(_hw, struct clk_si544, hw)

/**
 * struct clk_si544_muldiv - Multiplier/divider settings
 * @fb_div_frac:	integer part of feedback divider (32 bits)
 * @fb_div_int:		fractional part of feedback divider (11 bits)
 * @hs_div:		1st divider, 5..2046, must be even when >33
 * @ls_div_bits:	2nd divider, as 2^x, range 0..5
 *                      If ls_div_bits is non-zero, hs_div must be even
 * @delta_m:		Frequency shift for small -950..+950 ppm changes, 24 bit
 */
struct clk_si544_muldiv {
	u32 fb_div_frac;
	u16 fb_div_int;
	u16 hs_div;
	u8 ls_div_bits;
	s32 delta_m;
};

/* Enables or disables the output driver */
static int si544_enable_output(struct clk_si544 *data, bool enable)
{
	return regmap_update_bits(data->regmap, SI544_REG_OE_STATE,
		SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
}

static int si544_prepare(struct clk_hw *hw)
{
	struct clk_si544 *data = to_clk_si544(hw);

	return si544_enable_output(data, true);
}

static void si544_unprepare(struct clk_hw *hw)
{
	struct clk_si544 *data = to_clk_si544(hw);

	si544_enable_output(data, false);
}

static int si544_is_prepared(struct clk_hw *hw)
{
	struct clk_si544 *data = to_clk_si544(hw);
	unsigned int val;
	int err;

	err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val);
	if (err < 0)
		return err;

	return !!(val & SI544_OE_STATE_ODC_OE);
}

/* Retrieve clock multiplier and dividers from hardware */
static int si544_get_muldiv(struct clk_si544 *data,
	struct clk_si544_muldiv *settings)
{
	int err;
	u8 reg[6];

	err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2);
	if (err)
		return err;

	settings->ls_div_bits = (reg[1] >> 4) & 0x07;
	settings->hs_div = (reg[1] & 0x07) << 8 | reg[0];

	err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6);
	if (err)
		return err;

	settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
	settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
				reg[3] << 24;

	err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
	if (err)
		return err;

	/* Interpret as 24-bit signed number */
	settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
	settings->delta_m >>= 8;

	return 0;

Annotation

Implementation Notes