11241ef94SPadmavathi Venna /* 21241ef94SPadmavathi Venna * Copyright (c) 2013 Samsung Electronics Co., Ltd. 31241ef94SPadmavathi Venna * Author: Padmavathi Venna <padma.v@samsung.com> 41241ef94SPadmavathi Venna * 51241ef94SPadmavathi Venna * This program is free software; you can redistribute it and/or modify 61241ef94SPadmavathi Venna * it under the terms of the GNU General Public License version 2 as 71241ef94SPadmavathi Venna * published by the Free Software Foundation. 81241ef94SPadmavathi Venna * 91241ef94SPadmavathi Venna * Common Clock Framework support for Audio Subsystem Clock Controller. 101241ef94SPadmavathi Venna */ 111241ef94SPadmavathi Venna 121241ef94SPadmavathi Venna #include <linux/clkdev.h> 131241ef94SPadmavathi Venna #include <linux/io.h> 141241ef94SPadmavathi Venna #include <linux/clk-provider.h> 151241ef94SPadmavathi Venna #include <linux/of_address.h> 161241ef94SPadmavathi Venna #include <linux/syscore_ops.h> 171241ef94SPadmavathi Venna 181241ef94SPadmavathi Venna #include <dt-bindings/clk/exynos-audss-clk.h> 191241ef94SPadmavathi Venna 201241ef94SPadmavathi Venna static DEFINE_SPINLOCK(lock); 211241ef94SPadmavathi Venna static struct clk **clk_table; 221241ef94SPadmavathi Venna static void __iomem *reg_base; 231241ef94SPadmavathi Venna static struct clk_onecell_data clk_data; 241241ef94SPadmavathi Venna 251241ef94SPadmavathi Venna #define ASS_CLK_SRC 0x0 261241ef94SPadmavathi Venna #define ASS_CLK_DIV 0x4 271241ef94SPadmavathi Venna #define ASS_CLK_GATE 0x8 281241ef94SPadmavathi Venna 291241ef94SPadmavathi Venna static unsigned long reg_save[][2] = { 301241ef94SPadmavathi Venna {ASS_CLK_SRC, 0}, 311241ef94SPadmavathi Venna {ASS_CLK_DIV, 0}, 321241ef94SPadmavathi Venna {ASS_CLK_GATE, 0}, 331241ef94SPadmavathi Venna }; 341241ef94SPadmavathi Venna 351241ef94SPadmavathi Venna /* list of all parent clock list */ 361241ef94SPadmavathi Venna static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; 371241ef94SPadmavathi Venna static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; 381241ef94SPadmavathi Venna 391241ef94SPadmavathi Venna #ifdef CONFIG_PM_SLEEP 401241ef94SPadmavathi Venna static int exynos_audss_clk_suspend(void) 411241ef94SPadmavathi Venna { 421241ef94SPadmavathi Venna int i; 431241ef94SPadmavathi Venna 441241ef94SPadmavathi Venna for (i = 0; i < ARRAY_SIZE(reg_save); i++) 451241ef94SPadmavathi Venna reg_save[i][1] = readl(reg_base + reg_save[i][0]); 461241ef94SPadmavathi Venna 471241ef94SPadmavathi Venna return 0; 481241ef94SPadmavathi Venna } 491241ef94SPadmavathi Venna 501241ef94SPadmavathi Venna static void exynos_audss_clk_resume(void) 511241ef94SPadmavathi Venna { 521241ef94SPadmavathi Venna int i; 531241ef94SPadmavathi Venna 541241ef94SPadmavathi Venna for (i = 0; i < ARRAY_SIZE(reg_save); i++) 551241ef94SPadmavathi Venna writel(reg_save[i][1], reg_base + reg_save[i][0]); 561241ef94SPadmavathi Venna } 571241ef94SPadmavathi Venna 581241ef94SPadmavathi Venna static struct syscore_ops exynos_audss_clk_syscore_ops = { 591241ef94SPadmavathi Venna .suspend = exynos_audss_clk_suspend, 601241ef94SPadmavathi Venna .resume = exynos_audss_clk_resume, 611241ef94SPadmavathi Venna }; 621241ef94SPadmavathi Venna #endif /* CONFIG_PM_SLEEP */ 631241ef94SPadmavathi Venna 641241ef94SPadmavathi Venna /* register exynos_audss clocks */ 651190338fSSachin Kamat static void __init exynos_audss_clk_init(struct device_node *np) 661241ef94SPadmavathi Venna { 671241ef94SPadmavathi Venna reg_base = of_iomap(np, 0); 681241ef94SPadmavathi Venna if (!reg_base) { 691241ef94SPadmavathi Venna pr_err("%s: failed to map audss registers\n", __func__); 701241ef94SPadmavathi Venna return; 711241ef94SPadmavathi Venna } 721241ef94SPadmavathi Venna 731241ef94SPadmavathi Venna clk_table = kzalloc(sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS, 741241ef94SPadmavathi Venna GFP_KERNEL); 751241ef94SPadmavathi Venna if (!clk_table) { 761241ef94SPadmavathi Venna pr_err("%s: could not allocate clk lookup table\n", __func__); 771241ef94SPadmavathi Venna return; 781241ef94SPadmavathi Venna } 791241ef94SPadmavathi Venna 801241ef94SPadmavathi Venna clk_data.clks = clk_table; 811241ef94SPadmavathi Venna clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS; 821241ef94SPadmavathi Venna of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 831241ef94SPadmavathi Venna 841241ef94SPadmavathi Venna clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", 85*819c1de3SJames Hogan mout_audss_p, ARRAY_SIZE(mout_audss_p), 86*819c1de3SJames Hogan CLK_SET_RATE_NO_REPARENT, 871241ef94SPadmavathi Venna reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); 881241ef94SPadmavathi Venna 891241ef94SPadmavathi Venna clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s", 90*819c1de3SJames Hogan mout_i2s_p, ARRAY_SIZE(mout_i2s_p), 91*819c1de3SJames Hogan CLK_SET_RATE_NO_REPARENT, 921241ef94SPadmavathi Venna reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); 931241ef94SPadmavathi Venna 941241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp", 951241ef94SPadmavathi Venna "mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4, 961241ef94SPadmavathi Venna 0, &lock); 971241ef94SPadmavathi Venna 981241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_AUD_BUS] = clk_register_divider(NULL, 991241ef94SPadmavathi Venna "dout_aud_bus", "dout_srp", 0, 1001241ef94SPadmavathi Venna reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); 1011241ef94SPadmavathi Venna 1021241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_I2S] = clk_register_divider(NULL, "dout_i2s", 1031241ef94SPadmavathi Venna "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0, 1041241ef94SPadmavathi Venna &lock); 1051241ef94SPadmavathi Venna 1061241ef94SPadmavathi Venna clk_table[EXYNOS_SRP_CLK] = clk_register_gate(NULL, "srp_clk", 1071241ef94SPadmavathi Venna "dout_srp", CLK_SET_RATE_PARENT, 1081241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 0, 0, &lock); 1091241ef94SPadmavathi Venna 1101241ef94SPadmavathi Venna clk_table[EXYNOS_I2S_BUS] = clk_register_gate(NULL, "i2s_bus", 1111241ef94SPadmavathi Venna "dout_aud_bus", CLK_SET_RATE_PARENT, 1121241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 2, 0, &lock); 1131241ef94SPadmavathi Venna 1141241ef94SPadmavathi Venna clk_table[EXYNOS_SCLK_I2S] = clk_register_gate(NULL, "sclk_i2s", 1151241ef94SPadmavathi Venna "dout_i2s", CLK_SET_RATE_PARENT, 1161241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 3, 0, &lock); 1171241ef94SPadmavathi Venna 1181241ef94SPadmavathi Venna clk_table[EXYNOS_PCM_BUS] = clk_register_gate(NULL, "pcm_bus", 1191241ef94SPadmavathi Venna "sclk_pcm", CLK_SET_RATE_PARENT, 1201241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 4, 0, &lock); 1211241ef94SPadmavathi Venna 1221241ef94SPadmavathi Venna clk_table[EXYNOS_SCLK_PCM] = clk_register_gate(NULL, "sclk_pcm", 1231241ef94SPadmavathi Venna "div_pcm0", CLK_SET_RATE_PARENT, 1241241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 5, 0, &lock); 1251241ef94SPadmavathi Venna 1261241ef94SPadmavathi Venna #ifdef CONFIG_PM_SLEEP 1271241ef94SPadmavathi Venna register_syscore_ops(&exynos_audss_clk_syscore_ops); 1281241ef94SPadmavathi Venna #endif 1291241ef94SPadmavathi Venna 1301241ef94SPadmavathi Venna pr_info("Exynos: Audss: clock setup completed\n"); 1311241ef94SPadmavathi Venna } 1321241ef94SPadmavathi Venna CLK_OF_DECLARE(exynos4210_audss_clk, "samsung,exynos4210-audss-clock", 1331241ef94SPadmavathi Venna exynos_audss_clk_init); 1341241ef94SPadmavathi Venna CLK_OF_DECLARE(exynos5250_audss_clk, "samsung,exynos5250-audss-clock", 1351241ef94SPadmavathi Venna exynos_audss_clk_init); 136