linux/drivers/staging/fclk/xilinx_fclk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx fclk clock driver.
   4 * Copyright (c) 2017 - 2020 Xilinx Inc.
   5 */
   6
   7#include <linux/clk.h>
   8#include <linux/clk-provider.h>
   9#include <linux/errno.h>
  10#include <linux/io.h>
  11#include <linux/module.h>
  12#include <linux/of_device.h>
  13#include <linux/platform_device.h>
  14
  15struct fclk_state {
  16        struct device   *dev;
  17        struct clk      *pl;
  18};
  19
  20/* Match table for of_platform binding */
  21static const struct of_device_id fclk_of_match[] = {
  22        { .compatible = "xlnx,fclk",},
  23        { /* end of list */ },
  24};
  25MODULE_DEVICE_TABLE(of, fclk_of_match);
  26
  27static ssize_t set_rate_show(struct device *dev,
  28                             struct device_attribute *attr, char *buf)
  29{
  30        struct fclk_state *st = dev_get_drvdata(dev);
  31
  32        return scnprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(st->pl));
  33}
  34
  35static ssize_t set_rate_store(struct device *dev,
  36                              struct device_attribute *attr,
  37                              const char *buf, size_t count)
  38{
  39        int ret = 0;
  40        unsigned long rate;
  41        struct fclk_state *st = dev_get_drvdata(dev);
  42
  43        ret = kstrtoul(buf, 0, &rate);
  44        if (ret)
  45                return -EINVAL;
  46
  47        rate = clk_round_rate(st->pl, rate);
  48        ret = clk_set_rate(st->pl, rate);
  49
  50        return ret ? ret : count;
  51}
  52
  53static DEVICE_ATTR_RW(set_rate);
  54
  55static const struct attribute *fclk_ctrl_attrs[] = {
  56        &dev_attr_set_rate.attr,
  57        NULL,
  58};
  59
  60static const struct attribute_group fclk_ctrl_attr_grp = {
  61        .attrs = (struct attribute **)fclk_ctrl_attrs,
  62};
  63
  64static int fclk_probe(struct platform_device *pdev)
  65{
  66        struct fclk_state *st;
  67        int ret;
  68        struct device *dev = &pdev->dev;
  69
  70        st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
  71        if (!st)
  72                return -ENOMEM;
  73
  74        st->dev = dev;
  75        platform_set_drvdata(pdev, st);
  76
  77        st->pl = devm_clk_get(&pdev->dev, NULL);
  78        if (IS_ERR(st->pl))
  79                return PTR_ERR(st->pl);
  80
  81        ret = clk_prepare_enable(st->pl);
  82        if (ret) {
  83                dev_err(&pdev->dev, "Unable to enable clock.\n");
  84                return ret;
  85        }
  86
  87        ret = sysfs_create_group(&dev->kobj, &fclk_ctrl_attr_grp);
  88        if (ret)
  89                return ret;
  90
  91        return 0;
  92}
  93
  94static int fclk_remove(struct platform_device *pdev)
  95{
  96        struct fclk_state *st = platform_get_drvdata(pdev);
  97
  98        clk_disable_unprepare(st->pl);
  99        return 0;
 100}
 101
 102static struct platform_driver fclk_driver = {
 103        .driver = {
 104                .name = KBUILD_MODNAME,
 105                .of_match_table = fclk_of_match,
 106        },
 107        .probe          = fclk_probe,
 108        .remove         = fclk_remove,
 109};
 110
 111module_platform_driver(fclk_driver);
 112
 113MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>");
 114MODULE_DESCRIPTION("fclk enable");
 115MODULE_LICENSE("GPL v2");
 116