1*1241ef94SPadmavathi Venna /* 2*1241ef94SPadmavathi Venna * Copyright (c) 2013 Samsung Electronics Co., Ltd. 3*1241ef94SPadmavathi Venna * Author: Padmavathi Venna <padma.v@samsung.com> 4*1241ef94SPadmavathi Venna * 5*1241ef94SPadmavathi Venna * This program is free software; you can redistribute it and/or modify 6*1241ef94SPadmavathi Venna * it under the terms of the GNU General Public License version 2 as 7*1241ef94SPadmavathi Venna * published by the Free Software Foundation. 8*1241ef94SPadmavathi Venna * 9*1241ef94SPadmavathi Venna * Common Clock Framework support for Audio Subsystem Clock Controller. 10*1241ef94SPadmavathi Venna */ 11*1241ef94SPadmavathi Venna 12*1241ef94SPadmavathi Venna #include <linux/clkdev.h> 13*1241ef94SPadmavathi Venna #include <linux/io.h> 14*1241ef94SPadmavathi Venna #include <linux/clk-provider.h> 15*1241ef94SPadmavathi Venna #include <linux/of_address.h> 16*1241ef94SPadmavathi Venna #include <linux/syscore_ops.h> 17*1241ef94SPadmavathi Venna 18*1241ef94SPadmavathi Venna #include <dt-bindings/clk/exynos-audss-clk.h> 19*1241ef94SPadmavathi Venna 20*1241ef94SPadmavathi Venna static DEFINE_SPINLOCK(lock); 21*1241ef94SPadmavathi Venna static struct clk **clk_table; 22*1241ef94SPadmavathi Venna static void __iomem *reg_base; 23*1241ef94SPadmavathi Venna static struct clk_onecell_data clk_data; 24*1241ef94SPadmavathi Venna 25*1241ef94SPadmavathi Venna #define ASS_CLK_SRC 0x0 26*1241ef94SPadmavathi Venna #define ASS_CLK_DIV 0x4 27*1241ef94SPadmavathi Venna #define ASS_CLK_GATE 0x8 28*1241ef94SPadmavathi Venna 29*1241ef94SPadmavathi Venna static unsigned long reg_save[][2] = { 30*1241ef94SPadmavathi Venna {ASS_CLK_SRC, 0}, 31*1241ef94SPadmavathi Venna {ASS_CLK_DIV, 0}, 32*1241ef94SPadmavathi Venna {ASS_CLK_GATE, 0}, 33*1241ef94SPadmavathi Venna }; 34*1241ef94SPadmavathi Venna 35*1241ef94SPadmavathi Venna /* list of all parent clock list */ 36*1241ef94SPadmavathi Venna static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; 37*1241ef94SPadmavathi Venna static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; 38*1241ef94SPadmavathi Venna 39*1241ef94SPadmavathi Venna #ifdef CONFIG_PM_SLEEP 40*1241ef94SPadmavathi Venna static int exynos_audss_clk_suspend(void) 41*1241ef94SPadmavathi Venna { 42*1241ef94SPadmavathi Venna int i; 43*1241ef94SPadmavathi Venna 44*1241ef94SPadmavathi Venna for (i = 0; i < ARRAY_SIZE(reg_save); i++) 45*1241ef94SPadmavathi Venna reg_save[i][1] = readl(reg_base + reg_save[i][0]); 46*1241ef94SPadmavathi Venna 47*1241ef94SPadmavathi Venna return 0; 48*1241ef94SPadmavathi Venna } 49*1241ef94SPadmavathi Venna 50*1241ef94SPadmavathi Venna static void exynos_audss_clk_resume(void) 51*1241ef94SPadmavathi Venna { 52*1241ef94SPadmavathi Venna int i; 53*1241ef94SPadmavathi Venna 54*1241ef94SPadmavathi Venna for (i = 0; i < ARRAY_SIZE(reg_save); i++) 55*1241ef94SPadmavathi Venna writel(reg_save[i][1], reg_base + reg_save[i][0]); 56*1241ef94SPadmavathi Venna } 57*1241ef94SPadmavathi Venna 58*1241ef94SPadmavathi Venna static struct syscore_ops exynos_audss_clk_syscore_ops = { 59*1241ef94SPadmavathi Venna .suspend = exynos_audss_clk_suspend, 60*1241ef94SPadmavathi Venna .resume = exynos_audss_clk_resume, 61*1241ef94SPadmavathi Venna }; 62*1241ef94SPadmavathi Venna #endif /* CONFIG_PM_SLEEP */ 63*1241ef94SPadmavathi Venna 64*1241ef94SPadmavathi Venna /* register exynos_audss clocks */ 65*1241ef94SPadmavathi Venna void __init exynos_audss_clk_init(struct device_node *np) 66*1241ef94SPadmavathi Venna { 67*1241ef94SPadmavathi Venna reg_base = of_iomap(np, 0); 68*1241ef94SPadmavathi Venna if (!reg_base) { 69*1241ef94SPadmavathi Venna pr_err("%s: failed to map audss registers\n", __func__); 70*1241ef94SPadmavathi Venna return; 71*1241ef94SPadmavathi Venna } 72*1241ef94SPadmavathi Venna 73*1241ef94SPadmavathi Venna clk_table = kzalloc(sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS, 74*1241ef94SPadmavathi Venna GFP_KERNEL); 75*1241ef94SPadmavathi Venna if (!clk_table) { 76*1241ef94SPadmavathi Venna pr_err("%s: could not allocate clk lookup table\n", __func__); 77*1241ef94SPadmavathi Venna return; 78*1241ef94SPadmavathi Venna } 79*1241ef94SPadmavathi Venna 80*1241ef94SPadmavathi Venna clk_data.clks = clk_table; 81*1241ef94SPadmavathi Venna clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS; 82*1241ef94SPadmavathi Venna of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 83*1241ef94SPadmavathi Venna 84*1241ef94SPadmavathi Venna clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", 85*1241ef94SPadmavathi Venna mout_audss_p, ARRAY_SIZE(mout_audss_p), 0, 86*1241ef94SPadmavathi Venna reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); 87*1241ef94SPadmavathi Venna 88*1241ef94SPadmavathi Venna clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s", 89*1241ef94SPadmavathi Venna mout_i2s_p, ARRAY_SIZE(mout_i2s_p), 0, 90*1241ef94SPadmavathi Venna reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); 91*1241ef94SPadmavathi Venna 92*1241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp", 93*1241ef94SPadmavathi Venna "mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4, 94*1241ef94SPadmavathi Venna 0, &lock); 95*1241ef94SPadmavathi Venna 96*1241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_AUD_BUS] = clk_register_divider(NULL, 97*1241ef94SPadmavathi Venna "dout_aud_bus", "dout_srp", 0, 98*1241ef94SPadmavathi Venna reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); 99*1241ef94SPadmavathi Venna 100*1241ef94SPadmavathi Venna clk_table[EXYNOS_DOUT_I2S] = clk_register_divider(NULL, "dout_i2s", 101*1241ef94SPadmavathi Venna "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0, 102*1241ef94SPadmavathi Venna &lock); 103*1241ef94SPadmavathi Venna 104*1241ef94SPadmavathi Venna clk_table[EXYNOS_SRP_CLK] = clk_register_gate(NULL, "srp_clk", 105*1241ef94SPadmavathi Venna "dout_srp", CLK_SET_RATE_PARENT, 106*1241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 0, 0, &lock); 107*1241ef94SPadmavathi Venna 108*1241ef94SPadmavathi Venna clk_table[EXYNOS_I2S_BUS] = clk_register_gate(NULL, "i2s_bus", 109*1241ef94SPadmavathi Venna "dout_aud_bus", CLK_SET_RATE_PARENT, 110*1241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 2, 0, &lock); 111*1241ef94SPadmavathi Venna 112*1241ef94SPadmavathi Venna clk_table[EXYNOS_SCLK_I2S] = clk_register_gate(NULL, "sclk_i2s", 113*1241ef94SPadmavathi Venna "dout_i2s", CLK_SET_RATE_PARENT, 114*1241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 3, 0, &lock); 115*1241ef94SPadmavathi Venna 116*1241ef94SPadmavathi Venna clk_table[EXYNOS_PCM_BUS] = clk_register_gate(NULL, "pcm_bus", 117*1241ef94SPadmavathi Venna "sclk_pcm", CLK_SET_RATE_PARENT, 118*1241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 4, 0, &lock); 119*1241ef94SPadmavathi Venna 120*1241ef94SPadmavathi Venna clk_table[EXYNOS_SCLK_PCM] = clk_register_gate(NULL, "sclk_pcm", 121*1241ef94SPadmavathi Venna "div_pcm0", CLK_SET_RATE_PARENT, 122*1241ef94SPadmavathi Venna reg_base + ASS_CLK_GATE, 5, 0, &lock); 123*1241ef94SPadmavathi Venna 124*1241ef94SPadmavathi Venna #ifdef CONFIG_PM_SLEEP 125*1241ef94SPadmavathi Venna register_syscore_ops(&exynos_audss_clk_syscore_ops); 126*1241ef94SPadmavathi Venna #endif 127*1241ef94SPadmavathi Venna 128*1241ef94SPadmavathi Venna pr_info("Exynos: Audss: clock setup completed\n"); 129*1241ef94SPadmavathi Venna } 130*1241ef94SPadmavathi Venna CLK_OF_DECLARE(exynos4210_audss_clk, "samsung,exynos4210-audss-clock", 131*1241ef94SPadmavathi Venna exynos_audss_clk_init); 132*1241ef94SPadmavathi Venna CLK_OF_DECLARE(exynos5250_audss_clk, "samsung,exynos5250-audss-clock", 133*1241ef94SPadmavathi Venna exynos_audss_clk_init); 134