diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt new file mode 100644 index 000000000000..e08cf49dec42 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt @@ -0,0 +1,38 @@ +Amlogic meson GPIO interrupt controller + +Meson SoCs contains an interrupt controller which is able to watch the SoC +pads and generate an interrupt on edge or level. The controller is essentially +a 256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge +or level and polarity. It does not expose all 256 mux inputs because the +documentation shows that the upper part is not mapped to any pad. The actual +number of interrupt exposed depends on the SoC. + +Required properties: + +- compatible : must have "amlogic,meson8-gpio-intc” and either + “amlogic,meson8-gpio-intc” for meson8 SoCs (S802) or + “amlogic,meson8b-gpio-intc” for meson8b SoCs (S805) or + “amlogic,meson-gxbb-gpio-intc” for GXBB SoCs (S905) or + “amlogic,meson-gxl-gpio-intc” for GXL SoCs (S905X, S912) or + “amlogic,meson-axg-gpio-intc” for AXG SoCs (A113G, A113D) or + “amlogic,meson-txlx-gpio-intc” for TXLX SoCs (T962X, T962E) +- interrupt-parent : a phandle to the GIC the interrupts are routed to. + Usually this is provided at the root level of the device tree as it is + common to most of the SoC. +- 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 + interrupt source. The value must be 2. +- meson,channel-interrupts: Array with the 8 upstream hwirq numbers. These + are the hwirqs used on the parent interrupt controller. + +Example: + +gpio_interrupt: interrupt-controller@9880 { + compatible = "amlogic,meson-gxbb-gpio-intc", + "amlogic,meson-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + meson,channel-interrupts = <64 65 66 67 68 69 70 71>; +}; diff --git a/MAINTAINERS b/MAINTAINERS index fbb96ddb8686..987ccd269cfc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14222,3 +14222,8 @@ F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c AMLOGIC MESONGXL ADD SOUND DMIC MMAP FUNCTION M: peipeng.zhao F: sound/soc/amlogic/meson/dmic.h + +AMLOGIC GPIO IRQ +M: Xingyu Chen +F: drivers/amlogic/irqchip/* +F: Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi index 79732aa6bdb0..6bb0183d3f80 100644 --- a/arch/arm/boot/dts/amlogic/meson8b.dtsi +++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi @@ -347,6 +347,16 @@ clock-names = "clk_i2c"; }; + gpio_intc: interrupt-controller@9880 { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson8b-gpio-intc"; + reg = <0xc1109880 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; + status = "okay"; + }; + pinctrl_cbus: pinctrl@c1109880 { compatible = "amlogic,meson8b-cbus-pinctrl"; #address-cells = <1>; @@ -357,25 +367,13 @@ reg = <0xc11080b0 0x28>, <0xc11080e8 0x18>, <0xc1108120 0x18>, - <0xc1108030 0x38>, - <0xc1109880 0x10>; - interrupts = <0 64 1>, - <0 65 1>, - <0 66 1>, - <0 67 1>, - <0 68 1>, - <0 69 1>, - <0 70 1>, - <0 71 1>; + <0xc1108030 0x38>; reg-names = "mux", "pull", "pull-enable", - "gpio", - "irq"; + "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; a_i2c_master:a_i2c { @@ -634,16 +632,11 @@ gpio_ao: ao-bank@c1108030 { reg = <0xc8100014 0x4>, - <0xc810002c 0x4>, - <0xc8100024 0x8>, - <0xc8100084 0x4>; - interrupts = <0 200 1>, - <0 201 1>; - reg-names = "mux", "pull", "gpio", "irq"; + <0xc810002c 0x4>, + <0xc8100024 0x8>; + reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; remote_pins:remote_pin { mux { diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi index a70599b30e7f..abe0543a8550 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi @@ -279,15 +279,10 @@ gpio_ao: ao-bank@ff800014{ reg = <0x0 0xff800014 0x0 0x8>, <0x0 0xff80002c 0x0 0x4>, - <0x0 0xff800024 0x0 0x8>, - <0x0 0xff800084 0x0 0x4>; - interrupts = <0 200 1>, - <0 201 1>; - reg-names = "mux", "pull", "gpio", "irq"; + <0x0 0xff800024 0x0 0x8>; + reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -301,25 +296,13 @@ reg = <0x0 0xff634480 0x0 0x40>, <0x0 0xff6344e8 0x0 0x14>, <0x0 0xff634520 0x0 0x14>, - <0x0 0xff634430 0x0 0x3c>, - <0x0 0xffd0f080 0x0 0x10>; - interrupts = <0 64 1>, - <0 65 1>, - <0 66 1>, - <0 67 1>, - <0 68 1>, - <0 69 1>, - <0 70 1>, - <0 71 1>; + <0x0 0xff634430 0x0 0x3c>; reg-names = "mux", "pull", "pull-enable", - "gpio", - "irq"; + "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -337,6 +320,17 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x25000>; + gpio_intc: interrupt-controller@f080 { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-axg-gpio-intc"; + reg = <0x0 0xf080 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = + <64 65 66 67 68 69 70 71>; + status = "okay"; + }; + meson_clk_msr { compatible = "amlogic, gxl_measure"; reg = <0x0 0x18004 0x0 0x4 diff --git a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi index adeefc2a57b5..0d2063b1fc46 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi @@ -378,15 +378,10 @@ gpio_ao: bank@14 { reg = <0x0 0xc8100014 0x0 0x8>, <0x0 0xc810002c 0x0 0x4>, - <0x0 0xc8100024 0x0 0x8>, - <0x0 0xc8100084 0x0 0x4>; - interrupts = <0 200 IRQ_TYPE_EDGE_RISING>, - <0 201 IRQ_TYPE_EDGE_RISING>; - reg-names = "mux", "pull", "gpio", "irq"; + <0x0 0xc8100024 0x0 0x8>; + reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -400,22 +395,11 @@ reg = <0x0 0xc88344b0 0x0 0x28>, <0x0 0xc88344e8 0x0 0x14>, <0x0 0xc8834520 0x0 0x14>, - <0x0 0xc8834430 0x0 0x40>, - <0x0 0xc1109880 0x0 0x10>; - interrupts = <0 64 IRQ_TYPE_EDGE_RISING>, - <0 65 IRQ_TYPE_EDGE_RISING>, - <0 66 IRQ_TYPE_EDGE_RISING>, - <0 67 IRQ_TYPE_EDGE_RISING>, - <0 68 IRQ_TYPE_EDGE_RISING>, - <0 69 IRQ_TYPE_EDGE_RISING>, - <0 70 IRQ_TYPE_EDGE_RISING>, - <0 71 IRQ_TYPE_EDGE_RISING>; + <0x0 0xc8834430 0x0 0x40>; reg-names = "mux", "pull", - "pull-enable", "gpio", "irq"; + "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -432,6 +416,17 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>; + gpio_intc: interrupt-controller@9880 { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-gxl-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = + <64 65 66 67 68 69 70 71>; + status = "okay"; + }; + meson_clk_msr{ compatible = "amlogic, gxl_measure"; reg = <0x0 0x875c 0x0 0x4 diff --git a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi index 58009911db65..a643a0f20791 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi @@ -461,15 +461,10 @@ gpio_ao: bank@14 { reg = <0x0 0xc8100014 0x0 0x8>, <0x0 0xc810002c 0x0 0x4>, - <0x0 0xc8100024 0x0 0x8>, - <0x0 0xc8100084 0x0 0x4>; - interrupts = <0 200 IRQ_TYPE_EDGE_RISING>, - <0 201 IRQ_TYPE_EDGE_RISING>; - reg-names = "mux", "pull", "gpio", "irq"; + <0x0 0xc8100024 0x0 0x8>; + reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -483,22 +478,11 @@ reg = <0x0 0xc88344b0 0x0 0x28>, <0x0 0xc88344e8 0x0 0x14>, <0x0 0xc8834520 0x0 0x14>, - <0x0 0xc8834430 0x0 0x40>, - <0x0 0xc1109880 0x0 0x10>; - interrupts = <0 64 IRQ_TYPE_EDGE_RISING>, - <0 65 IRQ_TYPE_EDGE_RISING>, - <0 66 IRQ_TYPE_EDGE_RISING>, - <0 67 IRQ_TYPE_EDGE_RISING>, - <0 68 IRQ_TYPE_EDGE_RISING>, - <0 69 IRQ_TYPE_EDGE_RISING>, - <0 70 IRQ_TYPE_EDGE_RISING>, - <0 71 IRQ_TYPE_EDGE_RISING>; + <0x0 0xc8834430 0x0 0x40>; reg-names = "mux", "pull", - "pull-enable", "gpio", "irq"; + "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -515,6 +499,17 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>; + gpio_intc: interrupt-controller@9880 { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-gxl-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = + <64 65 66 67 68 69 70 71>; + status = "okay"; + }; + meson_clk_msr{ compatible = "amlogic, gxl_measure"; reg = <0x0 0x875c 0x0 0x4 diff --git a/arch/arm64/boot/dts/amlogic/mesontxlx.dtsi b/arch/arm64/boot/dts/amlogic/mesontxlx.dtsi index 4572a8e557da..89ed02629e26 100644 --- a/arch/arm64/boot/dts/amlogic/mesontxlx.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesontxlx.dtsi @@ -305,15 +305,10 @@ gpio_ao: ao-bank@ff800014{ reg = <0x0 0xff800014 0x0 0x8>, <0x0 0xff80002c 0x0 0x4>, - <0x0 0xff800024 0x0 0x8>, - <0x0 0xff800084 0x0 0x4>; - interrupts = <0 200 1>, - <0 201 1>; - reg-names = "mux", "pull", "gpio", "irq"; + <0x0 0xff800024 0x0 0x8>; + reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -327,25 +322,13 @@ reg = <0x0 0xff6344b0 0x0 0x34>, <0x0 0xff6344e8 0x0 0x14>, <0x0 0xff634520 0x0 0x14>, - <0x0 0xff634430 0x0 0x3c>, - <0x0 0xffd0f080 0x0 0x10>; - interrupts = <0 64 1>, - <0 65 1>, - <0 66 1>, - <0 67 1>, - <0 68 1>, - <0 69 1>, - <0 70 1>, - <0 71 1>; + <0x0 0xff634430 0x0 0x3c>; reg-names = "mux", "pull", "pull-enable", - "gpio", - "irq"; + "gpio"; gpio-controller; #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; }; }; @@ -557,6 +540,17 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x25000>; + gpio_intc: interrupt-controller@f080 { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-txlx-gpio-intc"; + reg = <0x0 0xf080 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = + <64 65 66 67 68 69 70 71>; + status = "okay"; + }; + meson_clk_msr { compatible = "amlogic, gxl_measure"; reg = <0x0 0x18004 0x0 0x4 diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 75ebf5b1013d..ad7c307ca2d7 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -330,6 +330,7 @@ CONFIG_AMLOGIC_IIO=y CONFIG_AMLOGIC_SARADC=y CONFIG_AMLOGIC_DDR_WINDOW_TOOL=m CONFIG_AMLOGIC_TEE=y +CONFIG_AMLOGIC_GPIO_IRQ=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y diff --git a/arch/arm64/configs/meson64_smarthome_defconfig b/arch/arm64/configs/meson64_smarthome_defconfig index 5a175d1214d1..ced6a63a36ab 100644 --- a/arch/arm64/configs/meson64_smarthome_defconfig +++ b/arch/arm64/configs/meson64_smarthome_defconfig @@ -302,6 +302,7 @@ CONFIG_AMLOGIC_IRBLASTER=y CONFIG_AMLOGIC_IIO=y CONFIG_AMLOGIC_SARADC=y CONFIG_AMLOGIC_DDR_WINDOW_TOOL=m +CONFIG_AMLOGIC_GPIO_IRQ=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y diff --git a/drivers/amlogic/Kconfig b/drivers/amlogic/Kconfig index 81842d3478e5..be057ed0038c 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -124,5 +124,6 @@ source "drivers/amlogic/ledring/Kconfig" source "drivers/amlogic/memory_ext/Kconfig" +source "drivers/amlogic/irqchip/Kconfig" endmenu endif diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index bbd859227ee9..2805351076dd 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -114,3 +114,5 @@ obj-$(CONFIG_AMLOGIC_TEE) += tee/ obj-$(CONFIG_AMLOGIC_MEMORY_EXTEND) += memory_ext/ obj-$(CONFIG_AMLOGIC_LEDRING) += ledring/ + +obj-$(CONFIG_AMLOGIC_GPIO_IRQ) += irqchip/ diff --git a/drivers/amlogic/irqchip/Kconfig b/drivers/amlogic/irqchip/Kconfig new file mode 100644 index 000000000000..2081d5bd9ed1 --- /dev/null +++ b/drivers/amlogic/irqchip/Kconfig @@ -0,0 +1,7 @@ +config AMLOGIC_GPIO_IRQ + bool "Meson GPIO Interrupt Multiplexer" + depends on IRQ_DOMAIN + depends on IRQ_DOMAIN_HIERARCHY + default n + help + Support Meson SoC Family GPIO Interrupt Multiplexer diff --git a/drivers/amlogic/irqchip/Makefile b/drivers/amlogic/irqchip/Makefile new file mode 100644 index 000000000000..d11b37a50f88 --- /dev/null +++ b/drivers/amlogic/irqchip/Makefile @@ -0,0 +1 @@ + obj-$(CONFIG_AMLOGIC_GPIO_IRQ) += irq-meson-gpio.o diff --git a/drivers/amlogic/irqchip/irq-meson-gpio.c b/drivers/amlogic/irqchip/irq-meson-gpio.c new file mode 100644 index 000000000000..2ad3125779bd --- /dev/null +++ b/drivers/amlogic/irqchip/irq-meson-gpio.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * Copyright (c) 2016 BayLibre, SAS. + * Author: Jerome Brunet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define NUM_CHANNEL 8 +#define MAX_INPUT_MUX 256 + +#define REG_EDGE_POL 0x00 +#define REG_PIN_03_SEL 0x04 +#define REG_PIN_47_SEL 0x08 +#define REG_FILTER_SEL 0x0c + +#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_PIN_SEL_SHIFT(x) (((x) % 4) * 8) +#define REG_FILTER_SEL_SHIFT(x) ((x) * 4) + +struct meson_gpio_irq_params { + unsigned int nr_hwirq; +}; + +static const struct meson_gpio_irq_params meson8_params = { + .nr_hwirq = 134, +}; + +static const struct meson_gpio_irq_params meson8b_params = { + .nr_hwirq = 119, +}; + +static const struct meson_gpio_irq_params gxbb_params = { + .nr_hwirq = 133, +}; + +static const struct meson_gpio_irq_params gxl_params = { + .nr_hwirq = 110, +}; + +static const struct meson_gpio_irq_params axg_params = { + .nr_hwirq = 100, +}; + +static const struct meson_gpio_irq_params txlx_params = { + .nr_hwirq = 119, +}; + +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-gxbb-gpio-intc", .data = &gxbb_params }, + { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, + { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, + { .compatible = "amlogic,meson-txlx-gpio-intc", .data = &txlx_params }, + { } +}; + +struct meson_gpio_irq_controller { + unsigned int nr_hwirq; + void __iomem *base; + u32 channel_irqs[NUM_CHANNEL]; + DECLARE_BITMAP(channel_map, NUM_CHANNEL); + spinlock_t lock; +}; + +static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl, + unsigned int reg, u32 mask, u32 val) +{ + u32 tmp; + + tmp = readl_relaxed(ctl->base + reg); + tmp &= ~mask; + tmp |= val; + writel_relaxed(tmp, ctl->base + reg); +} + +static unsigned int meson_gpio_irq_channel_to_reg(unsigned int channel) +{ + return (channel < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL; +} + +static int +meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl, + unsigned long hwirq, + u32 **channel_hwirq) +{ + unsigned int reg, idx; + + spin_lock(&ctl->lock); + + /* Find a free channel */ + idx = find_first_zero_bit(ctl->channel_map, NUM_CHANNEL); + if (idx >= NUM_CHANNEL) { + spin_unlock(&ctl->lock); + pr_debug("No channel available\n"); + return -ENOSPC; + } + + /* Mark the channel as used */ + set_bit(idx, ctl->channel_map); + + /* + * Setup the mux of the channel to route the signal of the pad + * to the appropriate input of the GIC + */ + reg = meson_gpio_irq_channel_to_reg(idx); + meson_gpio_irq_update_bits(ctl, reg, + 0xff << REG_PIN_SEL_SHIFT(idx), + hwirq << REG_PIN_SEL_SHIFT(idx)); + + /* + * Get the hwirq number assigned to this channel through + * a pointer the channel_irq table. The added benifit of this + * method is that we can also retrieve the channel index with + * it, using the table base. + */ + *channel_hwirq = &(ctl->channel_irqs[idx]); + + spin_unlock(&ctl->lock); + + pr_debug("hwirq %lu assigned to channel %d - irq %u\n", + hwirq, idx, **channel_hwirq); + + return 0; +} + +static unsigned int +meson_gpio_irq_get_channel_idx(struct meson_gpio_irq_controller *ctl, + u32 *channel_hwirq) +{ + return channel_hwirq - ctl->channel_irqs; +} + +static void +meson_gpio_irq_release_channel(struct meson_gpio_irq_controller *ctl, + u32 *channel_hwirq) +{ + unsigned int idx; + + idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq); + 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) +{ + u32 val = 0; + unsigned int idx; + + idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq); + + /* + * The controller has a filter block to operate in either LEVEL or + * EDGE mode, then signal is sent to the GIC. To enable LEVEL_LOW and + * EDGE_FALLING support (which the GIC does not support), the filter + * block is also able to invert the input signal it gets before + * providing it to the GIC. + */ + type &= IRQ_TYPE_SENSE_MASK; + + if (type == IRQ_TYPE_EDGE_BOTH) + return -EINVAL; + + 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); + + spin_lock(&ctl->lock); + + meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, + REG_EDGE_POL_MASK(idx), val); + + spin_unlock(&ctl->lock); + + return 0; +} + +static unsigned int meson_gpio_irq_type_output(unsigned int type) +{ + unsigned int sense = type & IRQ_TYPE_SENSE_MASK; + + type &= ~IRQ_TYPE_SENSE_MASK; + + /* + * The polarity of the signal provided to the GIC should always + * be high. + */ + 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)) + type |= IRQ_TYPE_EDGE_RISING; + + return type; +} + +static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct meson_gpio_irq_controller *ctl = data->domain->host_data; + u32 *channel_hwirq = irq_data_get_irq_chip_data(data); + int ret; + + ret = meson_gpio_irq_type_setup(ctl, type, channel_hwirq); + if (ret) + return ret; + + return irq_chip_set_type_parent(data, + meson_gpio_irq_type_output(type)); +} + +static struct irq_chip meson_gpio_irq_chip = { + .name = "meson-gpio-irqchip", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = meson_gpio_irq_set_type, + .irq_retrigger = irq_chip_retrigger_hierarchy, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + +static int meson_gpio_irq_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; + } + + return -EINVAL; +} + +static int meson_gpio_irq_allocate_gic_irq(struct irq_domain *domain, + unsigned int virq, + u32 hwirq, + unsigned int type) +{ + struct irq_fwspec fwspec; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; /* SPI */ + fwspec.param[1] = hwirq; + fwspec.param[2] = meson_gpio_irq_type_output(type); + + return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); +} + +static int meson_gpio_irq_domain_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *data) +{ + struct irq_fwspec *fwspec = data; + struct meson_gpio_irq_controller *ctl = domain->host_data; + unsigned long hwirq; + u32 *channel_hwirq; + unsigned int type; + int ret; + + if (WARN_ON(nr_irqs != 1)) + return -EINVAL; + + ret = meson_gpio_irq_domain_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + ret = meson_gpio_irq_request_channel(ctl, hwirq, &channel_hwirq); + if (ret) + return ret; + + ret = meson_gpio_irq_allocate_gic_irq(domain, virq, + *channel_hwirq, type); + if (ret < 0) { + pr_err("failed to allocate gic irq %u\n", *channel_hwirq); + meson_gpio_irq_release_channel(ctl, channel_hwirq); + return ret; + } + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &meson_gpio_irq_chip, channel_hwirq); + + return 0; +} + +static void meson_gpio_irq_domain_free(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs) +{ + struct meson_gpio_irq_controller *ctl = domain->host_data; + struct irq_data *irq_data; + u32 *channel_hwirq; + + if (WARN_ON(nr_irqs != 1)) + return; + + irq_domain_free_irqs_parent(domain, virq, 1); + + irq_data = irq_domain_get_irq_data(domain, virq); + channel_hwirq = irq_data_get_irq_chip_data(irq_data); + + meson_gpio_irq_release_channel(ctl, channel_hwirq); +} + +static const struct irq_domain_ops meson_gpio_irq_domain_ops = { + .alloc = meson_gpio_irq_domain_alloc, + .free = meson_gpio_irq_domain_free, + .translate = meson_gpio_irq_domain_translate, +}; + +static int __init meson_gpio_irq_parse_dt(struct device_node *node, + 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; + + ret = of_property_read_variable_u32_array(node, + "amlogic,channel-interrupts", + ctl->channel_irqs, + NUM_CHANNEL, + NUM_CHANNEL); + if (ret < 0) { + pr_err("can't get %d channel interrupts\n", NUM_CHANNEL); + return ret; + } + + return 0; +} + +static int __init meson_gpio_irq_of_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *domain, *parent_domain; + struct meson_gpio_irq_controller *ctl; + int ret; + + if (!parent) { + pr_err("missing parent interrupt node\n"); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("unable to obtain parent domain\n"); + return -ENXIO; + } + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return -ENOMEM; + + spin_lock_init(&ctl->lock); + + ctl->base = of_iomap(node, 0); + if (!ctl->base) { + ret = -ENOMEM; + goto free_ctl; + } + + ret = meson_gpio_irq_parse_dt(node, ctl); + if (ret) + goto free_channel_irqs; + + domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq, + of_node_to_fwnode(node), + &meson_gpio_irq_domain_ops, + ctl); + if (!domain) { + pr_err("failed to add domain\n"); + ret = -ENODEV; + goto free_channel_irqs; + } + + pr_info("%d to %d gpio interrupt mux initialized\n", + ctl->nr_hwirq, NUM_CHANNEL); + + return 0; + +free_channel_irqs: + iounmap(ctl->base); +free_ctl: + kfree(ctl); + + return ret; +} + +IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc", + meson_gpio_irq_of_init); diff --git a/drivers/amlogic/pinctrl/pinctrl-meson.c b/drivers/amlogic/pinctrl/pinctrl-meson.c index 0a92fc89d4cb..8e8211ad3c4a 100644 --- a/drivers/amlogic/pinctrl/pinctrl-meson.c +++ b/drivers/amlogic/pinctrl/pinctrl-meson.c @@ -711,383 +711,84 @@ static int meson_gpio_get(struct gpio_chip *chip, unsigned int gpio) return !!(val & BIT(bit)); } -/* - * NOP functions - */ -static void noop(struct irq_data *irqd) { } - -static void meson_gpio_irq_enable(struct irq_data *irqd) +static int meson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) { - struct meson_domain *domain = to_meson_domain(irqd->chip_data); - struct irq_data *parent_data; - unsigned long flags; - unsigned char cnt; - - spin_lock_irqsave(&domain->irq_res.irq_res_lock, flags); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (domain->irq_res.gpio_irq[cnt].hwirq == irqd->hwirq) { - parent_data = - irq_get_irq_data( - domain->irq_res.gpio_irq[cnt].parent_virq); - /*enable the interrupt line of gpio in GIC controller*/ - parent_data->chip->irq_unmask(parent_data); - } - } - spin_unlock_irqrestore(&domain->irq_res.irq_res_lock, flags); - -} - -static void meson_gpio_irq_disable(struct irq_data *irqd) -{ - struct meson_domain *domain = to_meson_domain(irqd->chip_data); - struct irq_data *parent_data; - unsigned long flags; - unsigned char cnt; - - spin_lock_irqsave(&domain->irq_res.irq_res_lock, flags); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (domain->irq_res.gpio_irq[cnt].hwirq == irqd->hwirq) { - parent_data = - irq_get_irq_data( - domain->irq_res.gpio_irq[cnt].parent_virq); - /*disable the interrupt line of gpio in GIC controller*/ - parent_data->chip->irq_mask(parent_data); - } - } - spin_unlock_irqrestore(&domain->irq_res.irq_res_lock, flags); -} - -/** - *free gpio irq when free_irq() is called, and another pin can use it again. - */ -static void meson_gpio_irq_shutdown(struct irq_data *irqd) -{ - struct meson_domain *domain = to_meson_domain(irqd->chip_data); - unsigned long flags; - unsigned char cnt; - - spin_lock_irqsave(&domain->irq_res.irq_res_lock, flags); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (domain->irq_res.gpio_irq[cnt].hwirq == irqd->hwirq) - domain->irq_res.gpio_irq[cnt].used_flag = 0; - } - spin_unlock_irqrestore(&domain->irq_res.irq_res_lock, flags); -} - -static int meson_ee_gpio_irq_type(struct irq_data *irqd, unsigned int type) -{ - struct meson_domain *domain = to_meson_domain(irqd->chip_data); + struct meson_domain *domain = to_meson_domain(chip); struct meson_bank *bank; - struct irq_data *parent_data; - unsigned long flags; - unsigned int trigger_type[2]; - unsigned char type_num; - unsigned char type_cnt; - unsigned char start_bit; - unsigned int gpio_virq; - unsigned char cnt; - unsigned char pin; - unsigned char irq_pin; - int ret; + struct irq_fwspec fwspec; + int hwirq; + int gpio; - type = type & IRQ_TYPE_SENSE_MASK; + gpio = chip->base + offset; - switch (type) { - case IRQ_TYPE_LEVEL_LOW: - trigger_type[0] = 0x10000; - type_num = 1; - break; - case IRQ_TYPE_LEVEL_HIGH: - trigger_type[0] = 0x0; - type_num = 1; - break; - case IRQ_TYPE_EDGE_RISING: - trigger_type[0] = 0x1; - type_num = 1; - break; - case IRQ_TYPE_EDGE_FALLING: - trigger_type[0] = 0x10001; - type_num = 1; - break; - case IRQ_TYPE_EDGE_BOTH: - trigger_type[0] = 0x1; - trigger_type[1] = 0x10001; - type_num = 2; - break; - default: + if (meson_get_bank(domain, gpio, &bank)) + return -EINVAL; + + if (bank->irq < 0) { + pr_warn("pinctrl-meson: no support irq for pin[%d]\n", gpio); return -EINVAL; } - for (type_cnt = 0; type_cnt < type_num; type_cnt++) { - /* dynamic allocate gpio irq for request pin*/ - spin_lock_irqsave(&domain->irq_res.irq_res_lock, flags); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (domain->irq_res.gpio_irq[cnt].used_flag) - continue; - else { - domain->irq_res.gpio_irq[cnt].used_flag = 1; - domain->irq_res.gpio_irq[cnt].hwirq = - irqd->hwirq; - break; - } - } - spin_unlock_irqrestore(&domain->irq_res.irq_res_lock, flags); - - if (domain->irq_res.irq_num == cnt) { - pr_err("meson_pinctrl: no more gpio irq available in EE GPIO INTC, allocate gpio irq for pin[%ld] failed.\n", - irqd->hwirq); - return -EINVAL; - } - - regmap_update_bits(domain->reg_irq, - (GPIO_IRQ_EDGE_OFFSET * 4), - 0x10001 << cnt, - trigger_type[type_cnt] << cnt); - - /*the gpio hwirq eqaul to gpio offset in gpio chip*/ - pin = domain->data->pin_base + irqd->hwirq; - - ret = meson_get_bank(domain, pin, &bank); - if (ret) - return ret; - - if (bank->irq < 0) - return -EINVAL; - - irq_pin = bank->irq + pin - bank->first; - - /*set pin select register*/ - start_bit = (cnt & 3) << 3; - regmap_update_bits(domain->reg_irq, - (cnt < 4)?(GPIO_IRQ_MUX_0_3 * 4):(GPIO_IRQ_MUX_4_7 * 4), - 0xff << start_bit, - irq_pin << start_bit); - /** - *TODO: support to configure the filter registers by - * the func interface. - * all filter registers for gpio will been set 0x7. - */ - start_bit = cnt << 2; - regmap_update_bits(domain->reg_irq, - (GPIO_IRQ_FILTER_OFFSET * 4), - 0x7 << start_bit, 0x7 << start_bit); - - parent_data = - irq_get_irq_data( - domain->irq_res.gpio_irq[cnt].parent_virq); - - /*set trigger type of gpio in GIC controller*/ - if (type & IRQ_TYPE_EDGE_BOTH) - parent_data->chip->irq_set_type(parent_data, - IRQ_TYPE_EDGE_RISING); - else - parent_data->chip->irq_set_type(parent_data, - IRQ_TYPE_LEVEL_HIGH); - - gpio_virq = irq_find_mapping(domain->chip.irqdomain, - domain->irq_res.gpio_irq[cnt].hwirq); - - pr_info("meson_pinctrl: gpio virq[%d] connect to GIC hwirq[%ld]\n", - gpio_virq, - parent_data->hwirq); - } - - return 0; -} - -static int meson_ao_gpio_irq_type(struct irq_data *irqd, unsigned int type) -{ - struct meson_domain *domain = to_meson_domain(irqd->chip_data); - struct meson_bank *bank; - struct irq_data *parent_data; - unsigned long flags; - unsigned int trigger_type[2]; - unsigned char type_num; - unsigned char type_cnt; - unsigned char start_bit; - unsigned int gpio_virq; - unsigned char cnt; - unsigned char pin; - unsigned char irq_pin; - int ret; - - type = type & IRQ_TYPE_SENSE_MASK; - - switch (type) { - case IRQ_TYPE_LEVEL_LOW: - trigger_type[0] = 0x10000; - type_num = 1; - break; - case IRQ_TYPE_LEVEL_HIGH: - trigger_type[0] = 0x0; - type_num = 1; - break; - case IRQ_TYPE_EDGE_RISING: - trigger_type[0] = 0x40000; - type_num = 1; - break; - case IRQ_TYPE_EDGE_FALLING: - trigger_type[0] = 0x50000; - type_num = 1; - break; - case IRQ_TYPE_EDGE_BOTH: - trigger_type[0] = 0x40000; - trigger_type[1] = 0x50000; - type_num = 2; - break; - default: + if (!domain->of_irq) { + pr_err("pinctrl-meson: invalid device node of gpio INTC\n"); return -EINVAL; } + hwirq = gpio - bank->first + bank->irq; - for (type_cnt = 0; type_cnt < type_num; type_cnt++) { - /* dynamic allocate gpio irq for request pin*/ - spin_lock_irqsave(&domain->irq_res.irq_res_lock, flags); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (domain->irq_res.gpio_irq[cnt].used_flag) - continue; - else { - domain->irq_res.gpio_irq[cnt].used_flag = 1; - domain->irq_res.gpio_irq[cnt].hwirq = - irqd->hwirq; - break; - } - } - spin_unlock_irqrestore(&domain->irq_res.irq_res_lock, flags); - - if (domain->irq_res.irq_num == cnt) { - pr_err("meson_pinctrl: no more gpio irq available in AO GPIO INTC, allocate gpio irq for pin[%ld] failed.\n", - irqd->hwirq); - return -EINVAL; - } - - /*set trigger type*/ - regmap_update_bits(domain->reg_irq, 0, - 0x50000 << cnt, - trigger_type[type_cnt] << cnt); - - /*the gpio hwirq eqaul to gpio offset in gpio chip*/ - pin = domain->data->pin_base + irqd->hwirq; - - ret = meson_get_bank(domain, pin, &bank); - if (ret) - return ret; - - if (bank->irq < 0) - return -EINVAL; - - irq_pin = bank->irq + pin - bank->first; - - /*set pin select register*/ - start_bit = cnt << 2; - regmap_update_bits(domain->reg_irq, 0, - 0xf << start_bit, - irq_pin << start_bit); - /** - *TODO: support to configure the filter registers by - * the func interface. - * all filter registers for gpio will been set 0x7. - */ - start_bit = cnt << 2; - regmap_update_bits(domain->reg_irq, 0, - 0x700 << start_bit, 0x700 << start_bit); - - parent_data = - irq_get_irq_data( - domain->irq_res.gpio_irq[cnt].parent_virq); - - /*set trigger type of gpio in GIC controller*/ - if (type & IRQ_TYPE_EDGE_BOTH) - parent_data->chip->irq_set_type(parent_data, - IRQ_TYPE_EDGE_RISING); - else - parent_data->chip->irq_set_type(parent_data, - IRQ_TYPE_LEVEL_HIGH); - - gpio_virq = irq_find_mapping(domain->chip.irqdomain, - domain->irq_res.gpio_irq[cnt].hwirq); - - pr_info("meson_pinctrl: gpio virq[%d] connect to GIC hwirq[%ld]\n", - gpio_virq, - parent_data->hwirq); - } - - return 0; + fwspec.fwnode = of_node_to_fwnode(domain->of_irq); + fwspec.param_count = 2; + fwspec.param[0] = hwirq; + fwspec.param[1] = IRQ_TYPE_NONE; + return irq_create_fwspec_mapping(&fwspec); } -static struct irq_chip meson_ee_gpio_irq_chip = { - .name = "GPIO-EE", - .irq_enable = meson_gpio_irq_enable, - .irq_disable = meson_gpio_irq_disable, - .irq_set_type = meson_ee_gpio_irq_type, - .irq_mask = noop, - .irq_unmask = noop, - .irq_shutdown = meson_gpio_irq_shutdown, -}; - -static struct irq_chip meson_ao_gpio_irq_chip = { - .name = "GPIO-AO", - .irq_enable = meson_gpio_irq_enable, - .irq_disable = meson_gpio_irq_disable, - .irq_set_type = meson_ao_gpio_irq_type, - .irq_mask = noop, - .irq_unmask = noop, - .irq_shutdown = meson_gpio_irq_shutdown, -}; struct meson_pinctrl_private meson_gxl_periphs = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson_gxl_periphs_pinctrl_data, - .irq_chip = &meson_ee_gpio_irq_chip, .init = meson_gxl_periphs_init, }; struct meson_pinctrl_private meson_gxl_aobus = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson_gxl_aobus_pinctrl_data, - .irq_chip = &meson_ao_gpio_irq_chip, .init = meson_gxl_aobus_init, }; struct meson_pinctrl_private meson_m8b_cbus = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson8b_cbus_pinctrl_data, - .irq_chip = &meson_ee_gpio_irq_chip, .init = NULL, }; struct meson_pinctrl_private meson_m8b_aobus = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson8b_aobus_pinctrl_data, - .irq_chip = &meson_ao_gpio_irq_chip, .init = NULL, }; struct meson_pinctrl_private meson_axg_periphs = { .pinmux_type = PINMUX_V2, .pinctrl_data = &meson_axg_periphs_pinctrl_data, - .irq_chip = &meson_ee_gpio_irq_chip, .init = NULL, }; struct meson_pinctrl_private meson_axg_aobus = { .pinmux_type = PINMUX_V2, .pinctrl_data = &meson_axg_aobus_pinctrl_data, - .irq_chip = &meson_ao_gpio_irq_chip, .init = meson_axg_aobus_init, }; struct meson_pinctrl_private meson_txlx_periphs = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson_txlx_periphs_pinctrl_data, - .irq_chip = &meson_ee_gpio_irq_chip, .init = NULL, }; struct meson_pinctrl_private meson_txlx_aobus = { .pinmux_type = PINMUX_V1, .pinctrl_data = &meson_txlx_aobus_pinctrl_data, - .irq_chip = &meson_ao_gpio_irq_chip, .init = meson_txlx_aobus_init, }; @@ -1145,6 +846,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) domain->chip.direction_output = meson_gpio_direction_output; domain->chip.get = meson_gpio_get; domain->chip.set = meson_gpio_set; + domain->chip.to_irq = meson_gpio_to_irq; domain->chip.set_pull = meson_gpio_pull_set; domain->chip.base = domain->data->pin_base; domain->chip.ngpio = domain->data->num_pins; @@ -1205,30 +907,6 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc, return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config); } -static int meson_irq_parse_and_map(struct meson_pinctrl *pc, - struct device_node *node) -{ - struct meson_domain *domain = pc->domain; - int cnt; - - domain->irq_res.irq_num = of_irq_count(node); - if (!domain->irq_res.irq_num) { - dev_err(pc->dev, "meson_pinctrl: can't find valid property 'interrupts'\n"); - return -EINVAL; - } - domain->irq_res.gpio_irq = devm_kzalloc(pc->dev, - sizeof(struct meson_gpio_irq_desc)*(domain->irq_res.irq_num), - GFP_KERNEL); - if (IS_ERR_OR_NULL(domain->irq_res.gpio_irq)) - return -ENOMEM; - - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - domain->irq_res.gpio_irq[cnt].parent_virq = - irq_of_parse_and_map(node, cnt); - } - return 0; -} - static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, struct device_node *node) { @@ -1255,6 +933,9 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, domain = pc->domain; domain->data = pc->data->domain_data; + domain->of_irq = of_find_compatible_node(NULL, + NULL, "amlogic,meson-gpio-intc"); + for_each_child_of_node(node, np) { if (!of_find_property(np, "gpio-controller", NULL)) continue; @@ -1284,76 +965,11 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, return PTR_ERR(domain->reg_gpio); } - domain->reg_irq = meson_map_resource(pc, np, "irq"); - if (IS_ERR(domain->reg_irq)) { - dev_err(pc->dev, "gpio irq registers not found\n"); - return PTR_ERR(domain->reg_irq); - } - - meson_irq_parse_and_map(pc, np); - break; } return 0; } -void meson_gpio_irq_handler(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc); - struct meson_domain *domain = to_meson_domain(gpio_chip); - unsigned char cnt; - unsigned int parent_virq; - - parent_virq = irq_desc_get_irq(desc); - - chained_irq_enter(chip, desc); - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - if (parent_virq == domain->irq_res.gpio_irq[cnt].parent_virq && - domain->irq_res.gpio_irq[cnt].used_flag) - generic_handle_irq(irq_find_mapping(gpio_chip->irqdomain, - domain->irq_res.gpio_irq[cnt].hwirq)); - } - chained_irq_exit(chip, desc); -} - -static int meson_irq_setup(struct meson_pinctrl *pc, struct irq_chip *irq_chip) -{ - struct meson_domain *domain = pc->domain; - struct irq_data *parent_data; - unsigned char cnt; - unsigned char ret; - - spin_lock_init(&domain->irq_res.irq_res_lock); - - ret = gpiochip_irqchip_add(&domain->chip, - irq_chip, - 0, - handle_simple_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(pc->dev, "couldn't add irqchip to gpiochip.\n"); - return ret; - } - - /* Then register the chain on the parent IRQ */ - for (cnt = 0; cnt < domain->irq_res.irq_num; cnt++) { - gpiochip_set_chained_irqchip(&domain->chip, - irq_chip, - domain->irq_res.gpio_irq[cnt].parent_virq, - meson_gpio_irq_handler); - - /*disable the interrupt line of gpio in GIC controller*/ - parent_data = - irq_get_irq_data( - domain->irq_res.gpio_irq[cnt].parent_virq); - parent_data->chip->irq_mask(parent_data); - } - - return 0; - -} - static int meson_pinctrl_add_function(struct meson_pinctrl *pc, const char *name) { @@ -1546,8 +1162,6 @@ static int meson_pinctrl_probe(struct platform_device *pdev) if (priv->init) priv->init(pc); - meson_irq_setup(pc, priv->irq_chip); - return 0; } diff --git a/drivers/amlogic/pinctrl/pinctrl-meson.h b/drivers/amlogic/pinctrl/pinctrl-meson.h index 49f93d82a980..8bb56bdd7f6d 100644 --- a/drivers/amlogic/pinctrl/pinctrl-meson.h +++ b/drivers/amlogic/pinctrl/pinctrl-meson.h @@ -116,41 +116,6 @@ struct meson_domain_data { unsigned int num_pins; }; -/** - *enum meson_irq_register - registers offset of gpio irq - */ -enum meson_irq_register { - GPIO_IRQ_EDGE_OFFSET, - GPIO_IRQ_MUX_0_3, - GPIO_IRQ_MUX_4_7, - GPIO_IRQ_FILTER_OFFSET, -}; - -/** - * struct meson_gpio_irq_desc - describe the gpio irq - * - * @used_flag: indicate the 'parent_virq' whether be used or not - * @parent_virq: gpio virtual interrupt number - * @hwirq: hw irq for gpio - */ -struct meson_gpio_irq_desc { - unsigned char used_flag; - unsigned int parent_virq; - unsigned int hwirq; -}; - -/*struct meson_irq_res - describe resource for gpio irq - * - * @irq_num: number of gpio irq - * @irq_res_lock: - * @gpio_irq: a pointer to 'struct meson_gpio_irq_desc' - */ -struct meson_irq_resource { - unsigned char irq_num; - spinlock_t irq_res_lock; - struct meson_gpio_irq_desc *gpio_irq; -}; - /** * struct meson_domain * @@ -158,9 +123,7 @@ struct meson_irq_resource { * @reg_pullen: registers for pull-enable settings * @reg_pull: registers for pull settings * @reg_gpio: registers for gpio settings - * @reg_irq: registers for gpio irq settings * @chip: gpio chip associated with the domain - * @irq_res: irq resource * @data: platform data for the domain * @node: device tree node for the domain * @@ -172,11 +135,10 @@ struct meson_domain { struct regmap *reg_pullen; struct regmap *reg_pull; struct regmap *reg_gpio; - struct regmap *reg_irq; struct gpio_chip chip; - struct meson_irq_resource irq_res; struct meson_domain_data *data; + struct device_node *of_irq; struct device_node *of_node; }; @@ -202,7 +164,6 @@ struct meson_pinctrl { struct meson_pinctrl_private { unsigned char pinmux_type; struct meson_pinctrl_data *pinctrl_data; - struct irq_chip *irq_chip; int (*init)(struct meson_pinctrl *pc); };