136 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Spreadtrum gate clock driver4//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 else26 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 register42 * common->reg + offset - set register43 * common->reg + 2 * offset - clear register44 */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);136