1*3bb16560SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c7bb4fc1SJonas Jensen /* 3c7bb4fc1SJonas Jensen * MOXA ART SoCs clock driver. 4c7bb4fc1SJonas Jensen * 5c7bb4fc1SJonas Jensen * Copyright (C) 2013 Jonas Jensen 6c7bb4fc1SJonas Jensen * 7c7bb4fc1SJonas Jensen * Jonas Jensen <jonas.jensen@gmail.com> 8c7bb4fc1SJonas Jensen */ 9c7bb4fc1SJonas Jensen 1067bb5408SStephen Boyd #include <linux/clk.h> 11c7bb4fc1SJonas Jensen #include <linux/clk-provider.h> 12c7bb4fc1SJonas Jensen #include <linux/io.h> 13c7bb4fc1SJonas Jensen #include <linux/of_address.h> 14c7bb4fc1SJonas Jensen #include <linux/clkdev.h> 15c7bb4fc1SJonas Jensen 1661ad23a1SStephen Boyd static void __init moxart_of_pll_clk_init(struct device_node *node) 17c7bb4fc1SJonas Jensen { 18c8108cf2SGustavo A. R. Silva void __iomem *base; 195a962d2eSStephen Boyd struct clk_hw *hw; 205a962d2eSStephen Boyd struct clk *ref_clk; 21c7bb4fc1SJonas Jensen unsigned int mul; 22c7bb4fc1SJonas Jensen const char *name = node->name; 23c7bb4fc1SJonas Jensen const char *parent_name; 24c7bb4fc1SJonas Jensen 25c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 26c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 27c7bb4fc1SJonas Jensen 28c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 29c7bb4fc1SJonas Jensen if (!base) { 3016673931SRob Herring pr_err("%pOF: of_iomap failed\n", node); 31c7bb4fc1SJonas Jensen return; 32c7bb4fc1SJonas Jensen } 33c7bb4fc1SJonas Jensen 34c7bb4fc1SJonas Jensen mul = readl(base + 0x30) >> 3 & 0x3f; 35c7bb4fc1SJonas Jensen iounmap(base); 36c7bb4fc1SJonas Jensen 37c7bb4fc1SJonas Jensen ref_clk = of_clk_get(node, 0); 38c7bb4fc1SJonas Jensen if (IS_ERR(ref_clk)) { 3916673931SRob Herring pr_err("%pOF: of_clk_get failed\n", node); 40c7bb4fc1SJonas Jensen return; 41c7bb4fc1SJonas Jensen } 42c7bb4fc1SJonas Jensen 435a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); 445a962d2eSStephen Boyd if (IS_ERR(hw)) { 4516673931SRob Herring pr_err("%pOF: failed to register clock\n", node); 46c7bb4fc1SJonas Jensen return; 47c7bb4fc1SJonas Jensen } 48c7bb4fc1SJonas Jensen 495a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name); 505a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); 51c7bb4fc1SJonas Jensen } 52c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", 53c7bb4fc1SJonas Jensen moxart_of_pll_clk_init); 54c7bb4fc1SJonas Jensen 5561ad23a1SStephen Boyd static void __init moxart_of_apb_clk_init(struct device_node *node) 56c7bb4fc1SJonas Jensen { 57c8108cf2SGustavo A. R. Silva void __iomem *base; 585a962d2eSStephen Boyd struct clk_hw *hw; 595a962d2eSStephen Boyd struct clk *pll_clk; 60c7bb4fc1SJonas Jensen unsigned int div, val; 61c7bb4fc1SJonas Jensen unsigned int div_idx[] = { 2, 3, 4, 6, 8}; 62c7bb4fc1SJonas Jensen const char *name = node->name; 63c7bb4fc1SJonas Jensen const char *parent_name; 64c7bb4fc1SJonas Jensen 65c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 66c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 67c7bb4fc1SJonas Jensen 68c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 69c7bb4fc1SJonas Jensen if (!base) { 7016673931SRob Herring pr_err("%pOF: of_iomap failed\n", node); 71c7bb4fc1SJonas Jensen return; 72c7bb4fc1SJonas Jensen } 73c7bb4fc1SJonas Jensen 74c7bb4fc1SJonas Jensen val = readl(base + 0xc) >> 4 & 0x7; 75c7bb4fc1SJonas Jensen iounmap(base); 76c7bb4fc1SJonas Jensen 77c7bb4fc1SJonas Jensen if (val > 4) 78c7bb4fc1SJonas Jensen val = 0; 79c7bb4fc1SJonas Jensen div = div_idx[val] * 2; 80c7bb4fc1SJonas Jensen 81c7bb4fc1SJonas Jensen pll_clk = of_clk_get(node, 0); 82c7bb4fc1SJonas Jensen if (IS_ERR(pll_clk)) { 8316673931SRob Herring pr_err("%pOF: of_clk_get failed\n", node); 84c7bb4fc1SJonas Jensen return; 85c7bb4fc1SJonas Jensen } 86c7bb4fc1SJonas Jensen 875a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div); 885a962d2eSStephen Boyd if (IS_ERR(hw)) { 8916673931SRob Herring pr_err("%pOF: failed to register clock\n", node); 90c7bb4fc1SJonas Jensen return; 91c7bb4fc1SJonas Jensen } 92c7bb4fc1SJonas Jensen 935a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name); 945a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); 95c7bb4fc1SJonas Jensen } 96c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", 97c7bb4fc1SJonas Jensen moxart_of_apb_clk_init); 98