2019-06-24 13:50:45 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 DENX Software Engineering
|
|
|
|
* Lukasz Majewski, DENX Software Engineering, lukma@denx.de
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
|
|
|
|
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* Gated clock implementation
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <clk-uclass.h>
|
|
|
|
#include <dm/device.h>
|
2020-02-03 14:36:15 +00:00
|
|
|
#include <dm/devres.h>
|
2019-06-24 13:50:45 +00:00
|
|
|
#include <linux/clk-provider.h>
|
|
|
|
#include <clk.h>
|
|
|
|
#include "clk.h"
|
2020-02-03 14:36:15 +00:00
|
|
|
#include <linux/err.h>
|
2019-06-24 13:50:45 +00:00
|
|
|
|
|
|
|
#define UBOOT_DM_CLK_IMX_GATE2 "imx_clk_gate2"
|
|
|
|
|
|
|
|
struct clk_gate2 {
|
|
|
|
struct clk clk;
|
|
|
|
void __iomem *reg;
|
|
|
|
u8 bit_idx;
|
|
|
|
u8 cgr_val;
|
|
|
|
u8 flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
|
|
|
|
|
|
|
|
static int clk_gate2_enable(struct clk *clk)
|
|
|
|
{
|
|
|
|
struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
|
|
|
|
u32 reg;
|
|
|
|
|
|
|
|
reg = readl(gate->reg);
|
|
|
|
reg &= ~(3 << gate->bit_idx);
|
|
|
|
reg |= gate->cgr_val << gate->bit_idx;
|
|
|
|
writel(reg, gate->reg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int clk_gate2_disable(struct clk *clk)
|
|
|
|
{
|
|
|
|
struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
|
|
|
|
u32 reg;
|
|
|
|
|
|
|
|
reg = readl(gate->reg);
|
|
|
|
reg &= ~(3 << gate->bit_idx);
|
|
|
|
writel(reg, gate->reg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-31 07:01:45 +00:00
|
|
|
static ulong clk_gate2_set_rate(struct clk *clk, ulong rate)
|
|
|
|
{
|
|
|
|
struct clk *parent = clk_get_parent(clk);
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
return clk_set_rate(parent, rate);
|
|
|
|
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2019-06-24 13:50:45 +00:00
|
|
|
static const struct clk_ops clk_gate2_ops = {
|
2019-07-31 07:01:45 +00:00
|
|
|
.set_rate = clk_gate2_set_rate,
|
2019-06-24 13:50:45 +00:00
|
|
|
.enable = clk_gate2_enable,
|
|
|
|
.disable = clk_gate2_disable,
|
|
|
|
.get_rate = clk_generic_get_rate,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct clk *clk_register_gate2(struct device *dev, const char *name,
|
|
|
|
const char *parent_name, unsigned long flags,
|
|
|
|
void __iomem *reg, u8 bit_idx, u8 cgr_val,
|
|
|
|
u8 clk_gate2_flags)
|
|
|
|
{
|
|
|
|
struct clk_gate2 *gate;
|
|
|
|
struct clk *clk;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
|
|
|
if (!gate)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
gate->reg = reg;
|
|
|
|
gate->bit_idx = bit_idx;
|
|
|
|
gate->cgr_val = cgr_val;
|
|
|
|
gate->flags = clk_gate2_flags;
|
|
|
|
|
|
|
|
clk = &gate->clk;
|
|
|
|
|
|
|
|
ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name, parent_name);
|
|
|
|
if (ret) {
|
|
|
|
kfree(gate);
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
return clk;
|
|
|
|
}
|
|
|
|
|
|
|
|
U_BOOT_DRIVER(clk_gate2) = {
|
|
|
|
.name = UBOOT_DM_CLK_IMX_GATE2,
|
|
|
|
.id = UCLASS_CLK,
|
|
|
|
.ops = &clk_gate2_ops,
|
|
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
|
|
};
|