114 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Spreadtrum clock infrastructure4//5// Copyright (C) 2017 Spreadtrum, Inc.6// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>7 8#include <linux/mfd/syscon.h>9#include <linux/module.h>10#include <linux/of_address.h>11#include <linux/platform_device.h>12#include <linux/regmap.h>13 14#include "common.h"15 16static const struct regmap_config sprdclk_regmap_config = {17 .reg_bits = 32,18 .reg_stride = 4,19 .val_bits = 32,20 .fast_io = true,21};22 23static void sprd_clk_set_regmap(const struct sprd_clk_desc *desc,24 struct regmap *regmap)25{26 int i;27 struct sprd_clk_common *cclk;28 29 for (i = 0; i < desc->num_clk_clks; i++) {30 cclk = desc->clk_clks[i];31 if (!cclk)32 continue;33 34 cclk->regmap = regmap;35 }36}37 38int sprd_clk_regmap_init(struct platform_device *pdev,39 const struct sprd_clk_desc *desc)40{41 void __iomem *base;42 struct device *dev = &pdev->dev;43 struct device_node *node = dev->of_node, *np;44 struct regmap *regmap;45 struct resource *res;46 struct regmap_config reg_config = sprdclk_regmap_config;47 48 if (of_property_present(node, "sprd,syscon")) {49 regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");50 if (IS_ERR(regmap)) {51 pr_err("%s: failed to get syscon regmap\n", __func__);52 return PTR_ERR(regmap);53 }54 } else if (of_device_is_compatible(np = of_get_parent(node), "syscon") ||55 (of_node_put(np), 0)) {56 regmap = device_node_to_regmap(np);57 of_node_put(np);58 if (IS_ERR(regmap)) {59 dev_err(dev, "failed to get regmap from its parent.\n");60 return PTR_ERR(regmap);61 }62 } else {63 base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);64 if (IS_ERR(base))65 return PTR_ERR(base);66 67 reg_config.max_register = resource_size(res) - reg_config.reg_stride;68 69 regmap = devm_regmap_init_mmio(&pdev->dev, base,70 ®_config);71 if (IS_ERR(regmap)) {72 pr_err("failed to init regmap\n");73 return PTR_ERR(regmap);74 }75 }76 77 sprd_clk_set_regmap(desc, regmap);78 79 return 0;80}81EXPORT_SYMBOL_GPL(sprd_clk_regmap_init);82 83int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw)84{85 int i, ret;86 struct clk_hw *hw;87 88 for (i = 0; i < clkhw->num; i++) {89 const char *name;90 91 hw = clkhw->hws[i];92 if (!hw)93 continue;94 95 name = hw->init->name;96 ret = devm_clk_hw_register(dev, hw);97 if (ret) {98 dev_err(dev, "Couldn't register clock %d - %s\n",99 i, name);100 return ret;101 }102 }103 104 ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw);105 if (ret)106 dev_err(dev, "Failed to add clock provider\n");107 108 return ret;109}110EXPORT_SYMBOL_GPL(sprd_clk_probe);111 112MODULE_DESCRIPTION("Spreadtrum clock infrastructure");113MODULE_LICENSE("GPL v2");114