diff options
| author | Mustafa Yigit Bilgen <mbilgen@nvidia.com> | 2017-03-31 19:10:37 -0400 |
|---|---|---|
| committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-06-22 21:34:32 -0400 |
| commit | d9e7472f4c8bec5f2b9d5092b11b098af7b2c206 (patch) | |
| tree | 31db259284fa615818195f37c86f8ab0b5ec03f7 | |
| parent | f3c0ba942b56212234fb22a4769d6d7eece25ba2 (diff) | |
serial: combined uart: add pm ops
Add support for suspend/resume. This is necessary to ensure that RX interrupts
are received after resuming from suspend.
Bug 1527617
Bug 1817040
Change-Id: Ic54af7a916fb99fc0017524a11cad9acf0424008
Signed-off-by: Mustafa Yigit Bilgen <mbilgen@nvidia.com>
Reviewed-on: http://git-master/r/1503302
Reviewed-by: Liang Cheng (SW) <licheng@nvidia.com>
Reviewed-by: Akhilesh Khumbum <akhumbum@nvidia.com>
Reviewed-by: Robert Collins <rcollins@nvidia.com>
GVS: Gerrit_Virtual_Submit
| -rw-r--r-- | drivers/tty/serial/tegra-combined-uart.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/drivers/tty/serial/tegra-combined-uart.c b/drivers/tty/serial/tegra-combined-uart.c index 76435e150..3f19319ed 100644 --- a/drivers/tty/serial/tegra-combined-uart.c +++ b/drivers/tty/serial/tegra-combined-uart.c | |||
| @@ -59,16 +59,45 @@ static int uart_null_func(struct uart_port *port) | |||
| 59 | return 0; | 59 | return 0; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static int uart_shutdown(struct uart_port *port) | 62 | static void tegra_combined_uart_disable_sm_irq(void) |
| 63 | { | 63 | { |
| 64 | u32 reg_val; | 64 | u32 reg_val; |
| 65 | /* | 65 | /* |
| 66 | * disable interrupt | ||
| 67 | * WARNING: HSP_INT_IE_0 is not protected for RMW. | 66 | * WARNING: HSP_INT_IE_0 is not protected for RMW. |
| 68 | */ | 67 | */ |
| 69 | reg_val = readl(top0_cmn_base + HSP_INT_IE_0); | 68 | reg_val = readl(top0_cmn_base + HSP_INT_IE_0); |
| 70 | reg_val &= ~(1 << MBOX0_FULL_BIT); | 69 | reg_val &= ~(1 << MBOX0_FULL_BIT); |
| 71 | writel(reg_val, top0_cmn_base + HSP_INT_IE_0); | 70 | writel(reg_val, top0_cmn_base + HSP_INT_IE_0); |
| 71 | } | ||
| 72 | |||
| 73 | static void tegra_combined_uart_enable_sm_irq(void) | ||
| 74 | { | ||
| 75 | u32 reg_val; | ||
| 76 | /* | ||
| 77 | * WARNING: HSP_INT_IE_0 is not protected for RMW. | ||
| 78 | */ | ||
| 79 | reg_val = readl(top0_cmn_base + HSP_INT_IE_0); | ||
| 80 | reg_val |= (1 << MBOX0_FULL_BIT); | ||
| 81 | writel(reg_val, top0_cmn_base + HSP_INT_IE_0); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int tegra_combined_uart_suspend(struct device *dev) | ||
| 85 | { | ||
| 86 | tegra_combined_uart_disable_sm_irq(); | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static int tegra_combined_uart_resume(struct device *dev) | ||
| 92 | { | ||
| 93 | tegra_combined_uart_enable_sm_irq(); | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int uart_shutdown(struct uart_port *port) | ||
| 99 | { | ||
| 100 | tegra_combined_uart_disable_sm_irq(); | ||
| 72 | /* free IRQ */ | 101 | /* free IRQ */ |
| 73 | free_irq(tegra_combined_uart_port.irq, port); | 102 | free_irq(tegra_combined_uart_port.irq, port); |
| 74 | 103 | ||
| @@ -222,13 +251,13 @@ static irqreturn_t tegra_combined_uart_rx(int irq, void *dev_id) | |||
| 222 | 251 | ||
| 223 | tegra_combined_uart_handle_rx_msg(reg_val); | 252 | tegra_combined_uart_handle_rx_msg(reg_val); |
| 224 | spin_unlock_irqrestore(&mbox_lock, flags); | 253 | spin_unlock_irqrestore(&mbox_lock, flags); |
| 254 | |||
| 225 | return IRQ_HANDLED; | 255 | return IRQ_HANDLED; |
| 226 | } | 256 | } |
| 227 | 257 | ||
| 228 | static int tegra_combined_uart_startup(struct uart_port *port) | 258 | static int tegra_combined_uart_startup(struct uart_port *port) |
| 229 | { | 259 | { |
| 230 | int ret; | 260 | int ret; |
| 231 | u32 reg_val; | ||
| 232 | /* allocate IRQ */ | 261 | /* allocate IRQ */ |
| 233 | ret = request_irq(tegra_combined_uart_port.irq, tegra_combined_uart_rx, | 262 | ret = request_irq(tegra_combined_uart_port.irq, tegra_combined_uart_rx, |
| 234 | 0, "combined_uart rx", port); | 263 | 0, "combined_uart rx", port); |
| @@ -236,13 +265,9 @@ static int tegra_combined_uart_startup(struct uart_port *port) | |||
| 236 | pr_err("%s: request_irq error\n", __func__); | 265 | pr_err("%s: request_irq error\n", __func__); |
| 237 | return ret; | 266 | return ret; |
| 238 | } | 267 | } |
| 239 | /* | 268 | |
| 240 | * enable interrupt | 269 | tegra_combined_uart_enable_sm_irq(); |
| 241 | * WARNING: HSP_INT_IE_0 is not protected for RMW. | 270 | |
| 242 | */ | ||
| 243 | reg_val = readl(top0_cmn_base + HSP_INT_IE_0); | ||
| 244 | reg_val |= (1 << MBOX0_FULL_BIT); | ||
| 245 | writel(reg_val, top0_cmn_base + HSP_INT_IE_0); | ||
| 246 | return ret; | 271 | return ret; |
| 247 | } | 272 | } |
| 248 | 273 | ||
| @@ -306,6 +331,7 @@ err_mapping: | |||
| 306 | iounmap(top0_mbox01_base); | 331 | iounmap(top0_mbox01_base); |
| 307 | if (top0_cmn_base != NULL && !IS_ERR(top0_cmn_base)) | 332 | if (top0_cmn_base != NULL && !IS_ERR(top0_cmn_base)) |
| 308 | iounmap(top0_cmn_base); | 333 | iounmap(top0_cmn_base); |
| 334 | |||
| 309 | return ret; | 335 | return ret; |
| 310 | } | 336 | } |
| 311 | 337 | ||
| @@ -317,6 +343,7 @@ static int tegra_combined_uart_remove(struct platform_device *pdev) | |||
| 317 | iounmap(spe_mbox_reg); | 343 | iounmap(spe_mbox_reg); |
| 318 | iounmap(top0_mbox01_base); | 344 | iounmap(top0_mbox01_base); |
| 319 | iounmap(top0_cmn_base); | 345 | iounmap(top0_cmn_base); |
| 346 | |||
| 320 | return 0; | 347 | return 0; |
| 321 | } | 348 | } |
| 322 | 349 | ||
| @@ -398,12 +425,22 @@ static struct uart_driver tegra_combined_uart_driver = { | |||
| 398 | .nr = 1, | 425 | .nr = 1, |
| 399 | }; | 426 | }; |
| 400 | 427 | ||
| 428 | #ifdef CONFIG_PM | ||
| 429 | static const struct dev_pm_ops tegra_combined_uart_pm_ops = { | ||
| 430 | .suspend = tegra_combined_uart_suspend, | ||
| 431 | .resume = tegra_combined_uart_resume, | ||
| 432 | }; | ||
| 433 | #endif | ||
| 434 | |||
| 401 | static struct platform_driver tegra_combined_uart_platform_driver = { | 435 | static struct platform_driver tegra_combined_uart_platform_driver = { |
| 402 | .probe = tegra_combined_uart_probe, | 436 | .probe = tegra_combined_uart_probe, |
| 403 | .remove = tegra_combined_uart_remove, | 437 | .remove = tegra_combined_uart_remove, |
| 404 | .driver = { | 438 | .driver = { |
| 405 | .name = "tegra-combined-uart", | 439 | .name = "tegra-combined-uart", |
| 406 | .of_match_table = of_match_ptr(tegra_combined_uart_of_match), | 440 | .of_match_table = of_match_ptr(tegra_combined_uart_of_match), |
| 441 | #ifdef CONFIG_PM | ||
| 442 | .pm = &tegra_combined_uart_pm_ops, | ||
| 443 | #endif | ||
| 407 | }, | 444 | }, |
| 408 | }; | 445 | }; |
| 409 | 446 | ||
