Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 166f3a8a authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'meson-clk-4.19-1' of https://github.com/BayLibre/clk-meson into clk-meson

Pull first round of updates for meson clocks from Jerome Brunet:

 - Remove legacy register access (finish moving to syscon)
 - Clean up configuration flags
 - Add axg PCIe clocks
 - Add GEN CLK on gxbb, gxl and axg
 - Remove clk_audio_divider driver
 - Add axg audio clock controller

* tag 'meson-clk-4.19-1' of https://github.com/BayLibre/clk-meson:
  clk: meson: add gen_clk
  clk: meson: gxbb: remove HHI_GEN_CLK_CTNL duplicate definition
  clk: meson-axg: add clocks required by pcie driver
  clk: meson: remove unused clk-audio-divider driver
  clk: meson: stop rate propagation for audio clocks
  clk: meson: axg: add the audio clock controller driver
  clk: meson: add axg audio sclk divider driver
  clk: meson: add triple phase clock driver
  clk: meson: add clk-phase clock driver
  clk: meson: clean-up meson clock configuration
  clk: meson: remove obsolete register access
  clk: meson: expose GEN_CLK clkid
  clk: meson-axg: add pcie and mipi clock bindings
  dt-bindings: clock: add meson axg audio clock controller bindings
  clk: meson: audio-divider is one based
  clk: add duty cycle support
  clk: meson-gxbb: set fclk_div2 as CLK_IS_CRITICAL
parents ce397d21 7df533a7
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
* Amlogic AXG Audio Clock Controllers

The Amlogic AXG audio clock controller generates and supplies clock to the
other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
devices.

Required Properties:

- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
- reg		: physical base address of the clock controller and length of
		  memory mapped region.
- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
		  in clock-names.
- clock-names	: must contain the following:
		  * "pclk" - Main peripheral bus clock
		  may contain the following:
		  * "mst_in[0-7]" - 8 input plls to generate clock signals
		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
				      components.
		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
				       components.
- resets	: phandle of the internal reset line
- #clock-cells	: should be 1.

Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
used in device tree sources.

Example:

clkc_audio: clock-controller@0 {
	compatible = "amlogic,axg-audio-clkc";
	reg = <0x0 0x0 0x0 0xb4>;
	#clock-cells = <1>;

	clocks = <&clkc CLKID_AUDIO>,
		 <&clkc CLKID_MPLL0>,
		 <&clkc CLKID_MPLL1>,
		 <&clkc CLKID_MPLL2>,
		 <&clkc CLKID_MPLL3>,
		 <&clkc CLKID_HIFI_PLL>,
		 <&clkc CLKID_FCLK_DIV3>,
		 <&clkc CLKID_FCLK_DIV4>,
		 <&clkc CLKID_GP0_PLL>;
	clock-names = "pclk",
		      "mst_in0",
		      "mst_in1",
		      "mst_in2",
		      "mst_in3",
		      "mst_in4",
		      "mst_in5",
		      "mst_in6",
		      "mst_in7";
	resets = <&reset RESET_AUDIO>;
};
+194 −5
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ struct clk_core {
	unsigned long		max_rate;
	unsigned long		accuracy;
	int			phase;
	struct clk_duty		duty;
	struct hlist_head	children;
	struct hlist_node	child_node;
	struct hlist_head	clks;
@@ -2402,6 +2403,172 @@ int clk_get_phase(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_get_phase);

static void clk_core_reset_duty_cycle_nolock(struct clk_core *core)
{
	/* Assume a default value of 50% */
	core->duty.num = 1;
	core->duty.den = 2;
}

static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core);

static int clk_core_update_duty_cycle_nolock(struct clk_core *core)
{
	struct clk_duty *duty = &core->duty;
	int ret = 0;

	if (!core->ops->get_duty_cycle)
		return clk_core_update_duty_cycle_parent_nolock(core);

	ret = core->ops->get_duty_cycle(core->hw, duty);
	if (ret)
		goto reset;

	/* Don't trust the clock provider too much */
	if (duty->den == 0 || duty->num > duty->den) {
		ret = -EINVAL;
		goto reset;
	}

	return 0;

reset:
	clk_core_reset_duty_cycle_nolock(core);
	return ret;
}

