Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

irq-ts71xxweim: Add IRQ polarity #22

Merged
merged 5 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions arch/arm/boot/dts/imx6ul-ts7250v3.dts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
&supervisor_rtc {
status = "okay";
};

&fpga_intc {
ts,haspolarity;
};
28 changes: 14 additions & 14 deletions arch/arm/boot/dts/imx6ul-ts7250v3.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@
reg = <0x0 0x50>;

interrupt-controller;
#interrupt-cells = <1>;
#interrupt-cells = <2>;

interrupt-parent = <&gpio5>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
Expand Down Expand Up @@ -549,7 +549,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};

/* COM2 RS-232 */
Expand All @@ -564,7 +564,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <1>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
};

/* COM3 RS-232 */
Expand All @@ -579,7 +579,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <2>;
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
};

/* COM2 RS-485 */
Expand All @@ -594,7 +594,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <3>;
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
};

/* COM2 RS-422 */
Expand All @@ -609,7 +609,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <4>;
interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
};

/* Mikrobus UART */
Expand All @@ -624,7 +624,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <5>;
interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
};

fpga_uart6: serial@60 {
Expand All @@ -638,7 +638,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <6>;
interrupts = <6 IRQ_TYPE_LEVEL_HIGH>;
};

fpga_uart7: serial@70 {
Expand All @@ -652,7 +652,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <7>;
interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
};

fpga_uart8: serial@80 {
Expand All @@ -666,7 +666,7 @@
fifo-size = <64>;
clock-frequency = <1843200>;
interrupt-parent = <&fpga_intc>;
interrupts = <8>;
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
};

opencores_spi0: spi@100 {
Expand All @@ -675,7 +675,7 @@
#size-cells = <0>;
reg = <0x100 32>;
interrupt-parent = <&fpga_intc>;
interrupts = <9>;
interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fpga_clk_weim_bclk>;
clock-names = "spi-oc-clk";
opencores-spi,idx = <0>;
Expand Down Expand Up @@ -710,7 +710,7 @@
#size-cells = <0>;
reg = <0x120 32>;
interrupt-parent = <&fpga_intc>;
interrupts = <10>;
interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fpga_clk_weim_bclk>;
clock-names = "spi-oc-clk";
opencores-spi,idx = <0>;
Expand All @@ -727,14 +727,14 @@
compatible = "technologic,ts-simple-adc";
reg = <0x180 4>;
interrupt-parent = <&fpga_intc>;
interrupts = <19>;
interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
};

mikro_i2c: mikro_i2c@188 {
compatible = "opencores,i2c-ocores";
reg = <0x188 16>;
interrupt-parent = <&fpga_intc>;
interrupts = <20>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&fpga_clk_weim_bclk>;
clock-names = "i2c-oc-clk";
reg-io-width = <1>;
Expand Down
137 changes: 81 additions & 56 deletions drivers/irqchip/irq-ts71xxweim.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,76 @@
#include <linux/of_device.h>

#define TSWEIM_IRQ_STATUS 0x24
#define TSWEIM_IRQ_POLARITY 0x28
#define TSWEIM_IRQ_MASK 0x48
#define TSWEIM_NUM_FPGA_IRQ 32

static struct tsweim_intc_priv {
struct tsweim_intc {
void __iomem *syscon;
struct irq_domain *irqdomain;
int irq;
struct irq_chip chip;
u32 mask;
} priv;

static const struct of_device_id tsweim_intc_of_match_table[] = {
{.compatible = "technologic,ts71xxweim-intc", },
{},
};
MODULE_DEVICE_TABLE(of, tsweim_intc_of_match_table);

static struct tsweim_intc *irq_data_to_priv(struct irq_data *data)
{
return data->domain->host_data;
}

static void tsweim_intc_mask(struct irq_data *d)
{
priv.mask = readl(priv.syscon + TSWEIM_IRQ_MASK) & ~BIT(d->hwirq);
writel(priv.mask, priv.syscon + TSWEIM_IRQ_MASK);
struct tsweim_intc *priv = irq_data_to_priv(d);

priv->mask = readl(priv->syscon + TSWEIM_IRQ_MASK) & ~BIT(d->hwirq);
writel(priv->mask, priv->syscon + TSWEIM_IRQ_MASK);
}

static void tsweim_intc_unmask(struct irq_data *d)
{
priv.mask = readl(priv.syscon + TSWEIM_IRQ_MASK) | BIT(d->hwirq);
writel(priv.mask, priv.syscon + TSWEIM_IRQ_MASK);
struct tsweim_intc *priv = irq_data_to_priv(d);

priv->mask = readl(priv->syscon + TSWEIM_IRQ_MASK) | BIT(d->hwirq);
writel(priv->mask, priv->syscon + TSWEIM_IRQ_MASK);
}

static int tsweim_intc_set_type(struct irq_data *d, unsigned int flow_type)
{
struct tsweim_intc *priv = irq_data_to_priv(d);
uint32_t polarity = readl(priv->syscon + TSWEIM_IRQ_POLARITY);
uint32_t bit = BIT_MASK(d->hwirq);

switch (flow_type) {
case IRQ_TYPE_LEVEL_LOW:
polarity |= bit;
break;
case IRQ_TYPE_LEVEL_HIGH:
polarity &= ~bit;
break;
default:
return -EINVAL;
}

writel(polarity, priv->syscon + TSWEIM_IRQ_POLARITY);

return 0;
}

static void tsweim_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct tsweim_intc *priv = irq_desc_get_handler_data(desc);
unsigned int irq;
unsigned int status;

chained_irq_enter(chip, desc);

while ((status =
(priv.mask & readl(priv.syscon + TSWEIM_IRQ_STATUS)))) {
(priv->mask & readl(priv->syscon + TSWEIM_IRQ_STATUS)))) {
irq = 0;
do {
if (status & 1) {
generic_handle_irq(irq_linear_revmap(
priv.irqdomain, irq));
priv->irqdomain, irq));
}
status >>= 1;
irq++;
Expand All @@ -60,18 +87,12 @@ static void tsweim_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

static struct irq_chip tsweim_irq_chip = {
.name = "tsweim_intc",
.irq_mask = tsweim_intc_mask,
.irq_unmask = tsweim_intc_unmask,
};

static int tsweim_intc_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &tsweim_irq_chip,
handle_level_irq);
struct tsweim_intc *priv = d->host_data;

irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
irq_set_status_flags(irq, IRQ_LEVEL);

Expand All @@ -80,75 +101,79 @@ static int tsweim_intc_irqdomain_map(struct irq_domain *d,

static const struct irq_domain_ops tsweim_intc_irqdomain_ops = {
.map = tsweim_intc_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};

static int tsweim_intc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct device_node *np = pdev->dev.of_node;
void __iomem *membase;
struct resource *res = 0;

match = of_match_device(tsweim_intc_of_match_table, dev);
if (!match)
return -EINVAL;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct tsweim_intc *priv;
struct resource *irq = 0;
struct irq_chip *chip;

if (res == NULL) {
pr_err("Can't get device address\n");
return -EFAULT;
}

membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (IS_ERR(membase)) {
pr_err("Could not map resource\n");
priv = devm_kzalloc(dev, sizeof(struct tsweim_intc), GFP_KERNEL);
if (!priv)
return -ENOMEM;
}

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
priv->syscon = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);

irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq == NULL) {
pr_err("Can't get interrupt\n");
return -EFAULT;
}

priv.irq = res->start;
priv.syscon = membase;
chip = &priv->chip;
chip->name = dev->of_node->name;
chip->irq_mask = tsweim_intc_mask;
chip->irq_unmask = tsweim_intc_unmask;

if (of_property_read_bool(dev->of_node, "ts,haspolarity"))
chip->irq_set_type = tsweim_intc_set_type;

priv.irqdomain = irq_domain_add_linear(
np, TSWEIM_NUM_FPGA_IRQ, &tsweim_intc_irqdomain_ops, &priv);
priv->irqdomain = irq_domain_add_linear(dev->of_node,
TSWEIM_NUM_FPGA_IRQ, &tsweim_intc_irqdomain_ops, priv);

if (!priv.irqdomain) {
pr_err("%s: unable to add irq domain\n", np->name);
if (!priv->irqdomain) {
pr_err("unable to add irq domain\n");
return -ENOMEM;
}

irq_set_handler_data(priv.irq, &priv);
irq_set_chained_handler(priv.irq, tsweim_irq_handler);
irq_set_handler_data(irq->start, priv);
irq_set_chained_handler(irq->start, tsweim_irq_handler);

platform_set_drvdata(pdev, &priv);
platform_set_drvdata(pdev, priv);

return 0;
}

static int tsweim_intc_remove(struct platform_device *pdev)
{
if (priv.irqdomain) {
struct tsweim_intc *priv = dev_get_platdata(&pdev->dev);

if (priv->irqdomain) {
int i, irq;

for (i = 0; i < TSWEIM_NUM_FPGA_IRQ; i++) {
irq = irq_find_mapping(priv.irqdomain, i);
irq = irq_find_mapping(priv->irqdomain, i);
if (irq > 0)
irq_dispose_mapping(irq);
}
irq_domain_remove(priv.irqdomain);
priv.irqdomain = NULL;
irq_domain_remove(priv->irqdomain);
priv->irqdomain = NULL;
}

return 0;
}

static const struct of_device_id tsweim_intc_of_match_table[] = {
{.compatible = "technologic,ts71xxweim-intc", },
{},
};
MODULE_DEVICE_TABLE(of, tsweim_intc_of_match_table);

static struct platform_driver tsweim_intc_driver = {
.driver = {
.name = "tsweim-intc",
Expand Down