static void sprd_sdio_card_remove(struct mmc_card *card) { struct mmc_host *host = card->host; if (mmc_card_sdio(card)) { if(host->caps & MMC_CAP_POWER_OFF_CARD) { pm_suspend_ignore_children(mmc_classdev(host), true); pm_runtime_idle(mmc_classdev(host)); } } }
static void sprd_sdio_card_remove(struct mmc_card *card) { struct mmc_host *host = card->host; if (mmc_card_sdio(card)) { if(host->caps & MMC_CAP_POWER_OFF_CARD) { pm_suspend_ignore_children(mmc_classdev(host), true); // avoid mmc_attach_sdio->pm_runtime_set_active returning with error -16 pm_runtime_idle(mmc_classdev(host)); // make platform devices runtime suspendable } } }
static int sprd_sdio_card_probe(struct mmc_card *card) { struct mmc_host *host = card->host; if (mmc_card_sdio(card)) { if(host->caps & MMC_CAP_POWER_OFF_CARD) { pm_runtime_no_callbacks(&card->dev); pm_suspend_ignore_children(mmc_classdev(host), false); return 0; } } return -EINVAL; }
static int sprd_sdio_card_probe(struct mmc_card *card) { struct mmc_host *host = card->host; if (mmc_card_sdio(card)) { if(host->caps & MMC_CAP_POWER_OFF_CARD) { pm_runtime_no_callbacks(&card->dev); // avoid default sdio bus runtime calling pm_suspend_ignore_children(mmc_classdev(host), false); // paired with remove function } return 0; } return -EINVAL; }
/* * Allocate and initialise a new MMC card structure. */ struct mmc_card *mmc_alloc_card(struct mmc_host *host) { struct mmc_card *card; card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); if (!card) return ERR_PTR(-ENOMEM); card->host = host; device_initialize(&card->dev); card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; return card; }
/* * Allocate and initialise a new MMC card structure. */ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) { struct mmc_card *card; card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); if (!card) return ERR_PTR(-ENOMEM); card->host = host; device_initialize(&card->dev); card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; card->dev.type = type; spin_lock_init(&card->wr_pack_stats.lock); return card; }
/* * Allocate and initialise a new MMC card structure. */ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) { struct mmc_card *card; DBG("[%s] s\n",__func__); card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); if (!card) { DBG("[%s] e1\n",__func__); return ERR_PTR(-ENOMEM); } card->host = host; device_initialize(&card->dev); card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; card->dev.type = type; DBG("[%s] e2\n",__func__); return card; }
static int __devinit sdhci_sprd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sdhci_host *host; struct resource *res; int ret, irq; #ifdef CONFIG_MMC_CARD_HOTPLUG int sd_detect_gpio; int detect_irq; #endif struct sprd_host_data *host_data; irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "no irq specified\n"); return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no memory specified\n"); return -ENOENT; } if(pdev->id == 0) { sd_buffer_pre_alloc(); } host = sdhci_alloc_host(dev, sizeof(struct sprd_host_data)); if (IS_ERR(host)) { dev_err(dev, "sdhci_alloc_host() failed\n"); return PTR_ERR(host); } host_data = sdhci_priv(host); host_data->platdata = dev_get_platdata(dev); host_data->clk_enable = 0; BUG_ON(NULL == host_data->platdata); printk("sdio probe %s, vdd %s (%d), clk %s parent %s\n", host_data->platdata->hw_name, host_data->platdata->vdd_name, host_data->platdata->volt_level, host_data->platdata->clk_name, host_data->platdata->clk_parent); platform_set_drvdata(pdev, host); host->vmmc = NULL; host->vmmc_ext = NULL; host->ioaddr = (void __iomem *)res->start; printk("sdio: host->ioaddr:0x%x\n", (u32)host->ioaddr); host->hw_name = (host_data->platdata->hw_name)? host_data->platdata->hw_name:pdev->name; host->ops = &sdhci_sprd_ops; host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |\ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |\ SDHCI_QUIRK_BROKEN_CARD_DETECTION|\ SDHCI_QUIRK_INVERTED_WRITE_PROTECT; host->irq = irq; #ifdef CONFIG_MMC_CARD_HOTPLUG sd_detect_gpio = host_data->platdata->detect_gpio; if(sd_detect_gpio > 0){ pr_info("%s, sd_detect_gpio:%d\n", __func__, sd_detect_gpio); if (0 == pdev->id){ ret = gpio_request(sd_detect_gpio, "sdio0_detect"); }else{ ret = gpio_request(sd_detect_gpio, "sdio1_detect"); } if (ret) { dev_err(dev, "cannot request gpio\n"); return -1; } ret = gpio_direction_input(sd_detect_gpio); if (ret) { dev_err(dev, "gpio can not change to input\n"); return -1; } detect_irq = gpio_to_irq(sd_detect_gpio); if (detect_irq < 0){ dev_err(dev, "cannot alloc detect irq\n"); return -1; } host_data->detect_irq = detect_irq; }else if (host_data->platdata->register_status_notify) { host_data->platdata->register_status_notify(sdhci_status_notify_cb, host); } else if (!host_data->platdata->status) { printk("%s: No card detect facilities available\n", mmc_hostname(host->mmc)); }else{ printk("%s, sd_detect_gpio == 0 \n", __func__ ); } #endif if(host_data->platdata->vdd_name) { host->vmmc = regulator_get(NULL, host_data->platdata->vdd_name); BUG_ON(IS_ERR(host->vmmc)); if(!is_sd_slot(host)) regulator_enable(host->vmmc); } if(host_data->platdata->vdd_ext_name) { host->vmmc_ext = regulator_get(NULL, host_data->platdata->vdd_ext_name); BUG_ON(IS_ERR(host->vmmc_ext)); regulator_enable(host->vmmc_ext); } host->clk = NULL; sdhci_module_init(host); switch(pdev->id) { case 0: host->mmc->pm_flags |= MMC_PM_ONLY_USED_SDIO0_SHARK; host->caps = sdhci_readl(host, SDHCI_CAPABILITIES) & (~(SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180)); host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; break; case 1: host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY|MMC_PM_KEEP_POWER |MMC_PM_DISABLE_TIMEOUT_IRQ; host->mmc->pm_caps |= MMC_PM_KEEP_POWER |MMC_PM_DISABLE_TIMEOUT_IRQ; #ifdef CONFIG_SDIO_CARD host->mmc->caps |= MMC_CAP_4_BIT_DATA |MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD; #else host->mmc->caps |= MMC_CAP_4_BIT_DATA |MMC_CAP_NONREMOVABLE; #endif break; case 2: host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY | MMC_PM_KEEP_POWER; host->mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD; break; case 3: host->caps = sdhci_readl(host, SDHCI_CAPABILITIES) & (~(SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_300)); host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY | MMC_PM_KEEP_POWER; host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA | MMC_CAP_HW_RESET; break; default: BUG(); break; } #ifdef CONFIG_PM_RUNTIME switch(pdev->id) { case 1: case 2: #ifdef CONFIG_SDIO_CARD pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_no_callbacks(mmc_classdev(host->mmc)); pm_suspend_ignore_children(mmc_classdev(host->mmc), true); pm_runtime_set_active(mmc_classdev(host->mmc)); pm_runtime_enable(mmc_classdev(host->mmc)); #endif break; case 3: case 0: pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); default: break; } #endif ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); goto err_add_host; } #ifdef CONFIG_MMC_BUS_SCAN if (pdev->id == 1) sdhci_host_g = host; #endif return 0; err_add_host: #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(&(pdev)->dev); pm_runtime_set_suspended(&(pdev)->dev); #endif if (host_data->clk_enable) { clk_disable(host->clk); host_data->clk_enable = 0; } sdhci_free_host(host); return ret; }