diff mbox

mmc: core: Remove MMC_CLKGATE

Message ID 1443776171-7127-1-git-send-email-ulf.hansson@linaro.org
State New
Headers show

Commit Message

Ulf Hansson Oct. 2, 2015, 8:56 a.m. UTC
MMC_CLKGATE was once invented to save power by gating the bus clock at
request inactivity. At that time it served its purpose. The modern way to
deal with power saving for these scenarios, is by using runtime PM.

Nowadays, several host drivers have deployed runtime PM, but for those
that haven't and which still cares power saving at request inactivity,
it's certainly time to deploy runtime PM as it has been around for several
years now.

To simplify code to mmc core and thus decrease maintenance efforts, this
patch removes all code related to MMC_CLKGATE.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 Documentation/mmc/mmc-dev-attrs.txt |  10 --
 drivers/mmc/core/Kconfig            |  10 --
 drivers/mmc/core/core.c             | 139 +++-----------------
 drivers/mmc/core/core.h             |   3 -
 drivers/mmc/core/debugfs.c          |   5 -
 drivers/mmc/core/host.c             | 245 ------------------------------------
 drivers/mmc/core/mmc.c              |   6 +-
 drivers/mmc/core/quirks.c           |  18 ---
 drivers/mmc/core/sd.c               |   2 -
 drivers/mmc/core/sdio.c             |   7 +-
 drivers/mmc/core/sdio_irq.c         |  14 +--
 include/linux/mmc/card.h            |   1 -
 include/linux/mmc/host.h            |  32 -----
 13 files changed, 20 insertions(+), 472 deletions(-)

Comments

Linus Walleij Oct. 2, 2015, 9:23 a.m. UTC | #1
On Fri, Oct 2, 2015 at 1:56 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:

> MMC_CLKGATE was once invented to save power by gating the bus clock at
> request inactivity. At that time it served its purpose. The modern way to
> deal with power saving for these scenarios, is by using runtime PM.
>
> Nowadays, several host drivers have deployed runtime PM, but for those
> that haven't and which still cares power saving at request inactivity,
> it's certainly time to deploy runtime PM as it has been around for several
> years now.
>
> To simplify code to mmc core and thus decrease maintenance efforts, this
> patch removes all code related to MMC_CLKGATE.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Runtime PM is the generic solution to the specific problem, good feat.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Oct. 8, 2015, 5:35 p.m. UTC | #2
On 2 October 2015 at 10:56, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> MMC_CLKGATE was once invented to save power by gating the bus clock at
> request inactivity. At that time it served its purpose. The modern way to
> deal with power saving for these scenarios, is by using runtime PM.
>
> Nowadays, several host drivers have deployed runtime PM, but for those
> that haven't and which still cares power saving at request inactivity,
> it's certainly time to deploy runtime PM as it has been around for several
> years now.
>
> To simplify code to mmc core and thus decrease maintenance efforts, this
> patch removes all code related to MMC_CLKGATE.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

I have queued this up for next to get some testing in linux-next and
kernelci. Still, it's not too late to provide input to the patch.

Kind regards
Uffe

