All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver
@ 2022-10-06 13:57 Biju Das
  2022-10-06 13:57 ` [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings Biju Das
                   ` (3 more replies)
  0 siblings, 4 replies; 23+ messages in thread
From: Biju Das @ 2022-10-06 13:57 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, William Breathitt Gray, Thierry Reding
  Cc: Biju Das, Lee Jones, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in
the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
channels and one 32-bit timer channel. It supports the following
functions
 - Counter
 - Timer
 - PWM

This patch series aim to add MFD and pwm driver for MTU3a.

The 8/16/32 bit registers are mixed in each channel. The HW
specifications of the IP is described in patch#1.

Current patch set is tested for PWM mode1 on MTU3 channel
and 16 and 32 bit phase counting modes.

v2->v3:
 * Dropped counter bindings and integrated with mfd as it has only one property.
 * Removed "#address-cells" and "#size-cells" as it do not have children with
   unit addresses.
 * Removed quotes from counter and pwm.
 * Provided full path for pwm bindings.
 * Updated the binding example.
 * removed unwanted header files
 * Added LUT for 32 bit registers as it needed for 32-bit cascade counting.
 * Exported 32 bit read/write functions.
 * Modelled as a counter device supporting 3 counters(2 16-bit and 
   32-bit)
 * Add kernel-doc comments to document struct rz_mtu3_cnt
 * Removed mmio variable from struct rz_mtu3_cnt
 * Removed cnt local variable from rz_mtu3_count_read()
 * Replaced -EINVAL->-ERANGE for out of range error conditions.
 * Removed explicit cast from write functions.
 * Removed local variable val from rz_mtu3_count_ceiling_read()
 * Added lock for RMW for counter/ceiling updates.
 * Added different synapses for counter0 and counter{1,2}
 * Used ARRAY for assigning num_counts.
 * Added PM runtime for managing clocks.
 * Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.

RFC->v2:
 * replaced devm_reset_control_get->devm_reset_control_get_exclusive
 * Dropped 'bindings' from the binding title
 * Updated the binding example
 * Added additionalProperties: false for counter bindings
 * Squashed all the binding patches
 * Modelled as a single counter device providing both 16-bit
   and 32-bit phase counting modes
 * Modelled as a single pwm device for supporting different pwm modes.
 * Moved counter and pwm bindings to respective subsystems.

