]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
serial: sh-sci: Handle GPIO function requests.
authorPaul Mundt <lethal@linux-sh.org>
Fri, 2 Dec 2011 11:09:48 +0000 (20:09 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 2 Dec 2011 11:09:48 +0000 (20:09 +0900)
This adds initial support for requesting the various GPIO functions
necessary for certain ports. This just plugs in dumb request/free logic,
but serves as a building block for migrating off of the ->init_pins mess
to a wholly gpiolib backed solution (primarily parts with external
RTS/CTS pins, but will also allow us to clean up RXD pin testing).

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
drivers/tty/serial/sh-sci.c
include/linux/serial_sci.h

index 761a800cb4831973450ea30263807ebbdb87d0b8..9e62349b3d9f22cfeb59d2fcea49da4b068aac34 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
@@ -73,6 +74,7 @@ struct sci_port {
        struct clk              *fclk;
 
        char                    *irqstr[SCIx_NR_IRQS];
+       char                    *gpiostr[SCIx_NR_FNS];
 
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
@@ -1105,6 +1107,67 @@ static void sci_free_irq(struct sci_port *port)
        }
 }
 
+static const char *sci_gpio_names[SCIx_NR_FNS] = {
+       "sck", "rxd", "txd", "cts", "rts",
+};
+
+static const char *sci_gpio_str(unsigned int index)
+{
+       return sci_gpio_names[index];
+}
+
+static void __devinit sci_init_gpios(struct sci_port *port)
+{
+       struct uart_port *up = &port->port;
+       int i;
+
+       if (!port->cfg)
+               return;
+
+       for (i = 0; i < SCIx_NR_FNS; i++) {
+               const char *desc;
+               int ret;
+
+               if (!port->cfg->gpios[i])
+                       continue;
+
+               desc = sci_gpio_str(i);
+
+               port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s",
+                                            dev_name(up->dev), desc);
+
+               /*
+                * If we've failed the allocation, we can still continue
+                * on with a NULL string.
+                */
+               if (!port->gpiostr[i])
+                       dev_notice(up->dev, "%s string allocation failure\n",
+                                  desc);
+
+               ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]);
+               if (unlikely(ret != 0)) {
+                       dev_notice(up->dev, "failed %s gpio request\n", desc);
+
+                       /*
+                        * If we can't get the GPIO for whatever reason,
+                        * no point in keeping the verbose string around.
+                        */
+                       kfree(port->gpiostr[i]);
+               }
+       }
+}
+
+static void sci_free_gpios(struct sci_port *port)
+{
+       int i;
+
+       for (i = 0; i < SCIx_NR_FNS; i++)
+               if (port->cfg->gpios[i]) {
+                       gpio_free(port->cfg->gpios[i]);
+                       kfree(port->gpiostr[i]);
+               }
+}
+
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
        unsigned short status = sci_in(port, SCxSR);
@@ -1962,6 +2025,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
        struct uart_port *port = &sci_port->port;
        int ret;
 
+       sci_port->cfg   = p;
+
        port->ops       = &sci_uart_ops;
        port->iotype    = UPIO_MEM;
        port->line      = index;
@@ -2007,6 +2072,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
 
                port->dev = &dev->dev;
 
+               sci_init_gpios(sci_port);
+
                pm_runtime_irq_safe(&dev->dev);
                pm_runtime_enable(&dev->dev);
        }
@@ -2041,8 +2108,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
                p->error_mask |= (1 << p->overrun_bit);
        }
 
-       sci_port->cfg           = p;
-
        port->mapbase           = p->mapbase;
        port->type              = p->type;
        port->flags             = p->flags;
@@ -2249,6 +2314,8 @@ static int sci_remove(struct platform_device *dev)
        cpufreq_unregister_notifier(&port->freq_transition,
                                    CPUFREQ_TRANSITION_NOTIFIER);
 
+       sci_free_gpios(port);
+
        uart_remove_one_port(&sci_uart_driver, &port->port);
 
        clk_put(port->iclk);
index 15b1bdcaa9f52e55b8e81bed64da2e4ecbe4dd3b..78779074f6e8ff9b4f0d95fe9575e008eb0d1c81 100644 (file)
@@ -64,6 +64,17 @@ enum {
        SCIx_MUX_IRQ = SCIx_NR_IRQS,    /* special case */
 };
 
+/* Offsets into the sci_port->gpios array */
+enum {
+       SCIx_SCK,
+       SCIx_RXD,
+       SCIx_TXD,
+       SCIx_CTS,
+       SCIx_RTS,
+
+       SCIx_NR_FNS,
+};
+
 enum {
        SCIx_PROBE_REGTYPE,
 
@@ -123,6 +134,7 @@ struct plat_sci_port_ops {
 struct plat_sci_port {
        unsigned long   mapbase;                /* resource base */
        unsigned int    irqs[SCIx_NR_IRQS];     /* ERI, RXI, TXI, BRI */
+       unsigned int    gpios[SCIx_NR_FNS];     /* SCK, RXD, TXD, CTS, RTS */
        unsigned int    type;                   /* SCI / SCIF / IRDA */
        upf_t           flags;                  /* UPF_* flags */
        unsigned long   capabilities;           /* Port features/capabilities */