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 13*67bb5408SStephen 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; 22c7bb4fc1SJonas Jensen struct clk *clk, *ref_clk; 23c7bb4fc1SJonas Jensen unsigned int mul; 24c7bb4fc1SJonas Jensen const char *name = node->name; 25c7bb4fc1SJonas Jensen const char *parent_name; 26c7bb4fc1SJonas Jensen 27c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 28c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 29c7bb4fc1SJonas Jensen 30c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 31c7bb4fc1SJonas Jensen if (!base) { 32c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 33c7bb4fc1SJonas Jensen return; 34c7bb4fc1SJonas Jensen } 35c7bb4fc1SJonas Jensen 36c7bb4fc1SJonas Jensen mul = readl(base + 0x30) >> 3 & 0x3f; 37c7bb4fc1SJonas Jensen iounmap(base); 38c7bb4fc1SJonas Jensen 39c7bb4fc1SJonas Jensen ref_clk = of_clk_get(node, 0); 40c7bb4fc1SJonas Jensen if (IS_ERR(ref_clk)) { 41c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 42c7bb4fc1SJonas Jensen return; 43c7bb4fc1SJonas Jensen } 44c7bb4fc1SJonas Jensen 45c7bb4fc1SJonas Jensen clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1); 46c7bb4fc1SJonas Jensen if (IS_ERR(clk)) { 47c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 48c7bb4fc1SJonas Jensen return; 49c7bb4fc1SJonas Jensen } 50c7bb4fc1SJonas Jensen 51c7bb4fc1SJonas Jensen clk_register_clkdev(clk, NULL, name); 52c7bb4fc1SJonas Jensen of_clk_add_provider(node, of_clk_src_simple_get, clk); 53c7bb4fc1SJonas Jensen } 54c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", 55c7bb4fc1SJonas Jensen moxart_of_pll_clk_init); 56c7bb4fc1SJonas Jensen 5761ad23a1SStephen Boyd static void __init moxart_of_apb_clk_init(struct device_node *node) 58c7bb4fc1SJonas Jensen { 59c7bb4fc1SJonas Jensen static void __iomem *base; 60c7bb4fc1SJonas Jensen struct clk *clk, *pll_clk; 61c7bb4fc1SJonas Jensen unsigned int div, val; 62c7bb4fc1SJonas Jensen unsigned int div_idx[] = { 2, 3, 4, 6, 8}; 63c7bb4fc1SJonas Jensen const char *name = node->name; 64c7bb4fc1SJonas Jensen const char *parent_name; 65c7bb4fc1SJonas Jensen 66c7bb4fc1SJonas Jensen of_property_read_string(node, "clock-output-names", &name); 67c7bb4fc1SJonas Jensen parent_name = of_clk_get_parent_name(node, 0); 68c7bb4fc1SJonas Jensen 69c7bb4fc1SJonas Jensen base = of_iomap(node, 0); 70c7bb4fc1SJonas Jensen if (!base) { 71c7bb4fc1SJonas Jensen pr_err("%s: of_iomap failed\n", node->full_name); 72c7bb4fc1SJonas Jensen return; 73c7bb4fc1SJonas Jensen } 74c7bb4fc1SJonas Jensen 75c7bb4fc1SJonas Jensen val = readl(base + 0xc) >> 4 & 0x7; 76c7bb4fc1SJonas Jensen iounmap(base); 77c7bb4fc1SJonas Jensen 78c7bb4fc1SJonas Jensen if (val > 4) 79c7bb4fc1SJonas Jensen val = 0; 80c7bb4fc1SJonas Jensen div = div_idx[val] * 2; 81c7bb4fc1SJonas Jensen 82c7bb4fc1SJonas Jensen pll_clk = of_clk_get(node, 0); 83c7bb4fc1SJonas Jensen if (IS_ERR(pll_clk)) { 84c7bb4fc1SJonas Jensen pr_err("%s: of_clk_get failed\n", node->full_name); 85c7bb4fc1SJonas Jensen return; 86c7bb4fc1SJonas Jensen } 87c7bb4fc1SJonas Jensen 88c7bb4fc1SJonas Jensen clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div); 89c7bb4fc1SJonas Jensen if (IS_ERR(clk)) { 90c7bb4fc1SJonas Jensen pr_err("%s: failed to register clock\n", node->full_name); 91c7bb4fc1SJonas Jensen return; 92c7bb4fc1SJonas Jensen } 93c7bb4fc1SJonas Jensen 94c7bb4fc1SJonas Jensen clk_register_clkdev(clk, NULL, name); 95c7bb4fc1SJonas Jensen of_clk_add_provider(node, of_clk_src_simple_get, clk); 96c7bb4fc1SJonas Jensen } 97c7bb4fc1SJonas Jensen CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock", 98c7bb4fc1SJonas Jensen moxart_of_apb_clk_init); 99