Commit 6e7a9f0c authored by Stephen Boyd's avatar Stephen Boyd

Merge branches 'clk-debugfs-danger', 'clk-basic-hw', 'clk-renesas',...

Merge branches 'clk-debugfs-danger', 'clk-basic-hw', 'clk-renesas', 'clk-amlogic' and 'clk-allwinner' into clk-next

 - Support dangerous debugfs actions on clks with dead code
 - Convert gpio, fixed-factor, mux, gate, divider basic clks to hw based APIs

* clk-debugfs-danger:
  clk: Add support for setting clk_rate via debugfs

* clk-basic-hw:
  clk: divider: Add support for specifying parents via DT/pointers
  clk: gate: Add support for specifying parents via DT/pointers
  clk: mux: Add support for specifying parents via DT/pointers
  clk: asm9260: Use parent accuracy in fixed rate clk
  clk: fixed-rate: Document that accuracy isn't a rate
  clk: fixed-rate: Add clk flags for parent accuracy
  clk: fixed-rate: Add support for specifying parents via DT/pointers
  clk: fixed-rate: Document accuracy member
  clk: fixed-rate: Move to_clk_fixed_rate() to C file
  clk: fixed-rate: Remove clk_register_fixed_rate_with_accuracy()
  clk: fixed-rate: Convert to clk_hw based APIs
  clk: gpio: Use DT way of specifying parents

* clk-renesas:
  clk: renesas: Prepare for split of R-Car H3 config symbol
  dt-bindings: clock: renesas: cpg-mssr: Fix r8a774b1 typo
  clk: renesas: r7s9210: Add SPIBSC clock
  clk: renesas: rcar-gen3: Allow changing the RPC[D2] clocks
  clk: renesas: Remove use of ARCH_R8A7796
  clk: renesas: rcar-gen2: Change multipliers and dividers to u8

* clk-amlogic:
  clk: clarify that clk_set_rate() does updates from top to bottom
  clk: meson: meson8b: make the CCF use the glitch-free mali mux
  clk: meson: pll: Fix by 0 division in __pll_params_to_rate()
  clk: meson: g12a: fix missing uart2 in regmap table
  clk: meson: meson8b: use of_clk_hw_register to register the clocks
  clk: meson: meson8b: don't register the XTAL clock when provided via OF
  clk: meson: meson8b: change references to the XTAL clock to use [fw_]name
  clk: meson: meson8b: use clk_hw_set_parent in the CPU clock notifier
  clk: meson: add a driver for the Meson8/8b/8m2 DDR clock controller
  dt-bindings: clock: meson8b: add the clock inputs
  dt-bindings: clock: add the Amlogic Meson8 DDR clock controller binding

