예제 #1
0
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			err = 0;
		}
	}
	mmc_bus_put(host);

	return err;
}
예제 #2
0
/* Do the card removal on suspend if card is assumed removeable
 * Do that in pm notifier while userspace isn't yet frozen, so we will be able
   to sync the card.
*/
int mmc_pm_notify(struct notifier_block *notify_block,
					unsigned long mode, void *unused)
{
	struct mmc_host *host = container_of(
		notify_block, struct mmc_host, pm_notify);
	unsigned long flags;


	switch (mode) {
	case PM_HIBERNATION_PREPARE:
	case PM_SUSPEND_PREPARE:
		// work around for WiFi issue
		if (__mmc_is_claimed(host)) {
			dev_err(&host->class_dev, "Failed to claim host %d in %lu, aborting suspend", host->index, mode);
			return NOTIFY_BAD;
		}

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_needs_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 1;
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);

		if (!host->bus_ops || host->bus_ops->suspend)
			break;

		mmc_claim_host(host);

		if (host->bus_ops->remove)
			host->bus_ops->remove(host);

		mmc_detach_bus(host);
		mmc_release_host(host);
		host->pm_flags = 0;
		break;

	case PM_POST_SUSPEND:
	case PM_POST_HIBERNATION:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_manual_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 0;
		spin_unlock_irqrestore(&host->lock, flags);
		mmc_detect_change(host, 0);

	}

	return 0;
}
예제 #3
0
/* Do the card removal on suspend if card is assumed removeable
 * Do that in pm notifier while userspace isn't yet frozen, so we will be able
   to sync the card.
*/
int mmc_pm_notify(struct notifier_block *notify_block,
					unsigned long mode, void *unused)
{
	struct mmc_host *host = container_of(
		notify_block, struct mmc_host, pm_notify);
	unsigned long flags;


	switch (mode) {
	case PM_HIBERNATION_PREPARE:
	case PM_SUSPEND_PREPARE:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_needs_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 1;
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);

		if (!host->bus_ops || host->bus_ops->suspend)
			break;

		mmc_claim_host(host);

		if (host->bus_ops->remove)
			host->bus_ops->remove(host);

		mmc_detach_bus(host);
		mmc_power_off(host);
		mmc_release_host(host);
		host->pm_flags = 0;
		break;

	case PM_POST_SUSPEND:
	case PM_POST_HIBERNATION:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_manual_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 0;
		spin_unlock_irqrestore(&host->lock, flags);
		if (!host->card || host->card->type
			!= MMC_TYPE_SDIO)

/*skip mmc_detect_change for sdio*/

		    mmc_detect_change(host, 0);
	}

	return 0;
}
예제 #4
0
파일: core.c 프로젝트: CL0SeY/i957kernel
/* Do the card removal on suspend if card is assumed removeable
 * Do that in pm notifier while userspace isn't yet frozen, so we will be able
 * to sync the card.
 */
int mmc_pm_notify(struct notifier_block *notify_block,
					unsigned long mode, void *unused)
{
	struct mmc_host *host = container_of(
		notify_block, struct mmc_host, pm_notify);
	unsigned long flags;

	switch (mode) {
	case PM_HIBERNATION_PREPARE:
	case PM_SUSPEND_PREPARE:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_needs_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 1;
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);

		if (!host->bus_ops || host->bus_ops->suspend)
			break;

		if (host->bus_ops->remove)
			host->bus_ops->remove(host);
		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_release_host(host);
		break;

	case PM_POST_SUSPEND:
	case PM_POST_HIBERNATION:
	case PM_POST_RESTORE:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_manual_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 0;
		spin_unlock_irqrestore(&host->lock, flags);
#ifdef BROADCOM_WIFI // for broadcomm wifi
		if (host->card && host->index == 2) // for broadcomm wifi
			printk("CORE : mmc_pm_notify WLAN SKIP DETECT CHANGE\n");
		else
#endif
			mmc_detect_change(host, 0);
	}

	return 0;
}
예제 #5
0
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
#ifdef CONFIG_ATH_WIFI
		if (!host->suspend_keep_power) {
#endif		
		mmc_power_up(host);
		mmc_select_voltage(host, host->ocr);
#ifdef CONFIG_ATH_WIFI
		}
#endif		
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			err = 0;
		}
	}
	mmc_bus_put(host);
#if defined(CONFIG_ATH_WIFI) || defined(CONFIG_BCM_WIFI)
	if (host->index == ATH_WIFI_SDCC_INDEX) {		
		pr_info("%s: mmc_resume_host in wifi slot skip cmd7\n",   mmc_hostname(host));
		return err;
	}
