]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pinctrl/pinctrl-nomadik.c
Merge remote-tracking branch 'gpio/for-next'
[karo-tx-linux.git] / drivers / pinctrl / pinctrl-nomadik.c
index 4a1cfdce22320aed2ad1579c61c30a7dbc955003..7111c3b591303cec2f3daa36d22329989c0847b9 100644 (file)
@@ -337,97 +337,6 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
        nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit));
 }
 
-static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
-                            pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
-{
-       static const char *afnames[] = {
-               [NMK_GPIO_ALT_GPIO]     = "GPIO",
-               [NMK_GPIO_ALT_A]        = "A",
-               [NMK_GPIO_ALT_B]        = "B",
-               [NMK_GPIO_ALT_C]        = "C"
-       };
-       static const char *pullnames[] = {
-               [NMK_GPIO_PULL_NONE]    = "none",
-               [NMK_GPIO_PULL_UP]      = "up",
-               [NMK_GPIO_PULL_DOWN]    = "down",
-               [3] /* illegal */       = "??"
-       };
-       static const char *slpmnames[] = {
-               [NMK_GPIO_SLPM_INPUT]           = "input/wakeup",
-               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change/no-wakeup",
-       };
-
-       int pin = PIN_NUM(cfg);
-       int pull = PIN_PULL(cfg);
-       int af = PIN_ALT(cfg);
-       int slpm = PIN_SLPM(cfg);
-       int output = PIN_DIR(cfg);
-       int val = PIN_VAL(cfg);
-       bool glitch = af == NMK_GPIO_ALT_C;
-
-       dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
-               pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
-               output ? "output " : "input",
-               output ? (val ? "high" : "low") : "");
-
-       if (sleep) {
-               int slpm_pull = PIN_SLPM_PULL(cfg);
-               int slpm_output = PIN_SLPM_DIR(cfg);
-               int slpm_val = PIN_SLPM_VAL(cfg);
-
-               af = NMK_GPIO_ALT_GPIO;
-
-               /*
-                * The SLPM_* values are normal values + 1 to allow zero to
-                * mean "same as normal".
-                */
-               if (slpm_pull)
-                       pull = slpm_pull - 1;
-               if (slpm_output)
-                       output = slpm_output - 1;
-               if (slpm_val)
-                       val = slpm_val - 1;
-
-               dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
-                       pin,
-                       slpm_pull ? pullnames[pull] : "same",
-                       slpm_output ? (output ? "output" : "input") : "same",
-                       slpm_val ? (val ? "high" : "low") : "same");
-       }
-
-       if (output)
-               __nmk_gpio_make_output(nmk_chip, offset, val);
-       else {
-               __nmk_gpio_make_input(nmk_chip, offset);
-               __nmk_gpio_set_pull(nmk_chip, offset, pull);
-       }
-
-       __nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg));
-
-       /*
-        * If the pin is switching to altfunc, and there was an interrupt
-        * installed on it which has been lazy disabled, actually mask the
-        * interrupt to prevent spurious interrupts that would occur while the
-        * pin is under control of the peripheral.  Only SKE does this.
-        */
-       if (af != NMK_GPIO_ALT_GPIO)
-               nmk_gpio_disable_lazy_irq(nmk_chip, offset);
-
-       /*
-        * If we've backed up the SLPM registers (glitch workaround), modify
-        * the backups since they will be restored.
-        */
-       if (slpmregs) {
-               if (slpm == NMK_GPIO_SLPM_NOCHANGE)
-                       slpmregs[nmk_chip->bank] |= BIT(offset);
-               else
-                       slpmregs[nmk_chip->bank] &= ~BIT(offset);
-       } else
-               __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
-
-       __nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
-}
-
 /*
  * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
  *  - Save SLPM registers
@@ -474,210 +383,6 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
        }
 }
 
-static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
-{
-       static unsigned int slpm[NUM_BANKS];
-       unsigned long flags;
-       bool glitch = false;
-       int ret = 0;
-       int i;
-
-       for (i = 0; i < num; i++) {
-               if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
-                       glitch = true;
-                       break;
-               }
-       }
-
-       spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-
-       if (glitch) {
-               memset(slpm, 0xff, sizeof(slpm));
-
-               for (i = 0; i < num; i++) {
-                       int pin = PIN_NUM(cfgs[i]);
-                       int offset = pin % NMK_GPIO_PER_CHIP;
-
-                       if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
-                               slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
-               }
-
-               nmk_gpio_glitch_slpm_init(slpm);
-       }
-
-       for (i = 0; i < num; i++) {
-               struct nmk_gpio_chip *nmk_chip;
-               int pin = PIN_NUM(cfgs[i]);
-
-               nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP];
-               if (!nmk_chip) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               clk_enable(nmk_chip->clk);
-               spin_lock(&nmk_chip->lock);
-               __nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP,
-                                cfgs[i], sleep, glitch ? slpm : NULL);
-               spin_unlock(&nmk_chip->lock);
-               clk_disable(nmk_chip->clk);
-       }
-
-       if (glitch)
-               nmk_gpio_glitch_slpm_restore(slpm);
-
-       spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-
-       return ret;
-}
-
-/**
- * nmk_config_pin - configure a pin's mux attributes
- * @cfg: pin confguration
- * @sleep: Non-zero to apply the sleep mode configuration
- * Configures a pin's mode (alternate function or GPIO), its pull up status,
- * and its sleep mode based on the specified configuration.  The @cfg is
- * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
- * are constructed using, and can be further enhanced with, the macros in
- * <linux/platform_data/pinctrl-nomadik.h>
- *
- * If a pin's mode is set to GPIO, it is configured as an input to avoid
- * side-effects.  The gpio can be manipulated later using standard GPIO API
- * calls.
- */
-int nmk_config_pin(pin_cfg_t cfg, bool sleep)
-{
-       return __nmk_config_pins(&cfg, 1, sleep);
-}
-EXPORT_SYMBOL(nmk_config_pin);
-
-/**
- * nmk_config_pins - configure several pins at once
- * @cfgs: array of pin configurations
- * @num: number of elments in the array
- *
- * Configures several pins using nmk_config_pin().  Refer to that function for
- * further information.
- */
-int nmk_config_pins(pin_cfg_t *cfgs, int num)
-{
-       return __nmk_config_pins(cfgs, num, false);
-}
-EXPORT_SYMBOL(nmk_config_pins);
-
-int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
-{
-       return __nmk_config_pins(cfgs, num, true);
-}
-EXPORT_SYMBOL(nmk_config_pins_sleep);
-
-/**
- * nmk_gpio_set_slpm() - configure the sleep mode of a pin
- * @gpio: pin number
- * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
- *
- * This register is actually in the pinmux layer, not the GPIO block itself.
- * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
- * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
- * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
- * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
- * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
- * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
- *
- * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
- * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
- * entered) regardless of the altfunction selected. Also wake-up detection is
- * ENABLED.
- *
- * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
- * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
- * (for altfunction GPIO) or respective on-chip peripherals (for other
- * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
- *
- * Note that enable_irq_wake() will automatically enable wakeup detection.
- */
-int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
-{
-       struct nmk_gpio_chip *nmk_chip;
-       unsigned long flags;
-
-       nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-       if (!nmk_chip)
-               return -EINVAL;
-
-       clk_enable(nmk_chip->clk);
-       spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-       spin_lock(&nmk_chip->lock);
-
-       __nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode);
-
-       spin_unlock(&nmk_chip->lock);
-       spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-       clk_disable(nmk_chip->clk);
-
-       return 0;
-}
-
-/**
- * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
- * @gpio: pin number
- * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
- *
- * Enables/disables pull up/down on a specified pin.  This only takes effect if
- * the pin is configured as an input (either explicitly or by the alternate
- * function).
- *
- * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
- * configured as an input.  Otherwise, due to the way the controller registers
- * work, this function will change the value output on the pin.
- */
-int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
-{
-       struct nmk_gpio_chip *nmk_chip;
-       unsigned long flags;
-
-       nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-       if (!nmk_chip)
-               return -EINVAL;
-
-       clk_enable(nmk_chip->clk);
-       spin_lock_irqsave(&nmk_chip->lock, flags);
-       __nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull);
-       spin_unlock_irqrestore(&nmk_chip->lock, flags);
-       clk_disable(nmk_chip->clk);
-
-       return 0;
-}
-
-/* Mode functions */
-/**
- * nmk_gpio_set_mode() - set the mux mode of a gpio pin
- * @gpio: pin number
- * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
- *            NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
- *
- * Sets the mode of the specified pin to one of the alternate functions or
- * plain GPIO.
- */
-int nmk_gpio_set_mode(int gpio, int gpio_mode)
-{
-       struct nmk_gpio_chip *nmk_chip;
-       unsigned long flags;
-
-       nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-       if (!nmk_chip)
-               return -EINVAL;
-
-       clk_enable(nmk_chip->clk);
-       spin_lock_irqsave(&nmk_chip->lock, flags);
-       __nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode);
-       spin_unlock_irqrestore(&nmk_chip->lock, flags);
-       clk_disable(nmk_chip->clk);
-
-       return 0;
-}
-EXPORT_SYMBOL(nmk_gpio_set_mode);
-
 static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
 {
        int i;
@@ -929,6 +634,10 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
 {
        struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
 
+       if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq))
+               dev_err(nmk_chip->chip.dev,
+                       "unable to lock HW IRQ %lu for IRQ\n",
+                       d->hwirq);
        clk_enable(nmk_chip->clk);
        nmk_gpio_irq_unmask(d);
        return 0;
@@ -940,6 +649,7 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d)
 
        nmk_gpio_irq_mask(d);
        clk_disable(nmk_chip->clk);
+       gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq);
 }
 
 static struct irq_chip nmk_gpio_irq_chip = {
@@ -1350,10 +1060,6 @@ static int nmk_gpio_probe(struct platform_device *dev)
                pdata->num_gpio   = NMK_GPIO_PER_CHIP;
        }
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
        irq = platform_get_irq(dev, 0);
        if (irq < 0)
                return irq;
@@ -1362,6 +1068,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
        if (secondary_irq >= 0 && !pdata->get_secondary_status)
                return -EINVAL;
 
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&dev->dev, res);
        if (IS_ERR(base))
                return PTR_ERR(base);
@@ -1807,7 +1514,7 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
        struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
        const struct nmk_pingroup *g;
        static unsigned int slpm[NUM_BANKS];
-       unsigned long flags;
+       unsigned long flags = 0;
        bool glitch;
        int ret = -EINVAL;
        int i;
@@ -1993,7 +1700,7 @@ static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
 }
 
 static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
-                             unsigned long config)
+                             unsigned long *configs, unsigned num_configs)
 {
        static const char *pullnames[] = {
                [NMK_GPIO_PULL_NONE]    = "none",
@@ -2010,20 +1717,9 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct pinctrl_gpio_range *range;
        struct gpio_chip *chip;
        unsigned bit;
-
-       /*
-        * The pin config contains pin number and altfunction fields, here
-        * we just ignore that part. It's being handled by the framework and
-        * pinmux callback respectively.
-        */
-       pin_cfg_t cfg = (pin_cfg_t) config;
-       int pull = PIN_PULL(cfg);
-       int slpm = PIN_SLPM(cfg);
-       int output = PIN_DIR(cfg);
-       int val = PIN_VAL(cfg);
-       bool lowemi = PIN_LOWEMI(cfg);
-       bool gpiomode = PIN_GPIOMODE(cfg);
-       bool sleep = PIN_SLEEPMODE(cfg);
+       pin_cfg_t cfg;
+       int pull, slpm, output, val, i;
+       bool lowemi, gpiomode, sleep;
 
        range = nmk_match_gpio_range(pctldev, pin);
        if (!range) {
@@ -2038,54 +1734,74 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        chip = range->gc;
        nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
 
-       if (sleep) {
-               int slpm_pull = PIN_SLPM_PULL(cfg);
-               int slpm_output = PIN_SLPM_DIR(cfg);
-               int slpm_val = PIN_SLPM_VAL(cfg);
-
-               /* All pins go into GPIO mode at sleep */
-               gpiomode = true;
-
+       for (i = 0; i < num_configs; i++) {
                /*
-                * The SLPM_* values are normal values + 1 to allow zero to
-                * mean "same as normal".
+                * The pin config contains pin number and altfunction fields,
+                * here we just ignore that part. It's being handled by the
+                * framework and pinmux callback respectively.
                 */
-               if (slpm_pull)
-                       pull = slpm_pull - 1;
-               if (slpm_output)
-                       output = slpm_output - 1;
-               if (slpm_val)
-                       val = slpm_val - 1;
-
-               dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
-                       pin,
-                       slpm_pull ? pullnames[pull] : "same",
-                       slpm_output ? (output ? "output" : "input") : "same",
-                       slpm_val ? (val ? "high" : "low") : "same");
-       }
+               cfg = (pin_cfg_t) configs[i];
+               pull = PIN_PULL(cfg);
+               slpm = PIN_SLPM(cfg);
+               output = PIN_DIR(cfg);
+               val = PIN_VAL(cfg);
+               lowemi = PIN_LOWEMI(cfg);
+               gpiomode = PIN_GPIOMODE(cfg);
+               sleep = PIN_SLEEPMODE(cfg);
+
+               if (sleep) {
+                       int slpm_pull = PIN_SLPM_PULL(cfg);
+                       int slpm_output = PIN_SLPM_DIR(cfg);
+                       int slpm_val = PIN_SLPM_VAL(cfg);
+
+                       /* All pins go into GPIO mode at sleep */
+                       gpiomode = true;
+
+                       /*
+                        * The SLPM_* values are normal values + 1 to allow zero
+                        * to mean "same as normal".
+                        */
+                       if (slpm_pull)
+                               pull = slpm_pull - 1;
+                       if (slpm_output)
+                               output = slpm_output - 1;
+                       if (slpm_val)
+                               val = slpm_val - 1;
+
+                       dev_dbg(nmk_chip->chip.dev,
+                               "pin %d: sleep pull %s, dir %s, val %s\n",
+                               pin,
+                               slpm_pull ? pullnames[pull] : "same",
+                               slpm_output ? (output ? "output" : "input")
+                               : "same",
+                               slpm_val ? (val ? "high" : "low") : "same");
+               }
 
-       dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
-               pin, cfg, pullnames[pull], slpmnames[slpm],
-               output ? "output " : "input",
-               output ? (val ? "high" : "low") : "",
-               lowemi ? "on" : "off");
+               dev_dbg(nmk_chip->chip.dev,
+                       "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
+                       pin, cfg, pullnames[pull], slpmnames[slpm],
+                       output ? "output " : "input",
+                       output ? (val ? "high" : "low") : "",
+                       lowemi ? "on" : "off");
 
-       clk_enable(nmk_chip->clk);
-       bit = pin % NMK_GPIO_PER_CHIP;
-       if (gpiomode)
-               /* No glitch when going to GPIO mode */
-               __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
-       if (output)
-               __nmk_gpio_make_output(nmk_chip, bit, val);
-       else {
-               __nmk_gpio_make_input(nmk_chip, bit);
-               __nmk_gpio_set_pull(nmk_chip, bit, pull);
-       }
-       /* TODO: isn't this only applicable on output pins? */
-       __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+               clk_enable(nmk_chip->clk);
+               bit = pin % NMK_GPIO_PER_CHIP;
+               if (gpiomode)
+                       /* No glitch when going to GPIO mode */
+                       __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+               if (output)
+                       __nmk_gpio_make_output(nmk_chip, bit, val);
+               else {
+                       __nmk_gpio_make_input(nmk_chip, bit);
+                       __nmk_gpio_set_pull(nmk_chip, bit, pull);
+               }
+               /* TODO: isn't this only applicable on output pins? */
+               __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+
+               __nmk_gpio_set_slpm(nmk_chip, bit, slpm);
+               clk_disable(nmk_chip->clk);
+       } /* for each config */
 
-       __nmk_gpio_set_slpm(nmk_chip, bit, slpm);
-       clk_disable(nmk_chip->clk);
        return 0;
 }