lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240715110251.261844-3-heiko@sntech.de>
Date: Mon, 15 Jul 2024 13:02:50 +0200
From: Heiko Stuebner <heiko@...ech.de>
To: mturquette@...libre.com,
	sboyd@...nel.org
Cc: robh@...nel.org,
	krzk+dt@...nel.org,
	conor+dt@...nel.org,
	heiko@...ech.de,
	linux-clk@...r.kernel.org,
	devicetree@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	linux-arm-kernel@...ts.infradead.org,
	linux-rockchip@...ts.infradead.org
Subject: [PATCH v2 2/3] clk: add driver for voltage controlled oscillators

In contrast to fixed clocks that are described as ungateable, boards
sometimes use additional oscillators for things like PCIe reference
clocks, that need actual supplies to get enabled and enable-gpios to be
toggled for them to work.

This adds a driver for those generic voltage controlled oscillators,
that can show up in schematics looking like

         ----------------
Enable - | 100MHz,3.3V, | - VDD
         |    3225      |
   GND - |              | - OUT
         ----------------

Signed-off-by: Heiko Stuebner <heiko@...ech.de>
---
 drivers/clk/Kconfig   |  10 ++++
 drivers/clk/Makefile  |   1 +
 drivers/clk/clk-vco.c | 133 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+)
 create mode 100644 drivers/clk/clk-vco.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3e9099504fad4..e93a380b6ee47 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -414,6 +414,16 @@ config COMMON_CLK_VC7
 	  Renesas Versaclock7 is a family of configurable clock generator
 	  and jitter attenuator ICs with fractional and integer dividers.
 
+config COMMON_CLK_VCO
+	tristate "Clock driver for voltage controlled oscillators"
+	depends on GPIOLIB && REGULATOR
+	help
+	  This driver supports generic voltage controlled oscillators that
+	  are not configurable but need supplies to be enabled to run.
+	  Generally they need a supply voltage to be enabled and may also
+	  require a separate enable pin, though in a lot of cases, vdd
+	  and enable control might be tied to the same supply.
+
 config COMMON_CLK_STM32F
 	def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746)
 	help
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 4abe16c8ccdfe..ca7b7b7ddfd8d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_COMMON_CLK_SI521XX)	+= clk-si521xx.o
 obj-$(CONFIG_COMMON_CLK_VC3)		+= clk-versaclock3.o
 obj-$(CONFIG_COMMON_CLK_VC5)		+= clk-versaclock5.o
 obj-$(CONFIG_COMMON_CLK_VC7)		+= clk-versaclock7.o
+obj-$(CONFIG_COMMON_CLK_VCO)		+= clk-vco.o
 obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 
diff --git a/drivers/clk/clk-vco.c b/drivers/clk/clk-vco.c
new file mode 100644
index 0000000000000..f7fe2bc627f36
--- /dev/null
+++ b/drivers/clk/clk-vco.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Heiko Stuebner <heiko@...ech.de>
+ *
+ * Generic voltage controlled oscillator
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct clk_vco {
+	struct device *dev;
+	struct clk_hw hw;
+	u32 rate;
+	struct regulator *supply;
+	struct gpio_desc *enable_gpio;
+};
+
+#define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw)
+
+static int clk_vco_prepare(struct clk_hw *hw)
+{
+	return regulator_enable(to_clk_vco(hw)->supply);
+}
+
+static void clk_vco_unprepare(struct clk_hw *hw)
+{
+	regulator_disable(to_clk_vco(hw)->supply);
+}
+
+static int clk_vco_enable(struct clk_hw *hw)
+{
+	gpiod_set_value(to_clk_vco(hw)->enable_gpio, 1);
+	return 0;
+}
+
+static void clk_vco_disable(struct clk_hw *hw)
+{
+	gpiod_set_value(to_clk_vco(hw)->enable_gpio, 0);
+}
+
+static unsigned long clk_vco_recalc_rate(struct clk_hw *hw,
+					       unsigned long parent_rate)
+{
+	return to_clk_vco(hw)->rate;
+}
+
+const struct clk_ops clk_vco_ops = {
+	.prepare = clk_vco_prepare,
+	.unprepare = clk_vco_unprepare,
+	.enable = clk_vco_enable,
+	.disable = clk_vco_disable,
+	.recalc_rate = clk_vco_recalc_rate,
+};
+
+static int clk_vco_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct clk_vco *clkgen;
+	const char *clk_name;
+	int ret;
+
+	clkgen = devm_kzalloc(dev, sizeof(*clkgen), GFP_KERNEL);
+	if (!clkgen)
+		return -ENOMEM;
+
+	clkgen->dev = dev;
+
+	if (device_property_read_u32(dev, "clock-frequency", &clkgen->rate))
+		return dev_err_probe(dev, -EIO, "failed to get clock-frequency");
+
+	ret = device_property_read_string(dev, "clock-output-names", &clk_name);
+	if (ret)
+		clk_name = fwnode_get_name(dev->fwnode);
+
+	clkgen->supply = devm_regulator_get_optional(dev, "vdd");
+	if (IS_ERR(clkgen->supply)) {
+		if (PTR_ERR(clkgen->supply) != -ENODEV)
+			return dev_err_probe(dev, PTR_ERR(clkgen->supply),
+					     "failed to get regulator\n");
+		clkgen->supply = NULL;
+	}
+
+	clkgen->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(clkgen->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(clkgen->enable_gpio),
+				     "failed to get gpio\n");
+
+	ret = gpiod_direction_output(clkgen->enable_gpio, 0);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to set gpio output");
+
+	clkgen->hw.init = CLK_HW_INIT_NO_PARENT(clk_name, &clk_vco_ops, 0);
+
+	/* register the clock */
+	ret = devm_clk_hw_register(dev, &clkgen->hw);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to register clock\n");
+
+	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+					  &clkgen->hw);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to register clock provider\n");
+
+	return 0;
+}
+
+static const struct of_device_id clk_vco_ids[] = {
+	{ .compatible = "voltage-oscillator" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, clk_vco_ids);
+
+static struct platform_driver clk_vco_driver = {
+	.driver = {
+		.name = "clk_vco",
+		.of_match_table = clk_vco_ids,
+	},
+	.probe = clk_vco_probe,
+};
+module_platform_driver(clk_vco_driver);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@...ech.de>");
+MODULE_DESCRIPTION("Voltage controlled oscillator driver");
+MODULE_LICENSE("GPL");
-- 
2.39.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