Message ID | 20211118132152.15722-4-zajec5@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | pinctrl: allow storing pins, groups & functions in DT | expand |
On Thu, Nov 18, 2021 at 3:22 PM Rafał Miłecki <zajec5@gmail.com> wrote: ... > --- a/drivers/pinctrl/pinmux.c > +++ b/drivers/pinctrl/pinmux.c > +#include <linux/of.h> I don't like this. This shows not thought through the design of the series. What I rather expect is a proper interfacing layer that you fill with options that can be provided by corresponding underlying implementation, e.g. DT. Moreover, before doing this you probably would need to refactor the pin control core to get rid of DT specifics, i.e. abstract them away first.
On 18.11.2021 14:57, Andy Shevchenko wrote: > On Thu, Nov 18, 2021 at 3:22 PM Rafał Miłecki <zajec5@gmail.com> wrote: > > ... > >> --- a/drivers/pinctrl/pinmux.c >> +++ b/drivers/pinctrl/pinmux.c > >> +#include <linux/of.h> > > I don't like this. This shows not thought through the design of the series. > > What I rather expect is a proper interfacing layer that you fill with > options that can be provided by corresponding underlying > implementation, e.g. DT. > > Moreover, before doing this you probably would need to refactor the > pin control core to get rid of DT specifics, i.e. abstract them away > first. Ouch, it seems like pinctrl got into a tricky state. As I understand it we need some abstraction layer between DT and pinctrl but noone is working on it? Does it mean we should consider pinctrl core frozen until it's refactored? It's quite inconvenient for me as I'm not sure if I can handle such heavy pinctrl refactoring while at the same time I'd like to add those small features to it. Can you point to an example of extra interfacing layer that could be used as a reference for what you expect for pinctrl one, please? Some solution in another Linux's subsystem?
On Thu, Nov 18, 2021 at 4:17 PM Rafał Miłecki <zajec5@gmail.com> wrote: > On 18.11.2021 14:57, Andy Shevchenko wrote: > > On Thu, Nov 18, 2021 at 3:22 PM Rafał Miłecki <zajec5@gmail.com> wrote: ... > >> +#include <linux/of.h> > > > > I don't like this. This shows not thought through the design of the series. > > > > What I rather expect is a proper interfacing layer that you fill with > > options that can be provided by corresponding underlying > > implementation, e.g. DT. > > > > Moreover, before doing this you probably would need to refactor the > > pin control core to get rid of DT specifics, i.e. abstract them away > > first. > > Ouch, it seems like pinctrl got into a tricky state. As I understand it > we need some abstraction layer between DT and pinctrl but noone is > working on it? Seems so to me. To be more specific, I'm talking about these: struct pinctrl_ops { ... int (*dt_node_to_map)... void (*dt_free_map)... } and this: struct pinctrl { ... struct list_head dt_maps; } In the latter case it is almost related to renaming dt_maps to something like fw_maps. In both cases it is about decoupling DT stuff out from the pin control core. So, with something like pinctrl_fw_ops to be introduced, the DT stuff moved to drivers/pinctrl/devicetree.c. > Does it mean we should consider pinctrl core frozen until > it's refactored? Solutions which are related to pin control core without keeping non-DT providers in mind will be NAKed by me, definitely. Of course it can be overridden by maintainers. > It's quite inconvenient for me as I'm not sure if I can handle such > heavy pinctrl refactoring while at the same time I'd like to add > those small features to it. Which effectively means "let give somebody else even more burden and problems". > Can you point to an example of extra interfacing layer that could be > used as a reference for what you expect for pinctrl one, please? Some > solution in another Linux's subsystem? GPIOLIB decoupled this. Another example (not sure if it's good enough here) is the fwnode API (see fwnode ops).
On Thu, Nov 18, 2021 at 2:58 PM Andy Shevchenko <andy.shevchenko@gmail.com> wrote: > On Thu, Nov 18, 2021 at 3:22 PM Rafał Miłecki <zajec5@gmail.com> wrote: > > +#include <linux/of.h> > > I don't like this. This shows not thought through the design of the series. > > What I rather expect is a proper interfacing layer that you fill with > options that can be provided by corresponding underlying > implementation, e.g. DT. I agree, the DT parts should land in pinctrl/devicetree.c in the end with an opt-in for ACPI & board files. I don't know if we can use software nodes fully instead of board file-specific helpers at this point, it seems to have grown pretty competent. Yours, Linus Walleij
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index ffe39336fcac..8f6ed8488313 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -515,8 +515,97 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); +int pinctrl_generic_get_dt_pins(struct pinctrl_desc *pctldesc, + struct device *dev) +{ + struct pinctrl_pin_desc *descs; + struct device_node *pins; + struct device_node *np; + int err = 0; + int i = 0; + + pins = of_get_child_by_name(dev->of_node, "pins"); + if (!pins) { + dev_err(dev, "failed to find \"pins\" DT node\n"); + err = -ENOENT; + goto err_out; + } + + pctldesc->npins = of_get_available_child_count(pins); + + descs = devm_kcalloc(dev, pctldesc->npins, sizeof(*descs), GFP_KERNEL); + if (!descs) { + err = -ENOMEM; + goto err_put_node; + } + + for_each_available_child_of_node(pins, np) { + if (of_property_read_u32(np, "reg", &descs[i].number)) { + dev_err(dev, "missing \"reg\" property in %pOF\n", np); + err = -ENOENT; + goto err_put_node; + } + + if (of_property_read_string(np, "label", &descs[i].name)) { + dev_err(dev, "missing \"label\" property in %pOF\n", np); + err = -ENOENT; + goto err_put_node; + } + + i++; + } + + pctldesc->pins = descs; + +err_put_node: + of_node_put(pins); +err_out: + return err; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_dt_pins); + #ifdef CONFIG_GENERIC_PINCTRL_GROUPS +int pinctrl_generic_get_dt_groups(struct pinctrl_dev *pctldev) +{ + struct device *dev = pctldev->dev; + struct device_node *groups; + struct device_node *np; + int err = 0; + + groups = of_get_child_by_name(dev->of_node, "groups"); + if (!groups) { + dev_err(dev, "failed to find \"groups\" DT node\n"); + err = -ENOENT; + goto err_out; + } + + for_each_available_child_of_node(groups, np) { + int num_pins; + u32 *pins; + + num_pins = of_property_count_u32_elems(np, "pins"); + pins = devm_kmalloc_array(dev, num_pins, sizeof(*pins), GFP_KERNEL); + if (!pins) { + err = -ENOMEM; + goto err_put_node; + } + + if (of_property_read_u32_array(np, "pins", pins, num_pins)) { + err = -EIO; + goto err_put_node; + } + + pinctrl_generic_add_group(pctldev, np->name, pins, num_pins, np); + } + +err_put_node: + of_node_put(groups); +err_out: + return err; +} +EXPORT_SYMBOL_GPL(pinctrl_generic_get_dt_groups); + /** * pinctrl_generic_get_group_count() - returns the number of pin groups * @pctldev: pin controller device diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 840103c40c14..59661d4d4cc7 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -182,6 +182,9 @@ struct pinctrl_maps { unsigned num_maps; }; +int pinctrl_generic_get_dt_pins(struct pinctrl_desc *pctldesc, + struct device *dev); + #ifdef CONFIG_GENERIC_PINCTRL_GROUPS /** @@ -198,6 +201,8 @@ struct group_desc { void *data; }; +int pinctrl_generic_get_dt_groups(struct pinctrl_dev *pctldev); + int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 6cdbd9ccf2f0..5e34bd3135f5 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -24,6 +24,7 @@ #include <linux/string.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/of.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinmux.h> #include "core.h" @@ -788,6 +789,48 @@ void pinmux_init_device_debugfs(struct dentry *devroot, #ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS +int pinmux_generic_get_dt_functions(struct pinctrl_dev *pctldev) +{ + struct device *dev = pctldev->dev; + struct device_node *functions; + struct device_node *np; + int err = 0; + + functions = of_get_child_by_name(dev->of_node, "functions"); + if (!functions) { + dev_err(dev, "failed to find \"functions\" DT node\n"); + err = -ENOENT; + goto err_out; + } + + for_each_available_child_of_node(functions, np) { + int num_groups = of_count_phandle_with_args(np, "groups", NULL); + struct of_phandle_iterator it; + const char **groups; + int ret; + int i; + + groups = devm_kmalloc_array(dev, num_groups, sizeof(*groups), GFP_KERNEL); + if (!groups) { + err = -ENOMEM; + goto err_put_node; + } + + i = 0; + of_for_each_phandle(&it, ret, np, "groups", NULL, 0) { + groups[i++] = it.node->name; + } + + pinmux_generic_add_function(pctldev, np->name, groups, num_groups, np); + } + +err_put_node: + of_node_put(functions); +err_out: + return err; +} +EXPORT_SYMBOL_GPL(pinmux_generic_get_dt_functions); + /** * pinmux_generic_get_function_count() - returns number of functions * @pctldev: pin controller device diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 78c3a31be882..ca69025fce46 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h @@ -134,6 +134,8 @@ struct function_desc { void *data; }; +int pinmux_generic_get_dt_functions(struct pinctrl_dev *pctldev); + int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev); const char *