Re: [PATCH] pinctrl: pinmux: Add pinmux-select debugfs file

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

 



On Fri, Jan 29, 2021 at 12:02:43PM +0100, Geert Uytterhoeven wrote:
> Hi Drew,
> 
> Thanks for your patch!
> 
> On Fri, Jan 29, 2021 at 9:49 AM Drew Fustini <drew@xxxxxxxxxxxxxxx> wrote:
> > Add "pinmux-select" to debugfs which will activate a function and group
> > when 2 integers "<function-selector> <group-selector>" are written to
> > the file. The write operation pinmux_select() handles this by checking
> > if fsel and gsel are 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 (fsel 4) and group pinmux-i2c1-pins
> > (gsel 4):
> >
> > echo '4 4' > pinmux-select
> 
> Shouldn't gsel be "0" in your example, as "pinmux-i2c1-pins" is the
> first entry in the groups array?
> 
> [ /me actually tries this]
> 
> Oh, gsel is not the index inside the groups array, but the global index?
> 
> On R-Car M2-W, which does not use pinctrl-single, I have:
> 
>     function 0: audio_clk, groups = [ audio_clk_a audio_clk_b
> audio_clk_b_b audio_clk_c audio_clkout ]
>     function 1: avb, groups = [ avb_link avb_magic avb_phy_int
> avb_mdio avb_mii avb_gmii ]
>     function 2: can0, groups = [ can0_data can0_data_b can0_data_c
> can0_data_d can0_data_e can0_data_f can_clk can_clk_b can_clk_c
> can_clk_d ]
>     function 3: can1, groups = [ can1_data can1_data_b can1_data_c
> can1_data_d can_clk can_clk_b can_clk_c can_clk_d ]
>     function 4: can_clk, groups = [ can_clk can_clk_b can_clk_c can_clk_d ]
>     function 5: du, groups = [ du_rgb666 du_rgb888 du_clk_out_0
> du_clk_out_1 du_sync du_oddf du_cde du_disp ]
>     function 6: du0, groups = [ du0_clk_in ]
>     function 7: du1, groups = [ du1_clk_in du1_clk_in_b du1_clk_in_c ]
>     function 8: eth, groups = [ eth_link eth_magic eth_mdio eth_rmii ]
>     function 9: hscif0, groups = [ hscif0_data hscif0_clk hscif0_ctrl
> hscif0_data_b hscif0_ctrl_b hscif0_data_c hscif0_clk_c ]
>     function 10: hscif1, groups = [ hscif1_data hscif1_clk hscif1_ctrl
> hscif1_data_b hscif1_data_c hscif1_clk_c hscif1_ctrl_c hscif1_data_d
> hscif1_data_e hscif1_clk_e hscif1_ctrl_e ]
>     function 11: hscif2, groups = [ hscif2_data hscif2_clk hscif2_ctrl
> hscif2_data_b hscif2_ctrl_b hscif2_data_c hscif2_clk_c hscif2_data_d ]
>     function 12: i2c0, groups = [ i2c0 i2c0_b i2c0_c ]
>     function 13: i2c1, groups = [ i2c1 i2c1_b i2c1_c i2c1_d i2c1_e ]
>     function 14: i2c2, groups = [ i2c2 i2c2_b i2c2_c i2c2_d ]
>     [...]
> 
> Took me a few tries, crashes, and debug prints, to discover that I did
> not count wrong, but that names were de-duplicated (the "can_clk*" in
> functions 2 and 3 are not accessible by gsel), and that "75" not "83" is
> the right number to configure i2c2.
> 
> But then it works (on the Koelsch board):
> 
>     # cd /sys/kernel/debug/pinctrl/e6060000.pinctrl-sh-pfc/
>     # echo 14 289 > pinmux-select   # Configure i2c2 pins for ssi2_ctrl
>     # i2cdetect -y -a 2             # Fails
>     # echo 14 75 > pinmux-select    # Restore i2c2
>     # i2cdetect -y -a 2             # Works again
> 
> Nice!
> 
> So we definitely want to use the actual names, not error-prone numbers,
> at least for pinctrl drivers that use the concept of names.
> As we do specify the names in DT, cfr.
> arch/arm/boot/dts/r8a7791-koelsch.dts:
> 
>         i2c2_pins: i2c2 {
>                 groups = "i2c2";
>                 function = "i2c2";
>         };
> 
> the pinmux core already knows how to look them up.
> See pinmux_map_to_setting().
> 
> > --- a/drivers/pinctrl/pinmux.c
> > +++ b/drivers/pinctrl/pinmux.c
> > @@ -673,6 +673,65 @@ void pinmux_show_setting(struct seq_file *s,
> >  DEFINE_SHOW_ATTRIBUTE(pinmux_functions);
> >  DEFINE_SHOW_ATTRIBUTE(pinmux_pins);
> >
> > +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 pinctrl_ops *pctlops = pctldev->desc->pctlops;
> > +       const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
> > +       int fsel, gsel, ret;
> > +       char buf[16];
> > +
> > +       if (len > sizeof(buf)) {
> > +               dev_err(pctldev->dev, "write too big for buffer");
> > +               return -EINVAL;
> > +       }
> > +
> > +       ret = strncpy_from_user(buf, user_buf, sizeof(buf));
> > +       if (ret < 0)
> > +               return ret;
> > +       buf[len-1] = '\0';
> > +
> > +       ret = sscanf(buf, "%d %d", &fsel, &gsel);
> > +       if (ret != 2) {
> > +               dev_err(pctldev->dev, "expected format: <function#> <group#>");
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (!pmxops->get_function_name(pctldev, fsel)) {
> 
> At least for the Renesas pinctrl driver, get_function_name() happily
> iterates beyond the end of the internal array, which may crash.
> Using pinmux_func_name_to_selector() would avoid that.
> 
> > +               dev_err(pctldev->dev, "function selector %u not valid\n", fsel);
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (!pctlops->get_group_name(pctldev, gsel)) {
> 
> Likewise.
> 
> Use pmxops->get_function_groups() and match_string() instead?
> 
> > +               dev_err(pctldev->dev, "group selector %u not valid\n", gsel);
> > +               return -EINVAL;
> > +       }
> > +
> > +       ret = pmxops->set_mux(pctldev, fsel, gsel);
> > +       if (ret) {
> > +               dev_err(pctldev->dev, "set_mux() failed: %d", ret);
> > +               return -EINVAL;
> > +       }
> > +
> > +       return len;
> > +}
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx
> 
> 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

Thanks very much for the comments, Geert. It is great to get feedback on
how it behaves on other pin control hardware.

I agree the selectors get confusing, and it does make more sense to use
the function and group names in 'pinmux-select'. I was initially
discouraged when I didn't see an efficient way to do a lookup in the
radix trees based on name. I'll take a look at the functions that you
mentioned as they look promising.

thanks,
drew




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux