Commit ea0a1fb7 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge branches 'clk-samsung', 'clk-formatting', 'clk-si5341' and 'clk-socfpga' into clk-next

* clk-samsung:
  clk: samsung: Remove redundant check in samsung_cmu_register_one

* clk-formatting:
  clk: Fix continuation of of_clk_detect_critical()

* clk-si5341:
  clk, clk-si5341: Support multiple input ports

* clk-socfpga:
  clk: socfpga: stratix10: simplify parameter passing
  clk: stratix10: use do_div() for 64-bit calculation
Loading
Loading
Loading
Loading
+196 −16
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
#include <linux/slab.h>
#include <asm/unaligned.h>

#define SI5341_NUM_INPUTS 4

#define SI5341_MAX_NUM_OUTPUTS 10
#define SI5340_MAX_NUM_OUTPUTS 4

@@ -56,8 +58,8 @@ struct clk_si5341 {
	struct i2c_client *i2c_client;
	struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
	struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
	struct clk *pxtal;
	const char *pxtal_name;
	struct clk *input_clk[SI5341_NUM_INPUTS];
	const char *input_clk_name[SI5341_NUM_INPUTS];
	const u16 *reg_output_offset;
	const u16 *reg_rdiv_offset;
	u64 freq_vco; /* 13500–14256 MHz */
@@ -78,10 +80,25 @@ struct clk_si5341_output_config {
#define SI5341_DEVICE_REV	0x0005
#define SI5341_STATUS		0x000C
#define SI5341_SOFT_RST		0x001C
#define SI5341_IN_SEL		0x0021
#define SI5341_XAXB_CFG		0x090E
#define SI5341_IN_EN		0x0949
#define SI5341_INX_TO_PFD_EN	0x094A

/* Input selection */
#define SI5341_IN_SEL_MASK	0x06
#define SI5341_IN_SEL_SHIFT	1
#define SI5341_IN_SEL_REGCTRL	0x01
#define SI5341_INX_TO_PFD_SHIFT	4

/* XTAL config bits */
#define SI5341_XAXB_CFG_EXTCLK_EN	BIT(0)
#define SI5341_XAXB_CFG_PDNB		BIT(1)

/* Input dividers (48-bit) */
#define SI5341_IN_PDIV(x)	(0x0208 + ((x) * 10))
#define SI5341_IN_PSET(x)	(0x020E + ((x) * 10))
#define SI5341_PX_UPD		0x0230

/* PLL configuration */
#define SI5341_PLL_M_NUM	0x0235
@@ -120,6 +137,10 @@ struct si5341_reg_default {
	u8 value;
};

static const char * const si5341_input_clock_names[] = {
	"in0", "in1", "in2", "xtal"
};

/* Output configuration registers 0..9 are not quite logically organized */
static const u16 si5341_reg_output_offset[] = {
	0x0108,
@@ -390,7 +411,112 @@ static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
	return (unsigned long)res;
}

static int si5341_clk_get_selected_input(struct clk_si5341 *data)
{
	int err;
	u32 val;

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

	return (val & SI5341_IN_SEL_MASK) >> SI5341_IN_SEL_SHIFT;
}

static u8 si5341_clk_get_parent(struct clk_hw *hw)
{
	struct clk_si5341 *data = to_clk_si5341(hw);
	int res = si5341_clk_get_selected_input(data);

	if (res < 0)
		return 0; /* Apparently we cannot report errors */

	return res;
}

static int si5341_clk_reparent(struct clk_si5341 *data, u8 index)
{
	int err;
	u8 val;

	val = (index << SI5341_IN_SEL_SHIFT) & SI5341_IN_SEL_MASK;
	/* Enable register-based input selection */
	val |= SI5341_IN_SEL_REGCTRL;

	err = regmap_update_bits(data->regmap,
		SI5341_IN_SEL, SI5341_IN_SEL_REGCTRL | SI5341_IN_SEL_MASK, val);
	if (err < 0)
		return err;

	if (index < 3) {
		/* Enable input buffer for selected input */
		err = regmap_update_bits(data->regmap,
				SI5341_IN_EN, 0x07, BIT(index));
		if (err < 0)
			return err;

		/* Enables the input to phase detector */
		err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN,
				0x7 << SI5341_INX_TO_PFD_SHIFT,
				BIT(index + SI5341_INX_TO_PFD_SHIFT));
		if (err < 0)
			return err;

		/* Power down XTAL oscillator and buffer */
		err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
				SI5341_XAXB_CFG_PDNB, 0);
		if (err < 0)
			return err;

		/*
		 * Set the P divider to "1". There's no explanation in the
		 * datasheet of these registers, but the clockbuilder software
		 * programs a "1" when the input is being used.
		 */
		err = regmap_write(data->regmap, SI5341_IN_PDIV(index), 1);
		if (err < 0)
			return err;

		err = regmap_write(data->regmap, SI5341_IN_PSET(index), 1);
		if (err < 0)
			return err;

		/* Set update PDIV bit */
		err = regmap_write(data->regmap, SI5341_PX_UPD, BIT(index));
		if (err < 0)
			return err;
	} else {
		/* Disable all input buffers */
		err = regmap_update_bits(data->regmap, SI5341_IN_EN, 0x07, 0);
		if (err < 0)
			return err;

		/* Disable input to phase detector */
		err = regmap_update_bits(data->regmap, SI5341_INX_TO_PFD_EN,
				0x7 << SI5341_INX_TO_PFD_SHIFT, 0);
		if (err < 0)
			return err;

		/* Power up XTAL oscillator and buffer */
		err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
				SI5341_XAXB_CFG_PDNB, SI5341_XAXB_CFG_PDNB);
		if (err < 0)
			return err;
	}

	return 0;
}

static int si5341_clk_set_parent(struct clk_hw *hw, u8 index)
{
	struct clk_si5341 *data = to_clk_si5341(hw);

	return si5341_clk_reparent(data, index);
}

static const struct clk_ops si5341_clk_ops = {
	.set_parent = si5341_clk_set_parent,
	.get_parent = si5341_clk_get_parent,
	.recalc_rate = si5341_clk_recalc_rate,
};

@@ -985,7 +1111,8 @@ static const struct regmap_range si5341_regmap_volatile_range[] = {
	regmap_reg_range(0x000C, 0x0012), /* Status */
	regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */
	regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */
	/* Update bits for synth config */
	/* Update bits for P divider and synth config */
	regmap_reg_range(SI5341_PX_UPD, SI5341_PX_UPD),
	regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)),
	regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)),
	regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)),
@@ -1122,6 +1249,7 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
	struct device_node *np = data->i2c_client->dev.of_node;
	u32 m_num = 0;
	u32 m_den = 0;
	int sel;

	if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) {
		dev_err(&data->i2c_client->dev,
@@ -1135,7 +1263,11 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
	if (!m_num || !m_den) {
		dev_err(&data->i2c_client->dev,
			"PLL configuration invalid, assume 14GHz\n");
		m_den = clk_get_rate(data->pxtal) / 10;
		sel = si5341_clk_get_selected_input(data);
		if (sel < 0)
			return sel;

		m_den = clk_get_rate(data->input_clk[sel]) / 10;
		m_num = 1400000000;
	}

@@ -1143,11 +1275,52 @@ static int si5341_initialize_pll(struct clk_si5341 *data)
			SI5341_PLL_M_NUM, m_num, m_den);
}

static int si5341_clk_select_active_input(struct clk_si5341 *data)
{
	int res;
	int err;
	int i;

	res = si5341_clk_get_selected_input(data);
	if (res < 0)
		return res;

	/* If the current register setting is invalid, pick the first input */
	if (!data->input_clk[res]) {
		dev_dbg(&data->i2c_client->dev,
			"Input %d not connected, rerouting\n", res);
		res = -ENODEV;
		for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
			if (data->input_clk[i]) {
				res = i;
				break;
			}
		}
		if (res < 0) {
			dev_err(&data->i2c_client->dev,
				"No clock input available\n");
			return res;
		}
	}

	/* Make sure the selected clock is also enabled and routed */
	err = si5341_clk_reparent(data, res);
	if (err < 0)
		return err;

	err = clk_prepare_enable(data->input_clk[res]);
	if (err < 0)
		return err;

	return res;
}

static int si5341_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct clk_si5341 *data;
	struct clk_init_data init;
	struct clk *input;
	const char *root_clock_name;
	const char *synth_clock_names[SI5341_NUM_SYNTH];
	int err;
@@ -1161,12 +1334,16 @@ static int si5341_probe(struct i2c_client *client,

	data->i2c_client = client;

	data->pxtal = devm_clk_get(&client->dev, "xtal");
	if (IS_ERR(data->pxtal)) {
		if (PTR_ERR(data->pxtal) == -EPROBE_DEFER)
	for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
		input = devm_clk_get(&client->dev, si5341_input_clock_names[i]);
		if (IS_ERR(input)) {
			if (PTR_ERR(input) == -EPROBE_DEFER)
				return -EPROBE_DEFER;

		dev_err(&client->dev, "Missing xtal clock input\n");
			data->input_clk_name[i] = si5341_input_clock_names[i];
		} else {
			data->input_clk[i] = input;
			data->input_clk_name[i] = __clk_get_name(input);
		}
	}

	err = si5341_dt_parse_dt(client, config);
@@ -1188,9 +1365,6 @@ static int si5341_probe(struct i2c_client *client,
	if (err < 0)
		return err;

	/* "Activate" the xtal (usually a fixed clock) */
	clk_prepare_enable(data->pxtal);

	if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
		initialization_required = true;
	} else {
@@ -1223,7 +1397,14 @@ static int si5341_probe(struct i2c_client *client,
					ARRAY_SIZE(si5341_reg_defaults));
		if (err < 0)
			return err;
	}

	/* Input must be up and running at this point */
	err = si5341_clk_select_active_input(data);
	if (err < 0)
		return err;

	if (initialization_required) {
		/* PLL configuration is required */
		err = si5341_initialize_pll(data);
		if (err < 0)
@@ -1231,9 +1412,8 @@ static int si5341_probe(struct i2c_client *client,
	}

	/* Register the PLL */
	data->pxtal_name = __clk_get_name(data->pxtal);
	init.parent_names = &data->pxtal_name;
	init.num_parents = 1; /* For now, only XTAL input supported */
	init.parent_names = data->input_clk_name;
	init.num_parents = SI5341_NUM_INPUTS;
	init.ops = &si5341_clk_ops;
	init.flags = 0;
	data->hw.init = &init;
+2 −2
Original line number Diff line number Diff line
@@ -4865,8 +4865,8 @@ static int parent_ready(struct device_node *np)
 *
 * Return: error code or zero on success
 */
int of_clk_detect_critical(struct device_node *np,
					  int index, unsigned long *flags)
int of_clk_detect_critical(struct device_node *np, int index,
			   unsigned long *flags)
{
	struct property *prop;
	const __be32 *cur;
+17 −23
Original line number Diff line number Diff line
@@ -65,54 +65,49 @@ static const struct clk_ops dbgclk_ops = {
	.get_parent = socfpga_gate_get_parent,
};

struct clk *s10_register_gate(const char *name, const char *parent_name,
			      const char * const *parent_names,
			      u8 num_parents, unsigned long flags,
			      void __iomem *regbase, unsigned long gate_reg,
			      unsigned long gate_idx, unsigned long div_reg,
			      unsigned long div_offset, u8 div_width,
			      unsigned long bypass_reg, u8 bypass_shift,
			      u8 fixed_div)
struct clk *s10_register_gate(const struct stratix10_gate_clock *clks, void __iomem *regbase)
{
	struct clk *clk;
	struct socfpga_gate_clk *socfpga_clk;
	struct clk_init_data init;
	const char * const *parent_names = clks->parent_names;
	const char *parent_name = clks->parent_name;

	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
	if (!socfpga_clk)
		return NULL;

	socfpga_clk->hw.reg = regbase + gate_reg;
	socfpga_clk->hw.bit_idx = gate_idx;
	socfpga_clk->hw.reg = regbase + clks->gate_reg;
	socfpga_clk->hw.bit_idx = clks->gate_idx;

	gateclk_ops.enable = clk_gate_ops.enable;
	gateclk_ops.disable = clk_gate_ops.disable;

	socfpga_clk->fixed_div = fixed_div;
	socfpga_clk->fixed_div = clks->fixed_div;

	if (div_reg)
		socfpga_clk->div_reg = regbase + div_reg;
	if (clks->div_reg)
		socfpga_clk->div_reg = regbase + clks->div_reg;
	else
		socfpga_clk->div_reg = NULL;

	socfpga_clk->width = div_width;
	socfpga_clk->shift = div_offset;
	socfpga_clk->width = clks->div_width;
	socfpga_clk->shift = clks->div_offset;

	if (bypass_reg)
		socfpga_clk->bypass_reg = regbase + bypass_reg;
	if (clks->bypass_reg)
		socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
	else
		socfpga_clk->bypass_reg = NULL;
	socfpga_clk->bypass_shift = bypass_shift;
	socfpga_clk->bypass_shift = clks->bypass_shift;

	if (streq(name, "cs_pdbg_clk"))
	if (streq(clks->name, "cs_pdbg_clk"))
		init.ops = &dbgclk_ops;
	else
		init.ops = &gateclk_ops;

	init.name = name;
	init.flags = flags;
	init.name = clks->name;
	init.flags = clks->flags;

	init.num_parents = num_parents;
	init.num_parents = clks->num_parents;
	init.parent_names = parent_names ? parent_names : &parent_name;
	socfpga_clk->hw.hw.init = &init;

@@ -121,6 +116,5 @@ struct clk *s10_register_gate(const char *name, const char *parent_name,
		kfree(socfpga_clk);
		return NULL;
	}

	return clk;
}
+21 −21
Original line number Diff line number Diff line
@@ -73,26 +73,27 @@ static const struct clk_ops peri_cnt_clk_ops = {
	.get_parent = clk_periclk_get_parent,
};

struct clk *s10_register_periph(const char *name, const char *parent_name,
				const char * const *parent_names,
				u8 num_parents, unsigned long flags,
				void __iomem *reg, unsigned long offset)
struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
				void __iomem *reg)
{
	struct clk *clk;
	struct socfpga_periph_clk *periph_clk;
	struct clk_init_data init;
	const char *name = clks->name;
	const char *parent_name = clks->parent_name;
	const char * const *parent_names = clks->parent_names;

	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
	if (WARN_ON(!periph_clk))
		return NULL;

	periph_clk->hw.reg = reg + offset;
	periph_clk->hw.reg = reg + clks->offset;

	init.name = name;
	init.ops = &peri_c_clk_ops;
	init.flags = flags;
	init.flags = clks->flags;

	init.num_parents = num_parents;
	init.num_parents = clks->num_parents;
	init.parent_names = parent_names ? parent_names : &parent_name;

	periph_clk->hw.hw.init = &init;
@@ -105,38 +106,37 @@ struct clk *s10_register_periph(const char *name, const char *parent_name,
	return clk;
}

struct clk *s10_register_cnt_periph(const char *name, const char *parent_name,
				    const char * const *parent_names,
				    u8 num_parents, unsigned long flags,
				    void __iomem *regbase, unsigned long offset,
				    u8 fixed_divider, unsigned long bypass_reg,
				    unsigned long bypass_shift)
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
				    void __iomem *regbase)
{
	struct clk *clk;
	struct socfpga_periph_clk *periph_clk;
	struct clk_init_data init;
	const char *name = clks->name;
	const char *parent_name = clks->parent_name;
	const char * const *parent_names = clks->parent_names;

	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
	if (WARN_ON(!periph_clk))
		return NULL;

	if (offset)
		periph_clk->hw.reg = regbase + offset;
	if (clks->offset)
		periph_clk->hw.reg = regbase + clks->offset;
	else
		periph_clk->hw.reg = NULL;

	if (bypass_reg)
		periph_clk->bypass_reg = regbase + bypass_reg;
	if (clks->bypass_reg)
		periph_clk->bypass_reg = regbase + clks->bypass_reg;
	else
		periph_clk->bypass_reg = NULL;
	periph_clk->bypass_shift = bypass_shift;
	periph_clk->fixed_div = fixed_divider;
	periph_clk->bypass_shift = clks->bypass_shift;
	periph_clk->fixed_div = clks->fixed_divider;

	init.name = name;
	init.ops = &peri_cnt_clk_ops;
	init.flags = flags;
	init.flags = clks->flags;

	init.num_parents = num_parents;
	init.num_parents = clks->num_parents;
	init.parent_names = parent_names ? parent_names : &parent_name;

	periph_clk->hw.hw.init = &init;
+10 −7
Original line number Diff line number Diff line
@@ -39,7 +39,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
	/* read VCO1 reg for numerator and denominator */
	reg = readl(socfpgaclk->hw.reg);
	refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
	vco_freq = (unsigned long long)parent_rate / refdiv;

	vco_freq = parent_rate;
	do_div(vco_freq, refdiv);

	/* Read mdiv and fdiv from the fdbck register */
	reg = readl(socfpgaclk->hw.reg + 0x4);
@@ -108,19 +110,20 @@ static struct clk_ops clk_boot_ops = {
	.prepare = clk_pll_prepare,
};

struct clk *s10_register_pll(const char *name, const char * const *parent_names,
				    u8 num_parents, unsigned long flags,
				    void __iomem *reg, unsigned long offset)
struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
			     void __iomem *reg)
{
	struct clk *clk;
	struct socfpga_pll *pll_clk;
	struct clk_init_data init;
	const char *name = clks->name;
	const char * const *parent_names = clks->parent_names;

	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
	if (WARN_ON(!pll_clk))
		return NULL;

	pll_clk->hw.reg = reg + offset;
	pll_clk->hw.reg = reg + clks->offset;

	if (streq(name, SOCFPGA_BOOT_CLK))
		init.ops = &clk_boot_ops;
@@ -128,9 +131,9 @@ struct clk *s10_register_pll(const char *name, const char * const *parent_names,
		init.ops = &clk_pll_ops;

	init.name = name;
	init.flags = flags;
	init.flags = clks->flags;

	init.num_parents = num_parents;
	init.num_parents = clks->num_parents;
	init.parent_names = parent_names;
	pll_clk->hw.hw.init = &init;

Loading