Skip to content

Commit

Permalink
mtd: sh_flctl: Add power management with QoS request
Browse files Browse the repository at this point in the history
Adds power management code with fine granularity. Every flash control
command is enclosed by runtime_put()/get()s. To make sure that no
overhead is generated by too frequent power state switches, a quality of
service request is issued.

Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
Bastian Hecht authored and David Woodhouse committed Mar 26, 2012
1 parent 42d7fbe commit cfe7819
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 9 deletions.
51 changes: 42 additions & 9 deletions drivers/mtd/nand/sh_flctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>

#include <linux/mtd/mtd.h>
Expand Down Expand Up @@ -515,6 +516,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
struct sh_flctl *flctl = mtd_to_flctl(mtd);
uint32_t read_cmd = 0;

pm_runtime_get_sync(&flctl->pdev->dev);

flctl->read_bytes = 0;
if (command != NAND_CMD_PAGEPROG)
flctl->index = 0;
Expand Down Expand Up @@ -670,31 +673,55 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
default:
break;
}
return;
goto runtime_exit;

read_normal_exit:
writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
empty_fifo(flctl);
start_translation(flctl);
read_fiforeg(flctl, flctl->read_bytes, 0);
wait_completion(flctl);
runtime_exit:
pm_runtime_put_sync(&flctl->pdev->dev);
return;
}

static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int ret;

switch (chipnr) {
case -1:
flctl->flcmncr_base &= ~CE0_ENABLE;

pm_runtime_get_sync(&flctl->pdev->dev);
writel(flctl->flcmncr_base, FLCMNCR(flctl));

if (flctl->qos_request) {
dev_pm_qos_remove_request(&flctl->pm_qos);
flctl->qos_request = 0;
}

pm_runtime_put_sync(&flctl->pdev->dev);
break;
case 0:
flctl->flcmncr_base |= CE0_ENABLE;
writel(flctl->flcmncr_base, FLCMNCR(flctl));
if (flctl->holden)

if (!flctl->qos_request) {
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
&flctl->pm_qos, 100);
if (ret < 0)
dev_err(&flctl->pdev->dev,
"PM QoS request failed: %d\n", ret);
flctl->qos_request = 1;
}

if (flctl->holden) {
pm_runtime_get_sync(&flctl->pdev->dev);
writel(HOLDEN, FLHOLDCR(flctl));
pm_runtime_put_sync(&flctl->pdev->dev);
}
break;
default:
BUG();
Expand Down Expand Up @@ -835,13 +862,13 @@ static int __devinit flctl_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
goto err;
goto err_iomap;
}

flctl->reg = ioremap(res->start, resource_size(res));
if (flctl->reg == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
goto err;
goto err_iomap;
}

platform_set_drvdata(pdev, flctl);
Expand Down Expand Up @@ -871,23 +898,28 @@ static int __devinit flctl_probe(struct platform_device *pdev)
nand->read_word = flctl_read_word;
}

pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);

ret = nand_scan_ident(flctl_mtd, 1, NULL);
if (ret)
goto err;
goto err_chip;

ret = flctl_chip_init_tail(flctl_mtd);
if (ret)
goto err;
goto err_chip;

ret = nand_scan_tail(flctl_mtd);
if (ret)
goto err;
goto err_chip;

mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);

return 0;

err:
err_chip:
pm_runtime_disable(&pdev->dev);
err_iomap:
kfree(flctl);
return ret;
}
Expand All @@ -897,6 +929,7 @@ static int __devexit flctl_remove(struct platform_device *pdev)
struct sh_flctl *flctl = platform_get_drvdata(pdev);

nand_release(&flctl->mtd);
pm_runtime_disable(&pdev->dev);
kfree(flctl);

return 0;
Expand Down
3 changes: 3 additions & 0 deletions include/linux/mtd/sh_flctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/pm_qos.h>

/* FLCTL registers */
#define FLCMNCR(f) (f->reg + 0x0)
Expand Down Expand Up @@ -131,6 +132,7 @@ struct sh_flctl {
struct mtd_info mtd;
struct nand_chip chip;
struct platform_device *pdev;
struct dev_pm_qos_request pm_qos;
void __iomem *reg;

uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
Expand All @@ -149,6 +151,7 @@ struct sh_flctl {
unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */
unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */
unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */
unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
};

struct sh_flctl_platform_data {
Expand Down

0 comments on commit cfe7819

Please sign in to comment.