Skip to content

Commit bd78ecd

Browse files
a3fgregkh
authored andcommitted
serial: imx: use hrtimers for rs485 delays
This patch imitates 6e0a5de ("serial: 8250: Use hrtimers for rs485 delays") in replacing the previously used classic timers with hrtimers. The old way provided a too coarse resolution on systems with configs of less than 1000 HZ. Use of hrtimers addresses this and can be easily extended to support microsecond resolution in future when support for this arrives upstream. Signed-off-by: Ahmad Fatoum <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent cb1a609 commit bd78ecd

File tree

1 file changed

+36
-26
lines changed

1 file changed

+36
-26
lines changed

drivers/tty/serial/imx.c

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/serial.h>
2121
#include <linux/clk.h>
2222
#include <linux/delay.h>
23+
#include <linux/ktime.h>
2324
#include <linux/pinctrl/consumer.h>
2425
#include <linux/rational.h>
2526
#include <linux/slab.h>
@@ -233,9 +234,8 @@ struct imx_port {
233234
bool context_saved;
234235

235236
enum imx_tx_state tx_state;
236-
unsigned long tx_state_next_change;
237-
struct timer_list trigger_start_tx;
238-
struct timer_list trigger_stop_tx;
237+
struct hrtimer trigger_start_tx;
238+
struct hrtimer trigger_stop_tx;
239239
};
240240

241241
struct imx_port_ucrs {
@@ -412,6 +412,15 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
412412
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
413413
}
414414

415+
static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
416+
{
417+
long sec = msec / MSEC_PER_SEC;
418+
long nsec = (msec % MSEC_PER_SEC) * 1000000;
419+
ktime_t t = ktime_set(sec, nsec);
420+
421+
hrtimer_start(hrt, t, HRTIMER_MODE_REL);
422+
}
423+
415424
/* called with port.lock taken and irqs off */
416425
static void imx_uart_start_rx(struct uart_port *port)
417426
{
@@ -468,16 +477,16 @@ static void imx_uart_stop_tx(struct uart_port *port)
468477
if (port->rs485.flags & SER_RS485_ENABLED) {
469478
if (sport->tx_state == SEND) {
470479
sport->tx_state = WAIT_AFTER_SEND;
471-
sport->tx_state_next_change =
472-
jiffies + DIV_ROUND_UP(port->rs485.delay_rts_after_send * HZ, 1000);
480+
start_hrtimer_ms(&sport->trigger_stop_tx,
481+
port->rs485.delay_rts_after_send);
482+
return;
473483
}
474484

475485
if (sport->tx_state == WAIT_AFTER_RTS ||
476-
(sport->tx_state == WAIT_AFTER_SEND &&
477-
time_after_eq(jiffies, sport->tx_state_next_change))) {
486+
sport->tx_state == WAIT_AFTER_SEND) {
478487
u32 ucr2;
479488

480-
del_timer(&sport->trigger_start_tx);
489+
hrtimer_try_to_cancel(&sport->trigger_start_tx);
481490

482491
ucr2 = imx_uart_readl(sport, UCR2);
483492
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
@@ -489,8 +498,6 @@ static void imx_uart_stop_tx(struct uart_port *port)
489498
imx_uart_start_rx(port);
490499

491500
sport->tx_state = OFF;
492-
} else if (sport->tx_state == WAIT_AFTER_SEND) {
493-
mod_timer(&sport->trigger_stop_tx, sport->tx_state_next_change);
494501
}
495502
} else {
496503
sport->tx_state = OFF;
@@ -710,15 +717,16 @@ static void imx_uart_start_tx(struct uart_port *port)
710717
imx_uart_stop_rx(port);
711718

712719
sport->tx_state = WAIT_AFTER_RTS;
713-
sport->tx_state_next_change =
714-
jiffies + DIV_ROUND_UP(port->rs485.delay_rts_before_send * HZ, 1000);
720+
start_hrtimer_ms(&sport->trigger_start_tx,
721+
port->rs485.delay_rts_before_send);
722+
return;
715723
}
716724

717-
if (sport->tx_state == WAIT_AFTER_SEND ||
718-
(sport->tx_state == WAIT_AFTER_RTS &&
719-
time_after_eq(jiffies, sport->tx_state_next_change))) {
725+
if (sport->tx_state == WAIT_AFTER_SEND
726+
|| sport->tx_state == WAIT_AFTER_RTS) {
727+
728+
hrtimer_try_to_cancel(&sport->trigger_stop_tx);
720729

721-
del_timer(&sport->trigger_stop_tx);
722730
/*
723731
* Enable transmitter and shifter empty irq only if DMA
724732
* is off. In the DMA case this is done in the
@@ -731,10 +739,6 @@ static void imx_uart_start_tx(struct uart_port *port)
731739
}
732740

733741
sport->tx_state = SEND;
734-
735-
} else if (sport->tx_state == WAIT_AFTER_RTS) {
736-
mod_timer(&sport->trigger_start_tx, sport->tx_state_next_change);
737-
return;
738742
}
739743
} else {
740744
sport->tx_state = SEND;
@@ -2283,26 +2287,30 @@ static void imx_uart_probe_pdata(struct imx_port *sport,
22832287
sport->have_rtscts = 1;
22842288
}
22852289

2286-
static void imx_trigger_start_tx(struct timer_list *t)
2290+
static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t)
22872291
{
2288-
struct imx_port *sport = from_timer(sport, t, trigger_start_tx);
2292+
struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx);
22892293
unsigned long flags;
22902294

22912295
spin_lock_irqsave(&sport->port.lock, flags);
22922296
if (sport->tx_state == WAIT_AFTER_RTS)
22932297
imx_uart_start_tx(&sport->port);
22942298
spin_unlock_irqrestore(&sport->port.lock, flags);
2299+
2300+
return HRTIMER_NORESTART;
22952301
}
22962302

2297-
static void imx_trigger_stop_tx(struct timer_list *t)
2303+
static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
22982304
{
2299-
struct imx_port *sport = from_timer(sport, t, trigger_stop_tx);
2305+
struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx);
23002306
unsigned long flags;
23012307

23022308
spin_lock_irqsave(&sport->port.lock, flags);
23032309
if (sport->tx_state == WAIT_AFTER_SEND)
23042310
imx_uart_stop_tx(&sport->port);
23052311
spin_unlock_irqrestore(&sport->port.lock, flags);
2312+
2313+
return HRTIMER_NORESTART;
23062314
}
23072315

23082316
static int imx_uart_probe(struct platform_device *pdev)
@@ -2451,8 +2459,10 @@ static int imx_uart_probe(struct platform_device *pdev)
24512459

24522460
clk_disable_unprepare(sport->clk_ipg);
24532461

2454-
timer_setup(&sport->trigger_start_tx, imx_trigger_start_tx, 0);
2455-
timer_setup(&sport->trigger_stop_tx, imx_trigger_stop_tx, 0);
2462+
hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
2463+
hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
2464+
sport->trigger_start_tx.function = imx_trigger_start_tx;
2465+
sport->trigger_stop_tx.function = imx_trigger_stop_tx;
24562466

24572467
/*
24582468
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later

0 commit comments

Comments
 (0)