Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dpll: Add basic Microchip ZL3073x support

Microchip Azurite ZL3073x represents chip family providing DPLL
and optionally PHC (PTP) functionality. The chips can be connected
be connected over I2C or SPI bus.

They have the following characteristics:
* up to 5 separate DPLL units (channels)
* 5 synthesizers
* 10 input pins (references)
* 10 outputs
* 20 output pins (output pin pair shares one output)
* Each reference and output can operate in either differential or
single-ended mode (differential mode uses 2 pins)
* Each output is connected to one of the synthesizers
* Each synthesizer is driven by one of the DPLL unit

The device uses 7-bit addresses and 8-bits values. It exposes 8-, 16-,
32- and 48-bits registers in address range <0x000,0x77F>. Due to 7bit
addressing, the range is organized into pages of 128 bytes, with each
page containing a page selector register at address 0x7F.
For reading/writing multi-byte registers, the device supports bulk
transfers.

Add basic functionality to access device registers, probe functionality
both I2C and SPI cases and add devlink support to provide info and
to set clock ID parameter.

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://patch.msgid.link/20250704182202.1641943-6-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Ivan Vecera and committed by
Jakub Kicinski
2df8e64e de9ccf22

+1121 -2
+1
Documentation/networking/devlink/index.rst
··· 98 98 iosm 99 99 octeontx2 100 100 sfc 101 + zl3073x
+51
Documentation/networking/devlink/zl3073x.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ======================= 4 + zl3073x devlink support 5 + ======================= 6 + 7 + This document describes the devlink features implemented by the ``zl3073x`` 8 + device driver. 9 + 10 + Parameters 11 + ========== 12 + 13 + .. list-table:: Generic parameters implemented 14 + :widths: 5 5 90 15 + 16 + * - Name 17 + - Mode 18 + - Notes 19 + * - ``clock_id`` 20 + - driverinit 21 + - Set the clock ID that is used by the driver for registering DPLL devices 22 + and pins. 23 + 24 + Info versions 25 + ============= 26 + 27 + The ``zl3073x`` driver reports the following versions 28 + 29 + .. list-table:: devlink info versions implemented 30 + :widths: 5 5 5 90 31 + 32 + * - Name 33 + - Type 34 + - Example 35 + - Description 36 + * - ``asic.id`` 37 + - fixed 38 + - 1E94 39 + - Chip identification number 40 + * - ``asic.rev`` 41 + - fixed 42 + - 300 43 + - Chip revision number 44 + * - ``fw`` 45 + - running 46 + - 7006 47 + - Firmware version number 48 + * - ``custom_cfg`` 49 + - running 50 + - 1.3.0.1 51 + - Device configuration version customized by OEM
+8
MAINTAINERS
··· 16514 16514 S: Supported 16515 16515 F: drivers/net/wireless/microchip/ 16516 16516 16517 + MICROCHIP ZL3073X DRIVER 16518 + M: Ivan Vecera <ivecera@redhat.com> 16519 + M: Prathosh Satish <Prathosh.Satish@microchip.com> 16520 + L: netdev@vger.kernel.org 16521 + S: Supported 16522 + F: Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml 16523 + F: drivers/dpll/zl3073x/ 16524 + 16517 16525 MICROSEMI MIPS SOCS 16518 16526 M: Alexandre Belloni <alexandre.belloni@bootlin.com> 16519 16527 M: UNGLinuxDriver@microchip.com
+2 -2
drivers/Kconfig
··· 77 77 78 78 source "drivers/ptp/Kconfig" 79 79 80 + source "drivers/dpll/Kconfig" 81 + 80 82 source "drivers/pinctrl/Kconfig" 81 83 82 84 source "drivers/gpio/Kconfig" ··· 246 244 source "drivers/hte/Kconfig" 247 245 248 246 source "drivers/cdx/Kconfig" 249 - 250 - source "drivers/dpll/Kconfig" 251 247 252 248 endmenu
+6
drivers/dpll/Kconfig
··· 3 3 # Generic DPLL drivers configuration 4 4 # 5 5 6 + menu "DPLL device support" 7 + 6 8 config DPLL 7 9 bool 10 + 11 + source "drivers/dpll/zl3073x/Kconfig" 12 + 13 + endmenu
+2
drivers/dpll/Makefile
··· 7 7 dpll-y += dpll_core.o 8 8 dpll-y += dpll_netlink.o 9 9 dpll-y += dpll_nl.o 10 + 11 + obj-$(CONFIG_ZL3073X) += zl3073x/
+38
drivers/dpll/zl3073x/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + config ZL3073X 4 + tristate "Microchip Azurite DPLL/PTP/SyncE devices" 5 + depends on NET 6 + select DPLL 7 + select NET_DEVLINK 8 + help 9 + This driver supports Microchip Azurite family DPLL/PTP/SyncE 10 + devices that support up to 5 independent DPLL channels, 11 + 10 input pins and up to 20 output pins. 12 + 13 + To compile this driver as a module, choose M here. The module 14 + will be called zl3073x. 15 + 16 + config ZL3073X_I2C 17 + tristate "I2C bus implementation for Microchip Azurite devices" 18 + depends on I2C && ZL3073X 19 + select REGMAP_I2C 20 + default m 21 + help 22 + This is I2C bus implementation for Microchip Azurite DPLL/PTP/SyncE 23 + devices. 24 + 25 + To compile this driver as a module, choose M here: the module will 26 + be called zl3073x_i2c. 27 + 28 + config ZL3073X_SPI 29 + tristate "SPI bus implementation for Microchip Azurite devices" 30 + depends on SPI && ZL3073X 31 + select REGMAP_SPI 32 + default m 33 + help 34 + This is SPI bus implementation for Microchip Azurite DPLL/PTP/SyncE 35 + devices. 36 + 37 + To compile this driver as a module, choose M here: the module will 38 + be called zl3073x_spi.
+10
drivers/dpll/zl3073x/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + obj-$(CONFIG_ZL3073X) += zl3073x.o 4 + zl3073x-objs := core.o devlink.o 5 + 6 + obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o 7 + zl3073x_i2c-objs := i2c.o 8 + 9 + obj-$(CONFIG_ZL3073X_SPI) += zl3073x_spi.o 10 + zl3073x_spi-objs := spi.o
+465
drivers/dpll/zl3073x/core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/array_size.h> 4 + #include <linux/bitfield.h> 5 + #include <linux/bits.h> 6 + #include <linux/dev_printk.h> 7 + #include <linux/device.h> 8 + #include <linux/export.h> 9 + #include <linux/module.h> 10 + #include <linux/netlink.h> 11 + #include <linux/regmap.h> 12 + #include <linux/sprintf.h> 13 + #include <linux/unaligned.h> 14 + #include <net/devlink.h> 15 + 16 + #include "core.h" 17 + #include "devlink.h" 18 + #include "regs.h" 19 + 20 + /* Chip IDs for zl30731 */ 21 + static const u16 zl30731_ids[] = { 22 + 0x0E93, 23 + 0x1E93, 24 + 0x2E93, 25 + }; 26 + 27 + const struct zl3073x_chip_info zl30731_chip_info = { 28 + .ids = zl30731_ids, 29 + .num_ids = ARRAY_SIZE(zl30731_ids), 30 + .num_channels = 1, 31 + }; 32 + EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, "ZL3073X"); 33 + 34 + /* Chip IDs for zl30732 */ 35 + static const u16 zl30732_ids[] = { 36 + 0x0E30, 37 + 0x0E94, 38 + 0x1E94, 39 + 0x1F60, 40 + 0x2E94, 41 + 0x3FC4, 42 + }; 43 + 44 + const struct zl3073x_chip_info zl30732_chip_info = { 45 + .ids = zl30732_ids, 46 + .num_ids = ARRAY_SIZE(zl30732_ids), 47 + .num_channels = 2, 48 + }; 49 + EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, "ZL3073X"); 50 + 51 + /* Chip IDs for zl30733 */ 52 + static const u16 zl30733_ids[] = { 53 + 0x0E95, 54 + 0x1E95, 55 + 0x2E95, 56 + }; 57 + 58 + const struct zl3073x_chip_info zl30733_chip_info = { 59 + .ids = zl30733_ids, 60 + .num_ids = ARRAY_SIZE(zl30733_ids), 61 + .num_channels = 3, 62 + }; 63 + EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, "ZL3073X"); 64 + 65 + /* Chip IDs for zl30734 */ 66 + static const u16 zl30734_ids[] = { 67 + 0x0E96, 68 + 0x1E96, 69 + 0x2E96, 70 + }; 71 + 72 + const struct zl3073x_chip_info zl30734_chip_info = { 73 + .ids = zl30734_ids, 74 + .num_ids = ARRAY_SIZE(zl30734_ids), 75 + .num_channels = 4, 76 + }; 77 + EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, "ZL3073X"); 78 + 79 + /* Chip IDs for zl30735 */ 80 + static const u16 zl30735_ids[] = { 81 + 0x0E97, 82 + 0x1E97, 83 + 0x2E97, 84 + }; 85 + 86 + const struct zl3073x_chip_info zl30735_chip_info = { 87 + .ids = zl30735_ids, 88 + .num_ids = ARRAY_SIZE(zl30735_ids), 89 + .num_channels = 5, 90 + }; 91 + EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X"); 92 + 93 + #define ZL_RANGE_OFFSET 0x80 94 + #define ZL_PAGE_SIZE 0x80 95 + #define ZL_NUM_PAGES 15 96 + #define ZL_PAGE_SEL 0x7F 97 + #define ZL_PAGE_SEL_MASK GENMASK(3, 0) 98 + #define ZL_NUM_REGS (ZL_NUM_PAGES * ZL_PAGE_SIZE) 99 + 100 + /* Regmap range configuration */ 101 + static const struct regmap_range_cfg zl3073x_regmap_range = { 102 + .range_min = ZL_RANGE_OFFSET, 103 + .range_max = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1, 104 + .selector_reg = ZL_PAGE_SEL, 105 + .selector_mask = ZL_PAGE_SEL_MASK, 106 + .selector_shift = 0, 107 + .window_start = 0, 108 + .window_len = ZL_PAGE_SIZE, 109 + }; 110 + 111 + static bool 112 + zl3073x_is_volatile_reg(struct device *dev __maybe_unused, unsigned int reg) 113 + { 114 + /* Only page selector is non-volatile */ 115 + return reg != ZL_PAGE_SEL; 116 + } 117 + 118 + const struct regmap_config zl3073x_regmap_config = { 119 + .reg_bits = 8, 120 + .val_bits = 8, 121 + .max_register = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1, 122 + .ranges = &zl3073x_regmap_range, 123 + .num_ranges = 1, 124 + .cache_type = REGCACHE_MAPLE, 125 + .volatile_reg = zl3073x_is_volatile_reg, 126 + }; 127 + EXPORT_SYMBOL_NS_GPL(zl3073x_regmap_config, "ZL3073X"); 128 + 129 + static bool 130 + zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size) 131 + { 132 + /* Check that multiop lock is held when accessing registers 133 + * from page 10 and above. 134 + */ 135 + if (ZL_REG_PAGE(reg) >= 10) 136 + lockdep_assert_held(&zldev->multiop_lock); 137 + 138 + /* Check the index is in valid range for indexed register */ 139 + if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) { 140 + dev_err(zldev->dev, "Index out of range for reg 0x%04lx\n", 141 + ZL_REG_ADDR(reg)); 142 + return false; 143 + } 144 + /* Check the requested size corresponds to register size */ 145 + if (ZL_REG_SIZE(reg) != size) { 146 + dev_err(zldev->dev, "Invalid size %zu for reg 0x%04lx\n", 147 + size, ZL_REG_ADDR(reg)); 148 + return false; 149 + } 150 + 151 + return true; 152 + } 153 + 154 + static int 155 + zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val, 156 + size_t size) 157 + { 158 + int rc; 159 + 160 + if (!zl3073x_check_reg(zldev, reg, size)) 161 + return -EINVAL; 162 + 163 + /* Map the register address to virtual range */ 164 + reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET; 165 + 166 + rc = regmap_bulk_read(zldev->regmap, reg, val, size); 167 + if (rc) { 168 + dev_err(zldev->dev, "Failed to read reg 0x%04x: %pe\n", reg, 169 + ERR_PTR(rc)); 170 + return rc; 171 + } 172 + 173 + return 0; 174 + } 175 + 176 + static int 177 + zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, const void *val, 178 + size_t size) 179 + { 180 + int rc; 181 + 182 + if (!zl3073x_check_reg(zldev, reg, size)) 183 + return -EINVAL; 184 + 185 + /* Map the register address to virtual range */ 186 + reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET; 187 + 188 + rc = regmap_bulk_write(zldev->regmap, reg, val, size); 189 + if (rc) { 190 + dev_err(zldev->dev, "Failed to write reg 0x%04x: %pe\n", reg, 191 + ERR_PTR(rc)); 192 + return rc; 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + /** 199 + * zl3073x_read_u8 - read value from 8bit register 200 + * @zldev: zl3073x device pointer 201 + * @reg: register to write to 202 + * @val: value to write 203 + * 204 + * Reads value from given 8bit register. 205 + * 206 + * Returns: 0 on success, <0 on error 207 + */ 208 + int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val) 209 + { 210 + return zl3073x_read_reg(zldev, reg, val, sizeof(*val)); 211 + } 212 + 213 + /** 214 + * zl3073x_write_u8 - write value to 16bit register 215 + * @zldev: zl3073x device pointer 216 + * @reg: register to write to 217 + * @val: value to write 218 + * 219 + * Writes value into given 8bit register. 220 + * 221 + * Returns: 0 on success, <0 on error 222 + */ 223 + int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val) 224 + { 225 + return zl3073x_write_reg(zldev, reg, &val, sizeof(val)); 226 + } 227 + 228 + /** 229 + * zl3073x_read_u16 - read value from 16bit register 230 + * @zldev: zl3073x device pointer 231 + * @reg: register to write to 232 + * @val: value to write 233 + * 234 + * Reads value from given 16bit register. 235 + * 236 + * Returns: 0 on success, <0 on error 237 + */ 238 + int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val) 239 + { 240 + int rc; 241 + 242 + rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val)); 243 + if (!rc) 244 + be16_to_cpus(val); 245 + 246 + return rc; 247 + } 248 + 249 + /** 250 + * zl3073x_write_u16 - write value to 16bit register 251 + * @zldev: zl3073x device pointer 252 + * @reg: register to write to 253 + * @val: value to write 254 + * 255 + * Writes value into given 16bit register. 256 + * 257 + * Returns: 0 on success, <0 on error 258 + */ 259 + int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val) 260 + { 261 + cpu_to_be16s(&val); 262 + 263 + return zl3073x_write_reg(zldev, reg, &val, sizeof(val)); 264 + } 265 + 266 + /** 267 + * zl3073x_read_u32 - read value from 32bit register 268 + * @zldev: zl3073x device pointer 269 + * @reg: register to write to 270 + * @val: value to write 271 + * 272 + * Reads value from given 32bit register. 273 + * 274 + * Returns: 0 on success, <0 on error 275 + */ 276 + int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val) 277 + { 278 + int rc; 279 + 280 + rc = zl3073x_read_reg(zldev, reg, val, sizeof(*val)); 281 + if (!rc) 282 + be32_to_cpus(val); 283 + 284 + return rc; 285 + } 286 + 287 + /** 288 + * zl3073x_write_u32 - write value to 32bit register 289 + * @zldev: zl3073x device pointer 290 + * @reg: register to write to 291 + * @val: value to write 292 + * 293 + * Writes value into given 32bit register. 294 + * 295 + * Returns: 0 on success, <0 on error 296 + */ 297 + int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val) 298 + { 299 + cpu_to_be32s(&val); 300 + 301 + return zl3073x_write_reg(zldev, reg, &val, sizeof(val)); 302 + } 303 + 304 + /** 305 + * zl3073x_read_u48 - read value from 48bit register 306 + * @zldev: zl3073x device pointer 307 + * @reg: register to write to 308 + * @val: value to write 309 + * 310 + * Reads value from given 48bit register. 311 + * 312 + * Returns: 0 on success, <0 on error 313 + */ 314 + int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val) 315 + { 316 + u8 buf[6]; 317 + int rc; 318 + 319 + rc = zl3073x_read_reg(zldev, reg, buf, sizeof(buf)); 320 + if (!rc) 321 + *val = get_unaligned_be48(buf); 322 + 323 + return rc; 324 + } 325 + 326 + /** 327 + * zl3073x_write_u48 - write value to 48bit register 328 + * @zldev: zl3073x device pointer 329 + * @reg: register to write to 330 + * @val: value to write 331 + * 332 + * Writes value into given 48bit register. 333 + * The value must be from the interval -S48_MIN to U48_MAX. 334 + * 335 + * Returns: 0 on success, <0 on error 336 + */ 337 + int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val) 338 + { 339 + u8 buf[6]; 340 + 341 + /* Check the value belongs to <S48_MIN, U48_MAX> 342 + * Any value >= S48_MIN has bits 47..63 set. 343 + */ 344 + if (val > GENMASK_ULL(47, 0) && val < GENMASK_ULL(63, 47)) { 345 + dev_err(zldev->dev, "Value 0x%0llx out of range\n", val); 346 + return -EINVAL; 347 + } 348 + 349 + put_unaligned_be48(val, buf); 350 + 351 + return zl3073x_write_reg(zldev, reg, buf, sizeof(buf)); 352 + } 353 + 354 + /** 355 + * zl3073x_poll_zero_u8 - wait for register to be cleared by device 356 + * @zldev: zl3073x device pointer 357 + * @reg: register to poll (has to be 8bit register) 358 + * @mask: bit mask for polling 359 + * 360 + * Waits for bits specified by @mask in register @reg value to be cleared 361 + * by the device. 362 + * 363 + * Returns: 0 on success, <0 on error 364 + */ 365 + int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask) 366 + { 367 + /* Register polling sleep & timeout */ 368 + #define ZL_POLL_SLEEP_US 10 369 + #define ZL_POLL_TIMEOUT_US 2000000 370 + unsigned int val; 371 + 372 + /* Check the register is 8bit */ 373 + if (ZL_REG_SIZE(reg) != 1) { 374 + dev_err(zldev->dev, "Invalid reg 0x%04lx size for polling\n", 375 + ZL_REG_ADDR(reg)); 376 + return -EINVAL; 377 + } 378 + 379 + /* Map the register address to virtual range */ 380 + reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET; 381 + 382 + return regmap_read_poll_timeout(zldev->regmap, reg, val, !(val & mask), 383 + ZL_POLL_SLEEP_US, ZL_POLL_TIMEOUT_US); 384 + } 385 + 386 + /** 387 + * zl3073x_dev_probe - initialize zl3073x device 388 + * @zldev: pointer to zl3073x device 389 + * @chip_info: chip info based on compatible 390 + * 391 + * Common initialization of zl3073x device structure. 392 + * 393 + * Returns: 0 on success, <0 on error 394 + */ 395 + int zl3073x_dev_probe(struct zl3073x_dev *zldev, 396 + const struct zl3073x_chip_info *chip_info) 397 + { 398 + u16 id, revision, fw_ver; 399 + unsigned int i; 400 + u32 cfg_ver; 401 + int rc; 402 + 403 + /* Read chip ID */ 404 + rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id); 405 + if (rc) 406 + return rc; 407 + 408 + /* Check it matches */ 409 + for (i = 0; i < chip_info->num_ids; i++) { 410 + if (id == chip_info->ids[i]) 411 + break; 412 + } 413 + 414 + if (i == chip_info->num_ids) { 415 + return dev_err_probe(zldev->dev, -ENODEV, 416 + "Unknown or non-match chip ID: 0x%0x\n", 417 + id); 418 + } 419 + 420 + /* Read revision, firmware version and custom config version */ 421 + rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); 422 + if (rc) 423 + return rc; 424 + rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver); 425 + if (rc) 426 + return rc; 427 + rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver); 428 + if (rc) 429 + return rc; 430 + 431 + dev_dbg(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id, 432 + revision, fw_ver); 433 + dev_dbg(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n", 434 + FIELD_GET(GENMASK(31, 24), cfg_ver), 435 + FIELD_GET(GENMASK(23, 16), cfg_ver), 436 + FIELD_GET(GENMASK(15, 8), cfg_ver), 437 + FIELD_GET(GENMASK(7, 0), cfg_ver)); 438 + 439 + /* Generate random clock ID as the device has not such property that 440 + * could be used for this purpose. A user can later change this value 441 + * using devlink. 442 + */ 443 + zldev->clock_id = get_random_u64(); 444 + 445 + /* Initialize mutex for operations where multiple reads, writes 446 + * and/or polls are required to be done atomically. 447 + */ 448 + rc = devm_mutex_init(zldev->dev, &zldev->multiop_lock); 449 + if (rc) 450 + return dev_err_probe(zldev->dev, rc, 451 + "Failed to initialize mutex\n"); 452 + 453 + /* Register the devlink instance and parameters */ 454 + rc = zl3073x_devlink_register(zldev); 455 + if (rc) 456 + return dev_err_probe(zldev->dev, rc, 457 + "Failed to register devlink instance\n"); 458 + 459 + return 0; 460 + } 461 + EXPORT_SYMBOL_NS_GPL(zl3073x_dev_probe, "ZL3073X"); 462 + 463 + MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>"); 464 + MODULE_DESCRIPTION("Microchip ZL3073x core driver"); 465 + MODULE_LICENSE("GPL");
+57
drivers/dpll/zl3073x/core.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _ZL3073X_CORE_H 4 + #define _ZL3073X_CORE_H 5 + 6 + #include <linux/mutex.h> 7 + #include <linux/types.h> 8 + 9 + struct device; 10 + struct regmap; 11 + 12 + /** 13 + * struct zl3073x_dev - zl3073x device 14 + * @dev: pointer to device 15 + * @regmap: regmap to access device registers 16 + * @multiop_lock: to serialize multiple register operations 17 + * @clock_id: clock id of the device 18 + */ 19 + struct zl3073x_dev { 20 + struct device *dev; 21 + struct regmap *regmap; 22 + struct mutex multiop_lock; 23 + u64 clock_id; 24 + }; 25 + 26 + struct zl3073x_chip_info { 27 + const u16 *ids; 28 + size_t num_ids; 29 + int num_channels; 30 + }; 31 + 32 + extern const struct zl3073x_chip_info zl30731_chip_info; 33 + extern const struct zl3073x_chip_info zl30732_chip_info; 34 + extern const struct zl3073x_chip_info zl30733_chip_info; 35 + extern const struct zl3073x_chip_info zl30734_chip_info; 36 + extern const struct zl3073x_chip_info zl30735_chip_info; 37 + extern const struct regmap_config zl3073x_regmap_config; 38 + 39 + struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev); 40 + int zl3073x_dev_probe(struct zl3073x_dev *zldev, 41 + const struct zl3073x_chip_info *chip_info); 42 + 43 + /********************** 44 + * Registers operations 45 + **********************/ 46 + 47 + int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask); 48 + int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val); 49 + int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val); 50 + int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val); 51 + int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val); 52 + int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val); 53 + int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val); 54 + int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val); 55 + int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val); 56 + 57 + #endif /* _ZL3073X_CORE_H */
+242
drivers/dpll/zl3073x/devlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/device/devres.h> 4 + #include <linux/netlink.h> 5 + #include <linux/sprintf.h> 6 + #include <linux/types.h> 7 + #include <net/devlink.h> 8 + 9 + #include "core.h" 10 + #include "devlink.h" 11 + #include "regs.h" 12 + 13 + /** 14 + * zl3073x_devlink_info_get - Devlink device info callback 15 + * @devlink: devlink structure pointer 16 + * @req: devlink request pointer to store information 17 + * @extack: netlink extack pointer to report errors 18 + * 19 + * Return: 0 on success, <0 on error 20 + */ 21 + static int 22 + zl3073x_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, 23 + struct netlink_ext_ack *extack) 24 + { 25 + struct zl3073x_dev *zldev = devlink_priv(devlink); 26 + u16 id, revision, fw_ver; 27 + char buf[16]; 28 + u32 cfg_ver; 29 + int rc; 30 + 31 + rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id); 32 + if (rc) 33 + return rc; 34 + 35 + snprintf(buf, sizeof(buf), "%X", id); 36 + rc = devlink_info_version_fixed_put(req, 37 + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 38 + buf); 39 + if (rc) 40 + return rc; 41 + 42 + rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); 43 + if (rc) 44 + return rc; 45 + 46 + snprintf(buf, sizeof(buf), "%X", revision); 47 + rc = devlink_info_version_fixed_put(req, 48 + DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, 49 + buf); 50 + if (rc) 51 + return rc; 52 + 53 + rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver); 54 + if (rc) 55 + return rc; 56 + 57 + snprintf(buf, sizeof(buf), "%u", fw_ver); 58 + rc = devlink_info_version_running_put(req, 59 + DEVLINK_INFO_VERSION_GENERIC_FW, 60 + buf); 61 + if (rc) 62 + return rc; 63 + 64 + rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver); 65 + if (rc) 66 + return rc; 67 + 68 + /* No custom config version */ 69 + if (cfg_ver == U32_MAX) 70 + return 0; 71 + 72 + snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu", 73 + FIELD_GET(GENMASK(31, 24), cfg_ver), 74 + FIELD_GET(GENMASK(23, 16), cfg_ver), 75 + FIELD_GET(GENMASK(15, 8), cfg_ver), 76 + FIELD_GET(GENMASK(7, 0), cfg_ver)); 77 + 78 + return devlink_info_version_running_put(req, "custom_cfg", buf); 79 + } 80 + 81 + static int 82 + zl3073x_devlink_reload_down(struct devlink *devlink, bool netns_change, 83 + enum devlink_reload_action action, 84 + enum devlink_reload_limit limit, 85 + struct netlink_ext_ack *extack) 86 + { 87 + if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) 88 + return -EOPNOTSUPP; 89 + 90 + return 0; 91 + } 92 + 93 + static int 94 + zl3073x_devlink_reload_up(struct devlink *devlink, 95 + enum devlink_reload_action action, 96 + enum devlink_reload_limit limit, 97 + u32 *actions_performed, 98 + struct netlink_ext_ack *extack) 99 + { 100 + struct zl3073x_dev *zldev = devlink_priv(devlink); 101 + union devlink_param_value val; 102 + int rc; 103 + 104 + if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) 105 + return -EOPNOTSUPP; 106 + 107 + rc = devl_param_driverinit_value_get(devlink, 108 + DEVLINK_PARAM_GENERIC_ID_CLOCK_ID, 109 + &val); 110 + if (rc) 111 + return rc; 112 + 113 + if (zldev->clock_id != val.vu64) { 114 + dev_dbg(zldev->dev, 115 + "'clock_id' changed to %016llx\n", val.vu64); 116 + zldev->clock_id = val.vu64; 117 + } 118 + 119 + *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 120 + 121 + return 0; 122 + } 123 + 124 + static const struct devlink_ops zl3073x_devlink_ops = { 125 + .info_get = zl3073x_devlink_info_get, 126 + .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 127 + .reload_down = zl3073x_devlink_reload_down, 128 + .reload_up = zl3073x_devlink_reload_up, 129 + }; 130 + 131 + static void 132 + zl3073x_devlink_free(void *ptr) 133 + { 134 + devlink_free(ptr); 135 + } 136 + 137 + /** 138 + * zl3073x_devm_alloc - allocates zl3073x device structure 139 + * @dev: pointer to device structure 140 + * 141 + * Allocates zl3073x device structure as device resource. 142 + * 143 + * Return: pointer to zl3073x device on success, error pointer on error 144 + */ 145 + struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev) 146 + { 147 + struct zl3073x_dev *zldev; 148 + struct devlink *devlink; 149 + int rc; 150 + 151 + devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev); 152 + if (!devlink) 153 + return ERR_PTR(-ENOMEM); 154 + 155 + /* Add devres action to free devlink device */ 156 + rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink); 157 + if (rc) 158 + return ERR_PTR(rc); 159 + 160 + zldev = devlink_priv(devlink); 161 + zldev->dev = dev; 162 + dev_set_drvdata(zldev->dev, zldev); 163 + 164 + return zldev; 165 + } 166 + EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X"); 167 + 168 + static int 169 + zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id, 170 + union devlink_param_value val, 171 + struct netlink_ext_ack *extack) 172 + { 173 + if (!val.vu64) { 174 + NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero"); 175 + return -EINVAL; 176 + } 177 + 178 + return 0; 179 + } 180 + 181 + static const struct devlink_param zl3073x_devlink_params[] = { 182 + DEVLINK_PARAM_GENERIC(CLOCK_ID, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 183 + NULL, NULL, 184 + zl3073x_devlink_param_clock_id_validate), 185 + }; 186 + 187 + static void 188 + zl3073x_devlink_unregister(void *ptr) 189 + { 190 + struct devlink *devlink = priv_to_devlink(ptr); 191 + 192 + devl_lock(devlink); 193 + 194 + /* Unregister devlink params */ 195 + devl_params_unregister(devlink, zl3073x_devlink_params, 196 + ARRAY_SIZE(zl3073x_devlink_params)); 197 + 198 + /* Unregister devlink instance */ 199 + devl_unregister(devlink); 200 + 201 + devl_unlock(devlink); 202 + } 203 + 204 + /** 205 + * zl3073x_devlink_register - register devlink instance and params 206 + * @zldev: zl3073x device to register the devlink for 207 + * 208 + * Register the devlink instance and parameters associated with the device. 209 + * 210 + * Return: 0 on success, <0 on error 211 + */ 212 + int zl3073x_devlink_register(struct zl3073x_dev *zldev) 213 + { 214 + struct devlink *devlink = priv_to_devlink(zldev); 215 + union devlink_param_value value; 216 + int rc; 217 + 218 + devl_lock(devlink); 219 + 220 + /* Register devlink params */ 221 + rc = devl_params_register(devlink, zl3073x_devlink_params, 222 + ARRAY_SIZE(zl3073x_devlink_params)); 223 + if (rc) { 224 + devl_unlock(devlink); 225 + 226 + return rc; 227 + } 228 + 229 + value.vu64 = zldev->clock_id; 230 + devl_param_driverinit_value_set(devlink, 231 + DEVLINK_PARAM_GENERIC_ID_CLOCK_ID, 232 + value); 233 + 234 + /* Register devlink instance */ 235 + devl_register(devlink); 236 + 237 + devl_unlock(devlink); 238 + 239 + /* Add devres action to unregister devlink device */ 240 + return devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister, 241 + zldev); 242 + }
+12
drivers/dpll/zl3073x/devlink.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _ZL3073X_DEVLINK_H 4 + #define _ZL3073X_DEVLINK_H 5 + 6 + struct zl3073x_dev; 7 + 8 + struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev); 9 + 10 + int zl3073x_devlink_register(struct zl3073x_dev *zldev); 11 + 12 + #endif /* _ZL3073X_DEVLINK_H */
+76
drivers/dpll/zl3073x/i2c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/dev_printk.h> 4 + #include <linux/err.h> 5 + #include <linux/i2c.h> 6 + #include <linux/module.h> 7 + #include <linux/regmap.h> 8 + 9 + #include "core.h" 10 + 11 + static int zl3073x_i2c_probe(struct i2c_client *client) 12 + { 13 + struct device *dev = &client->dev; 14 + struct zl3073x_dev *zldev; 15 + 16 + zldev = zl3073x_devm_alloc(dev); 17 + if (IS_ERR(zldev)) 18 + return PTR_ERR(zldev); 19 + 20 + zldev->regmap = devm_regmap_init_i2c(client, &zl3073x_regmap_config); 21 + if (IS_ERR(zldev->regmap)) 22 + return dev_err_probe(dev, PTR_ERR(zldev->regmap), 23 + "Failed to initialize regmap\n"); 24 + 25 + return zl3073x_dev_probe(zldev, i2c_get_match_data(client)); 26 + } 27 + 28 + static const struct i2c_device_id zl3073x_i2c_id[] = { 29 + { 30 + .name = "zl30731", 31 + .driver_data = (kernel_ulong_t)&zl30731_chip_info, 32 + }, 33 + { 34 + .name = "zl30732", 35 + .driver_data = (kernel_ulong_t)&zl30732_chip_info, 36 + }, 37 + { 38 + .name = "zl30733", 39 + .driver_data = (kernel_ulong_t)&zl30733_chip_info, 40 + }, 41 + { 42 + .name = "zl30734", 43 + .driver_data = (kernel_ulong_t)&zl30734_chip_info, 44 + }, 45 + { 46 + .name = "zl30735", 47 + .driver_data = (kernel_ulong_t)&zl30735_chip_info, 48 + }, 49 + { /* sentinel */ } 50 + }; 51 + MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id); 52 + 53 + static const struct of_device_id zl3073x_i2c_of_match[] = { 54 + { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, 55 + { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, 56 + { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, 57 + { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, 58 + { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, 59 + { /* sentinel */ } 60 + }; 61 + MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match); 62 + 63 + static struct i2c_driver zl3073x_i2c_driver = { 64 + .driver = { 65 + .name = "zl3073x-i2c", 66 + .of_match_table = zl3073x_i2c_of_match, 67 + }, 68 + .probe = zl3073x_i2c_probe, 69 + .id_table = zl3073x_i2c_id, 70 + }; 71 + module_i2c_driver(zl3073x_i2c_driver); 72 + 73 + MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>"); 74 + MODULE_DESCRIPTION("Microchip ZL3073x I2C driver"); 75 + MODULE_IMPORT_NS("ZL3073X"); 76 + MODULE_LICENSE("GPL");
+75
drivers/dpll/zl3073x/regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _ZL3073X_REGS_H 4 + #define _ZL3073X_REGS_H 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/bits.h> 8 + 9 + /* 10 + * Register address structure: 11 + * =========================== 12 + * 25 19 18 16 15 7 6 0 13 + * +------------------------------------------+ 14 + * | max_offset | size | page | page_offset | 15 + * +------------------------------------------+ 16 + * 17 + * page_offset ... <0x00..0x7F> 18 + * page .......... HW page number 19 + * size .......... register byte size (1, 2, 4 or 6) 20 + * max_offset .... maximal offset for indexed registers 21 + * (for non-indexed regs max_offset == page_offset) 22 + */ 23 + 24 + #define ZL_REG_OFFSET_MASK GENMASK(6, 0) 25 + #define ZL_REG_PAGE_MASK GENMASK(15, 7) 26 + #define ZL_REG_SIZE_MASK GENMASK(18, 16) 27 + #define ZL_REG_MAX_OFFSET_MASK GENMASK(25, 19) 28 + #define ZL_REG_ADDR_MASK GENMASK(15, 0) 29 + 30 + #define ZL_REG_OFFSET(_reg) FIELD_GET(ZL_REG_OFFSET_MASK, _reg) 31 + #define ZL_REG_PAGE(_reg) FIELD_GET(ZL_REG_PAGE_MASK, _reg) 32 + #define ZL_REG_MAX_OFFSET(_reg) FIELD_GET(ZL_REG_MAX_OFFSET_MASK, _reg) 33 + #define ZL_REG_SIZE(_reg) FIELD_GET(ZL_REG_SIZE_MASK, _reg) 34 + #define ZL_REG_ADDR(_reg) FIELD_GET(ZL_REG_ADDR_MASK, _reg) 35 + 36 + /** 37 + * ZL_REG_IDX - define indexed register 38 + * @_idx: index of register to access 39 + * @_page: register page 40 + * @_offset: register offset in page 41 + * @_size: register byte size (1, 2, 4 or 6) 42 + * @_items: number of register indices 43 + * @_stride: stride between items in bytes 44 + * 45 + * All parameters except @_idx should be constant. 46 + */ 47 + #define ZL_REG_IDX(_idx, _page, _offset, _size, _items, _stride) \ 48 + (FIELD_PREP(ZL_REG_OFFSET_MASK, \ 49 + (_offset) + (_idx) * (_stride)) | \ 50 + FIELD_PREP_CONST(ZL_REG_PAGE_MASK, _page) | \ 51 + FIELD_PREP_CONST(ZL_REG_SIZE_MASK, _size) | \ 52 + FIELD_PREP_CONST(ZL_REG_MAX_OFFSET_MASK, \ 53 + (_offset) + ((_items) - 1) * (_stride))) 54 + 55 + /** 56 + * ZL_REG - define simple (non-indexed) register 57 + * @_page: register page 58 + * @_offset: register offset in page 59 + * @_size: register byte size (1, 2, 4 or 6) 60 + * 61 + * All parameters should be constant. 62 + */ 63 + #define ZL_REG(_page, _offset, _size) \ 64 + ZL_REG_IDX(0, _page, _offset, _size, 1, 0) 65 + 66 + /************************** 67 + * Register Page 0, General 68 + **************************/ 69 + 70 + #define ZL_REG_ID ZL_REG(0, 0x01, 2) 71 + #define ZL_REG_REVISION ZL_REG(0, 0x03, 2) 72 + #define ZL_REG_FW_VER ZL_REG(0, 0x05, 2) 73 + #define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4) 74 + 75 + #endif /* _ZL3073X_REGS_H */
+76
drivers/dpll/zl3073x/spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/dev_printk.h> 4 + #include <linux/err.h> 5 + #include <linux/module.h> 6 + #include <linux/regmap.h> 7 + #include <linux/spi/spi.h> 8 + 9 + #include "core.h" 10 + 11 + static int zl3073x_spi_probe(struct spi_device *spi) 12 + { 13 + struct device *dev = &spi->dev; 14 + struct zl3073x_dev *zldev; 15 + 16 + zldev = zl3073x_devm_alloc(dev); 17 + if (IS_ERR(zldev)) 18 + return PTR_ERR(zldev); 19 + 20 + zldev->regmap = devm_regmap_init_spi(spi, &zl3073x_regmap_config); 21 + if (IS_ERR(zldev->regmap)) 22 + return dev_err_probe(dev, PTR_ERR(zldev->regmap), 23 + "Failed to initialize regmap\n"); 24 + 25 + return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi)); 26 + } 27 + 28 + static const struct spi_device_id zl3073x_spi_id[] = { 29 + { 30 + .name = "zl30731", 31 + .driver_data = (kernel_ulong_t)&zl30731_chip_info 32 + }, 33 + { 34 + .name = "zl30732", 35 + .driver_data = (kernel_ulong_t)&zl30732_chip_info, 36 + }, 37 + { 38 + .name = "zl30733", 39 + .driver_data = (kernel_ulong_t)&zl30733_chip_info, 40 + }, 41 + { 42 + .name = "zl30734", 43 + .driver_data = (kernel_ulong_t)&zl30734_chip_info, 44 + }, 45 + { 46 + .name = "zl30735", 47 + .driver_data = (kernel_ulong_t)&zl30735_chip_info, 48 + }, 49 + { /* sentinel */ } 50 + }; 51 + MODULE_DEVICE_TABLE(spi, zl3073x_spi_id); 52 + 53 + static const struct of_device_id zl3073x_spi_of_match[] = { 54 + { .compatible = "microchip,zl30731", .data = &zl30731_chip_info }, 55 + { .compatible = "microchip,zl30732", .data = &zl30732_chip_info }, 56 + { .compatible = "microchip,zl30733", .data = &zl30733_chip_info }, 57 + { .compatible = "microchip,zl30734", .data = &zl30734_chip_info }, 58 + { .compatible = "microchip,zl30735", .data = &zl30735_chip_info }, 59 + { /* sentinel */ } 60 + }; 61 + MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match); 62 + 63 + static struct spi_driver zl3073x_spi_driver = { 64 + .driver = { 65 + .name = "zl3073x-spi", 66 + .of_match_table = zl3073x_spi_of_match, 67 + }, 68 + .probe = zl3073x_spi_probe, 69 + .id_table = zl3073x_spi_id, 70 + }; 71 + module_spi_driver(zl3073x_spi_driver); 72 + 73 + MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>"); 74 + MODULE_DESCRIPTION("Microchip ZL3073x SPI driver"); 75 + MODULE_IMPORT_NS("ZL3073X"); 76 + MODULE_LICENSE("GPL");