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; 4569b39d25SChunyan Zhang struct resource *res; 46d41f59fdSChunyan Zhang 47d41f59fdSChunyan Zhang if (of_find_property(node, "sprd,syscon", NULL)) { 48d41f59fdSChunyan Zhang regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); 499629dbdaSBaolin Wang if (IS_ERR(regmap)) { 50d41f59fdSChunyan Zhang pr_err("%s: failed to get syscon regmap\n", __func__); 51d41f59fdSChunyan Zhang return PTR_ERR(regmap); 52d41f59fdSChunyan Zhang } 53d41f59fdSChunyan Zhang } else { 5469b39d25SChunyan Zhang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5569b39d25SChunyan Zhang base = devm_ioremap_resource(&pdev->dev, res); 5669b39d25SChunyan Zhang if (IS_ERR(base)) 5769b39d25SChunyan Zhang return PTR_ERR(base); 5869b39d25SChunyan Zhang 59d41f59fdSChunyan Zhang regmap = devm_regmap_init_mmio(&pdev->dev, base, 60d41f59fdSChunyan Zhang &sprdclk_regmap_config); 6178f52969SChunyan Zhang if (IS_ERR(regmap)) { 62d41f59fdSChunyan Zhang pr_err("failed to init regmap\n"); 63d41f59fdSChunyan Zhang return PTR_ERR(regmap); 64d41f59fdSChunyan Zhang } 65d41f59fdSChunyan Zhang } 66d41f59fdSChunyan Zhang 67d41f59fdSChunyan Zhang sprd_clk_set_regmap(desc, regmap); 68d41f59fdSChunyan Zhang 69d41f59fdSChunyan Zhang return 0; 70d41f59fdSChunyan Zhang } 71d41f59fdSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_clk_regmap_init); 72d41f59fdSChunyan Zhang 73d41f59fdSChunyan Zhang int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw) 74d41f59fdSChunyan Zhang { 75d41f59fdSChunyan Zhang int i, ret; 76d41f59fdSChunyan Zhang struct clk_hw *hw; 77d41f59fdSChunyan Zhang 78d41f59fdSChunyan Zhang for (i = 0; i < clkhw->num; i++) { 79f6c90df8SStephen Boyd const char *name; 80d41f59fdSChunyan Zhang 81d41f59fdSChunyan Zhang hw = clkhw->hws[i]; 82d41f59fdSChunyan Zhang if (!hw) 83d41f59fdSChunyan Zhang continue; 84d41f59fdSChunyan Zhang 85f6c90df8SStephen Boyd name = hw->init->name; 86d41f59fdSChunyan Zhang ret = devm_clk_hw_register(dev, hw); 87d41f59fdSChunyan Zhang if (ret) { 88d41f59fdSChunyan Zhang dev_err(dev, "Couldn't register clock %d - %s\n", 89f6c90df8SStephen Boyd i, name); 90d41f59fdSChunyan Zhang return ret; 91d41f59fdSChunyan Zhang } 92d41f59fdSChunyan Zhang } 93d41f59fdSChunyan Zhang 94d41f59fdSChunyan Zhang ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw); 95d41f59fdSChunyan Zhang if (ret) 96d41f59fdSChunyan Zhang dev_err(dev, "Failed to add clock provider\n"); 97d41f59fdSChunyan Zhang 98d41f59fdSChunyan Zhang return ret; 99d41f59fdSChunyan Zhang } 100d41f59fdSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_clk_probe); 101d41f59fdSChunyan Zhang 102d41f59fdSChunyan Zhang MODULE_LICENSE("GPL v2"); 103