^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016 Socionext Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "clk-uniphier.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define UNIPHIER_CLK_CPUGEAR_STAT 0 /* status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define UNIPHIER_CLK_CPUGEAR_SET 4 /* set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define UNIPHIER_CLK_CPUGEAR_UPD 8 /* update */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define UNIPHIER_CLK_CPUGEAR_UPD_BIT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct uniphier_clk_cpugear {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct clk_hw hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int regbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned int mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define to_uniphier_clk_cpugear(_hw) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) container_of(_hw, struct uniphier_clk_cpugear, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int uniphier_clk_cpugear_set_parent(struct clk_hw *hw, u8 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct uniphier_clk_cpugear *gear = to_uniphier_clk_cpugear(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ret = regmap_write_bits(gear->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) gear->regbase + UNIPHIER_CLK_CPUGEAR_SET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) gear->mask, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) ret = regmap_write_bits(gear->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) gear->regbase + UNIPHIER_CLK_CPUGEAR_UPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) UNIPHIER_CLK_CPUGEAR_UPD_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) UNIPHIER_CLK_CPUGEAR_UPD_BIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return regmap_read_poll_timeout(gear->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) gear->regbase + UNIPHIER_CLK_CPUGEAR_UPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) val, !(val & UNIPHIER_CLK_CPUGEAR_UPD_BIT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static u8 uniphier_clk_cpugear_get_parent(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct uniphier_clk_cpugear *gear = to_uniphier_clk_cpugear(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int num_parents = clk_hw_get_num_parents(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ret = regmap_read(gear->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) gear->regbase + UNIPHIER_CLK_CPUGEAR_STAT, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) val &= gear->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return val < num_parents ? val : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static const struct clk_ops uniphier_clk_cpugear_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .determine_rate = __clk_mux_determine_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .set_parent = uniphier_clk_cpugear_set_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .get_parent = uniphier_clk_cpugear_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct clk_hw *uniphier_clk_register_cpugear(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct regmap *regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) const struct uniphier_clk_cpugear_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct uniphier_clk_cpugear *gear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) gear = devm_kzalloc(dev, sizeof(*gear), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!gear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) init.ops = &uniphier_clk_cpugear_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) init.flags = CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) init.parent_names = data->parent_names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) init.num_parents = data->num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) gear->regmap = regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) gear->regbase = data->regbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) gear->mask = data->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) gear->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = devm_clk_hw_register(dev, &gear->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return &gear->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }