diff mbox series

[v7,2/3] pinctrl: pinmux: Add pinmux-select debugfs file

Message ID 20210217221457.1827266-3-drew@beagleboard.org
State New
Headers show
Series pinctrl: pinmux: Add pinmux-select debugfs file | expand

Commit Message

Drew Fustini Feb. 17, 2021, 10:14 p.m. UTC
Add "pinmux-select" to debugfs which will activate a function and group:

  echo "<function-name group-name>" > pinmux-select

The write operation pinmux_select() handles this by checking that the
names map to valid selectors and then calling ops->set_mux().

The existing "pinmux-functions" debugfs file lists the pin functions
registered for the pin controller. For example:

  function: pinmux-uart0, groups = [ pinmux-uart0-pins ]
  function: pinmux-mmc0, groups = [ pinmux-mmc0-pins ]
  function: pinmux-mmc1, groups = [ pinmux-mmc1-pins ]
  function: pinmux-i2c0, groups = [ pinmux-i2c0-pins ]
  function: pinmux-i2c1, groups = [ pinmux-i2c1-pins ]
  function: pinmux-spi1, groups = [ pinmux-spi1-pins ]

To activate function pinmux-i2c1 and group pinmux-i2c1-pins:

  echo "pinmux-i2c1 pinmux-i2c1-pins" > pinmux-select

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Drew Fustini <drew@beagleboard.org>
---
 drivers/pinctrl/pinmux.c | 102 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

Comments

Geert Uytterhoeven Feb. 19, 2021, 9:06 a.m. UTC | #1
Hi Drew,

On Wed, Feb 17, 2021 at 11:15 PM Drew Fustini <drew@beagleboard.org> wrote:
> Add "pinmux-select" to debugfs which will activate a function and group:
>
>   echo "<function-name group-name>" > pinmux-select
>
> The write operation pinmux_select() handles this by checking that the
> names map to valid selectors and then calling ops->set_mux().
>
> The existing "pinmux-functions" debugfs file lists the pin functions
> registered for the pin controller. For example:
>
>   function: pinmux-uart0, groups = [ pinmux-uart0-pins ]
>   function: pinmux-mmc0, groups = [ pinmux-mmc0-pins ]
>   function: pinmux-mmc1, groups = [ pinmux-mmc1-pins ]
>   function: pinmux-i2c0, groups = [ pinmux-i2c0-pins ]
>   function: pinmux-i2c1, groups = [ pinmux-i2c1-pins ]
>   function: pinmux-spi1, groups = [ pinmux-spi1-pins ]
>
> To activate function pinmux-i2c1 and group pinmux-i2c1-pins:
>
>   echo "pinmux-i2c1 pinmux-i2c1-pins" > pinmux-select
>
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> Reviewed-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Drew Fustini <drew@beagleboard.org>

Thanks for your patch!

On R-Car M2-W, which does not use pinctrl-single, I have:

    # cat pinmux-functions
    ...
    function 14: i2c2, groups = [ i2c2 i2c2_b i2c2_c i2c2_d ]
    ...
    function 51: ssi, groups = [ ssi0_data ssi0_data_b ssi0129_ctrl
ssi0129_ctrl_b ssi1_data ssi1_data_b ssi1_ctrl ssi1_ctrl_b ssi2_data
ssi2_ctrl ssi3_data ssi34_ctrl ssi4_data ssi4_ctrl ssi5_data ssi5_ctrl
ssi6_data ssi6_ctrl ssi7_data ssi7_data_b ssi78_ctrl ssi78_ctrl_b
ssi8_data ssi8_data_b ssi9_data ssi9_data_b ssi9_ctrl ssi9_ctrl_b ]
    ...

On the Koelsch board:

    # cd /sys/kernel/debug/pinctrl/e6060000.pinctrl-sh-pfc/
    # echo ssi ssi2_ctrl > pinmux-select # Configure i2c2 pins for ssi
    # i2cdetect -y -a 2                  # Fails
    # echo i2c2 i2c2 > pinmux-select     # Restore i2c2
    # i2cdetect -y -a 2                  # Works again

The order of the 2 parameters looks a bit odd to me, as the operation
configures the pins from "group" to be used for "function".
See also arch/arm/boot/dts/r8a7791-koelsch.dts
For the i2c2 example it's not that obvious, but for ssi it is.
Might feel different for pinctrl-single, and perhaps I just need to get
used to it ;-)

Anyway:
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>

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
Drew Fustini Feb. 20, 2021, 6:28 p.m. UTC | #2
On Fri, Feb 19, 2021 at 10:06:51AM +0100, Geert Uytterhoeven wrote:
> Hi Drew,
> 
> On Wed, Feb 17, 2021 at 11:15 PM Drew Fustini <drew@beagleboard.org> wrote:
> > Add "pinmux-select" to debugfs which will activate a function and group:
> >
> >   echo "<function-name group-name>" > pinmux-select
> >
> > The write operation pinmux_select() handles this by checking that the
> > names map to valid selectors and then calling ops->set_mux().
> >
> > The existing "pinmux-functions" debugfs file lists the pin functions
> > registered for the pin controller. For example:
> >
> >   function: pinmux-uart0, groups = [ pinmux-uart0-pins ]
> >   function: pinmux-mmc0, groups = [ pinmux-mmc0-pins ]
> >   function: pinmux-mmc1, groups = [ pinmux-mmc1-pins ]
> >   function: pinmux-i2c0, groups = [ pinmux-i2c0-pins ]
> >   function: pinmux-i2c1, groups = [ pinmux-i2c1-pins ]
> >   function: pinmux-spi1, groups = [ pinmux-spi1-pins ]
> >
> > To activate function pinmux-i2c1 and group pinmux-i2c1-pins:
> >
> >   echo "pinmux-i2c1 pinmux-i2c1-pins" > pinmux-select
> >
> > Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> > Reviewed-by: Tony Lindgren <tony@atomide.com>
> > Signed-off-by: Drew Fustini <drew@beagleboard.org>
> 
> Thanks for your patch!
> 
> On R-Car M2-W, which does not use pinctrl-single, I have:
> 
>     # cat pinmux-functions
>     ...
>     function 14: i2c2, groups = [ i2c2 i2c2_b i2c2_c i2c2_d ]
>     ...
>     function 51: ssi, groups = [ ssi0_data ssi0_data_b ssi0129_ctrl
> ssi0129_ctrl_b ssi1_data ssi1_data_b ssi1_ctrl ssi1_ctrl_b ssi2_data
> ssi2_ctrl ssi3_data ssi34_ctrl ssi4_data ssi4_ctrl ssi5_data ssi5_ctrl
> ssi6_data ssi6_ctrl ssi7_data ssi7_data_b ssi78_ctrl ssi78_ctrl_b
> ssi8_data ssi8_data_b ssi9_data ssi9_data_b ssi9_ctrl ssi9_ctrl_b ]
>     ...
> 
> On the Koelsch board:
> 
>     # cd /sys/kernel/debug/pinctrl/e6060000.pinctrl-sh-pfc/
>     # echo ssi ssi2_ctrl > pinmux-select # Configure i2c2 pins for ssi
>     # i2cdetect -y -a 2                  # Fails
>     # echo i2c2 i2c2 > pinmux-select     # Restore i2c2
>     # i2cdetect -y -a 2                  # Works again
> 
> The order of the 2 parameters looks a bit odd to me, as the operation
> configures the pins from "group" to be used for "function".
> See also arch/arm/boot/dts/r8a7791-koelsch.dts
> For the i2c2 example it's not that obvious, but for ssi it is.
> Might feel different for pinctrl-single, and perhaps I just need to get
> used to it ;-)

Thank you for comments and testing.

Regarding the order of "<function-name> <group-name>", I can change it
to "<group-name function-name>" if that seems more natural.

pinctrl-single does not actually use the group selector in pcs_set_mux()
so it essentially does not matter for pinctrl-single.

-Drew

