linux/drivers/clk/versatile/clk-impd1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Clock driver for the ARM Integrator/IM-PD1 board
   4 * Copyright (C) 2012-2013 Linus Walleij
   5 */
   6#include <linux/clk-provider.h>
   7#include <linux/clkdev.h>
   8#include <linux/err.h>
   9#include <linux/io.h>
  10#include <linux/platform_device.h>
  11#include <linux/module.h>
  12#include <linux/mfd/syscon.h>
  13#include <linux/regmap.h>
  14
  15#include "icst.h"
  16#include "clk-icst.h"
  17
  18#define IMPD1_OSC1      0x00
  19#define IMPD1_OSC2      0x04
  20#define IMPD1_LOCK      0x08
  21
  22/*
  23 * There are two VCO's on the IM-PD1
  24 */
  25
  26static const struct icst_params impd1_vco1_params = {
  27        .ref            = 24000000,     /* 24 MHz */
  28        .vco_max        = ICST525_VCO_MAX_3V,
  29        .vco_min        = ICST525_VCO_MIN,
  30        .vd_min         = 12,
  31        .vd_max         = 519,
  32        .rd_min         = 3,
  33        .rd_max         = 120,
  34        .s2div          = icst525_s2div,
  35        .idx2s          = icst525_idx2s,
  36};
  37
  38static const struct clk_icst_desc impd1_icst1_desc = {
  39        .params = &impd1_vco1_params,
  40        .vco_offset = IMPD1_OSC1,
  41        .lock_offset = IMPD1_LOCK,
  42};
  43
  44static const struct icst_params impd1_vco2_params = {
  45        .ref            = 24000000,     /* 24 MHz */
  46        .vco_max        = ICST525_VCO_MAX_3V,
  47        .vco_min        = ICST525_VCO_MIN,
  48        .vd_min         = 12,
  49        .vd_max         = 519,
  50        .rd_min         = 3,
  51        .rd_max         = 120,
  52        .s2div          = icst525_s2div,
  53        .idx2s          = icst525_idx2s,
  54};
  55
  56static const struct clk_icst_desc impd1_icst2_desc = {
  57        .params = &impd1_vco2_params,
  58        .vco_offset = IMPD1_OSC2,
  59        .lock_offset = IMPD1_LOCK,
  60};
  61
  62static int integrator_impd1_clk_spawn(struct device *dev,
  63                                      struct device_node *parent,
  64                                      struct device_node *np)
  65{
  66        struct regmap *map;
  67        struct clk *clk = ERR_PTR(-EINVAL);
  68        const char *name = np->name;
  69        const char *parent_name;
  70        const struct clk_icst_desc *desc;
  71        int ret;
  72
  73        map = syscon_node_to_regmap(parent);
  74        if (IS_ERR(map)) {
  75                pr_err("no regmap for syscon IM-PD1 ICST clock parent\n");
  76                return PTR_ERR(map);
  77        }
  78
  79        if (of_device_is_compatible(np, "arm,impd1-vco1")) {
  80                desc = &impd1_icst1_desc;
  81        } else if (of_device_is_compatible(np, "arm,impd1-vco2")) {
  82                desc = &impd1_icst2_desc;
  83        } else {
  84                dev_err(dev, "not a clock node %s\n", name);
  85                return -ENODEV;
  86        }
  87
  88        of_property_read_string(np, "clock-output-names", &name);
  89        parent_name = of_clk_get_parent_name(np, 0);
  90        clk = icst_clk_setup(NULL, desc, name, parent_name, map,
  91                             ICST_INTEGRATOR_IM_PD1);
  92        if (!IS_ERR(clk)) {
  93                of_clk_add_provider(np, of_clk_src_simple_get, clk);
  94                ret = 0;
  95        } else {
  96                dev_err(dev, "error setting up IM-PD1 ICST clock\n");
  97                ret = PTR_ERR(clk);
  98        }
  99
 100        return ret;
 101}
 102
 103static int integrator_impd1_clk_probe(struct platform_device *pdev)
 104{
 105        struct device *dev = &pdev->dev;
 106        struct device_node *np = dev->of_node;
 107        struct device_node *child;
 108        int ret = 0;
 109
 110        for_each_available_child_of_node(np, child) {
 111                ret = integrator_impd1_clk_spawn(dev, np, child);
 112                if (ret) {
 113                        of_node_put(child);
 114                        break;
 115                }
 116        }
 117
 118        return ret;
 119}
 120
 121static const struct of_device_id impd1_syscon_match[] = {
 122        { .compatible = "arm,im-pd1-syscon", },
 123        {}
 124};
 125MODULE_DEVICE_TABLE(of, impd1_syscon_match);
 126
 127static struct platform_driver impd1_clk_driver = {
 128        .driver = {
 129                .name = "impd1-clk",
 130                .of_match_table = impd1_syscon_match,
 131        },
 132        .probe  = integrator_impd1_clk_probe,
 133};
 134builtin_platform_driver(impd1_clk_driver);
 135
 136MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");
 137MODULE_DESCRIPTION("Arm IM-PD1 module clock driver");
 138MODULE_LICENSE("GPL v2");
 139