xref: /linux/drivers/dpll/zl3073x/core.c (revision a99a9f0ebdaaae14fe1d69d046633bce6110d0c2)
12df8e64eSIvan Vecera // SPDX-License-Identifier: GPL-2.0-only
22df8e64eSIvan Vecera 
32df8e64eSIvan Vecera #include <linux/array_size.h>
42df8e64eSIvan Vecera #include <linux/bitfield.h>
52df8e64eSIvan Vecera #include <linux/bits.h>
62df8e64eSIvan Vecera #include <linux/dev_printk.h>
72df8e64eSIvan Vecera #include <linux/device.h>
82df8e64eSIvan Vecera #include <linux/export.h>
9b7d907d1SIvan Vecera #include <linux/math64.h>
102df8e64eSIvan Vecera #include <linux/module.h>
112df8e64eSIvan Vecera #include <linux/netlink.h>
122df8e64eSIvan Vecera #include <linux/regmap.h>
132df8e64eSIvan Vecera #include <linux/sprintf.h>
14b7d907d1SIvan Vecera #include <linux/string_choices.h>
152df8e64eSIvan Vecera #include <linux/unaligned.h>
162df8e64eSIvan Vecera #include <net/devlink.h>
172df8e64eSIvan Vecera 
182df8e64eSIvan Vecera #include "core.h"
192df8e64eSIvan Vecera #include "devlink.h"
202df8e64eSIvan Vecera #include "regs.h"
212df8e64eSIvan Vecera 
222df8e64eSIvan Vecera /* Chip IDs for zl30731 */
232df8e64eSIvan Vecera static const u16 zl30731_ids[] = {
242df8e64eSIvan Vecera 	0x0E93,
252df8e64eSIvan Vecera 	0x1E93,
262df8e64eSIvan Vecera 	0x2E93,
272df8e64eSIvan Vecera };
282df8e64eSIvan Vecera 
292df8e64eSIvan Vecera const struct zl3073x_chip_info zl30731_chip_info = {
302df8e64eSIvan Vecera 	.ids = zl30731_ids,
312df8e64eSIvan Vecera 	.num_ids = ARRAY_SIZE(zl30731_ids),
322df8e64eSIvan Vecera 	.num_channels = 1,
332df8e64eSIvan Vecera };
342df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, "ZL3073X");
352df8e64eSIvan Vecera 
362df8e64eSIvan Vecera /* Chip IDs for zl30732 */
372df8e64eSIvan Vecera static const u16 zl30732_ids[] = {
382df8e64eSIvan Vecera 	0x0E30,
392df8e64eSIvan Vecera 	0x0E94,
402df8e64eSIvan Vecera 	0x1E94,
412df8e64eSIvan Vecera 	0x1F60,
422df8e64eSIvan Vecera 	0x2E94,
432df8e64eSIvan Vecera 	0x3FC4,
442df8e64eSIvan Vecera };
452df8e64eSIvan Vecera 
462df8e64eSIvan Vecera const struct zl3073x_chip_info zl30732_chip_info = {
472df8e64eSIvan Vecera 	.ids = zl30732_ids,
482df8e64eSIvan Vecera 	.num_ids = ARRAY_SIZE(zl30732_ids),
492df8e64eSIvan Vecera 	.num_channels = 2,
502df8e64eSIvan Vecera };
512df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, "ZL3073X");
522df8e64eSIvan Vecera 
532df8e64eSIvan Vecera /* Chip IDs for zl30733 */
542df8e64eSIvan Vecera static const u16 zl30733_ids[] = {
552df8e64eSIvan Vecera 	0x0E95,
562df8e64eSIvan Vecera 	0x1E95,
572df8e64eSIvan Vecera 	0x2E95,
582df8e64eSIvan Vecera };
592df8e64eSIvan Vecera 
602df8e64eSIvan Vecera const struct zl3073x_chip_info zl30733_chip_info = {
612df8e64eSIvan Vecera 	.ids = zl30733_ids,
622df8e64eSIvan Vecera 	.num_ids = ARRAY_SIZE(zl30733_ids),
632df8e64eSIvan Vecera 	.num_channels = 3,
642df8e64eSIvan Vecera };
652df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, "ZL3073X");
662df8e64eSIvan Vecera 
672df8e64eSIvan Vecera /* Chip IDs for zl30734 */
682df8e64eSIvan Vecera static const u16 zl30734_ids[] = {
692df8e64eSIvan Vecera 	0x0E96,
702df8e64eSIvan Vecera 	0x1E96,
712df8e64eSIvan Vecera 	0x2E96,
722df8e64eSIvan Vecera };
732df8e64eSIvan Vecera 
742df8e64eSIvan Vecera const struct zl3073x_chip_info zl30734_chip_info = {
752df8e64eSIvan Vecera 	.ids = zl30734_ids,
762df8e64eSIvan Vecera 	.num_ids = ARRAY_SIZE(zl30734_ids),
772df8e64eSIvan Vecera 	.num_channels = 4,
782df8e64eSIvan Vecera };
792df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, "ZL3073X");
802df8e64eSIvan Vecera 
812df8e64eSIvan Vecera /* Chip IDs for zl30735 */
822df8e64eSIvan Vecera static const u16 zl30735_ids[] = {
832df8e64eSIvan Vecera 	0x0E97,
842df8e64eSIvan Vecera 	0x1E97,
852df8e64eSIvan Vecera 	0x2E97,
862df8e64eSIvan Vecera };
872df8e64eSIvan Vecera 
882df8e64eSIvan Vecera const struct zl3073x_chip_info zl30735_chip_info = {
892df8e64eSIvan Vecera 	.ids = zl30735_ids,
902df8e64eSIvan Vecera 	.num_ids = ARRAY_SIZE(zl30735_ids),
912df8e64eSIvan Vecera 	.num_channels = 5,
922df8e64eSIvan Vecera };
932df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X");
942df8e64eSIvan Vecera 
952df8e64eSIvan Vecera #define ZL_RANGE_OFFSET		0x80
962df8e64eSIvan Vecera #define ZL_PAGE_SIZE		0x80
972df8e64eSIvan Vecera #define ZL_NUM_PAGES		15
982df8e64eSIvan Vecera #define ZL_PAGE_SEL		0x7F
992df8e64eSIvan Vecera #define ZL_PAGE_SEL_MASK	GENMASK(3, 0)
1002df8e64eSIvan Vecera #define ZL_NUM_REGS		(ZL_NUM_PAGES * ZL_PAGE_SIZE)
1012df8e64eSIvan Vecera 
1022df8e64eSIvan Vecera /* Regmap range configuration */
1032df8e64eSIvan Vecera static const struct regmap_range_cfg zl3073x_regmap_range = {
1042df8e64eSIvan Vecera 	.range_min	= ZL_RANGE_OFFSET,
1052df8e64eSIvan Vecera 	.range_max	= ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
1062df8e64eSIvan Vecera 	.selector_reg	= ZL_PAGE_SEL,
1072df8e64eSIvan Vecera 	.selector_mask	= ZL_PAGE_SEL_MASK,
1082df8e64eSIvan Vecera 	.selector_shift	= 0,
1092df8e64eSIvan Vecera 	.window_start	= 0,
1102df8e64eSIvan Vecera 	.window_len	= ZL_PAGE_SIZE,
1112df8e64eSIvan Vecera };
1122df8e64eSIvan Vecera 
1132df8e64eSIvan Vecera static bool
1142df8e64eSIvan Vecera zl3073x_is_volatile_reg(struct device *dev __maybe_unused, unsigned int reg)
1152df8e64eSIvan Vecera {
1162df8e64eSIvan Vecera 	/* Only page selector is non-volatile */
1172df8e64eSIvan Vecera 	return reg != ZL_PAGE_SEL;
1182df8e64eSIvan Vecera }
1192df8e64eSIvan Vecera 
1202df8e64eSIvan Vecera const struct regmap_config zl3073x_regmap_config = {
1212df8e64eSIvan Vecera 	.reg_bits	= 8,
1222df8e64eSIvan Vecera 	.val_bits	= 8,
1232df8e64eSIvan Vecera 	.max_register	= ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
1242df8e64eSIvan Vecera 	.ranges		= &zl3073x_regmap_range,
1252df8e64eSIvan Vecera 	.num_ranges	= 1,
1262df8e64eSIvan Vecera 	.cache_type	= REGCACHE_MAPLE,
1272df8e64eSIvan Vecera 	.volatile_reg	= zl3073x_is_volatile_reg,
1282df8e64eSIvan Vecera };
1292df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl3073x_regmap_config, "ZL3073X");
1302df8e64eSIvan Vecera 
131*a99a9f0eSIvan Vecera /**
132*a99a9f0eSIvan Vecera  * zl3073x_ref_freq_factorize - factorize given frequency
133*a99a9f0eSIvan Vecera  * @freq: input frequency
134*a99a9f0eSIvan Vecera  * @base: base frequency
135*a99a9f0eSIvan Vecera  * @mult: multiplier
136*a99a9f0eSIvan Vecera  *
137*a99a9f0eSIvan Vecera  * Checks if the given frequency can be factorized using one of the
138*a99a9f0eSIvan Vecera  * supported base frequencies. If so the base frequency and multiplier
139*a99a9f0eSIvan Vecera  * are stored into appropriate parameters if they are not NULL.
140*a99a9f0eSIvan Vecera  *
141*a99a9f0eSIvan Vecera  * Return: 0 on success, -EINVAL if the frequency cannot be factorized
142*a99a9f0eSIvan Vecera  */
143*a99a9f0eSIvan Vecera int
144*a99a9f0eSIvan Vecera zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
145*a99a9f0eSIvan Vecera {
146*a99a9f0eSIvan Vecera 	static const u16 base_freqs[] = {
147*a99a9f0eSIvan Vecera 		1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
148*a99a9f0eSIvan Vecera 		128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
149*a99a9f0eSIvan Vecera 		1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
150*a99a9f0eSIvan Vecera 		6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
151*a99a9f0eSIvan Vecera 		32000, 40000, 50000, 62500,
152*a99a9f0eSIvan Vecera 	};
153*a99a9f0eSIvan Vecera 	u32 div;
154*a99a9f0eSIvan Vecera 	int i;
155*a99a9f0eSIvan Vecera 
156*a99a9f0eSIvan Vecera 	for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
157*a99a9f0eSIvan Vecera 		div = freq / base_freqs[i];
158*a99a9f0eSIvan Vecera 
159*a99a9f0eSIvan Vecera 		if (div <= U16_MAX && (freq % base_freqs[i]) == 0) {
160*a99a9f0eSIvan Vecera 			if (base)
161*a99a9f0eSIvan Vecera 				*base = base_freqs[i];
162*a99a9f0eSIvan Vecera 			if (mult)
163*a99a9f0eSIvan Vecera 				*mult = div;
164*a99a9f0eSIvan Vecera 
165*a99a9f0eSIvan Vecera 			return 0;
166*a99a9f0eSIvan Vecera 		}
167*a99a9f0eSIvan Vecera 	}
168*a99a9f0eSIvan Vecera 
169*a99a9f0eSIvan Vecera 	return -EINVAL;
170*a99a9f0eSIvan Vecera }
171*a99a9f0eSIvan Vecera 
1722df8e64eSIvan Vecera static bool
1732df8e64eSIvan Vecera zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size)
1742df8e64eSIvan Vecera {
1752df8e64eSIvan Vecera 	/* Check that multiop lock is held when accessing registers
1762df8e64eSIvan Vecera 	 * from page 10 and above.
1772df8e64eSIvan Vecera 	 */
1782df8e64eSIvan Vecera 	if (ZL_REG_PAGE(reg) >= 10)
1792df8e64eSIvan Vecera 		lockdep_assert_held(&zldev->multiop_lock);
1802df8e64eSIvan Vecera 
1812df8e64eSIvan Vecera 	/* Check the index is in valid range for indexed register */
1822df8e64eSIvan Vecera 	if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
1832df8e64eSIvan Vecera 		dev_err(zldev->dev, "Index out of range for reg 0x%04lx\n",
1842df8e64eSIvan Vecera 			ZL_REG_ADDR(reg));
1852df8e64eSIvan Vecera 		return false;
1862df8e64eSIvan Vecera 	}
1872df8e64eSIvan Vecera 	/* Check the requested size corresponds to register size */
1882df8e64eSIvan Vecera 	if (ZL_REG_SIZE(reg) != size) {
1892df8e64eSIvan Vecera 		dev_err(zldev->dev, "Invalid size %zu for reg 0x%04lx\n",
1902df8e64eSIvan Vecera 			size, ZL_REG_ADDR(reg));
1912df8e64eSIvan Vecera 		return false;
1922df8e64eSIvan Vecera 	}
1932df8e64eSIvan Vecera 
1942df8e64eSIvan Vecera 	return true;
1952df8e64eSIvan Vecera }
1962df8e64eSIvan Vecera 
1972df8e64eSIvan Vecera static int
1982df8e64eSIvan Vecera zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val,
1992df8e64eSIvan Vecera 		 size_t size)
2002df8e64eSIvan Vecera {
2012df8e64eSIvan Vecera 	int rc;
2022df8e64eSIvan Vecera 
2032df8e64eSIvan Vecera 	if (!zl3073x_check_reg(zldev, reg, size))
2042df8e64eSIvan Vecera 		return -EINVAL;
2052df8e64eSIvan Vecera 
2062df8e64eSIvan Vecera 	/* Map the register address to virtual range */
2072df8e64eSIvan Vecera 	reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
2082df8e64eSIvan Vecera 
2092df8e64eSIvan Vecera 	rc = regmap_bulk_read(zldev->regmap, reg, val, size);
2102df8e64eSIvan Vecera 	if (rc) {
2112df8e64eSIvan Vecera 		dev_err(zldev->dev, "Failed to read reg 0x%04x: %pe\n", reg,
2122df8e64eSIvan Vecera 			ERR_PTR(rc));
2132df8e64eSIvan Vecera 		return rc;
2142df8e64eSIvan Vecera 	}
2152df8e64eSIvan Vecera 
2162df8e64eSIvan Vecera 	return 0;
2172df8e64eSIvan Vecera }
2182df8e64eSIvan Vecera 
2192df8e64eSIvan Vecera static int
2202df8e64eSIvan Vecera zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, const void *val,
2212df8e64eSIvan Vecera 		  size_t size)
2222df8e64eSIvan Vecera {
2232df8e64eSIvan Vecera 	int rc;
2242df8e64eSIvan Vecera 
2252df8e64eSIvan Vecera 	if (!zl3073x_check_reg(zldev, reg, size))
2262df8e64eSIvan Vecera 		return -EINVAL;
2272df8e64eSIvan Vecera 
2282df8e64eSIvan Vecera 	/* Map the register address to virtual range */
2292df8e64eSIvan Vecera 	reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
2302df8e64eSIvan Vecera 
2312df8e64eSIvan Vecera 	rc = regmap_bulk_write(zldev->regmap, reg, val, size);
2322df8e64eSIvan Vecera 	if (rc) {
2332df8e64eSIvan Vecera 		dev_err(zldev->dev, "Failed to write reg 0x%04x: %pe\n", reg,
2342df8e64eSIvan Vecera 			ERR_PTR(rc));
2352df8e64eSIvan Vecera 		return rc;
2362df8e64eSIvan Vecera 	}
2372df8e64eSIvan Vecera 
2382df8e64eSIvan Vecera 	return 0;
2392df8e64eSIvan Vecera }
2402df8e64eSIvan Vecera 
2412df8e64eSIvan Vecera /**
2422df8e64eSIvan Vecera  * zl3073x_read_u8 - read value from 8bit register
2432df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
2442df8e64eSIvan Vecera  * @reg: register to write to
2452df8e64eSIvan Vecera  * @val: value to write
2462df8e64eSIvan Vecera  *
2472df8e64eSIvan Vecera  * Reads value from given 8bit register.
2482df8e64eSIvan Vecera  *
2492df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
2502df8e64eSIvan Vecera  */
2512df8e64eSIvan Vecera int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val)
2522df8e64eSIvan Vecera {
2532df8e64eSIvan Vecera 	return zl3073x_read_reg(zldev, reg, val, sizeof(*val));
2542df8e64eSIvan Vecera }
2552df8e64eSIvan Vecera 
2562df8e64eSIvan Vecera /**
2572df8e64eSIvan Vecera  * zl3073x_write_u8 - write value to 16bit register
2582df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
2592df8e64eSIvan Vecera  * @reg: register to write to
2602df8e64eSIvan Vecera  * @val: value to write
2612df8e64eSIvan Vecera  *
2622df8e64eSIvan Vecera  * Writes value into given 8bit register.
2632df8e64eSIvan Vecera  *
2642df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
2652df8e64eSIvan Vecera  */
2662df8e64eSIvan Vecera int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val)
2672df8e64eSIvan Vecera {
2682df8e64eSIvan Vecera 	return zl3073x_write_reg(zldev, reg, &val, sizeof(val));
2692df8e64eSIvan Vecera }
2702df8e64eSIvan Vecera 
2712df8e64eSIvan Vecera /**
2722df8e64eSIvan Vecera  * zl3073x_read_u16 - read value from 16bit register
2732df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
2742df8e64eSIvan Vecera  * @reg: register to write to
2752df8e64eSIvan Vecera  * @val: value to write
2762df8e64eSIvan Vecera  *
2772df8e64eSIvan Vecera  * Reads value from given 16bit register.
2782df8e64eSIvan Vecera  *
2792df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
2802df8e64eSIvan Vecera  */
2812df8e64eSIvan Vecera int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val)
2822df8e64eSIvan Vecera {
2832df8e64eSIvan Vecera 	int rc;
2842df8e64eSIvan Vecera 
2852df8e64eSIvan Vecera 	rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val));
2862df8e64eSIvan Vecera 	if (!rc)
2872df8e64eSIvan Vecera 		be16_to_cpus(val);
2882df8e64eSIvan Vecera 
2892df8e64eSIvan Vecera 	return rc;
2902df8e64eSIvan Vecera }
2912df8e64eSIvan Vecera 
2922df8e64eSIvan Vecera /**
2932df8e64eSIvan Vecera  * zl3073x_write_u16 - write value to 16bit register
2942df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
2952df8e64eSIvan Vecera  * @reg: register to write to
2962df8e64eSIvan Vecera  * @val: value to write
2972df8e64eSIvan Vecera  *
2982df8e64eSIvan Vecera  * Writes value into given 16bit register.
2992df8e64eSIvan Vecera  *
3002df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
3012df8e64eSIvan Vecera  */
3022df8e64eSIvan Vecera int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val)
3032df8e64eSIvan Vecera {
3042df8e64eSIvan Vecera 	cpu_to_be16s(&val);
3052df8e64eSIvan Vecera 
3062df8e64eSIvan Vecera 	return zl3073x_write_reg(zldev, reg, &val, sizeof(val));
3072df8e64eSIvan Vecera }
3082df8e64eSIvan Vecera 
3092df8e64eSIvan Vecera /**
3102df8e64eSIvan Vecera  * zl3073x_read_u32 - read value from 32bit register
3112df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
3122df8e64eSIvan Vecera  * @reg: register to write to
3132df8e64eSIvan Vecera  * @val: value to write
3142df8e64eSIvan Vecera  *
3152df8e64eSIvan Vecera  * Reads value from given 32bit register.
3162df8e64eSIvan Vecera  *
3172df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
3182df8e64eSIvan Vecera  */
3192df8e64eSIvan Vecera int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val)
3202df8e64eSIvan Vecera {
3212df8e64eSIvan Vecera 	int rc;
3222df8e64eSIvan Vecera 
3232df8e64eSIvan Vecera 	rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val));
3242df8e64eSIvan Vecera 	if (!rc)
3252df8e64eSIvan Vecera 		be32_to_cpus(val);
3262df8e64eSIvan Vecera 
3272df8e64eSIvan Vecera 	return rc;
3282df8e64eSIvan Vecera }
3292df8e64eSIvan Vecera 
3302df8e64eSIvan Vecera /**
3312df8e64eSIvan Vecera  * zl3073x_write_u32 - write value to 32bit register
3322df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
3332df8e64eSIvan Vecera  * @reg: register to write to
3342df8e64eSIvan Vecera  * @val: value to write
3352df8e64eSIvan Vecera  *
3362df8e64eSIvan Vecera  * Writes value into given 32bit register.
3372df8e64eSIvan Vecera  *
3382df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
3392df8e64eSIvan Vecera  */
3402df8e64eSIvan Vecera int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val)
3412df8e64eSIvan Vecera {
3422df8e64eSIvan Vecera 	cpu_to_be32s(&val);
3432df8e64eSIvan Vecera 
3442df8e64eSIvan Vecera 	return zl3073x_write_reg(zldev, reg, &val, sizeof(val));
3452df8e64eSIvan Vecera }
3462df8e64eSIvan Vecera 
3472df8e64eSIvan Vecera /**
3482df8e64eSIvan Vecera  * zl3073x_read_u48 - read value from 48bit register
3492df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
3502df8e64eSIvan Vecera  * @reg: register to write to
3512df8e64eSIvan Vecera  * @val: value to write
3522df8e64eSIvan Vecera  *
3532df8e64eSIvan Vecera  * Reads value from given 48bit register.
3542df8e64eSIvan Vecera  *
3552df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
3562df8e64eSIvan Vecera  */
3572df8e64eSIvan Vecera int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val)
3582df8e64eSIvan Vecera {
3592df8e64eSIvan Vecera 	u8 buf[6];
3602df8e64eSIvan Vecera 	int rc;
3612df8e64eSIvan Vecera 
3622df8e64eSIvan Vecera 	rc = zl3073x_read_reg(zldev, reg, buf, sizeof(buf));
3632df8e64eSIvan Vecera 	if (!rc)
3642df8e64eSIvan Vecera 		*val = get_unaligned_be48(buf);
3652df8e64eSIvan Vecera 
3662df8e64eSIvan Vecera 	return rc;
3672df8e64eSIvan Vecera }
3682df8e64eSIvan Vecera 
3692df8e64eSIvan Vecera /**
3702df8e64eSIvan Vecera  * zl3073x_write_u48 - write value to 48bit register
3712df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
3722df8e64eSIvan Vecera  * @reg: register to write to
3732df8e64eSIvan Vecera  * @val: value to write
3742df8e64eSIvan Vecera  *
3752df8e64eSIvan Vecera  * Writes value into given 48bit register.
3762df8e64eSIvan Vecera  * The value must be from the interval -S48_MIN to U48_MAX.
3772df8e64eSIvan Vecera  *
3782df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
3792df8e64eSIvan Vecera  */
3802df8e64eSIvan Vecera int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val)
3812df8e64eSIvan Vecera {
3822df8e64eSIvan Vecera 	u8 buf[6];
3832df8e64eSIvan Vecera 
3842df8e64eSIvan Vecera 	/* Check the value belongs to <S48_MIN, U48_MAX>
3852df8e64eSIvan Vecera 	 * Any value >= S48_MIN has bits 47..63 set.
3862df8e64eSIvan Vecera 	 */
3872df8e64eSIvan Vecera 	if (val > GENMASK_ULL(47, 0) && val < GENMASK_ULL(63, 47)) {
3882df8e64eSIvan Vecera 		dev_err(zldev->dev, "Value 0x%0llx out of range\n", val);
3892df8e64eSIvan Vecera 		return -EINVAL;
3902df8e64eSIvan Vecera 	}
3912df8e64eSIvan Vecera 
3922df8e64eSIvan Vecera 	put_unaligned_be48(val, buf);
3932df8e64eSIvan Vecera 
3942df8e64eSIvan Vecera 	return zl3073x_write_reg(zldev, reg, buf, sizeof(buf));
3952df8e64eSIvan Vecera }
3962df8e64eSIvan Vecera 
3972df8e64eSIvan Vecera /**
3982df8e64eSIvan Vecera  * zl3073x_poll_zero_u8 - wait for register to be cleared by device
3992df8e64eSIvan Vecera  * @zldev: zl3073x device pointer
4002df8e64eSIvan Vecera  * @reg: register to poll (has to be 8bit register)
4012df8e64eSIvan Vecera  * @mask: bit mask for polling
4022df8e64eSIvan Vecera  *
4032df8e64eSIvan Vecera  * Waits for bits specified by @mask in register @reg value to be cleared
4042df8e64eSIvan Vecera  * by the device.
4052df8e64eSIvan Vecera  *
4062df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
4072df8e64eSIvan Vecera  */
4082df8e64eSIvan Vecera int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask)
4092df8e64eSIvan Vecera {
4102df8e64eSIvan Vecera 	/* Register polling sleep & timeout */
4112df8e64eSIvan Vecera #define ZL_POLL_SLEEP_US   10
4122df8e64eSIvan Vecera #define ZL_POLL_TIMEOUT_US 2000000
4132df8e64eSIvan Vecera 	unsigned int val;
4142df8e64eSIvan Vecera 
4152df8e64eSIvan Vecera 	/* Check the register is 8bit */
4162df8e64eSIvan Vecera 	if (ZL_REG_SIZE(reg) != 1) {
4172df8e64eSIvan Vecera 		dev_err(zldev->dev, "Invalid reg 0x%04lx size for polling\n",
4182df8e64eSIvan Vecera 			ZL_REG_ADDR(reg));
4192df8e64eSIvan Vecera 		return -EINVAL;
4202df8e64eSIvan Vecera 	}
4212df8e64eSIvan Vecera 
4222df8e64eSIvan Vecera 	/* Map the register address to virtual range */
4232df8e64eSIvan Vecera 	reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
4242df8e64eSIvan Vecera 
4252df8e64eSIvan Vecera 	return regmap_read_poll_timeout(zldev->regmap, reg, val, !(val & mask),
4262df8e64eSIvan Vecera 					ZL_POLL_SLEEP_US, ZL_POLL_TIMEOUT_US);
4272df8e64eSIvan Vecera }
4282df8e64eSIvan Vecera 
429b7d907d1SIvan Vecera int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
430b7d907d1SIvan Vecera 		  unsigned int mask_reg, u16 mask_val)
431b7d907d1SIvan Vecera {
432b7d907d1SIvan Vecera 	int rc;
433b7d907d1SIvan Vecera 
434b7d907d1SIvan Vecera 	/* Set mask for the operation */
435b7d907d1SIvan Vecera 	rc = zl3073x_write_u16(zldev, mask_reg, mask_val);
436b7d907d1SIvan Vecera 	if (rc)
437b7d907d1SIvan Vecera 		return rc;
438b7d907d1SIvan Vecera 
439b7d907d1SIvan Vecera 	/* Trigger the operation */
440b7d907d1SIvan Vecera 	rc = zl3073x_write_u8(zldev, op_reg, op_val);
441b7d907d1SIvan Vecera 	if (rc)
442b7d907d1SIvan Vecera 		return rc;
443b7d907d1SIvan Vecera 
444b7d907d1SIvan Vecera 	/* Wait for the operation to actually finish */
445b7d907d1SIvan Vecera 	return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
446b7d907d1SIvan Vecera }
447b7d907d1SIvan Vecera 
448b7d907d1SIvan Vecera /**
449b7d907d1SIvan Vecera  * zl3073x_ref_state_fetch - get input reference state
450b7d907d1SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
451b7d907d1SIvan Vecera  * @index: input reference index to fetch state for
452b7d907d1SIvan Vecera  *
453b7d907d1SIvan Vecera  * Function fetches information for the given input reference that are
454b7d907d1SIvan Vecera  * invariant and stores them for later use.
455b7d907d1SIvan Vecera  *
456b7d907d1SIvan Vecera  * Return: 0 on success, <0 on error
457b7d907d1SIvan Vecera  */
458b7d907d1SIvan Vecera static int
459b7d907d1SIvan Vecera zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
460b7d907d1SIvan Vecera {
461b7d907d1SIvan Vecera 	struct zl3073x_ref *input = &zldev->ref[index];
462b7d907d1SIvan Vecera 	u8 ref_config;
463b7d907d1SIvan Vecera 	int rc;
464b7d907d1SIvan Vecera 
465b7d907d1SIvan Vecera 	/* If the input is differential then the configuration for N-pin
466b7d907d1SIvan Vecera 	 * reference is ignored and P-pin config is used for both.
467b7d907d1SIvan Vecera 	 */
468b7d907d1SIvan Vecera 	if (zl3073x_is_n_pin(index) &&
469b7d907d1SIvan Vecera 	    zl3073x_ref_is_diff(zldev, index - 1)) {
470b7d907d1SIvan Vecera 		input->enabled = zl3073x_ref_is_enabled(zldev, index - 1);
471b7d907d1SIvan Vecera 		input->diff = true;
472b7d907d1SIvan Vecera 
473b7d907d1SIvan Vecera 		return 0;
474b7d907d1SIvan Vecera 	}
475b7d907d1SIvan Vecera 
476b7d907d1SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
477b7d907d1SIvan Vecera 
478b7d907d1SIvan Vecera 	/* Read reference configuration */
479b7d907d1SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
480b7d907d1SIvan Vecera 			   ZL_REG_REF_MB_MASK, BIT(index));
481b7d907d1SIvan Vecera 	if (rc)
482b7d907d1SIvan Vecera 		return rc;
483b7d907d1SIvan Vecera 
484b7d907d1SIvan Vecera 	/* Read ref_config register */
485b7d907d1SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref_config);
486b7d907d1SIvan Vecera 	if (rc)
487b7d907d1SIvan Vecera 		return rc;
488b7d907d1SIvan Vecera 
489b7d907d1SIvan Vecera 	input->enabled = FIELD_GET(ZL_REF_CONFIG_ENABLE, ref_config);
490b7d907d1SIvan Vecera 	input->diff = FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref_config);
491b7d907d1SIvan Vecera 
492b7d907d1SIvan Vecera 	dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
493b7d907d1SIvan Vecera 		str_enabled_disabled(input->enabled),
494b7d907d1SIvan Vecera 		input->diff ? "differential" : "single-ended");
495b7d907d1SIvan Vecera 
496b7d907d1SIvan Vecera 	return rc;
497b7d907d1SIvan Vecera }
498b7d907d1SIvan Vecera 
499b7d907d1SIvan Vecera /**
500b7d907d1SIvan Vecera  * zl3073x_out_state_fetch - get output state
501b7d907d1SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
502b7d907d1SIvan Vecera  * @index: output index to fetch state for
503b7d907d1SIvan Vecera  *
504b7d907d1SIvan Vecera  * Function fetches information for the given output (not output pin)
505b7d907d1SIvan Vecera  * that are invariant and stores them for later use.
506b7d907d1SIvan Vecera  *
507b7d907d1SIvan Vecera  * Return: 0 on success, <0 on error
508b7d907d1SIvan Vecera  */
509b7d907d1SIvan Vecera static int
510b7d907d1SIvan Vecera zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
511b7d907d1SIvan Vecera {
512b7d907d1SIvan Vecera 	struct zl3073x_out *out = &zldev->out[index];
513b7d907d1SIvan Vecera 	u8 output_ctrl, output_mode;
514b7d907d1SIvan Vecera 	int rc;
515b7d907d1SIvan Vecera 
516b7d907d1SIvan Vecera 	/* Read output configuration */
517b7d907d1SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &output_ctrl);
518b7d907d1SIvan Vecera 	if (rc)
519b7d907d1SIvan Vecera 		return rc;
520b7d907d1SIvan Vecera 
521b7d907d1SIvan Vecera 	/* Store info about output enablement and synthesizer the output
522b7d907d1SIvan Vecera 	 * is connected to.
523b7d907d1SIvan Vecera 	 */
524b7d907d1SIvan Vecera 	out->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl);
525b7d907d1SIvan Vecera 	out->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl);
526b7d907d1SIvan Vecera 
527b7d907d1SIvan Vecera 	dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
528b7d907d1SIvan Vecera 		str_enabled_disabled(out->enabled), out->synth);
529b7d907d1SIvan Vecera 
530b7d907d1SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
531b7d907d1SIvan Vecera 
532b7d907d1SIvan Vecera 	/* Read output configuration */
533b7d907d1SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
534b7d907d1SIvan Vecera 			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
535b7d907d1SIvan Vecera 	if (rc)
536b7d907d1SIvan Vecera 		return rc;
537b7d907d1SIvan Vecera 
538b7d907d1SIvan Vecera 	/* Read output_mode */
539b7d907d1SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
540b7d907d1SIvan Vecera 	if (rc)
541b7d907d1SIvan Vecera 		return rc;
542b7d907d1SIvan Vecera 
543b7d907d1SIvan Vecera 	/* Extract and store output signal format */
544b7d907d1SIvan Vecera 	out->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT,
545b7d907d1SIvan Vecera 				       output_mode);
546b7d907d1SIvan Vecera 
547b7d907d1SIvan Vecera 	dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
548b7d907d1SIvan Vecera 		out->signal_format);
549b7d907d1SIvan Vecera 
550b7d907d1SIvan Vecera 	return rc;
551b7d907d1SIvan Vecera }
552b7d907d1SIvan Vecera 
553b7d907d1SIvan Vecera /**
554b7d907d1SIvan Vecera  * zl3073x_synth_state_fetch - get synth state
555b7d907d1SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
556b7d907d1SIvan Vecera  * @index: synth index to fetch state for
557b7d907d1SIvan Vecera  *
558b7d907d1SIvan Vecera  * Function fetches information for the given synthesizer that are
559b7d907d1SIvan Vecera  * invariant and stores them for later use.
560b7d907d1SIvan Vecera  *
561b7d907d1SIvan Vecera  * Return: 0 on success, <0 on error
562b7d907d1SIvan Vecera  */
563b7d907d1SIvan Vecera static int
564b7d907d1SIvan Vecera zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
565b7d907d1SIvan Vecera {
566b7d907d1SIvan Vecera 	struct zl3073x_synth *synth = &zldev->synth[index];
567b7d907d1SIvan Vecera 	u16 base, m, n;
568b7d907d1SIvan Vecera 	u8 synth_ctrl;
569b7d907d1SIvan Vecera 	u32 mult;
570b7d907d1SIvan Vecera 	int rc;
571b7d907d1SIvan Vecera 
572b7d907d1SIvan Vecera 	/* Read synth control register */
573b7d907d1SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl);
574b7d907d1SIvan Vecera 	if (rc)
575b7d907d1SIvan Vecera 		return rc;
576b7d907d1SIvan Vecera 
577b7d907d1SIvan Vecera 	/* Store info about synth enablement and DPLL channel the synth is
578b7d907d1SIvan Vecera 	 * driven by.
579b7d907d1SIvan Vecera 	 */
580b7d907d1SIvan Vecera 	synth->enabled = FIELD_GET(ZL_SYNTH_CTRL_EN, synth_ctrl);
581b7d907d1SIvan Vecera 	synth->dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth_ctrl);
582b7d907d1SIvan Vecera 
583b7d907d1SIvan Vecera 	dev_dbg(zldev->dev, "SYNTH%u is %s and driven by DPLL%u\n", index,
584b7d907d1SIvan Vecera 		str_enabled_disabled(synth->enabled), synth->dpll);
585b7d907d1SIvan Vecera 
586b7d907d1SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
587b7d907d1SIvan Vecera 
588b7d907d1SIvan Vecera 	/* Read synth configuration */
589b7d907d1SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD,
590b7d907d1SIvan Vecera 			   ZL_REG_SYNTH_MB_MASK, BIT(index));
591b7d907d1SIvan Vecera 	if (rc)
592b7d907d1SIvan Vecera 		return rc;
593b7d907d1SIvan Vecera 
594b7d907d1SIvan Vecera 	/* The output frequency is determined by the following formula:
595b7d907d1SIvan Vecera 	 * base * multiplier * numerator / denominator
596b7d907d1SIvan Vecera 	 *
597b7d907d1SIvan Vecera 	 * Read registers with these values
598b7d907d1SIvan Vecera 	 */
599b7d907d1SIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &base);
600b7d907d1SIvan Vecera 	if (rc)
601b7d907d1SIvan Vecera 		return rc;
602b7d907d1SIvan Vecera 
603b7d907d1SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &mult);
604b7d907d1SIvan Vecera 	if (rc)
605b7d907d1SIvan Vecera 		return rc;
606b7d907d1SIvan Vecera 
607b7d907d1SIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &m);
608b7d907d1SIvan Vecera 	if (rc)
609b7d907d1SIvan Vecera 		return rc;
610b7d907d1SIvan Vecera 
611b7d907d1SIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &n);
612b7d907d1SIvan Vecera 	if (rc)
613b7d907d1SIvan Vecera 		return rc;
614b7d907d1SIvan Vecera 
615b7d907d1SIvan Vecera 	/* Check denominator for zero to avoid div by 0 */
616b7d907d1SIvan Vecera 	if (!n) {
617b7d907d1SIvan Vecera 		dev_err(zldev->dev,
618b7d907d1SIvan Vecera 			"Zero divisor for SYNTH%u retrieved from device\n",
619b7d907d1SIvan Vecera 			index);
620b7d907d1SIvan Vecera 		return -EINVAL;
621b7d907d1SIvan Vecera 	}
622b7d907d1SIvan Vecera 
623b7d907d1SIvan Vecera 	/* Compute and store synth frequency */
624b7d907d1SIvan Vecera 	zldev->synth[index].freq = div_u64(mul_u32_u32(base * m, mult), n);
625b7d907d1SIvan Vecera 
626b7d907d1SIvan Vecera 	dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index,
627b7d907d1SIvan Vecera 		zldev->synth[index].freq);
628b7d907d1SIvan Vecera 
629b7d907d1SIvan Vecera 	return rc;
630b7d907d1SIvan Vecera }
631b7d907d1SIvan Vecera 
632b7d907d1SIvan Vecera static int
633b7d907d1SIvan Vecera zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
634b7d907d1SIvan Vecera {
635b7d907d1SIvan Vecera 	int rc;
636b7d907d1SIvan Vecera 	u8 i;
637b7d907d1SIvan Vecera 
638b7d907d1SIvan Vecera 	for (i = 0; i < ZL3073X_NUM_REFS; i++) {
639b7d907d1SIvan Vecera 		rc = zl3073x_ref_state_fetch(zldev, i);
640b7d907d1SIvan Vecera 		if (rc) {
641b7d907d1SIvan Vecera 			dev_err(zldev->dev,
642b7d907d1SIvan Vecera 				"Failed to fetch input state: %pe\n",
643b7d907d1SIvan Vecera 				ERR_PTR(rc));
644b7d907d1SIvan Vecera 			return rc;
645b7d907d1SIvan Vecera 		}
646b7d907d1SIvan Vecera 	}
647b7d907d1SIvan Vecera 
648b7d907d1SIvan Vecera 	for (i = 0; i < ZL3073X_NUM_SYNTHS; i++) {
649b7d907d1SIvan Vecera 		rc = zl3073x_synth_state_fetch(zldev, i);
650b7d907d1SIvan Vecera 		if (rc) {
651b7d907d1SIvan Vecera 			dev_err(zldev->dev,
652b7d907d1SIvan Vecera 				"Failed to fetch synth state: %pe\n",
653b7d907d1SIvan Vecera 				ERR_PTR(rc));
654b7d907d1SIvan Vecera 			return rc;
655b7d907d1SIvan Vecera 		}
656b7d907d1SIvan Vecera 	}
657b7d907d1SIvan Vecera 
658b7d907d1SIvan Vecera 	for (i = 0; i < ZL3073X_NUM_OUTS; i++) {
659b7d907d1SIvan Vecera 		rc = zl3073x_out_state_fetch(zldev, i);
660b7d907d1SIvan Vecera 		if (rc) {
661b7d907d1SIvan Vecera 			dev_err(zldev->dev,
662b7d907d1SIvan Vecera 				"Failed to fetch output state: %pe\n",
663b7d907d1SIvan Vecera 				ERR_PTR(rc));
664b7d907d1SIvan Vecera 			return rc;
665b7d907d1SIvan Vecera 		}
666b7d907d1SIvan Vecera 	}
667b7d907d1SIvan Vecera 
668b7d907d1SIvan Vecera 	return rc;
669b7d907d1SIvan Vecera }
670b7d907d1SIvan Vecera 
6712df8e64eSIvan Vecera /**
6722df8e64eSIvan Vecera  * zl3073x_dev_probe - initialize zl3073x device
6732df8e64eSIvan Vecera  * @zldev: pointer to zl3073x device
6742df8e64eSIvan Vecera  * @chip_info: chip info based on compatible
6752df8e64eSIvan Vecera  *
6762df8e64eSIvan Vecera  * Common initialization of zl3073x device structure.
6772df8e64eSIvan Vecera  *
6782df8e64eSIvan Vecera  * Returns: 0 on success, <0 on error
6792df8e64eSIvan Vecera  */
6802df8e64eSIvan Vecera int zl3073x_dev_probe(struct zl3073x_dev *zldev,
6812df8e64eSIvan Vecera 		      const struct zl3073x_chip_info *chip_info)
6822df8e64eSIvan Vecera {
6832df8e64eSIvan Vecera 	u16 id, revision, fw_ver;
6842df8e64eSIvan Vecera 	unsigned int i;
6852df8e64eSIvan Vecera 	u32 cfg_ver;
6862df8e64eSIvan Vecera 	int rc;
6872df8e64eSIvan Vecera 
6882df8e64eSIvan Vecera 	/* Read chip ID */
6892df8e64eSIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id);
6902df8e64eSIvan Vecera 	if (rc)
6912df8e64eSIvan Vecera 		return rc;
6922df8e64eSIvan Vecera 
6932df8e64eSIvan Vecera 	/* Check it matches */
6942df8e64eSIvan Vecera 	for (i = 0; i < chip_info->num_ids; i++) {
6952df8e64eSIvan Vecera 		if (id == chip_info->ids[i])
6962df8e64eSIvan Vecera 			break;
6972df8e64eSIvan Vecera 	}
6982df8e64eSIvan Vecera 
6992df8e64eSIvan Vecera 	if (i == chip_info->num_ids) {
7002df8e64eSIvan Vecera 		return dev_err_probe(zldev->dev, -ENODEV,
7012df8e64eSIvan Vecera 				     "Unknown or non-match chip ID: 0x%0x\n",
7022df8e64eSIvan Vecera 				     id);
7032df8e64eSIvan Vecera 	}
7042df8e64eSIvan Vecera 
7052df8e64eSIvan Vecera 	/* Read revision, firmware version and custom config version */
7062df8e64eSIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
7072df8e64eSIvan Vecera 	if (rc)
7082df8e64eSIvan Vecera 		return rc;
7092df8e64eSIvan Vecera 	rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver);
7102df8e64eSIvan Vecera 	if (rc)
7112df8e64eSIvan Vecera 		return rc;
7122df8e64eSIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver);
7132df8e64eSIvan Vecera 	if (rc)
7142df8e64eSIvan Vecera 		return rc;
7152df8e64eSIvan Vecera 
7162df8e64eSIvan Vecera 	dev_dbg(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id,
7172df8e64eSIvan Vecera 		revision, fw_ver);
7182df8e64eSIvan Vecera 	dev_dbg(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n",
7192df8e64eSIvan Vecera 		FIELD_GET(GENMASK(31, 24), cfg_ver),
7202df8e64eSIvan Vecera 		FIELD_GET(GENMASK(23, 16), cfg_ver),
7212df8e64eSIvan Vecera 		FIELD_GET(GENMASK(15, 8), cfg_ver),
7222df8e64eSIvan Vecera 		FIELD_GET(GENMASK(7, 0), cfg_ver));
7232df8e64eSIvan Vecera 
7242df8e64eSIvan Vecera 	/* Generate random clock ID as the device has not such property that
7252df8e64eSIvan Vecera 	 * could be used for this purpose. A user can later change this value
7262df8e64eSIvan Vecera 	 * using devlink.
7272df8e64eSIvan Vecera 	 */
7282df8e64eSIvan Vecera 	zldev->clock_id = get_random_u64();
7292df8e64eSIvan Vecera 
7302df8e64eSIvan Vecera 	/* Initialize mutex for operations where multiple reads, writes
7312df8e64eSIvan Vecera 	 * and/or polls are required to be done atomically.
7322df8e64eSIvan Vecera 	 */
7332df8e64eSIvan Vecera 	rc = devm_mutex_init(zldev->dev, &zldev->multiop_lock);
7342df8e64eSIvan Vecera 	if (rc)
7352df8e64eSIvan Vecera 		return dev_err_probe(zldev->dev, rc,
7362df8e64eSIvan Vecera 				     "Failed to initialize mutex\n");
7372df8e64eSIvan Vecera 
738b7d907d1SIvan Vecera 	/* Fetch device state */
739b7d907d1SIvan Vecera 	rc = zl3073x_dev_state_fetch(zldev);
740b7d907d1SIvan Vecera 	if (rc)
741b7d907d1SIvan Vecera 		return rc;
742b7d907d1SIvan Vecera 
7432df8e64eSIvan Vecera 	/* Register the devlink instance and parameters */
7442df8e64eSIvan Vecera 	rc = zl3073x_devlink_register(zldev);
7452df8e64eSIvan Vecera 	if (rc)
7462df8e64eSIvan Vecera 		return dev_err_probe(zldev->dev, rc,
7472df8e64eSIvan Vecera 				     "Failed to register devlink instance\n");
7482df8e64eSIvan Vecera 
7492df8e64eSIvan Vecera 	return 0;
7502df8e64eSIvan Vecera }
7512df8e64eSIvan Vecera EXPORT_SYMBOL_NS_GPL(zl3073x_dev_probe, "ZL3073X");
7522df8e64eSIvan Vecera 
7532df8e64eSIvan Vecera MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
7542df8e64eSIvan Vecera MODULE_DESCRIPTION("Microchip ZL3073x core driver");
7552df8e64eSIvan Vecera MODULE_LICENSE("GPL");
756