18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Qualcomm A53 PLL driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2017, Linaro Limited
68c2ecf20Sopenharmony_ci * Author: Georgi Djakov <georgi.djakov@linaro.org>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/regmap.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "clk-pll.h"
168c2ecf20Sopenharmony_ci#include "clk-regmap.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic const struct pll_freq_tbl a53pll_freq[] = {
198c2ecf20Sopenharmony_ci	{  998400000, 52, 0x0, 0x1, 0 },
208c2ecf20Sopenharmony_ci	{ 1094400000, 57, 0x0, 0x1, 0 },
218c2ecf20Sopenharmony_ci	{ 1152000000, 62, 0x0, 0x1, 0 },
228c2ecf20Sopenharmony_ci	{ 1209600000, 63, 0x0, 0x1, 0 },
238c2ecf20Sopenharmony_ci	{ 1248000000, 65, 0x0, 0x1, 0 },
248c2ecf20Sopenharmony_ci	{ 1363200000, 71, 0x0, 0x1, 0 },
258c2ecf20Sopenharmony_ci	{ 1401600000, 73, 0x0, 0x1, 0 },
268c2ecf20Sopenharmony_ci	{ }
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const struct regmap_config a53pll_regmap_config = {
308c2ecf20Sopenharmony_ci	.reg_bits		= 32,
318c2ecf20Sopenharmony_ci	.reg_stride		= 4,
328c2ecf20Sopenharmony_ci	.val_bits		= 32,
338c2ecf20Sopenharmony_ci	.max_register		= 0x40,
348c2ecf20Sopenharmony_ci	.fast_io		= true,
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int qcom_a53pll_probe(struct platform_device *pdev)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
408c2ecf20Sopenharmony_ci	struct regmap *regmap;
418c2ecf20Sopenharmony_ci	struct resource *res;
428c2ecf20Sopenharmony_ci	struct clk_pll *pll;
438c2ecf20Sopenharmony_ci	void __iomem *base;
448c2ecf20Sopenharmony_ci	struct clk_init_data init = { };
458c2ecf20Sopenharmony_ci	int ret;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
488c2ecf20Sopenharmony_ci	if (!pll)
498c2ecf20Sopenharmony_ci		return -ENOMEM;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
528c2ecf20Sopenharmony_ci	base = devm_ioremap_resource(dev, res);
538c2ecf20Sopenharmony_ci	if (IS_ERR(base))
548c2ecf20Sopenharmony_ci		return PTR_ERR(base);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	regmap = devm_regmap_init_mmio(dev, base, &a53pll_regmap_config);
578c2ecf20Sopenharmony_ci	if (IS_ERR(regmap))
588c2ecf20Sopenharmony_ci		return PTR_ERR(regmap);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	pll->l_reg = 0x04;
618c2ecf20Sopenharmony_ci	pll->m_reg = 0x08;
628c2ecf20Sopenharmony_ci	pll->n_reg = 0x0c;
638c2ecf20Sopenharmony_ci	pll->config_reg = 0x14;
648c2ecf20Sopenharmony_ci	pll->mode_reg = 0x00;
658c2ecf20Sopenharmony_ci	pll->status_reg = 0x1c;
668c2ecf20Sopenharmony_ci	pll->status_bit = 16;
678c2ecf20Sopenharmony_ci	pll->freq_tbl = a53pll_freq;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	init.name = "a53pll";
708c2ecf20Sopenharmony_ci	init.parent_names = (const char *[]){ "xo" };
718c2ecf20Sopenharmony_ci	init.num_parents = 1;
728c2ecf20Sopenharmony_ci	init.ops = &clk_pll_sr2_ops;
738c2ecf20Sopenharmony_ci	init.flags = CLK_IS_CRITICAL;
748c2ecf20Sopenharmony_ci	pll->clkr.hw.init = &init;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	ret = devm_clk_register_regmap(dev, &pll->clkr);
778c2ecf20Sopenharmony_ci	if (ret) {
788c2ecf20Sopenharmony_ci		dev_err(dev, "failed to register regmap clock: %d\n", ret);
798c2ecf20Sopenharmony_ci		return ret;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
838c2ecf20Sopenharmony_ci					  &pll->clkr.hw);
848c2ecf20Sopenharmony_ci	if (ret) {
858c2ecf20Sopenharmony_ci		dev_err(dev, "failed to add clock provider: %d\n", ret);
868c2ecf20Sopenharmony_ci		return ret;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic const struct of_device_id qcom_a53pll_match_table[] = {
938c2ecf20Sopenharmony_ci	{ .compatible = "qcom,msm8916-a53pll" },
948c2ecf20Sopenharmony_ci	{ }
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, qcom_a53pll_match_table);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic struct platform_driver qcom_a53pll_driver = {
998c2ecf20Sopenharmony_ci	.probe = qcom_a53pll_probe,
1008c2ecf20Sopenharmony_ci	.driver = {
1018c2ecf20Sopenharmony_ci		.name = "qcom-a53pll",
1028c2ecf20Sopenharmony_ci		.of_match_table = qcom_a53pll_match_table,
1038c2ecf20Sopenharmony_ci	},
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_cimodule_platform_driver(qcom_a53pll_driver);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm A53 PLL Driver");
1088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
109