Commit 4845f2ff authored by Ivan Vecera's avatar Ivan Vecera Committed by Paolo Abeni
Browse files

dpll: zl3073x: detect DPLL channel count from chip ID at runtime



Replace the five per-variant zl3073x_chip_info structures and their
exported symbol definitions with a single consolidated chip ID lookup
table. The chip variant is now detected at runtime by reading the chip
ID register from hardware and looking it up in the table, rather than
being selected at compile time via the bus driver match data.

Repurpose struct zl3073x_chip_info to hold a single chip ID, its
channel count, and a flags field. Introduce enum zl3073x_flags with
ZL3073X_FLAG_REF_PHASE_COMP_32 to replace the chip_id switch statement
in zl3073x_dev_is_ref_phase_comp_32bit(). Store a pointer to the
detected chip_info entry in struct zl3073x_dev for runtime access.

This simplifies the bus drivers by removing per-variant .data and
.driver_data references from the I2C/SPI match tables, and makes
adding support for new chip variants a single-line table addition.

Signed-off-by: default avatarIvan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20260227105300.710272-2-ivecera@redhat.com


Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 2b12ffb6
Loading
Loading
Loading
Loading
+33 −85
Original line number Diff line number Diff line
@@ -20,79 +20,30 @@
#include "dpll.h"
#include "regs.h"

/* Chip IDs for zl30731 */
static const u16 zl30731_ids[] = {
	0x0E93,
	0x1E93,
	0x2E93,
#define ZL_CHIP_INFO(_id, _nchannels, _flags)				\
	{ .id = (_id), .num_channels = (_nchannels), .flags = (_flags) }

static const struct zl3073x_chip_info zl3073x_chip_ids[] = {
	ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x1E93, 1, 0),
	ZL_CHIP_INFO(0x1E94, 2, 0),
	ZL_CHIP_INFO(0x1E95, 3, 0),
	ZL_CHIP_INFO(0x1E96, 4, 0),
	ZL_CHIP_INFO(0x1E97, 5, 0),
	ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
	ZL_CHIP_INFO(0x2E93, 1, 0),
	ZL_CHIP_INFO(0x2E94, 2, 0),
	ZL_CHIP_INFO(0x2E95, 3, 0),
	ZL_CHIP_INFO(0x2E96, 4, 0),
	ZL_CHIP_INFO(0x2E97, 5, 0),
	ZL_CHIP_INFO(0x3FC4, 2, 0),
};

const struct zl3073x_chip_info zl30731_chip_info = {
	.ids = zl30731_ids,
	.num_ids = ARRAY_SIZE(zl30731_ids),
	.num_channels = 1,
};
EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, "ZL3073X");

/* Chip IDs for zl30732 */
static const u16 zl30732_ids[] = {
	0x0E30,
	0x0E94,
	0x1E94,
	0x1F60,
	0x2E94,
	0x3FC4,
};

const struct zl3073x_chip_info zl30732_chip_info = {
	.ids = zl30732_ids,
	.num_ids = ARRAY_SIZE(zl30732_ids),
	.num_channels = 2,
};
EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, "ZL3073X");

/* Chip IDs for zl30733 */
static const u16 zl30733_ids[] = {
	0x0E95,
	0x1E95,
	0x2E95,
};

const struct zl3073x_chip_info zl30733_chip_info = {
	.ids = zl30733_ids,
	.num_ids = ARRAY_SIZE(zl30733_ids),
	.num_channels = 3,
};
EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, "ZL3073X");

/* Chip IDs for zl30734 */
static const u16 zl30734_ids[] = {
	0x0E96,
	0x1E96,
	0x2E96,
};

const struct zl3073x_chip_info zl30734_chip_info = {
	.ids = zl30734_ids,
	.num_ids = ARRAY_SIZE(zl30734_ids),
	.num_channels = 4,
};
EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, "ZL3073X");

/* Chip IDs for zl30735 */
static const u16 zl30735_ids[] = {
	0x0E97,
	0x1E97,
	0x2E97,
};

const struct zl3073x_chip_info zl30735_chip_info = {
	.ids = zl30735_ids,
	.num_ids = ARRAY_SIZE(zl30735_ids),
	.num_channels = 5,
};
EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X");

#define ZL_RANGE_OFFSET		0x80
#define ZL_PAGE_SIZE		0x80
#define ZL_NUM_PAGES		256
@@ -942,7 +893,7 @@ static void zl3073x_dev_dpll_fini(void *ptr)
}