> ---
>  Documentation/mmc/mmc-dev-attrs.txt |  10 --
>  drivers/mmc/core/Kconfig            |  10 --
>  drivers/mmc/core/core.c             | 139 +++-----------------
>  drivers/mmc/core/core.h             |   3 -
>  drivers/mmc/core/debugfs.c          |   5 -
>  drivers/mmc/core/host.c             | 245 ------------------------------------
>  drivers/mmc/core/mmc.c              |   6 +-
>  drivers/mmc/core/quirks.c           |  18 ---
>  drivers/mmc/core/sd.c               |   2 -
>  drivers/mmc/core/sdio.c             |   7 +-
>  drivers/mmc/core/sdio_irq.c         |  14 +--
>  include/linux/mmc/card.h            |   1 -
>  include/linux/mmc/host.h            |  32 -----
>  13 files changed, 20 insertions(+), 472 deletions(-)
>
> diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
> index 189bab0..caa5557 100644
> --- a/Documentation/mmc/mmc-dev-attrs.txt
> +++ b/Documentation/mmc/mmc-dev-attrs.txt
> @@ -72,13 +72,3 @@ Note on raw_rpmb_size_mult:
>         "raw_rpmb_size_mult" is a mutliple of 128kB block.
>         RPMB size in byte is calculated by using the following equation:
>         RPMB partition size = 128kB x raw_rpmb_size_mult
> -
> -SD/MMC/SDIO Clock Gating Attribute
> -==================================
> -
> -Read and write access is provided to following attribute.
> -This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
> -
> -       clkgate_delay   Tune the clock gating delay with desired value in milliseconds.
> -
> -echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
> diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
> index 9ebee72..4c33d76 100644
> --- a/drivers/mmc/core/Kconfig
> +++ b/drivers/mmc/core/Kconfig
> @@ -1,13 +1,3 @@
>  #
>  # MMC core configuration
>  #
> -
> -config MMC_CLKGATE
> -       bool "MMC host clock gating"
> -       help
> -         This will attempt to aggressively gate the clock to the MMC card.
> -         This is done to save power due to gating off the logic and bus
> -         noise when the MMC card is not in use. Your host driver has to
> -         support handling this in order for it to be of any use.
> -
> -         If unsure, say N.
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 21cda23..1a36b02 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -187,8 +187,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
>
>                 if (mrq->done)
>                         mrq->done(mrq);
> -
> -               mmc_host_clk_release(host);
>         }
>  }
>
> @@ -292,7 +290,6 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>                         mrq->stop->mrq = mrq;
>                 }
>         }
> -       mmc_host_clk_hold(host);
>         led_trigger_event(host->led, LED_FULL);
>         __mmc_start_request(host, mrq);
>
> @@ -542,11 +539,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
>  static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
>                  bool is_first_req)
>  {
> -       if (host->ops->pre_req) {
> -               mmc_host_clk_hold(host);
> +       if (host->ops->pre_req)
>                 host->ops->pre_req(host, mrq, is_first_req);
> -               mmc_host_clk_release(host);
> -       }
>  }
>
>  /**
> @@ -561,11 +555,8 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
>  static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
>                          int err)
>  {
> -       if (host->ops->post_req) {
> -               mmc_host_clk_hold(host);
> +       if (host->ops->post_req)
>                 host->ops->post_req(host, mrq, err);
> -               mmc_host_clk_release(host);
> -       }
>  }
>
>  /**
> @@ -850,9 +841,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
>                 unsigned int timeout_us, limit_us;
>
>                 timeout_us = data->timeout_ns / 1000;
> -               if (mmc_host_clk_rate(card->host))
> +               if (card->host->ios.clock)
>                         timeout_us += data->timeout_clks * 1000 /
> -                               (mmc_host_clk_rate(card->host) / 1000);
> +                               (card->host->ios.clock / 1000);
>
>                 if (data->flags & MMC_DATA_WRITE)
>                         /*
> @@ -1050,8 +1041,6 @@ static inline void mmc_set_ios(struct mmc_host *host)
>                  ios->power_mode, ios->chip_select, ios->vdd,
>                  ios->bus_width, ios->timing);
>
> -       if (ios->clock > 0)
> -               mmc_set_ungated(host);
>         host->ops->set_ios(host, ios);
>  }
>
> @@ -1060,17 +1049,15 @@ static inline void mmc_set_ios(struct mmc_host *host)
>   */
>  void mmc_set_chip_select(struct mmc_host *host, int mode)
>  {
> -       mmc_host_clk_hold(host);
>         host->ios.chip_select = mode;
>         mmc_set_ios(host);
> -       mmc_host_clk_release(host);
>  }
>
>  /*
>   * Sets the host clock to the highest possible frequency that
>   * is below "hz".
>   */
> -static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
> +void mmc_set_clock(struct mmc_host *host, unsigned int hz)
>  {
>         WARN_ON(hz && hz < host->f_min);
>
> @@ -1081,68 +1068,6 @@ static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
>         mmc_set_ios(host);
>  }
>
> -void mmc_set_clock(struct mmc_host *host, unsigned int hz)
> -{
> -       mmc_host_clk_hold(host);
> -       __mmc_set_clock(host, hz);
> -       mmc_host_clk_release(host);
> -}
> -
> -#ifdef CONFIG_MMC_CLKGATE
> -/*
> - * This gates the clock by setting it to 0 Hz.
> - */
> -void mmc_gate_clock(struct mmc_host *host)
> -{
> -       unsigned long flags;
> -
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       host->clk_old = host->ios.clock;
> -       host->ios.clock = 0;
> -       host->clk_gated = true;
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -       mmc_set_ios(host);
> -}
> -
> -/*
> - * This restores the clock from gating by using the cached
> - * clock value.
> - */
> -void mmc_ungate_clock(struct mmc_host *host)
> -{
> -       /*
> -        * We should previously have gated the clock, so the clock shall
> -        * be 0 here! The clock may however be 0 during initialization,
> -        * when some request operations are performed before setting
> -        * the frequency. When ungate is requested in that situation
> -        * we just ignore the call.
> -        */
> -       if (host->clk_old) {
> -               BUG_ON(host->ios.clock);
> -               /* This call will also set host->clk_gated to false */
> -               __mmc_set_clock(host, host->clk_old);
> -       }
> -}
> -
> -void mmc_set_ungated(struct mmc_host *host)
> -{
> -       unsigned long flags;
> -
> -       /*
> -        * We've been given a new frequency while the clock is gated,
> -        * so make sure we regard this as ungating it.
> -        */
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       host->clk_gated = false;
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -}
> -
> -#else
> -void mmc_set_ungated(struct mmc_host *host)
> -{
> -}
> -#endif
> -
>  int mmc_execute_tuning(struct mmc_card *card)
>  {
>         struct mmc_host *host = card->host;
> @@ -1157,9 +1082,7 @@ int mmc_execute_tuning(struct mmc_card *card)
>         else
>                 opcode = MMC_SEND_TUNING_BLOCK;
>
> -       mmc_host_clk_hold(host);
>         err = host->ops->execute_tuning(host, opcode);
> -       mmc_host_clk_release(host);
>
>         if (err)
>                 pr_err("%s: tuning execution failed\n", mmc_hostname(host));
> @@ -1174,10 +1097,8 @@ int mmc_execute_tuning(struct mmc_card *card)
>   */
>  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
>  {
> -       mmc_host_clk_hold(host);
>         host->ios.bus_mode = mode;
>         mmc_set_ios(host);
> -       mmc_host_clk_release(host);
>  }
>
>  /*
> @@ -1185,10 +1106,8 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
>   */
>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
>  {
> -       mmc_host_clk_hold(host);
>         host->ios.bus_width = width;
>         mmc_set_ios(host);
> -       mmc_host_clk_release(host);
>  }
>
>  /*
> @@ -1532,11 +1451,8 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
>         int old_signal_voltage = host->ios.signal_voltage;
>
>         host->ios.signal_voltage = signal_voltage;
> -       if (host->ops->start_signal_voltage_switch) {
> -               mmc_host_clk_hold(host);
> +       if (host->ops->start_signal_voltage_switch)
>                 err = host->ops->start_signal_voltage_switch(host, &host->ios);
> -               mmc_host_clk_release(host);
> -       }
>
>         if (err)
>                 host->ios.signal_voltage = old_signal_voltage;
> @@ -1570,20 +1486,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
>                 pr_warn("%s: cannot verify signal voltage switch\n",
>                         mmc_hostname(host));
>
> -       mmc_host_clk_hold(host);
> -
>         cmd.opcode = SD_SWITCH_VOLTAGE;
>         cmd.arg = 0;
>         cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
>
>         err = mmc_wait_for_cmd(host, &cmd, 0);
>         if (err)
> -               goto err_command;
> +               return err;
> +
> +       if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
> +               return -EIO;
>
> -       if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
> -               err = -EIO;
> -               goto err_command;
> -       }
>         /*
>          * The card should drive cmd and dat[0:3] low immediately
>          * after the response of cmd11, but wait 1 ms to be sure
> @@ -1632,9 +1545,6 @@ power_cycle:
>                 mmc_power_cycle(host, ocr);
>         }
>
> -err_command:
> -       mmc_host_clk_release(host);
> -
>         return err;
>  }
>
> @@ -1643,10 +1553,8 @@ err_command:
>   */
>  void mmc_set_timing(struct mmc_host *host, unsigned int timing)
>  {
> -       mmc_host_clk_hold(host);
>         host->ios.timing = timing;
>         mmc_set_ios(host);
> -       mmc_host_clk_release(host);
>  }
>
>  /*
> @@ -1654,10 +1562,8 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
>   */
>  void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
>  {
> -       mmc_host_clk_hold(host);
>         host->ios.drv_type = drv_type;
>         mmc_set_ios(host);
> -       mmc_host_clk_release(host);
>  }
>
>  int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
> @@ -1665,7 +1571,6 @@ int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
>  {
>         struct mmc_host *host = card->host;
>         int host_drv_type = SD_DRIVER_TYPE_B;
> -       int drive_strength;
>
>         *drv_type = 0;
>
> @@ -1688,14 +1593,10 @@ int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
>          * information and let the hardware specific code
>          * return what is possible given the options
>          */
> -       mmc_host_clk_hold(host);
> -       drive_strength = host->ops->select_drive_strength(card, max_dtr,
> -                                                         host_drv_type,
> -                                                         card_drv_type,
> -                                                         drv_type);
> -       mmc_host_clk_release(host);
> -
> -       return drive_strength;
> +       return host->ops->select_drive_strength(card, max_dtr,
> +                                               host_drv_type,
> +                                               card_drv_type,
> +                                               drv_type);
>  }
>
>  /*
> @@ -1714,8 +1615,6 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
>         if (host->ios.power_mode == MMC_POWER_ON)
>                 return;
>
> -       mmc_host_clk_hold(host);
> -
>         mmc_pwrseq_pre_power_on(host);
>
>         host->ios.vdd = fls(ocr) - 1;
> @@ -1749,8 +1648,6 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
>          * time required to reach a stable voltage.
>          */
>         mmc_delay(10);
> -
> -       mmc_host_clk_release(host);
>  }
>
>  void mmc_power_off(struct mmc_host *host)
> @@ -1758,8 +1655,6 @@ void mmc_power_off(struct mmc_host *host)
>         if (host->ios.power_mode == MMC_POWER_OFF)
>                 return;
>
> -       mmc_host_clk_hold(host);
> -
>         mmc_pwrseq_power_off(host);
>
>         host->ios.clock = 0;
> @@ -1775,8 +1670,6 @@ void mmc_power_off(struct mmc_host *host)
>          * can be successfully turned on again.
>          */
>         mmc_delay(1);
> -
> -       mmc_host_clk_release(host);
>  }
>
>  void mmc_power_cycle(struct mmc_host *host, u32 ocr)
> @@ -1992,7 +1885,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
>                  */
>                 timeout_clks <<= 1;
>                 timeout_us += (timeout_clks * 1000) /
> -                             (mmc_host_clk_rate(card->host) / 1000);
> +                             (card->host->ios.clock / 1000);
>
>                 erase_timeout = timeout_us / 1000;
>
> @@ -2440,9 +2333,7 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
>  {
>         if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
>                 return;
> -       mmc_host_clk_hold(host);
>         host->ops->hw_reset(host);
> -       mmc_host_clk_release(host);
>  }
>
>  int mmc_hw_reset(struct mmc_host *host)
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index 1a22a82..09241e5 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -40,9 +40,6 @@ void mmc_init_erase(struct mmc_card *card);
>
>  void mmc_set_chip_select(struct mmc_host *host, int mode);
>  void mmc_set_clock(struct mmc_host *host, unsigned int hz);
> -void mmc_gate_clock(struct mmc_host *host);
> -void mmc_ungate_clock(struct mmc_host *host);
> -void mmc_set_ungated(struct mmc_host *host);
>  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
>  u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index f4db93e..154aced 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -255,11 +255,6 @@ void mmc_add_host_debugfs(struct mmc_host *host)
>                         &mmc_clock_fops))
>                 goto err_node;
>
> -#ifdef CONFIG_MMC_CLKGATE
> -       if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
> -                               root, &host->clk_delay))
> -               goto err_node;
> -#endif
>  #ifdef CONFIG_FAIL_MMC_REQUEST
>         if (fail_request)
>                 setup_fault_attr(&fail_default_attr, fail_request);
> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
> index 5466f25..970e690 100644
> --- a/drivers/mmc/core/host.c
> +++ b/drivers/mmc/core/host.c
> @@ -61,246 +61,6 @@ void mmc_unregister_host_class(void)
>         class_unregister(&mmc_host_class);
>  }
>
> -#ifdef CONFIG_MMC_CLKGATE
> -static ssize_t clkgate_delay_show(struct device *dev,
> -               struct device_attribute *attr, char *buf)
> -{
> -       struct mmc_host *host = cls_dev_to_mmc_host(dev);
> -       return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
> -}
> -
> -static ssize_t clkgate_delay_store(struct device *dev,
> -               struct device_attribute *attr, const char *buf, size_t count)
> -{
> -       struct mmc_host *host = cls_dev_to_mmc_host(dev);
> -       unsigned long flags, value;
> -
> -       if (kstrtoul(buf, 0, &value))
> -               return -EINVAL;
> -
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       host->clkgate_delay = value;
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -       return count;
> -}
> -
> -/*
> - * Enabling clock gating will make the core call out to the host
> - * once up and once down when it performs a request or card operation
> - * intermingled in any fashion. The driver will see this through
> - * set_ios() operations with ios.clock field set to 0 to gate (disable)
> - * the block clock, and to the old frequency to enable it again.
> - */
> -static void mmc_host_clk_gate_delayed(struct mmc_host *host)
> -{
> -       unsigned long tick_ns;
> -       unsigned long freq = host->ios.clock;
> -       unsigned long flags;
> -
> -       if (!freq) {
> -               pr_debug("%s: frequency set to 0 in disable function, "
> -                        "this means the clock is already disabled.\n",
> -                        mmc_hostname(host));
> -               return;
> -       }
> -       /*
> -        * New requests may have appeared while we were scheduling,
> -        * then there is no reason to delay the check before
> -        * clk_disable().
> -        */
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -
> -       /*
> -        * Delay n bus cycles (at least 8 from MMC spec) before attempting
> -        * to disable the MCI block clock. The reference count may have
> -        * gone up again after this delay due to rescheduling!
> -        */
> -       if (!host->clk_requests) {
> -               spin_unlock_irqrestore(&host->clk_lock, flags);
> -               tick_ns = DIV_ROUND_UP(1000000000, freq);
> -               ndelay(host->clk_delay * tick_ns);
> -       } else {
> -               /* New users appeared while waiting for this work */
> -               spin_unlock_irqrestore(&host->clk_lock, flags);
> -               return;
> -       }
> -       mutex_lock(&host->clk_gate_mutex);
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       if (!host->clk_requests) {
> -               spin_unlock_irqrestore(&host->clk_lock, flags);
> -               /* This will set host->ios.clock to 0 */
> -               mmc_gate_clock(host);
> -               spin_lock_irqsave(&host->clk_lock, flags);
> -               pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
> -       }
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -       mutex_unlock(&host->clk_gate_mutex);
> -}
> -
> -/*
> - * Internal work. Work to disable the clock at some later point.
> - */
> -static void mmc_host_clk_gate_work(struct work_struct *work)
> -{
> -       struct mmc_host *host = container_of(work, struct mmc_host,
> -                                             clk_gate_work.work);
> -
> -       mmc_host_clk_gate_delayed(host);
> -}
> -
> -/**
> - *     mmc_host_clk_hold - ungate hardware MCI clocks
> - *     @host: host to ungate.
> - *
> - *     Makes sure the host ios.clock is restored to a non-zero value
> - *     past this call. Increase clock reference count and ungate clock
> - *     if we're the first user.
> - */
> -void mmc_host_clk_hold(struct mmc_host *host)
> -{
> -       unsigned long flags;
> -
> -       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
> -       cancel_delayed_work_sync(&host->clk_gate_work);
> -       mutex_lock(&host->clk_gate_mutex);
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       if (host->clk_gated) {
> -               spin_unlock_irqrestore(&host->clk_lock, flags);
> -               mmc_ungate_clock(host);
> -               spin_lock_irqsave(&host->clk_lock, flags);
> -               pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
> -       }
> -       host->clk_requests++;
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -       mutex_unlock(&host->clk_gate_mutex);
> -}
> -
> -/**
> - *     mmc_host_may_gate_card - check if this card may be gated
> - *     @card: card to check.
> - */
> -static bool mmc_host_may_gate_card(struct mmc_card *card)
> -{
> -       /* If there is no card we may gate it */
> -       if (!card)
> -               return true;
> -       /*
> -        * Don't gate SDIO cards! These need to be clocked at all times
> -        * since they may be independent systems generating interrupts
> -        * and other events. The clock requests counter from the core will
> -        * go down to zero since the core does not need it, but we will not
> -        * gate the clock, because there is somebody out there that may still
> -        * be using it.
> -        */
> -       return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
> -}
> -
> -/**
> - *     mmc_host_clk_release - gate off hardware MCI clocks
> - *     @host: host to gate.
> - *
> - *     Calls the host driver with ios.clock set to zero as often as possible
> - *     in order to gate off hardware MCI clocks. Decrease clock reference
> - *     count and schedule disabling of clock.
> - */
> -void mmc_host_clk_release(struct mmc_host *host)
> -{
> -       unsigned long flags;
> -
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       host->clk_requests--;
> -       if (mmc_host_may_gate_card(host->card) &&
> -           !host->clk_requests)
> -               schedule_delayed_work(&host->clk_gate_work,
> -                                     msecs_to_jiffies(host->clkgate_delay));
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -}
> -
> -/**
> - *     mmc_host_clk_rate - get current clock frequency setting
> - *     @host: host to get the clock frequency for.
> - *
> - *     Returns current clock frequency regardless of gating.
> - */
> -unsigned int mmc_host_clk_rate(struct mmc_host *host)
> -{
> -       unsigned long freq;
> -       unsigned long flags;
> -
> -       spin_lock_irqsave(&host->clk_lock, flags);
> -       if (host->clk_gated)
> -               freq = host->clk_old;
> -       else
> -               freq = host->ios.clock;
> -       spin_unlock_irqrestore(&host->clk_lock, flags);
> -       return freq;
> -}
> -
> -/**
> - *     mmc_host_clk_init - set up clock gating code
> - *     @host: host with potential clock to control
> - */
> -static inline void mmc_host_clk_init(struct mmc_host *host)
> -{
> -       host->clk_requests = 0;
> -       /* Hold MCI clock for 8 cycles by default */
> -       host->clk_delay = 8;
> -       /*
> -        * Default clock gating delay is 0ms to avoid wasting power.
> -        * This value can be tuned by writing into sysfs entry.
> -        */
> -       host->clkgate_delay = 0;
> -       host->clk_gated = false;
> -       INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
> -       spin_lock_init(&host->clk_lock);
> -       mutex_init(&host->clk_gate_mutex);
> -}
> -
> -/**
> - *     mmc_host_clk_exit - shut down clock gating code
> - *     @host: host with potential clock to control
> - */
> -static inline void mmc_host_clk_exit(struct mmc_host *host)
> -{
> -       /*
> -        * Wait for any outstanding gate and then make sure we're
> -        * ungated before exiting.
> -        */
> -       if (cancel_delayed_work_sync(&host->clk_gate_work))
> -               mmc_host_clk_gate_delayed(host);
> -       if (host->clk_gated)
> -               mmc_host_clk_hold(host);
> -       /* There should be only one user now */
> -       WARN_ON(host->clk_requests > 1);
> -}
> -
> -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
> -{
> -       host->clkgate_delay_attr.show = clkgate_delay_show;
> -       host->clkgate_delay_attr.store = clkgate_delay_store;
> -       sysfs_attr_init(&host->clkgate_delay_attr.attr);
> -       host->clkgate_delay_attr.attr.name = "clkgate_delay";
> -       host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
> -       if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
> -               pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
> -                               mmc_hostname(host));
> -}
> -#else
> -
> -static inline void mmc_host_clk_init(struct mmc_host *host)
> -{
> -}
> -
> -static inline void mmc_host_clk_exit(struct mmc_host *host)
> -{
> -}
> -
> -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
> -{
> -}
> -
> -#endif
> -
>  void mmc_retune_enable(struct mmc_host *host)
>  {
>         host->can_retune = 1;
> @@ -583,8 +343,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
>                 return NULL;
>         }
>
> -       mmc_host_clk_init(host);
> -
>         spin_lock_init(&host->lock);
>         init_waitqueue_head(&host->wq);
>         INIT_DELAYED_WORK(&host->detect, mmc_rescan);
> @@ -633,7 +391,6 @@ int mmc_add_host(struct mmc_host *host)
>  #ifdef CONFIG_DEBUG_FS
>         mmc_add_host_debugfs(host);
>  #endif
> -       mmc_host_clk_sysfs_init(host);
>
>         mmc_start_host(host);
>         register_pm_notifier(&host->pm_notify);
> @@ -663,8 +420,6 @@ void mmc_remove_host(struct mmc_host *host)
>         device_del(&host->class_dev);
>
>         led_trigger_unregister_simple(host->led);
> -
> -       mmc_host_clk_exit(host);
>  }
>
>  EXPORT_SYMBOL(mmc_remove_host);
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index e726903..1b8907f 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1932,20 +1932,16 @@ static int mmc_reset(struct mmc_host *host)
>         if (!mmc_can_reset(card))
>                 return -EOPNOTSUPP;
>
> -       mmc_host_clk_hold(host);
>         mmc_set_clock(host, host->f_init);
>
>         host->ops->hw_reset(host);
>
>         /* If the reset has happened, then a status command will fail */
> -       if (!mmc_send_status(card, &status)) {
> -               mmc_host_clk_release(host);
> +       if (!mmc_send_status(card, &status))
>                 return -ENOSYS;
> -       }
>
>         /* Set initial state and call mmc_set_ios */
>         mmc_set_initial_state(host);
> -       mmc_host_clk_release(host);
>
>         return mmc_init_card(host, card->ocr, card);
>  }
> diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
> index dd1d1e0..fad660b 100644
> --- a/drivers/mmc/core/quirks.c
> +++ b/drivers/mmc/core/quirks.c
> @@ -35,25 +35,7 @@
>  #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
>  #endif
>
> -/*
> - * This hook just adds a quirk for all sdio devices
> - */
> -static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
> -{
> -       if (mmc_card_sdio(card))
> -               card->quirks |= data;
> -}
> -
>  static const struct mmc_fixup mmc_fixup_methods[] = {
> -       /* by default sdio devices are considered CLK_GATING broken */
> -       /* good cards will be whitelisted as they are tested */
> -       SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
> -                  add_quirk_for_sdio_devices,
> -                  MMC_QUIRK_BROKEN_CLK_GATING),
> -
> -       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
> -                  remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
> -
>         SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
>                    add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
>
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index e28ebf3..60a18ab 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -784,9 +784,7 @@ static int mmc_sd_get_ro(struct mmc_host *host)
>         if (!host->ops->get_ro)
>                 return -1;
>
> -       mmc_host_clk_hold(host);
>         ro = host->ops->get_ro(host);
> -       mmc_host_clk_release(host);
>
>         return ro;
>  }
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index 95bc101..16d838e 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -956,13 +956,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
>         }
>
>         if (!err && host->sdio_irqs) {
> -               if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
> +               if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
>                         wake_up_process(host->sdio_irq_thread);
> -               } else if (host->caps & MMC_CAP_SDIO_IRQ) {
> -                       mmc_host_clk_hold(host);
> +               else if (host->caps & MMC_CAP_SDIO_IRQ)
>                         host->ops->enable_sdio_irq(host, 1);
> -                       mmc_host_clk_release(host);
> -               }
>         }
>
>         mmc_release_host(host);
> diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
> index 09cc67d..91bbbfb 100644
> --- a/drivers/mmc/core/sdio_irq.c
> +++ b/drivers/mmc/core/sdio_irq.c
> @@ -168,21 +168,15 @@ static int sdio_irq_thread(void *_host)
>                 }
>
>                 set_current_state(TASK_INTERRUPTIBLE);
> -               if (host->caps & MMC_CAP_SDIO_IRQ) {
> -                       mmc_host_clk_hold(host);
> +               if (host->caps & MMC_CAP_SDIO_IRQ)
>                         host->ops->enable_sdio_irq(host, 1);
> -                       mmc_host_clk_release(host);
> -               }
>                 if (!kthread_should_stop())
>                         schedule_timeout(period);
>                 set_current_state(TASK_RUNNING);
>         } while (!kthread_should_stop());
>
> -       if (host->caps & MMC_CAP_SDIO_IRQ) {
> -               mmc_host_clk_hold(host);
> +       if (host->caps & MMC_CAP_SDIO_IRQ)
>                 host->ops->enable_sdio_irq(host, 0);
> -               mmc_host_clk_release(host);
> -       }
>
>         pr_debug("%s: IRQ thread exiting with code %d\n",
>                  mmc_hostname(host), ret);
> @@ -208,9 +202,7 @@ static int sdio_card_irq_get(struct mmc_card *card)
>                                 return err;
>                         }
>                 } else if (host->caps & MMC_CAP_SDIO_IRQ) {
> -                       mmc_host_clk_hold(host);
>                         host->ops->enable_sdio_irq(host, 1);
> -                       mmc_host_clk_release(host);
>                 }
>         }
>
> @@ -229,9 +221,7 @@ static int sdio_card_irq_put(struct mmc_card *card)
>                         atomic_set(&host->sdio_irq_thread_abort, 1);
>                         kthread_stop(host->sdio_irq_thread);
>                 } else if (host->caps & MMC_CAP_SDIO_IRQ) {
> -                       mmc_host_clk_hold(host);
>                         host->ops->enable_sdio_irq(host, 0);
> -                       mmc_host_clk_release(host);
>                 }
>         }
>
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index fdd0779..eb0151b 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -269,7 +269,6 @@ struct mmc_card {
>                                                 /* for byte mode */
>  #define MMC_QUIRK_NONSTD_SDIO  (1<<2)          /* non-standard SDIO card attached */
>                                                 /* (missing CIA registers) */
> -#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)     /* clock gating the sdio bus will make card fail */
>  #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)                /* SDIO card has nonstd function interfaces */
>  #define MMC_QUIRK_DISABLE_CD   (1<<5)          /* disconnect CD/DAT[3] resistor */
>  #define MMC_QUIRK_INAND_CMD38  (1<<6)          /* iNAND devices have broken CMD38 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 83b81fd..cfb3c99 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -292,18 +292,6 @@ struct mmc_host {
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> -#ifdef CONFIG_MMC_CLKGATE
> -       int                     clk_requests;   /* internal reference counter */
> -       unsigned int            clk_delay;      /* number of MCI clk hold cycles */
> -       bool                    clk_gated;      /* clock gated */
> -       struct delayed_work     clk_gate_work; /* delayed clock gate */
> -       unsigned int            clk_old;        /* old clock value cache */
> -       spinlock_t              clk_lock;       /* lock for clk fields */
> -       struct mutex            clk_gate_mutex; /* mutex for clock gating */
> -       struct device_attribute clkgate_delay_attr;
> -       unsigned long           clkgate_delay;
> -#endif
> -
>         /* host specific block data */
>         unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
>         unsigned short          max_segs;       /* see blk_queue_max_segments */
> @@ -479,26 +467,6 @@ static inline int mmc_host_packed_wr(struct mmc_host *host)
>         return host->caps2 & MMC_CAP2_PACKED_WR;
>  }
>
> -#ifdef CONFIG_MMC_CLKGATE
> -void mmc_host_clk_hold(struct mmc_host *host);
> -void mmc_host_clk_release(struct mmc_host *host);
> -unsigned int mmc_host_clk_rate(struct mmc_host *host);
> -
> -#else
> -static inline void mmc_host_clk_hold(struct mmc_host *host)
> -{
> -}
> -
> -static inline void mmc_host_clk_release(struct mmc_host *host)
> -{
> -}
> -
> -static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
> -{
> -       return host->ios.clock;
> -}
> -#endif
> -
>  static inline int mmc_card_hs(struct mmc_card *card)
>  {
>         return card->host->ios.timing == MMC_TIMING_SD_HS ||
> --
> 1.9.1
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ritesh Harjani (IBM) Oct. 12, 2015, 7:53 a.m. UTC | #3
Hi Ulf,

Wanted to understand this better, related to clk-gating and runtime-PM
before we completely remove clk-gating functionality.
Inline queries -


On Thu, Oct 8, 2015 at 11:05 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 2 October 2015 at 10:56, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> MMC_CLKGATE was once invented to save power by gating the bus clock at
>> request inactivity. At that time it served its purpose. The modern way to
>> deal with power saving for these scenarios, is by using runtime PM.

Inactivity duration of clk-gating and runtime PM can actually vary largely.
clk-gating can be used to turn the clks-off after a very short
duration of request inactivity say 200ms - (which can be used to save
the power of some voltage rail or something)
While runtime-PM would need ~10sec since it involves chain of devices
to be suspended.

For that to happen, we would need a longer duration of request
inactivity otherwise we would end up loosing power
if suspend keeps failing and often resumes are done to serve the request.


So, do you suggest to use runtime-PM in a way that can be used to gate
the clks-off in shorter duration and
then schedule the work for suspending of devices after longer duration
of request inactivity.

Sorry, if I am sounding foolish at any place, but I would like to
understand how are we handling the above problem if we remove
clk-gating?


>>
>> Nowadays, several host drivers have deployed runtime PM, but for those
>> that haven't and which still cares power saving at request inactivity,
>> it's certainly time to deploy runtime PM as it has been around for several
>> years now.

So, do you suggest here to use runtime-PM in a way that can be used to
gate the clks-off in shorter duration and
then schedule the work for suspending of devices after longer duration
of request inactivity.

>>
>> To simplify code to mmc core and thus decrease maintenance efforts, this
>> patch removes all code related to MMC_CLKGATE.
>>
>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>
> I have queued this up for next to get some testing in linux-next and
> kernelci. Still, it's not too late to provide input to the patch.
>
> Kind regards
> Uffe
>
>> ---
>>  Documentation/mmc/mmc-dev-attrs.txt |  10 --
>>  drivers/mmc/core/Kconfig            |  10 --
>>  drivers/mmc/core/core.c             | 139 +++-----------------
>>  drivers/mmc/core/core.h             |   3 -
>>  drivers/mmc/core/debugfs.c          |   5 -
>>  drivers/mmc/core/host.c             | 245 ------------------------------------
>>  drivers/mmc/core/mmc.c              |   6 +-
>>  drivers/mmc/core/quirks.c           |  18 ---
>>  drivers/mmc/core/sd.c               |   2 -
>>  drivers/mmc/core/sdio.c             |   7 +-
>>  drivers/mmc/core/sdio_irq.c         |  14 +--
>>  include/linux/mmc/card.h            |   1 -
>>  include/linux/mmc/host.h            |  32 -----
>>  13 files changed, 20 insertions(+), 472 deletions(-)
>>
>> diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
>> index 189bab0..caa5557 100644
>> --- a/Documentation/mmc/mmc-dev-attrs.txt
>> +++ b/Documentation/mmc/mmc-dev-attrs.txt
>> @@ -72,13 +72,3 @@ Note on raw_rpmb_size_mult:
>>         "raw_rpmb_size_mult" is a mutliple of 128kB block.
>>         RPMB size in byte is calculated by using the following equation:
>>         RPMB partition size = 128kB x raw_rpmb_size_mult
>> -
>> -SD/MMC/SDIO Clock Gating Attribute
>> -==================================
>> -
>> -Read and write access is provided to following attribute.
>> -This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
>> -
>> -       clkgate_delay   Tune the clock gating delay with desired value in milliseconds.
>> -
>> -echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
>> diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
>> index 9ebee72..4c33d76 100644
>> --- a/drivers/mmc/core/Kconfig
>> +++ b/drivers/mmc/core/Kconfig
>> @@ -1,13 +1,3 @@
>>  #
>>  # MMC core configuration
>>  #
>> -
>> -config MMC_CLKGATE
>> -       bool "MMC host clock gating"
>> -       help
>> -         This will attempt to aggressively gate the clock to the MMC card.
>> -         This is done to save power due to gating off the logic and bus
>> -         noise when the MMC card is not in use. Your host driver has to
>> -         support handling this in order for it to be of any use.
>> -
>> -         If unsure, say N.
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 21cda23..1a36b02 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -187,8 +187,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
>>
>>                 if (mrq->done)
>>                         mrq->done(mrq);
>> -
>> -               mmc_host_clk_release(host);
>>         }
>>  }
>>
>> @@ -292,7 +290,6 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>>                         mrq->stop->mrq = mrq;
>>                 }
>>         }
>> -       mmc_host_clk_hold(host);
>>         led_trigger_event(host->led, LED_FULL);
>>         __mmc_start_request(host, mrq);
>>
>> @@ -542,11 +539,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
>>  static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
>>                  bool is_first_req)
>>  {
>> -       if (host->ops->pre_req) {
>> -               mmc_host_clk_hold(host);
>> +       if (host->ops->pre_req)
>>                 host->ops->pre_req(host, mrq, is_first_req);
>> -               mmc_host_clk_release(host);
>> -       }
>>  }
>>
>>  /**
>> @@ -561,11 +555,8 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
>>  static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
>>                          int err)
>>  {
>> -       if (host->ops->post_req) {
>> -               mmc_host_clk_hold(host);
>> +       if (host->ops->post_req)
>>                 host->ops->post_req(host, mrq, err);
>> -               mmc_host_clk_release(host);
>> -       }
>>  }
>>
>>  /**
>> @@ -850,9 +841,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
>>                 unsigned int timeout_us, limit_us;
>>
>>                 timeout_us = data->timeout_ns / 1000;
>> -               if (mmc_host_clk_rate(card->host))
>> +               if (card->host->ios.clock)
>>                         timeout_us += data->timeout_clks * 1000 /
>> -                               (mmc_host_clk_rate(card->host) / 1000);
>> +                               (card->host->ios.clock / 1000);
>>
>>                 if (data->flags & MMC_DATA_WRITE)
>>                         /*
>> @@ -1050,8 +1041,6 @@ static inline void mmc_set_ios(struct mmc_host *host)
>>                  ios->power_mode, ios->chip_select, ios->vdd,
>>                  ios->bus_width, ios->timing);
>>
>> -       if (ios->clock > 0)
>> -               mmc_set_ungated(host);
>>         host->ops->set_ios(host, ios);
>>  }
>>
>> @@ -1060,17 +1049,15 @@ static inline void mmc_set_ios(struct mmc_host *host)
>>   */
>>  void mmc_set_chip_select(struct mmc_host *host, int mode)
>>  {
>> -       mmc_host_clk_hold(host);
>>         host->ios.chip_select = mode;
>>         mmc_set_ios(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  /*
>>   * Sets the host clock to the highest possible frequency that
>>   * is below "hz".
>>   */
>> -static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
>> +void mmc_set_clock(struct mmc_host *host, unsigned int hz)
>>  {
>>         WARN_ON(hz && hz < host->f_min);
>>
>> @@ -1081,68 +1068,6 @@ static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
>>         mmc_set_ios(host);
>>  }
>>
>> -void mmc_set_clock(struct mmc_host *host, unsigned int hz)
>> -{
>> -       mmc_host_clk_hold(host);
>> -       __mmc_set_clock(host, hz);
>> -       mmc_host_clk_release(host);
>> -}
>> -
>> -#ifdef CONFIG_MMC_CLKGATE
>> -/*
>> - * This gates the clock by setting it to 0 Hz.
>> - */
>> -void mmc_gate_clock(struct mmc_host *host)
>> -{
>> -       unsigned long flags;
>> -
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       host->clk_old = host->ios.clock;
>> -       host->ios.clock = 0;
>> -       host->clk_gated = true;
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -       mmc_set_ios(host);
>> -}
>> -
>> -/*
>> - * This restores the clock from gating by using the cached
>> - * clock value.
>> - */
>> -void mmc_ungate_clock(struct mmc_host *host)
>> -{
>> -       /*
>> -        * We should previously have gated the clock, so the clock shall
>> -        * be 0 here! The clock may however be 0 during initialization,
>> -        * when some request operations are performed before setting
>> -        * the frequency. When ungate is requested in that situation
>> -        * we just ignore the call.
>> -        */
>> -       if (host->clk_old) {
>> -               BUG_ON(host->ios.clock);
>> -               /* This call will also set host->clk_gated to false */
>> -               __mmc_set_clock(host, host->clk_old);
>> -       }
>> -}
>> -
>> -void mmc_set_ungated(struct mmc_host *host)
>> -{
>> -       unsigned long flags;
>> -
>> -       /*
>> -        * We've been given a new frequency while the clock is gated,
>> -        * so make sure we regard this as ungating it.
>> -        */
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       host->clk_gated = false;
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -}
>> -
>> -#else
>> -void mmc_set_ungated(struct mmc_host *host)
>> -{
>> -}
>> -#endif
>> -
>>  int mmc_execute_tuning(struct mmc_card *card)
>>  {
>>         struct mmc_host *host = card->host;
>> @@ -1157,9 +1082,7 @@ int mmc_execute_tuning(struct mmc_card *card)
>>         else
>>                 opcode = MMC_SEND_TUNING_BLOCK;
>>
>> -       mmc_host_clk_hold(host);
>>         err = host->ops->execute_tuning(host, opcode);
>> -       mmc_host_clk_release(host);
>>
>>         if (err)
>>                 pr_err("%s: tuning execution failed\n", mmc_hostname(host));
>> @@ -1174,10 +1097,8 @@ int mmc_execute_tuning(struct mmc_card *card)
>>   */
>>  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
>>  {
>> -       mmc_host_clk_hold(host);
>>         host->ios.bus_mode = mode;
>>         mmc_set_ios(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  /*
>> @@ -1185,10 +1106,8 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
>>   */
>>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
>>  {
>> -       mmc_host_clk_hold(host);
>>         host->ios.bus_width = width;
>>         mmc_set_ios(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  /*
>> @@ -1532,11 +1451,8 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
>>         int old_signal_voltage = host->ios.signal_voltage;
>>
>>         host->ios.signal_voltage = signal_voltage;
>> -       if (host->ops->start_signal_voltage_switch) {
>> -               mmc_host_clk_hold(host);
>> +       if (host->ops->start_signal_voltage_switch)
>>                 err = host->ops->start_signal_voltage_switch(host, &host->ios);
>> -               mmc_host_clk_release(host);
>> -       }
>>
>>         if (err)
>>                 host->ios.signal_voltage = old_signal_voltage;
>> @@ -1570,20 +1486,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
>>                 pr_warn("%s: cannot verify signal voltage switch\n",
>>                         mmc_hostname(host));
>>
>> -       mmc_host_clk_hold(host);
>> -
>>         cmd.opcode = SD_SWITCH_VOLTAGE;
>>         cmd.arg = 0;
>>         cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
>>
>>         err = mmc_wait_for_cmd(host, &cmd, 0);
>>         if (err)
>> -               goto err_command;
>> +               return err;
>> +
>> +       if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
>> +               return -EIO;
>>
>> -       if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
>> -               err = -EIO;
>> -               goto err_command;
>> -       }
>>         /*
>>          * The card should drive cmd and dat[0:3] low immediately
>>          * after the response of cmd11, but wait 1 ms to be sure
>> @@ -1632,9 +1545,6 @@ power_cycle:
>>                 mmc_power_cycle(host, ocr);
>>         }
>>
>> -err_command:
>> -       mmc_host_clk_release(host);
>> -
>>         return err;
>>  }
>>
>> @@ -1643,10 +1553,8 @@ err_command:
>>   */
>>  void mmc_set_timing(struct mmc_host *host, unsigned int timing)
>>  {
>> -       mmc_host_clk_hold(host);
>>         host->ios.timing = timing;
>>         mmc_set_ios(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  /*
>> @@ -1654,10 +1562,8 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
>>   */
>>  void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
>>  {
>> -       mmc_host_clk_hold(host);
>>         host->ios.drv_type = drv_type;
>>         mmc_set_ios(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
>> @@ -1665,7 +1571,6 @@ int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
>>  {
>>         struct mmc_host *host = card->host;
>>         int host_drv_type = SD_DRIVER_TYPE_B;
>> -       int drive_strength;
>>
>>         *drv_type = 0;
>>
>> @@ -1688,14 +1593,10 @@ int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
>>          * information and let the hardware specific code
>>          * return what is possible given the options
>>          */
>> -       mmc_host_clk_hold(host);
>> -       drive_strength = host->ops->select_drive_strength(card, max_dtr,
>> -                                                         host_drv_type,
>> -                                                         card_drv_type,
>> -                                                         drv_type);
>> -       mmc_host_clk_release(host);
>> -
>> -       return drive_strength;
>> +       return host->ops->select_drive_strength(card, max_dtr,
>> +                                               host_drv_type,
>> +                                               card_drv_type,
>> +                                               drv_type);
>>  }
>>
>>  /*
>> @@ -1714,8 +1615,6 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
>>         if (host->ios.power_mode == MMC_POWER_ON)
>>                 return;
>>
>> -       mmc_host_clk_hold(host);
>> -
>>         mmc_pwrseq_pre_power_on(host);
>>
>>         host->ios.vdd = fls(ocr) - 1;
>> @@ -1749,8 +1648,6 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
>>          * time required to reach a stable voltage.
>>          */
>>         mmc_delay(10);
>> -
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  void mmc_power_off(struct mmc_host *host)
>> @@ -1758,8 +1655,6 @@ void mmc_power_off(struct mmc_host *host)
>>         if (host->ios.power_mode == MMC_POWER_OFF)
>>                 return;
>>
>> -       mmc_host_clk_hold(host);
>> -
>>         mmc_pwrseq_power_off(host);
>>
>>         host->ios.clock = 0;
>> @@ -1775,8 +1670,6 @@ void mmc_power_off(struct mmc_host *host)
>>          * can be successfully turned on again.
>>          */
>>         mmc_delay(1);
>> -
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  void mmc_power_cycle(struct mmc_host *host, u32 ocr)
>> @@ -1992,7 +1885,7 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
>>                  */
>>                 timeout_clks <<= 1;
>>                 timeout_us += (timeout_clks * 1000) /
>> -                             (mmc_host_clk_rate(card->host) / 1000);
>> +                             (card->host->ios.clock / 1000);
>>
>>                 erase_timeout = timeout_us / 1000;
>>
>> @@ -2440,9 +2333,7 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
>>  {
>>         if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
>>                 return;
>> -       mmc_host_clk_hold(host);
>>         host->ops->hw_reset(host);
>> -       mmc_host_clk_release(host);
>>  }
>>
>>  int mmc_hw_reset(struct mmc_host *host)
>> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
>> index 1a22a82..09241e5 100644
>> --- a/drivers/mmc/core/core.h
>> +++ b/drivers/mmc/core/core.h
>> @@ -40,9 +40,6 @@ void mmc_init_erase(struct mmc_card *card);
>>
>>  void mmc_set_chip_select(struct mmc_host *host, int mode);
>>  void mmc_set_clock(struct mmc_host *host, unsigned int hz);
>> -void mmc_gate_clock(struct mmc_host *host);
>> -void mmc_ungate_clock(struct mmc_host *host);
>> -void mmc_set_ungated(struct mmc_host *host);
>>  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
>>  void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
>>  u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
>> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> index f4db93e..154aced 100644
>> --- a/drivers/mmc/core/debugfs.c
>> +++ b/drivers/mmc/core/debugfs.c
>> @@ -255,11 +255,6 @@ void mmc_add_host_debugfs(struct mmc_host *host)
>>                         &mmc_clock_fops))
>>                 goto err_node;
>>
>> -#ifdef CONFIG_MMC_CLKGATE
>> -       if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
>> -                               root, &host->clk_delay))
>> -               goto err_node;
>> -#endif
>>  #ifdef CONFIG_FAIL_MMC_REQUEST
>>         if (fail_request)
>>                 setup_fault_attr(&fail_default_attr, fail_request);
>> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
>> index 5466f25..970e690 100644
>> --- a/drivers/mmc/core/host.c
>> +++ b/drivers/mmc/core/host.c
>> @@ -61,246 +61,6 @@ void mmc_unregister_host_class(void)
>>         class_unregister(&mmc_host_class);
>>  }
>>
>> -#ifdef CONFIG_MMC_CLKGATE
>> -static ssize_t clkgate_delay_show(struct device *dev,
>> -               struct device_attribute *attr, char *buf)
>> -{
>> -       struct mmc_host *host = cls_dev_to_mmc_host(dev);
>> -       return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
>> -}
>> -
>> -static ssize_t clkgate_delay_store(struct device *dev,
>> -               struct device_attribute *attr, const char *buf, size_t count)
>> -{
>> -       struct mmc_host *host = cls_dev_to_mmc_host(dev);
>> -       unsigned long flags, value;
>> -
>> -       if (kstrtoul(buf, 0, &value))
>> -               return -EINVAL;
>> -
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       host->clkgate_delay = value;
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -       return count;
>> -}
>> -
>> -/*
>> - * Enabling clock gating will make the core call out to the host
>> - * once up and once down when it performs a request or card operation
>> - * intermingled in any fashion. The driver will see this through
>> - * set_ios() operations with ios.clock field set to 0 to gate (disable)
>> - * the block clock, and to the old frequency to enable it again.
>> - */
>> -static void mmc_host_clk_gate_delayed(struct mmc_host *host)
>> -{
>> -       unsigned long tick_ns;
>> -       unsigned long freq = host->ios.clock;
>> -       unsigned long flags;
>> -
>> -       if (!freq) {
>> -               pr_debug("%s: frequency set to 0 in disable function, "
>> -                        "this means the clock is already disabled.\n",
>> -                        mmc_hostname(host));
>> -               return;
>> -       }
>> -       /*
>> -        * New requests may have appeared while we were scheduling,
>> -        * then there is no reason to delay the check before
>> -        * clk_disable().
>> -        */
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -
>> -       /*
>> -        * Delay n bus cycles (at least 8 from MMC spec) before attempting
>> -        * to disable the MCI block clock. The reference count may have
>> -        * gone up again after this delay due to rescheduling!
>> -        */
>> -       if (!host->clk_requests) {
>> -               spin_unlock_irqrestore(&host->clk_lock, flags);
>> -               tick_ns = DIV_ROUND_UP(1000000000, freq);
>> -               ndelay(host->clk_delay * tick_ns);
>> -       } else {
>> -               /* New users appeared while waiting for this work */
>> -               spin_unlock_irqrestore(&host->clk_lock, flags);
>> -               return;
>> -       }
>> -       mutex_lock(&host->clk_gate_mutex);
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       if (!host->clk_requests) {
>> -               spin_unlock_irqrestore(&host->clk_lock, flags);
>> -               /* This will set host->ios.clock to 0 */
>> -               mmc_gate_clock(host);
>> -               spin_lock_irqsave(&host->clk_lock, flags);
>> -               pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
>> -       }
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -       mutex_unlock(&host->clk_gate_mutex);
>> -}
>> -
>> -/*
>> - * Internal work. Work to disable the clock at some later point.
>> - */
>> -static void mmc_host_clk_gate_work(struct work_struct *work)
>> -{
>> -       struct mmc_host *host = container_of(work, struct mmc_host,
>> -                                             clk_gate_work.work);
>> -
>> -       mmc_host_clk_gate_delayed(host);
>> -}
>> -
>> -/**
>> - *     mmc_host_clk_hold - ungate hardware MCI clocks
>> - *     @host: host to ungate.
>> - *
>> - *     Makes sure the host ios.clock is restored to a non-zero value
>> - *     past this call. Increase clock reference count and ungate clock
>> - *     if we're the first user.
>> - */
>> -void mmc_host_clk_hold(struct mmc_host *host)
>> -{
>> -       unsigned long flags;
>> -
>> -       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
>> -       cancel_delayed_work_sync(&host->clk_gate_work);
>> -       mutex_lock(&host->clk_gate_mutex);
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       if (host->clk_gated) {
>> -               spin_unlock_irqrestore(&host->clk_lock, flags);
>> -               mmc_ungate_clock(host);
>> -               spin_lock_irqsave(&host->clk_lock, flags);
>> -               pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
>> -       }
>> -       host->clk_requests++;
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -       mutex_unlock(&host->clk_gate_mutex);
>> -}
>> -
>> -/**
>> - *     mmc_host_may_gate_card - check if this card may be gated
>> - *     @card: card to check.
>> - */
>> -static bool mmc_host_may_gate_card(struct mmc_card *card)
>> -{
>> -       /* If there is no card we may gate it */
>> -       if (!card)
>> -               return true;
>> -       /*
>> -        * Don't gate SDIO cards! These need to be clocked at all times
>> -        * since they may be independent systems generating interrupts
>> -        * and other events. The clock requests counter from the core will
>> -        * go down to zero since the core does not need it, but we will not
>> -        * gate the clock, because there is somebody out there that may still
>> -        * be using it.
>> -        */
>> -       return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
>> -}
>> -
>> -/**
>> - *     mmc_host_clk_release - gate off hardware MCI clocks
>> - *     @host: host to gate.
>> - *
>> - *     Calls the host driver with ios.clock set to zero as often as possible
>> - *     in order to gate off hardware MCI clocks. Decrease clock reference
>> - *     count and schedule disabling of clock.
>> - */
>> -void mmc_host_clk_release(struct mmc_host *host)
>> -{
>> -       unsigned long flags;
>> -
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       host->clk_requests--;
>> -       if (mmc_host_may_gate_card(host->card) &&
>> -           !host->clk_requests)
>> -               schedule_delayed_work(&host->clk_gate_work,
>> -                                     msecs_to_jiffies(host->clkgate_delay));
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -}
>> -
>> -/**
>> - *     mmc_host_clk_rate - get current clock frequency setting
>> - *     @host: host to get the clock frequency for.
>> - *
>> - *     Returns current clock frequency regardless of gating.
>> - */
>> -unsigned int mmc_host_clk_rate(struct mmc_host *host)
>> -{
>> -       unsigned long freq;
>> -       unsigned long flags;
>> -
>> -       spin_lock_irqsave(&host->clk_lock, flags);
>> -       if (host->clk_gated)
>> -               freq = host->clk_old;
>> -       else
>> -               freq = host->ios.clock;
>> -       spin_unlock_irqrestore(&host->clk_lock, flags);
>> -       return freq;
>> -}
>> -
>> -/**
>> - *     mmc_host_clk_init - set up clock gating code
>> - *     @host: host with potential clock to control
>> - */
>> -static inline void mmc_host_clk_init(struct mmc_host *host)
>> -{
>> -       host->clk_requests = 0;
>> -       /* Hold MCI clock for 8 cycles by default */
>> -       host->clk_delay = 8;
>> -       /*
>> -        * Default clock gating delay is 0ms to avoid wasting power.
>> -        * This value can be tuned by writing into sysfs entry.
>> -        */
>> -       host->clkgate_delay = 0;
>> -       host->clk_gated = false;
>> -       INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
>> -       spin_lock_init(&host->clk_lock);
>> -       mutex_init(&host->clk_gate_mutex);
>> -}
>> -
>> -/**
>> - *     mmc_host_clk_exit - shut down clock gating code
>> - *     @host: host with potential clock to control
>> - */
>> -static inline void mmc_host_clk_exit(struct mmc_host *host)
>> -{
>> -       /*
>> -        * Wait for any outstanding gate and then make sure we're
>> -        * ungated before exiting.
>> -        */
>> -       if (cancel_delayed_work_sync(&host->clk_gate_work))
>> -               mmc_host_clk_gate_delayed(host);
>> -       if (host->clk_gated)
>> -               mmc_host_clk_hold(host);
>> -       /* There should be only one user now */
>> -       WARN_ON(host->clk_requests > 1);
>> -}
>> -
>> -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
>> -{
>> -       host->clkgate_delay_attr.show = clkgate_delay_show;
>> -       host->clkgate_delay_attr.store = clkgate_delay_store;
>> -       sysfs_attr_init(&host->clkgate_delay_attr.attr);
>> -       host->clkgate_delay_attr.attr.name = "clkgate_delay";
>> -       host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
>> -       if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
>> -               pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
>> -                               mmc_hostname(host));
>> -}
>> -#else
>> -
>> -static inline void mmc_host_clk_init(struct mmc_host *host)
>> -{
>> -}
>> -
>> -static inline void mmc_host_clk_exit(struct mmc_host *host)
>> -{
>> -}
>> -
>> -static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
>> -{
>> -}
>> -
>> -#endif
>> -
>>  void mmc_retune_enable(struct mmc_host *host)
>>  {
>>         host->can_retune = 1;
>> @@ -583,8 +343,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
>>                 return NULL;
>>         }
>>
>> -       mmc_host_clk_init(host);
>> -
>>         spin_lock_init(&host->lock);
>>         init_waitqueue_head(&host->wq);
>>         INIT_DELAYED_WORK(&host->detect, mmc_rescan);
>> @@ -633,7 +391,6 @@ int mmc_add_host(struct mmc_host *host)
>>  #ifdef CONFIG_DEBUG_FS
>>         mmc_add_host_debugfs(host);
>>  #endif
>> -       mmc_host_clk_sysfs_init(host);
>>
>>         mmc_start_host(host);
>>         register_pm_notifier(&host->pm_notify);
>> @@ -663,8 +420,6 @@ void mmc_remove_host(struct mmc_host *host)
>>         device_del(&host->class_dev);
>>
>>         led_trigger_unregister_simple(host->led);
>> -
>> -       mmc_host_clk_exit(host);
>>  }
>>
>>  EXPORT_SYMBOL(mmc_remove_host);
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index e726903..1b8907f 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -1932,20 +1932,16 @@ static int mmc_reset(struct mmc_host *host)
>>         if (!mmc_can_reset(card))
>>                 return -EOPNOTSUPP;
>>
>> -       mmc_host_clk_hold(host);
>>         mmc_set_clock(host, host->f_init);
>>
>>         host->ops->hw_reset(host);
>>
>>         /* If the reset has happened, then a status command will fail */
>> -       if (!mmc_send_status(card, &status)) {
>> -               mmc_host_clk_release(host);
>> +       if (!mmc_send_status(card, &status))
>>                 return -ENOSYS;
>> -       }
>>
>>         /* Set initial state and call mmc_set_ios */
>>         mmc_set_initial_state(host);
>> -       mmc_host_clk_release(host);
>>
>>         return mmc_init_card(host, card->ocr, card);
>>  }
>> diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
>> index dd1d1e0..fad660b 100644
>> --- a/drivers/mmc/core/quirks.c
>> +++ b/drivers/mmc/core/quirks.c
>> @@ -35,25 +35,7 @@
>>  #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
>>  #endif
>>
>> -/*
>> - * This hook just adds a quirk for all sdio devices
>> - */
>> -static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
>> -{
>> -       if (mmc_card_sdio(card))
>> -               card->quirks |= data;
>> -}
>> -
>>  static const struct mmc_fixup mmc_fixup_methods[] = {
>> -       /* by default sdio devices are considered CLK_GATING broken */
>> -       /* good cards will be whitelisted as they are tested */
>> -       SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
>> -                  add_quirk_for_sdio_devices,
>> -                  MMC_QUIRK_BROKEN_CLK_GATING),
>> -
>> -       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
>> -                  remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
>> -
>>         SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
>>                    add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
>>
>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> index e28ebf3..60a18ab 100644
>> --- a/drivers/mmc/core/sd.c
>> +++ b/drivers/mmc/core/sd.c
>> @@ -784,9 +784,7 @@ static int mmc_sd_get_ro(struct mmc_host *host)
>>         if (!host->ops->get_ro)
>>                 return -1;
>>
>> -       mmc_host_clk_hold(host);
>>         ro = host->ops->get_ro(host);
>> -       mmc_host_clk_release(host);
>>
>>         return ro;
>>  }
>> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> index 95bc101..16d838e 100644
>> --- a/drivers/mmc/core/sdio.c
>> +++ b/drivers/mmc/core/sdio.c
>> @@ -956,13 +956,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
>>         }
>>
>>         if (!err && host->sdio_irqs) {
>> -               if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
>> +               if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
>>                         wake_up_process(host->sdio_irq_thread);
>> -               } else if (host->caps & MMC_CAP_SDIO_IRQ) {
>> -                       mmc_host_clk_hold(host);
>> +               else if (host->caps & MMC_CAP_SDIO_IRQ)
>>                         host->ops->enable_sdio_irq(host, 1);
>> -                       mmc_host_clk_release(host);
>> -               }
>>         }
>>
>>         mmc_release_host(host);
>> diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
>> index 09cc67d..91bbbfb 100644
>> --- a/drivers/mmc/core/sdio_irq.c
>> +++ b/drivers/mmc/core/sdio_irq.c
>> @@ -168,21 +168,15 @@ static int sdio_irq_thread(void *_host)
>>                 }
>>
>>                 set_current_state(TASK_INTERRUPTIBLE);
>> -               if (host->caps & MMC_CAP_SDIO_IRQ) {
>> -                       mmc_host_clk_hold(host);
>> +               if (host->caps & MMC_CAP_SDIO_IRQ)
>>                         host->ops->enable_sdio_irq(host, 1);
>> -                       mmc_host_clk_release(host);
>> -               }
>>                 if (!kthread_should_stop())
>>                         schedule_timeout(period);
>>                 set_current_state(TASK_RUNNING);
>>         } while (!kthread_should_stop());
>>
>> -       if (host->caps & MMC_CAP_SDIO_IRQ) {
>> -               mmc_host_clk_hold(host);
>> +       if (host->caps & MMC_CAP_SDIO_IRQ)
>>                 host->ops->enable_sdio_irq(host, 0);
>> -               mmc_host_clk_release(host);
>> -       }
>>
>>         pr_debug("%s: IRQ thread exiting with code %d\n",
>>                  mmc_hostname(host), ret);
>> @@ -208,9 +202,7 @@ static int sdio_card_irq_get(struct mmc_card *card)
>>                                 return err;
>>                         }
>>                 } else if (host->caps & MMC_CAP_SDIO_IRQ) {
>> -                       mmc_host_clk_hold(host);
>>                         host->ops->enable_sdio_irq(host, 1);
>> -                       mmc_host_clk_release(host);
>>                 }
>>         }
>>
>> @@ -229,9 +221,7 @@ static int sdio_card_irq_put(struct mmc_card *card)
>>                         atomic_set(&host->sdio_irq_thread_abort, 1);
>>                         kthread_stop(host->sdio_irq_thread);
>>                 } else if (host->caps & MMC_CAP_SDIO_IRQ) {
>> -                       mmc_host_clk_hold(host);
>>                         host->ops->enable_sdio_irq(host, 0);
>> -                       mmc_host_clk_release(host);
>>                 }
>>         }
>>
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index fdd0779..eb0151b 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -269,7 +269,6 @@ struct mmc_card {
>>                                                 /* for byte mode */
>>  #define MMC_QUIRK_NONSTD_SDIO  (1<<2)          /* non-standard SDIO card attached */
>>                                                 /* (missing CIA registers) */
>> -#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)     /* clock gating the sdio bus will make card fail */
>>  #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)                /* SDIO card has nonstd function interfaces */
>>  #define MMC_QUIRK_DISABLE_CD   (1<<5)          /* disconnect CD/DAT[3] resistor */
>>  #define MMC_QUIRK_INAND_CMD38  (1<<6)          /* iNAND devices have broken CMD38 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 83b81fd..cfb3c99 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -292,18 +292,6 @@ struct mmc_host {
>>
>>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>>
>> -#ifdef CONFIG_MMC_CLKGATE
>> -       int                     clk_requests;   /* internal reference counter */
>> -       unsigned int            clk_delay;      /* number of MCI clk hold cycles */
>> -       bool                    clk_gated;      /* clock gated */
>> -       struct delayed_work     clk_gate_work; /* delayed clock gate */
>> -       unsigned int            clk_old;        /* old clock value cache */
>> -       spinlock_t              clk_lock;       /* lock for clk fields */
>> -       struct mutex            clk_gate_mutex; /* mutex for clock gating */
>> -       struct device_attribute clkgate_delay_attr;
>> -       unsigned long           clkgate_delay;
>> -#endif
>> -
>>         /* host specific block data */
>>         unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
>>         unsigned short          max_segs;       /* see blk_queue_max_segments */
>> @@ -479,26 +467,6 @@ static inline int mmc_host_packed_wr(struct mmc_host *host)
>>         return host->caps2 & MMC_CAP2_PACKED_WR;
>>  }
>>
>> -#ifdef CONFIG_MMC_CLKGATE
>> -void mmc_host_clk_hold(struct mmc_host *host);
>> -void mmc_host_clk_release(struct mmc_host *host);
>> -unsigned int mmc_host_clk_rate(struct mmc_host *host);
>> -
>> -#else
>> -static inline void mmc_host_clk_hold(struct mmc_host *host)
>> -{
>> -}
>> -
>> -static inline void mmc_host_clk_release(struct mmc_host *host)
>> -{
>> -}
>> -
>> -static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
>> -{
>> -       return host->ios.clock;
>> -}
>> -#endif
>> -
>>  static inline int mmc_card_hs(struct mmc_card *card)
>>  {
>>         return card->host->ios.timing == MMC_TIMING_SD_HS ||
>> --
>> 1.9.1
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Oct. 12, 2015, 11:01 a.m. UTC | #4
On 12 October 2015 at 09:53, Ritesh Harjani <ritesh.list@gmail.com> wrote:
> Hi Ulf,
>
> Wanted to understand this better, related to clk-gating and runtime-PM
> before we completely remove clk-gating functionality.
> Inline queries -
>
>
> On Thu, Oct 8, 2015 at 11:05 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>> On 2 October 2015 at 10:56, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>>> MMC_CLKGATE was once invented to save power by gating the bus clock at
>>> request inactivity. At that time it served its purpose. The modern way to
>>> deal with power saving for these scenarios, is by using runtime PM.
>
> Inactivity duration of clk-gating and runtime PM can actually vary largely.
> clk-gating can be used to turn the clks-off after a very short
> duration of request inactivity say 200ms - (which can be used to save
> the power of some voltage rail or something)
> While runtime-PM would need ~10sec since it involves chain of devices
> to be suspended.

What do you mean by "chain of devices"?

You may refer to that runtime PM respect parent/child relations, but
even so, each device can be runtime PM managed on its own.

Regarding the inactivity duration, currently most mmc host drivers
which have enabled the runtime PM autosuspend feature, uses 50 ms as
the *default* timeout value.
I haven't heard of anyone considering a ~10s or in that range, but if
that's the case I guess power saving is just less important for these
cases.

>
> For that to happen, we would need a longer duration of request
> inactivity otherwise we would end up loosing power
> if suspend keeps failing and often resumes are done to serve the request.

Why would suspend fail?

>
>
> So, do you suggest to use runtime-PM in a way that can be used to gate
> the clks-off in shorter duration and
> then schedule the work for suspending of devices after longer duration
> of request inactivity.

Well, what I suggested was to remove MMC_CLKGATE and use runtime PM instead. :-)

It seem like you think you need an intermediate phase, where clock
gating make sense in the first phase and the actual runtime_suspend of
the device in second phase. I have yet understood why, but if I assume
that's the case one could potentially use the ->runtime_idle()
callback and friends, to deal with this.

>
> Sorry, if I am sounding foolish at any place, but I would like to
> understand how are we handling the above problem if we remove
> clk-gating?

No, worries - thanks for you comments!

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 189bab0..caa5557 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -72,13 +72,3 @@  Note on raw_rpmb_size_mult:
 	"raw_rpmb_size_mult" is a mutliple of 128kB block.
 	RPMB size in byte is calculated by using the following equation:
 	RPMB partition size = 128kB x raw_rpmb_size_mult
-
-SD/MMC/SDIO Clock Gating Attribute
-==================================
-
-Read and write access is provided to following attribute.
-This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
-
-	clkgate_delay	Tune the clock gating delay with desired value in milliseconds.
-
-echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 9ebee72..4c33d76 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -1,13 +1,3 @@ 
 #
 # MMC core configuration
 #
-
-config MMC_CLKGATE
-	bool "MMC host clock gating"
-	help
-	  This will attempt to aggressively gate the clock to the MMC card.
-	  This is done to save power due to gating off the logic and bus
-	  noise when the MMC card is not in use. Your host driver has to
-	  support handling this in order for it to be of any use.
-
-	  If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 21cda23..1a36b02 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -187,8 +187,6 @@  void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
 
 		if (mrq->done)
 			mrq->done(mrq);
-
-		mmc_host_clk_release(host);
 	}
 }
 
@@ -292,7 +290,6 @@  static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 			mrq->stop->mrq = mrq;
 		}
 	}
-	mmc_host_clk_hold(host);
 	led_trigger_event(host->led, LED_FULL);
 	__mmc_start_request(host, mrq);
 
@@ -542,11 +539,8 @@  static void mmc_wait_for_req_done(struct mmc_host *host,
 static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
 		 bool is_first_req)
 {
-	if (host->ops->pre_req) {
-		mmc_host_clk_hold(host);
+	if (host->ops->pre_req)
 		host->ops->pre_req(host, mrq, is_first_req);
-		mmc_host_clk_release(host);
-	}
 }
 
 /**
@@ -561,11 +555,8 @@  static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
 static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
 			 int err)
 {
-	if (host->ops->post_req) {
-		mmc_host_clk_hold(host);
+	if (host->ops->post_req)
 		host->ops->post_req(host, mrq, err);
-		mmc_host_clk_release(host);
-	}
 }
 
 /**
@@ -850,9 +841,9 @@  void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 		unsigned int timeout_us, limit_us;
 
 		timeout_us = data->timeout_ns / 1000;
-		if (mmc_host_clk_rate(card->host))
+		if (card->host->ios.clock)
 			timeout_us += data->timeout_clks * 1000 /
-				(mmc_host_clk_rate(card->host) / 1000);
+				(card->host->ios.clock / 1000);
 
 		if (data->flags & MMC_DATA_WRITE)
 			/*
@@ -1050,8 +1041,6 @@  static inline void mmc_set_ios(struct mmc_host *host)
 		 ios->power_mode, ios->chip_select, ios->vdd,
 		 ios->bus_width, ios->timing);
 
-	if (ios->clock > 0)
-		mmc_set_ungated(host);
 	host->ops->set_ios(host, ios);
 }
 
@@ -1060,17 +1049,15 @@  static inline void mmc_set_ios(struct mmc_host *host)
  */
 void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
