Devicetree
 help / color / mirror / Atom feed
From: Krzysztof Kozlowski <krzk@kernel.org>
To: Ali Rouhi <arouhi@sitime.com>
Cc: "jiri@resnulli.us" <jiri@resnulli.us>,
	 "vadim.fedorenko@linux.dev" <vadim.fedorenko@linux.dev>,
	 "arkadiusz.kubalewski@intel.com"
	<arkadiusz.kubalewski@intel.com>,
	"robh@kernel.org" <robh@kernel.org>,
	 "krzk+dt@kernel.org" <krzk+dt@kernel.org>,
	"conor+dt@kernel.org" <conor+dt@kernel.org>,
	 "cjubran@nvidia.com" <cjubran@nvidia.com>,
	 "Oleg.Zadorozhnyi@devoxsoftware.com"
	<Oleg.Zadorozhnyi@devoxsoftware.com>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	 "netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH net-next v4 3/3] dpll: add SiTime SiT9531x DPLL clock driver
Date: Fri, 7 Aug 2026 09:45:44 +0200	[thread overview]
Message-ID: <20260807-opalescent-raspberry-newt-4792ba@quoll> (raw)
In-Reply-To: <20260806232439.27551-4-arouhi@sitime.com>

On Thu, Aug 06, 2026 at 11:24:44PM +0000, Ali Rouhi wrote:
> Add a DPLL subsystem driver for the SiTime SiT95316 and SiT95317
> clock generators. These devices provide low-jitter clock outputs
> commonly used in telecom, networking, and data center timing
> applications.
> 
> The driver exposes all inputs and outputs through the Linux DPLL
> subsystem, supporting:
>  - Lock status monitoring via register polling or optional INTRB IRQ
>  - Input priority management for automatic reference switchover
>  - Per-output frequency readback from hardware state
>  - DCO (digitally controlled oscillator) frequency adjustment
>  - Phase offset measurement via TDC (time-to-digital converter)
>  - Phase adjustment for fine output alignment
>  - Embedded sync (esync) pulse control
>  - SYSREF/SYNCB/Pulser output mode control
>  - Optional reset-gpios for hardware reset
> 
> The driver reads all configuration from the device's on-chip NVM
> at probe time -- no firmware loading is required.
> 
> Co-developed-by: Oleg Zadorozhnyi <Oleg.Zadorozhnyi@devoxsoftware.com>
> Signed-off-by: Oleg Zadorozhnyi <Oleg.Zadorozhnyi@devoxsoftware.com>
> Assisted-by: Claude:claude-4-opus [chat]

I can see that. Looks like a lot of AI slop coding style, not really
acceptable for mainline.

...

