|
7 | 7 | #include <linux/clkdev.h>
|
8 | 8 | #include <linux/err.h>
|
9 | 9 | #include <linux/io.h>
|
| 10 | +#include <linux/platform_device.h> |
10 | 11 | #include <linux/platform_data/clk-integrator.h>
|
| 12 | +#include <linux/module.h> |
| 13 | +#include <linux/mfd/syscon.h> |
| 14 | +#include <linux/regmap.h> |
11 | 15 |
|
12 | 16 | #include "icst.h"
|
13 | 17 | #include "clk-icst.h"
|
@@ -175,3 +179,78 @@ void integrator_impd1_clk_exit(unsigned int id)
|
175 | 179 | kfree(imc->pclkname);
|
176 | 180 | }
|
177 | 181 | EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit);
|
| 182 | + |
| 183 | +static int integrator_impd1_clk_spawn(struct device *dev, |
| 184 | + struct device_node *parent, |
| 185 | + struct device_node *np) |
| 186 | +{ |
| 187 | + struct regmap *map; |
| 188 | + struct clk *clk = ERR_PTR(-EINVAL); |
| 189 | + const char *name = np->name; |
| 190 | + const char *parent_name; |
| 191 | + const struct clk_icst_desc *desc; |
| 192 | + int ret; |
| 193 | + |
| 194 | + map = syscon_node_to_regmap(parent); |
| 195 | + if (IS_ERR(map)) { |
| 196 | + pr_err("no regmap for syscon IM-PD1 ICST clock parent\n"); |
| 197 | + return PTR_ERR(map); |
| 198 | + } |
| 199 | + |
| 200 | + if (of_device_is_compatible(np, "arm,impd1-vco1")) { |
| 201 | + desc = &impd1_icst1_desc; |
| 202 | + } else if (of_device_is_compatible(np, "arm,impd1-vco2")) { |
| 203 | + desc = &impd1_icst2_desc; |
| 204 | + } else { |
| 205 | + dev_err(dev, "not a clock node %s\n", name); |
| 206 | + return -ENODEV; |
| 207 | + } |
| 208 | + |
| 209 | + parent_name = of_clk_get_parent_name(np, 0); |
| 210 | + clk = icst_clk_setup(NULL, desc, name, parent_name, map, |
| 211 | + ICST_INTEGRATOR_IM_PD1); |
| 212 | + if (!IS_ERR(clk)) { |
| 213 | + of_clk_add_provider(np, of_clk_src_simple_get, clk); |
| 214 | + ret = 0; |
| 215 | + } else { |
| 216 | + dev_err(dev, "error setting up IM-PD1 ICST clock\n"); |
| 217 | + ret = PTR_ERR(clk); |
| 218 | + } |
| 219 | + |
| 220 | + return ret; |
| 221 | +} |
| 222 | + |
| 223 | +static int integrator_impd1_clk_probe(struct platform_device *pdev) |
| 224 | +{ |
| 225 | + struct device *dev = &pdev->dev; |
| 226 | + struct device_node *np = dev->of_node; |
| 227 | + struct device_node *child; |
| 228 | + int ret = 0; |
| 229 | + |
| 230 | + for_each_available_child_of_node(np, child) { |
| 231 | + ret = integrator_impd1_clk_spawn(dev, np, child); |
| 232 | + if (ret) |
| 233 | + break; |
| 234 | + } |
| 235 | + |
| 236 | + return ret; |
| 237 | +} |
| 238 | + |
| 239 | +static const struct of_device_id impd1_syscon_match[] = { |
| 240 | + { .compatible = "arm,im-pd1-syscon", }, |
| 241 | + {} |
| 242 | +}; |
| 243 | +MODULE_DEVICE_TABLE(of, impd1_syscon_match); |
| 244 | + |
| 245 | +static struct platform_driver impd1_clk_driver = { |
| 246 | + .driver = { |
| 247 | + .name = "impd1-clk", |
| 248 | + .of_match_table = impd1_syscon_match, |
| 249 | + }, |
| 250 | + .probe = integrator_impd1_clk_probe, |
| 251 | +}; |
| 252 | +builtin_platform_driver(impd1_clk_driver); |
| 253 | + |
| 254 | +MODULE_AUTHOR( "Linus Walleij <[email protected]>"); |
| 255 | +MODULE_DESCRIPTION("Arm IM-PD1 module clock driver"); |
| 256 | +MODULE_LICENSE("GPL v2"); |
0 commit comments