[PATCH 13/13] clk: mediatek: Add driver for MT6735 pericfg

Yassine Oudjana
2022-05-04T12:33:57Z

Add a driver for MT6735 pericfg clock gates and resets.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
MAINTAINERS | 1 +
drivers/clk/mediatek/Kconfig | 7 +
drivers/clk/mediatek/Makefile | 1 +
drivers/clk/mediatek/clk-mt6735-pericfg.c | 360 ++++++++++++++++++++++
4 files changed, 369 insertions(+)
create mode 100644 drivers/clk/mediatek/clk-mt6735-pericfg.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8662f12f34a2..5d90c2f2a587 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12444,6 +12444,7 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/clk/mediatek/clk-mt6735-apmixed.c
F: drivers/clk/mediatek/clk-mt6735-infracfg.c
+F: drivers/clk/mediatek/clk-mt6735-pericfg.c
F: drivers/clk/mediatek/clk-mt6735-topckgen.c
F: include/dt-bindings/clock/mediatek,mt6735-apmixedsys.h
F: include/dt-bindings/clock/mediatek,mt6735-infracfg.h
diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 62195e5d90a0..698ff2995460 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -131,6 +131,13 @@ config COMMON_CLK_MT6735_INFRACFG
help
This driver supports MediaTek MT6735 infracfg clocks and resets.

+config COMMON_CLK_MT6735_PERICFG
+ tristate "Clock driver for MediaTek MT6735 pericfg"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select COMMON_CLK_MEDIATEK
+ help
+ This driver supports MediaTek MT6735 pericfg clocks and resets.
+
config COMMON_CLK_MT6735_TOPCKGEN
tristate "Clock driver for MediaTek MT6735 topckgen"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index e5c1da6e2711..b1a4d18e382d 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.

