aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martinez Canillas <javier.martinez@collabora.co.uk>2014-08-18 04:33:00 -0400
committerMike Turquette <mturquette@linaro.org>2014-09-09 16:55:44 -0400
commit5dbbb00f712edff8454f9741db61f9e0a4fec919 (patch)
tree61c65532c51b8c9903f6b37b2b4228fd7e65679c
parenta8a76f563cfa1a4e47b6d8b2bef9c0d44a3fd7b0 (diff)
clk: Add generic driver for Maxim PMIC clocks
Maxim Integrated Power Management ICs are very similar with regard to their clock outputs. Most of the clock drivers for these chips are duplicating code and are simpler enough that can be converted to use a generic driver to consolidate code and avoid duplication. Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/Kconfig3
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-max-gen.c192
-rw-r--r--drivers/clk/clk-max-gen.h32
4 files changed, 228 insertions, 0 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index cfd3af7b2cbd..726d72aad49f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -32,6 +32,9 @@ config COMMON_CLK_WM831X
32 32
33source "drivers/clk/versatile/Kconfig" 33source "drivers/clk/versatile/Kconfig"
34 34
35config COMMON_CLK_MAX_GEN
36 bool
37
35config COMMON_CLK_MAX77686 38config COMMON_CLK_MAX77686
36 tristate "Clock driver for Maxim 77686 MFD" 39 tristate "Clock driver for Maxim 77686 MFD"
37 depends on MFD_MAX77686 40 depends on MFD_MAX77686
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f537a0b1f798..9de85f689ff5 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
22obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o 22obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
23obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o 23obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
24obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o 24obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
25obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
25obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o 26obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
26obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o 27obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
27obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o 28obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
new file mode 100644
index 000000000000..6505049d50f1
--- /dev/null
+++ b/drivers/clk/clk-max-gen.c
@@ -0,0 +1,192 @@
1/*
2 * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
3 *
4 * Copyright (C) 2014 Google, Inc
5 *
6 * Copyright (C) 2012 Samsung Electornics
7 * Jonghwa Lee <jonghwa3.lee@samsung.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * This driver is based on clk-max77686.c
20 *
21 */
22
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/err.h>
26#include <linux/regmap.h>
27#include <linux/platform_device.h>
28#include <linux/clk-provider.h>
29#include <linux/mutex.h>
30#include <linux/clkdev.h>
31#include <linux/of.h>
32#include <linux/export.h>
33
34struct max_gen_clk {
35 struct regmap *regmap;
36 u32 mask;
37 u32 reg;
38 struct clk_hw hw;
39};
40
41static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
42{
43 return container_of(hw, struct max_gen_clk, hw);
44}
45
46static int max_gen_clk_prepare(struct clk_hw *hw)
47{
48 struct max_gen_clk *max_gen = to_max_gen_clk(hw);
49
50 return regmap_update_bits(max_gen->regmap, max_gen->reg,
51 max_gen->mask, max_gen->mask);
52}
53
54static void max_gen_clk_unprepare(struct clk_hw *hw)
55{
56 struct max_gen_clk *max_gen = to_max_gen_clk(hw);
57
58 regmap_update_bits(max_gen->regmap, max_gen->reg,
59 max_gen->mask, ~max_gen->mask);
60}
61
62static int max_gen_clk_is_prepared(struct clk_hw *hw)
63{
64 struct max_gen_clk *max_gen = to_max_gen_clk(hw);
65 int ret;
66 u32 val;
67
68 ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
69
70 if (ret < 0)
71 return -EINVAL;
72
73 return val & max_gen->mask;
74}
75
76static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
77 unsigned long parent_rate)
78{
79 return 32768;
80}
81
82struct clk_ops max_gen_clk_ops = {
83 .prepare = max_gen_clk_prepare,
84 .unprepare = max_gen_clk_unprepare,
85 .is_prepared = max_gen_clk_is_prepared,
86 .recalc_rate = max_gen_recalc_rate,
87};
88EXPORT_SYMBOL_GPL(max_gen_clk_ops);
89
90static struct clk *max_gen_clk_register(struct device *dev,
91 struct max_gen_clk *max_gen)
92{
93 struct clk *clk;
94 struct clk_hw *hw = &max_gen->hw;
95 int ret;
96
97 clk = devm_clk_register(dev, hw);
98 if (IS_ERR(clk))
99 return clk;
100
101 ret = clk_register_clkdev(clk, hw->init->name, NULL);
102
103 if (ret)
104 return ERR_PTR(ret);
105
106 return clk;
107}
108
109int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
110 u32 reg, struct clk_init_data *clks_init, int num_init)
111{
112 int i, ret;
113 struct max_gen_clk *max_gen_clks;
114 struct clk **clocks;
115 struct device *dev = pdev->dev.parent;
116 const char *clk_name;
117 struct clk_init_data *init;
118
119 clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
120 if (!clocks)
121 return -ENOMEM;
122
123 max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
124 * num_init, GFP_KERNEL);
125 if (!max_gen_clks)
126 return -ENOMEM;
127
128 for (i = 0; i < num_init; i++) {
129 max_gen_clks[i].regmap = regmap;
130 max_gen_clks[i].mask = 1 << i;
131 max_gen_clks[i].reg = reg;
132
133 init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
134 if (!init)
135 return -ENOMEM;
136
137 if (dev->of_node &&
138 !of_property_read_string_index(dev->of_node,
139 "clock-output-names",
140 i, &clk_name))
141 init->name = clk_name;
142 else
143 init->name = clks_init[i].name;
144
145 init->ops = clks_init[i].ops;
146 init->flags = clks_init[i].flags;
147
148 max_gen_clks[i].hw.init = init;
149
150 clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
151 if (IS_ERR(clocks[i])) {
152 ret = PTR_ERR(clocks[i]);
153 dev_err(dev, "failed to register %s\n",
154 max_gen_clks[i].hw.init->name);
155 return ret;
156 }
157 }
158
159 platform_set_drvdata(pdev, clocks);
160
161 if (dev->of_node) {
162 struct clk_onecell_data *of_data;
163
164 of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
165 if (!of_data)
166 return -ENOMEM;
167
168 of_data->clks = clocks;
169 of_data->clk_num = num_init;
170 ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
171 of_data);
172
173 if (ret) {
174 dev_err(dev, "failed to register OF clock provider\n");
175 return ret;
176 }
177 }
178
179 return 0;
180}
181EXPORT_SYMBOL_GPL(max_gen_clk_probe);
182
183int max_gen_clk_remove(struct platform_device *pdev, int num_init)
184{
185 struct device *dev = pdev->dev.parent;
186
187 if (dev->of_node)
188 of_clk_del_provider(dev->of_node);
189
190 return 0;
191}
192EXPORT_SYMBOL_GPL(max_gen_clk_remove);
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
new file mode 100644
index 000000000000..997e86fc3f4d
--- /dev/null
+++ b/drivers/clk/clk-max-gen.h
@@ -0,0 +1,32 @@
1/*
2 * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
3 *
4 * Copyright (C) 2014 Google, Inc
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef __CLK_MAX_GEN_H__
19#define __CLK_MAX_GEN_H__
20
21#include <linux/types.h>
22#include <linux/device.h>
23#include <linux/clkdev.h>
24#include <linux/regmap.h>
25#include <linux/platform_device.h>
26
27int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
28 u32 reg, struct clk_init_data *clks_init, int num_init);
29int max_gen_clk_remove(struct platform_device *pdev, int num_init);
30extern struct clk_ops max_gen_clk_ops;
31
32#endif /* __CLK_MAX_GEN_H__ */