summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/raw/renesas-nand-controller.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/renesas-nand-controller.c')
-rw-r--r--drivers/mtd/nand/raw/renesas-nand-controller.c78
1 files changed, 37 insertions, 41 deletions
diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c
index 428e08362956..201dd62b9990 100644
--- a/drivers/mtd/nand/raw/renesas-nand-controller.c
+++ b/drivers/mtd/nand/raw/renesas-nand-controller.c
@@ -16,6 +16,7 @@
#include <linux/mtd/rawnand.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#define COMMAND_REG 0x00
@@ -209,15 +210,14 @@ struct rnand_chip {
u32 tim_gen_seq1;
u32 tim_gen_seq2;
u32 tim_gen_seq3;
- struct rnand_chip_sel sels[];
+ struct rnand_chip_sel sels[] __counted_by(nsels);
};
struct rnandc {
struct nand_controller controller;
struct device *dev;
void __iomem *regs;
- struct clk *hclk;
- struct clk *eclk;
+ unsigned long ext_clk_rate;
unsigned long assigned_cs;
struct list_head chips;
struct nand_chip *selected_chip;
@@ -426,6 +426,9 @@ static int rnandc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
/* Configure DMA */
dma_addr = dma_map_single(rnandc->dev, rnandc->buf, mtd->writesize,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(rnandc->dev, dma_addr))
+ return -ENOMEM;
+
writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
@@ -606,6 +609,9 @@ static int rnandc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
/* Configure DMA */
dma_addr = dma_map_single(rnandc->dev, (void *)rnandc->buf, mtd->writesize,
DMA_TO_DEVICE);
+ if (dma_mapping_error(rnandc->dev, dma_addr))
+ return -ENOMEM;
+
writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
@@ -891,7 +897,7 @@ static int rnandc_setup_interface(struct nand_chip *chip, int chipnr,
{
struct rnand_chip *rnand = to_rnand(chip);
struct rnandc *rnandc = to_rnandc(chip->controller);
- unsigned int period_ns = 1000000000 / clk_get_rate(rnandc->eclk);
+ unsigned int period_ns = 1000000000 / rnandc->ext_clk_rate;
const struct nand_sdr_timings *sdr;
unsigned int cyc, cle, ale, bef_dly, ca_to_data;
@@ -1297,28 +1303,23 @@ static void rnandc_chips_cleanup(struct rnandc *rnandc)
static int rnandc_chips_init(struct rnandc *rnandc)
{
- struct device_node *np;
int ret;
- for_each_child_of_node(rnandc->dev->of_node, np) {
+ for_each_child_of_node_scoped(rnandc->dev->of_node, np) {
ret = rnandc_chip_init(rnandc, np);
if (ret) {
- of_node_put(np);
- goto cleanup_chips;
+ rnandc_chips_cleanup(rnandc);
+ return ret;
}
}
return 0;
-
-cleanup_chips:
- rnandc_chips_cleanup(rnandc);
-
- return ret;
}
static int rnandc_probe(struct platform_device *pdev)
{
struct rnandc *rnandc;
+ struct clk *eclk;
int irq, ret;
rnandc = devm_kzalloc(&pdev->dev, sizeof(*rnandc), GFP_KERNEL);
@@ -1335,29 +1336,29 @@ static int rnandc_probe(struct platform_device *pdev)
if (IS_ERR(rnandc->regs))
return PTR_ERR(rnandc->regs);
- /* APB clock */
- rnandc->hclk = devm_clk_get(&pdev->dev, "hclk");
- if (IS_ERR(rnandc->hclk))
- return PTR_ERR(rnandc->hclk);
-
- /* External NAND bus clock */
- rnandc->eclk = devm_clk_get(&pdev->dev, "eclk");
- if (IS_ERR(rnandc->eclk))
- return PTR_ERR(rnandc->eclk);
-
- ret = clk_prepare_enable(rnandc->hclk);
+ ret = devm_pm_runtime_enable(&pdev->dev);
if (ret)
return ret;
- ret = clk_prepare_enable(rnandc->eclk);
- if (ret)
- goto disable_hclk;
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ /* The external NAND bus clock rate is needed for computing timings */
+ eclk = clk_get(&pdev->dev, "eclk");
+ if (IS_ERR(eclk)) {
+ ret = PTR_ERR(eclk);
+ goto dis_runtime_pm;
+ }
+
+ rnandc->ext_clk_rate = clk_get_rate(eclk);
+ clk_put(eclk);
rnandc_dis_interrupts(rnandc);
irq = platform_get_irq_optional(pdev, 0);
if (irq == -EPROBE_DEFER) {
ret = irq;
- goto disable_eclk;
+ goto dis_runtime_pm;
} else if (irq < 0) {
dev_info(&pdev->dev, "No IRQ found, fallback to polling\n");
rnandc->use_polling = true;
@@ -1365,12 +1366,12 @@ static int rnandc_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, rnandc_irq_handler, 0,
"renesas-nand-controller", rnandc);
if (ret < 0)
- goto disable_eclk;
+ goto dis_runtime_pm;
}
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
- goto disable_eclk;
+ goto dis_runtime_pm;
rnandc_clear_fifo(rnandc);
@@ -1378,28 +1379,23 @@ static int rnandc_probe(struct platform_device *pdev)
ret = rnandc_chips_init(rnandc);
if (ret)
- goto disable_eclk;
+ goto dis_runtime_pm;
return 0;
-disable_eclk:
- clk_disable_unprepare(rnandc->eclk);
-disable_hclk:
- clk_disable_unprepare(rnandc->hclk);
+dis_runtime_pm:
+ pm_runtime_put(&pdev->dev);
return ret;
}
-static int rnandc_remove(struct platform_device *pdev)
+static void rnandc_remove(struct platform_device *pdev)
{
struct rnandc *rnandc = platform_get_drvdata(pdev);
rnandc_chips_cleanup(rnandc);
- clk_disable_unprepare(rnandc->eclk);
- clk_disable_unprepare(rnandc->hclk);
-
- return 0;
+ pm_runtime_put(&pdev->dev);
}
static const struct of_device_id rnandc_id_table[] = {
@@ -1412,7 +1408,7 @@ MODULE_DEVICE_TABLE(of, rnandc_id_table);
static struct platform_driver rnandc_driver = {
.driver = {
.name = "renesas-nandc",
- .of_match_table = of_match_ptr(rnandc_id_table),
+ .of_match_table = rnandc_id_table,
},
.probe = rnandc_probe,
.remove = rnandc_remove,