diff mbox series

[RFC,4/8] pwm: rzg2l-gpt: Add support for linking with POEG

Message ID 20220510151112.16249-5-biju.das.jz@bp.renesas.com (mailing list archive)
State Under Review
Delegated to: Geert Uytterhoeven
Headers show
Series Add RZ/G2L POEG support | expand

Commit Message

Biju Das May 10, 2022, 3:11 p.m. UTC
This patch add support for linking POEG group with pwm, so that
POEG can control the output disable function.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
 drivers/pwm/pwm-rzg2l-gpt.c | 59 +++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

Comments

Geert Uytterhoeven May 19, 2022, 9:15 a.m. UTC | #1
Hi Biju,

On Tue, May 10, 2022 at 5:11 PM Biju Das <biju.das.jz@bp.renesas.com> wrote:
> This patch add support for linking POEG group with pwm, so that
> POEG can control the output disable function.
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>

Thanks for your patch!

> --- a/drivers/pwm/pwm-rzg2l-gpt.c
> +++ b/drivers/pwm/pwm-rzg2l-gpt.c
> @@ -266,6 +291,36 @@ static int rzg2l_gpt_apply(struct pwm_chip *chip, struct pwm_device *pwm,
>         return ret;
>  }
>
> +static int rzg2l_gpt_parse_properties(struct platform_device *pdev,
> +                                     struct rzg2l_gpt_chip *pc)
> +{
> +       static const u64 poeg_grp_addr[] = {
> +               POEG_GRP_A_ADDR, POEG_GRP_B_ADDR, POEG_GRP_C_ADDR, POEG_GRP_D_ADDR
> +       };
> +       struct device_node *np;
> +       unsigned int i;
> +       u64 addr;
> +
> +       pc->poeg_grp = GRP_INVALID;
> +       np = of_parse_phandle(pdev->dev.of_node, "renesas,poeg-group", 0);
> +       if (!np)
> +               return 0;
> +
> +       if (!of_property_read_u64(np, "reg", &addr)) {
> +               for (i = 0; i < ARRAY_SIZE(poeg_grp_addr); i++) {
> +                       if (addr == poeg_grp_addr[i]) {

Matching on addresses looks fragile to me.
Of course this is code, not DT, so it can be changed later.

Possible alternatives:
  1. Use a numeric property instead of a phandle, so you can store
     its value directly into pc->poeg_grp.
     This loses the linking by phandle, though, which is nice to
     have, and might be useful for other purposes later.
  2. Add a "renesas,id" property to each POEGx DT node, cfr.
     Documentation/devicetree/bindings/media/renesas,vin.yaml.

> +                               pc->poeg_grp = i;
> +                               break;
> +                       }
> +               }
> +       }
> +
> +       if (np)
> +               of_node_put(np);
> +
> +       return 0;
> +}

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
Biju Das June 8, 2022, 5:01 p.m. UTC | #2
Hi Geert,

Thanks for the feedback.

> Subject: Re: [RFC 4/8] pwm: rzg2l-gpt: Add support for linking with POEG
> 
> Hi Biju,
> 
> On Tue, May 10, 2022 at 5:11 PM Biju Das <biju.das.jz@bp.renesas.com>
> wrote:
> > This patch add support for linking POEG group with pwm, so that POEG
> > can control the output disable function.
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> 
> Thanks for your patch!
> 
> > --- a/drivers/pwm/pwm-rzg2l-gpt.c
> > +++ b/drivers/pwm/pwm-rzg2l-gpt.c
> > @@ -266,6 +291,36 @@ static int rzg2l_gpt_apply(struct pwm_chip *chip,
> struct pwm_device *pwm,
> >         return ret;
> >  }
> >
> > +static int rzg2l_gpt_parse_properties(struct platform_device *pdev,
> > +                                     struct rzg2l_gpt_chip *pc) {
> > +       static const u64 poeg_grp_addr[] = {
> > +               POEG_GRP_A_ADDR, POEG_GRP_B_ADDR, POEG_GRP_C_ADDR,
> POEG_GRP_D_ADDR
> > +       };
> > +       struct device_node *np;
> > +       unsigned int i;
> > +       u64 addr;
> > +
> > +       pc->poeg_grp = GRP_INVALID;
> > +       np = of_parse_phandle(pdev->dev.of_node, "renesas,poeg-group",
> 0);
> > +       if (!np)
> > +               return 0;
> > +
> > +       if (!of_property_read_u64(np, "reg", &addr)) {
> > +               for (i = 0; i < ARRAY_SIZE(poeg_grp_addr); i++) {
> > +                       if (addr == poeg_grp_addr[i]) {
> 
> Matching on addresses looks fragile to me.
> Of course this is code, not DT, so it can be changed later.
> 
> Possible alternatives:
>   1. Use a numeric property instead of a phandle, so you can store
>      its value directly into pc->poeg_grp.
>      This loses the linking by phandle, though, which is nice to
>      have, and might be useful for other purposes later.

OK, will use a numeric property as default POEGGroup.

Cheers,
Biju

>   2. Add a "renesas,id" property to each POEGx DT node, cfr.
>      Documentation/devicetree/bindings/media/renesas,vin.yaml.
> 
> > +                               pc->poeg_grp = i;
> > +                               break;
> > +                       }
> > +               }
> > +       }
> > +
> > +       if (np)
> > +               of_node_put(np);
> > +
> > +       return 0;
> > +}
> 
> 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
diff mbox series

Patch