Biju Das (4):
  dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  mfd: Add RZ/G2L MTU3 driver
  pwm: Add support for RZ/G2L MTU3 PWM
  counter: Add RZ/G2L MTU3 counter driver

 .../bindings/mfd/renesas,rz-mtu3.yaml         | 304 ++++++++++
 .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 ++
 drivers/counter/Kconfig                       |   9 +
 drivers/counter/Makefile                      |   1 +
 drivers/counter/rz-mtu3-cnt.c                 | 568 ++++++++++++++++++
 drivers/mfd/Kconfig                           |   9 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/rz-mtu3.c                         | 436 ++++++++++++++
 drivers/pwm/Kconfig                           |  11 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-rz-mtu3.c                     | 462 ++++++++++++++
 include/linux/mfd/rz-mtu3.h                   | 183 ++++++
 12 files changed, 2035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
 create mode 100644 Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
 create mode 100644 drivers/counter/rz-mtu3-cnt.c
 create mode 100644 drivers/mfd/rz-mtu3.c
 create mode 100644 drivers/pwm/pwm-rz-mtu3.c
 create mode 100644 include/linux/mfd/rz-mtu3.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-06 13:57 [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver Biju Das
@ 2022-10-06 13:57 ` Biju Das
  2022-10-06 20:17   ` Rob Herring
  2022-10-06 13:57 ` [PATCH v3 2/4] mfd: Add RZ/G2L MTU3 driver Biju Das
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 23+ messages in thread
From: Biju Das @ 2022-10-06 13:57 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, William Breathitt Gray, Thierry Reding
  Cc: Biju Das, Lee Jones, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in
the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
channels and one 32-bit timer channel. It supports the following
functions
 - Counter
 - Timer
 - PWM

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v2->v3:
 * Dropped counter bindings and integrated with mfd as it has only one property.
 * Removed "#address-cells" and "#size-cells" as it do not have children with
   unit addresses.
 * Removed quotes from counter and pwm.
 * Provided full path for pwm bindings.
 * Updated the example.
v1->v2:
 * Modelled counter and pwm as a single device that handles
   multiple channels.
 * Moved counter and pwm bindings to respective subsystems
 * Dropped 'bindings' from MFD binding title.
 * Updated the example
 * Changed the compatible names.
---
 .../bindings/mfd/renesas,rz-mtu3.yaml         | 304 ++++++++++++++++++
 .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
 2 files changed, 354 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
 create mode 100644 Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml

diff --git a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
new file mode 100644
index 000000000000..44c952ad8d35
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
@@ -0,0 +1,304 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/renesas,rz-mtu3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
+
+maintainers:
+  - Biju Das <biju.das.jz@bp.renesas.com>
+
+description: |
+  This hardware block pconsisting of eight 16-bit timer channels and one
+  32- bit timer channel. It supports the following specifications:
+    - Pulse input/output: 28 lines max.
+    - Pulse input 3 lines
+    - Count clock 11 clocks for each channel (14 clocks for MTU0, 12 clocks
+      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2 combination
+      (when LWA = 1))
+    - Operating frequency Up to 100 MHz
+    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
+        - Waveform output on compare match
+        - Input capture function (noise filter setting available)
+        - Counter-clearing operation
+        - Simultaneous writing to multiple timer counters (TCNT)
+          (excluding MTU8).
+        - Simultaneous clearing on compare match or input capture
+          (excluding MTU8).
+        - Simultaneous input and output to registers in synchronization with
+          counter operations           (excluding MTU8).
+        - Up to 12-phase PWM output in combination with synchronous operation
+          (excluding MTU8)
+    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
+        - Buffer operation specifiable
+    - [MTU1, MTU2]
+        - Phase counting mode can be specified independently
+        - 32-bit phase counting mode can be specified for interlocked operation
+          of MTU1 and MTU2 (when TMDR3.LWA = 1)
+        - Cascade connection operation available
+    - [MTU3, MTU4, MTU6, and MTU7]
+        - Through interlocked operation of MTU3/4 and MTU6/7, the positive and
+          negative signals in six phases (12 phases in total) can be output in
+          complementary PWM and reset-synchronized PWM operation.
+        - In complementary PWM mode, values can be transferred from buffer
+          registers to temporary registers at crests and troughs of the timer-
+          counter values or when the buffer registers (TGRD registers in MTU4
+          and MTU7) are written to.
+        - Double-buffering selectable in complementary PWM mode.
+    - [MTU3 and MTU4]
+        - Through interlocking with MTU0, a mode for driving AC synchronous
+          motors (brushless DC motors) by using complementary PWM output and
+          reset-synchronized PWM output is settable and allows the selection
+          of two types of waveform output (chopping or level).
+    - [MTU5]
+        - Capable of operation as a dead-time compensation counter.
+    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
+        - 32-bit phase counting mode specifiable by combining MTU1 and MTU2 and
+          through interlocked operation with MTU0/MTU5 and MTU8.
+    - Interrupt-skipping function
+        - In complementary PWM mode, interrupts on crests and troughs of counter
+          values and triggers to start conversion by the A/D converter can be
+          skipped.
+    - Interrupt sources: 43 sources.
+    - Buffer operation:
+        - Automatic transfer of register data (transfer from the buffer
+          register to the timer register).
+    - Trigger generation
+        - A/D converter start triggers can be generated
+        - A/D converter start request delaying function enables A/D converter
+          to be started with any desired timing and to be synchronized with
+          PWM output.
+    - Low power consumption function
+        - The MTU3a can be placed in the module-stop state.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
+          - renesas,r9a07g054-mtu3  # RZ/V2L
+      - const: renesas,rz-mtu3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: MTU0.TGRA input capture/compare match
+      - description: MTU0.TGRB input capture/compare match
+      - description: MTU0.TGRC input capture/compare match
+      - description: MTU0.TGRD input capture/compare match
+      - description: MTU0.TCNT overflow
+      - description: MTU0.TGRE compare match
+      - description: MTU0.TGRF compare match
+      - description: MTU1.TGRA input capture/compare match
+      - description: MTU1.TGRB input capture/compare match
+      - description: MTU1.TCNT overflow
+      - description: MTU1.TCNT underflow
+      - description: MTU2.TGRA input capture/compare match
+      - description: MTU2.TGRB input capture/compare match
+      - description: MTU2.TCNT overflow
+      - description: MTU2.TCNT underflow
+      - description: MTU3.TGRA input capture/compare match
+      - description: MTU3.TGRB input capture/compare match
+      - description: MTU3.TGRC input capture/compare match
+      - description: MTU3.TGRD input capture/compare match
+      - description: MTU3.TCNT overflow
+      - description: MTU4.TGRA input capture/compare match
+      - description: MTU4.TGRB input capture/compare match
+      - description: MTU4.TGRC input capture/compare match
+      - description: MTU4.TGRD input capture/compare match
+      - description: MTU4.TCNT overflow/underflow
+      - description: MTU5.TGRU input capture/compare match
+      - description: MTU5.TGRV input capture/compare match
+      - description: MTU5.TGRW input capture/compare match
+      - description: MTU6.TGRA input capture/compare match
+      - description: MTU6.TGRB input capture/compare match
+      - description: MTU6.TGRC input capture/compare match
+      - description: MTU6.TGRD input capture/compare match
+      - description: MTU6.TCNT overflow
+      - description: MTU7.TGRA input capture/compare match
+      - description: MTU7.TGRB input capture/compare match
+      - description: MTU7.TGRC input capture/compare match
+      - description: MTU7.TGRD input capture/compare match
+      - description: MTU7.TCNT overflow/underflow
+      - description: MTU8.TGRA input capture/compare match
+      - description: MTU8.TGRB input capture/compare match
+      - description: MTU8.TGRC input capture/compare match
+      - description: MTU8.TGRD input capture/compare match
+      - description: MTU8.TCNT overflow
+      - description: MTU8.TCNT underflow
+
+  interrupt-names:
+    items:
+      - const: tgia0
+      - const: tgib0
+      - const: tgic0
+      - const: tgid0
+      - const: tgiv0
+      - const: tgie0
+      - const: tgif0
+      - const: tgia1
+      - const: tgib1
+      - const: tgiv1
+      - const: tgiu1
+      - const: tgia2
+      - const: tgib2
+      - const: tgiv2
+      - const: tgiu2
+      - const: tgia3
+      - const: tgib3
+      - const: tgic3
+      - const: tgid3
+      - const: tgiv3
+      - const: tgia4
+      - const: tgib4
+      - const: tgic4
+      - const: tgid4
+      - const: tgiv4
+      - const: tgiu5
+      - const: tgiv5
+      - const: tgiw5
+      - const: tgia6
+      - const: tgib6
+      - const: tgic6
+      - const: tgid6
+      - const: tgiv6
+      - const: tgia7
+      - const: tgib7
+      - const: tgic7
+      - const: tgid7
+      - const: tgiv7
+      - const: tgia8
+      - const: tgib8
+      - const: tgic8
+      - const: tgid8
+      - const: tgiv8
+      - const: tgiu8
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  counter:
+    description:
+      There are two phase counting modes. 16-bit phase counting mode in which
+      MTU1 and MTU2 operate independently, and cascade connection 32-bit phase
+      counting mode in which MTU1 and MTU2 are cascaded.
+
+      In phase counting mode, the phase difference between two external input
+      clocks is detected and the corresponding TCNT is incremented or
+      decremented.
+      The below counters are supported
+        count0 - MTU1 16-bit phase counting
+        count1 - MTU2 16-bit phase counting
+        count2 - MTU1+ MTU2 32-bit phase counting
+
+    type: object
+
+    properties:
+      compatible:
+        const: renesas,rz-mtu3-counter
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  pwm:
+    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - clocks
+  - power-domains
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r9a07g044-cpg.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    mtu3: timer@10001200 {
+      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
+      reg = <0x10001200 0xb00>;
+      interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
+                   <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
+      interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0",
+                        "tgif0",
+                        "tgia1", "tgib1", "tgiv1", "tgiu1",
+                        "tgia2", "tgib2", "tgiv2", "tgiu2",
+                        "tgia3", "tgib3", "tgic3", "tgid3", "tgiv3",
+                        "tgia4", "tgib4", "tgic4", "tgid4", "tgiv4",
+                        "tgiu5", "tgiv5", "tgiw5",
+                        "tgia6", "tgib6", "tgic6", "tgid6", "tgiv6",
+                        "tgia7", "tgib7", "tgic7", "tgid7", "tgiv7",
+                        "tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8";
+      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
+      power-domains = <&cpg>;
+      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
+
+      counter {
+        compatible = "renesas,rz-mtu3-counter";
+      };
+
+      pwm {
+        compatible = "renesas,rz-mtu3-pwm";
+        #pwm-cells = <2>;
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml b/Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
new file mode 100644
index 000000000000..29d7d0fdf7f2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/renesas,rz-mtu3-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM driver for the RZ/G2L multi-function timer pulse unit 3 (MTU3a)
+
+maintainers:
+  - Biju Das <biju.das.jz@bp.renesas.com>
+
+description: |
+  This module is part of the RZ/G2L MTU3a multi-function device. For more
+  details see ../mfd/renesas,rz-mtu3.yaml.
+
+  The module supports PWM mode{1,2}, Reset-synchronized PWM mode and
+  complementary PWM mode{1,2,3}.
+
+  In complementary PWM mode, six positive-phase and six negative-phase PWM
+  waveforms (12 phases in total) with dead time can be output by
+  combining MTU{3,4} and MTU{6,7}.
+
+  The pwm channels corresponding to each hardware channels.
+  0  - MTU0.MTIOC0A PWM mode 1
+  1  - MTU0.MTIOC0C PWM mode 1
+  2  - MTU1.MTIOC1A PWM mode 1
+  3  - MTU2.MTIOC2A PWM mode 1
+  4  - MTU3.MTIOC3A PWM mode 1
+  5  - MTU3.MTIOC3C PWM mode 1
+  6  - MTU4.MTIOC4A PWM mode 1
+  7  - MTU4.MTIOC4C PWM mode 1
+  8  - MTU6.MTIOC6A PWM mode 1
+  9  - MTU6.MTIOC6C PWM mode 1
+  10 - MTU7.MTIOC7A PWM mode 1
+  11 - MTU7.MTIOC7C PWM mode 1
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    const: renesas,rz-mtu3-pwm
+
+  "#pwm-cells":
+    const: 2
+
+required:
+  - compatible
+
+additionalProperties: false
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 2/4] mfd: Add RZ/G2L MTU3 driver
  2022-10-06 13:57 [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver Biju Das
  2022-10-06 13:57 ` [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings Biju Das
@ 2022-10-06 13:57 ` Biju Das
  2022-10-06 13:57 ` [PATCH v3 3/4] pwm: Add support for RZ/G2L MTU3 PWM Biju Das
  2022-10-06 13:57 ` [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver Biju Das
  3 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-06 13:57 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Biju Das, Lee Jones, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Add RZ/G2L MTU3 MFD driver.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v2->v3:
 * removed unwanted header files
 * Added LUT for 32 bit registers as it needed for 32-bit cascade counting.
 * Exported 32 bit read/write functions.
v1->v2:
 * Changed the compatible name
 * Replaced devm_reset_control_get->devm_reset_control_get_exclusive
 * Renamed function names rzg2l_mtu3->rz_mtu3 as this is generic IP
   in RZ family SoC's.
---
 drivers/mfd/Kconfig         |   9 +
 drivers/mfd/Makefile        |   1 +
 drivers/mfd/rz-mtu3.c       | 436 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/rz-mtu3.h | 183 +++++++++++++++
 4 files changed, 629 insertions(+)
 create mode 100644 drivers/mfd/rz-mtu3.c
 create mode 100644 include/linux/mfd/rz-mtu3.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index abb58ab1a1a4..eec3ff5b9357 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1974,6 +1974,15 @@ config MFD_ROHM_BD957XMUF
 	  BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily
 	  designed to be used to power R-Car series processors.
 
+config MFD_RZ_MTU3
+	tristate "Support for RZ/G2L Multi-Function Timer Pulse Unit 3 MTU3a"
+	depends on (ARCH_RZG2L && OF) || COMPILE_TEST
+	select MFD_CORE
+	help
+	  Select this option to enable RZ/G2L MTU3 timers driver used
+	  for PWM, Clock Source, Clock event and Counter. This driver allow to
+	  share the registers between the others drivers.
+
 config MFD_STM32_LPTIMER
 	tristate "Support for STM32 Low-Power Timer"
 	depends on (ARCH_STM32 && OF) || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 858cacf659d6..dc10877fa48c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -251,6 +251,7 @@ obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
 obj-$(CONFIG_MFD_STPMIC1)	+= stpmic1.o
 obj-$(CONFIG_MFD_SUN4I_GPADC)	+= sun4i-gpadc.o
 
+obj-$(CONFIG_MFD_RZ_MTU3) 	+= rz-mtu3.o
 obj-$(CONFIG_MFD_STM32_LPTIMER)	+= stm32-lptimer.o
 obj-$(CONFIG_MFD_STM32_TIMERS) 	+= stm32-timers.o
 obj-$(CONFIG_MFD_MXS_LRADC)     += mxs-lradc.o
diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c
new file mode 100644
index 000000000000..14e55c382896
--- /dev/null
+++ b/drivers/mfd/rz-mtu3.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 - MTU3a
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/mfd/rz-mtu3.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = {
+	{
+		[RZ_MTU3_TIER] = 0x4, [RZ_MTU3_NFCR] = 0x70,
+		[RZ_MTU3_TCR] = 0x0, [RZ_MTU3_TCR2] = 0x28,
+		[RZ_MTU3_TMDR1] = 0x1, [RZ_MTU3_TIORH] = 0x2,
+		[RZ_MTU3_TIORL] = 0x3
+	},
+	{
+		[RZ_MTU3_TIER] = 0x4, [RZ_MTU3_NFCR] = 0xef,
+		[RZ_MTU3_TSR] = 0x5, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0x14, [RZ_MTU3_TMDR1] = 0x1,
+		[RZ_MTU3_TIOR] = 0x2
+	},
+	{
+		[RZ_MTU3_TIER] = 0x4, [RZ_MTU3_NFCR] = 0x16e,
+		[RZ_MTU3_TSR] = 0x5, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0xc, [RZ_MTU3_TMDR1] = 0x1,
+		[RZ_MTU3_TIOR] = 0x2
+	},
+	{
+		[RZ_MTU3_TIER] = 0x8, [RZ_MTU3_NFCR] = 0x93,
+		[RZ_MTU3_TSR] = 0x2c, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0x4c, [RZ_MTU3_TMDR1] = 0x2,
+		[RZ_MTU3_TIORH] = 0x4, [RZ_MTU3_TIORL] = 0x5,
+		[RZ_MTU3_TBTM] = 0x38
+	},
+	{
+		[RZ_MTU3_TIER] = 0x8, [RZ_MTU3_NFCR] = 0x93,
+		[RZ_MTU3_TSR] = 0x2c, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0x4c, [RZ_MTU3_TMDR1] = 0x2,
+		[RZ_MTU3_TIORH] = 0x5, [RZ_MTU3_TIORL] = 0x6,
+		[RZ_MTU3_TBTM] = 0x38
+	},
+	{
+		[RZ_MTU3_TIER] = 0x32, [RZ_MTU3_NFCR] = 0x1eb,
+		[RZ_MTU3_TSTR] = 0x34, [RZ_MTU3_TCNTCMPCLR] = 0x36,
+		[RZ_MTU3_TCRU] = 0x4, [RZ_MTU3_TCR2U] = 0x5,
+		[RZ_MTU3_TIORU] = 0x6, [RZ_MTU3_TCRV] = 0x14,
+		[RZ_MTU3_TCR2V] = 0x15, [RZ_MTU3_TIORV] = 0x16,
+		[RZ_MTU3_TCRW] = 0x24, [RZ_MTU3_TCR2W] = 0x25,
+		[RZ_MTU3_TIORW] = 0x26
+	},
+	{
+		[RZ_MTU3_TIER] = 0x8, [RZ_MTU3_NFCR] = 0x93,
+		[RZ_MTU3_TSR] = 0x2c, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0x4c, [RZ_MTU3_TMDR1] = 0x2,
+		[RZ_MTU3_TIORH] = 0x4, [RZ_MTU3_TIORL] = 0x5,
+		[RZ_MTU3_TBTM] = 0x38
+	},
+	{
+		[RZ_MTU3_TIER] = 0x8, [RZ_MTU3_NFCR] = 0x93,
+		[RZ_MTU3_TSR] = 0x2c, [RZ_MTU3_TCR] = 0x0,
+		[RZ_MTU3_TCR2] = 0x4c, [RZ_MTU3_TMDR1] = 0x2,
+		[RZ_MTU3_TIORH] = 0x5, [RZ_MTU3_TIORL] = 0x6,
+		[RZ_MTU3_TBTM] = 0x38
+	},
+	{
+		[RZ_MTU3_TIER] = 0x4, [RZ_MTU3_NFCR] = 0x368,
+		[RZ_MTU3_TCR] = 0x0, [RZ_MTU3_TCR2] = 0x6,
+		[RZ_MTU3_TMDR1] = 0x1, [RZ_MTU3_TIORH] = 0x2,
+		[RZ_MTU3_TIORL] = 0x3
+	}
+};
+
+static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = {
+	{
+		[RZ_MTU3_TCNT] = 0x6, [RZ_MTU3_TGRA] = 0x8,
+		[RZ_MTU3_TGRB] = 0xa, [RZ_MTU3_TGRC] = 0xc,
+		[RZ_MTU3_TGRD] = 0xe, [RZ_MTU3_TGRE] = 0x20,
+		[RZ_MTU3_TGRF] = 0x22
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x6, [RZ_MTU3_TGRA] = 0x8,
+		[RZ_MTU3_TGRB] = 0xa
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x6, [RZ_MTU3_TGRA] = 0x8,
+		[RZ_MTU3_TGRB] = 0xa
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x10, [RZ_MTU3_TGRA] = 0x18,
+		[RZ_MTU3_TGRB] = 0x1a, [RZ_MTU3_TGRC] = 0x24,
+		[RZ_MTU3_TGRD] = 0x26, [RZ_MTU3_TGRE] = 0x72
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x11, [RZ_MTU3_TGRA] = 0x1b,
+		[RZ_MTU3_TGRB] = 0x1d, [RZ_MTU3_TGRC] = 0x27,
+		[RZ_MTU3_TGRD] = 0x29, [RZ_MTU3_TGRE] = 0x73,
+		[RZ_MTU3_TGRF] = 0x75, [RZ_MTU3_TADCR] = 0x3f,
+		[RZ_MTU3_TADCORA] = 0x43, [RZ_MTU3_TADCORB] = 0x45,
+		[RZ_MTU3_TADCOBRA] = 0x47,
+		[RZ_MTU3_TADCOBRB] = 0x49
+	},
+	{
+		[RZ_MTU3_TCNTU] = 0x0, [RZ_MTU3_TGRU] = 0x2,
+		[RZ_MTU3_TCNTV] = 0x10, [RZ_MTU3_TGRV] = 0x12,
+		[RZ_MTU3_TCNTW] = 0x20, [RZ_MTU3_TGRW] = 0x22
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x10, [RZ_MTU3_TGRA] = 0x18,
+		[RZ_MTU3_TGRB] = 0x1a, [RZ_MTU3_TGRC] = 0x24,
+		[RZ_MTU3_TGRD] = 0x26, [RZ_MTU3_TGRE] = 0x72
+	},
+	{
+		[RZ_MTU3_TCNT] = 0x11, [RZ_MTU3_TGRA] = 0x1b,
+		[RZ_MTU3_TGRB] = 0x1d, [RZ_MTU3_TGRC] = 0x27,
+		[RZ_MTU3_TGRD] = 0x29, [RZ_MTU3_TGRE] = 0x73,
+		[RZ_MTU3_TGRF] = 0x75, [RZ_MTU3_TADCR] = 0x3f,
+		[RZ_MTU3_TADCORA] = 0x43, [RZ_MTU3_TADCORB] = 0x45,
+		[RZ_MTU3_TADCOBRA] = 0x47,
+		[RZ_MTU3_TADCOBRB] = 0x49
+	},
+};
+
+static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = {
+	{
+		[RZ_MTU3_TCNTLW] = 0x20, [RZ_MTU3_TGRALW] = 0x24,
+		[RZ_MTU3_TGRBLW] = 0x28
+	},
+	{	[RZ_MTU3_TCNT] = 0x8, [RZ_MTU3_TGRA] = 0xc,
+		[RZ_MTU3_TGRB] = 0x10, [RZ_MTU3_TGRC] = 0x14,
+		[RZ_MTU3_TGRD] = 0x18
+	}
+};
+
+static bool rz_mtu3_is_16bit_shared_reg(u16 off)
+{
+	return (off == RZ_MTU3_TDDRA || off == RZ_MTU3_TDDRB ||
+		off == RZ_MTU3_TCDRA || off == RZ_MTU3_TCDRB ||
+		off == RZ_MTU3_TCBRA || off == RZ_MTU3_TCBRB ||
+		off == RZ_MTU3_TCNTSA || off == RZ_MTU3_TCNTSB);
+}
+
+static u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
+
+	if (rz_mtu3_is_16bit_shared_reg(off))
+		return readw(mtu->mmio + off);
+	else
+		return readb(mtu->mmio + off);
+}
+
+u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	u16 ch_offs;
+
+	ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->index][off];
+	if (off != RZ_MTU3_TCR && ch_offs == 0)
+		return -EINVAL;
+
+	/*
+	 * NFCR register addresses on MTU{0,1,2,5,8} channels are smaller than
+	 * channel's base address.
+	 */
+	if (off == RZ_MTU3_NFCR && (ch->index <= RZ_MTU2 ||
+				    ch->index == RZ_MTU5 ||
+				    ch->index == RZ_MTU8))
+		return readb(ch->base - ch_offs);
+	else
+		return readb(ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read);
+
+u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	u16 ch_offs;
+
+	/* MTU8 doesn't have 16-bit registers */
+	if (ch->index == RZ_MTU8)
+		return 0;
+
+	ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->index][off];
+	if (ch->index != RZ_MTU5 && off != RZ_MTU3_TCNTU && ch_offs == 0)
+		return 0;
+
+	return readw(ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read);
+
+u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	u16 ch_offs;
+
+	if (ch->index == RZ_MTU1)
+		ch_offs = rz_mtu3_32bit_ch_reg_offs[0][off];
+	else if (ch->index == RZ_MTU8)
+		ch_offs = rz_mtu3_32bit_ch_reg_offs[1][off];
+
+	if (!ch_offs)
+		return -EINVAL;
+
+	return readl(ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read);
+
+void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val)
+{
+	u16 ch_offs;
+
+	ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->index][off];
+	if (ch->index != RZ_MTU5 && off != RZ_MTU3_TCR && ch_offs == 0)
+		return;
+
+	/*
+	 * NFCR register addresses on MTU{0,1,2,5,8} channels are smaller than
+	 * channel's base address.
+	 */
+	if (off == RZ_MTU3_NFCR && (ch->index <= RZ_MTU2 ||
+				    ch->index == RZ_MTU5 ||
+				    ch->index == RZ_MTU8))
+		writeb(val, ch->base - ch_offs);
+	else
+		writeb(val, ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write);
+
+void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val)
+{
+	u16 ch_offs;
+
+	/* MTU8 doesn't have 16-bit registers */
+	if (ch->index == RZ_MTU8)
+		return;
+
+	ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->index][off];
+	if (ch->index != RZ_MTU5 && off != RZ_MTU3_TCNTU && ch_offs == 0)
+		return;
+
+	writew(val, ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write);
+
+void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val)
+{
+	u16 ch_offs;
+
+	if (ch->index == RZ_MTU1)
+		ch_offs = rz_mtu3_32bit_ch_reg_offs[0][off];
+	else if (ch->index == RZ_MTU8)
+		ch_offs = rz_mtu3_32bit_ch_reg_offs[1][off];
+
+	if (!ch_offs)
+		return;
+
+	writel(val, ch->base + ch_offs);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write);
+
+void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 value)
+{
+	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
+
+	if (rz_mtu3_is_16bit_shared_reg(off))
+		writew(value, mtu->mmio + off);
+	else
+		writeb((u8)value, mtu->mmio + off);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write);
+
+static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start)
+{
+	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
+	unsigned long flags, value;
+	u8 offs;
+
+	/* start stop register shared by multiple timer channels */
+	raw_spin_lock_irqsave(&mtu->lock, flags);
+
+	if (ch->index == RZ_MTU6 || ch->index == RZ_MTU7) {
+		value = rz_mtu3_shared_reg_read(ch, RZ_MTU3_TSTRB);
+		if (start)
+			value |= 1 << ch->index;
+		else
+			value &= ~(1 << ch->index);
+		rz_mtu3_shared_reg_write(ch, RZ_MTU3_TSTRB, value);
+	} else if (ch->index != RZ_MTU5) {
+		value = rz_mtu3_shared_reg_read(ch, RZ_MTU3_TSTRA);
+		if (ch->index == RZ_MTU8)
+			offs = 0x08;
+		else if (ch->index < RZ_MTU3)
+			offs = 1 << ch->index;
+		else
+			offs = 1 << (ch->index + 3);
+		if (start)
+			value |= offs;
+		else
+			value &= ~offs;
+		rz_mtu3_shared_reg_write(ch, RZ_MTU3_TSTRA, value);
+	}
+
+	raw_spin_unlock_irqrestore(&mtu->lock, flags);
+}
+
+bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
+{
+	struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent);
+	unsigned long flags, value;
+	bool ret = false;
+	u8 offs;
+
+	/* start stop register shared by multiple timer channels */
+	raw_spin_lock_irqsave(&mtu->lock, flags);
+
+	if (ch->index == RZ_MTU6 || ch->index == RZ_MTU7) {
+		value = rz_mtu3_shared_reg_read(ch, RZ_MTU3_TSTRB);
+		ret = value & (1 << ch->index);
+	} else if (ch->index != RZ_MTU5) {
+		value = rz_mtu3_shared_reg_read(ch, RZ_MTU3_TSTRA);
+		if (ch->index == RZ_MTU8)
+			offs = 0x08;
+		else if (ch->index < RZ_MTU3)
+			offs = 1 << ch->index;
+		else
+			offs = 1 << (ch->index + 3);
+
+		ret = value & offs;
+	}
+
+	raw_spin_unlock_irqrestore(&mtu->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled);
+
+int rz_mtu3_enable(struct rz_mtu3_channel *ch)
+{
+	/* enable channel */
+	rz_mtu3_start_stop_ch(ch, true);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_enable);
+
+void rz_mtu3_disable(struct rz_mtu3_channel *ch)
+{
+	/* disable channel */
+	rz_mtu3_start_stop_ch(ch, false);
+}
+EXPORT_SYMBOL_GPL(rz_mtu3_disable);
+
+static const unsigned int ch_reg_offsets[] = {
+	0x100, 0x180, 0x200, 0x000, 0x001, 0xa80, 0x800, 0x801, 0x400
+};
+
+static void rz_mtu3_reset_assert(void *data)
+{
+	struct reset_control *rstc = data;
+
+	reset_control_assert(rstc);
+}
+
+static int rz_mtu3_probe(struct platform_device *pdev)
+{
+	struct reset_control *rstc;
+	struct rz_mtu3 *ddata;
+	unsigned int i;
+	int ret;
+
+	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+	ddata->mmio = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(ddata->mmio))
+		return PTR_ERR(ddata->mmio);
+
+	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	if (IS_ERR(rstc))
+		return PTR_ERR(rstc);
+
+	ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert,
+				       rstc);
+	if (ret < 0)
+		return ret;
+
+	ddata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(ddata->clk))
+		return PTR_ERR(ddata->clk);
+
+	raw_spin_lock_init(&ddata->lock);
+	reset_control_deassert(rstc);
+
+	for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) {
+		ddata->channels[i].index = i;
+		ddata->channels[i].function = RZ_MTU3_NORMAL;
+		ddata->channels[i].base = ddata->mmio + ch_reg_offsets[i];
+	}
+
+	platform_set_drvdata(pdev, ddata);
+
+	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+}
+
+static int rz_mtu3_remove(struct platform_device *pdev)
+{
+	of_platform_depopulate(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id rz_mtu3_of_match[] = {
+	{ .compatible = "renesas,rz-mtu3", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rz_mtu3_of_match);
+
+static struct platform_driver rz_mtu3_driver = {
+	.probe = rz_mtu3_probe,
+	.remove = rz_mtu3_remove,
+	.driver	= {
+		.name = "rz-mtu3",
+		.of_match_table = rz_mtu3_of_match,
+	},
+};
+module_platform_driver(rz_mtu3_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L MTU3 Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/rz-mtu3.h b/include/linux/mfd/rz-mtu3.h
new file mode 100644
index 000000000000..d623df90e1a0
--- /dev/null
+++ b/include/linux/mfd/rz-mtu3.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#ifndef __LINUX_RZ_MTU3_H__
+#define __LINUX_RZ_MTU3_H__
+
+#include <linux/clk.h>
+
+/* 8-bit shared register offsets macros */
+#define RZ_MTU3_TSTRA	0x080 /* Timer start register A */
+#define RZ_MTU3_TSTRB	0x880 /* Timer start register B */
+
+/* 16-bit shared register offset macros */
+#define RZ_MTU3_TDDRA	0x016 /* Timer dead time data register A */
+#define RZ_MTU3_TDDRB	0x816 /* Timer dead time data register B */
+#define RZ_MTU3_TCDRA	0x014 /* Timer cycle data register A */
+#define RZ_MTU3_TCDRB	0x814 /* Timer cycle data register B */
+#define RZ_MTU3_TCBRA	0x022 /* Timer cycle buffer register A */
+#define RZ_MTU3_TCBRB	0x822 /* Timer cycle buffer register B */
+#define RZ_MTU3_TCNTSA	0x020 /* Timer subcounter A */
+#define RZ_MTU3_TCNTSB	0x820 /* Timer subcounter B */
+
+/*
+ * MTU5 contains 3 timer counter registers and is totaly different
+ * from other channels, so we must separate its offset
+ */
+
+/* 8-bit register offset macros of MTU3 channels except MTU5 */
+#define RZ_MTU3_TIER	0 /* Timer interrupt register */
+#define RZ_MTU3_NFCR	1 /* Noise filter control register */
+#define RZ_MTU3_TSR	2 /* Timer status register */
+#define RZ_MTU3_TCR	3 /* Timer control register */
+#define RZ_MTU3_TCR2	4 /* Timer control register 2 */
+#define RZ_MTU3_TMDR1	5 /* Timer mode register 1 */
+#define RZ_MTU3_TIOR	6 /* Timer I/O control register */
+#define RZ_MTU3_TIORH	6 /* Timer I/O control register H */
+#define RZ_MTU3_TIORL	7 /* Timer I/O control register L */
+/* Only MTU3/4/6/7 have TBTM registers */
+#define RZ_MTU3_TBTM	8 /* Timer buffer operation transfer mode register */
+
+/* 8-bit MTU5 register offset macros */
+#define RZ_MTU3_TSTR		2 /* MTU5 Timer start register */
+#define RZ_MTU3_TCNTCMPCLR	3 /* MTU5 Timer compare match clear register */
+#define RZ_MTU3_TCRU		4 /* Timer control register U */
+#define RZ_MTU3_TCR2U		5 /* Timer control register 2U */
+#define RZ_MTU3_TIORU		6 /* Timer I/O control register U */
+#define RZ_MTU3_TCRV		7 /* Timer control register V */
+#define RZ_MTU3_TCR2V		8 /* Timer control register 2V */
+#define RZ_MTU3_TIORV		9 /* Timer I/O control register V */
+#define RZ_MTU3_TCRW		10 /* Timer control register W */
+#define RZ_MTU3_TCR2W		11 /* Timer control register 2W */
+#define RZ_MTU3_TIORW		12 /* Timer I/O control register W */
+
+/* 16-bit register offset macros of MTU3 channels except MTU5 */
+#define RZ_MTU3_TCNT		0 /* Timer counter */
+#define RZ_MTU3_TGRA		1 /* Timer general register A */
+#define RZ_MTU3_TGRB		2 /* Timer general register B */
+#define RZ_MTU3_TGRC		3 /* Timer general register C */
+#define RZ_MTU3_TGRD		4 /* Timer general register D */
+#define RZ_MTU3_TGRE		5 /* Timer general register E */
+#define RZ_MTU3_TGRF		6 /* Timer general register F */
+/* Timer A/D converter start request registers */
+#define RZ_MTU3_TADCR		7 /* control register */
+#define RZ_MTU3_TADCORA		8 /* cycle set register A */
+#define RZ_MTU3_TADCORB		9 /* cycle set register B */
+#define RZ_MTU3_TADCOBRA	10 /* cycle set buffer register A */
+#define RZ_MTU3_TADCOBRB	11 /* cycle set buffer register B */
+
+/* 16-bit MTU5 register offset macros */
+#define RZ_MTU3_TCNTU		0 /* MTU5 Timer counter U */
+#define RZ_MTU3_TGRU		1 /* MTU5 Timer general register U */
+#define RZ_MTU3_TCNTV		2 /* MTU5 Timer counter V */
+#define RZ_MTU3_TGRV		3 /* MTU5 Timer general register V */
+#define RZ_MTU3_TCNTW		4 /* MTU5 Timer counter W */
+#define RZ_MTU3_TGRW		5 /* MTU5 Timer general register W */
+
+/* 32-bit register offset */
+#define RZ_MTU3_TCNTLW		0 /* Timer longword counter */
+#define RZ_MTU3_TGRALW		1 /* Timer longword general register A */
+#define RZ_MTU3_TGRBLW		2 /* Timer longowrd general register B */
+
+#define RZ_MTU3_TMDR3		0x191 /* MTU1 Timer Mode Register 3 */
+
+/* Macros for setting registers */
+#define RZ_MTU3_TCR_CCLR_TGRA	BIT(5)
+
+enum rz_mtu3_channels {
+	RZ_MTU0,
+	RZ_MTU1,
+	RZ_MTU2,
+	RZ_MTU3,
+	RZ_MTU4,
+	RZ_MTU5,
+	RZ_MTU6,
+	RZ_MTU7,
+	RZ_MTU8,
+	RZ_MTU_NUM_CHANNELS
+};
+
+enum rz_mtu3_functions {
+	RZ_MTU3_NORMAL,
+	RZ_MTU3_16BIT_PHASE_COUNTING,
+	RZ_MTU3_32BIT_PHASE_COUNTING,
+	RZ_MTU3_PWM_MODE_1,
+};
+
+struct rz_mtu3_channel {
+	struct device *dev;
+	unsigned int index;
+	void __iomem *base;
+	enum rz_mtu3_functions function;
+};
+
+struct rz_mtu3 {
+	struct clk *clk;
+	void __iomem *mmio;
+	raw_spinlock_t lock; /* Protect the shared registers */
+	struct rz_mtu3_channel channels[RZ_MTU_NUM_CHANNELS];
+};
+
+#if IS_ENABLED(CONFIG_MFD_RZ_MTU3)
+bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch);
+void rz_mtu3_disable(struct rz_mtu3_channel *ch);
+int rz_mtu3_enable(struct rz_mtu3_channel *ch);
+
+u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
+u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
+u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off);
+
+void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val);
+void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val);
+void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val);
+void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val);
+#else
+static inline bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch)
+{
+	return false;
+}
+
+static inline void rz_mtu3_disable(struct rz_mtu3_channel *ch)
+{
+}
+
+static inline int rz_mtu3_enable(struct rz_mtu3_channel *ch)
+{
+	return 0;
+}
+
+static inline u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	return 0;
+}
+
+static inline u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	return 0;
+}
+
+static inline u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off)
+{
+	return 0;
+}
+
+static inline void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val)
+{
+}
+
+static inline void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val)
+{
+}
+
+static inline void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val)
+{
+}
+
+static inline void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val)
+{
+}
+#endif
+
+#endif /* __LINUX_RZ_MTU3_H__ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 3/4] pwm: Add support for RZ/G2L MTU3 PWM
  2022-10-06 13:57 [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver Biju Das
  2022-10-06 13:57 ` [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings Biju Das
  2022-10-06 13:57 ` [PATCH v3 2/4] mfd: Add RZ/G2L MTU3 driver Biju Das
@ 2022-10-06 13:57 ` Biju Das
  2022-10-06 13:57 ` [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver Biju Das
  3 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-06 13:57 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Biju Das, Uwe Kleine-König, linux-pwm, Geert Uytterhoeven,
	Chris Paterson, Biju Das, Prabhakar Mahadev Lad,
	linux-renesas-soc

Add support for RZ/G2L MTU3 PWM driver. The IP supports
following PWM modes

1) PWM mode 1
2) PWM mode 2
3) Reset-synchronized PWM mode
4) Complementary PWM mode 1 (transfer at crest)
5) Complementary PWM mode 2 (transfer at trough)
6) Complementary PWM mode 3 (transfer at crest and trough)

This patch adds basic pwm mode 1 support for RZ/G2L MTU3 driver
by creating separate logical channels for each IOs.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v2->v3:
 * No change.
v1->v2:
 * Modelled as a single PWM device handling multiple channles.
 * Used PM framework to manage the clocks.
---
 drivers/pwm/Kconfig       |  11 +
 drivers/pwm/Makefile      |   1 +
 drivers/pwm/pwm-rz-mtu3.c | 462 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 474 insertions(+)
 create mode 100644 drivers/pwm/pwm-rz-mtu3.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 60d13a949bc5..568f1be139b9 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -481,6 +481,17 @@ config PWM_ROCKCHIP
 	  Generic PWM framework driver for the PWM controller found on
 	  Rockchip SoCs.
 
+config PWM_RZ_MTU3
+	tristate "Renesas RZ/G2L MTU3 PWM Timer support"
+	depends on ARCH_RZG2L || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This driver exposes the MTU3 PWM Timer controller found in Renesas
+	  RZ/G2L like chips through the PWM API.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-rz-mtu3.
+
 config PWM_SAMSUNG
 	tristate "Samsung PWM support"
 	depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 7bf1a29f02b8..b85fc9fba326 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_PWM_RASPBERRYPI_POE)	+= pwm-raspberrypi-poe.o
 obj-$(CONFIG_PWM_RCAR)		+= pwm-rcar.o
 obj-$(CONFIG_PWM_RENESAS_TPU)	+= pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
+obj-$(CONFIG_PWM_RZ_MTU3)	+= pwm-rz-mtu3.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_SL28CPLD)	+= pwm-sl28cpld.o
diff --git a/drivers/pwm/pwm-rz-mtu3.c b/drivers/pwm/pwm-rz-mtu3.c
new file mode 100644
index 000000000000..b4c25e48a50e
--- /dev/null
+++ b/drivers/pwm/pwm-rz-mtu3.c
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L MTU3 PWM Timer driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ *
+ * Hardware manual for this IP can be found here
+ * https://www.renesas.com/eu/en/document/mah/rzg2l-group-rzg2lc-group-users-manual-hardware-0?language=en
+ *
+ * Limitations:
+ * - When PWM is disabled, the output is driven to Hi-Z.
+ * - While the hardware supports both polarities, the driver (for now)
+ *   only handles normal polarity.
+ * - While the hardware supports pwm mode{1,2}, reset-synchronized pwm and
+ *   complementary pwm modes, the driver (for now) only handles pwm mode1.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/rz-mtu3.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/limits.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/time.h>
+
+#define RZ_MTU3_TMDR1_MD_NORMAL		(0)
+#define RZ_MTU3_TMDR1_MD_PWM_MODE_1	(2)
+
+#define RZ_MTU3_TIOR_OC_RETAIN		(0)
+#define RZ_MTU3_TIOR_OC_0_H_COMP_MATCH	(2)
+#define RZ_MTU3_TIOR_OC_1_TOGGLE	(7)
+#define RZ_MTU3_TIOR_OC_IOA		GENMASK(3, 0)
+
+#define RZ_MTU3_TCR_CCLR_TGRC		(5 << 5)
+#define RZ_MTU3_TCR_CKEG_RISING		(0 << 3)
+
+#define RZ_MTU3_TCR_TPCS		GENMASK(2, 0)
+
+#define RZ_MTU3_MAX_PWM_MODE1_CHANNELS	(12)
+
+#define RZ_MTU3_MAX_HW_PWM_CHANNELS	(7)
+
+static const u8 rz_mtu3_pwm_mode1_num_ios[] = { 2, 1, 1, 2, 2, 2, 2 };
+
+struct rz_mtu3_pwm_chip {
+	struct pwm_chip chip;
+	struct clk *clk;
+	struct mutex lock;
+	unsigned long rate;
+	u32 user_count[RZ_MTU3_MAX_HW_PWM_CHANNELS];
+	struct rz_mtu3_channel *ch[RZ_MTU3_MAX_HW_PWM_CHANNELS];
+};
+
+static inline struct rz_mtu3_pwm_chip *to_rz_mtu3_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct rz_mtu3_pwm_chip, chip);
+}
+
+static u8 rz_mtu3_pwm_calculate_prescale(struct rz_mtu3_pwm_chip *rz_mtu3,
+					 u64 period_cycles)
+{
+	u32 prescaled_period_cycles;
+	u8 prescale;
+
+	prescaled_period_cycles = period_cycles >> 16;
+	if (prescaled_period_cycles >= 16)
+		prescale = 3;
+	else
+		prescale = (fls(prescaled_period_cycles) + 1) / 2;
+
+	return prescale;
+}
+
+static struct rz_mtu3_channel *
+rz_mtu3_get_hw_channel(struct rz_mtu3_pwm_chip *rz_mtu3_pwm, u32 channel)
+{
+	unsigned int i, ch_index = 0;
+
+	for (i = 0; i < ARRAY_SIZE(rz_mtu3_pwm_mode1_num_ios); i++) {
+		ch_index += rz_mtu3_pwm_mode1_num_ios[i];
+
+		if (ch_index > channel)
+			break;
+	}
+
+	return rz_mtu3_pwm->ch[i];
+}
+
+static u32 rz_mtu3_get_hw_channel_index(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
+					struct rz_mtu3_channel *ch)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(rz_mtu3_pwm_mode1_num_ios); i++) {
+		if (ch == rz_mtu3_pwm->ch[i])
+			break;
+	}
+
+	return i;
+}
+
+static bool rz_mtu3_pwm_is_second_channel(u32 ch_index, u32 hwpwm)
+{
+	u32 i, pwm_ch_index = 0;
+
+	for (i = 0; i < ch_index; i++)
+		pwm_ch_index += rz_mtu3_pwm_mode1_num_ios[i];
+
+	return pwm_ch_index != hwpwm;
+}
+
+static bool rz_mtu3_pwm_is_ch_enabled(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
+				      u32 hwpwm)
+{
+	struct rz_mtu3_channel *ch;
+	bool is_channel_en;
+	u32 ch_index;
+	u8 val;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+	is_channel_en = rz_mtu3_is_enabled(ch);
+
+	if (rz_mtu3_pwm_is_second_channel(ch_index, hwpwm))
+		val = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TIORL);
+	else
+		val = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TIORH);
+
+	return (is_channel_en && (val & RZ_MTU3_TIOR_OC_IOA));
+}
+
+static int rz_mtu3_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	struct rz_mtu3_channel *ch;
+	u32 ch_index;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+
+	mutex_lock(&rz_mtu3_pwm->lock);
+	rz_mtu3_pwm->user_count[ch_index]++;
+	mutex_unlock(&rz_mtu3_pwm->lock);
+
+	ch->function = RZ_MTU3_PWM_MODE_1;
+
+	return 0;
+}
+
+static void rz_mtu3_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	struct rz_mtu3_channel *ch;
+	u32 ch_index;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+
+	mutex_lock(&rz_mtu3_pwm->lock);
+	rz_mtu3_pwm->user_count[ch_index]--;
+	mutex_unlock(&rz_mtu3_pwm->lock);
+
+	if (!rz_mtu3_pwm->user_count[ch_index])
+		ch->function = RZ_MTU3_NORMAL;
+}
+
+static int rz_mtu3_pwm_enable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
+			      struct pwm_device *pwm)
+{
+	struct rz_mtu3_channel *ch;
+	u32 ch_index;
+	u8 val;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+	val = (RZ_MTU3_TIOR_OC_1_TOGGLE << 4) | RZ_MTU3_TIOR_OC_0_H_COMP_MATCH;
+
+	rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_MD_PWM_MODE_1);
+	if (rz_mtu3_pwm_is_second_channel(ch_index, pwm->hwpwm))
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIORL, val);
+	else
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIORH, val);
+
+	if (rz_mtu3_pwm->user_count[ch_index] <= 1)
+		rz_mtu3_enable(ch);
+
+	return 0;
+}
+
+static void rz_mtu3_pwm_disable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
+				struct pwm_device *pwm)
+{
+	struct rz_mtu3_channel *ch;
+	u32 ch_index;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+
+	/* Return to normal mode and disable output pins of MTU3 channel */
+	if (rz_mtu3_pwm->user_count[ch_index] <= 1)
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_MD_NORMAL);
+
+	if (rz_mtu3_pwm_is_second_channel(ch_index, pwm->hwpwm))
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIORL, RZ_MTU3_TIOR_OC_RETAIN);
+	else
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIORH, RZ_MTU3_TIOR_OC_RETAIN);
+
+	if (rz_mtu3_pwm->user_count[ch_index] <= 1)
+		rz_mtu3_disable(ch);
+}
+
+static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			      const struct pwm_state *state)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	struct rz_mtu3_channel *ch;
+	unsigned long pv, dc;
+	u64 period_cycles;
+	u64 duty_cycles;
+	u32 ch_index;
+	u8 prescale;
+	u8 val;
+
+	/*
+	 * Refuse clk rates > 1 GHz to prevent overflowing the following
+	 * calculation.
+	 */
+	if (rz_mtu3_pwm->rate > NSEC_PER_SEC)
+		return -EINVAL;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+	duty_cycles = state->duty_cycle;
+	if (!state->enabled)
+		duty_cycles = 0;
+
+	period_cycles = mul_u64_u32_div(state->period, rz_mtu3_pwm->rate,
+					NSEC_PER_SEC);
+	prescale = rz_mtu3_pwm_calculate_prescale(rz_mtu3_pwm, period_cycles);
+
+	if (period_cycles >> (2 * prescale) <= U16_MAX)
+		pv = period_cycles >> (2 * prescale);
+	else
+		pv = U16_MAX;
+
+	duty_cycles = mul_u64_u32_div(duty_cycles, rz_mtu3_pwm->rate,
+				      NSEC_PER_SEC);
+	if (duty_cycles >> (2 * prescale) <= U16_MAX)
+		dc = duty_cycles >> (2 * prescale);
+	else
+		dc = U16_MAX;
+
+	val = RZ_MTU3_TCR_CKEG_RISING | prescale;
+	if (rz_mtu3_pwm_is_second_channel(ch_index, pwm->hwpwm)) {
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR,
+				      RZ_MTU3_TCR_CCLR_TGRC | val);
+		rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRD, dc);
+		rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRC, pv);
+	} else {
+		rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR,
+				      RZ_MTU3_TCR_CCLR_TGRA | val);
+		rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRB, dc);
+		rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, pv);
+	}
+
+	return 0;
+}
+
+static void rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+				  struct pwm_state *state)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	struct rz_mtu3_channel *ch;
+	u8 prescale, val;
+	u32 ch_index;
+	u16 dc, pv;
+	u64 tmp;
+
+	ch = rz_mtu3_get_hw_channel(rz_mtu3_pwm, pwm->hwpwm);
+	ch_index = rz_mtu3_get_hw_channel_index(rz_mtu3_pwm, ch);
+	pm_runtime_get_sync(chip->dev);
+	state->enabled = rz_mtu3_pwm_is_ch_enabled(rz_mtu3_pwm, pwm->hwpwm);
+	if (state->enabled) {
+		val = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TCR);
+		prescale = FIELD_GET(RZ_MTU3_TCR_TPCS, val);
+
+		if (rz_mtu3_pwm_is_second_channel(ch_index, pwm->hwpwm)) {
+			dc = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TGRD);
+			pv = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TGRC);
+		} else {
+			dc = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TGRB);
+			pv = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TGRA);
+		}
+
+		tmp = NSEC_PER_SEC * (u64)pv << (2 * prescale);
+		state->period = DIV_ROUND_UP_ULL(tmp, rz_mtu3_pwm->rate);
+
+		tmp = NSEC_PER_SEC * (u64)dc << (2 * prescale);
+		state->duty_cycle = DIV_ROUND_UP_ULL(tmp, rz_mtu3_pwm->rate);
+	}
+
+	state->polarity = PWM_POLARITY_NORMAL;
+	pm_runtime_put(chip->dev);
+}
+
+static int rz_mtu3_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			     const struct pwm_state *state)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	struct pwm_state cur_state;
+	bool enabled;
+	int ret;
+
+	cur_state = pwm->state;
+	enabled = cur_state.enabled;
+	if (state->polarity != PWM_POLARITY_NORMAL)
+		return -EINVAL;
+
+	if (!enabled && state->enabled)
+		pm_runtime_get_sync(chip->dev);
+
+	ret = rz_mtu3_pwm_config(chip, pwm, state);
+	if (ret && state->enabled)
+		goto done;
+
+	if (!state->enabled) {
+		if (enabled)
+			rz_mtu3_pwm_disable(rz_mtu3_pwm, pwm);
+		ret = 0;
+		goto done;
+	}
+
+	return rz_mtu3_pwm_enable(rz_mtu3_pwm, pwm);
+done:
+	if (enabled && !state->enabled)
+		pm_runtime_put(chip->dev);
+
+	return ret;
+}
+
+static const struct pwm_ops rz_mtu3_pwm_ops = {
+	.request = rz_mtu3_pwm_request,
+	.free = rz_mtu3_pwm_free,
+	.get_state = rz_mtu3_pwm_get_state,
+	.apply = rz_mtu3_pwm_apply,
+	.owner = THIS_MODULE,
+};
+
+static const struct of_device_id rz_mtu3_pwm_of_table[] = {
+	{ .compatible = "renesas,rz-mtu3-pwm", },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rz_mtu3_pwm_of_table);
+
+static int __maybe_unused rz_mtu3_pwm_pm_runtime_suspend(struct device *dev)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(rz_mtu3_pwm->clk);
+
+	return 0;
+}
+
+static int __maybe_unused rz_mtu3_pwm_pm_runtime_resume(struct device *dev)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = dev_get_drvdata(dev);
+
+	clk_prepare_enable(rz_mtu3_pwm->clk);
+
+	return 0;
+}
+
+static const struct dev_pm_ops rz_mtu3_pwm_pm_ops = {
+	SET_RUNTIME_PM_OPS(rz_mtu3_pwm_pm_runtime_suspend, rz_mtu3_pwm_pm_runtime_resume, NULL)
+};
+
+static void rz_mtu3_pwm_pm_disable(void *data)
+{
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = dev_get_drvdata(data);
+
+	pm_runtime_disable(rz_mtu3_pwm->chip.dev);
+	pm_runtime_set_suspended(rz_mtu3_pwm->chip.dev);
+}
+
+static int rz_mtu3_pwm_probe(struct platform_device *pdev)
+{
+	struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct rz_mtu3_pwm_chip *rz_mtu3_pwm;
+	struct device *dev = &pdev->dev;
+	int num_pwm_hw_ch;
+	unsigned int i;
+	int ret;
+
+	rz_mtu3_pwm = devm_kzalloc(&pdev->dev, sizeof(*rz_mtu3_pwm), GFP_KERNEL);
+	if (!rz_mtu3_pwm)
+		return -ENOMEM;
+
+	rz_mtu3_pwm->clk = ddata->clk;
+	num_pwm_hw_ch = 0;
+	for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) {
+		if (i == RZ_MTU5 || i == RZ_MTU8)
+			continue;
+
+		rz_mtu3_pwm->ch[num_pwm_hw_ch] = &ddata->channels[i];
+		rz_mtu3_pwm->ch[num_pwm_hw_ch]->dev = dev;
+		if (rz_mtu3_pwm->ch[num_pwm_hw_ch]->function != RZ_MTU3_NORMAL)
+			return dev_err_probe(dev, -EINVAL,
+					     "channel '%u' is already claimed\n", i);
+		num_pwm_hw_ch++;
+	}
+
+	rz_mtu3_pwm->rate = clk_get_rate(rz_mtu3_pwm->clk);
+
+	mutex_init(&rz_mtu3_pwm->lock);
+
+	clk_prepare_enable(rz_mtu3_pwm->clk);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	ret = devm_add_action_or_reset(&pdev->dev,
+				       rz_mtu3_pwm_pm_disable,
+				       rz_mtu3_pwm);
+	if (ret < 0)
+		goto disable_clock;
+
+	platform_set_drvdata(pdev, rz_mtu3_pwm);
+
+	rz_mtu3_pwm->chip.dev = &pdev->dev;
+	rz_mtu3_pwm->chip.ops = &rz_mtu3_pwm_ops;
+	rz_mtu3_pwm->chip.npwm = RZ_MTU3_MAX_PWM_MODE1_CHANNELS;
+
+	ret = devm_pwmchip_add(&pdev->dev, &rz_mtu3_pwm->chip);
+	if (ret) {
+		dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
+		goto disable_clock;
+	}
+
+	return 0;
+
+disable_clock:
+	clk_disable_unprepare(rz_mtu3_pwm->clk);
+
+	return ret;
+}
+
+static struct platform_driver rz_mtu3_pwm_driver = {
+	.driver = {
+		.name = "pwm-rz-mtu3",
+		.pm = &rz_mtu3_pwm_pm_ops,
+		.of_match_table = of_match_ptr(rz_mtu3_pwm_of_table),
+	},
+	.probe = rz_mtu3_pwm_probe,
+};
+module_platform_driver(rz_mtu3_pwm_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L MTU3 PWM Timer Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-rz-mtu3");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-06 13:57 [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver Biju Das
                   ` (2 preceding siblings ...)
  2022-10-06 13:57 ` [PATCH v3 3/4] pwm: Add support for RZ/G2L MTU3 PWM Biju Das
@ 2022-10-06 13:57 ` Biju Das
  2022-10-08  1:37   ` William Breathitt Gray
  3 siblings, 1 reply; 23+ messages in thread
From: Biju Das @ 2022-10-06 13:57 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Biju Das, linux-iio, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Add RZ/G2L MTU3 counter driver.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v1->v3:
 * Modelled as a counter device supporting 3 counters(2 16-bit and 
   32-bit)
 * Add kernel-doc comments to document struct rz_mtu3_cnt
 * Removed mmio variable from struct rz_mtu3_cnt
 * Removed cnt local variable from rz_mtu3_count_read()
 * Replaced -EINVAL->-ERANGE for out of range error conditions.
 * Removed explicit cast from write functions.
 * Removed local variable val from rz_mtu3_count_ceiling_read()
 * Added lock for RMW for counter/ceiling updates.
 * Added different synapses for counter0 and counter{1,2}
 * Used ARRAY for assigning num_counts.
 * Added PM runtime for managing clocks.
 * Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.
---
 drivers/counter/Kconfig       |   9 +
 drivers/counter/Makefile      |   1 +
 drivers/counter/rz-mtu3-cnt.c | 568 ++++++++++++++++++++++++++++++++++
 3 files changed, 578 insertions(+)
 create mode 100644 drivers/counter/rz-mtu3-cnt.c

diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index d388bf26f4dc..531b187e4630 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -39,6 +39,15 @@ config INTERRUPT_CNT
 	  To compile this driver as a module, choose M here: the
 	  module will be called interrupt-cnt.
 
+config RZ_MTU3_CNT
+	tristate "RZ/G2L MTU3 counter driver"
+	depends on MFD_RZ_MTU3 || COMPILE_TEST
+	help
+	  Select this option to enable RZ/G2L MTU3 counter driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rz-mtu3-cnt.
+
 config STM32_TIMER_CNT
 	tristate "STM32 Timer encoder counter driver"
 	depends on MFD_STM32_TIMERS || COMPILE_TEST
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index b9a369e0d4fc..933fdd50b3e4 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o counter-chrdev.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_INTERRUPT_CNT)		+= interrupt-cnt.o
+obj-$(CONFIG_RZ_MTU3_CNT)	+= rz-mtu3-cnt.o
 obj-$(CONFIG_STM32_TIMER_CNT)	+= stm32-timer-cnt.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
 obj-$(CONFIG_TI_EQEP)		+= ti-eqep.o
diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c
new file mode 100644
index 000000000000..26b5ea3852f8
--- /dev/null
+++ b/drivers/counter/rz-mtu3-cnt.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L MTU3a Counter driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+#include <linux/counter.h>
+#include <linux/mfd/rz-mtu3.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#define RZ_MTU3_TSR_TCFD	BIT(7)
+#define RZ_MTU3_MAX_HW_CNTR_CHANNELS	(2)
+
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_1	(4)
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_2	(5)
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_3	(6)
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_4	(7)
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_5	(9)
+#define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK	(0xf)
+
+#define RZ_MTU3_TCR_CCLR	GENMASK(7, 5)
+#define RZ_MTU3_TCR_CCLR_NONE	FIELD_PREP(RZ_MTU3_TCR_CCLR, 0)
+
+#define RZ_MTU3_TMDR3_LWA	BIT(0)
+#define RZ_MTU3_32_BIT_CH	(2)
+
+#define RZ_MTU3_TIOR_IC_BOTH	(10)
+
+/**
+ * struct rz_mtu3_cnt - MTU3 counter private data
+ *
+ * @clk: MTU3 module clock
+ * @lock: Lock to prevent concurrent access for ceiling and count
+ * @rz_mtu3_channel: HW channels for the counters
+ */
+struct rz_mtu3_cnt {
+	struct clk *clk;
+	struct mutex lock;
+	struct rz_mtu3_channel *ch[RZ_MTU3_MAX_HW_CNTR_CHANNELS];
+};
+
+static const enum counter_function rz_mtu3_count_functions[] = {
+	COUNTER_FUNCTION_QUADRATURE_X4,
+	COUNTER_FUNCTION_PULSE_DIRECTION,
+	COUNTER_FUNCTION_QUADRATURE_X2_B,
+};
+
+static bool rz_mtu3_is_16_bit_cnt_mode(struct rz_mtu3_cnt *const priv)
+{
+	return (priv->ch[0]->function == RZ_MTU3_16BIT_PHASE_COUNTING ||
+		priv->ch[1]->function == RZ_MTU3_16BIT_PHASE_COUNTING);
+}
+
+static bool rz_mtu3_is_32_bit_cnt_mode(struct rz_mtu3_cnt *const priv)
+{
+	return (priv->ch[0]->function == RZ_MTU3_32BIT_PHASE_COUNTING &&
+		priv->ch[1]->function == RZ_MTU3_32BIT_PHASE_COUNTING);
+}
+
+static int rz_mtu3_count_read(struct counter_device *counter,
+			      struct counter_count *count, u64 *val)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+
+	if (count->id == RZ_MTU3_32_BIT_CH)
+		*val = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TCNTLW);
+	else
+		*val = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TCNT);
+
+	return 0;
+}
+
+static int rz_mtu3_count_write(struct counter_device *counter,
+			       struct counter_count *count, const u64 val)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+	u32 ceiling;
+
+	mutex_lock(&priv->lock);
+	if (count->id == RZ_MTU3_32_BIT_CH)
+		ceiling = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TGRALW);
+	else
+		ceiling = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TGRA);
+
+	if (val > ceiling) {
+		mutex_unlock(&priv->lock);
+		return -ERANGE;
+	}
+
+	if (count->id == RZ_MTU3_32_BIT_CH)
+		rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TCNTLW, val);
+	else
+		rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TCNT, val);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int rz_mtu3_count_function_read(struct counter_device *counter,
+				       struct counter_count *count,
+				       enum counter_function *function)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+	u8 val;
+
+	val = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TMDR1);
+
+	switch (val & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
+	case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
+		*function = COUNTER_FUNCTION_QUADRATURE_X4;
+		break;
+	case RZ_MTU3_TMDR1_PH_CNT_MODE_2:
+		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
+		break;
+	case RZ_MTU3_TMDR1_PH_CNT_MODE_4:
+		*function = COUNTER_FUNCTION_QUADRATURE_X2_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rz_mtu3_count_function_write(struct counter_device *counter,
+					struct counter_count *count,
+					enum counter_function function)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+	u8 mode;
+
+	switch (function) {
+	case COUNTER_FUNCTION_QUADRATURE_X4:
+		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1;
+		break;
+	case COUNTER_FUNCTION_PULSE_DIRECTION:
+		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2;
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X2_B:
+		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1, mode);
+
+	return 0;
+}
+
+static int rz_mtu3_count_direction_read(struct counter_device *counter,
+					struct counter_count *count,
+					enum counter_count_direction *direction)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+	u8 cnt;
+
+	cnt = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TSR);
+
+	if (cnt & RZ_MTU3_TSR_TCFD)
+		*direction = COUNTER_COUNT_DIRECTION_FORWARD;
+	else
+		*direction = COUNTER_COUNT_DIRECTION_BACKWARD;
+
+	return 0;
+}
+
+static int rz_mtu3_count_ceiling_read(struct counter_device *counter,
+				      struct counter_count *count,
+				      u64 *ceiling)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+
+	if (count->id == RZ_MTU3_32_BIT_CH)
+		*ceiling = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TGRALW);
+	else
+		*ceiling = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TGRA);
+
+	return 0;
+}
+
+static int rz_mtu3_count_ceiling_write(struct counter_device *counter,
+				       struct counter_count *count,
+				       u64 ceiling)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	u32 id = count->id & 1;
+
+	if (ceiling > U16_MAX && rz_mtu3_is_16_bit_cnt_mode(priv))
+		return -ERANGE;
+
+	if (ceiling > U32_MAX && rz_mtu3_is_32_bit_cnt_mode(priv))
+		return -ERANGE;
+
+	mutex_lock(&priv->lock);
+	if (ceiling == 0) {
+		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
+				      RZ_MTU3_TCR_CCLR_NONE);
+
+	} else {
+		if (count->id == RZ_MTU3_32_BIT_CH)
+			rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TGRALW, ceiling);
+		else
+			rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA, ceiling);
+
+		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
+				      RZ_MTU3_TCR_CCLR_TGRA);
+	}
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter, int id)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+
+	/*
+	 * 32-bit phase counting need MTU1 and MTU2 to create 32-bit cascade
+	 * counter.
+	 */
+	priv->ch[0]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
+	priv->ch[1]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
+
+	rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3, RZ_MTU3_TMDR3_LWA);
+
+	/* Phase counting mode 1 is used as default in initialization. */
+	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TMDR1,
+			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
+
+	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
+	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TIOR, RZ_MTU3_TIOR_IC_BOTH);
+
+	rz_mtu3_enable(priv->ch[0]);
+	rz_mtu3_enable(priv->ch[1]);
+}
+
+static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+
+	priv->ch[id]->function = RZ_MTU3_16BIT_PHASE_COUNTING;
+
+	/* Phase counting mode 1 is used as default in initialization. */
+	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1,
+			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
+
+	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
+	rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA, U16_MAX);
+
+	rz_mtu3_enable(priv->ch[id]);
+}
+
+static int rz_mtu3_initialize_counter(struct counter_device *counter, int id)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+
+	if (id == RZ_MTU3_32_BIT_CH && rz_mtu3_is_16_bit_cnt_mode(priv))
+		return -EBUSY;
+
+	if (id != RZ_MTU3_32_BIT_CH && rz_mtu3_is_32_bit_cnt_mode(priv))
+		return -EBUSY;
+
+	if (id == RZ_MTU3_32_BIT_CH)
+		rz_mtu3_32bit_cnt_setting(counter, id);
+	else
+		rz_mtu3_16bit_cnt_setting(counter, id);
+
+	return 0;
+}
+
+static void rz_mtu3_terminate_counter(struct counter_device *counter, int id)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+
+	if (id == RZ_MTU3_32_BIT_CH) {
+		priv->ch[0]->function = RZ_MTU3_NORMAL;
+		priv->ch[1]->function = RZ_MTU3_NORMAL;
+		rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3, 0);
+		rz_mtu3_disable(priv->ch[1]);
+		rz_mtu3_disable(priv->ch[0]);
+	} else {
+		priv->ch[id]->function = RZ_MTU3_NORMAL;
+		rz_mtu3_disable(priv->ch[id]);
+	}
+}
+
+static int rz_mtu3_count_enable_read(struct counter_device *counter,
+				     struct counter_count *count, u8 *enable)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+
+	if (count->id == RZ_MTU3_32_BIT_CH)
+		*enable = rz_mtu3_is_enabled(priv->ch[0]) &&
+			rz_mtu3_is_enabled(priv->ch[1]);
+	else
+		*enable = rz_mtu3_is_enabled(priv->ch[count->id]);
+
+	return 0;
+}
+
+static int rz_mtu3_count_enable_write(struct counter_device *counter,
+				      struct counter_count *count, u8 enable)
+{
+	struct rz_mtu3_cnt *const priv = counter_priv(counter);
+	struct rz_mtu3_channel *ch = priv->ch[count->id & 0x1];
+	int ret = 0;
+
+	if (enable) {
+		pm_runtime_get_sync(ch->dev);
+		ret = rz_mtu3_initialize_counter(counter, count->id);
+	} else {
+		rz_mtu3_terminate_counter(counter, count->id);
+		pm_runtime_put(ch->dev);
+	}
+
+	return ret;
+}
+
+static struct counter_comp rz_mtu3_count_ext[] = {
+	COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read),
+	COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read,
+			    rz_mtu3_count_enable_write),
+	COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read,
+			     rz_mtu3_count_ceiling_write),
+};
+
+static const enum counter_synapse_action rz_mtu3_synapse_actions[] = {
+	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
+	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
+	COUNTER_SYNAPSE_ACTION_NONE,
+};
+
+static int rz_mtu3_action_read(struct counter_device *counter,
+			       struct counter_count *count,
+			       struct counter_synapse *synapse,
+			       enum counter_synapse_action *action)
+{
+	const size_t signal_a_id = count->synapses[0].signal->id;
+	const size_t signal_b_id = count->synapses[1].signal->id;
+	enum counter_function function;
+	int err;
+
+	err = rz_mtu3_count_function_read(counter, count, &function);
+	if (err)
+		return err;
+
+	/* Default action mode */
+	*action = COUNTER_SYNAPSE_ACTION_NONE;
+
+	switch (function) {
+	case COUNTER_FUNCTION_PULSE_DIRECTION:
+		/*
+		 * Rising edges on signal A updates the respective count.
+		 * The input level of signal B determines direction.
+		 */
+		if (synapse->signal->id == signal_a_id)
+			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X2_B:
+		/*
+		 * Any state transition on quadrature pair signal B updates
+		 * the respective count.
+		 */
+		if (synapse->signal->id == signal_b_id)
+			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
+		break;
+	case COUNTER_FUNCTION_QUADRATURE_X4:
+		/* counts up/down on both edges of A and B signal*/
+		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct counter_ops rz_mtu3_cnt_ops = {
+	.count_read = rz_mtu3_count_read,
+	.count_write = rz_mtu3_count_write,
+	.function_read = rz_mtu3_count_function_read,
+	.function_write = rz_mtu3_count_function_write,
+	.action_read = rz_mtu3_action_read,
+};
+
+#define RZ_MTU3_PHASE_SIGNAL(_id, _name) {		\
+	.id = (_id),				\
+	.name = (_name),			\
+}
+
+static struct counter_signal rz_mtu3_signals[] = {
+	RZ_MTU3_PHASE_SIGNAL(0, "MTU1 MTCLKA"),
+	RZ_MTU3_PHASE_SIGNAL(1, "MTU1 MTCLKB"),
+	RZ_MTU3_PHASE_SIGNAL(2, "MTU2 MTCLKC"),
+	RZ_MTU3_PHASE_SIGNAL(3, "MTU2 MTCLKD"),
+};
+
+#define RZ_MTU3_COUNT_SYNAPSES(_id) {					\
+	{								\
+		.actions_list = rz_mtu3_synapse_actions,		\
+		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
+		.signal = rz_mtu3_signals + 2 * (_id)			\
+	},								\
+	{								\
+		.actions_list = rz_mtu3_synapse_actions,		\
+		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
+		.signal = rz_mtu3_signals + 2 * (_id) + 1		\
+	}								\
+}
+
+static struct counter_synapse rz_mtu3_count_synapses[][2] = {
+	RZ_MTU3_COUNT_SYNAPSES(0), RZ_MTU3_COUNT_SYNAPSES(1)
+};
+
+static struct counter_count rz_mtu3_counts[] = {
+	{
+		.id = 0,
+		.name = "Channel 1 Count(16-bit)",
+		.functions_list = rz_mtu3_count_functions,
+		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
+		.synapses = rz_mtu3_count_synapses[0],
+		.num_synapses = 2,
+		.ext = rz_mtu3_count_ext,
+		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
+	},
+	{
+		.id = 1,
+		.name = "Channel 2 Count(16-bit)",
+		.functions_list = rz_mtu3_count_functions,
+		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
+		.synapses = rz_mtu3_count_synapses[0],
+		.num_synapses = 4,
+		.ext = rz_mtu3_count_ext,
+		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
+	},
+	{
+		.id = 2,
+		.name = "Channel3 Count(32-bit)",
+		.functions_list = rz_mtu3_count_functions,
+		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
+		.synapses = rz_mtu3_count_synapses[0],
+		.num_synapses = 4,
+		.ext = rz_mtu3_count_ext,
+		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
+	}
+};
+
+static int __maybe_unused rz_mtu3_cnt_pm_runtime_suspend(struct device *dev)
+{
+	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+static int __maybe_unused rz_mtu3_cnt_pm_runtime_resume(struct device *dev)
+{
+	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
+
+	clk_prepare_enable(priv->clk);
+
+	return 0;
+}
+
+static const struct dev_pm_ops rz_mtu3_cnt_pm_ops = {
+	SET_RUNTIME_PM_OPS(rz_mtu3_cnt_pm_runtime_suspend, rz_mtu3_cnt_pm_runtime_resume, NULL)
+};
+
+static void rz_mtu3_cnt_pm_disable(void *data)
+{
+	struct device *dev = data;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+}
+
+static int rz_mtu3_cnt_probe(struct platform_device *pdev)
+{
+	struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct device *dev = &pdev->dev;
+	struct counter_device *counter;
+	struct rz_mtu3_cnt *priv;
+	unsigned int i;
+	int ret;
+
+	counter = devm_counter_alloc(dev, sizeof(*priv));
+	if (!counter)
+		return -ENOMEM;
+
+	priv = counter_priv(counter);
+	priv->clk = ddata->clk;
+
+	for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) {
+		priv->ch[i] = &ddata->channels[RZ_MTU1 + i];
+		priv->ch[i]->dev = dev;
+		if (priv->ch[i]->function != RZ_MTU3_NORMAL)
+			return dev_err_probe(dev, -EINVAL,
+					     "channel '%u' is already claimed\n", i);
+	}
+
+	mutex_init(&priv->lock);
+	clk_prepare_enable(priv->clk);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	ret = devm_add_action_or_reset(&pdev->dev,
+				       rz_mtu3_cnt_pm_disable,
+				       dev);
+	if (ret < 0)
+		goto disable_clock;
+
+	counter->name = dev_name(dev);
+	counter->parent = dev;
+	counter->ops = &rz_mtu3_cnt_ops;
+	counter->counts = rz_mtu3_counts;
+	counter->num_counts = ARRAY_SIZE(rz_mtu3_counts);
+	counter->signals = rz_mtu3_signals;
+	counter->num_signals = ARRAY_SIZE(rz_mtu3_signals);
+	platform_set_drvdata(pdev, priv);
+
+	/* Register Counter device */
+	ret = devm_counter_add(dev, counter);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "Failed to add counter\n");
+		goto disable_clock;
+	}
+
+	return 0;
+
+disable_clock:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static const struct of_device_id rz_mtu3_cnt_of_match[] = {
+	{ .compatible = "renesas,rz-mtu3-counter", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rz_mtu3_cnt_of_match);
+
+static struct platform_driver rz_mtu3_cnt_driver = {
+	.probe = rz_mtu3_cnt_probe,
+	.driver = {
+		.name = "rz-mtu3-counter",
+		.pm = &rz_mtu3_cnt_pm_ops,
+		.of_match_table = rz_mtu3_cnt_of_match,
+	},
+};
+module_platform_driver(rz_mtu3_cnt_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_ALIAS("platform:rz-mtu3-counter");
+MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(COUNTER);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-06 13:57 ` [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings Biju Das
@ 2022-10-06 20:17   ` Rob Herring
  2022-10-07 12:40     ` Biju Das
  0 siblings, 1 reply; 23+ messages in thread
From: Rob Herring @ 2022-10-06 20:17 UTC (permalink / raw)
  To: Biju Das
  Cc: Krzysztof Kozlowski, William Breathitt Gray, Thierry Reding,
	Lee Jones, Uwe Kleine-König, devicetree, linux-pwm,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in
> the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
> channels and one 32-bit timer channel. It supports the following
> functions
>  - Counter
>  - Timer
>  - PWM
> 
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> ---
> v2->v3:
>  * Dropped counter bindings and integrated with mfd as it has only one property.
>  * Removed "#address-cells" and "#size-cells" as it do not have children with
>    unit addresses.
>  * Removed quotes from counter and pwm.
>  * Provided full path for pwm bindings.
>  * Updated the example.
> v1->v2:
>  * Modelled counter and pwm as a single device that handles
>    multiple channels.
>  * Moved counter and pwm bindings to respective subsystems
>  * Dropped 'bindings' from MFD binding title.
>  * Updated the example
>  * Changed the compatible names.
> ---
>  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304 ++++++++++++++++++
>  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
>  2 files changed, 354 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
>  create mode 100644 Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> new file mode 100644
> index 000000000000..44c952ad8d35
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> @@ -0,0 +1,304 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/renesas,rz-mtu3.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
> +
> +maintainers:
> +  - Biju Das <biju.das.jz@bp.renesas.com>
> +
> +description: |
> +  This hardware block pconsisting of eight 16-bit timer channels and one
> +  32- bit timer channel. It supports the following specifications:
> +    - Pulse input/output: 28 lines max.
> +    - Pulse input 3 lines
> +    - Count clock 11 clocks for each channel (14 clocks for MTU0, 12 clocks
> +      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2 combination
> +      (when LWA = 1))
> +    - Operating frequency Up to 100 MHz
> +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
> +        - Waveform output on compare match
> +        - Input capture function (noise filter setting available)
> +        - Counter-clearing operation
> +        - Simultaneous writing to multiple timer counters (TCNT)
> +          (excluding MTU8).
> +        - Simultaneous clearing on compare match or input capture
> +          (excluding MTU8).
> +        - Simultaneous input and output to registers in synchronization with
> +          counter operations           (excluding MTU8).
> +        - Up to 12-phase PWM output in combination with synchronous operation
> +          (excluding MTU8)
> +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> +        - Buffer operation specifiable
> +    - [MTU1, MTU2]
> +        - Phase counting mode can be specified independently
> +        - 32-bit phase counting mode can be specified for interlocked operation
> +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> +        - Cascade connection operation available
> +    - [MTU3, MTU4, MTU6, and MTU7]
> +        - Through interlocked operation of MTU3/4 and MTU6/7, the positive and
> +          negative signals in six phases (12 phases in total) can be output in
> +          complementary PWM and reset-synchronized PWM operation.
> +        - In complementary PWM mode, values can be transferred from buffer
> +          registers to temporary registers at crests and troughs of the timer-
> +          counter values or when the buffer registers (TGRD registers in MTU4
> +          and MTU7) are written to.
> +        - Double-buffering selectable in complementary PWM mode.
> +    - [MTU3 and MTU4]
> +        - Through interlocking with MTU0, a mode for driving AC synchronous
> +          motors (brushless DC motors) by using complementary PWM output and
> +          reset-synchronized PWM output is settable and allows the selection
> +          of two types of waveform output (chopping or level).
> +    - [MTU5]
> +        - Capable of operation as a dead-time compensation counter.
> +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> +        - 32-bit phase counting mode specifiable by combining MTU1 and MTU2 and
> +          through interlocked operation with MTU0/MTU5 and MTU8.
> +    - Interrupt-skipping function
> +        - In complementary PWM mode, interrupts on crests and troughs of counter
> +          values and triggers to start conversion by the A/D converter can be
> +          skipped.
> +    - Interrupt sources: 43 sources.
> +    - Buffer operation:
> +        - Automatic transfer of register data (transfer from the buffer
> +          register to the timer register).
> +    - Trigger generation
> +        - A/D converter start triggers can be generated
> +        - A/D converter start request delaying function enables A/D converter
> +          to be started with any desired timing and to be synchronized with
> +          PWM output.
> +    - Low power consumption function
> +        - The MTU3a can be placed in the module-stop state.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> +          - renesas,r9a07g054-mtu3  # RZ/V2L
> +      - const: renesas,rz-mtu3
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    items:
> +      - description: MTU0.TGRA input capture/compare match
> +      - description: MTU0.TGRB input capture/compare match
> +      - description: MTU0.TGRC input capture/compare match
> +      - description: MTU0.TGRD input capture/compare match
> +      - description: MTU0.TCNT overflow
> +      - description: MTU0.TGRE compare match
> +      - description: MTU0.TGRF compare match
> +      - description: MTU1.TGRA input capture/compare match
> +      - description: MTU1.TGRB input capture/compare match
> +      - description: MTU1.TCNT overflow
> +      - description: MTU1.TCNT underflow
> +      - description: MTU2.TGRA input capture/compare match
> +      - description: MTU2.TGRB input capture/compare match
> +      - description: MTU2.TCNT overflow
> +      - description: MTU2.TCNT underflow
> +      - description: MTU3.TGRA input capture/compare match
> +      - description: MTU3.TGRB input capture/compare match
> +      - description: MTU3.TGRC input capture/compare match
> +      - description: MTU3.TGRD input capture/compare match
> +      - description: MTU3.TCNT overflow
> +      - description: MTU4.TGRA input capture/compare match
> +      - description: MTU4.TGRB input capture/compare match
> +      - description: MTU4.TGRC input capture/compare match
> +      - description: MTU4.TGRD input capture/compare match
> +      - description: MTU4.TCNT overflow/underflow
> +      - description: MTU5.TGRU input capture/compare match
> +      - description: MTU5.TGRV input capture/compare match
> +      - description: MTU5.TGRW input capture/compare match
> +      - description: MTU6.TGRA input capture/compare match
> +      - description: MTU6.TGRB input capture/compare match
> +      - description: MTU6.TGRC input capture/compare match
> +      - description: MTU6.TGRD input capture/compare match
> +      - description: MTU6.TCNT overflow
> +      - description: MTU7.TGRA input capture/compare match
> +      - description: MTU7.TGRB input capture/compare match
> +      - description: MTU7.TGRC input capture/compare match
> +      - description: MTU7.TGRD input capture/compare match
> +      - description: MTU7.TCNT overflow/underflow
> +      - description: MTU8.TGRA input capture/compare match
> +      - description: MTU8.TGRB input capture/compare match
> +      - description: MTU8.TGRC input capture/compare match
> +      - description: MTU8.TGRD input capture/compare match
> +      - description: MTU8.TCNT overflow
> +      - description: MTU8.TCNT underflow
> +
> +  interrupt-names:
> +    items:
> +      - const: tgia0
> +      - const: tgib0
> +      - const: tgic0
> +      - const: tgid0
> +      - const: tgiv0
> +      - const: tgie0
> +      - const: tgif0
> +      - const: tgia1
> +      - const: tgib1
> +      - const: tgiv1
> +      - const: tgiu1
> +      - const: tgia2
> +      - const: tgib2
> +      - const: tgiv2
> +      - const: tgiu2
> +      - const: tgia3
> +      - const: tgib3
> +      - const: tgic3
> +      - const: tgid3
> +      - const: tgiv3
> +      - const: tgia4
> +      - const: tgib4
> +      - const: tgic4
> +      - const: tgid4
> +      - const: tgiv4
> +      - const: tgiu5
> +      - const: tgiv5
> +      - const: tgiw5
> +      - const: tgia6
> +      - const: tgib6
> +      - const: tgic6
> +      - const: tgid6
> +      - const: tgiv6
> +      - const: tgia7
> +      - const: tgib7
> +      - const: tgic7
> +      - const: tgid7
> +      - const: tgiv7
> +      - const: tgia8
> +      - const: tgib8
> +      - const: tgic8
> +      - const: tgid8
> +      - const: tgiv8
> +      - const: tgiu8
> +
> +  clocks:
> +    maxItems: 1
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +  counter:
> +    description:
> +      There are two phase counting modes. 16-bit phase counting mode in which
> +      MTU1 and MTU2 operate independently, and cascade connection 32-bit phase
> +      counting mode in which MTU1 and MTU2 are cascaded.
> +
> +      In phase counting mode, the phase difference between two external input
> +      clocks is detected and the corresponding TCNT is incremented or
> +      decremented.
> +      The below counters are supported
> +        count0 - MTU1 16-bit phase counting
> +        count1 - MTU2 16-bit phase counting
> +        count2 - MTU1+ MTU2 32-bit phase counting
> +
> +    type: object
> +
> +    properties:
> +      compatible:
> +        const: renesas,rz-mtu3-counter
> +
> +    required:
> +      - compatible
> +
> +    additionalProperties: false
> +
> +  pwm:
> +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-names
> +  - clocks
> +  - power-domains
> +  - resets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    mtu3: timer@10001200 {
> +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
> +      reg = <0x10001200 0xb00>;
> +      interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
> +                   <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
> +      interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0",
> +                        "tgif0",
> +                        "tgia1", "tgib1", "tgiv1", "tgiu1",
> +                        "tgia2", "tgib2", "tgiv2", "tgiu2",
> +                        "tgia3", "tgib3", "tgic3", "tgid3", "tgiv3",
> +                        "tgia4", "tgib4", "tgic4", "tgid4", "tgiv4",
> +                        "tgiu5", "tgiv5", "tgiw5",
> +                        "tgia6", "tgib6", "tgic6", "tgid6", "tgiv6",
> +                        "tgia7", "tgib7", "tgic7", "tgid7", "tgiv7",
> +                        "tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8";
> +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
> +      power-domains = <&cpg>;
> +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
> +
> +      counter {
> +        compatible = "renesas,rz-mtu3-counter";

You don't have any resources for the counter in DT, so you don't even 
need a node here. Just have the parent driver instaniate the counter 
driver.

> +      };
> +
> +      pwm {
> +        compatible = "renesas,rz-mtu3-pwm";
> +        #pwm-cells = <2>;

Here too, just declaring a PWM provider. Just move this to the parent 
node.

Rob

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-06 20:17   ` Rob Herring
@ 2022-10-07 12:40     ` Biju Das
  2022-10-08  7:42       ` Biju Das
  0 siblings, 1 reply; 23+ messages in thread
From: Biju Das @ 2022-10-07 12:40 UTC (permalink / raw)
  To: Rob Herring
  Cc: Krzysztof Kozlowski, William Breathitt Gray, Thierry Reding,
	Lee Jones, Uwe Kleine-König, devicetree, linux-pwm,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi Rob,

Thanks for the feedback.

> Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> > The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in
> > the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
> > channels and one 32-bit timer channel. It supports the following
> > functions
> >  - Counter
> >  - Timer
> >  - PWM
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > ---
> > v2->v3:
> >  * Dropped counter bindings and integrated with mfd as it has only
> one property.
> >  * Removed "#address-cells" and "#size-cells" as it do not have
> children with
> >    unit addresses.
> >  * Removed quotes from counter and pwm.
> >  * Provided full path for pwm bindings.
> >  * Updated the example.
> > v1->v2:
> >  * Modelled counter and pwm as a single device that handles
> >    multiple channels.
> >  * Moved counter and pwm bindings to respective subsystems
> >  * Dropped 'bindings' from MFD binding title.
> >  * Updated the example
> >  * Changed the compatible names.
> > ---
> >  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304
> ++++++++++++++++++
> >  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
> >  2 files changed, 354 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> >  create mode 100644
> > Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > new file mode 100644
> > index 000000000000..44c952ad8d35
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > @@ -0,0 +1,304 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> >
> > +
> > +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
> > +
> > +maintainers:
> > +  - Biju Das <biju.das.jz@bp.renesas.com>
> > +
> > +description: |
> > +  This hardware block pconsisting of eight 16-bit timer channels
> and
> > +one
> > +  32- bit timer channel. It supports the following specifications:
> > +    - Pulse input/output: 28 lines max.
> > +    - Pulse input 3 lines
> > +    - Count clock 11 clocks for each channel (14 clocks for MTU0,
> 12 clocks
> > +      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2
> combination
> > +      (when LWA = 1))
> > +    - Operating frequency Up to 100 MHz
> > +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
> > +        - Waveform output on compare match
> > +        - Input capture function (noise filter setting available)
> > +        - Counter-clearing operation
> > +        - Simultaneous writing to multiple timer counters (TCNT)
> > +          (excluding MTU8).
> > +        - Simultaneous clearing on compare match or input capture
> > +          (excluding MTU8).
> > +        - Simultaneous input and output to registers in
> synchronization with
> > +          counter operations           (excluding MTU8).
> > +        - Up to 12-phase PWM output in combination with synchronous
> operation
> > +          (excluding MTU8)
> > +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> > +        - Buffer operation specifiable
> > +    - [MTU1, MTU2]
> > +        - Phase counting mode can be specified independently
> > +        - 32-bit phase counting mode can be specified for
> interlocked operation
> > +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> > +        - Cascade connection operation available
> > +    - [MTU3, MTU4, MTU6, and MTU7]
> > +        - Through interlocked operation of MTU3/4 and MTU6/7, the
> positive and
> > +          negative signals in six phases (12 phases in total) can
> be output in
> > +          complementary PWM and reset-synchronized PWM operation.
> > +        - In complementary PWM mode, values can be transferred from
> buffer
> > +          registers to temporary registers at crests and troughs of
> the timer-
> > +          counter values or when the buffer registers (TGRD
> registers in MTU4
> > +          and MTU7) are written to.
> > +        - Double-buffering selectable in complementary PWM mode.
> > +    - [MTU3 and MTU4]
> > +        - Through interlocking with MTU0, a mode for driving AC
> synchronous
> > +          motors (brushless DC motors) by using complementary PWM
> output and
> > +          reset-synchronized PWM output is settable and allows the
> selection
> > +          of two types of waveform output (chopping or level).
> > +    - [MTU5]
> > +        - Capable of operation as a dead-time compensation counter.
> > +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> > +        - 32-bit phase counting mode specifiable by combining MTU1
> and MTU2 and
> > +          through interlocked operation with MTU0/MTU5 and MTU8.
> > +    - Interrupt-skipping function
> > +        - In complementary PWM mode, interrupts on crests and
> troughs of counter
> > +          values and triggers to start conversion by the A/D
> converter can be
> > +          skipped.
> > +    - Interrupt sources: 43 sources.
> > +    - Buffer operation:
> > +        - Automatic transfer of register data (transfer from the
> buffer
> > +          register to the timer register).
> > +    - Trigger generation
> > +        - A/D converter start triggers can be generated
> > +        - A/D converter start request delaying function enables A/D
> converter
> > +          to be started with any desired timing and to be
> synchronized with
> > +          PWM output.
> > +    - Low power consumption function
> > +        - The MTU3a can be placed in the module-stop state.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> > +          - renesas,r9a07g054-mtu3  # RZ/V2L
> > +      - const: renesas,rz-mtu3
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    items:
> > +      - description: MTU0.TGRA input capture/compare match
> > +      - description: MTU0.TGRB input capture/compare match
> > +      - description: MTU0.TGRC input capture/compare match
> > +      - description: MTU0.TGRD input capture/compare match
> > +      - description: MTU0.TCNT overflow
> > +      - description: MTU0.TGRE compare match
> > +      - description: MTU0.TGRF compare match
> > +      - description: MTU1.TGRA input capture/compare match
> > +      - description: MTU1.TGRB input capture/compare match
> > +      - description: MTU1.TCNT overflow
> > +      - description: MTU1.TCNT underflow
> > +      - description: MTU2.TGRA input capture/compare match
> > +      - description: MTU2.TGRB input capture/compare match
> > +      - description: MTU2.TCNT overflow
> > +      - description: MTU2.TCNT underflow
> > +      - description: MTU3.TGRA input capture/compare match
> > +      - description: MTU3.TGRB input capture/compare match
> > +      - description: MTU3.TGRC input capture/compare match
> > +      - description: MTU3.TGRD input capture/compare match
> > +      - description: MTU3.TCNT overflow
> > +      - description: MTU4.TGRA input capture/compare match
> > +      - description: MTU4.TGRB input capture/compare match
> > +      - description: MTU4.TGRC input capture/compare match
> > +      - description: MTU4.TGRD input capture/compare match
> > +      - description: MTU4.TCNT overflow/underflow
> > +      - description: MTU5.TGRU input capture/compare match
> > +      - description: MTU5.TGRV input capture/compare match
> > +      - description: MTU5.TGRW input capture/compare match
> > +      - description: MTU6.TGRA input capture/compare match
> > +      - description: MTU6.TGRB input capture/compare match
> > +      - description: MTU6.TGRC input capture/compare match
> > +      - description: MTU6.TGRD input capture/compare match
> > +      - description: MTU6.TCNT overflow
> > +      - description: MTU7.TGRA input capture/compare match
> > +      - description: MTU7.TGRB input capture/compare match
> > +      - description: MTU7.TGRC input capture/compare match
> > +      - description: MTU7.TGRD input capture/compare match
> > +      - description: MTU7.TCNT overflow/underflow
> > +      - description: MTU8.TGRA input capture/compare match
> > +      - description: MTU8.TGRB input capture/compare match
> > +      - description: MTU8.TGRC input capture/compare match
> > +      - description: MTU8.TGRD input capture/compare match
> > +      - description: MTU8.TCNT overflow
> > +      - description: MTU8.TCNT underflow
> > +
> > +  interrupt-names:
> > +    items:
> > +      - const: tgia0
> > +      - const: tgib0
> > +      - const: tgic0
> > +      - const: tgid0
> > +      - const: tgiv0
> > +      - const: tgie0
> > +      - const: tgif0
> > +      - const: tgia1
> > +      - const: tgib1
> > +      - const: tgiv1
> > +      - const: tgiu1
> > +      - const: tgia2
> > +      - const: tgib2
> > +      - const: tgiv2
> > +      - const: tgiu2
> > +      - const: tgia3
> > +      - const: tgib3
> > +      - const: tgic3
> > +      - const: tgid3
> > +      - const: tgiv3
> > +      - const: tgia4
> > +      - const: tgib4
> > +      - const: tgic4
> > +      - const: tgid4
> > +      - const: tgiv4
> > +      - const: tgiu5
> > +      - const: tgiv5
> > +      - const: tgiw5
> > +      - const: tgia6
> > +      - const: tgib6
> > +      - const: tgic6
> > +      - const: tgid6
> > +      - const: tgiv6
> > +      - const: tgia7
> > +      - const: tgib7
> > +      - const: tgic7
> > +      - const: tgid7
> > +      - const: tgiv7
> > +      - const: tgia8
> > +      - const: tgib8
> > +      - const: tgic8
> > +      - const: tgid8
> > +      - const: tgiv8
> > +      - const: tgiu8
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  power-domains:
> > +    maxItems: 1
> > +
> > +  resets:
> > +    maxItems: 1
> > +
> > +  counter:
> > +    description:
> > +      There are two phase counting modes. 16-bit phase counting
> mode in which
> > +      MTU1 and MTU2 operate independently, and cascade connection
> 32-bit phase
> > +      counting mode in which MTU1 and MTU2 are cascaded.
> > +
> > +      In phase counting mode, the phase difference between two
> external input
> > +      clocks is detected and the corresponding TCNT is incremented
> or
> > +      decremented.
> > +      The below counters are supported
> > +        count0 - MTU1 16-bit phase counting
> > +        count1 - MTU2 16-bit phase counting
> > +        count2 - MTU1+ MTU2 32-bit phase counting
> > +
> > +    type: object
> > +
> > +    properties:
> > +      compatible:
> > +        const: renesas,rz-mtu3-counter
> > +
> > +    required:
> > +      - compatible
> > +
> > +    additionalProperties: false
> > +
> > +  pwm:
> > +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - interrupt-names
> > +  - clocks
> > +  - power-domains
> > +  - resets
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +
> > +    mtu3: timer@10001200 {
> > +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
> > +      reg = <0x10001200 0xb00>;
> > +      interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
> > +                   <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
> > +      interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0",
> "tgiv0", "tgie0",
> > +                        "tgif0",
> > +                        "tgia1", "tgib1", "tgiv1", "tgiu1",
> > +                        "tgia2", "tgib2", "tgiv2", "tgiu2",
> > +                        "tgia3", "tgib3", "tgic3", "tgid3",
> "tgiv3",
> > +                        "tgia4", "tgib4", "tgic4", "tgid4",
> "tgiv4",
> > +                        "tgiu5", "tgiv5", "tgiw5",
> > +                        "tgia6", "tgib6", "tgic6", "tgid6",
> "tgiv6",
> > +                        "tgia7", "tgib7", "tgic7", "tgid7",
> "tgiv7",
> > +                        "tgia8", "tgib8", "tgic8", "tgid8",
> "tgiv8", "tgiu8";
> > +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
> > +      power-domains = <&cpg>;
> > +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
> > +
> > +      counter {
> > +        compatible = "renesas,rz-mtu3-counter";
> 
> You don't have any resources for the counter in DT, so you don't even
> need a node here. Just have the parent driver instaniate the counter
> driver.

OK will remove the node and compatible(renesas,rz-mtu3-counter) and will add 
support for parent driver Instaniate the counter driver by just using 
"renesas,rz-mtu3" as it has resources.

> 
> > +      };
> > +
> > +      pwm {
> > +        compatible = "renesas,rz-mtu3-pwm";
> > +        #pwm-cells = <2>;
> 
> Here too, just declaring a PWM provider. Just move this to the parent
> node.

OK, will remove node and compatible. Will add support for parent driver instaniate
the PWM driver and also declaring as a PWM provider.

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-06 13:57 ` [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver Biju Das
@ 2022-10-08  1:37   ` William Breathitt Gray
  2022-10-08  9:01     ` Biju Das
  0 siblings, 1 reply; 23+ messages in thread
From: William Breathitt Gray @ 2022-10-08  1:37 UTC (permalink / raw)
  To: Biju Das
  Cc: linux-iio, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 26334 bytes --]

On Thu, Oct 06, 2022 at 02:57:17PM +0100, Biju Das wrote:
> Add RZ/G2L MTU3 counter driver.
> 
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>

Hi Biju,

This commit message is rather brief for an introduction of a new driver.
Provide a description of the functionality provided (e.g. two 16-bit
Counts or one 32-bit Count) as well as the hardware this driver supports
for context (e.g. what does MTU3 mean; is this a SoC; etc.).

> ---
> v1->v3:
>  * Modelled as a counter device supporting 3 counters(2 16-bit and 
>    32-bit)
>  * Add kernel-doc comments to document struct rz_mtu3_cnt
>  * Removed mmio variable from struct rz_mtu3_cnt
>  * Removed cnt local variable from rz_mtu3_count_read()
>  * Replaced -EINVAL->-ERANGE for out of range error conditions.
>  * Removed explicit cast from write functions.
>  * Removed local variable val from rz_mtu3_count_ceiling_read()
>  * Added lock for RMW for counter/ceiling updates.
>  * Added different synapses for counter0 and counter{1,2}
>  * Used ARRAY for assigning num_counts.
>  * Added PM runtime for managing clocks.
>  * Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.
> ---
>  drivers/counter/Kconfig       |   9 +
>  drivers/counter/Makefile      |   1 +
>  drivers/counter/rz-mtu3-cnt.c | 568 ++++++++++++++++++++++++++++++++++
>  3 files changed, 578 insertions(+)
>  create mode 100644 drivers/counter/rz-mtu3-cnt.c
> 
> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
> index d388bf26f4dc..531b187e4630 100644
> --- a/drivers/counter/Kconfig
> +++ b/drivers/counter/Kconfig
> @@ -39,6 +39,15 @@ config INTERRUPT_CNT
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called interrupt-cnt.
>  
> +config RZ_MTU3_CNT
> +	tristate "RZ/G2L MTU3 counter driver"
> +	depends on MFD_RZ_MTU3 || COMPILE_TEST
> +	help
> +	  Select this option to enable RZ/G2L MTU3 counter driver.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called rz-mtu3-cnt.
> +

Provide a bit more description of the hardware here; you should at least
mention this is a Renesas RZ/G2L as opposed to some other manufacturer.

>  config STM32_TIMER_CNT
>  	tristate "STM32 Timer encoder counter driver"
>  	depends on MFD_STM32_TIMERS || COMPILE_TEST
> diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
> index b9a369e0d4fc..933fdd50b3e4 100644
> --- a/drivers/counter/Makefile
> +++ b/drivers/counter/Makefile
> @@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o counter-chrdev.o
>  
>  obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
>  obj-$(CONFIG_INTERRUPT_CNT)		+= interrupt-cnt.o
> +obj-$(CONFIG_RZ_MTU3_CNT)	+= rz-mtu3-cnt.o
>  obj-$(CONFIG_STM32_TIMER_CNT)	+= stm32-timer-cnt.o
>  obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
>  obj-$(CONFIG_TI_EQEP)		+= ti-eqep.o
> diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c
> new file mode 100644
> index 000000000000..26b5ea3852f8
> --- /dev/null
> +++ b/drivers/counter/rz-mtu3-cnt.c
> @@ -0,0 +1,568 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas RZ/G2L MTU3a Counter driver
> + *
> + * Copyright (C) 2022 Renesas Electronics Corporation
> + */
> +#include <linux/counter.h>
> +#include <linux/mfd/rz-mtu3.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/types.h>
> +
> +#define RZ_MTU3_TSR_TCFD	BIT(7)
> +#define RZ_MTU3_MAX_HW_CNTR_CHANNELS	(2)
> +
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_1	(4)
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_2	(5)
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_3	(6)
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_4	(7)
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_5	(9)
> +#define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK	(0xf)
> +
> +#define RZ_MTU3_TCR_CCLR	GENMASK(7, 5)
> +#define RZ_MTU3_TCR_CCLR_NONE	FIELD_PREP(RZ_MTU3_TCR_CCLR, 0)
> +
> +#define RZ_MTU3_TMDR3_LWA	BIT(0)
> +#define RZ_MTU3_32_BIT_CH	(2)

Providing a define to identify the 32-bit channel is a good idea.
Defines for the other two 16-bit channels would also be good.

> +
> +#define RZ_MTU3_TIOR_IC_BOTH	(10)
> +
> +/**
> + * struct rz_mtu3_cnt - MTU3 counter private data
> + *
> + * @clk: MTU3 module clock
> + * @lock: Lock to prevent concurrent access for ceiling and count
> + * @rz_mtu3_channel: HW channels for the counters
> + */
> +struct rz_mtu3_cnt {
> +	struct clk *clk;
> +	struct mutex lock;
> +	struct rz_mtu3_channel *ch[RZ_MTU3_MAX_HW_CNTR_CHANNELS];

Does this need to be a pointer to an array of struct rz_mtu3_channel?
You can avoid the double dereferences in your code if you leave it as a
simple pointer to struct rz_mtu3_channel and use subscripts directly as
you would an array. Or is there something I'm missing?

> +};
> +
> +static const enum counter_function rz_mtu3_count_functions[] = {
> +	COUNTER_FUNCTION_QUADRATURE_X4,
> +	COUNTER_FUNCTION_PULSE_DIRECTION,
> +	COUNTER_FUNCTION_QUADRATURE_X2_B,
> +};
> +
> +static bool rz_mtu3_is_16_bit_cnt_mode(struct rz_mtu3_cnt *const priv)
> +{
> +	return (priv->ch[0]->function == RZ_MTU3_16BIT_PHASE_COUNTING ||
> +		priv->ch[1]->function == RZ_MTU3_16BIT_PHASE_COUNTING);

Is there ever a situation where one channel is equal to
RZ_MTU3_16BIT_PHASE_COUNTING while the other channel is equal to
RZ_MTU3_32BIT_PHASE_COUNTING?

> +}
> +
> +static bool rz_mtu3_is_32_bit_cnt_mode(struct rz_mtu3_cnt *const priv)
> +{
> +	return (priv->ch[0]->function == RZ_MTU3_32BIT_PHASE_COUNTING &&
> +		priv->ch[1]->function == RZ_MTU3_32BIT_PHASE_COUNTING);
> +}
> +
> +static int rz_mtu3_count_read(struct counter_device *counter,
> +			      struct counter_count *count, u64 *val)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

It is not immediately clear why you are ANDing the Count id here. After
looking at the rest of the code in this function I realized it's because
you want to call rz_mtu3_32bit_ch_read() with id = 0 when you have
count->id = RZ_MTU3_32_BIT_CH.

I wouldn't even bother with the local id variable in this function and
instead just hardcode priv->ch[0] in the rz_mtu3_32bit_ch_read() call
below directly.

> +
> +	if (count->id == RZ_MTU3_32_BIT_CH)
> +		*val = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TCNTLW);
> +	else
> +		*val = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TCNT);

Is there a risk of these read calls returning an error code?

> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_write(struct counter_device *counter,
> +			       struct counter_count *count, const u64 val)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

Same comment about local id variable as in rz_mtu3_count_read().

> +	u32 ceiling;
> +
> +	mutex_lock(&priv->lock);
> +	if (count->id == RZ_MTU3_32_BIT_CH)
> +		ceiling = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TGRALW);
> +	else
> +		ceiling = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TGRA);

The ceiling value isn't expected to change unless the user executes your
ceiling_write() function, right? It might make sense to cache the
current ceiling value in your rz_mtu3_cnt structure so that you don't
have to read it out from the device every time you check it.

> +
> +	if (val > ceiling) {
> +		mutex_unlock(&priv->lock);
> +		return -ERANGE;
> +	}
> +
> +	if (count->id == RZ_MTU3_32_BIT_CH)
> +		rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TCNTLW, val);
> +	else
> +		rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TCNT, val);
> +
> +	mutex_unlock(&priv->lock);
> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_function_read(struct counter_device *counter,
> +				       struct counter_count *count,
> +				       enum counter_function *function)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

