clk: add support for Rockchip gate clocks

This adds basic support for gate-clocks on Rockchip SoCs.
There are 16 gates in each register and use the HIWORD_MASK
mechanism for changing gate settings.

The gate registers form a continuos block which makes the dt node
structure a matter of taste, as either all 160 gates can be put into
one gate clock spanning all registers or they can be divided into
the 10 individual gates containing 16 clocks each.
The code supports both approaches.

Signed-off-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mike Turquette <[email protected]>
This commit is contained in:
Heiko Stübner 2013-06-13 16:59:40 +02:00 • committed by Mike Turquette
commit 646572c77d
4 changed files with 174 additions and 0 deletions

View file

@ -25,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o

View file

@ -0,0 +1,5 @@
#
# Rockchip Clock specific Makefile
#
obj-y += clk-rockchip.o

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* 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.
*
* 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.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
static DEFINE_SPINLOCK(clk_lock);
/*
* Gate clocks
*/
static void __init rk2928_gate_clk_init(struct device_node *node,
void *data)
{
struct clk_onecell_data *clk_data;
const char *clk_parent;
const char *clk_name;
void __iomem *reg;
void __iomem *reg_idx;
int flags;
int qty;
int reg_bit;
int clkflags = CLK_SET_RATE_PARENT;
int i;
qty = of_property_count_strings(node, "clock-output-names");
if (qty < 0) {
pr_err("%s: error in clock-output-names %d\n", __func__, qty);
return;
}
if (qty == 0) {
pr_info("%s: nothing to do\n", __func__);
return;
}
reg = of_iomap(node, 0);
clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
if (!clk_data)
return;
clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
if (!clk_data->clks) {
kfree(clk_data);
return;
}
flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
for (i = 0; i < qty; i++) {
of_property_read_string_index(node, "clock-output-names",
i, &clk_name);
/* ignore empty slots */
if (!strcmp("reserved", clk_name))
continue;
clk_parent = of_clk_get_parent_name(node, i);
/* keep all gates untouched for now */
clkflags |= CLK_IGNORE_UNUSED;
reg_idx = reg + (4 * (i / 16));
reg_bit = (i % 16);
clk_data->clks[i] = clk_register_gate(NULL, clk_name,
clk_parent, clkflags,
reg_idx, reg_bit,
flags,
&clk_lock);
WARN_ON(IS_ERR(clk_data->clks[i]));
}
clk_data->clk_num = qty;
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init);