From 9ab49168f35e3fae0fc3d035e868ff0ab370cdf5 Mon Sep 17 00:00:00 2001 From: Davide Cardillo <davide.cardillo@seco.com> Date: Wed, 15 Dec 2021 22:35:46 +0100 Subject: [PATCH] [CLK CONSUMER][drivers/clk/clk-consumer.c] Add driver v1.0 for CLK consumer This driver coming from SECO driver library: - driver: seco_clk_consumer - version: v1.0 This driver provides a SYSFS interface for a variable CLK. --- drivers/clk/Kconfig | 6 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-consumer.c | 145 +++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/clk/clk-consumer.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3853ce51b25500..2e714979a0afd1 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -359,6 +359,12 @@ config COMMON_CLK_FIXED_MMIO help Support for Memory Mapped IO Fixed clocks +config COMMON_CLK_CONSUMER + bool "Generic clock consumer" + depends on COMMON_CLK && OF + help + Provide sysfs interface for a flexible clock + source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8a52da49c99ae7..274995bcd2780a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_CONSUMER) += clk-consumer.o # please keep this section sorted lexicographically by directory path name obj-y += actions/ diff --git a/drivers/clk/clk-consumer.c b/drivers/clk/clk-consumer.c new file mode 100644 index 00000000000000..77901e4868a0b6 --- /dev/null +++ b/drivers/clk/clk-consumer.c @@ -0,0 +1,145 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/rational.h> +#include <linux/i2c.h> +#include <linux/of_platform.h> +#include <linux/platform_data/si5351.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <asm/div64.h> +#include <linux/sysctl.h> + + + +struct clk_consumer { + struct device *dev; + struct clk *clk; +}; + + +static ssize_t clk_consumer_show_clk_freq (struct device *dev, + struct device_attribute *attr, char *buf) { + + struct clk_consumer *consumer = + (struct clk_consumer *)dev_get_drvdata(dev); + + if ( !consumer ) + return 0; + + + return sprintf(buf, "%lu\n", clk_get_rate(consumer->clk)); +} + + +static ssize_t clk_consumer_store_clk_freq (struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + + int rc; + unsigned long rate; + struct clk_consumer *consumer = + (struct clk_consumer *)dev_get_drvdata(dev); + + if ( !consumer ) + return 0; + + rc = kstrtoul (buf, 0, &rate); + if ( rc ) + return rc; + + clk_set_rate (consumer->clk, rate); + + return count; +} + + +static DEVICE_ATTR(frequency, 0644, clk_consumer_show_clk_freq, clk_consumer_store_clk_freq); + +static struct attribute *clk_consumer_attrs[] = { + &dev_attr_frequency.attr, + NULL, +}; + +static struct attribute_group clk_consumer_attr_group = { + .attrs = clk_consumer_attrs, +}; + + +static int clk_consumer_probe (struct platform_device *pdev) { + int sys_err, ret; + + struct clk_consumer *consumer; + + + consumer = kzalloc (sizeof (struct clk_consumer), GFP_KERNEL); + if ( !consumer ) { + dev_err (&pdev->dev, "%s - failed to alloc resource\n", __func__); + return -ENOMEM; + } + + platform_set_drvdata (pdev, consumer); + + consumer->clk = devm_clk_get(&pdev->dev, NULL); + if ( IS_ERR (consumer->clk) ) { + dev_err (&pdev->dev, "%s - input clock not found.\n", __func__); + return PTR_ERR (consumer->clk); + } + ret = clk_prepare_enable (consumer->clk); + if ( ret ) { + dev_err (&pdev->dev, "%s - Unable to enable clock.\n", __func__); + return ret; + } + + consumer->dev = &pdev->dev; + + printk (KERN_INFO "%s - clock %s at rate %lu\n", __func__, + __clk_get_name(consumer->clk), clk_get_rate(consumer->clk)); + + sys_err = sysfs_create_group (&pdev->dev.kobj, &clk_consumer_attr_group); + return 0; +} + + +static int clk_consumer_remove (struct platform_device *pdev) { + return 0; +} + + +static const struct of_device_id clk_consumer_dt_ids[] = { + { .compatible = "seco,clk_consumer" }, + + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, clk_consumer_dt_ids); + + +static struct platform_driver clk_consumer_driver = { + .driver = { + .name = "clk-consumer", + .of_match_table = of_match_ptr(clk_consumer_dt_ids), + }, + .probe = clk_consumer_probe, + .remove = clk_consumer_remove, +}; + + +static int __init clk_consumer_init(void) { + return platform_driver_register (&clk_consumer_driver); +} +subsys_initcall(clk_consumer_init); + + +static void __exit clk_consumer__exit (void) { + return platform_driver_unregister (&clk_consumer_driver); +} + + + +MODULE_AUTHOR("Davide Cardillo <davide.cardillo@seco.com"); +MODULE_DESCRIPTION("Generic clock consumer"); +MODULE_LICENSE("GPL"); -- GitLab