As mentioned before, this AND operation obscures the intention of your
code. Instead, rename this variable and account for RZ_MTU3_32_BIT_CH
explicitly with something like this:

    const size_t ch_id = (count->id == RZ_MTU3_32_BIT_CH) ? 0 : count->id;

You could wrap this into a preprocessor macro to reuse again in your
code, but I'll leave it up to you if you want.

> +	u8 val;
> +
> +	val = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TMDR1);
> +
> +	switch (val & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
> +	case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
> +		*function = COUNTER_FUNCTION_QUADRATURE_X4;
> +		break;
> +	case RZ_MTU3_TMDR1_PH_CNT_MODE_2:
> +		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
> +		break;
> +	case RZ_MTU3_TMDR1_PH_CNT_MODE_4:
> +		*function = COUNTER_FUNCTION_QUADRATURE_X2_B;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_function_write(struct counter_device *counter,
> +					struct counter_count *count,
> +					enum counter_function function)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

Same comment as in rz_mtu3_count_function_read().

> +	u8 mode;
> +
> +	switch (function) {
> +	case COUNTER_FUNCTION_QUADRATURE_X4:
> +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1;
> +		break;
> +	case COUNTER_FUNCTION_PULSE_DIRECTION:
> +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2;
> +		break;
> +	case COUNTER_FUNCTION_QUADRATURE_X2_B:
> +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1, mode);
> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_direction_read(struct counter_device *counter,
> +					struct counter_count *count,
> +					enum counter_count_direction *direction)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

Same comment as in rz_mtu3_count_function_read().

> +	u8 cnt;
> +
> +	cnt = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TSR);

This is the timer status register, right? A variable name of 'cnt' seems
a bit strange to me; would 'tsr' be a better name here?

> +
> +	if (cnt & RZ_MTU3_TSR_TCFD)
> +		*direction = COUNTER_COUNT_DIRECTION_FORWARD;
> +	else
> +		*direction = COUNTER_COUNT_DIRECTION_BACKWARD;
> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_ceiling_read(struct counter_device *counter,
> +				      struct counter_count *count,
> +				      u64 *ceiling)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

Same comment about local id variable as in rz_mtu3_count_read().

> +
> +	if (count->id == RZ_MTU3_32_BIT_CH)
> +		*ceiling = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TGRALW);
> +	else
> +		*ceiling = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TGRA);

Assuming you're able to cache the ceiling value, you can set it here
directly and avoid the reads out to the device.

> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_ceiling_write(struct counter_device *counter,
> +				       struct counter_count *count,
> +				       u64 ceiling)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	u32 id = count->id & 1;

Same comment as in rz_mtu3_count_function_read().

> +	if (ceiling > U16_MAX && rz_mtu3_is_16_bit_cnt_mode(priv))
> +		return -ERANGE;
> +
> +	if (ceiling > U32_MAX && rz_mtu3_is_32_bit_cnt_mode(priv))
> +		return -ERANGE;

You can determine which maximum to consider by checking the count->id.
Instead of those two conditional statments, try this instead:

    switch (count->id) {
    case 0:
    case 1:
            if (ceiling > U16_MAX)
                    return -ERANGE;
            break;
    case RZ_MTU3_32_BIT_CH:
            if (ceiling > U32_MAX)
                    return -ERANGE;
            break;
    }

If you need to check whether you're in 32-bit phase mode before setting
the ceiling for the RZ_MTU3_32_BIT_CH Count (and similarly for the
16-bit Counts), check that separately and return -EBUSY as appropriate.

> +	mutex_lock(&priv->lock);
> +	if (ceiling == 0) {
> +		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> +				      RZ_MTU3_TCR_CCLR_NONE);

Looks like something different is done when ceiling is set to 0. Would
you explain what's happening in this case and why it's different that
then else case below; in other words, what's the difference between
RZ_MTU3_TCR_CCLR_NONE and RZ_MTU3_TCR_CCLR_TGRA?

> +

You can remove this empty line.

> +	} else {
> +		if (count->id == RZ_MTU3_32_BIT_CH)
> +			rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TGRALW, ceiling);
> +		else
> +			rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA, ceiling);
> +
> +		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> +				      RZ_MTU3_TCR_CCLR_TGRA);
> +	}
> +	mutex_unlock(&priv->lock);
> +
> +	return 0;
> +}
> +
> +static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter, int id)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +
> +	/*
> +	 * 32-bit phase counting need MTU1 and MTU2 to create 32-bit cascade
> +	 * counter.
> +	 */
> +	priv->ch[0]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
> +	priv->ch[1]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
> +
> +	rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3, RZ_MTU3_TMDR3_LWA);
> +
> +	/* Phase counting mode 1 is used as default in initialization. */
> +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TMDR1,
> +			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
> +
> +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
> +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TIOR, RZ_MTU3_TIOR_IC_BOTH);
> +
> +	rz_mtu3_enable(priv->ch[0]);
> +	rz_mtu3_enable(priv->ch[1]);
> +}
> +
> +static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +
> +	priv->ch[id]->function = RZ_MTU3_16BIT_PHASE_COUNTING;

If 16-bit phase counting is selected for one 16-bit counter, does the
other 16-bit counter need to be configured as well?

> +
> +	/* Phase counting mode 1 is used as default in initialization. */
> +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1,
> +			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
> +
> +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
> +	rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA, U16_MAX);
> +
> +	rz_mtu3_enable(priv->ch[id]);
> +}
> +
> +static int rz_mtu3_initialize_counter(struct counter_device *counter, int id)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +
> +	if (id == RZ_MTU3_32_BIT_CH && rz_mtu3_is_16_bit_cnt_mode(priv))
> +		return -EBUSY;
> +
> +	if (id != RZ_MTU3_32_BIT_CH && rz_mtu3_is_32_bit_cnt_mode(priv))
> +		return -EBUSY;
> +
> +	if (id == RZ_MTU3_32_BIT_CH)
> +		rz_mtu3_32bit_cnt_setting(counter, id);
> +	else
> +		rz_mtu3_16bit_cnt_setting(counter, id);

I think this code would flow better using a switch statement like this:

    switch (id) {
    case 0:
    case 1:
            if (rz_mtu3_is_32_bit_cnt_mode(priv))
                    return -EBUSY;
            rz_mtu3_16bit_cnt_setting(counter, id);
            break;
    case RZ_MTU3_32_BIT_CH:
            if (rz_mtu3_is_16_bit_cnt_mode(priv))
                    return -EBUSY;
            rz_mtu3_32bit_cnt_setting(counter, id);
            break;
    }

You should also protect this with a lock to prevent any races while
you're accessing and modifying the settings.

> +
> +	return 0;
> +}
> +
> +static void rz_mtu3_terminate_counter(struct counter_device *counter, int id)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +
> +	if (id == RZ_MTU3_32_BIT_CH) {
> +		priv->ch[0]->function = RZ_MTU3_NORMAL;
> +		priv->ch[1]->function = RZ_MTU3_NORMAL;
> +		rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3, 0);
> +		rz_mtu3_disable(priv->ch[1]);
> +		rz_mtu3_disable(priv->ch[0]);
> +	} else {
> +		priv->ch[id]->function = RZ_MTU3_NORMAL;
> +		rz_mtu3_disable(priv->ch[id]);
> +	}

You probably need a lock in this function to prevent races.

> +}
> +
> +static int rz_mtu3_count_enable_read(struct counter_device *counter,
> +				     struct counter_count *count, u8 *enable)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +
> +	if (count->id == RZ_MTU3_32_BIT_CH)
> +		*enable = rz_mtu3_is_enabled(priv->ch[0]) &&
> +			rz_mtu3_is_enabled(priv->ch[1]);

There's a race between checking for channel 0 and channel 1, so use a
lock to prevent that.

