diff mbox series

[RFC,07/12] gpio: amd-fch: add oftree probing support

Message ID 20210208222203.22335-8-info@metux.net
State New
Headers show
Series [RFC,01/12] of: base: improve error message in of_phandle_iterator_next() | expand

Commit Message

Enrico Weigelt, metux IT consult Feb. 8, 2021, 10:21 p.m. UTC
Add support for probing via device tree.
---
 drivers/gpio/gpio-amd-fch.c                     | 58 +++++++++++++++++++++++++
 include/dt-bindings/gpio/amd-fch-gpio.h         | 36 +++++++++++++++
 include/linux/platform_data/gpio/gpio-amd-fch.h | 24 ++--------
 3 files changed, 98 insertions(+), 20 deletions(-)
 create mode 100644 include/dt-bindings/gpio/amd-fch-gpio.h

Comments

Bartosz Golaszewski Feb. 11, 2021, 9:57 a.m. UTC | #1
On Mon, Feb 8, 2021 at 11:22 PM Enrico Weigelt, metux IT consult
<info@metux.net> wrote:
>
> Add support for probing via device tree.
> ---
>  drivers/gpio/gpio-amd-fch.c                     | 58 +++++++++++++++++++++++++
>  include/dt-bindings/gpio/amd-fch-gpio.h         | 36 +++++++++++++++
>  include/linux/platform_data/gpio/gpio-amd-fch.h | 24 ++--------
>  3 files changed, 98 insertions(+), 20 deletions(-)
>  create mode 100644 include/dt-bindings/gpio/amd-fch-gpio.h
>
> diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c
> index 2a21354ed6a0..32024f99dae5 100644
> --- a/drivers/gpio/gpio-amd-fch.c
> +++ b/drivers/gpio/gpio-amd-fch.c
> @@ -136,12 +136,61 @@ static int amd_fch_gpio_request(struct gpio_chip *chip,
>         return 0;
>  }
>
> +static struct amd_fch_gpio_pdata *load_pdata(struct device *dev)

Please stick to the amd_fch_ prefix to all symbols for consistency.

