# Base git commit: e93c9c99a629 # (Linux 5.1) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: fix debounce configuration # # There are several issues with the debounce configuration: # 1. when we unidle, having potentially lost all context, we configure the # debounce enables with the debounce time set to minimum. Only later # do we configure the debounce time (in omap_gpio_restore_context()). # This leaves a window for undebounced transitions to be detected. # # 2. if a gpio is configured for debounce, and omap_gpio_set_config() is # called for a different gpio in the same bank to disable debounce, # we clear the debounce time, setting it to minimum. # # 3. we potentially glitch the slow debounce clock during initial setup # with an enable-disable-enable transition. # # Work around all these by tracking the desired debounce state and the # real hardware state, updating the registers when something changes. # # Signed-off-by: Russell King # # 92ef1c88e0779bca7e13d0d5b8821ea3cf49f7a5 # drivers/gpio/gpio-omap.c | 119 +++++++++++++++++++++++------------------------ # 1 file changed, 57 insertions(+), 62 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: clean up register access in omap2_set_gpio_debounce() # # Signed-off-by: Russell King # # db3fe2241c8449784c42cba1ef6ff03196b18efa # drivers/gpio/gpio-omap.c | 4 +--- # 1 file changed, 1 insertion(+), 3 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: take pm_runtime usage while IRQs are claimed # # Bump the pm_runtime usage count while interrupts are in use, rather # than failing the pm_runtime callbacks. The logic here is a little # non-obvious - the calling order will be: # # omap_gpio_irq_bus_lock() # (optionally) raw_spin_lock_irqsave(desc->lock) # omap_gpio_irq_startup() # (optionally) raw_spin_unlock_irqrestore(desc->lock) # gpio_irq_bus_sync_unlock() # # As the irq_startup method may be called with interrupts disabled, we # must not use pm_runtime_get() here, so as the bus lock takes an initial # pm reference count us, use pm_runtime_get_if_in_use() which will merely # increment the use count. # # Signed-off-by: Russell King # # 25aca92fb884b4a6eba8e3e9864d446e07527766 # drivers/gpio/gpio-omap.c | 23 +++++++---------------- # 1 file changed, 7 insertions(+), 16 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: irq_startup() must not return error codes # # The irq_startup() method returns an unsigned int, but in __irq_startup() # it is assigned to an int. However, nothing checks for errors, so any # error that is returned is ignored. # # Remove the check for GPIO-input mode and the error return. # # Signed-off-by: Russell King # # f1b94c952128177e20ef9928dcc1899a27fe5ef3 # drivers/gpio/gpio-omap.c | 5 ----- # 1 file changed, 5 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: clean up wakeup handling # # Signed-off-by: Russell King # # 403cf7efd59b3feb08692d847cf7f7a646804f9a # drivers/gpio/gpio-omap.c | 36 +++++++++++++----------------------- # 1 file changed, 13 insertions(+), 23 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: constify register tables # # We must never alter the register tables; these are read-only as far # as the driver is concerned. Constify these tables. # # Signed-off-by: Russell King # # 4b6874c85769bf062ce7b38f30b944efdce85fcd # drivers/gpio/gpio-omap.c | 12 ++++++------ # include/linux/platform_data/gpio-omap.h | 2 +- # 2 files changed, 7 insertions(+), 7 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: clean up omap_gpio_restore_context() # # Use local variables to store the base iomem address and regs table # pointer like omap_gpio_init_context() does. Not only does this make # the function neater, it also avoids unnecessary reloads of the same # data multiple times. # # Signed-off-by: Russell King # # 4000b05bf9710dcd6a91fdb38ba607f380f00e5c # drivers/gpio/gpio-omap.c | 36 +++++++++++++++--------------------- # 1 file changed, 15 insertions(+), 21 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: remove dataout variation in context handling # # When a GPIO block has the set/clear dataout registers implemented, it # also has the normal dataout register implemented. Reading this register # reads the current GPIO output state, and writing it sets the GPIOs to # the explicit state. This is the behaviour that we want when saving and # restoring the context, so use the dataout register exclusively. # # Signed-off-by: Russell King # # 58e288f2cc2125224a54c373e44cc9a396214ea8 # drivers/gpio/gpio-omap.c | 12 ++---------- # 1 file changed, 2 insertions(+), 10 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify omap_set_gpio_irqenable() # # omap_set_gpio_irqenable() calls two helpers that are almost the same # apart from whether they set or clear bits. We can consolidate these: # # - in the set/clear bit register case, we can perform the operation on # our saved context copy and write the appropriate set/clear register. # - otherwise, we can use our read-modify-write helper and invert enable # if irqenable_inv is set. # # Signed-off-by: Russell King # # 9b20bf60081205a4350cb330eb5d0159cce07534 # drivers/gpio/gpio-omap.c | 61 ++++++++++++------------------------------------ # 1 file changed, 15 insertions(+), 46 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify omap_toggle_gpio_edge_triggering() # # This function open-codes an exclusive-or bitwise operation using an # if() statement and explicitly setting or clearing the bit. Instead, # use an exclusive-or operation instead, and simplify the function. # # We can combine the preprocessor conditional using IS_ENABLED() and # gain some additional compilation coverage. # # Signed-off-by: Russell King # # 19b00a587e0e9c32a73fc59f43627c4bb2259ec7 # drivers/gpio/gpio-omap.c | 22 ++++------------------ # 1 file changed, 4 insertions(+), 18 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify read-modify-write # # We already have a read-modify-write helper, but there's more that can # be done with a read-modify-write helper if it returned the new value. # Modify the existing helper to return the new value, and arrange for # it to take one less argument by having the caller compute the register # address. # # Signed-off-by: Russell King # # a3625be1d92f7a14c6273bca5df31944748fde41 # drivers/gpio/gpio-omap.c | 79 +++++++++++++++++------------------------------- # 1 file changed, 28 insertions(+), 51 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify bank->level_mask # # bank->level_mask is merely the bitwise or of the level detection # context which we have already read in this function. Rather than # repeating additional reads, compute it from the values already # read. # # Signed-off-by: Russell King # # 2ae4b0ab301059e429337396d1c081f746eb76aa # drivers/gpio/gpio-omap.c | 7 +++---- # 1 file changed, 3 insertions(+), 4 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: remove unnecessary goto in omap_set_gpio_trigger() # # The three levels of if() statement and goto are unnecessary in # omap_set_gpio_trigger(). Clean this up to make the code easier to # read, and improve the comment to describe what's going on here. # # Signed-off-by: Russell King # # 1fcb16c9a4ca9f1cd7b7faf08ba75d2cd4b502a7 # drivers/gpio/gpio-omap.c | 18 +++++++++--------- # 1 file changed, 9 insertions(+), 9 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify set_multiple() # # One of the reasons for set_multiple() to exist is to allow multiple # GPIOs on the same chip to be changed simultaneously - see commit # 5f42424354f5 ("gpiolib: allow simultaneous setting of multiple GPIO # outputs"): # # - Simultaneous glitch-free setting of multiple pins on any kind of # parallel bus attached to GPIOs provided they all reside on the # same chip and bank. # # In order for this to work, we should not use the atomic set/clear # registers, but instead read-modify-write the dataout register. We # already take the spinlock to ensure that happens atomically, so # move the code into the set_multiple() function and kill the two # helper functions. # # Signed-off-by: Russell King # # d3d9ed2181f87169bc1820769f9633aa618d5eb8 # drivers/gpio/gpio-omap.c | 45 +++++++-------------------------------------- # 1 file changed, 7 insertions(+), 38 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify get_multiple() # # There is no reason to have helper functions to read the datain and # dataout registers when they are only used in one location. Simplify # this code to make it more readable. # # Signed-off-by: Russell King # # cd6cae6a49fdb185197ebc008d65c3c33c96df6d # drivers/gpio/gpio-omap.c | 36 +++++++++++------------------------- # 1 file changed, 11 insertions(+), 25 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify get() method # # omap_gpio_get() calls omap_get_gpio_datain() or omap_get_gpio_dataout() # to read the GPIO state. These two functions are only called from this # method, so they don't add much value. Move their contents into # omap_gpio_get() method and simplify. # # Signed-off-by: Russell King # # bd52e9f299200d2966972b01e97892c84d7f8fe2 # drivers/gpio/gpio-omap.c | 25 ++++++------------------- # 1 file changed, 6 insertions(+), 19 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: simplify omap_gpio_get_direction() # # Architectures are single-copy atomic, which means that simply reading # a register is an inherently atomic operation. There is no need to # take a spinlock here. # # Signed-off-by: Russell King # # 1d4f44b429a7cb47976ed67cd3b4df51d634a27b # drivers/gpio/gpio-omap.c | 13 +++---------- # 1 file changed, 3 insertions(+), 10 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: move omap_gpio_request() and omap_gpio_free() # # Move these two functions to live beside the rest of the gpio chip # implementation, rather than in the middle of the irq chip # implementation. # # Signed-off-by: Russell King # # 62d7c29fc213a3010f7cc9d26b72ab1cb3b1ec59 # drivers/gpio/gpio-omap.c | 64 ++++++++++++++++++++++++------------------------ # 1 file changed, 32 insertions(+), 32 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: fix lack of irqstatus_raw0 for OMAP4 # # Commit 384ebe1c2849 ("gpio/omap: Add DT support to GPIO driver") added # the register definition tables to the gpio-omap driver. Subsequently to # that commit, commit 4e962e8998cc ("gpio/omap: remove cpu_is_omapxxxx() # checks from *_runtime_resume()") added definitions for irqstatus_raw* # registers to the legacy OMAP4 definitions, but missed the DT # definitions. # # This causes an unintentional change of behaviour for the 1.101 errata # workaround on OMAP4 platforms. Fix this oversight. # # Fixes: 4e962e8998cc ("gpio/omap: remove cpu_is_omapxxxx() checks from *_runtime_resume()") # Signed-off-by: Russell King # # b1e663cfe060246310dfe1e8262c3b3a89b6897e # drivers/gpio/gpio-omap.c | 2 ++ # 1 file changed, 2 insertions(+) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: ensure irq is enabled before wakeup # # Documentation states: # # NOTE: There must be a correlation between the wake-up enable and # interrupt-enable registers. If a GPIO pin has a wake-up configured # on it, it must also have the corresponding interrupt enabled (on # one of the two interrupt lines). # # Ensure that this condition is always satisfied by enabling the detection # events after enabling the interrupt, and disabling the detection before # disabling the interrupt. This ensures interrupt/wakeup events can not # happen until both the wakeup and interrupt enables correlate. # # If we do any clearing, clear between the interrupt enable/disable and # trigger setting. # # Signed-off-by: Russell King # # 74a11c5e30855c99bdd39470d4a58df2fcabd04a # drivers/gpio/gpio-omap.c | 15 ++++++++------- # 1 file changed, 8 insertions(+), 7 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: remove irq_ack method # # The irq_ack method does not fit our hardware requirements. Edge # interrupts must be cleared before we handle them, and level interrupts # must be cleared after handling them. # # We handle the interrupt clearance in our interrupt handler for edge IRQs # and in the unmask method for level IRQs. # # Replace the irq_ack method with the no-op method from the dummy irq # chip. # # Signed-off-by: Russell King # # be26039b186f3226891c0f829cee603adc6fa0ec # drivers/gpio/gpio-omap.c | 17 +++-------------- # 1 file changed, 3 insertions(+), 14 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: clean up edge interrupt handling # # The edge interrupt handling was effectively: # # isr = ISR_reg & enabled; # if (bank->level_mask) # level_mask = bank->level_mask & enabled; # else # level_mask = 0; # # edge = isr & ~level_mask; # # When bank->level_mask is zero, level_mask will be computed as zero # anyway, so the if() statement is redundant. We are then left with: # # isr = ISR_reg & enabled; # level_mask = bank->level_mask & enabled; # edge = isr & ~level_mask; # # This can be simplified further to: # # isr = ISR_reg & enabled; # edge = isr & ~bank->level_mask; # # since the second mask with 'enabled' is redundant. # # Improve the associated comment as well. # # Signed-off-by: Russell King # # 927703d38337386e50be63fddb68ac1ebf36f424 # drivers/gpio/gpio-omap.c | 20 +++++++++----------- # 1 file changed, 9 insertions(+), 11 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: remove remainder of list management # # Commit c4791bc6e3a6 ("gpio: omap: drop omap_gpio_list") removed the # list head and addition to the list head of each gpio bank, but failed # to remove the list_del() call and the node inside struct gpio_bank. # Remove these too. # # Fixes: c4791bc6e3a6 ("gpio: omap: drop omap_gpio_list") # Signed-off-by: Russell King # # 49f00ae37adfa1fa20eb42a2f7871ea4767127b0 # drivers/gpio/gpio-omap.c | 2 -- # 1 file changed, 2 deletions(-) # # Author: Russell King (Fri 14 Dec 14:46:58 GMT 2018) # Committer: Russell King (Thu 9 May 14:01:26 BST 2019) # # gpio: gpio-omap: configure edge detection for level IRQs for idle wakeup # # The GPIO block can enter idle independently of the CPU power management # calls via smart-idle. When the GPIO block enters idle, level detection # stops working due to clocks being shut off, and an alternative form of # edge detection is used. However, this needs the edge detection # registers set to mark the appropriate edges. # # Arrange to configure the edge detection enables along with the level # detection to ensure that any transition to active interrupt state that # occurs while the block is idle is detected as a wake-up event. # # Since we enable the edge detection when configuring the IRQ, both # omap2_gpio_enable_level_quirk() nor omap2_gpio_disable_level_quirk() # become redundant, which also means OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER # can be removed. # # Signed-off-by: Russell King # # 1910816a321e92e869ba8785abff0d06dd64b126 # drivers/gpio/gpio-omap.c | 90 ++++----------------------------- # include/linux/platform_data/gpio-omap.h | 2 - # 2 files changed, 11 insertions(+), 81 deletions(-) # diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 7f33024b6d83..d80ca32bad77 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -31,8 +31,6 @@ #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF -#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2) - struct gpio_regs { u32 irqenable1; u32 irqenable2; @@ -48,21 +46,14 @@ struct gpio_regs { u32 debounce_en; }; -struct gpio_bank; - -struct gpio_omap_funcs { - void (*idle_enable_level_quirk)(struct gpio_bank *bank); - void (*idle_disable_level_quirk)(struct gpio_bank *bank); -}; - struct gpio_bank { - struct list_head node; void __iomem *base; + const struct omap_gpio_reg_offs *regs; + int irq; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; - struct gpio_omap_funcs funcs; u32 saved_datain; u32 level_mask; u32 toggle_mask; @@ -74,8 +65,8 @@ struct gpio_bank { unsigned int is_suspended:1; u32 mod_usage; u32 irq_usage; - u32 dbck_enable_mask; - bool dbck_enabled; + u32 desired_debounce_en; + u32 desired_debounce; bool is_mpuio; bool dbck_flag; bool loses_context; @@ -84,14 +75,9 @@ struct gpio_bank { u32 width; int context_loss_count; bool workaround_enabled; - u32 quirks; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); - void (*set_dataout_multiple)(struct gpio_bank *bank, - unsigned long *mask, unsigned long *bits); int (*get_context_loss_count)(struct device *dev); - - struct omap_gpio_reg_offs *regs; }; #define GPIO_MOD_CTRL_BIT BIT(0) @@ -107,20 +93,25 @@ static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d) return gpiochip_get_data(chip); } -static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, - int is_input) +static inline u32 omap_gpio_rmw(void __iomem *reg, u32 mask, bool set) { - void __iomem *reg = bank->base; - u32 l; + u32 val = readl_relaxed(reg); - reg += bank->regs->direction; - l = readl_relaxed(reg); - if (is_input) - l |= BIT(gpio); + if (set) + val |= mask; else - l &= ~(BIT(gpio)); - writel_relaxed(l, reg); - bank->context.oe = l; + val &= ~mask; + + writel_relaxed(val, reg); + + return val; +} + +static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, + int is_input) +{ + bank->context.oe = omap_gpio_rmw(bank->base + bank->regs->direction, + BIT(gpio), is_input); } @@ -146,113 +137,64 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset, static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset, int enable) { - void __iomem *reg = bank->base + bank->regs->dataout; - u32 gpio_bit = BIT(offset); - u32 l; - - l = readl_relaxed(reg); - if (enable) - l |= gpio_bit; - else - l &= ~gpio_bit; - writel_relaxed(l, reg); - bank->context.dataout = l; -} - -static int omap_get_gpio_datain(struct gpio_bank *bank, int offset) -{ - void __iomem *reg = bank->base + bank->regs->datain; - - return (readl_relaxed(reg) & (BIT(offset))) != 0; -} - -static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - - return (readl_relaxed(reg) & (BIT(offset))) != 0; + bank->context.dataout = omap_gpio_rmw(bank->base + bank->regs->dataout, + BIT(offset), enable); } -/* set multiple data out values using dedicate set/clear register */ -static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank, - unsigned long *mask, - unsigned long *bits) -{ - void __iomem *reg = bank->base; - u32 l; - - l = *bits & *mask; - writel_relaxed(l, reg + bank->regs->set_dataout); - bank->context.dataout |= l; - - l = ~*bits & *mask; - writel_relaxed(l, reg + bank->regs->clr_dataout); - bank->context.dataout &= ~l; -} - -/* set multiple data out values using mask register */ -static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank, - unsigned long *mask, - unsigned long *bits) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); - - writel_relaxed(l, reg); - bank->context.dataout = l; -} - -static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank, - unsigned long *mask) -{ - void __iomem *reg = bank->base + bank->regs->datain; - - return readl_relaxed(reg) & *mask; -} - -static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank, - unsigned long *mask) -{ - void __iomem *reg = bank->base + bank->regs->dataout; - - return readl_relaxed(reg) & *mask; -} - -static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) +/* + * omap_gpio_dbck_update() is the primary manager of the debounce clock. + * We implicitly track the state using bank->context.debounce_en, which + * reflects the setting of the debounce enable register. + * + * When bank->context.debounce_en is zero, it means the clock is shut + * off, so if we have a non-zero desired_debounce_en, it means we are + * wanting to enable the clock and program the debounce. + * + * If bank->context.debounce_en is non-zero, it means the clock is + * currently enabled. If we have a zero desired_debounce_en, it means + * we're wanting to disable debounce and shut off the debounce clock. + * + * The only other function that is allowed to change context.debounce_en + * and the state of the debounce clock is omap_gpio_dbck_disable() + * which also follows this rule. + */ +static inline void omap_gpio_dbck_update(struct gpio_bank *bank) { - int l = readl_relaxed(base + reg); - - if (set) - l |= mask; - else - l &= ~mask; - - writel_relaxed(l, base + reg); -} + void __iomem *base = bank->base; -static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) -{ - if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_enable(bank->dbck); - bank->dbck_enabled = true; + if (bank->desired_debounce_en != bank->context.debounce_en) { + if (!bank->context.debounce_en) + clk_enable(bank->dbck); - writel_relaxed(bank->dbck_enable_mask, - bank->base + bank->regs->debounce_en); + bank->context.debounce_en = bank->desired_debounce_en; + writel_relaxed(bank->context.debounce_en, + base + bank->regs->debounce_en); + + bank->context.debounce = bank->desired_debounce; + writel_relaxed(bank->context.debounce, + base + bank->regs->debounce); + + if (!bank->desired_debounce_en) + clk_disable(bank->dbck); + } else if (bank->context.debounce != bank->desired_debounce) { + WARN_ON(!bank->context.debounce_en); + bank->context.debounce = bank->desired_debounce; + writel_relaxed(bank->context.debounce, + base + bank->regs->debounce); } } static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) { - if (bank->dbck_enable_mask && bank->dbck_enabled) { + if (bank->context.debounce_en) { /* * Disable debounce before cutting it's clock. If debounce is * enabled but the clock is not, GPIO module seems to be unable * to detect events and generate interrupts at least on OMAP3. */ + bank->context.debounce_en = 0; writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable(bank->dbck); - bank->dbck_enabled = false; } } @@ -271,10 +213,8 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce) { - void __iomem *reg; - u32 val; - u32 l; - bool enable = !!debounce; + u32 gpio_bit = BIT(offset); + bool enable = !!debounce; if (!bank->dbck_flag) return -ENOTSUPP; @@ -283,38 +223,20 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, debounce = DIV_ROUND_UP(debounce, 31) - 1; if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) return -EINVAL; - } - - l = BIT(offset); - - clk_enable(bank->dbck); - reg = bank->base + bank->regs->debounce; - writel_relaxed(debounce, reg); - - reg = bank->base + bank->regs->debounce_en; - val = readl_relaxed(reg); - if (enable) - val |= l; - else - val &= ~l; - bank->dbck_enable_mask = val; + bank->desired_debounce = debounce; + bank->desired_debounce_en |= gpio_bit; + } else { + bank->desired_debounce_en &= ~gpio_bit; + if (!bank->desired_debounce_en) + bank->desired_debounce = 0; + } - writel_relaxed(val, reg); - clk_disable(bank->dbck); /* - * Enable debounce clock per module. - * This call is mandatory because in omap_gpio_request() when - * *_runtime_get_sync() is called, _gpio_dbck_enable() within - * runtime callbck fails to turn on dbck because dbck_enable_mask - * used within _gpio_dbck_enable() is still not initialized at - * that point. Therefore we have to enable dbck here. + * Update the debounce settings. This will enable or disable the + * debounce clock as required. */ - omap_gpio_dbck_enable(bank); - if (bank->dbck_enable_mask) { - bank->context.debounce = debounce; - bank->context.debounce_en = val; - } + omap_gpio_dbck_update(bank); return 0; } @@ -331,26 +253,7 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, */ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset) { - u32 gpio_bit = BIT(offset); - - if (!bank->dbck_flag) - return; - - if (!(bank->dbck_enable_mask & gpio_bit)) - return; - - bank->dbck_enable_mask &= ~gpio_bit; - bank->context.debounce_en &= ~gpio_bit; - writel_relaxed(bank->context.debounce_en, - bank->base + bank->regs->debounce_en); - - if (!bank->dbck_enable_mask) { - bank->context.debounce = 0; - writel_relaxed(bank->context.debounce, bank->base + - bank->regs->debounce); - clk_disable(bank->dbck); - bank->dbck_enabled = false; - } + omap2_set_gpio_debounce(bank, offset, 0); } static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, @@ -359,14 +262,20 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, void __iomem *base = bank->base; u32 gpio_bit = BIT(gpio); - omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, + omap_gpio_rmw(base + bank->regs->leveldetect0, gpio_bit, trigger & IRQ_TYPE_LEVEL_LOW); - omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, + omap_gpio_rmw(base + bank->regs->leveldetect1, gpio_bit, trigger & IRQ_TYPE_LEVEL_HIGH); - omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); + + /* + * We need the edge detection enabled for to allow the GPIO block + * to be woken from idle state. Set the appropriate edge detection + * in addition to the level detection. + */ + omap_gpio_rmw(base + bank->regs->risingdetect, gpio_bit, + trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)); + omap_gpio_rmw(base + bank->regs->fallingdetect, gpio_bit, + trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)); bank->context.leveldetect0 = readl_relaxed(bank->base + bank->regs->leveldetect0); @@ -377,20 +286,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, bank->context.fallingdetect = readl_relaxed(bank->base + bank->regs->fallingdetect); - if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); - } - - /* This part needs to be executed always for OMAP{34xx, 44xx} */ - if (!bank->regs->irqctrl) { - /* On omap24xx proceed only when valid GPIO bit is set */ - if (bank->non_wakeup_gpios) { - if (!(bank->non_wakeup_gpios & gpio_bit)) - goto exit; - } + bank->level_mask = bank->context.leveldetect0 | + bank->context.leveldetect1; + /* + * We require the 1.101 workaround for all GPIOs on OMAP34xx and + * OMAP44xx, and for OMAP24xx for non-wakeup GPIOs. + * + * OMAP2+ is signified by irqctrl being zero, OMAP24xx by non-zero + * non_wakeup_gpios. + */ + if (!bank->regs->irqctrl && + (!bank->non_wakeup_gpios || bank->non_wakeup_gpios & gpio_bit)) { /* * Log the edge gpio and manually trigger the IRQ * after resume if the input level changes @@ -402,45 +309,25 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, else bank->enabled_non_wakeup_gpios &= ~gpio_bit; } - -exit: - bank->level_mask = - readl_relaxed(bank->base + bank->regs->leveldetect0) | - readl_relaxed(bank->base + bank->regs->leveldetect1); } -#ifdef CONFIG_ARCH_OMAP1 /* * This only applies to chips that can't do both rising and falling edge * detection at once. For all other chips, this function is a noop. */ static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) { - void __iomem *reg = bank->base; - u32 l = 0; + if (IS_ENABLED(CONFIG_ARCH_OMAP1) && bank->regs->irqctrl) { + void __iomem *reg = bank->base + bank->regs->irqctrl; - if (!bank->regs->irqctrl) - return; - - reg += bank->regs->irqctrl; - - l = readl_relaxed(reg); - if ((l >> gpio) & 1) - l &= ~(BIT(gpio)); - else - l |= BIT(gpio); - - writel_relaxed(l, reg); + writel_relaxed(readl_relaxed(reg) ^ BIT(gpio), reg); + } } -#else -static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} -#endif static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *reg = bank->base; - void __iomem *base = bank->base; u32 l = 0; if (bank->regs->leveldetect0 && bank->regs->wkup_en) { @@ -472,11 +359,6 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio, l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) l |= BIT(gpio << 1); - - /* Enable wake-up during idle for dynamic tick */ - omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); writel_relaxed(l, reg); } return 0; @@ -505,17 +387,6 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset) static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset) { - void __iomem *base = bank->base; - - if (bank->regs->wkup_en && - !LINE_USED(bank->mod_usage, offset) && - !LINE_USED(bank->irq_usage, offset)) { - /* Disable wake-up during idle for dynamic tick */ - omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); - } - if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; @@ -626,57 +497,39 @@ static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank) return l; } -static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, + unsigned offset, int enable) { void __iomem *reg = bank->base; - u32 l; + u32 gpio_mask = BIT(offset); - if (bank->regs->set_irqenable) { - reg += bank->regs->set_irqenable; - l = gpio_mask; - bank->context.irqenable1 |= gpio_mask; + if (bank->regs->set_irqenable && bank->regs->clr_irqenable) { + if (enable) { + reg += bank->regs->set_irqenable; + bank->context.irqenable1 |= gpio_mask; + } else { + reg += bank->regs->clr_irqenable; + bank->context.irqenable1 &= ~gpio_mask; + } + writel_relaxed(gpio_mask, reg); } else { - reg += bank->regs->irqenable; - l = readl_relaxed(reg); - if (bank->regs->irqenable_inv) - l &= ~gpio_mask; - else - l |= gpio_mask; - bank->context.irqenable1 = l; + bank->context.irqenable1 = + omap_gpio_rmw(reg + bank->regs->irqenable, gpio_mask, + enable ^ bank->regs->irqenable_inv); } - writel_relaxed(l, reg); -} - -static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) -{ - void __iomem *reg = bank->base; - u32 l; - - if (bank->regs->clr_irqenable) { - reg += bank->regs->clr_irqenable; - l = gpio_mask; - bank->context.irqenable1 &= ~gpio_mask; - } else { - reg += bank->regs->irqenable; - l = readl_relaxed(reg); - if (bank->regs->irqenable_inv) - l |= gpio_mask; - else - l &= ~gpio_mask; - bank->context.irqenable1 = l; + /* + * Program GPIO wakeup along with IRQ enable to satisfy OMAP4430 TRM + * note requiring correlation between the IRQ enable registers and + * the wakeup registers. In any case, we want wakeup from idle + * enabled for the GPIOs which support this feature. + */ + if (bank->regs->wkup_en && + (bank->regs->edgectrl1 || !(bank->non_wakeup_gpios & gpio_mask))) { + bank->context.wake_en = + omap_gpio_rmw(bank->base + bank->regs->wkup_en, + gpio_mask, enable); } - - writel_relaxed(l, reg); -} - -static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, - unsigned offset, int enable) -{ - if (enable) - omap_enable_gpio_irqbank(bank, BIT(offset)); - else - omap_disable_gpio_irqbank(bank, BIT(offset)); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ @@ -687,38 +540,6 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) return irq_set_irq_wake(bank->irq, enable); } -static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct gpio_bank *bank = gpiochip_get_data(chip); - unsigned long flags; - - pm_runtime_get_sync(chip->parent); - - raw_spin_lock_irqsave(&bank->lock, flags); - omap_enable_gpio_module(bank, offset); - bank->mod_usage |= BIT(offset); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct gpio_bank *bank = gpiochip_get_data(chip); - unsigned long flags; - - raw_spin_lock_irqsave(&bank->lock, flags); - bank->mod_usage &= ~(BIT(offset)); - if (!LINE_USED(bank->irq_usage, offset)) { - omap_set_gpio_direction(bank, offset, 1); - omap_clear_gpio_debounce(bank, offset); - } - omap_disable_gpio_module(bank, offset); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - pm_runtime_put(chip->parent); -} - /* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. @@ -731,7 +552,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) { void __iomem *isr_reg = NULL; - u32 enabled, isr, level_mask; + u32 enabled, isr, edge; unsigned int bit; struct gpio_bank *bank = gpiobank; unsigned long wa_lock_flags; @@ -751,16 +572,14 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) enabled = omap_get_gpio_irqbank_mask(bank); isr = readl_relaxed(isr_reg) & enabled; - if (bank->level_mask) - level_mask = bank->level_mask & enabled; - else - level_mask = 0; - - /* clear edge sensitive interrupts before handler(s) are - called so that we don't miss any interrupt occurred while - executing them */ - if (isr & ~level_mask) - omap_clear_gpio_irqbank(bank, isr & ~level_mask); + /* + * Clear edge sensitive interrupts before calling handler(s) + * so subsequent edge transitions are not missed while the + * handlers are running. + */ + edge = isr & ~bank->level_mask; + if (edge) + omap_clear_gpio_irqbank(bank, edge); raw_spin_unlock_irqrestore(&bank->lock, lock_flags); @@ -803,12 +622,13 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) unsigned long flags; unsigned offset = d->hwirq; + /* Take a reference on the runtime PM to prevent RPM suspends */ + WARN_ON(pm_runtime_get_if_in_use(bank->chip.parent) == 0); + raw_spin_lock_irqsave(&bank->lock, flags); if (!LINE_USED(bank->mod_usage, offset)) omap_set_gpio_direction(bank, offset, 1); - else if (!omap_gpio_is_input(bank, offset)) - goto err; omap_enable_gpio_module(bank, offset); bank->irq_usage |= BIT(offset); @@ -816,9 +636,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) omap_gpio_unmask_irq(d); return 0; -err: - raw_spin_unlock_irqrestore(&bank->lock, flags); - return -EINVAL; } static void omap_gpio_irq_shutdown(struct irq_data *d) @@ -829,13 +646,15 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); - omap_set_gpio_irqenable(bank, offset, 0); - omap_clear_gpio_irqstatus(bank, offset); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_clear_gpio_irqstatus(bank, offset); + omap_set_gpio_irqenable(bank, offset, 0); if (!LINE_USED(bank->mod_usage, offset)) omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); + + pm_runtime_put(bank->chip.parent); } static void omap_gpio_irq_bus_lock(struct irq_data *data) @@ -852,14 +671,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data) pm_runtime_put(bank->chip.parent); } -static void omap_gpio_ack_irq(struct irq_data *d) -{ - struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned offset = d->hwirq; - - omap_clear_gpio_irqstatus(bank, offset); -} - static void omap_gpio_mask_irq(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); @@ -867,8 +678,8 @@ static void omap_gpio_mask_irq(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&bank->lock, flags); - omap_set_gpio_irqenable(bank, offset, 0); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_set_gpio_irqenable(bank, offset, 0); raw_spin_unlock_irqrestore(&bank->lock, flags); } @@ -880,9 +691,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&bank->lock, flags); - if (trigger) - omap_set_gpio_triggering(bank, offset, trigger); - omap_set_gpio_irqenable(bank, offset, 1); /* @@ -890,48 +698,14 @@ static void omap_gpio_unmask_irq(struct irq_data *d) * is cleared, thus after the handler has run. OMAP4 needs this done * after enabing the interrupt to clear the wakeup status. */ - if (bank->level_mask & BIT(offset)) + if (bank->regs->leveldetect0 && bank->regs->wkup_en && + trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) omap_clear_gpio_irqstatus(bank, offset); - raw_spin_unlock_irqrestore(&bank->lock, flags); -} - -/* - * Only edges can generate a wakeup event to the PRCM. - * - * Therefore, ensure any wake-up capable GPIOs have - * edge-detection enabled before going idle to ensure a wakeup - * to the PRCM is generated on a GPIO transition. (c.f. 34xx - * NDA TRM 25.5.3.1) - * - * The normal values will be restored upon ->runtime_resume() - * by writing back the values saved in bank->context. - */ -static void __maybe_unused -omap2_gpio_enable_level_quirk(struct gpio_bank *bank) -{ - u32 wake_low, wake_hi; - - /* Enable additional edge detection for level gpios for idle */ - wake_low = bank->context.leveldetect0 & bank->context.wake_en; - if (wake_low) - writel_relaxed(wake_low | bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - - wake_hi = bank->context.leveldetect1 & bank->context.wake_en; - if (wake_hi) - writel_relaxed(wake_hi | bank->context.risingdetect, - bank->base + bank->regs->risingdetect); -} + if (trigger) + omap_set_gpio_triggering(bank, offset, trigger); -static void __maybe_unused -omap2_gpio_disable_level_quirk(struct gpio_bank *bank) -{ - /* Disable edge detection for level gpios after idle */ - writel_relaxed(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - writel_relaxed(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); + raw_spin_unlock_irqrestore(&bank->lock, flags); } /*---------------------------------------------------------------------*/ @@ -996,19 +770,44 @@ static inline void omap_mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ -static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; + struct gpio_bank *bank = gpiochip_get_data(chip); + unsigned long flags; + + pm_runtime_get_sync(chip->parent); + + raw_spin_lock_irqsave(&bank->lock, flags); + omap_enable_gpio_module(bank, offset); + bank->mod_usage |= BIT(offset); + raw_spin_unlock_irqrestore(&bank->lock, flags); + + return 0; +} + +static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); unsigned long flags; - void __iomem *reg; - int dir; - bank = gpiochip_get_data(chip); - reg = bank->base + bank->regs->direction; raw_spin_lock_irqsave(&bank->lock, flags); - dir = !!(readl_relaxed(reg) & BIT(offset)); + bank->mod_usage &= ~(BIT(offset)); + if (!LINE_USED(bank->irq_usage, offset)) { + omap_set_gpio_direction(bank, offset, 1); + omap_clear_gpio_debounce(bank, offset); + } + omap_disable_gpio_module(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); - return dir; + + pm_runtime_put(chip->parent); +} + +static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + + return !!(readl_relaxed(bank->base + bank->regs->direction) & + BIT(offset)); } static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) @@ -1025,14 +824,15 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) static int omap_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; - - bank = gpiochip_get_data(chip); + struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg; if (omap_gpio_is_input(bank, offset)) - return omap_get_gpio_datain(bank, offset); + reg = bank->base + bank->regs->datain; else - return omap_get_gpio_dataout(bank, offset); + reg = bank->base + bank->regs->dataout; + + return (readl_relaxed(reg) & BIT(offset)) != 0; } static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) @@ -1052,18 +852,20 @@ static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpio_bank *bank = gpiochip_get_data(chip); - void __iomem *reg = bank->base + bank->regs->direction; - unsigned long in = readl_relaxed(reg), l; + void __iomem *base = bank->base; + u32 direction, m, val = 0; + + direction = readl_relaxed(base + bank->regs->direction); - *bits = 0; + m = direction & *mask; + if (m) + val |= readl_relaxed(base + bank->regs->datain) & m; - l = in & *mask; - if (l) - *bits |= omap_get_gpio_datain_multiple(bank, &l); + m = ~direction & *mask; + if (m) + val |= readl_relaxed(base + bank->regs->dataout) & m; - l = ~in & *mask; - if (l) - *bits |= omap_get_gpio_dataout_multiple(bank, &l); + *bits = val; return 0; } @@ -1116,10 +918,14 @@ static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg = bank->base + bank->regs->dataout; unsigned long flags; + u32 l; raw_spin_lock_irqsave(&bank->lock, flags); - bank->set_dataout_multiple(bank, mask, bits); + l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); + writel_relaxed(l, reg); + bank->context.dataout = l; raw_spin_unlock_irqrestore(&bank->lock, flags); } @@ -1153,9 +959,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) return; } - omap_gpio_rmw(base, bank->regs->irqenable, l, + omap_gpio_rmw(base + bank->regs->irqenable, l, bank->regs->irqenable_inv); - omap_gpio_rmw(base, bank->regs->irqstatus, l, + omap_gpio_rmw(base + bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) writel_relaxed(0, base + bank->regs->debounce_en); @@ -1218,11 +1024,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) #endif /* MPUIO is a bit different, reading IRQ status clears it */ - if (bank->is_mpuio) { - irqc->irq_ack = dummy_irq_chip.irq_ack; - if (!bank->regs->wkup_en) - irqc->irq_set_wake = NULL; - } + if (bank->is_mpuio && !bank->regs->wkup_en) + irqc->irq_set_wake = NULL; irq = &bank->chip.irq; irq->chip = irqc; @@ -1310,7 +1113,7 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_startup = omap_gpio_irq_startup, irqc->irq_shutdown = omap_gpio_irq_shutdown, - irqc->irq_ack = omap_gpio_ack_irq, + irqc->irq_ack = dummy_irq_chip.irq_ack, irqc->irq_mask = omap_gpio_mask_irq, irqc->irq_unmask = omap_gpio_unmask_irq, irqc->irq_set_type = omap_gpio_irq_type, @@ -1334,7 +1137,6 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->chip.parent = dev; bank->chip.owner = THIS_MODULE; bank->dbck_flag = pdata->dbck_flag; - bank->quirks = pdata->quirks; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; bank->is_mpuio = pdata->is_mpuio; @@ -1355,21 +1157,10 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } - if (bank->regs->set_dataout && bank->regs->clr_dataout) { + if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = omap_set_gpio_dataout_reg; - bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple; - } else { + else bank->set_dataout = omap_set_gpio_dataout_mask; - bank->set_dataout_multiple = - omap_set_gpio_dataout_mask_multiple; - } - - if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) { - bank->funcs.idle_enable_level_quirk = - omap2_gpio_enable_level_quirk; - bank->funcs.idle_disable_level_quirk = - omap2_gpio_disable_level_quirk; - } raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); @@ -1413,11 +1204,8 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_show_rev(bank); - if (bank->funcs.idle_enable_level_quirk && - bank->funcs.idle_disable_level_quirk) { - bank->nb.notifier_call = gpio_omap_cpu_notifier; - cpu_pm_register_notifier(&bank->nb); - } + bank->nb.notifier_call = gpio_omap_cpu_notifier; + cpu_pm_register_notifier(&bank->nb); pm_runtime_put(dev); @@ -1428,9 +1216,7 @@ static int omap_gpio_remove(struct platform_device *pdev) { struct gpio_bank *bank = platform_get_drvdata(pdev); - if (bank->nb.notifier_call) - cpu_pm_unregister_notifier(&bank->nb); - list_del(&bank->node); + cpu_pm_unregister_notifier(&bank->nb); gpiochip_remove(&bank->chip); pm_runtime_disable(&pdev->dev); if (bank->dbck_flag) @@ -1446,9 +1232,6 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) struct device *dev = bank->chip.parent; u32 l1 = 0, l2 = 0; - if (bank->funcs.idle_enable_level_quirk) - bank->funcs.idle_enable_level_quirk(bank); - if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count; @@ -1502,10 +1285,7 @@ static void omap_gpio_unidle(struct gpio_bank *bank) bank->get_context_loss_count(dev); } - omap_gpio_dbck_enable(bank); - - if (bank->funcs.idle_disable_level_quirk) - bank->funcs.idle_disable_level_quirk(bank); + omap_gpio_dbck_update(bank); if (bank->loses_context) { if (!bank->get_context_loss_count) { @@ -1578,7 +1358,7 @@ static void omap_gpio_unidle(struct gpio_bank *bank) static void omap_gpio_init_context(struct gpio_bank *p) { - struct omap_gpio_reg_offs *regs = p->regs; + const struct omap_gpio_reg_offs *regs = p->regs; void __iomem *base = p->base; p->context.ctrl = readl_relaxed(base + regs->ctrl); @@ -1590,87 +1370,53 @@ static void omap_gpio_init_context(struct gpio_bank *p) p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect); p->context.irqenable1 = readl_relaxed(base + regs->irqenable); p->context.irqenable2 = readl_relaxed(base + regs->irqenable2); - - if (regs->set_dataout && p->regs->clr_dataout) - p->context.dataout = readl_relaxed(base + regs->set_dataout); - else - p->context.dataout = readl_relaxed(base + regs->dataout); + p->context.dataout = readl_relaxed(base + regs->dataout); p->context_valid = true; } static void omap_gpio_restore_context(struct gpio_bank *bank) { - writel_relaxed(bank->context.wake_en, - bank->base + bank->regs->wkup_en); - writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl); - writel_relaxed(bank->context.leveldetect0, - bank->base + bank->regs->leveldetect0); - writel_relaxed(bank->context.leveldetect1, - bank->base + bank->regs->leveldetect1); - writel_relaxed(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); - writel_relaxed(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - if (bank->regs->set_dataout && bank->regs->clr_dataout) - writel_relaxed(bank->context.dataout, - bank->base + bank->regs->set_dataout); - else - writel_relaxed(bank->context.dataout, - bank->base + bank->regs->dataout); - writel_relaxed(bank->context.oe, bank->base + bank->regs->direction); - - if (bank->dbck_enable_mask) { - writel_relaxed(bank->context.debounce, bank->base + - bank->regs->debounce); - writel_relaxed(bank->context.debounce_en, - bank->base + bank->regs->debounce_en); - } + const struct omap_gpio_reg_offs *regs = bank->regs; + void __iomem *base = bank->base; - writel_relaxed(bank->context.irqenable1, - bank->base + bank->regs->irqenable); - writel_relaxed(bank->context.irqenable2, - bank->base + bank->regs->irqenable2); + writel_relaxed(bank->context.wake_en, base + regs->wkup_en); + writel_relaxed(bank->context.ctrl, base + regs->ctrl); + writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0); + writel_relaxed(bank->context.leveldetect1, base + regs->leveldetect1); + writel_relaxed(bank->context.risingdetect, base + regs->risingdetect); + writel_relaxed(bank->context.fallingdetect, base + regs->fallingdetect); + writel_relaxed(bank->context.dataout, base + regs->dataout); + writel_relaxed(bank->context.oe, base + regs->direction); + /* debounce is already restored via omap_gpio_dbck_update() */ + writel_relaxed(bank->context.irqenable1, base + regs->irqenable); + writel_relaxed(bank->context.irqenable2, base + regs->irqenable2); } static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); unsigned long flags; - int error = 0; raw_spin_lock_irqsave(&bank->lock, flags); - /* Must be idled only by CPU_CLUSTER_PM_ENTER? */ - if (bank->irq_usage) { - error = -EBUSY; - goto unlock; - } omap_gpio_idle(bank, true); bank->is_suspended = true; -unlock: raw_spin_unlock_irqrestore(&bank->lock, flags); - return error; + return 0; } static int __maybe_unused omap_gpio_runtime_resume(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); unsigned long flags; - int error = 0; raw_spin_lock_irqsave(&bank->lock, flags); - /* Must be unidled only by CPU_CLUSTER_PM_ENTER? */ - if (bank->irq_usage) { - error = -EBUSY; - goto unlock; - } omap_gpio_unidle(bank); bank->is_suspended = false; -unlock: raw_spin_unlock_irqrestore(&bank->lock, flags); - return error; + return 0; } #ifdef CONFIG_ARCH_OMAP2PLUS @@ -1683,7 +1429,7 @@ static const struct dev_pm_ops gpio_pm_ops; #endif /* CONFIG_ARCH_OMAP2PLUS */ #if defined(CONFIG_OF) -static struct omap_gpio_reg_offs omap2_gpio_regs = { +static const struct omap_gpio_reg_offs omap2_gpio_regs = { .revision = OMAP24XX_GPIO_REVISION, .direction = OMAP24XX_GPIO_OE, .datain = OMAP24XX_GPIO_DATAIN, @@ -1706,7 +1452,7 @@ static struct omap_gpio_reg_offs omap2_gpio_regs = { .fallingdetect = OMAP24XX_GPIO_FALLINGDETECT, }; -static struct omap_gpio_reg_offs omap4_gpio_regs = { +static const struct omap_gpio_reg_offs omap4_gpio_regs = { .revision = OMAP4_GPIO_REVISION, .direction = OMAP4_GPIO_OE, .datain = OMAP4_GPIO_DATAIN, @@ -1715,6 +1461,8 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .clr_dataout = OMAP4_GPIO_CLEARDATAOUT, .irqstatus = OMAP4_GPIO_IRQSTATUS0, .irqstatus2 = OMAP4_GPIO_IRQSTATUS1, + .irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0, + .irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1, .irqenable = OMAP4_GPIO_IRQSTATUSSET0, .irqenable2 = OMAP4_GPIO_IRQSTATUSSET1, .set_irqenable = OMAP4_GPIO_IRQSTATUSSET0, @@ -1729,11 +1477,6 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; -/* - * Note that omap2 does not currently support idle modes with context loss so - * no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save - * and restore context. - */ static const struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, @@ -1744,14 +1487,12 @@ static const struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, - .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER, }; static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, - .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER, }; static const struct of_device_id omap_gpio_match[] = { diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h index 6d07eebb3f75..1ca400005233 100644 --- a/include/linux/platform_data/gpio-omap.h +++ b/include/linux/platform_data/gpio-omap.h @@ -200,9 +200,7 @@ struct omap_gpio_platform_data { bool is_mpuio; /* whether the bank is of type MPUIO */ u32 non_wakeup_gpios; - u32 quirks; /* Version specific quirks mask */ - - struct omap_gpio_reg_offs *regs; + const struct omap_gpio_reg_offs *regs; /* Return context loss count due to PM states changing */ int (*get_context_loss_count)(struct device *dev);