* [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1)
@ 2025-04-24 15:47 Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin Ivan Vecera
` (8 more replies)
0 siblings, 9 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Add support for Microchip Azurite DPLL/PTP/SyncE chip family that
provides DPLL and PTP functionality. This series bring first part
that adds the common MFD driver that provides an access to the bus
that can be either I2C or SPI.
The next part of the series is bringing the DPLL driver that will
covers DPLL functionality. Another series will bring PTP driver and
flashing capability via devlink in the MFD driver will follow soon.
Testing was done by myself and by Prathosh Satish on Microchip EDS2
development board with ZL30732 DPLL chip connected over I2C bus.
Patch breakdown
===============
Patch 1 - Common DT schema for DPLL device and pin
Patch 2 - DT bindings for microchip,zl3073* devices
Patch 3 - Basic support for I2C, SPI and regmap configuration
Patch 4 - Devlink device registration and info
Patch 5 - Helpers for reading and writing register mailboxes
Patch 6 - Fetch invariant register values used by DPLL/PTP sub-drivers
Patch 7 - Clock ID generation for DPLL driver
Patch 8 - Register/create DPLL device cells
---
v3->v4:
* fixed shortcomings in DT patches
* completely reworked register access
* removed a need to manage locking during mailbox accesses by callers
* regcache switched to maple
* dev_err_probe() in probe path
* static mfd cells during sub-devices registration
v1->v3:
* dropped macros for generating register access functions
* register access functions are provided in <linux/mfd/zl3073x_regs.h>
* fixed DT descriptions and compatible wildcard usage
* reworked regmap locking
- regmap uses implicit locking
- mailbox registers are additionally protected by extra mutex
* fixed regmap virtual address range
* added regmap rbtree cache (only for page selector now)
* dropped patches for exporting strnchrnul and for supporting mfg file
this will be maybe added later
Ivan Vecera (8):
dt-bindings: dpll: Add DPLL device and pin
dt-bindings: dpll: Add support for Microchip Azurite chip family
mfd: Add Microchip ZL3073x support
mfd: zl3073x: Add support for devlink device info
mfd: zl3073x: Add functions to work with register mailboxes
mfd: zl3073x: Fetch invariants during probe
mfd: zl3073x: Add clock_id field
mfd: zl3073x: Register DPLL sub-device during init
.../devicetree/bindings/dpll/dpll-device.yaml | 76 ++
.../devicetree/bindings/dpll/dpll-pin.yaml | 45 +
.../bindings/dpll/microchip,zl30731.yaml | 115 ++
MAINTAINERS | 11 +
drivers/mfd/Kconfig | 32 +
drivers/mfd/Makefile | 5 +
drivers/mfd/zl3073x-core.c | 1011 +++++++++++++++++
drivers/mfd/zl3073x-i2c.c | 68 ++
drivers/mfd/zl3073x-regs.h | 155 +++
drivers/mfd/zl3073x-spi.c | 68 ++
drivers/mfd/zl3073x.h | 31 +
include/linux/mfd/zl3073x.h | 308 +++++
12 files changed, 1925 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dpll/dpll-device.yaml
create mode 100644 Documentation/devicetree/bindings/dpll/dpll-pin.yaml
create mode 100644 Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
create mode 100644 drivers/mfd/zl3073x-core.c
create mode 100644 drivers/mfd/zl3073x-i2c.c
create mode 100644 drivers/mfd/zl3073x-regs.h
create mode 100644 drivers/mfd/zl3073x-spi.c
create mode 100644 drivers/mfd/zl3073x.h
create mode 100644 include/linux/mfd/zl3073x.h
--
2.49.0
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-25 7:39 ` Krzysztof Kozlowski
2025-04-24 15:47 ` [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family Ivan Vecera
` (7 subsequent siblings)
8 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Add a common DT schema for DPLL device and its associated pins.
The DPLL (device phase-locked loop) is a device used for precise clock
synchronization in networking and telecom hardware.
The device includes one or more DPLLs (channels) and one or more
physical input/output pins.
Each DPLL channel is used either to provide a pulse-per-clock signal or
to drive an Ethernet equipment clock.
The input and output pins have the following properties:
* label: specifies board label
* connection type: specifies its usage depending on wiring
* list of supported or allowed frequencies: depending on how the pin
is connected and where)
* embedded sync capability: indicates whether the pin supports this
Check:
$ make dt_binding_check DT_SCHEMA_FILES=/dpll/
SCHEMA Documentation/devicetree/bindings/processed-schema.json
/home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
CHKDT ./Documentation/devicetree/bindings
LINT ./Documentation/devicetree/bindings
DTEX Documentation/devicetree/bindings/dpll/dpll-pin.example.dts
DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
DTEX Documentation/devicetree/bindings/dpll/dpll-device.example.dts
DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* dropped $Ref from dpll-pin reg property
* added maxItems to dpll-pin reg property
* fixed paragraph in dpll-pin desc
* dpll-pin type property renamed to connection-type
v1->v3:
* rewritten description for both device and pin
* dropped num-dplls property
* supported-frequencies property renamed to supported-frequencies-hz
---
.../devicetree/bindings/dpll/dpll-device.yaml | 76 +++++++++++++++++++
.../devicetree/bindings/dpll/dpll-pin.yaml | 45 +++++++++++
MAINTAINERS | 2 +
3 files changed, 123 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dpll/dpll-device.yaml
create mode 100644 Documentation/devicetree/bindings/dpll/dpll-pin.yaml
diff --git a/Documentation/devicetree/bindings/dpll/dpll-device.yaml b/Documentation/devicetree/bindings/dpll/dpll-device.yaml
new file mode 100644
index 0000000000000..fb8d7a9a3693f
--- /dev/null
+++ b/Documentation/devicetree/bindings/dpll/dpll-device.yaml
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dpll/dpll-device.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Digital Phase-Locked Loop (DPLL) Device
+
+maintainers:
+ - Ivan Vecera <ivecera@redhat.com>
+
+description:
+ Digital Phase-Locked Loop (DPLL) device is used for precise clock
+ synchronization in networking and telecom hardware. The device can
+ have one or more channels (DPLLs) and one or more physical input and
+ output pins. Each DPLL channel can either produce pulse-per-clock signal
+ or drive ethernet equipment clock. The type of each channel can be
+ indicated by dpll-types property.
+
+properties:
+ $nodename:
+ pattern: "^dpll(@.*)?$"
+
+ "#address-cells":
+ const: 0
+
+ "#size-cells":
+ const: 0
+
+ dpll-types:
+ description: List of DPLL channel types, one per DPLL instance.
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ items:
+ enum: [pps, eec]
+
+ input-pins:
+ type: object
+ description: DPLL input pins
+ unevaluatedProperties: false
+
+ properties:
+ "#address-cells":
+ const: 1
+ "#size-cells":
+ const: 0
+
+ patternProperties:
+ "^pin@[0-9a-f]+$":
+ $ref: /schemas/dpll/dpll-pin.yaml
+ unevaluatedProperties: false
+
+ required:
+ - "#address-cells"
+ - "#size-cells"
+
+ output-pins:
+ type: object
+ description: DPLL output pins
+ unevaluatedProperties: false
+
+ properties:
+ "#address-cells":
+ const: 1
+ "#size-cells":
+ const: 0
+
+ patternProperties:
+ "^pin@[0-9]+$":
+ $ref: /schemas/dpll/dpll-pin.yaml
+ unevaluatedProperties: false
+
+ required:
+ - "#address-cells"
+ - "#size-cells"
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
new file mode 100644
index 0000000000000..51db93b77306f
--- /dev/null
+++ b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dpll/dpll-pin.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DPLL Pin
+
+maintainers:
+ - Ivan Vecera <ivecera@redhat.com>
+
+description: |
+ The DPLL pin is either a physical input or output pin that is provided
+ by a DPLL( Digital Phase-Locked Loop) device. The pin is identified by
+ its physical order number that is stored in reg property and can have
+ an additional set of properties like supported (allowed) frequencies,
+ label, type and may support embedded sync.
+
+ Note that the pin in this context has nothing to do with pinctrl.
+
+properties:
+ reg:
+ description: Hardware index of the DPLL pin.
+ maxItems: 1
+
+ connection-type:
+ description: Connection type of the pin
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ext, gnss, int, mux, synce]
+
+ esync-control:
+ description: Indicates whether the pin supports embedded sync functionality.
+ type: boolean
+
+ label:
+ description: String exposed as the pin board label
+ $ref: /schemas/types.yaml#/definitions/string
+
+ supported-frequencies-hz:
+ description: List of supported frequencies for this pin, expressed in Hz.
+
+required:
+ - reg
+
+additionalProperties: false
diff --git a/MAINTAINERS b/MAINTAINERS
index 82e4b96030df5..b815e02987f3c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7188,6 +7188,8 @@ M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
M: Jiri Pirko <jiri@resnulli.us>
L: netdev@vger.kernel.org
S: Supported
+F: Documentation/devicetree/bindings/dpll/dpll-device.yaml
+F: Documentation/devicetree/bindings/dpll/dpll-pin.yaml
F: Documentation/driver-api/dpll.rst
F: drivers/dpll/*
F: include/linux/dpll.h
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-25 7:41 ` Krzysztof Kozlowski
2025-04-24 15:47 ` [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support Ivan Vecera
` (6 subsequent siblings)
8 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Add DT bindings for Microchip Azurite DPLL chip family. These chips
provide up to 5 independent DPLL channels, 10 differential or
single-ended inputs and 10 differential or 20 single-ended outputs.
They can be connected via I2C or SPI busses.
Check:
$ make dt_binding_check DT_SCHEMA_FILES=/dpll/
SCHEMA Documentation/devicetree/bindings/processed-schema.json
/home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
CHKDT ./Documentation/devicetree/bindings
LINT ./Documentation/devicetree/bindings
DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
DTEX Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dts
DTC [C] Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dtb
DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* fixed $Id
* dpll-pin type property renamed to connection type
v1->v3:
* single file for both i2c & spi
* 5 compatibles for all supported chips from the family
---
.../bindings/dpll/microchip,zl30731.yaml | 115 ++++++++++++++++++
1 file changed, 115 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
diff --git a/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
new file mode 100644
index 0000000000000..17747f754b845
--- /dev/null
+++ b/Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dpll/microchip,zl30731.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip Azurite DPLL device
+
+maintainers:
+ - Ivan Vecera <ivecera@redhat.com>
+
+description:
+ Microchip Azurite DPLL (ZL3073x) is a family of DPLL devices that
+ provides up to 5 independent DPLL channels, up to 10 differential or
+ single-ended inputs and 10 differential or 20 single-ended outputs.
+ These devices support both I2C and SPI interfaces.
+
+properties:
+ compatible:
+ enum:
+ - microchip,zl30731
+ - microchip,zl30732
+ - microchip,zl30733
+ - microchip,zl30734
+ - microchip,zl30735
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: /schemas/dpll/dpll-device.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dpll@70 {
+ compatible = "microchip,zl30732";
+ reg = <0x70>;
+ dpll-types = "pps", "eec";
+
+ input-pins {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pin@0 { /* REF0P */
+ reg = <0>;
+ connection-type = "ext";
+ label = "Input 0";
+ supported-frequencies-hz = /bits/ 64 <1 1000>;
+ };
+ };
+
+ output-pins {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pin@3 { /* OUT1N */
+ reg = <3>;
+ connection-type = "gnss";
+ esync-control;
+ label = "Output 1";
+ supported-frequencies-hz = /bits/ 64 <1 10000>;
+ };
+ };
+ };
+ };
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dpll@70 {
+ compatible = "microchip,zl30731";
+ reg = <0x70>;
+ spi-max-frequency = <12500000>;
+
+ dpll-types = "pps";
+
+ input-pins {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pin@0 { /* REF0P */
+ reg = <0>;
+ connection-type = "ext";
+ label = "Input 0";
+ supported-frequencies-hz = /bits/ 64 <1 1000>;
+ };
+ };
+
+ output-pins {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pin@3 { /* OUT1N */
+ reg = <3>;
+ connection-type = "gnss";
+ esync-control;
+ label = "Output 1";
+ supported-frequencies-hz = /bits/ 64 <1 10000>;
+ };
+ };
+ };
+ };
+...
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 16:34 ` Andrew Lunn
2025-04-25 3:36 ` kernel test robot
2025-04-24 15:47 ` [PATCH net-next v4 4/8] mfd: zl3073x: Add support for devlink device info Ivan Vecera
` (5 subsequent siblings)
8 siblings, 2 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Add base MFD driver for Microchip Azurite ZL3073x chip family.
These chips provide DPLL and PHC (PTP) functionality and can
be connected over I2C or SPI bus.
The MFD driver handles basic communication and synchronization
over the bus, as well as common functionality that are used by
the DPLL driver (part 2) and by the PTP driver (to be added later).
The chip family has 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.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* zl3073x_regs.h moved to drivers/mfd/
* maple as regcache
* added and used general helper to read 16bit registers
* removed mailbox mutex for now
* removed parentheses in zl3073x_is_volatile_reg()
* used dev_err_probe() in probe path
* dropped <linux/device.h> inclusion
* dropped unneccessary i2c_set_clientdata() and spi_set_drvdata()
v2->v3:
* added chip_info with valid chip ids and num of DPLLs for compatibles
* regmap is using implicit locking
* mailbox registers requires extra mutex to be held
* added helpers to access registers
* report device firmware and config version using dev_dbg
* fixed regmap ranges
* enabled rbtree regcache for page selector
v1->v2:
* fixed header issues
* removed usage of of_match_ptr
* added check for devm_mutex_init
* removed commas after sentinels
* removed variable initialization in zl3073x_i2c_probe()
* moved device tables closer to their users
* renamed zl3073x_dev_alloc() to zl3073x_devm_alloc()
* removed empty zl3073x_dev_exit()
* spidev renamed to spi
* squashed together with device DT bindings
* used dev_err_probe() instead of dev_err() during probe
* added some function documentation
DT bindings:
* spliced to separate files for i2c and spi
* fixed property order in DT bindings' examples
* added description
---
MAINTAINERS | 9 ++
drivers/mfd/Kconfig | 30 ++++
drivers/mfd/Makefile | 5 +
drivers/mfd/zl3073x-core.c | 264 ++++++++++++++++++++++++++++++++++++
drivers/mfd/zl3073x-i2c.c | 66 +++++++++
drivers/mfd/zl3073x-regs.h | 74 ++++++++++
drivers/mfd/zl3073x-spi.c | 66 +++++++++
drivers/mfd/zl3073x.h | 31 +++++
include/linux/mfd/zl3073x.h | 21 +++
9 files changed, 566 insertions(+)
create mode 100644 drivers/mfd/zl3073x-core.c
create mode 100644 drivers/mfd/zl3073x-i2c.c
create mode 100644 drivers/mfd/zl3073x-regs.h
create mode 100644 drivers/mfd/zl3073x-spi.c
create mode 100644 drivers/mfd/zl3073x.h
create mode 100644 include/linux/mfd/zl3073x.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b815e02987f3c..0f6492ba50d68 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15998,6 +15998,15 @@ L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/net/wireless/microchip/
+MICROCHIP ZL3073X DRIVER
+M: Ivan Vecera <ivecera@redhat.com>
+M: Prathosh Satish <Prathosh.Satish@microchip.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/dpll/microchip,zl3073x*.yaml
+F: drivers/mfd/zl3073x*
+F: include/linux/mfd/zl3073x.h
+
MICROSEMI MIPS SOCS
M: Alexandre Belloni <alexandre.belloni@bootlin.com>
M: UNGLinuxDriver@microchip.com
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 22b9363100394..7d7902ec1d89a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2422,5 +2422,35 @@ config MFD_UPBOARD_FPGA
To compile this driver as a module, choose M here: the module will be
called upboard-fpga.
+config MFD_ZL3073X_CORE
+ tristate
+ select MFD_CORE
+
+config MFD_ZL3073X_I2C
+ tristate "Microchip Azurite DPLL/PTP/SyncE with I2C"
+ depends on I2C
+ select MFD_ZL3073X_CORE
+ select REGMAP_I2C
+ help
+ Say Y here if you want to build I2C support for the Microchip
+ Azurite DPLL/PTP/SyncE chip family.
+
+ To compile this driver as a module, choose M here: the module
+ will be called zl3073x_i2c and you will also get zl3073x for
+ the core module.
+
+config MFD_ZL3073X_SPI
+ tristate "Microchip Azurite DPLL/PTP/SyncE with SPI"
+ depends on SPI
+ select MFD_ZL3073X_CORE
+ select REGMAP_SPI
+ help
+ Say Y here if you want to build SPI support for the Microchip
+ Azurite DPLL/PTP/SyncE chip family.
+
+ To compile this driver as a module, choose M here: the module
+ will be called zl3073x_spi and you will also get zl3073x for
+ the core module.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 948cbdf42a18b..76e2babc1538f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -290,3 +290,8 @@ obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o
+
+zl3073x-y := zl3073x-core.o
+obj-$(CONFIG_MFD_ZL3073X_CORE) += zl3073x.o
+obj-$(CONFIG_MFD_ZL3073X_I2C) += zl3073x-i2c.o
+obj-$(CONFIG_MFD_ZL3073X_SPI) += zl3073x-spi.o
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
new file mode 100644
index 0000000000000..f30091ae48eca
--- /dev/null
+++ b/drivers/mfd/zl3073x-core.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/mfd/zl3073x.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/unaligned.h>
+#include "zl3073x.h"
+#include "zl3073x-regs.h"
+
+/* Chip IDs for zl30731 */
+static const u16 zl30731_ids[] = {
+ 0x0E93,
+ 0x1E93,
+ 0x2E93,
+};
+
+/* Chip IDs for zl30732 */
+static const u16 zl30732_ids[] = {
+ 0x0E30,
+ 0x0E94,
+ 0x1E94,
+ 0x1F60,
+ 0x2E94,
+ 0x3FC4,
+};
+
+/* Chip IDs for zl30733 */
+static const u16 zl30733_ids[] = {
+ 0x0E95,
+ 0x1E95,
+ 0x2E95,
+};
+
+/* Chip IDs for zl30734 */
+static const u16 zl30734_ids[] = {
+ 0x0E96,
+ 0x1E96,
+ 0x2E96,
+};
+
+/* Chip IDs for zl30735 */
+static const u16 zl30735_ids[] = {
+ 0x0E97,
+ 0x1E97,
+ 0x2E97,
+};
+
+const struct zl3073x_chip_info zl3073x_chip_info[] = {
+ [ZL30731] = {
+ .ids = zl30731_ids,
+ .num_ids = ARRAY_SIZE(zl30731_ids),
+ .num_channels = 1,
+ },
+ [ZL30732] = {
+ .ids = zl30732_ids,
+ .num_ids = ARRAY_SIZE(zl30732_ids),
+ .num_channels = 2,
+ },
+ [ZL30733] = {
+ .ids = zl30733_ids,
+ .num_ids = ARRAY_SIZE(zl30733_ids),
+ .num_channels = 3,
+ },
+ [ZL30734] = {
+ .ids = zl30734_ids,
+ .num_ids = ARRAY_SIZE(zl30734_ids),
+ .num_channels = 4,
+ },
+ [ZL30735] = {
+ .ids = zl30735_ids,
+ .num_ids = ARRAY_SIZE(zl30735_ids),
+ .num_channels = 5,
+ },
+};
+EXPORT_SYMBOL_NS_GPL(zl3073x_chip_info, "ZL3073X");
+
+#define ZL_RANGE_OFFSET 0x80
+#define ZL_PAGE_SIZE 0x80
+#define ZL_NUM_PAGES 15
+#define ZL_NUM_SIMPLE_PAGES 10
+#define ZL_PAGE_SEL 0x7F
+#define ZL_PAGE_SEL_MASK GENMASK(3, 0)
+#define ZL_NUM_REGS (ZL_NUM_PAGES * ZL_PAGE_SIZE)
+
+/* Regmap range configuration */
+static const struct regmap_range_cfg zl3073x_regmap_range = {
+ .range_min = ZL_RANGE_OFFSET,
+ .range_max = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
+ .selector_reg = ZL_PAGE_SEL,
+ .selector_mask = ZL_PAGE_SEL_MASK,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = ZL_PAGE_SIZE,
+};
+
+static bool
+zl3073x_is_volatile_reg(struct device *dev __maybe_unused, unsigned int reg)
+{
+ /* Only page selector is non-volatile */
+ return reg != ZL_PAGE_SEL;
+}
+
+static const struct regmap_config zl3073x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
+ .ranges = &zl3073x_regmap_range,
+ .num_ranges = 1,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = zl3073x_is_volatile_reg,
+};
+
+static int
+zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val)
+{
+ unsigned int len;
+ u8 buf[6];
+ int rc;
+
+ /* Offset of the last item in the indexed register or offset of
+ * the non-indexed register itself.
+ */
+ if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
+ dev_err(zldev->dev, "Index of out range for reg 0x%04lx\n",
+ ZL_REG_ADDR(reg));
+ return -EINVAL;
+ }
+
+ /* Get register size */
+ len = ZL_REG_SIZE(reg);
+
+ /* Map the register address to virtual range */
+ reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
+
+ rc = regmap_bulk_read(zldev->regmap, reg, buf, len);
+ if (rc) {
+ dev_err(zldev->dev, "Failed to read reg 0x%04x: %pe\n", reg,
+ ERR_PTR(rc));
+ return rc;
+ }
+
+ switch (len) {
+ case 1:
+ *(u8 *)val = buf[0];
+ break;
+ case 2:
+ *(u16 *)val = get_unaligned_be16(buf);
+ break;
+ case 4:
+ *(u32 *)val = get_unaligned_be32(buf);
+ break;
+ case 6:
+ *(u64 *)val = get_unaligned_be48(buf);
+ break;
+ default:
+ dev_err(zldev->dev, "Invalid reg-width %u for reg 0x%04x\n",
+ len, reg);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+/**
+ * zl3073x_devm_alloc - allocates zl3073x device structure
+ * @dev: pointer to device structure
+ *
+ * Allocates zl3073x device structure as device resource.
+ *
+ * Return: pointer to zl3073x device on success, error pointer on error
+ */
+struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
+{
+ struct zl3073x_dev *zldev;
+
+ zldev = devm_kzalloc(dev, sizeof(*zldev), GFP_KERNEL);
+ if (!zldev)
+ return ERR_PTR(-ENOMEM);
+
+ zldev->dev = dev;
+ dev_set_drvdata(zldev->dev, zldev);
+
+ return zldev;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X");
+
+/**
+ * zl3073x_dev_init_regmap_config - initialize regmap config
+ * @regmap_cfg: regmap_config structure to fill
+ *
+ * Initializes regmap config common for I2C and SPI.
+ */
+void zl3073x_dev_init_regmap_config(struct regmap_config *regmap_cfg)
+{
+ *regmap_cfg = zl3073x_regmap_config;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_dev_init_regmap_config, "ZL3073X");
+
+/**
+ * zl3073x_dev_probe - initialize zl3073x device
+ * @zldev: pointer to zl3073x device
+ * @chip_info: chip info based on compatible
+ *
+ * Common initialization of zl3073x device structure.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int zl3073x_dev_probe(struct zl3073x_dev *zldev,
+ const struct zl3073x_chip_info *chip_info)
+{
+ u16 id, revision, fw_ver;
+ unsigned int i;
+ u32 cfg_ver;
+ int rc;
+
+ /* Read chip ID */
+ rc = zl3073x_read_reg(zldev, ZL_REG_ID, &id);
+ if (rc)
+ return rc;
+
+ /* Check it matches */
+ for (i = 0; i < chip_info->num_ids; i++) {
+ if (id == chip_info->ids[i])
+ break;
+ }
+
+ if (i == chip_info->num_ids) {
+ return dev_err_probe(zldev->dev, -ENODEV,
+ "Unknown or non-match chip ID: 0x%0x\n",
+ id);
+ }
+
+ /* Read revision, firmware version and custom config version */
+ rc = zl3073x_read_reg(zldev, ZL_REG_REVISION, &revision);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_reg(zldev, ZL_REG_FW_VER, &fw_ver);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_reg(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver);
+ if (rc)
+ return rc;
+
+ dev_dbg(zldev->dev, "ChipID(%X), ChipRev(%X), FwVer(%u)\n", id,
+ revision, fw_ver);
+ dev_dbg(zldev->dev, "Custom config version: %lu.%lu.%lu.%lu\n",
+ FIELD_GET(GENMASK(31, 24), cfg_ver),
+ FIELD_GET(GENMASK(23, 16), cfg_ver),
+ FIELD_GET(GENMASK(15, 8), cfg_ver),
+ FIELD_GET(GENMASK(7, 0), cfg_ver));
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_dev_probe, "ZL3073X");
+
+MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
+MODULE_DESCRIPTION("Microchip ZL3073x core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/zl3073x-i2c.c b/drivers/mfd/zl3073x-i2c.c
new file mode 100644
index 0000000000000..da8bbd702d76c
--- /dev/null
+++ b/drivers/mfd/zl3073x-i2c.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/zl3073x.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include "zl3073x.h"
+
+static int zl3073x_i2c_probe(struct i2c_client *client)
+{
+ struct regmap_config regmap_cfg;
+ struct device *dev = &client->dev;
+ struct zl3073x_dev *zldev;
+
+ zldev = zl3073x_devm_alloc(dev);
+ if (IS_ERR(zldev))
+ return PTR_ERR(zldev);
+
+ zl3073x_dev_init_regmap_config(®map_cfg);
+
+ zldev->regmap = devm_regmap_init_i2c(client, ®map_cfg);
+ if (IS_ERR(zldev->regmap)) {
+ dev_err_probe(dev, PTR_ERR(zldev->regmap),
+ "Failed to initialize regmap\n");
+ return PTR_ERR(zldev->regmap);
+ }
+
+ return zl3073x_dev_probe(zldev, i2c_get_match_data(client));
+}
+
+static const struct i2c_device_id zl3073x_i2c_id[] = {
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30731] },
+ { "zl30732", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30732] },
+ { "zl30733", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30733] },
+ { "zl30734", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30734] },
+ { "zl30735", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30735] },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id);
+
+static const struct of_device_id zl3073x_i2c_of_match[] = {
+ { .compatible = "microchip,zl30731", .data = &zl3073x_chip_info[ZL30731] },
+ { .compatible = "microchip,zl30732", .data = &zl3073x_chip_info[ZL30732] },
+ { .compatible = "microchip,zl30733", .data = &zl3073x_chip_info[ZL30733] },
+ { .compatible = "microchip,zl30734", .data = &zl3073x_chip_info[ZL30734] },
+ { .compatible = "microchip,zl30735", .data = &zl3073x_chip_info[ZL30735] },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match);
+
+static struct i2c_driver zl3073x_i2c_driver = {
+ .driver = {
+ .name = "zl3073x-i2c",
+ .of_match_table = zl3073x_i2c_of_match,
+ },
+ .probe = zl3073x_i2c_probe,
+ .id_table = zl3073x_i2c_id,
+};
+module_i2c_driver(zl3073x_i2c_driver);
+
+MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
+MODULE_DESCRIPTION("Microchip ZL3073x I2C driver");
+MODULE_IMPORT_NS("ZL3073X");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/zl3073x-regs.h b/drivers/mfd/zl3073x-regs.h
new file mode 100644
index 0000000000000..3a8fcc860a6ea
--- /dev/null
+++ b/drivers/mfd/zl3073x-regs.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ZL3073X_REGS_H
+#define __ZL3073X_REGS_H
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+
+/*
+ * Register address structure:
+ * ===========================
+ * 25 19 18 16 15 7 6 0
+ * +-------------------------------------------+
+ * | max_offset | width | page | page_offset |
+ * +-------------------------------------------+
+ *
+ * page_offset ... <0x00..0x7F>
+ * page .......... HW page number
+ * size .......... register byte size (1, 2, 4 or 6)
+ * max_offset .... maximal offset for indexed registers
+ * (for non-indexed regs max_offset == page_offset)
+ */
+
+#define ZL_REG_OFFSET_MASK GENMASK(6, 0)
+#define ZL_REG_PAGE_MASK GENMASK(15, 7)
+#define ZL_REG_SIZE_MASK GENMASK(18, 16)
+#define ZL_REG_MAX_OFFSET_MASK GENMASK(25, 19)
+#define ZL_REG_ADDR_MASK GENMASK(15, 0)
+
+#define ZL_REG_OFFSET(_reg) FIELD_GET(ZL_REG_OFFSET_MASK, _reg)
+#define ZL_REG_MAX_OFFSET(_reg) FIELD_GET(ZL_REG_MAX_OFFSET_MASK, _reg)
+#define ZL_REG_SIZE(_reg) FIELD_GET(ZL_REG_SIZE_MASK, _reg)
+#define ZL_REG_ADDR(_reg) FIELD_GET(ZL_REG_ADDR_MASK, _reg)
+
+/**
+ * ZL_REG_IDX - define indexed register
+ * @_idx: index of register to access
+ * @_page: register page
+ * @_offset: register offset in page
+ * @_size: register byte size (1, 2, 4 or 6)
+ * @_items: number of register indices
+ * @_stride: stride between items in bytes
+ *
+ * All parameters except @_idx should be constant.
+ */
+#define ZL_REG_IDX(_idx, _page, _offset, _size, _items, _stride) \
+ (FIELD_PREP(ZL_REG_OFFSET_MASK, \
+ (_offset) + (_idx) * (_stride)) | \
+ FIELD_PREP_CONST(ZL_REG_PAGE_MASK, _page) | \
+ FIELD_PREP_CONST(ZL_REG_SIZE_MASK, _size) | \
+ FIELD_PREP_CONST(ZL_REG_MAX_OFFSET_MASK, \
+ (_offset) + ((_items) - 1) * (_stride)))
+
+/**
+ * ZL_REG - define simple (non-indexed) register
+ * @_page: register page
+ * @_offset: register offset in page
+ * @_size: register byte size (1, 2, 4 or 6)
+ *
+ * All parameters should be constant.
+ */
+#define ZL_REG(_page, _offset, _size) \
+ ZL_REG_IDX(0, _page, _offset, _size, 1, 0)
+
+/**************************
+ * Register Page 0, General
+ **************************/
+
+#define ZL_REG_ID ZL_REG(0, 0x01, 2)
+#define ZL_REG_REVISION ZL_REG(0, 0x03, 2)
+#define ZL_REG_FW_VER ZL_REG(0, 0x05, 2)
+#define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4)
+
+#endif /* __ZL3073X_REGS_H */
diff --git a/drivers/mfd/zl3073x-spi.c b/drivers/mfd/zl3073x-spi.c
new file mode 100644
index 0000000000000..962b6845c0325
--- /dev/null
+++ b/drivers/mfd/zl3073x-spi.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/mfd/zl3073x.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include "zl3073x.h"
+
+static int zl3073x_spi_probe(struct spi_device *spi)
+{
+ struct regmap_config regmap_cfg;
+ struct device *dev = &spi->dev;
+ struct zl3073x_dev *zldev;
+
+ zldev = zl3073x_devm_alloc(dev);
+ if (IS_ERR(zldev))
+ return PTR_ERR(zldev);
+
+ zl3073x_dev_init_regmap_config(®map_cfg);
+
+ zldev->regmap = devm_regmap_init_spi(spi, ®map_cfg);
+ if (IS_ERR(zldev->regmap)) {
+ dev_err_probe(dev, PTR_ERR(zldev->regmap),
+ "Failed to initialize regmap\n");
+ return PTR_ERR(zldev->regmap);
+ }
+
+ return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi));
+}
+
+static const struct spi_device_id zl3073x_spi_id[] = {
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30731] },
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30732] },
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30733] },
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30734] },
+ { "zl30731", .driver_data = (kernel_ulong_t)&zl3073x_chip_info[ZL30735] },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, zl3073x_spi_id);
+
+static const struct of_device_id zl3073x_spi_of_match[] = {
+ { .compatible = "microchip,zl30731", .data = &zl3073x_chip_info[ZL30731] },
+ { .compatible = "microchip,zl30732", .data = &zl3073x_chip_info[ZL30732] },
+ { .compatible = "microchip,zl30733", .data = &zl3073x_chip_info[ZL30733] },
+ { .compatible = "microchip,zl30734", .data = &zl3073x_chip_info[ZL30734] },
+ { .compatible = "microchip,zl30735", .data = &zl3073x_chip_info[ZL30735] },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match);
+
+static struct spi_driver zl3073x_spi_driver = {
+ .driver = {
+ .name = "zl3073x-spi",
+ .of_match_table = zl3073x_spi_of_match,
+ },
+ .probe = zl3073x_spi_probe,
+ .id_table = zl3073x_spi_id,
+};
+module_spi_driver(zl3073x_spi_driver);
+
+MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
+MODULE_DESCRIPTION("Microchip ZL3073x SPI driver");
+MODULE_IMPORT_NS("ZL3073X");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/zl3073x.h b/drivers/mfd/zl3073x.h
new file mode 100644
index 0000000000000..3a2fea61cf579
--- /dev/null
+++ b/drivers/mfd/zl3073x.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ZL3073X_CORE_H
+#define __ZL3073X_CORE_H
+
+struct device;
+struct regmap_config;
+struct zl3073x_dev;
+
+enum zl3073x_chip_type {
+ ZL30731,
+ ZL30732,
+ ZL30733,
+ ZL30734,
+ ZL30735,
+};
+
+struct zl3073x_chip_info {
+ const u16 *ids;
+ size_t num_ids;
+ int num_channels;
+};
+
+extern const struct zl3073x_chip_info zl3073x_chip_info[];
+
+struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
+void zl3073x_dev_init_regmap_config(struct regmap_config *regmap_cfg);
+int zl3073x_dev_probe(struct zl3073x_dev *zldev,
+ const struct zl3073x_chip_info *chip_info);
+
+#endif /* __ZL3073X_CORE_H */
diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h
new file mode 100644
index 0000000000000..ad5344a84b320
--- /dev/null
+++ b/include/linux/mfd/zl3073x.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __LINUX_MFD_ZL3073X_H
+#define __LINUX_MFD_ZL3073X_H
+
+#include <linux/mutex.h>
+
+struct device;
+struct regmap;
+
+/**
+ * struct zl3073x_dev - zl3073x device
+ * @dev: pointer to device
+ * @regmap: regmap to access device registers
+ */
+struct zl3073x_dev {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+#endif /* __LINUX_MFD_ZL3073X_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 4/8] mfd: zl3073x: Add support for devlink device info
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (2 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes Ivan Vecera
` (4 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Use devlink_alloc() to allocate zl3073x_dev structure, register
the device as a devlink device, and add devlink callback to provide
device info.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* pass error code from devm_add_action_or_reset() call
v2->v3:
* merged devlink device allocation, registration and device info
callback
v1->v2:
* dependency on NET moved to MFD_ZL3073X_CORE in Kconfig
* devlink register managed way
---
drivers/mfd/Kconfig | 2 +
drivers/mfd/zl3073x-core.c | 108 ++++++++++++++++++++++++++++++++++++-
2 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7d7902ec1d89a..e4eca15af175d 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2424,6 +2424,8 @@ config MFD_UPBOARD_FPGA
config MFD_ZL3073X_CORE
tristate
+ depends on NET
+ select NET_DEVLINK
select MFD_CORE
config MFD_ZL3073X_I2C
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
index f30091ae48eca..28cc25b7412e9 100644
--- a/drivers/mfd/zl3073x-core.c
+++ b/drivers/mfd/zl3073x-core.c
@@ -8,8 +8,11 @@
#include <linux/export.h>
#include <linux/mfd/zl3073x.h>
#include <linux/module.h>
+#include <linux/netlink.h>
#include <linux/regmap.h>
+#include <linux/sprintf.h>
#include <linux/unaligned.h>
+#include <net/devlink.h>
#include "zl3073x.h"
#include "zl3073x-regs.h"
@@ -167,6 +170,83 @@ zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val)
return rc;
}
+/**
+ * zl3073x_devlink_info_get - Devlink device info callback
+ * @devlink: devlink structure pointer
+ * @req: devlink request pointer to store information
+ * @extack: netlink extack pointer to report errors
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int zl3073x_devlink_info_get(struct devlink *devlink,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dev *zldev = devlink_priv(devlink);
+ u16 id, revision, fw_ver;
+ char buf[16];
+ u32 cfg_ver;
+ int rc;
+
+ rc = zl3073x_read_reg(zldev, ZL_REG_ID, &id);
+ if (rc)
+ return rc;
+
+ snprintf(buf, sizeof(buf), "%X", id);
+ rc = devlink_info_version_fixed_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
+ buf);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_reg(zldev, ZL_REG_REVISION, &revision);
+ if (rc)
+ return rc;
+
+ snprintf(buf, sizeof(buf), "%X", revision);
+ rc = devlink_info_version_fixed_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
+ buf);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_reg(zldev, ZL_REG_FW_VER, &fw_ver);
+ if (rc)
+ return rc;
+
+ snprintf(buf, sizeof(buf), "%u", fw_ver);
+ rc = devlink_info_version_fixed_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW,
+ buf);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_reg(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver);
+ if (rc)
+ return rc;
+
+ /* No custom config version */
+ if (cfg_ver == U32_MAX)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu",
+ FIELD_GET(GENMASK(31, 24), cfg_ver),
+ FIELD_GET(GENMASK(23, 16), cfg_ver),
+ FIELD_GET(GENMASK(15, 8), cfg_ver),
+ FIELD_GET(GENMASK(7, 0), cfg_ver));
+
+ return devlink_info_version_running_put(req, "cfg.custom_ver", buf);
+}
+
+static const struct devlink_ops zl3073x_devlink_ops = {
+ .info_get = zl3073x_devlink_info_get,
+};
+
+static void zl3073x_devlink_free(void *ptr)
+{
+ devlink_free(ptr);
+}
+
/**
* zl3073x_devm_alloc - allocates zl3073x device structure
* @dev: pointer to device structure
@@ -178,11 +258,19 @@ zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val)
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
{
struct zl3073x_dev *zldev;
+ struct devlink *devlink;
+ int rc;
- zldev = devm_kzalloc(dev, sizeof(*zldev), GFP_KERNEL);
- if (!zldev)
+ devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev);
+ if (!devlink)
return ERR_PTR(-ENOMEM);
+ /* Add devres action to free devlink device */
+ rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink);
+ if (rc)
+ return ERR_PTR(rc);
+
+ zldev = devlink_priv(devlink);
zldev->dev = dev;
dev_set_drvdata(zldev->dev, zldev);
@@ -202,6 +290,11 @@ void zl3073x_dev_init_regmap_config(struct regmap_config *regmap_cfg)
}
EXPORT_SYMBOL_NS_GPL(zl3073x_dev_init_regmap_config, "ZL3073X");
+static void zl3073x_devlink_unregister(void *ptr)
+{
+ devlink_unregister(ptr);
+}
+
/**
* zl3073x_dev_probe - initialize zl3073x device
* @zldev: pointer to zl3073x device
@@ -215,6 +308,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
const struct zl3073x_chip_info *chip_info)
{
u16 id, revision, fw_ver;
+ struct devlink *devlink;
unsigned int i;
u32 cfg_ver;
int rc;
@@ -255,6 +349,16 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
FIELD_GET(GENMASK(15, 8), cfg_ver),
FIELD_GET(GENMASK(7, 0), cfg_ver));
+ /* Register the device as devlink device */
+ devlink = priv_to_devlink(zldev);
+ devlink_register(devlink);
+
+ /* Add devres action to unregister devlink device */
+ rc = devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister,
+ devlink);
+ if (rc)
+ return rc;
+
return 0;
}
EXPORT_SYMBOL_NS_GPL(zl3073x_dev_probe, "ZL3073X");
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (3 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 4/8] mfd: zl3073x: Add support for devlink device info Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 16:43 ` Andrew Lunn
2025-04-24 15:47 ` [PATCH net-next v4 6/8] mfd: zl3073x: Fetch invariants during probe Ivan Vecera
` (3 subsequent siblings)
8 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Registers located on page 10 and above are called mailbox-type
registers. Each page represents a mailbox and is used to read from
and write to configuration of a specific object (DPLL, output,
reference or synth).
Each mailbox page contains a mask register, which selects an index of
the target object to interact with and a semaphore register, which
indicates the requested operation.
The remaining registers within the page are latch registers, which are
populated by the firmware during read operations or by the driver prior
to write operations.
Define structures for sending and receiving mailbox content for each
supported object types, along with functions to handle reading and
writing.
Currently, no locking is required, as only MFD driver accesses these
registers. This will change in future.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* completely reworked mailbox access
v1->v3:
* dropped ZL3073X_MB_OP macro usage
---
drivers/mfd/zl3073x-core.c | 420 ++++++++++++++++++++++++++++++++++++
drivers/mfd/zl3073x-regs.h | 64 ++++++
include/linux/mfd/zl3073x.h | 141 ++++++++++++
3 files changed, 625 insertions(+)
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
index 28cc25b7412e9..4f7c915f17980 100644
--- a/drivers/mfd/zl3073x-core.c
+++ b/drivers/mfd/zl3073x-core.c
@@ -170,6 +170,426 @@ zl3073x_read_reg(struct zl3073x_dev *zldev, unsigned int reg, void *val)
return rc;
}
+static int
+zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, const void *val)
+{
+ unsigned int len;
+ u8 buf[6];
+ int rc;
+
+ /* Offset of the last item in the indexed register or offset of
+ * the non-indexed register itself.
+ */
+ if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
+ dev_err(zldev->dev, "Index of out range for reg 0x%04lx\n",
+ ZL_REG_ADDR(reg));
+ return -EINVAL;
+ }
+
+ len = ZL_REG_SIZE(reg);
+ switch (len) {
+ case 1:
+ buf[0] = *(u8 *)val;
+ break;
+ case 2:
+ put_unaligned_be16(*(u16 *)val, buf);
+ break;
+ case 4:
+ put_unaligned_be32(*(u32 *)val, buf);
+ break;
+ case 6:
+ put_unaligned_be48(*(u64 *)val, buf);
+ break;
+ default:
+ dev_err(zldev->dev, "Invalid reg-width %u for reg 0x%04lx\n",
+ len, ZL_REG_ADDR(reg));
+ return -EINVAL;
+ }
+
+ /* Map the register address to virtual range */
+ reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
+
+ rc = regmap_bulk_write(zldev->regmap, reg, buf, len);
+ if (rc) {
+ dev_err(zldev->dev, "Failed to write reg 0x%04x: %pe\n", reg,
+ ERR_PTR(rc));
+ return rc;
+ }
+
+ return rc;
+}
+
+static int
+zl3073x_wait_reg_zero_bits(struct zl3073x_dev *zldev, unsigned int reg, u8 mask)
+{
+ /* Register polling sleep & timeout */
+#define ZL_POLL_SLEEP_US 10
+#define ZL_POLL_TIMEOUT_US 2000000
+ unsigned int val;
+
+ /* Only 8bit registers are supported */
+ BUILD_BUG_ON(ZL_REG_SIZE(reg) != 1);
+
+ /* Map the register address to virtual range for polling */
+ reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
+
+ return regmap_read_poll_timeout(zldev->regmap, reg, val, !(val & mask),
+ ZL_POLL_SLEEP_US, ZL_POLL_TIMEOUT_US);
+}
+
+static int
+zl3073x_mb_cmd_do(struct zl3073x_dev *zldev, unsigned int cmd_reg, u8 cmd,
+ unsigned int mask_reg, u16 mask)
+{
+ int rc;
+
+ rc = zl3073x_write_reg(zldev, mask_reg, &mask);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_write_reg(zldev, cmd_reg, &cmd);
+ if (rc)
+ return rc;
+
+ /* Wait for the command to finish */
+ return zl3073x_wait_reg_zero_bits(zldev, cmd_reg, cmd);
+}
+
+/**
+ * zl3073x_mb_dpll_read - read given DPLL configuration to mailbox
+ * @zldev: pointer to device structure
+ * @index: DPLL index
+ * @fields: mask of the mailbox fields to be filled
+ * @mb: DPLL mailbox
+ *
+ * Reads selected configuration of given reference into output mailbox.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_dpll_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_dpll *mb)
+{
+ int i, rc;
+
+ rc = zl3073x_mb_cmd_do(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD,
+ ZL_REG_DPLL_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(mb->ref_prio); i++) {
+ if (fields & BIT(i)) {
+ rc = zl3073x_read_reg(zldev, ZL_REG_DPLL_REF_PRIO(i),
+ &mb->ref_prio[i]);
+ if (rc)
+ break;
+ }
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_dpll_read, "ZL3073X");
+
+/**
+ * zl3073x_mb_dpll_write - write given DPLL configuration from mailbox
+ * @zldev: pointer to device structure
+ * @index: DPLL index
+ * @fields: mask of the mailbox fields to be written
+ * @mb: DPLL channel mailbox
+ *
+ * Writes selected fields from the mailbox into device.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_dpll_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_dpll *mb)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(mb->ref_prio); i++) {
+ if (fields & BIT(i)) {
+ rc = zl3073x_write_reg(zldev, ZL_REG_DPLL_REF_PRIO(i),
+ &mb->ref_prio[i]);
+ if (rc)
+ break;
+ }
+ }
+
+ return zl3073x_mb_cmd_do(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR,
+ ZL_REG_DPLL_MB_MASK, BIT(index));
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_dpll_write, "ZL3073X");
+
+/**
+ * zl3073x_mb_output_read - read given output configuration to mailbox
+ * @zldev: pointer to device structure
+ * @index: output index
+ * @fields: mask of the mailbox fields to be filled
+ * @mb: output mailbox
+ *
+ * Reads selected configuration of given reference into output mailbox.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_output_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_output *mb)
+{
+ int rc;
+
+ rc = zl3073x_mb_cmd_do(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
+ ZL_REG_OUTPUT_MB_MASK, BIT(index));
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_MODE))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_MODE, &mb->mode);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_DIV))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_DIV, &mb->div);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_WIDTH))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_WIDTH, &mb->width);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_ESYNC_PERIOD))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
+ &mb->esync_period);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_ESYNC_WIDTH))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
+ &mb->esync_width);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_PHASE_COMP))
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_PHASE_COMP,
+ &mb->phase_comp);
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_output_read, "ZL3073X");
+
+/**
+ * zl3073x_mb_output_write - write given output configuration from mailbox
+ * @zldev: pointer to device structure
+ * @index: output index
+ * @fields: mask of the mailbox fields to be written
+ * @mb: output mailbox
+ *
+ * Writes selected fields from the mailbox into device.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_output_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ const struct zl3073x_mb_output *mb)
+{
+ int rc = 0;
+
+ if (fields & ZL3073X_MB_OUTPUT_MODE)
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_MODE, &mb->mode);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_DIV))
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_DIV, &mb->div);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_WIDTH))
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_WIDTH, &mb->width);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_ESYNC_PERIOD))
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
+ &mb->esync_period);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_ESYNC_WIDTH))
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
+ &mb->esync_width);
+
+ if (!rc && (fields & ZL3073X_MB_OUTPUT_PHASE_COMP))
+ rc = zl3073x_write_reg(zldev, ZL_REG_OUTPUT_PHASE_COMP,
+ &mb->phase_comp);
+ if (rc)
+ return rc;
+
+ return zl3073x_mb_cmd_do(zldev,
+ ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
+ ZL_REG_OUTPUT_MB_MASK, BIT(index));
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_output_write, "ZL3073X");
+
+/**
+ * zl3073x_mb_ref_read - read given reference configuration to mailbox
+ * @zldev: pointer to device structure
+ * @index: reference index
+ * @fields: mask of the mailbox fields to be filled
+ * @mb: reference mailbox
+ *
+ * Reads selected configuration of given reference into ref mailbox.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_ref_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_ref *mb)
+{
+ int rc;
+
+ rc = zl3073x_mb_cmd_do(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
+ ZL_REG_REF_MB_MASK, BIT(index));
+
+ if (!rc && (fields & ZL3073X_MB_REF_FREQ_BASE))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_FREQ_BASE,
+ &mb->freq_base);
+
+ if (!rc && (fields & ZL3073X_MB_REF_FREQ_MULT))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_FREQ_MULT,
+ &mb->freq_mult);
+
+ if (!rc && (fields & ZL3073X_MB_REF_RATIO_M))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_RATIO_M, &mb->ratio_m);
+
+ if (!rc && (fields & ZL3073X_MB_REF_RATIO_N))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_RATIO_N, &mb->ratio_n);
+
+ if (!rc && (fields & ZL3073X_MB_REF_CONFIG))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_CONFIG, &mb->config);
+
+ if (!rc && (fields & ZL3073X_MB_REF_PHASE_OFFSET_COMP))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
+ &mb->phase_offset_comp);
+
+ if (!rc && (fields & ZL3073X_MB_REF_SYNC_CTRL))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_SYNC_CTRL,
+ &mb->sync_ctrl);
+
+ if (!rc && (fields & ZL3073X_MB_REF_ESYNC_DIV))
+ rc = zl3073x_read_reg(zldev, ZL_REG_REF_ESYNC_DIV,
+ &mb->esync_div);
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_ref_read, "ZL3073X");
+
+/**
+ * zl3073x_mb_ref_write - write given reference configuration from mailbox
+ * @zldev: pointer to device structure
+ * @index: reference index
+ * @fields: mask of the mailbox fields to be written
+ * @mb: reference mailbox
+ *
+ * Writes selected fields from the mailbox into device.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_ref_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ const struct zl3073x_mb_ref *mb)
+{
+ int rc = 0;
+
+ if (fields & ZL3073X_MB_REF_FREQ_BASE)
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_FREQ_BASE,
+ &mb->freq_base);
+
+ if (!rc && (fields & ZL3073X_MB_REF_FREQ_MULT))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_FREQ_MULT,
+ &mb->freq_mult);
+
+ if (!rc && (fields & ZL3073X_MB_REF_RATIO_M))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_RATIO_M,
+ &mb->ratio_m);
+
+ if (!rc && (fields & ZL3073X_MB_REF_RATIO_N))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_RATIO_N,
+ &mb->ratio_n);
+
+ if (!rc && (fields & ZL3073X_MB_REF_CONFIG))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_CONFIG, &mb->config);
+
+ if (!rc && (fields & ZL3073X_MB_REF_PHASE_OFFSET_COMP))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
+ &mb->phase_offset_comp);
+
+ if (!rc && (fields & ZL3073X_MB_REF_SYNC_CTRL))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_SYNC_CTRL,
+ &mb->sync_ctrl);
+
+ if (!rc && (fields & ZL3073X_MB_REF_ESYNC_DIV))
+ rc = zl3073x_write_reg(zldev, ZL_REG_REF_ESYNC_DIV,
+ &mb->esync_div);
+
+ if (rc)
+ return rc;
+
+ return zl3073x_mb_cmd_do(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
+ ZL_REG_REF_MB_MASK, BIT(index));
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_ref_write, "ZL3073X");
+
+/**
+ * zl3073x_mb_synth_read - read given synth configuration to mailbox
+ * @zldev: pointer to device structure
+ * @index: synth index
+ * @fields: mask of the mailbox fields to be filled
+ * @mb: synth mailbox
+ *
+ * Reads selected configuration of given reference into synth mailbox.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_synth *mb)
+{
+ int rc;
+
+ rc = zl3073x_mb_cmd_do(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD,
+ ZL_REG_SYNTH_MB_MASK, BIT(index));
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_BASE))
+ rc = zl3073x_read_reg(zldev, ZL_REG_SYNTH_FREQ_BASE,
+ &mb->freq_base);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_MULT))
+ rc = zl3073x_read_reg(zldev, ZL_REG_SYNTH_FREQ_MULT,
+ &mb->freq_mult);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_M))
+ rc = zl3073x_read_reg(zldev, ZL_REG_SYNTH_FREQ_M, &mb->freq_m);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_N))
+ rc = zl3073x_read_reg(zldev, ZL_REG_SYNTH_FREQ_N, &mb->freq_n);
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_synth_read, "ZL3073X");
+
+/**
+ * zl3073x_mb_synth_write - write given synth configuration from mailbox
+ * @zldev: pointer to device structure
+ * @index: synth index
+ * @fields: mask of the mailbox fields to be written
+ * @mb: synth mailbox
+ *
+ * Writes selected fields from the mailbox into device.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_synth *mb)
+{
+ int rc = 0;
+
+ if (fields & ZL3073X_MB_SYNTH_FREQ_BASE)
+ rc = zl3073x_write_reg(zldev, ZL_REG_SYNTH_FREQ_BASE,
+ &mb->freq_base);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_MULT))
+ rc = zl3073x_write_reg(zldev, ZL_REG_SYNTH_FREQ_MULT,
+ &mb->freq_mult);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_M))
+ rc = zl3073x_write_reg(zldev, ZL_REG_SYNTH_FREQ_M, &mb->freq_m);
+
+ if (!rc && (fields & ZL3073X_MB_SYNTH_FREQ_N))
+ rc = zl3073x_write_reg(zldev, ZL_REG_SYNTH_FREQ_N, &mb->freq_n);
+
+ if (rc)
+ return rc;
+
+ return zl3073x_mb_cmd_do(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_WR,
+ ZL_REG_SYNTH_MB_MASK, BIT(index));
+}
+EXPORT_SYMBOL_NS_GPL(zl3073x_mb_synth_write, "ZL3073X");
+
/**
* zl3073x_devlink_info_get - Devlink device info callback
* @devlink: devlink structure pointer
diff --git a/drivers/mfd/zl3073x-regs.h b/drivers/mfd/zl3073x-regs.h
index 3a8fcc860a6ea..a19f04c813cc6 100644
--- a/drivers/mfd/zl3073x-regs.h
+++ b/drivers/mfd/zl3073x-regs.h
@@ -71,4 +71,68 @@
#define ZL_REG_FW_VER ZL_REG(0, 0x05, 2)
#define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4)
+/*******************************
+ * Register Page 10, Ref Mailbox
+ *******************************/
+
+#define ZL_REG_REF_MB_MASK ZL_REG(10, 0x02, 2)
+
+#define ZL_REG_REF_MB_SEM ZL_REG(10, 0x04, 1)
+#define ZL_REF_MB_SEM_WR BIT(0)
+#define ZL_REF_MB_SEM_RD BIT(1)
+
+#define ZL_REG_REF_FREQ_BASE ZL_REG(10, 0x05, 2)
+#define ZL_REG_REF_FREQ_MULT ZL_REG(10, 0x07, 2)
+#define ZL_REG_REF_RATIO_M ZL_REG(10, 0x09, 2)
+#define ZL_REG_REF_RATIO_N ZL_REG(10, 0x0b, 2)
+#define ZL_REG_REF_CONFIG ZL_REG(10, 0x0d, 1)
+#define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6)
+#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
+#define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4)
+
+/********************************
+ * Register Page 12, DPLL Mailbox
+ ********************************/
+
+#define ZL_REG_DPLL_MB_MASK ZL_REG(12, 0x02, 2)
+
+#define ZL_REG_DPLL_MB_SEM ZL_REG(12, 0x04, 1)
+#define ZL_DPLL_MB_SEM_WR BIT(0)
+#define ZL_DPLL_MB_SEM_RD BIT(1)
+
+#define ZL_REG_DPLL_REF_PRIO(_idx) \
+ ZL_REG_IDX(_idx, 12, 0x52, 1, ZL3073X_NUM_INPUTS / 2, 1)
+
+/*********************************
+ * Register Page 13, Synth Mailbox
+ *********************************/
+
+#define ZL_REG_SYNTH_MB_MASK ZL_REG(13, 0x02, 2)
+
+#define ZL_REG_SYNTH_MB_SEM ZL_REG(13, 0x04, 1)
+#define ZL_SYNTH_MB_SEM_WR BIT(0)
+#define ZL_SYNTH_MB_SEM_RD BIT(1)
+
+#define ZL_REG_SYNTH_FREQ_BASE ZL_REG(13, 0x06, 2)
+#define ZL_REG_SYNTH_FREQ_MULT ZL_REG(13, 0x08, 4)
+#define ZL_REG_SYNTH_FREQ_M ZL_REG(13, 0x0c, 2)
+#define ZL_REG_SYNTH_FREQ_N ZL_REG(13, 0x0e, 2)
+
+/**********************************
+ * Register Page 14, Output Mailbox
+ **********************************/
+
+#define ZL_REG_OUTPUT_MB_MASK ZL_REG(14, 0x02, 2)
+
+#define ZL_REG_OUTPUT_MB_SEM ZL_REG(14, 0x04, 1)
+#define ZL_OUTPUT_MB_SEM_WR BIT(0)
+#define ZL_OUTPUT_MB_SEM_RD BIT(1)
+
+#define ZL_REG_OUTPUT_MODE ZL_REG(14, 0x05, 1)
+#define ZL_REG_OUTPUT_DIV ZL_REG(14, 0x0c, 4)
+#define ZL_REG_OUTPUT_WIDTH ZL_REG(14, 0x10, 4)
+#define ZL_REG_OUTPUT_ESYNC_PERIOD ZL_REG(14, 0x14, 4)
+#define ZL_REG_OUTPUT_ESYNC_WIDTH ZL_REG(14, 0x18, 4)
+#define ZL_REG_OUTPUT_PHASE_COMP ZL_REG(14, 0x20, 4)
+
#endif /* __ZL3073X_REGS_H */
diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h
index ad5344a84b320..352cd0f2f64a4 100644
--- a/include/linux/mfd/zl3073x.h
+++ b/include/linux/mfd/zl3073x.h
@@ -8,6 +8,13 @@
struct device;
struct regmap;
+/*
+ * Hardware limits for ZL3073x chip family
+ */
+#define ZL3073X_NUM_INPUTS 10
+#define ZL3073X_NUM_OUTPUTS 10
+#define ZL3073X_NUM_SYNTHS 5
+
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
@@ -18,4 +25,138 @@ struct zl3073x_dev {
struct regmap *regmap;
};
+/*************************
+ * DPLL mailbox operations
+ *************************/
+
+/**
+ * struct zl3073x_mb_dpll - DPLL channel mailbox
+ * @ref_prio: array of input reference priorities
+ */
+struct zl3073x_mb_dpll {
+ u8 ref_prio[ZL3073X_NUM_INPUTS / 2]; /* 4bits per ref */
+#define ZL_DPLL_REF_PRIO_REF_P GENMASK(3, 0)
+#define ZL_DPLL_REF_PRIO_REF_N GENMASK(7, 4)
+#define ZL_DPLL_REF_PRIO_MAX 14
+#define ZL_DPLL_REF_PRIO_NONE 15
+};
+#define ZL3073X_MB_DPLL_REF_PRIO(_ref_pair) BIT(_ref_pair)
+
+int zl3073x_mb_dpll_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_dpll *mb);
+int zl3073x_mb_dpll_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_dpll *mb);
+
+/***************************
+ * Output mailbox operations
+ ***************************/
+
+/**
+ * struct zl3073x_mb_output - output mailbox
+ * @mode: output mode
+ * @div: output divisor
+ * @width: output width
+ * @esync_period: embedded sync period
+ * @esync_width: embedded sync width
+ * @phase_comp: phase compensation
+ */
+struct zl3073x_mb_output {
+ u8 mode; /* page 14, offset 0x05 */
+#define ZL_OUTPUT_MODE_CLOCK_TYPE GENMASK(2, 0)
+#define ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL 0
+#define ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC 1
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT GENMASK(7, 4)
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED 0
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS 1
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF 2
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM 3
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2 4
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P 5
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N 6
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_INV 7
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV 12
+#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV 15
+ u32 div; /* page 14, offset 0x0c */
+ u32 width; /* page 14, offset 0x10 */
+ u32 esync_period; /* page 14, offset 0x14 */
+ u32 esync_width; /* page 14, offset 0x18 */
+ u32 phase_comp; /* page 14, offset 0x20 */
+};
+#define ZL3073X_MB_OUTPUT_MODE BIT(0)
+#define ZL3073X_MB_OUTPUT_DIV BIT(1)
+#define ZL3073X_MB_OUTPUT_WIDTH BIT(2)
+#define ZL3073X_MB_OUTPUT_ESYNC_PERIOD BIT(3)
+#define ZL3073X_MB_OUTPUT_ESYNC_WIDTH BIT(4)
+#define ZL3073X_MB_OUTPUT_PHASE_COMP BIT(5)
+
+int zl3073x_mb_output_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_output *output);
+int zl3073x_mb_output_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ const struct zl3073x_mb_output *output);
+
+/************************************
+ * Input reference mailbox operations
+ ************************************/
+
+/**
+ * struct zl3073x_mb_ref - input reference mailbox
+ * @freq_base: frequency base
+ * @freq_mult: frequency multiplier
+ * @ratio_m: FEC ratio numerator
+ * @ratio_n: FEC ratio denominator
+ * @config: reference configuration
+ * @phase_offset_comp: phase offset compensation
+ * @sync_ctrl: synchronization control
+ * @esync_div: embedded sync divisor
+ */
+struct zl3073x_mb_ref {
+ u16 freq_base; /* page 10, offset 0x05 */
+ u16 freq_mult; /* page 10, offset 0x07 */
+ u16 ratio_m; /* page 10, offset 0x09 */
+ u16 ratio_n; /* page 10, offset 0x0b */
+ u8 config; /* page 10, offset 0x0d */
+#define ZL_REF_CONFIG_ENABLE BIT(0)
+#define ZL_REF_CONFIG_DIFF_EN BIT(2)
+ u64 phase_offset_comp; /* page 10, offset 0x28 */
+ u8 sync_ctrl; /* page 10, offset 0x2e */
+#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
+#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
+#define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2
+ u32 esync_div; /* page 10, offset 0x30 */
+#define ZL_REF_ESYNC_DIV_1HZ 0
+};
+#define ZL3073X_MB_REF_FREQ_BASE BIT(0)
+#define ZL3073X_MB_REF_FREQ_MULT BIT(1)
+#define ZL3073X_MB_REF_RATIO_M BIT(2)
+#define ZL3073X_MB_REF_RATIO_N BIT(3)
+#define ZL3073X_MB_REF_CONFIG BIT(4)
+#define ZL3073X_MB_REF_PHASE_OFFSET_COMP BIT(5)
+#define ZL3073X_MB_REF_SYNC_CTRL BIT(6)
+#define ZL3073X_MB_REF_ESYNC_DIV BIT(7)
+
+int zl3073x_mb_ref_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_ref *ref);
+int zl3073x_mb_ref_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ const struct zl3073x_mb_ref *ref);
+
+/**************************
+ * Synth mailbox operations
+ **************************/
+
+struct zl3073x_mb_synth {
+ u16 freq_base; /* page 13, offset 0x06 */
+ u32 freq_mult; /* page 13, offset 0x08 */
+ u16 freq_m; /* page 13, offset 0x0c */
+ u16 freq_n; /* page 13, offset 0x0e */
+};
+#define ZL3073X_MB_SYNTH_FREQ_BASE BIT(0)
+#define ZL3073X_MB_SYNTH_FREQ_MULT BIT(1)
+#define ZL3073X_MB_SYNTH_FREQ_M BIT(2)
+#define ZL3073X_MB_SYNTH_FREQ_N BIT(3)
+
+int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_synth *mb);
+int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
+ struct zl3073x_mb_synth *mb);
+
#endif /* __LINUX_MFD_ZL3073X_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 6/8] mfd: zl3073x: Fetch invariants during probe
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (4 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 7/8] mfd: zl3073x: Add clock_id field Ivan Vecera
` (2 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Several configuration parameters will remain constant at runtime,
so we can load them during probe to avoid excessive reads from
the hardware.
These parameters will be frequently accessed by the DPLL sub-device
driver (in follow-up series), and later by the PHC/PTP sub-device
driver.
Read the following parameters from the device during probe and store
them for later use:
* frequencies of the synthesizers and their associated DPLL channels
* enablement and type (single-ended or differential) of input pins
* associated synthesizers, signal format, and enablement status of
outputs
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* adjusted for new mailbox API
v2->v3:
* dropped usage of macros for generating helper functions
v1->v2:
* fixed and added inline documentation
---
drivers/mfd/zl3073x-core.c | 200 ++++++++++++++++++++++++++++++++++++
drivers/mfd/zl3073x-regs.h | 17 +++
include/linux/mfd/zl3073x.h | 144 ++++++++++++++++++++++++++
3 files changed, 361 insertions(+)
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
index 4f7c915f17980..b6058de04f954 100644
--- a/drivers/mfd/zl3073x-core.c
+++ b/drivers/mfd/zl3073x-core.c
@@ -6,6 +6,7 @@
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/export.h>
+#include <linux/math64.h>
#include <linux/mfd/zl3073x.h>
#include <linux/module.h>
#include <linux/netlink.h>
@@ -715,6 +716,200 @@ static void zl3073x_devlink_unregister(void *ptr)
devlink_unregister(ptr);
}
+/**
+ * zl3073x_input_state_fetch - get input state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: input pin index to fetch state for
+ *
+ * Function fetches information for the given input reference that are
+ * invariant and stores them for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_input_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_input *input;
+ struct zl3073x_mb_ref ref;
+ int rc;
+
+ input = &zldev->input[index];
+
+ /* If the input is differential then the configuration for N-pin
+ * reference is ignored and P-pin config is used for both.
+ */
+ if (zl3073x_is_n_pin(index) &&
+ zl3073x_input_is_diff(zldev, index - 1)) {
+ input->enabled = zl3073x_input_is_enabled(zldev, index - 1);
+ input->diff = true;
+
+ return 0;
+ }
+
+ /* Read reference configuration into mailbox */
+ rc = zl3073x_mb_ref_read(zldev, index, ZL3073X_MB_REF_CONFIG, &ref);
+ if (rc)
+ return rc;
+
+ input->enabled = FIELD_GET(ZL_REF_CONFIG_ENABLE, ref.config);
+ input->diff = FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref.config);
+
+ dev_dbg(zldev->dev, "INPUT%u is %s and configured as %s\n", index,
+ input->enabled ? "enabled" : "disabled",
+ input->diff ? "differential" : "single-ended");
+
+ return rc;
+}
+
+/**
+ * zl3073x_output_state_fetch - get output state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: output index to fetch state for
+ *
+ * Function fetches information for the given output (not output pin)
+ * that are invariant and stores them for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_output_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_output *output;
+ struct zl3073x_mb_output mb;
+ u8 output_ctrl;
+ int rc;
+
+ output = &zldev->output[index];
+
+ /* Read output control register */
+ rc = zl3073x_read_reg(zldev, ZL_REG_OUTPUT_CTRL(index), &output_ctrl);
+ if (rc)
+ return rc;
+
+ /* Store info about output enablement and synthesizer the output
+ * is connected to.
+ */
+ output->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl);
+ output->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl);
+
+ dev_dbg(zldev->dev, "OUTPUT%u is %s, connected to SYNTH%u\n",
+ index, output->enabled ? "enabled" : "disabled", output->synth);
+
+ /* Read output config mailbox */
+ rc = zl3073x_mb_output_read(zldev, index, ZL3073X_MB_OUTPUT_MODE, &mb);
+ if (rc)
+ return rc;
+
+ /* Extract and store output signal format */
+ output->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT,
+ mb.mode);
+
+ dev_dbg(zldev->dev, "OUTPUT%u has signal format 0x%02x\n", index,
+ output->signal_format);
+
+ return rc;
+}
+
+/**
+ * zl3073x_synth_state_fetch - get synth state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: synth index to fetch state for
+ *
+ * Function fetches information for the given synthesizer that are
+ * invariant and stores them for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_mb_synth mb;
+ u8 synth_ctrl;
+ int rc;
+
+ /* Read synth control register */
+ rc = zl3073x_read_reg(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl);
+ if (rc)
+ return rc;
+
+ /* Extract and store DPLL channel the synth is driven by */
+ zldev->synth[index].dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL,
+ synth_ctrl);
+
+ dev_dbg(zldev->dev, "SYNTH%u is connected to DPLL%u\n", index,
+ zldev->synth[index].dpll);
+
+ /* Read synth configuration into mailbox */
+ rc = zl3073x_mb_synth_read(zldev, index,
+ ZL3073X_MB_SYNTH_FREQ_BASE |
+ ZL3073X_MB_SYNTH_FREQ_MULT |
+ ZL3073X_MB_SYNTH_FREQ_M |
+ ZL3073X_MB_SYNTH_FREQ_N, &mb);
+ if (rc)
+ return rc;
+
+ /* The output frequency is determined by the following formula:
+ * base * multiplier * numerator / denominator
+ */
+
+ /* Check denominator for zero to avoid div by 0 */
+ if (!mb.freq_n) {
+ dev_err(zldev->dev,
+ "Zero divisor for SYNTH%u retrieved from device\n",
+ index);
+ return -EINVAL;
+ }
+
+ /* Compute and store synth frequency */
+ zldev->synth[index].freq = mul_u64_u32_div(mul_u32_u32(mb.freq_base,
+ mb.freq_mult),
+ mb.freq_m, mb.freq_n);
+
+ dev_dbg(zldev->dev, "SYNTH%u frequency: %llu Hz\n", index,
+ zldev->synth[index].freq);
+
+ return rc;
+}
+
+static int
+zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
+{
+ int rc;
+ u8 i;
+
+ for (i = 0; i < ZL3073X_NUM_INPUTS; i++) {
+ rc = zl3073x_input_state_fetch(zldev, i);
+ if (rc) {
+ dev_err(zldev->dev,
+ "Failed to fetch input state: %pe\n",
+ ERR_PTR(rc));
+ return rc;
+ }
+ }
+
+ for (i = 0; i < ZL3073X_NUM_SYNTHS; i++) {
+ rc = zl3073x_synth_state_fetch(zldev, i);
+ if (rc) {
+ dev_err(zldev->dev,
+ "Failed to fetch synth state: %pe\n",
+ ERR_PTR(rc));
+ return rc;
+ }
+ }
+
+ for (i = 0; i < ZL3073X_NUM_OUTPUTS; i++) {
+ rc = zl3073x_output_state_fetch(zldev, i);
+ if (rc) {
+ dev_err(zldev->dev,
+ "Failed to fetch output state: %pe\n",
+ ERR_PTR(rc));
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
/**
* zl3073x_dev_probe - initialize zl3073x device
* @zldev: pointer to zl3073x device
@@ -769,6 +964,11 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
FIELD_GET(GENMASK(15, 8), cfg_ver),
FIELD_GET(GENMASK(7, 0), cfg_ver));
+ /* Fetch device state */
+ rc = zl3073x_dev_state_fetch(zldev);
+ if (rc)
+ return rc;
+
/* Register the device as devlink device */
devlink = priv_to_devlink(zldev);
devlink_register(devlink);
diff --git a/drivers/mfd/zl3073x-regs.h b/drivers/mfd/zl3073x-regs.h
index a19f04c813cc6..daac6703d9d1c 100644
--- a/drivers/mfd/zl3073x-regs.h
+++ b/drivers/mfd/zl3073x-regs.h
@@ -71,6 +71,23 @@
#define ZL_REG_FW_VER ZL_REG(0, 0x05, 2)
#define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4)
+/***********************************
+ * Register Page 9, Synth and Output
+ ***********************************/
+
+#define ZL_REG_SYNTH_CTRL(_idx) \
+ ZL_REG_IDX(_idx, 9, 0x00, 1, ZL3073X_NUM_SYNTHS, 1)
+#define ZL_SYNTH_CTRL_EN BIT(0)
+#define ZL_SYNTH_CTRL_DPLL_SEL GENMASK(6, 4)
+
+#define ZL_REG_OUTPUT_CTRL(_idx) \
+ ZL_REG_IDX(_idx, 9, 0x28, 1, ZL3073X_NUM_OUTPUTS, 1)
+#define ZL_OUTPUT_CTRL_EN BIT(0)
+#define ZL_OUTPUT_CTRL_STOP BIT(1)
+#define ZL_OUTPUT_CTRL_STOP_HIGH BIT(2)
+#define ZL_OUTPUT_CTRL_STOP_HZ BIT(3)
+#define ZL_OUTPUT_CTRL_SYNTH_SEL GENMASK(6, 4)
+
/*******************************
* Register Page 10, Ref Mailbox
*******************************/
diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h
index 352cd0f2f64a4..43171246093f2 100644
--- a/include/linux/mfd/zl3073x.h
+++ b/include/linux/mfd/zl3073x.h
@@ -15,14 +15,54 @@ struct regmap;
#define ZL3073X_NUM_OUTPUTS 10
#define ZL3073X_NUM_SYNTHS 5
+/**
+ * struct zl3073x_input - input invariant info
+ * @enabled: input is enabled or disabled
+ * @diff: true if input is differential
+ */
+struct zl3073x_input {
+ bool enabled;
+ bool diff;
+};
+
+/**
+ * struct zl3073x_output - output invariant info
+ * @enabled: output is enabled or disabled
+ * @synth: synthesizer the output is connected to
+ * @signal_format: output signal format
+ */
+struct zl3073x_output {
+ bool enabled;
+ u8 synth;
+ u8 signal_format;
+};
+
+/**
+ * struct zl3073x_synth - synthesizer invariant info
+ * @freq: synthesizer frequency
+ * @dpll: ID of DPLL the synthesizer is driven by
+ */
+struct zl3073x_synth {
+ u64 freq;
+ u8 dpll;
+};
+
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
* @regmap: regmap to access device registers
+ * @input: array of inputs' invariants
+ * @output: array of outputs' invariants
+ * @synth: array of synthesizers' invariants
*/
struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
+
+ /* Invariants */
+ struct zl3073x_input input[ZL3073X_NUM_INPUTS];
+ struct zl3073x_output output[ZL3073X_NUM_OUTPUTS];
+ struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
};
/*************************
@@ -159,4 +199,108 @@ int zl3073x_mb_synth_read(struct zl3073x_dev *zldev, u8 index, u32 fields,
int zl3073x_mb_synth_write(struct zl3073x_dev *zldev, u8 index, u32 fields,
struct zl3073x_mb_synth *mb);
+static inline
+bool zl3073x_is_n_pin(u8 index)
+{
+ /* P-pins indices are even while N-pins are odd */
+ return index & 1;
+}
+
+static inline
+bool zl3073x_is_p_pin(u8 index)
+{
+ return !zl3073x_is_n_pin(index);
+}
+
+/**
+ * zl3073x_input_is_diff - check if the given input ref is differential
+ * @zldev: pointer to zl3073x device
+ * @index: output index
+ *
+ * Return: true if input is differential, false if input is single-ended
+ */
+static inline
+bool zl3073x_input_is_diff(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->input[index].diff;
+}
+
+/**
+ * zl3073x_input_is_enabled - check if the given input ref is enabled
+ * @zldev: pointer to zl3073x device
+ * @index: input index
+ *
+ * Return: true if input is enabled, false if input is disabled
+ */
+static inline
+bool zl3073x_input_is_enabled(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->input[index].enabled;
+}
+
+/**
+ * zl3073x_output_is_enabled - check if the given output is enabled
+ * @zldev: pointer to zl3073x device
+ * @index: output index
+ *
+ * Return: true if output is enabled, false if output is disabled
+ */
+static inline
+u8 zl3073x_output_is_enabled(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->output[index].enabled;
+}
+
+/**
+ * zl3073x_output_signal_format_get - get output signal format
+ * @zldev: pointer to zl3073x device
+ * @index: output index
+ *
+ * Return: signal format of given output
+ */
+static inline
+u8 zl3073x_output_signal_format_get(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->output[index].signal_format;
+}
+
+/**
+ * zl3073x_output_synth_get - get synth connected to given output
+ * @zldev: pointer to zl3073x device
+ * @index: output index
+ *
+ * Return: index of synth connected to given output.
+ */
+static inline
+u8 zl3073x_output_synth_get(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->output[index].synth;
+}
+
+/**
+ * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
+ * @zldev: pointer to zl3073x device
+ * @index: synth index
+ *
+ * Return: ID of DPLL the given synthetizer is driven by
+ */
+static inline
+u64 zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->synth[index].dpll;
+}
+
+/**
+ * zl3073x_synth_freq_get - get synth current freq
+ * @zldev: pointer to zl3073x device
+ * @index: synth index
+ *
+ * Return: frequency of given synthetizer
+ */
+static inline
+u64 zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
+{
+ return zldev->synth[index].freq;
+}
+
#endif /* __LINUX_MFD_ZL3073X_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 7/8] mfd: zl3073x: Add clock_id field
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (5 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 6/8] mfd: zl3073x: Fetch invariants during probe Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 8/8] mfd: zl3073x: Register DPLL sub-device during init Ivan Vecera
2025-04-24 15:51 ` [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Lee Jones
8 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Add .clock_id to zl3073x_dev structure that will be used by later
commits introducing DPLL driver. The clock ID is required for DPLL
device registration.
To generate this ID, use chip ID read during device initialization.
In case where multiple zl3073x based chips are present, the chip ID
is shifted and lower bits are filled by an unique value - using
the I2C device address for I2C connections and the chip-select value
for SPI connections.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/mfd/zl3073x-core.c | 6 +++++-
drivers/mfd/zl3073x-i2c.c | 4 +++-
drivers/mfd/zl3073x-spi.c | 4 +++-
drivers/mfd/zl3073x.h | 2 +-
include/linux/mfd/zl3073x.h | 2 ++
5 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
index b6058de04f954..d0022dfb0236c 100644
--- a/drivers/mfd/zl3073x-core.c
+++ b/drivers/mfd/zl3073x-core.c
@@ -914,13 +914,14 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
* zl3073x_dev_probe - initialize zl3073x device
* @zldev: pointer to zl3073x device
* @chip_info: chip info based on compatible
+ * @dev_id: device ID to be used as part of clock ID
*
* Common initialization of zl3073x device structure.
*
* Returns: 0 on success, <0 on error
*/
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
- const struct zl3073x_chip_info *chip_info)
+ const struct zl3073x_chip_info *chip_info, u8 dev_id)
{
u16 id, revision, fw_ver;
struct devlink *devlink;
@@ -964,6 +965,9 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
FIELD_GET(GENMASK(15, 8), cfg_ver),
FIELD_GET(GENMASK(7, 0), cfg_ver));
+ /* Use chip ID and given dev ID as clock ID */
+ zldev->clock_id = ((u64)id << 8) | dev_id;
+
/* Fetch device state */
rc = zl3073x_dev_state_fetch(zldev);
if (rc)
diff --git a/drivers/mfd/zl3073x-i2c.c b/drivers/mfd/zl3073x-i2c.c
index da8bbd702d76c..e00277f87de92 100644
--- a/drivers/mfd/zl3073x-i2c.c
+++ b/drivers/mfd/zl3073x-i2c.c
@@ -27,7 +27,9 @@ static int zl3073x_i2c_probe(struct i2c_client *client)
return PTR_ERR(zldev->regmap);
}
- return zl3073x_dev_probe(zldev, i2c_get_match_data(client));
+ /* Initialize device and use I2C address as dev ID */
+ return zl3073x_dev_probe(zldev, i2c_get_match_data(client),
+ client->addr);
}
static const struct i2c_device_id zl3073x_i2c_id[] = {
diff --git a/drivers/mfd/zl3073x-spi.c b/drivers/mfd/zl3073x-spi.c
index 962b6845c0325..368001ae19db9 100644
--- a/drivers/mfd/zl3073x-spi.c
+++ b/drivers/mfd/zl3073x-spi.c
@@ -27,7 +27,9 @@ static int zl3073x_spi_probe(struct spi_device *spi)
return PTR_ERR(zldev->regmap);
}
- return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi));
+ /* Initialize device and use SPI chip select value as dev ID */
+ return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi),
+ spi_get_chipselect(spi, 0));
}
static const struct spi_device_id zl3073x_spi_id[] = {
diff --git a/drivers/mfd/zl3073x.h b/drivers/mfd/zl3073x.h
index 3a2fea61cf579..abd1ab9a56ded 100644
--- a/drivers/mfd/zl3073x.h
+++ b/drivers/mfd/zl3073x.h
@@ -26,6 +26,6 @@ extern const struct zl3073x_chip_info zl3073x_chip_info[];
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
void zl3073x_dev_init_regmap_config(struct regmap_config *regmap_cfg);
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
- const struct zl3073x_chip_info *chip_info);
+ const struct zl3073x_chip_info *chip_info, u8 dev_id);
#endif /* __ZL3073X_CORE_H */
diff --git a/include/linux/mfd/zl3073x.h b/include/linux/mfd/zl3073x.h
index 43171246093f2..ca6785ff9ecc9 100644
--- a/include/linux/mfd/zl3073x.h
+++ b/include/linux/mfd/zl3073x.h
@@ -51,6 +51,7 @@ struct zl3073x_synth {
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
* @regmap: regmap to access device registers
+ * @clock_id: clock id of the device
* @input: array of inputs' invariants
* @output: array of outputs' invariants
* @synth: array of synthesizers' invariants
@@ -58,6 +59,7 @@ struct zl3073x_synth {
struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
+ u64 clock_id;
/* Invariants */
struct zl3073x_input input[ZL3073X_NUM_INPUTS];
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH net-next v4 8/8] mfd: zl3073x: Register DPLL sub-device during init
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (6 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 7/8] mfd: zl3073x: Add clock_id field Ivan Vecera
@ 2025-04-24 15:47 ` Ivan Vecera
2025-04-24 15:51 ` [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Lee Jones
8 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 15:47 UTC (permalink / raw)
To: netdev
Cc: Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Prathosh Satish, Lee Jones,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
Register DPLL sub-devices to expose the functionality provided
by ZL3073x chip family. Each sub-device represents one of
the available DPLL channels.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
v3->v4:
* use static mfd cells
---
drivers/mfd/zl3073x-core.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/mfd/zl3073x-core.c b/drivers/mfd/zl3073x-core.c
index d0022dfb0236c..a8971b86db121 100644
--- a/drivers/mfd/zl3073x-core.c
+++ b/drivers/mfd/zl3073x-core.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/export.h>
#include <linux/math64.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/zl3073x.h>
#include <linux/module.h>
#include <linux/netlink.h>
@@ -910,6 +911,14 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
return rc;
}
+static const struct mfd_cell zl3073x_dpll_cells[] = {
+ MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 0),
+ MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 1),
+ MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 2),
+ MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 3),
+ MFD_CELL_BASIC("zl3073x-dpll", NULL, NULL, 0, 4),
+};
+
/**
* zl3073x_dev_probe - initialize zl3073x device
* @zldev: pointer to zl3073x device
@@ -973,6 +982,16 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
if (rc)
return rc;
+ /* Add DPLL sub-device cell for each DPLL channel */
+ rc = devm_mfd_add_devices(zldev->dev, PLATFORM_DEVID_AUTO,
+ zl3073x_dpll_cells, chip_info->num_channels,
+ NULL, 0, NULL);
+ if (rc) {
+ dev_err_probe(zldev->dev, rc,
+ "Failed to add DPLL sub-device\n");
+ return rc;
+ }
+
/* Register the device as devlink device */
devlink = priv_to_devlink(zldev);
devlink_register(devlink);
--
2.49.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1)
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
` (7 preceding siblings ...)
2025-04-24 15:47 ` [PATCH net-next v4 8/8] mfd: zl3073x: Register DPLL sub-device during init Ivan Vecera
@ 2025-04-24 15:51 ` Lee Jones
2025-04-24 16:29 ` Ivan Vecera
8 siblings, 1 reply; 33+ messages in thread
From: Lee Jones @ 2025-04-24 15:51 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
On Thu, 24 Apr 2025, Ivan Vecera wrote:
> Add support for Microchip Azurite DPLL/PTP/SyncE chip family that
> provides DPLL and PTP functionality. This series bring first part
> that adds the common MFD driver that provides an access to the bus
> that can be either I2C or SPI.
>
> The next part of the series is bringing the DPLL driver that will
> covers DPLL functionality. Another series will bring PTP driver and
> flashing capability via devlink in the MFD driver will follow soon.
>
> Testing was done by myself and by Prathosh Satish on Microchip EDS2
> development board with ZL30732 DPLL chip connected over I2C bus.
>
> Patch breakdown
> ===============
> Patch 1 - Common DT schema for DPLL device and pin
> Patch 2 - DT bindings for microchip,zl3073* devices
> Patch 3 - Basic support for I2C, SPI and regmap configuration
> Patch 4 - Devlink device registration and info
> Patch 5 - Helpers for reading and writing register mailboxes
Whoops! I just this second replied to v3.
This needs moving out to somewhere more appropriate.
Use MFD to allocate and split the resources, then the sub-devices can do
the technical and heavy API stuff.
> Patch 6 - Fetch invariant register values used by DPLL/PTP sub-drivers
> Patch 7 - Clock ID generation for DPLL driver
> Patch 8 - Register/create DPLL device cells
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1)
2025-04-24 15:51 ` [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Lee Jones
@ 2025-04-24 16:29 ` Ivan Vecera
0 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 16:29 UTC (permalink / raw)
To: Lee Jones
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Kees Cook, Andy Shevchenko, Andrew Morton, Michal Schmidt,
devicetree, linux-kernel, linux-hardening
On 24. 04. 25 5:51 odp., Lee Jones wrote:
> On Thu, 24 Apr 2025, Ivan Vecera wrote:
>
>> Add support for Microchip Azurite DPLL/PTP/SyncE chip family that
>> provides DPLL and PTP functionality. This series bring first part
>> that adds the common MFD driver that provides an access to the bus
>> that can be either I2C or SPI.
>>
>> The next part of the series is bringing the DPLL driver that will
>> covers DPLL functionality. Another series will bring PTP driver and
>> flashing capability via devlink in the MFD driver will follow soon.
>>
>> Testing was done by myself and by Prathosh Satish on Microchip EDS2
>> development board with ZL30732 DPLL chip connected over I2C bus.
>>
>> Patch breakdown
>> ===============
>> Patch 1 - Common DT schema for DPLL device and pin
>> Patch 2 - DT bindings for microchip,zl3073* devices
>> Patch 3 - Basic support for I2C, SPI and regmap configuration
>> Patch 4 - Devlink device registration and info
>> Patch 5 - Helpers for reading and writing register mailboxes
>
> Whoops! I just this second replied to v3.
>
> This needs moving out to somewhere more appropriate.
>
> Use MFD to allocate and split the resources, then the sub-devices can do
> the technical and heavy API stuff.
They cannot because the bus is shared and MFD parent device acts as bus
arbitrator. It has to ensure that sub-devices access the registers
safely.
Mailbox could be confusing for somebody but it does not have anything
common with HW mailboxes. In this context the mailbox is just a sequence
of register reads and writes in certain order and this sequence has
to be done atomically (I tried to describe this in my previous replies).
I have followed Andrew's recommendation to hide these special sequences
and provide sub-devices some simple API to use them without special
locking needs.
Thanks,
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support
2025-04-24 15:47 ` [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support Ivan Vecera
@ 2025-04-24 16:34 ` Andrew Lunn
2025-04-24 16:49 ` Ivan Vecera
2025-04-25 3:36 ` kernel test robot
1 sibling, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 16:34 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
> +++ b/drivers/mfd/zl3073x-regs.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __ZL3073X_REGS_H
> +#define __ZL3073X_REGS_H
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +
> +/*
> + * Register address structure:
> + * ===========================
> + * 25 19 18 16 15 7 6 0
> + * +-------------------------------------------+
> + * | max_offset | width | page | page_offset |
> + * +-------------------------------------------+
> + *
> + * page_offset ... <0x00..0x7F>
> + * page .......... HW page number
> + * size .......... register byte size (1, 2, 4 or 6)
> + * max_offset .... maximal offset for indexed registers
> + * (for non-indexed regs max_offset == page_offset)
> + */
Something i missed earlier. This does not really describe
hardware. The upper half is meta data about the register, which you
encode into the register number.
How many other Linux drivers do you know about which does this?
Also width vs size.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 15:47 ` [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes Ivan Vecera
@ 2025-04-24 16:43 ` Andrew Lunn
2025-04-24 17:10 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 16:43 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
> +static int
> +zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, const void *val)
> +{
> + unsigned int len;
> + u8 buf[6];
> + int rc;
> +
> + /* Offset of the last item in the indexed register or offset of
> + * the non-indexed register itself.
> + */
> + if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
> + dev_err(zldev->dev, "Index of out range for reg 0x%04lx\n",
> + ZL_REG_ADDR(reg));
> + return -EINVAL;
> + }
> +
> + len = ZL_REG_SIZE(reg);
I suggested you add helpers for zl3073x_write_reg_u8(),
zl3073x_write_reg_u16(), zl3073x_write_reg_32(), and
zl3073x_write_reg_48(). The compiler will then do type checking for
val, ensure what you pass is actually big enough.
Here you have a void *val. You have no idea how big a value that
pointer points to, and the compiler is not helping you.
I suggest you add the individual helpers. If you decided to keep the
register meta data, you can validate the correct helper has been
called.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support
2025-04-24 16:34 ` Andrew Lunn
@ 2025-04-24 16:49 ` Ivan Vecera
0 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 16:49 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 6:34 odp., Andrew Lunn wrote:
>> +++ b/drivers/mfd/zl3073x-regs.h
>> @@ -0,0 +1,74 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +
>> +#ifndef __ZL3073X_REGS_H
>> +#define __ZL3073X_REGS_H
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/bits.h>
>> +
>> +/*
>> + * Register address structure:
>> + * ===========================
>> + * 25 19 18 16 15 7 6 0
>> + * +-------------------------------------------+
>> + * | max_offset | width | page | page_offset |
>> + * +-------------------------------------------+
>> + *
>> + * page_offset ... <0x00..0x7F>
>> + * page .......... HW page number
>> + * size .......... register byte size (1, 2, 4 or 6)
>> + * max_offset .... maximal offset for indexed registers
>> + * (for non-indexed regs max_offset == page_offset)
>> + */
>
> Something i missed earlier. This does not really describe
> hardware. The upper half is meta data about the register, which you
> encode into the register number.
>
> How many other Linux drivers do you know about which does this?
This was proposed by Andy S.
Cite:
V4L2 (or media subsystem) solve the problem by providing a common
helpers for reading and writing tons of different registers in cameras.
See the commit 613cbb91e9ce ("media: Add MIPI CCI register access helper
functions").
They encode register address and size in register value. I have just
extend this approach to cover indexed registers. The max_offset is for
sanity during access to such registers, potential access out of
bounds is detected and error returned.
One can use just two simple functions for both register types:
zl3073x_read_reg(zldev, ZL_REG_NONIDX1, &value);
zl3073x_read_reg(zldev, ZL_REG_IDX1(idx), &value);
>
> Also width vs size.
I'm sorry, just a typo during reworking.
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 16:43 ` Andrew Lunn
@ 2025-04-24 17:10 ` Ivan Vecera
2025-04-24 19:10 ` Andrew Lunn
2025-04-24 19:18 ` Andrew Lunn
0 siblings, 2 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 17:10 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 6:43 odp., Andrew Lunn wrote:
>> +static int
>> +zl3073x_write_reg(struct zl3073x_dev *zldev, unsigned int reg, const void *val)
>> +{
>> + unsigned int len;
>> + u8 buf[6];
>> + int rc;
>> +
>> + /* Offset of the last item in the indexed register or offset of
>> + * the non-indexed register itself.
>> + */
>> + if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
>> + dev_err(zldev->dev, "Index of out range for reg 0x%04lx\n",
>> + ZL_REG_ADDR(reg));
>> + return -EINVAL;
>> + }
>> +
>> + len = ZL_REG_SIZE(reg);
>
> I suggested you add helpers for zl3073x_write_reg_u8(),
> zl3073x_write_reg_u16(), zl3073x_write_reg_32(), and
> zl3073x_write_reg_48(). The compiler will then do type checking for
> val, ensure what you pass is actually big enough.
>
> Here you have a void *val. You have no idea how big a value that
> pointer points to, and the compiler is not helping you.
During taking 613cbb91e9ce ("media: Add MIPI CCI register access helper
functions") approach I found they are using for these functions u64
regardless of register size... Just to accommodate the biggest
possible value. I know about weakness of 'void *' usage but u64 is not
also ideal as the caller is forced to pass always 8 bytes for reading
and forced to reserve 8 bytes for each read value on stack.
> I suggest you add the individual helpers. If you decided to keep the
> register meta data, you can validate the correct helper has been
> called.
Yes, this should be easily implemented, will follow this.
Anyway, still don't know what to do with mailboxes (aka multiple atomic
register operations). Lee seems to be against the placement of this
code in MFD parent driver.
Each sequence has to be protected by some lock and this lock needs to be
placed in MFD. Yes the routines for MB access can be for example in DPLL
driver but still the locks have to be inside MFD. So they have to be
exposed to sub-devices.
Thanks,
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 17:10 ` Ivan Vecera
@ 2025-04-24 19:10 ` Andrew Lunn
2025-04-24 19:26 ` Ivan Vecera
2025-04-24 19:18 ` Andrew Lunn
1 sibling, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 19:10 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
> Each sequence has to be protected by some lock and this lock needs to be
> placed in MFD. Yes the routines for MB access can be for example in DPLL
> driver but still the locks have to be inside MFD. So they have to be
> exposed to sub-devices.
The point of using MFD was gpio? Does the gpio driver need access to
the mailboxes? Does any other sub driver other than DPLL need to
access mailboxes?
The mutex needs to be shared, but that could be in the common data
structure.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 17:10 ` Ivan Vecera
2025-04-24 19:10 ` Andrew Lunn
@ 2025-04-24 19:18 ` Andrew Lunn
2025-04-24 19:53 ` Ivan Vecera
1 sibling, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 19:18 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
> During taking 613cbb91e9ce ("media: Add MIPI CCI register access helper
> functions") approach I found they are using for these functions u64
> regardless of register size... Just to accommodate the biggest
> possible value. I know about weakness of 'void *' usage but u64 is not
> also ideal as the caller is forced to pass always 8 bytes for reading
> and forced to reserve 8 bytes for each read value on stack.
In this device, how are the u48s used? Are they actually u48s, or are
they just u8[6], for example a MAC address? The network stack has lots
of functions like:
eth_hw_addr_set(struct net_device *dev, const u8 *addr)
and it is assumed that *addr is ETH_ALEN bytes in length. There is no
direct typing checking for this by the compiler, but the compiler is
getting smarter at checking for buffer overruns over function calls.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:10 ` Andrew Lunn
@ 2025-04-24 19:26 ` Ivan Vecera
2025-04-24 19:29 ` Andrew Lunn
0 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 19:26 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 9:10 odp., Andrew Lunn wrote:
>> Each sequence has to be protected by some lock and this lock needs to be
>> placed in MFD. Yes the routines for MB access can be for example in DPLL
>> driver but still the locks have to be inside MFD. So they have to be
>> exposed to sub-devices.
>
> The point of using MFD was gpio? Does the gpio driver need access to
> the mailboxes? Does any other sub driver other than DPLL need to
> access mailboxes?
Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for
some initial configuration.
> The mutex needs to be shared, but that could be in the common data
> structure.
Do you mean that sub-device would access mutexes placed in zl3073x_dev
which is parent (mfd) driver structure?
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:26 ` Ivan Vecera
@ 2025-04-24 19:29 ` Andrew Lunn
2025-04-24 19:58 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 19:29 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
> Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
> initial configuration.
O.K, so the mailbox code needs sharing. The question is, where do you
put it.
> > The mutex needs to be shared, but that could be in the common data
> > structure.
>
> Do you mean that sub-device would access mutexes placed in zl3073x_dev which
> is parent (mfd) driver structure?
Yes.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:18 ` Andrew Lunn
@ 2025-04-24 19:53 ` Ivan Vecera
2025-04-24 19:57 ` Andrew Lunn
0 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 19:53 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 9:18 odp., Andrew Lunn wrote:
>> During taking 613cbb91e9ce ("media: Add MIPI CCI register access helper
>> functions") approach I found they are using for these functions u64
>> regardless of register size... Just to accommodate the biggest
>> possible value. I know about weakness of 'void *' usage but u64 is not
>> also ideal as the caller is forced to pass always 8 bytes for reading
>> and forced to reserve 8 bytes for each read value on stack.
>
> In this device, how are the u48s used? Are they actually u48s, or are
> they just u8[6], for example a MAC address? The network stack has lots
> of functions like:
>
> eth_hw_addr_set(struct net_device *dev, const u8 *addr)
u48 registers always represent 48bit integer... they read from device
using bulk read as big-endian 48bit int. The same is valid also for u16
and u32.
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:53 ` Ivan Vecera
@ 2025-04-24 19:57 ` Andrew Lunn
2025-04-25 13:04 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2025-04-24 19:57 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On Thu, Apr 24, 2025 at 09:53:39PM +0200, Ivan Vecera wrote:
>
>
> On 24. 04. 25 9:18 odp., Andrew Lunn wrote:
> > > During taking 613cbb91e9ce ("media: Add MIPI CCI register access helper
> > > functions") approach I found they are using for these functions u64
> > > regardless of register size... Just to accommodate the biggest
> > > possible value. I know about weakness of 'void *' usage but u64 is not
> > > also ideal as the caller is forced to pass always 8 bytes for reading
> > > and forced to reserve 8 bytes for each read value on stack.
> >
> > In this device, how are the u48s used? Are they actually u48s, or are
> > they just u8[6], for example a MAC address? The network stack has lots
> > of functions like:
> >
> > eth_hw_addr_set(struct net_device *dev, const u8 *addr)
>
> u48 registers always represent 48bit integer... they read from device using
> bulk read as big-endian 48bit int. The same is valid also for u16
> and u32.
Then a u64 makes sense, plus on write to hardware a check the upper
bits are 0. These u48s are going to be stored in a u64 anyway, since C
does not have a u48 type.
But all the other types do exist in C, so you should use them and have
type checking.
Andrew
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:29 ` Andrew Lunn
@ 2025-04-24 19:58 ` Ivan Vecera
2025-04-25 6:55 ` Lee Jones
0 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-24 19:58 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 9:29 odp., Andrew Lunn wrote:
>> Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
>> initial configuration.
>
> O.K, so the mailbox code needs sharing. The question is, where do you
> put it.
This is crucial question... If I put the MB API into DPLL sub-driver
then PTP sub-driver will depend on it. Potential GPIO sub-driver as
well.
There could be some special library module to provide this for
sub-drivers but is this what we want? And if so where to put it?
>>> The mutex needs to be shared, but that could be in the common data
>>> structure.
>>
>> Do you mean that sub-device would access mutexes placed in zl3073x_dev which
>> is parent (mfd) driver structure?
>
> Yes.
So, some helper functions for taking and releasing lock... The v4
approach uses (will use) one mutex per mailbox type but one mutex for
MB access is also sufficient.
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support
2025-04-24 15:47 ` [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support Ivan Vecera
2025-04-24 16:34 ` Andrew Lunn
@ 2025-04-25 3:36 ` kernel test robot
1 sibling, 0 replies; 33+ messages in thread
From: kernel test robot @ 2025-04-25 3:36 UTC (permalink / raw)
To: Ivan Vecera, netdev
Cc: oe-kbuild-all, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Linux Memory Management List, Michal Schmidt, devicetree,
linux-kernel, linux-hardening
Hi Ivan,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Ivan-Vecera/dt-bindings-dpll-Add-DPLL-device-and-pin/20250424-235141
base: net-next/main
patch link: https://lore.kernel.org/r/20250424154722.534284-4-ivecera%40redhat.com
patch subject: [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support
reproduce: (https://download.01.org/0day-ci/archive/20250425/202504251112.NvSTD02Y-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504251112.NvSTD02Y-lkp@intel.com/
All warnings (new ones prefixed by >>):
Warning: Documentation/translations/ja_JP/process/submit-checklist.rst references a file that doesn't exist: Documentation/translations/ja_JP/SubmitChecklist
Warning: Documentation/translations/zh_CN/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
Warning: Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
Warning: Documentation/translations/zh_TW/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
Warning: Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
>> Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/dpll/microchip,zl3073x*.yaml
Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/leds/backlight/ti,lp8864.yaml
Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 984.
make[2]: *** [Documentation/Makefile:121: htmldocs] Error 255
make[1]: *** [Makefile:1804: htmldocs] Error 2
make: *** [Makefile:248: __sub-make] Error 2
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:58 ` Ivan Vecera
@ 2025-04-25 6:55 ` Lee Jones
2025-04-25 10:13 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Lee Jones @ 2025-04-25 6:55 UTC (permalink / raw)
To: Ivan Vecera
Cc: Andrew Lunn, netdev, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Prathosh Satish, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On Thu, 24 Apr 2025, Ivan Vecera wrote:
>
>
> On 24. 04. 25 9:29 odp., Andrew Lunn wrote:
> > > Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
> > > initial configuration.
> >
> > O.K, so the mailbox code needs sharing. The question is, where do you
> > put it.
>
> This is crucial question... If I put the MB API into DPLL sub-driver
> then PTP sub-driver will depend on it. Potential GPIO sub-driver as
> well.
>
> There could be some special library module to provide this for
> sub-drivers but is this what we want? And if so where to put it?
MFD is designed to take potentially large, monolithic devices and split
them up into smaller, more organised chunks, then Linusify them. This
way, area experts (subsystem maintainers) get to concern themselves only
with the remit to which they are most specialised / knowledgable. MFD
will handle how each of these areas are divided up and create all of the
shared resources for them. On the odd occasion it will also provide a
_small_ API that the children can use to talk to the parent device.
However .... some devices, like yours, demand an API which is too
complex to reside in the MFD subsystem itself. This is not the first
time this has happened and I doubt it will be the last. My first
recommendation is usually to place all of the comms in drivers/platform,
since, at least in my own mind, if a complex API is required, then the
device has become almost platform-like. There are lots of examples of
H/W comm APIs in there already for you to peruse.
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin
2025-04-24 15:47 ` [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin Ivan Vecera
@ 2025-04-25 7:39 ` Krzysztof Kozlowski
2025-04-25 9:36 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-25 7:39 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On Thu, Apr 24, 2025 at 05:47:15PM GMT, Ivan Vecera wrote:
> Add a common DT schema for DPLL device and its associated pins.
> The DPLL (device phase-locked loop) is a device used for precise clock
> synchronization in networking and telecom hardware.
>
> The device includes one or more DPLLs (channels) and one or more
> physical input/output pins.
>
> Each DPLL channel is used either to provide a pulse-per-clock signal or
> to drive an Ethernet equipment clock.
>
> The input and output pins have the following properties:
> * label: specifies board label
> * connection type: specifies its usage depending on wiring
> * list of supported or allowed frequencies: depending on how the pin
> is connected and where)
> * embedded sync capability: indicates whether the pin supports this
>
> Check:
This does not belong to commit msg. You do not add compile commands of C
files, do you?
Whatever you want to inform and is not relevant in the Git history
should be in changelog part.
> $ make dt_binding_check DT_SCHEMA_FILES=/dpll/
> SCHEMA Documentation/devicetree/bindings/processed-schema.json
> /home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
> CHKDT ./Documentation/devicetree/bindings
> LINT ./Documentation/devicetree/bindings
> DTEX Documentation/devicetree/bindings/dpll/dpll-pin.example.dts
> DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
> DTEX Documentation/devicetree/bindings/dpll/dpll-device.example.dts
> DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
> v3->v4:
> * dropped $Ref from dpll-pin reg property
> * added maxItems to dpll-pin reg property
> * fixed paragraph in dpll-pin desc
...
> +
> +properties:
> + $nodename:
> + pattern: "^dpll(@.*)?$"
> +
> + "#address-cells":
> + const: 0
> +
> + "#size-cells":
> + const: 0
> +
> + dpll-types:
> + description: List of DPLL channel types, one per DPLL instance.
> + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
> + items:
> + enum: [pps, eec]
Do channels have other properties as well in general?
> +
> + input-pins:
> + type: object
> + description: DPLL input pins
> + unevaluatedProperties: false
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family
2025-04-24 15:47 ` [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family Ivan Vecera
@ 2025-04-25 7:41 ` Krzysztof Kozlowski
2025-04-25 9:38 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-25 7:41 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On Thu, Apr 24, 2025 at 05:47:16PM GMT, Ivan Vecera wrote:
> Add DT bindings for Microchip Azurite DPLL chip family. These chips
> provide up to 5 independent DPLL channels, 10 differential or
> single-ended inputs and 10 differential or 20 single-ended outputs.
> They can be connected via I2C or SPI busses.
>
> Check:
> $ make dt_binding_check DT_SCHEMA_FILES=/dpll/
None of these commands belong to the commit msg. Look at all other
commits: do you see it anywhere?
> SCHEMA Documentation/devicetree/bindings/processed-schema.json
> /home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
> CHKDT ./Documentation/devicetree/bindings
> LINT ./Documentation/devicetree/bindings
> DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
> DTEX Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dts
> DTC [C] Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dtb
> DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
>
With above fixed:
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
<form letter>
This is an automated instruction, just in case, because many review tags
are being ignored. If you know the process, you can skip it (please do
not feel offended by me posting it here - no bad intentions intended).
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions of patchset, under or above your Signed-off-by tag, unless
patch changed significantly (e.g. new properties added to the DT
bindings). Tag is "received", when provided in a message replied to you
on the mailing list. Tools like b4 can help here. However, there's no
need to repost patches *only* to add the tags. The upstream maintainer
will do that for tags received on the version they apply.
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
</form letter>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin
2025-04-25 7:39 ` Krzysztof Kozlowski
@ 2025-04-25 9:36 ` Ivan Vecera
2025-04-25 9:40 ` Krzysztof Kozlowski
0 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-25 9:36 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 25. 04. 25 9:39 dop., Krzysztof Kozlowski wrote:
> On Thu, Apr 24, 2025 at 05:47:15PM GMT, Ivan Vecera wrote:
>> Add a common DT schema for DPLL device and its associated pins.
>> The DPLL (device phase-locked loop) is a device used for precise clock
>> synchronization in networking and telecom hardware.
>>
>> The device includes one or more DPLLs (channels) and one or more
>> physical input/output pins.
>>
>> Each DPLL channel is used either to provide a pulse-per-clock signal or
>> to drive an Ethernet equipment clock.
>>
>> The input and output pins have the following properties:
>> * label: specifies board label
>> * connection type: specifies its usage depending on wiring
>> * list of supported or allowed frequencies: depending on how the pin
>> is connected and where)
>> * embedded sync capability: indicates whether the pin supports this
>>
>> Check:
>
> This does not belong to commit msg. You do not add compile commands of C
> files, do you?
>
> Whatever you want to inform and is not relevant in the Git history
> should be in changelog part.
OK
>> $ make dt_binding_check DT_SCHEMA_FILES=/dpll/
>> SCHEMA Documentation/devicetree/bindings/processed-schema.json
>> /home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
>> CHKDT ./Documentation/devicetree/bindings
>> LINT ./Documentation/devicetree/bindings
>> DTEX Documentation/devicetree/bindings/dpll/dpll-pin.example.dts
>> DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
>> DTEX Documentation/devicetree/bindings/dpll/dpll-device.example.dts
>> DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
>>
>> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
>> ---
>> v3->v4:
>> * dropped $Ref from dpll-pin reg property
>> * added maxItems to dpll-pin reg property
>> * fixed paragraph in dpll-pin desc
>
> ...
>
>> +
>> +properties:
>> + $nodename:
>> + pattern: "^dpll(@.*)?$"
>> +
>> + "#address-cells":
>> + const: 0
>> +
>> + "#size-cells":
>> + const: 0
>> +
>> + dpll-types:
>> + description: List of DPLL channel types, one per DPLL instance.
>> + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
>> + items:
>> + enum: [pps, eec]
>
> Do channels have other properties as well in general?
No, other characteristics should be deducible either from compatible or
in runtime.
>> +
>> + input-pins:
>> + type: object
>> + description: DPLL input pins
>> + unevaluatedProperties: false
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family
2025-04-25 7:41 ` Krzysztof Kozlowski
@ 2025-04-25 9:38 ` Ivan Vecera
0 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-25 9:38 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 25. 04. 25 9:41 dop., Krzysztof Kozlowski wrote:
> On Thu, Apr 24, 2025 at 05:47:16PM GMT, Ivan Vecera wrote:
>> Add DT bindings for Microchip Azurite DPLL chip family. These chips
>> provide up to 5 independent DPLL channels, 10 differential or
>> single-ended inputs and 10 differential or 20 single-ended outputs.
>> They can be connected via I2C or SPI busses.
>>
>> Check:
>> $ make dt_binding_check DT_SCHEMA_FILES=/dpll/
>
> None of these commands belong to the commit msg. Look at all other
> commits: do you see it anywhere?
+1
>> SCHEMA Documentation/devicetree/bindings/processed-schema.json
>> /home/cera/devel/kernel/linux-2.6/Documentation/devicetree/bindings/net/snps,dwmac.yaml: mac-mode: missing type definition
>> CHKDT ./Documentation/devicetree/bindings
>> LINT ./Documentation/devicetree/bindings
>> DTC [C] Documentation/devicetree/bindings/dpll/dpll-pin.example.dtb
>> DTEX Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dts
>> DTC [C] Documentation/devicetree/bindings/dpll/microchip,zl30731.example.dtb
>> DTC [C] Documentation/devicetree/bindings/dpll/dpll-device.example.dtb
>>
>
> With above fixed:
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Thank you.
I.
> ---
>
> <form letter>
> This is an automated instruction, just in case, because many review tags
> are being ignored. If you know the process, you can skip it (please do
> not feel offended by me posting it here - no bad intentions intended).
> If you do not know the process, here is a short explanation:
>
> Please add Acked-by/Reviewed-by/Tested-by tags when posting new
> versions of patchset, under or above your Signed-off-by tag, unless
> patch changed significantly (e.g. new properties added to the DT
> bindings). Tag is "received", when provided in a message replied to you
> on the mailing list. Tools like b4 can help here. However, there's no
> need to repost patches *only* to add the tags. The upstream maintainer
> will do that for tags received on the version they apply.
>
> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
> </form letter>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin
2025-04-25 9:36 ` Ivan Vecera
@ 2025-04-25 9:40 ` Krzysztof Kozlowski
0 siblings, 0 replies; 33+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-25 9:40 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 25/04/2025 11:36, Ivan Vecera wrote:
>>> + const: 0
>>> +
>>> + dpll-types:
>>> + description: List of DPLL channel types, one per DPLL instance.
>>> + $ref: /schemas/types.yaml#/definitions/non-unique-string-array
>>> + items:
>>> + enum: [pps, eec]
>>
>> Do channels have other properties as well in general?
>
> No, other characteristics should be deducible either from compatible or
> in runtime.
>
OK, with fixes in commit msg:
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-25 6:55 ` Lee Jones
@ 2025-04-25 10:13 ` Ivan Vecera
2025-04-25 10:17 ` Lee Jones
0 siblings, 1 reply; 33+ messages in thread
From: Ivan Vecera @ 2025-04-25 10:13 UTC (permalink / raw)
To: Lee Jones
Cc: Andrew Lunn, netdev, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Prathosh Satish, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 25. 04. 25 8:55 dop., Lee Jones wrote:
> On Thu, 24 Apr 2025, Ivan Vecera wrote:
>
>>
>>
>> On 24. 04. 25 9:29 odp., Andrew Lunn wrote:
>>>> Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
>>>> initial configuration.
>>>
>>> O.K, so the mailbox code needs sharing. The question is, where do you
>>> put it.
>>
>> This is crucial question... If I put the MB API into DPLL sub-driver
>> then PTP sub-driver will depend on it. Potential GPIO sub-driver as
>> well.
>>
>> There could be some special library module to provide this for
>> sub-drivers but is this what we want? And if so where to put it?
>
> MFD is designed to take potentially large, monolithic devices and split
> them up into smaller, more organised chunks, then Linusify them. This
> way, area experts (subsystem maintainers) get to concern themselves only
> with the remit to which they are most specialised / knowledgable. MFD
> will handle how each of these areas are divided up and create all of the
> shared resources for them. On the odd occasion it will also provide a
> _small_ API that the children can use to talk to the parent device.
>
> However .... some devices, like yours, demand an API which is too
> complex to reside in the MFD subsystem itself. This is not the first
> time this has happened and I doubt it will be the last. My first
> recommendation is usually to place all of the comms in drivers/platform,
> since, at least in my own mind, if a complex API is required, then the
> device has become almost platform-like. There are lots of examples of
> H/W comm APIs in there already for you to peruse.
OK, I will do it differently... Will drop MB API at all from MFD and
just expose the additional mutex from MFD for multi-op access.
Mailboxes will be handled directly by sub-devices.
Short description:
MFD exposes:
zl3073x_{read,write}_u{8,16,32,48}() & zl3073x_poll_u8()
- to read/write/poll registers
- they checks that multiop_lock is taken when caller is accessing
registers from Page 10 and above
zl3073x_multiop_{lock,unlock}()
- to protect operation where multiple reads, writes and poll is required
to be done atomically
Is this OK for you?
Thanks,
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-25 10:13 ` Ivan Vecera
@ 2025-04-25 10:17 ` Lee Jones
2025-04-25 10:29 ` Ivan Vecera
0 siblings, 1 reply; 33+ messages in thread
From: Lee Jones @ 2025-04-25 10:17 UTC (permalink / raw)
To: Ivan Vecera
Cc: Andrew Lunn, netdev, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Prathosh Satish, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On Fri, 25 Apr 2025, Ivan Vecera wrote:
>
>
> On 25. 04. 25 8:55 dop., Lee Jones wrote:
> > On Thu, 24 Apr 2025, Ivan Vecera wrote:
> >
> > >
> > >
> > > On 24. 04. 25 9:29 odp., Andrew Lunn wrote:
> > > > > Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
> > > > > initial configuration.
> > > >
> > > > O.K, so the mailbox code needs sharing. The question is, where do you
> > > > put it.
> > >
> > > This is crucial question... If I put the MB API into DPLL sub-driver
> > > then PTP sub-driver will depend on it. Potential GPIO sub-driver as
> > > well.
> > >
> > > There could be some special library module to provide this for
> > > sub-drivers but is this what we want? And if so where to put it?
> >
> > MFD is designed to take potentially large, monolithic devices and split
> > them up into smaller, more organised chunks, then Linusify them. This
> > way, area experts (subsystem maintainers) get to concern themselves only
> > with the remit to which they are most specialised / knowledgable. MFD
> > will handle how each of these areas are divided up and create all of the
> > shared resources for them. On the odd occasion it will also provide a
> > _small_ API that the children can use to talk to the parent device.
> >
> > However .... some devices, like yours, demand an API which is too
> > complex to reside in the MFD subsystem itself. This is not the first
> > time this has happened and I doubt it will be the last. My first
> > recommendation is usually to place all of the comms in drivers/platform,
> > since, at least in my own mind, if a complex API is required, then the
> > device has become almost platform-like. There are lots of examples of
> > H/W comm APIs in there already for you to peruse.
>
> OK, I will do it differently... Will drop MB API at all from MFD and
> just expose the additional mutex from MFD for multi-op access.
> Mailboxes will be handled directly by sub-devices.
>
> Short description:
> MFD exposes:
> zl3073x_{read,write}_u{8,16,32,48}() & zl3073x_poll_u8()
> - to read/write/poll registers
> - they checks that multiop_lock is taken when caller is accessing
> registers from Page 10 and above
>
> zl3073x_multiop_{lock,unlock}()
> - to protect operation where multiple reads, writes and poll is required
> to be done atomically
Looks sensible. If this is aligned with the discussions that have been
taking place between you and Andrew. Let's see the code before we make
any binding agreements. =:)
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-25 10:17 ` Lee Jones
@ 2025-04-25 10:29 ` Ivan Vecera
0 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-25 10:29 UTC (permalink / raw)
To: Lee Jones
Cc: Andrew Lunn, netdev, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Prathosh Satish, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 25. 04. 25 12:17 odp., Lee Jones wrote:
> On Fri, 25 Apr 2025, Ivan Vecera wrote:
>
>>
>>
>> On 25. 04. 25 8:55 dop., Lee Jones wrote:
>>> On Thu, 24 Apr 2025, Ivan Vecera wrote:
>>>
>>>>
>>>>
>>>> On 24. 04. 25 9:29 odp., Andrew Lunn wrote:
>>>>>> Yes, PHC (PTP) sub-driver is using mailboxes as well. Gpio as well for some
>>>>>> initial configuration.
>>>>>
>>>>> O.K, so the mailbox code needs sharing. The question is, where do you
>>>>> put it.
>>>>
>>>> This is crucial question... If I put the MB API into DPLL sub-driver
>>>> then PTP sub-driver will depend on it. Potential GPIO sub-driver as
>>>> well.
>>>>
>>>> There could be some special library module to provide this for
>>>> sub-drivers but is this what we want? And if so where to put it?
>>>
>>> MFD is designed to take potentially large, monolithic devices and split
>>> them up into smaller, more organised chunks, then Linusify them. This
>>> way, area experts (subsystem maintainers) get to concern themselves only
>>> with the remit to which they are most specialised / knowledgable. MFD
>>> will handle how each of these areas are divided up and create all of the
>>> shared resources for them. On the odd occasion it will also provide a
>>> _small_ API that the children can use to talk to the parent device.
>>>
>>> However .... some devices, like yours, demand an API which is too
>>> complex to reside in the MFD subsystem itself. This is not the first
>>> time this has happened and I doubt it will be the last. My first
>>> recommendation is usually to place all of the comms in drivers/platform,
>>> since, at least in my own mind, if a complex API is required, then the
>>> device has become almost platform-like. There are lots of examples of
>>> H/W comm APIs in there already for you to peruse.
>>
>> OK, I will do it differently... Will drop MB API at all from MFD and
>> just expose the additional mutex from MFD for multi-op access.
>> Mailboxes will be handled directly by sub-devices.
>>
>> Short description:
>> MFD exposes:
>> zl3073x_{read,write}_u{8,16,32,48}() & zl3073x_poll_u8()
>> - to read/write/poll registers
>> - they checks that multiop_lock is taken when caller is accessing
>> registers from Page 10 and above
>>
>> zl3073x_multiop_{lock,unlock}()
>> - to protect operation where multiple reads, writes and poll is required
>> to be done atomically
Or maybe just define zl3073x_dev.multiop_lock and allow callers to use
guard(mutex)(zldev->multiop_lock)
--or--
scoped_guard(mutex)(zldev_multiop_lock) {
...
}
> Looks sensible. If this is aligned with the discussions that have been
> taking place between you and Andrew. Let's see the code before we make
> any binding agreements. =:)
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes
2025-04-24 19:57 ` Andrew Lunn
@ 2025-04-25 13:04 ` Ivan Vecera
0 siblings, 0 replies; 33+ messages in thread
From: Ivan Vecera @ 2025-04-25 13:04 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Vadim Fedorenko, Arkadiusz Kubalewski, Jiri Pirko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Prathosh Satish,
Lee Jones, Kees Cook, Andy Shevchenko, Andrew Morton,
Michal Schmidt, devicetree, linux-kernel, linux-hardening
On 24. 04. 25 9:57 odp., Andrew Lunn wrote:
> On Thu, Apr 24, 2025 at 09:53:39PM +0200, Ivan Vecera wrote:
>>
>>
>> On 24. 04. 25 9:18 odp., Andrew Lunn wrote:
>>>> During taking 613cbb91e9ce ("media: Add MIPI CCI register access helper
>>>> functions") approach I found they are using for these functions u64
>>>> regardless of register size... Just to accommodate the biggest
>>>> possible value. I know about weakness of 'void *' usage but u64 is not
>>>> also ideal as the caller is forced to pass always 8 bytes for reading
>>>> and forced to reserve 8 bytes for each read value on stack.
>>>
>>> In this device, how are the u48s used? Are they actually u48s, or are
>>> they just u8[6], for example a MAC address? The network stack has lots
>>> of functions like:
>>>
>>> eth_hw_addr_set(struct net_device *dev, const u8 *addr)
>>
>> u48 registers always represent 48bit integer... they read from device using
>> bulk read as big-endian 48bit int. The same is valid also for u16
>> and u32.
>
> Then a u64 makes sense, plus on write to hardware a check the upper
> bits are 0. These u48s are going to be stored in a u64 anyway, since C
> does not have a u48 type.
Just note that some of 48bit registers uses signed values so the check
should be:
x is in <S48_MIN, U48_MAX>
this could be done using bit operations:
(!(GENMASK_ULL(63, 49) & ((u64)(x) + BIT_ULL(47))))
Ivan
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2025-04-25 13:04 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-24 15:47 [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 1/8] dt-bindings: dpll: Add DPLL device and pin Ivan Vecera
2025-04-25 7:39 ` Krzysztof Kozlowski
2025-04-25 9:36 ` Ivan Vecera
2025-04-25 9:40 ` Krzysztof Kozlowski
2025-04-24 15:47 ` [PATCH net-next v4 2/8] dt-bindings: dpll: Add support for Microchip Azurite chip family Ivan Vecera
2025-04-25 7:41 ` Krzysztof Kozlowski
2025-04-25 9:38 ` Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 3/8] mfd: Add Microchip ZL3073x support Ivan Vecera
2025-04-24 16:34 ` Andrew Lunn
2025-04-24 16:49 ` Ivan Vecera
2025-04-25 3:36 ` kernel test robot
2025-04-24 15:47 ` [PATCH net-next v4 4/8] mfd: zl3073x: Add support for devlink device info Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 5/8] mfd: zl3073x: Add functions to work with register mailboxes Ivan Vecera
2025-04-24 16:43 ` Andrew Lunn
2025-04-24 17:10 ` Ivan Vecera
2025-04-24 19:10 ` Andrew Lunn
2025-04-24 19:26 ` Ivan Vecera
2025-04-24 19:29 ` Andrew Lunn
2025-04-24 19:58 ` Ivan Vecera
2025-04-25 6:55 ` Lee Jones
2025-04-25 10:13 ` Ivan Vecera
2025-04-25 10:17 ` Lee Jones
2025-04-25 10:29 ` Ivan Vecera
2025-04-24 19:18 ` Andrew Lunn
2025-04-24 19:53 ` Ivan Vecera
2025-04-24 19:57 ` Andrew Lunn
2025-04-25 13:04 ` Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 6/8] mfd: zl3073x: Fetch invariants during probe Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 7/8] mfd: zl3073x: Add clock_id field Ivan Vecera
2025-04-24 15:47 ` [PATCH net-next v4 8/8] mfd: zl3073x: Register DPLL sub-device during init Ivan Vecera
2025-04-24 15:51 ` [PATCH net-next v4 0/8] Add Microchip ZL3073x support (part 1) Lee Jones
2025-04-24 16:29 ` Ivan Vecera
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).