819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. From ff3d8063eed907bed728a14e1519dc659036315a Mon Sep 17 00:00:00 2001
  2. From: Fugang Duan <[email protected]>
  3. Date: Wed, 11 Sep 2019 16:36:48 +0800
  4. Subject: [PATCH] MLK-17133-02 tty: serial: lpuart: add runtime pm support
  5. Add runtime pm support to manage lpuart clock and its power domain
  6. to save power in system idle and system suspend stages.
  7. Signed-off-by: Fugang Duan <[email protected]>
  8. Reviewed-by: Robin Gong <[email protected]>
  9. ---
  10. drivers/tty/serial/fsl_lpuart.c | 80 ++++++++++++++++++++++++++++++++++++-----
  11. 1 file changed, 72 insertions(+), 8 deletions(-)
  12. --- a/drivers/tty/serial/fsl_lpuart.c
  13. +++ b/drivers/tty/serial/fsl_lpuart.c
  14. @@ -245,6 +245,7 @@
  15. /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
  16. #define DMA_RX_TIMEOUT (10)
  17. +#define UART_AUTOSUSPEND_TIMEOUT 3000
  18. #define DRIVER_NAME "fsl-lpuart"
  19. #define DEV_NAME "ttyLP"
  20. @@ -859,6 +860,20 @@ static void lpuart32_start_tx(struct uar
  21. }
  22. }
  23. +static void
  24. +lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
  25. +{
  26. + switch (state) {
  27. + case UART_PM_STATE_OFF:
  28. + pm_runtime_mark_last_busy(port->dev);
  29. + pm_runtime_put_autosuspend(port->dev);
  30. + break;
  31. + default:
  32. + pm_runtime_get_sync(port->dev);
  33. + break;
  34. + }
  35. +}
  36. +
  37. /* return TIOCSER_TEMT when transmitter is not busy */
  38. static unsigned int lpuart_tx_empty(struct uart_port *port)
  39. {
  40. @@ -2283,6 +2298,7 @@ static const struct uart_ops lpuart_pops
  41. .break_ctl = lpuart_break_ctl,
  42. .startup = lpuart_startup,
  43. .shutdown = lpuart_shutdown,
  44. + .pm = lpuart_uart_pm,
  45. .set_termios = lpuart_set_termios,
  46. .type = lpuart_type,
  47. .request_port = lpuart_request_port,
  48. @@ -2307,6 +2323,7 @@ static const struct uart_ops lpuart32_po
  49. .break_ctl = lpuart32_break_ctl,
  50. .startup = lpuart32_startup,
  51. .shutdown = lpuart32_shutdown,
  52. + .pm = lpuart_uart_pm,
  53. .set_termios = lpuart32_set_termios,
  54. .type = lpuart_type,
  55. .request_port = lpuart_request_port,
  56. @@ -2766,6 +2783,11 @@ static int lpuart_probe(struct platform_
  57. if (ret)
  58. goto failed_irq_request;
  59. + pm_runtime_use_autosuspend(&pdev->dev);
  60. + pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
  61. + pm_runtime_set_active(&pdev->dev);
  62. + pm_runtime_enable(&pdev->dev);
  63. +
  64. ret = uart_add_one_port(&lpuart_reg, &sport->port);
  65. if (ret)
  66. goto failed_attach_port;
  67. @@ -2800,6 +2822,9 @@ static int lpuart_probe(struct platform_
  68. failed_reset:
  69. uart_remove_one_port(&lpuart_reg, &sport->port);
  70. failed_attach_port:
  71. + pm_runtime_disable(&pdev->dev);
  72. + pm_runtime_set_suspended(&pdev->dev);
  73. + pm_runtime_dont_use_autosuspend(&pdev->dev);
  74. failed_irq_request:
  75. lpuart_disable_clks(sport);
  76. failed_clock_enable:
  77. @@ -2826,15 +2851,41 @@ static int lpuart_remove(struct platform
  78. if (sport->dma_rx_chan)
  79. dma_release_channel(sport->dma_rx_chan);
  80. + pm_runtime_disable(&pdev->dev);
  81. + pm_runtime_set_suspended(&pdev->dev);
  82. + pm_runtime_dont_use_autosuspend(&pdev->dev);
  83. return 0;
  84. }
  85. #ifdef CONFIG_PM_SLEEP
  86. +static int lpuart_runtime_suspend(struct device *dev)
  87. +{
  88. + struct platform_device *pdev = to_platform_device(dev);
  89. + struct lpuart_port *sport = platform_get_drvdata(pdev);
  90. +
  91. + lpuart_disable_clks(sport);
  92. +
  93. + return 0;
  94. +};
  95. +
  96. +static int lpuart_runtime_resume(struct device *dev)
  97. +{
  98. + struct platform_device *pdev = to_platform_device(dev);
  99. + struct lpuart_port *sport = platform_get_drvdata(pdev);
  100. +
  101. + return lpuart_enable_clks(sport);
  102. +};
  103. +
  104. static int lpuart_suspend(struct device *dev)
  105. {
  106. struct lpuart_port *sport = dev_get_drvdata(dev);
  107. unsigned long temp;
  108. bool irq_wake;
  109. + int ret;
  110. +
  111. + ret = clk_prepare_enable(sport->ipg_clk);
  112. + if (ret)
  113. + return ret;
  114. if (lpuart_is_32(sport)) {
  115. /* disable Rx/Tx and interrupts */
  116. @@ -2848,10 +2899,14 @@ static int lpuart_suspend(struct device
  117. writeb(temp, sport->port.membase + UARTCR2);
  118. }
  119. + clk_disable_unprepare(sport->ipg_clk);
  120. +
  121. uart_suspend_port(&lpuart_reg, &sport->port);
  122. /* uart_suspend_port() might set wakeup flag */
  123. irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
  124. + if (sport->port.suspended && !irq_wake)
  125. + return 0;
  126. if (sport->lpuart_dma_rx_use) {
  127. /*
  128. @@ -2882,9 +2937,6 @@ static int lpuart_suspend(struct device
  129. dmaengine_terminate_all(sport->dma_tx_chan);
  130. }
  131. - if (sport->port.suspended && !irq_wake)
  132. - lpuart_disable_clks(sport);
  133. -
  134. return 0;
  135. }
  136. @@ -2892,9 +2944,11 @@ static int lpuart_resume(struct device *
  137. {
  138. struct lpuart_port *sport = dev_get_drvdata(dev);
  139. bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
  140. + int ret;
  141. - if (sport->port.suspended && !irq_wake)
  142. - lpuart_enable_clks(sport);
  143. + ret = clk_prepare_enable(sport->ipg_clk);
  144. + if (ret)
  145. + return ret;
  146. if (lpuart_is_32(sport))
  147. lpuart32_setup_watermark_enable(sport);
  148. @@ -2915,13 +2969,23 @@ static int lpuart_resume(struct device *
  149. if (lpuart_is_32(sport))
  150. lpuart32_configure(sport);
  151. + clk_disable_unprepare(sport->ipg_clk);
  152. +
  153. uart_resume_port(&lpuart_reg, &sport->port);
  154. return 0;
  155. }
  156. -#endif
  157. +static const struct dev_pm_ops lpuart_pm_ops = {
  158. + SET_RUNTIME_PM_OPS(lpuart_runtime_suspend,
  159. + lpuart_runtime_resume, NULL)
  160. + SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
  161. +};
  162. +#define SERIAL_LPUART_PM_OPS (&lpuart_pm_ops)
  163. -static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
  164. +#else /* !CONFIG_PM_SLEEP */
  165. +
  166. +#define SERIAL_LPUART_PM_OPS NULL
  167. +#endif
  168. static struct platform_driver lpuart_driver = {
  169. .probe = lpuart_probe,
  170. @@ -2929,7 +2993,7 @@ static struct platform_driver lpuart_dri
  171. .driver = {
  172. .name = "fsl-lpuart",
  173. .of_match_table = lpuart_dt_ids,
  174. - .pm = &lpuart_pm_ops,
  175. + .pm = SERIAL_LPUART_PM_OPS,
  176. },
  177. };