[PATCH/RFC] CPM1: implement GPIO API
Jochen Friedrich
jochen at scram.de
Thu Dec 13 03:42:06 EST 2007
This is based on [PATCH RFC 3/7] [POWERPC] CPM2: implement GPIO API.
Signed-off-by: Jochen Friedrich <jochen at scram.de>
---
arch/powerpc/platforms/8xx/Kconfig | 1 +
arch/powerpc/sysdev/commproc.c | 199 +++++++++++++++++++++++++++++++++++-
2 files changed, 199 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index bd28655..4dc4d0c 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -4,6 +4,7 @@ config FADS
config CPM1
bool
select CPM
+ select GENERIC_GPIO
choice
prompt "8xx Machine Type"
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
index f6a6378..219cb4f 100644
--- a/arch/powerpc/sysdev/commproc.c
+++ b/arch/powerpc/sysdev/commproc.c
@@ -27,6 +27,7 @@
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -36,6 +37,7 @@
#include <asm/8xx_immap.h>
#include <asm/commproc.h>
#include <asm/io.h>
+#include <asm/gpio.h>
#include <asm/tlbflush.h>
#include <asm/rheap.h>
#include <asm/prom.h>
@@ -56,6 +58,57 @@ static cpic8xx_t __iomem *cpic_reg;
static struct irq_host *cpm_pic_host;
+static spinlock_t *cpm1_port_locks;
+static int cpm1_num_ports;
+
+static int par_io_xlate(struct device_node *np, int index)
+{
+ return __of_parse_gpio_bank_pin(np, index, 32, cpm1_num_ports);
+}
+
+static struct of_gpio_chip of_gpio_chip = {
+ .xlate = par_io_xlate,
+};
+
+int cpm_init_par_io(void)
+{
+ int ret;
+ struct device_node *np;
+ const u32 *num_ports;
+ int i;
+
+ np = of_find_node_by_name(NULL, "par_io");
+ if (!np) {
+ ret = -ENOENT;
+ goto err0;
+ }
+
+ num_ports = of_get_property(np, "num-ports", NULL);
+ if (!num_ports) {
+ ret = -ENOENT;
+ goto err1;
+ }
+
+ cpm1_num_ports = *num_ports;
+ cpm1_port_locks = kzalloc(sizeof(*cpm1_port_locks) * cpm1_num_ports,
+ GFP_KERNEL);
+ if (!cpm1_port_locks) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ for (i = 0; i < cpm1_num_ports; i++)
+ spin_lock_init(&cpm1_port_locks[i]);
+
+ np->data = &of_gpio_chip;
+
+ return 0;
+err1:
+ of_node_put(np);
+err0:
+ return ret;
+}
+
static void cpm_mask_irq(unsigned int irq)
{
unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
@@ -199,6 +252,7 @@ end:
void __init cpm_reset(void)
{
sysconf8xx_t __iomem *siu_conf;
+ int ret;
mpc8xx_immr = ioremap(get_immrbase(), 0x4000);
if (!mpc8xx_immr) {
@@ -238,6 +292,10 @@ void __init cpm_reset(void)
/* Reclaim the DP memory for our use. */
m8xx_cpm_dpinit();
#endif
+
+ ret = cpm_init_par_io();
+ if (ret)
+ pr_warning("CPM PIO not initialized!\n");
}
/* We used to do this earlier, but have to postpone as long as possible
@@ -413,7 +471,7 @@ struct cpm_ioport16 {
};
struct cpm_ioport32 {
- __be32 dir, par, sor;
+ __be32 dir, par, sor, dat;
};
static void cpm1_set_pin32(int port, int pin, int flags)
@@ -451,6 +509,39 @@ static void cpm1_set_pin32(int port, int pin, int flags)
}
}
+static void cpm1_set_value32(int port, int pin, int value)
+{
+ struct cpm_ioport32 __iomem *iop;
+ pin = 1 << (31 - pin);
+
+ if (port == CPM_PORTB)
+ iop = (struct cpm_ioport32 __iomem *)
+ &mpc8xx_immr->im_cpm.cp_pbdir;
+ else
+ iop = (struct cpm_ioport32 __iomem *)
+ &mpc8xx_immr->im_cpm.cp_pedir;
+
+ if (value)
+ setbits32(&iop->dat, pin);
+ else
+ clrbits32(&iop->dat, pin);
+}
+
+static int cpm1_get_value32(int port, int pin)
+{
+ struct cpm_ioport32 __iomem *iop;
+ pin = 1 << (31 - pin);
+
+ if (port == CPM_PORTB)
+ iop = (struct cpm_ioport32 __iomem *)
+ &mpc8xx_immr->im_cpm.cp_pbdir;
+ else
+ iop = (struct cpm_ioport32 __iomem *)
+ &mpc8xx_immr->im_cpm.cp_pedir;
+
+ return !!(in_be32(&iop->dat) & pin);
+}
+
static void cpm1_set_pin16(int port, int pin, int flags)
{
struct cpm_ioport16 __iomem *iop =
@@ -479,6 +570,35 @@ static void cpm1_set_pin16(int port, int pin, int flags)
}
}
+static void cpm1_set_value16(int port, int pin, int value)
+{
+ struct cpm_ioport16 __iomem *iop =
+ (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport;
+
+ pin = 1 << (15 - pin);
+
+ if (port != 0)
+ iop += port - 1;
+
+ if (value)
+ setbits16(&iop->dat, pin);
+ else
+ clrbits16(&iop->dat, pin);
+}
+
+static int cpm1_get_value16(int port, int pin)
+{
+ struct cpm_ioport16 __iomem *iop =
+ (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport;
+
+ pin = 1 << (15 - pin);
+
+ if (port != 0)
+ iop += port - 1;
+
+ return !!(in_be16(&iop->dat) & pin);
+}
+
void cpm1_set_pin(enum cpm_port port, int pin, int flags)
{
if (port == CPM_PORTB || port == CPM_PORTE)
@@ -607,3 +727,80 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
return 0;
}
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+ if (!cpm1_port_locks)
+ return -ENODEV;
+
+ if (gpio / 32 > cpm1_num_ports)
+ return -EINVAL;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_request);
+
+int gpio_direction_input(unsigned int gpio)
+{
+ unsigned long flags;
+ int port = gpio / 32;
+ int pin = gpio % 32;
+
+ spin_lock_irqsave(&cpm1_port_locks[port], flags);
+
+ cpm1_set_pin(port, pin, CPM_PIN_INPUT | CPM_PIN_GPIO);
+
+ spin_unlock_irqrestore(&cpm1_port_locks[port], flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio, int value)
+{
+ int port = gpio / 32;
+ int pin = gpio % 32;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cpm1_port_locks[port], flags);
+
+ cpm1_set_pin(port, pin, CPM_PIN_OUTPUT | CPM_PIN_GPIO);
+
+ if (port == CPM_PORTB || port == CPM_PORTE)
+ cpm1_set_value32(port, pin, value);
+ else
+ cpm1_set_value16(port, pin, value);
+
+ spin_unlock_irqrestore(&cpm1_port_locks[port], flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+ int port = gpio / 32;
+ int pin = gpio % 32;
+
+ if (port == CPM_PORTB || port == CPM_PORTE)
+ return cpm1_get_value32(port, pin);
+ else
+ return cpm1_get_value16(port, pin);
+}
+EXPORT_SYMBOL_GPL(gpio_get_value);
+
+int gpio_set_value(unsigned int gpio, int value)
+{
+ int port = gpio / 32;
+ int pin = gpio % 32;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cpm1_port_locks[port], flags);
+
+ if (port == CPM_PORTB || port == CPM_PORTE)
+ cpm1_set_value32(port, pin, value);
+ else
+ cpm1_set_value16(port, pin, value);
+
+ spin_unlock_irqrestore(&cpm1_port_locks[port], flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_set_value);
--
1.5.3.7
More information about the Linuxppc-dev
mailing list