mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-19 10:14:23 +08:00
GPIO fixes for v4.20:
- ACPI IRQ request deferral - OMAP: revert deferred wakeup quirk - MAX7301: fix DMA safe memory handling - MVEBU: selective probe failure on missing clk -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJcHKOUAAoJEEEQszewGV1zFCoP/0E/AfCLVxTZSgEPBlhzBL1a naXw4bFAM5WLF3t9aXqck0+mZ5T8ko7/VutOmmn54ogmAW++bGK+FyGmSxu+i9Ia EDVRlHzSvGmT6mQ1zK/J4YrWIlaW9paTOsbAdTkqrl2fsJygdyKOoWF0IzcHa0St L90+sCseloPj285GS96EYQFolCvyIEqaRVfRiBsnxD7fIpSNRpywKvKG83b8WGdZ aPyDfkjeDk9DZBaUx7je9INz5LwO5Aa3wnlEs26DXTj426+/KKPN/4Q64V2FSmbT 3WE2rOtgadyVqjF0YopjQ+IqK97/cN6dXYrPJKpW8QaOAS+4MWy4cvRrXyUSGfOS piu6DzSyBMUPjRhbo8Vxxhu4N+MKxBu4wwLKtuW4sVS03e2DZ7JIwhZQbGkP26+3 v3vmbHL2/KN5N2syW5d5ZKURcf6cG1DWC5ZL1XFrXFv1635DAPfT9i9cHBNMxRLO p1M5bgmIyVsIHQ96xEW/2Bvrw+MkS8KVLWrNHmqengGWrXM2X01GKzgD+CmkWh6b KU5u7kmNjACoYg+cCF+yN8YKrkrc+NxbFEgh3MhUUilgggCTCqFUOkJCAf8wuaqD FS1tpRe3s7RFW3u06Yb94q7Dt6jNsAzIOSTriSQExxydtQDI6ukyizxeVZRorwaU Np4KSWpl+gl1CfcZvimQ =+Iw2 -----END PGP SIGNATURE----- Merge tag 'gpio-v4.20-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO fixes from Linus Walleij: "Hopefully last round of GPIO fixes. The ACPI patch is pretty important for some laptop users, the rest is driver-specific for embedded (mostly ARM) systems. I took out one ACPI patch that wasn't critical enough because I couldn't justify sending it at this point, and that is why the commit date is today, but the patches have been in linux-next. Sorry for not sending some of them earlier :( Notice that we have a co-maintainer for GPIO now, Bartosz Golaszewski, and he might jump in and make some pull requests at times when I am off. Summary: - ACPI IRQ request deferral - OMAP: revert deferred wakeup quirk - MAX7301: fix DMA safe memory handling - MVEBU: selective probe failure on missing clk" * tag 'gpio-v4.20-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: gpio: mvebu: only fail on missing clk if pwm is actually to be used gpio: max7301: fix driver for use with CONFIG_VMAP_STACK gpio: gpio-omap: Revert deferred wakeup quirk handling for regressions gpiolib-acpi: Only defer request_irq for GpioInt ACPI event handlers
This commit is contained in:
commit
bc380733a5
@ -25,7 +25,7 @@ static int max7301_spi_write(struct device *dev, unsigned int reg,
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
|
||||
|
||||
return spi_write(spi, (const u8 *)&word, sizeof(word));
|
||||
return spi_write_then_read(spi, &word, sizeof(word), NULL, 0);
|
||||
}
|
||||
|
||||
/* A read from the MAX7301 means two transfers; here, one message each */
|
||||
@ -37,14 +37,8 @@ static int max7301_spi_read(struct device *dev, unsigned int reg)
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
word = 0x8000 | (reg << 8);
|
||||
ret = spi_write(spi, (const u8 *)&word, sizeof(word));
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* This relies on the fact, that a transfer with NULL tx_buf shifts out
|
||||
* zero bytes (=NOOP for MAX7301)
|
||||
*/
|
||||
ret = spi_read(spi, (u8 *)&word, sizeof(word));
|
||||
ret = spi_write_then_read(spi, &word, sizeof(word), &word,
|
||||
sizeof(word));
|
||||
if (ret)
|
||||
return ret;
|
||||
return word & 0xff;
|
||||
|
@ -773,9 +773,6 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
"marvell,armada-370-gpio"))
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
/*
|
||||
* There are only two sets of PWM configuration registers for
|
||||
* all the GPIO lines on those SoCs which this driver reserves
|
||||
@ -786,6 +783,9 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
/*
|
||||
* Use set A for lines of GPIO chip with id 0, B for GPIO chip
|
||||
* with id 1. Don't allow further GPIO chips to be used for PWM.
|
||||
|
@ -32,7 +32,6 @@
|
||||
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
|
||||
|
||||
#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2)
|
||||
#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1)
|
||||
|
||||
struct gpio_regs {
|
||||
u32 irqenable1;
|
||||
@ -379,18 +378,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
||||
readl_relaxed(bank->base + bank->regs->fallingdetect);
|
||||
|
||||
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
|
||||
/* Defer wkup_en register update until we idle? */
|
||||
if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
|
||||
if (trigger)
|
||||
bank->context.wake_en |= gpio_bit;
|
||||
else
|
||||
bank->context.wake_en &= ~gpio_bit;
|
||||
} else {
|
||||
omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
|
||||
trigger != 0);
|
||||
bank->context.wake_en =
|
||||
readl_relaxed(bank->base + bank->regs->wkup_en);
|
||||
}
|
||||
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} */
|
||||
@ -942,44 +932,6 @@ omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
|
||||
bank->base + bank->regs->risingdetect);
|
||||
}
|
||||
|
||||
/*
|
||||
* On omap4 and later SoC variants a level interrupt with wkup_en
|
||||
* enabled blocks the GPIO functional clock from idling until the GPIO
|
||||
* instance has been reset. To avoid that, we must set wkup_en only for
|
||||
* idle for level interrupts, and clear level registers for the duration
|
||||
* of idle. The level interrupts will be still there on wakeup by their
|
||||
* nature.
|
||||
*/
|
||||
static void __maybe_unused
|
||||
omap4_gpio_enable_level_quirk(struct gpio_bank *bank)
|
||||
{
|
||||
/* Update wake register for idle, edge bits might be already set */
|
||||
writel_relaxed(bank->context.wake_en,
|
||||
bank->base + bank->regs->wkup_en);
|
||||
|
||||
/* Clear level registers for idle */
|
||||
writel_relaxed(0, bank->base + bank->regs->leveldetect0);
|
||||
writel_relaxed(0, bank->base + bank->regs->leveldetect1);
|
||||
}
|
||||
|
||||
static void __maybe_unused
|
||||
omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
|
||||
{
|
||||
/* Restore level registers after idle */
|
||||
writel_relaxed(bank->context.leveldetect0,
|
||||
bank->base + bank->regs->leveldetect0);
|
||||
writel_relaxed(bank->context.leveldetect1,
|
||||
bank->base + bank->regs->leveldetect1);
|
||||
|
||||
/* Clear saved wkup_en for level, it will be set for next idle again */
|
||||
bank->context.wake_en &= ~(bank->context.leveldetect0 |
|
||||
bank->context.leveldetect1);
|
||||
|
||||
/* Update wake with only edge configuration */
|
||||
writel_relaxed(bank->context.wake_en,
|
||||
bank->base + bank->regs->wkup_en);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static int omap_mpuio_suspend_noirq(struct device *dev)
|
||||
@ -1412,12 +1364,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
omap_set_gpio_dataout_mask_multiple;
|
||||
}
|
||||
|
||||
if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
|
||||
bank->funcs.idle_enable_level_quirk =
|
||||
omap4_gpio_enable_level_quirk;
|
||||
bank->funcs.idle_disable_level_quirk =
|
||||
omap4_gpio_disable_level_quirk;
|
||||
} else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
|
||||
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 =
|
||||
@ -1806,8 +1753,7 @@ 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 |
|
||||
OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN,
|
||||
.quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap_gpio_match[] = {
|
||||
|
@ -19,11 +19,28 @@
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
/**
|
||||
* struct acpi_gpio_event - ACPI GPIO event handler data
|
||||
*
|
||||
* @node: list-entry of the events list of the struct acpi_gpio_chip
|
||||
* @handle: handle of ACPI method to execute when the IRQ triggers
|
||||
* @handler: irq_handler to pass to request_irq when requesting the IRQ
|
||||
* @pin: GPIO pin number on the gpio_chip
|
||||
* @irq: Linux IRQ number for the event, for request_ / free_irq
|
||||
* @irqflags: flags to pass to request_irq when requesting the IRQ
|
||||
* @irq_is_wake: If the ACPI flags indicate the IRQ is a wakeup source
|
||||
* @is_requested: True if request_irq has been done
|
||||
* @desc: gpio_desc for the GPIO pin for this event
|
||||
*/
|
||||
struct acpi_gpio_event {
|
||||
struct list_head node;
|
||||
acpi_handle handle;
|
||||
irq_handler_t handler;
|
||||
unsigned int pin;
|
||||
unsigned int irq;
|
||||
unsigned long irqflags;
|
||||
bool irq_is_wake;
|
||||
bool irq_requested;
|
||||
struct gpio_desc *desc;
|
||||
};
|
||||
|
||||
@ -49,10 +66,10 @@ struct acpi_gpio_chip {
|
||||
|
||||
/*
|
||||
* For gpiochips which call acpi_gpiochip_request_interrupts() before late_init
|
||||
* (so builtin drivers) we register the ACPI GpioInt event handlers from a
|
||||
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
|
||||
* late_initcall_sync handler, so that other builtin drivers can register their
|
||||
* OpRegions before the event handlers can run. This list contains gpiochips
|
||||
* for which the acpi_gpiochip_request_interrupts() has been deferred.
|
||||
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
||||
*/
|
||||
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
|
||||
static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
|
||||
@ -133,8 +150,42 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
|
||||
|
||||
static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
void *context)
|
||||
static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
|
||||
struct acpi_gpio_event *event)
|
||||
{
|
||||
int ret, value;
|
||||
|
||||
ret = request_threaded_irq(event->irq, NULL, event->handler,
|
||||
event->irqflags, "ACPI:Event", event);
|
||||
if (ret) {
|
||||
dev_err(acpi_gpio->chip->parent,
|
||||
"Failed to setup interrupt handler for %d\n",
|
||||
event->irq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->irq_is_wake)
|
||||
enable_irq_wake(event->irq);
|
||||
|
||||
event->irq_requested = true;
|
||||
|
||||
/* Make sure we trigger the initial state of edge-triggered IRQs */
|
||||
value = gpiod_get_raw_value_cansleep(event->desc);
|
||||
if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
|
||||
((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
|
||||
event->handler(event->irq, event);
|
||||
}
|
||||
|
||||
static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
|
||||
{
|
||||
struct acpi_gpio_event *event;
|
||||
|
||||
list_for_each_entry(event, &acpi_gpio->events, node)
|
||||
acpi_gpiochip_request_irq(acpi_gpio, event);
|
||||
}
|
||||
|
||||
static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
void *context)
|
||||
{
|
||||
struct acpi_gpio_chip *acpi_gpio = context;
|
||||
struct gpio_chip *chip = acpi_gpio->chip;
|
||||
@ -143,8 +194,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
struct acpi_gpio_event *event;
|
||||
irq_handler_t handler = NULL;
|
||||
struct gpio_desc *desc;
|
||||
unsigned long irqflags;
|
||||
int ret, pin, irq, value;
|
||||
int ret, pin, irq;
|
||||
|
||||
if (!acpi_gpio_get_irq_resource(ares, &agpio))
|
||||
return AE_OK;
|
||||
@ -175,8 +225,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
|
||||
gpiod_direction_input(desc);
|
||||
|
||||
value = gpiod_get_value_cansleep(desc);
|
||||
|
||||
ret = gpiochip_lock_as_irq(chip, pin);
|
||||
if (ret) {
|
||||
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
|
||||
@ -189,64 +237,42 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
goto fail_unlock_irq;
|
||||
}
|
||||
|
||||
irqflags = IRQF_ONESHOT;
|
||||
if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
|
||||
if (agpio->polarity == ACPI_ACTIVE_HIGH)
|
||||
irqflags |= IRQF_TRIGGER_HIGH;
|
||||
else
|
||||
irqflags |= IRQF_TRIGGER_LOW;
|
||||
} else {
|
||||
switch (agpio->polarity) {
|
||||
case ACPI_ACTIVE_HIGH:
|
||||
irqflags |= IRQF_TRIGGER_RISING;
|
||||
break;
|
||||
case ACPI_ACTIVE_LOW:
|
||||
irqflags |= IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
default:
|
||||
irqflags |= IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||
if (!event)
|
||||
goto fail_unlock_irq;
|
||||
|
||||
event->irqflags = IRQF_ONESHOT;
|
||||
if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
|
||||
if (agpio->polarity == ACPI_ACTIVE_HIGH)
|
||||
event->irqflags |= IRQF_TRIGGER_HIGH;
|
||||
else
|
||||
event->irqflags |= IRQF_TRIGGER_LOW;
|
||||
} else {
|
||||
switch (agpio->polarity) {
|
||||
case ACPI_ACTIVE_HIGH:
|
||||
event->irqflags |= IRQF_TRIGGER_RISING;
|
||||
break;
|
||||
case ACPI_ACTIVE_LOW:
|
||||
event->irqflags |= IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
default:
|
||||
event->irqflags |= IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event->handle = evt_handle;
|
||||
event->handler = handler;
|
||||
event->irq = irq;
|
||||
event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE;
|
||||
event->pin = pin;
|
||||
event->desc = desc;
|
||||
|
||||
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
|
||||
"ACPI:Event", event);
|
||||
if (ret) {
|
||||
dev_err(chip->parent,
|
||||
"Failed to setup interrupt handler for %d\n",
|
||||
event->irq);
|
||||
goto fail_free_event;
|
||||
}
|
||||
|
||||
if (agpio->wake_capable == ACPI_WAKE_CAPABLE)
|
||||
enable_irq_wake(irq);
|
||||
|
||||
list_add_tail(&event->node, &acpi_gpio->events);
|
||||
|
||||
/*
|
||||
* Make sure we trigger the initial state of the IRQ when using RISING
|
||||
* or FALLING. Note we run the handlers on late_init, the AML code
|
||||
* may refer to OperationRegions from other (builtin) drivers which
|
||||
* may be probed after us.
|
||||
*/
|
||||
if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
|
||||
((irqflags & IRQF_TRIGGER_FALLING) && value == 0))
|
||||
handler(event->irq, event);
|
||||
|
||||
return AE_OK;
|
||||
|
||||
fail_free_event:
|
||||
kfree(event);
|
||||
fail_unlock_irq:
|
||||
gpiochip_unlock_as_irq(chip, pin);
|
||||
fail_free_desc:
|
||||
@ -283,6 +309,9 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
acpi_walk_resources(handle, "_AEI",
|
||||
acpi_gpiochip_alloc_event, acpi_gpio);
|
||||
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
defer = !acpi_gpio_deferred_req_irqs_done;
|
||||
if (defer)
|
||||
@ -293,8 +322,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||
if (defer)
|
||||
return;
|
||||
|
||||
acpi_walk_resources(handle, "_AEI",
|
||||
acpi_gpiochip_request_interrupt, acpi_gpio);
|
||||
acpi_gpiochip_request_irqs(acpi_gpio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
|
||||
|
||||
@ -331,10 +359,13 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
|
||||
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
|
||||
struct gpio_desc *desc;
|
||||
|
||||
if (irqd_is_wakeup_set(irq_get_irq_data(event->irq)))
|
||||
disable_irq_wake(event->irq);
|
||||
if (event->irq_requested) {
|
||||
if (event->irq_is_wake)
|
||||
disable_irq_wake(event->irq);
|
||||
|
||||
free_irq(event->irq, event);
|
||||
}
|
||||
|
||||
free_irq(event->irq, event);
|
||||
desc = event->desc;
|
||||
if (WARN_ON(IS_ERR(desc)))
|
||||
continue;
|
||||
@ -1200,23 +1231,16 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
|
||||
return con_id == NULL;
|
||||
}
|
||||
|
||||
/* Run deferred acpi_gpiochip_request_interrupts() */
|
||||
static int acpi_gpio_handle_deferred_request_interrupts(void)
|
||||
/* Run deferred acpi_gpiochip_request_irqs() */
|
||||
static int acpi_gpio_handle_deferred_request_irqs(void)
|
||||
{
|
||||
struct acpi_gpio_chip *acpi_gpio, *tmp;
|
||||
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
list_for_each_entry_safe(acpi_gpio, tmp,
|
||||
&acpi_gpio_deferred_req_irqs_list,
|
||||
deferred_req_irqs_list_entry) {
|
||||
acpi_handle handle;
|
||||
|
||||
handle = ACPI_HANDLE(acpi_gpio->chip->parent);
|
||||
acpi_walk_resources(handle, "_AEI",
|
||||
acpi_gpiochip_request_interrupt, acpi_gpio);
|
||||
|
||||
list_del_init(&acpi_gpio->deferred_req_irqs_list_entry);
|
||||
}
|
||||
deferred_req_irqs_list_entry)
|
||||
acpi_gpiochip_request_irqs(acpi_gpio);
|
||||
|
||||
acpi_gpio_deferred_req_irqs_done = true;
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
@ -1224,4 +1248,4 @@ static int acpi_gpio_handle_deferred_request_interrupts(void)
|
||||
return 0;
|
||||
}
|
||||
/* We must use _sync so that this runs after the first deferred_probe run */
|
||||
late_initcall_sync(acpi_gpio_handle_deferred_request_interrupts);
|
||||
late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
|
||||
|
Loading…
Reference in New Issue
Block a user