Skip to content

Commit 4fb92bd

Browse files
jason77-wanggregkh
authored andcommitted
serial: sc16is7xx: hardware reset chip if reset-gpios is defined in DT
Some boards connect a GPIO to the reset pin, and the reset pin needs to be set up correctly before accessing the chip. Add a function to handle the chip reset. If the reset-gpios is defined in the DT, do hardware reset through this GPIO, otherwise do software reset as before. Reviewed-by: Lech Perczak <[email protected]> Tested-by: Hugo Villeneuve <[email protected]> Reviewed-by: Hugo Villeneuve <[email protected]> Signed-off-by: Hui Wang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a9411ef commit 4fb92bd

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

drivers/tty/serial/sc16is7xx.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/delay.h>
1515
#include <linux/device.h>
1616
#include <linux/export.h>
17+
#include <linux/gpio/consumer.h>
1718
#include <linux/gpio/driver.h>
1819
#include <linux/idr.h>
1920
#include <linux/kthread.h>
@@ -1467,6 +1468,29 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = {
14671468
.delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
14681469
};
14691470

1471+
/* Reset device, purging any pending irq / data */
1472+
static int sc16is7xx_reset(struct device *dev, struct regmap *regmap)
1473+
{
1474+
struct gpio_desc *reset_gpio;
1475+
1476+
/* Assert reset GPIO if defined and valid. */
1477+
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
1478+
if (IS_ERR(reset_gpio))
1479+
return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to get reset GPIO\n");
1480+
1481+
if (reset_gpio) {
1482+
/* The minimum reset pulse width is 3 us. */
1483+
fsleep(5);
1484+
gpiod_set_value_cansleep(reset_gpio, 0); /* Deassert GPIO */
1485+
} else {
1486+
/* Software reset */
1487+
regmap_write(regmap, SC16IS7XX_IOCONTROL_REG,
1488+
SC16IS7XX_IOCONTROL_SRESET_BIT);
1489+
}
1490+
1491+
return 0;
1492+
}
1493+
14701494
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
14711495
struct regmap *regmaps[], int irq)
14721496
{
@@ -1536,9 +1560,9 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
15361560
}
15371561
sched_set_fifo(s->kworker_task);
15381562

1539-
/* reset device, purging any pending irq / data */
1540-
regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG,
1541-
SC16IS7XX_IOCONTROL_SRESET_BIT);
1563+
ret = sc16is7xx_reset(dev, regmaps[0]);
1564+
if (ret)
1565+
goto out_kthread;
15421566

15431567
/* Mark each port line and status as uninitialised. */
15441568
for (i = 0; i < devtype->nr_uart; ++i) {
@@ -1663,6 +1687,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
16631687
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
16641688
}
16651689

1690+
out_kthread:
16661691
kthread_stop(s->kworker_task);
16671692

16681693
out_clk:

0 commit comments

Comments
 (0)