Skip to content

Commit 75a71ec

Browse files
ivecerakuba-moo
authored andcommitted
dpll: zl3073x: Register DPLL devices and pins
Enumerate all available DPLL channels and registers a DPLL device for each of them. Check all input references and outputs and register DPLL pins for them. Number of registered DPLL pins depends on configuration of references and outputs. If the reference or output is configured as differential one then only one DPLL pin is registered. Both references and outputs can be also disabled from firmware configuration and in this case no DPLL pins are registered. All registrable references are registered to all available DPLL devices with exception of DPLLs that are configured in NCO (numerically controlled oscillator) mode. In this mode DPLL channel acts as PHC and cannot be locked to any reference. Device outputs are connected to one of synthesizers and each synthesizer is driven by some DPLL channel. So output pins belonging to given output are registered to DPLL device that drives associated synthesizer. Finally add kworker task to monitor async changes on all DPLL channels and input pins and to notify about them DPLL core. Output pins are not monitored as their parameters are not changed asynchronously by the device. Co-developed-by: Prathosh Satish <Prathosh.Satish@microchip.com> Signed-off-by: Prathosh Satish <Prathosh.Satish@microchip.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Link: https://patch.msgid.link/20250704182202.1641943-9-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent a99a9f0 commit 75a71ec

File tree

7 files changed

+1156
-1
lines changed

7 files changed

+1156
-1
lines changed

drivers/dpll/zl3073x/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22

33
obj-$(CONFIG_ZL3073X) += zl3073x.o
4-
zl3073x-objs := core.o devlink.o prop.o
4+
zl3073x-objs := core.o devlink.o dpll.o prop.o
55

66
obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o
77
zl3073x_i2c-objs := i2c.o

drivers/dpll/zl3073x/core.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "core.h"
1919
#include "devlink.h"
20+
#include "dpll.h"
2021
#include "regs.h"
2122

2223
/* Chip IDs for zl30731 */
@@ -668,6 +669,104 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
668669
return rc;
669670
}
670671

672+
static void
673+
zl3073x_dev_periodic_work(struct kthread_work *work)
674+
{
675+
struct zl3073x_dev *zldev = container_of(work, struct zl3073x_dev,
676+
work.work);
677+
struct zl3073x_dpll *zldpll;
678+
679+
list_for_each_entry(zldpll, &zldev->dplls, list)
680+
zl3073x_dpll_changes_check(zldpll);
681+
682+
/* Run twice a second */
683+
kthread_queue_delayed_work(zldev->kworker, &zldev->work,
684+
msecs_to_jiffies(500));
685+
}
686+
687+
static void zl3073x_dev_dpll_fini(void *ptr)
688+
{
689+
struct zl3073x_dpll *zldpll, *next;
690+
struct zl3073x_dev *zldev = ptr;
691+
692+
/* Stop monitoring thread */
693+
if (zldev->kworker) {
694+
kthread_cancel_delayed_work_sync(&zldev->work);
695+
kthread_destroy_worker(zldev->kworker);
696+
zldev->kworker = NULL;
697+
}
698+
699+
/* Release DPLLs */
700+
list_for_each_entry_safe(zldpll, next, &zldev->dplls, list) {
701+
zl3073x_dpll_unregister(zldpll);
702+
list_del(&zldpll->list);
703+
zl3073x_dpll_free(zldpll);
704+
}
705+
}
706+
707+
static int
708+
zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
709+
{
710+
struct kthread_worker *kworker;
711+
struct zl3073x_dpll *zldpll;
712+
unsigned int i;
713+
int rc;
714+
715+
INIT_LIST_HEAD(&zldev->dplls);
716+
717+
/* Initialize all DPLLs */
718+
for (i = 0; i < num_dplls; i++) {
719+
zldpll = zl3073x_dpll_alloc(zldev, i);
720+
if (IS_ERR(zldpll)) {
721+
dev_err_probe(zldev->dev, PTR_ERR(zldpll),
722+
"Failed to alloc DPLL%u\n", i);
723+
rc = PTR_ERR(zldpll);
724+
goto error;
725+
}
726+
727+
rc = zl3073x_dpll_register(zldpll);
728+
if (rc) {
729+
dev_err_probe(zldev->dev, rc,
730+
"Failed to register DPLL%u\n", i);
731+
zl3073x_dpll_free(zldpll);
732+
goto error;
733+
}
734+
735+
list_add_tail(&zldpll->list, &zldev->dplls);
736+
}
737+
738+
/* Perform initial firmware fine phase correction */
739+
rc = zl3073x_dpll_init_fine_phase_adjust(zldev);
740+
if (rc) {
741+
dev_err_probe(zldev->dev, rc,
742+
"Failed to init fine phase correction\n");
743+
goto error;
744+
}
745+
746+
/* Initialize monitoring thread */
747+
kthread_init_delayed_work(&zldev->work, zl3073x_dev_periodic_work);
748+
kworker = kthread_run_worker(0, "zl3073x-%s", dev_name(zldev->dev));
749+
if (IS_ERR(kworker)) {
750+
rc = PTR_ERR(kworker);
751+
goto error;
752+
}
753+
754+
zldev->kworker = kworker;
755+
kthread_queue_delayed_work(zldev->kworker, &zldev->work, 0);
756+
757+
/* Add devres action to release DPLL related resources */
758+
rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev);
759+
if (rc)
760+
goto error;
761+
762+
return 0;
763+
764+
error:
765+
zl3073x_dev_dpll_fini(zldev);
766+
767+
return rc;
768+
}
769+
671770
/**
672771
* zl3073x_dev_probe - initialize zl3073x device
673772
* @zldev: pointer to zl3073x device
@@ -740,6 +839,11 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
740839
if (rc)
741840
return rc;
742841

842+
/* Register DPLL channels */
843+
rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels);
844+
if (rc)
845+
return rc;
846+
743847
/* Register the devlink instance and parameters */
744848
rc = zl3073x_devlink_register(zldev);
745849
if (rc)

