diff options
Diffstat (limited to 'drivers/mtd/nand/raw/tegra_nand.c')
| -rw-r--r-- | drivers/mtd/nand/raw/tegra_nand.c | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index fbf67722a049..7f9eb5f042a7 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -17,8 +17,11 @@ #include <linux/mtd/rawnand.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/reset.h> +#include <soc/tegra/common.h> + #define COMMAND 0x00 #define COMMAND_GO BIT(31) #define COMMAND_CLE BIT(30) @@ -1144,7 +1147,6 @@ static int tegra_nand_probe(struct platform_device *pdev) { struct reset_control *rst; struct tegra_nand_controller *ctrl; - struct resource *res; int err = 0; ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); @@ -1152,11 +1154,11 @@ static int tegra_nand_probe(struct platform_device *pdev) return -ENOMEM; ctrl->dev = &pdev->dev; + platform_set_drvdata(pdev, ctrl); nand_controller_init(&ctrl->controller); ctrl->controller.ops = &tegra_nand_controller_ops; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctrl->regs = devm_ioremap_resource(&pdev->dev, res); + ctrl->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctrl->regs)) return PTR_ERR(ctrl->regs); @@ -1168,14 +1170,23 @@ static int tegra_nand_probe(struct platform_device *pdev) if (IS_ERR(ctrl->clk)) return PTR_ERR(ctrl->clk); - err = clk_prepare_enable(ctrl->clk); + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (err) return err; + /* + * This driver doesn't support active power management yet, + * so we will simply keep device resumed. + */ + pm_runtime_enable(&pdev->dev); + err = pm_runtime_resume_and_get(&pdev->dev); + if (err) + goto err_dis_pm; + err = reset_control_reset(rst); if (err) { dev_err(ctrl->dev, "Failed to reset HW: %d\n", err); - goto err_disable_clk; + goto err_put_pm; } writel_relaxed(HWSTATUS_CMD_DEFAULT, ctrl->regs + HWSTATUS_CMD); @@ -1186,46 +1197,75 @@ static int tegra_nand_probe(struct platform_device *pdev) init_completion(&ctrl->dma_complete); ctrl->irq = platform_get_irq(pdev, 0); + if (ctrl->irq < 0) { + err = ctrl->irq; + goto err_put_pm; + } err = devm_request_irq(&pdev->dev, ctrl->irq, tegra_nand_irq, 0, dev_name(&pdev->dev), ctrl); if (err) { dev_err(ctrl->dev, "Failed to get IRQ: %d\n", err); - goto err_disable_clk; + goto err_put_pm; } writel_relaxed(DMA_MST_CTRL_IS_DONE, ctrl->regs + DMA_MST_CTRL); err = tegra_nand_chips_init(ctrl->dev, ctrl); if (err) - goto err_disable_clk; - - platform_set_drvdata(pdev, ctrl); + goto err_put_pm; return 0; -err_disable_clk: - clk_disable_unprepare(ctrl->clk); +err_put_pm: + pm_runtime_put_sync_suspend(ctrl->dev); + pm_runtime_force_suspend(ctrl->dev); +err_dis_pm: + pm_runtime_disable(&pdev->dev); return err; } -static int tegra_nand_remove(struct platform_device *pdev) +static void tegra_nand_remove(struct platform_device *pdev) { struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev); struct nand_chip *chip = ctrl->chip; struct mtd_info *mtd = nand_to_mtd(chip); - int ret; - ret = mtd_device_unregister(mtd); - if (ret) - return ret; + WARN_ON(mtd_device_unregister(mtd)); nand_cleanup(chip); + pm_runtime_put_sync_suspend(ctrl->dev); + pm_runtime_force_suspend(ctrl->dev); +} + +static int __maybe_unused tegra_nand_runtime_resume(struct device *dev) +{ + struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(ctrl->clk); + if (err) { + dev_err(dev, "Failed to enable clock: %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra_nand_runtime_suspend(struct device *dev) +{ + struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); + clk_disable_unprepare(ctrl->clk); return 0; } +static const struct dev_pm_ops tegra_nand_pm = { + SET_RUNTIME_PM_OPS(tegra_nand_runtime_suspend, tegra_nand_runtime_resume, + NULL) +}; + static const struct of_device_id tegra_nand_of_match[] = { { .compatible = "nvidia,tegra20-nand" }, { /* sentinel */ } @@ -1236,6 +1276,7 @@ static struct platform_driver tegra_nand_driver = { .driver = { .name = "tegra-nand", .of_match_table = tegra_nand_of_match, + .pm = &tegra_nand_pm, }, .probe = tegra_nand_probe, .remove = tegra_nand_remove, |
