@@ -314,6 +314,7 @@
#define SC16IS7XX_FIFO_SIZE (64)
#define SC16IS7XX_GPIOS_PER_BANK 4
+#define SC16IS7XX_POLL_PERIOD 10 /*ms*/
#define SC16IS7XX_RECONF_MD BIT(0)
#define SC16IS7XX_RECONF_IER BIT(1)
#define SC16IS7XX_RECONF_RS485 BIT(2)
@@ -348,6 +349,9 @@ struct sc16is7xx_port {
u8 mctrl_mask;
struct kthread_worker kworker;
struct task_struct *kworker_task;
+ struct kthread_delayed_work poll_work;
+ bool polling;
+ bool shutdown;
struct sc16is7xx_one p[];
};
@@ -861,6 +865,19 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void sc16is7xx_transmission_poll(struct kthread_work *work)
+{
+ struct sc16is7xx_port *s = container_of(work, struct sc16is7xx_port, poll_work.work);
+
+ /* Resuse standard IRQ handler. Interrupt ID is unused in this context. */
+ sc16is7xx_irq(0, s);
+
+ /* setup delay based on SC16IS7XX_POLL_PERIOD */
+ if (!s->shutdown)
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD));
+}
+
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
@@ -1149,6 +1166,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
static int sc16is7xx_startup(struct uart_port *port)
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
@@ -1210,6 +1228,11 @@ static int sc16is7xx_startup(struct uart_port *port)
uart_port_lock_irqsave(port, &flags);
sc16is7xx_enable_ms(port);
uart_port_unlock_irqrestore(port, flags);
+ if (s->polling) {
+ s->shutdown = false;
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD));
+ }
return 0;
}
@@ -1232,6 +1255,10 @@ static void sc16is7xx_shutdown(struct uart_port *port)
sc16is7xx_power(port, 0);
+ if (s->polling) {
+ s->shutdown = true;
+ kthread_cancel_delayed_work_sync(&s->poll_work);
+ }
kthread_flush_worker(&s->kworker);
}
@@ -1537,7 +1564,13 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
+ s->polling = !device_property_present(dev, "interrupts");
+ if (s->polling) {
+ dev_warn(dev,
+ "No interrupt definition found. Falling back to polling mode.\n");
+ irq = 0;
+ }
s->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
@@ -1664,6 +1697,11 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
if (ret)
goto out_ports;
#endif
+ if (s->polling) {
+ /* Initialize Kernel timer for polling */
+ kthread_init_delayed_work(&s->poll_work, sc16is7xx_transmission_poll);
+ return 0;
+ }
/*
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
@@ -1724,6 +1762,8 @@ void sc16is7xx_remove(struct device *dev)
sc16is7xx_power(&s->p[i].port, 0);
}
+ if (s->polling)
+ kthread_cancel_delayed_work_sync(&s->poll_work);
kthread_flush_worker(&s->kworker);
kthread_stop(s->kworker_task);
Fall back to polling mode if no interrupt is configured because not possible. If "interrupts" property is missing in devicetree the driver uses a delayed worker to pull state of interrupt status registers. Signed-off-by: Andre Werner <andre.werner@systec-electronic.com> --- This driver was tested on Linux 5.10. We had a custom board that was not able to connect the interrupt port. Only I2C was available. --- --- drivers/tty/serial/sc16is7xx.c | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)