static int
zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
zl3073x_devm_dpll_init(struct zl3073x_dev *zldev)
{
	struct kthread_worker *kworker;
	struct zl3073x_dpll *zldpll;
@@ -952,7 +903,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
	INIT_LIST_HEAD(&zldev->dplls);

	/* Allocate all DPLLs */
	for (i = 0; i < num_dplls; i++) {
	for (i = 0; i < zldev->info->num_channels; i++) {
		zldpll = zl3073x_dpll_alloc(zldev, i);
		if (IS_ERR(zldpll)) {
			dev_err_probe(zldev->dev, PTR_ERR(zldpll),
@@ -992,14 +943,12 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
/**
 * zl3073x_dev_probe - initialize zl3073x device
 * @zldev: pointer to zl3073x device
 * @chip_info: chip info based on compatible
 *
 * Common initialization of zl3073x device structure.
 *
 * Returns: 0 on success, <0 on error
 */
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
		      const struct zl3073x_chip_info *chip_info)
int zl3073x_dev_probe(struct zl3073x_dev *zldev)
{
	u16 id, revision, fw_ver;
	unsigned int i;
@@ -1011,18 +960,17 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
	if (rc)
		return rc;

	/* Check it matches */
	for (i = 0; i < chip_info->num_ids; i++) {
		if (id == chip_info->ids[i])
	/* Detect chip variant */
	for (i = 0; i < ARRAY_SIZE(zl3073x_chip_ids); i++) {
		if (zl3073x_chip_ids[i].id == id)
			break;
	}

	if (i == chip_info->num_ids) {
	if (i == ARRAY_SIZE(zl3073x_chip_ids))
		return dev_err_probe(zldev->dev, -ENODEV,
				     "Unknown or non-match chip ID: 0x%0x\n",
				     id);
	}
	zldev->chip_id = id;
				     "Unknown chip ID: 0x%04x\n", id);

	zldev->info = &zl3073x_chip_ids[i];

	/* Read revision, firmware version and custom config version */
	rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
@@ -1061,7 +1009,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
				     "Failed to initialize mutex\n");

	/* Register DPLL channels */
	rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels);
	rc = zl3073x_devm_dpll_init(zldev);
	if (rc)
		return rc;

+27 −30
Original line number Diff line number Diff line
@@ -30,12 +30,32 @@ struct zl3073x_dpll;
#define ZL3073X_NUM_PINS	(ZL3073X_NUM_INPUT_PINS + \
				 ZL3073X_NUM_OUTPUT_PINS)

enum zl3073x_flags {
	ZL3073X_FLAG_REF_PHASE_COMP_32_BIT,
	ZL3073X_FLAGS_NBITS /* must be last */
};

#define __ZL3073X_FLAG(name)	BIT(ZL3073X_FLAG_ ## name ## _BIT)
#define ZL3073X_FLAG_REF_PHASE_COMP_32	__ZL3073X_FLAG(REF_PHASE_COMP_32)

/**
 * struct zl3073x_chip_info - chip variant identification
 * @id: chip ID
 * @num_channels: number of DPLL channels supported by this variant
 * @flags: chip variant flags
 */
struct zl3073x_chip_info {
	u16		id;
	u8		num_channels;
	unsigned long	flags;
};

/**
 * struct zl3073x_dev - zl3073x device
 * @dev: pointer to device
 * @regmap: regmap to access device registers
 * @info: detected chip info
 * @multiop_lock: to serialize multiple register operations
 * @chip_id: chip ID read from hardware
 * @ref: array of input references' invariants
 * @out: array of outs' invariants
 * @synth: array of synths' invariants
@@ -48,8 +68,8 @@ struct zl3073x_dpll;
struct zl3073x_dev {
	struct device			*dev;
	struct regmap			*regmap;
	const struct zl3073x_chip_info	*info;
	struct mutex			multiop_lock;
	u16			chip_id;

	/* Invariants */
	struct zl3073x_ref	ref[ZL3073X_NUM_REFS];
@@ -68,22 +88,10 @@ struct zl3073x_dev {
	u8			phase_avg_factor;
};

struct zl3073x_chip_info {
	const u16	*ids;
	size_t		num_ids;
	int		num_channels;
};

extern const struct zl3073x_chip_info zl30731_chip_info;
extern const struct zl3073x_chip_info zl30732_chip_info;
extern const struct zl3073x_chip_info zl30733_chip_info;
extern const struct zl3073x_chip_info zl30734_chip_info;
extern const struct zl3073x_chip_info zl30735_chip_info;
extern const struct regmap_config zl3073x_regmap_config;

struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
		      const struct zl3073x_chip_info *chip_info);
int zl3073x_dev_probe(struct zl3073x_dev *zldev);

int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full);
void zl3073x_dev_stop(struct zl3073x_dev *zldev);
@@ -158,18 +166,7 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
static inline bool
zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev)
{
	switch (zldev->chip_id) {
	case 0x0E30:
	case 0x0E93:
	case 0x0E94:
	case 0x0E95:
	case 0x0E96:
	case 0x0E97:
	case 0x1F60:
		return true;
	default:
		return false;
	}
	return zldev->info->flags & ZL3073X_FLAG_REF_PHASE_COMP_32;
}

