Skip to content

Commit

Permalink
clk: sunxi-ng: Add gate clock support
Browse files Browse the repository at this point in the history
Some clocks in the Allwinner SoCs clocks unit are just simple gates. Add
support for those clocks.

Since it's a feature that can also be found in more complex clocks, provide
a bunch of helpers that can be reused later on.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
Link: lkml.kernel.org/r/20160629190535.11855-5-maxime.ripard@free-electrons.com
  • Loading branch information
Maxime Ripard authored and Michael Turquette committed Jul 9, 2016
1 parent 89a3dfb commit 1a7e7c3
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/clk/sunxi-ng/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ if SUNXI_CCU
config SUNXI_CCU_FRAC
bool

config SUNXI_CCU_GATE
bool

endif
1 change: 1 addition & 0 deletions drivers/clk/sunxi-ng/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ obj-$(CONFIG_SUNXI_CCU) += ccu_reset.o

# Base clock types
obj-$(CONFIG_SUNXI_CCU_FRAC) += ccu_frac.o
obj-$(CONFIG_SUNXI_CCU_GATE) += ccu_gate.o
82 changes: 82 additions & 0 deletions drivers/clk/sunxi-ng/ccu_gate.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*/

#include <linux/clk-provider.h>

#include "ccu_gate.h"

void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
{
unsigned long flags;
u32 reg;

if (!gate)
return;

spin_lock_irqsave(common->lock, flags);

reg = readl(common->base + common->reg);
writel(reg & ~gate, common->base + common->reg);

spin_unlock_irqrestore(common->lock, flags);
}

static void ccu_gate_disable(struct clk_hw *hw)
{
struct ccu_gate *cg = hw_to_ccu_gate(hw);

return ccu_gate_helper_disable(&cg->common, cg->enable);
}

int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
{
unsigned long flags;
u32 reg;

if (!gate)
return 0;

spin_lock_irqsave(common->lock, flags);

reg = readl(common->base + common->reg);
writel(reg | gate, common->base + common->reg);

spin_unlock_irqrestore(common->lock, flags);

return 0;
}

static int ccu_gate_enable(struct clk_hw *hw)
{
struct ccu_gate *cg = hw_to_ccu_gate(hw);

return ccu_gate_helper_enable(&cg->common, cg->enable);
}

int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
{
if (!gate)
return 1;

return readl(common->base + common->reg) & gate;
}

static int ccu_gate_is_enabled(struct clk_hw *hw)
{
struct ccu_gate *cg = hw_to_ccu_gate(hw);

return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
}

const struct clk_ops ccu_gate_ops = {
.disable = ccu_gate_disable,
.enable = ccu_gate_enable,
.is_enabled = ccu_gate_is_enabled,
};
52 changes: 52 additions & 0 deletions drivers/clk/sunxi-ng/ccu_gate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef _CCU_GATE_H_
#define _CCU_GATE_H_

#include <linux/clk-provider.h>

#include "ccu_common.h"

struct ccu_gate {
u32 enable;

struct ccu_common common;
};

#define SUNXI_CCU_GATE(_struct, _name, _parent, _reg, _gate, _flags) \
struct ccu_gate _struct = { \
.enable = _gate, \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_gate_ops, \
_flags), \
} \
}

static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
{
struct ccu_common *common = hw_to_ccu_common(hw);

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

void ccu_gate_helper_disable(struct ccu_common *common, u32 gate);
int ccu_gate_helper_enable(struct ccu_common *common, u32 gate);
int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate);

extern const struct clk_ops ccu_gate_ops;

#endif /* _CCU_GATE_H_ */

0 comments on commit 1a7e7c3

Please sign in to comment.