File Index
Files and directories
Sign in
FILE

ccu_div.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/sunxi-ng/ccu_div.c C
  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 unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
 14					struct clk_hw *parent,
 15					unsigned long *parent_rate,
 16					unsigned long rate,
 17					void *data)
 18{
 19	struct ccu_div *cd = data;
 20
 21	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
 22		rate *= cd->fixed_post_div;
 23
 24	rate = divider_round_rate_parent(&cd->common.hw, parent,
 25					 rate, parent_rate,
 26					 cd->div.table, cd->div.width,
 27					 cd->div.flags);
 28
 29	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
 30		rate /= cd->fixed_post_div;
 31
 32	return rate;
 33}
 34
 35static void ccu_div_disable(struct clk_hw *hw)
 36{
 37	struct ccu_div *cd = hw_to_ccu_div(hw);
 38
 39	return ccu_gate_helper_disable(&cd->common, cd->enable);
 40}
 41
 42static int ccu_div_enable(struct clk_hw *hw)
 43{
 44	struct ccu_div *cd = hw_to_ccu_div(hw);
 45
 46	return ccu_gate_helper_enable(&cd->common, cd->enable);
 47}
 48
 49static int ccu_div_is_enabled(struct clk_hw *hw)
 50{
 51	struct ccu_div *cd = hw_to_ccu_div(hw);
 52
 53	return ccu_gate_helper_is_enabled(&cd->common, cd->enable);
 54}
 55
 56static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
 57					unsigned long parent_rate)
 58{
 59	struct ccu_div *cd = hw_to_ccu_div(hw);
 60	unsigned long val;
 61	u32 reg;
 62
 63	reg = readl(cd->common.base + cd->common.reg);
 64	val = reg >> cd->div.shift;
 65	val &= (1 << cd->div.width) - 1;
 66
 67	parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
 68						  parent_rate);
 69
 70	val = divider_recalc_rate(hw, parent_rate, val, cd->div.table,
 71				  cd->div.flags, cd->div.width);
 72
 73	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
 74		val /= cd->fixed_post_div;
 75
 76	return val;
 77}
 78
 79static int ccu_div_determine_rate(struct clk_hw *hw,
 80				struct clk_rate_request *req)
 81{
 82	struct ccu_div *cd = hw_to_ccu_div(hw);
 83
 84	return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
 85					     req, ccu_div_round_rate, cd);
 86}
 87
 88static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
 89			   unsigned long parent_rate)
 90{
 91	struct ccu_div *cd = hw_to_ccu_div(hw);
 92	unsigned long flags;
 93	unsigned long val;
 94	u32 reg;
 95
 96	parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
 97						  parent_rate);
 98
 99	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
100		rate *= cd->fixed_post_div;
101
102	val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
103			      cd->div.flags);
104
105	spin_lock_irqsave(cd->common.lock, flags);
106
107	reg = readl(cd->common.base + cd->common.reg);
108	reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
109	if (cd->common.features & CCU_FEATURE_UPDATE_BIT)
110		reg |= CCU_SUNXI_UPDATE_BIT;
111
112	writel(reg | (val << cd->div.shift),
113	       cd->common.base + cd->common.reg);
114
115	spin_unlock_irqrestore(cd->common.lock, flags);
116
117	return 0;
118}
119
120static u8 ccu_div_get_parent(struct clk_hw *hw)
121{
122	struct ccu_div *cd = hw_to_ccu_div(hw);
123
124	return ccu_mux_helper_get_parent(&cd->common, &cd->mux);
125}
126
127static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
128{
129	struct ccu_div *cd = hw_to_ccu_div(hw);
130
131	return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
132}
133
134const struct clk_ops ccu_div_ops = {
135	.disable	= ccu_div_disable,
136	.enable		= ccu_div_enable,
137	.is_enabled	= ccu_div_is_enabled,
138
139	.get_parent	= ccu_div_get_parent,
140	.set_parent	= ccu_div_set_parent,
141
142	.determine_rate	= ccu_div_determine_rate,
143	.recalc_rate	= ccu_div_recalc_rate,
144	.set_rate	= ccu_div_set_rate,
145};
146EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
~/ Read-only file preview.