linux/drivers/clk/clk-bd718x7.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2018 ROHM Semiconductors
   3
   4#include <linux/kernel.h>
   5#include <linux/module.h>
   6#include <linux/init.h>
   7#include <linux/err.h>
   8#include <linux/platform_device.h>
   9#include <linux/slab.h>
  10#include <linux/mfd/rohm-bd718x7.h>
  11#include <linux/clk-provider.h>
  12#include <linux/clkdev.h>
  13#include <linux/regmap.h>
  14
  15struct bd718xx_clk {
  16        struct clk_hw hw;
  17        u8 reg;
  18        u8 mask;
  19        struct platform_device *pdev;
  20        struct bd718xx *mfd;
  21};
  22
  23static int bd71837_clk_set(struct clk_hw *hw, int status)
  24{
  25        struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
  26
  27        return regmap_update_bits(c->mfd->regmap, c->reg, c->mask, status);
  28}
  29
  30static void bd71837_clk_disable(struct clk_hw *hw)
  31{
  32        int rv;
  33        struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
  34
  35        rv = bd71837_clk_set(hw, 0);
  36        if (rv)
  37                dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv);
  38}
  39
  40static int bd71837_clk_enable(struct clk_hw *hw)
  41{
  42        return bd71837_clk_set(hw, 1);
  43}
  44
  45static int bd71837_clk_is_enabled(struct clk_hw *hw)
  46{
  47        int enabled;
  48        int rval;
  49        struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
  50
  51        rval = regmap_read(c->mfd->regmap, c->reg, &enabled);
  52
  53        if (rval)
  54                return rval;
  55
  56        return enabled & c->mask;
  57}
  58
  59static const struct clk_ops bd71837_clk_ops = {
  60        .prepare = &bd71837_clk_enable,
  61        .unprepare = &bd71837_clk_disable,
  62        .is_prepared = &bd71837_clk_is_enabled,
  63};
  64
  65static int bd71837_clk_probe(struct platform_device *pdev)
  66{
  67        struct bd718xx_clk *c;
  68        int rval = -ENOMEM;
  69        const char *parent_clk;
  70        struct device *parent = pdev->dev.parent;
  71        struct bd718xx *mfd = dev_get_drvdata(parent);
  72        struct clk_init_data init = {
  73                .name = "bd718xx-32k-out",
  74                .ops = &bd71837_clk_ops,
  75        };
  76
  77        c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL);
  78        if (!c)
  79                return -ENOMEM;
  80
  81        init.num_parents = 1;
  82        parent_clk = of_clk_get_parent_name(parent->of_node, 0);
  83
  84        init.parent_names = &parent_clk;
  85        if (!parent_clk) {
  86                dev_err(&pdev->dev, "No parent clk found\n");
  87                return -EINVAL;
  88        }
  89
  90        c->reg = BD718XX_REG_OUT32K;
  91        c->mask = BD718XX_OUT32K_EN;
  92        c->mfd = mfd;
  93        c->pdev = pdev;
  94        c->hw.init = &init;
  95
  96        of_property_read_string_index(parent->of_node,
  97                                      "clock-output-names", 0, &init.name);
  98
  99        rval = devm_clk_hw_register(&pdev->dev, &c->hw);
 100        if (rval) {
 101                dev_err(&pdev->dev, "failed to register 32K clk");
 102                return rval;
 103        }
 104        rval = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
 105                                           &c->hw);
 106        if (rval)
 107                dev_err(&pdev->dev, "adding clk provider failed\n");
 108
 109        return rval;
 110}
 111
 112static struct platform_driver bd71837_clk = {
 113        .driver = {
 114                .name = "bd718xx-clk",
 115        },
 116        .probe = bd71837_clk_probe,
 117};
 118
 119module_platform_driver(bd71837_clk);
 120
 121MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
 122MODULE_DESCRIPTION("BD71837 chip clk driver");
 123MODULE_LICENSE("GPL");
 124