Skip to content

Commit

Permalink
serial: sh-sci: Handle GPIO function requests.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paul Mundt committed Dec 2, 2011
1 parent 73c3d53 commit 50f0959
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
71 changes: 69 additions & 2 deletions drivers/tty/serial/sh-sci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions include/linux/serial_sci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 50f0959

Please sign in to comment.