diff --git a/Documentation/devicetree/bindings/clock/clock-bindings.txt b/Documentation/devicetree/bindings/clock/clock-bindings.txt index f2ea53832ac63e..d9a783c35c5a1f 100644 --- a/Documentation/devicetree/bindings/clock/clock-bindings.txt +++ b/Documentation/devicetree/bindings/clock/clock-bindings.txt @@ -169,6 +169,22 @@ a shared clock is forbidden. Configuration of common clocks, which affect multiple consumer devices can be similarly specified in the clock provider node. +==Critical clocks== + +Some platforms require clock to be always running, e.g. because those clock +supply devices which are not otherwise attached to the system. One example +is a system where the SoC serves as a crystal oscillator replacement for a +programmable logic device. The critical-clock property of a clock controller +allows listing clock which must never be turned off. + + clock-controller@a000f000 { + compatible = "vendor,clk95; + reg = <0xa000f000 0x1000> + #clocks-cells = <1>; + ... + critical-clocks = , ; + }; + ==Protected clocks== Some platforms or firmwares may not fully expose all the clocks to the OS, such diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c index ac40b669d60b74..90b81a35f503f9 100644 --- a/drivers/clk/clk-bd718x7.c +++ b/drivers/clk/clk-bd718x7.c @@ -70,10 +70,25 @@ static int bd71837_clk_is_enabled(struct clk_hw *hw) return enabled & c->mask; } +static int bd71837_match_clkspec(struct clk_hw *hw, struct of_phandle_args *clkspec) +{ + struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); + + /* + * if (clk_hw == clkspec) + * return 0; + * else + * return 1; + */ + + return 0; +} + static const struct clk_ops bd71837_clk_ops = { .prepare = &bd71837_clk_enable, .unprepare = &bd71837_clk_disable, .is_prepared = &bd71837_clk_is_enabled, + .match_clkspec = &bd71837_match_clkspec, }; static int bd71837_clk_probe(struct platform_device *pdev) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f467d63bbf1eef..fa8e9ea446158f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3849,6 +3849,31 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) core->max_rate = ULONG_MAX; hw->core = core; + struct of_phandle_args clkspec; + u32 clksize, clktotal; + int i, index; + + if (np && core->ops->match_clkspec && !of_property_read_u32(np, "#clock-cells", &clksize)) { + if (clksize == 0) { + if (of_property_read_bool(np, "critical-clocks")) + core->flags |= CLK_IS_CRITICAL; + clktotal = 0; + } else { + clkspec.np = np; + clktotal = of_property_count_u32_elems(np, "critical-clocks"); + clktotal /= clksize; + for (index = 0; index < clktotal; index++) { + for (i = 0; i < clksize; i++) { + ret = of_property_read_u32_index(np, "critical-clocks", + (index * clksize) + i, + &(clkspec.args[i])); + } + if (!core->ops->match_clkspec(hw, &clkspec)) + core->flags |= CLK_IS_CRITICAL; + } + } + } + ret = clk_core_populate_parent_map(core, init); if (ret) goto fail_parents; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index f59c875271a0ee..766e93efb23c55 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -205,6 +205,7 @@ struct clk_duty { * directory is provided as an argument. Called with * prepare_lock held. Returns 0 on success, -EERROR otherwise. * + * @match_clkspec: Check whether clk_hw matches DT clock specifier * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable @@ -252,6 +253,7 @@ struct clk_ops { int (*init)(struct clk_hw *hw); void (*terminate)(struct clk_hw *hw); void (*debug_init)(struct clk_hw *hw, struct dentry *dentry); + int (*match_clkspec)(struct clk_hw *hw, struct of_phandle_args *clkspec); }; /**