Skip to content

Commit

Permalink
Merge tag 'meson-clk-4.19-1' of https://github.com/BayLibre/clk-meson
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Stephen Boyd committed Jul 9, 2018
2 parents ce397d2 + 7df533a commit 166f3a8
Show file tree
Hide file tree
Showing 22 changed files with 2,141 additions and 211 deletions.
56 changes: 56 additions & 0 deletions Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
* 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>;
};
199 changes: 194 additions & 5 deletions drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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();

Expand All @@ -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)
Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down
28 changes: 19 additions & 9 deletions drivers/clk/meson/Kconfig
Original file line number Diff line number Diff line change
@@ -1,46 +1,56 @@
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
select REGMAP

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
want peripherals and CPU frequency scaling to work.

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.
Say Y if you want peripherals and CPU frequency scaling to work.

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.
Loading

0 comments on commit 166f3a8

Please sign in to comment.