2 * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
4 * Copyright (C) 2014 Google, Inc
6 * Copyright (C) 2012 Samsung Electornics
7 * Jonghwa Lee <jonghwa3.lee@samsung.com>
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.
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.
19 * This driver is based on clk-max77686.c
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>
32 #include <linux/export.h>
34 #include "clk-max-gen.h"
37 struct regmap
*regmap
;
43 static struct max_gen_clk
*to_max_gen_clk(struct clk_hw
*hw
)
45 return container_of(hw
, struct max_gen_clk
, hw
);
48 static int max_gen_clk_prepare(struct clk_hw
*hw
)
50 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
52 return regmap_update_bits(max_gen
->regmap
, max_gen
->reg
,
53 max_gen
->mask
, max_gen
->mask
);
56 static void max_gen_clk_unprepare(struct clk_hw
*hw
)
58 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
60 regmap_update_bits(max_gen
->regmap
, max_gen
->reg
,
61 max_gen
->mask
, ~max_gen
->mask
);
64 static int max_gen_clk_is_prepared(struct clk_hw
*hw
)
66 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
70 ret
= regmap_read(max_gen
->regmap
, max_gen
->reg
, &val
);
75 return val
& max_gen
->mask
;
78 static unsigned long max_gen_recalc_rate(struct clk_hw
*hw
,
79 unsigned long parent_rate
)
84 struct clk_ops max_gen_clk_ops
= {
85 .prepare
= max_gen_clk_prepare
,
86 .unprepare
= max_gen_clk_unprepare
,
87 .is_prepared
= max_gen_clk_is_prepared
,
88 .recalc_rate
= max_gen_recalc_rate
,
90 EXPORT_SYMBOL_GPL(max_gen_clk_ops
);
92 static struct clk
*max_gen_clk_register(struct device
*dev
,
93 struct max_gen_clk
*max_gen
)
96 struct clk_hw
*hw
= &max_gen
->hw
;
99 clk
= devm_clk_register(dev
, hw
);
103 ret
= clk_register_clkdev(clk
, hw
->init
->name
, NULL
);
111 int max_gen_clk_probe(struct platform_device
*pdev
, struct regmap
*regmap
,
112 u32 reg
, struct clk_init_data
*clks_init
, int num_init
)
115 struct max_gen_clk
*max_gen_clks
;
117 struct device
*dev
= pdev
->dev
.parent
;
118 const char *clk_name
;
119 struct clk_init_data
*init
;
121 clocks
= devm_kzalloc(dev
, sizeof(struct clk
*) * num_init
, GFP_KERNEL
);
125 max_gen_clks
= devm_kzalloc(dev
, sizeof(struct max_gen_clk
)
126 * num_init
, GFP_KERNEL
);
130 for (i
= 0; i
< num_init
; i
++) {
131 max_gen_clks
[i
].regmap
= regmap
;
132 max_gen_clks
[i
].mask
= 1 << i
;
133 max_gen_clks
[i
].reg
= reg
;
135 init
= devm_kzalloc(dev
, sizeof(*init
), GFP_KERNEL
);
140 !of_property_read_string_index(dev
->of_node
,
141 "clock-output-names",
143 init
->name
= clk_name
;
145 init
->name
= clks_init
[i
].name
;
147 init
->ops
= clks_init
[i
].ops
;
148 init
->flags
= clks_init
[i
].flags
;
150 max_gen_clks
[i
].hw
.init
= init
;
152 clocks
[i
] = max_gen_clk_register(dev
, &max_gen_clks
[i
]);
153 if (IS_ERR(clocks
[i
])) {
154 ret
= PTR_ERR(clocks
[i
]);
155 dev_err(dev
, "failed to register %s\n",
156 max_gen_clks
[i
].hw
.init
->name
);
161 platform_set_drvdata(pdev
, clocks
);
164 struct clk_onecell_data
*of_data
;
166 of_data
= devm_kzalloc(dev
, sizeof(*of_data
), GFP_KERNEL
);
170 of_data
->clks
= clocks
;
171 of_data
->clk_num
= num_init
;
172 ret
= of_clk_add_provider(dev
->of_node
, of_clk_src_onecell_get
,
176 dev_err(dev
, "failed to register OF clock provider\n");
183 EXPORT_SYMBOL_GPL(max_gen_clk_probe
);
185 int max_gen_clk_remove(struct platform_device
*pdev
, int num_init
)
187 struct device
*dev
= pdev
->dev
.parent
;
190 of_clk_del_provider(dev
->of_node
);
194 EXPORT_SYMBOL_GPL(max_gen_clk_remove
);