> +	else
> +		*enable = rz_mtu3_is_enabled(priv->ch[count->id]);
> +
> +	return 0;
> +}
> +
> +static int rz_mtu3_count_enable_write(struct counter_device *counter,
> +				      struct counter_count *count, u8 enable)
> +{
> +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> +	struct rz_mtu3_channel *ch = priv->ch[count->id & 0x1];

Same comment about the AND operation as mentioned before.

> +	int ret = 0;
> +
> +	if (enable) {
> +		pm_runtime_get_sync(ch->dev);
> +		ret = rz_mtu3_initialize_counter(counter, count->id);

Are you using the Count's "enable" extension to switch between 16-bit
and 32-bit phase modes?

> +	} else {
> +		rz_mtu3_terminate_counter(counter, count->id);
> +		pm_runtime_put(ch->dev);
> +	}
> +
> +	return ret;
> +}
> +
> +static struct counter_comp rz_mtu3_count_ext[] = {
> +	COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read),
> +	COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read,
> +			    rz_mtu3_count_enable_write),
> +	COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read,
> +			     rz_mtu3_count_ceiling_write),
> +};
> +
> +static const enum counter_synapse_action rz_mtu3_synapse_actions[] = {
> +	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
> +	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
> +	COUNTER_SYNAPSE_ACTION_NONE,
> +};
> +
> +static int rz_mtu3_action_read(struct counter_device *counter,
> +			       struct counter_count *count,
> +			       struct counter_synapse *synapse,
> +			       enum counter_synapse_action *action)
> +{
> +	const size_t signal_a_id = count->synapses[0].signal->id;
> +	const size_t signal_b_id = count->synapses[1].signal->id;

If this is "Channel 2" Count then you will have four Synapses for
four possible Signals (MTCLKA, MTCLKB, MTCLKC, MTCLKD), so you'll need
to account for those two other Signals as well.

> +	enum counter_function function;
> +	int err;
> +
> +	err = rz_mtu3_count_function_read(counter, count, &function);
> +	if (err)
> +		return err;
> +
> +	/* Default action mode */
> +	*action = COUNTER_SYNAPSE_ACTION_NONE;
> +
> +	switch (function) {
> +	case COUNTER_FUNCTION_PULSE_DIRECTION:
> +		/*
> +		 * Rising edges on signal A updates the respective count.
> +		 * The input level of signal B determines direction.
> +		 */
> +		if (synapse->signal->id == signal_a_id)
> +			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
> +		break;
> +	case COUNTER_FUNCTION_QUADRATURE_X2_B:
> +		/*
> +		 * Any state transition on quadrature pair signal B updates
> +		 * the respective count.
> +		 */
> +		if (synapse->signal->id == signal_b_id)
> +			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
> +		break;
> +	case COUNTER_FUNCTION_QUADRATURE_X4:
> +		/* counts up/down on both edges of A and B signal*/
> +		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct counter_ops rz_mtu3_cnt_ops = {
> +	.count_read = rz_mtu3_count_read,
> +	.count_write = rz_mtu3_count_write,
> +	.function_read = rz_mtu3_count_function_read,
> +	.function_write = rz_mtu3_count_function_write,
> +	.action_read = rz_mtu3_action_read,
> +};
> +
> +#define RZ_MTU3_PHASE_SIGNAL(_id, _name) {		\
> +	.id = (_id),				\
> +	.name = (_name),			\
> +}
> +
> +static struct counter_signal rz_mtu3_signals[] = {
> +	RZ_MTU3_PHASE_SIGNAL(0, "MTU1 MTCLKA"),
> +	RZ_MTU3_PHASE_SIGNAL(1, "MTU1 MTCLKB"),
> +	RZ_MTU3_PHASE_SIGNAL(2, "MTU2 MTCLKC"),
> +	RZ_MTU3_PHASE_SIGNAL(3, "MTU2 MTCLKD"),
> +};

These names can be in a human-readable form (e.g. "Multi-function Timer
Clock A") if you think it's easier to understand, but I'll leave it up
to you if you want to change it.

> +
> +#define RZ_MTU3_COUNT_SYNAPSES(_id) {					\
> +	{								\
> +		.actions_list = rz_mtu3_synapse_actions,		\
> +		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
> +		.signal = rz_mtu3_signals + 2 * (_id)			\
> +	},								\
> +	{								\
> +		.actions_list = rz_mtu3_synapse_actions,		\
> +		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
> +		.signal = rz_mtu3_signals + 2 * (_id) + 1		\
> +	}								\
> +}
> +
> +static struct counter_synapse rz_mtu3_count_synapses[][2] = {
> +	RZ_MTU3_COUNT_SYNAPSES(0), RZ_MTU3_COUNT_SYNAPSES(1)
> +};

I know the 104-quad-8 module also creates a multidimensional array to
represent the synapses, but I would advise against this pattern because
it obscures the intention of the code.

Instead, create a separate distinct array for each group of Synapses; I
suppose there will be two arrays in this case judging from your existing
code.

> +
> +static struct counter_count rz_mtu3_counts[] = {
> +	{
> +		.id = 0,
> +		.name = "Channel 1 Count(16-bit)",
> +		.functions_list = rz_mtu3_count_functions,
> +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> +		.synapses = rz_mtu3_count_synapses[0],
> +		.num_synapses = 2,

As mentioned in the comment above, refer to the distinct Synapse array
for the particular Count and then use ARRAY_SIZE for that array to set
num_synapses.

> +		.ext = rz_mtu3_count_ext,
> +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> +	},
> +	{
> +		.id = 1,
> +		.name = "Channel 2 Count(16-bit)",
> +		.functions_list = rz_mtu3_count_functions,
> +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> +		.synapses = rz_mtu3_count_synapses[0],
> +		.num_synapses = 4,
> +		.ext = rz_mtu3_count_ext,
> +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> +	},
> +	{
> +		.id = 2,

Set id = RZ_MTU3_32_BIT_CH to make it more obvious here.

> +		.name = "Channel3 Count(32-bit)",

We probably don't need the "(32-bit)" in the name when it's obvious
already from the channel id and ceiling value.

I wonder how this counter is described in the RZ/G2L user documentation;
is it named "Channel 3" or "Channel 1 and 2"?

> +		.functions_list = rz_mtu3_count_functions,
> +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> +		.synapses = rz_mtu3_count_synapses[0],
> +		.num_synapses = 4,
> +		.ext = rz_mtu3_count_ext,
> +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> +	}
> +};
> +
> +static int __maybe_unused rz_mtu3_cnt_pm_runtime_suspend(struct device *dev)
> +{
> +	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(priv->clk);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused rz_mtu3_cnt_pm_runtime_resume(struct device *dev)
> +{
> +	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
> +
> +	clk_prepare_enable(priv->clk);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops rz_mtu3_cnt_pm_ops = {
> +	SET_RUNTIME_PM_OPS(rz_mtu3_cnt_pm_runtime_suspend, rz_mtu3_cnt_pm_runtime_resume, NULL)
> +};
> +
> +static void rz_mtu3_cnt_pm_disable(void *data)
> +{
> +	struct device *dev = data;
> +
> +	pm_runtime_disable(dev);
> +	pm_runtime_set_suspended(dev);
> +}
> +
> +static int rz_mtu3_cnt_probe(struct platform_device *pdev)
> +{
> +	struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent);
> +	struct device *dev = &pdev->dev;
> +	struct counter_device *counter;
> +	struct rz_mtu3_cnt *priv;
> +	unsigned int i;
> +	int ret;
> +
> +	counter = devm_counter_alloc(dev, sizeof(*priv));
> +	if (!counter)
> +		return -ENOMEM;
> +
> +	priv = counter_priv(counter);
> +	priv->clk = ddata->clk;
> +
> +	for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) {
> +		priv->ch[i] = &ddata->channels[RZ_MTU1 + i];
> +		priv->ch[i]->dev = dev;
> +		if (priv->ch[i]->function != RZ_MTU3_NORMAL)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "channel '%u' is already claimed\n", i);
> +	}
> +
> +	mutex_init(&priv->lock);
> +	clk_prepare_enable(priv->clk);
> +	pm_runtime_set_active(&pdev->dev);
> +	pm_runtime_enable(&pdev->dev);
> +	ret = devm_add_action_or_reset(&pdev->dev,
> +				       rz_mtu3_cnt_pm_disable,
> +				       dev);
> +	if (ret < 0)
> +		goto disable_clock;
> +
> +	counter->name = dev_name(dev);
> +	counter->parent = dev;
> +	counter->ops = &rz_mtu3_cnt_ops;
> +	counter->counts = rz_mtu3_counts;
> +	counter->num_counts = ARRAY_SIZE(rz_mtu3_counts);
> +	counter->signals = rz_mtu3_signals;
> +	counter->num_signals = ARRAY_SIZE(rz_mtu3_signals);
> +	platform_set_drvdata(pdev, priv);

It looks like you only ever use clk in your callbacks; how about setting
your drvdata to clk instead and removing it from your rz_mtu3_cnt
structure?

William Breathitt Gray

> +
> +	/* Register Counter device */
> +	ret = devm_counter_add(dev, counter);
> +	if (ret < 0) {
> +		dev_err_probe(dev, ret, "Failed to add counter\n");
> +		goto disable_clock;
> +	}
> +
> +	return 0;
> +
> +disable_clock:
> +	clk_disable_unprepare(priv->clk);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id rz_mtu3_cnt_of_match[] = {
> +	{ .compatible = "renesas,rz-mtu3-counter", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, rz_mtu3_cnt_of_match);
> +
> +static struct platform_driver rz_mtu3_cnt_driver = {
> +	.probe = rz_mtu3_cnt_probe,
> +	.driver = {
> +		.name = "rz-mtu3-counter",
> +		.pm = &rz_mtu3_cnt_pm_ops,
> +		.of_match_table = rz_mtu3_cnt_of_match,
> +	},
> +};
> +module_platform_driver(rz_mtu3_cnt_driver);
> +
> +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> +MODULE_ALIAS("platform:rz-mtu3-counter");
> +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS(COUNTER);
> -- 
> 2.25.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-07 12:40     ` Biju Das
@ 2022-10-08  7:42       ` Biju Das
  2022-10-08 10:51         ` Biju Das
                           ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Biju Das @ 2022-10-08  7:42 UTC (permalink / raw)
  To: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel
  Cc: Krzysztof Kozlowski, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi Rob and all,

> Subject: RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> Hi Rob,
> 
> Thanks for the feedback.
> 
> > Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> > bindings
> >
> > On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> > > The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded
> in
> > > the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
> > > channels and one 32-bit timer channel. It supports the following
> > > functions
> > >  - Counter
> > >  - Timer
> > >  - PWM
> > >
> > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > > ---
> > > v2->v3:
> > >  * Dropped counter bindings and integrated with mfd as it has only
> > one property.
> > >  * Removed "#address-cells" and "#size-cells" as it do not have
> > children with
> > >    unit addresses.
> > >  * Removed quotes from counter and pwm.
> > >  * Provided full path for pwm bindings.
> > >  * Updated the example.
> > > v1->v2:
> > >  * Modelled counter and pwm as a single device that handles
> > >    multiple channels.
> > >  * Moved counter and pwm bindings to respective subsystems
> > >  * Dropped 'bindings' from MFD binding title.
> > >  * Updated the example
> > >  * Changed the compatible names.
> > > ---
> > >  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304
> > ++++++++++++++++++
> > >  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
> > >  2 files changed, 354 insertions(+)
> > >  create mode 100644
> > > Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > >  create mode 100644
> > > Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > new file mode 100644
> > > index 000000000000..44c952ad8d35
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > @@ -0,0 +1,304 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> 1.2
> > > +---
> > > +$id:
> > >
> > > +
> > > +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
> > > +
> > > +maintainers:
> > > +  - Biju Das <biju.das.jz@bp.renesas.com>
> > > +
> > > +description: |
> > > +  This hardware block pconsisting of eight 16-bit timer channels
> > and
> > > +one
> > > +  32- bit timer channel. It supports the following
> specifications:
> > > +    - Pulse input/output: 28 lines max.
> > > +    - Pulse input 3 lines
> > > +    - Count clock 11 clocks for each channel (14 clocks for MTU0,
> > 12 clocks
> > > +      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2
> > combination
> > > +      (when LWA = 1))
> > > +    - Operating frequency Up to 100 MHz
> > > +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
> > > +        - Waveform output on compare match
> > > +        - Input capture function (noise filter setting available)
> > > +        - Counter-clearing operation
> > > +        - Simultaneous writing to multiple timer counters (TCNT)
> > > +          (excluding MTU8).
> > > +        - Simultaneous clearing on compare match or input capture
> > > +          (excluding MTU8).
> > > +        - Simultaneous input and output to registers in
> > synchronization with
> > > +          counter operations           (excluding MTU8).
> > > +        - Up to 12-phase PWM output in combination with
> synchronous
> > operation
> > > +          (excluding MTU8)
> > > +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> > > +        - Buffer operation specifiable
> > > +    - [MTU1, MTU2]
> > > +        - Phase counting mode can be specified independently
> > > +        - 32-bit phase counting mode can be specified for
> > interlocked operation
> > > +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> > > +        - Cascade connection operation available
> > > +    - [MTU3, MTU4, MTU6, and MTU7]
> > > +        - Through interlocked operation of MTU3/4 and MTU6/7, the
> > positive and
> > > +          negative signals in six phases (12 phases in total) can
> > be output in
> > > +          complementary PWM and reset-synchronized PWM operation.
> > > +        - In complementary PWM mode, values can be transferred
> from
> > buffer
> > > +          registers to temporary registers at crests and troughs
> of
> > the timer-
> > > +          counter values or when the buffer registers (TGRD
> > registers in MTU4
> > > +          and MTU7) are written to.
> > > +        - Double-buffering selectable in complementary PWM mode.
> > > +    - [MTU3 and MTU4]
> > > +        - Through interlocking with MTU0, a mode for driving AC
> > synchronous
> > > +          motors (brushless DC motors) by using complementary PWM
> > output and
> > > +          reset-synchronized PWM output is settable and allows
> the
> > selection
> > > +          of two types of waveform output (chopping or level).
> > > +    - [MTU5]
> > > +        - Capable of operation as a dead-time compensation
> counter.
> > > +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> > > +        - 32-bit phase counting mode specifiable by combining
> MTU1
> > and MTU2 and
> > > +          through interlocked operation with MTU0/MTU5 and MTU8.
> > > +    - Interrupt-skipping function
> > > +        - In complementary PWM mode, interrupts on crests and
> > troughs of counter
> > > +          values and triggers to start conversion by the A/D
> > converter can be
> > > +          skipped.
> > > +    - Interrupt sources: 43 sources.
> > > +    - Buffer operation:
> > > +        - Automatic transfer of register data (transfer from the
> > buffer
> > > +          register to the timer register).
> > > +    - Trigger generation
> > > +        - A/D converter start triggers can be generated
> > > +        - A/D converter start request delaying function enables
> A/D
> > converter
> > > +          to be started with any desired timing and to be
> > synchronized with
> > > +          PWM output.
> > > +    - Low power consumption function
> > > +        - The MTU3a can be placed in the module-stop state.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    items:
> > > +      - enum:
> > > +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> > > +          - renesas,r9a07g054-mtu3  # RZ/V2L
> > > +      - const: renesas,rz-mtu3
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  interrupts:
> > > +    items:
> > > +      - description: MTU0.TGRA input capture/compare match
> > > +      - description: MTU0.TGRB input capture/compare match
> > > +      - description: MTU0.TGRC input capture/compare match
> > > +      - description: MTU0.TGRD input capture/compare match
> > > +      - description: MTU0.TCNT overflow
> > > +      - description: MTU0.TGRE compare match
> > > +      - description: MTU0.TGRF compare match
> > > +      - description: MTU1.TGRA input capture/compare match
> > > +      - description: MTU1.TGRB input capture/compare match
> > > +      - description: MTU1.TCNT overflow
> > > +      - description: MTU1.TCNT underflow
> > > +      - description: MTU2.TGRA input capture/compare match
> > > +      - description: MTU2.TGRB input capture/compare match
> > > +      - description: MTU2.TCNT overflow
> > > +      - description: MTU2.TCNT underflow
> > > +      - description: MTU3.TGRA input capture/compare match
> > > +      - description: MTU3.TGRB input capture/compare match
> > > +      - description: MTU3.TGRC input capture/compare match
> > > +      - description: MTU3.TGRD input capture/compare match
> > > +      - description: MTU3.TCNT overflow
> > > +      - description: MTU4.TGRA input capture/compare match
> > > +      - description: MTU4.TGRB input capture/compare match
> > > +      - description: MTU4.TGRC input capture/compare match
> > > +      - description: MTU4.TGRD input capture/compare match
> > > +      - description: MTU4.TCNT overflow/underflow
> > > +      - description: MTU5.TGRU input capture/compare match
> > > +      - description: MTU5.TGRV input capture/compare match
> > > +      - description: MTU5.TGRW input capture/compare match
> > > +      - description: MTU6.TGRA input capture/compare match
> > > +      - description: MTU6.TGRB input capture/compare match
> > > +      - description: MTU6.TGRC input capture/compare match
> > > +      - description: MTU6.TGRD input capture/compare match
> > > +      - description: MTU6.TCNT overflow
> > > +      - description: MTU7.TGRA input capture/compare match
> > > +      - description: MTU7.TGRB input capture/compare match
> > > +      - description: MTU7.TGRC input capture/compare match
> > > +      - description: MTU7.TGRD input capture/compare match
> > > +      - description: MTU7.TCNT overflow/underflow
> > > +      - description: MTU8.TGRA input capture/compare match
> > > +      - description: MTU8.TGRB input capture/compare match
> > > +      - description: MTU8.TGRC input capture/compare match
> > > +      - description: MTU8.TGRD input capture/compare match
> > > +      - description: MTU8.TCNT overflow
> > > +      - description: MTU8.TCNT underflow
> > > +
> > > +  interrupt-names:
> > > +    items:
> > > +      - const: tgia0
> > > +      - const: tgib0
> > > +      - const: tgic0
> > > +      - const: tgid0
> > > +      - const: tgiv0
> > > +      - const: tgie0
> > > +      - const: tgif0
> > > +      - const: tgia1
> > > +      - const: tgib1
> > > +      - const: tgiv1
> > > +      - const: tgiu1
> > > +      - const: tgia2
> > > +      - const: tgib2
> > > +      - const: tgiv2
> > > +      - const: tgiu2
> > > +      - const: tgia3
> > > +      - const: tgib3
> > > +      - const: tgic3
> > > +      - const: tgid3
> > > +      - const: tgiv3
> > > +      - const: tgia4
> > > +      - const: tgib4
> > > +      - const: tgic4
> > > +      - const: tgid4
> > > +      - const: tgiv4
> > > +      - const: tgiu5
> > > +      - const: tgiv5
> > > +      - const: tgiw5
> > > +      - const: tgia6
> > > +      - const: tgib6
> > > +      - const: tgic6
> > > +      - const: tgid6
> > > +      - const: tgiv6
> > > +      - const: tgia7
> > > +      - const: tgib7
> > > +      - const: tgic7
> > > +      - const: tgid7
> > > +      - const: tgiv7
> > > +      - const: tgia8
> > > +      - const: tgib8
> > > +      - const: tgic8
> > > +      - const: tgid8
> > > +      - const: tgiv8
> > > +      - const: tgiu8
> > > +
> > > +  clocks:
> > > +    maxItems: 1
> > > +
> > > +  power-domains:
> > > +    maxItems: 1
> > > +
> > > +  resets:
> > > +    maxItems: 1
> > > +
> > > +  counter:
> > > +    description:
> > > +      There are two phase counting modes. 16-bit phase counting
> > mode in which
> > > +      MTU1 and MTU2 operate independently, and cascade connection
> > 32-bit phase
> > > +      counting mode in which MTU1 and MTU2 are cascaded.
> > > +
> > > +      In phase counting mode, the phase difference between two
> > external input
> > > +      clocks is detected and the corresponding TCNT is
> incremented
> > or
> > > +      decremented.
> > > +      The below counters are supported
> > > +        count0 - MTU1 16-bit phase counting
> > > +        count1 - MTU2 16-bit phase counting
> > > +        count2 - MTU1+ MTU2 32-bit phase counting
> > > +
> > > +    type: object
> > > +
> > > +    properties:
> > > +      compatible:
> > > +        const: renesas,rz-mtu3-counter
> > > +
> > > +    required:
> > > +      - compatible
> > > +
> > > +    additionalProperties: false
> > > +
> > > +  pwm:
> > > +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - interrupts
> > > +  - interrupt-names
> > > +  - clocks
> > > +  - power-domains
> > > +  - resets
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > +
> > > +    mtu3: timer@10001200 {
> > > +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
> > > +      reg = <0x10001200 0xb00>;
> > > +      interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
> > > +                   <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
> > > +      interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0",
> > "tgiv0", "tgie0",
> > > +                        "tgif0",
> > > +                        "tgia1", "tgib1", "tgiv1", "tgiu1",
> > > +                        "tgia2", "tgib2", "tgiv2", "tgiu2",
> > > +                        "tgia3", "tgib3", "tgic3", "tgid3",
> > "tgiv3",
> > > +                        "tgia4", "tgib4", "tgic4", "tgid4",
> > "tgiv4",
> > > +                        "tgiu5", "tgiv5", "tgiw5",
> > > +                        "tgia6", "tgib6", "tgic6", "tgid6",
> > "tgiv6",
> > > +                        "tgia7", "tgib7", "tgic7", "tgid7",
> > "tgiv7",
> > > +                        "tgia8", "tgib8", "tgic8", "tgid8",
> > "tgiv8", "tgiu8";
> > > +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
> > > +      power-domains = <&cpg>;
> > > +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
> > > +
> > > +      counter {
> > > +        compatible = "renesas,rz-mtu3-counter";
> >
> > You don't have any resources for the counter in DT, so you don't
> even
> > need a node here. Just have the parent driver instaniate the counter
> > driver.
> 

If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then instantiating 
the counter and pwm driver from parent driver by directly calling probe function is
giving cyclic dependency error[1].

So looks like either we need to use compatible "renesas,rz-mtu3-counter" and 
"renesas,rz-mtu3-pwm" if these functionalities to be in respective subsystem tree

or 

squash counter and pwm functionalities to MFD subsystem.

Please share your views on this. Is there any better way to handle this?

[1]
depmod: ../tools/depmod.c:1792: depmod_report_cycles_from_root: Assertion `is < stack_size' failed.
depmod: ERROR: Cycle detected: rz_mtu3 -> rz_mtu3_cnt -> rz_mtu3
depmod: ERROR: Cycle detected: rz_mtu3 -> rz_mtu3_pwm -> rz_mtu3
depmod: ERROR: Found 3 modules in dependency cycles!
make: *** [Makefile:1781: modules_install] Error 1

Cheers,
Biju

> 
> >
> > > +      };
> > > +
> > > +      pwm {
> > > +        compatible = "renesas,rz-mtu3-pwm";
> > > +        #pwm-cells = <2>;
> >
> > Here too, just declaring a PWM provider. Just move this to the
> parent
> > node.
> 
> OK, will remove node and compatible. Will add support for parent
> driver instaniate the PWM driver and also declaring as a PWM provider.
> 
> Cheers,
> Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-08  1:37   ` William Breathitt Gray
@ 2022-10-08  9:01     ` Biju Das
  2022-10-11 13:15       ` William Breathitt Gray
  0 siblings, 1 reply; 23+ messages in thread
From: Biju Das @ 2022-10-08  9:01 UTC (permalink / raw)
  To: William Breathitt Gray, Philipp Zabel, Rob Herring, Lee Jones
  Cc: linux-iio, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi William Breathitt Gray,

Thanks for the feedback.

> Subject: Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
> 
> On Thu, Oct 06, 2022 at 02:57:17PM +0100, Biju Das wrote:
> > Add RZ/G2L MTU3 counter driver.
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> 
> Hi Biju,
> 
> This commit message is rather brief for an introduction of a new
> driver.
> Provide a description of the functionality provided (e.g. two 16-bit
> Counts or one 32-bit Count) as well as the hardware this driver
> supports for context (e.g. what does MTU3 mean; is this a SoC; etc.).

OK Will do. MTU3- Multi-Function Timer Pulse Unit 3 (MTU3a). It is
an on-chip module on RZ/G2L SoC

> 
> > ---
> > v1->v3:
> >  * Modelled as a counter device supporting 3 counters(2 16-bit and
> >    32-bit)
> >  * Add kernel-doc comments to document struct rz_mtu3_cnt
> >  * Removed mmio variable from struct rz_mtu3_cnt
> >  * Removed cnt local variable from rz_mtu3_count_read()
> >  * Replaced -EINVAL->-ERANGE for out of range error conditions.
> >  * Removed explicit cast from write functions.
> >  * Removed local variable val from rz_mtu3_count_ceiling_read()
> >  * Added lock for RMW for counter/ceiling updates.
> >  * Added different synapses for counter0 and counter{1,2}
> >  * Used ARRAY for assigning num_counts.
> >  * Added PM runtime for managing clocks.
> >  * Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.
> > ---
> >  drivers/counter/Kconfig       |   9 +
> >  drivers/counter/Makefile      |   1 +
> >  drivers/counter/rz-mtu3-cnt.c | 568
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 578 insertions(+)
> >  create mode 100644 drivers/counter/rz-mtu3-cnt.c
> >
> > diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index
> > d388bf26f4dc..531b187e4630 100644
> > --- a/drivers/counter/Kconfig
> > +++ b/drivers/counter/Kconfig
> > @@ -39,6 +39,15 @@ config INTERRUPT_CNT
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called interrupt-cnt.
> >
> > +config RZ_MTU3_CNT
> > +	tristate "RZ/G2L MTU3 counter driver"
> > +	depends on MFD_RZ_MTU3 || COMPILE_TEST
> > +	help
> > +	  Select this option to enable RZ/G2L MTU3 counter driver.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called rz-mtu3-cnt.
> > +
> 
> Provide a bit more description of the hardware here; you should at
> least mention this is a Renesas RZ/G2L as opposed to some other
> manufacturer.

OK.

> 
> >  config STM32_TIMER_CNT
> >  	tristate "STM32 Timer encoder counter driver"
> >  	depends on MFD_STM32_TIMERS || COMPILE_TEST diff --git
> > a/drivers/counter/Makefile b/drivers/counter/Makefile index
> > b9a369e0d4fc..933fdd50b3e4 100644
> > --- a/drivers/counter/Makefile
> > +++ b/drivers/counter/Makefile
> > @@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o
> > counter-chrdev.o
> >
> >  obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
> >  obj-$(CONFIG_INTERRUPT_CNT)		+= interrupt-cnt.o
> > +obj-$(CONFIG_RZ_MTU3_CNT)	+= rz-mtu3-cnt.o
> >  obj-$(CONFIG_STM32_TIMER_CNT)	+= stm32-timer-cnt.o
> >  obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
> >  obj-$(CONFIG_TI_EQEP)		+= ti-eqep.o
> > diff --git a/drivers/counter/rz-mtu3-cnt.c
> > b/drivers/counter/rz-mtu3-cnt.c new file mode 100644 index
> > 000000000000..26b5ea3852f8
> > --- /dev/null
> > +++ b/drivers/counter/rz-mtu3-cnt.c
> > @@ -0,0 +1,568 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Renesas RZ/G2L MTU3a Counter driver
> > + *
> > + * Copyright (C) 2022 Renesas Electronics Corporation  */ #include
> > +<linux/counter.h> #include <linux/mfd/rz-mtu3.h> #include
> > +<linux/module.h> #include <linux/of.h> #include
> > +<linux/platform_device.h> #include <linux/pm_runtime.h> #include
> > +<linux/types.h>
> > +
> > +#define RZ_MTU3_TSR_TCFD	BIT(7)
> > +#define RZ_MTU3_MAX_HW_CNTR_CHANNELS	(2)
> > +
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_1	(4)
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_2	(5)
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_3	(6)
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_4	(7)
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_5	(9)
> > +#define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK	(0xf)
> > +
> > +#define RZ_MTU3_TCR_CCLR	GENMASK(7, 5)
> > +#define RZ_MTU3_TCR_CCLR_NONE	FIELD_PREP(RZ_MTU3_TCR_CCLR, 0)
> > +
> > +#define RZ_MTU3_TMDR3_LWA	BIT(0)
> > +#define RZ_MTU3_32_BIT_CH	(2)
> 
> Providing a define to identify the 32-bit channel is a good idea.
> Defines for the other two 16-bit channels would also be good.

OK, will do.

> 
> > +
> > +#define RZ_MTU3_TIOR_IC_BOTH	(10)
> > +
> > +/**
> > + * struct rz_mtu3_cnt - MTU3 counter private data
> > + *
> > + * @clk: MTU3 module clock
> > + * @lock: Lock to prevent concurrent access for ceiling and count
> > + * @rz_mtu3_channel: HW channels for the counters  */ struct
> > +rz_mtu3_cnt {
> > +	struct clk *clk;
> > +	struct mutex lock;
> > +	struct rz_mtu3_channel *ch[RZ_MTU3_MAX_HW_CNTR_CHANNELS];
> 
> Does this need to be a pointer to an array of struct rz_mtu3_channel?

Yes, HW has MTU{0..8} channels and MTU{1,2} supports counters
At probe time this array is filled with *ch[0]= MTU1 and *ch[1]= MTU2

> You can avoid the double dereferences in your code if you leave it as
> a simple pointer to struct rz_mtu3_channel and use subscripts directly
> as you would an array. Or is there something I'm missing?

Please see above.

> 
> > +};
> > +
> > +static const enum counter_function rz_mtu3_count_functions[] = {
> > +	COUNTER_FUNCTION_QUADRATURE_X4,
> > +	COUNTER_FUNCTION_PULSE_DIRECTION,
> > +	COUNTER_FUNCTION_QUADRATURE_X2_B,
> > +};
> > +
> > +static bool rz_mtu3_is_16_bit_cnt_mode(struct rz_mtu3_cnt *const
> > +priv) {
> > +	return (priv->ch[0]->function == RZ_MTU3_16BIT_PHASE_COUNTING ||
> > +		priv->ch[1]->function == RZ_MTU3_16BIT_PHASE_COUNTING);
> 
> Is there ever a situation where one channel is equal to
> RZ_MTU3_16BIT_PHASE_COUNTING while the other channel is equal to
> RZ_MTU3_32BIT_PHASE_COUNTING?

No that will never happen

The check is to detect runtime conditions. For eg:- user enables ch0 and then tries
to enable Ch2 

or 

ch1 and then tries ch2.

> 
> > +}
> > +
> > +static bool rz_mtu3_is_32_bit_cnt_mode(struct rz_mtu3_cnt *const
> > +priv) {
> > +	return (priv->ch[0]->function == RZ_MTU3_32BIT_PHASE_COUNTING &&
> > +		priv->ch[1]->function == RZ_MTU3_32BIT_PHASE_COUNTING); }
> > +
> > +static int rz_mtu3_count_read(struct counter_device *counter,
> > +			      struct counter_count *count, u64 *val) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> It is not immediately clear why you are ANDing the Count id here.
> After looking at the rest of the code in this function I realized it's
> because you want to call rz_mtu3_32bit_ch_read() with id = 0 when you
> have
> count->id = RZ_MTU3_32_BIT_CH.
> 
> I wouldn't even bother with the local id variable in this function and
> instead just hardcode priv->ch[0] in the rz_mtu3_32bit_ch_read() call
> below directly.

OK. Will do.

> 
> > +
> > +	if (count->id == RZ_MTU3_32_BIT_CH)
> > +		*val = rz_mtu3_32bit_ch_read(priv->ch[id], RZ_MTU3_TCNTLW);
> > +	else
> > +		*val = rz_mtu3_16bit_ch_read(priv->ch[id], RZ_MTU3_TCNT);
> 
> Is there a risk of these read calls returning an error code?

There is no risk. as the calls with these macros{RZ_MTU3_TCNTLW,RZ_MTU3_TCNT}
It never return error.

> 
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_write(struct counter_device *counter,
> > +			       struct counter_count *count, const u64 val) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> Same comment about local id variable as in rz_mtu3_count_read().
OK. Agreed.

> 
> > +	u32 ceiling;
> > +
> > +	mutex_lock(&priv->lock);
> > +	if (count->id == RZ_MTU3_32_BIT_CH)
> > +		ceiling = rz_mtu3_32bit_ch_read(priv->ch[id],
> RZ_MTU3_TGRALW);
> > +	else
> > +		ceiling = rz_mtu3_16bit_ch_read(priv->ch[id],
> RZ_MTU3_TGRA);
> 
> The ceiling value isn't expected to change unless the user executes
> your
> ceiling_write() function, right? It might make sense to cache the
> current ceiling value in your rz_mtu3_cnt structure so that you don't
> have to read it out from the device every time you check it.

OK. will add channel specific array to cache these values.

> 
> > +
> > +	if (val > ceiling) {
> > +		mutex_unlock(&priv->lock);
> > +		return -ERANGE;
> > +	}
> > +
> > +	if (count->id == RZ_MTU3_32_BIT_CH)
> > +		rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TCNTLW, val);
> > +	else
> > +		rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TCNT, val);
> > +
> > +	mutex_unlock(&priv->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_function_read(struct counter_device
> *counter,
> > +				       struct counter_count *count,
> > +				       enum counter_function *function) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> As mentioned before, this AND operation obscures the intention of your
> code. Instead, rename this variable and account for RZ_MTU3_32_BIT_CH
> explicitly with something like this:
> 
>     const size_t ch_id = (count->id == RZ_MTU3_32_BIT_CH) ? 0 : count-
> >id;

OK.

> 
> You could wrap this into a preprocessor macro to reuse again in your
> code, but I'll leave it up to you if you want.

OK.

> 
> > +	u8 val;
> > +
> > +	val = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TMDR1);
> > +
> > +	switch (val & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
> > +	case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
> > +		*function = COUNTER_FUNCTION_QUADRATURE_X4;
> > +		break;
> > +	case RZ_MTU3_TMDR1_PH_CNT_MODE_2:
> > +		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
> > +		break;
> > +	case RZ_MTU3_TMDR1_PH_CNT_MODE_4:
> > +		*function = COUNTER_FUNCTION_QUADRATURE_X2_B;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_function_write(struct counter_device
> *counter,
> > +					struct counter_count *count,
> > +					enum counter_function function)
> > +{
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> Same comment as in rz_mtu3_count_function_read().

OK.

> 
> > +	u8 mode;
> > +
> > +	switch (function) {
> > +	case COUNTER_FUNCTION_QUADRATURE_X4:
> > +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1;
> > +		break;
> > +	case COUNTER_FUNCTION_PULSE_DIRECTION:
> > +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2;
> > +		break;
> > +	case COUNTER_FUNCTION_QUADRATURE_X2_B:
> > +		mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1, mode);
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_direction_read(struct counter_device
> *counter,
> > +					struct counter_count *count,
> > +					enum counter_count_direction *direction)
> {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> Same comment as in rz_mtu3_count_function_read().
OK.
> 
> > +	u8 cnt;
> > +
> > +	cnt = rz_mtu3_8bit_ch_read(priv->ch[id], RZ_MTU3_TSR);
> 
> This is the timer status register, right? A variable name of 'cnt'
> seems a bit strange to me; would 'tsr' be a better name here?

Yes, it is timer status register. Will change it to tsr.

> 
> > +
> > +	if (cnt & RZ_MTU3_TSR_TCFD)
> > +		*direction = COUNTER_COUNT_DIRECTION_FORWARD;
> > +	else
> > +		*direction = COUNTER_COUNT_DIRECTION_BACKWARD;
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_ceiling_read(struct counter_device
> *counter,
> > +				      struct counter_count *count,
> > +				      u64 *ceiling)
> > +{
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> Same comment about local id variable as in rz_mtu3_count_read().

OK.
> 
> > +
> > +	if (count->id == RZ_MTU3_32_BIT_CH)
> > +		*ceiling = rz_mtu3_32bit_ch_read(priv->ch[id],
> RZ_MTU3_TGRALW);
> > +	else
> > +		*ceiling = rz_mtu3_16bit_ch_read(priv->ch[id],
> RZ_MTU3_TGRA);
> 
> Assuming you're able to cache the ceiling value, you can set it here
> directly and avoid the reads out to the device.

OK.

> 
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_ceiling_write(struct counter_device
> *counter,
> > +				       struct counter_count *count,
> > +				       u64 ceiling)
> > +{
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	u32 id = count->id & 1;
> 
> Same comment as in rz_mtu3_count_function_read().
OK.
> 
> > +	if (ceiling > U16_MAX && rz_mtu3_is_16_bit_cnt_mode(priv))
> > +		return -ERANGE;
> > +
> > +	if (ceiling > U32_MAX && rz_mtu3_is_32_bit_cnt_mode(priv))
> > +		return -ERANGE;
> 
> You can determine which maximum to consider by checking the count->id.
> Instead of those two conditional statments, try this instead:
> 
>     switch (count->id) {
>     case 0:
>     case 1:
>             if (ceiling > U16_MAX)
>                     return -ERANGE;
>             break;
>     case RZ_MTU3_32_BIT_CH:
>             if (ceiling > U32_MAX)
>                     return -ERANGE;
>             break;
>     }
> 
OK.

> If you need to check whether you're in 32-bit phase mode before
> setting the ceiling for the RZ_MTU3_32_BIT_CH Count (and similarly for
> the 16-bit Counts), check that separately and return -EBUSY as
> appropriate.

OK.
> 
> > +	mutex_lock(&priv->lock);
> > +	if (ceiling == 0) {
> > +		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> > +				      RZ_MTU3_TCR_CCLR_NONE);
> 
> Looks like something different is done when ceiling is set to 0. Would
> you explain what's happening in this case and why it's different that
> then else case below; in other words, what's the difference between
> RZ_MTU3_TCR_CCLR_NONE and RZ_MTU3_TCR_CCLR_TGRA?

RZ_MTU3_TCR_CCLR_TGRA --> for triggering counter count using Z-Phase signal.
RZ_MTU3_TCR_CCLR_NONE --> No clearing.

> 
> > +
> 
> You can remove this empty line.
OK.
> 
> > +	} else {
> > +		if (count->id == RZ_MTU3_32_BIT_CH)
> > +			rz_mtu3_32bit_ch_write(priv->ch[id], RZ_MTU3_TGRALW,
> ceiling);
> > +		else
> > +			rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA,
> ceiling);
> > +
> > +		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> > +				      RZ_MTU3_TCR_CCLR_TGRA);
> > +	}
> > +	mutex_unlock(&priv->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rz_mtu3_32bit_cnt_setting(struct counter_device
> *counter,
> > +int id) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +
> > +	/*
> > +	 * 32-bit phase counting need MTU1 and MTU2 to create 32-bit
> cascade
> > +	 * counter.
> > +	 */
> > +	priv->ch[0]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
> > +	priv->ch[1]->function = RZ_MTU3_32BIT_PHASE_COUNTING;
> > +
> > +	rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3,
> > +RZ_MTU3_TMDR3_LWA);
> > +
> > +	/* Phase counting mode 1 is used as default in initialization. */
> > +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TMDR1,
> > +			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
> > +
> > +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TCR,
> RZ_MTU3_TCR_CCLR_TGRA);
> > +	rz_mtu3_8bit_ch_write(priv->ch[0], RZ_MTU3_TIOR,
> > +RZ_MTU3_TIOR_IC_BOTH);
> > +
> > +	rz_mtu3_enable(priv->ch[0]);
> > +	rz_mtu3_enable(priv->ch[1]);
> > +}
> > +
> > +static void rz_mtu3_16bit_cnt_setting(struct counter_device
> *counter,
> > +int id) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +
> > +	priv->ch[id]->function = RZ_MTU3_16BIT_PHASE_COUNTING;
> 
> If 16-bit phase counting is selected for one 16-bit counter, does the
> other 16-bit counter need to be configured as well?

Not required I guess, as it is run time decision.

After this, if user tries to enable 16-bit on other channel,
we will configure that channel. otherwise, we will return error,
if user tries to enable 32-bit channel.

Are you ok with this? 


> 
> > +
> > +	/* Phase counting mode 1 is used as default in initialization. */
> > +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TMDR1,
> > +			      RZ_MTU3_TMDR1_PH_CNT_MODE_1);
> > +
> > +	rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> RZ_MTU3_TCR_CCLR_TGRA);
> > +	rz_mtu3_16bit_ch_write(priv->ch[id], RZ_MTU3_TGRA, U16_MAX);
> > +
> > +	rz_mtu3_enable(priv->ch[id]);
> > +}
> > +
> > +static int rz_mtu3_initialize_counter(struct counter_device
> *counter,
> > +int id) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +
> > +	if (id == RZ_MTU3_32_BIT_CH && rz_mtu3_is_16_bit_cnt_mode(priv))
> > +		return -EBUSY;
> > +
> > +	if (id != RZ_MTU3_32_BIT_CH && rz_mtu3_is_32_bit_cnt_mode(priv))
> > +		return -EBUSY;
> > +
> > +	if (id == RZ_MTU3_32_BIT_CH)
> > +		rz_mtu3_32bit_cnt_setting(counter, id);
> > +	else
> > +		rz_mtu3_16bit_cnt_setting(counter, id);
> 
> I think this code would flow better using a switch statement like
> this:
> 
>     switch (id) {
>     case 0:
>     case 1:
>             if (rz_mtu3_is_32_bit_cnt_mode(priv))
>                     return -EBUSY;
>             rz_mtu3_16bit_cnt_setting(counter, id);
>             break;
>     case RZ_MTU3_32_BIT_CH:
>             if (rz_mtu3_is_16_bit_cnt_mode(priv))
>                     return -EBUSY;
>             rz_mtu3_32bit_cnt_setting(counter, id);
>             break;
>     }
> 
> You should also protect this with a lock to prevent any races while
> you're accessing and modifying the settings.

OK.

> 
> > +
> > +	return 0;
> > +}
> > +
> > +static void rz_mtu3_terminate_counter(struct counter_device
> *counter,
> > +int id) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +
> > +	if (id == RZ_MTU3_32_BIT_CH) {
> > +		priv->ch[0]->function = RZ_MTU3_NORMAL;
> > +		priv->ch[1]->function = RZ_MTU3_NORMAL;
> > +		rz_mtu3_shared_reg_write(priv->ch[0], RZ_MTU3_TMDR3, 0);
> > +		rz_mtu3_disable(priv->ch[1]);
> > +		rz_mtu3_disable(priv->ch[0]);
> > +	} else {
> > +		priv->ch[id]->function = RZ_MTU3_NORMAL;
> > +		rz_mtu3_disable(priv->ch[id]);
> > +	}
> 
> You probably need a lock in this function to prevent races.

OK.

> 
> > +}
> > +
> > +static int rz_mtu3_count_enable_read(struct counter_device
> *counter,
> > +				     struct counter_count *count, u8 *enable) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +
> > +	if (count->id == RZ_MTU3_32_BIT_CH)
> > +		*enable = rz_mtu3_is_enabled(priv->ch[0]) &&
> > +			rz_mtu3_is_enabled(priv->ch[1]);
> 
> There's a race between checking for channel 0 and channel 1, so use a
> lock to prevent that.

OK. Agreed.
> 
> > +	else
> > +		*enable = rz_mtu3_is_enabled(priv->ch[count->id]);
> > +
> > +	return 0;
> > +}
> > +
> > +static int rz_mtu3_count_enable_write(struct counter_device
> *counter,
> > +				      struct counter_count *count, u8 enable) {
> > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > +	struct rz_mtu3_channel *ch = priv->ch[count->id & 0x1];
> 
> Same comment about the AND operation as mentioned before.

OK.
> 
> > +	int ret = 0;
> > +
> > +	if (enable) {
> > +		pm_runtime_get_sync(ch->dev);
> > +		ret = rz_mtu3_initialize_counter(counter, count->id);
> 
> Are you using the Count's "enable" extension to switch between 16-bit
> and 32-bit phase modes?

No. But will use that for switching on the next version.


> 
> > +	} else {
> > +		rz_mtu3_terminate_counter(counter, count->id);
> > +		pm_runtime_put(ch->dev);
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static struct counter_comp rz_mtu3_count_ext[] = {
> > +	COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read),
> > +	COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read,
> > +			    rz_mtu3_count_enable_write),
> > +	COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read,
> > +			     rz_mtu3_count_ceiling_write), };
> > +
> > +static const enum counter_synapse_action rz_mtu3_synapse_actions[]
> = {
> > +	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
> > +	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
> > +	COUNTER_SYNAPSE_ACTION_NONE,
> > +};
> > +
> > +static int rz_mtu3_action_read(struct counter_device *counter,
> > +			       struct counter_count *count,
> > +			       struct counter_synapse *synapse,
> > +			       enum counter_synapse_action *action) {
> > +	const size_t signal_a_id = count->synapses[0].signal->id;
> > +	const size_t signal_b_id = count->synapses[1].signal->id;
> 
> If this is "Channel 2" Count then you will have four Synapses for four
> possible Signals (MTCLKA, MTCLKB, MTCLKC, MTCLKD), so you'll need to
> account for those two other Signals as well.

OK.

> 
> > +	enum counter_function function;
> > +	int err;
> > +
> > +	err = rz_mtu3_count_function_read(counter, count, &function);
> > +	if (err)
> > +		return err;
> > +
> > +	/* Default action mode */
> > +	*action = COUNTER_SYNAPSE_ACTION_NONE;
> > +
> > +	switch (function) {
> > +	case COUNTER_FUNCTION_PULSE_DIRECTION:
> > +		/*
> > +		 * Rising edges on signal A updates the respective count.
> > +		 * The input level of signal B determines direction.
> > +		 */
> > +		if (synapse->signal->id == signal_a_id)
> > +			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
> > +		break;
> > +	case COUNTER_FUNCTION_QUADRATURE_X2_B:
> > +		/*
> > +		 * Any state transition on quadrature pair signal B updates
> > +		 * the respective count.
> > +		 */
> > +		if (synapse->signal->id == signal_b_id)
> > +			*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
> > +		break;
> > +	case COUNTER_FUNCTION_QUADRATURE_X4:
> > +		/* counts up/down on both edges of A and B signal*/
> > +		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct counter_ops rz_mtu3_cnt_ops = {
> > +	.count_read = rz_mtu3_count_read,
> > +	.count_write = rz_mtu3_count_write,
> > +	.function_read = rz_mtu3_count_function_read,
> > +	.function_write = rz_mtu3_count_function_write,
> > +	.action_read = rz_mtu3_action_read,
> > +};
> > +
> > +#define RZ_MTU3_PHASE_SIGNAL(_id, _name) {		\
> > +	.id = (_id),				\
> > +	.name = (_name),			\
> > +}
> > +
> > +static struct counter_signal rz_mtu3_signals[] = {
> > +	RZ_MTU3_PHASE_SIGNAL(0, "MTU1 MTCLKA"),
> > +	RZ_MTU3_PHASE_SIGNAL(1, "MTU1 MTCLKB"),
> > +	RZ_MTU3_PHASE_SIGNAL(2, "MTU2 MTCLKC"),
> > +	RZ_MTU3_PHASE_SIGNAL(3, "MTU2 MTCLKD"), };
> 
> These names can be in a human-readable form (e.g. "Multi-function
> Timer Clock A") if you think it's easier to understand, but I'll leave
> it up to you if you want to change it.

HW manual says MTCLK{A,B,C,D}. that is the reason.

> 
> > +
> > +#define RZ_MTU3_COUNT_SYNAPSES(_id) {					\
> > +	{								\
> > +		.actions_list = rz_mtu3_synapse_actions,		\
> > +		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
> > +		.signal = rz_mtu3_signals + 2 * (_id)			\
> > +	},								\
> > +	{								\
> > +		.actions_list = rz_mtu3_synapse_actions,		\
> > +		.num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions),	\
> > +		.signal = rz_mtu3_signals + 2 * (_id) + 1		\
> > +	}								\
> > +}
> > +
> > +static struct counter_synapse rz_mtu3_count_synapses[][2] = {
> > +	RZ_MTU3_COUNT_SYNAPSES(0), RZ_MTU3_COUNT_SYNAPSES(1) };
> 
> I know the 104-quad-8 module also creates a multidimensional array to
> represent the synapses, but I would advise against this pattern
> because it obscures the intention of the code.
> 
> Instead, create a separate distinct array for each group of Synapses;
> I suppose there will be two arrays in this case judging from your
> existing code.

OK. Will do.

> 
> > +
> > +static struct counter_count rz_mtu3_counts[] = {
> > +	{
> > +		.id = 0,
> > +		.name = "Channel 1 Count(16-bit)",
> > +		.functions_list = rz_mtu3_count_functions,
> > +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> > +		.synapses = rz_mtu3_count_synapses[0],
> > +		.num_synapses = 2,
> 
> As mentioned in the comment above, refer to the distinct Synapse array
> for the particular Count and then use ARRAY_SIZE for that array to set
> num_synapses.

OK will do.
> 
> > +		.ext = rz_mtu3_count_ext,
> > +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> > +	},
> > +	{
> > +		.id = 1,
> > +		.name = "Channel 2 Count(16-bit)",
> > +		.functions_list = rz_mtu3_count_functions,
> > +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> > +		.synapses = rz_mtu3_count_synapses[0],
> > +		.num_synapses = 4,
> > +		.ext = rz_mtu3_count_ext,
> > +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> > +	},
> > +	{
> > +		.id = 2,
> 
> Set id = RZ_MTU3_32_BIT_CH to make it more obvious here.
> 
> > +		.name = "Channel3 Count(32-bit)",
> 
> We probably don't need the "(32-bit)" in the name when it's obvious
> already from the channel id and ceiling value.

OK will remove it.
> 
> I wonder how this counter is described in the RZ/G2L user
> documentation; is it named "Channel 3" or "Channel 1 and 2"?

It is mentioned as MTU1 and MTU2 channels.

These channels can be used for phase counting and PWM operations.

> 
> > +		.functions_list = rz_mtu3_count_functions,
> > +		.num_functions = ARRAY_SIZE(rz_mtu3_count_functions),
> > +		.synapses = rz_mtu3_count_synapses[0],
> > +		.num_synapses = 4,
> > +		.ext = rz_mtu3_count_ext,
> > +		.num_ext = ARRAY_SIZE(rz_mtu3_count_ext),
> > +	}
> > +};
> > +
> > +static int __maybe_unused rz_mtu3_cnt_pm_runtime_suspend(struct
> > +device *dev) {
> > +	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
> > +
> > +	clk_disable_unprepare(priv->clk);
> > +
> > +	return 0;
> > +}
> > +
> > +static int __maybe_unused rz_mtu3_cnt_pm_runtime_resume(struct
> device
> > +*dev) {
> > +	struct rz_mtu3_cnt *const priv = dev_get_drvdata(dev);
> > +
> > +	clk_prepare_enable(priv->clk);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct dev_pm_ops rz_mtu3_cnt_pm_ops = {
> > +	SET_RUNTIME_PM_OPS(rz_mtu3_cnt_pm_runtime_suspend,
> > +rz_mtu3_cnt_pm_runtime_resume, NULL) };
> > +
> > +static void rz_mtu3_cnt_pm_disable(void *data) {
> > +	struct device *dev = data;
> > +
> > +	pm_runtime_disable(dev);
> > +	pm_runtime_set_suspended(dev);
> > +}
> > +
> > +static int rz_mtu3_cnt_probe(struct platform_device *pdev) {
> > +	struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent);
> > +	struct device *dev = &pdev->dev;
> > +	struct counter_device *counter;
> > +	struct rz_mtu3_cnt *priv;
> > +	unsigned int i;
> > +	int ret;
> > +
> > +	counter = devm_counter_alloc(dev, sizeof(*priv));
> > +	if (!counter)
> > +		return -ENOMEM;
> > +
> > +	priv = counter_priv(counter);
> > +	priv->clk = ddata->clk;
> > +
> > +	for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) {
> > +		priv->ch[i] = &ddata->channels[RZ_MTU1 + i];
> > +		priv->ch[i]->dev = dev;
> > +		if (priv->ch[i]->function != RZ_MTU3_NORMAL)
> > +			return dev_err_probe(dev, -EINVAL,
> > +					     "channel '%u' is already claimed\n",
> i);
> > +	}
> > +
> > +	mutex_init(&priv->lock);
> > +	clk_prepare_enable(priv->clk);
> > +	pm_runtime_set_active(&pdev->dev);
> > +	pm_runtime_enable(&pdev->dev);
> > +	ret = devm_add_action_or_reset(&pdev->dev,
> > +				       rz_mtu3_cnt_pm_disable,
> > +				       dev);
> > +	if (ret < 0)
> > +		goto disable_clock;
> > +
> > +	counter->name = dev_name(dev);
> > +	counter->parent = dev;
> > +	counter->ops = &rz_mtu3_cnt_ops;
> > +	counter->counts = rz_mtu3_counts;
> > +	counter->num_counts = ARRAY_SIZE(rz_mtu3_counts);
> > +	counter->signals = rz_mtu3_signals;
> > +	counter->num_signals = ARRAY_SIZE(rz_mtu3_signals);
> > +	platform_set_drvdata(pdev, priv);
> 
> It looks like you only ever use clk in your callbacks; how about
> setting your drvdata to clk instead and removing it from your
> rz_mtu3_cnt structure?

OK. Will do. 

Note:
This change is based on feedback[1] on bindings.

[1] https://patchwork.kernel.org/project/linux-renesas-soc/patch/20221006135717.1748560-2-biju.das.jz@bp.renesas.com/

Cheers,
Biju

> 
> > +
> > +	/* Register Counter device */
> > +	ret = devm_counter_add(dev, counter);
> > +	if (ret < 0) {
> > +		dev_err_probe(dev, ret, "Failed to add counter\n");
> > +		goto disable_clock;
> > +	}
> > +
> > +	return 0;
> > +
> > +disable_clock:
> > +	clk_disable_unprepare(priv->clk);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct of_device_id rz_mtu3_cnt_of_match[] = {
> > +	{ .compatible = "renesas,rz-mtu3-counter", },
> > +	{ /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, rz_mtu3_cnt_of_match);
> > +
> > +static struct platform_driver rz_mtu3_cnt_driver = {
> > +	.probe = rz_mtu3_cnt_probe,
> > +	.driver = {
> > +		.name = "rz-mtu3-counter",
> > +		.pm = &rz_mtu3_cnt_pm_ops,
> > +		.of_match_table = rz_mtu3_cnt_of_match,
> > +	},
> > +};
> > +module_platform_driver(rz_mtu3_cnt_driver);
> > +
> > +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> > +MODULE_ALIAS("platform:rz-mtu3-counter");
> > +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver");
> > +MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(COUNTER);
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-08  7:42       ` Biju Das
@ 2022-10-08 10:51         ` Biju Das
  2022-10-09 14:38         ` Geert Uytterhoeven
  2022-10-09 15:16         ` Krzysztof Kozlowski
  2 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-08 10:51 UTC (permalink / raw)
  To: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel
  Cc: Krzysztof Kozlowski, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc



> -----Original Message-----
> From: Biju Das
> Sent: 08 October 2022 08:43
> To: Rob Herring <robh@kernel.org>; William Breathitt Gray
> <william.gray@linaro.org>; Thierry Reding <thierry.reding@gmail.com>;
> Lee Jones <lee@kernel.org>; Philipp Zabel <p.zabel@pengutronix.de>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>; Uwe
> Kleine-König <u.kleine-koenig@pengutronix.de>;
> devicetree@vger.kernel.org; linux-pwm@vger.kernel.org; Geert
> Uytterhoeven <geert+renesas@glider.be>; Chris Paterson
> <Chris.Paterson2@renesas.com>; Biju Das <biju.das@bp.renesas.com>;
> Prabhakar Mahadev Lad <prabhakar.mahadev-lad.rj@bp.renesas.com>;
> linux-renesas-soc@vger.kernel.org
> Subject: RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> Hi Rob and all,
> 
> > Subject: RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> > bindings
> >
> > Hi Rob,
> >
> > Thanks for the feedback.
> >
> > > Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L
> MTU3a
> > > bindings
> > >
> > > On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> > > > The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded
> > in
> > > > the Renesas RZ/G2L family SoC's. It consists of eight 16-bit
> timer
> > > > channels and one 32-bit timer channel. It supports the following
> > > > functions
> > > >  - Counter
> > > >  - Timer
> > > >  - PWM
> > > >
> > > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > > > ---
> > > > v2->v3:
> > > >  * Dropped counter bindings and integrated with mfd as it has
> only
> > > one property.
> > > >  * Removed "#address-cells" and "#size-cells" as it do not have
> > > children with
> > > >    unit addresses.
> > > >  * Removed quotes from counter and pwm.
> > > >  * Provided full path for pwm bindings.
> > > >  * Updated the example.
> > > > v1->v2:
> > > >  * Modelled counter and pwm as a single device that handles
> > > >    multiple channels.
> > > >  * Moved counter and pwm bindings to respective subsystems
> > > >  * Dropped 'bindings' from MFD binding title.
> > > >  * Updated the example
> > > >  * Changed the compatible names.
> > > > ---
> > > >  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304
> > > ++++++++++++++++++
> > > >  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
> > > >  2 files changed, 354 insertions(+)  create mode 100644
> > > > Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > >  create mode 100644
> > > > Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> > > >
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > new file mode 100644
> > > > index 000000000000..44c952ad8d35
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > @@ -0,0 +1,304 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> > 1.2
> > > > +---
> > > > +$id:
> > > >
> > > > +
> > > > +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
> > > > +
> > > > +maintainers:
> > > > +  - Biju Das <biju.das.jz@bp.renesas.com>
> > > > +
> > > > +description: |
> > > > +  This hardware block pconsisting of eight 16-bit timer
> channels
> > > and
> > > > +one
> > > > +  32- bit timer channel. It supports the following
> > specifications:
> > > > +    - Pulse input/output: 28 lines max.
> > > > +    - Pulse input 3 lines
> > > > +    - Count clock 11 clocks for each channel (14 clocks for
> MTU0,
> > > 12 clocks
> > > > +      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-
> MTU2
> > > combination
> > > > +      (when LWA = 1))
> > > > +    - Operating frequency Up to 100 MHz
> > > > +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
> > > > +        - Waveform output on compare match
> > > > +        - Input capture function (noise filter setting
> available)
> > > > +        - Counter-clearing operation
> > > > +        - Simultaneous writing to multiple timer counters
> (TCNT)
> > > > +          (excluding MTU8).
> > > > +        - Simultaneous clearing on compare match or input
> capture
> > > > +          (excluding MTU8).
> > > > +        - Simultaneous input and output to registers in
> > > synchronization with
> > > > +          counter operations           (excluding MTU8).
> > > > +        - Up to 12-phase PWM output in combination with
> > synchronous
> > > operation
> > > > +          (excluding MTU8)
> > > > +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> > > > +        - Buffer operation specifiable
> > > > +    - [MTU1, MTU2]
> > > > +        - Phase counting mode can be specified independently
> > > > +        - 32-bit phase counting mode can be specified for
> > > interlocked operation
> > > > +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> > > > +        - Cascade connection operation available
> > > > +    - [MTU3, MTU4, MTU6, and MTU7]
> > > > +        - Through interlocked operation of MTU3/4 and MTU6/7,
> the
> > > positive and
> > > > +          negative signals in six phases (12 phases in total)
> can
> > > be output in
> > > > +          complementary PWM and reset-synchronized PWM
> operation.
> > > > +        - In complementary PWM mode, values can be transferred
> > from
> > > buffer
> > > > +          registers to temporary registers at crests and
> troughs
> > of
> > > the timer-
> > > > +          counter values or when the buffer registers (TGRD
> > > registers in MTU4
> > > > +          and MTU7) are written to.
> > > > +        - Double-buffering selectable in complementary PWM
> mode.
> > > > +    - [MTU3 and MTU4]
> > > > +        - Through interlocking with MTU0, a mode for driving AC
> > > synchronous
> > > > +          motors (brushless DC motors) by using complementary
> PWM
> > > output and
> > > > +          reset-synchronized PWM output is settable and allows
> > the
> > > selection
> > > > +          of two types of waveform output (chopping or level).
> > > > +    - [MTU5]
> > > > +        - Capable of operation as a dead-time compensation
> > counter.
> > > > +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> > > > +        - 32-bit phase counting mode specifiable by combining
> > MTU1
> > > and MTU2 and
> > > > +          through interlocked operation with MTU0/MTU5 and
> MTU8.
> > > > +    - Interrupt-skipping function
> > > > +        - In complementary PWM mode, interrupts on crests and
> > > troughs of counter
> > > > +          values and triggers to start conversion by the A/D
> > > converter can be
> > > > +          skipped.
> > > > +    - Interrupt sources: 43 sources.
> > > > +    - Buffer operation:
> > > > +        - Automatic transfer of register data (transfer from
> the
> > > buffer
> > > > +          register to the timer register).
> > > > +    - Trigger generation
> > > > +        - A/D converter start triggers can be generated
> > > > +        - A/D converter start request delaying function enables
> > A/D
> > > converter
> > > > +          to be started with any desired timing and to be
> > > synchronized with
> > > > +          PWM output.
> > > > +    - Low power consumption function
> > > > +        - The MTU3a can be placed in the module-stop state.
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    items:
> > > > +      - enum:
> > > > +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> > > > +          - renesas,r9a07g054-mtu3  # RZ/V2L
> > > > +      - const: renesas,rz-mtu3
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  interrupts:
> > > > +    items:
> > > > +      - description: MTU0.TGRA input capture/compare match
> > > > +      - description: MTU0.TGRB input capture/compare match
> > > > +      - description: MTU0.TGRC input capture/compare match
> > > > +      - description: MTU0.TGRD input capture/compare match
> > > > +      - description: MTU0.TCNT overflow
> > > > +      - description: MTU0.TGRE compare match
> > > > +      - description: MTU0.TGRF compare match
> > > > +      - description: MTU1.TGRA input capture/compare match
> > > > +      - description: MTU1.TGRB input capture/compare match
> > > > +      - description: MTU1.TCNT overflow
> > > > +      - description: MTU1.TCNT underflow
> > > > +      - description: MTU2.TGRA input capture/compare match
> > > > +      - description: MTU2.TGRB input capture/compare match
> > > > +      - description: MTU2.TCNT overflow
> > > > +      - description: MTU2.TCNT underflow
> > > > +      - description: MTU3.TGRA input capture/compare match
> > > > +      - description: MTU3.TGRB input capture/compare match
> > > > +      - description: MTU3.TGRC input capture/compare match
> > > > +      - description: MTU3.TGRD input capture/compare match
> > > > +      - description: MTU3.TCNT overflow
> > > > +      - description: MTU4.TGRA input capture/compare match
> > > > +      - description: MTU4.TGRB input capture/compare match
> > > > +      - description: MTU4.TGRC input capture/compare match
> > > > +      - description: MTU4.TGRD input capture/compare match
> > > > +      - description: MTU4.TCNT overflow/underflow
> > > > +      - description: MTU5.TGRU input capture/compare match
> > > > +      - description: MTU5.TGRV input capture/compare match
> > > > +      - description: MTU5.TGRW input capture/compare match
> > > > +      - description: MTU6.TGRA input capture/compare match
> > > > +      - description: MTU6.TGRB input capture/compare match
> > > > +      - description: MTU6.TGRC input capture/compare match
> > > > +      - description: MTU6.TGRD input capture/compare match
> > > > +      - description: MTU6.TCNT overflow
> > > > +      - description: MTU7.TGRA input capture/compare match
> > > > +      - description: MTU7.TGRB input capture/compare match
> > > > +      - description: MTU7.TGRC input capture/compare match
> > > > +      - description: MTU7.TGRD input capture/compare match
> > > > +      - description: MTU7.TCNT overflow/underflow
> > > > +      - description: MTU8.TGRA input capture/compare match
> > > > +      - description: MTU8.TGRB input capture/compare match
> > > > +      - description: MTU8.TGRC input capture/compare match
> > > > +      - description: MTU8.TGRD input capture/compare match
> > > > +      - description: MTU8.TCNT overflow
> > > > +      - description: MTU8.TCNT underflow
> > > > +
> > > > +  interrupt-names:
> > > > +    items:
> > > > +      - const: tgia0
> > > > +      - const: tgib0
> > > > +      - const: tgic0
> > > > +      - const: tgid0
> > > > +      - const: tgiv0
> > > > +      - const: tgie0
> > > > +      - const: tgif0
> > > > +      - const: tgia1
> > > > +      - const: tgib1
> > > > +      - const: tgiv1
> > > > +      - const: tgiu1
> > > > +      - const: tgia2
> > > > +      - const: tgib2
> > > > +      - const: tgiv2
> > > > +      - const: tgiu2
> > > > +      - const: tgia3
> > > > +      - const: tgib3
> > > > +      - const: tgic3
> > > > +      - const: tgid3
> > > > +      - const: tgiv3
> > > > +      - const: tgia4
> > > > +      - const: tgib4
> > > > +      - const: tgic4
> > > > +      - const: tgid4
> > > > +      - const: tgiv4
> > > > +      - const: tgiu5
> > > > +      - const: tgiv5
> > > > +      - const: tgiw5
> > > > +      - const: tgia6
> > > > +      - const: tgib6
> > > > +      - const: tgic6
> > > > +      - const: tgid6
> > > > +      - const: tgiv6
> > > > +      - const: tgia7
> > > > +      - const: tgib7
> > > > +      - const: tgic7
> > > > +      - const: tgid7
> > > > +      - const: tgiv7
> > > > +      - const: tgia8
> > > > +      - const: tgib8
> > > > +      - const: tgic8
> > > > +      - const: tgid8
> > > > +      - const: tgiv8
> > > > +      - const: tgiu8
> > > > +
> > > > +  clocks:
> > > > +    maxItems: 1
> > > > +
> > > > +  power-domains:
> > > > +    maxItems: 1
> > > > +
> > > > +  resets:
> > > > +    maxItems: 1
> > > > +
> > > > +  counter:
> > > > +    description:
> > > > +      There are two phase counting modes. 16-bit phase counting
> > > mode in which
> > > > +      MTU1 and MTU2 operate independently, and cascade
> connection
> > > 32-bit phase
> > > > +      counting mode in which MTU1 and MTU2 are cascaded.
> > > > +
> > > > +      In phase counting mode, the phase difference between two
> > > external input
> > > > +      clocks is detected and the corresponding TCNT is
> > incremented
> > > or
> > > > +      decremented.
> > > > +      The below counters are supported
> > > > +        count0 - MTU1 16-bit phase counting
> > > > +        count1 - MTU2 16-bit phase counting
> > > > +        count2 - MTU1+ MTU2 32-bit phase counting
> > > > +
> > > > +    type: object
> > > > +
> > > > +    properties:
> > > > +      compatible:
> > > > +        const: renesas,rz-mtu3-counter
> > > > +
> > > > +    required:
> > > > +      - compatible
> > > > +
> > > > +    additionalProperties: false
> > > > +
> > > > +  pwm:
> > > > +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +  - interrupts
> > > > +  - interrupt-names
> > > > +  - clocks
> > > > +  - power-domains
> > > > +  - resets
> > > > +
> > > > +additionalProperties: false
> > > > +
> > > > +examples:
> > > > +  - |
> > > > +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> > > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > > +
> > > > +    mtu3: timer@10001200 {
> > > > +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
> > > > +      reg = <0x10001200 0xb00>;
> > > > +      interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>,
> > > > +                   <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>;
> > > > +      interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0",
> > > "tgiv0", "tgie0",
> > > > +                        "tgif0",
> > > > +                        "tgia1", "tgib1", "tgiv1", "tgiu1",
> > > > +                        "tgia2", "tgib2", "tgiv2", "tgiu2",
> > > > +                        "tgia3", "tgib3", "tgic3", "tgid3",
> > > "tgiv3",
> > > > +                        "tgia4", "tgib4", "tgic4", "tgid4",
> > > "tgiv4",
> > > > +                        "tgiu5", "tgiv5", "tgiw5",
> > > > +                        "tgia6", "tgib6", "tgic6", "tgid6",
> > > "tgiv6",
> > > > +                        "tgia7", "tgib7", "tgic7", "tgid7",
> > > "tgiv7",
> > > > +                        "tgia8", "tgib8", "tgic8", "tgid8",
> > > "tgiv8", "tgiu8";
> > > > +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
> > > > +      power-domains = <&cpg>;
> > > > +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
> > > > +
> > > > +      counter {
> > > > +        compatible = "renesas,rz-mtu3-counter";
> > >
> > > You don't have any resources for the counter in DT, so you don't
> > even
> > > need a node here. Just have the parent driver instaniate the
> counter
> > > driver.
> >
> 
> If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then
> instantiating the counter and pwm driver from parent driver by
> directly calling probe function is giving cyclic dependency error[1].
> 
> So looks like either we need to use compatible "renesas,rz-mtu3-
> counter" and "renesas,rz-mtu3-pwm" if these functionalities to be in
> respective subsystem tree
> 
> or
> 
> squash counter and pwm functionalities to MFD subsystem.
> 
> Please share your views on this. Is there any better way to handle
> this?
> 
> [1]
> depmod: ../tools/depmod.c:1792: depmod_report_cycles_from_root:
> Assertion `is < stack_size' failed.
> depmod: ERROR: Cycle detected: rz_mtu3 -> rz_mtu3_cnt -> rz_mtu3
> depmod: ERROR: Cycle detected: rz_mtu3 -> rz_mtu3_pwm -> rz_mtu3
> depmod: ERROR: Found 3 modules in dependency cycles!
> make: *** [Makefile:1781: modules_install] Error 1


Just to add the below drivers have compatibles that does not have any resources. Am I missing anything here?

[1] https://elixir.bootlin.com/linux/v6.0/source/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml#L209
[2] https://elixir.bootlin.com/linux/v6.0/source/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml#L105
[3] https://elixir.bootlin.com/linux/v6.0/source/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml#L71

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-08  7:42       ` Biju Das
  2022-10-08 10:51         ` Biju Das
@ 2022-10-09 14:38         ` Geert Uytterhoeven
  2022-10-09 15:17           ` Krzysztof Kozlowski
  2022-10-10  7:10           ` Biju Das
  2022-10-09 15:16         ` Krzysztof Kozlowski
  2 siblings, 2 replies; 23+ messages in thread
From: Geert Uytterhoeven @ 2022-10-09 14:38 UTC (permalink / raw)
  To: Biju Das
  Cc: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel, Krzysztof Kozlowski, Uwe Kleine-König,
	devicetree, linux-pwm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Biju,

On Sat, Oct 8, 2022 at 9:42 AM Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > > On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> > > > The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded
> > in
> > > > the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer
> > > > channels and one 32-bit timer channel. It supports the following
> > > > functions
> > > >  - Counter
> > > >  - Timer
> > > >  - PWM
> > > >
> > > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > > > ---
> > > > v2->v3:
> > > >  * Dropped counter bindings and integrated with mfd as it has only
> > > one property.
> > > >  * Removed "#address-cells" and "#size-cells" as it do not have
> > > children with
> > > >    unit addresses.
> > > >  * Removed quotes from counter and pwm.
> > > >  * Provided full path for pwm bindings.
> > > >  * Updated the example.
> > > > v1->v2:
> > > >  * Modelled counter and pwm as a single device that handles
> > > >    multiple channels.
> > > >  * Moved counter and pwm bindings to respective subsystems
> > > >  * Dropped 'bindings' from MFD binding title.
> > > >  * Updated the example
> > > >  * Changed the compatible names.
> > > > ---
> > > >  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304
> > > ++++++++++++++++++
> > > >  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
> > > >  2 files changed, 354 insertions(+)
> > > >  create mode 100644
> > > > Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > >  create mode 100644
> > > > Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> > > >
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > new file mode 100644
> > > > index 000000000000..44c952ad8d35
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > @@ -0,0 +1,304 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> > 1.2
> > > > +---
> > > > +$id:
> > > >
> > > > +
> > > > +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a)
> > > > +
> > > > +maintainers:
> > > > +  - Biju Das <biju.das.jz@bp.renesas.com>
> > > > +
> > > > +description: |
> > > > +  This hardware block pconsisting of eight 16-bit timer channels
> > > and
> > > > +one
> > > > +  32- bit timer channel. It supports the following
> > specifications:
> > > > +    - Pulse input/output: 28 lines max.
> > > > +    - Pulse input 3 lines
> > > > +    - Count clock 11 clocks for each channel (14 clocks for MTU0,
> > > 12 clocks
> > > > +      for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2
> > > combination
> > > > +      (when LWA = 1))
> > > > +    - Operating frequency Up to 100 MHz
> > > > +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8]
> > > > +        - Waveform output on compare match
> > > > +        - Input capture function (noise filter setting available)
> > > > +        - Counter-clearing operation
> > > > +        - Simultaneous writing to multiple timer counters (TCNT)
> > > > +          (excluding MTU8).
> > > > +        - Simultaneous clearing on compare match or input capture
> > > > +          (excluding MTU8).
> > > > +        - Simultaneous input and output to registers in
> > > synchronization with
> > > > +          counter operations           (excluding MTU8).
> > > > +        - Up to 12-phase PWM output in combination with
> > synchronous
> > > operation
> > > > +          (excluding MTU8)
> > > > +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> > > > +        - Buffer operation specifiable
> > > > +    - [MTU1, MTU2]
> > > > +        - Phase counting mode can be specified independently
> > > > +        - 32-bit phase counting mode can be specified for
> > > interlocked operation
> > > > +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> > > > +        - Cascade connection operation available
> > > > +    - [MTU3, MTU4, MTU6, and MTU7]
> > > > +        - Through interlocked operation of MTU3/4 and MTU6/7, the
> > > positive and
> > > > +          negative signals in six phases (12 phases in total) can
> > > be output in
> > > > +          complementary PWM and reset-synchronized PWM operation.
> > > > +        - In complementary PWM mode, values can be transferred
> > from
> > > buffer
> > > > +          registers to temporary registers at crests and troughs
> > of
> > > the timer-
> > > > +          counter values or when the buffer registers (TGRD
> > > registers in MTU4
> > > > +          and MTU7) are written to.
> > > > +        - Double-buffering selectable in complementary PWM mode.
> > > > +    - [MTU3 and MTU4]
> > > > +        - Through interlocking with MTU0, a mode for driving AC
> > > synchronous
> > > > +          motors (brushless DC motors) by using complementary PWM
> > > output and
> > > > +          reset-synchronized PWM output is settable and allows
> > the
> > > selection
> > > > +          of two types of waveform output (chopping or level).
> > > > +    - [MTU5]
> > > > +        - Capable of operation as a dead-time compensation
> > counter.
> > > > +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> > > > +        - 32-bit phase counting mode specifiable by combining
> > MTU1
> > > and MTU2 and
> > > > +          through interlocked operation with MTU0/MTU5 and MTU8.
> > > > +    - Interrupt-skipping function
> > > > +        - In complementary PWM mode, interrupts on crests and
> > > troughs of counter
> > > > +          values and triggers to start conversion by the A/D
> > > converter can be
> > > > +          skipped.
> > > > +    - Interrupt sources: 43 sources.
> > > > +    - Buffer operation:
> > > > +        - Automatic transfer of register data (transfer from the
> > > buffer
> > > > +          register to the timer register).
> > > > +    - Trigger generation
> > > > +        - A/D converter start triggers can be generated
> > > > +        - A/D converter start request delaying function enables
> > A/D
> > > converter
> > > > +          to be started with any desired timing and to be
> > > synchronized with
> > > > +          PWM output.
> > > > +    - Low power consumption function
> > > > +        - The MTU3a can be placed in the module-stop state.
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    items:
> > > > +      - enum:
> > > > +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> > > > +          - renesas,r9a07g054-mtu3  # RZ/V2L
> > > > +      - const: renesas,rz-mtu3
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  interrupts:
> > > > +    items:
> > > > +      - description: MTU0.TGRA input capture/compare match
> > > > +      - description: MTU0.TGRB input capture/compare match
> > > > +      - description: MTU0.TGRC input capture/compare match
> > > > +      - description: MTU0.TGRD input capture/compare match
> > > > +      - description: MTU0.TCNT overflow
> > > > +      - description: MTU0.TGRE compare match
> > > > +      - description: MTU0.TGRF compare match
> > > > +      - description: MTU1.TGRA input capture/compare match
> > > > +      - description: MTU1.TGRB input capture/compare match
> > > > +      - description: MTU1.TCNT overflow
> > > > +      - description: MTU1.TCNT underflow
> > > > +      - description: MTU2.TGRA input capture/compare match
> > > > +      - description: MTU2.TGRB input capture/compare match
> > > > +      - description: MTU2.TCNT overflow
> > > > +      - description: MTU2.TCNT underflow
> > > > +      - description: MTU3.TGRA input capture/compare match
> > > > +      - description: MTU3.TGRB input capture/compare match
> > > > +      - description: MTU3.TGRC input capture/compare match
> > > > +      - description: MTU3.TGRD input capture/compare match
> > > > +      - description: MTU3.TCNT overflow
> > > > +      - description: MTU4.TGRA input capture/compare match
> > > > +      - description: MTU4.TGRB input capture/compare match
> > > > +      - description: MTU4.TGRC input capture/compare match
> > > > +      - description: MTU4.TGRD input capture/compare match
> > > > +      - description: MTU4.TCNT overflow/underflow
> > > > +      - description: MTU5.TGRU input capture/compare match
> > > > +      - description: MTU5.TGRV input capture/compare match
> > > > +      - description: MTU5.TGRW input capture/compare match
> > > > +      - description: MTU6.TGRA input capture/compare match
> > > > +      - description: MTU6.TGRB input capture/compare match
> > > > +      - description: MTU6.TGRC input capture/compare match
> > > > +      - description: MTU6.TGRD input capture/compare match
> > > > +      - description: MTU6.TCNT overflow
> > > > +      - description: MTU7.TGRA input capture/compare match
> > > > +      - description: MTU7.TGRB input capture/compare match
> > > > +      - description: MTU7.TGRC input capture/compare match
> > > > +      - description: MTU7.TGRD input capture/compare match
> > > > +      - description: MTU7.TCNT overflow/underflow
> > > > +      - description: MTU8.TGRA input capture/compare match
> > > > +      - description: MTU8.TGRB input capture/compare match
> > > > +      - description: MTU8.TGRC input capture/compare match
> > > > +      - description: MTU8.TGRD input capture/compare match
> > > > +      - description: MTU8.TCNT overflow
> > > > +      - description: MTU8.TCNT underflow
> > > > +
> > > > +  interrupt-names:
> > > > +    items:
> > > > +      - const: tgia0
> > > > +      - const: tgib0
> > > > +      - const: tgic0
> > > > +      - const: tgid0
> > > > +      - const: tgiv0
> > > > +      - const: tgie0
> > > > +      - const: tgif0
> > > > +      - const: tgia1
> > > > +      - const: tgib1
> > > > +      - const: tgiv1
> > > > +      - const: tgiu1
> > > > +      - const: tgia2
> > > > +      - const: tgib2
> > > > +      - const: tgiv2
> > > > +      - const: tgiu2
> > > > +      - const: tgia3
> > > > +      - const: tgib3
> > > > +      - const: tgic3
> > > > +      - const: tgid3
> > > > +      - const: tgiv3
> > > > +      - const: tgia4
> > > > +      - const: tgib4
> > > > +      - const: tgic4
> > > > +      - const: tgid4
> > > > +      - const: tgiv4
> > > > +      - const: tgiu5
> > > > +      - const: tgiv5
> > > > +      - const: tgiw5
> > > > +      - const: tgia6
> > > > +      - const: tgib6
> > > > +      - const: tgic6
> > > > +      - const: tgid6
> > > > +      - const: tgiv6
> > > > +      - const: tgia7
> > > > +      - const: tgib7
> > > > +      - const: tgic7
> > > > +      - const: tgid7
> > > > +      - const: tgiv7
> > > > +      - const: tgia8
> > > > +      - const: tgib8
> > > > +      - const: tgic8
> > > > +      - const: tgid8
> > > > +      - const: tgiv8
> > > > +      - const: tgiu8
> > > > +
> > > > +  clocks:
> > > > +    maxItems: 1
> > > > +
> > > > +  power-domains:
> > > > +    maxItems: 1
> > > > +
> > > > +  resets:
> > > > +    maxItems: 1
> > > > +
> > > > +  counter:
> > > > +    description:
> > > > +      There are two phase counting modes. 16-bit phase counting
> > > mode in which
> > > > +      MTU1 and MTU2 operate independently, and cascade connection
> > > 32-bit phase
> > > > +      counting mode in which MTU1 and MTU2 are cascaded.
> > > > +
> > > > +      In phase counting mode, the phase difference between two
> > > external input
> > > > +      clocks is detected and the corresponding TCNT is
> > incremented
> > > or
> > > > +      decremented.
> > > > +      The below counters are supported
> > > > +        count0 - MTU1 16-bit phase counting
> > > > +        count1 - MTU2 16-bit phase counting
> > > > +        count2 - MTU1+ MTU2 32-bit phase counting
> > > > +
> > > > +    type: object
> > > > +
> > > > +    properties:
> > > > +      compatible:
> > > > +        const: renesas,rz-mtu3-counter
> > > > +
> > > > +    required:
> > > > +      - compatible
> > > > +
> > > > +    additionalProperties: false
> > > > +
> > > > +  pwm:
> > > > +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +  - interrupts
> > > > +  - interrupt-names
> > > > +  - clocks
> > > > +  - power-domains
> > > > +  - resets
> > > > +
> > > > +additionalProperties: false
> > > > +
> > > > +examples:
> > > > +  - |
> > > > +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> > > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > > +
> > > > +    mtu3: timer@10001200 {
> > > > +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3";
> > > > +      reg = <0x10001200 0xb00>;

> > > > +
> > > > +      counter {
> > > > +        compatible = "renesas,rz-mtu3-counter";
> > >
> > > You don't have any resources for the counter in DT, so you don't
> > even
> > > need a node here. Just have the parent driver instaniate the counter
> > > driver.
> >
>
> If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then instantiating
> the counter and pwm driver from parent driver by directly calling probe function is
> giving cyclic dependency error[1].
>
> So looks like either we need to use compatible "renesas,rz-mtu3-counter" and
> "renesas,rz-mtu3-pwm" if these functionalities to be in respective subsystem tree
>
> or
>
> squash counter and pwm functionalities to MFD subsystem.
>
> Please share your views on this. Is there any better way to handle this?

I think what Rob means is that you can have a single driver that binds
against "renesas,rz-mtu3", and registers both the counter and the pwm
functionalities. Just like the clock driver, which registers clock,
reset, and PM Domain functionalities.  I.e. no mfd would be involved
anymore.
You can still split the driver functionality across multiple source
files (core, counter, pwm).

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-08  7:42       ` Biju Das
  2022-10-08 10:51         ` Biju Das
  2022-10-09 14:38         ` Geert Uytterhoeven
@ 2022-10-09 15:16         ` Krzysztof Kozlowski
  2022-10-10 15:13           ` Biju Das
  2 siblings, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2022-10-09 15:16 UTC (permalink / raw)
  To: Biju Das, Rob Herring, William Breathitt Gray, Thierry Reding,
	Lee Jones, Philipp Zabel
  Cc: Krzysztof Kozlowski, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

On 08/10/2022 09:42, Biju Das wrote:

>>>> +                        "tgia8", "tgib8", "tgic8", "tgid8",
>>> "tgiv8", "tgiu8";
>>>> +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
>>>> +      power-domains = <&cpg>;
>>>> +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
>>>> +
>>>> +      counter {
>>>> +        compatible = "renesas,rz-mtu3-counter";
>>>
>>> You don't have any resources for the counter in DT, so you don't
>> even
>>> need a node here. Just have the parent driver instaniate the counter
>>> driver.
>>
> 
> If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then instantiating 
> the counter and pwm driver from parent driver by directly calling probe function is
> giving cyclic dependency error[1].

How is this related to DT? Purpose of DT is not to solve your probe
problems.

> 
> So looks like either we need to use compatible "renesas,rz-mtu3-counter" and 
> "renesas,rz-mtu3-pwm" if these functionalities to be in respective subsystem tree
> 

No, you don't need. Your driver implementation is not really related to
the bindings.


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-09 14:38         ` Geert Uytterhoeven
@ 2022-10-09 15:17           ` Krzysztof Kozlowski
  2022-10-10 13:00             ` Biju Das
  2022-10-10  7:10           ` Biju Das
  1 sibling, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2022-10-09 15:17 UTC (permalink / raw)
  To: Geert Uytterhoeven, Biju Das
  Cc: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel, Krzysztof Kozlowski, Uwe Kleine-König,
	devicetree, linux-pwm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

On 09/10/2022 16:38, Geert Uytterhoeven wrote:
>>
>> So looks like either we need to use compatible "renesas,rz-mtu3-counter" and
>> "renesas,rz-mtu3-pwm" if these functionalities to be in respective subsystem tree
>>
>> or
>>
>> squash counter and pwm functionalities to MFD subsystem.
>>
>> Please share your views on this. Is there any better way to handle this?
> 
> I think what Rob means is that you can have a single driver that binds
> against "renesas,rz-mtu3", and registers both the counter and the pwm
> functionalities. Just like the clock driver, which registers clock,
> reset, and PM Domain functionalities.  I.e. no mfd would be involved
> anymore.
> You can still split the driver functionality across multiple source
> files (core, counter, pwm).

Yes.

Bindings design is independent of driver design (e.g. still MFD framework).

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-09 14:38         ` Geert Uytterhoeven
  2022-10-09 15:17           ` Krzysztof Kozlowski
@ 2022-10-10  7:10           ` Biju Das
  1 sibling, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-10  7:10 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel, Krzysztof Kozlowski, Uwe Kleine-König,
	devicetree, linux-pwm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Geert,

Thanks for the feedback.

> Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> Hi Biju,
> 
> On Sat, Oct 8, 2022 at 9:42 AM Biju Das <biju.das.jz@bp.renesas.com>
> wrote:
> > > > On Thu, Oct 06, 2022 at 02:57:14PM +0100, Biju Das wrote:
> > > > > The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is
> embedded
> > > in
> > > > > the Renesas RZ/G2L family SoC's. It consists of eight 16-bit
> > > > > timer channels and one 32-bit timer channel. It supports the
> > > > > following functions
> > > > >  - Counter
> > > > >  - Timer
> > > > >  - PWM
> > > > >
> > > > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > > > > ---
> > > > > v2->v3:
> > > > >  * Dropped counter bindings and integrated with mfd as it has
> > > > > only
> > > > one property.
> > > > >  * Removed "#address-cells" and "#size-cells" as it do not
> have
> > > > children with
> > > > >    unit addresses.
> > > > >  * Removed quotes from counter and pwm.
> > > > >  * Provided full path for pwm bindings.
> > > > >  * Updated the example.
> > > > > v1->v2:
> > > > >  * Modelled counter and pwm as a single device that handles
> > > > >    multiple channels.
> > > > >  * Moved counter and pwm bindings to respective subsystems
> > > > >  * Dropped 'bindings' from MFD binding title.
> > > > >  * Updated the example
> > > > >  * Changed the compatible names.
> > > > > ---
> > > > >  .../bindings/mfd/renesas,rz-mtu3.yaml         | 304
> > > > ++++++++++++++++++
> > > > >  .../bindings/pwm/renesas,rz-mtu3-pwm.yaml     |  50 +++
> > > > >  2 files changed, 354 insertions(+)  create mode 100644
> > > > > Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > >  create mode 100644
> > > > > Documentation/devicetree/bindings/pwm/renesas,rz-mtu3-pwm.yaml
> > > > >
> > > > > diff --git
> > > > > a/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > > b/Documentation/devicetree/bindings/mfd/renesas,rz-mtu3.yaml
> > > > > new file mode 100644
> > > > > index 000000000000..44c952ad8d35
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/mfd/renesas,rz-
> mtu3.yaml
> > > > > @@ -0,0 +1,304 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> %YAML
> > > 1.2
> > > > > +---
> > > > > +$id:
> > > > >
> > > > > +
> > > > > +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3
> (MTU3a)
> > > > > +
> > > > > +maintainers:
> > > > > +  - Biju Das <biju.das.jz@bp.renesas.com>
> > > > > +
> > > > > +description: |
> > > > > +  This hardware block pconsisting of eight 16-bit timer
> > > > > +channels
> > > > and
> > > > > +one
> > > > > +  32- bit timer channel. It supports the following
> > > specifications:
> > > > > +    - Pulse input/output: 28 lines max.
> > > > > +    - Pulse input 3 lines
> > > > > +    - Count clock 11 clocks for each channel (14 clocks for
> > > > > + MTU0,
> > > > 12 clocks
> > > > > +      for MTU2, and 10 clocks for MTU5, four clocks for
> > > > > + MTU1-MTU2
> > > > combination
> > > > > +      (when LWA = 1))
> > > > > +    - Operating frequency Up to 100 MHz
> > > > > +    - Available operations [MTU0 to MTU4, MTU6, MTU7, and
> MTU8]
> > > > > +        - Waveform output on compare match
> > > > > +        - Input capture function (noise filter setting
> available)
> > > > > +        - Counter-clearing operation
> > > > > +        - Simultaneous writing to multiple timer counters
> (TCNT)
> > > > > +          (excluding MTU8).
> > > > > +        - Simultaneous clearing on compare match or input
> capture
> > > > > +          (excluding MTU8).
> > > > > +        - Simultaneous input and output to registers in
> > > > synchronization with
> > > > > +          counter operations           (excluding MTU8).
> > > > > +        - Up to 12-phase PWM output in combination with
> > > synchronous
> > > > operation
> > > > > +          (excluding MTU8)
> > > > > +    - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8]
> > > > > +        - Buffer operation specifiable
> > > > > +    - [MTU1, MTU2]
> > > > > +        - Phase counting mode can be specified independently
> > > > > +        - 32-bit phase counting mode can be specified for
> > > > interlocked operation
> > > > > +          of MTU1 and MTU2 (when TMDR3.LWA = 1)
> > > > > +        - Cascade connection operation available
> > > > > +    - [MTU3, MTU4, MTU6, and MTU7]
> > > > > +        - Through interlocked operation of MTU3/4 and MTU6/7,
> > > > > + the
> > > > positive and
> > > > > +          negative signals in six phases (12 phases in total)
> > > > > + can
> > > > be output in
> > > > > +          complementary PWM and reset-synchronized PWM
> operation.
> > > > > +        - In complementary PWM mode, values can be
> transferred
> > > from
> > > > buffer
> > > > > +          registers to temporary registers at crests and
> > > > > + troughs
> > > of
> > > > the timer-
> > > > > +          counter values or when the buffer registers (TGRD
> > > > registers in MTU4
> > > > > +          and MTU7) are written to.
> > > > > +        - Double-buffering selectable in complementary PWM
> mode.
> > > > > +    - [MTU3 and MTU4]
> > > > > +        - Through interlocking with MTU0, a mode for driving
> AC
> > > > synchronous
> > > > > +          motors (brushless DC motors) by using complementary
> > > > > + PWM
> > > > output and
> > > > > +          reset-synchronized PWM output is settable and
> allows
> > > the
> > > > selection
> > > > > +          of two types of waveform output (chopping or
> level).
> > > > > +    - [MTU5]
> > > > > +        - Capable of operation as a dead-time compensation
> > > counter.
> > > > > +    - [MTU0/MTU5, MTU1, MTU2, and MTU8]
> > > > > +        - 32-bit phase counting mode specifiable by combining
> > > MTU1
> > > > and MTU2 and
> > > > > +          through interlocked operation with MTU0/MTU5 and
> MTU8.
> > > > > +    - Interrupt-skipping function
> > > > > +        - In complementary PWM mode, interrupts on crests and
> > > > troughs of counter
> > > > > +          values and triggers to start conversion by the A/D
> > > > converter can be
> > > > > +          skipped.
> > > > > +    - Interrupt sources: 43 sources.
> > > > > +    - Buffer operation:
> > > > > +        - Automatic transfer of register data (transfer from
> > > > > + the
> > > > buffer
> > > > > +          register to the timer register).
> > > > > +    - Trigger generation
> > > > > +        - A/D converter start triggers can be generated
> > > > > +        - A/D converter start request delaying function
> enables
> > > A/D
> > > > converter
> > > > > +          to be started with any desired timing and to be
> > > > synchronized with
> > > > > +          PWM output.
> > > > > +    - Low power consumption function
> > > > > +        - The MTU3a can be placed in the module-stop state.
> > > > > +
> > > > > +properties:
> > > > > +  compatible:
> > > > > +    items:
> > > > > +      - enum:
> > > > > +          - renesas,r9a07g044-mtu3  # RZ/G2{L,LC}
> > > > > +          - renesas,r9a07g054-mtu3  # RZ/V2L
> > > > > +      - const: renesas,rz-mtu3
> > > > > +
> > > > > +  reg:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  interrupts:
> > > > > +    items:
> > > > > +      - description: MTU0.TGRA input capture/compare match
> > > > > +      - description: MTU0.TGRB input capture/compare match
> > > > > +      - description: MTU0.TGRC input capture/compare match
> > > > > +      - description: MTU0.TGRD input capture/compare match
> > > > > +      - description: MTU0.TCNT overflow
> > > > > +      - description: MTU0.TGRE compare match
> > > > > +      - description: MTU0.TGRF compare match
> > > > > +      - description: MTU1.TGRA input capture/compare match
> > > > > +      - description: MTU1.TGRB input capture/compare match
> > > > > +      - description: MTU1.TCNT overflow
> > > > > +      - description: MTU1.TCNT underflow
> > > > > +      - description: MTU2.TGRA input capture/compare match
> > > > > +      - description: MTU2.TGRB input capture/compare match
> > > > > +      - description: MTU2.TCNT overflow
> > > > > +      - description: MTU2.TCNT underflow
> > > > > +      - description: MTU3.TGRA input capture/compare match
> > > > > +      - description: MTU3.TGRB input capture/compare match
> > > > > +      - description: MTU3.TGRC input capture/compare match
> > > > > +      - description: MTU3.TGRD input capture/compare match
> > > > > +      - description: MTU3.TCNT overflow
> > > > > +      - description: MTU4.TGRA input capture/compare match
> > > > > +      - description: MTU4.TGRB input capture/compare match
> > > > > +      - description: MTU4.TGRC input capture/compare match
> > > > > +      - description: MTU4.TGRD input capture/compare match
> > > > > +      - description: MTU4.TCNT overflow/underflow
> > > > > +      - description: MTU5.TGRU input capture/compare match
> > > > > +      - description: MTU5.TGRV input capture/compare match
> > > > > +      - description: MTU5.TGRW input capture/compare match
> > > > > +      - description: MTU6.TGRA input capture/compare match
> > > > > +      - description: MTU6.TGRB input capture/compare match
> > > > > +      - description: MTU6.TGRC input capture/compare match
> > > > > +      - description: MTU6.TGRD input capture/compare match
> > > > > +      - description: MTU6.TCNT overflow
> > > > > +      - description: MTU7.TGRA input capture/compare match
> > > > > +      - description: MTU7.TGRB input capture/compare match
> > > > > +      - description: MTU7.TGRC input capture/compare match
> > > > > +      - description: MTU7.TGRD input capture/compare match
> > > > > +      - description: MTU7.TCNT overflow/underflow
> > > > > +      - description: MTU8.TGRA input capture/compare match
> > > > > +      - description: MTU8.TGRB input capture/compare match
> > > > > +      - description: MTU8.TGRC input capture/compare match
> > > > > +      - description: MTU8.TGRD input capture/compare match
> > > > > +      - description: MTU8.TCNT overflow
> > > > > +      - description: MTU8.TCNT underflow
> > > > > +
> > > > > +  interrupt-names:
> > > > > +    items:
> > > > > +      - const: tgia0
> > > > > +      - const: tgib0
> > > > > +      - const: tgic0
> > > > > +      - const: tgid0
> > > > > +      - const: tgiv0
> > > > > +      - const: tgie0
> > > > > +      - const: tgif0
> > > > > +      - const: tgia1
> > > > > +      - const: tgib1
> > > > > +      - const: tgiv1
> > > > > +      - const: tgiu1
> > > > > +      - const: tgia2
> > > > > +      - const: tgib2
> > > > > +      - const: tgiv2
> > > > > +      - const: tgiu2
> > > > > +      - const: tgia3
> > > > > +      - const: tgib3
> > > > > +      - const: tgic3
> > > > > +      - const: tgid3
> > > > > +      - const: tgiv3
> > > > > +      - const: tgia4
> > > > > +      - const: tgib4
> > > > > +      - const: tgic4
> > > > > +      - const: tgid4
> > > > > +      - const: tgiv4
> > > > > +      - const: tgiu5
> > > > > +      - const: tgiv5
> > > > > +      - const: tgiw5
> > > > > +      - const: tgia6
> > > > > +      - const: tgib6
> > > > > +      - const: tgic6
> > > > > +      - const: tgid6
> > > > > +      - const: tgiv6
> > > > > +      - const: tgia7
> > > > > +      - const: tgib7
> > > > > +      - const: tgic7
> > > > > +      - const: tgid7
> > > > > +      - const: tgiv7
> > > > > +      - const: tgia8
> > > > > +      - const: tgib8
> > > > > +      - const: tgic8
> > > > > +      - const: tgid8
> > > > > +      - const: tgiv8
> > > > > +      - const: tgiu8
> > > > > +
> > > > > +  clocks:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  power-domains:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  resets:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  counter:
> > > > > +    description:
> > > > > +      There are two phase counting modes. 16-bit phase
> counting
> > > > mode in which
> > > > > +      MTU1 and MTU2 operate independently, and cascade
> > > > > + connection
> > > > 32-bit phase
> > > > > +      counting mode in which MTU1 and MTU2 are cascaded.
> > > > > +
> > > > > +      In phase counting mode, the phase difference between
> two
> > > > external input
> > > > > +      clocks is detected and the corresponding TCNT is
> > > incremented
> > > > or
> > > > > +      decremented.
> > > > > +      The below counters are supported
> > > > > +        count0 - MTU1 16-bit phase counting
> > > > > +        count1 - MTU2 16-bit phase counting
> > > > > +        count2 - MTU1+ MTU2 32-bit phase counting
> > > > > +
> > > > > +    type: object
> > > > > +
> > > > > +    properties:
> > > > > +      compatible:
> > > > > +        const: renesas,rz-mtu3-counter
> > > > > +
> > > > > +    required:
> > > > > +      - compatible
> > > > > +
> > > > > +    additionalProperties: false
> > > > > +
> > > > > +  pwm:
> > > > > +    $ref: /schemas/pwm/renesas,rz-mtu3-pwm.yaml
> > > > > +
> > > > > +required:
> > > > > +  - compatible
> > > > > +  - reg
> > > > > +  - interrupts
> > > > > +  - interrupt-names
> > > > > +  - clocks
> > > > > +  - power-domains
> > > > > +  - resets
> > > > > +
> > > > > +additionalProperties: false
> > > > > +
> > > > > +examples:
> > > > > +  - |
> > > > > +    #include <dt-bindings/clock/r9a07g044-cpg.h>
> > > > > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > > > +
> > > > > +    mtu3: timer@10001200 {
> > > > > +      compatible = "renesas,r9a07g044-mtu3", "renesas,rz-
> mtu3";
> > > > > +      reg = <0x10001200 0xb00>;
> 
> > > > > +
> > > > > +      counter {
> > > > > +        compatible = "renesas,rz-mtu3-counter";
> > > >
> > > > You don't have any resources for the counter in DT, so you don't
> > > even
> > > > need a node here. Just have the parent driver instaniate the
> > > > counter driver.
> > >
> >
> > If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then
> > instantiating the counter and pwm driver from parent driver by
> > directly calling probe function is giving cyclic dependency
> error[1].
> >
> > So looks like either we need to use compatible
> > "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" if these
> > functionalities to be in respective subsystem tree
> >
> > or
> >
> > squash counter and pwm functionalities to MFD subsystem.
> >
> > Please share your views on this. Is there any better way to handle
> this?
> 
> I think what Rob means is that you can have a single driver that binds
> against "renesas,rz-mtu3", and registers both the counter and the pwm
> functionalities. Just like the clock driver, which registers clock,
> reset, and PM Domain functionalities.  I.e. no mfd would be involved
> anymore.

Thanks for clarification. OK, will use single driver that binds
against "renesas,rz-mtu3".

> You can still split the driver functionality across multiple source
> files (core, counter, pwm).

Yep, Will do. This split will give clear separation to make reviews easier
for the relevant subsystem people.

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-09 15:17           ` Krzysztof Kozlowski
@ 2022-10-10 13:00             ` Biju Das
  0 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-10 13:00 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Geert Uytterhoeven
  Cc: Rob Herring, William Breathitt Gray, Thierry Reding, Lee Jones,
	Philipp Zabel, Krzysztof Kozlowski, Uwe Kleine-König,
	devicetree, linux-pwm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Krzysztof Kozlowski,

Thanks for the feedback.

> Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> On 09/10/2022 16:38, Geert Uytterhoeven wrote:
> >>
> >> So looks like either we need to use compatible
> >> "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" if these
> >> functionalities to be in respective subsystem tree
> >>
> >> or
> >>
> >> squash counter and pwm functionalities to MFD subsystem.
> >>
> >> Please share your views on this. Is there any better way to handle
> this?
> >
> > I think what Rob means is that you can have a single driver that
> binds
> > against "renesas,rz-mtu3", and registers both the counter and the
> pwm
> > functionalities. Just like the clock driver, which registers clock,
> > reset, and PM Domain functionalities.  I.e. no mfd would be involved
> > anymore.
> > You can still split the driver functionality across multiple source
> > files (core, counter, pwm).
> 
> Yes.

Ok.

> 
> Bindings design is independent of driver design (e.g. still MFD
> framework).

I agree, binding is for describing hardware.

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings
  2022-10-09 15:16         ` Krzysztof Kozlowski
@ 2022-10-10 15:13           ` Biju Das
  0 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-10 15:13 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Rob Herring, William Breathitt Gray,
	Thierry Reding, Lee Jones, Philipp Zabel
  Cc: Krzysztof Kozlowski, Uwe Kleine-König, devicetree,
	linux-pwm, Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi Krzysztof Kozlowski,

> Subject: Re: [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a
> bindings
> 
> On 08/10/2022 09:42, Biju Das wrote:
> 
> >>>> +                        "tgia8", "tgib8", "tgic8", "tgid8",
> >>> "tgiv8", "tgiu8";
> >>>> +      clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
> >>>> +      power-domains = <&cpg>;
> >>>> +      resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
> >>>> +
> >>>> +      counter {
> >>>> +        compatible = "renesas,rz-mtu3-counter";
> >>>
> >>> You don't have any resources for the counter in DT, so you don't
> >> even
> >>> need a node here. Just have the parent driver instaniate the
> counter
> >>> driver.
> >>
> >
> > If I remove "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" then
> > instantiating the counter and pwm driver from parent driver by
> > directly calling probe function is giving cyclic dependency
> error[1].
> 
> How is this related to DT? Purpose of DT is not to solve your probe
> problems.

OK.

> 
> >
> > So looks like either we need to use compatible
> > "renesas,rz-mtu3-counter" and "renesas,rz-mtu3-pwm" if these
> > functionalities to be in respective subsystem tree
> >
> 
> No, you don't need. Your driver implementation is not really related
> to the bindings.

OK. Posted [1] with the suggested binding changes.

[1] https://patchwork.kernel.org/project/linux-renesas-soc/list/?series=684233

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-08  9:01     ` Biju Das
@ 2022-10-11 13:15       ` William Breathitt Gray
  2022-10-11 15:50         ` Biju Das
  0 siblings, 1 reply; 23+ messages in thread
From: William Breathitt Gray @ 2022-10-11 13:15 UTC (permalink / raw)
  To: Biju Das
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 6303 bytes --]

On Sat, Oct 08, 2022 at 09:01:21AM +0000, Biju Das wrote:
> Hi William Breathitt Gray,
> 
> Thanks for the feedback.

Hello Biju,

I see that you have already released a v4, so some of my comments may no
longer apply, but I want to respond here to continue our discussions;
I'll reiterate any relevant suggestions when I review v4 in the coming
days.

By the way, if you agree with a review comment there is no need to reply
with "OK"; just delete the parts you agree with from your response and
I'll know those are okay. Doing this will reduce the amount of text we
have to scroll through and thus allow us to focus on just the questions
we have remaining. ;-)

> > > +/**
> > > + * struct rz_mtu3_cnt - MTU3 counter private data
> > > + *
> > > + * @clk: MTU3 module clock
> > > + * @lock: Lock to prevent concurrent access for ceiling and count
> > > + * @rz_mtu3_channel: HW channels for the counters  */ struct
> > > +rz_mtu3_cnt {
> > > +	struct clk *clk;
> > > +	struct mutex lock;
> > > +	struct rz_mtu3_channel *ch[RZ_MTU3_MAX_HW_CNTR_CHANNELS];
> > 
> > Does this need to be a pointer to an array of struct rz_mtu3_channel?
> 
> Yes, HW has MTU{0..8} channels and MTU{1,2} supports counters
> At probe time this array is filled with *ch[0]= MTU1 and *ch[1]= MTU2

In the rz_mtu3_cnt_probe() function I see the rz_mtu3_cnt.ch elements
manually set to the address of each rz_mtu3.channels element:

    for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) {
        priv->ch[i] = &ddata->channels[RZ_MTU1 + i];
	priv->ch[i]->dev = dev;
    ...

The rz_mut3.channels member is a contiguous array of struct
rz_mtu3_channel. If you change the rz_mtu3_channel to a pointer to
struct rz_mtu3_channel, you can set it to the RZ_MTU1 offset address
outside of the for loop and thus avoid the double dereference because
these address are contiguous:

    priv->ch = &ddata->channels[RZ_MTU1];
    for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) {
	priv->ch[i].dev = dev;
    ...

> > > +	mutex_lock(&priv->lock);
> > > +	if (ceiling == 0) {
> > > +		rz_mtu3_8bit_ch_write(priv->ch[id], RZ_MTU3_TCR,
> > > +				      RZ_MTU3_TCR_CCLR_NONE);
> > 
> > Looks like something different is done when ceiling is set to 0. Would
> > you explain what's happening in this case and why it's different that
> > then else case below; in other words, what's the difference between
> > RZ_MTU3_TCR_CCLR_NONE and RZ_MTU3_TCR_CCLR_TGRA?
> 
> RZ_MTU3_TCR_CCLR_TGRA --> for triggering counter count using Z-Phase signal.
> RZ_MTU3_TCR_CCLR_NONE --> No clearing.

Does the Z-Phase signal trigger a reset of the counter count back to the
ceiling value? Does the count loop back to 0 when it passes the ceiling
value, or does it remain at the ceiling until the direction changes?
By "no clearing" do you mean that the ceiling is disabled in this case
and the Counter count increases without limit?

In the Counter subsystem, the "ceiling" Count extension puts an upper
limit on the Count value. This means that setting "ceiling" to 0 would
put the upper limit at 0, effectively restricting the Count value to 0
until the value of "ceiling" is raised.

If the device is unable to support a ceiling value of 0, you should
return -ERANGE rather than disable the ceiling.

> > > +static void rz_mtu3_16bit_cnt_setting(struct counter_device
> > *counter,
> > > +int id) {
> > > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > > +
> > > +	priv->ch[id]->function = RZ_MTU3_16BIT_PHASE_COUNTING;
> > 
> > If 16-bit phase counting is selected for one 16-bit counter, does the
> > other 16-bit counter need to be configured as well?
> 
> Not required I guess, as it is run time decision.
> 
> After this, if user tries to enable 16-bit on other channel,
> we will configure that channel. otherwise, we will return error,
> if user tries to enable 32-bit channel.
> 
> Are you ok with this? 

Because the phase mode affects how the device interprets multiple
channels rather than a specific one, maybe it's better to save this
state as an enum rz_mtu3_function member of struct rz_mtu3_cnt. Or if
this is affecting the entire device, move it to your struct rz_mut3 and
share a pointer to that for your Counter and PWM drivers.

It makes me wonder if the rz_mut3_cnt structure is necessary for this
Counter driver at all when you could pass a pointer your existing
rz_mut3 structure instead in order to access the channels.

> > > +	int ret = 0;
> > > +
> > > +	if (enable) {
> > > +		pm_runtime_get_sync(ch->dev);
> > > +		ret = rz_mtu3_initialize_counter(counter, count->id);
> > 
> > Are you using the Count's "enable" extension to switch between 16-bit
> > and 32-bit phase modes?
> 
> No. But will use that for switching on the next version.

Sorry, I wasn't clear with my question. Please do not implement the
"enable" Count extensions as a way to toggle between the 16-bit and
32-bit phase modes. The purpose of "enable" is to provide a pause/resume
mechanism for a Count: the existing count value should be preserved when
a Count is disabled, and should continue where it left off when the
Count is enabled.

To support the phase mode selection, implement a Counter device
extension for that specific purpose. You can use DEFINE_COUNTER_ENUM()
and COUNTER_COMP_DEVICE_ENUM() to create a device extension that will
allow users to toggle between "16-bit" and "32-bit" phase modes. If you
need help with these macros, just let me know.

> > > +		.name = "Channel3 Count(32-bit)",
> > 
> > We probably don't need the "(32-bit)" in the name when it's obvious
> > already from the channel id and ceiling value.
> 
> OK will remove it.
> > 
> > I wonder how this counter is described in the RZ/G2L user
> > documentation; is it named "Channel 3" or "Channel 1 and 2"?
> 
> It is mentioned as MTU1 and MTU2 channels.
> 
> These channels can be used for phase counting and PWM operations.

We should avoid calling it "Channel 3" in that case to avoid confusion.
Perhaps "Channel 1 and 2 (combined) Count" would be better; that's just
something I came up with off the top of my head, but if you can think of
a better way to phrase it then please do.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-11 13:15       ` William Breathitt Gray
@ 2022-10-11 15:50         ` Biju Das
  2022-10-11 17:55           ` Biju Das
  2022-10-13  0:19           ` William Breathitt Gray
  0 siblings, 2 replies; 23+ messages in thread
From: Biju Das @ 2022-10-11 15:50 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi William Breathitt Gray,

Thanks for the feedback.

> Subject: Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
> 
> On Sat, Oct 08, 2022 at 09:01:21AM +0000, Biju Das wrote:
> > Hi William Breathitt Gray,
> >
> > Thanks for the feedback.
> 
> Hello Biju,
> 
> I see that you have already released a v4, so some of my comments may
> no longer apply, but I want to respond here to continue our
> discussions; I'll reiterate any relevant suggestions when I review v4
> in the coming days.
> 
> By the way, if you agree with a review comment there is no need to
> reply with "OK"; just delete the parts you agree with from your
> response and I'll know those are okay. Doing this will reduce the
> amount of text we have to scroll through and thus allow us to focus on
> just the questions we have remaining. ;-)

OK.

> > > Looks like something different is done when ceiling is set to 0.
> > > Would you explain what's happening in this case and why it's
> > > different that then else case below; in other words, what's the
> > > difference between RZ_MTU3_TCR_CCLR_NONE and
> RZ_MTU3_TCR_CCLR_TGRA?
> >
> > RZ_MTU3_TCR_CCLR_TGRA --> for triggering counter count using Z-Phase
> signal.
> > RZ_MTU3_TCR_CCLR_NONE --> No clearing.
> 
> Does the Z-Phase signal trigger a reset of the counter count back to
> the ceiling value? 

No, It resets to 0.

Does the count loop back to 0 when it passes the
> ceiling value,

Yes, it loopback to 0.

 or does it remain at the ceiling until the direction
> changes?

No.

> By "no clearing" do you mean that the ceiling is disabled in this case
> and the Counter count increases without limit?

Counter clear source disabled. So the counter won't reset to 0 by applying
Z-Phase signal.

> 
> In the Counter subsystem, the "ceiling" Count extension puts an upper
> limit on the Count value. This means that setting "ceiling" to 0 would
> put the upper limit at 0, effectively restricting the Count value to 0
> until the value of "ceiling" is raised.
> 
> If the device is unable to support a ceiling value of 0, you should
> return -ERANGE rather than disable the ceiling.

OK, will check this.


> 
> > > > +static void rz_mtu3_16bit_cnt_setting(struct counter_device
> > > *counter,
> > > > +int id) {
> > > > +	struct rz_mtu3_cnt *const priv = counter_priv(counter);
> > > > +
> > > > +	priv->ch[id]->function = RZ_MTU3_16BIT_PHASE_COUNTING;
> > >
> > > If 16-bit phase counting is selected for one 16-bit counter, does
> > > the other 16-bit counter need to be configured as well?
> >
> > Not required I guess, as it is run time decision.
> >
> > After this, if user tries to enable 16-bit on other channel, we will
> > configure that channel. otherwise, we will return error, if user
> tries
> > to enable 32-bit channel.
> >
> > Are you ok with this?
> 
> Because the phase mode affects how the device interprets multiple
> channels rather than a specific one, maybe it's better to save this
> state as an enum rz_mtu3_function member of struct rz_mtu3_cnt. Or if
> this is affecting the entire device, move it to your struct rz_mut3
> and share a pointer to that for your Counter and PWM drivers.

It is the same pointer allocated by parent and shared to both Counter
and PWM drivers. At runtime any device can claim the channel by checking
RZ_MTU3_NORMAL function.

> 
> It makes me wonder if the rz_mut3_cnt structure is necessary for this
> Counter driver at all when you could pass a pointer your existing
> rz_mut3 structure instead in order to access the channels.

It is a shared pointer. For easy handling I have added 
only 2 channels that are relevant for the counter in rz_mut3_cnt.
Similar case for pwm.

> 
> > > > +	int ret = 0;
> > > > +
> > > > +	if (enable) {
> > > > +		pm_runtime_get_sync(ch->dev);
> > > > +		ret = rz_mtu3_initialize_counter(counter, count->id);
> > >
> > > Are you using the Count's "enable" extension to switch between
> > > 16-bit and 32-bit phase modes?
> >
> > No. But will use that for switching on the next version.
> 
> Sorry, I wasn't clear with my question. Please do not implement the
> "enable" Count extensions as a way to toggle between the 16-bit and
> 32-bit phase modes. The purpose of "enable" is to provide a
> pause/resume mechanism for a Count: the existing count value should be
> preserved when a Count is disabled, and should continue where it left
> off when the Count is enabled.

I use below sample program to test 16-bit and 32-bit phase mode
Counting with trigger for clear count by grounding the Z-phase pin.

16-bit phase testing
------------------
echo 1 > /sys/bus/counter/devices/counter0/count0/enable
echo 0 > /sys/bus/counter/devices/counter0/count0/count
echo 20 > /sys/bus/counter/devices/counter0/count0/ceiling
       
echo 1 > /sys/bus/counter/devices/counter0/count1/enable
echo 0 > /sys/bus/counter/devices/counter0/count1/count
echo 20 > /sys/bus/counter/devices/counter0/count1/ceiling

for i in {1..200};
do
   cat /sys/bus/counter/devices/counter0/count0/count;
   cat /sys/bus/counter/devices/counter0/count1/count;
done

echo 0 > /sys/bus/counter/devices/counter0/count1/enable
echo 0 > /sys/bus/counter/devices/counter0/count0/enable

32-bit phase count testing
--------------------------
echo 1 > /sys/bus/counter/devices/counter0/count2/enable
echo 0 > /sys/bus/counter/devices/counter0/count2/count
echo 20 > /sys/bus/counter/devices/counter0/count2/ceiling

for i in {1..200};
do
   cat /sys/bus/counter/devices/counter0/count2/count;
done

echo 0 > /sys/bus/counter/devices/counter0/count2/enable
 
> To support the phase mode selection, implement a Counter device
> extension for that specific purpose. You can use DEFINE_COUNTER_ENUM()
> and COUNTER_COMP_DEVICE_ENUM() to create a device extension that will
> allow users to toggle between "16-bit" and "32-bit" phase modes. If
> you need help with these macros, just let me know.

Yes please, that will be helpful. 

Cheers,
Biju

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-11 15:50         ` Biju Das
@ 2022-10-11 17:55           ` Biju Das
  2022-10-13  0:24             ` William Breathitt Gray
  2022-10-13  0:19           ` William Breathitt Gray
  1 sibling, 1 reply; 23+ messages in thread
From: Biju Das @ 2022-10-11 17:55 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

Hi William Breathitt Gray,

> Subject: RE: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
> 
> Hi William Breathitt Gray,
> 
> Thanks for the feedback.
> 
> > Subject: Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
> >
> > On Sat, Oct 08, 2022 at 09:01:21AM +0000, Biju Das wrote:
> > > Hi William Breathitt Gray,
> > >
> > > Thanks for the feedback.
> >
> > Hello Biju,
> >
> > I see that you have already released a v4, so some of my comments
> may
> > no longer apply, but I want to respond here to continue our
> > discussions; I'll reiterate any relevant suggestions when I review
> v4
> > in the coming days.
> >
> > By the way, if you agree with a review comment there is no need to
> > reply with "OK"; just delete the parts you agree with from your
> > response and I'll know those are okay. Doing this will reduce the
> > amount of text we have to scroll through and thus allow us to focus
> on
> > just the questions we have remaining. ;-)
> 
> OK.
> 
> > > > Looks like something different is done when ceiling is set to 0.
> > > > Would you explain what's happening in this case and why it's
> > > > different that then else case below; in other words, what's the
> > > > difference between RZ_MTU3_TCR_CCLR_NONE and
> > RZ_MTU3_TCR_CCLR_TGRA?
> > >
> > > RZ_MTU3_TCR_CCLR_TGRA --> for triggering counter count using Z-
> Phase
> > signal.
> > > RZ_MTU3_TCR_CCLR_NONE --> No clearing.
> >
> > Does the Z-Phase signal trigger a reset of the counter count back to
> > the ceiling value?
> 
> No, It resets to 0.

It reset to 0 for forward counting
and resets to U16_MAX or U32_MAX for backword counting

> 
> Does the count loop back to 0 when it passes the
> > ceiling value,
> 
> Yes, it loopback to 0.

Same as above.

> 
>  or does it remain at the ceiling until the direction
> > changes?
> 
> No.
> 
> > By "no clearing" do you mean that the ceiling is disabled in this
> case
> > and the Counter count increases without limit?
> 
> Counter clear source disabled. So the counter won't reset to 0 by
> applying Z-Phase signal.
> 
> >
> > In the Counter subsystem, the "ceiling" Count extension puts an
> upper
> > limit on the Count value. This means that setting "ceiling" to 0
> would
> > put the upper limit at 0, effectively restricting the Count value to
> 0
> > until the value of "ceiling" is raised.
> >
> > If the device is unable to support a ceiling value of 0, you should
> > return -ERANGE rather than disable the ceiling.
> 
> OK, will check this.

HW supports ceiling value of 0.

Cheers,
Biju


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-11 15:50         ` Biju Das
  2022-10-11 17:55           ` Biju Das
@ 2022-10-13  0:19           ` William Breathitt Gray
  2022-10-13  5:47             ` Biju Das
  1 sibling, 1 reply; 23+ messages in thread
From: William Breathitt Gray @ 2022-10-13  0:19 UTC (permalink / raw)
  To: Biju Das
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 1869 bytes --]

On Tue, Oct 11, 2022 at 03:50:38PM +0000, Biju Das wrote:
> > To support the phase mode selection, implement a Counter device
> > extension for that specific purpose. You can use DEFINE_COUNTER_ENUM()
> > and COUNTER_COMP_DEVICE_ENUM() to create a device extension that will
> > allow users to toggle between "16-bit" and "32-bit" phase modes. If
> > you need help with these macros, just let me know.
> 
> Yes please, that will be helpful. 
> 
> Cheers,
> Biju

It'll look something like this::

    static const char *const rz_mtu3_phase_counting_modes[] = {
            "16-bit",
            "32-bit",
    };
    
    static int rz_mtu3_phase_counting_mode_get(struct counter_device *counter,
                                               u32 *phase_counting_mode);
    static int rz_mtu3_phase_counting_mode_set(struct counter_device *counter,
                                               u32 phase_counting_mode);
    
    static DEFINE_COUNTER_ENUM(rz_mtu3_phase_counting_mode_enum,
                               rz_mtu3_phase_counting_modes);
    
    static struct counter_comp rz_mtu3_device_ext[] = {
            COUNTER_COMP_DEVICE_ENUM("phase_counting_mode",
                                     rz_mtu3_phase_counting_mode_get,
                                     rz_mtu3_phase_counting_mode_set,
                                     rz_mtu3_phase_counting_mode_enum),
    };

Using the get/set callbacks, you can get/set the index for the
respective mode of your rz_mtu3_phase_counting_modes array.

In rz_mtu3_cnt_probe() you could set the counter_device ext member to
rz_mtu3_device_ext. This will make the extensions appear in the sysfs
tree for your Counter device. You should also add a new entry in
Documentation/ABI/testing/sysfs-bus-counter to document this new sysfs
file.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-11 17:55           ` Biju Das
@ 2022-10-13  0:24             ` William Breathitt Gray
  0 siblings, 0 replies; 23+ messages in thread
From: William Breathitt Gray @ 2022-10-13  0:24 UTC (permalink / raw)
  To: Biju Das
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc

[-- Attachment #1: Type: text/plain, Size: 882 bytes --]

On Tue, Oct 11, 2022 at 05:55:50PM +0000, Biju Das wrote:
> > > > > Looks like something different is done when ceiling is set to 0.
> > > > > Would you explain what's happening in this case and why it's
> > > > > different that then else case below; in other words, what's the
> > > > > difference between RZ_MTU3_TCR_CCLR_NONE and
> > > RZ_MTU3_TCR_CCLR_TGRA?
> > > >
> > > > RZ_MTU3_TCR_CCLR_TGRA --> for triggering counter count using Z-
> > Phase
> > > signal.
> > > > RZ_MTU3_TCR_CCLR_NONE --> No clearing.
> > >
> > > Does the Z-Phase signal trigger a reset of the counter count back to
> > > the ceiling value?
> > 
> > No, It resets to 0.
> 
> It reset to 0 for forward counting
> and resets to U16_MAX or U32_MAX for backword counting

So when counting backwards, will the value reset to the ceiling value
when it passes 0?

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
  2022-10-13  0:19           ` William Breathitt Gray
@ 2022-10-13  5:47             ` Biju Das
  0 siblings, 0 replies; 23+ messages in thread
From: Biju Das @ 2022-10-13  5:47 UTC (permalink / raw)
  To: William Breathitt Gray
  Cc: Philipp Zabel, Rob Herring, Lee Jones, linux-iio,
	Geert Uytterhoeven, Chris Paterson, Biju Das,
	Prabhakar Mahadev Lad, linux-renesas-soc


Hi William Breathitt Gray,

Thanks for the feedback.

> Subject: Re: [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver
> 
> On Tue, Oct 11, 2022 at 03:50:38PM +0000, Biju Das wrote:
> > > To support the phase mode selection, implement a Counter device
> > > extension for that specific purpose. You can use
> > > DEFINE_COUNTER_ENUM() and COUNTER_COMP_DEVICE_ENUM() to create a
> > > device extension that will allow users to toggle between "16-bit"
> > > and "32-bit" phase modes. If you need help with these macros, just
> let me know.
> >
> > Yes please, that will be helpful.
> >
> > Cheers,
> > Biju
> 
> It'll look something like this::
> 
>     static const char *const rz_mtu3_phase_counting_modes[] = {
>             "16-bit",
>             "32-bit",
>     };
> 
>     static int rz_mtu3_phase_counting_mode_get(struct counter_device
> *counter,
>                                                u32
> *phase_counting_mode);
>     static int rz_mtu3_phase_counting_mode_set(struct counter_device
> *counter,
>                                                u32
> phase_counting_mode);
> 
>     static DEFINE_COUNTER_ENUM(rz_mtu3_phase_counting_mode_enum,
>                                rz_mtu3_phase_counting_modes);
> 
>     static struct counter_comp rz_mtu3_device_ext[] = {
>             COUNTER_COMP_DEVICE_ENUM("phase_counting_mode",
>                                      rz_mtu3_phase_counting_mode_get,
>                                      rz_mtu3_phase_counting_mode_set,
> 
> rz_mtu3_phase_counting_mode_enum),
>     };
> 
> Using the get/set callbacks, you can get/set the index for the
> respective mode of your rz_mtu3_phase_counting_modes array.
> 
> In rz_mtu3_cnt_probe() you could set the counter_device ext member to
> rz_mtu3_device_ext. This will make the extensions appear in the sysfs
> tree for your Counter device. You should also add a new entry in
> Documentation/ABI/testing/sysfs-bus-counter to document this new sysfs
> file.

cool, Will do it in the next version v5.

Cheers,
Biju




^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2022-10-13  5:47 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 13:57 [PATCH v3 0/4] Add RZ/G2L MTU3a MFD, Counter and pwm driver Biju Das
2022-10-06 13:57 ` [PATCH v3 1/4] dt-bindings: mfd: Document RZ/G2L MTU3a bindings Biju Das
2022-10-06 20:17   ` Rob Herring
2022-10-07 12:40     ` Biju Das
2022-10-08  7:42       ` Biju Das
2022-10-08 10:51         ` Biju Das
2022-10-09 14:38         ` Geert Uytterhoeven
2022-10-09 15:17           ` Krzysztof Kozlowski
2022-10-10 13:00             ` Biju Das
2022-10-10  7:10           ` Biju Das
2022-10-09 15:16         ` Krzysztof Kozlowski
2022-10-10 15:13           ` Biju Das
2022-10-06 13:57 ` [PATCH v3 2/4] mfd: Add RZ/G2L MTU3 driver Biju Das
2022-10-06 13:57 ` [PATCH v3 3/4] pwm: Add support for RZ/G2L MTU3 PWM Biju Das
2022-10-06 13:57 ` [PATCH v3 4/4] counter: Add RZ/G2L MTU3 counter driver Biju Das
2022-10-08  1:37   ` William Breathitt Gray
2022-10-08  9:01     ` Biju Das
2022-10-11 13:15       ` William Breathitt Gray
2022-10-11 15:50         ` Biju Das
2022-10-11 17:55           ` Biju Das
2022-10-13  0:24             ` William Breathitt Gray
2022-10-13  0:19           ` William Breathitt Gray
2022-10-13  5:47             ` Biju Das

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.