Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 2 | /* |
| 3 | * H8/300 divide clock driver |
| 4 | * |
| 5 | * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp> |
| 6 | */ |
| 7 | |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 8 | #include <linux/clk-provider.h> |
| 9 | #include <linux/err.h> |
Stephen Boyd | 62e59c4 | 2019-04-18 15:20:22 -0700 | [diff] [blame] | 10 | #include <linux/io.h> |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 11 | #include <linux/of.h> |
| 12 | #include <linux/of_address.h> |
| 13 | |
| 14 | static DEFINE_SPINLOCK(clklock); |
| 15 | |
| 16 | static void __init h8300_div_clk_setup(struct device_node *node) |
| 17 | { |
Stephen Boyd | ebf3f9a | 2016-02-19 17:36:51 -0800 | [diff] [blame] | 18 | unsigned int num_parents; |
Stephen Boyd | 8b2bdc7 | 2016-08-16 15:37:57 -0700 | [diff] [blame] | 19 | struct clk_hw *hw; |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 20 | const char *clk_name = node->name; |
| 21 | const char *parent_name; |
| 22 | void __iomem *divcr = NULL; |
| 23 | int width; |
Yoshinori Sato | aca2518 | 2015-05-31 23:25:35 +0900 | [diff] [blame] | 24 | int offset; |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 25 | |
| 26 | num_parents = of_clk_get_parent_count(node); |
Stephen Boyd | ebf3f9a | 2016-02-19 17:36:51 -0800 | [diff] [blame] | 27 | if (!num_parents) { |
Arvind Yadav | 1f7e655 | 2017-11-24 12:25:33 +0530 | [diff] [blame] | 28 | pr_err("%s: no parent found\n", clk_name); |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 29 | return; |
| 30 | } |
| 31 | |
| 32 | divcr = of_iomap(node, 0); |
| 33 | if (divcr == NULL) { |
Arvind Yadav | 1f7e655 | 2017-11-24 12:25:33 +0530 | [diff] [blame] | 34 | pr_err("%s: failed to map divide register\n", clk_name); |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 35 | goto error; |
| 36 | } |
Yoshinori Sato | aca2518 | 2015-05-31 23:25:35 +0900 | [diff] [blame] | 37 | offset = (unsigned long)divcr & 3; |
| 38 | offset = (3 - offset) * 8; |
Stephen Boyd | d3622b5 | 2016-02-22 12:36:15 -0800 | [diff] [blame] | 39 | divcr = (void __iomem *)((unsigned long)divcr & ~3); |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 40 | |
| 41 | parent_name = of_clk_get_parent_name(node, 0); |
| 42 | of_property_read_u32(node, "renesas,width", &width); |
Stephen Boyd | 8b2bdc7 | 2016-08-16 15:37:57 -0700 | [diff] [blame] | 43 | hw = clk_hw_register_divider(NULL, clk_name, parent_name, |
Yoshinori Sato | aca2518 | 2015-05-31 23:25:35 +0900 | [diff] [blame] | 44 | CLK_SET_RATE_GATE, divcr, offset, width, |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 45 | CLK_DIVIDER_POWER_OF_TWO, &clklock); |
Stephen Boyd | 8b2bdc7 | 2016-08-16 15:37:57 -0700 | [diff] [blame] | 46 | if (!IS_ERR(hw)) { |
| 47 | of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 48 | return; |
| 49 | } |
| 50 | pr_err("%s: failed to register %s div clock (%ld)\n", |
Stephen Boyd | 8b2bdc7 | 2016-08-16 15:37:57 -0700 | [diff] [blame] | 51 | __func__, clk_name, PTR_ERR(hw)); |
Yoshinori Sato | 7b5bb89 | 2015-05-08 23:31:57 +0900 | [diff] [blame] | 52 | error: |
| 53 | if (divcr) |
| 54 | iounmap(divcr); |
| 55 | } |
| 56 | |
| 57 | CLK_OF_DECLARE(h8300_div_clk, "renesas,h8300-div-clock", h8300_div_clk_setup); |