From feb0bf2d9b83cb19c75be4cd12b3e7a584f513b5 Mon Sep 17 00:00:00 2001 From: Romuald JEANNE Date: Tue, 13 Nov 2018 12:21:06 +0100 Subject: [PATCH 07/52] ARM: stm32mp1-r0-rc1: INPUT TTY --- drivers/input/misc/Kconfig | 11 + drivers/input/misc/Makefile | 2 + drivers/input/misc/stpmic1_onkey.c | 197 ++++++++++++++++++ drivers/tty/serial/stm32-usart.c | 398 +++++++++++++++++++++++++++++-------- drivers/tty/serial/stm32-usart.h | 34 +++- 5 files changed, 550 insertions(+), 92 deletions(-) create mode 100644 drivers/input/misc/stpmic1_onkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca59a2b..279fb02 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -851,4 +851,15 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config INPUT_STPMIC1_ONKEY + tristate "STPMIC1 PMIC Onkey support" + depends on MFD_STPMIC1 + help + Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey + can be used to wakeup from low power modes and force a shut-down on + long press. + + To compile this driver as a module, choose M here: the + module will be called stpmic1_onkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9d0f9d1..1b44202 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o @@ -81,3 +82,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o + diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c new file mode 100644 index 0000000..6a7f08b --- /dev/null +++ b/drivers/input/misc/stpmic1_onkey.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct stpmic1_onkey - OnKey data + * @input_dev: pointer to input device + * @irq_falling: irq that we are hooked on to + * @irq_rising: irq that we are hooked on to + */ +struct stpmic1_onkey { + struct input_dev *input_dev; + int irq_falling; + int irq_rising; +}; + +static irqreturn_t onkey_falling_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 1); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t onkey_rising_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 0); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static int stpmic1_onkey_probe(struct platform_device *pdev) +{ + struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct stpmic1_onkey *onkey; + unsigned int val, reg = 0; + int error; + + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling"); + if (onkey->irq_falling < 0) { + dev_err(dev, "failed: request IRQ onkey-falling %d\n", + onkey->irq_falling); + return onkey->irq_falling; + } + + onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising"); + if (onkey->irq_rising < 0) { + dev_err(dev, "failed: request IRQ onkey-rising %d\n", + onkey->irq_rising); + return onkey->irq_rising; + } + + if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { + if ((val > 0) && (val <= 16)) { + dev_dbg(dev, "power-off-time=%d seconds\n", val); + reg |= PONKEY_PWR_OFF; + reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK); + } else { + dev_err(dev, "power-off-time-sec out of range\n"); + return -EINVAL; + } + } + + if (device_property_present(dev, "st,onkey-clear-cc-flag")) + reg |= PONKEY_CC_FLAG_CLEAR; + + error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR, + PONKEY_TURNOFF_MASK, reg); + if (error) { + dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error); + return error; + } + + if (device_property_present(dev, "st,onkey-pu-inactive")) { + error = regmap_update_bits(pmic->regmap, PADS_PULL_CR, + PONKEY_PU_INACTIVE, + PONKEY_PU_INACTIVE); + if (error) { + dev_err(dev, "ONKEY Pads configuration failed: %d\n", error); + return error; + } + } + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + dev_err(dev, "Can't allocate Pwr Onkey Input Device\n"); + return -ENOMEM; + } + + input_dev->name = "pmic_onkey"; + input_dev->phys = "pmic_onkey/input0"; + + input_set_capability(input_dev, EV_KEY, KEY_POWER); + + onkey->input_dev = input_dev; + + /* interrupt is nested in a thread */ + error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL, + onkey_falling_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL, + onkey_rising_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, onkey); + device_init_wakeup(dev, true); + + return 0; +} + +static int __maybe_unused stpmic1_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + enable_irq_wake(onkey->irq_falling); + enable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static int __maybe_unused stpmic1_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + disable_irq_wake(onkey->irq_falling); + disable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm, + stpmic1_onkey_suspend, + stpmic1_onkey_resume); + +static const struct of_device_id of_stpmic1_onkey_match[] = { + { .compatible = "st,stpmic1-onkey" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match); + +static struct platform_driver stpmic1_onkey_driver = { + .probe = stpmic1_onkey_probe, + .driver = { + .name = "stpmic1_onkey", + .of_match_table = of_match_ptr(of_stpmic1_onkey_match), + .pm = &stpmic1_onkey_pm, + }, +}; +module_platform_driver(stpmic1_onkey_driver); + +MODULE_DESCRIPTION("Onkey driver for STPMIC1"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index e8d7a7b..5c6c3c0 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -180,14 +182,18 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, *sr = readl_relaxed(port->membase + ofs->isr); if (threaded && stm32_port->rx_ch) { + if (stm32_port->rx_dma_cb == CALLBACK_CALLED) + return 1; status = dmaengine_tx_status(stm32_port->rx_ch, stm32_port->rx_ch->cookie, &state); if ((status == DMA_IN_PROGRESS) && - (*last_res != state.residue)) + (*last_res != state.residue)) { + stm32_port->rx_dma_cb = CALLBACK_IGNORED; return 1; - else + } else { return 0; + } } else if (*sr & USART_SR_RXNE) { return 1; } @@ -203,8 +209,11 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) if (stm32_port->rx_ch) { c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; - if ((*last_res) == 0) + if ((*last_res) == 0) { *last_res = RX_BUF_L; + if (stm32_port->rx_dma_cb == CALLBACK_CALLED) + stm32_port->rx_dma_cb = CALLBACK_NOT_CALLED; + } return c; } else { return readl_relaxed(port->membase + ofs->rdr); @@ -271,22 +280,8 @@ static void stm32_tx_dma_complete(void *arg) struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32port->info->ofs; - unsigned int isr; - int ret; - - ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, - isr, - (isr & USART_SR_TC), - 10, 100000); - - if (ret) - dev_err(port->dev, "terminal count not set\n"); - - if (ofs->icr == UNDEF_REG) - stm32_clr_bits(port, ofs->isr, USART_SR_TC); - else - stm32_set_bits(port, ofs->icr, USART_CR_TC); + dmaengine_terminate_async(stm32port->tx_ch); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); stm32port->tx_dma_busy = false; @@ -294,32 +289,56 @@ static void stm32_tx_dma_complete(void *arg) stm32_transmit_chars(port); } +static void stm32_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + struct stm32_port *stm32port = to_stm32_port(port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* + * If the dma controller is sending the data on + * the fly then we have CALLBACK_IGNORED + */ + + if (stm32port->rx_dma_cb == CALLBACK_NOT_CALLED) { + stm32port->rx_dma_cb = CALLBACK_CALLED; + stm32_receive_chars(port, true); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + static void stm32_transmit_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; - unsigned int isr; - int ret; if (stm32_port->tx_dma_busy) { stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); stm32_port->tx_dma_busy = false; } - ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, - isr, - (isr & USART_SR_TXE), - 10, 100000); - - if (ret) - dev_err(port->dev, "tx empty not set\n"); - - stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); + while (!uart_circ_empty(xmit)) { + if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) + break; + writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } - writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + if (uart_circ_empty(xmit)) + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + else + if (stm32_port->fifoen) + stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else + stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); } static void stm32_transmit_chars_dma(struct uart_port *port) @@ -377,7 +396,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); - stm32_clr_bits(port, ofs->isr, USART_SR_TC); stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); @@ -401,15 +419,18 @@ static void stm32_transmit_chars(struct uart_port *port) return; } - if (uart_tx_stopped(port)) { - stm32_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); return; } - if (uart_circ_empty(xmit)) { - stm32_stop_tx(port); - return; - } + if (ofs->icr == UNDEF_REG) + stm32_clr_bits(port, ofs->isr, USART_SR_TC); + else + stm32_set_bits(port, ofs->icr, USART_ICR_TCCF); if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); @@ -419,8 +440,12 @@ static void stm32_transmit_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - stm32_stop_tx(port); + if (uart_circ_empty(xmit)) { + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + } } static irqreturn_t stm32_interrupt(int irq, void *ptr) @@ -434,6 +459,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) sr = readl_relaxed(port->membase + ofs->isr); + if ((sr & USART_SR_RTOF) && (ofs->icr != UNDEF_REG)) + writel_relaxed(USART_ICR_RTOCF, + port->membase + ofs->icr); + if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) writel_relaxed(USART_ICR_WUCF, port->membase + ofs->icr); @@ -456,11 +485,21 @@ static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; spin_lock(&port->lock); - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + dma_sync_single_for_cpu(port->dev, + stm32_port->rx_dma_buf, + RX_BUF_L, DMA_FROM_DEVICE); stm32_receive_chars(port, true); + dma_sync_single_for_device(port->dev, + stm32_port->rx_dma_buf, + RX_BUF_L, DMA_FROM_DEVICE); + stm32_set_bits(port, ofs->cr3, USART_CR3_DMAR); + } spin_unlock(&port->lock); @@ -472,7 +511,10 @@ static unsigned int stm32_tx_empty(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) + return TIOCSER_TEMT; + + return 0; } static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -498,7 +540,15 @@ static void stm32_stop_tx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + else + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); + + if (stm32_port->tx_dma_busy) { + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + } } /* There are probably characters waiting to be transmitted. */ @@ -512,6 +562,22 @@ static void stm32_start_tx(struct uart_port *port) stm32_transmit_chars(port); } +/* Flush the transmit buffer. */ +static void stm32_flush_buffer(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (stm32_port->tx_ch) { + spin_lock(&port->lock); + dmaengine_terminate_async(stm32_port->tx_ch); + spin_unlock(&port->lock); + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_port->tx_dma_busy = false; + } +} + /* Throttle the remote when input buffer is about to overflow. */ static void stm32_throttle(struct uart_port *port) { @@ -520,7 +586,10 @@ static void stm32_throttle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); + if (stm32_port->cr3_irq) + stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + + stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); spin_unlock_irqrestore(&port->lock, flags); } @@ -532,7 +601,10 @@ static void stm32_unthrottle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE); + if (stm32_port->cr3_irq) + stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + + stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq); spin_unlock_irqrestore(&port->lock, flags); } @@ -542,7 +614,10 @@ static void stm32_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); + if (stm32_port->cr3_irq) + stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + + stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); } /* Handle breaks - ignored by us */ @@ -554,31 +629,41 @@ static int stm32_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; - u32 val; + u32 val, sr, dr; int ret; + sr = readl_relaxed(port->membase + ofs->isr); + + if ((sr & USART_SR_RXNE) && (stm32_port->rx_ch)) { + ret = readl_relaxed_poll_timeout_atomic(port->membase + + ofs->rdr, + dr, + !(sr & USART_SR_RXNE), + 10, 100000); + if (ret) + return ret; + } + ret = request_threaded_irq(port->irq, stm32_interrupt, stm32_threaded_interrupt, IRQF_NO_SUSPEND, name, port); if (ret) return ret; - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { - ret = dev_pm_set_dedicated_wake_irq(port->dev, - stm32_port->wakeirq); - if (ret) { - free_irq(port->irq, port); - return ret; - } - } - - val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + val = stm32_port->cr1_irq | USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; stm32_set_bits(port, ofs->cr1, val); + if (stm32_port->fifoen) { + val = readl_relaxed(port->membase + ofs->cr3); + val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); + val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; + val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; + writel_relaxed(val, port->membase + ofs->cr3); + } + return 0; } @@ -587,15 +672,29 @@ static void stm32_shutdown(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; + u32 val, isr; + int ret; - val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + val = USART_CR1_TXEIE | USART_CR1_TE; + val |= stm32_port->cr1_irq | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; + + ret = readl_relaxed_poll_timeout(port->membase + ofs->isr, + isr, + (isr & USART_SR_TC), + 10, 100000); + + if (ret) + dev_err(port->dev, "transmission complete not set\n"); + stm32_clr_bits(port, ofs->cr1, val); - dev_pm_clear_wake_irq(port->dev); + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, + USART_CR3_TXFTIE | USART_CR3_RXFTIE); + free_irq(port->irq, port); } @@ -606,7 +705,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; struct serial_rs485 *rs485conf = &port->rs485; - unsigned int baud; + unsigned int baud, bits; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; u32 cr1, cr2, cr3; @@ -622,16 +721,50 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, /* Stop serial port and reset value */ writel_relaxed(0, port->membase + ofs->cr1); - cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; + cr1 = USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; cr2 = 0; - cr3 = 0; + cr3 = readl_relaxed(port->membase + ofs->cr3); + cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE + | USART_CR3_TXFTCFG_MASK; if (cflag & CSTOPB) cr2 |= USART_CR2_STOP_2B; + if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || + stm32_port->fifoen)) { + switch (cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; /* CS8 */ + break; + } + + if (cflag & CSTOPB) + bits++; /* 2 stop bits */ + + /* RX timeout irq to occur after last stop bit + bits */ + stm32_port->cr1_irq = USART_CR1_RTOIE; + writel_relaxed(bits, port->membase + ofs->rtor); + cr2 |= USART_CR2_RTOEN; + + /* Not using dma, enable fifo threshold irq */ + if (!stm32_port->rx_ch) + stm32_port->cr3_irq = USART_CR3_RXFTIE; + } + cr1 |= stm32_port->cr1_irq; + cr3 |= stm32_port->cr3_irq; + if (cflag & PARENB) { cr1 |= USART_CR1_PCE; if ((cflag & CSIZE) == CS8) { @@ -715,8 +848,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, } } else { - cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); - cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + cr3 &= ~USART_CR3_DEM; + cr3 &= ~USART_CR3_DEP; + cr1 &= ~USART_CR1_DEDT_MASK; + cr1 &= ~USART_CR1_DEAT_MASK; } writel_relaxed(cr3, port->membase + ofs->cr3); @@ -765,13 +900,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, switch (state) { case UART_PM_STATE_ON: - clk_prepare_enable(stm32port->clk); + pm_runtime_get_sync(port->dev); break; case UART_PM_STATE_OFF: spin_lock_irqsave(&port->lock, flags); stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); - clk_disable_unprepare(stm32port->clk); + pm_runtime_put_sync(port->dev); break; } } @@ -788,6 +923,7 @@ static const struct uart_ops stm32_uart_ops = { .break_ctl = stm32_break_ctl, .startup = stm32_startup, .shutdown = stm32_shutdown, + .flush_buffer = stm32_flush_buffer, .set_termios = stm32_set_termios, .pm = stm32_pm, .type = stm32_type, @@ -808,13 +944,19 @@ static int stm32_init_port(struct stm32_port *stm32port, port->flags = UPF_BOOT_AUTOCONF; port->ops = &stm32_uart_ops; port->dev = &pdev->dev; - port->irq = platform_get_irq(pdev, 0); - port->rs485_config = stm32_config_rs485; + port->irq = platform_get_irq_byname(pdev, "event"); + port->fifosize = stm32port->info->cfg.fifosize; + port->rs485_config = stm32_config_rs485; stm32_init_rs485(port, pdev); - stm32port->wakeirq = platform_get_irq(pdev, 1); + stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); stm32port->fifoen = stm32port->info->cfg.has_fifo; + stm32port->console_pins = pinctrl_lookup_state(pdev->dev.pins->p, + "no_console_suspend"); + if (IS_ERR(stm32port->console_pins) + && PTR_ERR(stm32port->console_pins) != -ENODEV) + return PTR_ERR(stm32port->console_pins); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->membase = devm_ioremap_resource(&pdev->dev, res); @@ -862,7 +1004,11 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) stm32_ports[id].hw_flow_control = of_property_read_bool(np, "st,hw-flow-ctrl"); stm32_ports[id].port.line = id; + stm32_ports[id].cr1_irq = USART_CR1_RXNEIE; + stm32_ports[id].cr3_irq = 0; stm32_ports[id].last_res = RX_BUF_L; + stm32_ports[id].rx_dma_buf = 0; + stm32_ports[id].tx_dma_buf = 0; return &stm32_ports[id]; } @@ -890,10 +1036,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, /* Request DMA RX channel */ stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); - if (!stm32port->rx_ch) { - dev_info(dev, "rx dma alloc failed\n"); + if (!stm32port->rx_ch) return -ENODEV; - } stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, &stm32port->rx_dma_buf, GFP_KERNEL); @@ -925,9 +1069,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, goto config_err; } - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; + desc->callback = stm32_rx_dma_complete; + desc->callback_param = port; /* Push current DMA transaction in the pending queue */ cookie = dmaengine_submit(desc); @@ -962,10 +1105,8 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, /* Request DMA TX channel */ stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); - if (!stm32port->tx_ch) { - dev_info(dev, "tx dma alloc failed\n"); + if (!stm32port->tx_ch) return -ENODEV; - } stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, &stm32port->tx_dma_buf, GFP_KERNEL); @@ -1024,11 +1165,18 @@ static int stm32_serial_probe(struct platform_device *pdev) ret = device_init_wakeup(&pdev->dev, true); if (ret) goto err_uninit; + + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, + stm32port->wakeirq); + if (ret) + goto err_nowup; + + device_set_wakeup_enable(&pdev->dev, false); } ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); if (ret) - goto err_nowup; + goto err_wirq; ret = stm32_of_dma_rx_probe(stm32port, pdev); if (ret) @@ -1040,8 +1188,17 @@ static int stm32_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &stm32port->port); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + return 0; +err_wirq: + if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) + dev_pm_clear_wake_irq(&pdev->dev); + err_nowup: if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) device_init_wakeup(&pdev->dev, false); @@ -1058,11 +1215,16 @@ static int stm32_serial_remove(struct platform_device *pdev) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; + int err; + + pm_runtime_get_sync(&pdev->dev); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + dmaengine_terminate_async(stm32_port->rx_ch); dma_release_channel(stm32_port->rx_ch); + } if (stm32_port->rx_dma_buf) dma_free_coherent(&pdev->dev, @@ -1071,20 +1233,29 @@ static int stm32_serial_remove(struct platform_device *pdev) stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - if (stm32_port->tx_ch) + if (stm32_port->tx_ch) { + dmaengine_terminate_async(stm32_port->tx_ch); dma_release_channel(stm32_port->tx_ch); + } if (stm32_port->tx_dma_buf) dma_free_coherent(&pdev->dev, TX_BUF_L, stm32_port->tx_buf, stm32_port->tx_dma_buf); - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) + if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); + } clk_disable_unprepare(stm32_port->clk); - return uart_remove_one_port(&stm32_usart_driver, port); + err = uart_remove_one_port(&stm32_usart_driver, port); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return err; } @@ -1215,14 +1386,41 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) static int stm32_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_struct *tty = port->state->port.tty; - uart_suspend_port(&stm32_usart_driver, port); + if (tty) { + struct device *tty_dev = tty->dev; + + if (tty_dev && (device_may_wakeup(tty_dev) + != device_may_wakeup(dev))) { + dev_err(port->dev, + "UART and TTY wakeup are not coherent\n"); + return -EINVAL; + } + } if (device_may_wakeup(dev)) stm32_serial_enable_wakeup(port, true); else stm32_serial_enable_wakeup(port, false); + uart_suspend_port(&stm32_usart_driver, port); + + if (uart_console(port) && !console_suspend_enabled) { + if (IS_ERR(stm32_port->console_pins)) { + dev_err(dev, "no_console_suspend pinctrl not found\n"); + return PTR_ERR(stm32_port->console_pins); + } + + pinctrl_select_state(dev->pins->p, stm32_port->console_pins); + } else { + if (device_may_wakeup(dev)) + pinctrl_pm_select_idle_state(dev); + else + pinctrl_pm_select_sleep_state(dev); + } + return 0; } @@ -1230,6 +1428,8 @@ static int stm32_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + pinctrl_pm_select_default_state(dev); + if (device_may_wakeup(dev)) stm32_serial_enable_wakeup(port, false); @@ -1237,7 +1437,31 @@ static int stm32_serial_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM +static int stm32_serial_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + clk_disable_unprepare(stm32port->clk); + + return 0; +} + +static int stm32_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + return clk_prepare_enable(stm32port->clk); +} +#endif /* CONFIG_PM */ + static const struct dev_pm_ops stm32_serial_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, + stm32_serial_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) }; diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 6f294e2..f1f5c1c 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -27,6 +27,7 @@ struct stm32_usart_config { bool has_7bits_data; bool has_wakeup; bool has_fifo; + int fifosize; }; struct stm32_usart_info { @@ -54,6 +55,7 @@ struct stm32_usart_info stm32f4_info = { .cfg = { .uart_enable_bit = 13, .has_7bits_data = false, + .fifosize = 1, } }; @@ -74,6 +76,7 @@ struct stm32_usart_info stm32f7_info = { .cfg = { .uart_enable_bit = 0, .has_7bits_data = true, + .fifosize = 1, } }; @@ -96,6 +99,7 @@ struct stm32_usart_info stm32h7_info = { .has_7bits_data = true, .has_wakeup = true, .has_fifo = true, + .fifosize = 16, } }; @@ -125,9 +129,6 @@ struct stm32_usart_info stm32h7_info = { /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) -/* USART_ICR (F7) */ -#define USART_CR_TC BIT(6) - /* USART_DR */ #define USART_DR_MASK GENMASK(8, 0) @@ -209,6 +210,19 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */ #define USART_CR3_WUS_START_BIT BIT(21) /* H7 */ #define USART_CR3_WUFIE BIT(22) /* H7 */ +#define USART_CR3_TXFTIE BIT(23) /* H7 */ +#define USART_CR3_TCBGTIE BIT(24) /* H7 */ +#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */ +#define USART_CR3_RXFTCFG_SHIFT 25 /* H7 */ +#define USART_CR3_RXFTIE BIT(28) /* H7 */ +#define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ +#define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ + +/* TX FIFO threashold set to half of its depth */ +#define USART_CR3_TXFTCFG_HALF 0x2 + +/* RX FIFO threashold set to half of its depth */ +#define USART_CR3_RXFTCFG_HALF 0x2 /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) @@ -242,9 +256,15 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 -#define RX_BUF_L 200 /* dma rx buffer length */ +#define RX_BUF_L 160 /* dma rx buffer length */ #define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ + +enum dma_cb { + CALLBACK_NOT_CALLED, + CALLBACK_CALLED, + CALLBACK_IGNORED, +}; struct stm32_port { struct uart_port port; @@ -256,11 +276,15 @@ struct stm32_port { struct dma_chan *tx_ch; /* dma tx channel */ dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ unsigned char *tx_buf; /* dma tx buffer cpu address */ + u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ + u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; + enum dma_cb rx_dma_cb; /* dma rx callback status */ bool tx_dma_busy; /* dma tx busy */ bool hw_flow_control; bool fifoen; int wakeirq; + struct pinctrl_state *console_pins; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; -- 2.7.4