Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Spreadtrum gate clock driver
  4//
  5// Copyright (C) 2017 Spreadtrum, Inc.
  6// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
  7
  8#include <linux/clk-provider.h>
  9#include <linux/regmap.h>
 10
 11#include "gate.h"
 12
 13static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
 14{
 15	const struct sprd_clk_common *common = &sg->common;
 16	unsigned int reg;
 17	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;
 18
 19	set ^= en;
 20
 21	regmap_read(common->regmap, common->reg, &reg);
 22
 23	if (set)
 24		reg |= sg->enable_mask;
 25	else
 26		reg &= ~sg->enable_mask;
 27
 28	regmap_write(common->regmap, common->reg, reg);
 29}
 30
 31static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
 32{
 33	const struct sprd_clk_common *common = &sg->common;
 34	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
 35	unsigned int offset;
 36
 37	set ^= en;
 38
 39	/*
 40	 * Each set/clear gate clock has three registers:
 41	 * common->reg			- base register
 42	 * common->reg + offset		- set register
 43	 * common->reg + 2 * offset	- clear register
 44	 */
 45	offset = set ? sg->sc_offset : sg->sc_offset * 2;
 46
 47	regmap_write(common->regmap, common->reg + offset,
 48			  sg->enable_mask);
 49}
 50
 51static void sprd_gate_disable(struct clk_hw *hw)
 52{
 53	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 54
 55	clk_gate_toggle(sg, false);
 56}
 57
 58static int sprd_gate_enable(struct clk_hw *hw)
 59{
 60	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 61
 62	clk_gate_toggle(sg, true);
 63
 64	return 0;
 65}
 66
 67static void sprd_sc_gate_disable(struct clk_hw *hw)
 68{
 69	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 70
 71	clk_sc_gate_toggle(sg, false);
 72}
 73
 74static int sprd_sc_gate_enable(struct clk_hw *hw)
 75{
 76	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 77
 78	clk_sc_gate_toggle(sg, true);
 79
 80	return 0;
 81}
 82
 83static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
 84{
 85	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 86
 87	clk_sc_gate_toggle(sg, true);
 88	udelay(sg->udelay);
 89
 90	return 0;
 91}
 92
 93static int sprd_gate_is_enabled(struct clk_hw *hw)
 94{
 95	struct sprd_gate *sg = hw_to_sprd_gate(hw);
 96	struct sprd_clk_common *common = &sg->common;
 97	struct clk_hw *parent;
 98	unsigned int reg;
 99
100	if (sg->flags & SPRD_GATE_NON_AON) {
101		parent = clk_hw_get_parent(hw);
102		if (!parent || !clk_hw_is_enabled(parent))
103			return 0;
104	}
105
106	regmap_read(common->regmap, common->reg, &reg);
107
108	if (sg->flags & CLK_GATE_SET_TO_DISABLE)
109		reg ^= sg->enable_mask;
110
111	reg &= sg->enable_mask;
112
113	return reg ? 1 : 0;
114}
115
116const struct clk_ops sprd_gate_ops = {
117	.disable	= sprd_gate_disable,
118	.enable		= sprd_gate_enable,
119	.is_enabled	= sprd_gate_is_enabled,
120};
121EXPORT_SYMBOL_GPL(sprd_gate_ops);
122
123const struct clk_ops sprd_sc_gate_ops = {
124	.disable	= sprd_sc_gate_disable,
125	.enable		= sprd_sc_gate_enable,
126	.is_enabled	= sprd_gate_is_enabled,
127};
128EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
129
130const struct clk_ops sprd_pll_sc_gate_ops = {
131	.unprepare	= sprd_sc_gate_disable,
132	.prepare	= sprd_pll_sc_gate_prepare,
133	.is_enabled	= sprd_gate_is_enabled,
134};
135EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);