-	mmc_host_clk_hold(host);
 	host->ios.chip_select = mode;
 	mmc_set_ios(host);
-	mmc_host_clk_release(host);
 }
 
 /*
  * Sets the host clock to the highest possible frequency that
  * is below "hz".
  */
-static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
 {
 	WARN_ON(hz && hz < host->f_min);
 
@@ -1081,68 +1068,6 @@  static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
 	mmc_set_ios(host);
 }
 
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
-{
-	mmc_host_clk_hold(host);
-	__mmc_set_clock(host, hz);
-	mmc_host_clk_release(host);
-}
-
-#ifdef CONFIG_MMC_CLKGATE
-/*
- * This gates the clock by setting it to 0 Hz.
- */
-void mmc_gate_clock(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->clk_lock, flags);
-	host->clk_old = host->ios.clock;
-	host->ios.clock = 0;
-	host->clk_gated = true;
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-	mmc_set_ios(host);
-}
-
-/*
- * This restores the clock from gating by using the cached
- * clock value.
- */
-void mmc_ungate_clock(struct mmc_host *host)
-{
-	/*
-	 * We should previously have gated the clock, so the clock shall
-	 * be 0 here! The clock may however be 0 during initialization,
-	 * when some request operations are performed before setting
-	 * the frequency. When ungate is requested in that situation
-	 * we just ignore the call.
-	 */
-	if (host->clk_old) {
-		BUG_ON(host->ios.clock);
-		/* This call will also set host->clk_gated to false */
-		__mmc_set_clock(host, host->clk_old);
-	}
-}
-
-void mmc_set_ungated(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	/*
-	 * We've been given a new frequency while the clock is gated,
-	 * so make sure we regard this as ungating it.
-	 */
-	spin_lock_irqsave(&host->clk_lock, flags);
-	host->clk_gated = false;
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-}
-
-#else
-void mmc_set_ungated(struct mmc_host *host)
-{
-}
-#endif
-
 int mmc_execute_tuning(struct mmc_card *card)
 {
 	struct mmc_host *host = card->host;
@@ -1157,9 +1082,7 @@  int mmc_execute_tuning(struct mmc_card *card)
 	else
 		opcode = MMC_SEND_TUNING_BLOCK;
 
-	mmc_host_clk_hold(host);
 	err = host->ops->execute_tuning(host, opcode);
-	mmc_host_clk_release(host);
 
 	if (err)
 		pr_err("%s: tuning execution failed\n", mmc_hostname(host));
@@ -1174,10 +1097,8 @@  int mmc_execute_tuning(struct mmc_card *card)
  */
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 {
-	mmc_host_clk_hold(host);
 	host->ios.bus_mode = mode;
 	mmc_set_ios(host);
-	mmc_host_clk_release(host);
 }
 
 /*
@@ -1185,10 +1106,8 @@  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
-	mmc_host_clk_hold(host);
 	host->ios.bus_width = width;
 	mmc_set_ios(host);
-	mmc_host_clk_release(host);
 }
 
 /*
@@ -1532,11 +1451,8 @@  int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
 	int old_signal_voltage = host->ios.signal_voltage;
 
 	host->ios.signal_voltage = signal_voltage;
-	if (host->ops->start_signal_voltage_switch) {
-		mmc_host_clk_hold(host);
+	if (host->ops->start_signal_voltage_switch)
 		err = host->ops->start_signal_voltage_switch(host, &host->ios);
-		mmc_host_clk_release(host);
-	}
 
 	if (err)
 		host->ios.signal_voltage = old_signal_voltage;
@@ -1570,20 +1486,17 @@  int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
 		pr_warn("%s: cannot verify signal voltage switch\n",
 			mmc_hostname(host));
 
-	mmc_host_clk_hold(host);
-
 	cmd.opcode = SD_SWITCH_VOLTAGE;
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
-		goto err_command;
+		return err;
+
+	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+		return -EIO;
 
-	if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
-		err = -EIO;
-		goto err_command;
-	}
 	/*
 	 * The card should drive cmd and dat[0:3] low immediately
 	 * after the response of cmd11, but wait 1 ms to be sure
@@ -1632,9 +1545,6 @@  power_cycle:
 		mmc_power_cycle(host, ocr);
 	}
 
-err_command:
-	mmc_host_clk_release(host);
-
 	return err;
 }
 
@@ -1643,10 +1553,8 @@  err_command:
  */
 void mmc_set_timing(struct mmc_host *host, unsigned int timing)
 {
-	mmc_host_clk_hold(host);
 	host->ios.timing = timing;
 	mmc_set_ios(host);
-	mmc_host_clk_release(host);
 }
 
 /*
@@ -1654,10 +1562,8 @@  void mmc_set_timing(struct mmc_host *host, unsigned int timing)
  */
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
 {
-	mmc_host_clk_hold(host);
 	host->ios.drv_type = drv_type;
 	mmc_set_ios(host);
-	mmc_host_clk_release(host);
 }
 
 int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -1665,7 +1571,6 @@  int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
 {
 	struct mmc_host *host = card->host;
 	int host_drv_type = SD_DRIVER_TYPE_B;
-	int drive_strength;
 
 	*drv_type = 0;
 
@@ -1688,14 +1593,10 @@  int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
 	 * information and let the hardware specific code
 	 * return what is possible given the options
 	 */
-	mmc_host_clk_hold(host);
-	drive_strength = host->ops->select_drive_strength(card, max_dtr,
-							  host_drv_type,
-							  card_drv_type,
-							  drv_type);
-	mmc_host_clk_release(host);
-
-	return drive_strength;
+	return host->ops->select_drive_strength(card, max_dtr,
+						host_drv_type,
+						card_drv_type,
+						drv_type);
 }
 
 /*
@@ -1714,8 +1615,6 @@  void mmc_power_up(struct mmc_host *host, u32 ocr)
 	if (host->ios.power_mode == MMC_POWER_ON)
 		return;
 
-	mmc_host_clk_hold(host);
-
 	mmc_pwrseq_pre_power_on(host);
 
 	host->ios.vdd = fls(ocr) - 1;
@@ -1749,8 +1648,6 @@  void mmc_power_up(struct mmc_host *host, u32 ocr)
 	 * time required to reach a stable voltage.
 	 */
 	mmc_delay(10);
-
-	mmc_host_clk_release(host);
 }
 
 void mmc_power_off(struct mmc_host *host)
@@ -1758,8 +1655,6 @@  void mmc_power_off(struct mmc_host *host)
 	if (host->ios.power_mode == MMC_POWER_OFF)
 		return;
 
-	mmc_host_clk_hold(host);
-
 	mmc_pwrseq_power_off(host);
 
 	host->ios.clock = 0;
@@ -1775,8 +1670,6 @@  void mmc_power_off(struct mmc_host *host)
 	 * can be successfully turned on again.
 	 */
 	mmc_delay(1);
-
-	mmc_host_clk_release(host);
 }
 
 void mmc_power_cycle(struct mmc_host *host, u32 ocr)
@@ -1992,7 +1885,7 @@  static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
 		 */
 		timeout_clks <<= 1;
 		timeout_us += (timeout_clks * 1000) /
-			      (mmc_host_clk_rate(card->host) / 1000);
+			      (card->host->ios.clock / 1000);
 
 		erase_timeout = timeout_us / 1000;
 
@@ -2440,9 +2333,7 @@  static void mmc_hw_reset_for_init(struct mmc_host *host)
 {
 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
 		return;
-	mmc_host_clk_hold(host);
 	host->ops->hw_reset(host);
-	mmc_host_clk_release(host);
 }
 
 int mmc_hw_reset(struct mmc_host *host)
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 1a22a82..09241e5 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -40,9 +40,6 @@  void mmc_init_erase(struct mmc_card *card);
 
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
-void mmc_gate_clock(struct mmc_host *host);
-void mmc_ungate_clock(struct mmc_host *host);
-void mmc_set_ungated(struct mmc_host *host);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index f4db93e..154aced 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -255,11 +255,6 @@  void mmc_add_host_debugfs(struct mmc_host *host)
 			&mmc_clock_fops))
 		goto err_node;
 
