[v4,4/5] irqchip/irq-pruss-intc: Implement irq_{get,set}_irqchip_state ops
diff mbox series

Message ID 1595927918-19845-5-git-send-email-grzegorz.jaszczyk@linaro.org
State New
Headers show
Series
  • Add TI PRUSS Local Interrupt Controller IRQChip driver
Related show

Commit Message

Grzegorz Jaszczyk July 28, 2020, 9:18 a.m. UTC
From: David Lechner <david@lechnology.com>

This implements the irq_get_irqchip_state and irq_set_irqchip_state
callbacks for the TI PRUSS INTC driver. The set callback can be used
by drivers to "kick" a PRU by injecting a PRU system event.

Example:
     irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);

Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
Reviewed-by: Lee Jones <lee.jones@linaro.org>
---
v3->v4:
- Update commit message
v2->v3:
- Get rid of unnecessary pruss_intc_check_write() and use
  pruss_intc_write_reg directly.
v1->v2:
- https://patchwork.kernel.org/patch/11069769/
---
 drivers/irqchip/irq-pruss-intc.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

Comments

David Lechner July 29, 2020, 7:23 p.m. UTC | #1
On 7/28/20 4:18 AM, Grzegorz Jaszczyk wrote:
> From: David Lechner <david@lechnology.com>
> 
> This implements the irq_get_irqchip_state and irq_set_irqchip_state
> callbacks for the TI PRUSS INTC driver. The set callback can be used
> by drivers to "kick" a PRU by injecting a PRU system event.
> 
> Example:

We could improve this example by showing a device tree node of a
firmware-defined device implemented in the PRU:

	/* Software-defined UART in PRU */
	pru_uart: serial@XXXX {
		compatible = "ti,pru-uart";
		...
		interrupt-parent = <&pruss_intc>;
		/* PRU system event 31, channel 0, host event 0 */
		interrupts = <31 0 0>, ...;
		interrupt-names = "kick", ...;
		...
	},

Then driver would request the IRQ during probe:

	data->kick_irq = of_irq_get_byname(dev, "kick");
	if (data->kick_irq < 0)
		...
	

And later the driver would use the IRQ to kick the PRU:

	irq_set_irqchip_state(data->kick_irq, IRQCHIP_STATE_PENDING, true);


>       irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);
> 
> Signed-off-by: David Lechner <david@lechnology.com>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
> Reviewed-by: Lee Jones <lee.jones@linaro.org>
> ---
Grzegorz Jaszczyk July 31, 2020, 12:28 p.m. UTC | #2
On Wed, 29 Jul 2020 at 21:23, David Lechner <david@lechnology.com> wrote:
>
> On 7/28/20 4:18 AM, Grzegorz Jaszczyk wrote:
> > From: David Lechner <david@lechnology.com>
> >
> > This implements the irq_get_irqchip_state and irq_set_irqchip_state
> > callbacks for the TI PRUSS INTC driver. The set callback can be used
> > by drivers to "kick" a PRU by injecting a PRU system event.
> >
> > Example:
>
> We could improve this example by showing a device tree node of a
> firmware-defined device implemented in the PRU:
>
>         /* Software-defined UART in PRU */
>         pru_uart: serial@XXXX {
>                 compatible = "ti,pru-uart";
>                 ...
>                 interrupt-parent = <&pruss_intc>;
>                 /* PRU system event 31, channel 0, host event 0 */
>                 interrupts = <31 0 0>, ...;
>                 interrupt-names = "kick", ...;
>                 ...
>         },
>
> Then driver would request the IRQ during probe:
>
>         data->kick_irq = of_irq_get_byname(dev, "kick");
>         if (data->kick_irq < 0)
>                 ...
>
>
> And later the driver would use the IRQ to kick the PRU:
>
>         irq_set_irqchip_state(data->kick_irq, IRQCHIP_STATE_PENDING, true);
>
>

