/** * 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; }
/* 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; }
/* 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; }
/* 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
/** * 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; }
/** * 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; }
/* 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; }
/** * 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; }