18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Pengutronix
48c2ecf20Sopenharmony_ci * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/io.h>
78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
88c2ecf20Sopenharmony_ci#include <linux/of.h>
98c2ecf20Sopenharmony_ci#include <linux/of_address.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <dt-bindings/clock/efm32-cmu.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define CMU_HFPERCLKEN0		0x44
158c2ecf20Sopenharmony_ci#define CMU_MAX_CLKS		37
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic struct clk_hw_onecell_data *clk_data;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void __init efm32gg_cmu_init(struct device_node *np)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	int i;
228c2ecf20Sopenharmony_ci	void __iomem *base;
238c2ecf20Sopenharmony_ci	struct clk_hw **hws;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	clk_data = kzalloc(struct_size(clk_data, hws, CMU_MAX_CLKS),
268c2ecf20Sopenharmony_ci			   GFP_KERNEL);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	if (!clk_data)
298c2ecf20Sopenharmony_ci		return;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	hws = clk_data->hws;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	for (i = 0; i < CMU_MAX_CLKS; ++i)
348c2ecf20Sopenharmony_ci		hws[i] = ERR_PTR(-ENOENT);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	base = of_iomap(np, 0);
378c2ecf20Sopenharmony_ci	if (!base) {
388c2ecf20Sopenharmony_ci		pr_warn("Failed to map address range for efm32gg,cmu node\n");
398c2ecf20Sopenharmony_ci		return;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	hws[clk_HFXO] = clk_hw_register_fixed_rate(NULL, "HFXO", NULL, 0,
438c2ecf20Sopenharmony_ci						   48000000);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKUSART0] = clk_hw_register_gate(NULL, "HFPERCLK.USART0",
468c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 0, 0, NULL);
478c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKUSART1] = clk_hw_register_gate(NULL, "HFPERCLK.USART1",
488c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 1, 0, NULL);
498c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKUSART2] = clk_hw_register_gate(NULL, "HFPERCLK.USART2",
508c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 2, 0, NULL);
518c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKUART0] = clk_hw_register_gate(NULL, "HFPERCLK.UART0",
528c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 3, 0, NULL);
538c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKUART1] = clk_hw_register_gate(NULL, "HFPERCLK.UART1",
548c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 4, 0, NULL);
558c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKTIMER0] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER0",
568c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 5, 0, NULL);
578c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKTIMER1] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER1",
588c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 6, 0, NULL);
598c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKTIMER2] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER2",
608c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 7, 0, NULL);
618c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKTIMER3] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER3",
628c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 8, 0, NULL);
638c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKACMP0] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP0",
648c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 9, 0, NULL);
658c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKACMP1] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP1",
668c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 10, 0, NULL);
678c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKI2C0] = clk_hw_register_gate(NULL, "HFPERCLK.I2C0",
688c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 11, 0, NULL);
698c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKI2C1] = clk_hw_register_gate(NULL, "HFPERCLK.I2C1",
708c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 12, 0, NULL);
718c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKGPIO] = clk_hw_register_gate(NULL, "HFPERCLK.GPIO",
728c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 13, 0, NULL);
738c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKVCMP] = clk_hw_register_gate(NULL, "HFPERCLK.VCMP",
748c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 14, 0, NULL);
758c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKPRS] = clk_hw_register_gate(NULL, "HFPERCLK.PRS",
768c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 15, 0, NULL);
778c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKADC0] = clk_hw_register_gate(NULL, "HFPERCLK.ADC0",
788c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 16, 0, NULL);
798c2ecf20Sopenharmony_ci	hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0",
808c2ecf20Sopenharmony_ci			"HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ciCLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init);
85