aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2014-07-23 11:33:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-27 14:07:08 -0400
commitc8ed99d4f6a8ac03f397877d25428698f461a2af (patch)
tree8d2580e722004f2790cf315e59ef313c37382d8e
parent7fe090bf48b522de8cd6fe85e2b3252ed74e74f8 (diff)
serial: 8250_dw: Add support for deferred probing
The 8250_dw driver fails to probe if the specified clock isn't registered at probe time. Even if a clock frequency is given, the required clock might be gated because it wasn't properly enabled. This happened to me when the device is registered through DT, and the clock was part of an MFD, the PRCM found on A31 and A23 SoCs. Unlike core clocks that are registered with OF_CLK_DECLARE, which happen almost immediately after the kernel starts, the clocks are registered as sub-devices of the PRCM MFD platform device. Even though devices are registered in the order they are found in the DT, the drivers are registered in a different, arbitrary order. It is possible that the 8250_dw driver is registered, and thus associated with the device and probed, before the clock driver is registered and probed. 8250_dw then reports unable to get the clock, and fails. Without a working console, the kernel panics. This patch adds support for deferred probe handling for the clock and reset controller. It also fixes the cleanup path if serial8250_register_8250_port fails. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/8250/8250_dw.c41
1 files changed, 34 insertions, 7 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 501db2f58fd2..4db7987ec225 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -365,8 +365,10 @@ static int dw8250_probe(struct platform_device *pdev)
365 365
366 data->usr_reg = DW_UART_USR; 366 data->usr_reg = DW_UART_USR;
367 data->clk = devm_clk_get(&pdev->dev, "baudclk"); 367 data->clk = devm_clk_get(&pdev->dev, "baudclk");
368 if (IS_ERR(data->clk)) 368 if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
369 data->clk = devm_clk_get(&pdev->dev, NULL); 369 data->clk = devm_clk_get(&pdev->dev, NULL);
370 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
371 return -EPROBE_DEFER;
370 if (!IS_ERR(data->clk)) { 372 if (!IS_ERR(data->clk)) {
371 err = clk_prepare_enable(data->clk); 373 err = clk_prepare_enable(data->clk);
372 if (err) 374 if (err)
@@ -377,15 +379,23 @@ static int dw8250_probe(struct platform_device *pdev)
377 } 379 }
378 380
379 data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 381 data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
382 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
383 err = -EPROBE_DEFER;
384 goto err_clk;
385 }
380 if (!IS_ERR(data->pclk)) { 386 if (!IS_ERR(data->pclk)) {
381 err = clk_prepare_enable(data->pclk); 387 err = clk_prepare_enable(data->pclk);
382 if (err) { 388 if (err) {
383 dev_err(&pdev->dev, "could not enable apb_pclk\n"); 389 dev_err(&pdev->dev, "could not enable apb_pclk\n");
384 return err; 390 goto err_clk;
385 } 391 }
386 } 392 }
387 393
388 data->rst = devm_reset_control_get_optional(&pdev->dev, NULL); 394 data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
395 if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
396 err = -EPROBE_DEFER;
397 goto err_pclk;
398 }
389 if (!IS_ERR(data->rst)) 399 if (!IS_ERR(data->rst))
390 reset_control_deassert(data->rst); 400 reset_control_deassert(data->rst);
391 401
@@ -403,18 +413,21 @@ static int dw8250_probe(struct platform_device *pdev)
403 if (pdev->dev.of_node) { 413 if (pdev->dev.of_node) {
404 err = dw8250_probe_of(&uart.port, data); 414 err = dw8250_probe_of(&uart.port, data);
405 if (err) 415 if (err)
406 return err; 416 goto err_reset;
407 } else if (ACPI_HANDLE(&pdev->dev)) { 417 } else if (ACPI_HANDLE(&pdev->dev)) {
408 err = dw8250_probe_acpi(&uart, data); 418 err = dw8250_probe_acpi(&uart, data);
409 if (err) 419 if (err)
410 return err; 420 goto err_reset;
411 } else { 421 } else {
412 return -ENODEV; 422 err = -ENODEV;
423 goto err_reset;
413 } 424 }
414 425
415 data->line = serial8250_register_8250_port(&uart); 426 data->line = serial8250_register_8250_port(&uart);
416 if (data->line < 0) 427 if (data->line < 0) {
417 return data->line; 428 err = data->line;
429 goto err_reset;
430 }
418 431
419 platform_set_drvdata(pdev, data); 432 platform_set_drvdata(pdev, data);
420 433
@@ -422,6 +435,20 @@ static int dw8250_probe(struct platform_device *pdev)
422 pm_runtime_enable(&pdev->dev); 435 pm_runtime_enable(&pdev->dev);
423 436
424 return 0; 437 return 0;
438
439err_reset:
440 if (!IS_ERR(data->rst))
441 reset_control_assert(data->rst);
442
443err_pclk:
444 if (!IS_ERR(data->pclk))
445 clk_disable_unprepare(data->pclk);
446
447err_clk:
448 if (!IS_ERR(data->clk))
449 clk_disable_unprepare(data->clk);
450
451 return err;
425} 452}
426 453
427static int dw8250_remove(struct platform_device *pdev) 454static int dw8250_remove(struct platform_device *pdev)