clk: rockchip: Add support for clk input / output switch
This patch add support switch for clk-bidirection which located
at GRF, such as SAIx_MCLK_{IN OUT} which share the same pin.
and these config maybe located in many pieces of GRF,
which hard to addressed in one single clk driver. so, we add
this simple helper driver to address this situation.
In order to simplify implement and usage, and also for safety
clk usage (avoid high freq glitch), we set all clk out as disabled
(which means Input default for clk-bidrection) in the pre-stage,
such boot-loader or init by HW default. And then set a safety freq
before enable clk-out, such as "assign-clock-rates" or clk_set_rate
in drivers.
e.g.
1. mclk{out,in}_sai0 define:
mclkin_sai0: mclkin-sai0 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <12288000>;
clock-output-names = "mclk_sai0_from_io";
};
mclkout_sai0: mclkout-sai0@ff040070 {
compatible = "rockchip,clk-out";
reg = <0 0xff040070 0 0x4>;
clocks = <&cru MCLK_SAI0_OUT2IO>;
#clock-cells = <0>;
clock-output-names = "mclk_sai0_to_io";
rockchip,bit-shift = <4>;
//example with PD if reg access needed
power-domains = <&power RK3562_PD_VO>;
};
Note:
clock-output-names of mclkin_sai0 should equal to strings in drivers. such as:
drivers/clk/rockchip/clk-rk3562.c:
PNAME(clk_sai0_p) = { "clk_sai0_src", "clk_sai0_frac", "xin_osc0_half", "mclk_sai0_from_io" };
2. mclkout_sai0 usage:
&ext_codec {
clocks = <&mclkout_sai0>;
clock-names = "mclk";
assigned-clocks = <&mclkout_sai0>;
assigned-clock-rates = <12288000>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0m0_mclk>;
};
clk_summary on sai0 work:
cat /sys/kernel/debug/clk/clk_summary | egrep "pll|sai0"
clk_sai0_src 1 1 0 1188000000 0 0 50000
clk_sai0_frac 1 1 0 12288000 0 0 50000
clk_sai0 1 1 0 12288000 0 0 50000
mclk_sai0 1 1 0 12288000 0 0 50000
mclk_sai0_out2io 1 1 0 12288000 0 0 50000
mclk_sai0_to_io 1 1 0 12288000 0 0 50000
example with PD if reg access needed:
* PD status when mclk_sai0_to_io on:
cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
domain status children
/device runtime status
----------------------------------------------------------------------
...
vo on
/devices/platform/clocks/ff040070.mclkout-sai0 active
...
* PD status when mclk_sai0_to_io off:
cat /sys/kernel/debug/pm_genpd/pm_genpd_summary
domain status children
/device runtime status
----------------------------------------------------------------------
...
vo off-0
/devices/platform/clocks/ff040070.mclkout-sai0 suspended
...
3. mclkin_sai0 usage:
please override freq of mclkin as the real external clkin, such as:
&mclkin_sai0 {
clock-frequency = <24576000>;
}
&ext_codec {
clocks = <&mclkin_sai0>;
clock-names = "mclk";
assigned-clocks = <&cru CLK_SAI0>;
assigned-clock-parents = <&mclkin_sai0>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0m0_mclk>;
};
clk_summary on sai0 work:
cat /sys/kernel/debug/clk/clk_summary | egrep "pll|sai0"
mclk_sai0_from_io 1 1 0 12288000 0 0 50000
clk_sai0 1 1 0 12288000 0 0 50000
mclk_sai0 1 1 0 12288000 0 0 50000
mclk_sai0_out2io 0 0 0 12288000 0 0 50000
mclk_sai0_to_io 0 0 0 12288000 0 0 50000
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: Ibe8286bb98ea1fc3bc6421c30f6e46fc0b1b0d88
This commit is contained in:
@@ -0,0 +1,107 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/clock/rockchip,clk-out.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Rockchip Clock Out Control Module Binding
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sugar Zhang <sugar.zhang@rock-chips.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This add support switch for clk-bidirection which located
|
||||||
|
at GRF, such as SAIx_MCLK_{IN OUT} which share the same pin.
|
||||||
|
and these config maybe located in many pieces of GRF,
|
||||||
|
which hard to addressed in one single clk driver. so, we add
|
||||||
|
this simple helper driver to address this situation.
|
||||||
|
|
||||||
|
In order to simplify implement and usage, and also for safety
|
||||||
|
clk usage (avoid high freq glitch), we set all clk out as disabled
|
||||||
|
(which means Input default for clk-bidrection) in the pre-stage,
|
||||||
|
such boot-loader or init by HW default. And then set a safety freq
|
||||||
|
before enable clk-out, such as "assign-clock-rates" or clk_set_rate
|
||||||
|
in drivers.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- rockchip,clk-out
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#clock-cells":
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
description: parent clocks.
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-output-names:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
rockchip,bit-shift:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Defines the bit shift of clk out enable.
|
||||||
|
|
||||||
|
rockchip,bit-set-to-disable:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
By default this clock sets the bit at bit-shift to enable the clock.
|
||||||
|
Setting this property does the opposite: setting the bit disable
|
||||||
|
the clock and clearing it enables the clock.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- clocks
|
||||||
|
- "#clock-cells"
|
||||||
|
- clock-output-names
|
||||||
|
- rockchip,bit-shift
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
# Clock Provider node:
|
||||||
|
- |
|
||||||
|
mclkin_sai0: mclkin-sai0 {
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clock-frequency = <12288000>;
|
||||||
|
clock-output-names = "mclk_sai0_from_io";
|
||||||
|
};
|
||||||
|
|
||||||
|
mclkout_sai0: mclkout-sai0@ff040070 {
|
||||||
|
compatible = "rockchip,clk-out";
|
||||||
|
reg = <0 0xff040070 0 0x4>;
|
||||||
|
clocks = <&cru MCLK_SAI0_OUT2IO>;
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clock-output-names = "mclk_sai0_to_io";
|
||||||
|
rockchip,bit-shift = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Clock mclkout Consumer node:
|
||||||
|
- |
|
||||||
|
ext_codec {
|
||||||
|
clocks = <&mclkout_sai0>;
|
||||||
|
clock-names = "mclk";
|
||||||
|
assigned-clocks = <&mclkout_sai0>;
|
||||||
|
assigned-clock-rates = <12288000>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&i2s0m0_mclk>;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Clock mclkin Consumer node:
|
||||||
|
- |
|
||||||
|
ext_codec {
|
||||||
|
clocks = <&mclkin_sai0>;
|
||||||
|
clock-names = "mclk";
|
||||||
|
assigned-clocks = <&cru CLK_SAI0>;
|
||||||
|
assigned-clock-parents = <&mclkin_sai0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&i2s0m0_mclk>;
|
||||||
|
};
|
||||||
@@ -158,6 +158,12 @@ config ROCKCHIP_CLK_INV
|
|||||||
help
|
help
|
||||||
Say y here to enable clk Inverter.
|
Say y here to enable clk Inverter.
|
||||||
|
|
||||||
|
config ROCKCHIP_CLK_OUT
|
||||||
|
tristate "Rockchip Clk Out / Input Switch"
|
||||||
|
default y if !ROCKCHIP_MINI_KERNEL
|
||||||
|
help
|
||||||
|
Say y here to enable clk out / input switch.
|
||||||
|
|
||||||
config ROCKCHIP_CLK_PVTM
|
config ROCKCHIP_CLK_PVTM
|
||||||
bool "Rockchip Clk Pvtm"
|
bool "Rockchip Clk Pvtm"
|
||||||
default y if !CPU_RV1126 && !CPU_RV1106
|
default y if !CPU_RV1126 && !CPU_RV1106
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ clk-rockchip-$(CONFIG_ROCKCHIP_CLK_PVTM) += clk-pvtm.o
|
|||||||
clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o
|
clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o
|
||||||
|
|
||||||
obj-$(CONFIG_ROCKCHIP_CLK_LINK) += clk-link.o
|
obj-$(CONFIG_ROCKCHIP_CLK_LINK) += clk-link.o
|
||||||
|
obj-$(CONFIG_ROCKCHIP_CLK_OUT) += clk-out.o
|
||||||
|
|
||||||
obj-$(CONFIG_CLK_PX30) += clk-px30.o
|
obj-$(CONFIG_CLK_PX30) += clk-px30.o
|
||||||
obj-$(CONFIG_CLK_RV1106) += clk-rv1106.o
|
obj-$(CONFIG_CLK_RV1106) += clk-rv1106.o
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Rockchip Electronics Co., Ltd
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(clk_out_lock);
|
||||||
|
|
||||||
|
static int rockchip_clk_out_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct device_node *node = pdev->dev.of_node;
|
||||||
|
struct clk_hw *hw;
|
||||||
|
struct resource *res;
|
||||||
|
const char *clk_name = node->name;
|
||||||
|
const char *parent_name;
|
||||||
|
void __iomem *reg;
|
||||||
|
u32 shift = 0;
|
||||||
|
u8 clk_gate_flags = CLK_GATE_HIWORD_MASK;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = device_property_read_string(dev, "clock-output-names", &clk_name);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = device_property_read_u32(dev, "rockchip,bit-shift", &shift);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (device_property_read_bool(dev, "rockchip,bit-set-to-disable"))
|
||||||
|
clk_gate_flags |= CLK_GATE_SET_TO_DISABLE;
|
||||||
|
|
||||||
|
ret = of_clk_parent_fill(node, &parent_name, 1);
|
||||||
|
if (ret != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
reg = devm_ioremap(dev, res->start, resource_size(res));
|
||||||
|
if (!reg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
|
hw = clk_hw_register_gate(dev, clk_name, parent_name, CLK_SET_RATE_PARENT,
|
||||||
|
reg, shift, clk_gate_flags, &clk_out_lock);
|
||||||
|
if (IS_ERR(hw)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_disable_pm_runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_disable_pm_runtime:
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rockchip_clk_out_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *node = pdev->dev.of_node;
|
||||||
|
|
||||||
|
of_clk_del_provider(node);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id rockchip_clk_out_match[] = {
|
||||||
|
{ .compatible = "rockchip,clk-out", },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver rockchip_clk_out_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "rockchip-clk-out",
|
||||||
|
.of_match_table = rockchip_clk_out_match,
|
||||||
|
},
|
||||||
|
.probe = rockchip_clk_out_probe,
|
||||||
|
.remove = rockchip_clk_out_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rockchip_clk_out_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Rockchip Clock Input-Output-Switch");
|
||||||
|
MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_DEVICE_TABLE(of, rockchip_clk_out_match);
|
||||||
Reference in New Issue
Block a user