17b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/*
27b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * r8a7779 Core CPG Clocks
37b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *
47b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Copyright (C) 2013, 2014 Horms Solutions Ltd.
57b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *
67b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Contact: Simon Horman <horms@verge.net.au>
77b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *
87b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * This program is free software; you can redistribute it and/or modify
97b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * it under the terms of the GNU General Public License as published by
107b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * the Free Software Foundation; version 2 of the License.
117b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */
127b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
137b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clk-provider.h>
147b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clkdev.h>
157b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clk/shmobile.h>
167b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/init.h>
177b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/kernel.h>
187b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/of.h>
197b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/of_address.h>
207b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/spinlock.h>
217b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
227b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <dt-bindings/clock/r8a7779-clock.h>
237b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
247b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_NUM_CLOCKS			(R8A7779_CLK_OUT + 1)
257b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
267b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstruct r8a7779_cpg {
277b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	struct clk_onecell_data data;
287b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	spinlock_t lock;
297b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	void __iomem *reg;
307b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman};
317b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
327b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* -----------------------------------------------------------------------------
337b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * CPG Clock Data
347b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */
357b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
367b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/*
377b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *		MD1 = 1			MD1 = 0
387b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *		(PLLA = 1500)		(PLLA = 1600)
397b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *		(MHz)			(MHz)
407b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *------------------------------------------------+--------------------
417b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkz		1000   (2/3)		800   (1/2)
427b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkzs	 250   (1/6)		200   (1/8)
437b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clki		 750   (1/2)		800   (1/2)
447b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks		 250   (1/6)		200   (1/8)
457b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks1	 125   (1/12)		100   (1/16)
467b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks3	 187.5 (1/8)		200   (1/8)
477b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks4	  93.7 (1/16)		100   (1/16)
487b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkp		  62.5 (1/24)		 50   (1/32)
497b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkg		  62.5 (1/24)		 66.6 (1/24)
507b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkb, CLKOUT
517b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (MD2 = 0)	  62.5 (1/24)		 66.6 (1/24)
527b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (MD2 = 1)	  41.6 (1/36)		 50   (1/32)
537b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */
547b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
557b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_CLK_CONFIG_INDEX(md)	(((md) & (BIT(2)|BIT(1))) >> 1)
567b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
577b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstruct cpg_clk_config {
587b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int z_mult;
597b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int z_div;
607b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int zs_and_s_div;
617b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int s1_div;
627b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int p_div;
637b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int b_and_out_div;
647b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman};
657b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
667b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
677b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	{ 1, 2, 8, 16, 32, 24 },
687b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	{ 2, 3, 6, 12, 24, 24 },
697b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	{ 1, 2, 8, 16, 32, 32 },
707b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	{ 2, 3, 6, 12, 24, 36 },
717b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman};
727b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
737b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/*
747b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *   MD		PLLA Ratio
757b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 12 11
767b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *------------------------
777b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 0  0		x42
787b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 0  1		x48
797b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 1  0		x56
807b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 1  1		x64
817b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */
827b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
837b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_PLLA_MULT_INDEX(md)	(((md) & (BIT(12)|BIT(11))) >> 11)
847b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
857b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
867b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
877b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* -----------------------------------------------------------------------------
887b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Initialization
897b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */
907b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
917b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic u32 cpg_mode __initdata;
927b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
937b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic struct clk * __init
947b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanr8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
957b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman			   const struct cpg_clk_config *config,
967b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman			   unsigned int plla_mult, const char *name)
977b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{
987b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	const char *parent_name = "plla";
997b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int mult = 1;
1007b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int div = 1;
1017b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1027b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	if (!strcmp(name, "plla")) {
1037b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		parent_name = of_clk_get_parent_name(np, 0);
1047b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		mult = plla_mult;
1057b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else if (!strcmp(name, "z")) {
1067b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		div = config->z_div;
1077b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		mult = config->z_mult;
1087b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
1097b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		div = config->zs_and_s_div;
1107b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else if (!strcmp(name, "s1")) {
1117b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		div = config->s1_div;
1127b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else if (!strcmp(name, "p")) {
1137b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		div = config->p_div;
1147b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else if (!strcmp(name, "b") || !strcmp(name, "out")) {
1157b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		div = config->b_and_out_div;
1167b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	} else {
1177b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		return ERR_PTR(-EINVAL);
1187b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	}
1197b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1207b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
1217b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}
1227b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1237b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic void __init r8a7779_cpg_clocks_init(struct device_node *np)
1247b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{
1257b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	const struct cpg_clk_config *config;
1267b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	struct r8a7779_cpg *cpg;
1277b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	struct clk **clks;
1287b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	unsigned int i, plla_mult;
1297b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	int num_clks;
1307b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1317b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	num_clks = of_property_count_strings(np, "clock-output-names");
1327b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	if (num_clks < 0) {
1337b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		pr_err("%s: failed to count clocks\n", __func__);
1347b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		return;
1357b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	}
1367b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1377b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
1387b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL);
1397b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	if (cpg == NULL || clks == NULL) {
1407b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		/* We're leaking memory on purpose, there's no point in cleaning
1417b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		 * up as the system won't boot anyway.
1427b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		 */
1437b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		return;
1447b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	}
1457b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1467b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	spin_lock_init(&cpg->lock);
1477b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1487b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	cpg->data.clks = clks;
1497b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	cpg->data.clk_num = num_clks;
1507b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1517b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
1527b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
1537b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1547b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	for (i = 0; i < num_clks; ++i) {
1557b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		const char *name;
1567b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		struct clk *clk;
1577b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1587b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		of_property_read_string_index(np, "clock-output-names", i,
1597b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman					      &name);
1607b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1617b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		clk = r8a7779_cpg_register_clock(np, cpg, config,
1627b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman						 plla_mult, name);
1637b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		if (IS_ERR(clk))
1647b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman			pr_err("%s: failed to register %s %s clock (%ld)\n",
1657b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman			       __func__, np->name, name, PTR_ERR(clk));
1667b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman		else
1677b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman			cpg->data.clks[i] = clk;
1687b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	}
1697b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1707b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
1717b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}
1727b42a997bfb93c6ae0709f34ec8e2860757804b5Simon HormanCLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
1737b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	       r8a7779_cpg_clocks_init);
1747b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1757b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanvoid __init r8a7779_clocks_init(u32 mode)
1767b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{
1777b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	cpg_mode = mode;
1787b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman
1797b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman	of_clk_init(NULL);
1807b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}
181