Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1274556 > unrolled thread
| Started by | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| First post | 2015-11-21 01:20 +0100 |
| Last post | 2015-11-30 14:50 +0100 |
| Articles | 16 on this page of 36 — 9 participants |
Back to article view | Back to linux.kernel
[PATCH 00/14] Initial Microchip PIC32MZDA Support Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:20 +0100
[PATCH 09/14] DEVICETREE: Add bindings for PIC32 usart driver Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:20 +0100
Re: [PATCH 09/14] DEVICETREE: Add bindings for PIC32 usart driver Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - 2015-11-21 16:30 +0100
Re: [PATCH 09/14] DEVICETREE: Add bindings for PIC32 usart driver Rob Herring <robh@kernel.org> - 2015-11-22 23:00 +0100
[PATCH 07/14] DEVICETREE: Add bindings for PIC32 pin control and GPIO Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:20 +0100
Re: [PATCH 07/14] DEVICETREE: Add bindings for PIC32 pin control and GPIO Rob Herring <robh@kernel.org> - 2015-11-22 22:50 +0100
[PATCH 12/14] DEVICETREE: Add bindings for PIC32 SDHC host controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:20 +0100
Re: [PATCH 12/14] DEVICETREE: Add bindings for PIC32 SDHC host controller Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - 2015-11-21 16:30 +0100
Re: [PATCH 12/14] DEVICETREE: Add bindings for PIC32 SDHC host controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-26 05:50 +0100
Re: [PATCH 12/14] DEVICETREE: Add bindings for PIC32 SDHC host controller Rob Herring <robh@kernel.org> - 2015-11-22 23:00 +0100
Re: [PATCH 12/14] DEVICETREE: Add bindings for PIC32 SDHC host controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-26 06:20 +0100
[PATCH 05/14] DEVICETREE: Add bindings for PIC32/MZDA platforms Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 05/14] DEVICETREE: Add bindings for PIC32/MZDA platforms Rob Herring <robh@kernel.org> - 2015-11-22 22:40 +0100
[PATCH 11/14] mmc: sdhci-pic32: Add PIC32 SDHC host controller driver Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 11/14] mmc: sdhci-pic32: Add PIC32 SDHC host controller driver Ulf Hansson <ulf.hansson@linaro.org> - 2015-11-25 17:00 +0100
Re: [PATCH 11/14] mmc: sdhci-pic32: Add PIC32 SDHC host controller driver Ulf Hansson <ulf.hansson@linaro.org> - 2015-11-25 17:40 +0100
RE: [PATCH 11/14] mmc: sdhci-pic32: Add PIC32 SDHC host controller driver <Paul.Thacker@microchip.com> - 2015-11-29 21:30 +0100
[PATCH 13/14] MIPS: dts: Add initial DTS for the PIC32MZDA Starter Kit Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
[PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation Arnd Bergmann <arnd@arndb.de> - 2015-11-21 21:50 +0100
Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-26 05:10 +0100
Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation Rob Herring <robh@kernel.org> - 2015-11-22 22:40 +0100
Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-26 06:40 +0100
[PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller Marc Zyngier <marc.zyngier@arm.com> - 2015-11-22 12:50 +0100
Re: [PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-25 19:30 +0100
[PATCH 10/14] serial: pic32_uart: Add PIC32 uart driver Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
[PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller Arnd Bergmann <arnd@arndb.de> - 2015-11-21 21:50 +0100
Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-25 19:30 +0100
Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller Rob Herring <robh@kernel.org> - 2015-11-22 22:20 +0100
Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-26 06:10 +0100
[PATCH 14/14] MIPS: pic32mzda: Add initial PIC32MZDA Starter Kit defconfig Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-21 01:30 +0100
Re: [PATCH 06/14] MIPS: Add support for PIC32MZDA platform Alban <albeu@free.fr> - 2015-11-21 13:40 +0100
Re: [PATCH 06/14] MIPS: Add support for PIC32MZDA platform Joshua Henderson <joshua.henderson@microchip.com> - 2015-11-22 17:30 +0100
Re: [PATCH 08/14] pinctrl: Add PIC32 pin control driver Linus Walleij <linus.walleij@linaro.org> - 2015-11-30 14:50 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-26 05:10 +0100 |
| Subject | Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation |
| Message-ID | <qyW2B-7N7-1@gated-at.bofh.it> |
| In reply to | #1274751 |
Hi Arnd,
On 11/21/2015 1:49 PM, Arnd Bergmann wrote:
> On Friday 20 November 2015 17:17:15 Joshua Henderson wrote:
>> +/* PIC32 specific clks */
>> +pic32_clktree {
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + reg = <0x1f801200 0x200>;
>> + compatible = "microchip,pic32-clk";
>> + interrupts = <12>;
>> + ranges;
>> +
>> + /* secondary oscillator; external input on SOSCI pin */
>> + SOSC:sosc_clk {
>> + #clock-cells = <0>;
>> + compatible = "microchip,pic32-sosc";
>> + clock-frequency = <32768>;
>> + reg = <0x1f801200 0x10 /* enable reg */
>> + 0x1f801390 0x10>; /* status reg */
>> + microchip,bit-mask = <0x02>; /* enable mask */
>> + microchip,status-bit-mask = <0x10>; /* status-mask*/
>> + };
>>
>
> If you want to use the reg property in this way for each cell,
> at least use a 'ranges' that only translates the actual registers
> like this
>
> ranges = <0 0x1f801200 0x200>
>
> sosc_clk {
> ...
> reg = <0x000 0x10>, <0x190 0x10>;
> ...
> };
>
> Arnd
>
This does indeed seem to be the correct way to use ranges in this case. Consider it done.
Thanks for the feedback,
Josh
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2015-11-22 22:40 +0100 |
| Subject | Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation |
| Message-ID | <qxKwy-Y6-9@gated-at.bofh.it> |
| In reply to | #1274567 |
On Fri, Nov 20, 2015 at 05:17:15PM -0700, Joshua Henderson wrote: > From: Purna Chandra Mandal <purna.mandal@microchip.com> > > Document the devicetree bindings for the clock driver found on Microchip > PIC32 class devices. > > Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com> > Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> > --- > .../devicetree/bindings/clock/microchip,pic32.txt | 263 ++++++++++++++++++++ > 1 file changed, 263 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/microchip,pic32.txt > > diff --git a/Documentation/devicetree/bindings/clock/microchip,pic32.txt b/Documentation/devicetree/bindings/clock/microchip,pic32.txt > new file mode 100644 > index 0000000..4cef72d > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/microchip,pic32.txt > @@ -0,0 +1,263 @@ > +Binding for a Clock hardware block found on > +certain Microchip PIC32 MCU devices. > + > +Microchip SoC clocks-node consists of few oscillators, PLL, multiplexer > +and few divider nodes. [...] > +Required properties: > +- compatible : should have "microchip,pic32-clk". > +- reg : A Base address and length of the register set. > +- interrupts : source of interrupt. > + > +Optional properties (for subnodes): > +- #clock-cells: From common clock binding, should be 0. > + > +- microchip,clock-indices: in multiplexer node clock sources always aren't linear > + and contiguous. This property helps define clock-sources with respect to > + the mux clock node. > + > +- microchip,ignore-unused : ignore gate request even if the gated clock is unused. There is some discussion about this upstream with "critical-clocks" binding. Can you use and wait for that? > +- microchip,status-bit-mask: bitmask for status check. This will be used to confirm > + particular operation by clock sub-node is completed. It is dependent sub-node. > +- microchip,bit-mask: enable mask, similar to microchip,status-bit-mask. We've generally decided not to describe clocks at this level of detail in DT. It's fine though for simple clock trees. This one seems to be borderline IMO. > +- microchip,slew-step: enable frequency slewing(stepping) during rate change; > + applicable only to sys-clock subnode. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-26 06:40 +0100 |
| Subject | Re: [PATCH 03/14] DEVICETREE: Add PIC32 clock binding documentation |
| Message-ID | <qyXrH-m4-1@gated-at.bofh.it> |
| In reply to | #1274960 |
Hi Rob, On 11/22/2015 2:31 PM, Rob Herring wrote: > On Fri, Nov 20, 2015 at 05:17:15PM -0700, Joshua Henderson wrote: >> From: Purna Chandra Mandal <purna.mandal@microchip.com> >> >> Document the devicetree bindings for the clock driver found on Microchip >> PIC32 class devices. >> >> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com> >> Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> >> --- >> .../devicetree/bindings/clock/microchip,pic32.txt | 263 ++++++++++++++++++++ >> 1 file changed, 263 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/clock/microchip,pic32.txt >> >> diff --git a/Documentation/devicetree/bindings/clock/microchip,pic32.txt b/Documentation/devicetree/bindings/clock/microchip,pic32.txt >> new file mode 100644 >> index 0000000..4cef72d >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/clock/microchip,pic32.txt >> @@ -0,0 +1,263 @@ >> +Binding for a Clock hardware block found on >> +certain Microchip PIC32 MCU devices. >> + >> +Microchip SoC clocks-node consists of few oscillators, PLL, multiplexer >> +and few divider nodes. > > [...] > >> +Required properties: >> +- compatible : should have "microchip,pic32-clk". >> +- reg : A Base address and length of the register set. >> +- interrupts : source of interrupt. >> + >> +Optional properties (for subnodes): >> +- #clock-cells: From common clock binding, should be 0. >> + >> +- microchip,clock-indices: in multiplexer node clock sources always aren't linear >> + and contiguous. This property helps define clock-sources with respect to >> + the mux clock node. >> + >> +- microchip,ignore-unused : ignore gate request even if the gated clock is unused. > > There is some discussion about this upstream with "critical-clocks" > binding. Can you use and wait for that? > The way this is going, we might not have to wait. :) Is there a patch available yet to try it out? >> +- microchip,status-bit-mask: bitmask for status check. This will be used to confirm >> + particular operation by clock sub-node is completed. It is dependent sub-node. >> +- microchip,bit-mask: enable mask, similar to microchip,status-bit-mask. > > We've generally decided not to describe clocks at this level of detail > in DT. It's fine though for simple clock trees. This one seems to be > borderline IMO. > The binding example is the entire clock tree. These masks are right from the datasheet. For reference, do you have an example of a better alternative? >> +- microchip,slew-step: enable frequency slewing(stepping) during rate change; >> + applicable only to sys-clock subnode. > Thanks, Josh -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-21 01:30 +0100 |
| Subject | [PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller |
| Message-ID | <qx4dY-6bp-21@gated-at.bofh.it> |
| In reply to | #1274556 |
From: Cristian Birsan <cristian.birsan@microchip.com>
This adds support for the EVIC present on a PIC32MZDA.
The following features are supported:
- DT properties for EVIC and for devices that use interrupt lines
- persistent and non-persistent interrupt handling
- Priority, sub-priority and polariy settings for each interrupt line
- irqdomain support
Signed-off-by: Cristian Birsan <cristian.birsan@microchip.com>
Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com>
---
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-pic32-evic.c | 309 ++++++++++++++++++++++++++++++++++++
include/linux/irqchip/pic32-evic.h | 19 +++
3 files changed, 329 insertions(+)
create mode 100644 drivers/irqchip/irq-pic32-evic.c
create mode 100644 include/linux/irqchip/pic32-evic.h
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..e3608fc 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o
obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
+obj-$(CONFIG_MACH_PIC32) += irq-pic32-evic.o
diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c
new file mode 100644
index 0000000..7b87b43
--- /dev/null
+++ b/drivers/irqchip/irq-pic32-evic.c
@@ -0,0 +1,309 @@
+/*
+ * Cristian Birsan <cristian.birsan@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <dt-bindings/interrupt-controller/microchip,pic32mz-evic.h>
+
+struct irq_domain *evic_irq_domain;
+static struct evic __iomem *evic_base;
+
+static unsigned int *evic_irq_prio;
+
+struct pic_reg {
+ u32 val; /* value register*/
+ u32 clr; /* clear register */
+ u32 set; /* set register */
+ u32 inv; /* inv register */
+} __packed;
+
+struct evic {
+ struct pic_reg intcon;
+ struct pic_reg priss;
+ struct pic_reg intstat;
+ struct pic_reg iptmr;
+ struct pic_reg ifs[6];
+ u32 reserved1[8];
+ struct pic_reg iec[6];
+ u32 reserved2[8];
+ struct pic_reg ipc[48];
+ u32 reserved3[64];
+ u32 off[191];
+} __packed;
+
+static int get_ext_irq_index(irq_hw_number_t hw);
+static void evic_set_ext_irq_polarity(int ext_irq, u32 type);
+
+#define BIT_REG_MASK(bit, reg, mask) \
+ do { \
+ reg = bit/32; \
+ mask = 1 << (bit % 32); \
+ } while (0)
+
+asmlinkage void __weak plat_irq_dispatch(void)
+{
+ unsigned int irq, hwirq;
+ u32 reg, mask;
+
+ hwirq = readl(&evic_base->intstat.val) & 0xFF;
+
+ /* Check if the interrupt was really triggered by hardware*/
+ BIT_REG_MASK(hwirq, reg, mask);
+ if (likely(readl(&evic_base->ifs[reg].val) &
+ readl(&evic_base->iec[reg].val) & mask)) {
+ irq = irq_linear_revmap(evic_irq_domain, hwirq);
+ do_IRQ(irq);
+ } else
+ spurious_interrupt();
+}
+
+/* mask off an interrupt */
+static inline void mask_pic32_irq(struct irq_data *irqd)
+{
+ u32 reg, mask;
+ unsigned int hwirq = irqd_to_hwirq(irqd);
+
+ BIT_REG_MASK(hwirq, reg, mask);
+ writel(mask, &evic_base->iec[reg].clr);
+}
+
+/* unmask an interrupt */
+static inline void unmask_pic32_irq(struct irq_data *irqd)
+{
+ u32 reg, mask;
+ unsigned int hwirq = irqd_to_hwirq(irqd);
+
+ BIT_REG_MASK(hwirq, reg, mask);
+ writel(mask, &evic_base->iec[reg].set);
+}
+
+/* acknowledge an interrupt */
+static void ack_pic32_irq(struct irq_data *irqd)
+{
+ u32 reg, mask;
+ unsigned int hwirq = irqd_to_hwirq(irqd);
+
+ BIT_REG_MASK(hwirq, reg, mask);
+ writel(mask, &evic_base->ifs[reg].clr);
+}
+
+/* mask off and acknowledge an interrupt */
+static inline void mask_ack_pic32_irq(struct irq_data *irqd)
+{
+ u32 reg, mask;
+ unsigned int hwirq = irqd_to_hwirq(irqd);
+
+ BIT_REG_MASK(hwirq, reg, mask);
+ writel(mask, &evic_base->iec[reg].clr);
+ writel(mask, &evic_base->ifs[reg].clr);
+}
+
+static int set_type_pic32_irq(struct irq_data *data, unsigned int flow_type)
+{
+ int index;
+
+ switch (flow_type) {
+
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_set_handler_locked(data, handle_edge_irq);
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_set_handler_locked(data, handle_fasteoi_irq);
+ break;
+
+ default:
+ pr_err("Invalid interrupt type !\n");
+ return -EINVAL;
+ }
+
+ /* set polarity for external interrupts only */
+ index = get_ext_irq_index(data->hwirq);
+ if (index >= 0)
+ evic_set_ext_irq_polarity(index, flow_type);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void pic32_bind_evic_interrupt(int irq, int set)
+{
+ writel(set, &evic_base->off[irq]);
+}
+
+int pic32_get_c0_compare_int(void)
+{
+ int virq;
+
+ virq = irq_create_mapping(evic_irq_domain, CORE_TIMER_INTERRUPT);
+ irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+ return virq;
+}
+
+static struct irq_chip pic32_irq_chip = {
+ .name = "PIC32-EVIC",
+ .irq_ack = ack_pic32_irq,
+ .irq_mask = mask_pic32_irq,
+ .irq_mask_ack = mask_ack_pic32_irq,
+ .irq_unmask = unmask_pic32_irq,
+ .irq_eoi = ack_pic32_irq,
+ .irq_set_type = set_type_pic32_irq,
+ .irq_enable = unmask_pic32_irq,
+ .irq_disable = mask_pic32_irq,
+};
+
+static void evic_set_irq_priority(int irq, int priority)
+{
+ u32 reg, shift;
+
+ reg = irq / 4;
+ shift = (irq % 4) * 8;
+
+ /* set priority */
+ writel(INT_MASK << shift, &evic_base->ipc[reg].clr);
+ writel(priority << shift, &evic_base->ipc[reg].set);
+}
+
+static void evic_set_ext_irq_polarity(int ext_irq, u32 type)
+{
+ if (WARN_ON(ext_irq >= NR_EXT_IRQS))
+ return;
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ writel(1 << ext_irq, &evic_base->intcon.set);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ writel(1 << ext_irq, &evic_base->intcon.clr);
+ break;
+ default:
+ pr_err("Invalid external interrupt polarity !\n");
+ }
+}
+
+static int get_ext_irq_index(irq_hw_number_t hw)
+{
+ switch (hw) {
+ case EXTERNAL_INTERRUPT_0:
+ return 0;
+ case EXTERNAL_INTERRUPT_1:
+ return 1;
+ case EXTERNAL_INTERRUPT_2:
+ return 2;
+ case EXTERNAL_INTERRUPT_3:
+ return 3;
+ case EXTERNAL_INTERRUPT_4:
+ return 4;
+ default:
+ return -1;
+ }
+}
+
+static int evic_intc_map(struct irq_domain *irqd, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ u32 reg, mask;
+
+ irq_set_chip(virq, &pic32_irq_chip);
+
+ BIT_REG_MASK(hw, reg, mask);
+
+ /* disable */
+ writel(mask, &evic_base->iec[reg].clr);
+
+ /* clear flag */
+ writel(mask, &evic_base->ifs[reg].clr);
+
+ evic_set_irq_priority(hw, evic_irq_prio[hw]);
+
+ return 0;
+}
+
+static int evic_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *ctrlr,
+ const u32 *intspec,
+ unsigned int intsize,
+ irq_hw_number_t *out_hwirq,
+ unsigned int *out_type)
+{
+ /* Check for number of params */
+ if (WARN_ON(intsize < 3))
+ return -EINVAL;
+ if (WARN_ON(intspec[0] >= NR_IRQS))
+ return -EINVAL;
+ /* Check for correct priority settings */
+ if (WARN_ON((intspec[1] < MICROCHIP_EVIC_MIN_PRIORITY)
+ || (intspec[1] > MICROCHIP_EVIC_MAX_PRIORITY)))
+ return -EINVAL;
+
+ *out_hwirq = intspec[0];
+
+ evic_irq_prio[*out_hwirq] = intspec[1];
+
+ *out_type = intspec[2];
+
+ return 0;
+}
+
+static const struct irq_domain_ops evic_intc_irq_domain_ops = {
+ .map = evic_intc_map,
+ .xlate = evic_irq_domain_xlate,
+};
+
+#ifdef CONFIG_OF
+
+static int __init
+microchip_evic_of_init(struct device_node *node, struct device_node *parent)
+{
+ struct resource res;
+
+ if (WARN_ON(!node))
+ return -ENODEV;
+
+ evic_irq_prio = kcalloc(NR_IRQS, sizeof(*evic_irq_prio),
+ GFP_KERNEL);
+ if (!evic_irq_prio)
+ return -ENOMEM;
+
+ evic_irq_prio[CORE_TIMER_INTERRUPT] = DEFAULT_INT_PRI; /* Default IRQ*/
+
+ if (of_address_to_resource(node, 0, &res))
+ panic("Failed to get evic memory range");
+
+ if (request_mem_region(res.start, resource_size(&res),
+ res.name) == NULL)
+ panic("Failed to request evic memory");
+
+ evic_base = ioremap_nocache(res.start, resource_size(&res));
+ if (!evic_base)
+ panic("Failed to remap evic memory");
+
+ board_bind_eic_interrupt = &pic32_bind_evic_interrupt;
+
+ evic_irq_domain = irq_domain_add_linear(node, NR_IRQS,
+ &evic_intc_irq_domain_ops, NULL);
+ if (!evic_irq_domain)
+ panic("Failed to add linear irqdomain for EVIC");
+
+ irq_set_default_host(evic_irq_domain);
+
+ return 0;
+}
+
+IRQCHIP_DECLARE(microchip_evic, "microchip,evic-v2", microchip_evic_of_init);
+#endif
diff --git a/include/linux/irqchip/pic32-evic.h b/include/linux/irqchip/pic32-evic.h
new file mode 100644
index 0000000..c514bae
--- /dev/null
+++ b/include/linux/irqchip/pic32-evic.h
@@ -0,0 +1,19 @@
+/*
+ * Joshua Henderson, <joshua.henderson@microchip.com>
+ * Copyright (C) 2015 Microchip Technology Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+#ifndef __LINUX_IRQCHIP_PIC32_EVIC_H
+#define __LINUX_IRQCHIP_PIC32_EVIC_H
+
+extern int pic32_get_c0_compare_int(void);
+
+#endif /* __LINUX_IRQCHIP_PIC32_EVIC_H */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Marc Zyngier <marc.zyngier@arm.com> |
|---|---|
| Date | 2015-11-22 12:50 +0100 |
| Subject | Re: [PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller |
| Message-ID | <qxBjz-3am-1@gated-at.bofh.it> |
| In reply to | #1274568 |
On Fri, 20 Nov 2015 17:17:14 -0700 Joshua Henderson <joshua.henderson@microchip.com> wrote: Joshua, Cristian, > From: Cristian Birsan <cristian.birsan@microchip.com> > > This adds support for the EVIC present on a PIC32MZDA. > > The following features are supported: > - DT properties for EVIC and for devices that use interrupt lines > - persistent and non-persistent interrupt handling > - Priority, sub-priority and polariy settings for each interrupt line > - irqdomain support > I haven't reviewed the code yet, but the fact that you allow (and actually request) the interrupt priorities to be encoded in the DT raises some concerns: - Aren't priorities entirely under software control (and hence don't belong in DT)? - More crucially, how do you deal with nested interrupts when you have interrupts running at different priorities? Most parts of Linux cannot cope with that without additional support. Thanks, M. -- Jazz is not dead. It just smells funny. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-25 19:30 +0100 |
| Subject | Re: [PATCH 02/14] irqchip: irq-pic32-evic: Add support for PIC32 interrupt controller |
| Message-ID | <qyMZk-1sg-29@gated-at.bofh.it> |
| In reply to | #1274853 |
On 11/22/2015 4:45 AM, Marc Zyngier wrote: > On Fri, 20 Nov 2015 17:17:14 -0700 > Joshua Henderson <joshua.henderson@microchip.com> wrote: > > Joshua, Cristian, > >> From: Cristian Birsan <cristian.birsan@microchip.com> >> >> This adds support for the EVIC present on a PIC32MZDA. >> >> The following features are supported: >> - DT properties for EVIC and for devices that use interrupt lines >> - persistent and non-persistent interrupt handling >> - Priority, sub-priority and polariy settings for each interrupt line >> - irqdomain support >> > > I haven't reviewed the code yet, but the fact that you allow (and > actually request) the interrupt priorities to be encoded in the DT > raises some concerns: > > - Aren't priorities entirely under software control (and hence don't > belong in DT)? These are hardware priorities configured by software. They arbitrate pending hardware interrupts to the CPU. We can agree that DT is probably not the best place for this configuration. They will be removed from the binding. > - More crucially, how do you deal with nested interrupts when you have > interrupts running at different priorities? Most parts of Linux > cannot cope with that without additional support. > We do not support nested interrupts. > Thanks, > > M. > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-21 01:30 +0100 |
| Subject | [PATCH 10/14] serial: pic32_uart: Add PIC32 uart driver |
| Message-ID | <qx4dY-6bp-15@gated-at.bofh.it> |
| In reply to | #1274556 |
From: Andrei Pistirica <andrei.pistirica@microchip.com>
This adds UART and a serial console driver for Microchip PIC32 class
devices.
Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com>
---
drivers/tty/serial/Kconfig | 21 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/pic32_uart.c | 930 ++++++++++++++++++++++++++++++++++++++
drivers/tty/serial/pic32_uart.h | 199 ++++++++
include/uapi/linux/serial_core.h | 3 +
5 files changed, 1154 insertions(+)
create mode 100644 drivers/tty/serial/pic32_uart.c
create mode 100644 drivers/tty/serial/pic32_uart.h
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 1aec440..c844c32 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -901,6 +901,27 @@ config SERIAL_SGI_L1_CONSOLE
controller serial port as your console (you want this!),
say Y. Otherwise, say N.
+config SERIAL_PIC32
+ tristate "Microchip PIC32 serial support"
+ depends on MACH_PIC32
+ select SERIAL_CORE
+ help
+ If you have a PIC32, this driver supports the serial ports.
+
+ Say Y or M to use PIC32 serial ports, otherwise say N. Note that
+ to use a serial port as a console, this must be included in kernel and
+ not as a module.
+
+config SERIAL_PIC32_CONSOLE
+ bool "PIC32 serial console support"
+ depends on SERIAL_PIC32
+ select SERIAL_CORE_CONSOLE
+ help
+ If you have a PIC32, this driver supports the putting a console on one
+ of the serial ports.
+
+ Say Y to use the PIC32 console, otherwise say N.
+
config SERIAL_MPC52xx
tristate "Freescale MPC52xx/MPC512x family PSC serial support"
depends on PPC_MPC52xx || PPC_MPC512x
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 5ab4111..bc5e354 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
+obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
new file mode 100644
index 0000000..5b5ec94
--- /dev/null
+++ b/drivers/tty/serial/pic32_uart.c
@@ -0,0 +1,930 @@
+/*
+ * PIC32 Integrated Serial Driver.
+ *
+ * Copyright (C) 2015 Microchip Technology, Inc.
+ *
+ * Authors:
+ * Steve Scott <steve.scott@microchip.com>,
+ * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/console.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <uapi/linux/serial_core.h>
+#include <linux/delay.h>
+
+#include "pic32_uart.h"
+
+/* UART name and device definitions */
+#define PIC32_DEV_NAME "pic32-usart"
+#define PIC32_MAX_UARTS 6
+
+#define PIC32_SDEV_NAME "ttyS"
+#define PIC32_SDEV_MAJOR TTY_MAJOR
+#define PIC32_SDEV_MINOR 64
+
+/* pic32_sport pointer for console use */
+static struct pic32_sport *pic32_sports[PIC32_MAX_UARTS];
+
+static inline int pic32_enable_clock(struct pic32_sport *sport)
+{
+ sport->ref_clk++;
+
+ return clk_prepare_enable(sport->clk);
+}
+
+static inline void pic32_disable_clock(struct pic32_sport *sport)
+{
+ sport->ref_clk--;
+ clk_disable_unprepare(sport->clk);
+}
+
+/* serial core request to check if uart tx buffer is empty */
+static unsigned int pic32_uart_tx_empty(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ u32 val = pic32_uart_read(sport, PIC32_UART_STA);
+
+ return (val & PIC32_UART_STA_TRMT) ? 1 : 0;
+}
+
+/* serial core request to set UART outputs */
+static void pic32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ /* set loopback mode */
+ if (mctrl & TIOCM_LOOP)
+ pic32_uart_rset(PIC32_UART_MODE_LPBK, sport, PIC32_UART_MODE);
+ else
+ pic32_uart_rclr(PIC32_UART_MODE_LPBK, sport, PIC32_UART_MODE);
+}
+
+/* get the state of CTS input pin for this port */
+static unsigned int get_cts_state(struct pic32_sport *sport)
+{
+ /* default state must be asserted */
+ int val = 1;
+
+ /* read and invert UxCTS */
+ if (gpio_is_valid(sport->cts_gpio))
+ val = !gpio_get_value(sport->cts_gpio);
+
+ return val;
+}
+
+/* serial core request to return the state of misc UART input pins */
+static unsigned int pic32_uart_get_mctrl(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ unsigned int mctrl = 0;
+
+ if (!sport->hw_flow_ctrl) {
+ mctrl |= TIOCM_CTS;
+ goto ret;
+ }
+
+ if (get_cts_state(sport))
+ mctrl |= TIOCM_CTS;
+
+ret:
+ /* DSR and CD are not supported in PIC32, so return 1
+ * RI is not supported in PIC32, so return 0
+ */
+ mctrl |= TIOCM_CD;
+ mctrl |= TIOCM_DSR;
+
+ return mctrl;
+}
+
+/* stop tx and start tx are not called in pairs, therefore a flag indicates
+ * the status of irq to control the irq-depth.
+ */
+static inline void pic32_uart_irqtxen(struct pic32_sport *sport, u8 en)
+{
+ if (en && !tx_irq_enabled(sport)) {
+ enable_irq(sport->irq_tx);
+ tx_irq_enabled(sport) = 1;
+ } else if (!en && tx_irq_enabled(sport)) {
+ /* use disable_irq_nosync() and not disable_irq() to avoid self
+ * imposed deadlock by not waiting for irq handler to end,
+ * since this callback is called from interrupt context.
+ */
+ disable_irq_nosync(sport->irq_tx);
+ tx_irq_enabled(sport) = 0;
+ }
+}
+
+/* serial core request to disable tx ASAP (used for flow control) */
+static void pic32_uart_stop_tx(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ if (!(pic32_uart_read(sport, PIC32_UART_MODE) & PIC32_UART_MODE_ON))
+ return;
+
+ if (!(pic32_uart_read(sport, PIC32_UART_STA) & PIC32_UART_STA_UTXEN))
+ return;
+
+ /* wait for tx empty */
+ while (!(pic32_uart_read(sport, PIC32_UART_STA) & PIC32_UART_STA_TRMT))
+ udelay(1);
+
+ pic32_uart_rclr(PIC32_UART_STA_UTXEN, sport, PIC32_UART_STA);
+ pic32_uart_irqtxen(sport, 0);
+}
+
+/* serial core request to (re)enable tx */
+static void pic32_uart_start_tx(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ pic32_uart_irqtxen(sport, 1);
+ pic32_uart_rset(PIC32_UART_STA_UTXEN, sport, PIC32_UART_STA);
+}
+
+/* serial core request to stop rx, called before port shutdown */
+static void pic32_uart_stop_rx(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ /* disable rx interrupts */
+ disable_irq(sport->irq_rx);
+
+ /* receiver Enable bit OFF */
+ pic32_uart_rclr(PIC32_UART_STA_URXEN, sport, PIC32_UART_STA);
+}
+
+/* serial core request to start/stop emitting break char */
+static void pic32_uart_break_ctl(struct uart_port *port, int ctl)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (ctl)
+ pic32_uart_rset(PIC32_UART_STA_UTXBRK, sport, PIC32_UART_STA);
+ else
+ pic32_uart_rclr(PIC32_UART_STA_UTXBRK, sport, PIC32_UART_STA);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* get port type in string format */
+static const char *pic32_uart_type(struct uart_port *port)
+{
+ return (port->type == PORT_PIC32) ? PIC32_DEV_NAME : NULL;
+}
+
+/* read all chars in rx fifo and send them to core */
+static void pic32_uart_do_rx(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ struct tty_port *tty;
+ unsigned int max_count;
+
+ /* limit number of char read in interrupt, should not be
+ * higher than fifo size anyway since we're much faster than
+ * serial port
+ */
+ max_count = PIC32_UART_RX_FIFO_DEPTH;
+
+ spin_lock(&port->lock);
+
+ tty = &port->state->port;
+
+ do {
+ u32 sta_reg, c;
+ char flag;
+
+ /* get overrun/fifo empty information from status register */
+ sta_reg = pic32_uart_read(sport, PIC32_UART_STA);
+ if (unlikely(sta_reg & PIC32_UART_STA_OERR)) {
+
+ /* fifo reset is required to clear interrupt */
+ pic32_uart_rclr(PIC32_UART_STA_OERR, sport,
+ PIC32_UART_STA);
+
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+
+ /* Can at least one more character can be read? */
+ if (!(sta_reg & PIC32_UART_STA_URXDA))
+ break;
+
+ /* read the character and increment the rx counter */
+ c = pic32_uart_read(sport, PIC32_UART_RX);
+
+ port->icount.rx++;
+ flag = TTY_NORMAL;
+ c &= 0xff;
+
+ if (unlikely((sta_reg & PIC32_UART_STA_PERR) ||
+ (sta_reg & PIC32_UART_STA_FERR))) {
+
+ /* do stats first */
+ if (sta_reg & PIC32_UART_STA_PERR)
+ port->icount.parity++;
+ if (sta_reg & PIC32_UART_STA_FERR)
+ port->icount.frame++;
+
+ /* update flag wrt read_status_mask */
+ sta_reg &= port->read_status_mask;
+
+ if (sta_reg & PIC32_UART_STA_FERR)
+ flag = TTY_FRAME;
+ if (sta_reg & PIC32_UART_STA_PERR)
+ flag = TTY_PARITY;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+
+ if ((sta_reg & port->ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, c, flag);
+
+ } while (--max_count);
+
+ spin_unlock(&port->lock);
+
+ tty_flip_buffer_push(tty);
+}
+
+/* fill tx fifo with chars to send, stop when fifo is about to be full
+ * or when all chars have been sent.
+ */
+static void pic32_uart_do_tx(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH;
+
+ if (port->x_char) {
+ pic32_uart_write(port->x_char, sport, PIC32_UART_TX);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_tx_stopped(port)) {
+ pic32_uart_stop_tx(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit))
+ goto txq_empty;
+
+ /* keep stuffing chars into uart tx buffer
+ * 1) until uart fifo is full
+ * or
+ * 2) until the circ buffer is empty
+ * (all chars have been sent)
+ * or
+ * 3) until the max count is reached
+ * (prevents lingering here for too long in certain cases)
+ */
+ while (!(PIC32_UART_STA_UTXBF &
+ pic32_uart_rval(sport, PIC32_UART_STA))) {
+ unsigned int c = xmit->buf[xmit->tail];
+
+ pic32_uart_write(c, sport, PIC32_UART_TX);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ --max_count;
+ if (uart_circ_empty(xmit))
+ break;
+ if (max_count == 0)
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ goto txq_empty;
+
+ return;
+
+txq_empty:
+ pic32_uart_irqtxen(sport, 0);
+}
+
+/* RX interrupt handler */
+static irqreturn_t pic32_uart_rx_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+
+ pic32_uart_do_rx(port);
+
+ return IRQ_HANDLED;
+}
+
+/* TX interrupt handler */
+static irqreturn_t pic32_uart_tx_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ pic32_uart_do_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/* FAULT interrupt handler */
+static irqreturn_t pic32_uart_fault_interrupt(int irq, void *dev_id)
+{
+ /* do nothing: pic32_uart_do_rx() handles faults. */
+ return IRQ_HANDLED;
+}
+
+/* enable rx & tx operation on uart */
+static void pic32_uart_en_and_unmask(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ pic32_uart_rset(PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN,
+ sport, PIC32_UART_STA);
+ pic32_uart_rset(PIC32_UART_MODE_ON, sport, PIC32_UART_MODE);
+}
+
+/* disable rx & tx operation on uart */
+static void pic32_uart_dsbl_and_mask(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ pic32_uart_rclr(PIC32_UART_MODE_ON, sport, PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN,
+ sport, PIC32_UART_STA);
+}
+
+/* serial core request to initialize uart and start rx operation */
+static int pic32_uart_startup(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ u32 dflt_baud = ((port->uartclk / PIC32_UART_DFLT_BRATE) / 16) - 1;
+ unsigned long flags;
+ int ret = 0;
+
+ local_irq_save(flags);
+
+ ret = pic32_enable_clock(sport);
+ if (ret)
+ goto out_unlock;
+
+ /* clear status and mode registers */
+ pic32_uart_write(0, sport, PIC32_UART_MODE);
+ pic32_uart_write(0, sport, PIC32_UART_STA);
+
+ /* disable uart and mask all interrupts */
+ pic32_uart_dsbl_and_mask(port);
+
+ /* set default baud */
+ pic32_uart_write(dflt_baud, sport, PIC32_UART_BRG);
+
+ local_irq_restore(flags);
+
+ /* Each UART of a PIC32 has three interrupts therefore,
+ * we setup driver to register the 3 irqs for the device.
+ *
+ * For each irq request_irq() is called with interrupt disabled.
+ * And the irq is enabled as soon as we are ready to handle them.
+ */
+ tx_irq_enabled(sport) = 0;
+
+ sport->irq_fault_name = kasprintf(GFP_KERNEL, "%s%d-fault",
+ pic32_uart_type(port),
+ sport->idx);
+ irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN);
+ ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt,
+ sport->irqflags_fault, sport->irq_fault_name, port);
+ if (ret) {
+ dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
+ __func__, sport->irq_fault, ret,
+ pic32_uart_type(port));
+ goto out_done;
+ }
+
+ sport->irq_rx_name = kasprintf(GFP_KERNEL, "%s%d-rx",
+ pic32_uart_type(port),
+ sport->idx);
+ irq_set_status_flags(sport->irq_rx, IRQ_NOAUTOEN);
+ ret = request_irq(sport->irq_rx, pic32_uart_rx_interrupt,
+ sport->irqflags_rx, sport->irq_rx_name, port);
+ if (ret) {
+ dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
+ __func__, sport->irq_rx, ret,
+ pic32_uart_type(port));
+ goto out_done;
+ }
+
+ sport->irq_tx_name = kasprintf(GFP_KERNEL, "%s%d-tx",
+ pic32_uart_type(port),
+ sport->idx);
+ irq_set_status_flags(sport->irq_tx, IRQ_NOAUTOEN);
+ ret = request_irq(sport->irq_tx, pic32_uart_tx_interrupt,
+ sport->irqflags_tx, sport->irq_tx_name, port);
+ if (ret) {
+ dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
+ __func__, sport->irq_tx, ret,
+ pic32_uart_type(port));
+ goto out_done;
+ }
+
+ local_irq_save(flags);
+
+ /* set rx interrupt on first receive */
+ pic32_uart_rclr(PIC32_UART_STA_URXISEL1 | PIC32_UART_STA_URXISEL0,
+ sport, PIC32_UART_STA);
+
+ /* set interrupt on empty */
+ pic32_uart_rclr(PIC32_UART_STA_UTXISEL1, sport, PIC32_UART_STA);
+
+ /* enable all interrupts and eanable uart */
+ pic32_uart_en_and_unmask(port);
+
+ enable_irq(sport->irq_fault);
+ enable_irq(sport->irq_rx);
+
+out_unlock:
+ local_irq_restore(flags);
+
+out_done:
+ return ret;
+}
+
+/* serial core request to flush & disable uart */
+static void pic32_uart_shutdown(struct uart_port *port)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ unsigned long flags;
+
+ /* disable uart */
+ spin_lock_irqsave(&port->lock, flags);
+ pic32_uart_dsbl_and_mask(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ pic32_disable_clock(sport);
+
+ /* free all 3 interrupts for this UART */
+ free_irq(sport->irq_fault, port);
+ free_irq(sport->irq_tx, port);
+ free_irq(sport->irq_rx, port);
+}
+
+/* serial core request to change current uart setting */
+static void pic32_uart_set_termios(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+ unsigned int baud;
+ unsigned int quot;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* disable uart and mask all interrupts while changing speed */
+ pic32_uart_dsbl_and_mask(port);
+
+ /* stop bit options */
+ if (new->c_cflag & CSTOPB)
+ pic32_uart_rset(PIC32_UART_MODE_STSEL, sport, PIC32_UART_MODE);
+ else
+ pic32_uart_rclr(PIC32_UART_MODE_STSEL, sport, PIC32_UART_MODE);
+
+ /* parity options */
+ if (new->c_cflag & PARENB) {
+ if (new->c_cflag & PARODD) {
+ pic32_uart_rset(PIC32_UART_MODE_PDSEL1, sport,
+ PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_PDSEL0, sport,
+ PIC32_UART_MODE);
+ } else {
+ pic32_uart_rset(PIC32_UART_MODE_PDSEL0, sport,
+ PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_PDSEL1, sport,
+ PIC32_UART_MODE);
+ }
+ } else {
+ pic32_uart_rclr(PIC32_UART_MODE_PDSEL1 | PIC32_UART_MODE_PDSEL0,
+ sport, PIC32_UART_MODE);
+ }
+ /* if hw flow ctrl, then the pins must be specified in device tree */
+ if ((new->c_cflag & CRTSCTS) && sport->hw_flow_ctrl) {
+ /* enable hardware flow control */
+ pic32_uart_rset(PIC32_UART_MODE_UEN1, sport, PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_UEN0, sport, PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_RTSMD, sport, PIC32_UART_MODE);
+ } else {
+ /* disable hardware flow control */
+ pic32_uart_rclr(PIC32_UART_MODE_UEN1, sport, PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_UEN0, sport, PIC32_UART_MODE);
+ pic32_uart_rclr(PIC32_UART_MODE_RTSMD, sport, PIC32_UART_MODE);
+ }
+
+ /* update baud */
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud) - 1;
+ pic32_uart_write(quot, sport, PIC32_UART_BRG);
+ uart_update_timeout(port, new->c_cflag, baud);
+
+ /* enable uart */
+ pic32_uart_en_and_unmask(port);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* serial core request to claim uart iomem */
+static int pic32_uart_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *res_mem;
+ unsigned int res_size;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res_mem))
+ return -EINVAL;
+ res_size = resource_size(res_mem);
+
+ if (!request_mem_region(port->mapbase, res_size, "pic32_uart_mem")) {
+ dev_err(port->dev, "Memory region busy\n");
+ return -EBUSY;
+ }
+
+ port->membase = devm_ioremap_nocache(port->dev,
+ port->mapbase, res_size);
+ if (!port->membase) {
+ dev_err(port->dev, "Unable to map registers\n");
+ release_mem_region(port->mapbase, res_size);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* serial core request to release uart iomem */
+static void pic32_uart_release_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *res_mem;
+ unsigned int res_size;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res_mem))
+ return;
+ res_size = resource_size(res_mem);
+
+ release_mem_region(port->mapbase, res_size);
+ devm_iounmap(port->dev, port->membase);
+}
+
+/* serial core request to do any port required auto-configuration */
+static void pic32_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ if (pic32_uart_request_port(port))
+ return;
+ port->type = PORT_PIC32;
+ }
+}
+
+/* serial core request to check that port information in serinfo are suitable */
+static int pic32_uart_verify_port(struct uart_port *port,
+ struct serial_struct *serinfo)
+{
+ if (port->type != PORT_PIC32)
+ return -EINVAL;
+ if (port->irq != serinfo->irq)
+ return -EINVAL;
+ if (port->iotype != serinfo->io_type)
+ return -EINVAL;
+ if (port->mapbase != (unsigned long)serinfo->iomem_base)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* serial core callbacks */
+static const struct uart_ops pic32_uart_ops = {
+ .tx_empty = pic32_uart_tx_empty,
+ .get_mctrl = pic32_uart_get_mctrl,
+ .set_mctrl = pic32_uart_set_mctrl,
+ .start_tx = pic32_uart_start_tx,
+ .stop_tx = pic32_uart_stop_tx,
+ .stop_rx = pic32_uart_stop_rx,
+ .break_ctl = pic32_uart_break_ctl,
+ .startup = pic32_uart_startup,
+ .shutdown = pic32_uart_shutdown,
+ .set_termios = pic32_uart_set_termios,
+ .type = pic32_uart_type,
+ .release_port = pic32_uart_release_port,
+ .request_port = pic32_uart_request_port,
+ .config_port = pic32_uart_config_port,
+ .verify_port = pic32_uart_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_PIC32_CONSOLE
+/* output given char */
+static void pic32_console_putchar(struct uart_port *port, int ch)
+{
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ if (!(pic32_uart_read(sport, PIC32_UART_MODE) & PIC32_UART_MODE_ON))
+ return;
+
+ if (!(pic32_uart_read(sport, PIC32_UART_STA) & PIC32_UART_STA_UTXEN))
+ return;
+
+ /* wait for tx empty */
+ while (!(pic32_uart_read(sport, PIC32_UART_STA) & PIC32_UART_STA_TRMT))
+ udelay(1);
+
+ pic32_uart_write(ch & 0xff, sport, PIC32_UART_TX);
+}
+
+/* console core request to output given string */
+static void pic32_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct pic32_sport *sport = pic32_sports[co->index];
+ struct uart_port *port = pic32_get_port(sport);
+
+ /* call uart helper to deal with \r\n */
+ uart_console_write(port, s, count, pic32_console_putchar);
+}
+
+/* console core request to setup given console, find matching uart
+ * port and setup it.
+ */
+static int pic32_console_setup(struct console *co, char *options)
+{
+ struct pic32_sport *sport;
+ struct uart_port *port = NULL;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret = 0;
+
+ if (unlikely(co->index < 0 || co->index >= PIC32_MAX_UARTS))
+ return -ENODEV;
+
+ sport = pic32_sports[co->index];
+ if (!sport)
+ return -ENODEV;
+ port = pic32_get_port(sport);
+
+ ret = pic32_enable_clock(sport);
+ if (ret)
+ return ret;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver pic32_uart_driver;
+static struct console pic32_console = {
+ .name = PIC32_SDEV_NAME,
+ .write = pic32_console_write,
+ .device = uart_console_device,
+ .setup = pic32_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &pic32_uart_driver,
+};
+#define PIC32_SCONSOLE (&pic32_console)
+
+static int __init pic32_console_init(void)
+{
+ register_console(&pic32_console);
+ return 0;
+}
+console_initcall(pic32_console_init);
+
+static inline bool is_pic32_console_port(struct uart_port *port)
+{
+ return (port->cons && port->cons->index == port->line);
+}
+
+/*
+ * Late console initialization.
+ */
+static int __init pic32_late_console_init(void)
+{
+ if (!(pic32_console.flags & CON_ENABLED))
+ register_console(&pic32_console);
+
+ return 0;
+}
+
+core_initcall(pic32_late_console_init);
+
+#else
+#define PIC32_SCONSOLE NULL
+#endif
+
+static struct uart_driver pic32_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = PIC32_DEV_NAME,
+ .dev_name = PIC32_SDEV_NAME,
+ .major = PIC32_SDEV_MAJOR,
+ .minor = PIC32_SDEV_MINOR,
+ .nr = PIC32_MAX_UARTS,
+ .cons = PIC32_SCONSOLE,
+};
+
+static int pic32_uart_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct pic32_sport *sport;
+ int uart_idx = 0;
+ struct resource *res_mem;
+ struct uart_port *port;
+ int ret = 0;
+
+ uart_idx = of_alias_get_id(np, "serial");
+ if (uart_idx < 0 || uart_idx >= PIC32_MAX_UARTS)
+ return -EINVAL;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem)
+ return -EINVAL;
+
+ sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
+ if (!sport)
+ return -ENOMEM;
+
+ sport->idx = uart_idx;
+ sport->irq_fault = irq_of_parse_and_map(np, 0);
+ sport->irqflags_fault = IRQF_NO_THREAD;
+ sport->irq_rx = irq_of_parse_and_map(np, 1);
+ sport->irqflags_rx = IRQF_NO_THREAD;
+ sport->irq_tx = irq_of_parse_and_map(np, 2);
+ sport->irqflags_tx = IRQF_NO_THREAD;
+ sport->clk = devm_clk_get(&pdev->dev, NULL);
+ sport->cts_gpio = -EINVAL;
+ sport->dev = &pdev->dev;
+
+ ret = pic32_enable_clock(sport);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable ?\n");
+ goto err;
+ }
+
+ sport->hw_flow_ctrl = of_property_read_bool(np,
+ "microchip,uart-has-rtscts");
+ if (!sport->hw_flow_ctrl)
+ goto uart_no_flow_ctrl;
+
+ /* Hardware flow control: gpios
+ * !Note: Basically, CTS is needed for reading the status.
+ */
+ sport->cts_gpio = of_get_named_gpio(np, "cts-gpios", 0);
+ if (gpio_is_valid(sport->cts_gpio)) {
+ ret = devm_gpio_request(sport->dev,
+ sport->cts_gpio, "CTS");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "error requesting CTS GPIO\n");
+ goto err_disable_clk;
+ }
+
+ ret = gpio_direction_input(sport->cts_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "error setting CTS GPIO\n");
+ goto err_disable_clk;
+ }
+ }
+
+uart_no_flow_ctrl:
+ pic32_sports[uart_idx] = sport;
+ port = &sport->port;
+ memset(port, 0, sizeof(*port));
+ port->iotype = UPIO_MEM;
+ port->mapbase = res_mem->start;
+ port->ops = &pic32_uart_ops;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->dev = &pdev->dev;
+ port->fifosize = PIC32_UART_TX_FIFO_DEPTH;
+ port->uartclk = clk_get_rate(sport->clk);
+ port->line = uart_idx;
+
+ ret = uart_add_one_port(&pic32_uart_driver, port);
+ if (ret) {
+ port->membase = 0;
+ dev_err(port->dev, "%s: uart add port error!\n", __func__);
+ goto err_disable_clk;
+ }
+
+#ifdef CONFIG_SERIAL_PIC32_CONSOLE
+ if (is_pic32_console_port(port) &&
+ (pic32_console.flags & CON_ENABLED)) {
+ /* The peripheral clock has been enabled by console_setup,
+ * so disable it till the port is used.
+ */
+ pic32_disable_clock(sport);
+ }
+#endif
+
+ platform_set_drvdata(pdev, port);
+
+ dev_info(&pdev->dev, "%s: uart(%d) driver initialized.\n",
+ __func__, uart_idx);
+ ret = 0;
+
+err_disable_clk:
+ /* disable clock till the port is used. */
+ pic32_disable_clock(sport);
+err:
+ /* automatic unroll of sport and gpios */
+ return ret;
+}
+
+static int pic32_uart_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct pic32_sport *sport = to_pic32_sport(port);
+
+ uart_remove_one_port(&pic32_uart_driver, port);
+ pic32_disable_clock(sport);
+ platform_set_drvdata(pdev, NULL);
+ pic32_sports[sport->idx] = NULL;
+
+ /* automatic unroll of sport and gpios */
+ return 0;
+}
+
+static const struct of_device_id pic32_serial_dt_ids[] = {
+ { .compatible = "microchip,pic32-usart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids);
+
+static struct platform_driver pic32_uart_platform_driver = {
+ .probe = pic32_uart_probe,
+ .remove = pic32_uart_remove,
+ .driver = {
+ .name = PIC32_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pic32_serial_dt_ids),
+ },
+};
+
+static int __init pic32_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&pic32_uart_driver);
+ if (ret) {
+ pr_err("failed to register %s:%d\n",
+ pic32_uart_driver.driver_name, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&pic32_uart_platform_driver);
+ if (ret) {
+ pr_err("fail to register pic32 uart\n");
+ uart_unregister_driver(&pic32_uart_driver);
+ }
+
+ return ret;
+}
+arch_initcall(pic32_uart_init);
+
+static void __exit pic32_uart_exit(void)
+{
+#ifdef CONFIG_SERIAL_PIC32_CONSOLE
+ unregister_console(&pic32_console);
+#endif
+ platform_driver_unregister(&pic32_uart_platform_driver);
+ uart_unregister_driver(&pic32_uart_driver);
+}
+module_exit(pic32_uart_exit);
+
+MODULE_AUTHOR("Steve Scott <steve.scott@microchip.com>");
+MODULE_DESCRIPTION("Microchip PIC32 integrated serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/pic32_uart.h b/drivers/tty/serial/pic32_uart.h
new file mode 100644
index 0000000..157ae7a
--- /dev/null
+++ b/drivers/tty/serial/pic32_uart.h
@@ -0,0 +1,199 @@
+/*
+ * PIC32 Integrated Serial Driver.
+ *
+ * Copyright (C) 2015 Microchip Technology, Inc.
+ *
+ * Authors:
+ * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+#ifndef __DT_PIC32_UART_H__
+#define __DT_PIC32_UART_H__
+
+#define PIC32_UART_DFLT_BRATE (9600)
+#define PIC32_UART_TX_FIFO_DEPTH (8)
+#define PIC32_UART_RX_FIFO_DEPTH (8)
+
+struct pic32_console_opt {
+ int baud;
+ int parity;
+ int bits;
+ int flow;
+};
+/* struct pic32_sport - pic32 serial port descriptor
+ * @port: uart port descriptor
+ * @idx: port index
+ * @irq_fault: virtual fault interrupt number
+ * @irqflags_fault: flags related to fault irq
+ * @irq_fault_name: irq fault name
+ * @irq_rx: virtual rx interrupt number
+ * @irqflags_rx: flags related to rx irq
+ * @irq_rx_name: irq rx name
+ * @irq_tx: virtual tx interrupt number
+ * @irqflags_tx: : flags related to tx irq
+ * @irq_tx_name: irq tx name
+ * @cts_gpio: clear to send gpio
+ * @rts_gpio: ready to sent gpio
+ * @dev: device descriptor
+ **/
+struct pic32_sport {
+ struct uart_port port;
+ struct pic32_console_opt opt;
+ int idx;
+
+ int irq_fault;
+ int irqflags_fault;
+ const char *irq_fault_name;
+ int irq_rx;
+ int irqflags_rx;
+ const char *irq_rx_name;
+ int irq_tx;
+ int irqflags_tx;
+ const char *irq_tx_name;
+ u8 enable_tx_irq;
+
+ bool hw_flow_ctrl;
+ int cts_gpio;
+
+ int ref_clk;
+ struct clk *clk;
+
+ struct device *dev;
+};
+#define to_pic32_sport(c) container_of(c, struct pic32_sport, port)
+#define pic32_get_port(sport) (&sport->port)
+#define pic32_get_opt(sport) (&sport->opt)
+#define tx_irq_enabled(sport) (sport->enable_tx_irq)
+
+struct pic32_reg {
+ u32 val;
+ u32 clr;
+ u32 set;
+ u32 inv;
+} __packed;
+#define PIC32_REGS 4
+#define PIC32_REG_SIZE 4
+
+enum pic32_uart_regs {
+ PIC32_UART_UNKNOWN = 0,
+ PIC32_UART_MODE = 1,
+ PIC32_UART_STA = 2,
+ PIC32_UART_TX = 3,
+ PIC32_UART_RX = 4,
+ PIC32_UART_BRG = 5,
+
+ /* add above this line */
+ PIC32_UART_LAST
+};
+
+/* uart register offsets */
+static u32 pic32_uart_lookup_reg[PIC32_UART_LAST] = {
+ [PIC32_UART_MODE] = 0 * PIC32_REGS * PIC32_REG_SIZE,
+ [PIC32_UART_STA] = 1 * PIC32_REGS * PIC32_REG_SIZE,
+ [PIC32_UART_TX] = 2 * PIC32_REGS * PIC32_REG_SIZE,
+ [PIC32_UART_RX] = 3 * PIC32_REGS * PIC32_REG_SIZE,
+ [PIC32_UART_BRG] = 4 * PIC32_REGS * PIC32_REG_SIZE,
+};
+
+static inline void __iomem *pic32_uart_get_reg(struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ struct uart_port *port = pic32_get_port(sport);
+
+ return port->membase + pic32_uart_lookup_reg[reg];
+}
+
+static inline u32 pic32_uart_rval(struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+ struct pic32_reg __iomem *reg_addr = (struct pic32_reg __iomem *)addr;
+
+ return readl(®_addr->val);
+}
+
+static inline void pic32_uart_rset(u32 val,
+ struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+ struct pic32_reg __iomem *reg_addr = (struct pic32_reg __iomem *)addr;
+
+ writel(val, ®_addr->set);
+}
+
+static inline void pic32_uart_rclr(u32 val,
+ struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+ struct pic32_reg __iomem *reg_addr = (struct pic32_reg __iomem *)addr;
+
+ writel(val, ®_addr->clr);
+}
+
+static inline void pic32_uart_rinv(u32 val,
+ struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+ struct pic32_reg __iomem *reg_addr = (struct pic32_reg __iomem *)addr;
+
+ writel(val, ®_addr->inv);
+}
+
+static inline void pic32_uart_write(u32 val,
+ struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+
+ writel(val, addr);
+}
+
+static inline u32 pic32_uart_read(struct pic32_sport *sport,
+ enum pic32_uart_regs reg)
+{
+ void __iomem *addr = pic32_uart_get_reg(sport, reg);
+
+ return readl(addr);
+}
+
+/* pic32 uart mode register bits */
+#define PIC32_UART_MODE_ON (1 << 15)
+#define PIC32_UART_MODE_FRZ (1 << 14)
+#define PIC32_UART_MODE_SIDL (1 << 13)
+#define PIC32_UART_MODE_IREN (1 << 12)
+#define PIC32_UART_MODE_RTSMD (1 << 11)
+#define PIC32_UART_MODE_RESV1 (1 << 10)
+#define PIC32_UART_MODE_UEN1 (1 << 9)
+#define PIC32_UART_MODE_UEN0 (1 << 8)
+#define PIC32_UART_MODE_WAKE (1 << 7)
+#define PIC32_UART_MODE_LPBK (1 << 6)
+#define PIC32_UART_MODE_ABAUD (1 << 5)
+#define PIC32_UART_MODE_RXINV (1 << 4)
+#define PIC32_UART_MODE_BRGH (1 << 3)
+#define PIC32_UART_MODE_PDSEL1 (1 << 2)
+#define PIC32_UART_MODE_PDSEL0 (1 << 1)
+#define PIC32_UART_MODE_STSEL (1 << 0)
+
+/* pic32 uart status register bits */
+#define PIC32_UART_STA_UTXISEL1 (1 << 15)
+#define PIC32_UART_STA_UTXISEL0 (1 << 14)
+#define PIC32_UART_STA_UTXINV (1 << 13)
+#define PIC32_UART_STA_URXEN (1 << 12)
+#define PIC32_UART_STA_UTXBRK (1 << 11)
+#define PIC32_UART_STA_UTXEN (1 << 10)
+#define PIC32_UART_STA_UTXBF (1 << 9)
+#define PIC32_UART_STA_TRMT (1 << 8)
+#define PIC32_UART_STA_URXISEL1 (1 << 7)
+#define PIC32_UART_STA_URXISEL0 (1 << 6)
+#define PIC32_UART_STA_ADDEN (1 << 5)
+#define PIC32_UART_STA_RIDLE (1 << 4)
+#define PIC32_UART_STA_PERR (1 << 3)
+#define PIC32_UART_STA_FERR (1 << 2)
+#define PIC32_UART_STA_OERR (1 << 1)
+#define PIC32_UART_STA_URXDA (1 << 0)
+
+#endif /* __DT_PIC32_UART_H__ */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 93ba148..9df0a98 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -261,4 +261,7 @@
/* STM32 USART */
#define PORT_STM32 113
+/* Microchip PIC32 UART */
+#define PORT_PIC32 114
+
#endif /* _UAPILINUX_SERIAL_CORE_H */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-21 01:30 +0100 |
| Subject | [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller |
| Message-ID | <qx4dY-6bp-23@gated-at.bofh.it> |
| In reply to | #1274556 |
From: Cristian Birsan <cristian.birsan@microchip.com>
Document the devicetree bindings for the interrupt controller on Microchip
PIC32 class devices. This also adds a header defining associated interrupts
and related settings.
Signed-off-by: Cristian Birsan <cristian.birsan@microchip.com>
Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com>
---
.../microchip,pic32mz-evic.txt | 65 ++++++
.../interrupt-controller/microchip,pic32mz-evic.h | 238 ++++++++++++++++++++
2 files changed, 303 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt
create mode 100644 include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
diff --git a/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt
new file mode 100644
index 0000000..12fb91f
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt
@@ -0,0 +1,65 @@
+Microchip PIC32MZ Interrupt Controller
+======================================
+
+The Microchip PIC32MZ SOC contains an Enhanced Vectored Interrupt Controller
+(EVIC) version 2. It handles internal and external interrupts and provides
+support for priority, sub-priority, irq type and polarity.
+
+Required properties
+-------------------
+
+- compatible: Should be "microchip,evic-v2"
+
+- reg: specifies physical base address and size of register range.
+
+- interrupt-controller: Identifies the node as an interrupt controller.
+
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+source connected to this controller. The value shall be 3 and interrupt
+descriptor shall have the following format:
+ <hw_irq irq_priority_and_subpriority irq_type>
+
+hw_irq - represents the hardware interrupt number as in the data sheet.
+
+irq_priority_and_subpriority - sets the priority and sub-priority for the
+interrupt line. The INT_PRI(pri, subpri) macro can be used to set desired
+values or the DEFAULT_INT_PRI can be used for the default value.
+
+irq_type - is used to describe the type and polarity of an interrupt. For
+internal interrupts use IRQ_TYPE_EDGE_RISING for non persistent interrupts and
+IRQ_TYPE_LEVEL_HIGH for persistent interrupts. For external interrupts use
+IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING to select the desired polarity.
+
+Example
+-------
+
+evic: interrupt-controller@1f810000 {
+ compatible = "microchip,evic-v2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x1f810000 0x1000>;
+ device_type="evic-v2";
+};
+
+Each device must request his interrupt line with the associated priority and
+polarity
+
+Internal interrupt DTS snippet
+------------------------------
+
+device@1f800000 {
+ ...
+ interrupt-parent = <&evic>;
+ interrupts = <UART1_RECEIVE_DONE DEFAULT_INT_PRI IRQ_TYPE_NONE>;
+ ...
+};
+
+External interrupt DTS snippet
+------------------------------
+
+device@1f800000 {
+ ...
+ interrupt-parent = <&evic>;
+ interrupts = <EXTERNAL_INTERRUPT_0 DEFAULT_INT_PRI IRQ_TYPE_EDGE_RISING>;
+ ...
+};
diff --git a/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
new file mode 100644
index 0000000..2c466b8
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
@@ -0,0 +1,238 @@
+/*
+ * This header provides constants for the MICROCHIP PIC32 EVIC.
+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/* Hardware interrupt number */
+#define CORE_TIMER_INTERRUPT 0
+#define CORE_SOFTWARE_INTERRUPT_0 1
+#define CORE_SOFTWARE_INTERRUPT_1 2
+#define EXTERNAL_INTERRUPT_0 3
+#define TIMER1 4
+#define INPUT_CAPTURE_1_ERROR 5
+#define INPUT_CAPTURE_1 6
+#define OUTPUT_COMPARE_1 7
+#define EXTERNAL_INTERRUPT_1 8
+#define TIMER2 9
+#define INPUT_CAPTURE_2_ERROR 10
+#define INPUT_CAPTURE_2 11
+#define OUTPUT_COMPARE_2 12
+#define EXTERNAL_INTERRUPT_2 13
+#define TIMER3 14
+#define INPUT_CAPTURE_3_ERROR 15
+#define INPUT_CAPTURE_3 16
+#define OUTPUT_COMPARE_3 17
+#define EXTERNAL_INTERRUPT_3 18
+#define TIMER4 19
+#define INPUT_CAPTURE_4_ERROR 20
+#define INPUT_CAPTURE_4 21
+#define OUTPUT_COMPARE_4 22
+#define EXTERNAL_INTERRUPT_4 23
+#define TIMER5 24
+#define INPUT_CAPTURE_5_ERROR 25
+#define INPUT_CAPTURE_5 26
+#define OUTPUT_COMPARE_5 27
+#define TIMER6 28
+#define INPUT_CAPTURE_6_ERROR 29
+#define INPUT_CAPTURE_6 30
+#define OUTPUT_COMPARE_6 31
+#define TIMER7 32
+#define INPUT_CAPTURE_7_ERROR 33
+#define INPUT_CAPTURE_7 34
+#define OUTPUT_COMPARE_7 35
+#define TIMER8 36
+#define INPUT_CAPTURE_8_ERROR 37
+#define INPUT_CAPTURE_8 38
+#define OUTPUT_COMPARE_8 39
+#define TIMER9 40
+#define INPUT_CAPTURE_9_ERROR 41
+#define INPUT_CAPTURE_9 42
+#define OUTPUT_COMPARE_9 43
+/* ADC */
+#define ADC1_GLOBAL 44
+/* Reserved */
+#define ADC1_DIGITAL_COMPARATOR_1 46
+#define ADC1_DIGITAL_COMPARATOR_2 47
+#define ADC1_DIGITAL_COMPARATOR_3 48
+#define ADC1_DIGITAL_COMPARATOR_4 49
+#define ADC1_DIGITAL_COMPARATOR_5 50
+#define ADC1_DIGITAL_COMPARATOR_6 51
+#define ADC1_DIGITAL_FILTER_1 52
+#define ADC1_DIGITAL_FILTER_2 53
+#define ADC1_DIGITAL_FILTER_3 54
+#define ADC1_DIGITAL_FILTER_4 55
+#define ADC1_DIGITAL_FILTER_5 56
+#define ADC1_DIGITAL_FILTER_6 57
+/* Reserved */
+#define ADC1_DATA_0 59
+#define ADC1_DATA_1 60
+#define ADC1_DATA_2 61
+#define ADC1_DATA_3 62
+#define ADC1_DATA_4 63
+#define ADC1_DATA_5 64
+#define ADC1_DATA_6 65
+#define ADC1_DATA_7 66
+#define ADC1_DATA_8 67
+#define ADC1_DATA_9 68
+#define ADC1_DATA_10 69
+#define ADC1_DATA_11 70
+#define ADC1_DATA_12 71
+#define ADC1_DATA_13 72
+#define ADC1_DATA_14 73
+#define ADC1_DATA_15 74
+#define ADC1_DATA_16 75
+#define ADC1_DATA_17 76
+#define ADC1_DATA_18 77
+#define ADC1_DATA_19 78
+#define ADC1_DATA_20 79
+#define ADC1_DATA_21 80
+#define ADC1_DATA_22 81
+#define ADC1_DATA_23 82
+#define ADC1_DATA_24 83
+#define ADC1_DATA_25 84
+#define ADC1_DATA_26 85
+#define ADC1_DATA_27 86
+#define ADC1_DATA_28 87
+#define ADC1_DATA_29 88
+#define ADC1_DATA_30 89
+#define ADC1_DATA_31 90
+#define ADC1_DATA_32 91
+#define ADC1_DATA_33 92
+#define ADC1_DATA_34 93
+#define ADC1_DATA_35 94
+#define ADC1_DATA_36 95
+#define ADC1_DATA_37 96
+#define ADC1_DATA_38 97
+#define ADC1_DATA_39 98
+#define ADC1_DATA_40 99
+#define ADC1_DATA_41 100
+#define ADC1_DATA_42 101
+#define ADC1_DATA_43 102
+#define ADC1_DATA_44 103
+#define CORE_PERFORMANCE_COUNTER_INTERRUPT 104
+#define CORE_FAST_DEBUG_CHANNEL_INTERRUPT 105
+#define SYSTEM_BUS_PROTECTION_VIOLATION 106
+#define CRYPTO_ENGINE_EVENT 107
+/* Reserved */
+#define SPI1_FAULT 109
+#define SPI1_RECEIVE_DONE 110
+#define SPI1_TRANSFER_DONE 111
+#define UART1_FAULT 112
+#define UART1_RECEIVE_DONE 113
+#define UART1_TRANSFER_DONE 114
+#define I2C1_BUS_COLLISION_EVENT 115
+#define I2C1_SLAVE_EVENT 116
+#define I2C1_MASTER_EVENT 117
+#define PORTA_INPUT_CHANGE_INTERRUPT 118
+#define PORTB_INPUT_CHANGE_INTERRUPT 119
+#define PORTC_INPUT_CHANGE_INTERRUPT 120
+#define PORTD_INPUT_CHANGE_INTERRUPT 121
+#define PORTE_INPUT_CHANGE_INTERRUPT 122
+#define PORTF_INPUT_CHANGE_INTERRUPT 123
+#define PORTG_INPUT_CHANGE_INTERRUPT 124
+#define PORTH_INPUT_CHANGE_INTERRUPT 125
+#define PORTJ_INPUT_CHANGE_INTERRUPT 126
+#define PORTK_INPUT_CHANGE_INTERRUPT 127
+#define PARALLEL_MASTER_PORT 128
+#define PARALLEL_MASTER_PORT_ERROR 129
+#define COMPARATOR_1_INTERRUPT 130
+#define COMPARATOR_2_INTERRUPT 131
+#define USB_GENERAL_EVENT 132
+#define USB_DMA_EVENT 133
+#define DMA_CHANNEL_0 134
+#define DMA_CHANNEL_1 135
+#define DMA_CHANNEL_2 136
+#define DMA_CHANNEL_3 137
+#define DMA_CHANNEL_4 138
+#define DMA_CHANNEL_5 139
+#define DMA_CHANNEL_6 140
+#define DMA_CHANNEL_7 141
+#define SPI2_FAULT 142
+#define SPI2_RECEIVE_DONE 143
+#define SPI2_TRANSFER_DONE 144
+#define UART2_FAULT 145
+#define UART2_RECEIVE_DONE 146
+#define UART2_TRANSFER_DONE 147
+#define I2C2_BUS_COLLISION_EVENT 148
+#define I2C2_SLAVE_EVENT 149
+#define I2C2_MASTER_EVENT 150
+#define CONTROL_AREA_NETWORK_1 151
+#define CONTROL_AREA_NETWORK_2 152
+#define ETHERNET_INTERRUPT 153
+#define SPI3_FAULT 154
+#define SPI3_RECEIVE_DONE 155
+#define SPI3_TRANSFER_DONE 156
+#define UART3_FAULT 157
+#define UART3_RECEIVE_DONE 158
+#define UART3_TRANSFER_DONE 159
+#define I2C3_BUS_COLLISION_EVENT 160
+#define I2C3_SLAVE_EVENT 161
+#define I2C3_MASTER_EVENT 162
+#define SPI4_FAULT 163
+#define SPI4_RECEIVE_DONE 164
+#define SPI4_TRANSFER_DONE 165
+#define REAL_TIME_CLOCK 166
+#define FLASH_CONTROL_EVENT 167
+#define PREFETCH_MODULE_SEC_EVENT 168
+#define SQI1_EVENT 169
+#define UART4_FAULT 170
+#define UART4_RECEIVE_DONE 171
+#define UART4_TRANSFER_DONE 172
+#define I2C4_BUS_COLLISION_EVENT 173
+#define I2C4_SLAVE_EVENT 174
+#define I2C4_MASTER_EVENT 175
+#define SPI5_FAULT 176
+#define SPI5_RECEIVE_DONE 177
+#define SPI5_TRANSFER_DONE 178
+#define UART5_FAULT 179
+#define UART5_RECEIVE_DONE 180
+#define UART5_TRANSFER_DONE 181
+#define I2C5_BUS_COLLISION_EVENT 182
+#define I2C5_SLAVE_EVENT 183
+#define I2C5_MASTER_EVENT 184
+#define SPI6_FAULT 185
+#define SPI6_RECEIVE_DONE 186
+#define SPI6_TRANSFER_DONE 187
+#define UART6_FAULT 188
+#define UART6_RECEIVE_DONE 189
+#define UART6_TRANSFER_DONE 190
+#define SDHC_EVENT 191
+#define GLCD_INTERRUPT 192
+#define GPU_INTERRUPT 193
+
+/* Interrupt priority bits */
+#define PRI_0 0 /* Note:This priority disables the interrupt! */
+#define PRI_1 1
+#define PRI_2 2
+#define PRI_3 3
+#define PRI_4 4
+#define PRI_5 5
+#define PRI_6 6
+#define PRI_7 7
+
+/* Interrupt subpriority bits */
+#define SUB_PRI_0 0
+#define SUB_PRI_1 1
+#define SUB_PRI_2 2
+#define SUB_PRI_3 3
+
+#define PRI_MASK 0x7 /* 3 bit priority mask */
+#define SUBPRI_MASK 0x3 /* 2 bit subpriority mask */
+#define INT_MASK 0x1F /* 5 bit pri and subpri mask */
+#define NR_EXT_IRQS 5 /* 5 external interrupts sources */
+
+#define MICROCHIP_EVIC_MIN_PRIORITY 0
+#define MICROCHIP_EVIC_MAX_PRIORITY INT_MASK
+
+#define INT_PRI(pri, subpri) \
+ (((pri & PRI_MASK) << 2) | (subpri & SUBPRI_MASK))
+
+#define DEFINE_INT(irq, pri) { irq, pri }
+
+#define DEFAULT_INT_PRI INT_PRI(2, 0)
+
+#endif /*_DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H*/
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Arnd Bergmann <arnd@arndb.de> |
|---|---|
| Date | 2015-11-21 21:50 +0100 |
| Subject | Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller |
| Message-ID | <qxngC-1ZX-15@gated-at.bofh.it> |
| In reply to | #1274570 |
On Friday 20 November 2015 17:17:13 Joshua Henderson wrote:
> +Example
> +-------
> +
> +evic: interrupt-controller@1f810000 {
> + compatible = "microchip,evic-v2";
> + interrupt-controller;
> + #interrupt-cells = <3>;
> + reg = <0x1f810000 0x1000>;
> + device_type="evic-v2";
> +};
This is not a correct use of device_type. Just drop that property.
> diff --git a/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
> new file mode 100644
> index 0000000..2c466b8
> --- /dev/null
> +++ b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
> @@ -0,0 +1,238 @@
> +/*
> + * This header provides constants for the MICROCHIP PIC32 EVIC.
> + */
> +
> +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
> +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
> +
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/* Hardware interrupt number */
> +#define CORE_TIMER_INTERRUPT 0
> +#define CORE_SOFTWARE_INTERRUPT_0 1
> +#define CORE_SOFTWARE_INTERRUPT_1 2
> +#define EXTERNAL_INTERRUPT_0 3
> +#define TIMER1 4
A header file like this is just going to make everyone's life
miserable. Try to remove as much as possible here: normally
you can just use the numbers from the data sheet that match
the actual hardware registers, and put them into the dts file.
> +/* Interrupt priority bits */
> +#define PRI_0 0 /* Note:This priority disables the interrupt! */
> +#define PRI_1 1
> +#define PRI_2 2
> +#define PRI_3 3
> +#define PRI_4 4
> +#define PRI_5 5
> +#define PRI_6 6
> +#define PRI_7 7
> +/* Interrupt subpriority bits */
> +#define SUB_PRI_0 0
> +#define SUB_PRI_1 1
> +#define SUB_PRI_2 2
> +#define SUB_PRI_3 3
These are obviously silly and should be removed/
> +#define PRI_MASK 0x7 /* 3 bit priority mask */
> +#define SUBPRI_MASK 0x3 /* 2 bit subpriority mask */
> +#define INT_MASK 0x1F /* 5 bit pri and subpri mask */
> +#define NR_EXT_IRQS 5 /* 5 external interrupts sources */
> +
> +#define MICROCHIP_EVIC_MIN_PRIORITY 0
> +#define MICROCHIP_EVIC_MAX_PRIORITY INT_MASK
> +
> +#define INT_PRI(pri, subpri) \
> + (((pri & PRI_MASK) << 2) | (subpri & SUBPRI_MASK))
> +
> +#define DEFINE_INT(irq, pri) { irq, pri }
> +
> +#define DEFAULT_INT_PRI INT_PRI(2, 0)
Is it required to have a specific priority configured for each line?
If these are software selectable, it's probably better to not put
them into DT in the first place.
If you absolutely need them, I would suggest using two separate cells
for pri and subpri so you can avoid the macro.
Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-25 19:30 +0100 |
| Subject | Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller |
| Message-ID | <qyMZk-1sg-15@gated-at.bofh.it> |
| In reply to | #1274753 |
On 11/21/2015 1:47 PM, Arnd Bergmann wrote:
> On Friday 20 November 2015 17:17:13 Joshua Henderson wrote:
>
>> +Example
>> +-------
>> +
>> +evic: interrupt-controller@1f810000 {
>> + compatible = "microchip,evic-v2";
>> + interrupt-controller;
>> + #interrupt-cells = <3>;
>> + reg = <0x1f810000 0x1000>;
>> + device_type="evic-v2";
>> +};
>
> This is not a correct use of device_type. Just drop that property.
Ack.
>
>> diff --git a/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
>> new file mode 100644
>> index 0000000..2c466b8
>> --- /dev/null
>> +++ b/include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h
>> @@ -0,0 +1,238 @@
>> +/*
>> + * This header provides constants for the MICROCHIP PIC32 EVIC.
>> + */
>> +
>> +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
>> +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MICROCHIP_EVIC_H
>> +
>> +#include <dt-bindings/interrupt-controller/irq.h>
>> +
>> +/* Hardware interrupt number */
>> +#define CORE_TIMER_INTERRUPT 0
>> +#define CORE_SOFTWARE_INTERRUPT_0 1
>> +#define CORE_SOFTWARE_INTERRUPT_1 2
>> +#define EXTERNAL_INTERRUPT_0 3
>> +#define TIMER1 4
>
> A header file like this is just going to make everyone's life
> miserable. Try to remove as much as possible here: normally
> you can just use the numbers from the data sheet that match
> the actual hardware registers, and put them into the dts file.
>
Agreed. Removing these defines along with removing the priorities from the bindings as suggested makes sense. With doing that, this header file becomes pointless and it will be dropped.
>> +/* Interrupt priority bits */
>> +#define PRI_0 0 /* Note:This priority disables the interrupt! */
>> +#define PRI_1 1
>> +#define PRI_2 2
>> +#define PRI_3 3
>> +#define PRI_4 4
>> +#define PRI_5 5
>> +#define PRI_6 6
>> +#define PRI_7 7
>
>> +/* Interrupt subpriority bits */
>> +#define SUB_PRI_0 0
>> +#define SUB_PRI_1 1
>> +#define SUB_PRI_2 2
>> +#define SUB_PRI_3 3
>
> These are obviously silly and should be removed/
>
Ack.
>> +#define PRI_MASK 0x7 /* 3 bit priority mask */
>> +#define SUBPRI_MASK 0x3 /* 2 bit subpriority mask */
>> +#define INT_MASK 0x1F /* 5 bit pri and subpri mask */
>> +#define NR_EXT_IRQS 5 /* 5 external interrupts sources */
>> +
>> +#define MICROCHIP_EVIC_MIN_PRIORITY 0
>> +#define MICROCHIP_EVIC_MAX_PRIORITY INT_MASK
>> +
>> +#define INT_PRI(pri, subpri) \
>> + (((pri & PRI_MASK) << 2) | (subpri & SUBPRI_MASK))
>> +
>> +#define DEFINE_INT(irq, pri) { irq, pri }
>> +
>> +#define DEFAULT_INT_PRI INT_PRI(2, 0)
>
> Is it required to have a specific priority configured for each line?
> If these are software selectable, it's probably better to not put
> them into DT in the first place.
>
> If you absolutely need them, I would suggest using two separate cells
> for pri and subpri so you can avoid the macro.
>
These priorities are hardware priorities that arbitrate pending interrupts to the CPU. These are indeed software configurable and we can agree that DT is probably not the best place to put this configuration in light of this. We'll default to something sane instead. They will be removed from the binding.
Josh
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2015-11-22 22:20 +0100 |
| Subject | Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller |
| Message-ID | <qxKdc-Rx-3@gated-at.bofh.it> |
| In reply to | #1274570 |
On Fri, Nov 20, 2015 at 05:17:13PM -0700, Joshua Henderson wrote: > From: Cristian Birsan <cristian.birsan@microchip.com> > > Document the devicetree bindings for the interrupt controller on Microchip > PIC32 class devices. This also adds a header defining associated interrupts > and related settings. > > Signed-off-by: Cristian Birsan <cristian.birsan@microchip.com> > Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> > --- > .../microchip,pic32mz-evic.txt | 65 ++++++ > .../interrupt-controller/microchip,pic32mz-evic.h | 238 ++++++++++++++++++++ > 2 files changed, 303 insertions(+) > create mode 100644 Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt > create mode 100644 include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h > > diff --git a/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt > new file mode 100644 > index 0000000..12fb91f > --- /dev/null > +++ b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt > @@ -0,0 +1,65 @@ > +Microchip PIC32MZ Interrupt Controller > +====================================== > + > +The Microchip PIC32MZ SOC contains an Enhanced Vectored Interrupt Controller > +(EVIC) version 2. It handles internal and external interrupts and provides > +support for priority, sub-priority, irq type and polarity. > + > +Required properties > +------------------- > + > +- compatible: Should be "microchip,evic-v2" This should be more specific like "microchip,pic32mz-evic". You can keep this one in addition if you like for matching. Rob -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-26 06:10 +0100 |
| Subject | Re: [PATCH 01/14] DEVICETREE: Add bindings for PIC32 interrupt controller |
| Message-ID | <qyWYF-8v8-5@gated-at.bofh.it> |
| In reply to | #1274956 |
Hi Rob, On 11/22/2015 2:14 PM, Rob Herring wrote: > On Fri, Nov 20, 2015 at 05:17:13PM -0700, Joshua Henderson wrote: >> From: Cristian Birsan <cristian.birsan@microchip.com> >> >> Document the devicetree bindings for the interrupt controller on Microchip >> PIC32 class devices. This also adds a header defining associated interrupts >> and related settings. >> >> Signed-off-by: Cristian Birsan <cristian.birsan@microchip.com> >> Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> >> --- >> .../microchip,pic32mz-evic.txt | 65 ++++++ >> .../interrupt-controller/microchip,pic32mz-evic.h | 238 ++++++++++++++++++++ >> 2 files changed, 303 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt >> create mode 100644 include/dt-bindings/interrupt-controller/microchip,pic32mz-evic.h >> >> diff --git a/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt >> new file mode 100644 >> index 0000000..12fb91f >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/interrupt-controller/microchip,pic32mz-evic.txt >> @@ -0,0 +1,65 @@ >> +Microchip PIC32MZ Interrupt Controller >> +====================================== >> + >> +The Microchip PIC32MZ SOC contains an Enhanced Vectored Interrupt Controller >> +(EVIC) version 2. It handles internal and external interrupts and provides >> +support for priority, sub-priority, irq type and polarity. >> + >> +Required properties >> +------------------- >> + >> +- compatible: Should be "microchip,evic-v2" > > This should be more specific like "microchip,pic32mz-evic". You can keep > this one in addition if you like for matching. > > Rob > Agreed. Due to feedback, we are settling on microchip,pic32mzda-evic and similar for all compatible properties in this patch series. I don't see a need to keep a more abstract name around here if you don't. Josh -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-21 01:30 +0100 |
| Subject | [PATCH 14/14] MIPS: pic32mzda: Add initial PIC32MZDA Starter Kit defconfig |
| Message-ID | <qx4dY-6bp-25@gated-at.bofh.it> |
| In reply to | #1274556 |
This adds an initial default config that enables all available PIC32 drivers and is enough for booting a PIC32MZDA Starter Kit. Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> --- arch/mips/configs/pic32mzda_defconfig | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 arch/mips/configs/pic32mzda_defconfig diff --git a/arch/mips/configs/pic32mzda_defconfig b/arch/mips/configs/pic32mzda_defconfig new file mode 100644 index 0000000..17014ca --- /dev/null +++ b/arch/mips/configs/pic32mzda_defconfig @@ -0,0 +1,88 @@ +CONFIG_MACH_PIC32=y +CONFIG_DTB_PIC32_MZDA_SK=y +CONFIG_HZ_100=y +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_SECCOMP is not set +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_RELAY=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_SGI_PARTITION=y +CONFIG_BINFMT_MISC=m +# CONFIG_SUSPEND is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_ALLOW_DEV_COREDUMP is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_INPUT_LEDS=m +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_GPIO_POLLED=m +# CONFIG_MOUSE_PS2 is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_PIC32=y +CONFIG_SERIAL_PIC32_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_RAW_DRIVER=m +CONFIG_GPIO_SYSFS=y +# CONFIG_HWMON is not set +CONFIG_HIDRAW=y +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_MICROCHIP_PIC32=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_FSCACHE=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Alban <albeu@free.fr> |
|---|---|
| Date | 2015-11-21 13:40 +0100 |
| Subject | Re: [PATCH 06/14] MIPS: Add support for PIC32MZDA platform |
| Message-ID | <qxfCq-5gE-15@gated-at.bofh.it> |
| In reply to | #1274556 |
On Fri, 20 Nov 2015 17:17:18 -0700 Joshua Henderson <joshua.henderson@microchip.com> wrote: > This adds support for the Microchip PIC32 MIPS microcontroller with > the specific variant PIC32MZDA. PIC32MZDA is based on the MIPS m14KEc > core and boots using device tree. > > This includes an early pin setup and early clock setup needed prior to > device tree being initialized. In additon, an interface is provided to > synchronize access to registers shared across several peripherals. > > Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> > >[...] > > diff --git a/arch/mips/include/asm/mach-pic32/gpio.h > b/arch/mips/include/asm/mach-pic32/gpio.h new file mode 100644 Custom GPIO header are not used anymore, this file can be dropped. Alban -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Joshua Henderson <joshua.henderson@microchip.com> |
|---|---|
| Date | 2015-11-22 17:30 +0100 |
| Subject | Re: [PATCH 06/14] MIPS: Add support for PIC32MZDA platform |
| Message-ID | <qxFGy-6iL-11@gated-at.bofh.it> |
| In reply to | #1274642 |
On 11/21/2015 04:37 AM, Alban wrote: > On Fri, 20 Nov 2015 17:17:18 -0700 > Joshua Henderson <joshua.henderson@microchip.com> wrote: > >> This adds support for the Microchip PIC32 MIPS microcontroller with >> the specific variant PIC32MZDA. PIC32MZDA is based on the MIPS m14KEc >> core and boots using device tree. >> >> This includes an early pin setup and early clock setup needed prior to >> device tree being initialized. In additon, an interface is provided to >> synchronize access to registers shared across several peripherals. >> >> Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com> >> >> [...] >> >> diff --git a/arch/mips/include/asm/mach-pic32/gpio.h >> b/arch/mips/include/asm/mach-pic32/gpio.h new file mode 100644 > > Custom GPIO header are not used anymore, this file can be dropped. > Ack. Will drop. Josh -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Linus Walleij <linus.walleij@linaro.org> |
|---|---|
| Date | 2015-11-30 14:50 +0100 |
| Subject | Re: [PATCH 08/14] pinctrl: Add PIC32 pin control driver |
| Message-ID | <qAx08-4hY-39@gated-at.bofh.it> |
| In reply to | #1274556 |
On Sat, Nov 21, 2015 at 1:17 AM, Joshua Henderson
<joshua.henderson@microchip.com> wrote:
> From: Andrei Pistirica <andrei.pistirica@microchip.com>
>
> Add a driver for the pin controller present on the Microchip PIC32
> including the specific variant PIC32MZDA. This driver provides pinmux
> and pinconfig operations as well as GPIO and IRQ chips for the GPIO
> banks.
>
> Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
> Signed-off-by: Joshua Henderson <joshua.henderson@microchip.com>
> +config PINCTRL_PIC32
> + bool "Microchip PIC32 pin controller driver"
> + depends on OF
> + depends on MACH_PIC32
> + select PINMUX
> + select GENERIC_PINCONF
> + select GPIOLIB_IRQCHIP
Nice but...
> +struct pic32_gpio_irq {
> + struct irq_chip gpio_irqchip;
> + struct irq_domain *domain;
If you're using GPIOLIB_IRQCHIP with a separate irq_domain
you are totally missing the point of GPIOLIB_IRQCHIP.
Look closer at other drivers using GPIOLIB_IRQCHIP and
get your driver to use the infrastructure properly.
> +#define to_pic32_gpio_chip(c) container_of(c, struct pic32_gpio_chip, chip)
Make this a static inline function instead. #defines are
hard to read.
> +static struct pic32_gpio_chip *gpio_chips[MAX_PIO_BANKS];
Why? You should not need to keep track of the chips
in some local array.
> +int pic32_pinconf_open_drain_runtime(unsigned pin_id, int value)
> +{
> + struct pic32_gpio_chip *pic32_chip = gpio_to_pic32_gpio_chip(pin_id);
> + unsigned pin = pin_id % PINS_PER_BANK;
> +
> + if (IS_ERR_OR_NULL(pic32_chip))
> + return -ENODEV;
> +
> + return pic32_pinconf_open_drain(pic32_chip, pin, value);
> +}
> +EXPORT_SYMBOL(pic32_pinconf_open_drain_runtime);
NO WAY are you going to call this from outside of the driver, even
less other modules.
Use pin control states to control the pins, no cross calling of
functions in the middle of everything thanks.
You shouldn't need one set of calls for "runtime" either, all pin
control states are possible to control at runtime, we have no
distinction between boot time and any other time.
> +static int pic32_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> + int gpio = chip->base + offset;
> + int bank = chip->base / chip->ngpio;
> +
> + dev_dbg(chip->dev, "%s: request GPIO-%c:%d(%d)\n", __func__,
> + 'A' + bank, offset, gpio);
> +
> + return pinctrl_request_gpio(gpio);
> +}
> +
> +static void pic32_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> + int gpio = chip->base + offset;
> + int bank = chip->base / chip->ngpio;
> +
> + dev_dbg(chip->dev, "%s: free GPIO-%c:%d(%d)\n", __func__,
> + 'A' + bank, offset, gpio);
> +
> + pinctrl_free_gpio(gpio);
> +}
This looks nice.
> +static int pic32_gpio_get(struct gpio_chip *chip, unsigned gpio)
> +{
> + struct pic32_gpio_chip *pic32_chip = to_pic32_gpio_chip(chip);
> + struct pic32_reg __iomem *port_reg = (struct pic32_reg __iomem *)
> + pic32_pio_get_reg(pic32_chip, PIC32_PORT);
> + u32 mask = BIT(gpio);
> +
> + if (WARN_ON(port_reg == NULL || gpio >= chip->ngpio))
> + return -EINVAL;
> +
> + return readl(&port_reg->val) & mask;
return !!(readl(&port_reg->val) & mask);
to clamp it to 0/1.
> +static int pic32_gpio_get_dir(struct gpio_chip *chip, unsigned offset)
> +{
> + struct pic32_gpio_chip *pic32_chip = to_pic32_gpio_chip(chip);
> + struct pic32_reg __iomem *tris_reg = (struct pic32_reg __iomem *)
> + pic32_pio_get_reg(pic32_chip, PIC32_TRIS);
> + u32 mask = BIT(offset);
> +
> + if (WARN_ON(tris_reg == NULL))
> + return -EINVAL;
> +
> + return readl(&tris_reg->val) & mask;
Dito.
> +static int pic32_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> + struct pic32_gpio_chip *pic32_chip = to_pic32_gpio_chip(chip);
> + struct pic32_gpio_irq *gpio_irq = &pic32_chip->gpio_irq;
> + int virq;
> +
> + if (offset < chip->ngpio)
> + virq = irq_create_mapping(gpio_irq->domain, offset);
> + else
> + virq = -ENXIO;
> +
> + dev_dbg(chip->dev, "%s: request IRQ for GPIO:%d, return:%d\n",
> + __func__, offset + chip->base, virq);
> +
> + return virq;
> +}
This is handled by GPIOLIB_IRQCHIP and you should not define
.to_irq() for a driver using that.
> +static void pic32_gpio_ranges_setup(struct platform_device *pdev,
> + struct pic32_gpio_chip *pic32_chip)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + struct pinctrl_gpio_range *range;
> + struct of_phandle_args args;
> + int ret;
> +
> + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
> + pic32_chip->gpio_base = (ret == 0) ? args.args[1] + args.args[0] :
> + pic32_chip->pio_idx * PINS_PER_BANK;
> + pic32_chip->ngpio = (ret == 0) ? args.args[2] - args.args[0] :
> + PINS_PER_BANK;
> +
> + range = &pic32_chip->range;
> + range->name = dev_name(&pdev->dev);
> + range->id = pic32_chip->pio_idx;
> + range->pin_base = range->base = pic32_chip->gpio_base;
> +
> + range->npins = pic32_chip->ngpio;
> + range->gc = &pic32_chip->chip;
> +
> + dev_dbg(&pdev->dev, "%s: GPIO-%c ranges: (%d,%d)\n", __func__,
> + 'A' + range->id,
> + pic32_chip->gpio_base, pic32_chip->ngpio);
> +}
What is the point of this? We alread add the ranged in the gpiolib
core.
> +static unsigned int gpio_irq_startup(struct irq_data *d)
This is a too generic name for a function, rename all of these
prefixed with your custom name like pic32_irq_type() etc.
> +{
> + struct pic32_gpio_chip *pic32_chip = irq_data_get_irq_chip_data(d);
> + struct pic32_gpio_irq *gpio_irq = &pic32_chip->gpio_irq;
> + unsigned pin = d->hwirq;
> + int ret;
> +
> + ret = gpiochip_lock_as_irq(&pic32_chip->chip, pin);
> + if (ret) {
> + dev_err(pic32_chip->chip.dev, "unable to lock pind %lu IRQ\n",
> + d->hwirq);
> + return ret;
> + }
This should not be called in .irq_startup() but in .irq_request_resources()
and will not be needed at all if you use GPIOLIB_IRQCHIP properly
since it defines these callbacks for you and handle them in the
gpiolib core.
> +
> + /* start CN */
> + switch (gpio_irq->type[pin]) {
> + case IRQ_TYPE_EDGE_RISING:
> + pic32_gpio_irq_rise_dset(pic32_chip, pin);
> + break;
> + case IRQ_TYPE_EDGE_FALLING:
> + pic32_gpio_irq_fall_dset(pic32_chip, pin);
> + break;
> + case IRQ_TYPE_EDGE_BOTH:
> + pic32_gpio_irq_rise_dset(pic32_chip, pin);
> + pic32_gpio_irq_fall_dset(pic32_chip, pin);
> + break;
> + default:
> + return -EINVAL;
> + }
Why are you doin this in the .startup() callback? This should be done
in .set_type().
> +static int gpio_irq_type(struct irq_data *d, unsigned type)
This is a too generic name for a function, rename all of these
prefixed with your custom name like pic32_irq_type() etc.
> +{
> + struct pic32_gpio_chip *pic32_chip = irq_data_get_irq_chip_data(d);
> + struct pic32_gpio_irq *gpio_irq = &pic32_chip->gpio_irq;
> + unsigned pin = d->hwirq;
> +
> + dev_dbg(pic32_chip->chip.dev, "%s: irq type:%u\n", __func__, type);
> +
> + switch (type) {
> + case IRQ_TYPE_EDGE_RISING:
> + case IRQ_TYPE_EDGE_FALLING:
> + case IRQ_TYPE_EDGE_BOTH:
> + gpio_irq->type[pin] = type;
> + return IRQ_SET_MASK_OK;
> + default:
> + gpio_irq->type[pin] = IRQ_TYPE_NONE;
> + return -EINVAL;
> + }
> +}
Do you rely on semantic call order like this being called before startup?
I do't think that's good, why can't you write to the hardware directly
in this function?
> +/* map virtual irq on hw irq: domain translation */
> +static int pic32_gpio_irq_map(struct irq_domain *d,
> + unsigned int virq,
> + irq_hw_number_t hw)
> +/* decode irq number: base + pin */
> +static int pic32_gpio_irq_domain_xlate(struct irq_domain *d,
> + struct device_node *ctrlr,
> + const u32 *intspec,
> + unsigned int intsize,
> + irq_hw_number_t *out_hwirq,
> + unsigned int *out_type)
> +{
None of these should be needed if you use GPIOLIB_IRQCHIP.
> +static int pic32_gpio_irq_map(struct irq_domain *d,
> + unsigned int virq,
> + irq_hw_number_t hw)
> +{
> + struct pic32_gpio_chip *pic32_chip = d->host_data;
> + struct pic32_gpio_irq *gpio_irq = &pic32_chip->gpio_irq;
> + struct irq_chip *irqchip = &gpio_irq->gpio_irqchip;
> +
> + dev_dbg(pic32_chip->chip.dev, "%s: GPIO-%c:%d map virq:%u\n", __func__,
> + 'A' + pic32_chip->pio_idx, virq, virq);
> +
> + /* set the gpioX chip */
> + irq_set_chip(virq, irqchip);
> + irq_set_chip_data(virq, pic32_chip);
> + irq_set_handler(virq, handle_simple_irq);
This driver should use handle_edge_irq() and implement .irq_ack().
> +static struct irq_domain_ops pic32_gpio_irqd_ops = {
> + .map = pic32_gpio_irq_map,
> + .xlate = pic32_gpio_irq_domain_xlate,
> +};
And no custom domain at all.
> +static int pic32_gpio_of_irq_setup(struct platform_device *pdev,
> + struct pic32_gpio_chip *pic32_chip)
> +{
> + struct device_node *node = pdev->dev.of_node;
> + struct pic32_gpio_irq *gpio_irq = &pic32_chip->gpio_irq;
> + struct irq_chip *irqchip = &gpio_irq->gpio_irqchip;
> + int base_irq;
> +
> + /* set irqchip */
> + irqchip->name = kasprintf(GFP_KERNEL, "GPIO-%c",
> + pic32_chip->pio_idx + 'A');
> + irqchip->irq_startup = gpio_irq_startup;
> + irqchip->irq_shutdown = gpio_irq_shutdown;
> + irqchip->irq_set_type = gpio_irq_type;
Since you are supporting *only* edge IRQs you should
implement and ->irq_ack() callback that ACKs the IRQ.
Most likely the gpio controller is holding a level IRQ to the
next interrupt controller active until you do this.
You should also make sure to use handle_edge_irq() as IRQ
handler as this is what the chip supports.
> + base_irq = platform_get_irq(pdev, 0);
> + if (base_irq < 0)
> + return base_irq;
> +
> + gpio_irq->pio_irq = base_irq;
> +
> + /* Setup irq domain of ngpio lines */
> + gpio_irq->domain = irq_domain_add_linear(
> + node,
> + pic32_chip->chip.ngpio,
> + &pic32_gpio_irqd_ops, pic32_chip);
> + if (!gpio_irq->domain) {
> + dev_err(pic32_chip->chip.dev, "Couldn't allocate IRQ domain\n");
> + return -ENXIO;
> + }
This stuff should not be needed with GPIOLIB_IRQCHIP.
> + dev_dbg(&pdev->dev, "%s: irq GPIO-%c, base_irq:%d, domain:%d\n",
> + __func__, pic32_chip->pio_idx + 'A',
> + base_irq, pic32_chip->chip.ngpio);
> +
> + /* setup chained handler */
> + irq_set_chip_data(gpio_irq->pio_irq, pic32_chip);
> + irq_set_chained_handler(gpio_irq->pio_irq, gpio_irq_handler);
And you should add the GPIO irqchip with
gpiolib_add_irqchip().
> +int pic32_gpio_probe(struct platform_device *pdev,
> + unsigned (*reg_lookup_off)[],
> + unsigned lookup_size)
> +{
> + struct device_node *np = pdev->dev.of_node;
> + int alias_idx = of_alias_get_id(np, "gpio");
> + struct pic32_gpio_chip *pic32_chip = NULL;
> + struct gpio_chip *chip;
> + struct resource *r;
> + int ret = 0;
> +
> + dev_dbg(&pdev->dev, "%s: probing...\n", __func__);
> +
> + if (!np)
> + return -ENODEV;
> +
> + if (WARN_ON(alias_idx >= ARRAY_SIZE(gpio_chips)))
> + return -EINVAL;
> +
> + if (gpio_chips[alias_idx]) {
> + dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
> + return -EBUSY;
> + }
> +
> + /* pic32 gpio chip - private data */
> + pic32_chip = devm_kzalloc(&pdev->dev, sizeof(*pic32_chip),
> + GFP_KERNEL);
> + if (!pic32_chip)
> + return -ENOMEM;
> +
> + /* base address of pio(alias_idx) registers */
> + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!r) {
> + ret = -EINVAL;
> + goto probe_err;
> + }
> + pic32_chip->pio_base = devm_ioremap_nocache(&pdev->dev, r->start,
> + resource_size(r));
> + if (IS_ERR(pic32_chip->pio_base)) {
> + ret = PTR_ERR(pic32_chip->pio_base);
> + goto probe_err;
> + }
> +
> + /* clocks */
> + pic32_chip->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(pic32_chip->clk)) {
> + ret = PTR_ERR(pic32_chip->clk);
> + dev_err(&pdev->dev, "clk get failed\n");
> + goto probe_err;
> + }
> +
> + ret = clk_prepare_enable(pic32_chip->clk);
> + if (ret) {
> + dev_err(&pdev->dev, "clk enable failed\n");
> + goto probe_err;
> + }
> +
> + pic32_chip->reg_lookup_off = *reg_lookup_off;
> + pic32_chip->lookup_size = lookup_size;
> + pic32_chip->pio_idx = alias_idx;
> + pic32_chip->chip = gpio_template;
> + pic32_gpio_ranges_setup(pdev, pic32_chip);/* pin_ranges: unsupported */
I can't see why you have this. The gpiolib core handles this.
Please fix the above and repost, and I can look at the pin control
parts. As it is now there are too many problems with the GPIO
parts.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web