mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: - Improvements to the tlb_dump code - KVM fixes - Add support for appended DTB - Minor improvements to the R12000 support - Minor improvements to the R12000 support - Various platform improvments for BCM47xx - The usual pile of minor cleanups - A number of BPF fixes and improvments - Some improvments to the support for R3000 and DECstations - Some improvments to the ATH79 platform support - A major patchset for the JZ4740 SOC adding support for the CI20 platform - Add support for the Pistachio SOC - Minor BMIPS/BCM63xx platform support improvments. - Avoid "SYNC 0" as memory barrier when unlocking spinlocks - Add support for the XWR-1750 board. - Paul's __cpuinit/__cpuinitdata cleanups. - New Malta CPU board support large memory so enable ZONE_DMA32. * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (131 commits) MIPS: spinlock: Adjust arch_spin_lock back-off time MIPS: asmmacro: Ensure 64-bit FP registers are used with MSA MIPS: BCM47xx: Simplify handling SPROM revisions MIPS: Cobalt Don't use module_init in non-modular MTD registration. MIPS: BCM47xx: Move NVRAM driver to the drivers/firmware/ MIPS: use for_each_sg() MIPS: BCM47xx: Don't select BCMA_HOST_PCI MIPS: BCM47xx: Add helper variable for storing NVRAM length MIPS: IRQ/IP27: Move IRQ allocation API to platform code. MIPS: Replace smp_mb with release barrier function in unlocks. MIPS: i8259: DT support MIPS: Malta: Basic DT plumbing MIPS: include errno.h for ENODEV in mips-cm.h MIPS: Define GCR_GIC_STATUS register fields MIPS: BPF: Introduce BPF ASM helpers MIPS: BPF: Use BPF register names to describe the ABI MIPS: BPF: Move register definition to the BPF header MIPS: net: BPF: Replace RSIZE with SZREG MIPS: BPF: Free up some callee-saved registers MIPS: Xtalk: Update xwidget.h with known Xtalk device numbers ...
This commit is contained in:
commit
78c10e556e
281 changed files with 6271 additions and 2321 deletions
|
|
@ -24,7 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
|
|||
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
|
||||
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
|
||||
obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o
|
||||
|
|
@ -51,6 +51,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
|
|||
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
|
||||
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
|
||||
obj-$(CONFIG_ARCH_MXC) += imx/
|
||||
obj-$(CONFIG_MACH_INGENIC) += ingenic/
|
||||
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
|
||||
ifeq ($(CONFIG_COMMON_CLK), y)
|
||||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
|
|
|
|||
3
drivers/clk/ingenic/Makefile
Normal file
3
drivers/clk/ingenic/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
obj-y += cgu.o
|
||||
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
|
||||
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
|
||||
711
drivers/clk/ingenic/cgu.c
Normal file
711
drivers/clk/ingenic/cgu.c
Normal file
|
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
* Ingenic SoC CGU driver
|
||||
*
|
||||
* Copyright (c) 2013-2015 Imagination Technologies
|
||||
* Author: Paul Burton <paul.burton@imgtec.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.
|
||||
*
|
||||
* 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/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "cgu.h"
|
||||
|
||||
#define MHZ (1000 * 1000)
|
||||
|
||||
/**
|
||||
* ingenic_cgu_gate_get() - get the value of clock gate register bit
|
||||
* @cgu: reference to the CGU whose registers should be read
|
||||
* @info: info struct describing the gate bit
|
||||
*
|
||||
* Retrieves the state of the clock gate bit described by info. The
|
||||
* caller must hold cgu->lock.
|
||||
*
|
||||
* Return: true if the gate bit is set, else false.
|
||||
*/
|
||||
static inline bool
|
||||
ingenic_cgu_gate_get(struct ingenic_cgu *cgu,
|
||||
const struct ingenic_cgu_gate_info *info)
|
||||
{
|
||||
return readl(cgu->base + info->reg) & BIT(info->bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* ingenic_cgu_gate_set() - set the value of clock gate register bit
|
||||
* @cgu: reference to the CGU whose registers should be modified
|
||||
* @info: info struct describing the gate bit
|
||||
* @val: non-zero to gate a clock, otherwise zero
|
||||
*
|
||||
* Sets the given gate bit in order to gate or ungate a clock.
|
||||
*
|
||||
* The caller must hold cgu->lock.
|
||||
*/
|
||||
static inline void
|
||||
ingenic_cgu_gate_set(struct ingenic_cgu *cgu,
|
||||
const struct ingenic_cgu_gate_info *info, bool val)
|
||||
{
|
||||
u32 clkgr = readl(cgu->base + info->reg);
|
||||
|
||||
if (val)
|
||||
clkgr |= BIT(info->bit);
|
||||
else
|
||||
clkgr &= ~BIT(info->bit);
|
||||
|
||||
writel(clkgr, cgu->base + info->reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* PLL operations
|
||||
*/
|
||||
|
||||
static unsigned long
|
||||
ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
const struct ingenic_cgu_pll_info *pll_info;
|
||||
unsigned m, n, od_enc, od;
|
||||
bool bypass, enable;
|
||||
unsigned long flags;
|
||||
u32 ctl;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
BUG_ON(clk_info->type != CGU_CLK_PLL);
|
||||
pll_info = &clk_info->pll;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ctl = readl(cgu->base + pll_info->reg);
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
|
||||
m = (ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0);
|
||||
m += pll_info->m_offset;
|
||||
n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0);
|
||||
n += pll_info->n_offset;
|
||||
od_enc = ctl >> pll_info->od_shift;
|
||||
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
|
||||
bypass = !!(ctl & BIT(pll_info->bypass_bit));
|
||||
enable = !!(ctl & BIT(pll_info->enable_bit));
|
||||
|
||||
if (bypass)
|
||||
return parent_rate;
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
for (od = 0; od < pll_info->od_max; od++) {
|
||||
if (pll_info->od_encoding[od] == od_enc)
|
||||
break;
|
||||
}
|
||||
BUG_ON(od == pll_info->od_max);
|
||||
od++;
|
||||
|
||||
return div_u64((u64)parent_rate * m, n * od);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
|
||||
unsigned long rate, unsigned long parent_rate,
|
||||
unsigned *pm, unsigned *pn, unsigned *pod)
|
||||
{
|
||||
const struct ingenic_cgu_pll_info *pll_info;
|
||||
unsigned m, n, od;
|
||||
|
||||
pll_info = &clk_info->pll;
|
||||
od = 1;
|
||||
|
||||
/*
|
||||
* The frequency after the input divider must be between 10 and 50 MHz.
|
||||
* The highest divider yields the best resolution.
|
||||
*/
|
||||
n = parent_rate / (10 * MHZ);
|
||||
n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
|
||||
n = max_t(unsigned, n, pll_info->n_offset);
|
||||
|
||||
m = (rate / MHZ) * od * n / (parent_rate / MHZ);
|
||||
m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
|
||||
m = max_t(unsigned, m, pll_info->m_offset);
|
||||
|
||||
if (pm)
|
||||
*pm = m;
|
||||
if (pn)
|
||||
*pn = n;
|
||||
if (pod)
|
||||
*pod = od;
|
||||
|
||||
return div_u64((u64)parent_rate * m, n * od);
|
||||
}
|
||||
|
||||
static long
|
||||
ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
BUG_ON(clk_info->type != CGU_CLK_PLL);
|
||||
|
||||
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
const unsigned timeout = 100;
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
const struct ingenic_cgu_pll_info *pll_info;
|
||||
unsigned long rate, flags;
|
||||
unsigned m, n, od, i;
|
||||
u32 ctl;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
BUG_ON(clk_info->type != CGU_CLK_PLL);
|
||||
pll_info = &clk_info->pll;
|
||||
|
||||
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
|
||||
&m, &n, &od);
|
||||
if (rate != req_rate)
|
||||
pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n",
|
||||
clk_info->name, req_rate, rate);
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ctl = readl(cgu->base + pll_info->reg);
|
||||
|
||||
ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift);
|
||||
ctl |= (m - pll_info->m_offset) << pll_info->m_shift;
|
||||
|
||||
ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
|
||||
ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
|
||||
|
||||
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
|
||||
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
|
||||
|
||||
ctl &= ~BIT(pll_info->bypass_bit);
|
||||
ctl |= BIT(pll_info->enable_bit);
|
||||
|
||||
writel(ctl, cgu->base + pll_info->reg);
|
||||
|
||||
/* wait for the PLL to stabilise */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
ctl = readl(cgu->base + pll_info->reg);
|
||||
if (ctl & BIT(pll_info->stable_bit))
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
|
||||
if (i == timeout)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops ingenic_pll_ops = {
|
||||
.recalc_rate = ingenic_pll_recalc_rate,
|
||||
.round_rate = ingenic_pll_round_rate,
|
||||
.set_rate = ingenic_pll_set_rate,
|
||||
};
|
||||
|
||||
/*
|
||||
* Operations for all non-PLL clocks
|
||||
*/
|
||||
|
||||
static u8 ingenic_clk_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
u32 reg;
|
||||
u8 i, hw_idx, idx = 0;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_MUX) {
|
||||
reg = readl(cgu->base + clk_info->mux.reg);
|
||||
hw_idx = (reg >> clk_info->mux.shift) &
|
||||
GENMASK(clk_info->mux.bits - 1, 0);
|
||||
|
||||
/*
|
||||
* Convert the hardware index to the parent index by skipping
|
||||
* over any -1's in the parents array.
|
||||
*/
|
||||
for (i = 0; i < hw_idx; i++) {
|
||||
if (clk_info->parents[i] != -1)
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int ingenic_clk_set_parent(struct clk_hw *hw, u8 idx)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
unsigned long flags;
|
||||
u8 curr_idx, hw_idx, num_poss;
|
||||
u32 reg, mask;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_MUX) {
|
||||
/*
|
||||
* Convert the parent index to the hardware index by adding
|
||||
* 1 for any -1 in the parents array preceding the given
|
||||
* index. That is, we want the index of idx'th entry in
|
||||
* clk_info->parents which does not equal -1.
|
||||
*/
|
||||
hw_idx = curr_idx = 0;
|
||||
num_poss = 1 << clk_info->mux.bits;
|
||||
for (; hw_idx < num_poss; hw_idx++) {
|
||||
if (clk_info->parents[hw_idx] == -1)
|
||||
continue;
|
||||
if (curr_idx == idx)
|
||||
break;
|
||||
curr_idx++;
|
||||
}
|
||||
|
||||
/* idx should always be a valid parent */
|
||||
BUG_ON(curr_idx != idx);
|
||||
|
||||
mask = GENMASK(clk_info->mux.bits - 1, 0);
|
||||
mask <<= clk_info->mux.shift;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
|
||||
/* write the register */
|
||||
reg = readl(cgu->base + clk_info->mux.reg);
|
||||
reg &= ~mask;
|
||||
reg |= hw_idx << clk_info->mux.shift;
|
||||
writel(reg, cgu->base + clk_info->mux.reg);
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return idx ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
unsigned long rate = parent_rate;
|
||||
u32 div_reg, div;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_DIV) {
|
||||
div_reg = readl(cgu->base + clk_info->div.reg);
|
||||
div = (div_reg >> clk_info->div.shift) &
|
||||
GENMASK(clk_info->div.bits - 1, 0);
|
||||
div += 1;
|
||||
|
||||
rate /= div;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
|
||||
unsigned long parent_rate, unsigned long req_rate)
|
||||
{
|
||||
unsigned div;
|
||||
|
||||
/* calculate the divide */
|
||||
div = DIV_ROUND_UP(parent_rate, req_rate);
|
||||
|
||||
/* and impose hardware constraints */
|
||||
div = min_t(unsigned, div, 1 << clk_info->div.bits);
|
||||
div = max_t(unsigned, div, 1);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
static long
|
||||
ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
long rate = *parent_rate;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_DIV)
|
||||
rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
|
||||
else if (clk_info->type & CGU_CLK_FIXDIV)
|
||||
rate /= clk_info->fixdiv.div;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int
|
||||
ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
const unsigned timeout = 100;
|
||||
unsigned long rate, flags;
|
||||
unsigned div, i;
|
||||
u32 reg, mask;
|
||||
int ret = 0;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_DIV) {
|
||||
div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
|
||||
rate = parent_rate / div;
|
||||
|
||||
if (rate != req_rate)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
reg = readl(cgu->base + clk_info->div.reg);
|
||||
|
||||
/* update the divide */
|
||||
mask = GENMASK(clk_info->div.bits - 1, 0);
|
||||
reg &= ~(mask << clk_info->div.shift);
|
||||
reg |= (div - 1) << clk_info->div.shift;
|
||||
|
||||
/* clear the stop bit */
|
||||
if (clk_info->div.stop_bit != -1)
|
||||
reg &= ~BIT(clk_info->div.stop_bit);
|
||||
|
||||
/* set the change enable bit */
|
||||
if (clk_info->div.ce_bit != -1)
|
||||
reg |= BIT(clk_info->div.ce_bit);
|
||||
|
||||
/* update the hardware */
|
||||
writel(reg, cgu->base + clk_info->div.reg);
|
||||
|
||||
/* wait for the change to take effect */
|
||||
if (clk_info->div.busy_bit != -1) {
|
||||
for (i = 0; i < timeout; i++) {
|
||||
reg = readl(cgu->base + clk_info->div.reg);
|
||||
if (!(reg & BIT(clk_info->div.busy_bit)))
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
if (i == timeout)
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ingenic_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
unsigned long flags;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_GATE) {
|
||||
/* ungate the clock */
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ingenic_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
unsigned long flags;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_GATE) {
|
||||
/* gate the clock */
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ingenic_cgu_gate_set(cgu, &clk_info->gate, true);
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static int ingenic_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_clk_info *clk_info;
|
||||
unsigned long flags;
|
||||
int enabled = 1;
|
||||
|
||||
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
||||
|
||||
if (clk_info->type & CGU_CLK_GATE) {
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
enabled = !ingenic_cgu_gate_get(cgu, &clk_info->gate);
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static const struct clk_ops ingenic_clk_ops = {
|
||||
.get_parent = ingenic_clk_get_parent,
|
||||
.set_parent = ingenic_clk_set_parent,
|
||||
|
||||
.recalc_rate = ingenic_clk_recalc_rate,
|
||||
.round_rate = ingenic_clk_round_rate,
|
||||
.set_rate = ingenic_clk_set_rate,
|
||||
|
||||
.enable = ingenic_clk_enable,
|
||||
.disable = ingenic_clk_disable,
|
||||
.is_enabled = ingenic_clk_is_enabled,
|
||||
};
|
||||
|
||||
/*
|
||||
* Setup functions.
|
||||
*/
|
||||
|
||||
static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
|
||||
{
|
||||
const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx];
|
||||
struct clk_init_data clk_init;
|
||||
struct ingenic_clk *ingenic_clk = NULL;
|
||||
struct clk *clk, *parent;
|
||||
const char *parent_names[4];
|
||||
unsigned caps, i, num_possible;
|
||||
int err = -EINVAL;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names));
|
||||
|
||||
if (clk_info->type == CGU_CLK_EXT) {
|
||||
clk = of_clk_get_by_name(cgu->np, clk_info->name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: no external clock '%s' provided\n",
|
||||
__func__, clk_info->name);
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
err = clk_register_clkdev(clk, clk_info->name, NULL);
|
||||
if (err) {
|
||||
clk_put(clk);
|
||||
goto out;
|
||||
}
|
||||
cgu->clocks.clks[idx] = clk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!clk_info->type) {
|
||||
pr_err("%s: no clock type specified for '%s'\n", __func__,
|
||||
clk_info->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ingenic_clk = kzalloc(sizeof(*ingenic_clk), GFP_KERNEL);
|
||||
if (!ingenic_clk) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ingenic_clk->hw.init = &clk_init;
|
||||
ingenic_clk->cgu = cgu;
|
||||
ingenic_clk->idx = idx;
|
||||
|
||||
clk_init.name = clk_info->name;
|
||||
clk_init.flags = 0;
|
||||
clk_init.parent_names = parent_names;
|
||||
|
||||
caps = clk_info->type;
|
||||
|
||||
if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) {
|
||||
clk_init.num_parents = 0;
|
||||
|
||||
if (caps & CGU_CLK_MUX)
|
||||
num_possible = 1 << clk_info->mux.bits;
|
||||
else
|
||||
num_possible = ARRAY_SIZE(clk_info->parents);
|
||||
|
||||
for (i = 0; i < num_possible; i++) {
|
||||
if (clk_info->parents[i] == -1)
|
||||
continue;
|
||||
|
||||
parent = cgu->clocks.clks[clk_info->parents[i]];
|
||||
parent_names[clk_init.num_parents] =
|
||||
__clk_get_name(parent);
|
||||
clk_init.num_parents++;
|
||||
}
|
||||
|
||||
BUG_ON(!clk_init.num_parents);
|
||||
BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names));
|
||||
} else {
|
||||
BUG_ON(clk_info->parents[0] == -1);
|
||||
clk_init.num_parents = 1;
|
||||
parent = cgu->clocks.clks[clk_info->parents[0]];
|
||||
parent_names[0] = __clk_get_name(parent);
|
||||
}
|
||||
|
||||
if (caps & CGU_CLK_CUSTOM) {
|
||||
clk_init.ops = clk_info->custom.clk_ops;
|
||||
|
||||
caps &= ~CGU_CLK_CUSTOM;
|
||||
|
||||
if (caps) {
|
||||
pr_err("%s: custom clock may not be combined with type 0x%x\n",
|
||||
__func__, caps);
|
||||
goto out;
|
||||
}
|
||||
} else if (caps & CGU_CLK_PLL) {
|
||||
clk_init.ops = &ingenic_pll_ops;
|
||||
|
||||
caps &= ~CGU_CLK_PLL;
|
||||
|
||||
if (caps) {
|
||||
pr_err("%s: PLL may not be combined with type 0x%x\n",
|
||||
__func__, caps);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
clk_init.ops = &ingenic_clk_ops;
|
||||
}
|
||||
|
||||
/* nothing to do for gates or fixed dividers */
|
||||
caps &= ~(CGU_CLK_GATE | CGU_CLK_FIXDIV);
|
||||
|
||||
if (caps & CGU_CLK_MUX) {
|
||||
if (!(caps & CGU_CLK_MUX_GLITCHFREE))
|
||||
clk_init.flags |= CLK_SET_PARENT_GATE;
|
||||
|
||||
caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE);
|
||||
}
|
||||
|
||||
if (caps & CGU_CLK_DIV) {
|
||||
caps &= ~CGU_CLK_DIV;
|
||||
} else {
|
||||
/* pass rate changes to the parent clock */
|
||||
clk_init.flags |= CLK_SET_RATE_PARENT;
|
||||
}
|
||||
|
||||
if (caps) {
|
||||
pr_err("%s: unknown clock type 0x%x\n", __func__, caps);
|
||||
goto out;
|
||||
}
|
||||
|
||||
clk = clk_register(NULL, &ingenic_clk->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock '%s'\n", __func__,
|
||||
clk_info->name);
|
||||
err = PTR_ERR(clk);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = clk_register_clkdev(clk, clk_info->name, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
cgu->clocks.clks[idx] = clk;
|
||||
out:
|
||||
if (err)
|
||||
kfree(ingenic_clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct ingenic_cgu *
|
||||
ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
|
||||
unsigned num_clocks, struct device_node *np)
|
||||
{
|
||||
struct ingenic_cgu *cgu;
|
||||
|
||||
cgu = kzalloc(sizeof(*cgu), GFP_KERNEL);
|
||||
if (!cgu)
|
||||
goto err_out;
|
||||
|
||||
cgu->base = of_iomap(np, 0);
|
||||
if (!cgu->base) {
|
||||
pr_err("%s: failed to map CGU registers\n", __func__);
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
cgu->np = np;
|
||||
cgu->clock_info = clock_info;
|
||||
cgu->clocks.clk_num = num_clocks;
|
||||
|
||||
spin_lock_init(&cgu->lock);
|
||||
|
||||
return cgu;
|
||||
|
||||
err_out_free:
|
||||
kfree(cgu);
|
||||
err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu)
|
||||
{
|
||||
unsigned i;
|
||||
int err;
|
||||
|
||||
cgu->clocks.clks = kcalloc(cgu->clocks.clk_num, sizeof(struct clk *),
|
||||
GFP_KERNEL);
|
||||
if (!cgu->clocks.clks) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < cgu->clocks.clk_num; i++) {
|
||||
err = ingenic_register_clock(cgu, i);
|
||||
if (err)
|
||||
goto err_out_unregister;
|
||||
}
|
||||
|
||||
err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get,
|
||||
&cgu->clocks);
|
||||
if (err)
|
||||
goto err_out_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_unregister:
|
||||
for (i = 0; i < cgu->clocks.clk_num; i++) {
|
||||
if (!cgu->clocks.clks[i])
|
||||
continue;
|
||||
if (cgu->clock_info[i].type & CGU_CLK_EXT)
|
||||
clk_put(cgu->clocks.clks[i]);
|
||||
else
|
||||
clk_unregister(cgu->clocks.clks[i]);
|
||||
}
|
||||
kfree(cgu->clocks.clks);
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
223
drivers/clk/ingenic/cgu.h
Normal file
223
drivers/clk/ingenic/cgu.h
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Ingenic SoC CGU driver
|
||||
*
|
||||
* Copyright (c) 2013-2015 Imagination Technologies
|
||||
* Author: Paul Burton <paul.burton@imgtec.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.
|
||||
*
|
||||
* 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 __DRIVERS_CLK_INGENIC_CGU_H__
|
||||
#define __DRIVERS_CLK_INGENIC_CGU_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_pll_info - information about a PLL
|
||||
* @reg: the offset of the PLL's control register within the CGU
|
||||
* @m_shift: the number of bits to shift the multiplier value by (ie. the
|
||||
* index of the lowest bit of the multiplier value in the PLL's
|
||||
* control register)
|
||||
* @m_bits: the size of the multiplier field in bits
|
||||
* @m_offset: the multiplier value which encodes to 0 in the PLL's control
|
||||
* register
|
||||
* @n_shift: the number of bits to shift the divider value by (ie. the
|
||||
* index of the lowest bit of the divider value in the PLL's
|
||||
* control register)
|
||||
* @n_bits: the size of the divider field in bits
|
||||
* @n_offset: the divider value which encodes to 0 in the PLL's control
|
||||
* register
|
||||
* @od_shift: the number of bits to shift the post-VCO divider value by (ie.
|
||||
* the index of the lowest bit of the post-VCO divider value in
|
||||
* the PLL's control register)
|
||||
* @od_bits: the size of the post-VCO divider field in bits
|
||||
* @od_max: the maximum post-VCO divider value
|
||||
* @od_encoding: a pointer to an array mapping post-VCO divider values to
|
||||
* their encoded values in the PLL control register, or -1 for
|
||||
* unsupported values
|
||||
* @bypass_bit: the index of the bypass bit in the PLL control register
|
||||
* @enable_bit: the index of the enable bit in the PLL control register
|
||||
* @stable_bit: the index of the stable bit in the PLL control register
|
||||
*/
|
||||
struct ingenic_cgu_pll_info {
|
||||
unsigned reg;
|
||||
const s8 *od_encoding;
|
||||
u8 m_shift, m_bits, m_offset;
|
||||
u8 n_shift, n_bits, n_offset;
|
||||
u8 od_shift, od_bits, od_max;
|
||||
u8 bypass_bit;
|
||||
u8 enable_bit;
|
||||
u8 stable_bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_mux_info - information about a clock mux
|
||||
* @reg: offset of the mux control register within the CGU
|
||||
* @shift: number of bits to shift the mux value by (ie. the index of
|
||||
* the lowest bit of the mux value within its control register)
|
||||
* @bits: the size of the mux value in bits
|
||||
*/
|
||||
struct ingenic_cgu_mux_info {
|
||||
unsigned reg;
|
||||
u8 shift;
|
||||
u8 bits;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_div_info - information about a divider
|
||||
* @reg: offset of the divider control register within the CGU
|
||||
* @shift: number of bits to shift the divide value by (ie. the index of
|
||||
* the lowest bit of the divide value within its control register)
|
||||
* @bits: the size of the divide value in bits
|
||||
* @ce_bit: the index of the change enable bit within reg, or -1 if there
|
||||
* isn't one
|
||||
* @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
|
||||
* @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
|
||||
*/
|
||||
struct ingenic_cgu_div_info {
|
||||
unsigned reg;
|
||||
u8 shift;
|
||||
u8 bits;
|
||||
s8 ce_bit;
|
||||
s8 busy_bit;
|
||||
s8 stop_bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_fixdiv_info - information about a fixed divider
|
||||
* @div: the divider applied to the parent clock
|
||||
*/
|
||||
struct ingenic_cgu_fixdiv_info {
|
||||
unsigned div;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_gate_info - information about a clock gate
|
||||
* @reg: offset of the gate control register within the CGU
|
||||
* @bit: offset of the bit in the register that controls the gate
|
||||
*/
|
||||
struct ingenic_cgu_gate_info {
|
||||
unsigned reg;
|
||||
u8 bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_custom_info - information about a custom (SoC) clock
|
||||
* @clk_ops: custom clock operation callbacks
|
||||
*/
|
||||
struct ingenic_cgu_custom_info {
|
||||
struct clk_ops *clk_ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu_clk_info - information about a clock
|
||||
* @name: name of the clock
|
||||
* @type: a bitmask formed from CGU_CLK_* values
|
||||
* @parents: an array of the indices of potential parents of this clock
|
||||
* within the clock_info array of the CGU, or -1 in entries
|
||||
* which correspond to no valid parent
|
||||
* @pll: information valid if type includes CGU_CLK_PLL
|
||||
* @gate: information valid if type includes CGU_CLK_GATE
|
||||
* @mux: information valid if type includes CGU_CLK_MUX
|
||||
* @div: information valid if type includes CGU_CLK_DIV
|
||||
* @fixdiv: information valid if type includes CGU_CLK_FIXDIV
|
||||
* @custom: information valid if type includes CGU_CLK_CUSTOM
|
||||
*/
|
||||
struct ingenic_cgu_clk_info {
|
||||
const char *name;
|
||||
|
||||
enum {
|
||||
CGU_CLK_NONE = 0,
|
||||
CGU_CLK_EXT = BIT(0),
|
||||
CGU_CLK_PLL = BIT(1),
|
||||
CGU_CLK_GATE = BIT(2),
|
||||
CGU_CLK_MUX = BIT(3),
|
||||
CGU_CLK_MUX_GLITCHFREE = BIT(4),
|
||||
CGU_CLK_DIV = BIT(5),
|
||||
CGU_CLK_FIXDIV = BIT(6),
|
||||
CGU_CLK_CUSTOM = BIT(7),
|
||||
} type;
|
||||
|
||||
int parents[4];
|
||||
|
||||
union {
|
||||
struct ingenic_cgu_pll_info pll;
|
||||
|
||||
struct {
|
||||
struct ingenic_cgu_gate_info gate;
|
||||
struct ingenic_cgu_mux_info mux;
|
||||
struct ingenic_cgu_div_info div;
|
||||
struct ingenic_cgu_fixdiv_info fixdiv;
|
||||
};
|
||||
|
||||
struct ingenic_cgu_custom_info custom;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_cgu - data about the CGU
|
||||
* @np: the device tree node that caused the CGU to be probed
|
||||
* @base: the ioremap'ed base address of the CGU registers
|
||||
* @clock_info: an array containing information about implemented clocks
|
||||
* @clocks: used to provide clocks to DT, allows lookup of struct clk*
|
||||
* @lock: lock to be held whilst manipulating CGU registers
|
||||
*/
|
||||
struct ingenic_cgu {
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
|
||||
const struct ingenic_cgu_clk_info *clock_info;
|
||||
struct clk_onecell_data clocks;
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ingenic_clk - private data for a clock
|
||||
* @hw: see Documentation/clk.txt
|
||||
* @cgu: a pointer to the CGU data
|
||||
* @idx: the index of this clock in cgu->clock_info
|
||||
*/
|
||||
struct ingenic_clk {
|
||||
struct clk_hw hw;
|
||||
struct ingenic_cgu *cgu;
|
||||
unsigned idx;
|
||||
};
|
||||
|
||||
#define to_ingenic_clk(_hw) container_of(_hw, struct ingenic_clk, hw)
|
||||
|
||||
/**
|
||||
* ingenic_cgu_new() - create a new CGU instance
|
||||
* @clock_info: an array of clock information structures describing the clocks
|
||||
* which are implemented by the CGU
|
||||
* @num_clocks: the number of entries in clock_info
|
||||
* @np: the device tree node which causes this CGU to be probed
|
||||
*
|
||||
* Return: a pointer to the CGU instance if initialisation is successful,
|
||||
* otherwise NULL.
|
||||
*/
|
||||
struct ingenic_cgu *
|
||||
ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
|
||||
unsigned num_clocks, struct device_node *np);
|
||||
|
||||
/**
|
||||
* ingenic_cgu_register_clocks() - Registers the clocks
|
||||
* @cgu: pointer to cgu data
|
||||
*
|
||||
* Register the clocks described by the CGU with the common clock framework.
|
||||
*
|
||||
* Return: 0 on success or -errno if unsuccesful.
|
||||
*/
|
||||
int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu);
|
||||
|
||||
#endif /* __DRIVERS_CLK_INGENIC_CGU_H__ */
|
||||
303
drivers/clk/ingenic/jz4740-cgu.c
Normal file
303
drivers/clk/ingenic/jz4740-cgu.c
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Ingenic JZ4740 SoC CGU driver
|
||||
*
|
||||
* Copyright (c) 2015 Imagination Technologies
|
||||
* Author: Paul Burton <paul.burton@imgtec.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.
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <dt-bindings/clock/jz4740-cgu.h>
|
||||
#include <asm/mach-jz4740/clock.h>
|
||||
#include "cgu.h"
|
||||
|
||||
/* CGU register offsets */
|
||||
#define CGU_REG_CPCCR 0x00
|
||||
#define CGU_REG_LCR 0x04
|
||||
#define CGU_REG_CPPCR 0x10
|
||||
#define CGU_REG_CLKGR 0x20
|
||||
#define CGU_REG_SCR 0x24
|
||||
#define CGU_REG_I2SCDR 0x60
|
||||
#define CGU_REG_LPCDR 0x64
|
||||
#define CGU_REG_MSCCDR 0x68
|
||||
#define CGU_REG_UHCCDR 0x6c
|
||||
#define CGU_REG_SSICDR 0x74
|
||||
|
||||
/* bits within a PLL control register */
|
||||
#define PLLCTL_M_SHIFT 23
|
||||
#define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT)
|
||||
#define PLLCTL_N_SHIFT 18
|
||||
#define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT)
|
||||
#define PLLCTL_OD_SHIFT 16
|
||||
#define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT)
|
||||
#define PLLCTL_STABLE (1 << 10)
|
||||
#define PLLCTL_BYPASS (1 << 9)
|
||||
#define PLLCTL_ENABLE (1 << 8)
|
||||
|
||||
/* bits within the LCR register */
|
||||
#define LCR_SLEEP (1 << 0)
|
||||
|
||||
/* bits within the CLKGR register */
|
||||
#define CLKGR_UDC (1 << 11)
|
||||
|
||||
static struct ingenic_cgu *cgu;
|
||||
|
||||
static const s8 pll_od_encoding[4] = {
|
||||
0x0, 0x1, -1, 0x3,
|
||||
};
|
||||
|
||||
static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
|
||||
|
||||
/* External clocks */
|
||||
|
||||
[JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
|
||||
[JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
|
||||
|
||||
[JZ4740_CLK_PLL] = {
|
||||
"pll", CGU_CLK_PLL,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.pll = {
|
||||
.reg = CGU_REG_CPPCR,
|
||||
.m_shift = 23,
|
||||
.m_bits = 9,
|
||||
.m_offset = 2,
|
||||
.n_shift = 18,
|
||||
.n_bits = 5,
|
||||
.n_offset = 2,
|
||||
.od_shift = 16,
|
||||
.od_bits = 2,
|
||||
.od_max = 4,
|
||||
.od_encoding = pll_od_encoding,
|
||||
.stable_bit = 10,
|
||||
.bypass_bit = 9,
|
||||
.enable_bit = 8,
|
||||
},
|
||||
},
|
||||
|
||||
/* Muxes & dividers */
|
||||
|
||||
[JZ4740_CLK_PLL_HALF] = {
|
||||
"pll half", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_CCLK] = {
|
||||
"cclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_HCLK] = {
|
||||
"hclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_PCLK] = {
|
||||
"pclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_MCLK] = {
|
||||
"mclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_LCD] = {
|
||||
"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
|
||||
.div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 10 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_LCD_PCLK] = {
|
||||
"lcd_pclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
|
||||
.div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_I2S] = {
|
||||
"i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
|
||||
.mux = { CGU_REG_CPCCR, 31, 1 },
|
||||
.div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 6 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_SPI] = {
|
||||
"spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
|
||||
.mux = { CGU_REG_SSICDR, 31, 1 },
|
||||
.div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 4 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_MMC] = {
|
||||
"mmc", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
|
||||
.div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 7 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_UHC] = {
|
||||
"uhc", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
|
||||
.div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 14 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_UDC] = {
|
||||
"udc", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
|
||||
.mux = { CGU_REG_CPCCR, 29, 1 },
|
||||
.div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
|
||||
.gate = { CGU_REG_SCR, 6 },
|
||||
},
|
||||
|
||||
/* Gate-only clocks */
|
||||
|
||||
[JZ4740_CLK_UART0] = {
|
||||
"uart0", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 0 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_UART1] = {
|
||||
"uart1", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 15 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_DMA] = {
|
||||
"dma", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 12 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_IPU] = {
|
||||
"ipu", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 13 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_ADC] = {
|
||||
"adc", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 8 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_I2C] = {
|
||||
"i2c", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 3 },
|
||||
},
|
||||
|
||||
[JZ4740_CLK_AIC] = {
|
||||
"aic", CGU_CLK_GATE,
|
||||
.parents = { JZ4740_CLK_EXT, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 5 },
|
||||
},
|
||||
};
|
||||
|
||||
static void __init jz4740_cgu_init(struct device_node *np)
|
||||
{
|
||||
int retval;
|
||||
|
||||
cgu = ingenic_cgu_new(jz4740_cgu_clocks,
|
||||
ARRAY_SIZE(jz4740_cgu_clocks), np);
|
||||
if (!cgu) {
|
||||
pr_err("%s: failed to initialise CGU\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
retval = ingenic_cgu_register_clocks(cgu);
|
||||
if (retval)
|
||||
pr_err("%s: failed to register CGU Clocks\n", __func__);
|
||||
}
|
||||
CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
|
||||
|
||||
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
|
||||
{
|
||||
uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
|
||||
|
||||
switch (mode) {
|
||||
case JZ4740_WAIT_MODE_IDLE:
|
||||
lcr &= ~LCR_SLEEP;
|
||||
break;
|
||||
|
||||
case JZ4740_WAIT_MODE_SLEEP:
|
||||
lcr |= LCR_SLEEP;
|
||||
break;
|
||||
}
|
||||
|
||||
writel(lcr, cgu->base + CGU_REG_LCR);
|
||||
}
|
||||
|
||||
void jz4740_clock_udc_disable_auto_suspend(void)
|
||||
{
|
||||
uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
|
||||
|
||||
clkgr &= ~CLKGR_UDC;
|
||||
writel(clkgr, cgu->base + CGU_REG_CLKGR);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
|
||||
|
||||
void jz4740_clock_udc_enable_auto_suspend(void)
|
||||
{
|
||||
uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
|
||||
|
||||
clkgr |= CLKGR_UDC;
|
||||
writel(clkgr, cgu->base + CGU_REG_CLKGR);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
|
||||
|
||||
#define JZ_CLOCK_GATE_UART0 BIT(0)
|
||||
#define JZ_CLOCK_GATE_TCU BIT(1)
|
||||
#define JZ_CLOCK_GATE_DMAC BIT(12)
|
||||
|
||||
void jz4740_clock_suspend(void)
|
||||
{
|
||||
uint32_t clkgr, cppcr;
|
||||
|
||||
clkgr = readl(cgu->base + CGU_REG_CLKGR);
|
||||
clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
|
||||
writel(clkgr, cgu->base + CGU_REG_CLKGR);
|
||||
|
||||
cppcr = readl(cgu->base + CGU_REG_CPPCR);
|
||||
cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
|
||||
writel(cppcr, cgu->base + CGU_REG_CPPCR);
|
||||
}
|
||||
|
||||
void jz4740_clock_resume(void)
|
||||
{
|
||||
uint32_t clkgr, cppcr, stable;
|
||||
|
||||
cppcr = readl(cgu->base + CGU_REG_CPPCR);
|
||||
cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
|
||||
writel(cppcr, cgu->base + CGU_REG_CPPCR);
|
||||
|
||||
stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
|
||||
do {
|
||||
cppcr = readl(cgu->base + CGU_REG_CPPCR);
|
||||
} while (!(cppcr & stable));
|
||||
|
||||
clkgr = readl(cgu->base + CGU_REG_CLKGR);
|
||||
clkgr &= ~JZ_CLOCK_GATE_TCU;
|
||||
clkgr &= ~JZ_CLOCK_GATE_DMAC;
|
||||
clkgr &= ~JZ_CLOCK_GATE_UART0;
|
||||
writel(clkgr, cgu->base + CGU_REG_CLKGR);
|
||||
}
|
||||
733
drivers/clk/ingenic/jz4780-cgu.c
Normal file
733
drivers/clk/ingenic/jz4780-cgu.c
Normal file
|
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
* Ingenic JZ4780 SoC CGU driver
|
||||
*
|
||||
* Copyright (c) 2013-2015 Imagination Technologies
|
||||
* Author: Paul Burton <paul.burton@imgtec.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.
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <dt-bindings/clock/jz4780-cgu.h>
|
||||
#include "cgu.h"
|
||||
|
||||
/* CGU register offsets */
|
||||
#define CGU_REG_CLOCKCONTROL 0x00
|
||||
#define CGU_REG_PLLCONTROL 0x0c
|
||||
#define CGU_REG_APLL 0x10
|
||||
#define CGU_REG_MPLL 0x14
|
||||
#define CGU_REG_EPLL 0x18
|
||||
#define CGU_REG_VPLL 0x1c
|
||||
#define CGU_REG_CLKGR0 0x20
|
||||
#define CGU_REG_OPCR 0x24
|
||||
#define CGU_REG_CLKGR1 0x28
|
||||
#define CGU_REG_DDRCDR 0x2c
|
||||
#define CGU_REG_VPUCDR 0x30
|
||||
#define CGU_REG_USBPCR 0x3c
|
||||
#define CGU_REG_USBRDT 0x40
|
||||
#define CGU_REG_USBVBFIL 0x44
|
||||
#define CGU_REG_USBPCR1 0x48
|
||||
#define CGU_REG_LP0CDR 0x54
|
||||
#define CGU_REG_I2SCDR 0x60
|
||||
#define CGU_REG_LP1CDR 0x64
|
||||
#define CGU_REG_MSC0CDR 0x68
|
||||
#define CGU_REG_UHCCDR 0x6c
|
||||
#define CGU_REG_SSICDR 0x74
|
||||
#define CGU_REG_CIMCDR 0x7c
|
||||
#define CGU_REG_PCMCDR 0x84
|
||||
#define CGU_REG_GPUCDR 0x88
|
||||
#define CGU_REG_HDMICDR 0x8c
|
||||
#define CGU_REG_MSC1CDR 0xa4
|
||||
#define CGU_REG_MSC2CDR 0xa8
|
||||
#define CGU_REG_BCHCDR 0xac
|
||||
#define CGU_REG_CLOCKSTATUS 0xd4
|
||||
|
||||
/* bits within the OPCR register */
|
||||
#define OPCR_SPENDN0 (1 << 7)
|
||||
#define OPCR_SPENDN1 (1 << 6)
|
||||
|
||||
/* bits within the USBPCR register */
|
||||
#define USBPCR_USB_MODE BIT(31)
|
||||
#define USBPCR_IDPULLUP_MASK (0x3 << 28)
|
||||
#define USBPCR_COMMONONN BIT(25)
|
||||
#define USBPCR_VBUSVLDEXT BIT(24)
|
||||
#define USBPCR_VBUSVLDEXTSEL BIT(23)
|
||||
#define USBPCR_POR BIT(22)
|
||||
#define USBPCR_OTG_DISABLE BIT(20)
|
||||
#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
|
||||
#define USBPCR_OTGTUNE_MASK (0x7 << 14)
|
||||
#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
|
||||
#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
|
||||
#define USBPCR_TXPREEMPHTUNE BIT(6)
|
||||
#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
|
||||
#define USBPCR_TXVREFTUNE_MASK 0xf
|
||||
|
||||
/* bits within the USBPCR1 register */
|
||||
#define USBPCR1_REFCLKSEL_SHIFT 26
|
||||
#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
|
||||
#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
|
||||
#define USBPCR1_REFCLKDIV_SHIFT 24
|
||||
#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
|
||||
#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
|
||||
#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
|
||||
#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
|
||||
#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
|
||||
#define USBPCR1_USB_SEL BIT(28)
|
||||
#define USBPCR1_WORD_IF0 BIT(19)
|
||||
#define USBPCR1_WORD_IF1 BIT(18)
|
||||
|
||||
/* bits within the USBRDT register */
|
||||
#define USBRDT_VBFIL_LD_EN BIT(25)
|
||||
#define USBRDT_USBRDT_MASK 0x7fffff
|
||||
|
||||
/* bits within the USBVBFIL register */
|
||||
#define USBVBFIL_IDDIGFIL_SHIFT 16
|
||||
#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
|
||||
#define USBVBFIL_USBVBFIL_MASK (0xffff)
|
||||
|
||||
static struct ingenic_cgu *cgu;
|
||||
|
||||
static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
/* we only use CLKCORE, revisit if that ever changes */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 usbpcr1;
|
||||
|
||||
if (idx > 0)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
|
||||
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
|
||||
usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
|
||||
/* we only use CLKCORE */
|
||||
usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
|
||||
writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 usbpcr1;
|
||||
unsigned refclk_div;
|
||||
|
||||
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
|
||||
refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
|
||||
|
||||
switch (refclk_div) {
|
||||
case USBPCR1_REFCLKDIV_12:
|
||||
return 12000000;
|
||||
|
||||
case USBPCR1_REFCLKDIV_24:
|
||||
return 24000000;
|
||||
|
||||
case USBPCR1_REFCLKDIV_48:
|
||||
return 48000000;
|
||||
|
||||
case USBPCR1_REFCLKDIV_19_2:
|
||||
return 19200000;
|
||||
}
|
||||
|
||||
BUG();
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
if (req_rate < 15600000)
|
||||
return 12000000;
|
||||
|
||||
if (req_rate < 21600000)
|
||||
return 19200000;
|
||||
|
||||
if (req_rate < 36000000)
|
||||
return 24000000;
|
||||
|
||||
return 48000000;
|
||||
}
|
||||
|
||||
static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 usbpcr1, div_bits;
|
||||
|
||||
switch (req_rate) {
|
||||
case 12000000:
|
||||
div_bits = USBPCR1_REFCLKDIV_12;
|
||||
break;
|
||||
|
||||
case 19200000:
|
||||
div_bits = USBPCR1_REFCLKDIV_19_2;
|
||||
break;
|
||||
|
||||
case 24000000:
|
||||
div_bits = USBPCR1_REFCLKDIV_24;
|
||||
break;
|
||||
|
||||
case 48000000:
|
||||
div_bits = USBPCR1_REFCLKDIV_48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
|
||||
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
|
||||
usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
|
||||
usbpcr1 |= div_bits;
|
||||
writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops jz4780_otg_phy_ops = {
|
||||
.get_parent = jz4780_otg_phy_get_parent,
|
||||
.set_parent = jz4780_otg_phy_set_parent,
|
||||
|
||||
.recalc_rate = jz4780_otg_phy_recalc_rate,
|
||||
.round_rate = jz4780_otg_phy_round_rate,
|
||||
.set_rate = jz4780_otg_phy_set_rate,
|
||||
};
|
||||
|
||||
static const s8 pll_od_encoding[16] = {
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
||||
};
|
||||
|
||||
static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
|
||||
|
||||
/* External clocks */
|
||||
|
||||
[JZ4780_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
|
||||
[JZ4780_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
|
||||
|
||||
/* PLLs */
|
||||
|
||||
#define DEF_PLL(name) { \
|
||||
.reg = CGU_REG_ ## name, \
|
||||
.m_shift = 19, \
|
||||
.m_bits = 13, \
|
||||
.m_offset = 1, \
|
||||
.n_shift = 13, \
|
||||
.n_bits = 6, \
|
||||
.n_offset = 1, \
|
||||
.od_shift = 9, \
|
||||
.od_bits = 4, \
|
||||
.od_max = 16, \
|
||||
.od_encoding = pll_od_encoding, \
|
||||
.stable_bit = 6, \
|
||||
.bypass_bit = 1, \
|
||||
.enable_bit = 0, \
|
||||
}
|
||||
|
||||
[JZ4780_CLK_APLL] = {
|
||||
"apll", CGU_CLK_PLL,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.pll = DEF_PLL(APLL),
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MPLL] = {
|
||||
"mpll", CGU_CLK_PLL,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.pll = DEF_PLL(MPLL),
|
||||
},
|
||||
|
||||
[JZ4780_CLK_EPLL] = {
|
||||
"epll", CGU_CLK_PLL,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.pll = DEF_PLL(EPLL),
|
||||
},
|
||||
|
||||
[JZ4780_CLK_VPLL] = {
|
||||
"vpll", CGU_CLK_PLL,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.pll = DEF_PLL(VPLL),
|
||||
},
|
||||
|
||||
#undef DEF_PLL
|
||||
|
||||
/* Custom (SoC-specific) OTG PHY */
|
||||
|
||||
[JZ4780_CLK_OTGPHY] = {
|
||||
"otg_phy", CGU_CLK_CUSTOM,
|
||||
.parents = { -1, -1, JZ4780_CLK_EXCLK, -1 },
|
||||
.custom = { &jz4780_otg_phy_ops },
|
||||
},
|
||||
|
||||
/* Muxes & dividers */
|
||||
|
||||
[JZ4780_CLK_SCLKA] = {
|
||||
"sclk_a", CGU_CLK_MUX,
|
||||
.parents = { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK,
|
||||
JZ4780_CLK_RTCLK },
|
||||
.mux = { CGU_REG_CLOCKCONTROL, 30, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_CPUMUX] = {
|
||||
"cpumux", CGU_CLK_MUX,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL },
|
||||
.mux = { CGU_REG_CLOCKCONTROL, 28, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_CPU] = {
|
||||
"cpu", CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_L2CACHE] = {
|
||||
"l2cache", CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AHB0] = {
|
||||
"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL },
|
||||
.mux = { CGU_REG_CLOCKCONTROL, 26, 2 },
|
||||
.div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AHB2PMUX] = {
|
||||
"ahb2_apb_mux", CGU_CLK_MUX,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_RTCLK },
|
||||
.mux = { CGU_REG_CLOCKCONTROL, 24, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AHB2] = {
|
||||
"ahb2", CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_PCLK] = {
|
||||
"pclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_DDR] = {
|
||||
"ddr", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
|
||||
.mux = { CGU_REG_DDRCDR, 30, 2 },
|
||||
.div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_VPU] = {
|
||||
"vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL, -1 },
|
||||
.mux = { CGU_REG_VPUCDR, 30, 2 },
|
||||
.div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR1, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_I2SPLL] = {
|
||||
"i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 },
|
||||
.mux = { CGU_REG_I2SCDR, 30, 1 },
|
||||
.div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_I2S] = {
|
||||
"i2s", CGU_CLK_MUX,
|
||||
.parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1, -1 },
|
||||
.mux = { CGU_REG_I2SCDR, 31, 1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_LCD0PIXCLK] = {
|
||||
"lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_VPLL, -1 },
|
||||
.mux = { CGU_REG_LP0CDR, 30, 2 },
|
||||
.div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_LCD1PIXCLK] = {
|
||||
"lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_VPLL, -1 },
|
||||
.mux = { CGU_REG_LP1CDR, 30, 2 },
|
||||
.div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MSCMUX] = {
|
||||
"msc_mux", CGU_CLK_MUX,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
|
||||
.mux = { CGU_REG_MSC0CDR, 30, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MSC0] = {
|
||||
"msc0", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR0, 3 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MSC1] = {
|
||||
"msc1", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR0, 11 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MSC2] = {
|
||||
"msc2", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
|
||||
.div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR0, 12 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UHC] = {
|
||||
"uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY },
|
||||
.mux = { CGU_REG_UHCCDR, 30, 2 },
|
||||
.div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR0, 24 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SSIPLL] = {
|
||||
"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
|
||||
.mux = { CGU_REG_SSICDR, 30, 1 },
|
||||
.div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SSI] = {
|
||||
"ssi", CGU_CLK_MUX,
|
||||
.parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1, -1 },
|
||||
.mux = { CGU_REG_SSICDR, 31, 1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_CIMMCLK] = {
|
||||
"cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
|
||||
.mux = { CGU_REG_CIMCDR, 31, 1 },
|
||||
.div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_PCMPLL] = {
|
||||
"pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL, JZ4780_CLK_VPLL },
|
||||
.mux = { CGU_REG_PCMCDR, 29, 2 },
|
||||
.div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_PCM] = {
|
||||
"pcm", CGU_CLK_MUX | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1, -1 },
|
||||
.mux = { CGU_REG_PCMCDR, 31, 1 },
|
||||
.gate = { CGU_REG_CLKGR1, 3 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_GPU] = {
|
||||
"gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL },
|
||||
.mux = { CGU_REG_GPUCDR, 30, 2 },
|
||||
.div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR1, 4 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_HDMI] = {
|
||||
"hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_VPLL, -1 },
|
||||
.mux = { CGU_REG_HDMICDR, 30, 2 },
|
||||
.div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 },
|
||||
.gate = { CGU_REG_CLKGR1, 9 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_BCH] = {
|
||||
"bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
|
||||
JZ4780_CLK_EPLL },
|
||||
.mux = { CGU_REG_BCHCDR, 30, 2 },
|
||||
.div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR0, 1 },
|
||||
},
|
||||
|
||||
/* Gate-only clocks */
|
||||
|
||||
[JZ4780_CLK_NEMC] = {
|
||||
"nemc", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_AHB2, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 0 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_OTG0] = {
|
||||
"otg0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 2 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SSI0] = {
|
||||
"ssi0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SSI, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 4 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SMB0] = {
|
||||
"smb0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 5 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SMB1] = {
|
||||
"smb1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 6 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SCC] = {
|
||||
"scc", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 7 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AIC] = {
|
||||
"aic", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 8 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_TSSI0] = {
|
||||
"tssi0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 9 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_OWI] = {
|
||||
"owi", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 10 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_KBC] = {
|
||||
"kbc", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 13 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SADC] = {
|
||||
"sadc", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 14 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UART0] = {
|
||||
"uart0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 15 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UART1] = {
|
||||
"uart1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 16 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UART2] = {
|
||||
"uart2", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 17 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UART3] = {
|
||||
"uart3", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 18 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SSI1] = {
|
||||
"ssi1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SSI, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 19 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SSI2] = {
|
||||
"ssi2", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_SSI, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 20 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_PDMA] = {
|
||||
"pdma", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 21 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_GPS] = {
|
||||
"gps", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 22 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_MAC] = {
|
||||
"mac", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 23 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SMB2] = {
|
||||
"smb2", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 24 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_CIM] = {
|
||||
"cim", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 26 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_LCD] = {
|
||||
"lcd", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 28 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_TVE] = {
|
||||
"tve", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_LCD, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 27 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_IPU] = {
|
||||
"ipu", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 29 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_DDR0] = {
|
||||
"ddr0", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_DDR, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 30 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_DDR1] = {
|
||||
"ddr1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_DDR, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR0, 31 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SMB3] = {
|
||||
"smb3", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 0 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_TSSI1] = {
|
||||
"tssi1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 1 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_COMPRESS] = {
|
||||
"compress", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 5 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AIC1] = {
|
||||
"aic1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 6 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_GPVLC] = {
|
||||
"gpvlc", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 7 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_OTG1] = {
|
||||
"otg1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 8 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_UART4] = {
|
||||
"uart4", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 10 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_AHBMON] = {
|
||||
"ahb_mon", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 11 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_SMB4] = {
|
||||
"smb4", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 12 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_DES] = {
|
||||
"des", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 13 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_X2D] = {
|
||||
"x2d", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 14 },
|
||||
},
|
||||
|
||||
[JZ4780_CLK_CORE1] = {
|
||||
"core1", CGU_CLK_GATE,
|
||||
.parents = { JZ4780_CLK_CPU, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR1, 15 },
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static void __init jz4780_cgu_init(struct device_node *np)
|
||||
{
|
||||
int retval;
|
||||
|
||||
cgu = ingenic_cgu_new(jz4780_cgu_clocks,
|
||||
ARRAY_SIZE(jz4780_cgu_clocks), np);
|
||||
if (!cgu) {
|
||||
pr_err("%s: failed to initialise CGU\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
retval = ingenic_cgu_register_clocks(cgu);
|
||||
if (retval) {
|
||||
pr_err("%s: failed to register CGU Clocks\n", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
|
||||
Loading…
Reference in a new issue