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 13c7bb4fc1SJonas Jensen #include <linux/clk-provider.h> 14c7bb4fc1SJonas Jensen #include <linux/io.h> 15c7bb4fc1SJonas Jensen #include <linux/of_address.h> 16c7bb4fc1SJonas Jensen #include <linux/clkdev.h> 17c7bb4fc1SJonas Jensen 18*61ad23a1SStephen Boyd static void __init moxart_of_pll_clk_init(struct device_node *node) 19c7bb4fc1SJonas Jensen { 20c7bb4fc1SJonas Jensen static void __iomem *base; 21c7bb4fc1SJonas Jensen struct clk *clk, *ref_clk; 22c7bb4fc1SJonas Jensen unsigned int mul; 23c7bb4fc1SJonas Jensen const char *name = node->name; 24c7bb4fc1SJonas Jensen const char *parent_name; 25c7bb4fc1SJonas Jensen 26c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 27c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 28c7bb4fc1SJonas Jensen 29c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 30c7bb4fc1SJonas Jensen if (!base) { 31c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 32c7bb4fc1SJonas Jensen return; 33c7bb4fc1SJonas Jensen } 34c7bb4fc1SJonas Jensen 35c7bb4fc1SJonas Jensen mul = readl(base + 0x30) >> 3 & 0x3f; 36c7bb4fc1SJonas Jensen iounmap(base); 37c7bb4fc1SJonas Jensen 38c7bb4fc1SJonas Jensen ref_clk = of_clk_get(node, 0); 39c7bb4fc1SJonas Jensen if (IS_ERR(ref_clk)) { 40c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 41c7bb4fc1SJonas Jensen return; 42c7bb4fc1SJonas Jensen } 43c7bb4fc1SJonas Jensen 44c7bb4fc1SJonas Jensen clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); 45c7bb4fc1SJonas Jensen if (IS_ERR(clk)) { 46c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 47c7bb4fc1SJonas Jensen return; 48c7bb4fc1SJonas Jensen } 49c7bb4fc1SJonas Jensen 50c7bb4fc1SJonas Jensen clk_register_clkdev(clk, NULL, name); 51c7bb4fc1SJonas Jensen of_clk_add_provider(node, of_clk_src_simple_get, clk); 52c7bb4fc1SJonas Jensen } 53c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", 54c7bb4fc1SJonas Jensen moxart_of_pll_clk_init); 55c7bb4fc1SJonas Jensen 56*61ad23a1SStephen Boyd static void __init moxart_of_apb_clk_init(struct device_node *node) 57c7bb4fc1SJonas Jensen { 58c7bb4fc1SJonas Jensen static void __iomem *base; 59c7bb4fc1SJonas Jensen struct clk *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) { 70c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 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)) { 83c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 84c7bb4fc1SJonas Jensen return; 85c7bb4fc1SJonas Jensen } 86c7bb4fc1SJonas Jensen 87c7bb4fc1SJonas Jensen clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div); 88c7bb4fc1SJonas Jensen if (IS_ERR(clk)) { 89c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 90c7bb4fc1SJonas Jensen return; 91c7bb4fc1SJonas Jensen } 92c7bb4fc1SJonas Jensen 93c7bb4fc1SJonas Jensen clk_register_clkdev(clk, NULL, name); 94c7bb4fc1SJonas Jensen of_clk_add_provider(node, of_clk_src_simple_get, clk); 95c7bb4fc1SJonas Jensen } 96c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", 97c7bb4fc1SJonas Jensen moxart_of_apb_clk_init); 98