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 v4.17-rc4 175 lines 4.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2018 BayLibre, SAS. 3// Author: Jerome Brunet <jbrunet@baylibre.com> 4 5#include "clk-regmap.h" 6 7static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) 8{ 9 struct clk_regmap *clk = to_clk_regmap(hw); 10 struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); 11 int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; 12 13 set ^= enable; 14 15 return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx), 16 set ? BIT(gate->bit_idx) : 0); 17} 18 19static int clk_regmap_gate_enable(struct clk_hw *hw) 20{ 21 return clk_regmap_gate_endisable(hw, 1); 22} 23 24static void clk_regmap_gate_disable(struct clk_hw *hw) 25{ 26 clk_regmap_gate_endisable(hw, 0); 27} 28 29static int clk_regmap_gate_is_enabled(struct clk_hw *hw) 30{ 31 struct clk_regmap *clk = to_clk_regmap(hw); 32 struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); 33 unsigned int val; 34 35 regmap_read(clk->map, gate->offset, &val); 36 if (gate->flags & CLK_GATE_SET_TO_DISABLE) 37 val ^= BIT(gate->bit_idx); 38 39 val &= BIT(gate->bit_idx); 40 41 return val ? 1 : 0; 42} 43 44const struct clk_ops clk_regmap_gate_ops = { 45 .enable = clk_regmap_gate_enable, 46 .disable = clk_regmap_gate_disable, 47 .is_enabled = clk_regmap_gate_is_enabled, 48}; 49EXPORT_SYMBOL_GPL(clk_regmap_gate_ops); 50 51static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, 52 unsigned long prate) 53{ 54 struct clk_regmap *clk = to_clk_regmap(hw); 55 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); 56 unsigned int val; 57 int ret; 58 59 ret = regmap_read(clk->map, div->offset, &val); 60 if (ret) 61 /* Gives a hint that something is wrong */ 62 return 0; 63 64 val >>= div->shift; 65 val &= clk_div_mask(div->width); 66 return divider_recalc_rate(hw, prate, val, div->table, div->flags, 67 div->width); 68} 69 70static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate, 71 unsigned long *prate) 72{ 73 struct clk_regmap *clk = to_clk_regmap(hw); 74 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); 75 unsigned int val; 76 int ret; 77 78 /* if read only, just return current value */ 79 if (div->flags & CLK_DIVIDER_READ_ONLY) { 80 ret = regmap_read(clk->map, div->offset, &val); 81 if (ret) 82 /* Gives a hint that something is wrong */ 83 return 0; 84 85 val >>= div->shift; 86 val &= clk_div_mask(div->width); 87 88 return divider_ro_round_rate(hw, rate, prate, div->table, 89 div->width, div->flags, val); 90 } 91 92 return divider_round_rate(hw, rate, prate, div->table, div->width, 93 div->flags); 94} 95 96static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, 97 unsigned long parent_rate) 98{ 99 struct clk_regmap *clk = to_clk_regmap(hw); 100 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); 101 unsigned int val; 102 int ret; 103 104 ret = divider_get_val(rate, parent_rate, div->table, div->width, 105 div->flags); 106 if (ret < 0) 107 return ret; 108 109 val = (unsigned int)ret << div->shift; 110 return regmap_update_bits(clk->map, div->offset, 111 clk_div_mask(div->width) << div->shift, val); 112}; 113 114/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ 115 116const struct clk_ops clk_regmap_divider_ops = { 117 .recalc_rate = clk_regmap_div_recalc_rate, 118 .round_rate = clk_regmap_div_round_rate, 119 .set_rate = clk_regmap_div_set_rate, 120}; 121EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); 122 123const struct clk_ops clk_regmap_divider_ro_ops = { 124 .recalc_rate = clk_regmap_div_recalc_rate, 125 .round_rate = clk_regmap_div_round_rate, 126}; 127EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); 128 129static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) 130{ 131 struct clk_regmap *clk = to_clk_regmap(hw); 132 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); 133 unsigned int val; 134 int ret; 135 136 ret = regmap_read(clk->map, mux->offset, &val); 137 if (ret) 138 return ret; 139 140 val >>= mux->shift; 141 val &= mux->mask; 142 return clk_mux_val_to_index(hw, mux->table, mux->flags, val); 143} 144 145static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) 146{ 147 struct clk_regmap *clk = to_clk_regmap(hw); 148 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); 149 unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index); 150 151 return regmap_update_bits(clk->map, mux->offset, 152 mux->mask << mux->shift, 153 val << mux->shift); 154} 155 156static int clk_regmap_mux_determine_rate(struct clk_hw *hw, 157 struct clk_rate_request *req) 158{ 159 struct clk_regmap *clk = to_clk_regmap(hw); 160 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); 161 162 return clk_mux_determine_rate_flags(hw, req, mux->flags); 163} 164 165const struct clk_ops clk_regmap_mux_ops = { 166 .get_parent = clk_regmap_mux_get_parent, 167 .set_parent = clk_regmap_mux_set_parent, 168 .determine_rate = clk_regmap_mux_determine_rate, 169}; 170EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); 171 172const struct clk_ops clk_regmap_mux_ro_ops = { 173 .get_parent = clk_regmap_mux_get_parent, 174}; 175EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);