^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 SYSTEM_MAX_ID 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define SYSTEM_MAX_NAME_SZ 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct clk_system {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct clk_hw hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u8 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static inline int is_pck(int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return (id >= 8) && (id <= 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static inline bool clk_system_ready(struct regmap *regmap, int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) regmap_read(regmap, AT91_PMC_SR, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return !!(status & (1 << id));
^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 int clk_system_prepare(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct clk_system *sys = to_clk_system(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (!is_pck(sys->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) while (!clk_system_ready(sys->regmap, sys->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void clk_system_unprepare(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct clk_system *sys = to_clk_system(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static int clk_system_is_prepared(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct clk_system *sys = to_clk_system(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (!(status & (1 << sys->id)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!is_pck(sys->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) regmap_read(sys->regmap, AT91_PMC_SR, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return !!(status & (1 << sys->id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static const struct clk_ops system_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .prepare = clk_system_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .unprepare = clk_system_unprepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .is_prepared = clk_system_is_prepared,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct clk_hw * __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) at91_clk_register_system(struct regmap *regmap, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const char *parent_name, u8 id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct clk_system *sys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct clk_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!parent_name || id > SYSTEM_MAX_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) sys = kzalloc(sizeof(*sys), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!sys)
^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 = &system_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) init.parent_names = &parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) init.num_parents = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) init.flags = CLK_SET_RATE_PARENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) sys->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) sys->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) sys->regmap = regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) hw = &sys->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ret = clk_hw_register(NULL, &sys->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) kfree(sys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) hw = ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }