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