]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/mmc/host/sdhci.c
mmc: sdhci: removed unneeded function wrappers
[mirror_ubuntu-artful-kernel.git] / drivers / mmc / host / sdhci.c
index 8670f162dec7452153625f589a3d24aec22e889d..e010ea4eb6f5672ecc4d1f7e8cfac98856e6b243 100644 (file)
 #define DBG(f, x...) \
        pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
 
-#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
-       defined(CONFIG_MMC_SDHCI_MODULE))
-#define SDHCI_USE_LEDS_CLASS
-#endif
-
 #define MAX_TUNING_LOOP 40
 
 static unsigned int debug_quirks = 0;
@@ -53,29 +48,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static int sdhci_do_get_cd(struct sdhci_host *host);
-
-#ifdef CONFIG_PM
-static int sdhci_runtime_pm_get(struct sdhci_host *host);
-static int sdhci_runtime_pm_put(struct sdhci_host *host);
-static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
-#else
-static inline int sdhci_runtime_pm_get(struct sdhci_host *host)
-{
-       return 0;
-}
-static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
-{
-       return 0;
-}
-static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
-{
-}
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
-{
-}
-#endif
+static int sdhci_get_cd(struct mmc_host *mmc);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
@@ -171,6 +144,22 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
        sdhci_set_card_detection(host, false);
 }
 
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+       if (host->bus_on)
+               return;
+       host->bus_on = true;
+       pm_runtime_get_noresume(host->mmc->parent);
+}
+
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+       if (!host->bus_on)
+               return;
+       host->bus_on = false;
+       pm_runtime_put_noidle(host->mmc->parent);
+}
+
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
@@ -204,7 +193,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
 static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
 {
        if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!sdhci_do_get_cd(host))
+               if (!sdhci_get_cd(host->mmc))
                        return;
        }
 
@@ -252,7 +241,7 @@ static void sdhci_reinit(struct sdhci_host *host)
        sdhci_enable_card_detection(host);
 }
 
-static void sdhci_activate_led(struct sdhci_host *host)
+static void __sdhci_led_activate(struct sdhci_host *host)
 {
        u8 ctrl;
 
@@ -261,7 +250,7 @@ static void sdhci_activate_led(struct sdhci_host *host)
        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
 
-static void sdhci_deactivate_led(struct sdhci_host *host)
+static void __sdhci_led_deactivate(struct sdhci_host *host)
 {
        u8 ctrl;
 
@@ -270,9 +259,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
 
-#ifdef SDHCI_USE_LEDS_CLASS
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
 static void sdhci_led_control(struct led_classdev *led,
-       enum led_brightness brightness)
+                             enum led_brightness brightness)
 {
        struct sdhci_host *host = container_of(led, struct sdhci_host, led);
        unsigned long flags;
@@ -283,12 +272,62 @@ static void sdhci_led_control(struct led_classdev *led,
                goto out;
 
        if (brightness == LED_OFF)
-               sdhci_deactivate_led(host);
+               __sdhci_led_deactivate(host);
        else
-               sdhci_activate_led(host);
+               __sdhci_led_activate(host);
 out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
+
+static int sdhci_led_register(struct sdhci_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       snprintf(host->led_name, sizeof(host->led_name),
+                "%s::", mmc_hostname(mmc));
+
+       host->led.name = host->led_name;
+       host->led.brightness = LED_OFF;
+       host->led.default_trigger = mmc_hostname(mmc);
+       host->led.brightness_set = sdhci_led_control;
+
+       return led_classdev_register(mmc_dev(mmc), &host->led);
+}
+
+static void sdhci_led_unregister(struct sdhci_host *host)
+{
+       led_classdev_unregister(&host->led);
+}
+
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+}
+
+#else
+
+static inline int sdhci_led_register(struct sdhci_host *host)
+{
+       return 0;
+}
+
+static inline void sdhci_led_unregister(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+       __sdhci_led_activate(host);
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+       __sdhci_led_deactivate(host);
+}
+
 #endif
 
 /*****************************************************************************\
@@ -1091,23 +1130,14 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
        return preset;
 }
 
-void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
+                  unsigned int *actual_clock)
 {
        int div = 0; /* Initialized for compiler warning */
        int real_div = div, clk_mul = 1;
        u16 clk = 0;
-       unsigned long timeout;
        bool switch_base_clk = false;
 
-       host->mmc->actual_clock = 0;
-
-       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-       if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST)
-               mdelay(1);
-
-       if (clock == 0)
-               return;
-
        if (host->version >= SDHCI_SPEC_300) {
                if (host->preset_enabled) {
                        u16 pre_val;
@@ -1184,10 +1214,29 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 
 clock_set:
        if (real_div)
-               host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
+               *actual_clock = (host->max_clk * clk_mul) / real_div;
        clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
+
+       return clk;
+}
+EXPORT_SYMBOL_GPL(sdhci_calc_clk);
+
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       u16 clk;
+       unsigned long timeout;
+
+       host->mmc->actual_clock = 0;
+
+       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+       if (clock == 0)
+               return;
+
+       clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+
        clk |= SDHCI_CLOCK_INT_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
@@ -1210,10 +1259,24 @@ clock_set:
 }
 EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-                           unsigned short vdd)
