#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x)))
#define REG_EDGE_POL_EDGE(x) BIT(x)
#define REG_EDGE_POL_LOW(x) BIT(16 + (x))
+#define REG_EDGE_BOTH_EDGE(x) BIT(8 + (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;
+ u8 support_double_edge;
};
static const struct meson_gpio_irq_params meson8_params = {
.nr_hwirq = 102,
};
+static const struct meson_gpio_irq_params sm1_params = {
+ .nr_hwirq = 100,
+ .support_double_edge = 1,
+};
+
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-g12a-gpio-intc", .data = &g12a_params },
{ .compatible = "amlogic,meson-txl-gpio-intc", .data = &txl_params },
{ .compatible = "amlogic,meson-tl1-gpio-intc", .data = &tl1_params },
+ { .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
{ }
};
struct meson_gpio_irq_controller {
unsigned int nr_hwirq;
+ u8 support_double_edge;
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;
+ if (type == IRQ_TYPE_EDGE_BOTH) {
+ if (!ctl->support_double_edge)
+ return -EINVAL;
+ val |= REG_EDGE_BOTH_EDGE(idx);
+ spin_lock(&ctl->lock);
+ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
+ REG_EDGE_BOTH_EDGE(idx), val);
+ spin_unlock(&ctl->lock);
+ return 0;
+ }
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_EDGE(idx);
spin_lock(&ctl->lock);
+ /* Double-edge has priority over all others. If a double-edge gpio
+ * changes to another method's, we need to reset the corresponding bit
+ * of double-edge register.
+ */
+ if (ctl->support_double_edge)
+ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
+ REG_EDGE_BOTH_EDGE(idx), 0);
+
meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
REG_EDGE_POL_MASK(idx), val);
params = match->data;
ctl->nr_hwirq = params->nr_hwirq;
+ ctl->support_double_edge = params->support_double_edge;
ret = of_property_read_variable_u32_array(node,
"amlogic,channel-interrupts",