drivers/dpll/zl3073x/core.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
#ifndef _ZL3073X_CORE_H
44
#define _ZL3073X_CORE_H
55

6+
#include <linux/kthread.h>
7+
#include <linux/list.h>
68
#include <linux/mutex.h>
79
#include <linux/types.h>
810

911
#include "regs.h"
1012

1113
struct device;
1214
struct regmap;
15+
struct zl3073x_dpll;
1316

1417
/*
1518
* Hardware limits for ZL3073x chip family
@@ -18,6 +21,10 @@ struct regmap;
1821
#define ZL3073X_NUM_REFS 10
1922
#define ZL3073X_NUM_OUTS 10
2023
#define ZL3073X_NUM_SYNTHS 5
24+
#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS
25+
#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)
26+
#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
27+
ZL3073X_NUM_OUTPUT_PINS)
2128

2229
/**
2330
* struct zl3073x_ref - input reference invariant info
@@ -62,6 +69,9 @@ struct zl3073x_synth {
6269
* @ref: array of input references' invariants
6370
* @out: array of outs' invariants
6471
* @synth: array of synths' invariants
72+
* @dplls: list of DPLLs
73+
* @kworker: thread for periodic work
74+
* @work: periodic work
6575
*/
6676
struct zl3073x_dev {
6777
struct device *dev;
@@ -73,6 +83,13 @@ struct zl3073x_dev {
7383
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
7484
struct zl3073x_out out[ZL3073X_NUM_OUTS];
7585
struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
86+
87+
/* DPLL channels */
88+
struct list_head dplls;
89+
90+
/* Monitor */
91+
struct kthread_worker *kworker;
92+
struct kthread_delayed_work work;
7693
};
7794

7895
struct zl3073x_chip_info {

drivers/dpll/zl3073x/devlink.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "core.h"
1010
#include "devlink.h"
11+
#include "dpll.h"
1112
#include "regs.h"
1213

1314
/**
@@ -84,9 +85,16 @@ zl3073x_devlink_reload_down(struct devlink *devlink, bool netns_change,
8485
enum devlink_reload_limit limit,
8586
struct netlink_ext_ack *extack)
8687
{
88+
struct zl3073x_dev *zldev = devlink_priv(devlink);
89+
struct zl3073x_dpll *zldpll;
90+
8791
if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
8892
return -EOPNOTSUPP;
8993

94+
/* Unregister all DPLLs */
95+
list_for_each_entry(zldpll, &zldev->dplls, list)
96+
zl3073x_dpll_unregister(zldpll);
97+
9098
return 0;
9199
}
92100

@@ -99,6 +107,7 @@ zl3073x_devlink_reload_up(struct devlink *devlink,
99107
{
100108
struct zl3073x_dev *zldev = devlink_priv(devlink);
101109
union devlink_param_value val;
110+
struct zl3073x_dpll *zldpll;
102111
int rc;
103112

104113
if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
@@ -116,6 +125,14 @@ zl3073x_devlink_reload_up(struct devlink *devlink,
116125
zldev->clock_id = val.vu64;
117126
}
118127

128+
/* Re-register all DPLLs */
129+
list_for_each_entry(zldpll, &zldev->dplls, list) {
130+
rc = zl3073x_dpll_register(zldpll);
131+
if (rc)
132+
dev_warn(zldev->dev,
133+
"Failed to re-register DPLL%u\n", zldpll->id);
134+
}
135+
119136
*actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
120137

121138
return 0;

0 commit comments

Comments
 (0)