#define REG_PIN_47_SEL 0x08
#define REG_FILTER_SEL 0x0c
-#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x)))
+/*
+ * Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by
+ * bits 24 to 31. Tests on the actual HW show that these bits are
+ * stuck at 0. Bits 8 to 15 are responsive and have the expected
+ * effect.
+ */
#define REG_EDGE_POL_EDGE(x) BIT(x)
#define REG_EDGE_POL_LOW(x) BIT(16 + (x))
+#define REG_BOTH_EDGE(x) BIT(8 + (x))
+#define REG_EDGE_POL_MASK(x) ( \
+ REG_EDGE_POL_EDGE(x) | \
+ REG_EDGE_POL_LOW(x) | \
+ REG_BOTH_EDGE(x))
#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
#define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
struct meson_gpio_irq_params {
unsigned int nr_hwirq;
+ bool support_edge_both;
};
static const struct meson_gpio_irq_params meson8_params = {
.nr_hwirq = 100,
};
+static const struct meson_gpio_irq_params sm1_params = {
+ .nr_hwirq = 100,
+ .support_edge_both = true,
+};
+
static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
{ .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
{ .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
+ { .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
{ }
};
struct meson_gpio_irq_controller {
- unsigned int nr_hwirq;
+ const struct meson_gpio_irq_params *params;
void __iomem *base;
u32 channel_irqs[NUM_CHANNEL];
DECLARE_BITMAP(channel_map, NUM_CHANNEL);
*/
type &= IRQ_TYPE_SENSE_MASK;
- if (type == IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
+ /*
+ * New controller support EDGE_BOTH trigger. This setting takes
+ * precedence over the other edge/polarity settings
+ */
+ if (type == IRQ_TYPE_EDGE_BOTH) {
+ if (!ctl->params->support_edge_both)
+ return -EINVAL;
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
- val |= REG_EDGE_POL_EDGE(idx);
+ val |= REG_BOTH_EDGE(idx);
+ } else {
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ val |= REG_EDGE_POL_EDGE(idx);
- if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
- val |= REG_EDGE_POL_LOW(idx);
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+ val |= REG_EDGE_POL_LOW(idx);
+ }
spin_lock(&ctl->lock);
*/
if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
type |= IRQ_TYPE_LEVEL_HIGH;
- else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ else
type |= IRQ_TYPE_EDGE_RISING;
return type;
struct meson_gpio_irq_controller *ctl)
{
const struct of_device_id *match;
- const struct meson_gpio_irq_params *params;
int ret;
match = of_match_node(meson_irq_gpio_matches, node);
if (!match)
return -ENODEV;
- params = match->data;
- ctl->nr_hwirq = params->nr_hwirq;
+ ctl->params = match->data;
ret = of_property_read_variable_u32_array(node,
"amlogic,channel-interrupts",
if (ret)
goto free_channel_irqs;
- domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq,
+ domain = irq_domain_create_hierarchy(parent_domain, 0,
+ ctl->params->nr_hwirq,
of_node_to_fwnode(node),
&meson_gpio_irq_domain_ops,
ctl);
}
pr_info("%d to %d gpio interrupt mux initialized\n",
- ctl->nr_hwirq, NUM_CHANNEL);
+ ctl->params->nr_hwirq, NUM_CHANNEL);
return 0;