9
0
Fork 0

clk: imx: Add clk-cpu support

Taken from the kernel as of 4.10-rc3. Needed for i.MX7

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2017-01-12 09:49:17 +01:00
parent 0ada0c03af
commit 9a89ed9d28
3 changed files with 114 additions and 0 deletions

View File

@ -5,6 +5,7 @@ obj-$(CONFIG_COMMON_CLK) += \
clk-pfd.o \
clk-gate2.o \
clk-gate-exclusive.o \
clk-cpu.o \
clk.o
obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o

110
drivers/clk/imx/clk-cpu.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
*
* 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.
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <common.h>
#include <init.h>
#include <driver.h>
#include <linux/clk.h>
#include <io.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <malloc.h>
#include <clock.h>
#include "clk.h"
struct clk_cpu {
struct clk clk;
struct clk *div;
struct clk *mux;
struct clk *pll;
struct clk *step;
};
static inline struct clk_cpu *to_clk_cpu(struct clk *clk)
{
return container_of(clk, struct clk_cpu, clk);
}
static unsigned long clk_cpu_recalc_rate(struct clk *clk,
unsigned long parent_rate)
{
struct clk_cpu *cpu = to_clk_cpu(clk);
return clk_get_rate(cpu->div);
}
static long clk_cpu_round_rate(struct clk *clk, unsigned long rate,
unsigned long *prate)
{
struct clk_cpu *cpu = to_clk_cpu(clk);
return clk_round_rate(cpu->pll, rate);
}
static int clk_cpu_set_rate(struct clk *clk, unsigned long rate,
unsigned long parent_rate)
{
struct clk_cpu *cpu = to_clk_cpu(clk);
int ret;
/* switch to PLL bypass clock */
ret = clk_set_parent(cpu->mux, cpu->step);
if (ret)
return ret;
/* reprogram PLL */
ret = clk_set_rate(cpu->pll, rate);
if (ret) {
clk_set_parent(cpu->mux, cpu->pll);
return ret;
}
/* switch back to PLL clock */
clk_set_parent(cpu->mux, cpu->pll);
/* Ensure the divider is what we expect */
clk_set_rate(cpu->div, rate);
return 0;
}
static const struct clk_ops clk_cpu_ops = {
.recalc_rate = clk_cpu_recalc_rate,
.round_rate = clk_cpu_round_rate,
.set_rate = clk_cpu_set_rate,
};
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step)
{
struct clk_cpu *cpu;
int ret;
cpu = xzalloc(sizeof(*cpu));
cpu->div = div;
cpu->mux = mux;
cpu->pll = pll;
cpu->step = step;
cpu->clk.name = name;
cpu->clk.ops = &clk_cpu_ops;
cpu->clk.flags = 0;
cpu->clk.parent_names = &parent_name;
cpu->clk.num_parents = 1;
ret = clk_register(&cpu->clk);
if (ret)
free(cpu);
return &cpu->clk;
}

View File

@ -125,5 +125,8 @@ struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
void imx_check_clocks(struct clk *clks[], unsigned int count);
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
#endif /* __IMX_CLK_H */