162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// OWL common clock driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2014 Actions Semi Inc.
662306a36Sopenharmony_ci// Author: David Liu <liuwei@actions-semi.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Copyright (c) 2018 Linaro Ltd.
962306a36Sopenharmony_ci// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/regmap.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "owl-common.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic const struct regmap_config owl_regmap_config = {
1762306a36Sopenharmony_ci	.reg_bits	= 32,
1862306a36Sopenharmony_ci	.reg_stride	= 4,
1962306a36Sopenharmony_ci	.val_bits	= 32,
2062306a36Sopenharmony_ci	.max_register	= 0x00cc,
2162306a36Sopenharmony_ci	.fast_io	= true,
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void owl_clk_set_regmap(const struct owl_clk_desc *desc,
2562306a36Sopenharmony_ci			 struct regmap *regmap)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int i;
2862306a36Sopenharmony_ci	struct owl_clk_common *clks;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	for (i = 0; i < desc->num_clks; i++) {
3162306a36Sopenharmony_ci		clks = desc->clks[i];
3262306a36Sopenharmony_ci		if (!clks)
3362306a36Sopenharmony_ci			continue;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci		clks->regmap = regmap;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciint owl_clk_regmap_init(struct platform_device *pdev,
4062306a36Sopenharmony_ci			struct owl_clk_desc *desc)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	void __iomem *base;
4362306a36Sopenharmony_ci	struct regmap *regmap;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
4662306a36Sopenharmony_ci	if (IS_ERR(base))
4762306a36Sopenharmony_ci		return PTR_ERR(base);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	regmap = devm_regmap_init_mmio(&pdev->dev, base, &owl_regmap_config);
5062306a36Sopenharmony_ci	if (IS_ERR(regmap)) {
5162306a36Sopenharmony_ci		pr_err("failed to init regmap\n");
5262306a36Sopenharmony_ci		return PTR_ERR(regmap);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	owl_clk_set_regmap(desc, regmap);
5662306a36Sopenharmony_ci	desc->regmap = regmap;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return 0;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciint owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int i, ret;
6462306a36Sopenharmony_ci	struct clk_hw *hw;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	for (i = 0; i < hw_clks->num; i++) {
6762306a36Sopenharmony_ci		const char *name;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		hw = hw_clks->hws[i];
7062306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(hw))
7162306a36Sopenharmony_ci			continue;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		name = hw->init->name;
7462306a36Sopenharmony_ci		ret = devm_clk_hw_register(dev, hw);
7562306a36Sopenharmony_ci		if (ret) {
7662306a36Sopenharmony_ci			dev_err(dev, "Couldn't register clock %d - %s\n",
7762306a36Sopenharmony_ci				i, name);
7862306a36Sopenharmony_ci			return ret;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_clks);
8362306a36Sopenharmony_ci	if (ret)
8462306a36Sopenharmony_ci		dev_err(dev, "Failed to add clock provider\n");
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return ret;
8762306a36Sopenharmony_ci}
88