^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) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/clkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk/at91_pmc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "pmc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define SMD_DIV_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define SMD_MAX_DIV 0xf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct at91sam9x5_clk_smd {
^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) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define to_at91sam9x5_clk_smd(hw) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) container_of(hw, struct at91sam9x5_clk_smd, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int smdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u8 smddiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) smddiv = (smdr & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return parent_rate / (smddiv + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned long bestrate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (rate >= *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return *parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) div = *parent_rate / rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (div > SMD_MAX_DIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return *parent_rate / (SMD_MAX_DIV + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) bestrate = *parent_rate / div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) tmp = *parent_rate / (div + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (bestrate - rate > rate - tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) bestrate = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return bestrate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (index > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) index ? AT91_PMC_SMDS : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned int smdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return smdr & AT91_PMC_SMDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long div = parent_rate / rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) (div - 1) << SMD_DIV_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static const struct clk_ops at91sam9x5_smd_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .recalc_rate = at91sam9x5_clk_smd_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .round_rate = at91sam9x5_clk_smd_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .get_parent = at91sam9x5_clk_smd_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .set_parent = at91sam9x5_clk_smd_set_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .set_rate = at91sam9x5_clk_smd_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct clk_hw * __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) const char **parent_names, u8 num_parents)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct at91sam9x5_clk_smd *smd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) smd = kzalloc(sizeof(*smd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (!smd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) init.ops = &at91sam9x5_smd_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) init.parent_names = parent_names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) init.num_parents = num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) smd->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) smd->regmap = regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) hw = &smd->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ret = clk_hw_register(NULL, &smd->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) kfree(smd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) hw = ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }