summaryrefslogtreecommitdiff
path: root/drivers/pinctrl
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/core.c2
-rw-r--r--drivers/pinctrl/pinctrl-imx.c32
-rw-r--r--drivers/pinctrl/pinctrl-imx6q.c2
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c13
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c27
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c491
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1310.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1340.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear300.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear310.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear320.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.h2
15 files changed, 556 insertions, 39 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index c3b331b74fa0..0cc053af70bd 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -61,7 +61,7 @@ static LIST_HEAD(pinctrl_maps);
list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
_i_ < _maps_node_->num_maps; \
- i++, _map_ = &_maps_node_->maps[_i_])
+ _i_++, _map_ = &_maps_node_->maps[_i_])
/**
* pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index f6e7c670906c..90c837f469a6 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -27,16 +27,16 @@
#include "core.h"
#include "pinctrl-imx.h"
-#define IMX_PMX_DUMP(info, p, m, c, n) \
-{ \
- int i, j; \
- printk("Format: Pin Mux Config\n"); \
- for (i = 0; i < n; i++) { \
- j = p[i]; \
- printk("%s %d 0x%lx\n", \
- info->pins[j].name, \
- m[i], c[i]); \
- } \
+#define IMX_PMX_DUMP(info, p, m, c, n) \
+{ \
+ int i, j; \
+ printk(KERN_DEBUG "Format: Pin Mux Config\n"); \
+ for (i = 0; i < n; i++) { \
+ j = p[i]; \
+ printk(KERN_DEBUG "%s %d 0x%lx\n", \
+ info->pins[j].name, \
+ m[i], c[i]); \
+ } \
}
/* The bits in CONFIG cell defined in binding doc*/
@@ -173,8 +173,10 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
/* create mux map */
parent = of_get_parent(np);
- if (!parent)
+ if (!parent) {
+ kfree(new_map);
return -EINVAL;
+ }
new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
new_map[0].data.mux.function = parent->name;
new_map[0].data.mux.group = np->name;
@@ -193,7 +195,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
}
dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
- new_map->data.mux.function, new_map->data.mux.group, map_num);
+ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
return 0;
}
@@ -201,10 +203,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
static void imx_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
- int i;
-
- for (i = 0; i < num_maps; i++)
- kfree(map);
+ kfree(map);
}
static struct pinctrl_ops imx_pctrl_ops = {
@@ -478,6 +477,7 @@ static int __devinit imx_pinctrl_parse_groups(struct device_node *np,
#ifdef DEBUG
IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins);
#endif
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c
index 7737d4d71a3c..e9bf71fbedca 100644
--- a/drivers/pinctrl/pinctrl-imx6q.c
+++ b/drivers/pinctrl/pinctrl-imx6q.c
@@ -1950,6 +1950,8 @@ static struct imx_pin_reg imx6q_pin_regs[] = {
IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__GPIO_1_12 */
IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__SJC_DONE */
IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 */
+ IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 0, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID */
+ IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_1__ANATOP_USBOTG_ID */
};
/* Pad names for the pinmux subsystem */
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
index 556e45a213eb..4ba4636b6a4a 100644
--- a/drivers/pinctrl/pinctrl-mxs.c
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -107,8 +107,10 @@ static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev,
/* Compose group name */
group = kzalloc(length, GFP_KERNEL);
- if (!group)
- return -ENOMEM;
+ if (!group) {
+ ret = -ENOMEM;
+ goto free;
+ }
snprintf(group, length, "%s.%d", np->name, reg);
new_map[i].data.mux.group = group;
i++;
@@ -118,7 +120,7 @@ static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev,
pconfig = kmemdup(&config, sizeof(config), GFP_KERNEL);
if (!pconfig) {
ret = -ENOMEM;
- goto free;
+ goto free_group;
}
new_map[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
@@ -133,6 +135,9 @@ static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
+free_group:
+ if (!purecfg)
+ kfree(group);
free:
kfree(new_map);
return ret;
@@ -511,6 +516,7 @@ int __devinit mxs_pinctrl_probe(struct platform_device *pdev,
return 0;
err:
+ platform_set_drvdata(pdev, NULL);
iounmap(d->base);
return ret;
}
@@ -520,6 +526,7 @@ int __devexit mxs_pinctrl_remove(struct platform_device *pdev)
{
struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
pinctrl_unregister(d->pctl);
iounmap(d->base);
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index b26395d16347..dd9e6f26416d 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -673,7 +673,7 @@ static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
* wakeup is anyhow controlled by the RIMSC and FIMSC registers.
*/
if (nmk_chip->sleepmode && on) {
- __nmk_gpio_set_slpm(nmk_chip, gpio % nmk_chip->chip.base,
+ __nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP,
NMK_GPIO_SLPM_WAKEUP_ENABLE);
}
@@ -1198,7 +1198,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
if (!pdata)
return -ENOMEM;
- if (of_get_property(np, "supports-sleepmode", NULL))
+ if (of_get_property(np, "st,supports-sleepmode", NULL))
pdata->supports_sleepmode = true;
if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
@@ -1246,6 +1246,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
ret = PTR_ERR(clk);
goto out_unmap;
}
+ clk_prepare(clk);
nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
if (!nmk_chip) {
@@ -1437,7 +1438,27 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins);
- /* Handle this special glitch on altfunction C */
+ /*
+ * If we're setting altfunc C by setting both AFSLA and AFSLB to 1,
+ * we may pass through an undesired state. In this case we take
+ * some extra care.
+ *
+ * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
+ * - Save SLPM registers (since we have a shadow register in the
+ * nmk_chip we're using that as backup)
+ * - Set SLPM=0 for the IOs you want to switch and others to 1
+ * - Configure the GPIO registers for the IOs that are being switched
+ * - Set IOFORCE=1
+ * - Modify the AFLSA/B registers for the IOs that are being switched
+ * - Set IOFORCE=0
+ * - Restore SLPM registers
+ * - Any spurious wake up event during switch sequence to be ignored
+ * and cleared
+ *
+ * We REALLY need to save ALL slpm registers, because the external
+ * IOFORCE will switch *all* ports to their sleepmode setting to as
+ * to avoid glitches. (Not just one port!)
+ */
glitch = (g->altsetting == NMK_GPIO_ALT_C);
if (glitch) {
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index ba15b1a29e52..2aae8a8978e9 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -8,24 +8,61 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/irqdomain.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#define DRIVER_NAME "pinmux-sirf"
#define SIRFSOC_NUM_PADS 622
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
#define SIRFSOC_RSC_PIN_MUX 0x4
+#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4)
+#define SIRFSOC_GPIO_DSP_EN0 (0x80)
+#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C)
+
+#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1
+#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK 0x2
+#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK 0x4
+#define SIRFSOC_GPIO_CTL_INTR_EN_MASK 0x8
+#define SIRFSOC_GPIO_CTL_INTR_STS_MASK 0x10
+#define SIRFSOC_GPIO_CTL_OUT_EN_MASK 0x20
+#define SIRFSOC_GPIO_CTL_DATAOUT_MASK 0x40
+#define SIRFSOC_GPIO_CTL_DATAIN_MASK 0x80
+#define SIRFSOC_GPIO_CTL_PULL_MASK 0x100
+#define SIRFSOC_GPIO_CTL_PULL_HIGH 0x200
+#define SIRFSOC_GPIO_CTL_DSP_INT 0x400
+
+#define SIRFSOC_GPIO_NO_OF_BANKS 5
+#define SIRFSOC_GPIO_BANK_SIZE 32
+#define SIRFSOC_GPIO_NUM(bank, index) (((bank)*(32)) + (index))
+
+struct sirfsoc_gpio_bank {
+ struct of_mm_gpio_chip chip;
+ struct irq_domain *domain;
+ int id;
+ int parent_irq;
+ spinlock_t lock;
+};
+
+static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
+static DEFINE_SPINLOCK(sgpio_lock);
+
/*
* pad list for the pinmux subsystem
* refer to CS-131858-DC-6A.xls
@@ -1184,7 +1221,7 @@ out_no_gpio_remap:
return ret;
}
-static const struct of_device_id pinmux_ids[] = {
+static const struct of_device_id pinmux_ids[] __devinitconst = {
{ .compatible = "sirf,prima2-gpio-pinmux" },
{}
};
@@ -1204,7 +1241,457 @@ static int __init sirfsoc_pinmux_init(void)
}
arch_initcall(sirfsoc_pinmux_init);
+static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip),
+ struct sirfsoc_gpio_bank, chip);
+
+ return irq_find_mapping(bank->domain, offset);
+}
+
+static inline int sirfsoc_gpio_to_offset(unsigned int gpio)
+{
+ return gpio % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio)
+{
+ return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE];
+}
+
+void sirfsoc_gpio_set_pull(unsigned gpio, unsigned mode)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(gpio);
+ int idx = sirfsoc_gpio_to_offset(gpio);
+ u32 val, offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ val = readl(bank->chip.regs + offset);
+
+ switch (mode) {
+ case SIRFSOC_GPIO_PULL_NONE:
+ val &= ~SIRFSOC_GPIO_CTL_PULL_MASK;
+ break;
+ case SIRFSOC_GPIO_PULL_UP:
+ val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+ val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
+ break;
+ case SIRFSOC_GPIO_PULL_DOWN:
+ val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+ val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
+ break;
+ default:
+ break;
+ }
+
+ writel(val, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+EXPORT_SYMBOL(sirfsoc_gpio_set_pull);
+
+static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip)
+{
+ return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip);
+}
+
+static void sirfsoc_gpio_irq_ack(struct irq_data *d)
+{
+ struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+ u32 val, offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ val = readl(bank->chip.regs + offset);
+
+ writel(val, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx)
+{
+ u32 val, offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ val = readl(bank->chip.regs + offset);
+ val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+ val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+ writel(val, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static void sirfsoc_gpio_irq_mask(struct irq_data *d)
+{
+ struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
+}
+
+static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
+{
+ struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+ u32 val, offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ val = readl(bank->chip.regs + offset);
+ val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+ val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+ writel(val, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+ u32 val, offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ val = readl(bank->chip.regs + offset);
+ val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+ val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+ val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK |
+ SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+ val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+ val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+ break;
+ }
+
+ writel(val, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+
+ return 0;
+}
+
+static struct irq_chip sirfsoc_irq_chip = {
+ .name = "sirf-gpio-irq",
+ .irq_ack = sirfsoc_gpio_irq_ack,
+ .irq_mask = sirfsoc_gpio_irq_mask,
+ .irq_unmask = sirfsoc_gpio_irq_unmask,
+ .irq_set_type = sirfsoc_gpio_irq_type,
+};
+
+static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq);
+ u32 status, ctrl;
+ int idx = 0;
+ unsigned int first_irq;
+
+ status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id));
+ if (!status) {
+ printk(KERN_WARNING
+ "%s: gpio id %d status %#x no interrupt is flaged\n",
+ __func__, bank->id, status);
+ handle_bad_irq(irq, desc);
+ return;
+ }
+
+ first_irq = bank->domain->revmap_data.legacy.first_irq;
+
+ while (status) {
+ ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx));
+
+ /*
+ * Here we must check whether the corresponding GPIO's interrupt
+ * has been enabled, otherwise just skip it
+ */
+ if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
+ pr_debug("%s: gpio id %d idx %d happens\n",
+ __func__, bank->id, idx);
+ generic_handle_irq(first_irq + idx);
+ }
+
+ idx++;
+ status = status >> 1;
+ }
+}
+
+static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl(bank->chip.regs + ctrl_offset);
+ val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+ writel(val, bank->chip.regs + ctrl_offset);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ unsigned long flags;
+
+ if (pinctrl_request_gpio(chip->base + offset))
+ return -ENODEV;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ /*
+ * default status:
+ * set direction as input and mask irq
+ */
+ sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
+ __sirfsoc_gpio_irq_mask(bank, offset);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ return 0;
+}
+
+static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ __sirfsoc_gpio_irq_mask(bank, offset);
+ sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ int idx = sirfsoc_gpio_to_offset(gpio);
+ unsigned long flags;
+ unsigned offset;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ sirfsoc_gpio_set_input(bank, offset);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ return 0;
+}
+
+static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset,
+ int value)
+{
+ u32 out_ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ out_ctrl = readl(bank->chip.regs + offset);
+ if (value)
+ out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+ else
+ out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+
+ out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+ out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+ writel(out_ctrl, bank->chip.regs + offset);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ int idx = sirfsoc_gpio_to_offset(gpio);
+ u32 offset;
+ unsigned long flags;
+
+ offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+
+ sirfsoc_gpio_set_output(bank, offset, value);
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+
+ return 0;
+}
+
+static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK);
+}
+
+static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+ u32 ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+ if (value)
+ ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+ else
+ ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+ writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct sirfsoc_gpio_bank *bank = d->host_data;
+
+ if (!bank)
+ return -EINVAL;
+
+ irq_set_chip(irq, &sirfsoc_irq_chip);
+ irq_set_handler(irq, handle_level_irq);
+ irq_set_chip_data(irq, bank);
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
+ .map = sirfsoc_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int __devinit sirfsoc_gpio_probe(struct device_node *np)
+{
+ int i, err = 0;
+ struct sirfsoc_gpio_bank *bank;
+ void *regs;
+ struct platform_device *pdev;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ return -ENODEV;
+
+ regs = of_iomap(np, 0);
+ if (!regs)
+ return -ENOMEM;
+
+ for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+ bank = &sgpio_bank[i];
+ spin_lock_init(&bank->lock);
+ bank->chip.gc.request = sirfsoc_gpio_request;
+ bank->chip.gc.free = sirfsoc_gpio_free;
+ bank->chip.gc.direction_input = sirfsoc_gpio_direction_input;
+ bank->chip.gc.get = sirfsoc_gpio_get_value;
+ bank->chip.gc.direction_output = sirfsoc_gpio_direction_output;
+ bank->chip.gc.set = sirfsoc_gpio_set_value;
+ bank->chip.gc.to_irq = sirfsoc_gpio_to_irq;
+ bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE;
+ bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
+ bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
+ bank->chip.gc.of_node = np;
+ bank->chip.regs = regs;
+ bank->id = i;
+ bank->parent_irq = platform_get_irq(pdev, i);
+ if (bank->parent_irq < 0) {
+ err = bank->parent_irq;
+ goto out;
+ }
+
+ err = gpiochip_add(&bank->chip.gc);
+ if (err) {
+ pr_err("%s: error in probe function with status %d\n",
+ np->full_name, err);
+ goto out;
+ }
+
+ bank->domain = irq_domain_add_legacy(np, SIRFSOC_GPIO_BANK_SIZE,
+ SIRFSOC_GPIO_IRQ_START + i * SIRFSOC_GPIO_BANK_SIZE, 0,
+ &sirfsoc_gpio_irq_simple_ops, bank);
+
+ if (!bank->domain) {
+ pr_err("%s: Failed to create irqdomain\n", np->full_name);
+ err = -ENOSYS;
+ goto out;
+ }
+
+ irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq);
+ irq_set_handler_data(bank->parent_irq, bank);
+ }
+
+out:
+ iounmap(regs);
+ return err;
+}
+
+static int __init sirfsoc_gpio_init(void)
+{
+
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, pinmux_ids);
+
+ if (!np)
+ return -ENODEV;
+
+ return sirfsoc_gpio_probe(np);
+}
+subsys_initcall(sirfsoc_gpio_init);
+
MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
+ "Yuping Luo <yuping.luo@csr.com>, "
"Barry Song <baohua.song@csr.com>");
MODULE_DESCRIPTION("SIRFSOC pin control driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index 5ae50aadf885..b3f6b2873fdd 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* Inspired from:
* - U300 Pinctl drivers
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
index 9155783bb47f..d950eb78d939 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.h
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -2,7 +2,7 @@
* Driver header file for the ST Microelectronics SPEAr pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c
index fff168be7f00..d6cca8c81b92 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1310.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr1310 pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -2192,7 +2192,7 @@ static void __exit spear1310_pinctrl_exit(void)
}
module_exit(spear1310_pinctrl_exit);
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
MODULE_DESCRIPTION("ST Microelectronics SPEAr1310 pinctrl driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, spear1310_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c
index a8ab2a6f51bf..a0eb057e55bd 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1340.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1340.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr1340 pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -1983,7 +1983,7 @@ static void __exit spear1340_pinctrl_exit(void)
}
module_exit(spear1340_pinctrl_exit);
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
MODULE_DESCRIPTION("ST Microelectronics SPEAr1340 pinctrl driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, spear1340_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
index 9c82a35e4e78..4dfc2849b172 100644
--- a/drivers/pinctrl/spear/pinctrl-spear300.c
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr300 pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -702,7 +702,7 @@ static void __exit spear300_pinctrl_exit(void)
}
module_exit(spear300_pinctrl_exit);
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
index 1a9707605125..96883693fb7e 100644
--- a/drivers/pinctrl/spear/pinctrl-spear310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr310 pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -425,7 +425,7 @@ static void __exit spear310_pinctrl_exit(void)
}
module_exit(spear310_pinctrl_exit);
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
index de726e6c283a..020b1e0bdb3e 100644
--- a/drivers/pinctrl/spear/pinctrl-spear320.c
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr320 pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -3462,7 +3462,7 @@ static void __exit spear320_pinctrl_exit(void)
}
module_exit(spear320_pinctrl_exit);
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
index 91c883bc46a6..0242378f7cb8 100644
--- a/drivers/pinctrl/spear/pinctrl-spear3xx.c
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -2,7 +2,7 @@
* Driver for the ST Microelectronics SPEAr3xx pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.h b/drivers/pinctrl/spear/pinctrl-spear3xx.h
index 5d5fdd8df7b8..31f44347f17c 100644
--- a/drivers/pinctrl/spear/pinctrl-spear3xx.h
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.h
@@ -2,7 +2,7 @@
* Header file for the ST Microelectronics SPEAr3xx pinmux
*
* Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.kumar@st.com>
+ * Viresh Kumar <viresh.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any