-#ifdef CONFIG_MMC_CLKGATE
-	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
-				root, &host->clk_delay))
-		goto err_node;
-#endif
 #ifdef CONFIG_FAIL_MMC_REQUEST
 	if (fail_request)
 		setup_fault_attr(&fail_default_attr, fail_request);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 5466f25..970e690 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -61,246 +61,6 @@  void mmc_unregister_host_class(void)
 	class_unregister(&mmc_host_class);
 }
 
-#ifdef CONFIG_MMC_CLKGATE
-static ssize_t clkgate_delay_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct mmc_host *host = cls_dev_to_mmc_host(dev);
-	return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
-}
-
-static ssize_t clkgate_delay_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct mmc_host *host = cls_dev_to_mmc_host(dev);
-	unsigned long flags, value;
-
-	if (kstrtoul(buf, 0, &value))
-		return -EINVAL;
-
-	spin_lock_irqsave(&host->clk_lock, flags);
-	host->clkgate_delay = value;
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-	return count;
-}
-
-/*
- * Enabling clock gating will make the core call out to the host
- * once up and once down when it performs a request or card operation
- * intermingled in any fashion. The driver will see this through
- * set_ios() operations with ios.clock field set to 0 to gate (disable)
- * the block clock, and to the old frequency to enable it again.
- */
-static void mmc_host_clk_gate_delayed(struct mmc_host *host)
-{
-	unsigned long tick_ns;
-	unsigned long freq = host->ios.clock;
-	unsigned long flags;
-
-	if (!freq) {
-		pr_debug("%s: frequency set to 0 in disable function, "
-			 "this means the clock is already disabled.\n",
-			 mmc_hostname(host));
-		return;
-	}
-	/*
-	 * New requests may have appeared while we were scheduling,
-	 * then there is no reason to delay the check before
-	 * clk_disable().
-	 */
-	spin_lock_irqsave(&host->clk_lock, flags);
-
-	/*
-	 * Delay n bus cycles (at least 8 from MMC spec) before attempting
-	 * to disable the MCI block clock. The reference count may have
-	 * gone up again after this delay due to rescheduling!
-	 */
-	if (!host->clk_requests) {
-		spin_unlock_irqrestore(&host->clk_lock, flags);
-		tick_ns = DIV_ROUND_UP(1000000000, freq);
-		ndelay(host->clk_delay * tick_ns);
-	} else {
-		/* New users appeared while waiting for this work */
-		spin_unlock_irqrestore(&host->clk_lock, flags);
-		return;
-	}
-	mutex_lock(&host->clk_gate_mutex);
-	spin_lock_irqsave(&host->clk_lock, flags);
-	if (!host->clk_requests) {
-		spin_unlock_irqrestore(&host->clk_lock, flags);
-		/* This will set host->ios.clock to 0 */
-		mmc_gate_clock(host);
-		spin_lock_irqsave(&host->clk_lock, flags);
-		pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
-	}
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-	mutex_unlock(&host->clk_gate_mutex);
-}
-
-/*
- * Internal work. Work to disable the clock at some later point.
- */
-static void mmc_host_clk_gate_work(struct work_struct *work)
-{
-	struct mmc_host *host = container_of(work, struct mmc_host,
-					      clk_gate_work.work);
-
-	mmc_host_clk_gate_delayed(host);
-}
-
-/**
- *	mmc_host_clk_hold - ungate hardware MCI clocks
- *	@host: host to ungate.
- *
- *	Makes sure the host ios.clock is restored to a non-zero value
- *	past this call.	Increase clock reference count and ungate clock
- *	if we're the first user.
- */
-void mmc_host_clk_hold(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	/* cancel any clock gating work scheduled by mmc_host_clk_release() */
-	cancel_delayed_work_sync(&host->clk_gate_work);
-	mutex_lock(&host->clk_gate_mutex);
-	spin_lock_irqsave(&host->clk_lock, flags);
-	if (host->clk_gated) {
-		spin_unlock_irqrestore(&host->clk_lock, flags);
-		mmc_ungate_clock(host);
-		spin_lock_irqsave(&host->clk_lock, flags);
-		pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
-	}
-	host->clk_requests++;
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-	mutex_unlock(&host->clk_gate_mutex);
-}
-
-/**
- *	mmc_host_may_gate_card - check if this card may be gated
- *	@card: card to check.
- */
-static bool mmc_host_may_gate_card(struct mmc_card *card)
-{
-	/* If there is no card we may gate it */
-	if (!card)
-		return true;
-	/*
-	 * Don't gate SDIO cards! These need to be clocked at all times
-	 * since they may be independent systems generating interrupts
-	 * and other events. The clock requests counter from the core will
-	 * go down to zero since the core does not need it, but we will not
-	 * gate the clock, because there is somebody out there that may still
-	 * be using it.
-	 */
-	return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
-}
-
-/**
- *	mmc_host_clk_release - gate off hardware MCI clocks
- *	@host: host to gate.
- *
- *	Calls the host driver with ios.clock set to zero as often as possible
- *	in order to gate off hardware MCI clocks. Decrease clock reference
- *	count and schedule disabling of clock.
- */
-void mmc_host_clk_release(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->clk_lock, flags);
-	host->clk_requests--;
-	if (mmc_host_may_gate_card(host->card) &&
-	    !host->clk_requests)
-		schedule_delayed_work(&host->clk_gate_work,
-				      msecs_to_jiffies(host->clkgate_delay));
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-}
-
-/**
- *	mmc_host_clk_rate - get current clock frequency setting
- *	@host: host to get the clock frequency for.
- *
- *	Returns current clock frequency regardless of gating.
- */
-unsigned int mmc_host_clk_rate(struct mmc_host *host)
-{
-	unsigned long freq;
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->clk_lock, flags);
-	if (host->clk_gated)
-		freq = host->clk_old;
-	else
-		freq = host->ios.clock;
-	spin_unlock_irqrestore(&host->clk_lock, flags);
-	return freq;
-}
-
-/**
- *	mmc_host_clk_init - set up clock gating code
- *	@host: host with potential clock to control
- */
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
-	host->clk_requests = 0;
-	/* Hold MCI clock for 8 cycles by default */
-	host->clk_delay = 8;
-	/*
-	 * Default clock gating delay is 0ms to avoid wasting power.
-	 * This value can be tuned by writing into sysfs entry.
-	 */
-	host->clkgate_delay = 0;
-	host->clk_gated = false;
-	INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
-	spin_lock_init(&host->clk_lock);
-	mutex_init(&host->clk_gate_mutex);
-}
-
-/**
- *	mmc_host_clk_exit - shut down clock gating code
- *	@host: host with potential clock to control
- */
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
-	/*
-	 * Wait for any outstanding gate and then make sure we're
-	 * ungated before exiting.
-	 */
-	if (cancel_delayed_work_sync(&host->clk_gate_work))
-		mmc_host_clk_gate_delayed(host);
-	if (host->clk_gated)
-		mmc_host_clk_hold(host);
-	/* There should be only one user now */
-	WARN_ON(host->clk_requests > 1);
-}
-
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
-{
-	host->clkgate_delay_attr.show = clkgate_delay_show;
-	host->clkgate_delay_attr.store = clkgate_delay_store;
-	sysfs_attr_init(&host->clkgate_delay_attr.attr);
-	host->clkgate_delay_attr.attr.name = "clkgate_delay";
-	host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
-	if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
-		pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
-				mmc_hostname(host));
-}
-#else
-
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
-}
-
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
-}
-
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
-{
-}
-
-#endif
-
 void mmc_retune_enable(struct mmc_host *host)
 {
 	host->can_retune = 1;
@@ -583,8 +343,6 @@  struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 		return NULL;
 	}
 