* clk-allwinner:
  clk: sunxi: a23/a33: Export the MIPI PLL
  clk: sunxi: a31: Export the MIPI PLL
  clk: sunxi-ng: a64: export CLK_CPUX clock for DVFS
  clk: sunxi-ng: add mux and pll notifiers for A64 CPU clock
  clk: sunxi-ng: r40: Export MBUS clock
  clk: sunxi: use of_device_get_match_data
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/amlogic,meson8-ddr-clkc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic DDR Clock Controller Device Tree Bindings
maintainers:
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
properties:
compatible:
enum:
- amlogic,meson8-ddr-clkc
- amlogic,meson8b-ddr-clkc
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: xtal
"#clock-cells":
const: 1
required:
- compatible
- reg
- clocks
- clock-names
- "#clock-cells"
additionalProperties: false
examples:
- |
ddr_clkc: clock-controller@400 {
compatible = "amlogic,meson8-ddr-clkc";
reg = <0x400 0x20>;
clocks = <&xtal>;
clock-names = "xtal";
#clock-cells = <1>;
};
...
......@@ -11,6 +11,11 @@ Required Properties:
- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
- #clock-cells: should be 1.
- #reset-cells: should be 1.
- clocks: list of clock phandles, one for each entry in clock-names
- clock-names: should contain the following:
* "xtal": the 24MHz system oscillator
* "ddr_pll": the DDR PLL clock
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
......
......@@ -19,7 +19,7 @@ Required Properties:
- "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
- "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
- "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M)
- "renesas,r8a774b1-cpg-mssr" for the r8a774a1 SoC (RZ/G2N)
- "renesas,r8a774b1-cpg-mssr" for the r8a774b1 SoC (RZ/G2N)
- "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E)
- "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2)
- "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W)
......
......@@ -260,7 +260,6 @@ static void __init asm9260_acc_init(struct device_node *np)
const char *ref_clk, *pll_clk = "pll";
u32 rate;
int n;
u32 accuracy = 0;
clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
if (!clk_data)
......@@ -275,10 +274,11 @@ static void __init asm9260_acc_init(struct device_node *np)
/* register pll */
rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
/* TODO: Convert to DT parent scheme */
ref_clk = of_clk_get_parent_name(np, 0);
accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, pll_clk,
ref_clk, 0, rate, accuracy);
hw = __clk_hw_register_fixed_rate_with_accuracy(NULL, NULL, pll_clk,
ref_clk, NULL, NULL, 0, rate, 0,
CLK_FIXED_RATE_PARENT_ACCURACY);
if (IS_ERR(hw))
panic("%pOFn: can't register REFCLK. Check DT!", np);
......
......@@ -463,11 +463,12 @@ const struct clk_ops clk_divider_ro_ops = {
};
EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
static struct clk_hw *_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
struct clk_hw *__clk_hw_register_divider(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_divider *div;
struct clk_hw *hw;
......@@ -514,55 +515,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name,
return hw;
}
/**
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
struct clk_hw *hw;
hw = _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_divider);
/**
* clk_hw_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_divider);
EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
/**
* clk_register_divider_table - register a table based divider clock with
......@@ -586,39 +539,15 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
{
struct clk_hw *hw;
hw = _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
hw = __clk_hw_register_divider(dev, NULL, name, parent_name, NULL,
NULL, flags, reg, shift, width, clk_divider_flags,
table, lock);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_divider_table);
/**
* clk_hw_register_divider_table - register a table based divider clock with
* the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @table: array of divider/value pairs ending with a div set to 0
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_divider_table(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_divider_table);
void clk_unregister_divider(struct clk *clk)
{
struct clk_divider *div;
......
......@@ -24,6 +24,8 @@
* parent - fixed parent. No clk_set_parent support
*/
#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
......@@ -33,7 +35,12 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw,
unsigned long parent_accuracy)
{
return to_clk_fixed_rate(hw)->fixed_accuracy;
struct clk_fixed_rate *fixed = to_clk_fixed_rate(hw);
if (fixed->flags & CLK_FIXED_RATE_PARENT_ACCURACY)
return parent_accuracy;
return fixed->fixed_accuracy;
}
const struct clk_ops clk_fixed_rate_ops = {
......@@ -42,24 +49,17 @@ const struct clk_ops clk_fixed_rate_ops = {
};
EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
/**
* clk_hw_register_fixed_rate_with_accuracy - register fixed-rate clock with
* the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
* @fixed_accuracy: non-adjustable clock rate
*/
struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned long fixed_rate, unsigned long fixed_accuracy)
struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
unsigned long fixed_rate, unsigned long fixed_accuracy,
unsigned long clk_fixed_flags)
{
struct clk_fixed_rate *fixed;
struct clk_hw *hw;
struct clk_init_data init = {};
int ret;
int ret = -EINVAL;
/* allocate fixed-rate clock */
fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
......@@ -69,17 +69,26 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
init.name = name;
init.ops = &clk_fixed_rate_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
init.parent_names = parent_name ? &parent_name : NULL;
init.parent_hws = parent_hw ? &parent_hw : NULL;
init.parent_data = parent_data;
if (parent_name || parent_hw || parent_data)
init.num_parents = 1;
else
init.num_parents = 0;
/* struct clk_fixed_rate assignments */
fixed->flags = clk_fixed_flags;
fixed->fixed_rate = fixed_rate;
fixed->fixed_accuracy = fixed_accuracy;
fixed->hw.init = &init;
/* register the clock */
hw = &fixed->hw;
ret = clk_hw_register(dev, hw);
if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) {
kfree(fixed);
hw = ERR_PTR(ret);
......@@ -87,47 +96,20 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate_with_accuracy);
EXPORT_SYMBOL_GPL(__clk_hw_register_fixed_rate);
struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned long fixed_rate, unsigned long fixed_accuracy)
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
{
struct clk_hw *hw;
hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, fixed_accuracy);
flags, fixed_rate, 0);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy);
/**
* clk_hw_register_fixed_rate - register fixed-rate clock with the clock
* framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
*/
struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
{
return clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, 0);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate);
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
{
return clk_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, 0);
}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
void clk_unregister_fixed_rate(struct clk *clk)
......@@ -155,9 +137,9 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
#ifdef CONFIG_OF
static struct clk *_of_fixed_clk_setup(struct device_node *node)
static struct clk_hw *_of_fixed_clk_setup(struct device_node *node)
{
struct clk *clk;
struct clk_hw *hw;
const char *clk_name = node->name;
u32 rate;
u32 accuracy = 0;
......@@ -170,18 +152,18 @@ static struct clk *_of_fixed_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
0, rate, accuracy);
if (IS_ERR(clk))
return clk;
if (IS_ERR(hw))
return hw;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
if (ret) {
clk_unregister(clk);
clk_hw_unregister_fixed_rate(hw);
return ERR_PTR(ret);
}
return clk;
return hw;
}
/**
......@@ -195,27 +177,27 @@ CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
static int of_fixed_clk_remove(struct platform_device *pdev)
{
struct clk *clk = platform_get_drvdata(pdev);
struct clk_hw *hw = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_rate(clk);
clk_hw_unregister_fixed_rate(hw);
return 0;
}
static int of_fixed_clk_probe(struct platform_device *pdev)
{
struct clk *clk;
struct clk_hw *hw;
/*
* This function is not executed when of_fixed_clk_setup
* succeeded.
*/
clk = _of_fixed_clk_setup(pdev->dev.of_node);
if (IS_ERR(clk))
return PTR_ERR(clk);
hw = _of_fixed_clk_setup(pdev->dev.of_node);
if (IS_ERR(hw))
return PTR_ERR(hw);
platform_set_drvdata(pdev, clk);
platform_set_drvdata(pdev, hw);
return 0;
}
......@@ -224,7 +206,6 @@ static const struct of_device_id of_fixed_clk_ids[] = {
{ .compatible = "fixed-clock" },
{ }
};
MODULE_DEVICE_TABLE(of, of_fixed_clk_ids);
static struct platform_driver of_fixed_clk_driver = {
.driver = {
......
......@@ -123,26 +123,18 @@ const struct clk_ops clk_gate_ops = {
};
EXPORT_SYMBOL_GPL(clk_gate_ops);
/**
* clk_hw_register_gate - register a gate clock with the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of this clock's parent
* @flags: framework-specific flags for this clock
* @reg: register address to control gating of this clock
* @bit_idx: which bit in the register controls gating of this clock
* @clk_gate_flags: gate-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
struct clk_hw *__clk_hw_register_gate(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data,
unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
{
struct clk_gate *gate;
struct clk_hw *hw;
struct clk_init_data init = {};
int ret;
int ret = -EINVAL;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
if (bit_idx > 15) {
......@@ -160,7 +152,12 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
init.ops = &clk_gate_ops;
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.parent_hws = parent_hw ? &parent_hw : NULL;
init.parent_data = parent_data;
if (parent_name || parent_hw || parent_data)
init.num_parents = 1;
else
init.num_parents = 0;
/* struct clk_gate assignments */
gate->reg = reg;
......@@ -170,15 +167,19 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
gate->hw.init = &init;
hw = &gate->hw;
ret = clk_hw_register(dev, hw);
if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) {
kfree(gate);
hw = ERR_PTR(ret);
}
return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_gate);
EXPORT_SYMBOL_GPL(__clk_hw_register_gate);
struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
......
......@@ -28,6 +28,26 @@
* parent - fixed parent. No clk_set_parent support
*/
/**
* struct clk_gpio - gpio gated clock
*
* @hw: handle between common and hardware-specific interfaces
* @gpiod: gpio descriptor
*
* Clock with a gpio control for enabling and disabling the parent clock
* or switching between two parents by asserting or deasserting the gpio.
*
* Implements .enable, .disable and .is_enabled or
* .get_parent, .set_parent and .determine_rate depending on which clk_ops
* is used.
*/
struct clk_gpio {
struct clk_hw hw;
struct gpio_desc *gpiod;
};
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
static int clk_gpio_gate_enable(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
......@@ -51,12 +71,11 @@ static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
return gpiod_get_value(clk->gpiod);
}
const struct clk_ops clk_gpio_gate_ops = {
static const struct clk_ops clk_gpio_gate_ops = {
.enable = clk_gpio_gate_enable,
.disable = clk_gpio_gate_disable,
.is_enabled = clk_gpio_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
{
......@@ -111,67 +130,49 @@ static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
const struct clk_ops clk_gpio_mux_ops = {
static const struct clk_ops clk_gpio_mux_ops = {
.get_parent = clk_gpio_mux_get_parent,
.set_parent = clk_gpio_mux_set_parent,
.determine_rate = __clk_mux_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
static struct clk_hw *clk_register_gpio(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
unsigned long flags, const struct clk_ops *clk_gpio_ops)
static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
struct gpio_desc *gpiod,
const struct clk_ops *clk_gpio_ops)
{
struct clk_gpio *clk_gpio;
struct clk_hw *hw;
struct clk_init_data init = {};
int err;
const struct clk_parent_data gpio_parent_data[] = {
{ .index = 0 },
{ .index = 1 },
};
if (dev)
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
else
clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
if (!clk_gpio)
return ERR_PTR(-ENOMEM);
init.name = name;
init.name = dev->of_node->name;
init.ops = clk_gpio_ops;
init.flags = flags;
init.parent_names = parent_names;
init.parent_data = gpio_parent_data;
init.num_parents = num_parents;
init.flags = CLK_SET_RATE_PARENT;
clk_gpio->gpiod = gpiod;
clk_gpio->hw.init = &init;
hw = &clk_gpio->hw;
if (dev)
err = devm_clk_hw_register(dev, hw);
else
err = clk_hw_register(NULL, hw);
if (!err)
return hw;
if (!dev) {
kfree(clk_gpio);
}
err = devm_clk_hw_register(dev, hw);
if (err)
return ERR_PTR(err);
return ERR_PTR(err);
return hw;
}
/**
* clk_hw_register_gpio_gate - register a gpio clock gate with the clock
* framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of this clock's parent
* @gpiod: gpio descriptor to gate this clock
* @flags: clock flags
*/
struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
const char *parent_name, struct gpio_desc *gpiod,
unsigned long flags)
static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
int num_parents,
struct gpio_desc *gpiod)
{
const struct clk_ops *ops;
......@@ -180,88 +181,36 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
else
ops = &clk_gpio_gate_ops;
return clk_register_gpio(dev, name,
(parent_name ? &parent_name : NULL),
(parent_name ? 1 : 0), gpiod, flags, ops);
return clk_register_gpio(dev, num_parents, gpiod, ops);
}
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
const char *parent_name, struct gpio_desc *gpiod,
unsigned long flags)
static struct clk_hw *clk_hw_register_gpio_mux(struct device *dev,
struct gpio_desc *gpiod)
{
struct clk_hw *hw;
hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpiod, flags);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
return clk_register_gpio(dev, 2, gpiod, &clk_gpio_mux_ops);
}
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
/**
* clk_hw_register_gpio_mux - register a gpio clock mux with the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_names: names of this clock's parents
* @num_parents: number of parents listed in @parent_names
* @gpiod: gpio descriptor to gate this clock
* @flags: clock flags
*/
struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
unsigned long flags)
{
if (num_parents != 2) {
pr_err("mux-clock %s must have 2 parents\n", name);
return ERR_PTR(-EINVAL);
}
return clk_register_gpio(dev, name, parent_names, num_parents,
gpiod, flags, &clk_gpio_mux_ops);
}
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux);
struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
unsigned long flags)
{
struct clk_hw *hw;
hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents,
gpiod, flags);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
static int gpio_clk_driver_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const char **parent_names, *gpio_name;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
const char *gpio_name;
unsigned int num_parents;
struct gpio_desc *gpiod;
struct clk *clk;
struct clk_hw *hw;
bool is_mux;
int ret;
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
num_parents = of_clk_get_parent_count(node);
if (num_parents) {
parent_names = devm_kcalloc(&pdev->dev, num_parents,
sizeof(char *), GFP_KERNEL);
if (!parent_names)
return -ENOMEM;
of_clk_parent_fill(node, parent_names, num_parents);
} else {
parent_names = NULL;
if (is_mux && num_parents != 2) {
dev_err(dev, "mux-clock must have 2 parents\n");
return -EINVAL;
}
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
gpio_name = is_mux ? "select" : "enable";
gpiod = devm_gpiod_get(&pdev->dev, gpio_name, GPIOD_OUT_LOW);
gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
if (ret == -EPROBE_DEFER)
......@@ -275,16 +224,13 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
}
if (is_mux)
clk = clk_register_gpio_mux(&pdev->dev, node->name,
parent_names, num_parents, gpiod, 0);
hw = clk_hw_register_gpio_mux(dev, gpiod);
else
clk = clk_register_gpio_gate(&pdev->dev, node->name,
parent_names ? parent_names[0] : NULL, gpiod,
CLK_SET_RATE_PARENT);
if (IS_ERR(clk))
return PTR_ERR(clk);
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
if (IS_ERR(hw))
return PTR_ERR(hw);
return of_clk_add_provider(node, of_clk_src_simple_get, clk);
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct of_device_id gpio_clk_match_table[] = {
......
......@@ -145,17 +145,19 @@ const struct clk_ops clk_mux_ro_ops = {
};
EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u32 mask,
struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
const char *name, u8 num_parents,
const char * const *parent_names,
const struct clk_hw **parent_hws,
const struct clk_parent_data *parent_data,
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
struct clk_mux *mux;
struct clk_hw *hw;
struct clk_init_data init = {};
u8 width = 0;
int ret;
int ret = -EINVAL;
if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
width = fls(mask) - ffs(mask) + 1;
......@@ -177,6 +179,8 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
init.ops = &clk_mux_ops;
init.flags = flags;
init.parent_names = parent_names;
init.parent_data = parent_data;
init.parent_hws = parent_hws;
init.num_parents = num_parents;
/* struct clk_mux assignments */
......@@ -189,7 +193,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
mux->hw.init = &init;
hw = &mux->hw;
ret = clk_hw_register(dev, hw);
if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) {
kfree(mux);
hw = ERR_PTR(ret);
......@@ -197,53 +204,24 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_mux_table);
EXPORT_SYMBOL_GPL(__clk_hw_register_mux);
struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u32 mask,
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
struct clk_hw *hw;
hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
table, lock);
hw = clk_hw_register_mux_table(dev, name, parent_names,
num_parents, flags, reg, shift, mask,
clk_mux_flags, table, lock);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_mux_table);
struct clk *clk_register_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
{
u32 mask = BIT(width) - 1;
return clk_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);
struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
{
u32 mask = BIT(width) - 1;
return clk_hw_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_mux);
void clk_unregister_mux(struct clk *clk)
{
struct clk_mux *mux;
......
......@@ -2996,6 +2996,41 @@ static int clk_dump_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(clk_dump);
#undef CLOCK_ALLOW_WRITE_DEBUGFS
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous, therefore don't provide any real compile time
* configuration option for this feature.
* People who want to use this will need to modify the source code directly.
*/
static int clk_rate_set(void *data, u64 val)
{
struct clk_core *core = data;
int ret;
clk_prepare_lock();
ret = clk_core_set_rate_nolock(core, val);
clk_prepare_unlock();
return ret;
}
#define clk_rate_mode 0644
#else
#define clk_rate_set NULL
#define clk_rate_mode 0444
#endif
static int clk_rate_get(void *data, u64 *val)
{
struct clk_core *core = data;
*val = core->rate;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(clk_rate_fops, clk_rate_get, clk_rate_set, "%llu\n");
static const struct {
unsigned long flag;
const char *name;
......@@ -3145,7 +3180,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
root = debugfs_create_dir(core->name, pdentry);
core->dentry = root;
debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
debugfs_create_file("clk_rate", clk_rate_mode, root, core,
&clk_rate_fops);
debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
......
......@@ -18,4 +18,4 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
......@@ -77,6 +77,15 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
unsigned int m, n, frac;
n = meson_parm_read(clk->map, &pll->n);
/*
* On some HW, N is set to zero on init. This value is invalid as
* it would result in a division by zero. The rate can't be
* calculated in this case
*/
if (n == 0)
return 0;
m = meson_parm_read(clk->map, &pll->m);
frac = MESON_PARM_APPLICABLE(&pll->frac) ?
......
......@@ -4692,6 +4692,7 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&g12a_bt656,
&g12a_usb1_to_ddr,
&g12a_mmc_pclk,
&g12a_uart2,
&g12a_vpu_intr,
&g12a_gic,
&g12a_sd_emmc_a_clk0,
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Amlogic Meson8 DDR clock controller
*
* Copyright (C) 2019 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <dt-bindings/clock/meson8-ddr-clkc.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-regmap.h"
#include "clk-pll.h"
#define AM_DDR_PLL_CNTL 0x00
#define AM_DDR_PLL_CNTL1 0x04
#define AM_DDR_PLL_CNTL2 0x08
#define AM_DDR_PLL_CNTL3 0x0c
#define AM_DDR_PLL_CNTL4 0x10
#define AM_DDR_PLL_STS 0x14
#define DDR_CLK_CNTL 0x18
#define DDR_CLK_STS 0x1c
static struct clk_regmap meson8_ddr_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = AM_DDR_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = AM_DDR_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = AM_DDR_PLL_CNTL,
.shift = 9,
.width = 5,
},
.l = {
.reg_off = AM_DDR_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = AM_DDR_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){
.name = "ddr_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
},
.num_parents = 1,
},
};
static struct clk_regmap meson8_ddr_pll = {
.data = &(struct clk_regmap_div_data){
.offset = AM_DDR_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "ddr_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8_ddr_pll_dco.hw
},
.num_parents = 1,
},
};
static struct clk_hw_onecell_data meson8_ddr_clk_hw_onecell_data = {
.hws = {
[DDR_CLKID_DDR_PLL_DCO] = &meson8_ddr_pll_dco.hw,
[DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw,
},
.num = 2,
};
static struct clk_regmap *const meson8_ddr_clk_regmaps[] = {
&meson8_ddr_pll_dco,
&meson8_ddr_pll,
};
static const struct regmap_config meson8_ddr_clkc_regmap_config = {
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = DDR_CLK_STS,
};
static int meson8_ddr_clkc_probe(struct platform_device *pdev)
{
struct regmap *regmap;
void __iomem *base;
struct clk_hw *hw;
int ret, i;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(&pdev->dev, base,
&meson8_ddr_clkc_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
/* Populate regmap */
for (i = 0; i < ARRAY_SIZE(meson8_ddr_clk_regmaps); i++)
meson8_ddr_clk_regmaps[i]->map = regmap;
/* Register all clks */
for (i = 0; i < meson8_ddr_clk_hw_onecell_data.num; i++) {
hw = meson8_ddr_clk_hw_onecell_data.hws[i];
ret = devm_clk_hw_register(&pdev->dev, hw);
if (ret) {
dev_err(&pdev->dev, "Clock registration failed\n");
return ret;
}
}
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
&meson8_ddr_clk_hw_onecell_data);
}
static const struct of_device_id meson8_ddr_clkc_match_table[] = {
{ .compatible = "amlogic,meson8-ddr-clkc" },
{ .compatible = "amlogic,meson8b-ddr-clkc" },
{ /* sentinel */ }
};
static struct platform_driver meson8_ddr_clkc_driver = {
.probe = meson8_ddr_clkc_probe,
.driver = {
.name = "meson8-ddr-clkc",
.of_match_table = meson8_ddr_clkc_match_table,
},
};
builtin_platform_driver(meson8_ddr_clkc_driver);
......@@ -97,8 +97,10 @@ static struct clk_regmap meson8b_fixed_pll_dco = {
.hw.init = &(struct clk_init_data){
.name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
.name = "xtal",
.index = -1,
},
.num_parents = 1,
},
......@@ -162,8 +164,10 @@ static struct clk_regmap meson8b_hdmi_pll_dco = {
/* sometimes also called "HPLL" or "HPLL PLL" */
.name = "hdmi_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
.name = "xtal",
.index = -1,
},
.num_parents = 1,
},
......@@ -237,8 +241,10 @@ static struct clk_regmap meson8b_sys_pll_dco = {
.hw.init = &(struct clk_init_data){
.name = "sys_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
.name = "xtal",
.index = -1,
},
.num_parents = 1,
},
......@@ -631,9 +637,9 @@ static struct clk_regmap meson8b_cpu_in_sel = {
.hw.init = &(struct clk_init_data){
.name = "cpu_in_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw,
&meson8b_sys_pll.hw,
.parent_data = (const struct clk_parent_data[]) {
{ .fw_name = "xtal", .name = "xtal", .index = -1, },
{ .hw = &meson8b_sys_pll.hw, },
},
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
......@@ -736,9 +742,9 @@ static struct clk_regmap meson8b_cpu_clk = {
.hw.init = &(struct clk_init_data){
.name = "cpu_clk",
.ops = &clk_regmap_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw,
&meson8b_cpu_scale_out_sel.hw,
.parent_data = (const struct clk_parent_data[]) {
{ .fw_name = "xtal", .name = "xtal", .index = -1, },
{ .hw = &meson8b_cpu_scale_out_sel.hw, },
},
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
......@@ -758,12 +764,12 @@ static struct clk_regmap meson8b_nand_clk_sel = {
.name = "nand_clk_sel",
.ops = &clk_regmap_mux_ops,
/* FIXME all other parents are unknown: */
.parent_hws = (const struct clk_hw *[]) {
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
&meson8b_fclk_div7.hw,
&meson8b_xtal.hw,
.parent_data = (const struct clk_parent_data[]) {
{ .hw = &meson8b_fclk_div4.hw, },
{ .hw = &meson8b_fclk_div3.hw, },
{ .hw = &meson8b_fclk_div5.hw, },
{ .hw = &meson8b_fclk_div7.hw, },
{ .fw_name = "xtal", .name = "xtal", .index = -1, },
},
.num_parents = 5,
.flags = CLK_SET_RATE_PARENT,
......@@ -1721,8 +1727,10 @@ static struct clk_regmap meson8b_hdmi_sys_sel = {
.name = "hdmi_sys_sel",
.ops = &clk_regmap_mux_ro_ops,
/* FIXME: all other parents are unknown */
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
.name = "xtal",
.index = -1,
},
.num_parents = 1,
.flags = CLK_SET_RATE_NO_REPARENT,
......@@ -1764,17 +1772,20 @@ static struct clk_regmap meson8b_hdmi_sys = {
/*
* The MALI IP is clocked by two identical clocks (mali_0 and mali_1)
* muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only
* has mali_0 and no glitch-free mux.
* muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can
* actually manage this glitch-free mux because it does top-to-bottom
* updates the each clock tree and switches to the "inactive" one when
* CLK_SET_RATE_GATE is set.
* Meson8 only has mali_0 and no glitch-free mux.
*/
static const struct clk_hw *meson8b_mali_0_1_parent_hws[] = {
&meson8b_xtal.hw,
&meson8b_mpll2.hw,
&meson8b_mpll1.hw,
&meson8b_fclk_div7.hw,
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
static const struct clk_parent_data meson8b_mali_0_1_parent_data[] = {
{ .fw_name = "xtal", .name = "xtal", .index = -1, },
{ .hw = &meson8b_mpll2.hw, },
{ .hw = &meson8b_mpll1.hw, },
{ .hw = &meson8b_fclk_div7.hw, },
{ .hw = &meson8b_fclk_div4.hw, },
{ .hw = &meson8b_fclk_div3.hw, },
{ .hw = &meson8b_fclk_div5.hw, },
};
static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 };
......@@ -1789,8 +1800,8 @@ static struct clk_regmap meson8b_mali_0_sel = {
.hw.init = &(struct clk_init_data){
.name = "mali_0_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_mali_0_1_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws),
.parent_data = meson8b_mali_0_1_parent_data,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data),
/*
* Don't propagate rate changes up because the only changeable
* parents are mpll1 and mpll2 but we need those for audio and
......@@ -1830,7 +1841,7 @@ static struct clk_regmap meson8b_mali_0 = {
&meson8b_mali_0_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
......@@ -1844,8 +1855,8 @@ static struct clk_regmap meson8b_mali_1_sel = {
.hw.init = &(struct clk_init_data){
.name = "mali_1_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_mali_0_1_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws),
.parent_data = meson8b_mali_0_1_parent_data,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data),
/*
* Don't propagate rate changes up because the only changeable
* parents are mpll1 and mpll2 but we need those for audio and
......@@ -1885,7 +1896,7 @@ static struct clk_regmap meson8b_mali_1 = {
&meson8b_mali_1_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
......@@ -1944,8 +1955,10 @@ static struct clk_regmap meson8m2_gp_pll_dco = {
.hw.init = &(struct clk_init_data){
.name = "gp_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_hws = (const struct clk_hw *[]) {
&meson8b_xtal.hw
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xtal",
.name = "xtal",
.index = -1,
},
.num_parents = 1,
},
......@@ -3585,7 +3598,7 @@ static const struct reset_control_ops meson8b_clk_reset_ops = {
struct meson8b_nb_data {
struct notifier_block nb;
struct clk_hw_onecell_data *onecell_data;
struct clk_hw *cpu_clk;
};
static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb,
......@@ -3593,30 +3606,25 @@ static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb,
{
struct meson8b_nb_data *nb_data =
container_of(nb, struct meson8b_nb_data, nb);
struct clk_hw **hws = nb_data->onecell_data->hws;
struct clk_hw *cpu_clk_hw, *parent_clk_hw;
struct clk *cpu_clk, *parent_clk;
struct clk_hw *parent_clk;
int ret;
switch (event) {
case PRE_RATE_CHANGE:
parent_clk_hw = hws[CLKID_XTAL];
/* xtal */
parent_clk = clk_hw_get_parent_by_index(nb_data->cpu_clk, 0);
break;
case POST_RATE_CHANGE:
parent_clk_hw = hws[CLKID_CPU_SCALE_OUT_SEL];
/* cpu_scale_out_sel */
parent_clk = clk_hw_get_parent_by_index(nb_data->cpu_clk, 1);
break;
default:
return NOTIFY_DONE;
}
cpu_clk_hw = hws[CLKID_CPUCLK];
cpu_clk = __clk_lookup(clk_hw_get_name(cpu_clk_hw));
parent_clk = __clk_lookup(clk_hw_get_name(parent_clk_hw));
ret = clk_set_parent(cpu_clk, parent_clk);
ret = clk_hw_set_parent(nb_data->cpu_clk, parent_clk);
if (ret)
return notifier_from_errno(ret);
......@@ -3682,20 +3690,26 @@ static void __init meson8b_clkc_init_common(struct device_node *np,
meson8b_clk_regmaps[i]->map = map;
/*
* register all clks
* CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
* always skip CLKID_UNUSED and also skip XTAL if the .dtb provides the
* XTAL clock as input.
*/
for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) {
if (!IS_ERR(of_clk_get_by_name(np, "xtal")))
i = CLKID_PLL_FIXED;
else
i = CLKID_XTAL;
/* register all clks */
for (; i < CLK_NR_CLKS; i++) {
/* array might be sparse */
if (!clk_hw_onecell_data->hws[i])
continue;
ret = clk_hw_register(NULL, clk_hw_onecell_data->hws[i]);
ret = of_clk_hw_register(np, clk_hw_onecell_data->hws[i]);
if (ret)
return;
}
meson8b_cpu_nb_data.onecell_data = clk_hw_onecell_data;
meson8b_cpu_nb_data.cpu_clk = clk_hw_onecell_data->hws[CLKID_CPUCLK];
/*
* FIXME we shouldn't program the muxes in notifier handlers. The
......
......@@ -20,8 +20,8 @@ config CLK_RENESAS
select CLK_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
select CLK_R8A7792 if ARCH_R8A7792
select CLK_R8A7794 if ARCH_R8A7794
select CLK_R8A7795 if ARCH_R8A7795
select CLK_R8A77960 if ARCH_R8A77960 || ARCH_R8A7796
select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951 || ARCH_R8A7795
select CLK_R8A77960 if ARCH_R8A77960
select CLK_R8A77961 if ARCH_R8A77961
select CLK_R8A77965 if ARCH_R8A77965
select CLK_R8A77970 if ARCH_R8A77970
......
......@@ -93,6 +93,7 @@ static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
DEF_MOD_STB("ether1", 64, R7S9210_CLK_B),
DEF_MOD_STB("ether0", 65, R7S9210_CLK_B),
DEF_MOD_STB("spibsc", 83, R7S9210_CLK_P1),
DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1),
DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1),
DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1),
......
......@@ -24,10 +24,10 @@ enum rcar_gen2_clk_types {
};
struct rcar_gen2_cpg_pll_config {
unsigned int extal_div;
unsigned int pll1_mult;
unsigned int pll3_mult;
unsigned int pll0_mult; /* leave as zero if PLL0CR exists */
u8 extal_div;
u8 pll1_mult;
u8 pll3_mult;
u8 pll0_mult; /* leave as zero if PLL0CR exists */
};
struct clk *rcar_gen2_cpg_clk_register(struct device *dev,
......
......@@ -470,7 +470,8 @@ static struct clk * __init cpg_rpc_clk_register(const char *name,
clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
&rpc->div.hw, &clk_divider_ops,
&rpc->gate.hw, &clk_gate_ops, 0);
&rpc->gate.hw, &clk_gate_ops,
CLK_SET_RATE_PARENT);
if (IS_ERR(clk)) {
kfree(rpc);
return clk;
......@@ -506,7 +507,8 @@ static struct clk * __init cpg_rpcd2_clk_register(const char *name,
clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
&rpcd2->fixed.hw, &clk_fixed_factor_ops,
&rpcd2->gate.hw, &clk_gate_ops, 0);
&rpcd2->gate.hw, &clk_gate_ops,
CLK_SET_RATE_PARENT);
if (IS_ERR(clk))
kfree(rpcd2);
......
......@@ -921,11 +921,26 @@ static const struct sunxi_ccu_desc sun50i_a64_ccu_desc = {
.num_resets = ARRAY_SIZE(sun50i_a64_ccu_resets),
};
static struct ccu_pll_nb sun50i_a64_pll_cpu_nb = {
.common = &pll_cpux_clk.common,
/* copy from pll_cpux_clk */
.enable = BIT(31),
.lock = BIT(28),
};
static struct ccu_mux_nb sun50i_a64_cpu_nb = {
.common = &cpux_clk.common,
.cm = &cpux_clk.mux,
.delay_us = 1, /* > 8 clock cycles at 24 MHz */
.bypass_index = 1, /* index of 24 MHz oscillator */
};
static int sun50i_a64_ccu_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *reg;
u32 val;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
......@@ -939,7 +954,18 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev)
writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc);
if (ret)
return ret;
/* Gate then ungate PLL CPU after any rate changes */
ccu_pll_notifier_register(&sun50i_a64_pll_cpu_nb);
/* Reparent CPU during PLL CPU rate changes */
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
&sun50i_a64_cpu_nb);
return 0;
}
static const struct of_device_id sun50i_a64_ccu_ids[] = {
......
......@@ -36,7 +36,6 @@
#define CLK_PLL_HSIC 18
#define CLK_PLL_DE 19
#define CLK_PLL_DDR1 20
#define CLK_CPUX 21
#define CLK_AXI 22
#define CLK_APB 23
#define CLK_AHB1 24
......
......@@ -32,7 +32,9 @@
/* The PLL_VIDEO1_2X clock is exported */
#define CLK_PLL_GPU 14
#define CLK_PLL_MIPI 15
/* The PLL_VIDEO1_2X clock is exported */
#define CLK_PLL9 16
#define CLK_PLL10 17
......
......@@ -24,7 +24,9 @@
#define CLK_PLL_PERIPH 10
#define CLK_PLL_PERIPH_2X 11
#define CLK_PLL_GPU 12
#define CLK_PLL_MIPI 13
/* The PLL MIPI clock is exported */
#define CLK_PLL_HSIC 14
#define CLK_PLL_DE 15
#define CLK_PLL_DDR1 16
......
......@@ -55,10 +55,6 @@
/* Some more module clocks are exported */
#define CLK_MBUS 155
/* Another bunch of module clocks are exported */
#define CLK_NUMBER (CLK_OUTB + 1)
#endif /* _CCU_SUN8I_R40_H_ */
......@@ -37,7 +37,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct clk_onecell_data *clk_data;
const struct of_device_id *device;
const struct gates_data *data;
const char *clk_parent;
const char *clk_name;
......@@ -50,10 +49,9 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
if (!np)
return -ENODEV;
device = of_match_device(sun6i_a31_apb0_gates_clk_dt_ids, &pdev->dev);
if (!device)
data = of_device_get_match_data(&pdev->dev);
if (!data)
return -ENODEV;
data = device->data;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, r);
......
......@@ -751,9 +751,9 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
hw = clk_hw_register_mux(dev, clk_name,
(const char *[]){
((const char *[]){
parent, parent2, parent3, parent4
}, 4, 0, pll_10nm->phy_cmn_mmio +
}), 4, 0, pll_10nm->phy_cmn_mmio +
REG_DSI_10nm_PHY_CMN_CLK_CFG1,
0, 2, 0, NULL);
if (IS_ERR(hw)) {
......
......@@ -554,9 +554,9 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
clks[num++] = clk_register_mux(dev, clk_name,
(const char *[]){
((const char *[]){
parent1, parent2
}, 2, CLK_SET_RATE_PARENT, pll_28nm->mmio +
}), 2, CLK_SET_RATE_PARENT, pll_28nm->mmio +
REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
......
/* SPDX-License-Identifier: GPL-2.0 */
#define DDR_CLKID_DDR_PLL_DCO 0
#define DDR_CLKID_DDR_PLL 1
......@@ -46,6 +46,7 @@
#define CLK_PLL_VIDEO0 7
#define CLK_PLL_PERIPH0 11
#define CLK_CPUX 21
#define CLK_BUS_MIPI_DSI 28
#define CLK_BUS_CE 29
#define CLK_BUS_DMA 30
......
......@@ -49,6 +49,8 @@
#define CLK_PLL_VIDEO1_2X 13
#define CLK_PLL_MIPI 15
#define CLK_CPU 18
#define CLK_AHB1_MIPIDSI 23
......
......@@ -43,6 +43,8 @@
#ifndef _DT_BINDINGS_CLK_SUN8I_A23_A33_H_
#define _DT_BINDINGS_CLK_SUN8I_A23_A33_H_
#define CLK_PLL_MIPI 13
#define CLK_CPUX 18
#define CLK_BUS_MIPI_DSI 23
......
......@@ -176,7 +176,7 @@
#define CLK_AVS 152
#define CLK_HDMI 153
#define CLK_HDMI_SLOW 154
#define CLK_MBUS 155
#define CLK_DSI_DPHY 156
#define CLK_TVE0 157
#define CLK_TVE1 158
......
This diff is collapsed.
......@@ -627,6 +627,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate);
* @clk: clock source
* @rate: desired clock rate in Hz
*
* Updating the rate starts at the top-most affected clock and then
* walks the tree down to the bottom-most clock that needs updating.
*
* Returns success (0) or negative errno.
*/
int clk_set_rate(struct clk *clk, unsigned long rate);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment