Merge tag 'gpio-v4.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO fix from Linus Walleij: "This is a single GPIO fix for the v4.16 series affecting the Renesas driver, and fixes wakeup from external stuff" * tag 'gpio-v4.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: gpio: rcar: Use wakeup_path i.s.o. explicit clock handling
This commit is contained in:
@ -14,7 +14,6 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
@ -37,10 +36,9 @@ struct gpio_rcar_priv {
|
|||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct gpio_chip gpio_chip;
|
struct gpio_chip gpio_chip;
|
||||||
struct irq_chip irq_chip;
|
struct irq_chip irq_chip;
|
||||||
struct clk *clk;
|
|
||||||
unsigned int irq_parent;
|
unsigned int irq_parent;
|
||||||
|
atomic_t wakeup_path;
|
||||||
bool has_both_edge_trigger;
|
bool has_both_edge_trigger;
|
||||||
bool needs_clk;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||||
@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p->clk)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (on)
|
if (on)
|
||||||
clk_enable(p->clk);
|
atomic_inc(&p->wakeup_path);
|
||||||
else
|
else
|
||||||
clk_disable(p->clk);
|
atomic_dec(&p->wakeup_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||||||
|
|
||||||
struct gpio_rcar_info {
|
struct gpio_rcar_info {
|
||||||
bool has_both_edge_trigger;
|
bool has_both_edge_trigger;
|
||||||
bool needs_clk;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
|
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
|
||||||
.has_both_edge_trigger = false,
|
.has_both_edge_trigger = false,
|
||||||
.needs_clk = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
|
static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
|
||||||
.has_both_edge_trigger = true,
|
.has_both_edge_trigger = true,
|
||||||
.needs_clk = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id gpio_rcar_of_table[] = {
|
static const struct of_device_id gpio_rcar_of_table[] = {
|
||||||
@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
|
|||||||
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
|
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
|
||||||
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
|
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
|
||||||
p->has_both_edge_trigger = info->has_both_edge_trigger;
|
p->has_both_edge_trigger = info->has_both_edge_trigger;
|
||||||
p->needs_clk = info->needs_clk;
|
|
||||||
|
|
||||||
if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
|
if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
|
||||||
dev_warn(&p->pdev->dev,
|
dev_warn(&p->pdev->dev,
|
||||||
@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, p);
|
platform_set_drvdata(pdev, p);
|
||||||
|
|
||||||
p->clk = devm_clk_get(dev, NULL);
|
|
||||||
if (IS_ERR(p->clk)) {
|
|
||||||
if (p->needs_clk) {
|
|
||||||
dev_err(dev, "unable to get clock\n");
|
|
||||||
ret = PTR_ERR(p->clk);
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
p->clk = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused gpio_rcar_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct gpio_rcar_priv *p = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (atomic_read(&p->wakeup_path))
|
||||||
|
device_set_wakeup_path(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL);
|
||||||
|
|
||||||
static struct platform_driver gpio_rcar_device_driver = {
|
static struct platform_driver gpio_rcar_device_driver = {
|
||||||
.probe = gpio_rcar_probe,
|
.probe = gpio_rcar_probe,
|
||||||
.remove = gpio_rcar_remove,
|
.remove = gpio_rcar_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gpio_rcar",
|
.name = "gpio_rcar",
|
||||||
|
.pm = &gpio_rcar_pm_ops,
|
||||||
.of_match_table = of_match_ptr(gpio_rcar_of_table),
|
.of_match_table = of_match_ptr(gpio_rcar_of_table),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user