Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eda002fc authored by Tatyana Brokhman's avatar Tatyana Brokhman Committed by Stephen Boyd
Browse files

mmc: Add long power off notification support



At the moment only POWER_OFF_SHORT is sent to the device in case the host
is suspended. This patch adds the support of sending POWER_OFF_LONG
notification in case the device is powered off.

According to device vendors the POWER_OFF_LONG notification will shorten
the initialization time of the eMMC card during next boot up.

Change-Id: I3c6f224398450cf10463cbb316613fd430d1e8d2
Signed-off-by: default avatarTatyana Brokhman <tlinder@codeaurora.org>
Signed-off-by: default avatarSujit Reddy Thumma <sthumma@codeaurora.org>
parent 65ecad44
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -3204,6 +3204,37 @@ static void mmc_blk_remove(struct mmc_card *card)
#endif
}

static void mmc_blk_shutdown(struct mmc_card *card)
{
	struct mmc_blk_data *part_md;
	struct mmc_blk_data *md = mmc_get_drvdata(card);
	int rc;

	/* Silent the block layer */
	if (md) {
		rc = mmc_queue_suspend(&md->queue);
		if (rc)
			goto suspend_error;
		list_for_each_entry(part_md, &md->part, part) {
			rc = mmc_queue_suspend(&part_md->queue);
			if (rc)
				goto suspend_error;
		}
	}

	/* send power off notification */
	if (mmc_card_mmc(card)) {
		mmc_rpm_hold(card->host, &card->dev);
		mmc_send_long_pon(card);
		mmc_rpm_release(card->host, &card->dev);
	}
	return;

suspend_error:
	pr_err("%s: mmc_queue_suspend returned error = %d",
			mmc_hostname(card->host), rc);
}

#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
{
@@ -3263,6 +3294,7 @@ static struct mmc_driver mmc_driver = {
	.remove		= mmc_blk_remove,
	.suspend	= mmc_blk_suspend,
	.resume		= mmc_blk_resume,
	.shutdown	= mmc_blk_shutdown,
};

static int __init mmc_blk_init(void)
+10 −0
Original line number Diff line number Diff line
@@ -123,6 +123,15 @@ static int mmc_bus_remove(struct device *dev)
	return 0;
}

static void mmc_bus_shutdown(struct device *dev)
{
	struct mmc_driver *drv = to_mmc_driver(dev->driver);
	struct mmc_card *card = mmc_dev_to_card(dev);

	if (drv->shutdown)
		drv->shutdown(card);
}

#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
@@ -246,6 +255,7 @@ static struct bus_type mmc_bus_type = {
	.uevent		= mmc_bus_uevent,
	.probe		= mmc_bus_probe,
	.remove		= mmc_bus_remove,
	.shutdown        = mmc_bus_shutdown,
	.pm		= &mmc_bus_pm_ops,
};

+35 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/pm_runtime.h>
#include <linux/reboot.h>

#include "core.h"
#include "bus.h"
@@ -906,6 +907,20 @@ out:
	return err;
}

static int mmc_reboot_notify(struct notifier_block *notify_block,
		unsigned long event, void *unused)
{
	struct mmc_card *card = container_of(
			notify_block, struct mmc_card, reboot_notify);

	if (event != SYS_RESTART)
		card->issue_long_pon = true;
	else
		card->issue_long_pon = false;

	return NOTIFY_OK;
}

/*
 * Handle the detection and initialisation of a card.
 *
@@ -982,6 +997,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		card->type = MMC_TYPE_MMC;
		card->rca = 1;
		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
		card->reboot_notify.notifier_call = mmc_reboot_notify;
	}

	/*
@@ -1468,6 +1484,22 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
	return err;
}

int mmc_send_long_pon(struct mmc_card *card)
{
	int err = 0;
	struct mmc_host *host = card->host;

	mmc_claim_host(host);
	if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
		err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
		if (err)
			pr_warning("%s: error %d sending Long PON",
					mmc_hostname(host), err);
	}
	mmc_release_host(host);
	return err;
}

/*
 * Host is being removed. Free up the current card.
 */
@@ -1476,6 +1508,7 @@ static void mmc_remove(struct mmc_host *host)
	BUG_ON(!host);
	BUG_ON(!host->card);

	unregister_reboot_notifier(&host->card->reboot_notify);
	mmc_remove_card(host->card);

	mmc_claim_host(host);
@@ -1743,6 +1776,8 @@ int mmc_attach_mmc(struct mmc_host *host)

	mmc_init_clk_scaling(host);

	register_reboot_notifier(&host->card->reboot_notify);

	return 0;

remove_card:
+5 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mmc/core.h>
#include <linux/mod_devicetable.h>
#include <linux/notifier.h>

struct mmc_cid {
	unsigned int		manfid;
@@ -386,6 +387,8 @@ struct mmc_card {

	struct device_attribute rpm_attrib;
	unsigned int		idle_timeout;
	struct notifier_block        reboot_notify;
	bool issue_long_pon;
};

/*
@@ -606,6 +609,7 @@ struct mmc_driver {
	void (*remove)(struct mmc_card *);
	int (*suspend)(struct mmc_card *);
	int (*resume)(struct mmc_card *);
	void (*shutdown)(struct mmc_card *);
};

extern int mmc_register_driver(struct mmc_driver *);
@@ -617,4 +621,5 @@ extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
			struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
extern int mmc_send_long_pon(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */