All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-15 11:50 Mike Looijmans
  2018-03-18 12:52 ` Rob Herring
  2018-03-20  8:15 ` [PATCH v3] " Mike Looijmans
  0 siblings, 2 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-15 11:50 UTC (permalink / raw)
  To: linux-clk, devicetree
  Cc: linux-kernel, mturquette, sboyd, robh+dt, mark.rutland, Mike Looijmans

This patch adds the driver and devicetree documentation for the
Silicon Labs SI544 clock generator chip. This is an I2C controlled
oscillator capable of generating clock signals ranging from 200kHz
to 1500MHz.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---
v2: Add u64 cast to ls_div_bits calculation loop
    When ls_div_bits is non-zero, the hs_div must always be even

 .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
 drivers/clk/Kconfig                                |  10 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-si544.c                            | 422 +++++++++++++++++++++
 4 files changed, 458 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt
 create mode 100644 drivers/clk/clk-si544.c

diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt
new file mode 100644
index 0000000..eec1787
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
@@ -0,0 +1,25 @@
+Binding for Silicon Labs 544 programmable I2C clock generator.
+
+Reference
+This binding uses the common clock binding[1]. Details about the device can be
+found in the datasheet[2].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Si544 datasheet
+    https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
+
+Required properties:
+ - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
+               to the speed grade of the chip.
+ - reg: I2C device address.
+ - #clock-cells: From common clock bindings: Shall be 0.
+
+Optional properties:
+ - clock-output-names: From common clock bindings. Recommended to be "si544".
+
+Example:
+	si544: clock-generator@55 {
+		reg = <0x55>;
+		#clock-cells = <0>;
+		compatible = "silabs,si544b";
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 98ce9fc..5c7dc8e 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -91,6 +91,16 @@ config COMMON_CLK_SI514
 	  This driver supports the Silicon Labs 514 programmable clock
 	  generator.
 
+config COMMON_CLK_SI544
+	tristate "Clock driver for SiLabs 544 devices"
+	depends on I2C
+	depends on OF
+	select REGMAP_I2C
+	help
+	---help---
+	  This driver supports the Silicon Labs 544 programmable clock
+	  generator.
+
 config COMMON_CLK_SI570
 	tristate "Clock driver for SiLabs 570 and compatible devices"
 	depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71ec41e..bde614a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_S2MPS11)	+= clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCPI)           += clk-scpi.o
 obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
+obj-$(CONFIG_COMMON_CLK_SI544)		+= clk-si544.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32f4.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32h7.o
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
new file mode 100644
index 0000000..a392acf
--- /dev/null
+++ b/drivers/clk/clk-si544.c
@@ -0,0 +1,422 @@
+/*
+ * Driver for Silicon Labs Si544 Programmable Oscillator
+ *
+ * Copyright (C) 2018 Topic Embedded Products
+ *
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* I2C registers (decimal as in datasheet) */
+#define SI544_REG_CONTROL	7
+#define SI544_REG_OE_STATE	17
+#define SI544_REG_HS_DIV	23
+#define SI544_REG_LS_HS_DIV	24
+#define SI544_REG_FBDIV0	26
+#define SI544_REG_FBDIV8	27
+#define SI544_REG_FBDIV16	28
+#define SI544_REG_FBDIV24	29
+#define SI544_REG_FBDIV32	30
+#define SI544_REG_FBDIV40	31
+#define SI544_REG_FCAL_OVR	69
+#define SI544_REG_ADPLL_DELTA_M0	231
+#define SI544_REG_ADPLL_DELTA_M8	232
+#define SI544_REG_ADPLL_DELTA_M16	233
+#define SI544_REG_PAGE_SELECT	255
+
+/* Register values */
+#define SI544_CONTROL_RESET	BIT(7)
+#define SI544_CONTROL_MS_ICAL2	BIT(3)
+
+#define SI544_OE_STATE_ODC_OE	BIT(0)
+
+/* Max freq depends on speed grade */
+#define SI544_MIN_FREQ	    200000U
+
+/* Si544 Internal oscilator runs at 55.05 MHz */
+#define FXO		  55050000U
+
+/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
+#define FVCO_MIN       10800000000ULL
+
+#define HS_DIV_MAX	2046
+#define HS_DIV_MAX_ODD	33
+
+enum si544_speed_grade {
+	si544a,
+	si544b,
+	si544c,
+};
+
+struct clk_si544 {
+	struct clk_hw hw;
+	struct regmap *regmap;
+	struct i2c_client *i2c_client;
+	enum si544_speed_grade speed_grade;
+};
+#define to_clk_si544(_hw)	container_of(_hw, struct clk_si544, hw)
+
+/* Multiplier/divider settings */
+struct clk_si544_muldiv {
+	u32 fb_div_frac;  /* Integer part of feedback divider (32 bits) */
+	u16 fb_div_int;  /* Fractional part of feedback divider (11 bits) */
+	u16 hs_div; /* 1st divider, 5..2046, must be even when >33 */
+	u8 ls_div_bits; /* 2nd divider, as 2^x, range 0..5 */
+};
+
+/* Enables or disables the output driver */
+static int si544_enable_output(struct clk_si544 *data, bool enable)
+{
+	return regmap_update_bits(data->regmap, SI544_REG_OE_STATE,
+		SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
+}
+
+/* Retrieve clock multiplier and dividers from hardware */
+static int si544_get_muldiv(struct clk_si544 *data,
+	struct clk_si544_muldiv *settings)
+{
+	int err;
+	u8 reg[6];
+
+	err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2);
+	if (err)
+		return err;
+
+	settings->ls_div_bits = (reg[1] >> 4) & 0x07;
+	settings->hs_div = (reg[1] & 0x07) << 8 | reg[0];
+
+	err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6);
+	if (err)
+		return err;
+
+	settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
+	settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
+				reg[3] << 24;
+	return 0;
+}
+
+static int si544_set_muldiv(struct clk_si544 *data,
+	struct clk_si544_muldiv *settings)
+{
+	int err;
+	u8 reg[6];
+
+	reg[0] = settings->hs_div;
+	reg[1] = settings->hs_div >> 8 | settings->ls_div_bits << 4;
+
+	err = regmap_bulk_write(data->regmap, SI544_REG_HS_DIV, reg, 2);
+	if (err < 0)
+		return err;
+
+	reg[0] = settings->fb_div_frac;
+	reg[1] = settings->fb_div_frac >> 8;
+	reg[2] = settings->fb_div_frac >> 16;
+	reg[3] = settings->fb_div_frac >> 24;
+	reg[4] = settings->fb_div_int;
+	reg[5] = settings->fb_div_int >> 8;
+
+	/*
+	 * Writing to SI544_REG_FBDIV40 triggers the clock change, so that
+	 * must be written last
+	 */
+	return regmap_bulk_write(data->regmap, SI544_REG_FBDIV0, reg, 6);
+}
+
+static bool is_valid_frequency(const struct clk_si544 *data,
+	unsigned long frequency)
+{
+	unsigned long max_freq;
+
+	if (frequency < SI544_MIN_FREQ)
+		return false;
+
+	switch (data->speed_grade) {
+	case si544a:
+		max_freq = 1500000000;
+		break;
+	case si544b:
+		max_freq = 800000000;
+		break;
+	case si544c:
+		max_freq = 350000000;
+		break;
+	default:
+		return false;
+	}
+
+	if (frequency > max_freq)
+		return false;
+
+	return true;
+}
+
+/* Calculate divider settings for a given frequency */
+static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
+	unsigned long frequency)
+{
+	u64 vco;
+	u32 ls_freq;
+	u32 tmp;
+	u8 res;
+
+	/* Determine the minimum value of LS_DIV and resulting target freq. */
+	ls_freq = frequency;
+	settings->ls_div_bits = 0;
+
+	if (frequency >= (FVCO_MIN / HS_DIV_MAX))
+		settings->ls_div_bits = 0;
+	else {
+		res = 1;
+		tmp = 2 * HS_DIV_MAX;
+		while (tmp <= (HS_DIV_MAX * 32)) {
+			if (((u64)frequency * tmp) >= FVCO_MIN)
+				break;
+			++res;
+			tmp <<= 1;
+		}
+		settings->ls_div_bits = res;
+		ls_freq = frequency << res;
+	}
+
+	/* Determine minimum HS_DIV by rounding up */
+	vco = FVCO_MIN + ls_freq - 1;
+	do_div(vco, ls_freq);
+	settings->hs_div = vco;
+	/* round up to even number when required */
+	if ((settings->hs_div & 1) &&
+	    ((settings->hs_div > HS_DIV_MAX_ODD) || settings->ls_div_bits))
+		++settings->hs_div;
+	/* Calculate VCO frequency (in 10..12GHz range) */
+	vco = (u64)ls_freq * settings->hs_div;
+	/* Calculate the integer part of the feedback divider */
+	tmp = do_div(vco, FXO);
+	settings->fb_div_int = vco;
+	/* And the fractional bits using the remainder */
+	vco = (u64)tmp << 32;
+	do_div(vco, FXO);
+	settings->fb_div_frac = vco;
+
+	return 0;
+}
+
+/* Calculate resulting frequency given the register settings */
+static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+{
+	u32 d = settings->hs_div * BIT(settings->ls_div_bits);
+	u64 vco;
+
+	/* Calculate VCO while preventing overflow */
+	vco = (u64)settings->fb_div_int * FXO;
+	vco += (((u64)settings->fb_div_frac * FXO) + (FXO / 2)) >> 32;
+
+	do_div(vco, d);
+
+	return vco;
+}
+
+static unsigned long si544_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	err = si544_get_muldiv(data, &settings);
+	if (err) {
+		dev_err(&data->i2c_client->dev, "unable to retrieve settings\n");
+		return 0;
+	}
+
+	return si544_calc_rate(&settings);
+}
+
+static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	if (!rate)
+		return 0;
+
+	if (!is_valid_frequency(data, rate))
+		return -EINVAL;
+
+	err = si544_calc_muldiv(&settings, rate);
+	if (err)
+		return err;
+
+	return si544_calc_rate(&settings);
+}
+
+/*
+ * Update output frequency for "big" frequency changes
+ */
+static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	if (!is_valid_frequency(data, rate))
+		return -EINVAL;
+
+	err = si544_calc_muldiv(&settings, rate);
+	if (err)
+		return err;
+
+	si544_enable_output(data, false);
+
+	/* Allow FCAL for this frequency update */
+	err = regmap_write(data->regmap, SI544_REG_FCAL_OVR, 0);
+	if (err < 0)
+		return err;
+
+
+	err = si544_set_muldiv(data, &settings);
+	if (err < 0)
+		return err; /* Undefined state now, best to leave disabled */
+
+	/* Trigger calibration */
+	err = regmap_write(data->regmap, SI544_REG_CONTROL,
+			   SI544_CONTROL_MS_ICAL2);
+	if (err < 0)
+		return err;
+
+	/* Applying a new frequency can take up to 10ms */
+	usleep_range(10000, 12000);
+
+	si544_enable_output(data, true);
+
+	return err;
+}
+
+static const struct clk_ops si544_clk_ops = {
+	.recalc_rate = si544_recalc_rate,
+	.round_rate = si544_round_rate,
+	.set_rate = si544_set_rate,
+};
+
+static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SI544_REG_CONTROL:
+	case SI544_REG_FCAL_OVR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config si544_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = SI544_REG_PAGE_SELECT,
+	.volatile_reg = si544_regmap_is_volatile,
+};
+
+static int si544_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct clk_si544 *data;
+	struct clk_init_data init;
+	int err;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	init.ops = &si544_clk_ops;
+	init.flags = 0;
+	init.num_parents = 0;
+	data->hw.init = &init;
+	data->i2c_client = client;
+	data->speed_grade = id->driver_data;
+
+	if (of_property_read_string(client->dev.of_node, "clock-output-names",
+			&init.name))
+		init.name = client->dev.of_node->name;
+
+	data->regmap = devm_regmap_init_i2c(client, &si544_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		dev_err(&client->dev, "failed to allocate register map\n");
+		return PTR_ERR(data->regmap);
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/* Select page 0, just to be sure, there appear to be no more */
+	err = regmap_write(data->regmap, SI544_REG_PAGE_SELECT, 0);
+	if (err < 0)
+		return err;
+
+	err = devm_clk_hw_register(&client->dev, &data->hw);
+	if (err) {
+		dev_err(&client->dev, "clock registration failed\n");
+		return err;
+	}
+	err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get,
+				     &data->hw);
+	if (err) {
+		dev_err(&client->dev, "unable to add clk provider\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int si544_remove(struct i2c_client *client)
+{
+	of_clk_del_provider(client->dev.of_node);
+	return 0;
+}
+
+static const struct i2c_device_id si544_id[] = {
+	{ "si544a", si544a },
+	{ "si544b", si544b },
+	{ "si544c", si544c },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, si544_id);
+
+static const struct of_device_id clk_si544_of_match[] = {
+	{ .compatible = "silabs,si544a" },
+	{ .compatible = "silabs,si544b" },
+	{ .compatible = "silabs,si544c" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, clk_si544_of_match);
+
+static struct i2c_driver si544_driver = {
+	.driver = {
+		.name = "si544",
+		.of_match_table = clk_si544_of_match,
+	},
+	.probe		= si544_probe,
+	.remove		= si544_remove,
+	.id_table	= si544_id,
+};
+module_i2c_driver(si544_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Si544 driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
  2018-03-15 11:50 [PATCH v2] clk: Add driver for the si544 clock generator chip Mike Looijmans
@ 2018-03-18 12:52 ` Rob Herring
  2018-03-19 15:04     ` Mike Looijmans
  2018-03-20  8:15 ` [PATCH v3] " Mike Looijmans
  1 sibling, 1 reply; 15+ messages in thread
From: Rob Herring @ 2018-03-18 12:52 UTC (permalink / raw)
  To: Mike Looijmans
  Cc: linux-clk, devicetree, linux-kernel, mturquette, sboyd, mark.rutland

On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
> This patch adds the driver and devicetree documentation for the
> Silicon Labs SI544 clock generator chip. This is an I2C controlled
> oscillator capable of generating clock signals ranging from 200kHz
> to 1500MHz.
> 
> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
> ---
> v2: Add u64 cast to ls_div_bits calculation loop
>     When ls_div_bits is non-zero, the hs_div must always be even
> 
>  .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
>  drivers/clk/Kconfig                                |  10 +
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/clk-si544.c                            | 422 +++++++++++++++++++++
>  4 files changed, 458 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt
>  create mode 100644 drivers/clk/clk-si544.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt
> new file mode 100644
> index 0000000..eec1787
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
> @@ -0,0 +1,25 @@
> +Binding for Silicon Labs 544 programmable I2C clock generator.
> +
> +Reference
> +This binding uses the common clock binding[1]. Details about the device can be
> +found in the datasheet[2].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +[2] Si544 datasheet
> +    https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
> +
> +Required properties:
> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
> +               to the speed grade of the chip.
> + - reg: I2C device address.
> + - #clock-cells: From common clock bindings: Shall be 0.
> +
> +Optional properties:
> + - clock-output-names: From common clock bindings. Recommended to be "si544".

What's the point if there is only 1 clock output?

> +
> +Example:
> +	si544: clock-generator@55 {

clock-controller@55 is the standard node name.

> +		reg = <0x55>;
> +		#clock-cells = <0>;
> +		compatible = "silabs,si544b";
> +	};

Otherwise, for the binding:

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
  2018-03-18 12:52 ` Rob Herring
  2018-03-19 15:04     ` Mike Looijmans
@ 2018-03-19 15:04     ` Mike Looijmans
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-19 15:04 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, sboyd, mark.rutland

On 18-03-18 13:52, Rob Herring wrote:
> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>> This patch adds the driver and devicetree documentation for the
>> Silicon Labs SI544 clock generator chip. This is an I2C controlled
>> oscillator capable of generating clock signals ranging from 200kHz
>> to 1500MHz.
>>
>> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
>> ---
>> v2: Add u64 cast to ls_div_bits calculation loop
>>      When ls_div_bits is non-zero, the hs_div must always be even
>>
>>   .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
>>   drivers/clk/Kconfig                                |  10 +
>>   drivers/clk/Makefile                               |   1 +
>>   drivers/clk/clk-si544.c                            | 422 +++++++++++++++++++++
>>   4 files changed, 458 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt
>>   create mode 100644 drivers/clk/clk-si544.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt
>> new file mode 100644
>> index 0000000..eec1787
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
>> @@ -0,0 +1,25 @@
>> +Binding for Silicon Labs 544 programmable I2C clock generator.
>> +
>> +Reference
>> +This binding uses the common clock binding[1]. Details about the device can be
>> +found in the datasheet[2].
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>> +[2] Si544 datasheet
>> +    https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
>> +
>> +Required properties:
>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
>> +               to the speed grade of the chip.
>> + - reg: I2C device address.
>> + - #clock-cells: From common clock bindings: Shall be 0.
>> +
>> +Optional properties:
>> + - clock-output-names: From common clock bindings. Recommended to be "si544".
> 
> What's the point if there is only 1 clock output?

I have a board with 6 of these chips, and the clock registration fails if they 
don't have unique names. Providing a clock-output-names property was the 
easiest way around it.

Should I just omit the line or change the wording to reflect the above or is 
there a better solution (maybe I can use the DT node name as clock name in the 
driver, will look into that)

> 
>> +
>> +Example:
>> +	si544: clock-generator@55 {
> 
> clock-controller@55 is the standard node name.

I'll change and post patch v3

> 
>> +		reg = <0x55>;
>> +		#clock-cells = <0>;
>> +		compatible = "silabs,si544b";
>> +	};
> 
> Otherwise, for the binding:
> 
> Reviewed-by: Rob Herring <robh@kernel.org>
> 



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-19 15:04     ` Mike Looijmans
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-19 15:04 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, sboyd, mark.rutland

On 18-03-18 13:52, Rob Herring wrote:
> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>> This patch adds the driver and devicetree documentation for the
>> Silicon Labs SI544 clock generator chip. This is an I2C controlled
>> oscillator capable of generating clock signals ranging from 200kHz
>> to 1500MHz.
>>
>> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
>> ---
>> v2: Add u64 cast to ls_div_bits calculation loop
>>      When ls_div_bits is non-zero, the hs_div must always be even
>>
>>   .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
>>   drivers/clk/Kconfig                                |  10 +
>>   drivers/clk/Makefile                               |   1 +
>>   drivers/clk/clk-si544.c                            | 422 +++++++++++++++++++++
>>   4 files changed, 458 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt
>>   create mode 100644 drivers/clk/clk-si544.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt
>> new file mode 100644
>> index 0000000..eec1787
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
>> @@ -0,0 +1,25 @@
>> +Binding for Silicon Labs 544 programmable I2C clock generator.
>> +
>> +Reference
>> +This binding uses the common clock binding[1]. Details about the device can be
>> +found in the datasheet[2].
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>> +[2] Si544 datasheet
>> +    https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
>> +
>> +Required properties:
>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
>> +               to the speed grade of the chip.
>> + - reg: I2C device address.
>> + - #clock-cells: From common clock bindings: Shall be 0.
>> +
>> +Optional properties:
>> + - clock-output-names: From common clock bindings. Recommended to be "si544".
> 
> What's the point if there is only 1 clock output?

I have a board with 6 of these chips, and the clock registration fails if they 
don't have unique names. Providing a clock-output-names property was the 
easiest way around it.

Should I just omit the line or change the wording to reflect the above or is 
there a better solution (maybe I can use the DT node name as clock name in the 
driver, will look into that)

> 
>> +
>> +Example:
>> +	si544: clock-generator@55 {
> 
> clock-controller@55 is the standard node name.

I'll change and post patch v3

> 
>> +		reg = <0x55>;
>> +		#clock-cells = <0>;
>> +		compatible = "silabs,si544b";
>> +	};
> 
> Otherwise, for the binding:
> 
> Reviewed-by: Rob Herring <robh@kernel.org>
> 



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-19 15:04     ` Mike Looijmans
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-19 15:04 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, sboyd, mark.rutland

=EF=BB=BFOn 18-03-18 13:52, Rob Herring wrote:
> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>> This patch adds the driver and devicetree documentation for the
>> Silicon Labs SI544 clock generator chip. This is an I2C controlled
>> oscillator capable of generating clock signals ranging from 200kHz
>> to 1500MHz.
>>
>> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
>> ---
>> v2: Add u64 cast to ls_div_bits calculation loop
>>      When ls_div_bits is non-zero, the hs_div must always be even
>>
>>   .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
>>   drivers/clk/Kconfig                                |  10 +
>>   drivers/clk/Makefile                               |   1 +
>>   drivers/clk/clk-si544.c                            | 422 +++++++++++++=
++++++++
>>   4 files changed, 458 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/silabs,si54=
4.txt
>>   create mode 100644 drivers/clk/clk-si544.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/=
Documentation/devicetree/bindings/clock/silabs,si544.txt
>> new file mode 100644
>> index 0000000..eec1787
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
>> @@ -0,0 +1,25 @@
>> +Binding for Silicon Labs 544 programmable I2C clock generator.
>> +
>> +Reference
>> +This binding uses the common clock binding[1]. Details about the device=
 can be
>> +found in the datasheet[2].
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>> +[2] Si544 datasheet
>> +    https://www.silabs.com/documents/public/data-sheets/si544-datasheet=
.pdf
>> +
>> +Required properties:
>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" =
according
>> +               to the speed grade of the chip.
>> + - reg: I2C device address.
>> + - #clock-cells: From common clock bindings: Shall be 0.
>> +
>> +Optional properties:
>> + - clock-output-names: From common clock bindings. Recommended to be "s=
i544".
>=20
> What's the point if there is only 1 clock output?

I have a board with 6 of these chips, and the clock registration fails if t=
hey=20
don't have unique names. Providing a clock-output-names property was the=20
easiest way around it.

Should I just omit the line or change the wording to reflect the above or i=
s=20
there a better solution (maybe I can use the DT node name as clock name in =
the=20
driver, will look into that)

>=20
>> +
>> +Example:
>> +	si544: clock-generator@55 {
>=20
> clock-controller@55 is the standard node name.

I'll change and post patch v3

>=20
>> +		reg =3D <0x55>;
>> +		#clock-cells =3D <0>;
>> +		compatible =3D "silabs,si544b";
>> +	};
>=20
> Otherwise, for the binding:
>=20
> Reviewed-by: Rob Herring <robh@kernel.org>
>=20



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
  2018-03-19 15:04     ` Mike Looijmans
@ 2018-03-19 21:08       ` Stephen Boyd
  -1 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-19 21:08 UTC (permalink / raw)
  To: Mike Looijmans, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

Quoting Mike Looijmans (2018-03-19 08:04:15)
> On 18-03-18 13:52, Rob Herring wrote:
> > On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
> >> +Required properties:
> >> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
> >> +               to the speed grade of the chip.
> >> + - reg: I2C device address.
> >> + - #clock-cells: From common clock bindings: Shall be 0.
> >> +
> >> +Optional properties:
> >> + - clock-output-names: From common clock bindings. Recommended to be "si544".
> > 
> > What's the point if there is only 1 clock output?
> 
> I have a board with 6 of these chips, and the clock registration fails if they 
> don't have unique names. Providing a clock-output-names property was the 
> easiest way around it.
> 
> Should I just omit the line or change the wording to reflect the above or is 
> there a better solution (maybe I can use the DT node name as clock name in the 
> driver, will look into that)

I would leave clock-output-names for now. One day we can get off of
strings in CCF. Soon perhaps.

> 
> > 
> >> +
> >> +Example:
> >> +    si544: clock-generator@55 {
> > 
> > clock-controller@55 is the standard node name.
> 
> I'll change and post patch v3
> 

I made some comments on v1. Please fold those into v3.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-19 21:08       ` Stephen Boyd
  0 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-19 21:08 UTC (permalink / raw)
  To: Mike Looijmans, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

Quoting Mike Looijmans (2018-03-19 08:04:15)
> On 18-03-18 13:52, Rob Herring wrote:
> > On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
> >> +Required properties:
> >> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c=
" according
> >> +               to the speed grade of the chip.
> >> + - reg: I2C device address.
> >> + - #clock-cells: From common clock bindings: Shall be 0.
> >> +
> >> +Optional properties:
> >> + - clock-output-names: From common clock bindings. Recommended to be =
"si544".
> > =

> > What's the point if there is only 1 clock output?
> =

> I have a board with 6 of these chips, and the clock registration fails if=
 they =

> don't have unique names. Providing a clock-output-names property was the =

> easiest way around it.
> =

> Should I just omit the line or change the wording to reflect the above or=
 is =

> there a better solution (maybe I can use the DT node name as clock name i=
n the =

> driver, will look into that)

I would leave clock-output-names for now. One day we can get off of
strings in CCF. Soon perhaps.

> =

> > =

> >> +
> >> +Example:
> >> +    si544: clock-generator@55 {
> > =

> > clock-controller@55 is the standard node name.
> =

> I'll change and post patch v3
> =


I made some comments on v1. Please fold those into v3.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
  2018-03-19 21:08       ` Stephen Boyd
  (?)
@ 2018-03-20  7:15         ` Mike Looijmans
  -1 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-20  7:15 UTC (permalink / raw)
  To: Stephen Boyd, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

On 19-03-18 22:08, Stephen Boyd wrote:
> Quoting Mike Looijmans (2018-03-19 08:04:15)
>> On 18-03-18 13:52, Rob Herring wrote:
>>> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>>>> +Required properties:
>>>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
>>>> +               to the speed grade of the chip.
>>>> + - reg: I2C device address.
>>>> + - #clock-cells: From common clock bindings: Shall be 0.
>>>> +
>>>> +Optional properties:
>>>> + - clock-output-names: From common clock bindings. Recommended to be "si544".
>>>
>>> What's the point if there is only 1 clock output?
>>
>> I have a board with 6 of these chips, and the clock registration fails if they
>> don't have unique names. Providing a clock-output-names property was the
>> easiest way around it.
>>
>> Should I just omit the line or change the wording to reflect the above or is
>> there a better solution (maybe I can use the DT node name as clock name in the
>> driver, will look into that)
> 
> I would leave clock-output-names for now. One day we can get off of
> strings in CCF. Soon perhaps.
> 
>>
>>>
>>>> +
>>>> +Example:
>>>> +    si544: clock-generator@55 {
>>>
>>> clock-controller@55 is the standard node name.
>>
>> I'll change and post patch v3
>>
> 
> I made some comments on v1. Please fold those into v3.


Thanks, found them on patchwork, somehow they didn't end up in my mailbox.

Comments are clear, will incorporate them, I only have trouble with your 
remark on the DT documentation "Can this reference stuff go to the bottom of 
this document?". I copied the style from the other documents in the same 
directory, I'm slightly puzzled about where the reference part should go now.



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-20  7:15         ` Mike Looijmans
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-20  7:15 UTC (permalink / raw)
  To: Stephen Boyd, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

On 19-03-18 22:08, Stephen Boyd wrote:
> Quoting Mike Looijmans (2018-03-19 08:04:15)
>> On 18-03-18 13:52, Rob Herring wrote:
>>> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>>>> +Required properties:
>>>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
>>>> +               to the speed grade of the chip.
>>>> + - reg: I2C device address.
>>>> + - #clock-cells: From common clock bindings: Shall be 0.
>>>> +
>>>> +Optional properties:
>>>> + - clock-output-names: From common clock bindings. Recommended to be "si544".
>>>
>>> What's the point if there is only 1 clock output?
>>
>> I have a board with 6 of these chips, and the clock registration fails if they
>> don't have unique names. Providing a clock-output-names property was the
>> easiest way around it.
>>
>> Should I just omit the line or change the wording to reflect the above or is
>> there a better solution (maybe I can use the DT node name as clock name in the
>> driver, will look into that)
> 
> I would leave clock-output-names for now. One day we can get off of
> strings in CCF. Soon perhaps.
> 
>>
>>>
>>>> +
>>>> +Example:
>>>> +    si544: clock-generator@55 {
>>>
>>> clock-controller@55 is the standard node name.
>>
>> I'll change and post patch v3
>>
> 
> I made some comments on v1. Please fold those into v3.


Thanks, found them on patchwork, somehow they didn't end up in my mailbox.

Comments are clear, will incorporate them, I only have trouble with your 
remark on the DT documentation "Can this reference stuff go to the bottom of 
this document?". I copied the style from the other documents in the same 
directory, I'm slightly puzzled about where the reference part should go now.



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-20  7:15         ` Mike Looijmans
  0 siblings, 0 replies; 15+ messages in thread
From: Mike Looijmans @ 2018-03-20  7:15 UTC (permalink / raw)
  To: Stephen Boyd, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

=EF=BB=BFOn 19-03-18 22:08, Stephen Boyd wrote:
> Quoting Mike Looijmans (2018-03-19 08:04:15)
>> On 18-03-18 13:52, Rob Herring wrote:
>>> On Thu, Mar 15, 2018 at 12:50:08PM +0100, Mike Looijmans wrote:
>>>> +Required properties:
>>>> + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c=
" according
>>>> +               to the speed grade of the chip.
>>>> + - reg: I2C device address.
>>>> + - #clock-cells: From common clock bindings: Shall be 0.
>>>> +
>>>> +Optional properties:
>>>> + - clock-output-names: From common clock bindings. Recommended to be =
"si544".
>>>
>>> What's the point if there is only 1 clock output?
>>
>> I have a board with 6 of these chips, and the clock registration fails i=
f they
>> don't have unique names. Providing a clock-output-names property was the
>> easiest way around it.
>>
>> Should I just omit the line or change the wording to reflect the above o=
r is
>> there a better solution (maybe I can use the DT node name as clock name =
in the
>> driver, will look into that)
>=20
> I would leave clock-output-names for now. One day we can get off of
> strings in CCF. Soon perhaps.
>=20
>>
>>>
>>>> +
>>>> +Example:
>>>> +    si544: clock-generator@55 {
>>>
>>> clock-controller@55 is the standard node name.
>>
>> I'll change and post patch v3
>>
>=20
> I made some comments on v1. Please fold those into v3.


Thanks, found them on patchwork, somehow they didn't end up in my mailbox.

Comments are clear, will incorporate them, I only have trouble with your=20
remark on the DT documentation "Can this reference stuff go to the bottom o=
f=20
this document?". I copied the style from the other documents in the same=20
directory, I'm slightly puzzled about where the reference part should go no=
w.



Kind regards,

Mike Looijmans
System Expert

TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com

Please consider the environment before printing this e-mail

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
  2018-03-20  7:15         ` Mike Looijmans
@ 2018-03-20  7:18           ` Stephen Boyd
  -1 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-20  7:18 UTC (permalink / raw)
  To: Mike Looijmans, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

Quoting Mike Looijmans (2018-03-20 00:15:36)
> Thanks, found them on patchwork, somehow they didn't end up in my mailbox.
> 
> Comments are clear, will incorporate them, I only have trouble with your 
> remark on the DT documentation "Can this reference stuff go to the bottom of 
> this document?". I copied the style from the other documents in the same 
> directory, I'm slightly puzzled about where the reference part should go now.
> 
> 

Ok. It's fine either way.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] clk: Add driver for the si544 clock generator chip
@ 2018-03-20  7:18           ` Stephen Boyd
  0 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-20  7:18 UTC (permalink / raw)
  To: Mike Looijmans, Rob Herring
  Cc: linux-clk, devicetree, linux-kernel, mturquette, mark.rutland

Quoting Mike Looijmans (2018-03-20 00:15:36)
> Thanks, found them on patchwork, somehow they didn't end up in my mailbox.
> =

> Comments are clear, will incorporate them, I only have trouble with your =

> remark on the DT documentation "Can this reference stuff go to the bottom=
 of =

> this document?". I copied the style from the other documents in the same =

> directory, I'm slightly puzzled about where the reference part should go =
now.
> =

> =


Ok. It's fine either way.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3] clk: Add driver for the si544 clock generator chip
  2018-03-15 11:50 [PATCH v2] clk: Add driver for the si544 clock generator chip Mike Looijmans
  2018-03-18 12:52 ` Rob Herring
@ 2018-03-20  8:15 ` Mike Looijmans
  2018-03-23 17:04     ` Stephen Boyd
  1 sibling, 1 reply; 15+ messages in thread
From: Mike Looijmans @ 2018-03-20  8:15 UTC (permalink / raw)
  To: linux-clk; +Cc: linux-kernel, mturquette, sboyd, Mike Looijmans

This patch adds the driver and devicetree documentation for the
Silicon Labs SI544 clock generator chip. This is an I2C controlled
oscillator capable of generating clock signals ranging from 200kHz
to 1500MHz.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---
v2: Add u64 cast to ls_div_bits calculation loop
    When ls_div_bits is non-zero, the hs_div must always be even
v3: Remove "depends on OF" from Kconfig
    Use clock-controller@55 as example node name
    SPDX style license
    Add MIN_HSDIV_FREQ define
    Various style issues (Stephen Boyd)
    Remove rate==0 special casing (is_valid_frequency already checks)
    Reduce error messages
    Use devm_of_clk_add_hw_provider()

 .../devicetree/bindings/clock/silabs,si544.txt     |  25 ++
 drivers/clk/Kconfig                                |   9 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-si544.c                            | 411 +++++++++++++++++++++
 4 files changed, 446 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt
 create mode 100644 drivers/clk/clk-si544.c

diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt
new file mode 100644
index 0000000..b86535b
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si544.txt
@@ -0,0 +1,25 @@
+Binding for Silicon Labs 544 programmable I2C clock generator.
+
+Reference
+This binding uses the common clock binding[1]. Details about the device can be
+found in the datasheet[2].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Si544 datasheet
+    https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
+
+Required properties:
+ - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
+               to the speed grade of the chip.
+ - reg: I2C device address.
+ - #clock-cells: From common clock bindings: Shall be 0.
+
+Optional properties:
+ - clock-output-names: From common clock bindings. Recommended to be "si544".
+
+Example:
+	si544: clock-controller@55 {
+		reg = <0x55>;
+		#clock-cells = <0>;
+		compatible = "silabs,si544b";
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 98ce9fc..580fc04 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -91,6 +91,15 @@ config COMMON_CLK_SI514
 	  This driver supports the Silicon Labs 514 programmable clock
 	  generator.
 
+config COMMON_CLK_SI544
+	tristate "Clock driver for SiLabs 544 devices"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	---help---
+	  This driver supports the Silicon Labs 544 programmable clock
+	  generator.
+
 config COMMON_CLK_SI570
 	tristate "Clock driver for SiLabs 570 and compatible devices"
 	depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71ec41e..bde614a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_S2MPS11)	+= clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCPI)           += clk-scpi.o
 obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
+obj-$(CONFIG_COMMON_CLK_SI544)		+= clk-si544.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32f4.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32h7.o
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
new file mode 100644
index 0000000..d437722
--- /dev/null
+++ b/drivers/clk/clk-si544.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si544 Programmable Oscillator
+ * Copyright (C) 2018 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* I2C registers (decimal as in datasheet) */
+#define SI544_REG_CONTROL	7
+#define SI544_REG_OE_STATE	17
+#define SI544_REG_HS_DIV	23
+#define SI544_REG_LS_HS_DIV	24
+#define SI544_REG_FBDIV0	26
+#define SI544_REG_FBDIV8	27
+#define SI544_REG_FBDIV16	28
+#define SI544_REG_FBDIV24	29
+#define SI544_REG_FBDIV32	30
+#define SI544_REG_FBDIV40	31
+#define SI544_REG_FCAL_OVR	69
+#define SI544_REG_ADPLL_DELTA_M0	231
+#define SI544_REG_ADPLL_DELTA_M8	232
+#define SI544_REG_ADPLL_DELTA_M16	233
+#define SI544_REG_PAGE_SELECT	255
+
+/* Register values */
+#define SI544_CONTROL_RESET	BIT(7)
+#define SI544_CONTROL_MS_ICAL2	BIT(3)
+
+#define SI544_OE_STATE_ODC_OE	BIT(0)
+
+/* Max freq depends on speed grade */
+#define SI544_MIN_FREQ	    200000U
+
+/* Si544 Internal oscilator runs at 55.05 MHz */
+#define FXO		  55050000U
+
+/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
+#define FVCO_MIN       10800000000ULL
+
+#define HS_DIV_MAX	2046
+#define HS_DIV_MAX_ODD	33
+
+/* Lowest frequency synthesizeable using only the HS divider */
+#define MIN_HSDIV_FREQ	(FVCO_MIN / HS_DIV_MAX)
+
+enum si544_speed_grade {
+	si544a,
+	si544b,
+	si544c,
+};
+
+struct clk_si544 {
+	struct clk_hw hw;
+	struct regmap *regmap;
+	struct i2c_client *i2c_client;
+	enum si544_speed_grade speed_grade;
+};
+#define to_clk_si544(_hw)	container_of(_hw, struct clk_si544, hw)
+
+/**
+ * struct clk_si544_muldiv - Multiplier/divider settings
+ * @fb_div_frac:	integer part of feedback divider (32 bits)
+ * @fb_div_int:		fractional part of feedback divider (11 bits)
+ * @hs_div:		1st divider, 5..2046, must be even when >33
+ * @ls_div_bits:	2nd divider, as 2^x, range 0..5
+ *                      If ls_div_bits is non-zero, hs_div must be even
+ */
+struct clk_si544_muldiv {
+	u32 fb_div_frac;
+	u16 fb_div_int;
+	u16 hs_div;
+	u8 ls_div_bits;
+};
+
+/* Enables or disables the output driver */
+static int si544_enable_output(struct clk_si544 *data, bool enable)
+{
+	return regmap_update_bits(data->regmap, SI544_REG_OE_STATE,
+		SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
+}
+
+/* Retrieve clock multiplier and dividers from hardware */
+static int si544_get_muldiv(struct clk_si544 *data,
+	struct clk_si544_muldiv *settings)
+{
+	int err;
+	u8 reg[6];
+
+	err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2);
+	if (err)
+		return err;
+
+	settings->ls_div_bits = (reg[1] >> 4) & 0x07;
+	settings->hs_div = (reg[1] & 0x07) << 8 | reg[0];
+
+	err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6);
+	if (err)
+		return err;
+
+	settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
+	settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
+				reg[3] << 24;
+	return 0;
+}
+
+static int si544_set_muldiv(struct clk_si544 *data,
+	struct clk_si544_muldiv *settings)
+{
+	int err;
+	u8 reg[6];
+
+	reg[0] = settings->hs_div;
+	reg[1] = settings->hs_div >> 8 | settings->ls_div_bits << 4;
+
+	err = regmap_bulk_write(data->regmap, SI544_REG_HS_DIV, reg, 2);
+	if (err < 0)
+		return err;
+
+	reg[0] = settings->fb_div_frac;
+	reg[1] = settings->fb_div_frac >> 8;
+	reg[2] = settings->fb_div_frac >> 16;
+	reg[3] = settings->fb_div_frac >> 24;
+	reg[4] = settings->fb_div_int;
+	reg[5] = settings->fb_div_int >> 8;
+
+	/*
+	 * Writing to SI544_REG_FBDIV40 triggers the clock change, so that
+	 * must be written last
+	 */
+	return regmap_bulk_write(data->regmap, SI544_REG_FBDIV0, reg, 6);
+}
+
+static bool is_valid_frequency(const struct clk_si544 *data,
+	unsigned long frequency)
+{
+	unsigned long max_freq;
+
+	if (frequency < SI544_MIN_FREQ)
+		return false;
+
+	switch (data->speed_grade) {
+	case si544a:
+		max_freq = 1500000000;
+		break;
+	case si544b:
+		max_freq = 800000000;
+		break;
+	case si544c:
+		max_freq = 350000000;
+		break;
+	}
+
+	return frequency <= max_freq;
+}
+
+/* Calculate divider settings for a given frequency */
+static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
+	unsigned long frequency)
+{
+	u64 vco;
+	u32 ls_freq;
+	u32 tmp;
+	u8 res;
+
+	/* Determine the minimum value of LS_DIV and resulting target freq. */
+	ls_freq = frequency;
+	settings->ls_div_bits = 0;
+
+	if (frequency >= MIN_HSDIV_FREQ) {
+		settings->ls_div_bits = 0;
+	} else {
+		res = 1;
+		tmp = 2 * HS_DIV_MAX;
+		while (tmp <= (HS_DIV_MAX * 32)) {
+			if (((u64)frequency * tmp) >= FVCO_MIN)
+				break;
+			++res;
+			tmp <<= 1;
+		}
+		settings->ls_div_bits = res;
+		ls_freq = frequency << res;
+	}
+
+	/* Determine minimum HS_DIV by rounding up */
+	vco = FVCO_MIN + ls_freq - 1;
+	do_div(vco, ls_freq);
+	settings->hs_div = vco;
+
+	/* round up to even number when required */
+	if ((settings->hs_div & 1) &&
+	    (settings->hs_div > HS_DIV_MAX_ODD || settings->ls_div_bits))
+		++settings->hs_div;
+
+	/* Calculate VCO frequency (in 10..12GHz range) */
+	vco = (u64)ls_freq * settings->hs_div;
+
+	/* Calculate the integer part of the feedback divider */
+	tmp = do_div(vco, FXO);
+	settings->fb_div_int = vco;
+
+	/* And the fractional bits using the remainder */
+	vco = (u64)tmp << 32;
+	do_div(vco, FXO);
+	settings->fb_div_frac = vco;
+
+	return 0;
+}
+
+/* Calculate resulting frequency given the register settings */
+static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+{
+	u32 d = settings->hs_div * BIT(settings->ls_div_bits);
+	u64 vco;
+
+	/* Calculate VCO from the fractional part */
+	vco = (u64)settings->fb_div_frac * FXO;
+	vco += (FXO / 2);
+	vco >>= 32;
+
+	/* Add the integer part of the VCO frequency */
+	vco += (u64)settings->fb_div_int * FXO;
+
+	/* Apply divider to obtain the generated frequency */
+	do_div(vco, d);
+
+	return vco;
+}
+
+static unsigned long si544_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	err = si544_get_muldiv(data, &settings);
+	if (err)
+		return 0;
+
+	return si544_calc_rate(&settings);
+}
+
+static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	if (!is_valid_frequency(data, rate))
+		return -EINVAL;
+
+	err = si544_calc_muldiv(&settings, rate);
+	if (err)
+		return err;
+
+	return si544_calc_rate(&settings);
+}
+
+/*
+ * Update output frequency for "big" frequency changes
+ */
+static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_si544 *data = to_clk_si544(hw);
+	struct clk_si544_muldiv settings;
+	int err;
+
+	if (!is_valid_frequency(data, rate))
+		return -EINVAL;
+
+	err = si544_calc_muldiv(&settings, rate);
+	if (err)
+		return err;
+
+	si544_enable_output(data, false);
+
+	/* Allow FCAL for this frequency update */
+	err = regmap_write(data->regmap, SI544_REG_FCAL_OVR, 0);
+	if (err < 0)
+		return err;
+
+
+	err = si544_set_muldiv(data, &settings);
+	if (err < 0)
+		return err; /* Undefined state now, best to leave disabled */
+
+	/* Trigger calibration */
+	err = regmap_write(data->regmap, SI544_REG_CONTROL,
+			   SI544_CONTROL_MS_ICAL2);
+	if (err < 0)
+		return err;
+
+	/* Applying a new frequency can take up to 10ms */
+	usleep_range(10000, 12000);
+
+	si544_enable_output(data, true);
+
+	return err;
+}
+
+static const struct clk_ops si544_clk_ops = {
+	.recalc_rate = si544_recalc_rate,
+	.round_rate = si544_round_rate,
+	.set_rate = si544_set_rate,
+};
+
+static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SI544_REG_CONTROL:
+	case SI544_REG_FCAL_OVR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config si544_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = SI544_REG_PAGE_SELECT,
+	.volatile_reg = si544_regmap_is_volatile,
+};
+
+static int si544_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct clk_si544 *data;
+	struct clk_init_data init;
+	int err;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	init.ops = &si544_clk_ops;
+	init.flags = 0;
+	init.num_parents = 0;
+	data->hw.init = &init;
+	data->i2c_client = client;
+	data->speed_grade = id->driver_data;
+
+	if (of_property_read_string(client->dev.of_node, "clock-output-names",
+			&init.name))
+		init.name = client->dev.of_node->name;
+
+	data->regmap = devm_regmap_init_i2c(client, &si544_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	i2c_set_clientdata(client, data);
+
+	/* Select page 0, just to be sure, there appear to be no more */
+	err = regmap_write(data->regmap, SI544_REG_PAGE_SELECT, 0);
+	if (err < 0)
+		return err;
+
+	err = devm_clk_hw_register(&client->dev, &data->hw);
+	if (err) {
+		dev_err(&client->dev, "clock registration failed\n");
+		return err;
+	}
+	err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get,
+					  &data->hw);
+	if (err) {
+		dev_err(&client->dev, "unable to add clk provider\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id si544_id[] = {
+	{ "si544a", si544a },
+	{ "si544b", si544b },
+	{ "si544c", si544c },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, si544_id);
+
+static const struct of_device_id clk_si544_of_match[] = {
+	{ .compatible = "silabs,si544a" },
+	{ .compatible = "silabs,si544b" },
+	{ .compatible = "silabs,si544c" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, clk_si544_of_match);
+
+static struct i2c_driver si544_driver = {
+	.driver = {
+		.name = "si544",
+		.of_match_table = clk_si544_of_match,
+	},
+	.probe		= si544_probe,
+	.id_table	= si544_id,
+};
+module_i2c_driver(si544_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Si544 driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v3] clk: Add driver for the si544 clock generator chip
  2018-03-20  8:15 ` [PATCH v3] " Mike Looijmans
@ 2018-03-23 17:04     ` Stephen Boyd
  0 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-23 17:04 UTC (permalink / raw)
  To: Mike Looijmans, linux-clk; +Cc: linux-kernel, mturquette, Mike Looijmans

Quoting Mike Looijmans (2018-03-20 01:15:41)
> +
> +static bool is_valid_frequency(const struct clk_si544 *data,
> +       unsigned long frequency)
> +{
> +       unsigned long max_freq;
> +
> +       if (frequency < SI544_MIN_FREQ)
> +               return false;
> +
> +       switch (data->speed_grade) {
> +       case si544a:
> +               max_freq = 1500000000;
> +               break;
> +       case si544b:
> +               max_freq = 800000000;
> +               break;
> +       case si544c:
> +               max_freq = 350000000;
> +               break;
> +       }

Sad. My compiler complains about max_freq being possibly unassigned
here, even though that seems impossible I guess we need to put back the
default case. I'll take care of it when applying and assign max_freq to
0 by default.

Otherwise, applied to clk-next.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3] clk: Add driver for the si544 clock generator chip
@ 2018-03-23 17:04     ` Stephen Boyd
  0 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2018-03-23 17:04 UTC (permalink / raw)
  To: Mike Looijmans, linux-clk; +Cc: linux-kernel, mturquette, Mike Looijmans

Quoting Mike Looijmans (2018-03-20 01:15:41)
> +
> +static bool is_valid_frequency(const struct clk_si544 *data,
> +       unsigned long frequency)
> +{
> +       unsigned long max_freq;
> +
> +       if (frequency < SI544_MIN_FREQ)
> +               return false;
> +
> +       switch (data->speed_grade) {
> +       case si544a:
> +               max_freq =3D 1500000000;
> +               break;
> +       case si544b:
> +               max_freq =3D 800000000;
> +               break;
> +       case si544c:
> +               max_freq =3D 350000000;
> +               break;
> +       }

Sad. My compiler complains about max_freq being possibly unassigned
here, even though that seems impossible I guess we need to put back the
default case. I'll take care of it when applying and assign max_freq to
0 by default.

Otherwise, applied to clk-next.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2018-03-23 17:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-15 11:50 [PATCH v2] clk: Add driver for the si544 clock generator chip Mike Looijmans
2018-03-18 12:52 ` Rob Herring
2018-03-19 15:04   ` Mike Looijmans
2018-03-19 15:04     ` Mike Looijmans
2018-03-19 15:04     ` Mike Looijmans
2018-03-19 21:08     ` Stephen Boyd
2018-03-19 21:08       ` Stephen Boyd
2018-03-20  7:15       ` Mike Looijmans
2018-03-20  7:15         ` Mike Looijmans
2018-03-20  7:15         ` Mike Looijmans
2018-03-20  7:18         ` Stephen Boyd
2018-03-20  7:18           ` Stephen Boyd
2018-03-20  8:15 ` [PATCH v3] " Mike Looijmans
2018-03-23 17:04   ` Stephen Boyd
2018-03-23 17:04     ` Stephen Boyd

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.