mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
A single patch to the Qualcomm driver fixing missing dual
edge PCH interrupts. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl8lenUACgkQQRCzN7AZ XXMBTRAAwHvIfwQIau/WdxdWEWowubi5pe5FyINYasMzCBmMBKIHSUnPeI9dtcMn 7gLWaeGzgI/MldyHenmfcnbnUNYhXvlvLHutTf3pnt+pe0/WqJaWH79okKygzCbJ 8bDul2/YsiYU0Z642uSqtYtl/w/OFtEJCuffdWywOncso8FzoPbtSBrjveuuLgvq zMLeS9IaWkTtuGQe1GynFV/nZxCAPm74H99+RSLiAYoMQG+knqRhEYLDyLtoaPpK E5SSM76D6nRe/brPCc1oFzzAnlWFrAi5EfycrKjaRkOE2F4FbkGKy7w/7j4zxwEw kvDZD9LmGrPVHrpRpP8zLjwQDpi9IuMfCjM0KsgRqY0N1vxvzIpqO4APqUeFDXdu Ls+cmEkbnB7MJmTX+TXUvywfhHlM58BxnCEzFAq4uzJOllMT17dyWRIpIBxotUqA PSM9pHZ6ykKnEwCrJKGzvF9PO0FC0iemr+rJuXic/2YlzW3oit3jhapKA7qUSIRS dSjSSG/AlVc380EKpbePAhq4AZKYOhvZK0UVkeyONIV4MM8qlFDd9Hf1huqbq+sM nuJqBtuDOPjyw3o0vDfSYTlCqNXjzPdfU1WtbXGFTRNyQ6OwTCtj+kV8/AVLH2UW KF0gLsolV4btkiQfw3IDoPCwlbRCEXC5IyznzMBv2CfDCxQZur0= =sCkm -----END PGP SIGNATURE----- Merge tag 'pinctrl-v5.8-4' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl Pull pin control fix from Linus Walleij: "A single last minute pin control fix to the Qualcomm driver fixing missing dual edge PCH interrupts" * tag 'pinctrl-v5.8-4' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: pinctrl: qcom: Handle broken/missing PDC dual edge IRQs on sc7180
This commit is contained in:
commit
d52daa8620
@ -7,6 +7,8 @@ config PINCTRL_MSM
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select IRQ_FASTEOI_HIERARCHY_HANDLERS
|
||||
|
||||
config PINCTRL_APQ8064
|
||||
tristate "Qualcomm APQ8064 pin controller driver"
|
||||
|
@ -832,6 +832,52 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
|
||||
msm_gpio_irq_clear_unmask(d, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_gpio_update_dual_edge_parent() - Prime next edge for IRQs handled by parent.
|
||||
* @d: The irq dta.
|
||||
*
|
||||
* This is much like msm_gpio_update_dual_edge_pos() but for IRQs that are
|
||||
* normally handled by the parent irqchip. The logic here is slightly
|
||||
* different due to what's easy to do with our parent, but in principle it's
|
||||
* the same.
|
||||
*/
|
||||
static void msm_gpio_update_dual_edge_parent(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
const struct msm_pingroup *g = &pctrl->soc->groups[d->hwirq];
|
||||
int loop_limit = 100;
|
||||
unsigned int val;
|
||||
unsigned int type;
|
||||
|
||||
/* Read the value and make a guess about what edge we need to catch */
|
||||
val = msm_readl_io(pctrl, g) & BIT(g->in_bit);
|
||||
type = val ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
do {
|
||||
/* Set the parent to catch the next edge */
|
||||
irq_chip_set_type_parent(d, type);
|
||||
|
||||
/*
|
||||
* Possibly the line changed between when we last read "val"
|
||||
* (and decided what edge we needed) and when set the edge.
|
||||
* If the value didn't change (or changed and then changed
|
||||
* back) then we're done.
|
||||
*/
|
||||
val = msm_readl_io(pctrl, g) & BIT(g->in_bit);
|
||||
if (type == IRQ_TYPE_EDGE_RISING) {
|
||||
if (!val)
|
||||
return;
|
||||
type = IRQ_TYPE_EDGE_FALLING;
|
||||
} else if (type == IRQ_TYPE_EDGE_FALLING) {
|
||||
if (val)
|
||||
return;
|
||||
type = IRQ_TYPE_EDGE_RISING;
|
||||
}
|
||||
} while (loop_limit-- > 0);
|
||||
dev_warn_once(pctrl->dev, "dual-edge irq failed to stabilize\n");
|
||||
}
|
||||
|
||||
static void msm_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
@ -840,8 +886,11 @@ static void msm_gpio_irq_ack(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
|
||||
if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) {
|
||||
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
|
||||
msm_gpio_update_dual_edge_parent(d);
|
||||
return;
|
||||
}
|
||||
|
||||
g = &pctrl->soc->groups[d->hwirq];
|
||||
|
||||
@ -860,6 +909,17 @@ static void msm_gpio_irq_ack(struct irq_data *d)
|
||||
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
|
||||
}
|
||||
|
||||
static bool msm_gpio_needs_dual_edge_parent_workaround(struct irq_data *d,
|
||||
unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
|
||||
return type == IRQ_TYPE_EDGE_BOTH &&
|
||||
pctrl->soc->wakeirq_dual_edge_errata && d->parent_data &&
|
||||
test_bit(d->hwirq, pctrl->skip_wake_irqs);
|
||||
}
|
||||
|
||||
static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
@ -868,11 +928,21 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) {
|
||||
set_bit(d->hwirq, pctrl->dual_edge_irqs);
|
||||
irq_set_handler_locked(d, handle_fasteoi_ack_irq);
|
||||
msm_gpio_update_dual_edge_parent(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->parent_data)
|
||||
irq_chip_set_type_parent(d, type);
|
||||
|
||||
if (test_bit(d->hwirq, pctrl->skip_wake_irqs))
|
||||
if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) {
|
||||
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
|
||||
irq_set_handler_locked(d, handle_fasteoi_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
g = &pctrl->soc->groups[d->hwirq];
|
||||
|
||||
|
@ -113,6 +113,9 @@ struct msm_gpio_wakeirq_map {
|
||||
* @pull_no_keeper: The SoC does not support keeper bias.
|
||||
* @wakeirq_map: The map of wakeup capable GPIOs and the pin at PDC/MPM
|
||||
* @nwakeirq_map: The number of entries in @wakeirq_map
|
||||
* @wakeirq_dual_edge_errata: If true then GPIOs using the wakeirq_map need
|
||||
* to be aware that their parent can't handle dual
|
||||
* edge interrupts.
|
||||
*/
|
||||
struct msm_pinctrl_soc_data {
|
||||
const struct pinctrl_pin_desc *pins;
|
||||
@ -128,6 +131,7 @@ struct msm_pinctrl_soc_data {
|
||||
const int *reserved_gpios;
|
||||
const struct msm_gpio_wakeirq_map *wakeirq_map;
|
||||
unsigned int nwakeirq_map;
|
||||
bool wakeirq_dual_edge_errata;
|
||||
};
|
||||
|
||||
extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
|
||||
|
@ -1147,6 +1147,7 @@ static const struct msm_pinctrl_soc_data sc7180_pinctrl = {
|
||||
.ntiles = ARRAY_SIZE(sc7180_tiles),
|
||||
.wakeirq_map = sc7180_pdc_map,
|
||||
.nwakeirq_map = ARRAY_SIZE(sc7180_pdc_map),
|
||||
.wakeirq_dual_edge_errata = true,
|
||||
};
|
||||
|
||||
static int sc7180_pinctrl_probe(struct platform_device *pdev)
|
||||
|
Loading…
Reference in New Issue
Block a user