// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "pmc.h"
#define MASTER_SOURCE_MAX 4
#define PERIPHERAL_AT91RM9200 0
#define PERIPHERAL_AT91SAM9X5 1
#define PERIPHERAL_MAX 64
#define PERIPHERAL_ID_MIN 2
#define PROG_SOURCE_MAX 5
#define PROG_ID_MAX 7
#define SYSTEM_MAX_ID 31
#define GCK_INDEX_DT_AUDIO_PLL 5
static DEFINE_SPINLOCK(mck_lock);
#ifdef CONFIG_HAVE_AT91_AUDIO_PLL
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
struct device_node *parent_np;
parent_np = of_get_parent(np);
regmap = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
"atmel,sama5d2-clk-audio-pll-frac",
of_sama5d2_clk_audio_pll_frac_setup);
static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
struct device_node *parent_np;
parent_np = of_get_parent(np);
regmap = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
"atmel,sama5d2-clk-audio-pll-pad",
of_sama5d2_clk_audio_pll_pad_setup);
static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
struct device_node *parent_np;
parent_np = of_get_parent(np);
regmap = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
"atmel,sama5d2-clk-audio-pll-pmc",
of_sama5d2_clk_audio_pll_pmc_setup);
#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
static const struct clk_pcr_layout dt_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(5, 0),
.div_mask = GENMASK(17, 16),
.gckcss_mask = GENMASK(10, 8),
};
#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
#define GENERATED_SOURCE_MAX 6
#define GCK_ID_I2S0 54
#define GCK_ID_I2S1 55
#define GCK_ID_CLASSD 59
static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
int num;
u32 id;
const char *name;
struct clk_hw *hw;
unsigned int num_parents;
const char *parent_names[GENERATED_SOURCE_MAX];
struct device_node *gcknp, *parent_np;
struct clk_range range = CLK_RANGE(0, 0);
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np);
if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)