1d41f59fdSChunyan Zhang // SPDX-License-Identifier: GPL-2.0 2d41f59fdSChunyan Zhang // 3d41f59fdSChunyan Zhang // Spreadtrum clock infrastructure 4d41f59fdSChunyan Zhang // 5d41f59fdSChunyan Zhang // Copyright (C) 2017 Spreadtrum, Inc. 6d41f59fdSChunyan Zhang // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> 7d41f59fdSChunyan Zhang 8d41f59fdSChunyan Zhang #include <linux/mfd/syscon.h> 9d41f59fdSChunyan Zhang #include <linux/module.h> 10d41f59fdSChunyan Zhang #include <linux/of_address.h> 11d41f59fdSChunyan Zhang #include <linux/of_platform.h> 12d41f59fdSChunyan Zhang #include <linux/regmap.h> 13d41f59fdSChunyan Zhang 14d41f59fdSChunyan Zhang #include "common.h" 15d41f59fdSChunyan Zhang 16d41f59fdSChunyan Zhang static const struct regmap_config sprdclk_regmap_config = { 17d41f59fdSChunyan Zhang .reg_bits = 32, 18d41f59fdSChunyan Zhang .reg_stride = 4, 19d41f59fdSChunyan Zhang .val_bits = 32, 20d41f59fdSChunyan Zhang .max_register = 0xffff, 21d41f59fdSChunyan Zhang .fast_io = true, 22d41f59fdSChunyan Zhang }; 23d41f59fdSChunyan Zhang 24d41f59fdSChunyan Zhang static void sprd_clk_set_regmap(const struct sprd_clk_desc *desc, 25d41f59fdSChunyan Zhang struct regmap *regmap) 26d41f59fdSChunyan Zhang { 27d41f59fdSChunyan Zhang int i; 28d41f59fdSChunyan Zhang struct sprd_clk_common *cclk; 29d41f59fdSChunyan Zhang 30d41f59fdSChunyan Zhang for (i = 0; i < desc->num_clk_clks; i++) { 31d41f59fdSChunyan Zhang cclk = desc->clk_clks[i]; 32d41f59fdSChunyan Zhang if (!cclk) 33d41f59fdSChunyan Zhang continue; 34d41f59fdSChunyan Zhang 35d41f59fdSChunyan Zhang cclk->regmap = regmap; 36d41f59fdSChunyan Zhang } 37d41f59fdSChunyan Zhang } 38d41f59fdSChunyan Zhang 39d41f59fdSChunyan Zhang int sprd_clk_regmap_init(struct platform_device *pdev, 40d41f59fdSChunyan Zhang const struct sprd_clk_desc *desc) 41d41f59fdSChunyan Zhang { 42d41f59fdSChunyan Zhang void __iomem *base; 43d41f59fdSChunyan Zhang struct device_node *node = pdev->dev.of_node; 44d41f59fdSChunyan Zhang struct regmap *regmap; 45d41f59fdSChunyan Zhang 46d41f59fdSChunyan Zhang if (of_find_property(node, "sprd,syscon", NULL)) { 47d41f59fdSChunyan Zhang regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); 48d41f59fdSChunyan Zhang if (IS_ERR_OR_NULL(regmap)) { 49d41f59fdSChunyan Zhang pr_err("%s: failed to get syscon regmap\n", __func__); 50d41f59fdSChunyan Zhang return PTR_ERR(regmap); 51d41f59fdSChunyan Zhang } 52d41f59fdSChunyan Zhang } else { 53*793ee798SBaolin Wang base = devm_platform_ioremap_resource(pdev, 0); 5469b39d25SChunyan Zhang if (IS_ERR(base)) 5569b39d25SChunyan Zhang return PTR_ERR(base); 5669b39d25SChunyan Zhang 57d41f59fdSChunyan Zhang regmap = devm_regmap_init_mmio(&pdev->dev, base, 58d41f59fdSChunyan Zhang &sprdclk_regmap_config); 5978f52969SChunyan Zhang if (IS_ERR(regmap)) { 60d41f59fdSChunyan Zhang pr_err("failed to init regmap\n"); 61d41f59fdSChunyan Zhang return PTR_ERR(regmap); 62d41f59fdSChunyan Zhang } 63d41f59fdSChunyan Zhang } 64d41f59fdSChunyan Zhang 65d41f59fdSChunyan Zhang sprd_clk_set_regmap(desc, regmap); 66d41f59fdSChunyan Zhang 67d41f59fdSChunyan Zhang return 0; 68d41f59fdSChunyan Zhang } 69d41f59fdSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_clk_regmap_init); 70d41f59fdSChunyan Zhang 71d41f59fdSChunyan Zhang int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw) 72d41f59fdSChunyan Zhang { 73d41f59fdSChunyan Zhang int i, ret; 74d41f59fdSChunyan Zhang struct clk_hw *hw; 75d41f59fdSChunyan Zhang 76d41f59fdSChunyan Zhang for (i = 0; i < clkhw->num; i++) { 77f6c90df8SStephen Boyd const char *name; 78d41f59fdSChunyan Zhang 79d41f59fdSChunyan Zhang hw = clkhw->hws[i]; 80d41f59fdSChunyan Zhang if (!hw) 81d41f59fdSChunyan Zhang continue; 82d41f59fdSChunyan Zhang 83f6c90df8SStephen Boyd name = hw->init->name; 84d41f59fdSChunyan Zhang ret = devm_clk_hw_register(dev, hw); 85d41f59fdSChunyan Zhang if (ret) { 86d41f59fdSChunyan Zhang dev_err(dev, "Couldn't register clock %d - %s\n", 87f6c90df8SStephen Boyd i, name); 88d41f59fdSChunyan Zhang return ret; 89d41f59fdSChunyan Zhang } 90d41f59fdSChunyan Zhang } 91d41f59fdSChunyan Zhang 92d41f59fdSChunyan Zhang ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw); 93d41f59fdSChunyan Zhang if (ret) 94d41f59fdSChunyan Zhang dev_err(dev, "Failed to add clock provider\n"); 95d41f59fdSChunyan Zhang 96d41f59fdSChunyan Zhang return ret; 97d41f59fdSChunyan Zhang } 98d41f59fdSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_clk_probe); 99d41f59fdSChunyan Zhang 100d41f59fdSChunyan Zhang MODULE_LICENSE("GPL v2"); 101