+static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
+                               unsigned short vdd)
 {
        struct mmc_host *mmc = host->mmc;
+
+       spin_unlock_irq(&host->lock);
+       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+       spin_lock_irq(&host->lock);
+
+       if (mode != MMC_POWER_OFF)
+               sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+       else
+               sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+}
+
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+                    unsigned short vdd)
+{
        u8 pwr = 0;
 
        if (mode != MMC_POWER_OFF) {
@@ -1245,7 +1308,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
                if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
                        sdhci_runtime_pm_bus_off(host);
-               vdd = 0;
        } else {
                /*
                 * Spec says that we should clear the power reg before setting
@@ -1276,12 +1338,20 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
                        mdelay(10);
        }
+}
+EXPORT_SYMBOL_GPL(sdhci_set_power);
 
-       if (!IS_ERR(mmc->supply.vmmc)) {
-               spin_unlock_irq(&host->lock);
-               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-               spin_lock_irq(&host->lock);
-       }
+static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+                             unsigned short vdd)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (host->ops->set_power)
+               host->ops->set_power(host, mode, vdd);
+       else if (!IS_ERR(mmc->supply.vmmc))
+               sdhci_set_power_reg(host, mode, vdd);
+       else
+               sdhci_set_power(host, mode, vdd);
 }
 
 /*****************************************************************************\
@@ -1298,8 +1368,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        host = mmc_priv(mmc);
 
-       sdhci_runtime_pm_get(host);
-
        /* Firstly check card presence */
        present = mmc->ops->get_cd(mmc);
 
@@ -1307,9 +1375,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        WARN_ON(host->mrq != NULL);
 
-#ifndef SDHCI_USE_LEDS_CLASS
-       sdhci_activate_led(host);
-#endif
+       sdhci_led_activate(host);
 
        /*
         * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
@@ -1384,11 +1450,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
-static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
        u8 ctrl;
-       struct mmc_host *mmc = host->mmc;
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1431,7 +1497,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                }
        }
 
-       sdhci_set_power(host, ios->power_mode, ios->vdd);
+       __sdhci_set_power(host, ios->power_mode, ios->vdd);
 
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1542,18 +1608,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static int sdhci_get_cd(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
-
-       sdhci_runtime_pm_get(host);
-       sdhci_do_set_ios(host, ios);
-       sdhci_runtime_pm_put(host);
-}
-
-static int sdhci_do_get_cd(struct sdhci_host *host)
-{
-       int gpio_cd = mmc_gpio_get_cd(host->mmc);
+       int gpio_cd = mmc_gpio_get_cd(mmc);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
                return 0;
@@ -1577,17 +1635,6 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
        return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
 }
 
-static int sdhci_get_cd(struct mmc_host *mmc)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-       int ret;
-
-       sdhci_runtime_pm_get(host);
-       ret = sdhci_do_get_cd(host);
-       sdhci_runtime_pm_put(host);
-       return ret;
-}
-
 static int sdhci_check_ro(struct sdhci_host *host)
 {
        unsigned long flags;
@@ -1612,8 +1659,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
 
 #define SAMPLE_COUNT   5
 
-static int sdhci_do_get_ro(struct sdhci_host *host)
+static int sdhci_get_ro(struct mmc_host *mmc)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        int i, ro_count;
 
        if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
@@ -1638,17 +1686,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
                host->ops->hw_reset(host);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-       int ret;
-
-       sdhci_runtime_pm_get(host);
-       ret = sdhci_do_get_ro(host);
-       sdhci_runtime_pm_put(host);
-       return ret;
-}
-
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
        if (!(host->flags & SDHCI_DEVICE_DEAD)) {
@@ -1668,8 +1705,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
-       sdhci_runtime_pm_get(host);
-
        spin_lock_irqsave(&host->lock, flags);
        if (enable)
                host->flags |= SDHCI_SDIO_IRQ_ENABLED;
@@ -1678,14 +1713,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 
        sdhci_enable_sdio_irq_nolock(host, enable);
        spin_unlock_irqrestore(&host->lock, flags);
-
-       sdhci_runtime_pm_put(host);
 }
 
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-                                               struct mmc_ios *ios)
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+                                            struct mmc_ios *ios)
 {
-       struct mmc_host *mmc = host->mmc;
+       struct sdhci_host *host = mmc_priv(mmc);
        u16 ctrl;
        int ret;
 
@@ -1773,29 +1806,13 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
        }
 }
 
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
-       struct mmc_ios *ios)
-{
-       struct sdhci_host *host = mmc_priv(mmc);
-       int err;
-
-       if (host->version < SDHCI_SPEC_300)
-               return 0;
-       sdhci_runtime_pm_get(host);
-       err = sdhci_do_start_signal_voltage_switch(host, ios);
-       sdhci_runtime_pm_put(host);
-       return err;
-}
-
 static int sdhci_card_busy(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        u32 present_state;
 
-       sdhci_runtime_pm_get(host);
        /* Check whether DAT[3:0] is 0000 */
        present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
-       sdhci_runtime_pm_put(host);
 
        return !(present_state & SDHCI_DATA_LVL_MASK);
 }
@@ -1822,7 +1839,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        unsigned int tuning_count = 0;
        bool hs400_tuning;
 
-       sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
        hs400_tuning = host->flags & SDHCI_HS400_TUNING;
@@ -1858,8 +1874,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                break;
 
        case MMC_TIMING_UHS_SDR50:
-               if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-                   host->flags & SDHCI_SDR104_NEEDS_TUNING)
+               if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
                        break;
                /* FALLTHROUGH */
 
