Skip to content

Commit

Permalink
[BACKPORT] Merged in bkueng/nuttx/uart_invert_ioctl_continued (pull r…
Browse files Browse the repository at this point in the history
…equest #930)

serial: add TIOCSINVERT and TIOCSSWAP ioctl's for stm32{l4,h7} and imxrt

* stm32l4 serial: add TIOCSINVERT and TIOCSSWAP ioctl's

* stm32l4 serial: ensure TIOCSSINGLEWIRE is atomic and UE disabled

* stm32h7 serial: add TIOCSINVERT and TIOCSSWAP ioctl's

* imxrt serial: add TIOCSINVERT ioctl

Approved-by: Gregory Nutt <[email protected]>
  • Loading branch information
bkueng authored and dagar committed Jul 4, 2019
1 parent 54a0897 commit 0ebab19
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 0 deletions.
13 changes: 13 additions & 0 deletions arch/arm/src/imxrt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,19 @@ config IMXRT_LPUART8

endmenu # LPUART Peripherals

menu "LPUART Configuration"
depends on IMXRT_HAVE_LPUART

config IMXRT_LPUART_INVERT
bool "Signal Invert Support"
default n
depends on IMXRT_HAVE_LPUART
---help---
Enable signal inversion UART support. The option enables support for the
TIOCSINVERT ioctl in the IMXRT serial driver.

endmenu # LPUART Configuration

menu "LPI2C Peripherals"

menuconfig IMXRT_LPI2C1
Expand Down
47 changes: 47 additions & 0 deletions arch/arm/src/imxrt/imxrt_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,53 @@ static int imxrt_ioctl(struct file *filep, int cmd, unsigned long arg)
break;
#endif /* CONFIG_SERIAL_TERMIOS */

#ifdef CONFIG_IMXRT_LPUART_INVERT
case TIOCSINVERT:
{
uint32_t ctrl;
uint32_t stat;
uint32_t regval;
irqstate_t flags;

flags = spin_lock_irqsave();
ctrl = imxrt_serialin(priv, IMXRT_LPUART_CTRL_OFFSET);
stat = imxrt_serialin(priv, IMXRT_LPUART_STAT_OFFSET);
regval = ctrl;

/* {R|T}XINV bit field can only be written when the receiver is disabled (RE=0). */

regval &= ~LPUART_CTRL_RE;

imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, regval);

/* Enable/disable signal inversion. */

if (arg & SER_INVERT_ENABLED_RX)
{
stat |= LPUART_STAT_RXINV;
}
else
{
stat &= ~LPUART_STAT_RXINV;
}

if (arg & SER_INVERT_ENABLED_TX)
{
ctrl |= LPUART_CTRL_TXINV;
}
else
{
ctrl &= ~LPUART_CTRL_TXINV;
}

imxrt_serialout(priv, IMXRT_LPUART_STAT_OFFSET, stat);
imxrt_serialout(priv, IMXRT_LPUART_CTRL_OFFSET, ctrl);

spin_unlock_irqrestore(flags);
}
break;
#endif

case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
default:
Expand Down
16 changes: 16 additions & 0 deletions arch/arm/src/stm32h7/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,22 @@ config STM32H7_USART_SINGLEWIRE
Enable single wire UART support. The option enables support for the
TIOCSSINGLEWIRE ioctl in the STM32H7 serial driver.

config STM32H7_USART_INVERT
bool "Signal Invert Support"
default n
depends on STM32H7_USART
---help---
Enable signal inversion UART support. The option enables support for the
TIOCSINVERT ioctl in the STM32H7 serial driver.

config STM32H7_USART_SWAP
bool "Swap RX/TX pins support"
default n
depends on STM32H7_USART
---help---
Enable RX/TX pin swapping support. The option enables support for the
TIOCSSWAP ioctl in the STM32H7 serial driver.

if PM

config STM32H7_PM_SERIAL_ACTIVITY
Expand Down
93 changes: 93 additions & 0 deletions arch/arm/src/stm32h7/stm32_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,99 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
break;
#endif

#ifdef CONFIG_STM32H7_USART_INVERT
case TIOCSINVERT:
{
uint32_t cr1;
uint32_t cr1_ue;
irqstate_t flags;

flags = enter_critical_section();

/* Get the original state of UE */

cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET);
cr1_ue = cr1 & USART_CR1_UE;
cr1 &= ~USART_CR1_UE;

/* Disable UE, {R,T}XINV can only be written when UE=0 */

up_serialout(priv, STM32_USART_CR1_OFFSET, cr1);

/* Enable/disable signal inversion. */

uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET);

if (arg & SER_INVERT_ENABLED_RX)
{
cr |= USART_CR2_RXINV;
}
else
{
cr &= ~USART_CR2_RXINV;
}

if (arg & SER_INVERT_ENABLED_TX)
{
cr |= USART_CR2_TXINV;
}
else
{
cr &= ~USART_CR2_TXINV;
}

up_serialout(priv, STM32_USART_CR2_OFFSET, cr);

/* Re-enable UE if appropriate */

up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue);
leave_critical_section(flags);
}
break;
#endif

#ifdef CONFIG_STM32H7_USART_SWAP
case TIOCSSWAP:
{
uint32_t cr1;
uint32_t cr1_ue;
irqstate_t flags;

flags = enter_critical_section();

/* Get the original state of UE */

cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET);
cr1_ue = cr1 & USART_CR1_UE;
cr1 &= ~USART_CR1_UE;

/* Disable UE, SWAP can only be written when UE=0 */

up_serialout(priv, STM32_USART_CR1_OFFSET, cr1);

/* Enable/disable Swap mode. */

uint32_t cr = up_serialin(priv, STM32_USART_CR2_OFFSET);

if (arg == SER_SWAP_ENABLED)
{
cr |= USART_CR2_SWAP;
}
else
{
cr &= ~USART_CR2_SWAP;
}

up_serialout(priv, STM32_USART_CR2_OFFSET, cr);

/* Re-enable UE if appropriate */

up_serialout(priv, STM32_USART_CR1_OFFSET, cr1 | cr1_ue);
leave_critical_section(flags);
}
break;
#endif

#ifdef CONFIG_SERIAL_TERMIOS
case TCGETS:
{
Expand Down
16 changes: 16 additions & 0 deletions arch/arm/src/stm32l4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4005,6 +4005,22 @@ config STM32L4_USART_SINGLEWIRE
Enable single wire UART support. The option enables support for the
TIOCSSINGLEWIRE ioctl in the STM32L4 serial driver.

config STM32L4_USART_INVERT
bool "Signal Invert Support"
default n
depends on STM32L4_USART
---help---
Enable signal inversion UART support. The option enables support for the
TIOCSINVERT ioctl in the STM32L4 serial driver.

config STM32L4_USART_SWAP
bool "Swap RX/TX pins support"
default n
depends on STM32L4_USART
---help---
Enable RX/TX pin swapping support. The option enables support for the
TIOCSSWAP ioctl in the STM32L4 serial driver.

if PM

config STM32L4_PM_SERIAL_ACTIVITY
Expand Down
115 changes: 115 additions & 0 deletions arch/arm/src/stm32l4/stm32l4_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,23 @@ static int stm32l4serial_ioctl(FAR struct file *filep, int cmd,
#ifdef CONFIG_STM32L4_USART_SINGLEWIRE
case TIOCSSINGLEWIRE:
{

uint32_t cr1;
uint32_t cr1_ue;
irqstate_t flags;

flags = enter_critical_section();

/* Get the original state of UE */

cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET);
cr1_ue = cr1 & USART_CR1_UE;
cr1 &= ~USART_CR1_UE;

/* Disable UE, HDSEL can only be written when UE=0 */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1);

/* Change the TX port to be open-drain/push-pull and enable/disable
* half-duplex mode.
*/
Expand All @@ -1807,6 +1824,104 @@ static int stm32l4serial_ioctl(FAR struct file *filep, int cmd,
}

stm32l4serial_putreg(priv, STM32L4_USART_CR3_OFFSET, cr);

/* Re-enable UE if appropriate */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue);
leave_critical_section(flags);
}
break;
#endif

#ifdef CONFIG_STM32L4_USART_INVERT
case TIOCSINVERT:
{
uint32_t cr1;
uint32_t cr1_ue;
irqstate_t flags;

flags = enter_critical_section();

/* Get the original state of UE */

cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET);
cr1_ue = cr1 & USART_CR1_UE;
cr1 &= ~USART_CR1_UE;

/* Disable UE, {R,T}XINV can only be written when UE=0 */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1);

/* Enable/disable signal inversion. */

uint32_t cr = stm32l4serial_getreg(priv, STM32L4_USART_CR2_OFFSET);

if (arg & SER_INVERT_ENABLED_RX)
{
cr |= USART_CR2_RXINV;
}
else
{
cr &= ~USART_CR2_RXINV;
}

if (arg & SER_INVERT_ENABLED_TX)
{
cr |= USART_CR2_TXINV;
}
else
{
cr &= ~USART_CR2_TXINV;
}

stm32l4serial_putreg(priv, STM32L4_USART_CR2_OFFSET, cr);

/* Re-enable UE if appropriate */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue);
leave_critical_section(flags);
}
break;
#endif

#ifdef CONFIG_STM32L4_USART_SWAP
case TIOCSSWAP:
{
uint32_t cr1;
uint32_t cr1_ue;
irqstate_t flags;

flags = enter_critical_section();

/* Get the original state of UE */

cr1 = stm32l4serial_getreg(priv, STM32L4_USART_CR1_OFFSET);
cr1_ue = cr1 & USART_CR1_UE;
cr1 &= ~USART_CR1_UE;

/* Disable UE, SWAP can only be written when UE=0 */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1);

/* Enable/disable Swap mode. */

uint32_t cr = stm32l4serial_getreg(priv, STM32L4_USART_CR2_OFFSET);

if (arg == SER_SWAP_ENABLED)
{
cr |= USART_CR2_SWAP;
}
else
{
cr &= ~USART_CR2_SWAP;
}

stm32l4serial_putreg(priv, STM32L4_USART_CR2_OFFSET, cr);

/* Re-enable UE if appropriate */

stm32l4serial_putreg(priv, STM32L4_USART_CR1_OFFSET, cr1 | cr1_ue);
leave_critical_section(flags);
}
break;
#endif
Expand Down

0 comments on commit 0ebab19

Please sign in to comment.