18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Clock driver for the ARM Integrator/AP, Integrator/CP, Versatile AB and
48c2ecf20Sopenharmony_ci * Versatile PB boards.
58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Linus Walleij
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/of.h>
108c2ecf20Sopenharmony_ci#include <linux/of_address.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "icst.h"
138c2ecf20Sopenharmony_ci#include "clk-icst.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define INTEGRATOR_HDR_LOCK_OFFSET	0x14
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define VERSATILE_SYS_OSCCLCD_OFFSET	0x1c
188c2ecf20Sopenharmony_ci#define VERSATILE_SYS_LOCK_OFFSET	0x20
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* Base offset for the core module */
218c2ecf20Sopenharmony_cistatic void __iomem *cm_base;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic const struct icst_params cp_auxosc_params = {
248c2ecf20Sopenharmony_ci	.vco_max	= ICST525_VCO_MAX_5V,
258c2ecf20Sopenharmony_ci	.vco_min	= ICST525_VCO_MIN,
268c2ecf20Sopenharmony_ci	.vd_min 	= 8,
278c2ecf20Sopenharmony_ci	.vd_max 	= 263,
288c2ecf20Sopenharmony_ci	.rd_min 	= 3,
298c2ecf20Sopenharmony_ci	.rd_max 	= 65,
308c2ecf20Sopenharmony_ci	.s2div		= icst525_s2div,
318c2ecf20Sopenharmony_ci	.idx2s		= icst525_idx2s,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const struct clk_icst_desc cm_auxosc_desc __initconst = {
358c2ecf20Sopenharmony_ci	.params = &cp_auxosc_params,
368c2ecf20Sopenharmony_ci	.vco_offset = 0x1c,
378c2ecf20Sopenharmony_ci	.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct icst_params versatile_auxosc_params = {
418c2ecf20Sopenharmony_ci	.vco_max	= ICST307_VCO_MAX,
428c2ecf20Sopenharmony_ci	.vco_min	= ICST307_VCO_MIN,
438c2ecf20Sopenharmony_ci	.vd_min		= 4 + 8,
448c2ecf20Sopenharmony_ci	.vd_max		= 511 + 8,
458c2ecf20Sopenharmony_ci	.rd_min		= 1 + 2,
468c2ecf20Sopenharmony_ci	.rd_max		= 127 + 2,
478c2ecf20Sopenharmony_ci	.s2div		= icst307_s2div,
488c2ecf20Sopenharmony_ci	.idx2s		= icst307_idx2s,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct clk_icst_desc versatile_auxosc_desc __initconst = {
528c2ecf20Sopenharmony_ci	.params = &versatile_auxosc_params,
538c2ecf20Sopenharmony_ci	.vco_offset = VERSATILE_SYS_OSCCLCD_OFFSET,
548c2ecf20Sopenharmony_ci	.lock_offset = VERSATILE_SYS_LOCK_OFFSET,
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_cistatic void __init cm_osc_setup(struct device_node *np,
578c2ecf20Sopenharmony_ci				const struct clk_icst_desc *desc)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct clk *clk;
608c2ecf20Sopenharmony_ci	const char *clk_name = np->name;
618c2ecf20Sopenharmony_ci	const char *parent_name;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (!cm_base) {
648c2ecf20Sopenharmony_ci		/* Remap the core module base if not done yet */
658c2ecf20Sopenharmony_ci		struct device_node *parent;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		parent = of_get_parent(np);
688c2ecf20Sopenharmony_ci		if (!parent) {
698c2ecf20Sopenharmony_ci			pr_err("no parent on core module clock\n");
708c2ecf20Sopenharmony_ci			return;
718c2ecf20Sopenharmony_ci		}
728c2ecf20Sopenharmony_ci		cm_base = of_iomap(parent, 0);
738c2ecf20Sopenharmony_ci		of_node_put(parent);
748c2ecf20Sopenharmony_ci		if (!cm_base) {
758c2ecf20Sopenharmony_ci			pr_err("could not remap core module base\n");
768c2ecf20Sopenharmony_ci			return;
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	parent_name = of_clk_get_parent_name(np, 0);
818c2ecf20Sopenharmony_ci	clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base);
828c2ecf20Sopenharmony_ci	if (!IS_ERR(clk))
838c2ecf20Sopenharmony_ci		of_clk_add_provider(np, of_clk_src_simple_get, clk);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void __init of_integrator_cm_osc_setup(struct device_node *np)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	cm_osc_setup(np, &cm_auxosc_desc);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciCLK_OF_DECLARE(integrator_cm_auxosc_clk,
918c2ecf20Sopenharmony_ci	"arm,integrator-cm-auxosc", of_integrator_cm_osc_setup);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void __init of_versatile_cm_osc_setup(struct device_node *np)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	cm_osc_setup(np, &versatile_auxosc_desc);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciCLK_OF_DECLARE(versatile_cm_auxosc_clk,
988c2ecf20Sopenharmony_ci	       "arm,versatile-cm-auxosc", of_versatile_cm_osc_setup);
99