> 
> Anyway:
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> 
> 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/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index c651b2db0925..39770af56562 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -12,6 +12,7 @@ 
  */
 #define pr_fmt(fmt) "pinmux core: " fmt
 
+#include <linux/ctype.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -673,6 +674,105 @@  void pinmux_show_setting(struct seq_file *s,
 DEFINE_SHOW_ATTRIBUTE(pinmux_functions);
 DEFINE_SHOW_ATTRIBUTE(pinmux_pins);
 
+#define PINMUX_SELECT_MAX 50
+static ssize_t pinmux_select(struct file *file, const char __user *user_buf,
+				   size_t len, loff_t *ppos)
+{
+	struct seq_file *sfile = file->private_data;
+	struct pinctrl_dev *pctldev = sfile->private;
+	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+	const char *const *groups;
+	char *buf, *fname, *gname;
+	unsigned int num_groups;
+	int fsel, gsel, ret;
+
+	if (len > PINMUX_SELECT_MAX)
+		return -ENOMEM;
+
+	buf = kzalloc(PINMUX_SELECT_MAX, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = strncpy_from_user(buf, user_buf, PINMUX_SELECT_MAX);
+	if (ret < 0)
+		goto exit_free_buf;
+	buf[len-1] = '\0';
+
+	/* remove leading and trailing spaces of input buffer */
+	fname = strstrip(buf);
+	if (*fname == '\0') {
+		ret = -EINVAL;
+		goto exit_free_buf;
+	}
+
+	/* find a separator which is a spacelike character */
+	for (gname = fname; !isspace(*gname); gname++) {
+		if (*gname == '\0') {
+			ret = -EINVAL;
+			goto exit_free_buf;
+		}
+	}
+	*gname = '\0';
+
+	/* drop extra spaces between function and group names */
+	gname = skip_spaces(gname + 1);
+	if (*gname == '\0') {
+		ret = -EINVAL;
+		goto exit_free_buf;
+	}
+
+	ret = pinmux_func_name_to_selector(pctldev, fname);
+	if (ret < 0) {
+		dev_err(pctldev->dev, "invalid function %s in map table\n", fname);
+		goto exit_free_buf;
+	}
+	fsel = ret;
+
+	ret = pmxops->get_function_groups(pctldev, fsel, &groups, &num_groups);
+	if (ret) {
+		dev_err(pctldev->dev, "no groups for function %d (%s)", fsel, fname);
+		goto exit_free_buf;
+	}
+
+	ret = match_string(groups, num_groups, gname);
+	if (ret < 0) {
+		dev_err(pctldev->dev, "invalid group %s", gname);
+		goto exit_free_buf;
+	}
+
+	ret = pinctrl_get_group_selector(pctldev, gname);
+	if (ret < 0) {
+		dev_err(pctldev->dev, "failed to get group selector for %s", gname);
+		goto exit_free_buf;
+	}
+	gsel = ret;
+
+	ret = pmxops->set_mux(pctldev, fsel, gsel);
+	if (ret) {
+		dev_err(pctldev->dev, "set_mux() failed: %d", ret);
+		goto exit_free_buf;
+	}
+	ret = len;
+
+exit_free_buf:
+	kfree(buf);
+
+	return ret;
+}
+
+static int pinmux_select_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, NULL, inode->i_private);
+}
+
+static const struct file_operations pinmux_select_ops = {
+	.owner = THIS_MODULE,
+	.open = pinmux_select_open,
+	.write = pinmux_select,
+	.llseek = no_llseek,
+	.release = single_release,
+};
+
 void pinmux_init_device_debugfs(struct dentry *devroot,
 			 struct pinctrl_dev *pctldev)
 {
@@ -680,6 +780,8 @@  void pinmux_init_device_debugfs(struct dentry *devroot,
 			    devroot, pctldev, &pinmux_functions_fops);
 	debugfs_create_file("pinmux-pins", 0444,
 			    devroot, pctldev, &pinmux_pins_fops);
+	debugfs_create_file("pinmux-select", 0200,
+			    devroot, pctldev, &pinmux_select_ops);
 }
 
 #endif /* CONFIG_DEBUG_FS */