Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 145 lines 3.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2016 Maxime Ripard 4 * Maxime Ripard <maxime.ripard@free-electrons.com> 5 */ 6 7#include <linux/clk-provider.h> 8#include <linux/io.h> 9 10#include "ccu_gate.h" 11#include "ccu_div.h" 12 13static int ccu_div_determine_rate_helper(struct ccu_mux_internal *mux, 14 struct clk_rate_request *req, 15 void *data) 16{ 17 struct ccu_div *cd = data; 18 int ret; 19 20 if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) 21 req->rate *= cd->fixed_post_div; 22 23 ret = divider_determine_rate(&cd->common.hw, req, cd->div.table, 24 cd->div.width, cd->div.flags); 25 if (ret) 26 return ret; 27 28 if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) 29 req->rate /= cd->fixed_post_div; 30 31 return 0; 32} 33 34static void ccu_div_disable(struct clk_hw *hw) 35{ 36 struct ccu_div *cd = hw_to_ccu_div(hw); 37 38 return ccu_gate_helper_disable(&cd->common, cd->enable); 39} 40 41static int ccu_div_enable(struct clk_hw *hw) 42{ 43 struct ccu_div *cd = hw_to_ccu_div(hw); 44 45 return ccu_gate_helper_enable(&cd->common, cd->enable); 46} 47 48static int ccu_div_is_enabled(struct clk_hw *hw) 49{ 50 struct ccu_div *cd = hw_to_ccu_div(hw); 51 52 return ccu_gate_helper_is_enabled(&cd->common, cd->enable); 53} 54 55static unsigned long ccu_div_recalc_rate(struct clk_hw *hw, 56 unsigned long parent_rate) 57{ 58 struct ccu_div *cd = hw_to_ccu_div(hw); 59 unsigned long val; 60 u32 reg; 61 62 reg = readl(cd->common.base + cd->common.reg); 63 val = reg >> cd->div.shift; 64 val &= (1 << cd->div.width) - 1; 65 66 parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1, 67 parent_rate); 68 69 val = divider_recalc_rate(hw, parent_rate, val, cd->div.table, 70 cd->div.flags, cd->div.width); 71 72 if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) 73 val /= cd->fixed_post_div; 74 75 return val; 76} 77 78static int ccu_div_determine_rate(struct clk_hw *hw, 79 struct clk_rate_request *req) 80{ 81 struct ccu_div *cd = hw_to_ccu_div(hw); 82 83 return ccu_mux_helper_determine_rate(&cd->common, &cd->mux, 84 req, ccu_div_determine_rate_helper, cd); 85} 86 87static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate, 88 unsigned long parent_rate) 89{ 90 struct ccu_div *cd = hw_to_ccu_div(hw); 91 unsigned long flags; 92 unsigned long val; 93 u32 reg; 94 95 parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1, 96 parent_rate); 97 98 if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) 99 rate *= cd->fixed_post_div; 100 101 val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width, 102 cd->div.flags); 103 104 spin_lock_irqsave(cd->common.lock, flags); 105 106 reg = readl(cd->common.base + cd->common.reg); 107 reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift); 108 if (cd->common.features & CCU_FEATURE_UPDATE_BIT) 109 reg |= CCU_SUNXI_UPDATE_BIT; 110 111 writel(reg | (val << cd->div.shift), 112 cd->common.base + cd->common.reg); 113 114 spin_unlock_irqrestore(cd->common.lock, flags); 115 116 return 0; 117} 118 119static u8 ccu_div_get_parent(struct clk_hw *hw) 120{ 121 struct ccu_div *cd = hw_to_ccu_div(hw); 122 123 return ccu_mux_helper_get_parent(&cd->common, &cd->mux); 124} 125 126static int ccu_div_set_parent(struct clk_hw *hw, u8 index) 127{ 128 struct ccu_div *cd = hw_to_ccu_div(hw); 129 130 return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index); 131} 132 133const struct clk_ops ccu_div_ops = { 134 .disable = ccu_div_disable, 135 .enable = ccu_div_enable, 136 .is_enabled = ccu_div_is_enabled, 137 138 .get_parent = ccu_div_get_parent, 139 .set_parent = ccu_div_set_parent, 140 141 .determine_rate = ccu_div_determine_rate, 142 .recalc_rate = ccu_div_recalc_rate, 143 .set_rate = ccu_div_set_rate, 144}; 145EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");