static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core)
{
	int ret = 0;

	if (core->parent &&
	    core->flags & CLK_DUTY_CYCLE_PARENT) {
		ret = clk_core_update_duty_cycle_nolock(core->parent);
		memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
	} else {
		clk_core_reset_duty_cycle_nolock(core);
	}

	return ret;
}

static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
						 struct clk_duty *duty);

static int clk_core_set_duty_cycle_nolock(struct clk_core *core,
					  struct clk_duty *duty)
{
	int ret;

	lockdep_assert_held(&prepare_lock);

	if (clk_core_rate_is_protected(core))
		return -EBUSY;

	trace_clk_set_duty_cycle(core, duty);

	if (!core->ops->set_duty_cycle)
		return clk_core_set_duty_cycle_parent_nolock(core, duty);

	ret = core->ops->set_duty_cycle(core->hw, duty);
	if (!ret)
		memcpy(&core->duty, duty, sizeof(*duty));

	trace_clk_set_duty_cycle_complete(core, duty);

	return ret;
}

static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
						 struct clk_duty *duty)
{
	int ret = 0;

	if (core->parent &&
	    core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) {
		ret = clk_core_set_duty_cycle_nolock(core->parent, duty);
		memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
	}

	return ret;
}

/**
 * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
 * @clk: clock signal source
 * @num: numerator of the duty cycle ratio to be applied
 * @den: denominator of the duty cycle ratio to be applied
 *
 * Apply the duty cycle ratio if the ratio is valid and the clock can
 * perform this operation
 *
 * Returns (0) on success, a negative errno otherwise.
 */
int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den)
{
	int ret;
	struct clk_duty duty;

	if (!clk)
		return 0;

	/* sanity check the ratio */
	if (den == 0 || num > den)
		return -EINVAL;

	duty.num = num;
	duty.den = den;

	clk_prepare_lock();

	if (clk->exclusive_count)
		clk_core_rate_unprotect(clk->core);

	ret = clk_core_set_duty_cycle_nolock(clk->core, &duty);

	if (clk->exclusive_count)
		clk_core_rate_protect(clk->core);

	clk_prepare_unlock();

	return ret;
}
EXPORT_SYMBOL_GPL(clk_set_duty_cycle);

static int clk_core_get_scaled_duty_cycle(struct clk_core *core,
					  unsigned int scale)
{
	struct clk_duty *duty = &core->duty;
	int ret;

	clk_prepare_lock();

	ret = clk_core_update_duty_cycle_nolock(core);
	if (!ret)
		ret = mult_frac(scale, duty->num, duty->den);

	clk_prepare_unlock();

	return ret;
}

/**
 * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
 * @clk: clock signal source
 * @scale: scaling factor to be applied to represent the ratio as an integer
 *
 * Returns the duty cycle ratio of a clock node multiplied by the provided
 * scaling factor, or negative errno on error.
 */
int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale)
{
	if (!clk)
		return 0;

	return clk_core_get_scaled_duty_cycle(clk->core, scale);
}
EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle);

/**
 * clk_is_match - check if two clk's point to the same hardware clock
 * @p: clk compared against q
@@ -2455,12 +2622,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
	if (!c)
		return;

	seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
	seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
		   level * 3 + 1, "",
		   30 - level * 3, c->name,
		   c->enable_count, c->prepare_count, c->protect_count,
		   clk_core_get_rate(c), clk_core_get_accuracy(c),
		   clk_core_get_phase(c));
		   clk_core_get_phase(c),
		   clk_core_get_scaled_duty_cycle(c, 100000));
}

static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2482,9 +2650,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
	struct clk_core *c;
	struct hlist_head **lists = (struct hlist_head **)s->private;

	seq_puts(s, "                                 enable  prepare  protect                               \n");
	seq_puts(s, "   clock                          count    count    count        rate   accuracy   phase\n");
	seq_puts(s, "----------------------------------------------------------------------------------------\n");
	seq_puts(s, "                                 enable  prepare  protect                                duty\n");
	seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle\n");
	seq_puts(s, "---------------------------------------------------------------------------------------------\n");

	clk_prepare_lock();

@@ -2511,6 +2679,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
	seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
	seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
	seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
	seq_printf(s, "\"duty_cycle\": %u",
		   clk_core_get_scaled_duty_cycle(c, 100000));
}

static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
@@ -2572,6 +2742,7 @@ static const struct {
	ENTRY(CLK_SET_RATE_UNGATE),
	ENTRY(CLK_IS_CRITICAL),
	ENTRY(CLK_OPS_PARENT_ENABLE),
	ENTRY(CLK_DUTY_CYCLE_PARENT),
#undef ENTRY
};

@@ -2610,6 +2781,17 @@ static int possible_parents_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(possible_parents);

static int clk_duty_cycle_show(struct seq_file *s, void *data)
{
	struct clk_core *core = s->private;
	struct clk_duty *duty = &core->duty;

	seq_printf(s, "%u/%u\n", duty->num, duty->den);

	return 0;
}
DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);

static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
{
	struct dentry *root;
@@ -2628,6 +2810,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
	debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
	debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
	debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
	debugfs_create_file("clk_duty_cycle", 0444, root, core,
			    &clk_duty_cycle_fops);

	if (core->num_parents > 1)
		debugfs_create_file("clk_possible_parents", 0444, root, core,
@@ -2845,6 +3029,11 @@ static int __clk_core_init(struct clk_core *core)
	else
		core->phase = 0;

	/*
	 * Set clk's duty cycle.
	 */
	clk_core_update_duty_cycle_nolock(core);

	/*
	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
	 * simple clocks and lazy developers the default fallback is to use the
+19 −9
Original line number Diff line number Diff line
config COMMON_CLK_AMLOGIC
	bool
	depends on OF
	depends on ARCH_MESON || COMPILE_TEST
	select COMMON_CLK_REGMAP_MESON

config COMMON_CLK_AMLOGIC_AUDIO
	bool
	depends on ARCH_MESON || COMPILE_TEST
	select COMMON_CLK_AMLOGIC

config COMMON_CLK_MESON_AO
	bool
	depends on OF
	depends on ARCH_MESON || COMPILE_TEST
	select COMMON_CLK_REGMAP_MESON
	select RESET_CONTROLLER

config COMMON_CLK_REGMAP_MESON
	bool
@@ -15,9 +21,8 @@ config COMMON_CLK_REGMAP_MESON

config COMMON_CLK_MESON8B
	bool
	depends on COMMON_CLK_AMLOGIC
	select COMMON_CLK_AMLOGIC
	select RESET_CONTROLLER
	select COMMON_CLK_REGMAP_MESON
	help
	  Support for the clock controller on AmLogic S802 (Meson8),
	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
@@ -25,10 +30,8 @@ config COMMON_CLK_MESON8B

config COMMON_CLK_GXBB
	bool
	depends on COMMON_CLK_AMLOGIC
	select RESET_CONTROLLER
	select COMMON_CLK_AMLOGIC
	select COMMON_CLK_MESON_AO
	select COMMON_CLK_REGMAP_MESON
	select MFD_SYSCON
	help
	  Support for the clock controller on AmLogic S905 devices, aka gxbb.
@@ -36,11 +39,18 @@ config COMMON_CLK_GXBB

config COMMON_CLK_AXG
	bool
	depends on COMMON_CLK_AMLOGIC
	select RESET_CONTROLLER
	select COMMON_CLK_AMLOGIC
	select COMMON_CLK_MESON_AO
	select COMMON_CLK_REGMAP_MESON
	select MFD_SYSCON
	help
	  Support for the clock controller on AmLogic A113D devices, aka axg.
	  Say Y if you want peripherals and CPU frequency scaling to work.

config COMMON_CLK_AXG_AUDIO
	tristate "Meson AXG Audio Clock Controller Driver"
	depends on COMMON_CLK_AXG
	select COMMON_CLK_AMLOGIC_AUDIO
	select MFD_SYSCON
	help
	  Support for the audio clock controller on AmLogic A113D devices,
	  aka axg, Say Y if you want audio subsystem to work.
+3 −1
Original line number Diff line number Diff line
@@ -2,9 +2,11 @@
# Makefile for Meson specific clk
#

obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)	+= axg-audio.o
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)	+= clk-regmap.o
+845 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading