|
@@ -118,3 +118,113 @@ static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
|
|
|
|
|
|
if (mctrl & TIOCM_DTR)
|
|
|
mdm_ctl0 &= ~MDM_CTL0_DTR1;
|
|
|
+ else
|
|
|
+ mdm_ctl0 |= MDM_CTL0_DTR1;
|
|
|
+ }
|
|
|
+
|
|
|
+ writeb_relaxed(mdm_ctl0, base + MDM_CTL_0);
|
|
|
+}
|
|
|
+
|
|
|
+static u_int neponset_get_mctrl(struct uart_port *port)
|
|
|
+{
|
|
|
+ void __iomem *base = nep_base;
|
|
|
+ u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
|
|
|
+ u_int mdm_ctl1;
|
|
|
+
|
|
|
+ if (!base)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
|
|
|
+ if (port->mapbase == _Ser1UTCR0) {
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_DCD2)
|
|
|
+ ret &= ~TIOCM_CD;
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_CTS2)
|
|
|
+ ret &= ~TIOCM_CTS;
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_DSR2)
|
|
|
+ ret &= ~TIOCM_DSR;
|
|
|
+ } else if (port->mapbase == _Ser3UTCR0) {
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_DCD1)
|
|
|
+ ret &= ~TIOCM_CD;
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_CTS1)
|
|
|
+ ret &= ~TIOCM_CTS;
|
|
|
+ if (mdm_ctl1 & MDM_CTL1_DSR1)
|
|
|
+ ret &= ~TIOCM_DSR;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static struct sa1100_port_fns neponset_port_fns = {
|
|
|
+ .set_mctrl = neponset_set_mctrl,
|
|
|
+ .get_mctrl = neponset_get_mctrl,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * Install handler for Neponset IRQ. Note that we have to loop here
|
|
|
+ * since the ETHERNET and USAR IRQs are level based, and we need to
|
|
|
+ * ensure that the IRQ signal is deasserted before returning. This
|
|
|
+ * is rather unfortunate.
|
|
|
+ */
|
|
|
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|
|
+{
|
|
|
+ struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
|
|
|
+ unsigned int irr;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ /*
|
|
|
+ * Acknowledge the parent IRQ.
|
|
|
+ */
|
|
|
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Read the interrupt reason register. Let's have all
|
|
|
+ * active IRQ bits high. Note: there is a typo in the
|
|
|
+ * Neponset user's guide for the SA1111 IRR level.
|
|
|
+ */
|
|
|
+ irr = readb_relaxed(d->base + IRR);
|
|
|
+ irr ^= IRR_ETHERNET | IRR_USAR;
|
|
|
+
|
|
|
+ if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Since there is no individual mask, we have to
|
|
|
+ * mask the parent IRQ. This is safe, since we'll
|
|
|
+ * recheck the register for any pending IRQs.
|
|
|
+ */
|
|
|
+ if (irr & (IRR_ETHERNET | IRR_USAR)) {
|
|
|
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Ack the interrupt now to prevent re-entering
|
|
|
+ * this neponset handler. Again, this is safe
|
|
|
+ * since we'll check the IRR register prior to
|
|
|
+ * leaving.
|
|
|
+ */
|
|
|
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
|
|
|
+
|
|
|
+ if (irr & IRR_ETHERNET)
|
|
|
+ generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
|
|
|
+
|
|
|
+ if (irr & IRR_USAR)
|
|
|
+ generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
|
|
|
+
|
|
|
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (irr & IRR_SA1111)
|
|
|
+ generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* Yes, we really do not have any kind of masking or unmasking */
|
|
|
+static void nochip_noop(struct irq_data *irq)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_chip nochip = {
|
|
|
+ .name = "neponset",
|
|
|
+ .irq_ack = nochip_noop,
|
|
|
+ .irq_mask = nochip_noop,
|
|
|
+ .irq_unmask = nochip_noop,
|
|
|
+};
|