Hi. We are building a i.MX6ULL system with a modem connected to CPU serial port, but the DCD signal is routed via an IO expander (PCA953x). This is configured via DT:
&uart2 {
label = "lte_modem_uart";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2dte>;
uart-has-rtscts;
fsl,dte-mode;
status = "okay";
dcd-gpios = <&i2c_gpio1 6 GPIO_ACTIVE_LOW>;
};
However, when booting we get:
imx-uart 21e8000.serial: failed to request irq for dcd (idx=0, err=-22)
We have determined that this is due to this code:
manage.c:
...
/*
* Check whether the interrupt nests into another interrupt
* thread.
*/
nested = irq_settings_is_nested_thread(desc);
if (nested) {
if (!new->thread_fn) {
ret = -EINVAL;
goto out_mput;
}
Don't really know how this can be fixed. However, perhaps it would be easier to use a polling solution for DCD instead? imx.c actually polls for it's own DCD, but a naive implementation to poll the IO expander does not work:
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index f6afe305f72d..e7fca2665ae3 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -927,6 +927,8 @@ static void imx_uart_mctrl_check(struct imx_port *sport)
unsigned int status, changed;
status = imx_uart_get_hwmctrl(sport);
+ mctrl_gpio_get(sport->gpios, &status);
+
changed = status ^ sport->old_status;
if (changed == 0)
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index fb4781292d40..5e9d43ccaff1 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -82,7 +82,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) {
- if (gpiod_get_value(gpios->gpio[i]))
+ if (gpiod_get_value_cansleep(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
@@ -206,6 +206,10 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i))
continue;
+ /* No IRQ for DCD */
+ if (mctrl_gpios_desc[i].mctrl & TIOCM_CD)
+ continue;
+
ret = gpiod_to_irq(gpios->gpio[i]);
if (ret <= 0) {
dev_err(port->dev,
This unfortunately gives "BUG: scheduling while atomic".
So, how is this supposed to work...? imx.c and serial_mctrl_gpio.c obviously tries to support generic GPIO via gpiod, but for some reason this does not work for our IO expander. Thankful for any help.
Using i.MX yocto platform L5.4.24_2.1.0. Also tried kernel from lf-5.10.y.