gate.c (2935B)
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, ®); 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, ®); 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);