mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
Merge branches 'clk-x86', 'clk-xilinx', 'clk-cleanup', 'clk-mstar' and 'clk-ingenic' into clk-next
- Make MxL's CGU driver secure compatible - Support for CPU PLL on MStar/SigmaStar SoCs - Ingenic JZ4755 SoC clk support - Support audio clks on X1000 SoCs * clk-x86: clk: mxl: syscon_node_to_regmap() returns error pointers clk: mxl: Fix a clk entry by adding relevant flags clk: mxl: Add option to override gate clks clk: mxl: Remove redundant spinlocks clk: mxl: Switch from direct readl/writel based IO to regmap based IO * clk-xilinx: clk: xilinx: Drop duplicate depends on COMMON_CLK * clk-cleanup: clk: nomadik: correct struct name kernel-doc warning clk: lmk04832: fix kernel-doc warnings clk: lmk04832: drop superfluous #include clk: lmk04832: drop unnecessary semicolons clk: lmk04832: declare variables as const when possible clk: socfpga: Fix memory leak in socfpga_gate_init() clk: st: Fix memory leak in st_of_quadfs_setup() clk: samsung: Fix memory leak in _samsung_clk_register_pll() clk: visconti: Fix memory leak in visconti_register_pll() clk: Remove a useless include clk: samsung: Fix reference to CLK_OF_DECLARE in comment clk: stm32mp1: Staticize ethrx_src clk: keystone: syscon-clk: Use dev_err_probe() helper clk: bulk: Use dev_err_probe() helper in __clk_bulk_get() clk: cdce925: simplify using devm_regulator_get_enable() * clk-mstar: clk: mstar: msc313 cpupll clk driver * clk-ingenic: clk: Add Ingenic JZ4755 CGU driver dt-bindings: clock: Add Ingenic JZ4755 CGU header dt-bindings: ingenic: Add support for the JZ4755 CGU clk: ingenic: Minor cosmetic fixups for X1000 clk: ingenic: Add X1000 audio clocks dt-bindings: ingenic,x1000-cgu: Add audio clocks clk: ingenic: Add .set_rate_hook() for PLL clocks clk: ingenic: Make PLL clock enable_bit and stable_bit optional clk: ingenic: Make PLL clock "od" field optional
This commit is contained in:
commit
a9fc882f57
@ -22,6 +22,7 @@ select:
|
||||
enum:
|
||||
- ingenic,jz4740-cgu
|
||||
- ingenic,jz4725b-cgu
|
||||
- ingenic,jz4755-cgu
|
||||
- ingenic,jz4760-cgu
|
||||
- ingenic,jz4760b-cgu
|
||||
- ingenic,jz4770-cgu
|
||||
@ -51,6 +52,7 @@ properties:
|
||||
- enum:
|
||||
- ingenic,jz4740-cgu
|
||||
- ingenic,jz4725b-cgu
|
||||
- ingenic,jz4755-cgu
|
||||
- ingenic,jz4760-cgu
|
||||
- ingenic,jz4760b-cgu
|
||||
- ingenic,jz4770-cgu
|
||||
|
@ -96,9 +96,9 @@ static int __clk_bulk_get(struct device *dev, int num_clks,
|
||||
if (ret == -ENOENT && optional)
|
||||
continue;
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get clk '%s': %d\n",
|
||||
clks[i].id, ret);
|
||||
dev_err_probe(dev, ret,
|
||||
"Failed to get clk '%s'\n",
|
||||
clks[i].id);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
@ -603,28 +603,15 @@ of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data)
|
||||
return &data->clk[idx].hw;
|
||||
}
|
||||
|
||||
static void cdce925_regulator_disable(void *regulator)
|
||||
{
|
||||
regulator_disable(regulator);
|
||||
}
|
||||
|
||||
static int cdce925_regulator_enable(struct device *dev, const char *name)
|
||||
{
|
||||
struct regulator *regulator;
|
||||
int err;
|
||||
|
||||
regulator = devm_regulator_get(dev, name);
|
||||
if (IS_ERR(regulator))
|
||||
return PTR_ERR(regulator);
|
||||
err = devm_regulator_get_enable(dev, name);
|
||||
if (err)
|
||||
dev_err_probe(dev, err, "Failed to enable %s:\n", name);
|
||||
|
||||
err = regulator_enable(regulator);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to enable %s: %d\n", name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(dev, cdce925_regulator_disable,
|
||||
regulator);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The CDCE925 uses a funky way to read/write registers. Bulk mode is
|
||||
|
@ -12,12 +12,10 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@ -177,14 +175,14 @@ enum lmk04832_device_types {
|
||||
};
|
||||
|
||||
/**
|
||||
* lmk04832_device_info - Holds static device information that is specific to
|
||||
* the chip revision
|
||||
* struct lmk04832_device_info - Holds static device information that is
|
||||
* specific to the chip revision
|
||||
*
|
||||
* pid: Product Identifier
|
||||
* maskrev: IC version identifier
|
||||
* num_channels: Number of available output channels (clkout count)
|
||||
* vco0_range: {min, max} of the VCO0 operating range (in MHz)
|
||||
* vco1_range: {min, max} of the VCO1 operating range (in MHz)
|
||||
* @pid: Product Identifier
|
||||
* @maskrev: IC version identifier
|
||||
* @num_channels: Number of available output channels (clkout count)
|
||||
* @vco0_range: {min, max} of the VCO0 operating range (in MHz)
|
||||
* @vco1_range: {min, max} of the VCO1 operating range (in MHz)
|
||||
*/
|
||||
struct lmk04832_device_info {
|
||||
u16 pid;
|
||||
@ -282,7 +280,7 @@ static bool lmk04832_regmap_rd_regs(struct device *dev, unsigned int reg)
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg)
|
||||
{
|
||||
@ -305,7 +303,7 @@ static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg)
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
.name = "lmk04832",
|
||||
@ -371,7 +369,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
|
||||
unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7};
|
||||
const unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7};
|
||||
unsigned int pll2_n, p, pll2_r;
|
||||
unsigned int pll2_misc;
|
||||
unsigned long vco_rate;
|
||||
@ -403,7 +401,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
|
||||
pll2_misc)) * pll2_n * pll2_p[p] / pll2_r;
|
||||
|
||||
return vco_rate;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* lmk04832_check_vco_ranges - Check requested VCO frequency against VCO ranges
|
||||
@ -414,7 +412,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
|
||||
* The LMK04832 has 2 internal VCO, each with independent operating ranges.
|
||||
* Use the device_info structure to determine which VCO to use based on rate.
|
||||
*
|
||||
* Returns VCO_MUX value or negative errno.
|
||||
* Returns: VCO_MUX value or negative errno.
|
||||
*/
|
||||
static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate)
|
||||
{
|
||||
@ -451,7 +449,7 @@ static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate)
|
||||
*
|
||||
* VCO = OSCin * 2 * PLL2_N * PLL2_P / PLL2_R
|
||||
*
|
||||
* Returns vco rate or negative errno.
|
||||
* Returns: vco rate or negative errno.
|
||||
*/
|
||||
static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate,
|
||||
unsigned int *n, unsigned int *p,
|
||||
@ -509,7 +507,7 @@ static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return -EINVAL;
|
||||
|
||||
return vco_rate;
|
||||
};
|
||||
}
|
||||
|
||||
static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
@ -568,7 +566,7 @@ static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
return regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_2,
|
||||
FIELD_GET(0x0000ff, n));
|
||||
};
|
||||
}
|
||||
|
||||
static const struct clk_ops lmk04832_vco_ops = {
|
||||
.is_enabled = lmk04832_vco_is_enabled,
|
||||
@ -633,7 +631,7 @@ static int lmk04832_register_vco(struct lmk04832 *lmk)
|
||||
|
||||
static int lmk04832_clkout_set_ddly(struct lmk04832 *lmk, int id)
|
||||
{
|
||||
int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0};
|
||||
const int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0};
|
||||
unsigned int sclkx_y_ddly = 10;
|
||||
unsigned int dclkx_y_ddly;
|
||||
unsigned int dclkx_y_div;
|
||||
@ -1063,7 +1061,7 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw,
|
||||
rate = DIV_ROUND_CLOSEST(prate, dclk_div);
|
||||
|
||||
return rate;
|
||||
};
|
||||
}
|
||||
|
||||
static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
@ -1085,7 +1083,7 @@ static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return -EINVAL;
|
||||
|
||||
return dclk_rate;
|
||||
};
|
||||
}
|
||||
|
||||
static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
@ -1147,7 +1145,7 @@ static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
dev_err(lmk->dev, "SYNC sequence failed\n");
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
static const struct clk_ops lmk04832_dclk_ops = {
|
||||
.is_enabled = lmk04832_dclk_is_enabled,
|
||||
@ -1551,6 +1549,7 @@ static void lmk04832_remove(struct spi_device *spi)
|
||||
clk_disable_unprepare(lmk->oscin);
|
||||
of_clk_del_provider(spi->dev.of_node);
|
||||
}
|
||||
|
||||
static const struct spi_device_id lmk04832_id[] = {
|
||||
{ "lmk04832", LMK04832 },
|
||||
{}
|
||||
|
@ -138,7 +138,7 @@ out_put:
|
||||
}
|
||||
|
||||
/**
|
||||
* struct clk_pll1 - Nomadik PLL1 clock
|
||||
* struct clk_pll - Nomadik PLL clock
|
||||
* @hw: corresponding clock hardware entry
|
||||
* @id: PLL instance: 1 or 2
|
||||
*/
|
||||
|
@ -155,7 +155,7 @@ static const char * const eth_src[] = {
|
||||
"pll4_p", "pll3_q"
|
||||
};
|
||||
|
||||
const struct clk_parent_data ethrx_src[] = {
|
||||
static const struct clk_parent_data ethrx_src[] = {
|
||||
{ .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" },
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -15,6 +15,16 @@ config INGENIC_CGU_JZ4740
|
||||
|
||||
If building for a JZ4740 SoC, you want to say Y here.
|
||||
|
||||
config INGENIC_CGU_JZ4755
|
||||
bool "Ingenic JZ4755 CGU driver"
|
||||
default MACH_JZ4755
|
||||
select INGENIC_CGU_COMMON
|
||||
help
|
||||
Support the clocks provided by the CGU hardware on Ingenic JZ4755
|
||||
and compatible SoCs.
|
||||
|
||||
If building for a JZ4755 SoC, you want to say Y here.
|
||||
|
||||
config INGENIC_CGU_JZ4725B
|
||||
bool "Ingenic JZ4725B CGU driver"
|
||||
default MACH_JZ4725B
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o pm.o
|
||||
obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
|
||||
obj-$(CONFIG_INGENIC_CGU_JZ4755) += jz4755-cgu.o
|
||||
obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
|
||||
obj-$(CONFIG_INGENIC_CGU_JZ4760) += jz4760-cgu.o
|
||||
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
|
||||
|
@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
||||
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
||||
const struct ingenic_cgu_pll_info *pll_info;
|
||||
unsigned m, n, od_enc, od;
|
||||
unsigned m, n, od, od_enc = 0;
|
||||
bool bypass;
|
||||
u32 ctl;
|
||||
|
||||
@ -96,8 +96,11 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
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);
|
||||
|
||||
if (pll_info->od_bits > 0) {
|
||||
od_enc = ctl >> pll_info->od_shift;
|
||||
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
|
||||
}
|
||||
|
||||
if (pll_info->bypass_bit >= 0) {
|
||||
ctl = readl(cgu->base + pll_info->bypass_reg);
|
||||
@ -108,11 +111,15 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
for (od = 0; od < pll_info->od_max; od++) {
|
||||
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);
|
||||
|
||||
/* if od_max = 0, od_bits should be 0 and od is fixed to 1. */
|
||||
if (pll_info->od_max == 0)
|
||||
BUG_ON(pll_info->od_bits != 0);
|
||||
else
|
||||
BUG_ON(od == pll_info->od_max);
|
||||
od++;
|
||||
|
||||
return div_u64((u64)parent_rate * m * pll_info->rate_multiplier,
|
||||
@ -182,6 +189,9 @@ static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu,
|
||||
{
|
||||
u32 ctl;
|
||||
|
||||
if (pll_info->stable_bit < 0)
|
||||
return 0;
|
||||
|
||||
return readl_poll_timeout(cgu->base + pll_info->reg, ctl,
|
||||
ctl & BIT(pll_info->stable_bit),
|
||||
0, 100 * USEC_PER_MSEC);
|
||||
@ -215,13 +225,18 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
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;
|
||||
if (pll_info->od_bits > 0) {
|
||||
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
|
||||
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
|
||||
}
|
||||
|
||||
writel(ctl, cgu->base + pll_info->reg);
|
||||
|
||||
if (pll_info->set_rate_hook)
|
||||
pll_info->set_rate_hook(pll_info, rate, parent_rate);
|
||||
|
||||
/* If the PLL is enabled, verify that it's stable */
|
||||
if (ctl & BIT(pll_info->enable_bit))
|
||||
if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit)))
|
||||
ret = ingenic_pll_check_stable(cgu, pll_info);
|
||||
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
@ -239,6 +254,9 @@ static int ingenic_pll_enable(struct clk_hw *hw)
|
||||
int ret;
|
||||
u32 ctl;
|
||||
|
||||
if (pll_info->enable_bit < 0)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
if (pll_info->bypass_bit >= 0) {
|
||||
ctl = readl(cgu->base + pll_info->bypass_reg);
|
||||
@ -269,6 +287,9 @@ static void ingenic_pll_disable(struct clk_hw *hw)
|
||||
unsigned long flags;
|
||||
u32 ctl;
|
||||
|
||||
if (pll_info->enable_bit < 0)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ctl = readl(cgu->base + pll_info->reg);
|
||||
|
||||
@ -286,6 +307,9 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw)
|
||||
const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
|
||||
u32 ctl;
|
||||
|
||||
if (pll_info->enable_bit < 0)
|
||||
return true;
|
||||
|
||||
ctl = readl(cgu->base + pll_info->reg);
|
||||
|
||||
return !!(ctl & BIT(pll_info->enable_bit));
|
||||
|
@ -33,7 +33,8 @@
|
||||
* @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_bits: the size of the post-VCO divider field in bits, or 0 if no
|
||||
* OD field exists (then the OD is fixed to 1)
|
||||
* @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
|
||||
@ -41,8 +42,12 @@
|
||||
* @bypass_reg: the offset of the bypass control register within the CGU
|
||||
* @bypass_bit: the index of the bypass bit in the PLL control register, or
|
||||
* -1 if there is no bypass bit
|
||||
* @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
|
||||
* @enable_bit: the index of the enable bit in the PLL control register, or
|
||||
* -1 if there is no enable bit (ie, the PLL is always on)
|
||||
* @stable_bit: the index of the stable bit in the PLL control register, or
|
||||
* -1 if there is no stable bit
|
||||
* @set_rate_hook: hook called immediately after updating the CGU register,
|
||||
* before releasing the spinlock
|
||||
*/
|
||||
struct ingenic_cgu_pll_info {
|
||||
unsigned reg;
|
||||
@ -53,11 +58,13 @@ struct ingenic_cgu_pll_info {
|
||||
u8 od_shift, od_bits, od_max;
|
||||
unsigned bypass_reg;
|
||||
s8 bypass_bit;
|
||||
u8 enable_bit;
|
||||
u8 stable_bit;
|
||||
s8 enable_bit;
|
||||
s8 stable_bit;
|
||||
void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
|
||||
unsigned long rate, unsigned long parent_rate,
|
||||
unsigned int *m, unsigned int *n, unsigned int *od);
|
||||
void (*set_rate_hook)(const struct ingenic_cgu_pll_info *pll_info,
|
||||
unsigned long rate, unsigned long parent_rate);
|
||||
};
|
||||
|
||||
/**
|
||||
|
346
drivers/clk/ingenic/jz4755-cgu.c
Normal file
346
drivers/clk/ingenic/jz4755-cgu.c
Normal file
@ -0,0 +1,346 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Ingenic JZ4755 SoC CGU driver
|
||||
* Heavily based on JZ4725b CGU driver
|
||||
*
|
||||
* Copyright (C) 2022 Siarhei Volkau
|
||||
* Author: Siarhei Volkau <lis8215@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <dt-bindings/clock/ingenic,jz4755-cgu.h>
|
||||
|
||||
#include "cgu.h"
|
||||
#include "pm.h"
|
||||
|
||||
/* CGU register offsets */
|
||||
#define CGU_REG_CPCCR 0x00
|
||||
#define CGU_REG_CPPCR 0x10
|
||||
#define CGU_REG_CLKGR 0x20
|
||||
#define CGU_REG_OPCR 0x24
|
||||
#define CGU_REG_I2SCDR 0x60
|
||||
#define CGU_REG_LPCDR 0x64
|
||||
#define CGU_REG_MSCCDR 0x68
|
||||
#define CGU_REG_SSICDR 0x74
|
||||
#define CGU_REG_CIMCDR 0x7C
|
||||
|
||||
static struct ingenic_cgu *cgu;
|
||||
|
||||
static const s8 pll_od_encoding[4] = {
|
||||
0x0, 0x1, -1, 0x3,
|
||||
};
|
||||
|
||||
static const u8 jz4755_cgu_cpccr_div_table[] = {
|
||||
1, 2, 3, 4, 6, 8,
|
||||
};
|
||||
|
||||
static const u8 jz4755_cgu_pll_half_div_table[] = {
|
||||
2, 1,
|
||||
};
|
||||
|
||||
static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = {
|
||||
|
||||
/* External clocks */
|
||||
|
||||
[JZ4755_CLK_EXT] = { "ext", CGU_CLK_EXT },
|
||||
[JZ4755_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
|
||||
|
||||
[JZ4755_CLK_PLL] = {
|
||||
"pll", CGU_CLK_PLL,
|
||||
.parents = { JZ4755_CLK_EXT, },
|
||||
.pll = {
|
||||
.reg = CGU_REG_CPPCR,
|
||||
.rate_multiplier = 1,
|
||||
.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_reg = CGU_REG_CPPCR,
|
||||
.bypass_bit = 9,
|
||||
.enable_bit = 8,
|
||||
},
|
||||
},
|
||||
|
||||
/* Muxes & dividers */
|
||||
|
||||
[JZ4755_CLK_PLL_HALF] = {
|
||||
"pll half", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
|
||||
jz4755_cgu_pll_half_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_EXT_HALF] = {
|
||||
"ext half", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_EXT, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0,
|
||||
NULL,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_CCLK] = {
|
||||
"cclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
|
||||
jz4755_cgu_cpccr_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_H0CLK] = {
|
||||
"hclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
|
||||
jz4755_cgu_cpccr_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_PCLK] = {
|
||||
"pclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
|
||||
jz4755_cgu_cpccr_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_MCLK] = {
|
||||
"mclk", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
|
||||
jz4755_cgu_cpccr_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_H1CLK] = {
|
||||
"h1clk", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL, },
|
||||
.div = {
|
||||
CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
|
||||
jz4755_cgu_cpccr_div_table,
|
||||
},
|
||||
},
|
||||
|
||||
[JZ4755_CLK_UDC] = {
|
||||
"udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, },
|
||||
.mux = { CGU_REG_CPCCR, 29, 1 },
|
||||
.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 10 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_LCD] = {
|
||||
"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_PLL_HALF, },
|
||||
.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 9 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_MMC] = {
|
||||
"mmc", CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_PLL_HALF, },
|
||||
.div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_I2S] = {
|
||||
"i2s", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, },
|
||||
.mux = { CGU_REG_CPCCR, 31, 1 },
|
||||
.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_SPI] = {
|
||||
"spi", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_PLL_HALF, },
|
||||
.div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 4 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_TVE] = {
|
||||
"tve", CGU_CLK_MUX | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, },
|
||||
.mux = { CGU_REG_LPCDR, 31, 1 },
|
||||
.gate = { CGU_REG_CLKGR, 18 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_RTC] = {
|
||||
"rtc", CGU_CLK_MUX | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, },
|
||||
.mux = { CGU_REG_OPCR, 2, 1},
|
||||
.gate = { CGU_REG_CLKGR, 2 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_CIM] = {
|
||||
"cim", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_PLL_HALF, },
|
||||
.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 8 },
|
||||
},
|
||||
|
||||
/* Gate-only clocks */
|
||||
|
||||
[JZ4755_CLK_UART0] = {
|
||||
"uart0", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 0 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_UART1] = {
|
||||
"uart1", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 14 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_UART2] = {
|
||||
"uart2", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 15 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_ADC] = {
|
||||
"adc", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 7 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_AIC] = {
|
||||
"aic", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 5 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_I2C] = {
|
||||
"i2c", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_CLKGR, 3 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_BCH] = {
|
||||
"bch", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 11 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_TCU] = {
|
||||
"tcu", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT, },
|
||||
.gate = { CGU_REG_CLKGR, 1 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_DMA] = {
|
||||
"dma", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_PCLK, },
|
||||
.gate = { CGU_REG_CLKGR, 12 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_MMC0] = {
|
||||
"mmc0", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_MMC, },
|
||||
.gate = { CGU_REG_CLKGR, 6 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_MMC1] = {
|
||||
"mmc1", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_MMC, },
|
||||
.gate = { CGU_REG_CLKGR, 16 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_AUX_CPU] = {
|
||||
"aux_cpu", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 24 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_AHB1] = {
|
||||
"ahb1", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 23 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_IDCT] = {
|
||||
"idct", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 22 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_DB] = {
|
||||
"db", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 21 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_ME] = {
|
||||
"me", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 20 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_MC] = {
|
||||
"mc", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR, 19 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_TSSI] = {
|
||||
"tssi", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF/* not sure */, },
|
||||
.gate = { CGU_REG_CLKGR, 17 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_IPU] = {
|
||||
"ipu", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_PLL_HALF/* not sure */, },
|
||||
.gate = { CGU_REG_CLKGR, 13 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_EXT512] = {
|
||||
"ext/512", CGU_CLK_FIXDIV,
|
||||
.parents = { JZ4755_CLK_EXT, },
|
||||
|
||||
.fixdiv = { 512 },
|
||||
},
|
||||
|
||||
[JZ4755_CLK_UDC_PHY] = {
|
||||
"udc_phy", CGU_CLK_GATE,
|
||||
.parents = { JZ4755_CLK_EXT_HALF, },
|
||||
.gate = { CGU_REG_OPCR, 6, true },
|
||||
},
|
||||
};
|
||||
|
||||
static void __init jz4755_cgu_init(struct device_node *np)
|
||||
{
|
||||
int retval;
|
||||
|
||||
cgu = ingenic_cgu_new(jz4755_cgu_clocks,
|
||||
ARRAY_SIZE(jz4755_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__);
|
||||
|
||||
ingenic_cgu_register_syscore_ops(cgu);
|
||||
}
|
||||
/*
|
||||
* CGU has some children devices, this is useful for probing children devices
|
||||
* in the case where the device node is compatible with "simple-mfd".
|
||||
*/
|
||||
CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu", jz4755_cgu_init);
|
@ -8,6 +8,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/rational.h>
|
||||
|
||||
#include <dt-bindings/clock/ingenic,x1000-cgu.h>
|
||||
|
||||
@ -168,6 +169,38 @@ static const struct clk_ops x1000_otg_phy_ops = {
|
||||
.is_enabled = x1000_usb_phy_is_enabled,
|
||||
};
|
||||
|
||||
static void
|
||||
x1000_i2spll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
|
||||
unsigned long rate, unsigned long parent_rate,
|
||||
unsigned int *pm, unsigned int *pn, unsigned int *pod)
|
||||
{
|
||||
const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0);
|
||||
const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0);
|
||||
unsigned long m, n;
|
||||
|
||||
rational_best_approximation(rate, parent_rate, m_max, n_max, &m, &n);
|
||||
|
||||
/* n should not be less than 2*m */
|
||||
if (n < 2 * m)
|
||||
n = 2 * m;
|
||||
|
||||
*pm = m;
|
||||
*pn = n;
|
||||
*pod = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
x1000_i2spll_set_rate_hook(const struct ingenic_cgu_pll_info *pll_info,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
/*
|
||||
* Writing 0 causes I2SCDR1.I2SDIV_D to be automatically recalculated
|
||||
* based on the current value of I2SCDR.I2SDIV_N, which is needed for
|
||||
* the divider to function correctly.
|
||||
*/
|
||||
writel(0, cgu->base + CGU_REG_I2SCDR1);
|
||||
}
|
||||
|
||||
static const s8 pll_od_encoding[8] = {
|
||||
0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
|
||||
};
|
||||
@ -183,7 +216,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_APLL] = {
|
||||
"apll", CGU_CLK_PLL,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.pll = {
|
||||
.reg = CGU_REG_APLL,
|
||||
.rate_multiplier = 1,
|
||||
@ -206,7 +239,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_MPLL] = {
|
||||
"mpll", CGU_CLK_PLL,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.pll = {
|
||||
.reg = CGU_REG_MPLL,
|
||||
.rate_multiplier = 1,
|
||||
@ -256,7 +289,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
* system; mark it critical.
|
||||
*/
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
.parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_CPUMUX },
|
||||
.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 30 },
|
||||
},
|
||||
@ -268,7 +301,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
* disabling it or any parent clocks will hang the system.
|
||||
*/
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
.parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_CPUMUX },
|
||||
.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
|
||||
},
|
||||
|
||||
@ -287,13 +320,13 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_AHB2] = {
|
||||
"ahb2", CGU_CLK_DIV,
|
||||
.parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_AHB2PMUX },
|
||||
.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
|
||||
},
|
||||
|
||||
[X1000_CLK_PCLK] = {
|
||||
"pclk", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_AHB2PMUX },
|
||||
.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
|
||||
.gate = { CGU_REG_CLKGR, 28 },
|
||||
},
|
||||
@ -319,6 +352,37 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
.gate = { CGU_REG_CLKGR, 25 },
|
||||
},
|
||||
|
||||
[X1000_CLK_I2SPLLMUX] = {
|
||||
"i2s_pll_mux", CGU_CLK_MUX,
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
|
||||
.mux = { CGU_REG_I2SCDR, 31, 1 },
|
||||
},
|
||||
|
||||
[X1000_CLK_I2SPLL] = {
|
||||
"i2s_pll", CGU_CLK_PLL,
|
||||
.parents = { X1000_CLK_I2SPLLMUX },
|
||||
.pll = {
|
||||
.reg = CGU_REG_I2SCDR,
|
||||
.rate_multiplier = 1,
|
||||
.m_shift = 13,
|
||||
.m_bits = 9,
|
||||
.n_shift = 0,
|
||||
.n_bits = 13,
|
||||
.calc_m_n_od = x1000_i2spll_calc_m_n_od,
|
||||
.set_rate_hook = x1000_i2spll_set_rate_hook,
|
||||
},
|
||||
},
|
||||
|
||||
[X1000_CLK_I2S] = {
|
||||
"i2s", CGU_CLK_MUX,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, X1000_CLK_I2SPLL },
|
||||
/*
|
||||
* NOTE: the mux is at bit 30; bit 29 enables the M/N divider.
|
||||
* Therefore, the divider is disabled when EXCLK is selected.
|
||||
*/
|
||||
.mux = { CGU_REG_I2SCDR, 29, 2 },
|
||||
},
|
||||
|
||||
[X1000_CLK_LCD] = {
|
||||
"lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
|
||||
@ -329,13 +393,13 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_MSCMUX] = {
|
||||
"msc_mux", CGU_CLK_MUX,
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL},
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
|
||||
.mux = { CGU_REG_MSC0CDR, 31, 1 },
|
||||
},
|
||||
|
||||
[X1000_CLK_MSC0] = {
|
||||
"msc0", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_MSCMUX },
|
||||
.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR, 4 },
|
||||
},
|
||||
@ -349,8 +413,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_OTG] = {
|
||||
"otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
|
||||
.parents = { X1000_CLK_EXCLK, -1,
|
||||
X1000_CLK_APLL, X1000_CLK_MPLL },
|
||||
.parents = { X1000_CLK_EXCLK, -1, X1000_CLK_APLL, X1000_CLK_MPLL },
|
||||
.mux = { CGU_REG_USBCDR, 30, 2 },
|
||||
.div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 },
|
||||
.gate = { CGU_REG_CLKGR, 3 },
|
||||
@ -358,7 +421,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_SSIPLL] = {
|
||||
"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL, -1, -1 },
|
||||
.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
|
||||
.mux = { CGU_REG_SSICDR, 31, 1 },
|
||||
.div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },
|
||||
},
|
||||
@ -371,7 +434,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_SSIMUX] = {
|
||||
"ssi_mux", CGU_CLK_MUX,
|
||||
.parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2 },
|
||||
.mux = { CGU_REG_SSICDR, 30, 1 },
|
||||
},
|
||||
|
||||
@ -392,79 +455,85 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
|
||||
|
||||
[X1000_CLK_EMC] = {
|
||||
"emc", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_AHB2, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_AHB2 },
|
||||
.gate = { CGU_REG_CLKGR, 0 },
|
||||
},
|
||||
|
||||
[X1000_CLK_EFUSE] = {
|
||||
"efuse", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_AHB2, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_AHB2 },
|
||||
.gate = { CGU_REG_CLKGR, 1 },
|
||||
},
|
||||
|
||||
[X1000_CLK_SFC] = {
|
||||
"sfc", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_SSIPLL, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_SSIPLL },
|
||||
.gate = { CGU_REG_CLKGR, 2 },
|
||||
},
|
||||
|
||||
[X1000_CLK_I2C0] = {
|
||||
"i2c0", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_PCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_PCLK },
|
||||
.gate = { CGU_REG_CLKGR, 7 },
|
||||
},
|
||||
|
||||
[X1000_CLK_I2C1] = {
|
||||
"i2c1", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_PCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_PCLK },
|
||||
.gate = { CGU_REG_CLKGR, 8 },
|
||||
},
|
||||
|
||||
[X1000_CLK_I2C2] = {
|
||||
"i2c2", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_PCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_PCLK },
|
||||
.gate = { CGU_REG_CLKGR, 9 },
|
||||
},
|
||||
|
||||
[X1000_CLK_AIC] = {
|
||||
"aic", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 11 },
|
||||
},
|
||||
|
||||
[X1000_CLK_UART0] = {
|
||||
"uart0", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 14 },
|
||||
},
|
||||
|
||||
[X1000_CLK_UART1] = {
|
||||
"uart1", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK},
|
||||
.gate = { CGU_REG_CLKGR, 15 },
|
||||
},
|
||||
|
||||
[X1000_CLK_UART2] = {
|
||||
"uart2", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 16 },
|
||||
},
|
||||
|
||||
[X1000_CLK_TCU] = {
|
||||
"tcu", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 18 },
|
||||
},
|
||||
|
||||
[X1000_CLK_SSI] = {
|
||||
"ssi", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_SSIMUX, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_SSIMUX },
|
||||
.gate = { CGU_REG_CLKGR, 19 },
|
||||
},
|
||||
|
||||
[X1000_CLK_OST] = {
|
||||
"ost", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 20 },
|
||||
},
|
||||
|
||||
[X1000_CLK_PDMA] = {
|
||||
"pdma", CGU_CLK_GATE,
|
||||
.parents = { X1000_CLK_EXCLK, -1, -1, -1 },
|
||||
.parents = { X1000_CLK_EXCLK },
|
||||
.gate = { CGU_REG_CLKGR, 21 },
|
||||
},
|
||||
};
|
||||
|
@ -102,12 +102,9 @@ static int ti_syscon_gate_clk_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
|
||||
regmap = syscon_node_to_regmap(dev->of_node);
|
||||
if (IS_ERR(regmap)) {
|
||||
if (PTR_ERR(regmap) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(dev, "failed to find parent regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"failed to find parent regmap\n");
|
||||
|
||||
num_clks = 0;
|
||||
for (p = data; p->name; p++)
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rational.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
|
@ -1,4 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config MSTAR_MSC313_CPUPLL
|
||||
bool "MStar CPUPLL driver"
|
||||
depends on ARCH_MSTARV7 || COMPILE_TEST
|
||||
default ARCH_MSTARV7
|
||||
help
|
||||
Support for the CPU PLL present on MStar/Sigmastar SoCs.
|
||||
|
||||
config MSTAR_MSC313_MPLL
|
||||
bool "MStar MPLL driver"
|
||||
depends on ARCH_MSTARV7 || COMPILE_TEST
|
||||
|
@ -3,4 +3,5 @@
|
||||
# Makefile for mstar specific clk
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MSTAR_MSC313_CPUPLL) += clk-msc313-cpupll.o
|
||||
obj-$(CONFIG_MSTAR_MSC313_MPLL) += clk-msc313-mpll.o
|
||||
|
220
drivers/clk/mstar/clk-msc313-cpupll.c
Normal file
220
drivers/clk/mstar/clk-msc313-cpupll.c
Normal file
@ -0,0 +1,220 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Daniel Palmer <daniel@thingy.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* This IP is not documented outside of the messy vendor driver.
|
||||
* Below is what we think the registers look like based on looking at
|
||||
* the vendor code and poking at the hardware:
|
||||
*
|
||||
* 0x140 -- LPF low. Seems to store one half of the clock transition
|
||||
* 0x144 /
|
||||
* 0x148 -- LPF high. Seems to store one half of the clock transition
|
||||
* 0x14c /
|
||||
* 0x150 -- vendor code says "toggle lpf enable"
|
||||
* 0x154 -- mu?
|
||||
* 0x15c -- lpf_update_count?
|
||||
* 0x160 -- vendor code says "switch to LPF". Clock source config? Register bank?
|
||||
* 0x164 -- vendor code says "from low to high" which seems to mean transition from LPF low to
|
||||
* LPF high.
|
||||
* 0x174 -- Seems to be the PLL lock status bit
|
||||
* 0x180 -- Seems to be the current frequency, this might need to be populated by software?
|
||||
* 0x184 / The vendor driver uses these to set the initial value of LPF low
|
||||
*
|
||||
* Frequency seems to be calculated like this:
|
||||
* (parent clock (432mhz) / register_magic_value) * 16 * 524288
|
||||
* Only the lower 24 bits of the resulting value will be used. In addition, the
|
||||
* PLL doesn't seem to be able to lock on frequencies lower than 220 MHz, as
|
||||
* divisor 0xfb586f (220 MHz) works but 0xfb7fff locks up.
|
||||
*
|
||||
* Vendor values:
|
||||
* frequency - register value
|
||||
*
|
||||
* 400000000 - 0x0067AE14
|
||||
* 600000000 - 0x00451EB8,
|
||||
* 800000000 - 0x0033D70A,
|
||||
* 1000000000 - 0x002978d4,
|
||||
*/
|
||||
|
||||
#define REG_LPF_LOW_L 0x140
|
||||
#define REG_LPF_LOW_H 0x144
|
||||
#define REG_LPF_HIGH_BOTTOM 0x148
|
||||
#define REG_LPF_HIGH_TOP 0x14c
|
||||
#define REG_LPF_TOGGLE 0x150
|
||||
#define REG_LPF_MYSTERYTWO 0x154
|
||||
#define REG_LPF_UPDATE_COUNT 0x15c
|
||||
#define REG_LPF_MYSTERYONE 0x160
|
||||
#define REG_LPF_TRANSITIONCTRL 0x164
|
||||
#define REG_LPF_LOCK 0x174
|
||||
#define REG_CURRENT 0x180
|
||||
|
||||
#define LPF_LOCK_TIMEOUT 100000000
|
||||
|
||||
#define MULTIPLIER_1 16
|
||||
#define MULTIPLIER_2 524288
|
||||
#define MULTIPLIER (MULTIPLIER_1 * MULTIPLIER_2)
|
||||
|
||||
struct msc313_cpupll {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
};
|
||||
|
||||
#define to_cpupll(_hw) container_of(_hw, struct msc313_cpupll, clk_hw)
|
||||
|
||||
static u32 msc313_cpupll_reg_read32(struct msc313_cpupll *cpupll, unsigned int reg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = ioread16(cpupll->base + reg + 4) << 16;
|
||||
value |= ioread16(cpupll->base + reg);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void msc313_cpupll_reg_write32(struct msc313_cpupll *cpupll, unsigned int reg, u32 value)
|
||||
{
|
||||
u16 l = value & 0xffff, h = (value >> 16) & 0xffff;
|
||||
|
||||
iowrite16(l, cpupll->base + reg);
|
||||
iowrite16(h, cpupll->base + reg + 4);
|
||||
}
|
||||
|
||||
static void msc313_cpupll_setfreq(struct msc313_cpupll *cpupll, u32 regvalue)
|
||||
{
|
||||
ktime_t timeout;
|
||||
|
||||
msc313_cpupll_reg_write32(cpupll, REG_LPF_HIGH_BOTTOM, regvalue);
|
||||
|
||||
iowrite16(0x1, cpupll->base + REG_LPF_MYSTERYONE);
|
||||
iowrite16(0x6, cpupll->base + REG_LPF_MYSTERYTWO);
|
||||
iowrite16(0x8, cpupll->base + REG_LPF_UPDATE_COUNT);
|
||||
iowrite16(BIT(12), cpupll->base + REG_LPF_TRANSITIONCTRL);
|
||||
|
||||
iowrite16(0, cpupll->base + REG_LPF_TOGGLE);
|
||||
iowrite16(1, cpupll->base + REG_LPF_TOGGLE);
|
||||
|
||||
timeout = ktime_add_ns(ktime_get(), LPF_LOCK_TIMEOUT);
|
||||
while (!(ioread16(cpupll->base + REG_LPF_LOCK))) {
|
||||
if (ktime_after(ktime_get(), timeout)) {
|
||||
pr_err("timeout waiting for LPF_LOCK\n");
|
||||
return;
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
iowrite16(0, cpupll->base + REG_LPF_TOGGLE);
|
||||
|
||||
msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, regvalue);
|
||||
}
|
||||
|
||||
static unsigned long msc313_cpupll_frequencyforreg(u32 reg, unsigned long parent_rate)
|
||||
{
|
||||
unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER;
|
||||
|
||||
if (prescaled == 0 || reg == 0)
|
||||
return 0;
|
||||
return DIV_ROUND_DOWN_ULL(prescaled, reg);
|
||||
}
|
||||
|
||||
static u32 msc313_cpupll_regforfrequecy(unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER;
|
||||
|
||||
if (prescaled == 0 || rate == 0)
|
||||
return 0;
|
||||
return DIV_ROUND_UP_ULL(prescaled, rate);
|
||||
}
|
||||
|
||||
static unsigned long msc313_cpupll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct msc313_cpupll *cpupll = to_cpupll(hw);
|
||||
|
||||
return msc313_cpupll_frequencyforreg(msc313_cpupll_reg_read32(cpupll, REG_LPF_LOW_L),
|
||||
parent_rate);
|
||||
}
|
||||
|
||||
static long msc313_cpupll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
u32 reg = msc313_cpupll_regforfrequecy(rate, *parent_rate);
|
||||
long rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate);
|
||||
|
||||
/*
|
||||
* This is my poor attempt at making sure the resulting
|
||||
* rate doesn't overshoot the requested rate.
|
||||
*/
|
||||
for (; rounded >= rate && reg > 0; reg--)
|
||||
rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate);
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
static int msc313_cpupll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct msc313_cpupll *cpupll = to_cpupll(hw);
|
||||
u32 reg = msc313_cpupll_regforfrequecy(rate, parent_rate);
|
||||
|
||||
msc313_cpupll_setfreq(cpupll, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops msc313_cpupll_ops = {
|
||||
.recalc_rate = msc313_cpupll_recalc_rate,
|
||||
.round_rate = msc313_cpupll_round_rate,
|
||||
.set_rate = msc313_cpupll_set_rate,
|
||||
};
|
||||
|
||||
static const struct of_device_id msc313_cpupll_of_match[] = {
|
||||
{ .compatible = "mstar,msc313-cpupll" },
|
||||
{}
|
||||
};
|
||||
|
||||
static int msc313_cpupll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_init_data clk_init = {};
|
||||
struct clk_parent_data cpupll_parent = { .index = 0 };
|
||||
struct device *dev = &pdev->dev;
|
||||
struct msc313_cpupll *cpupll;
|
||||
int ret;
|
||||
|
||||
cpupll = devm_kzalloc(&pdev->dev, sizeof(*cpupll), GFP_KERNEL);
|
||||
if (!cpupll)
|
||||
return -ENOMEM;
|
||||
|
||||
cpupll->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(cpupll->base))
|
||||
return PTR_ERR(cpupll->base);
|
||||
|
||||
/* LPF might not contain the current frequency so fix that up */
|
||||
msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L,
|
||||
msc313_cpupll_reg_read32(cpupll, REG_CURRENT));
|
||||
|
||||
clk_init.name = dev_name(dev);
|
||||
clk_init.ops = &msc313_cpupll_ops;
|
||||
clk_init.parent_data = &cpupll_parent;
|
||||
clk_init.num_parents = 1;
|
||||
cpupll->clk_hw.init = &clk_init;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &cpupll->clk_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, &cpupll->clk_hw);
|
||||
}
|
||||
|
||||
static struct platform_driver msc313_cpupll_driver = {
|
||||
.driver = {
|
||||
.name = "mstar-msc313-cpupll",
|
||||
.of_match_table = msc313_cpupll_of_match,
|
||||
},
|
||||
.probe = msc313_cpupll_probe,
|
||||
};
|
||||
builtin_platform_driver(msc313_cpupll_driver);
|
@ -21,7 +21,6 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/rational.h>
|
||||
|
||||
#include "../clk-fractional-divider.h"
|
||||
#include "clk.h"
|
||||
|
@ -47,10 +47,10 @@ static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx,
|
||||
/*
|
||||
* Pass the needed clock provider context and register sub-CMU clocks
|
||||
*
|
||||
* NOTE: This function has to be called from the main, OF_CLK_DECLARE-
|
||||
* NOTE: This function has to be called from the main, CLK_OF_DECLARE-
|
||||
* initialized clock provider driver. This happens very early during boot
|
||||
* process. Then this driver, during core_initcall registers two platform
|
||||
* drivers: one which binds to the same device-tree node as OF_CLK_DECLARE
|
||||
* drivers: one which binds to the same device-tree node as CLK_OF_DECLARE
|
||||
* driver and second, for handling its per-domain child-devices. Those
|
||||
* platform drivers are bound to their devices a bit later in arch_initcall,
|
||||
* when OF-core populates all device-tree nodes.
|
||||
|
@ -1583,6 +1583,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
|
||||
if (ret) {
|
||||
pr_err("%s: failed to register pll clock %s : %d\n",
|
||||
__func__, pll_clk->name, ret);
|
||||
kfree(pll->rate_table);
|
||||
kfree(pll);
|
||||
return;
|
||||
}
|
||||
|
@ -188,8 +188,10 @@ void __init socfpga_gate_init(struct device_node *node)
|
||||
return;
|
||||
|
||||
ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL);
|
||||
if (WARN_ON(!ops))
|
||||
if (WARN_ON(!ops)) {
|
||||
kfree(socfpga_clk);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
|
||||
if (rc)
|
||||
@ -243,6 +245,7 @@ void __init socfpga_gate_init(struct device_node *node)
|
||||
|
||||
err = clk_hw_register(NULL, hw_clk);
|
||||
if (err) {
|
||||
kfree(ops);
|
||||
kfree(socfpga_clk);
|
||||
return;
|
||||
}
|
||||
|
@ -1020,9 +1020,10 @@ static void __init st_of_quadfs_setup(struct device_node *np,
|
||||
|
||||
clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data,
|
||||
reg, lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(lock);
|
||||
goto err_exit;
|
||||
else
|
||||
} else
|
||||
pr_debug("%s: parent %s rate %u\n",
|
||||
__clk_get_name(clk),
|
||||
__clk_get_name(clk_get_parent(clk)),
|
||||
|
@ -277,6 +277,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
|
||||
ret = clk_hw_register(NULL, &pll->hw);
|
||||
if (ret) {
|
||||
pr_err("failed to register pll clock %s : %d\n", name, ret);
|
||||
kfree(pll->rate_table);
|
||||
kfree(pll);
|
||||
pll_hw_clk = ERR_PTR(ret);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CLK_LGM_CGU
|
||||
depends on OF && HAS_IOMEM && (X86 || COMPILE_TEST)
|
||||
select MFD_SYSCON
|
||||
select OF_EARLY_FLATTREE
|
||||
bool "Clock driver for Lightning Mountain(LGM) platform"
|
||||
help
|
||||
Clock Generation Unit(CGU) driver for Intel Lightning Mountain(LGM)
|
||||
network processor SoC.
|
||||
Clock Generation Unit(CGU) driver for MaxLinear's x86 based
|
||||
Lightning Mountain(LGM) network processor SoC.
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
@ -40,13 +41,10 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned int div, mult, frac;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
mult = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 0, 12);
|
||||
div = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 18, 6);
|
||||
frac = lgm_get_clk_val(pll->membase, pll->reg, 2, 24);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
|
||||
if (pll->type == TYPE_LJPLL)
|
||||
div *= 4;
|
||||
@ -57,12 +55,9 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
static int lgm_pll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
ret = lgm_get_clk_val(pll->membase, pll->reg, 0, 1);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -70,15 +65,13 @@ static int lgm_pll_is_enabled(struct clk_hw *hw)
|
||||
static int lgm_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 1);
|
||||
ret = readl_poll_timeout_atomic(pll->membase + pll->reg,
|
||||
val, (val & 0x1), 1, 100);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
ret = regmap_read_poll_timeout_atomic(pll->membase, pll->reg,
|
||||
val, (val & 0x1), 1, 100);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -86,11 +79,8 @@ static int lgm_pll_enable(struct clk_hw *hw)
|
||||
static void lgm_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 0);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
}
|
||||
|
||||
static const struct clk_ops lgm_pll_ops = {
|
||||
@ -121,7 +111,6 @@ lgm_clk_register_pll(struct lgm_clk_provider *ctx,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->membase = ctx->membase;
|
||||
pll->lock = ctx->lock;
|
||||
pll->reg = list->reg;
|
||||
pll->flags = list->flags;
|
||||
pll->type = list->type;
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
@ -24,14 +25,10 @@
|
||||
static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&ctx->lock, flags);
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift,
|
||||
list->div_width, list->div_val);
|
||||
spin_unlock_irqrestore(&ctx->lock, flags);
|
||||
}
|
||||
|
||||
return clk_hw_register_fixed_rate(NULL, list->name,
|
||||
list->parent_data[0].name,
|
||||
@ -41,33 +38,27 @@ static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx,
|
||||
static u8 lgm_clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_mux *mux = to_lgm_clk_mux(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (mux->flags & MUX_CLK_SW)
|
||||
val = mux->reg;
|
||||
else
|
||||
val = lgm_get_clk_val(mux->membase, mux->reg, mux->shift,
|
||||
mux->width);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
return clk_mux_val_to_index(hw, NULL, mux->flags, val);
|
||||
}
|
||||
|
||||
static int lgm_clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct lgm_clk_mux *mux = to_lgm_clk_mux(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
val = clk_mux_index_to_val(NULL, mux->flags, index);
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (mux->flags & MUX_CLK_SW)
|
||||
mux->reg = val;
|
||||
else
|
||||
lgm_set_clk_val(mux->membase, mux->reg, mux->shift,
|
||||
mux->width, val);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -90,7 +81,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->mux_flags;
|
||||
unsigned long cflags = list->mux_flags;
|
||||
struct device *dev = ctx->dev;
|
||||
u8 shift = list->mux_shift;
|
||||
u8 width = list->mux_width;
|
||||
@ -111,7 +102,6 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = list->num_parents;
|
||||
|
||||
mux->membase = ctx->membase;
|
||||
mux->lock = ctx->lock;
|
||||
mux->reg = reg;
|
||||
mux->shift = shift;
|
||||
mux->width = width;
|
||||
@ -123,11 +113,8 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(mux->membase, reg, shift, width, list->mux_val);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@ -136,13 +123,10 @@ static unsigned long
|
||||
lgm_clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct lgm_clk_divider *divider = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
|
||||
spin_lock_irqsave(÷r->lock, flags);
|
||||
val = lgm_get_clk_val(divider->membase, divider->reg,
|
||||
divider->shift, divider->width);
|
||||
spin_unlock_irqrestore(÷r->lock, flags);
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, divider->table,
|
||||
divider->flags, divider->width);
|
||||
@ -163,7 +147,6 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct lgm_clk_divider *divider = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
int value;
|
||||
|
||||
value = divider_get_val(rate, prate, divider->table,
|
||||
@ -171,10 +154,8 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
spin_lock_irqsave(÷r->lock, flags);
|
||||
lgm_set_clk_val(divider->membase, divider->reg,
|
||||
divider->shift, divider->width, value);
|
||||
spin_unlock_irqrestore(÷r->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -182,12 +163,10 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static int lgm_clk_divider_enable_disable(struct clk_hw *hw, int enable)
|
||||
{
|
||||
struct lgm_clk_divider *div = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&div->lock, flags);
|
||||
lgm_set_clk_val(div->membase, div->reg, div->shift_gate,
|
||||
div->width_gate, enable);
|
||||
spin_unlock_irqrestore(&div->lock, flags);
|
||||
if (div->flags != DIV_CLK_NO_MASK)
|
||||
lgm_set_clk_val(div->membase, div->reg, div->shift_gate,
|
||||
div->width_gate, enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -213,7 +192,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->div_flags;
|
||||
unsigned long cflags = list->div_flags;
|
||||
struct device *dev = ctx->dev;
|
||||
struct lgm_clk_divider *div;
|
||||
struct clk_init_data init = {};
|
||||
@ -236,7 +215,6 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = 1;
|
||||
|
||||
div->membase = ctx->membase;
|
||||
div->lock = ctx->lock;
|
||||
div->reg = reg;
|
||||
div->shift = shift;
|
||||
div->width = width;
|
||||
@ -251,11 +229,8 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&div->lock, flags);
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(div->membase, reg, shift, width, list->div_val);
|
||||
spin_unlock_irqrestore(&div->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@ -264,7 +239,6 @@ static struct clk_hw *
|
||||
lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = clk_hw_register_fixed_factor(ctx->dev, list->name,
|
||||
@ -273,12 +247,9 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
if (IS_ERR(hw))
|
||||
return ERR_CAST(hw);
|
||||
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&ctx->lock, flags);
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift,
|
||||
list->div_width, list->div_val);
|
||||
spin_unlock_irqrestore(&ctx->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@ -286,13 +257,10 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
static int lgm_clk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned long flags;
|
||||
unsigned int reg;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_EN(gate->reg);
|
||||
lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -300,25 +268,19 @@ static int lgm_clk_gate_enable(struct clk_hw *hw)
|
||||
static void lgm_clk_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned long flags;
|
||||
unsigned int reg;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_DIS(gate->reg);
|
||||
lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
}
|
||||
|
||||
static int lgm_clk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned int reg, ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_STAT(gate->reg);
|
||||
ret = lgm_get_clk_val(gate->membase, reg, gate->shift, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -333,7 +295,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->gate_flags;
|
||||
unsigned long cflags = list->gate_flags;
|
||||
const char *pname = list->parent_data[0].name;
|
||||
struct device *dev = ctx->dev;
|
||||
u8 shift = list->gate_shift;
|
||||
@ -354,7 +316,6 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = pname ? 1 : 0;
|
||||
|
||||
gate->membase = ctx->membase;
|
||||
gate->lock = ctx->lock;
|
||||
gate->reg = reg;
|
||||
gate->shift = shift;
|
||||
gate->flags = cflags;
|
||||
@ -366,9 +327,7 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
lgm_set_clk_val(gate->membase, reg, shift, 1, list->gate_val);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
@ -396,8 +355,22 @@ int lgm_clk_register_branches(struct lgm_clk_provider *ctx,
|
||||
hw = lgm_clk_register_fixed_factor(ctx, list);
|
||||
break;
|
||||
case CLK_TYPE_GATE:
|
||||
hw = lgm_clk_register_gate(ctx, list);
|
||||
if (list->gate_flags & GATE_CLK_HW) {
|
||||
hw = lgm_clk_register_gate(ctx, list);
|
||||
} else {
|
||||
/*
|
||||
* GATE_CLKs can be controlled either from
|
||||
* CGU clk driver i.e. this driver or directly
|
||||
* from power management driver/daemon. It is
|
||||
* dependent on the power policy/profile requirements
|
||||
* of the end product. To override control of gate
|
||||
* clks from this driver, provide NULL for this index
|
||||
* of gate clk provider.
|
||||
*/
|
||||
hw = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ctx->dev, "invalid clk type\n");
|
||||
return -EINVAL;
|
||||
@ -443,24 +416,18 @@ lgm_clk_ddiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
static int lgm_clk_ddiv_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate,
|
||||
ddiv->width_gate, 1);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lgm_clk_ddiv_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate,
|
||||
ddiv->width_gate, 0);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -497,32 +464,25 @@ lgm_clk_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
u32 div, ddiv1, ddiv2;
|
||||
unsigned long flags;
|
||||
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
|
||||
div = div * 2;
|
||||
}
|
||||
|
||||
if (div <= 0) {
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
if (div <= 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2)) {
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift0, ddiv->width0,
|
||||
ddiv1 - 1);
|
||||
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift1, ddiv->width1,
|
||||
ddiv2 - 1);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -533,18 +493,15 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
u32 div, ddiv1, ddiv2;
|
||||
unsigned long flags;
|
||||
u64 rate64;
|
||||
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)*prate, rate);
|
||||
|
||||
/* if predivide bit is enabled, modify div by factor of 2.5 */
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
div = div * 2;
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
|
||||
}
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
if (div <= 0)
|
||||
return *prate;
|
||||
@ -558,12 +515,10 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
do_div(rate64, ddiv2);
|
||||
|
||||
/* if predivide bit is enabled, modify rounded rate by factor of 2.5 */
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
rate64 = rate64 * 2;
|
||||
rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5);
|
||||
}
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
return rate64;
|
||||
}
|
||||
@ -600,7 +555,6 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = 1;
|
||||
|
||||
ddiv->membase = ctx->membase;
|
||||
ddiv->lock = ctx->lock;
|
||||
ddiv->reg = list->reg;
|
||||
ddiv->shift0 = list->shift0;
|
||||
ddiv->width0 = list->width0;
|
||||
|
@ -1,28 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright(c) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLK_CGU_H
|
||||
#define __CLK_CGU_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct lgm_clk_mux {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_divider {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
@ -30,12 +30,11 @@ struct lgm_clk_divider {
|
||||
u8 width_gate;
|
||||
unsigned long flags;
|
||||
const struct clk_div_table *table;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_ddiv {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift0;
|
||||
u8 width0;
|
||||
@ -48,16 +47,14 @@ struct lgm_clk_ddiv {
|
||||
unsigned int mult;
|
||||
unsigned int div;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_gate {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum lgm_clk_type {
|
||||
@ -77,11 +74,10 @@ enum lgm_clk_type {
|
||||
* @clk_data: array of hw clocks and clk number.
|
||||
*/
|
||||
struct lgm_clk_provider {
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
struct device_node *np;
|
||||
struct device *dev;
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum pll_type {
|
||||
@ -92,11 +88,10 @@ enum pll_type {
|
||||
|
||||
struct lgm_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
unsigned long flags;
|
||||
enum pll_type type;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -202,6 +197,8 @@ struct lgm_clk_branch {
|
||||
/* clock flags definition */
|
||||
#define CLOCK_FLAG_VAL_INIT BIT(16)
|
||||
#define MUX_CLK_SW BIT(17)
|
||||
#define GATE_CLK_HW BIT(18)
|
||||
#define DIV_CLK_NO_MASK BIT(19)
|
||||
|
||||
#define LGM_MUX(_id, _name, _pdata, _f, _reg, \
|
||||
_shift, _width, _cf, _v) \
|
||||
@ -300,29 +297,32 @@ struct lgm_clk_branch {
|
||||
.div = _d, \
|
||||
}
|
||||
|
||||
static inline void lgm_set_clk_val(void __iomem *membase, u32 reg,
|
||||
static inline void lgm_set_clk_val(struct regmap *membase, u32 reg,
|
||||
u8 shift, u8 width, u32 set_val)
|
||||
{
|
||||
u32 mask = (GENMASK(width - 1, 0) << shift);
|
||||
u32 regval;
|
||||
|
||||
regval = readl(membase + reg);
|
||||
regval = (regval & ~mask) | ((set_val << shift) & mask);
|
||||
writel(regval, membase + reg);
|
||||
regmap_update_bits(membase, reg, mask, set_val << shift);
|
||||
}
|
||||
|
||||
static inline u32 lgm_get_clk_val(void __iomem *membase, u32 reg,
|
||||
static inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg,
|
||||
u8 shift, u8 width)
|
||||
{
|
||||
u32 mask = (GENMASK(width - 1, 0) << shift);
|
||||
u32 val;
|
||||
|
||||
val = readl(membase + reg);
|
||||
if (regmap_read(membase, reg, &val)) {
|
||||
WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = (val & mask) >> shift;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lgm_clk_register_branches(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list,
|
||||
unsigned int nr_clk);
|
||||
|
@ -1,10 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/clock/intel,lgm-clk.h>
|
||||
@ -253,8 +255,8 @@ static const struct lgm_clk_branch lgm_branch_clks[] = {
|
||||
LGM_FIXED(LGM_CLK_SLIC, "slic", NULL, 0, CGU_IF_CLK1,
|
||||
8, 2, CLOCK_FLAG_VAL_INIT, 8192000, 2),
|
||||
LGM_FIXED(LGM_CLK_DOCSIS, "v_docsis", NULL, 0, 0, 0, 0, 0, 16000000, 0),
|
||||
LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", 0, CGU_PCMCR,
|
||||
25, 3, 0, 0, 0, 0, dcl_div),
|
||||
LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", CLK_SET_RATE_PARENT, CGU_PCMCR,
|
||||
25, 3, 0, 0, DIV_CLK_NO_MASK, 0, dcl_div),
|
||||
LGM_MUX(LGM_CLK_PCM, "pcm", pcm_p, 0, CGU_C55_PCMCR,
|
||||
0, 1, CLK_MUX_ROUND_CLOSEST, 0),
|
||||
LGM_FIXED_FACTOR(LGM_CLK_DDR_PHY, "ddr_phy", "ddr",
|
||||
@ -433,13 +435,15 @@ static int lgm_cgu_probe(struct platform_device *pdev)
|
||||
|
||||
ctx->clk_data.num = CLK_NR_CLKS;
|
||||
|
||||
ctx->membase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctx->membase))
|
||||
ctx->membase = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(ctx->membase)) {
|
||||
dev_err(dev, "Failed to get clk CGU iomem\n");
|
||||
return PTR_ERR(ctx->membase);
|
||||
}
|
||||
|
||||
|
||||
ctx->np = np;
|
||||
ctx->dev = dev;
|
||||
spin_lock_init(&ctx->lock);
|
||||
|
||||
ret = lgm_clk_register_plls(ctx, lgm_pll_clks,
|
||||
ARRAY_SIZE(lgm_pll_clks));
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
config XILINX_VCU
|
||||
tristate "Xilinx VCU logicoreIP Init"
|
||||
depends on HAS_IOMEM && COMMON_CLK
|
||||
depends on HAS_IOMEM
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Provides the driver to enable and disable the isolation between the
|
||||
@ -19,7 +19,7 @@ config XILINX_VCU
|
||||
|
||||
config COMMON_CLK_XLNX_CLKWZRD
|
||||
tristate "Xilinx Clocking Wizard"
|
||||
depends on COMMON_CLK && OF
|
||||
depends on OF
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Support for the Xilinx Clocking Wizard IP core clock generator.
|
||||
|
49
include/dt-bindings/clock/ingenic,jz4755-cgu.h
Normal file
49
include/dt-bindings/clock/ingenic,jz4755-cgu.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
||||
/*
|
||||
* This header provides clock numbers for the ingenic,jz4755-cgu DT binding.
|
||||
*/
|
||||
|
||||
#ifndef __DT_BINDINGS_CLOCK_JZ4755_CGU_H__
|
||||
#define __DT_BINDINGS_CLOCK_JZ4755_CGU_H__
|
||||
|
||||
#define JZ4755_CLK_EXT 0
|
||||
#define JZ4755_CLK_OSC32K 1
|
||||
#define JZ4755_CLK_PLL 2
|
||||
#define JZ4755_CLK_PLL_HALF 3
|
||||
#define JZ4755_CLK_EXT_HALF 4
|
||||
#define JZ4755_CLK_CCLK 5
|
||||
#define JZ4755_CLK_H0CLK 6
|
||||
#define JZ4755_CLK_PCLK 7
|
||||
#define JZ4755_CLK_MCLK 8
|
||||
#define JZ4755_CLK_H1CLK 9
|
||||
#define JZ4755_CLK_UDC 10
|
||||
#define JZ4755_CLK_LCD 11
|
||||
#define JZ4755_CLK_UART0 12
|
||||
#define JZ4755_CLK_UART1 13
|
||||
#define JZ4755_CLK_UART2 14
|
||||
#define JZ4755_CLK_DMA 15
|
||||
#define JZ4755_CLK_MMC 16
|
||||
#define JZ4755_CLK_MMC0 17
|
||||
#define JZ4755_CLK_MMC1 18
|
||||
#define JZ4755_CLK_EXT512 19
|
||||
#define JZ4755_CLK_RTC 20
|
||||
#define JZ4755_CLK_UDC_PHY 21
|
||||
#define JZ4755_CLK_I2S 22
|
||||
#define JZ4755_CLK_SPI 23
|
||||
#define JZ4755_CLK_AIC 24
|
||||
#define JZ4755_CLK_ADC 25
|
||||
#define JZ4755_CLK_TCU 26
|
||||
#define JZ4755_CLK_BCH 27
|
||||
#define JZ4755_CLK_I2C 28
|
||||
#define JZ4755_CLK_TVE 29
|
||||
#define JZ4755_CLK_CIM 30
|
||||
#define JZ4755_CLK_AUX_CPU 31
|
||||
#define JZ4755_CLK_AHB1 32
|
||||
#define JZ4755_CLK_IDCT 33
|
||||
#define JZ4755_CLK_DB 34
|
||||
#define JZ4755_CLK_ME 35
|
||||
#define JZ4755_CLK_MC 36
|
||||
#define JZ4755_CLK_TSSI 37
|
||||
#define JZ4755_CLK_IPU 38
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_JZ4755_CGU_H__ */
|
@ -50,5 +50,9 @@
|
||||
#define X1000_CLK_PDMA 35
|
||||
#define X1000_CLK_EXCLK_DIV512 36
|
||||
#define X1000_CLK_RTC 37
|
||||
#define X1000_CLK_AIC 38
|
||||
#define X1000_CLK_I2SPLLMUX 39
|
||||
#define X1000_CLK_I2SPLL 40
|
||||
#define X1000_CLK_I2S 41
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_X1000_CGU_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user