aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/Kconfig11
-rw-r--r--drivers/mmc/core/core.c62
-rw-r--r--drivers/mmc/core/core.h3
-rw-r--r--drivers/mmc/core/debugfs.c5
-rw-r--r--drivers/mmc/core/host.c205
-rw-r--r--drivers/mmc/core/host.h21
6 files changed, 305 insertions, 2 deletions
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index bb22ffd76ef..ef103871517 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -16,3 +16,14 @@ config MMC_UNSAFE_RESUME
16 16
17 This option sets a default which can be overridden by the 17 This option sets a default which can be overridden by the
18 module parameter "removable=0" or "removable=1". 18 module parameter "removable=0" or "removable=1".
19
20config MMC_CLKGATE
21 bool "MMC host clock gating (EXPERIMENTAL)"
22 depends on EXPERIMENTAL
23 help
24 This will attempt to aggressively gate the clock to the MMC card.
25 This is done to save power due to gating off the logic and bus
26 noise when the MMC card is not in use. Your host driver has to
27 support handling this in order for it to be of any use.
28
29 If unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index a3a780faf85..722af2dce3b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -130,6 +130,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
130 130
131 if (mrq->done) 131 if (mrq->done)
132 mrq->done(mrq); 132 mrq->done(mrq);
133
134 mmc_host_clk_gate(host);
133 } 135 }
134} 136}
135 137
@@ -190,6 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
190 mrq->stop->mrq = mrq; 192 mrq->stop->mrq = mrq;
191 } 193 }
192 } 194 }
195 mmc_host_clk_ungate(host);
193 host->ops->request(host, mrq); 196 host->ops->request(host, mrq);
194} 197}
195 198
@@ -296,7 +299,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
296 299
297 timeout_us = data->timeout_ns / 1000; 300 timeout_us = data->timeout_ns / 1000;
298 timeout_us += data->timeout_clks * 1000 / 301 timeout_us += data->timeout_clks * 1000 /
299 (card->host->ios.clock / 1000); 302 (mmc_host_clk_rate(card->host) / 1000);
300 303
301 if (data->flags & MMC_DATA_WRITE) 304 if (data->flags & MMC_DATA_WRITE)
302 /* 305 /*
@@ -614,6 +617,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
614 ios->power_mode, ios->chip_select, ios->vdd, 617 ios->power_mode, ios->chip_select, ios->vdd,
615 ios->bus_width, ios->timing); 618 ios->bus_width, ios->timing);
616 619
620 if (ios->clock > 0)
621 mmc_set_ungated(host);
617 host->ops->set_ios(host, ios); 622 host->ops->set_ios(host, ios);
618} 623}
619 624
@@ -641,6 +646,61 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
641 mmc_set_ios(host); 646 mmc_set_ios(host);
642} 647}
643 648
649#ifdef CONFIG_MMC_CLKGATE
650/*
651 * This gates the clock by setting it to 0 Hz.
652 */
653void mmc_gate_clock(struct mmc_host *host)
654{
655 unsigned long flags;
656
657 spin_lock_irqsave(&host->clk_lock, flags);
658 host->clk_old = host->ios.clock;
659 host->ios.clock = 0;
660 host->clk_gated = true;
661 spin_unlock_irqrestore(&host->clk_lock, flags);
662 mmc_set_ios(host);
663}
664
665/*
666 * This restores the clock from gating by using the cached
667 * clock value.
668 */
669void mmc_ungate_clock(struct mmc_host *host)
670{
671 /*
672 * We should previously have gated the clock, so the clock shall
673 * be 0 here! The clock may however be 0 during initialization,
674 * when some request operations are performed before setting
675 * the frequency. When ungate is requested in that situation
676 * we just ignore the call.
677 */
678 if (host->clk_old) {
679 BUG_ON(host->ios.clock);
680 /* This call will also set host->clk_gated to false */
681 mmc_set_clock(host, host->clk_old);
682 }
683}
684
685void mmc_set_ungated(struct mmc_host *host)
686{
687 unsigned long flags;
688
689 /*
690 * We've been given a new frequency while the clock is gated,
691 * so make sure we regard this as ungating it.
692 */
693 spin_lock_irqsave(&host->clk_lock, flags);
694 host->clk_gated = false;
695 spin_unlock_irqrestore(&host->clk_lock, flags);
696}
697
698#else
699void mmc_set_ungated(struct mmc_host *host)
700{
701}
702#endif
703
644/* 704/*
645 * Change the bus mode (open drain/push-pull) of a host. 705 * Change the bus mode (open drain/push-pull) of a host.
646 */ 706 */
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 77240cd11bc..026c975b99a 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -33,6 +33,9 @@ void mmc_init_erase(struct mmc_card *card);
33 33
34void mmc_set_chip_select(struct mmc_host *host, int mode); 34void mmc_set_chip_select(struct mmc_host *host, int mode);
35void mmc_set_clock(struct mmc_host *host, unsigned int hz); 35void mmc_set_clock(struct mmc_host *host, unsigned int hz);
36void mmc_gate_clock(struct mmc_host *host);
37void mmc_ungate_clock(struct mmc_host *host);
38void mmc_set_ungated(struct mmc_host *host);
36void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); 39void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
37void mmc_set_bus_width(struct mmc_host *host, unsigned int width); 40void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
38void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, 41void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index eed1405fd74..998797ed67a 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -183,6 +183,11 @@ void mmc_add_host_debugfs(struct mmc_host *host)
183 &mmc_clock_fops)) 183 &mmc_clock_fops))
184 goto err_node; 184 goto err_node;
185 185
186#ifdef CONFIG_MMC_CLKGATE
187 if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
188 root, &host->clk_delay))
189 goto err_node;
190#endif
186 return; 191 return;
187 192
188err_node: 193err_node:
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 10b8af27e03..92e33703e43 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2003 Russell King, All Rights Reserved. 4 * Copyright (C) 2003 Russell King, All Rights Reserved.
5 * Copyright (C) 2007-2008 Pierre Ossman 5 * Copyright (C) 2007-2008 Pierre Ossman
6 * Copyright (C) 2010 Linus Walleij
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -20,6 +21,7 @@
20#include <linux/suspend.h> 21#include <linux/suspend.h>
21 22
22#include <linux/mmc/host.h> 23#include <linux/mmc/host.h>
24#include <linux/mmc/card.h>
23 25
24#include "core.h" 26#include "core.h"
25#include "host.h" 27#include "host.h"
@@ -50,6 +52,204 @@ void mmc_unregister_host_class(void)
50static DEFINE_IDR(mmc_host_idr); 52static DEFINE_IDR(mmc_host_idr);
51static DEFINE_SPINLOCK(mmc_host_lock); 53static DEFINE_SPINLOCK(mmc_host_lock);
52 54
55#ifdef CONFIG_MMC_CLKGATE
56
57/*
58 * Enabling clock gating will make the core call out to the host
59 * once up and once down when it performs a request or card operation
60 * intermingled in any fashion. The driver will see this through
61 * set_ios() operations with ios.clock field set to 0 to gate (disable)
62 * the block clock, and to the old frequency to enable it again.
63 */
64static void mmc_host_clk_gate_delayed(struct mmc_host *host)
65{
66 unsigned long tick_ns;
67 unsigned long freq = host->ios.clock;
68 unsigned long flags;
69
70 if (!freq) {
71 pr_debug("%s: frequency set to 0 in disable function, "
72 "this means the clock is already disabled.\n",
73 mmc_hostname(host));
74 return;
75 }
76 /*
77 * New requests may have appeared while we were scheduling,
78 * then there is no reason to delay the check before
79 * clk_disable().
80 */
81 spin_lock_irqsave(&host->clk_lock, flags);
82
83 /*
84 * Delay n bus cycles (at least 8 from MMC spec) before attempting
85 * to disable the MCI block clock. The reference count may have
86 * gone up again after this delay due to rescheduling!
87 */
88 if (!host->clk_requests) {
89 spin_unlock_irqrestore(&host->clk_lock, flags);
90 tick_ns = DIV_ROUND_UP(1000000000, freq);
91 ndelay(host->clk_delay * tick_ns);
92 } else {
93 /* New users appeared while waiting for this work */
94 spin_unlock_irqrestore(&host->clk_lock, flags);
95 return;
96 }
97 mutex_lock(&host->clk_gate_mutex);
98 spin_lock_irqsave(&host->clk_lock, flags);
99 if (!host->clk_requests) {
100 spin_unlock_irqrestore(&host->clk_lock, flags);
101 /* This will set host->ios.clock to 0 */
102 mmc_gate_clock(host);
103 spin_lock_irqsave(&host->clk_lock, flags);
104 pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
105 }
106 spin_unlock_irqrestore(&host->clk_lock, flags);
107 mutex_unlock(&host->clk_gate_mutex);
108}
109
110/*
111 * Internal work. Work to disable the clock at some later point.
112 */
113static void mmc_host_clk_gate_work(struct work_struct *work)
114{
115 struct mmc_host *host = container_of(work, struct mmc_host,
116 clk_gate_work);
117
118 mmc_host_clk_gate_delayed(host);
119}
120
121/**
122 * mmc_host_clk_ungate - ungate hardware MCI clocks
123 * @host: host to ungate.
124 *
125 * Makes sure the host ios.clock is restored to a non-zero value
126 * past this call. Increase clock reference count and ungate clock
127 * if we're the first user.
128 */
129void mmc_host_clk_ungate(struct mmc_host *host)
130{
131 unsigned long flags;
132
133 mutex_lock(&host->clk_gate_mutex);
134 spin_lock_irqsave(&host->clk_lock, flags);
135 if (host->clk_gated) {
136 spin_unlock_irqrestore(&host->clk_lock, flags);
137 mmc_ungate_clock(host);
138 spin_lock_irqsave(&host->clk_lock, flags);
139 pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
140 }
141 host->clk_requests++;
142 spin_unlock_irqrestore(&host->clk_lock, flags);
143 mutex_unlock(&host->clk_gate_mutex);
144}
145
146/**
147 * mmc_host_may_gate_card - check if this card may be gated
148 * @card: card to check.
149 */
150static bool mmc_host_may_gate_card(struct mmc_card *card)
151{
152 /* If there is no card we may gate it */
153 if (!card)
154 return true;
155 /*
156 * Don't gate SDIO cards! These need to be clocked at all times
157 * since they may be independent systems generating interrupts
158 * and other events. The clock requests counter from the core will
159 * go down to zero since the core does not need it, but we will not
160 * gate the clock, because there is somebody out there that may still
161 * be using it.
162 */
163 if (mmc_card_sdio(card))
164 return false;
165
166 return true;
167}
168
169/**
170 * mmc_host_clk_gate - gate off hardware MCI clocks
171 * @host: host to gate.
172 *
173 * Calls the host driver with ios.clock set to zero as often as possible
174 * in order to gate off hardware MCI clocks. Decrease clock reference
175 * count and schedule disabling of clock.
176 */
177void mmc_host_clk_gate(struct mmc_host *host)
178{
179 unsigned long flags;
180
181 spin_lock_irqsave(&host->clk_lock, flags);
182 host->clk_requests--;
183 if (mmc_host_may_gate_card(host->card) &&
184 !host->clk_requests)
185 schedule_work(&host->clk_gate_work);
186 spin_unlock_irqrestore(&host->clk_lock, flags);
187}
188
189/**
190 * mmc_host_clk_rate - get current clock frequency setting
191 * @host: host to get the clock frequency for.
192 *
193 * Returns current clock frequency regardless of gating.
194 */
195unsigned int mmc_host_clk_rate(struct mmc_host *host)
196{
197 unsigned long freq;
198 unsigned long flags;
199
200 spin_lock_irqsave(&host->clk_lock, flags);
201 if (host->clk_gated)
202 freq = host->clk_old;
203 else
204 freq = host->ios.clock;
205 spin_unlock_irqrestore(&host->clk_lock, flags);
206 return freq;
207}
208
209/**
210 * mmc_host_clk_init - set up clock gating code
211 * @host: host with potential clock to control
212 */
213static inline void mmc_host_clk_init(struct mmc_host *host)
214{
215 host->clk_requests = 0;
216 /* Hold MCI clock for 8 cycles by default */
217 host->clk_delay = 8;
218 host->clk_gated = false;
219 INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
220 spin_lock_init(&host->clk_lock);
221 mutex_init(&host->clk_gate_mutex);
222}
223
224/**
225 * mmc_host_clk_exit - shut down clock gating code
226 * @host: host with potential clock to control
227 */
228static inline void mmc_host_clk_exit(struct mmc_host *host)
229{
230 /*
231 * Wait for any outstanding gate and then make sure we're
232 * ungated before exiting.
233 */
234 if (cancel_work_sync(&host->clk_gate_work))
235 mmc_host_clk_gate_delayed(host);
236 if (host->clk_gated)
237 mmc_host_clk_ungate(host);
238 BUG_ON(host->clk_requests > 0);
239}
240
241#else
242
243static inline void mmc_host_clk_init(struct mmc_host *host)
244{
245}
246
247static inline void mmc_host_clk_exit(struct mmc_host *host)
248{
249}
250
251#endif
252
53/** 253/**
54 * mmc_alloc_host - initialise the per-host structure. 254 * mmc_alloc_host - initialise the per-host structure.
55 * @extra: sizeof private data structure 255 * @extra: sizeof private data structure
@@ -82,6 +282,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
82 host->class_dev.class = &mmc_host_class; 282 host->class_dev.class = &mmc_host_class;
83 device_initialize(&host->class_dev); 283 device_initialize(&host->class_dev);
84 284
285 mmc_host_clk_init(host);
286
85 spin_lock_init(&host->lock); 287 spin_lock_init(&host->lock);
86 init_waitqueue_head(&host->wq); 288 init_waitqueue_head(&host->wq);
87 INIT_DELAYED_WORK(&host->detect, mmc_rescan); 289 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -163,6 +365,8 @@ void mmc_remove_host(struct mmc_host *host)
163 device_del(&host->class_dev); 365 device_del(&host->class_dev);
164 366
165 led_trigger_unregister_simple(host->led); 367 led_trigger_unregister_simple(host->led);
368
369 mmc_host_clk_exit(host);
166} 370}
167 371
168EXPORT_SYMBOL(mmc_remove_host); 372EXPORT_SYMBOL(mmc_remove_host);
@@ -183,4 +387,3 @@ void mmc_free_host(struct mmc_host *host)
183} 387}
184 388
185EXPORT_SYMBOL(mmc_free_host); 389EXPORT_SYMBOL(mmc_free_host);
186
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 8c87e1109a3..de199f91192 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -10,10 +10,31 @@
10 */ 10 */
11#ifndef _MMC_CORE_HOST_H 11#ifndef _MMC_CORE_HOST_H
12#define _MMC_CORE_HOST_H 12#define _MMC_CORE_HOST_H
13#include <linux/mmc/host.h>
13 14
14int mmc_register_host_class(void); 15int mmc_register_host_class(void);
15void mmc_unregister_host_class(void); 16void mmc_unregister_host_class(void);
16 17
18#ifdef CONFIG_MMC_CLKGATE
19void mmc_host_clk_ungate(struct mmc_host *host);
20void mmc_host_clk_gate(struct mmc_host *host);
21unsigned int mmc_host_clk_rate(struct mmc_host *host);
22
23#else
24static inline void mmc_host_clk_ungate(struct mmc_host *host)
25{
26}
27
28static inline void mmc_host_clk_gate(struct mmc_host *host)
29{
30}
31
32static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
33{
34 return host->ios.clock;
35}
36#endif
37
17void mmc_host_deeper_disable(struct work_struct *work); 38void mmc_host_deeper_disable(struct work_struct *work);
18 39
19#endif 40#endif