1c7bb4fc1SJonas Jensen /* 2c7bb4fc1SJonas Jensen * MOXA ART SoCs clock driver. 3c7bb4fc1SJonas Jensen * 4c7bb4fc1SJonas Jensen * Copyright (C) 2013 Jonas Jensen 5c7bb4fc1SJonas Jensen * 6c7bb4fc1SJonas Jensen * Jonas Jensen <jonas.jensen@gmail.com> 7c7bb4fc1SJonas Jensen * 8c7bb4fc1SJonas Jensen * This file is licensed under the terms of the GNU General Public 9c7bb4fc1SJonas Jensen * License version 2. This program is licensed "as is" without any 10c7bb4fc1SJonas Jensen * warranty of any kind, whether express or implied. 11c7bb4fc1SJonas Jensen */ 12c7bb4fc1SJonas Jensen 1367bb5408SStephen Boyd #include <linux/clk.h> 14c7bb4fc1SJonas Jensen #include <linux/clk-provider.h> 15c7bb4fc1SJonas Jensen #include <linux/io.h> 16c7bb4fc1SJonas Jensen #include <linux/of_address.h> 17c7bb4fc1SJonas Jensen #include <linux/clkdev.h> 18c7bb4fc1SJonas Jensen 1961ad23a1SStephen Boyd static void __init moxart_of_pll_clk_init(struct device_node *node) 20c7bb4fc1SJonas Jensen { 21c7bb4fc1SJonas Jensen static void __iomem *base; 22*5a962d2eSStephen Boyd struct clk_hw *hw; 23*5a962d2eSStephen Boyd struct clk *ref_clk; 24c7bb4fc1SJonas Jensen unsigned int mul; 25c7bb4fc1SJonas Jensen const char *name = node->name; 26c7bb4fc1SJonas Jensen const char *parent_name; 27c7bb4fc1SJonas Jensen 28c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 29c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 30c7bb4fc1SJonas Jensen 31c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 32c7bb4fc1SJonas Jensen if (!base) { 33c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 34c7bb4fc1SJonas Jensen return; 35c7bb4fc1SJonas Jensen } 36c7bb4fc1SJonas Jensen 37c7bb4fc1SJonas Jensen mul = readl(base + 0x30) >> 3 & 0x3f; 38c7bb4fc1SJonas Jensen iounmap(base); 39c7bb4fc1SJonas Jensen 40c7bb4fc1SJonas Jensen ref_clk = of_clk_get(node, 0); 41c7bb4fc1SJonas Jensen if (IS_ERR(ref_clk)) { 42c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 43c7bb4fc1SJonas Jensen return; 44c7bb4fc1SJonas Jensen } 45c7bb4fc1SJonas Jensen 46*5a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); 47*5a962d2eSStephen Boyd if (IS_ERR(hw)) { 48c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 49c7bb4fc1SJonas Jensen return; 50c7bb4fc1SJonas Jensen } 51c7bb4fc1SJonas Jensen 52*5a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name); 53*5a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); 54c7bb4fc1SJonas Jensen } 55c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", 56c7bb4fc1SJonas Jensen moxart_of_pll_clk_init); 57c7bb4fc1SJonas Jensen 5861ad23a1SStephen Boyd static void __init moxart_of_apb_clk_init(struct device_node *node) 59c7bb4fc1SJonas Jensen { 60c7bb4fc1SJonas Jensen static void __iomem *base; 61*5a962d2eSStephen Boyd struct clk_hw *hw; 62*5a962d2eSStephen Boyd struct clk *pll_clk; 63c7bb4fc1SJonas Jensen unsigned int div, val; 64c7bb4fc1SJonas Jensen unsigned int div_idx[] = { 2, 3, 4, 6, 8}; 65c7bb4fc1SJonas Jensen const char *name = node->name; 66c7bb4fc1SJonas Jensen const char *parent_name; 67c7bb4fc1SJonas Jensen 68c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 69c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 70c7bb4fc1SJonas Jensen 71c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 72c7bb4fc1SJonas Jensen if (!base) { 73c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 74c7bb4fc1SJonas Jensen return; 75c7bb4fc1SJonas Jensen } 76c7bb4fc1SJonas Jensen 77c7bb4fc1SJonas Jensen val = readl(base + 0xc) >> 4 & 0x7; 78c7bb4fc1SJonas Jensen iounmap(base); 79c7bb4fc1SJonas Jensen 80c7bb4fc1SJonas Jensen if (val > 4) 81c7bb4fc1SJonas Jensen val = 0; 82c7bb4fc1SJonas Jensen div = div_idx[val] * 2; 83c7bb4fc1SJonas Jensen 84c7bb4fc1SJonas Jensen pll_clk = of_clk_get(node, 0); 85c7bb4fc1SJonas Jensen if (IS_ERR(pll_clk)) { 86c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 87c7bb4fc1SJonas Jensen return; 88c7bb4fc1SJonas Jensen } 89c7bb4fc1SJonas Jensen 90*5a962d2eSStephen Boyd hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div); 91*5a962d2eSStephen Boyd if (IS_ERR(hw)) { 92c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 93c7bb4fc1SJonas Jensen return; 94c7bb4fc1SJonas Jensen } 95c7bb4fc1SJonas Jensen 96*5a962d2eSStephen Boyd clk_hw_register_clkdev(hw, NULL, name); 97*5a962d2eSStephen Boyd of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); 98c7bb4fc1SJonas Jensen } 99c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", 100c7bb4fc1SJonas Jensen moxart_of_apb_clk_init); 101