We could but I am not sure if this kind of complex example should land
in the commit log.
Marc could you please comment how you want to see this?

Thank you,
Grzegorz
David Lechner July 31, 2020, 3:59 p.m. UTC | #3
On 7/31/20 7:28 AM, Grzegorz Jaszczyk wrote:
> On Wed, 29 Jul 2020 at 21:23, David Lechner <david@lechnology.com> wrote:
>>
>> On 7/28/20 4:18 AM, Grzegorz Jaszczyk wrote:
>>> From: David Lechner <david@lechnology.com>
>>>
>>> This implements the irq_get_irqchip_state and irq_set_irqchip_state
>>> callbacks for the TI PRUSS INTC driver. The set callback can be used
>>> by drivers to "kick" a PRU by injecting a PRU system event.
>>>
>>> Example:
>>
>> We could improve this example by showing a device tree node of a
>> firmware-defined device implemented in the PRU:
>>
>>          /* Software-defined UART in PRU */
>>          pru_uart: serial@XXXX {
>>                  compatible = "ti,pru-uart";
>>                  ...
>>                  interrupt-parent = <&pruss_intc>;
>>                  /* PRU system event 31, channel 0, host event 0 */
>>                  interrupts = <31 0 0>, ...;
>>                  interrupt-names = "kick", ...;
>>                  ...
>>          },
>>
>> Then driver would request the IRQ during probe:
>>
>>          data->kick_irq = of_irq_get_byname(dev, "kick");
>>          if (data->kick_irq < 0)
>>                  ...
>>
>>
>> And later the driver would use the IRQ to kick the PRU:
>>
>>          irq_set_irqchip_state(data->kick_irq, IRQCHIP_STATE_PENDING, true);
>>
>>
> 
> We could but I am not sure if this kind of complex example should land
> in the commit log.
> Marc could you please comment how you want to see this?
> 
> Thank you,
> Grzegorz
> 

Based on the discussion in the device tree binding patch, the expanded
example I gave is incorrect, so we can just drop it.

Patch
diff mbox series

diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index cf9a59b..c13ba14 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -7,6 +7,7 @@ 
  *	Suman Anna <s-anna@ti.com>
  */
 
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
@@ -316,6 +317,43 @@  static void pruss_intc_irq_relres(struct irq_data *data)
 	module_put(THIS_MODULE);
 }
 
+static int pruss_intc_irq_get_irqchip_state(struct irq_data *data,
+					    enum irqchip_irq_state which,
+					    bool *state)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	u32 reg, mask, srsr;
+
+	if (which != IRQCHIP_STATE_PENDING)
+		return -EINVAL;
+
+	reg = PRU_INTC_SRSR(data->hwirq / 32);
+	mask = BIT(data->hwirq % 32);
+
+	srsr = pruss_intc_read_reg(intc, reg);
+
+	*state = !!(srsr & mask);
+
+	return 0;
+}
+
+static int pruss_intc_irq_set_irqchip_state(struct irq_data *data,
+					    enum irqchip_irq_state which,
+					    bool state)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+
+	if (which != IRQCHIP_STATE_PENDING)
+		return -EINVAL;
+
+	if (state)
+		pruss_intc_write_reg(intc, PRU_INTC_SISR, data->hwirq);
+	else
+		pruss_intc_write_reg(intc, PRU_INTC_SICR, data->hwirq);
+
+	return 0;
+}
+
 static struct irq_chip pruss_irqchip = {
 	.name = "pruss-intc",
 	.irq_ack = pruss_intc_irq_ack,
@@ -323,6 +361,8 @@  static struct irq_chip pruss_irqchip = {
 	.irq_unmask = pruss_intc_irq_unmask,
 	.irq_request_resources = pruss_intc_irq_reqres,
 	.irq_release_resources = pruss_intc_irq_relres,
+	.irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state,
+	.irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state,
 };
 
 static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event,