Re: [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




Hi Chris,
   thanks for looking into this...

On 09/03/2017 15:55, Chris Brandt wrote:
Hi Jacopo,

On Monday, February 20, 2017, Jacopo Mondi wrote:

Add combined gpio and pin controller driver for Renesas RZ/A1
r7s72100 SoC.

Signed-off-by: Jacopo Mondi <jacopo+renesas@xxxxxxxxxx>
---
 drivers/pinctrl/Kconfig        |   10 +
 drivers/pinctrl/Makefile       |    1 +
 drivers/pinctrl/pinctrl-rza1.c | 1026
++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1037 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-rza1.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af..61310ac 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -163,6 +163,16 @@ config PINCTRL_ROCKCHIP
 	select GENERIC_IRQ_CHIP
 	select MFD_SYSCON

+config PINCTRL_RZA1
+	bool "Renesas r7s72100 RZ/A1 gpio and pinctrl driver"

You can drop the "r7s72100" and just say RZ/A1.



+/**
+ * rza1_pin_set_direction() - set I/O direction on a pin in port mode
+ *
+ * When running in output port mode keep PBDC enabled to allow reading
the
+ * pin value from PPR.
+ * When in alternate mode disable that (if not explicitly required) not
to
+ * interfere with the alternate function mode.
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ * @input: input enable/disable flag
+ */
+static inline void rza1_pin_set_direction(struct rza1_port *port,
+					  unsigned int offset,
+					  bool input)
+{
+	spin_lock(&port->lock);
+	if (input)
+		rza1_set_bit(port, PIBC_REG, offset, 1);
+	else {
+		rza1_set_bit(port, PM_REG, offset, 0);
+		rza1_set_bit(port, PBDC_REG, offset, 1);
+	}
+	spin_unlock(&port->lock);

When input==true, you only set PIBC_REG. Otherwise you only set PM_REG and PBDC_REG. This would imply that this function will only ever get called once for a pin and never get called a second time with a different direction...meaning it would not really change a pin from output to input. I would assume that you would need to change this function to set those 3 registers either one way or the other.

I would suggest:
   PIBC_REG = 1 /* always gets set for GPIO mode */
 input:
   PM_REG = 1
   PBDC_REG = 0
output:
   PM_REG = 0
   PBDC_REG = 1


I assumed "set_direction()" to always be called after a "request()", so that the pin is always in reset state.
This is obviously not true, so I'm going to fix this as you suggested.
I'm just wondering why we should keep input buffer enabled even if we're running in output mode. This seems to be "safe" according to TRM but I'm a bit afraid of unexpected consequences (am I too paranoid?)



+/**
+ * rza1_alternate_function_conf() - configure pin in alternate function
mode
+ *
+ * @pinctrl: RZ/A1 pin controller device
+ * @pin_conf: single pin configuration descriptor
+ */
+static int rza1_alternate_function_conf(struct rza1_pinctrl *rza1_pctl,
+					struct rza1_pin_conf *pin_conf)
+{
+	unsigned int offset = pin_conf->offset;
+	struct rza1_port *port = &rza1_pctl->ports[pin_conf->port];
+	u8 mux_mode = (pin_conf->mux_conf - 1) & MUX_FUNC_MASK;
+	u8 mux_conf = pin_conf->mux_conf >> MUX_FUNC_OFFS;
+	bool swio_en = !!(mux_conf & MUX_CONF_SWIO);
+	bool input_en = !!(mux_conf & MUX_CONF_INPUT_ENABLE);
+
+	rza1_pin_reset(port, offset);
+
+	/*
+	 * When configuring pin with Software Controlled IO mode in
alternate
+	 * mode, do not enable bi-directional control to avoid driving Pn
+	 * value to the pin input.
+	 * When working in direct IO mode (aka alternate function drives the
+	 * pin direction), enable bi-directional control for input pins in
+	 * order to enable the pin's input buffer as a consequence.
+	 */
+	if ((!swio_en && input_en) || (swio_en && !input_en))
+		rza1_set_bit(port, PBDC_REG, offset, 1);


Maybe just set PBDC_REG at the end of the function with everything else.
See below...


Let me reply below to both these comments...



+
+	/*
+	 * Enable alternate function mode and select it.
+	 *
+	 * ----------------------------------------------------
+	 * Alternate mode selection table:
+	 *
+	 * PMC	PFC	PFCE	PFCAE	mux_mode
+	 * 1	0	0	0	0
+	 * 1	1	0	0	1
+	 * 1	0	1	0	2
+	 * 1	1	1	0	3
+	 * 1	0	0	1	4
+	 * 1	1	0	1	5
+	 * 1	0	1	1	6
+	 * 1	1	1	1	7
+	 * ----------------------------------------------------
+	 */
+	rza1_set_bit(port, PFC_REG, offset, mux_mode & MUX_FUNC_PFC_MASK);
+	rza1_set_bit(port, PFCE_REG, offset, mux_mode & MUX_FUNC_PFCE_MASK);
+	rza1_set_bit(port, PFCEA_REG, offset, mux_mode &
MUX_FUNC_PFCEA_MASK);
+
+	/*
+	 * All alternate functions except a few (4) need PIPCn = 1.
+	 * If PIPCn has to stay disabled (SW IO mode), configure PMn
according
+	 * to I/O direction specified by pin configuration -after- PMC has
been
+	 * set to one.
+	 */
+	if (!swio_en)
+		rza1_set_bit(port, PIPC_REG, offset, 1);
+
+	rza1_set_bit(port, PMC_REG, offset, 1);
+
+	if (swio_en)
+		rza1_set_bit(port, PM_REG, offset, input_en);


I would suggest something like this:

	if (bidir)
		rza1_set_bit(port, PBDC_REG, offset, 1);
	else {
		rza1_set_bit(port, PBDC_REG, offset, 0);
		rza1_set_bit(port, PM_REG, offset, swio_in);
	}

	rza1_set_bit(port, PMC_REG, offset, 1);



This looks nicer, for sure, but from my testing I found out that the sequence reported in section 54.19-c of TRM has to be carefully respected, particularly setting PM after PMC (and iirc setting PBDC before PFC*)
Am I wrong? I will give your suggestion spin anyway...

This apart, you suggestion is tied to your comment on [2/7] on replacing INPUT_EN with BIDIR and introduce SWIO_IN and SWIO_OUT, which I mostly agree on (I'll comment on that as well).

A sort of middle-ground to get rid of horrible conditions like
"if ((!swio_en && input_en) || (swio_en && !input_en))"
which requires a 7 lines comments to be explained and I still found obscure after a month I was not looking at it, would be making BIDIR and SWIO_[IN|OUT] exclusive, as if a pin is set to be SWIO it already has direction specified, and if it is said to be BIDIR, it means its direction is decided by the alternate function, not by software. Does this fly for you? Do you see cases where those flags may have to be specified together?
If not, it would simplify this routine for sure...

Thanks
   j


+
+	return 0;
+}




Chris

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux