162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (c) 2021 MediaTek Inc.
462306a36Sopenharmony_ci// Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "clk-mtk.h"
762306a36Sopenharmony_ci#include "clk-pll.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <dt-bindings/clock/mt8195-clk.h>
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define MT8195_PLL_FMAX		(3800UL * MHZ)
1462306a36Sopenharmony_ci#define MT8195_PLL_FMIN		(1500UL * MHZ)
1562306a36Sopenharmony_ci#define MT8195_INTEGER_BITS	(8)
1662306a36Sopenharmony_ci#define MT8195_PCW_BITS		(22)
1762306a36Sopenharmony_ci#define MT8195_POSDIV_SHIFT	(24)
1862306a36Sopenharmony_ci#define MT8195_PLL_EN_BIT	(0)
1962306a36Sopenharmony_ci#define MT8195_PCW_SHIFT	(0)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * The "en_reg" and "pcw_chg_reg" fields are standard offset register compared
2362306a36Sopenharmony_ci * with "reg" field, so set zero to imply it.
2462306a36Sopenharmony_ci * No tuner control in apu pll, so set "tuner_XXX" as zero to imply it.
2562306a36Sopenharmony_ci * No rst or post divider enable in apu pll, so set "rst_bar_mask" and "en_mask"
2662306a36Sopenharmony_ci * as zero to imply it.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci#define PLL(_id, _name, _reg, _pwr_reg, _pd_reg, _pcw_reg) {		\
2962306a36Sopenharmony_ci		.id = _id,						\
3062306a36Sopenharmony_ci		.name = _name,						\
3162306a36Sopenharmony_ci		.reg = _reg,						\
3262306a36Sopenharmony_ci		.pwr_reg = _pwr_reg,					\
3362306a36Sopenharmony_ci		.en_mask = 0,						\
3462306a36Sopenharmony_ci		.flags = 0,						\
3562306a36Sopenharmony_ci		.rst_bar_mask = 0,					\
3662306a36Sopenharmony_ci		.fmax = MT8195_PLL_FMAX,				\
3762306a36Sopenharmony_ci		.fmin = MT8195_PLL_FMIN,				\
3862306a36Sopenharmony_ci		.pcwbits = MT8195_PCW_BITS,				\
3962306a36Sopenharmony_ci		.pcwibits = MT8195_INTEGER_BITS,			\
4062306a36Sopenharmony_ci		.pd_reg = _pd_reg,					\
4162306a36Sopenharmony_ci		.pd_shift = MT8195_POSDIV_SHIFT,			\
4262306a36Sopenharmony_ci		.tuner_reg = 0,						\
4362306a36Sopenharmony_ci		.tuner_en_reg = 0,					\
4462306a36Sopenharmony_ci		.tuner_en_bit = 0,					\
4562306a36Sopenharmony_ci		.pcw_reg = _pcw_reg,					\
4662306a36Sopenharmony_ci		.pcw_shift = MT8195_PCW_SHIFT,				\
4762306a36Sopenharmony_ci		.pcw_chg_reg = 0,					\
4862306a36Sopenharmony_ci		.en_reg = 0,						\
4962306a36Sopenharmony_ci		.pll_en_bit = MT8195_PLL_EN_BIT,			\
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic const struct mtk_pll_data apusys_plls[] = {
5362306a36Sopenharmony_ci	PLL(CLK_APUSYS_PLL_APUPLL, "apusys_pll_apupll", 0x008, 0x014, 0x00c, 0x00c),
5462306a36Sopenharmony_ci	PLL(CLK_APUSYS_PLL_NPUPLL, "apusys_pll_npupll", 0x018, 0x024, 0x01c, 0x01c),
5562306a36Sopenharmony_ci	PLL(CLK_APUSYS_PLL_APUPLL1, "apusys_pll_apupll1", 0x028, 0x034, 0x02c, 0x02c),
5662306a36Sopenharmony_ci	PLL(CLK_APUSYS_PLL_APUPLL2, "apusys_pll_apupll2", 0x038, 0x044, 0x03c, 0x03c),
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int clk_mt8195_apusys_pll_probe(struct platform_device *pdev)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_data;
6262306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
6362306a36Sopenharmony_ci	int r;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	clk_data = mtk_alloc_clk_data(CLK_APUSYS_PLL_NR_CLK);
6662306a36Sopenharmony_ci	if (!clk_data)
6762306a36Sopenharmony_ci		return -ENOMEM;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
7062306a36Sopenharmony_ci	if (r)
7162306a36Sopenharmony_ci		goto free_apusys_pll_data;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
7462306a36Sopenharmony_ci	if (r)
7562306a36Sopenharmony_ci		goto unregister_plls;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	platform_set_drvdata(pdev, clk_data);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return r;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciunregister_plls:
8262306a36Sopenharmony_ci	mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
8362306a36Sopenharmony_cifree_apusys_pll_data:
8462306a36Sopenharmony_ci	mtk_free_clk_data(clk_data);
8562306a36Sopenharmony_ci	return r;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void clk_mt8195_apusys_pll_remove(struct platform_device *pdev)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
9162306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	of_clk_del_provider(node);
9462306a36Sopenharmony_ci	mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
9562306a36Sopenharmony_ci	mtk_free_clk_data(clk_data);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
9962306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8195-apusys_pll", },
10062306a36Sopenharmony_ci	{}
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_match_clk_mt8195_apusys_pll);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic struct platform_driver clk_mt8195_apusys_pll_drv = {
10562306a36Sopenharmony_ci	.probe = clk_mt8195_apusys_pll_probe,
10662306a36Sopenharmony_ci	.remove_new = clk_mt8195_apusys_pll_remove,
10762306a36Sopenharmony_ci	.driver = {
10862306a36Sopenharmony_ci		.name = "clk-mt8195-apusys_pll",
10962306a36Sopenharmony_ci		.of_match_table = of_match_clk_mt8195_apusys_pll,
11062306a36Sopenharmony_ci	},
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_cimodule_platform_driver(clk_mt8195_apusys_pll_drv);
11362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
114