Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Base on code in drivers/clk/clk-divider.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * See clk-divider.c for further copyright information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * This program is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * it under the terms of the GNU General Public License as published by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * the Free Software Foundation; either version 2 of the License, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * (at your option) any later version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * This program is distributed in the hope that it will be useful,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * but WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include "clk-regmap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #define div_mask(width)	((1 << (width)) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #define to_clk_regmap_divider(_hw)	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 		container_of(_hw, struct clk_regmap_divider, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) clk_regmap_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	struct clk_regmap_divider *divider = to_clk_regmap_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	unsigned int val, div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	regmap_read(divider->regmap, divider->reg, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	div = val >> divider->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	div &= div_mask(divider->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	return divider_recalc_rate(hw, parent_rate, div, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 				   CLK_DIVIDER_ROUND_CLOSEST, divider->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) clk_regmap_divider_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 			      unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	struct clk_regmap_divider *divider = to_clk_regmap_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	return divider_round_rate(hw, rate, prate, NULL, divider->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 				  CLK_DIVIDER_ROUND_CLOSEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static int div_round_closest(unsigned long parent_rate, unsigned long rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	int up, down;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	unsigned long up_rate, down_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	up = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	down = parent_rate / rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	return (rate - up_rate) <= (down_rate - rate) ? up : down;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) clk_regmap_divider_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 			    unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	struct clk_regmap_divider *divider = to_clk_regmap_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	u32 val, div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	div = div_round_closest(parent_rate, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	dev_dbg(divider->dev, "%s: parent_rate=%ld, div=%d, rate=%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		clk_hw_get_name(hw), parent_rate, div, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	val = div_mask(divider->width) << (divider->shift + 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	val |= (div - 1) << divider->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	return regmap_write(divider->regmap, divider->reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) const struct clk_ops clk_regmap_divider_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	.recalc_rate = clk_regmap_divider_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	.round_rate = clk_regmap_divider_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	.set_rate = clk_regmap_divider_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) struct clk *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) devm_clk_regmap_register_divider(struct device *dev, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 				 const char *parent_name, struct regmap *regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 				 u32 reg, u8 shift, u8 width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 				 unsigned long flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	struct clk_regmap_divider *divider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	struct clk_init_data init = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	if (!divider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	init.ops = &clk_regmap_divider_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	init.flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	init.parent_names = (parent_name ? &parent_name : NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	init.num_parents = (parent_name ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	divider->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	divider->regmap = regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	divider->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	divider->shift = shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	divider->width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	divider->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	return devm_clk_register(dev, &divider->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) EXPORT_SYMBOL_GPL(devm_clk_regmap_register_divider);