Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Spreadtrum clock infrastructure
0004 //
0005 // Copyright (C) 2017 Spreadtrum, Inc.
0006 // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
0007 
0008 #include <linux/mfd/syscon.h>
0009 #include <linux/module.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_platform.h>
0012 #include <linux/regmap.h>
0013 
0014 #include "common.h"
0015 
0016 static const struct regmap_config sprdclk_regmap_config = {
0017     .reg_bits   = 32,
0018     .reg_stride = 4,
0019     .val_bits   = 32,
0020     .max_register   = 0xffff,
0021     .fast_io    = true,
0022 };
0023 
0024 static void sprd_clk_set_regmap(const struct sprd_clk_desc *desc,
0025              struct regmap *regmap)
0026 {
0027     int i;
0028     struct sprd_clk_common *cclk;
0029 
0030     for (i = 0; i < desc->num_clk_clks; i++) {
0031         cclk = desc->clk_clks[i];
0032         if (!cclk)
0033             continue;
0034 
0035         cclk->regmap = regmap;
0036     }
0037 }
0038 
0039 int sprd_clk_regmap_init(struct platform_device *pdev,
0040              const struct sprd_clk_desc *desc)
0041 {
0042     void __iomem *base;
0043     struct device *dev = &pdev->dev;
0044     struct device_node *node = dev->of_node;
0045     struct regmap *regmap;
0046 
0047     if (of_find_property(node, "sprd,syscon", NULL)) {
0048         regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
0049         if (IS_ERR(regmap)) {
0050             pr_err("%s: failed to get syscon regmap\n", __func__);
0051             return PTR_ERR(regmap);
0052         }
0053     } else if (of_device_is_compatible(of_get_parent(dev->of_node),
0054                "syscon")) {
0055         regmap = device_node_to_regmap(of_get_parent(dev->of_node));
0056         if (IS_ERR(regmap)) {
0057             dev_err(dev, "failed to get regmap from its parent.\n");
0058             return PTR_ERR(regmap);
0059         }
0060     } else {
0061         base = devm_platform_ioremap_resource(pdev, 0);
0062         if (IS_ERR(base))
0063             return PTR_ERR(base);
0064 
0065         regmap = devm_regmap_init_mmio(&pdev->dev, base,
0066                            &sprdclk_regmap_config);
0067         if (IS_ERR(regmap)) {
0068             pr_err("failed to init regmap\n");
0069             return PTR_ERR(regmap);
0070         }
0071     }
0072 
0073     sprd_clk_set_regmap(desc, regmap);
0074 
0075     return 0;
0076 }
0077 EXPORT_SYMBOL_GPL(sprd_clk_regmap_init);
0078 
0079 int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw)
0080 {
0081     int i, ret;
0082     struct clk_hw *hw;
0083 
0084     for (i = 0; i < clkhw->num; i++) {
0085         const char *name;
0086 
0087         hw = clkhw->hws[i];
0088         if (!hw)
0089             continue;
0090 
0091         name = hw->init->name;
0092         ret = devm_clk_hw_register(dev, hw);
0093         if (ret) {
0094             dev_err(dev, "Couldn't register clock %d - %s\n",
0095                 i, name);
0096             return ret;
0097         }
0098     }
0099 
0100     ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw);
0101     if (ret)
0102         dev_err(dev, "Failed to add clock provider\n");
0103 
0104     return ret;
0105 }
0106 EXPORT_SYMBOL_GPL(sprd_clk_probe);
0107 
0108 MODULE_LICENSE("GPL v2");