162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Clock driver for the ARM Integrator/AP, Integrator/CP, Versatile AB and
462306a36Sopenharmony_ci * Versatile PB boards.
562306a36Sopenharmony_ci * Copyright (C) 2012 Linus Walleij
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/of_address.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "icst.h"
1362306a36Sopenharmony_ci#include "clk-icst.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define INTEGRATOR_HDR_LOCK_OFFSET	0x14
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define VERSATILE_SYS_OSCCLCD_OFFSET	0x1c
1862306a36Sopenharmony_ci#define VERSATILE_SYS_LOCK_OFFSET	0x20
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Base offset for the core module */
2162306a36Sopenharmony_cistatic void __iomem *cm_base;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic const struct icst_params cp_auxosc_params = {
2462306a36Sopenharmony_ci	.vco_max	= ICST525_VCO_MAX_5V,
2562306a36Sopenharmony_ci	.vco_min	= ICST525_VCO_MIN,
2662306a36Sopenharmony_ci	.vd_min 	= 8,
2762306a36Sopenharmony_ci	.vd_max 	= 263,
2862306a36Sopenharmony_ci	.rd_min 	= 3,
2962306a36Sopenharmony_ci	.rd_max 	= 65,
3062306a36Sopenharmony_ci	.s2div		= icst525_s2div,
3162306a36Sopenharmony_ci	.idx2s		= icst525_idx2s,
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const struct clk_icst_desc cm_auxosc_desc __initconst = {
3562306a36Sopenharmony_ci	.params = &cp_auxosc_params,
3662306a36Sopenharmony_ci	.vco_offset = 0x1c,
3762306a36Sopenharmony_ci	.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic const struct icst_params versatile_auxosc_params = {
4162306a36Sopenharmony_ci	.vco_max	= ICST307_VCO_MAX,
4262306a36Sopenharmony_ci	.vco_min	= ICST307_VCO_MIN,
4362306a36Sopenharmony_ci	.vd_min		= 4 + 8,
4462306a36Sopenharmony_ci	.vd_max		= 511 + 8,
4562306a36Sopenharmony_ci	.rd_min		= 1 + 2,
4662306a36Sopenharmony_ci	.rd_max		= 127 + 2,
4762306a36Sopenharmony_ci	.s2div		= icst307_s2div,
4862306a36Sopenharmony_ci	.idx2s		= icst307_idx2s,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct clk_icst_desc versatile_auxosc_desc __initconst = {
5262306a36Sopenharmony_ci	.params = &versatile_auxosc_params,
5362306a36Sopenharmony_ci	.vco_offset = VERSATILE_SYS_OSCCLCD_OFFSET,
5462306a36Sopenharmony_ci	.lock_offset = VERSATILE_SYS_LOCK_OFFSET,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_cistatic void __init cm_osc_setup(struct device_node *np,
5762306a36Sopenharmony_ci				const struct clk_icst_desc *desc)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct clk *clk;
6062306a36Sopenharmony_ci	const char *clk_name = np->name;
6162306a36Sopenharmony_ci	const char *parent_name;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (!cm_base) {
6462306a36Sopenharmony_ci		/* Remap the core module base if not done yet */
6562306a36Sopenharmony_ci		struct device_node *parent;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		parent = of_get_parent(np);
6862306a36Sopenharmony_ci		if (!parent) {
6962306a36Sopenharmony_ci			pr_err("no parent on core module clock\n");
7062306a36Sopenharmony_ci			return;
7162306a36Sopenharmony_ci		}
7262306a36Sopenharmony_ci		cm_base = of_iomap(parent, 0);
7362306a36Sopenharmony_ci		of_node_put(parent);
7462306a36Sopenharmony_ci		if (!cm_base) {
7562306a36Sopenharmony_ci			pr_err("could not remap core module base\n");
7662306a36Sopenharmony_ci			return;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	parent_name = of_clk_get_parent_name(np, 0);
8162306a36Sopenharmony_ci	clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base);
8262306a36Sopenharmony_ci	if (!IS_ERR(clk))
8362306a36Sopenharmony_ci		of_clk_add_provider(np, of_clk_src_simple_get, clk);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void __init of_integrator_cm_osc_setup(struct device_node *np)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	cm_osc_setup(np, &cm_auxosc_desc);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ciCLK_OF_DECLARE(integrator_cm_auxosc_clk,
9162306a36Sopenharmony_ci	"arm,integrator-cm-auxosc", of_integrator_cm_osc_setup);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void __init of_versatile_cm_osc_setup(struct device_node *np)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	cm_osc_setup(np, &versatile_auxosc_desc);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ciCLK_OF_DECLARE(versatile_cm_auxosc_clk,
9862306a36Sopenharmony_ci	       "arm,versatile-cm-auxosc", of_versatile_cm_osc_setup);
99