#endif 

	/*
	 * We add a slight delay here so that resume can progress
	 * in parallel.
	 */
	mmc_detect_change(host, 1);

	return err;
}
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!mmc_card_keep_power(host)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
			/*
			 * Tell runtime PM core we just powered up the card,
			 * since it still believes the card is powered off.
			 * Note that currently runtime PM is only enabled
			 * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
			 */
			if (mmc_card_sdio(host->card) &&
				(host->caps & MMC_CAP_POWER_OFF_CARD)) {
				pm_runtime_disable(&host->card->dev);
				pm_runtime_set_active(&host->card->dev);
				pm_runtime_enable(&host->card->dev);
			}
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			err = 0;
		}
	}

	/* clear flag */
	host->pm_flags &= ~MMC_PM_KEEP_POWER;
	
	mmc_bus_put(host);

	return err;
}
예제 #7
0
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			#if 0
			if (host->bus_ops->remove)
				host->bus_ops->remove(host);
			mmc_claim_host(host);
			mmc_detach_bus(host);
			mmc_release_host(host);
			/* no need to bother upper layers */
			#endif
			err = 0;
		}
	}
	mmc_bus_put(host);

	/*
	 * We add a slight delay here so that resume can progress
	 * in parallel.
	 */
	if (!(host->pm_flags & MMC_PM_KEEP_POWER))
		mmc_detect_change(host, 1);

	return err;
}
예제 #8
0
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			err = 0;
		}
	}
	mmc_bus_put(host);

	/*
	 * We add a slight delay here so that resume can progress
	 * in parallel.
	 */
#if 1 /* ATHENV */
	if (!host->card || host->card->type != MMC_TYPE_SDIO) 
#endif /* ATHENV */
#if 1//PMMC
	;
#else//ORG
	mmc_detect_change(host, 2);
#endif//PMMC

	return err;
}
예제 #9
0
/**
 *	mmc_suspend_host - suspend a host
 *	@host: mmc host
 */
int mmc_suspend_host(struct mmc_host *host)
{
	int err = 0;

	if (mmc_bus_needs_resume(host))
		return 0;

	if (host->caps & MMC_CAP_DISABLE)
		cancel_delayed_work(&host->disable);
	cancel_delayed_work(&host->detect);
	mmc_flush_scheduled_work();

	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {
		if (host->bus_ops->suspend)
			err = host->bus_ops->suspend(host);
		if (err == -ENOSYS || !host->bus_ops->resume) {
			/*
			 * We simply "remove" the card in this case.
			 * It will be redetected on resume.
			 */
			if (host->bus_ops->remove)
				host->bus_ops->remove(host);
			mmc_claim_host(host);
			mmc_detach_bus(host);
			mmc_release_host(host);
			host->pm_flags = 0;
			err = 0;
		}
	}
#ifdef CONFIG_PM_RUNTIME
	if (mmc_bus_manual_resume(host))
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
#endif
	mmc_bus_put(host);

	if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
		mmc_power_off(host);

	return err;
}
예제 #10
0
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) 
		{
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			err = 0;
		}
	}

	if(!strncmp(mmc_hostname(host),"mmc1",4))
	{
		memcpy(&host->ios,&ios_backup,sizeof(struct mmc_ios));
		mmc_set_ios(host);
		printk("\n(IOS restore)\n%s: clock %uHz busmode %u powermode %u cs %u Vdd %u  width %u timing %u\n",mmc_hostname(host), ios_backup.clock, ios_backup.bus_mode,ios_backup.power_mode, ios_backup.chip_select, ios_backup.vdd,ios_backup.bus_width, ios_backup.timing);
	}
	
	mmc_bus_put(host);

	return err;
}
예제 #11
0
파일: core.c 프로젝트: CL0SeY/i957kernel
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			struct mmc_ios *ios = &host->ios;
			
			//temporary debug code
			pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
						"width %u timing %u\n",
						 mmc_hostname(host), ios->clock, ios->bus_mode,
						 ios->power_mode, ios->chip_select, ios->vdd,
						 ios->bus_width, ios->timing);
			
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
			
			err = 0;
		}
	}
	mmc_bus_put(host);

	return err;
}
예제 #12
0
/**
 *	mmc_suspend_host - suspend a host
 *	@host: mmc host
 */
int mmc_suspend_host(struct mmc_host *host)
{
	int err = 0;

	if (mmc_bus_needs_resume(host))
		return 0;

	if (host->caps & MMC_CAP_DISABLE)
		cancel_delayed_work(&host->disable);
	cancel_delayed_work(&host->detect);
	mmc_flush_scheduled_work();

	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {

		/*
		 * A long response time is not acceptable for device drivers
		 * when doing suspend. Prevent mmc_claim_host in the suspend
		 * sequence, to potentially wait "forever" by trying to
		 * pre-claim the host.
		 *
		 * Skip try claim host for SDIO cards, doing so fixes deadlock
		 * conditions. The function driver suspend may again call into
		 * SDIO driver within a different context for enabling power
		 * save mode in the card and hence wait in mmc_claim_host
		 * causing deadlock.
		 */
		if (!(host->card && mmc_card_sdio(host->card)))
			if (!mmc_try_claim_host(host))
				err = -EBUSY;

		if (!err) {
			if (host->bus_ops->suspend)
				err = host->bus_ops->suspend(host);
			if (!(host->card && mmc_card_sdio(host->card)))
				mmc_do_release_host(host);

			if (err == -ENOSYS || !host->bus_ops->resume) {
				/*
				 * We simply "remove" the card in this case.
				 * It will be redetected on resume.
				 */
				if (host->bus_ops->remove)
					host->bus_ops->remove(host);
				mmc_claim_host(host);
				mmc_detach_bus(host);
				mmc_power_off(host);
				mmc_release_host(host);
				host->pm_flags = 0;
				err = 0;
			}
		}
	}
#ifdef CONFIG_PM_RUNTIME
	if (mmc_bus_manual_resume(host))
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
#endif
	mmc_bus_put(host);

	if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
		mmc_power_off(host);

	return err;
}
예제 #13
0
/* Do the card removal on suspend if card is assumed removeable
 * Do that in pm notifier while userspace isn't yet frozen, so we will be able
 * to sync the card.
 */
int mmc_pm_notify(struct notifier_block *notify_block,
					unsigned long mode, void *unused)
{
	struct mmc_host *host = container_of(
		notify_block, struct mmc_host, pm_notify);
	unsigned long flags;

	switch (mode) {
	case PM_HIBERNATION_PREPARE:
	case PM_SUSPEND_PREPARE:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_needs_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 1;
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);

		if (!host->bus_ops || host->bus_ops->suspend)
			break;

		if (host->bus_ops->remove)
			host->bus_ops->remove(host);
		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_release_host(host);
		break;

	case PM_POST_SUSPEND:
	case PM_POST_HIBERNATION:

		spin_lock_irqsave(&host->lock, flags);
		if (mmc_bus_manual_resume(host)) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		host->rescan_disable = 0;
		spin_unlock_irqrestore(&host->lock, flags);
#if defined(CONFIG_MACH_ACER_A4) || defined(CONFIG_MACH_ACER_A5)
		printk("*** %s: trigger polling\n", __func__);
		if (host && host->card && host->card->cis.vendor == ATHR_MANUF_CODE) {
			printk("*** %s: WIFI slot. Skip detect.\n", __func__);
			return 0;
		}
#endif
#if defined(CONFIG_MACH_ACER_A4)
		if (host && !strcmp(mmc_hostname(host), "mmc1")) {
			pr_info("*** %s: mmc1. Skip detect.\n", __func__);
			return 0;
		}
#endif
#if defined(CONFIG_MACH_ACER_A5)
		if (host && !strcmp(mmc_hostname(host), "mmc0")) {
			pr_info("*** %s: mmc0 slot. Skip detect.\n", __func__);
			return 0;
		}
		if (host && !strcmp(mmc_hostname(host), "mmc2")) {
			pr_info("*** %s: mmc2 slot. Skip detect.\n", __func__);
			return 0;
		}
#endif
		mmc_detect_change(host, 0);
	}

	return 0;
}
예제 #14
0
/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
	int err = 0;

	mmc_bus_get(host);
	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		mmc_bus_put(host);
		return 0;
	}

	if (host->bus_ops && !host->bus_dead) {
		if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
			mmc_power_up(host);
			mmc_select_voltage(host, host->ocr);
		}
		BUG_ON(!host->bus_ops->resume);
		err = host->bus_ops->resume(host);
		if (err) {
			printk(KERN_WARNING "%s: error %d during resume "
					    "(card was removed?)\n",
					    mmc_hostname(host), err);
#if defined(CONFIG_MACH_ACER_A4) || defined(CONFIG_MACH_ACER_A5)
			if (host->bus_ops->remove)
				host->bus_ops->remove(host);
			mmc_claim_host(host);
			mmc_detach_bus(host);
			mmc_release_host(host);
			/* no need to bother upper layers */
#endif
			err = 0;
		}
	}
	mmc_bus_put(host);

#if defined(CONFIG_MACH_ACER_A4) || defined(CONFIG_MACH_ACER_A5)
/* ATHENV */
	if (host && host->card) {
		struct mmc_card *card = host->card;
		if (card->cis.vendor == ATHR_MANUF_CODE) {
		/* WIFI doesn't need to detect again. */
		return 0;
		 }
	}
/* ATHENV */
#endif
#if defined(CONFIG_MACH_ACER_A4)
	if (host && !strcmp(mmc_hostname(host), "mmc1")) {
		pr_info("*** %s: mmc1. Skip detect.\n", __func__);
		return 0;
	}
#endif
#if defined(CONFIG_MACH_ACER_A5)
	if (host && !strcmp(mmc_hostname(host), "mmc0")) {
		pr_info("*** %s: mmc0. Skip detect.\n", __func__);
		return 0;
	}
	if (host && !strcmp(mmc_hostname(host), "mmc2")) {
		pr_info("*** %s: mmc2. Skip detect.\n", __func__);
		return 0;
	}
#endif

	return err;
}