diff --git a/drivers/pwm/pwm-rzg2l-gpt.c b/drivers/pwm/pwm-rzg2l-gpt.c
index d5d22b1ff792..8eaf96b2052d 100644
--- a/drivers/pwm/pwm-rzg2l-gpt.c
+++ b/drivers/pwm/pwm-rzg2l-gpt.c
@@ -21,6 +21,7 @@ 
 #define GTCR		0x2c
 #define GTUDDTYC	0x30
 #define GTIOR		0x34
+#define GTINTAD		0x38
 #define GTBER		0x40
 #define GTCNT		0x48
 #define GTCCRA		0x4c
@@ -37,9 +38,14 @@ 
 #define UP_COUNTING	(GTUDDTYC_UP | GTUDDTYC_UDF)
 
 #define GTIOR_GTIOA_MASK			GENMASK(4, 0)
+#define GTIOR_OADF_MASK				GENMASK(10, 9)
 #define GTIOR_GTIOB_MASK			GENMASK(20, 16)
+#define GTIOR_OBDF_MASK				GENMASK(26, 25)
+
 #define GTIOR_OAE				BIT(8)
 #define GTIOR_OBE				BIT(24)
+#define GTIOR_OADF_HIGH_IMP_ON_OUT_DISABLE	(1 << 9)
+#define GTIOR_OBDF_HIGH_IMP_ON_OUT_DISABLE	(1 << 25)
 
 #define INIT_OUT_LO_OUT_LO_END_TOGGLE		(0x07)
 #define INIT_OUT_HI_OUT_HI_END_TOGGLE		(0x1B)
@@ -48,6 +54,13 @@ 
 #define GTIOR_GTIOB_OUT_HI_END_TOGGLE_CMP_MATCH	((INIT_OUT_HI_OUT_HI_END_TOGGLE << 16) | GTIOR_OBE)
 #define GTIOR_GTIOB_OUT_LO_END_TOGGLE_CMP_MATCH	((INIT_OUT_LO_OUT_LO_END_TOGGLE << 16) | GTIOR_OBE)
 
+#define GTINTAD_GRP_MASK	GENMASK(25, 24)
+#define GRP_INVALID		(0xFF)
+#define POEG_GRP_A_ADDR		(0x10048800)
+#define POEG_GRP_B_ADDR		(0x10048c00)
+#define POEG_GRP_C_ADDR		(0x10049000)
+#define POEG_GRP_D_ADDR		(0x10049400)
+
 struct phase {
 	u32 value;
 	u32 mask;
@@ -85,6 +98,7 @@  struct rzg2l_gpt_chip {
 	void __iomem *mmio;
 	struct reset_control *rstc;
 	struct clk *clk;
+	u8 poeg_grp;
 };
 
 static inline struct rzg2l_gpt_chip *to_rzg2l_gpt_chip(struct pwm_chip *chip)
@@ -220,6 +234,17 @@  static int rzg2l_gpt_config(struct pwm_chip *chip, struct pwm_device *_pwm,
 	/* Set period */
 	rzg2l_gpt_write(pc, GTPR, pv);
 
+	if (pc->poeg_grp != GRP_INVALID) {
+		rzg2l_gpt_modify(pc, GTINTAD, GTINTAD_GRP_MASK, pc->poeg_grp << 24);
+
+		if (pwm->channel)
+			rzg2l_gpt_modify(pc, GTIOR, GTIOR_OBDF_MASK,
+					 GTIOR_OBDF_HIGH_IMP_ON_OUT_DISABLE);
+		else
+			rzg2l_gpt_modify(pc, GTIOR, GTIOR_OADF_MASK,
+					 GTIOR_OADF_HIGH_IMP_ON_OUT_DISABLE);
+	}
+
 	/* Enable pin output */
 	rzg2l_gpt_modify(pc, GTIOR, pwm->ph->mask, pwm->ph->value);
 
@@ -266,6 +291,36 @@  static int rzg2l_gpt_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	return ret;
 }
 
+static int rzg2l_gpt_parse_properties(struct platform_device *pdev,
+				      struct rzg2l_gpt_chip *pc)
+{
+	static const u64 poeg_grp_addr[] = {
+		POEG_GRP_A_ADDR, POEG_GRP_B_ADDR, POEG_GRP_C_ADDR, POEG_GRP_D_ADDR
+	};
+	struct device_node *np;
+	unsigned int i;
+	u64 addr;
+
+	pc->poeg_grp = GRP_INVALID;
+	np = of_parse_phandle(pdev->dev.of_node, "renesas,poeg-group", 0);
+	if (!np)
+		return 0;
+
+	if (!of_property_read_u64(np, "reg", &addr)) {
+		for (i = 0; i < ARRAY_SIZE(poeg_grp_addr); i++) {
+			if (addr == poeg_grp_addr[i]) {
+				pc->poeg_grp = i;
+				break;
+			}
+		}
+	}
+
+	if (np)
+		of_node_put(np);
+
+	return 0;
+}
+
 static const struct pwm_ops rzg2l_gpt_ops = {
 	.request = rzg2l_gpt_request,
 	.free = rzg2l_gpt_free,
@@ -288,6 +343,10 @@  static int rzg2l_gpt_probe(struct platform_device *pdev)
 	if (!rzg2l_gpt)
 		return -ENOMEM;
 
+	ret = rzg2l_gpt_parse_properties(pdev, rzg2l_gpt);
+	if (ret)
+		return ret;
+
 	rzg2l_gpt->mmio = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(rzg2l_gpt->mmio))
 		return PTR_ERR(rzg2l_gpt->mmio);