Re: [PATCH 2/2] clk: cs2600: Add Fractional-N clock driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Dec 10, 2024 at 06:32:36PM -0600, Paul Handrigan wrote:
> Add support for the CS2600 Fractional-N Clock Synthesizer
> and Multiplier driver.
> 
> Signed-off-by: Paul Handrigan <paulha@xxxxxxxxxxxxxxxxxxxxx>
> ---
>  drivers/clk/Kconfig      |    9 +
>  drivers/clk/Makefile     |    1 +
>  drivers/clk/clk-cs2600.c | 1152 ++++++++++++++++++++++++++++++++++++++
>  drivers/clk/clk-cs2600.h |  176 ++++++
>  4 files changed, 1338 insertions(+)
>  create mode 100644 drivers/clk/clk-cs2600.c
>  create mode 100644 drivers/clk/clk-cs2600.h
> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 713573b6c86c..6b279ebf9c80 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -209,6 +209,15 @@ config COMMON_CLK_CS2000_CP
>  	help
>  	  If you say yes here you get support for the CS2000 clock multiplier.
>  
> +config COMMON_CLK_CS2600
> +	tristate "Clock driver for CS2600 Fractional-N Clock Synthesizer & Clock Multiplier"
> +	depends on I2C
> +	depends on OF
> +	select REGMAP_I2C
> +	help
> +	  If you say yes here you get support for the CS2600 clock synthesizer
> +	  and multiplier.
> +
>  config COMMON_CLK_EN7523
>  	bool "Clock driver for Airoha EN7523 SoC system clocks"
>  	depends on OF
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index bf4bd45adc3a..5d5264432613 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -53,6 +53,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
>  obj-$(CONFIG_COMMON_CLK_CDCE925)	+= clk-cdce925.o
>  obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
>  obj-$(CONFIG_COMMON_CLK_CS2000_CP)	+= clk-cs2000-cp.o
> +obj-$(CONFIG_COMMON_CLK_CS2600)		+= clk-cs2600.o
>  obj-$(CONFIG_COMMON_CLK_EP93XX)		+= clk-ep93xx.o
>  obj-$(CONFIG_ARCH_SPARX5)		+= clk-sparx5.o
>  obj-$(CONFIG_COMMON_CLK_EN7523)		+= clk-en7523.o
> diff --git a/drivers/clk/clk-cs2600.c b/drivers/clk/clk-cs2600.c
> new file mode 100644
> index 000000000000..694736bbbff0
> --- /dev/null
> +++ b/drivers/clk/clk-cs2600.c
> @@ -0,0 +1,1152 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// CS2600  --  CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
> +//
> +// Copyright (C) 2024 Cirrus Logic, Inc. and
> +//                    Cirrus Logic International Semiconductor Ltd.
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/container_of.h>
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +
> +#include "clk-cs2600.h"

You do not include here even the bindings, so clearly
CS2600_AUX_OUTPUT_FREQ_UNLOCK and others are not bindings.

...

> +static int cs2600_check_device_id(struct cs2600 *cs2600)
> +{
> +	struct device *dev = cs2600->dev;
> +	unsigned int dev_id, rev;
> +	int ret;
> +
> +	ret = regmap_read(cs2600->regmap, CS2600_DEVICE_ID1, &dev_id);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Can't read device ID\n");
> +
> +	if (dev_id != CS2600_DEVICE_ID_VALUE)
> +		return dev_err_probe(dev, -ENODEV, "Invalid device id 0x%x\n",
> +				     dev_id);
> +
> +	ret = regmap_read(cs2600->regmap, CS2600_DEVICE_ID2, &rev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Can't read device revision\n");
> +
> +	dev_dbg(dev, "Device ID %x Rev %x", dev_id, rev);
> +
> +	return 0;
> +}
> +
> +static int cs2600_i2c_probe(struct i2c_client *client)
> +{
> +	struct device *dev = &client->dev;
> +	struct cs2600 *cs2600;
> +	int ret;
> +
> +	cs2600 = devm_kzalloc(dev, sizeof(*cs2600), GFP_KERNEL);
> +	if (!cs2600)
> +		return -ENOMEM;
> +
> +	ret = devm_regulator_get_enable(dev, "vdd");
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Error with vdd supply\n");
> +
> +	cs2600->dev = dev;
> +	i2c_set_clientdata(client, cs2600);
> +
> +	cs2600->regmap = devm_regmap_init_i2c(client, &cs2600_regmap_config);
> +	if (IS_ERR(cs2600->regmap))
> +		return dev_err_probe(dev, PTR_ERR(cs2600->regmap),
> +				     "Regmap not created\n");
> +
> +	/* Required to wait at least 20ms after vdd is enabled */
> +	usleep_range(20000, 21000);
> +	ret = cs2600_check_device_id(cs2600);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(cs2600->regmap, CS2600_SW_RESET, CS2600_SW_RST_VAL);
> +	if (ret)
> +		return ret;
> +
> +	/* Required to wait at least 5ms after software reset */
> +	usleep_range(5000, 6000);
> +	ret = cs2600_clk_get(cs2600);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Invalid parent clocks\n");
> +
> +	/* Set output clocks to HiZ */
> +	cs2600_set_freeze(cs2600);
> +	regmap_set_bits(cs2600->regmap, CS2600_PLL_CFG1, CS2600_CLK_OUT_DIS);
> +	regmap_set_bits(cs2600->regmap, CS2600_OUTPUT_CFG1,
> +			CS2600_BCLK_OUT_DIS | CS2600_FSYNC_OUT_DIS);
> +	cs2600_clear_freeze(cs2600);
> +
> +	ret = cs2600_parse_dt_params(cs2600);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Cannot parse dt params\n");
> +
> +	ret = cs2600_clk_register(cs2600);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Cannot register clocks\n");
> +
> +	if (cs2600->ref_clk) {
> +		cs2600->refclk_rate = clk_get_rate(cs2600->ref_clk);
> +		regmap_update_bits(cs2600->regmap, CS2600_PLL_CFG3,
> +				   CS2600_SYSCLK_SRC_MASK,
> +				   CS2600_SYSCLK_SRC_REFCLK);
> +	} else {
> +		cs2600->refclk_rate = CS2600_INTERNAL_OSC_RATE;
> +		regmap_update_bits(cs2600->regmap, CS2600_PLL_CFG3,
> +				   CS2600_SYSCLK_SRC_MASK,
> +				   CS2600_SYSCLK_SRC_OSC);
> +	}
> +
> +	if (cs2600->refclk_rate < 8000000 || cs2600->refclk_rate > 75000000)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "Invalid REFCLK Frequency %lu\n",
> +				     cs2600->refclk_rate);
> +
> +	return 0;
> +}
> +

ID table definition goes here or somewhere around the probe.

> +static struct i2c_driver cs2600_driver = {
> +	.driver = {
> +		.name = "cs2600",
> +		.of_match_table = cs2600_of_match,
> +	},
> +	.probe		= cs2600_i2c_probe,
> +	.id_table	= cs2600_id,
> +};
> +
> +module_i2c_driver(cs2600_driver);
> +
> +MODULE_DESCRIPTION("CS2600 clock driver");
> +MODULE_AUTHOR("Paul Handrigan <paulha@xxxxxxxxxxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL");

Best regards,
Krzysztof





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux