diff mbox

[10/33] pcmcia: soc_common: switch to using gpio_descs

Message ID E1beJkO-0000mg-Lu@rmk-PC.armlinux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King (Oracle) Aug. 29, 2016, 10:24 a.m. UTC
Switch to using the gpiod_* consumer API rather than the legacy API.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/pcmcia/soc_common.c | 57 +++++++++++++++++++++++++++++++++------------
 drivers/pcmcia/soc_common.h |  3 +++
 2 files changed, 45 insertions(+), 15 deletions(-)

Comments

Linus Walleij Sept. 14, 2016, 11:29 a.m. UTC | #1
On Mon, Aug 29, 2016 at 12:24 PM, Russell King
<rmk+kernel@armlinux.org.uk> wrote:

> Switch to using the gpiod_* consumer API rather than the legacy API.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
(...)

> +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
> +               struct gpio_desc *desc;
> +

Here I inserted:

        /* Skip over unnamed GPIOs, assume unused */
        if (!skt->stat[i].name)
            continue;

to get it working again on h3600.

> +               desc = gpiod_get(skt->socket.dev.parent,
> +                                skt->stat[i].name, GPIOD_IN);
> +               if (IS_ERR(desc)) {
> +                       dev_err(skt->socket.dev.parent,
> +                               "Failed to get GPIO for %s: %ld\n",
> +                               skt->stat[i].name, PTR_ERR(desc));
> +                       __soc_pcmcia_hw_shutdown(skt, i);
> +                       return PTR_ERR(desc);
> +               }


It bugs out for me on the legacy h3600, since it only defines
two of these pins not all of the ARRAY_SIZE(skt->stat) pins
will succeed and we get an error message like this:

sa11x0-pcmcia sa11x0-pcmcia: Failed to get GPIO for (null): -2
sa11x0-pcmcia: probe of sa11x0-pcmcia failed with error -2

With the patch above it goes away and the log is silent.
The debugfs gpio file looks like this:

cat gpio
gpiochip0: GPIOs 0-27, gpio:
 gpio-0   (                    |Power Button        ) in  hi
 gpio-10  (                    |pcmcia1-detect      ) in  hi
 gpio-11  (                    |pcmcia1-ready       ) in  hi
 gpio-17  (                    |pcmcia0-detect      ) in  hi
 gpio-18  (                    |Action button       ) in  hi
 gpio-21  (                    |pcmcia0-ready       ) in  hi
 gpio-23  (                    |dcd                 ) in  hi
 gpio-25  (                    |cts                 ) in  lo
 gpio-26  (                    |rts                 ) out lo

gpiochip1: GPIOs 28-43, parent: platform/htc-egpio, htc-egpio:
 gpio-28  (                    |Flash Vpp           ) out lo
 gpio-29  (                    |PCMCIA CARD RESET   ) out lo
 gpio-30  (                    |OPT RESET           ) out lo
 gpio-32  (                    |OPT NVRAM ON        ) out lo
 gpio-33  (                    |OPT ON              ) out lo
 gpio-34  (                    |LCD power           ) out lo
 gpio-36  (                    |LCD control         ) out lo
 gpio-42  (                    |LCD 5v              ) out lo
 gpio-43  (                    |LCD 9v/-6.5v        ) out lo

Which seems like before the patch series.

I still suspect the PCMCIA is not really working but I have
limited experience of the bus so I don't really know how
to test it deeply or have my PCMCIA ethernet or harddrive
probe properly.

There are no regressions however, so with something like
the above patch applied:
Tested-by: Linus Walleij <linus.walleij@linaro.org>

For the whole patch series on H3600.

Yours,
Linus Walleij
Russell King (Oracle) Sept. 14, 2016, 12:10 p.m. UTC | #2
On Wed, Sep 14, 2016 at 01:29:04PM +0200, Linus Walleij wrote:
> On Mon, Aug 29, 2016 at 12:24 PM, Russell King
> <rmk+kernel@armlinux.org.uk> wrote:
> 
> > Switch to using the gpiod_* consumer API rather than the legacy API.
> >
> > Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> (...)
> 
> > +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
> > +               struct gpio_desc *desc;
> > +
> 
> Here I inserted:
> 
>         /* Skip over unnamed GPIOs, assume unused */
>         if (!skt->stat[i].name)
>             continue;
> 
> to get it working again on h3600.

Thanks, I'll add that.

> > +               desc = gpiod_get(skt->socket.dev.parent,
> > +                                skt->stat[i].name, GPIOD_IN);
> > +               if (IS_ERR(desc)) {
> > +                       dev_err(skt->socket.dev.parent,
> > +                               "Failed to get GPIO for %s: %ld\n",
> > +                               skt->stat[i].name, PTR_ERR(desc));
> > +                       __soc_pcmcia_hw_shutdown(skt, i);
> > +                       return PTR_ERR(desc);
> > +               }
> 
> 
> It bugs out for me on the legacy h3600, since it only defines
> two of these pins not all of the ARRAY_SIZE(skt->stat) pins
> will succeed and we get an error message like this:
> 
> sa11x0-pcmcia sa11x0-pcmcia: Failed to get GPIO for (null): -2
> sa11x0-pcmcia: probe of sa11x0-pcmcia failed with error -2
> 
> With the patch above it goes away and the log is silent.
> The debugfs gpio file looks like this:
> 
> cat gpio
> gpiochip0: GPIOs 0-27, gpio:
>  gpio-0   (                    |Power Button        ) in  hi
>  gpio-10  (                    |pcmcia1-detect      ) in  hi
>  gpio-11  (                    |pcmcia1-ready       ) in  hi
>  gpio-17  (                    |pcmcia0-detect      ) in  hi
>  gpio-18  (                    |Action button       ) in  hi
>  gpio-21  (                    |pcmcia0-ready       ) in  hi
>  gpio-23  (                    |dcd                 ) in  hi
>  gpio-25  (                    |cts                 ) in  lo
>  gpio-26  (                    |rts                 ) out lo
> 
> gpiochip1: GPIOs 28-43, parent: platform/htc-egpio, htc-egpio:
>  gpio-28  (                    |Flash Vpp           ) out lo
>  gpio-29  (                    |PCMCIA CARD RESET   ) out lo
>  gpio-30  (                    |OPT RESET           ) out lo
>  gpio-32  (                    |OPT NVRAM ON        ) out lo
>  gpio-33  (                    |OPT ON              ) out lo
>  gpio-34  (                    |LCD power           ) out lo
>  gpio-36  (                    |LCD control         ) out lo
>  gpio-42  (                    |LCD 5v              ) out lo
>  gpio-43  (                    |LCD 9v/-6.5v        ) out lo
> 
> Which seems like before the patch series.

Yay.

> I still suspect the PCMCIA is not really working but I have
> limited experience of the bus so I don't really know how
> to test it deeply or have my PCMCIA ethernet or harddrive
> probe properly.

Yes, to me the H3600 code looks really really really weird - the way
H3XXX_EGPIO_CARD_RESET is "shared" (badly) between both sockets is
certainly racy.  I've no idea what the semantics there are supposed
to be - I suspect that H3600 PCMCIA hasn't worked for a very long
time, or if it has, it's probably not been reliable.

> There are no regressions however, so with something like
> the above patch applied:
> Tested-by: Linus Walleij <linus.walleij@linaro.org>
> 
> For the whole patch series on H3600.

Thanks!
diff mbox

Patch

diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index d5ca760c4eb2..5d167512e96e 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -33,6 +33,7 @@ 
 
 #include <linux/cpufreq.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -114,8 +115,8 @@  static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
 	for (i = 0; i < nr; i++) {
 		if (skt->stat[i].irq)
 			free_irq(skt->stat[i].irq, skt);
-		if (gpio_is_valid(skt->stat[i].gpio))
-			gpio_free(skt->stat[i].gpio);
+		if (skt->stat[i].desc)
+			gpiod_put(skt->stat[i].desc);
 	}
 
 	if (skt->ops->hw_shutdown)
@@ -129,6 +130,30 @@  static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 	__soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
 }
 
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+		struct gpio_desc *desc;
+
+		desc = gpiod_get(skt->socket.dev.parent,
+				 skt->stat[i].name, GPIOD_IN);
+		if (IS_ERR(desc)) {
+			dev_err(skt->socket.dev.parent,
+				"Failed to get GPIO for %s: %ld\n",
+				skt->stat[i].name, PTR_ERR(desc));
+			__soc_pcmcia_hw_shutdown(skt, i);
+			return PTR_ERR(desc);
+		}
+
+		skt->stat[i].desc = desc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
+
 static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int ret = 0, i;
@@ -143,8 +168,6 @@  static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 
 	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
 		if (gpio_is_valid(skt->stat[i].gpio)) {
-			int irq;
-
 			ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN,
 					       skt->stat[i].name);
 			if (ret) {
@@ -152,7 +175,11 @@  static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 				return ret;
 			}
 
-			irq = gpio_to_irq(skt->stat[i].gpio);
+			skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
+		}
+
+		if (skt->stat[i].desc) {
+			int irq = gpiod_to_irq(skt->stat[i].desc);
 
 			if (i == SOC_STAT_RDY)
 				skt->socket.pci_irq = irq;
@@ -166,8 +193,8 @@  static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 					  IRQF_TRIGGER_NONE,
 					  skt->stat[i].name, skt);
 			if (ret) {
-				if (gpio_is_valid(skt->stat[i].gpio))
-					gpio_free(skt->stat[i].gpio);
+				if (skt->stat[i].desc)
+					gpiod_put(skt->stat[i].desc);
 				__soc_pcmcia_hw_shutdown(skt, i);
 				return ret;
 			}
@@ -209,16 +236,16 @@  static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
 	state.bvd2 = 1;
 
 	/* CD is active low by default */
-	if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio))
-		state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio);
+	if (skt->stat[SOC_STAT_CD].desc)
+		state.detect = !gpiod_get_raw_value(skt->stat[SOC_STAT_CD].desc);
 
 	/* RDY and BVD are active high by default */
-	if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio))
-		state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio);
-	if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio))
-		state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio);
-	if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio))
-		state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio);
+	if (skt->stat[SOC_STAT_RDY].desc)
+		state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
+	if (skt->stat[SOC_STAT_BVD1].desc)
+		state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
+	if (skt->stat[SOC_STAT_BVD2].desc)
+		state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
 
 	skt->ops->socket_state(skt, &state);
 
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 94762a54d731..ee40db16dc40 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -17,6 +17,7 @@ 
 
 
 struct device;
+struct gpio_desc;
 struct pcmcia_low_level;
 
 /*
@@ -52,6 +53,7 @@  struct soc_pcmcia_socket {
 
 	struct {
 		int		gpio;
+		struct gpio_desc *desc;
 		unsigned int	irq;
 		const char	*name;
 	} stat[4];
@@ -136,6 +138,7 @@  void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
 	struct pcmcia_low_level *ops, struct device *dev);
 void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
 int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
+int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt);
 
 
 #ifdef CONFIG_PCMCIA_DEBUG