obj-$(CONFIG_COMMON_CLK_MT6735_APMIXED) += clk-mt6735-apmixed.o
obj-$(CONFIG_COMMON_CLK_MT6735_INFRACFG) += clk-mt6735-infracfg.o
+obj-$(CONFIG_COMMON_CLK_MT6735_PERICFG) += clk-mt6735-pericfg.o
obj-$(CONFIG_COMMON_CLK_MT6735_TOPCKGEN) += clk-mt6735-topckgen.o
obj-$(CONFIG_COMMON_CLK_MT6765) += clk-mt6765.o
obj-$(CONFIG_COMMON_CLK_MT6765_AUDIOSYS) += clk-mt6765-audio.o
diff --git a/drivers/clk/mediatek/clk-mt6735-pericfg.c b/drivers/clk/mediatek/clk-mt6735-pericfg.c
new file mode 100644
index 000000000000..8a01aa63a81e
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt6735-pericfg.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+
+#include "clk-gate.h"
+#include "clk-mtk.h"
+
+#include <dt-bindings/clock/mediatek,mt6735-pericfg.h>
+
+#define PERI_GLOBALCON_RST0 0x00
+#define PERI_GLOBALCON_PDN0_SET 0x08
+#define PERI_GLOBALCON_PDN0_CLR 0x10
+#define PERI_GLOBALCON_PDN0_STA 0x18
+
+struct mt6735_pericfg {
+ struct clk_onecell_data *clk_data;
+ struct mtk_reset *reset_data;
+};
+
+static struct mtk_gate_regs peri_cg_regs = {
+ .set_ofs = PERI_GLOBALCON_PDN0_SET,
+ .clr_ofs = PERI_GLOBALCON_PDN0_CLR,
+ .sta_ofs = PERI_GLOBALCON_PDN0_STA,
+};
+
+static const struct mtk_gate pericfg_gates[] = {
+ {
+ .id = DISP_PWM,
+ .name = "disp_pwm",
+ .parent_name = "disppwm_sel",
+ .regs = &peri_cg_regs,
+ .shift = 0,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = THERM,
+ .name = "therm",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 1,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM1,
+ .name = "pwm1",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 2,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM2,
+ .name = "pwm2",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 3,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM3,
+ .name = "pwm3",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 4,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM4,
+ .name = "pwm4",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 5,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM5,
+ .name = "pwm5",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 6,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM6,
+ .name = "pwm6",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 7,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM7,
+ .name = "pwm7",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 8,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = PWM,
+ .name = "pwm",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 9,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = USB0,
+ .name = "usb0",
+ .parent_name = "usb20_sel",
+ .regs = &peri_cg_regs,
+ .shift = 10,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = IRDA,
+ .name = "irda",
+ .parent_name = "irda_sel",
+ .regs = &peri_cg_regs,
+ .shift = 11,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = APDMA,
+ .name = "apdma",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 12,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = MSDC30_0,
+ .name = "msdc30_0",
+ .parent_name = "msdc30_0_sel",
+ .regs = &peri_cg_regs,
+ .shift = 13,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = MSDC30_1,
+ .name = "msdc30_1",
+ .parent_name = "msdc30_1_sel",
+ .regs = &peri_cg_regs,
+ .shift = 14,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = MSDC30_2,
+ .name = "msdc30_2",
+ .parent_name = "msdc30_2_sel",
+ .regs = &peri_cg_regs,
+ .shift = 15,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = MSDC30_3,
+ .name = "msdc30_3",
+ .parent_name = "msdc30_3_sel",
+ .regs = &peri_cg_regs,
+ .shift = 16,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = UART0,
+ .name = "uart0",
+ .parent_name = "uart_sel",
+ .regs = &peri_cg_regs,
+ .shift = 17,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = UART1,
+ .name = "uart1",
+ .parent_name = "uart_sel",
+ .regs = &peri_cg_regs,
+ .shift = 18,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = UART2,
+ .name = "uart2",
+ .parent_name = "uart_sel",
+ .regs = &peri_cg_regs,
+ .shift = 19,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = UART3,
+ .name = "uart3",
+ .parent_name = "uart_sel",
+ .regs = &peri_cg_regs,
+ .shift = 20,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = UART4,
+ .name = "uart4",
+ .parent_name = "uart_sel",
+ .regs = &peri_cg_regs,
+ .shift = 21,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = BTIF,
+ .name = "btif",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 22,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = I2C0,
+ .name = "i2c0",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 23,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = I2C1,
+ .name = "i2c1",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 24,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = I2C2,
+ .name = "i2c2",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 25,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = I2C3,
+ .name = "i2c3",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 26,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = AUXADC,
+ .name = "auxadc",
+ .parent_name = "axi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 27,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = SPI0,
+ .name = "spi0",
+ .parent_name = "spi_sel",
+ .regs = &peri_cg_regs,
+ .shift = 28,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+ {
+ .id = IRTX,
+ .name = "IRTX",
+ .parent_name = "irtx_sel",
+ .regs = &peri_cg_regs,
+ .shift = 29,
+ .ops = &mtk_clk_gate_ops_setclr
+ },
+};
+
+int clk_mt6735_pericfg_probe(struct platform_device *pdev)
+{
+ void __iomem *base;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct mt6735_pericfg *pericfg;
+ int ret;
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ pericfg = devm_kmalloc(&pdev->dev, sizeof(struct mt6735_pericfg),
+ GFP_KERNEL);
+ if (!pericfg)
+ return -ENOMEM;
+
+ pericfg->clk_data = mtk_alloc_clk_data(ARRAY_SIZE(pericfg_gates));
+ if (!pericfg->clk_data)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pericfg);
+
+ ret = mtk_clk_register_gates_with_dev(pdev->dev.of_node, pericfg_gates,
+ ARRAY_SIZE(pericfg_gates),
+ pericfg->clk_data, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register gates: %pe\n",
+ ERR_PTR(ret));
+ goto free_clk_data;
+ }
+
+ ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get,
+ pericfg->clk_data);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to register clock provider: %pe\n",
+ ERR_PTR(ret));
+ goto unregister_gates;
+ }
+
+ pericfg->reset_data = mtk_register_reset_controller(pdev->dev.of_node, 2,
+ PERI_GLOBALCON_RST0);
+ if (IS_ERR(pericfg->reset_data)) {
+ dev_err(&pdev->dev, "Failed to register reset controller: %pe\n",
+ pericfg->reset_data);
+ return PTR_ERR(pericfg->reset_data);
+ }
+
+ return 0;
+unregister_gates:
+ mtk_clk_unregister_gates(pericfg_gates, ARRAY_SIZE(pericfg_gates),
+ pericfg->clk_data);
+free_clk_data:
+ mtk_free_clk_data(pericfg->clk_data);
+
+ return ret;
+}
+
+int clk_mt6735_pericfg_remove(struct platform_device *pdev)
+{
+ struct mt6735_pericfg *pericfg = platform_get_drvdata(pdev);
+
+ mtk_unregister_reset_controller(pericfg->reset_data);
+ of_clk_del_provider(pdev->dev.of_node);
+ mtk_clk_unregister_gates(pericfg_gates, ARRAY_SIZE(pericfg_gates),
+ pericfg->clk_data);
+ mtk_free_clk_data(pericfg->clk_data);
+
+ return 0;
+}
+
+static const struct of_device_id of_match_mt6735_pericfg[] = {
+ { .compatible = "mediatek,mt6735-pericfg" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt6735_pericfg = {
+ .probe = clk_mt6735_pericfg_probe,
+ .remove = clk_mt6735_pericfg_remove,
+ .driver = {
+ .name = "clk-mt6735-pericfg",
+ .of_match_table = of_match_mt6735_pericfg,
+ },
+};
+module_platform_driver(clk_mt6735_pericfg);
+
+MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
+MODULE_DESCRIPTION("Mediatek MT6735 pericfg clock driver");
+MODULE_LICENSE("GPL");
--
2.36.0