diff --git a/Documentation/devicetree/bindings/clock/rockchip,clk-out.yaml b/Documentation/devicetree/bindings/clock/rockchip,clk-out.yaml new file mode 100644 index 000000000000..6582605ab945 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,clk-out.yaml @@ -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 + +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>; + }; diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig index e711ba005825..3ba13a494af3 100644 --- a/drivers/clk/rockchip/Kconfig +++ b/drivers/clk/rockchip/Kconfig @@ -158,6 +158,12 @@ config ROCKCHIP_CLK_INV help 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 bool "Rockchip Clk Pvtm" default y if !CPU_RV1126 && !CPU_RV1106 diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 65e7dc9c5bb1..03ddb4baaa5a 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -18,6 +18,7 @@ clk-rockchip-$(CONFIG_ROCKCHIP_CLK_PVTM) += clk-pvtm.o clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.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_RV1106) += clk-rv1106.o diff --git a/drivers/clk/rockchip/clk-out.c b/drivers/clk/rockchip/clk-out.c new file mode 100644 index 000000000000..22dcd98fbbef --- /dev/null +++ b/drivers/clk/rockchip/clk-out.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, rockchip_clk_out_match);