@@ -1870,7 +1885,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        if (host->ops->platform_execute_tuning) {
                spin_unlock_irqrestore(&host->lock, flags);
                err = host->ops->platform_execute_tuning(host, opcode);
-               sdhci_runtime_pm_put(host);
                return err;
        }
 
@@ -2002,8 +2016,6 @@ out:
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 out_unlock:
        spin_unlock_irqrestore(&host->lock, flags);
-       sdhci_runtime_pm_put(host);
-
        return err;
 }
 
@@ -2084,7 +2096,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
        if (host->ops->card_event)
                host->ops->card_event(host);
 
-       present = sdhci_do_get_cd(host);
+       present = sdhci_get_cd(host->mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -2193,15 +2205,12 @@ static void sdhci_tasklet_finish(unsigned long param)
        host->cmd = NULL;
        host->data = NULL;
 
-#ifndef SDHCI_USE_LEDS_CLASS
-       sdhci_deactivate_led(host);
-#endif
+       sdhci_led_deactivate(host);
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
        mmc_request_done(host->mmc, mrq);
-       sdhci_runtime_pm_put(host);
 }
 
 static void sdhci_timeout_timer(unsigned long data)
@@ -2658,7 +2667,7 @@ int sdhci_resume_host(struct sdhci_host *host)
                sdhci_init(host, 0);
                host->pwr = 0;
                host->clock = 0;
-               sdhci_do_set_ios(host, &host->mmc->ios);
+               sdhci_set_ios(host->mmc, &host->mmc->ios);
        } else {
                sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
                mmiowb();
@@ -2682,33 +2691,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 
 EXPORT_SYMBOL_GPL(sdhci_resume_host);
 
-static int sdhci_runtime_pm_get(struct sdhci_host *host)
-{
-       return pm_runtime_get_sync(host->mmc->parent);
-}
-
-static int sdhci_runtime_pm_put(struct sdhci_host *host)
-{
-       pm_runtime_mark_last_busy(host->mmc->parent);
-       return pm_runtime_put_autosuspend(host->mmc->parent);
-}
-
-static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
-{
-       if (host->bus_on)
-               return;
-       host->bus_on = true;
-       pm_runtime_get_noresume(host->mmc->parent);
-}
-
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
-{
-       if (!host->bus_on)
-               return;
-       host->bus_on = false;
-       pm_runtime_put_noidle(host->mmc->parent);
-}
-
 int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
        unsigned long flags;
@@ -2747,8 +2729,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        /* Force clock and power re-program */
        host->pwr = 0;
        host->clock = 0;
-       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
-       sdhci_do_set_ios(host, &host->mmc->ios);
+       sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios);
+       sdhci_set_ios(host->mmc, &host->mmc->ios);
 
        if ((host_flags & SDHCI_PV_ENABLED) &&
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
@@ -2993,7 +2975,8 @@ int sdhci_add_host(struct sdhci_host *host)
                if (!host->ops->get_max_clock) {
                        pr_err("%s: Hardware doesn't specify base clock frequency.\n",
                               mmc_hostname(mmc));
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto undma;
                }
                host->max_clk = host->ops->get_max_clock(host);
        }
