Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cdb09f67 authored by Chunyan Zhang's avatar Chunyan Zhang Committed by Stephen Boyd
Browse files

clk: sprd: add gate clock support



Some clocks on the Spreadtrum's SoCs are just simple gates. Add
support for those clocks.

Signed-off-by: default avatarChunyan Zhang <chunyan.zhang@spreadtrum.com>
Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
parent d41f59fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_SPRD_COMMON_CLK)	+= clk-sprd.o

clk-sprd-y	+= common.o
clk-sprd-y	+= gate.o
+111 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
//
// Spreadtrum gate clock driver
//
// Copyright (C) 2017 Spreadtrum, Inc.
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>

#include <linux/clk-provider.h>
#include <linux/regmap.h>

#include "gate.h"

static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
{
	const struct sprd_clk_common *common = &sg->common;
	unsigned int reg;
	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;

	set ^= en;

	regmap_read(common->regmap, common->reg, &reg);

	if (set)
		reg |= sg->enable_mask;
	else
		reg &= ~sg->enable_mask;

	regmap_write(common->regmap, common->reg, reg);
}

static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
{
	const struct sprd_clk_common *common = &sg->common;
	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
	unsigned int offset;

	set ^= en;

	/*
	 * Each set/clear gate clock has three registers:
	 * common->reg			- base register
	 * common->reg + offset		- set register
	 * common->reg + 2 * offset	- clear register
	 */
	offset = set ? sg->sc_offset : sg->sc_offset * 2;

	regmap_write(common->regmap, common->reg + offset,
			  sg->enable_mask);
}

static void sprd_gate_disable(struct clk_hw *hw)
{
	struct sprd_gate *sg = hw_to_sprd_gate(hw);

	clk_gate_toggle(sg, false);
}

static int sprd_gate_enable(struct clk_hw *hw)
{
	struct sprd_gate *sg = hw_to_sprd_gate(hw);

	clk_gate_toggle(sg, true);

	return 0;
}

static void sprd_sc_gate_disable(struct clk_hw *hw)
{
	struct sprd_gate *sg = hw_to_sprd_gate(hw);

	clk_sc_gate_toggle(sg, false);
}

static int sprd_sc_gate_enable(struct clk_hw *hw)
{
	struct sprd_gate *sg = hw_to_sprd_gate(hw);

	clk_sc_gate_toggle(sg, true);

	return 0;
}
static int sprd_gate_is_enabled(struct clk_hw *hw)
{
	struct sprd_gate *sg = hw_to_sprd_gate(hw);
	struct sprd_clk_common *common = &sg->common;
	unsigned int reg;

	regmap_read(common->regmap, common->reg, &reg);

	if (sg->flags & CLK_GATE_SET_TO_DISABLE)
		reg ^= sg->enable_mask;

	reg &= sg->enable_mask;

	return reg ? 1 : 0;
}

const struct clk_ops sprd_gate_ops = {
	.disable	= sprd_gate_disable,
	.enable		= sprd_gate_enable,
	.is_enabled	= sprd_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(sprd_gate_ops);

const struct clk_ops sprd_sc_gate_ops = {
	.disable	= sprd_sc_gate_disable,
	.enable		= sprd_sc_gate_enable,
	.is_enabled	= sprd_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
+59 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
//
// Spreadtrum gate clock driver
//
// Copyright (C) 2017 Spreadtrum, Inc.
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>

#ifndef _SPRD_GATE_H_
#define _SPRD_GATE_H_

#include "common.h"

struct sprd_gate {
	u32			enable_mask;
	u16			flags;
	u16			sc_offset;

	struct sprd_clk_common	common;
};

#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset,	\
			     _enable_mask, _flags, _gate_flags, _ops)	\
	struct sprd_gate _struct = {					\
		.enable_mask	= _enable_mask,				\
		.sc_offset	= _sc_offset,				\
		.flags		= _gate_flags,				\
		.common	= {						\
			.regmap		= NULL,				\
			.reg		= _reg,				\
			.hw.init	= CLK_HW_INIT(_name,		\
						      _parent,		\
						      _ops,		\
						      _flags),		\
		}							\
	}

#define SPRD_GATE_CLK(_struct, _name, _parent, _reg,			\
		      _enable_mask, _flags, _gate_flags)		\
	SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0,		\
			     _enable_mask, _flags, _gate_flags,		\
			     &sprd_gate_ops)

#define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset,	\
			 _enable_mask, _flags, _gate_flags)		\
	SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset,	\
			     _enable_mask, _flags, _gate_flags,		\
			     &sprd_sc_gate_ops)

static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw)
{
	struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);

	return container_of(common, struct sprd_gate, common);
}

extern const struct clk_ops sprd_gate_ops;
extern const struct clk_ops sprd_sc_gate_ops;

#endif /* _SPRD_GATE_H_ */