Message ID | 20210302053059.1049035-3-drew@beagleboard.org |
---|---|
State | Accepted |
Commit | 6199f6becc869d30ca9394ca0f7a484bf9d598eb |
Headers | show |
Series | pinctrl: pinmux: Add pinmux-select debugfs file | expand |
On 02.03.21 06:30, Drew Fustini wrote: Hi folks, > Add "pinmux-select" to debugfs which will activate a pin function for a > given pin group: > > echo "<group-name function-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(). I've already been playing with similar idea, but for external muxes. For example, some boards have multiple SIM slots that can be switched via some gpio pin. Not sure whether traditional pinmux would be a good match for that. --mtx -- --- Hinweis: unverschlüsselte E-Mails können leicht abgehört und manipuliert werden ! Für eine vertrauliche Kommunikation senden Sie bitte ihren GPG/PGP-Schlüssel zu. --- Enrico Weigelt, metux IT consult Free software and Linux embedded engineering info@metux.net -- +49-151-27565287
On Fri, Mar 12, 2021 at 02:57:54PM +0100, Enrico Weigelt, metux IT consult wrote: > On 02.03.21 06:30, Drew Fustini wrote: > > Hi folks, > > > Add "pinmux-select" to debugfs which will activate a pin function for a > > given pin group: > > > > echo "<group-name function-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(). > > I've already been playing with similar idea, but for external muxes. > For example, some boards have multiple SIM slots that can be switched > via some gpio pin. > > Not sure whether traditional pinmux would be a good match for that. > > > --mtx > Thank you for your comment. I am interested in understanding other use cases. Linus can hopefully correct me, but I think this is covered by section "Drivers needing both pin control and GPIOs" in pinctl.rst [1]. The driver could be both a GPIO consumer and pinctrl consumer and then be able to call pinctrl_select_state() and devm_gpio_request(). Thank you, Drew [1] https://www.kernel.org/doc/html/latest/driver-api/pinctl.html
On 12/03/2021 14:57:54+0100, Enrico Weigelt, metux IT consult wrote: > On 02.03.21 06:30, Drew Fustini wrote: > > Hi folks, > > > Add "pinmux-select" to debugfs which will activate a pin function for a > > given pin group: > > > > echo "<group-name function-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(). > > I've already been playing with similar idea, but for external muxes. > For example, some boards have multiple SIM slots that can be switched > via some gpio pin. > > Not sure whether traditional pinmux would be a good match for that. > If you want to be able to use both, then I guess gpio-mux is what you are looking for. Obviously, it will also require support in the bus core. On what bus are those SIMs? (I guess the answer will be UART and then unfortunately UARTs are not represented as busses). -- Alexandre Belloni, co-owner and COO, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Hi Alexandre, On Sat, Mar 13, 2021 at 10:28 AM Alexandre Belloni <alexandre.belloni@bootlin.com> wrote: > On 12/03/2021 14:57:54+0100, Enrico Weigelt, metux IT consult wrote: > > On 02.03.21 06:30, Drew Fustini wrote: > > > Add "pinmux-select" to debugfs which will activate a pin function for a > > > given pin group: > > > > > > echo "<group-name function-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(). > > > > I've already been playing with similar idea, but for external muxes. > > For example, some boards have multiple SIM slots that can be switched > > via some gpio pin. > > > > Not sure whether traditional pinmux would be a good match for that. > > If you want to be able to use both, then I guess gpio-mux is what you > are looking for. Obviously, it will also require support in the bus > core. On what bus are those SIMs? (I guess the answer will be UART and > then unfortunately UARTs are not represented as busses). We do have support for devices connected to UARTs. See patternProperties in Documentation/devicetree/bindings/serial/serial.yaml. Or do you mean something different? 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
On Fri, Mar 12, 2021 at 2:57 PM Enrico Weigelt, metux IT consult <lkml@metux.net> wrote: > On 02.03.21 06:30, Drew Fustini wrote: > > Hi folks, > > > Add "pinmux-select" to debugfs which will activate a pin function for a > > given pin group: > > > > echo "<group-name function-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(). > > I've already been playing with similar idea, but for external muxes. > For example, some boards have multiple SIM slots that can be switched > via some gpio pin. > > Not sure whether traditional pinmux would be a good match for that. What is wrong with the subsystem drivers/mux? It's exactly for this usecase I think. Peter Rosin already wrote a GPIO-controlled mux driver too. Yours, Linus Walleij
On 13.03.21 19:47, Geert Uytterhoeven wrote: >>> I've already been playing with similar idea, but for external muxes. >>> For example, some boards have multiple SIM slots that can be switched >>> via some gpio pin. >>> >>> Not sure whether traditional pinmux would be a good match for that. >> >> If you want to be able to use both, then I guess gpio-mux is what you >> are looking for. Obviously, it will also require support in the bus >> core. On what bus are those SIMs? (I guess the answer will be UART and >> then unfortunately UARTs are not represented as busses). > > We do have support for devices connected to UARTs. > See patternProperties in Documentation/devicetree/bindings/serial/serial.yaml. > Or do you mean something different? in my case, the SIM cards are connected directly to the baseband (there're extra lines on the m2 slots for that). CPU doesn't ever see any of this traffic, just can select which SIM card is routed to the m2 slot via gpio. --mtx -- --- Hinweis: unverschlüsselte E-Mails können leicht abgehört und manipuliert werden ! Für eine vertrauliche Kommunikation senden Sie bitte ihren GPG/PGP-Schlüssel zu. --- Enrico Weigelt, metux IT consult Free software and Linux embedded engineering info@metux.net -- +49-151-27565287
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index c651b2db0925..f4abfaecfc5c 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 128 +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, *gname, *fname; + 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 */ + gname = strstrip(buf); + if (*gname == '\0') { + ret = -EINVAL; + goto exit_free_buf; + } + + /* find a separator which is a spacelike character */ + for (fname = gname; !isspace(*fname); fname++) { + if (*fname == '\0') { + ret = -EINVAL; + goto exit_free_buf; + } + } + *fname = '\0'; + + /* drop extra spaces between function and group names */ + fname = skip_spaces(fname + 1); + if (*fname == '\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 */