static inline bool
+11 −26
Original line number Diff line number Diff line
@@ -22,40 +22,25 @@ static int zl3073x_i2c_probe(struct i2c_client *client)
		return dev_err_probe(dev, PTR_ERR(zldev->regmap),
				     "Failed to initialize regmap\n");

	return zl3073x_dev_probe(zldev, i2c_get_match_data(client));
	return zl3073x_dev_probe(zldev);
}

static const struct i2c_device_id zl3073x_i2c_id[] = {
	{
		.name = "zl30731",
		.driver_data = (kernel_ulong_t)&zl30731_chip_info,
	},
	{
		.name = "zl30732",
		.driver_data = (kernel_ulong_t)&zl30732_chip_info,
	},
	{
		.name = "zl30733",
		.driver_data = (kernel_ulong_t)&zl30733_chip_info,
	},
	{
		.name = "zl30734",
		.driver_data = (kernel_ulong_t)&zl30734_chip_info,
	},
	{
		.name = "zl30735",
		.driver_data = (kernel_ulong_t)&zl30735_chip_info,
	},
	{ "zl30731" },
	{ "zl30732" },
	{ "zl30733" },
	{ "zl30734" },
	{ "zl30735" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id);

static const struct of_device_id zl3073x_i2c_of_match[] = {
	{ .compatible = "microchip,zl30731", .data = &zl30731_chip_info },
	{ .compatible = "microchip,zl30732", .data = &zl30732_chip_info },
	{ .compatible = "microchip,zl30733", .data = &zl30733_chip_info },
	{ .compatible = "microchip,zl30734", .data = &zl30734_chip_info },
	{ .compatible = "microchip,zl30735", .data = &zl30735_chip_info },
	{ .compatible = "microchip,zl30731" },
	{ .compatible = "microchip,zl30732" },
	{ .compatible = "microchip,zl30733" },
	{ .compatible = "microchip,zl30734" },
	{ .compatible = "microchip,zl30735" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match);
+11 −26
Original line number Diff line number Diff line
@@ -22,40 +22,25 @@ static int zl3073x_spi_probe(struct spi_device *spi)
		return dev_err_probe(dev, PTR_ERR(zldev->regmap),
				     "Failed to initialize regmap\n");

	return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi));
	return zl3073x_dev_probe(zldev);
}

static const struct spi_device_id zl3073x_spi_id[] = {
	{
		.name = "zl30731",
		.driver_data = (kernel_ulong_t)&zl30731_chip_info
	},
	{
		.name = "zl30732",
		.driver_data = (kernel_ulong_t)&zl30732_chip_info,
	},
	{
		.name = "zl30733",
		.driver_data = (kernel_ulong_t)&zl30733_chip_info,
	},
	{
		.name = "zl30734",
		.driver_data = (kernel_ulong_t)&zl30734_chip_info,
	},
	{
		.name = "zl30735",
		.driver_data = (kernel_ulong_t)&zl30735_chip_info,
	},
	{ "zl30731" },
	{ "zl30732" },
	{ "zl30733" },
	{ "zl30734" },
	{ "zl30735" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, zl3073x_spi_id);

static const struct of_device_id zl3073x_spi_of_match[] = {
	{ .compatible = "microchip,zl30731", .data = &zl30731_chip_info },
	{ .compatible = "microchip,zl30732", .data = &zl30732_chip_info },
	{ .compatible = "microchip,zl30733", .data = &zl30733_chip_info },
	{ .compatible = "microchip,zl30734", .data = &zl30734_chip_info },
	{ .compatible = "microchip,zl30735", .data = &zl30735_chip_info },
	{ .compatible = "microchip,zl30731" },
	{ .compatible = "microchip,zl30732" },
	{ .compatible = "microchip,zl30733" },
	{ .compatible = "microchip,zl30734" },
	{ .compatible = "microchip,zl30735" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match);