Serial port on i.MX6 with DCD via IO expander

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Serial port on i.MX6 with DCD via IO expander

592 Views
astrand
Contributor I

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.

Labels (1)
Tags (1)
0 Kudos
Reply
0 Replies