brintos

brintos / linux-shallow public Read only

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