> +{
> +       struct amd_fch_gpio_pdata *pdata;
> +       int ret;
> +
> +       pdata = devm_kzalloc(dev, sizeof(struct amd_fch_gpio_pdata),
> +                            GFP_KERNEL);
> +       if (!pdata)
> +               goto nomem;
> +
> +       pdata->gpio_num = of_property_count_elems_of_size(dev->of_node,
> +                                                         "gpio-regs",
> +                                                         sizeof(u32));
> +       pdata->gpio_reg = devm_kzalloc(dev, sizeof(int)*pdata->gpio_num,
> +                                      GFP_KERNEL);
> +       if (!pdata->gpio_reg)
> +               goto nomem;
> +
> +       pdata->gpio_names = devm_kzalloc(dev, sizeof(char*)*pdata->gpio_num,
> +                                        GFP_KERNEL);
> +       if (!pdata->gpio_names)
> +               goto nomem;
> +
> +       ret = of_property_read_variable_u32_array(dev->of_node, "gpio-regs",
> +                                                 pdata->gpio_reg,
> +                                                 pdata->gpio_num,
> +                                                 pdata->gpio_num);
> +       if (ret != pdata->gpio_num) {
> +               dev_err(dev, "failed reading gpio-regs from DT: %d\n", ret);
> +               return NULL;
> +       }
> +
> +       ret = of_property_read_string_array(dev->of_node, "gpio-line-names",
> +                                           pdata->gpio_names, pdata->gpio_num);
> +       if (ret != pdata->gpio_num) {
> +               dev_err(dev, "failed reading gpio-names from DT: %d\n", ret);
> +               return NULL;
> +       }

Since you're not iterating over DT nodes nor use any interfaces
specific to OF - I suggest you use the generic device properties to
load the fill the platform data.

> +
> +       return pdata;
> +
> +nomem:
> +       dev_err(dev, "load_pdata: failed allocating memory\n");
> +       return NULL;
> +}
> +
>  static int amd_fch_gpio_probe(struct platform_device *pdev)
>  {
>         struct amd_fch_gpio_priv *priv;
>         struct amd_fch_gpio_pdata *pdata;
>
>         pdata = dev_get_platdata(&pdev->dev);
> +       if (!pdata)
> +               pdata = load_pdata(&pdev->dev);
> +
>         if (!pdata) {
>                 dev_err(&pdev->dev, "no platform_data\n");
>                 return -ENOENT;
> @@ -165,6 +214,9 @@ static int amd_fch_gpio_probe(struct platform_device *pdev)
>         priv->gc.get_direction          = amd_fch_gpio_get_direction;
>         priv->gc.get                    = amd_fch_gpio_get;
>         priv->gc.set                    = amd_fch_gpio_set;
> +#ifdef CONFIG_OF_GPIO
> +       priv->gc.of_node                = pdev->dev.of_node;
> +#endif
>
>         spin_lock_init(&priv->lock);
>
> @@ -177,9 +229,15 @@ static int amd_fch_gpio_probe(struct platform_device *pdev)
>         return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
>  }
>
> +static const struct of_device_id amd_fch_gpio_of_match[] = {
> +       { .compatible = "amd,fch-gpio" },
> +       {}
> +};

Don't you need the module table?

> +
>  static struct platform_driver amd_fch_gpio_driver = {
>         .driver = {
>                 .name = AMD_FCH_GPIO_DRIVER_NAME,
> +               .of_match_table = amd_fch_gpio_of_match,
>         },
>         .probe = amd_fch_gpio_probe,
>  };
> diff --git a/include/dt-bindings/gpio/amd-fch-gpio.h b/include/dt-bindings/gpio/amd-fch-gpio.h
> new file mode 100644
> index 000000000000..7a47e6debcdb
> --- /dev/null
> +++ b/include/dt-bindings/gpio/amd-fch-gpio.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * AMD FCH gpio platform data definitions
> + *
> + * Copyright (C) 2020 metux IT consult
> + * Author: Enrico Weigelt <info@metux.net>
> + *
> + */
> +
> +#ifndef __DT_BINDINGS_GPIO_AMD_FCH_REGS_H
> +#define __DT_BINDINGS_GPIO_AMD_FCH_REGS_H
> +
> +/*
> + * gpio registers addresses
> + *
> + * these regs need to be assigned by board setup, since they're wired
> + * in very board specifici was, rarely documented, this should not be
> + * available to users.
> + */
> +#define AMD_FCH_GPIO_REG_GPIO49                0x40
> +#define AMD_FCH_GPIO_REG_GPIO50                0x41
> +#define AMD_FCH_GPIO_REG_GPIO51                0x42
> +#define AMD_FCH_GPIO_REG_GPIO55_DEVSLP0        0x43
> +#define AMD_FCH_GPIO_REG_GPIO57                0x44
> +#define AMD_FCH_GPIO_REG_GPIO58                0x45
> +#define AMD_FCH_GPIO_REG_GPIO59_DEVSLP1        0x46
> +#define AMD_FCH_GPIO_REG_GPIO64                0x47
> +#define AMD_FCH_GPIO_REG_GPIO68                0x48
> +#define AMD_FCH_GPIO_REG_GPIO66_SPKR   0x5B
> +#define AMD_FCH_GPIO_REG_GPIO71                0x4D
> +#define AMD_FCH_GPIO_REG_GPIO32_GE1    0x59
> +#define AMD_FCH_GPIO_REG_GPIO33_GE2    0x5A
> +#define AMT_FCH_GPIO_REG_GEVT22                0x09
> +
> +#endif /* __DT_BINDINGS_GPIO_AMD_FCH_REGS_H */
> diff --git a/include/linux/platform_data/gpio/gpio-amd-fch.h b/include/linux/platform_data/gpio/gpio-amd-fch.h
> index 255d51c9d36d..336f7387e82c 100644
> --- a/include/linux/platform_data/gpio/gpio-amd-fch.h
> +++ b/include/linux/platform_data/gpio/gpio-amd-fch.h
> @@ -11,25 +11,9 @@
>  #ifndef __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H
>  #define __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H
>
> -#define AMD_FCH_GPIO_DRIVER_NAME "gpio_amd_fch"
> +#include <dt-bindings/gpio/amd-fch-gpio.h>
>
> -/*
> - * gpio register index definitions
> - */
> -#define AMD_FCH_GPIO_REG_GPIO49                0x40
> -#define AMD_FCH_GPIO_REG_GPIO50                0x41
> -#define AMD_FCH_GPIO_REG_GPIO51                0x42
> -#define AMD_FCH_GPIO_REG_GPIO55_DEVSLP0        0x43
> -#define AMD_FCH_GPIO_REG_GPIO57                0x44
> -#define AMD_FCH_GPIO_REG_GPIO58                0x45
> -#define AMD_FCH_GPIO_REG_GPIO59_DEVSLP1        0x46
> -#define AMD_FCH_GPIO_REG_GPIO64                0x47
> -#define AMD_FCH_GPIO_REG_GPIO68                0x48
> -#define AMD_FCH_GPIO_REG_GPIO66_SPKR   0x5B
> -#define AMD_FCH_GPIO_REG_GPIO71                0x4D
> -#define AMD_FCH_GPIO_REG_GPIO32_GE1    0x59
> -#define AMD_FCH_GPIO_REG_GPIO33_GE2    0x5A
> -#define AMT_FCH_GPIO_REG_GEVT22                0x09
> +#define AMD_FCH_GPIO_DRIVER_NAME "gpio_amd_fch"
>
>  /*
>   * struct amd_fch_gpio_pdata - GPIO chip platform data
> @@ -39,8 +23,8 @@
>   */
>  struct amd_fch_gpio_pdata {
>         int                     gpio_num;
> -       int                     *gpio_reg;
> -       const char * const      *gpio_names;
> +       u32                     *gpio_reg;
> +       const char *            *gpio_names;
>  };
>
>  #endif /* __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H */
> --
> 2.11.0
>

Bartosz
Linus Walleij March 1, 2021, 2:51 p.m. UTC | #2
On Mon, Feb 8, 2021 at 11:24 PM Enrico Weigelt, metux IT consult
<info@metux.net> wrote:

> Add support for probing via device tree.
(...)
> +       pdata->gpio_num = of_property_count_elems_of_size(dev->of_node,
> +                                                         "gpio-regs",
> +                                                         sizeof(u32));
> +       pdata->gpio_reg = devm_kzalloc(dev, sizeof(int)*pdata->gpio_num,
> +                                      GFP_KERNEL);
> +       if (!pdata->gpio_reg)
> +               goto nomem;

I don't know what the idea is with this but register are not normally defined
in the DTS files. The registers are determined from the compatible value.

> +       pdata->gpio_names = devm_kzalloc(dev, sizeof(char*)*pdata->gpio_num,
> +                                        GFP_KERNEL);
> +       if (!pdata->gpio_names)
> +               goto nomem;
(...)
> +       ret = of_property_read_string_array(dev->of_node, "gpio-line-names",
> +                                           pdata->gpio_names, pdata->gpio_num);

And this is already handled by the core.

Yours,
Linus Walleij
Enrico Weigelt, metux IT consult March 11, 2021, 10:17 a.m. UTC | #3
On 01.03.21 15:51, Linus Walleij wrote:

Hi,

> I don't know what the idea is with this but register are not normally defined
> in the DTS files. The registers are determined from the compatible value.

The idea is basically replacing the pdata struct by oftree node.
(subsequent patches in this queue use this by doing the board setup via
compiled-in dtb, instead of the currently hardcoded tables).

On these SoCs, the gpio setup is a little bit more complex than just
having a fixed range of registers (one per pin): the actual meaning
depends und Soc model and board type - some regs aren't even gpios.
(I'm still in progress of RE'ing the bios blob, to find out more,
eg. pinmux setups, etc). Writing to the wrong regs can cause weird
effects (actually not even sure whether it could lead to damage)

In essence: only a specific subset of the register range can be used
for GPIOs - the others shouldn't ever be touched. And this specific
subset is soc/board specific.


--mtx
Andy Shevchenko March 11, 2021, 10:42 a.m. UTC | #4
On Thu, Mar 11, 2021 at 12:20 PM Enrico Weigelt, metux IT consult
<info@metux.net> wrote:
> On 01.03.21 15:51, Linus Walleij wrote:

> > I don't know what the idea is with this but register are not normally defined
> > in the DTS files. The registers are determined from the compatible value.
>
> The idea is basically replacing the pdata struct by oftree node.
> (subsequent patches in this queue use this by doing the board setup via
> compiled-in dtb, instead of the currently hardcoded tables).

You are a bit late. We have built-in device properties (and
corresponding API, which recently becomes swnode) which aims exactly
this.
Enrico Weigelt, metux IT consult March 18, 2021, 8 a.m. UTC | #5
On 11.03.21 11:42, Andy Shevchenko wrote:

Hi,

> You are a bit late. We have built-in device properties (and
> corresponding API, which recently becomes swnode) which aims exactly
> this.

Is there some compact notation for swnode's that's as small and simple
as some piece of DTS ?

My reasons for choosing built-in dtb have been:

* it's a very small and compact notation for describing devices
* no more open-coded registrations, etc
* no more need for board drivers (except for the little piece of DT)


--mtx
Linus Walleij March 25, 2021, 9:09 a.m. UTC | #6
On Thu, Mar 18, 2021 at 9:00 AM Enrico Weigelt, metux IT consult
<lkml@metux.net> wrote:

> Is there some compact notation for swnode's that's as small and simple
> as some piece of DTS ?

Yes it's really neat. It's all in <linux/property.h> and examples
in e.g. the testsuite:
drivers/base/test/property-entry-test.c

You can just grep for PROPERTY_ENTRY and you find some
examples of how we use it.

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c
index 2a21354ed6a0..32024f99dae5 100644
--- a/drivers/gpio/gpio-amd-fch.c
+++ b/drivers/gpio/gpio-amd-fch.c
@@ -136,12 +136,61 @@  static int amd_fch_gpio_request(struct gpio_chip *chip,
 	return 0;
 }
 
+static struct amd_fch_gpio_pdata *load_pdata(struct device *dev)
+{
+	struct amd_fch_gpio_pdata *pdata;
+	int ret;
+
+	pdata = devm_kzalloc(dev, sizeof(struct amd_fch_gpio_pdata),
+			     GFP_KERNEL);
+	if (!pdata)
+		goto nomem;
+
+	pdata->gpio_num = of_property_count_elems_of_size(dev->of_node,
+							  "gpio-regs",
+							  sizeof(u32));
+	pdata->gpio_reg = devm_kzalloc(dev, sizeof(int)*pdata->gpio_num,
+				       GFP_KERNEL);
+	if (!pdata->gpio_reg)
+		goto nomem;
+
+	pdata->gpio_names = devm_kzalloc(dev, sizeof(char*)*pdata->gpio_num,
+					 GFP_KERNEL);
+	if (!pdata->gpio_names)
+		goto nomem;
+
+	ret = of_property_read_variable_u32_array(dev->of_node, "gpio-regs",
+						  pdata->gpio_reg,
+						  pdata->gpio_num,
+						  pdata->gpio_num);
+	if (ret != pdata->gpio_num) {
+		dev_err(dev, "failed reading gpio-regs from DT: %d\n", ret);
+		return NULL;
+	}
+
+	ret = of_property_read_string_array(dev->of_node, "gpio-line-names",
+					    pdata->gpio_names, pdata->gpio_num);
+	if (ret != pdata->gpio_num) {
+		dev_err(dev, "failed reading gpio-names from DT: %d\n", ret);
+		return NULL;
+	}
+
+	return pdata;
+
+nomem:
+	dev_err(dev, "load_pdata: failed allocating memory\n");
+	return NULL;
+}
+
 static int amd_fch_gpio_probe(struct platform_device *pdev)
 {
 	struct amd_fch_gpio_priv *priv;
 	struct amd_fch_gpio_pdata *pdata;
 
 	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		pdata = load_pdata(&pdev->dev);
+
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform_data\n");
 		return -ENOENT;
@@ -165,6 +214,9 @@  static int amd_fch_gpio_probe(struct platform_device *pdev)
 	priv->gc.get_direction		= amd_fch_gpio_get_direction;
 	priv->gc.get			= amd_fch_gpio_get;
 	priv->gc.set			= amd_fch_gpio_set;
+#ifdef CONFIG_OF_GPIO
+	priv->gc.of_node		= pdev->dev.of_node;
+#endif
 
 	spin_lock_init(&priv->lock);
 
@@ -177,9 +229,15 @@  static int amd_fch_gpio_probe(struct platform_device *pdev)
 	return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
 }
 
+static const struct of_device_id amd_fch_gpio_of_match[] = {
+	{ .compatible = "amd,fch-gpio" },
+	{}
+};
+
 static struct platform_driver amd_fch_gpio_driver = {
 	.driver = {
 		.name = AMD_FCH_GPIO_DRIVER_NAME,
+		.of_match_table = amd_fch_gpio_of_match,
 	},
 	.probe = amd_fch_gpio_probe,
 };
diff --git a/include/dt-bindings/gpio/amd-fch-gpio.h b/include/dt-bindings/gpio/amd-fch-gpio.h
new file mode 100644
index 000000000000..7a47e6debcdb
--- /dev/null
+++ b/include/dt-bindings/gpio/amd-fch-gpio.h
@@ -0,0 +1,36 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * AMD FCH gpio platform data definitions
+ *
+ * Copyright (C) 2020 metux IT consult
+ * Author: Enrico Weigelt <info@metux.net>
+ *
+ */
+
+#ifndef __DT_BINDINGS_GPIO_AMD_FCH_REGS_H
+#define __DT_BINDINGS_GPIO_AMD_FCH_REGS_H
+
+/*
+ * gpio registers addresses
+ *
+ * these regs need to be assigned by board setup, since they're wired
+ * in very board specifici was, rarely documented, this should not be
+ * available to users.
+ */
+#define AMD_FCH_GPIO_REG_GPIO49		0x40
+#define AMD_FCH_GPIO_REG_GPIO50		0x41
+#define AMD_FCH_GPIO_REG_GPIO51		0x42
+#define AMD_FCH_GPIO_REG_GPIO55_DEVSLP0	0x43
+#define AMD_FCH_GPIO_REG_GPIO57		0x44
+#define AMD_FCH_GPIO_REG_GPIO58		0x45
+#define AMD_FCH_GPIO_REG_GPIO59_DEVSLP1	0x46
+#define AMD_FCH_GPIO_REG_GPIO64		0x47
+#define AMD_FCH_GPIO_REG_GPIO68		0x48
+#define AMD_FCH_GPIO_REG_GPIO66_SPKR	0x5B
+#define AMD_FCH_GPIO_REG_GPIO71		0x4D
+#define AMD_FCH_GPIO_REG_GPIO32_GE1	0x59
+#define AMD_FCH_GPIO_REG_GPIO33_GE2	0x5A
+#define AMT_FCH_GPIO_REG_GEVT22		0x09
+
+#endif /* __DT_BINDINGS_GPIO_AMD_FCH_REGS_H */
diff --git a/include/linux/platform_data/gpio/gpio-amd-fch.h b/include/linux/platform_data/gpio/gpio-amd-fch.h
index 255d51c9d36d..336f7387e82c 100644
--- a/include/linux/platform_data/gpio/gpio-amd-fch.h
+++ b/include/linux/platform_data/gpio/gpio-amd-fch.h
@@ -11,25 +11,9 @@ 
 #ifndef __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H
 #define __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H
 
-#define AMD_FCH_GPIO_DRIVER_NAME "gpio_amd_fch"
+#include <dt-bindings/gpio/amd-fch-gpio.h>
 
-/*
- * gpio register index definitions
- */
-#define AMD_FCH_GPIO_REG_GPIO49		0x40
-#define AMD_FCH_GPIO_REG_GPIO50		0x41
-#define AMD_FCH_GPIO_REG_GPIO51		0x42
-#define AMD_FCH_GPIO_REG_GPIO55_DEVSLP0	0x43
-#define AMD_FCH_GPIO_REG_GPIO57		0x44
-#define AMD_FCH_GPIO_REG_GPIO58		0x45
-#define AMD_FCH_GPIO_REG_GPIO59_DEVSLP1	0x46
-#define AMD_FCH_GPIO_REG_GPIO64		0x47
-#define AMD_FCH_GPIO_REG_GPIO68		0x48
-#define AMD_FCH_GPIO_REG_GPIO66_SPKR	0x5B
-#define AMD_FCH_GPIO_REG_GPIO71		0x4D
-#define AMD_FCH_GPIO_REG_GPIO32_GE1	0x59
-#define AMD_FCH_GPIO_REG_GPIO33_GE2	0x5A
-#define AMT_FCH_GPIO_REG_GEVT22		0x09
+#define AMD_FCH_GPIO_DRIVER_NAME "gpio_amd_fch"
 
 /*
  * struct amd_fch_gpio_pdata - GPIO chip platform data
@@ -39,8 +23,8 @@ 
  */
 struct amd_fch_gpio_pdata {
 	int			gpio_num;
-	int			*gpio_reg;
-	const char * const	*gpio_names;
+	u32			*gpio_reg;
+	const char * 		*gpio_names;
 };
 
 #endif /* __LINUX_PLATFORM_DATA_GPIO_AMD_FCH_H */