clk: exynos-audss: convert to platform device
[deliverable/linux.git] / drivers / clk / samsung / clk-exynos-audss.c
CommitLineData
1241ef94
PV
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>
b37a4224
AB
17#include <linux/module.h>
18#include <linux/platform_device.h>
1241ef94
PV
19
20#include <dt-bindings/clk/exynos-audss-clk.h>
21
22static DEFINE_SPINLOCK(lock);
23static struct clk **clk_table;
24static void __iomem *reg_base;
25static struct clk_onecell_data clk_data;
26
27#define ASS_CLK_SRC 0x0
28#define ASS_CLK_DIV 0x4
29#define ASS_CLK_GATE 0x8
30
3fd68c99
KK
31/* list of all parent clock list */
32static const char *mout_audss_p[] = { "fin_pll", "fout_epll" };
33static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" };
34
35#ifdef CONFIG_PM_SLEEP
1241ef94
PV
36static unsigned long reg_save[][2] = {
37 {ASS_CLK_SRC, 0},
38 {ASS_CLK_DIV, 0},
39 {ASS_CLK_GATE, 0},
40};
41
1241ef94
PV
42static int exynos_audss_clk_suspend(void)
43{
44 int i;
45
46 for (i = 0; i < ARRAY_SIZE(reg_save); i++)
47 reg_save[i][1] = readl(reg_base + reg_save[i][0]);
48
49 return 0;
50}
51
52static void exynos_audss_clk_resume(void)
53{
54 int i;
55
56 for (i = 0; i < ARRAY_SIZE(reg_save); i++)
57 writel(reg_save[i][1], reg_base + reg_save[i][0]);
58}
59
60static struct syscore_ops exynos_audss_clk_syscore_ops = {
61 .suspend = exynos_audss_clk_suspend,
62 .resume = exynos_audss_clk_resume,
63};
64#endif /* CONFIG_PM_SLEEP */
65
66/* register exynos_audss clocks */
b37a4224 67static int exynos_audss_clk_probe(struct platform_device *pdev)
1241ef94 68{
b37a4224
AB
69 int i, ret = 0;
70 struct resource *res;
71
72 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
73 reg_base = devm_ioremap_resource(&pdev->dev, res);
74 if (IS_ERR(reg_base)) {
75 dev_err(&pdev->dev, "failed to map audss registers\n");
76 return PTR_ERR(reg_base);
1241ef94
PV
77 }
78
b37a4224
AB
79 clk_table = devm_kzalloc(&pdev->dev,
80 sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS,
1241ef94 81 GFP_KERNEL);
b37a4224
AB
82 if (!clk_table)
83 return -ENOMEM;
1241ef94
PV
84
85 clk_data.clks = clk_table;
86 clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS;
1241ef94
PV
87
88 clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss",
819c1de3
JH
89 mout_audss_p, ARRAY_SIZE(mout_audss_p),
90 CLK_SET_RATE_NO_REPARENT,
1241ef94
PV
91 reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
92
93 clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s",
819c1de3
JH
94 mout_i2s_p, ARRAY_SIZE(mout_i2s_p),
95 CLK_SET_RATE_NO_REPARENT,
1241ef94
PV
96 reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
97
98 clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp",
99 "mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4,
100 0, &lock);
101
102 clk_table[EXYNOS_DOUT_AUD_BUS] = clk_register_divider(NULL,
103 "dout_aud_bus", "dout_srp", 0,
104 reg_base + ASS_CLK_DIV, 4, 4, 0, &lock);
105
106 clk_table[EXYNOS_DOUT_I2S] = clk_register_divider(NULL, "dout_i2s",
107 "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0,
108 &lock);
109
110 clk_table[EXYNOS_SRP_CLK] = clk_register_gate(NULL, "srp_clk",
111 "dout_srp", CLK_SET_RATE_PARENT,
112 reg_base + ASS_CLK_GATE, 0, 0, &lock);
113
114 clk_table[EXYNOS_I2S_BUS] = clk_register_gate(NULL, "i2s_bus",
115 "dout_aud_bus", CLK_SET_RATE_PARENT,
116 reg_base + ASS_CLK_GATE, 2, 0, &lock);
117
118 clk_table[EXYNOS_SCLK_I2S] = clk_register_gate(NULL, "sclk_i2s",
119 "dout_i2s", CLK_SET_RATE_PARENT,
120 reg_base + ASS_CLK_GATE, 3, 0, &lock);
121
122 clk_table[EXYNOS_PCM_BUS] = clk_register_gate(NULL, "pcm_bus",
123 "sclk_pcm", CLK_SET_RATE_PARENT,
124 reg_base + ASS_CLK_GATE, 4, 0, &lock);
125
126 clk_table[EXYNOS_SCLK_PCM] = clk_register_gate(NULL, "sclk_pcm",
127 "div_pcm0", CLK_SET_RATE_PARENT,
128 reg_base + ASS_CLK_GATE, 5, 0, &lock);
129
b37a4224
AB
130 for (i = 0; i < clk_data.clk_num; i++) {
131 if (IS_ERR(clk_table[i])) {
132 dev_err(&pdev->dev, "failed to register clock %d\n", i);
133 ret = PTR_ERR(clk_table[i]);
134 goto unregister;
135 }
136 }
137
138 ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get,
139 &clk_data);
140 if (ret) {
141 dev_err(&pdev->dev, "failed to add clock provider\n");
142 goto unregister;
143 }
144
1241ef94
PV
145#ifdef CONFIG_PM_SLEEP
146 register_syscore_ops(&exynos_audss_clk_syscore_ops);
147#endif
148
b37a4224
AB
149 dev_info(&pdev->dev, "setup completed\n");
150
151 return 0;
152
153unregister:
154 for (i = 0; i < clk_data.clk_num; i++) {
155 if (!IS_ERR(clk_table[i]))
156 clk_unregister(clk_table[i]);
157 }
158
159 return ret;
160}
161
162static int exynos_audss_clk_remove(struct platform_device *pdev)
163{
164 int i;
165
166 of_clk_del_provider(pdev->dev.of_node);
167
168 for (i = 0; i < clk_data.clk_num; i++) {
169 if (!IS_ERR(clk_table[i]))
170 clk_unregister(clk_table[i]);
171 }
172
173 return 0;
1241ef94 174}
b37a4224
AB
175
176static const struct of_device_id exynos_audss_clk_of_match[] = {
177 { .compatible = "samsung,exynos4210-audss-clock", },
178 { .compatible = "samsung,exynos5250-audss-clock", },
179 {},
180};
181
182static struct platform_driver exynos_audss_clk_driver = {
183 .driver = {
184 .name = "exynos-audss-clk",
185 .owner = THIS_MODULE,
186 .of_match_table = exynos_audss_clk_of_match,
187 },
188 .probe = exynos_audss_clk_probe,
189 .remove = exynos_audss_clk_remove,
190};
191
192static int __init exynos_audss_clk_init(void)
193{
194 return platform_driver_register(&exynos_audss_clk_driver);
195}
196core_initcall(exynos_audss_clk_init);
197
198static void __exit exynos_audss_clk_exit(void)
199{
200 platform_driver_unregister(&exynos_audss_clk_driver);
201}
202module_exit(exynos_audss_clk_exit);
203
204MODULE_AUTHOR("Padmavathi Venna <padma.v@samsung.com>");
205MODULE_DESCRIPTION("Exynos Audio Subsystem Clock Controller");
206MODULE_LICENSE("GPL v2");
207MODULE_ALIAS("platform:exynos-audss-clk");
This page took 0.055566 seconds and 5 git commands to generate.