> +/*
> + * sit9531x_irq_thread_fn - threaded IRQ handler for the chip's INTRB line
> + *
> + * Triggered when the chip asserts INTRB (and only when DT wires up the
> + * client interrupt; absent property == handler never installed).  The
> + * action mirrors a periodic-work tick: queue an immediate run so status
> + * registers are read and DPLL changes_check fires without waiting for
> + * the next poll deadline.  Polling continues to run as a fallback.
> + */
> +static irqreturn_t sit9531x_irq_thread_fn(int irq, void *data)
> +{
> +	struct sit9531x_dev *sitdev = data;
> +	int rc;
> +
> +	/*
> +	 * Acknowledge the chip's notification latches from the threaded
> +	 * handler itself.  With IRQF_ONESHOT the line is unmasked on
> +	 * return, so deferring the W1C clear to the async kworker would
> +	 * let a still-asserted INTRB re-fire immediately (interrupt storm).
> +	 * Clear here, then kick the poll worker to read state and run
> +	 * changes_check.
> +	 */
> +	mutex_lock(&sitdev->multiop_lock);
> +	rc = sit9531x_clear_notifications(sitdev);
> +	mutex_unlock(&sitdev->multiop_lock);
> +	if (rc)
> +		dev_warn_ratelimited(sitdev->dev,
> +				     "IRQ: failed to clear notifications: %d\n",
> +				     rc);
> +
> +	kthread_mod_delayed_work(sitdev->kworker, &sitdev->work, 0);
> +	return IRQ_HANDLED;
> +}
> +
> +/* ====================================================================
> + * Device lifecycle -- start / stop / dpll_init / dpll_fini
> + * ====================================================================
> + */
> +
> +/**
> + * sit9531x_dev_start - start normal operation
> + * @sitdev:	device pointer
> + *
> + * Fetches initial hardware state, registers all DPLL devices and
> + * their pins, and starts the periodic monitoring thread.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +int sit9531x_dev_start(struct sit9531x_dev *sitdev)
> +{
> +	struct sit9531x_dpll *sitdpll;
> +	int rc;
> +
> +	/* Fetch device state */
> +	rc = sit9531x_dev_state_fetch(sitdev);
> +	if (rc)
> +		return rc;
> +
> +	/* Register all DPLLs */
> +	list_for_each_entry(sitdpll, &sitdev->dplls, list) {
> +		rc = sit9531x_dpll_register(sitdpll);
> +		if (rc) {
> +			dev_err_probe(sitdev->dev, rc,
> +				      "Failed to register DPLL%u\n",
> +				      sitdpll->id);
> +			return rc;
> +		}
> +	}
> +
> +	/* Start monitoring */
> +	kthread_queue_delayed_work(sitdev->kworker, &sitdev->work, 0);
> +
> +	return 0;
> +}
> +
> +/**
> + * sit9531x_dev_stop - stop normal operation
> + * @sitdev:	device pointer
> + *
> + * Cancels the monitoring thread and unregisters all DPLL devices
> + * and their pins.
> + */
> +void sit9531x_dev_stop(struct sit9531x_dev *sitdev)
> +{
> +	struct sit9531x_dpll *sitdpll;
> +
> +	/* Stop monitoring */
> +	kthread_cancel_delayed_work_sync(&sitdev->work);
> +
> +	/* Unregister all DPLLs */
> +	list_for_each_entry(sitdpll, &sitdev->dplls, list) {
> +		if (sitdpll->dpll_dev)
> +			sit9531x_dpll_unregister(sitdpll);
> +	}
> +}
> +
> +static void sit9531x_dev_dpll_fini(void *ptr)
> +{
> +	struct sit9531x_dpll *sitdpll, *next;
> +	struct sit9531x_dev *sitdev = ptr;
> +
> +	/* Stop monitoring and unregister DPLLs */
> +	sit9531x_dev_stop(sitdev);

sit9531x_dev_dpll_fini() this is called from sit9531x_devm_dpll_init()
before device was started. Very confusing code. I find this driver
difficult to read. It's over complicated, too many comments, multiple
helper functions, 10-steps of init from probe and then turns out that
this init is not even correct.

> +
> +	/* Destroy monitoring thread */
> +	if (sitdev->kworker) {

How is this possible? This is called from error path, so either this was
set or not. Why are you calling function with unknown state of your
driver?

> +		kthread_destroy_worker(sitdev->kworker);
> +		sitdev->kworker = NULL;
> +	}
> +
> +	/* Free all DPLLs */
> +	list_for_each_entry_safe(sitdpll, next, &sitdev->dplls, list) {
> +		list_del(&sitdpll->list);
> +		sit9531x_dpll_free(sitdpll);
> +	}
> +}
> +
> +/*
> + * sit9531x_devm_dpll_init - allocate DPLLs and start the device
> + * @sitdev:	device pointer
> + *
> + * Allocates one DPLL per PLL channel, creates the monitoring thread,
> + * starts normal operation, and registers a devres cleanup action.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int sit9531x_devm_dpll_init(struct sit9531x_dev *sitdev)
> +{
> +	struct kthread_worker *kworker;
> +	struct sit9531x_dpll *sitdpll;
> +	unsigned int i;
> +	int rc;
> +
> +	INIT_LIST_HEAD(&sitdev->dplls);
> +
> +	/*
> +	 * Initialize the monitoring work before anything that can fail into
> +	 * the error path: sit9531x_dev_dpll_fini() -> sit9531x_dev_stop()
> +	 * calls kthread_cancel_delayed_work_sync(&sitdev->work)
> +	 * unconditionally, which must not run on an uninitialized work.
> +	 */
> +	kthread_init_delayed_work(&sitdev->work, sit9531x_dev_periodic_work);
> +
> +	/* Allocate all DPLLs */
> +	for (i = 0; i < SIT9531X_NUM_PLLS; i++) {
> +		sitdpll = sit9531x_dpll_alloc(sitdev, i);
> +		if (IS_ERR(sitdpll)) {
> +			dev_err_probe(sitdev->dev, PTR_ERR(sitdpll),
> +				      "Failed to alloc DPLL%u\n", i);
> +			rc = PTR_ERR(sitdpll);

Syntax is rc = dev_err_probe()

> +			goto error;
> +		}
> +
> +		list_add_tail(&sitdpll->list, &sitdev->dplls);
> +	}
> +
> +	/* Start the monitoring thread worker */
> +	kworker = kthread_run_worker(0, "sit9531x-%s",
> +				     dev_name(sitdev->dev));
> +	if (IS_ERR(kworker)) {
> +		rc = PTR_ERR(kworker);
> +		goto error;
> +	}
> +	sitdev->kworker = kworker;
> +
> +	/* Start normal operation */
> +	rc = sit9531x_dev_start(sitdev);
> +	if (rc) {
> +		dev_err_probe(sitdev->dev, rc, "Failed to start device\n");
> +		goto error;
> +	}
> +
> +	/* Add devres action to release DPLL related resources */
> +	return devm_add_action_or_reset(sitdev->dev, sit9531x_dev_dpll_fini,
> +					sitdev);
> +
> +error:
> +	sit9531x_dev_dpll_fini(sitdev);
> +
> +	return rc;
> +}
> +
> +/* ====================================================================
> + * Chip identification
> + * ====================================================================
> + */
> +
> +/*
> + * sit9531x_read_variant_id - read chip variant ID byte from hardware
> + * @sitdev:	device pointer
> + * @id:		output variant ID byte
> + *
> + * Reads the single-byte variant identification register from Page 0
> + * reg 0x02 (95317 = 0x17, 95316 = 0x31).  Reg 0x03 holds a separate
> + * revision byte and is intentionally not consumed here.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int sit9531x_read_variant_id(struct sit9531x_dev *sitdev, u8 *id)
> +{
> +	return sit9531x_read_u8(sitdev, SIT9531X_REG_VARIANT_ID, id);
> +}
> +
> +/*
> + * sit9531x_match_variant - match variant ID against known variants
> + * @id:	variant ID byte
> + *
> + * Return: pointer to chip_info on match, NULL on unknown ID
> + */
> +static const struct sit9531x_chip_info *sit9531x_match_variant(u8 id)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(sit9531x_chip_ids); i++) {
> +		if (sit9531x_chip_ids[i].id == id)
> +			return &sit9531x_chip_ids[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +/*
> + * sit9531x_derive_clock_id - build EUI-64 clock identifier
> + * @sitdev:	device pointer
> + *
> + * Generates a deterministic 64-bit identifier from the SiTime OUI,
> + * the chip ID, and the I2C address.  This provides a stable clock_id
> + * across reboots.
> + *
> + * Return: 64-bit clock identifier
> + */
> +static u64 sit9531x_derive_clock_id(struct sit9531x_dev *sitdev)
> +{
> +	u64 clkid;
> +
> +	clkid  = SIT9531X_OUI << 24;
> +	clkid |= (u64)sitdev->info->id << 8;
> +	clkid |= (u64)sitdev->client->addr;
> +
> +	return clkid;
> +}
> +
> +/* ====================================================================
> + * Probe entry point
> + * ====================================================================
> + */
> +
> +/**
> + * sit9531x_dev_probe - initialize SiT9531x device
> + * @sitdev:	pointer to device structure (caller-allocated)
> + *
> + * Common initialization: read chip ID, match variant, generate
> + * clock_id, initialize synchronization mutex, and register DPLL
> + * channels.  Called from the I2C probe function.
> + *
> + * Return: 0 on success, <0 on error

There is little point in describing standard functions. Redundant
comments are not helping.

> + */
> +int sit9531x_dev_probe(struct sit9531x_dev *sitdev)
> +{
> +	struct clk *xtal_clk;
> +	u8 variant_id;
> +	int rc;
> +
> +	/*
> +	 * Read the external reference (XO) feeding the chip's XIN/XO_CLK
> +	 * input.  Required: Fvco computation does
> +	 * Fvco = Fref * (DIVN + frac/2^32) with Fref = xtal_freq << doubler,
> +	 * so without a populated xtal_freq every freq_set/phase_adjust path
> +	 * dividing by Fvco fails with -EIO.  The rate normally comes from a
> +	 * "clocks" phandle (clock-names = "xtal").  As a fallback, when the
> +	 * firmware does not yet expose the XO through the clock framework,
> +	 * take the rate from a "clock-frequency" device property instead.
> +	 */
> +	xtal_clk = devm_clk_get_optional_enabled(sitdev->dev, "xtal");
> +	if (IS_ERR(xtal_clk))
> +		return dev_err_probe(sitdev->dev, PTR_ERR(xtal_clk),
> +				     "Failed to get xtal clock\n");
> +	sitdev->xtal_freq = xtal_clk ? clk_get_rate(xtal_clk) : 0;

The entire comparison is pointless.

> +	if (!sitdev->xtal_freq) {
> +		u32 freq;
> +
> +		if (!device_property_read_u32(sitdev->dev, "clock-frequency",
> +					      &freq))
> +			sitdev->xtal_freq = freq;
> +	}
> +	if (!sitdev->xtal_freq)
> +		return dev_err_probe(sitdev->dev, -EINVAL,
> +				     "no xtal rate: provide clocks=<&xo> + clock-names=\"xtal\", or a clock-frequency property\n");
> +	dev_info(sitdev->dev, "xtal_freq=%u Hz\n", sitdev->xtal_freq);

Drop, driver should be silent on success.

> +
> +	/*
> +	 * Optional DT-described reset line.  Requested in the deasserted
> +	 * state so any prior chip programming is not torn down by the
> +	 * request itself.  The driver deliberately never pulses reset at
> +	 * runtime: the chip configuration (filter coefficients, output
> +	 * routing, priority tables) is loaded from efuse or an NVM blob
> +	 * before probe, and a hardware reset would discard it.  The line
> +	 * is held deasserted only to guarantee the chip is out of reset
> +	 * for I2C.  Absent DT property == descriptor stays NULL, no
> +	 * behaviour change.
> +	 *
> +	 * Must run before the first I2C access: if the board wires reset
> +	 * and starts with the line asserted, the chip is held in reset and
> +	 * variant-ID reads return -EIO/-ETIMEDOUT.
> +	 */
> +	sitdev->reset_gpio = devm_gpiod_get_optional(sitdev->dev, "reset",
> +						     GPIOD_OUT_LOW);
> +	if (IS_ERR(sitdev->reset_gpio))
> +		return dev_err_probe(sitdev->dev, PTR_ERR(sitdev->reset_gpio),
> +				     "Failed to request reset gpio\n");
> +	if (sitdev->reset_gpio) {
> +		dev_info(sitdev->dev, "reset-gpios: present (held deasserted)\n");

Drop

> +		/*
> +		 * If the board powered up with RESETB asserted, requesting
> +		 * the line deasserted above just released the chip.  Wait for
> +		 * its internal boot to complete before the first I2C access so
> +		 * sit9531x_read_variant_id() below does not race chip
> +		 * readiness and return -EIO/-ETIMEDOUT.
> +		 */
> +		fsleep(10000);
> +	}
> +
> +	/*
> +	 * Optional board-config overrides for fixed (efuse/blob) routing
> +	 * that the chip registers do not expose unambiguously.  Absent
> +	 * properties leave pll_fvco[] zeroed (derive from DIVN) and
> +	 * out_pll_map_valid false (use the OUT_MAP registers).
> +	 */
> +	device_property_read_u64_array(sitdev->dev, "sitime,pll-fvco",
> +				       sitdev->pll_fvco, SIT9531X_NUM_PLLS);
> +
> +	if (device_property_present(sitdev->dev, "sitime,output-pll-map")) {
> +		u32 map[SIT9531X_MAX_OUTPUTS];
> +		int n, i;
> +
> +		/*
> +		 * Accept any 1..MAX_OUTPUTS length so the 8-output SiT95317
> +		 * can supply an 8-entry map instead of being forced to pad to
> +		 * 12.  Variant detection has not run yet; entries beyond the
> +		 * detected num_outputs are simply never indexed.
> +		 *
> +		 * Default every entry to "unmapped" first: when a shorter map
> +		 * is supplied for a variant with more outputs, the trailing
> +		 * entries must not read back as 0 (== PLLA) and falsely mark
> +		 * unrouted outputs as active in sit9531x_out_state_fetch().
> +		 */
> +		memset(sitdev->out_pll_map, SIT9531X_OUT_PLL_UNMAPPED,
> +		       sizeof(sitdev->out_pll_map));
> +
> +		n = device_property_count_u32(sitdev->dev,
> +					      "sitime,output-pll-map");
> +		if (n > 0 && n <= SIT9531X_MAX_OUTPUTS &&
> +		    !device_property_read_u32_array(sitdev->dev,
> +						    "sitime,output-pll-map",
> +						    map, n)) {
> +			for (i = 0; i < n; i++)
> +				sitdev->out_pll_map[i] = map[i];
> +			sitdev->out_pll_map_valid = true;
> +		}
> +	}
> +
> +	/* Read variant ID byte */
> +	rc = sit9531x_read_variant_id(sitdev, &variant_id);
> +	if (rc)
> +		return rc;
> +
> +	/* Detect chip variant */
> +	sitdev->info = sit9531x_match_variant(variant_id);

So devices are fully detectable, thus compatible. Express the
compatibility in the binding and drop redundant OF device id table
entry.

> +	if (!sitdev->info)
> +		return dev_err_probe(sitdev->dev, -ENODEV,
> +				     "Unknown variant ID: 0x%02x\n", variant_id);
> +
> +	dev_info(sitdev->dev, "VariantID(0x%02X), %s (%u in, %u out)\n",
> +		 variant_id, sitdev->info->name,
> +		 sitdev->info->num_inputs, sitdev->info->num_outputs);
> +
> +	/* Generate deterministic clock ID */
> +	sitdev->clock_id = sit9531x_derive_clock_id(sitdev);
> +
> +	/* No PLL sources inter-PLL synchronization until requested */
> +	sitdev->intsync_src = -1;
> +
> +	/* Initialize mutex for multi-register atomic operations */
> +	rc = devm_mutex_init(sitdev->dev, &sitdev->multiop_lock);
> +	if (rc)
> +		return dev_err_probe(sitdev->dev, rc,
> +				     "Failed to initialize mutex\n");
> +
> +	/*
> +	 * Register DPLL channels and create the kworker first.  The IRQ
> +	 * handler dereferences sitdev->kworker via
> +	 * kthread_mod_delayed_work(), so it must be live before any
> +	 * INTRB assertion can land on the request_threaded_irq path.
> +	 */
> +	rc = sit9531x_devm_dpll_init(sitdev);
> +	if (rc)
> +		return rc;
> +
> +	/*
> +	 * Optional INTRB IRQ from DT.  The I2C subsystem populates
> +	 * client->irq from the node's "interrupts"/"interrupts-extended"
> +	 * property; if no IRQ is wired client->irq is 0 and we keep
> +	 * relying on the periodic poll.
> +	 */
> +	sitdev->irq = sitdev->client ? sitdev->client->irq : 0;
> +	if (sitdev->irq > 0) {
> +		rc = devm_request_threaded_irq(sitdev->dev, sitdev->irq,
> +					       NULL, sit9531x_irq_thread_fn,
> +					       IRQF_ONESHOT,
> +					       dev_name(sitdev->dev), sitdev);
> +		if (rc)
> +			return dev_err_probe(sitdev->dev, rc,
> +					     "Failed to request IRQ %d\n",
> +					     sitdev->irq);
> +		dev_info(sitdev->dev,
> +			 "INTRB IRQ %d wired (threaded handler kicks periodic poll)\n",
> +			 sitdev->irq);
> +	}
> +
> +	return 0;
> +}
> +
> +/* ====================================================================
> + * I2C driver
> + * ====================================================================
> + */

That's not even Linux coding style comment... Please clean up driver
from non-Linux comments.

> +
> +static int sit9531x_i2c_probe(struct i2c_client *client)
> +{
> +	struct sit9531x_dev *sitdev;
> +	struct regmap *regmap;
> +
> +	regmap = devm_regmap_init_i2c(client, &sit9531x_regmap_config);
> +	if (IS_ERR(regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(regmap),
> +				     "Failed to initialize regmap\n");
> +
> +	sitdev = devm_kzalloc(&client->dev, sizeof(*sitdev), GFP_KERNEL);
> +	if (!sitdev)
> +		return -ENOMEM;
> +
> +	sitdev->dev = &client->dev;
> +	sitdev->client = client;
> +	sitdev->regmap = regmap;
> +	i2c_set_clientdata(client, sitdev);
> +
> +	return sit9531x_dev_probe(sitdev);
> +}
> +
> +static const struct i2c_device_id sit9531x_i2c_id[] = {
> +	{ "sit95317" },
> +	{ "sit95316" },

Why reversed order?

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, sit9531x_i2c_id);
> +
> +static const struct of_device_id sit9531x_of_match[] = {
> +	{ .compatible = "sitime,sit95317" },

So this one is not neede., express the compatibility.

> +	{ .compatible = "sitime,sit95316" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sit9531x_of_match);
> +
> +static struct i2c_driver sit9531x_i2c_driver = {
> +	.driver = {
> +		.name		= "sit9531x",
> +		.of_match_table	= sit9531x_of_match,
> +	},
> +	.probe		= sit9531x_i2c_probe,
> +	.id_table	= sit9531x_i2c_id,
> +};
> +module_i2c_driver(sit9531x_i2c_driver);
> +


...

> +/* ====================================================================
> + * Pin allocation, registration, and cleanup
> + * ====================================================================
> + */
> +
> +static const struct dpll_pin_ops *
> +sit9531x_dpll_pin_ops_get(const struct sit9531x_dpll_pin *pin)
> +{
> +	if (!sit9531x_dpll_is_input_pin(pin)) {
> +		if (sit9531x_dpll_is_intsync_src_pin(pin))
> +			return &sit9531x_dpll_intsync_src_pin_ops;
> +		return &sit9531x_dpll_output_pin_ops;
> +	}
> +	if (sit9531x_dpll_is_intsync_pin(pin))
> +		return &sit9531x_dpll_intsync_dst_pin_ops;
> +	if (sit9531x_dpll_is_xo_pin(pin))
> +		return &sit9531x_dpll_xo_pin_ops;
> +	return &sit9531x_dpll_input_pin_ops;
> +}
> +
> +/*
> + * sit9531x_dpll_pin_alloc - allocate a DPLL pin
> + * @sitdpll:	DPLL device this pin belongs to
> + * @dir:	pin direction
> + * @id:		hardware pin index
> + *
> + * Return: pointer to allocated pin on success, error pointer on error
> + */
> +static struct sit9531x_dpll_pin *
> +sit9531x_dpll_pin_alloc(struct sit9531x_dpll *sitdpll,
> +			enum dpll_pin_direction dir, u8 id)
> +{
> +	struct sit9531x_dpll_pin *pin;
> +
> +	pin = kzalloc_obj(*pin, GFP_KERNEL);
> +	if (!pin)
> +		return ERR_PTR(-ENOMEM);
> +
> +	pin->dpll = sitdpll;
> +	pin->dir = dir;
> +	pin->id = id;
> +
> +	return pin;
> +}
> +
> +/*
> + * sit9531x_dpll_pin_free - deallocate a DPLL pin
> + * @pin:	pin to free
> + */
> +static void sit9531x_dpll_pin_free(struct sit9531x_dpll_pin *pin)
> +{
> +	WARN(pin->dpll_pin, "DPLL pin is still registered\n");
> +	kfree(pin);
> +}
> +
> +/*
> + * sit9531x_dpll_pin_register - register a DPLL pin with the subsystem
> + * @pin:	pin to register
> + * @index:	absolute pin index for clock_id namespace
> + *
> + * Gets pin properties from firmware, creates or gets a dpll_pin,
> + * and registers it with the parent DPLL device.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int sit9531x_dpll_pin_register(struct sit9531x_dpll_pin *pin,
> +				      u32 index)
> +{
> +	struct sit9531x_dpll *sitdpll = pin->dpll;
> +	struct sit9531x_pin_props *props;
> +	const struct dpll_pin_ops *ops;
> +	int rc;
> +
> +	/* Get pin properties from firmware nodes */
> +	props = sit9531x_pin_props_get(sitdpll->dev, pin->dir, pin->id);
> +	if (IS_ERR(props))
> +		return PTR_ERR(props);
> +
> +	/* Save package label and firmware node */
> +	strscpy(pin->label, props->package_label, sizeof(pin->label));
> +	pin->fwnode = fwnode_handle_get(props->fwnode);
> +	pin->esync_control = props->esync_control;
> +
> +	/* Create or get existing DPLL pin */
> +	pin->dpll_pin = dpll_pin_get(sitdpll->dev->clock_id, index,
> +				     THIS_MODULE, &props->dpll_props,
> +				     &pin->tracker);
> +	if (IS_ERR(pin->dpll_pin)) {
> +		rc = PTR_ERR(pin->dpll_pin);
> +		goto err_pin_get;
> +	}
> +	dpll_pin_fwnode_set(pin->dpll_pin, props->fwnode);
> +
> +	ops = sit9531x_dpll_pin_ops_get(pin);
> +
> +	/* Register the pin */
> +	rc = dpll_pin_register(sitdpll->dpll_dev, pin->dpll_pin, ops, pin);
> +	if (rc)
> +		goto err_register;
> +
> +	/* Free pin properties */
> +	sit9531x_pin_props_put(props);

This is all probe code, so it should be immediately before the probe()
functions, not in other units.

> +
> +	return 0;
> +
> +err_register:
> +	dpll_pin_put(pin->dpll_pin, &pin->tracker);
> +err_pin_get:
> +	/*
> +	 * On the dpll_pin_get() failure path pin->dpll_pin holds an ERR_PTR;
> +	 * clear it so the caller's sit9531x_dpll_pin_free() does not mistake
> +	 * it for a still-registered pin and emit a spurious WARN().
> +	 */
> +	pin->dpll_pin = NULL;
> +	fwnode_handle_put(pin->fwnode);
> +	pin->fwnode = NULL;
> +	sit9531x_pin_props_put(props);
> +
> +	return rc;
> +}
> +
> +/*
> + * sit9531x_dpll_pin_unregister - unregister a DPLL pin

Can sit9531x_dpll_pin_unregister() do anything than unregister a DPLL
pin? How useful are such comments?

Best regards,
Krzysztof


  reply	other threads:[~2026-08-07  7:45 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06 23:24 [PATCH net-next v4 0/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-08-06 23:24 ` [PATCH net-next v4 1/3] dt-bindings: vendor-prefixes: add SiTime Corporation Ali Rouhi
2026-08-06 23:24 ` [PATCH net-next v4 2/3] dt-bindings: dpll: add SiTime SiT9531x clock generator Ali Rouhi
2026-08-07  7:48   ` Krzysztof Kozlowski
2026-08-06 23:24 ` [PATCH net-next v4 3/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-08-07  7:45   ` Krzysztof Kozlowski [this message]
2026-08-07 23:24   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260807-opalescent-raspberry-newt-4792ba@quoll \
    --to=krzk@kernel.org \
    --cc=Oleg.Zadorozhnyi@devoxsoftware.com \
    --cc=arkadiusz.kubalewski@intel.com \
    --cc=arouhi@sitime.com \
    --cc=cjubran@nvidia.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jiri@resnulli.us \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=vadim.fedorenko@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox