static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, int gpio, bool on) { if (nmk_chip->sleepmode) { __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, on ? NMK_GPIO_SLPM_WAKEUP_ENABLE : NMK_GPIO_SLPM_WAKEUP_DISABLE); } __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); }
static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, int gpio, bool on) { /* * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is * disabled, since setting SLPM to 1 increases power consumption, and * 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_SLPM_WAKEUP_ENABLE); } __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); }
/** * 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 = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); if (!nmk_chip) return -EINVAL; spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); spin_lock(&nmk_chip->lock); __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode); spin_unlock(&nmk_chip->lock); spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); return 0; }
/** * 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; }
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); }
int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long config) { 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", }; struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); struct nmk_gpio_chip *nmk_chip; 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); range = nmk_match_gpio_range(pctldev, pin); if (!range) { dev_err(npct->dev, "invalid pin offset %d\n", pin); return -EINVAL; } if (!range->gc) { dev_err(npct->dev, "GPIO chip missing in range for pin %d\n", pin); return -EINVAL; } 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; /* * 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" ); 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); return 0; }
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); } /* * 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); }