-	mmc_host_clk_init(host);
-
 	spin_lock_init(&host->lock);
 	init_waitqueue_head(&host->wq);
 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -633,7 +391,6 @@  int mmc_add_host(struct mmc_host *host)
 #ifdef CONFIG_DEBUG_FS
 	mmc_add_host_debugfs(host);
 #endif
-	mmc_host_clk_sysfs_init(host);
 
 	mmc_start_host(host);
 	register_pm_notifier(&host->pm_notify);
@@ -663,8 +420,6 @@  void mmc_remove_host(struct mmc_host *host)
 	device_del(&host->class_dev);
 
 	led_trigger_unregister_simple(host->led);
-
-	mmc_host_clk_exit(host);
 }
 
 EXPORT_SYMBOL(mmc_remove_host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e726903..1b8907f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1932,20 +1932,16 @@  static int mmc_reset(struct mmc_host *host)
 	if (!mmc_can_reset(card))
 		return -EOPNOTSUPP;
 
-	mmc_host_clk_hold(host);
 	mmc_set_clock(host, host->f_init);
 
 	host->ops->hw_reset(host);
 
 	/* If the reset has happened, then a status command will fail */
-	if (!mmc_send_status(card, &status)) {
-		mmc_host_clk_release(host);
+	if (!mmc_send_status(card, &status))
 		return -ENOSYS;
-	}
 
 	/* Set initial state and call mmc_set_ios */
 	mmc_set_initial_state(host);
-	mmc_host_clk_release(host);
 
 	return mmc_init_card(host, card->ocr, card);
 }
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index dd1d1e0..fad660b 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -35,25 +35,7 @@ 
 #define SDIO_DEVICE_ID_MARVELL_8797_F0	0x9128
 #endif
 
-/*
- * This hook just adds a quirk for all sdio devices
- */
-static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
-{
-	if (mmc_card_sdio(card))
-		card->quirks |= data;
-}
-
 static const struct mmc_fixup mmc_fixup_methods[] = {
-	/* by default sdio devices are considered CLK_GATING broken */
-	/* good cards will be whitelisted as they are tested */
-	SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
-		   add_quirk_for_sdio_devices,
-		   MMC_QUIRK_BROKEN_CLK_GATING),
-
-	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
-		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
-
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index e28ebf3..60a18ab 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -784,9 +784,7 @@  static int mmc_sd_get_ro(struct mmc_host *host)
 	if (!host->ops->get_ro)
 		return -1;
 
-	mmc_host_clk_hold(host);
 	ro = host->ops->get_ro(host);
-	mmc_host_clk_release(host);
 
 	return ro;
 }
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 95bc101..16d838e 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -956,13 +956,10 @@  static int mmc_sdio_resume(struct mmc_host *host)
 	}
 
 	if (!err && host->sdio_irqs) {
-		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
+		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
 			wake_up_process(host->sdio_irq_thread);
-		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
-			mmc_host_clk_hold(host);
+		else if (host->caps & MMC_CAP_SDIO_IRQ)
 			host->ops->enable_sdio_irq(host, 1);
-			mmc_host_clk_release(host);
-		}
 	}
 
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 09cc67d..91bbbfb 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -168,21 +168,15 @@  static int sdio_irq_thread(void *_host)
 		}
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (host->caps & MMC_CAP_SDIO_IRQ) {
-			mmc_host_clk_hold(host);
+		if (host->caps & MMC_CAP_SDIO_IRQ)
 			host->ops->enable_sdio_irq(host, 1);
-			mmc_host_clk_release(host);
-		}
 		if (!kthread_should_stop())
 			schedule_timeout(period);
 		set_current_state(TASK_RUNNING);
 	} while (!kthread_should_stop());
 
-	if (host->caps & MMC_CAP_SDIO_IRQ) {
-		mmc_host_clk_hold(host);
+	if (host->caps & MMC_CAP_SDIO_IRQ)
 		host->ops->enable_sdio_irq(host, 0);
-		mmc_host_clk_release(host);
-	}
 
 	pr_debug("%s: IRQ thread exiting with code %d\n",
 		 mmc_hostname(host), ret);
@@ -208,9 +202,7 @@  static int sdio_card_irq_get(struct mmc_card *card)
 				return err;
 			}
 		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
-			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 1);
-			mmc_host_clk_release(host);
 		}
 	}
 
@@ -229,9 +221,7 @@  static int sdio_card_irq_put(struct mmc_card *card)
 			atomic_set(&host->sdio_irq_thread_abort, 1);
 			kthread_stop(host->sdio_irq_thread);
 		} else if (host->caps & MMC_CAP_SDIO_IRQ) {
-			mmc_host_clk_hold(host);
 			host->ops->enable_sdio_irq(host, 0);
-			mmc_host_clk_release(host);
 		}
 	}
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fdd0779..eb0151b 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -269,7 +269,6 @@  struct mmc_card {
 						/* for byte mode */
 #define MMC_QUIRK_NONSTD_SDIO	(1<<2)		/* non-standard SDIO card attached */
 						/* (missing CIA registers) */
-#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)	/* clock gating the sdio bus will make card fail */
 #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)		/* SDIO card has nonstd function interfaces */
 #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */
 #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 83b81fd..cfb3c99 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -292,18 +292,6 @@  struct mmc_host {
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-#ifdef CONFIG_MMC_CLKGATE
-	int			clk_requests;	/* internal reference counter */
-	unsigned int		clk_delay;	/* number of MCI clk hold cycles */
-	bool			clk_gated;	/* clock gated */
-	struct delayed_work	clk_gate_work; /* delayed clock gate */
-	unsigned int		clk_old;	/* old clock value cache */
-	spinlock_t		clk_lock;	/* lock for clk fields */
-	struct mutex		clk_gate_mutex;	/* mutex for clock gating */
-	struct device_attribute clkgate_delay_attr;
-	unsigned long           clkgate_delay;
-#endif
-
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_segs;	/* see blk_queue_max_segments */
@@ -479,26 +467,6 @@  static inline int mmc_host_packed_wr(struct mmc_host *host)
 	return host->caps2 & MMC_CAP2_PACKED_WR;
 }
 
-#ifdef CONFIG_MMC_CLKGATE
-void mmc_host_clk_hold(struct mmc_host *host);
-void mmc_host_clk_release(struct mmc_host *host);
-unsigned int mmc_host_clk_rate(struct mmc_host *host);
-
-#else
-static inline void mmc_host_clk_hold(struct mmc_host *host)
-{
-}
-
-static inline void mmc_host_clk_release(struct mmc_host *host)
-{
-}
-
-static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
-{
-	return host->ios.clock;
-}
-#endif
-
 static inline int mmc_card_hs(struct mmc_card *card)
 {
 	return card->host->ios.timing == MMC_TIMING_SD_HS ||