@@ -3030,7 +3013,7 @@ int sdhci_add_host(struct sdhci_host *host)
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
-       if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk)))
+       if (!mmc->f_max || mmc->f_max > max_clk)
                mmc->f_max = max_clk;
 
        if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
@@ -3043,7 +3026,8 @@ int sdhci_add_host(struct sdhci_host *host)
                        } else {
                                pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
                                        mmc_hostname(mmc));
-                               return -ENODEV;
+                               ret = -ENODEV;
+                               goto undma;
                        }
                }
 
@@ -3097,8 +3081,9 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /* If there are external regulators, get them */
-       if (mmc_regulator_get_supply(mmc) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               goto undma;
 
        /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
        if (!IS_ERR(mmc->supply.vqmmc)) {
@@ -3153,10 +3138,6 @@ int sdhci_add_host(struct sdhci_host *host)
        if (caps[1] & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
-       /* Does the host need tuning for SDR104 / HS200? */
-       if (mmc->caps2 & MMC_CAP2_HS200)
-               host->flags |= SDHCI_SDR104_NEEDS_TUNING;
-
        /* Driver Type(s) (A, C, D) supported by the host */
        if (caps[1] & SDHCI_DRIVER_TYPE_A)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
@@ -3255,7 +3236,8 @@ int sdhci_add_host(struct sdhci_host *host)
        if (mmc->ocr_avail == 0) {
                pr_err("%s: Hardware doesn't report any support voltages.\n",
                       mmc_hostname(mmc));
-               return -ENODEV;
+               ret = -ENODEV;
+               goto unreg;
        }
 
        spin_lock_init(&host->lock);
@@ -3339,25 +3321,18 @@ int sdhci_add_host(struct sdhci_host *host)
        sdhci_dumpregs(host);
 #endif
 
-#ifdef SDHCI_USE_LEDS_CLASS
-       snprintf(host->led_name, sizeof(host->led_name),
-               "%s::", mmc_hostname(mmc));
-       host->led.name = host->led_name;
-       host->led.brightness = LED_OFF;
-       host->led.default_trigger = mmc_hostname(mmc);
-       host->led.brightness_set = sdhci_led_control;
-
-       ret = led_classdev_register(mmc_dev(mmc), &host->led);
+       ret = sdhci_led_register(host);
        if (ret) {
                pr_err("%s: Failed to register LED device: %d\n",
                       mmc_hostname(mmc), ret);
-               goto reset;
+               goto unirq;
        }
-#endif
 
        mmiowb();
 
-       mmc_add_host(mmc);
+       ret = mmc_add_host(mmc);
+       if (ret)
+               goto unled;
 
        pr_info("%s: SDHCI controller on %s [%s] using %s\n",
                mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
@@ -3369,15 +3344,25 @@ int sdhci_add_host(struct sdhci_host *host)
 
        return 0;
 
-#ifdef SDHCI_USE_LEDS_CLASS
-reset:
+unled:
+       sdhci_led_unregister(host);
+unirq:
        sdhci_do_reset(host, SDHCI_RESET_ALL);
        sdhci_writel(host, 0, SDHCI_INT_ENABLE);
        sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
-#endif
 untasklet:
        tasklet_kill(&host->finish_tasklet);
+unreg:
+       if (!IS_ERR(mmc->supply.vqmmc))
+               regulator_disable(mmc->supply.vqmmc);
+undma:
+       if (host->align_buffer)
+               dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+                                 host->adma_table_sz, host->align_buffer,
+                                 host->align_addr);
+       host->adma_table = NULL;
+       host->align_buffer = NULL;
 
        return ret;
 }
@@ -3409,9 +3394,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 
        mmc_remove_host(mmc);
 
-#ifdef SDHCI_USE_LEDS_CLASS
-       led_classdev_unregister(&host->led);
-#endif
+       sdhci_led_unregister(host);
 
        if (!dead)
                sdhci_do_reset(host, SDHCI_RESET_ALL);