diff options
-rw-r--r-- | Documentation/devicetree/bindings/clock/clk-exynos-audss.txt | 64 | ||||
-rw-r--r-- | drivers/clk/samsung/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos-audss.c | 133 | ||||
-rw-r--r-- | include/dt-bindings/clk/exynos-audss-clk.h | 25 |
4 files changed, 223 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt b/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt new file mode 100644 index 000000000000..a1201802f90d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/clk-exynos-audss.txt | |||
@@ -0,0 +1,64 @@ | |||
1 | * Samsung Audio Subsystem Clock Controller | ||
2 | |||
3 | The Samsung Audio Subsystem clock controller generates and supplies clocks | ||
4 | to Audio Subsystem block available in the S5PV210 and Exynos SoCs. The clock | ||
5 | binding described here is applicable to all SoC's in Exynos family. | ||
6 | |||
7 | Required Properties: | ||
8 | |||
9 | - compatible: should be one of the following: | ||
10 | - "samsung,exynos4210-audss-clock" - controller compatible with all Exynos4 SoCs. | ||
11 | - "samsung,exynos5250-audss-clock" - controller compatible with all Exynos5 SoCs. | ||
12 | |||
13 | - reg: physical base address and length of the controller's register set. | ||
14 | |||
15 | - #clock-cells: should be 1. | ||
16 | |||
17 | The following is the list of clocks generated by the controller. Each clock is | ||
18 | assigned an identifier and client nodes use this identifier to specify the | ||
19 | clock which they consume. Some of the clocks are available only on a particular | ||
20 | Exynos4 SoC and this is specified where applicable. | ||
21 | |||
22 | Provided clocks: | ||
23 | |||
24 | Clock ID SoC (if specific) | ||
25 | ----------------------------------------------- | ||
26 | |||
27 | mout_audss 0 | ||
28 | mout_i2s 1 | ||
29 | dout_srp 2 | ||
30 | dout_aud_bus 3 | ||
31 | dout_i2s 4 | ||
32 | srp_clk 5 | ||
33 | i2s_bus 6 | ||
34 | sclk_i2s 7 | ||
35 | pcm_bus 8 | ||
36 | sclk_pcm 9 | ||
37 | |||
38 | Example 1: An example of a clock controller node is listed below. | ||
39 | |||
40 | clock_audss: audss-clock-controller@3810000 { | ||
41 | compatible = "samsung,exynos5250-audss-clock"; | ||
42 | reg = <0x03810000 0x0C>; | ||
43 | #clock-cells = <1>; | ||
44 | }; | ||
45 | |||
46 | Example 2: I2S controller node that consumes the clock generated by the clock | ||
47 | controller. Refer to the standard clock bindings for information | ||
48 | about 'clocks' and 'clock-names' property. | ||
49 | |||
50 | i2s0: i2s@03830000 { | ||
51 | compatible = "samsung,i2s-v5"; | ||
52 | reg = <0x03830000 0x100>; | ||
53 | dmas = <&pdma0 10 | ||
54 | &pdma0 9 | ||
55 | &pdma0 8>; | ||
56 | dma-names = "tx", "rx", "tx-sec"; | ||
57 | clocks = <&clock_audss EXYNOS_I2S_BUS>, | ||
58 | <&clock_audss EXYNOS_I2S_BUS>, | ||
59 | <&clock_audss EXYNOS_SCLK_I2S>, | ||
60 | <&clock_audss EXYNOS_MOUT_AUDSS>, | ||
61 | <&clock_audss EXYNOS_MOUT_I2S>; | ||
62 | clock-names = "iis", "i2s_opclk0", "i2s_opclk1", | ||
63 | "mout_audss", "mout_i2s"; | ||
64 | }; | ||
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index b7c232e67425..187681013bdb 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o | |||
6 | obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o | 6 | obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o |
7 | obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o | 7 | obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o |
8 | obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o | 8 | obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o |
9 | obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o | ||
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c new file mode 100644 index 000000000000..9b1bbd52fd1f --- /dev/null +++ b/drivers/clk/samsung/clk-exynos-audss.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
3 | * Author: Padmavathi Venna <padma.v@samsung.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * Common Clock Framework support for Audio Subsystem Clock Controller. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clkdev.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/of_address.h> | ||
16 | #include <linux/syscore_ops.h> | ||
17 | |||
18 | #include <dt-bindings/clk/exynos-audss-clk.h> | ||
19 | |||
20 | static DEFINE_SPINLOCK(lock); | ||
21 | static struct clk **clk_table; | ||
22 | static void __iomem *reg_base; | ||
23 | static struct clk_onecell_data clk_data; | ||
24 | |||
25 | #define ASS_CLK_SRC 0x0 | ||
26 | #define ASS_CLK_DIV 0x4 | ||
27 | #define ASS_CLK_GATE 0x8 | ||
28 | |||
29 | static unsigned long reg_save[][2] = { | ||
30 | {ASS_CLK_SRC, 0}, | ||
31 | {ASS_CLK_DIV, 0}, | ||
32 | {ASS_CLK_GATE, 0}, | ||
33 | }; | ||
34 | |||
35 | /* list of all parent clock list */ | ||
36 | static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; | ||
37 | static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; | ||
38 | |||
39 | #ifdef CONFIG_PM_SLEEP | ||
40 | static int exynos_audss_clk_suspend(void) | ||
41 | { | ||
42 | int i; | ||
43 | |||
44 | for (i = 0; i < ARRAY_SIZE(reg_save); i++) | ||
45 | reg_save[i][1] = readl(reg_base + reg_save[i][0]); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void exynos_audss_clk_resume(void) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | for (i = 0; i < ARRAY_SIZE(reg_save); i++) | ||
55 | writel(reg_save[i][1], reg_base + reg_save[i][0]); | ||
56 | } | ||
57 | |||
58 | static struct syscore_ops exynos_audss_clk_syscore_ops = { | ||
59 | .suspend = exynos_audss_clk_suspend, | ||
60 | .resume = exynos_audss_clk_resume, | ||
61 | }; | ||
62 | #endif /* CONFIG_PM_SLEEP */ | ||
63 | |||
64 | /* register exynos_audss clocks */ | ||
65 | void __init exynos_audss_clk_init(struct device_node *np) | ||
66 | { | ||
67 | reg_base = of_iomap(np, 0); | ||
68 | if (!reg_base) { | ||
69 | pr_err("%s: failed to map audss registers\n", __func__); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | clk_table = kzalloc(sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS, | ||
74 | GFP_KERNEL); | ||
75 | if (!clk_table) { | ||
76 | pr_err("%s: could not allocate clk lookup table\n", __func__); | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | clk_data.clks = clk_table; | ||
81 | clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS; | ||
82 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
83 | |||
84 | clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", | ||
85 | mout_audss_p, ARRAY_SIZE(mout_audss_p), 0, | ||
86 | reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); | ||
87 | |||
88 | clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s", | ||
89 | mout_i2s_p, ARRAY_SIZE(mout_i2s_p), 0, | ||
90 | reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); | ||
91 | |||
92 | clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp", | ||
93 | "mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4, | ||
94 | 0, &lock); | ||
95 | |||
96 | clk_table[EXYNOS_DOUT_AUD_BUS] = clk_register_divider(NULL, | ||
97 | "dout_aud_bus", "dout_srp", 0, | ||
98 | reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); | ||
99 | |||
100 | clk_table[EXYNOS_DOUT_I2S] = clk_register_divider(NULL, "dout_i2s", | ||
101 | "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0, | ||
102 | &lock); | ||
103 | |||
104 | clk_table[EXYNOS_SRP_CLK] = clk_register_gate(NULL, "srp_clk", | ||
105 | "dout_srp", CLK_SET_RATE_PARENT, | ||
106 | reg_base + ASS_CLK_GATE, 0, 0, &lock); | ||
107 | |||
108 | clk_table[EXYNOS_I2S_BUS] = clk_register_gate(NULL, "i2s_bus", | ||
109 | "dout_aud_bus", CLK_SET_RATE_PARENT, | ||
110 | reg_base + ASS_CLK_GATE, 2, 0, &lock); | ||
111 | |||
112 | clk_table[EXYNOS_SCLK_I2S] = clk_register_gate(NULL, "sclk_i2s", | ||
113 | "dout_i2s", CLK_SET_RATE_PARENT, | ||
114 | reg_base + ASS_CLK_GATE, 3, 0, &lock); | ||
115 | |||
116 | clk_table[EXYNOS_PCM_BUS] = clk_register_gate(NULL, "pcm_bus", | ||
117 | "sclk_pcm", CLK_SET_RATE_PARENT, | ||
118 | reg_base + ASS_CLK_GATE, 4, 0, &lock); | ||
119 | |||
120 | clk_table[EXYNOS_SCLK_PCM] = clk_register_gate(NULL, "sclk_pcm", | ||
121 | "div_pcm0", CLK_SET_RATE_PARENT, | ||
122 | reg_base + ASS_CLK_GATE, 5, 0, &lock); | ||
123 | |||
124 | #ifdef CONFIG_PM_SLEEP | ||
125 | register_syscore_ops(&exynos_audss_clk_syscore_ops); | ||
126 | #endif | ||
127 | |||
128 | pr_info("Exynos: Audss: clock setup completed\n"); | ||
129 | } | ||
130 | CLK_OF_DECLARE(exynos4210_audss_clk, "samsung,exynos4210-audss-clock", | ||
131 | exynos_audss_clk_init); | ||
132 | CLK_OF_DECLARE(exynos5250_audss_clk, "samsung,exynos5250-audss-clock", | ||
133 | exynos_audss_clk_init); | ||
diff --git a/include/dt-bindings/clk/exynos-audss-clk.h b/include/dt-bindings/clk/exynos-audss-clk.h new file mode 100644 index 000000000000..8279f427c60f --- /dev/null +++ b/include/dt-bindings/clk/exynos-audss-clk.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * This header provides constants for Samsung audio subsystem | ||
3 | * clock controller. | ||
4 | * | ||
5 | * The constants defined in this header are being used in dts | ||
6 | * and exynos audss driver. | ||
7 | */ | ||
8 | |||
9 | #ifndef _DT_BINDINGS_CLK_EXYNOS_AUDSS_H | ||
10 | #define _DT_BINDINGS_CLK_EXYNOS_AUDSS_H | ||
11 | |||
12 | #define EXYNOS_MOUT_AUDSS 0 | ||
13 | #define EXYNOS_MOUT_I2S 1 | ||
14 | #define EXYNOS_DOUT_SRP 2 | ||
15 | #define EXYNOS_DOUT_AUD_BUS 3 | ||
16 | #define EXYNOS_DOUT_I2S 4 | ||
17 | #define EXYNOS_SRP_CLK 5 | ||
18 | #define EXYNOS_I2S_BUS 6 | ||
19 | #define EXYNOS_SCLK_I2S 7 | ||
20 | #define EXYNOS_PCM_BUS 8 | ||
21 | #define EXYNOS_SCLK_PCM 9 | ||
22 | |||
23 | #define EXYNOS_AUDSS_MAX_CLKS 10 | ||
24 | |||
25 | #endif | ||