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