Merge branch irq/meson-gpio into irq/irqchip-next
* irq/meson-gpio: : . : Expand meson-gpio support to deal with the new Meson-S4 SoC : . irqchip/meson-gpio: Add support for meson s4 SoCs irqchip/meson-gpio: add select trigger type callback irqchip/meson-gpio: support more than 8 channels gpio irq dt-bindings: interrupt-controller: New binding for Meson-S4 SoCs Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
commit
92af5d4790
|
@ -18,6 +18,7 @@ Required properties:
|
|||
"amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2)
|
||||
"amlogic,meson-sm1-gpio-intc" for SM1 SoCs (S905D3, S905X3, S905Y3)
|
||||
"amlogic,meson-a1-gpio-intc" for A1 SoCs (A113L)
|
||||
"amlogic,meson-s4-gpio-intc" for S4 SoCs (S802X2, S905Y4, S805X2G, S905W2)
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
- interrupt-controller : Identifies the node as an interrupt controller.
|
||||
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#define NUM_CHANNEL 8
|
||||
#define MAX_NUM_CHANNEL 64
|
||||
#define MAX_INPUT_MUX 256
|
||||
|
||||
#define REG_EDGE_POL 0x00
|
||||
|
@ -26,6 +26,8 @@
|
|||
|
||||
/* use for A1 like chips */
|
||||
#define REG_PIN_A1_SEL 0x04
|
||||
/* Used for s4 chips */
|
||||
#define REG_EDGE_POL_S4 0x1c
|
||||
|
||||
/*
|
||||
* Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by
|
||||
|
@ -51,15 +53,22 @@ static void meson_a1_gpio_irq_sel_pin(struct meson_gpio_irq_controller *ctl,
|
|||
unsigned int channel,
|
||||
unsigned long hwirq);
|
||||
static void meson_a1_gpio_irq_init(struct meson_gpio_irq_controller *ctl);
|
||||
static int meson8_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type, u32 *channel_hwirq);
|
||||
static int meson_s4_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type, u32 *channel_hwirq);
|
||||
|
||||
struct irq_ctl_ops {
|
||||
void (*gpio_irq_sel_pin)(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int channel, unsigned long hwirq);
|
||||
void (*gpio_irq_init)(struct meson_gpio_irq_controller *ctl);
|
||||
int (*gpio_irq_set_type)(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type, u32 *channel_hwirq);
|
||||
};
|
||||
|
||||
struct meson_gpio_irq_params {
|
||||
unsigned int nr_hwirq;
|
||||
unsigned int nr_channels;
|
||||
bool support_edge_both;
|
||||
unsigned int edge_both_offset;
|
||||
unsigned int edge_single_offset;
|
||||
|
@ -68,28 +77,44 @@ struct meson_gpio_irq_params {
|
|||
struct irq_ctl_ops ops;
|
||||
};
|
||||
|
||||
#define INIT_MESON_COMMON(irqs, init, sel) \
|
||||
#define INIT_MESON_COMMON(irqs, init, sel, type) \
|
||||
.nr_hwirq = irqs, \
|
||||
.ops = { \
|
||||
.gpio_irq_init = init, \
|
||||
.gpio_irq_sel_pin = sel, \
|
||||
.gpio_irq_set_type = type, \
|
||||
},
|
||||
|
||||
#define INIT_MESON8_COMMON_DATA(irqs) \
|
||||
INIT_MESON_COMMON(irqs, meson_gpio_irq_init_dummy, \
|
||||
meson8_gpio_irq_sel_pin) \
|
||||
meson8_gpio_irq_sel_pin, \
|
||||
meson8_gpio_irq_set_type) \
|
||||
.edge_single_offset = 0, \
|
||||
.pol_low_offset = 16, \
|
||||
.pin_sel_mask = 0xff, \
|
||||
.nr_channels = 8, \
|
||||
|
||||
#define INIT_MESON_A1_COMMON_DATA(irqs) \
|
||||
INIT_MESON_COMMON(irqs, meson_a1_gpio_irq_init, \
|
||||
meson_a1_gpio_irq_sel_pin) \
|
||||
meson_a1_gpio_irq_sel_pin, \
|
||||
meson8_gpio_irq_set_type) \
|
||||
.support_edge_both = true, \
|
||||
.edge_both_offset = 16, \
|
||||
.edge_single_offset = 8, \
|
||||
.pol_low_offset = 0, \
|
||||
.pin_sel_mask = 0x7f, \
|
||||
.nr_channels = 8, \
|
||||
|
||||
#define INIT_MESON_S4_COMMON_DATA(irqs) \
|
||||
INIT_MESON_COMMON(irqs, meson_a1_gpio_irq_init, \
|
||||
meson_a1_gpio_irq_sel_pin, \
|
||||
meson_s4_gpio_irq_set_type) \
|
||||
.support_edge_both = true, \
|
||||
.edge_both_offset = 0, \
|
||||
.edge_single_offset = 12, \
|
||||
.pol_low_offset = 0, \
|
||||
.pin_sel_mask = 0xff, \
|
||||
.nr_channels = 12, \
|
||||
|
||||
static const struct meson_gpio_irq_params meson8_params = {
|
||||
INIT_MESON8_COMMON_DATA(134)
|
||||
|
@ -121,6 +146,10 @@ static const struct meson_gpio_irq_params a1_params = {
|
|||
INIT_MESON_A1_COMMON_DATA(62)
|
||||
};
|
||||
|
||||
static const struct meson_gpio_irq_params s4_params = {
|
||||
INIT_MESON_S4_COMMON_DATA(82)
|
||||
};
|
||||
|
||||
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 },
|
||||
|
@ -130,14 +159,15 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
|
|||
{ .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
|
||||
{ .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
|
||||
{ .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params },
|
||||
{ .compatible = "amlogic,meson-s4-gpio-intc", .data = &s4_params },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct meson_gpio_irq_controller {
|
||||
const struct meson_gpio_irq_params *params;
|
||||
void __iomem *base;
|
||||
u32 channel_irqs[NUM_CHANNEL];
|
||||
DECLARE_BITMAP(channel_map, NUM_CHANNEL);
|
||||
u32 channel_irqs[MAX_NUM_CHANNEL];
|
||||
DECLARE_BITMAP(channel_map, MAX_NUM_CHANNEL);
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
@ -207,8 +237,8 @@ meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl,
|
|||
spin_lock_irqsave(&ctl->lock, flags);
|
||||
|
||||
/* Find a free channel */
|
||||
idx = find_first_zero_bit(ctl->channel_map, NUM_CHANNEL);
|
||||
if (idx >= NUM_CHANNEL) {
|
||||
idx = find_first_zero_bit(ctl->channel_map, ctl->params->nr_channels);
|
||||
if (idx >= ctl->params->nr_channels) {
|
||||
spin_unlock_irqrestore(&ctl->lock, flags);
|
||||
pr_err("No channel available\n");
|
||||
return -ENOSPC;
|
||||
|
@ -256,9 +286,8 @@ meson_gpio_irq_release_channel(struct meson_gpio_irq_controller *ctl,
|
|||
clear_bit(idx, ctl->channel_map);
|
||||
}
|
||||
|
||||
static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type,
|
||||
u32 *channel_hwirq)
|
||||
static int meson8_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type, u32 *channel_hwirq)
|
||||
{
|
||||
u32 val = 0;
|
||||
unsigned int idx;
|
||||
|
@ -299,6 +328,51 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* gpio irq relative registers for s4
|
||||
* -PADCTRL_GPIO_IRQ_CTRL0
|
||||
* bit[31]: enable/disable all the irq lines
|
||||
* bit[12-23]: single edge trigger
|
||||
* bit[0-11]: polarity trigger
|
||||
*
|
||||
* -PADCTRL_GPIO_IRQ_CTRL[X]
|
||||
* bit[0-16]: 7 bits to choose gpio source for irq line 2*[X] - 2
|
||||
* bit[16-22]:7 bits to choose gpio source for irq line 2*[X] - 1
|
||||
* where X = 1-6
|
||||
*
|
||||
* -PADCTRL_GPIO_IRQ_CTRL[7]
|
||||
* bit[0-11]: both edge trigger
|
||||
*/
|
||||
static int meson_s4_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl,
|
||||
unsigned int type, u32 *channel_hwirq)
|
||||
{
|
||||
u32 val = 0;
|
||||
unsigned int idx;
|
||||
|
||||
idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq);
|
||||
|
||||
type &= IRQ_TYPE_SENSE_MASK;
|
||||
|
||||
meson_gpio_irq_update_bits(ctl, REG_EDGE_POL_S4, BIT(idx), 0);
|
||||
|
||||
if (type == IRQ_TYPE_EDGE_BOTH) {
|
||||
val |= BIT(ctl->params->edge_both_offset + idx);
|
||||
meson_gpio_irq_update_bits(ctl, REG_EDGE_POL_S4,
|
||||
BIT(ctl->params->edge_both_offset + idx), val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
|
||||
val |= BIT(ctl->params->pol_low_offset + idx);
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
val |= BIT(ctl->params->edge_single_offset + idx);
|
||||
|
||||
meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
|
||||
BIT(idx) | BIT(12 + idx), val);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static unsigned int meson_gpio_irq_type_output(unsigned int type)
|
||||
{
|
||||
unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
|
||||
|
@ -323,7 +397,7 @@ static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
|||
u32 *channel_hwirq = irq_data_get_irq_chip_data(data);
|
||||
int ret;
|
||||
|
||||
ret = meson_gpio_irq_type_setup(ctl, type, channel_hwirq);
|
||||
ret = ctl->params->ops.gpio_irq_set_type(ctl, type, channel_hwirq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -450,10 +524,10 @@ static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_i
|
|||
ret = of_property_read_variable_u32_array(node,
|
||||
"amlogic,channel-interrupts",
|
||||
ctl->channel_irqs,
|
||||
NUM_CHANNEL,
|
||||
NUM_CHANNEL);
|
||||
ctl->params->nr_channels,
|
||||
ctl->params->nr_channels);
|
||||
if (ret < 0) {
|
||||
pr_err("can't get %d channel interrupts\n", NUM_CHANNEL);
|
||||
pr_err("can't get %d channel interrupts\n", ctl->params->nr_channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -507,7 +581,7 @@ static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *
|
|||
}
|
||||
|
||||
pr_info("%d to %d gpio interrupt mux initialized\n",
|
||||
ctl->params->nr_hwirq, NUM_CHANNEL);
|
||||
ctl->params->nr_hwirq, ctl->params->nr_channels);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue