Some pin control fixes for v6.0:
- Fix IRQ wakeup and pins for UFS and SDC2 issues on the Qualcomm SC8180x - Fix the Rockchip driver to support interrupt on both rising and falling edges. - Name the Allwinner A100 R_PIO properly - Fix several issues with the Ocelot interrupts. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAmMkaAgACgkQQRCzN7AZ XXN5Hg/+Ktv4bK5aN8ldE8csIDHFQ6VCTMk70dqpLVSpbKwuoY5ag1+bmTzcqmUB zP+ToL9a2CH1rDuDhM+hPHgzjYs/qD+wdm9q1qPSpbtbNEKCvQpWxEtFsBKvcdRy JfEsK0fyld7MCJBZp9Y1qSpmcKMWaaxXaffcaE2k2fG7/BcrXpnyfa2vHdji64YE 5JXhpA6CtTmEjclVKcRw595Z8o0ml1UBjgRqWX14YQwtL5rj2bf+pWbjkN8w6DRw WyuFHxY55ww95dkTPcI5VkF5dVdrIiqilxxpiSyyDJxm2s1HUsWOPuAfo3NKyH7y s9qO5LRblvB3kS8Yuh94gzO/sgXC6D3gKDQp5Hkf6zn2X4tO1M5IH+5mZyeTPbDb LoGg4AF+E4buK3ztA0oSTe2Ok3aVwtdd4HUaWffHK7dVhET/eVEIup33hq2eY+z+ jHaC26MvP6qL7EDKNg2OY70ok1qGVupuIHz/Km/asBymzgRzotdWNCr1rxl4E3LF VY7eecXYEyCZQ9C3llaDZvbIuIQPuM0yTsI36i2fdv4aqBtgteW+gSOnPpVpoFSg j9jo8F57FKcZM28qpXSorPY0TFq2/U/rLwR5Zg8jtguudEtm2izUjiNDY/yiN7Hr 5hWn2CKVi8du7JZKJImOhQ3v/cYWqke4uv2rnwJ/D3jzPGxpFx8= =i8Nw -----END PGP SIGNATURE----- Merge tag 'pinctrl-v6.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl Pull pin control fixes from Linus Walleij: "Nothing special, just driver fixes: - Fix IRQ wakeup and pins for UFS and SDC2 issues on the Qualcomm SC8180x - Fix the Rockchip driver to support interrupt on both rising and falling edges. - Name the Allwinner A100 R_PIO properly - Fix several issues with the Ocelot interrupts" * tag 'pinctrl-v6.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: pinctrl: ocelot: Fix interrupt controller pinctrl: sunxi: Fix name for A100 R_PIO pinctrl: rockchip: Enhance support for IRQ_TYPE_EDGE_BOTH pinctrl: qcom: sc8180x: Fix wrong pin numbers pinctrl: qcom: sc8180x: Fix gpio_wakeirq_map
This commit is contained in:
Коммит
6879c2d3b9
|
@ -419,11 +419,11 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
bank->toggle_edge_mode |= mask;
|
bank->toggle_edge_mode |= mask;
|
||||||
level |= mask;
|
level &= ~mask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine gpio state. If 1 next interrupt should be
|
* Determine gpio state. If 1 next interrupt should be
|
||||||
* falling otherwise rising.
|
* low otherwise high.
|
||||||
*/
|
*/
|
||||||
data = readl(bank->reg_base + bank->gpio_regs->ext_port);
|
data = readl(bank->reg_base + bank->gpio_regs->ext_port);
|
||||||
if (data & mask)
|
if (data & mask)
|
||||||
|
|
|
@ -331,6 +331,7 @@ struct ocelot_pinctrl {
|
||||||
const struct ocelot_pincfg_data *pincfg_data;
|
const struct ocelot_pincfg_data *pincfg_data;
|
||||||
struct ocelot_pmx_func func[FUNC_MAX];
|
struct ocelot_pmx_func func[FUNC_MAX];
|
||||||
u8 stride;
|
u8 stride;
|
||||||
|
struct workqueue_struct *wq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ocelot_match_data {
|
struct ocelot_match_data {
|
||||||
|
@ -338,6 +339,11 @@ struct ocelot_match_data {
|
||||||
struct ocelot_pincfg_data pincfg_data;
|
struct ocelot_pincfg_data pincfg_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ocelot_irq_work {
|
||||||
|
struct work_struct irq_work;
|
||||||
|
struct irq_desc *irq_desc;
|
||||||
|
};
|
||||||
|
|
||||||
#define LUTON_P(p, f0, f1) \
|
#define LUTON_P(p, f0, f1) \
|
||||||
static struct ocelot_pin_caps luton_pin_##p = { \
|
static struct ocelot_pin_caps luton_pin_##p = { \
|
||||||
.pin = p, \
|
.pin = p, \
|
||||||
|
@ -1813,6 +1819,75 @@ static void ocelot_irq_mask(struct irq_data *data)
|
||||||
gpiochip_disable_irq(chip, gpio);
|
gpiochip_disable_irq(chip, gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ocelot_irq_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ocelot_irq_work *w = container_of(work, struct ocelot_irq_work, irq_work);
|
||||||
|
struct irq_chip *parent_chip = irq_desc_get_chip(w->irq_desc);
|
||||||
|
struct gpio_chip *chip = irq_desc_get_chip_data(w->irq_desc);
|
||||||
|
struct irq_data *data = irq_desc_get_irq_data(w->irq_desc);
|
||||||
|
unsigned int gpio = irqd_to_hwirq(data);
|
||||||
|
|
||||||
|
local_irq_disable();
|
||||||
|
chained_irq_enter(parent_chip, w->irq_desc);
|
||||||
|
generic_handle_domain_irq(chip->irq.domain, gpio);
|
||||||
|
chained_irq_exit(parent_chip, w->irq_desc);
|
||||||
|
local_irq_enable();
|
||||||
|
|
||||||
|
kfree(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocelot_irq_unmask_level(struct irq_data *data)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||||
|
struct ocelot_pinctrl *info = gpiochip_get_data(chip);
|
||||||
|
struct irq_desc *desc = irq_data_to_desc(data);
|
||||||
|
unsigned int gpio = irqd_to_hwirq(data);
|
||||||
|
unsigned int bit = BIT(gpio % 32);
|
||||||
|
bool ack = false, active = false;
|
||||||
|
u8 trigger_level;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
trigger_level = irqd_get_trigger_type(data);
|
||||||
|
|
||||||
|
/* Check if the interrupt line is still active. */
|
||||||
|
regmap_read(info->map, REG(OCELOT_GPIO_IN, info, gpio), &val);
|
||||||
|
if ((!(val & bit) && trigger_level == IRQ_TYPE_LEVEL_LOW) ||
|
||||||
|
(val & bit && trigger_level == IRQ_TYPE_LEVEL_HIGH))
|
||||||
|
active = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the interrupt controller has seen any changes in the
|
||||||
|
* interrupt line.
|
||||||
|
*/
|
||||||
|
regmap_read(info->map, REG(OCELOT_GPIO_INTR, info, gpio), &val);
|
||||||
|
if (val & bit)
|
||||||
|
ack = true;
|
||||||
|
|
||||||
|
/* Enable the interrupt now */
|
||||||
|
gpiochip_enable_irq(chip, gpio);
|
||||||
|
regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
|
||||||
|
bit, bit);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case the interrupt line is still active and the interrupt
|
||||||
|
* controller has not seen any changes in the interrupt line, then it
|
||||||
|
* means that there happen another interrupt while the line was active.
|
||||||
|
* So we missed that one, so we need to kick the interrupt again
|
||||||
|
* handler.
|
||||||
|
*/
|
||||||
|
if (active && !ack) {
|
||||||
|
struct ocelot_irq_work *work;
|
||||||
|
|
||||||
|
work = kmalloc(sizeof(*work), GFP_ATOMIC);
|
||||||
|
if (!work)
|
||||||
|
return;
|
||||||
|
|
||||||
|
work->irq_desc = desc;
|
||||||
|
INIT_WORK(&work->irq_work, ocelot_irq_work);
|
||||||
|
queue_work(info->wq, &work->irq_work);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ocelot_irq_unmask(struct irq_data *data)
|
static void ocelot_irq_unmask(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||||
|
@ -1836,13 +1911,12 @@ static void ocelot_irq_ack(struct irq_data *data)
|
||||||
|
|
||||||
static int ocelot_irq_set_type(struct irq_data *data, unsigned int type);
|
static int ocelot_irq_set_type(struct irq_data *data, unsigned int type);
|
||||||
|
|
||||||
static struct irq_chip ocelot_eoi_irqchip = {
|
static struct irq_chip ocelot_level_irqchip = {
|
||||||
.name = "gpio",
|
.name = "gpio",
|
||||||
.irq_mask = ocelot_irq_mask,
|
.irq_mask = ocelot_irq_mask,
|
||||||
.irq_eoi = ocelot_irq_ack,
|
.irq_ack = ocelot_irq_ack,
|
||||||
.irq_unmask = ocelot_irq_unmask,
|
.irq_unmask = ocelot_irq_unmask_level,
|
||||||
.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
|
.flags = IRQCHIP_IMMUTABLE,
|
||||||
IRQCHIP_IMMUTABLE,
|
|
||||||
.irq_set_type = ocelot_irq_set_type,
|
.irq_set_type = ocelot_irq_set_type,
|
||||||
GPIOCHIP_IRQ_RESOURCE_HELPERS
|
GPIOCHIP_IRQ_RESOURCE_HELPERS
|
||||||
};
|
};
|
||||||
|
@ -1859,14 +1933,9 @@ static struct irq_chip ocelot_irqchip = {
|
||||||
|
|
||||||
static int ocelot_irq_set_type(struct irq_data *data, unsigned int type)
|
static int ocelot_irq_set_type(struct irq_data *data, unsigned int type)
|
||||||
{
|
{
|
||||||
type &= IRQ_TYPE_SENSE_MASK;
|
if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||||
|
irq_set_chip_handler_name_locked(data, &ocelot_level_irqchip,
|
||||||
if (!(type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_HIGH)))
|
handle_level_irq, NULL);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (type & IRQ_TYPE_LEVEL_HIGH)
|
|
||||||
irq_set_chip_handler_name_locked(data, &ocelot_eoi_irqchip,
|
|
||||||
handle_fasteoi_irq, NULL);
|
|
||||||
if (type & IRQ_TYPE_EDGE_BOTH)
|
if (type & IRQ_TYPE_EDGE_BOTH)
|
||||||
irq_set_chip_handler_name_locked(data, &ocelot_irqchip,
|
irq_set_chip_handler_name_locked(data, &ocelot_irqchip,
|
||||||
handle_edge_irq, NULL);
|
handle_edge_irq, NULL);
|
||||||
|
@ -1996,6 +2065,10 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
|
||||||
if (!info->desc)
|
if (!info->desc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
info->wq = alloc_ordered_workqueue("ocelot_ordered", 0);
|
||||||
|
if (!info->wq)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
info->pincfg_data = &data->pincfg_data;
|
info->pincfg_data = &data->pincfg_data;
|
||||||
|
|
||||||
reset = devm_reset_control_get_optional_shared(dev, "switch");
|
reset = devm_reset_control_get_optional_shared(dev, "switch");
|
||||||
|
@ -2018,7 +2091,7 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
|
||||||
dev_err(dev, "Failed to create regmap\n");
|
dev_err(dev, "Failed to create regmap\n");
|
||||||
return PTR_ERR(info->map);
|
return PTR_ERR(info->map);
|
||||||
}
|
}
|
||||||
dev_set_drvdata(dev, info->map);
|
dev_set_drvdata(dev, info);
|
||||||
info->dev = dev;
|
info->dev = dev;
|
||||||
|
|
||||||
/* Pinconf registers */
|
/* Pinconf registers */
|
||||||
|
@ -2043,6 +2116,15 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ocelot_pinctrl_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct ocelot_pinctrl *info = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
destroy_workqueue(info->wq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct platform_driver ocelot_pinctrl_driver = {
|
static struct platform_driver ocelot_pinctrl_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "pinctrl-ocelot",
|
.name = "pinctrl-ocelot",
|
||||||
|
@ -2050,6 +2132,7 @@ static struct platform_driver ocelot_pinctrl_driver = {
|
||||||
.suppress_bind_attrs = true,
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
.probe = ocelot_pinctrl_probe,
|
.probe = ocelot_pinctrl_probe,
|
||||||
|
.remove = ocelot_pinctrl_remove,
|
||||||
};
|
};
|
||||||
module_platform_driver(ocelot_pinctrl_driver);
|
module_platform_driver(ocelot_pinctrl_driver);
|
||||||
MODULE_LICENSE("Dual MIT/GPL");
|
MODULE_LICENSE("Dual MIT/GPL");
|
||||||
|
|
|
@ -530,10 +530,10 @@ DECLARE_MSM_GPIO_PINS(187);
|
||||||
DECLARE_MSM_GPIO_PINS(188);
|
DECLARE_MSM_GPIO_PINS(188);
|
||||||
DECLARE_MSM_GPIO_PINS(189);
|
DECLARE_MSM_GPIO_PINS(189);
|
||||||
|
|
||||||
static const unsigned int sdc2_clk_pins[] = { 190 };
|
static const unsigned int ufs_reset_pins[] = { 190 };
|
||||||
static const unsigned int sdc2_cmd_pins[] = { 191 };
|
static const unsigned int sdc2_clk_pins[] = { 191 };
|
||||||
static const unsigned int sdc2_data_pins[] = { 192 };
|
static const unsigned int sdc2_cmd_pins[] = { 192 };
|
||||||
static const unsigned int ufs_reset_pins[] = { 193 };
|
static const unsigned int sdc2_data_pins[] = { 193 };
|
||||||
|
|
||||||
enum sc8180x_functions {
|
enum sc8180x_functions {
|
||||||
msm_mux_adsp_ext,
|
msm_mux_adsp_ext,
|
||||||
|
@ -1582,7 +1582,7 @@ static const int sc8180x_acpi_reserved_gpios[] = {
|
||||||
static const struct msm_gpio_wakeirq_map sc8180x_pdc_map[] = {
|
static const struct msm_gpio_wakeirq_map sc8180x_pdc_map[] = {
|
||||||
{ 3, 31 }, { 5, 32 }, { 8, 33 }, { 9, 34 }, { 10, 100 }, { 12, 104 },
|
{ 3, 31 }, { 5, 32 }, { 8, 33 }, { 9, 34 }, { 10, 100 }, { 12, 104 },
|
||||||
{ 24, 37 }, { 26, 38 }, { 27, 41 }, { 28, 42 }, { 30, 39 }, { 36, 43 },
|
{ 24, 37 }, { 26, 38 }, { 27, 41 }, { 28, 42 }, { 30, 39 }, { 36, 43 },
|
||||||
{ 37, 43 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
|
{ 37, 44 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
|
||||||
{ 42, 48 }, { 46, 50 }, { 47, 49 }, { 48, 51 }, { 49, 53 }, { 50, 52 },
|
{ 42, 48 }, { 46, 50 }, { 47, 49 }, { 48, 51 }, { 49, 53 }, { 50, 52 },
|
||||||
{ 51, 116 }, { 51, 123 }, { 53, 54 }, { 54, 55 }, { 55, 56 },
|
{ 51, 116 }, { 51, 123 }, { 53, 54 }, { 54, 55 }, { 55, 56 },
|
||||||
{ 56, 57 }, { 58, 58 }, { 60, 60 }, { 68, 62 }, { 70, 63 }, { 76, 86 },
|
{ 56, 57 }, { 58, 58 }, { 60, 60 }, { 68, 62 }, { 70, 63 }, { 76, 86 },
|
||||||
|
|
|
@ -99,7 +99,7 @@ MODULE_DEVICE_TABLE(of, a100_r_pinctrl_match);
|
||||||
static struct platform_driver a100_r_pinctrl_driver = {
|
static struct platform_driver a100_r_pinctrl_driver = {
|
||||||
.probe = a100_r_pinctrl_probe,
|
.probe = a100_r_pinctrl_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sun50iw10p1-r-pinctrl",
|
.name = "sun50i-a100-r-pinctrl",
|
||||||
.of_match_table = a100_r_pinctrl_match,
|
.of_match_table = a100_r_pinctrl_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче