xref: /kernel/linux/linux-5.10/drivers/clk/sprd/mux.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Spreadtrum multiplexer clock driver
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (C) 2017 Spreadtrum, Inc.
68c2ecf20Sopenharmony_ci// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
108c2ecf20Sopenharmony_ci#include <linux/regmap.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "mux.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciu8 sprd_mux_helper_get_parent(const struct sprd_clk_common *common,
158c2ecf20Sopenharmony_ci			      const struct sprd_mux_ssel *mux)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	unsigned int reg;
188c2ecf20Sopenharmony_ci	u8 parent;
198c2ecf20Sopenharmony_ci	int num_parents;
208c2ecf20Sopenharmony_ci	int i;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	regmap_read(common->regmap, common->reg, &reg);
238c2ecf20Sopenharmony_ci	parent = reg >> mux->shift;
248c2ecf20Sopenharmony_ci	parent &= (1 << mux->width) - 1;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (!mux->table)
278c2ecf20Sopenharmony_ci		return parent;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	num_parents = clk_hw_get_num_parents(&common->hw);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents - 1; i++)
328c2ecf20Sopenharmony_ci		if (parent >= mux->table[i] && parent < mux->table[i + 1])
338c2ecf20Sopenharmony_ci			return i;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return num_parents - 1;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_mux_helper_get_parent);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic u8 sprd_mux_get_parent(struct clk_hw *hw)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct sprd_mux *cm = hw_to_sprd_mux(hw);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return sprd_mux_helper_get_parent(&cm->common, &cm->mux);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciint sprd_mux_helper_set_parent(const struct sprd_clk_common *common,
478c2ecf20Sopenharmony_ci			       const struct sprd_mux_ssel *mux,
488c2ecf20Sopenharmony_ci			       u8 index)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned int reg;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (mux->table)
538c2ecf20Sopenharmony_ci		index = mux->table[index];
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	regmap_read(common->regmap, common->reg, &reg);
568c2ecf20Sopenharmony_ci	reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
578c2ecf20Sopenharmony_ci	regmap_write(common->regmap, common->reg,
588c2ecf20Sopenharmony_ci			  reg | (index << mux->shift));
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return 0;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_mux_helper_set_parent);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int sprd_mux_set_parent(struct clk_hw *hw, u8 index)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct sprd_mux *cm = hw_to_sprd_mux(hw);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return sprd_mux_helper_set_parent(&cm->common, &cm->mux, index);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciconst struct clk_ops sprd_mux_ops = {
728c2ecf20Sopenharmony_ci	.get_parent = sprd_mux_get_parent,
738c2ecf20Sopenharmony_ci	.set_parent = sprd_mux_set_parent,
748c2ecf20Sopenharmony_ci	.determine_rate = __clk_mux_determine_rate,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_mux_ops);
77