diff options
author | Colin Cross <ccross@android.com> | 2011-02-12 19:14:03 -0500 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-02-21 03:10:46 -0500 |
commit | 310992ca4b994db8c869e1c0f32c004b7a196147 (patch) | |
tree | d6fc862591aef9f29f97c6edc3ca2218847eebc1 /arch/arm/mach-tegra/tegra2_clocks.c | |
parent | 89a5fb84dabdf6daeae7d5301a6b1ae4754425dd (diff) |
ARM: tegra: clock: Add shared bus clock type
Some clocks may have multiple downstream users that need to request a
higher clock rate. Shared bus clocks provide a unique shared_bus_user
clock to each user. The frequency of the bus is set to the highest
enabled shared_bus_user clock, with a minimum value set by the
shared bus. Drivers can use clk_enable and clk_disable to enable
or disable their requirement, and clk_set_rate to set the minimum rate.
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 94793dd97aec..1e414ba6df4b 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c | |||
@@ -1188,6 +1188,110 @@ static struct clk_ops tegra_cdev_clk_ops = { | |||
1188 | .disable = &tegra2_cdev_clk_disable, | 1188 | .disable = &tegra2_cdev_clk_disable, |
1189 | }; | 1189 | }; |
1190 | 1190 | ||
1191 | /* shared bus ops */ | ||
1192 | /* | ||
1193 | * Some clocks may have multiple downstream users that need to request a | ||
1194 | * higher clock rate. Shared bus clocks provide a unique shared_bus_user | ||
1195 | * clock to each user. The frequency of the bus is set to the highest | ||
1196 | * enabled shared_bus_user clock, with a minimum value set by the | ||
1197 | * shared bus. | ||
1198 | */ | ||
1199 | static int tegra_clk_shared_bus_update(struct clk *bus) | ||
1200 | { | ||
1201 | struct clk *c; | ||
1202 | unsigned long rate = bus->min_rate; | ||
1203 | |||
1204 | list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node) | ||
1205 | if (c->u.shared_bus_user.enabled) | ||
1206 | rate = max(c->u.shared_bus_user.rate, rate); | ||
1207 | |||
1208 | if (rate == clk_get_rate_locked(bus)) | ||
1209 | return 0; | ||
1210 | |||
1211 | return clk_set_rate_locked(bus, rate); | ||
1212 | }; | ||
1213 | |||
1214 | static void tegra_clk_shared_bus_init(struct clk *c) | ||
1215 | { | ||
1216 | unsigned long flags; | ||
1217 | |||
1218 | c->max_rate = c->parent->max_rate; | ||
1219 | c->u.shared_bus_user.rate = c->parent->max_rate; | ||
1220 | c->state = OFF; | ||
1221 | #ifdef CONFIG_DEBUG_FS | ||
1222 | c->set = true; | ||
1223 | #endif | ||
1224 | |||
1225 | spin_lock_irqsave(&c->parent->spinlock, flags); | ||
1226 | |||
1227 | list_add_tail(&c->u.shared_bus_user.node, | ||
1228 | &c->parent->shared_bus_list); | ||
1229 | |||
1230 | spin_unlock_irqrestore(&c->parent->spinlock, flags); | ||
1231 | } | ||
1232 | |||
1233 | static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate) | ||
1234 | { | ||
1235 | unsigned long flags; | ||
1236 | int ret; | ||
1237 | |||
1238 | rate = clk_round_rate(c->parent, rate); | ||
1239 | if (rate < 0) | ||
1240 | return rate; | ||
1241 | |||
1242 | spin_lock_irqsave(&c->parent->spinlock, flags); | ||
1243 | |||
1244 | c->u.shared_bus_user.rate = rate; | ||
1245 | ret = tegra_clk_shared_bus_update(c->parent); | ||
1246 | |||
1247 | spin_unlock_irqrestore(&c->parent->spinlock, flags); | ||
1248 | |||
1249 | return ret; | ||
1250 | } | ||
1251 | |||
1252 | static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate) | ||
1253 | { | ||
1254 | return clk_round_rate(c->parent, rate); | ||
1255 | } | ||
1256 | |||
1257 | static int tegra_clk_shared_bus_enable(struct clk *c) | ||
1258 | { | ||
1259 | unsigned long flags; | ||
1260 | int ret; | ||
1261 | |||
1262 | spin_lock_irqsave(&c->parent->spinlock, flags); | ||
1263 | |||
1264 | c->u.shared_bus_user.enabled = true; | ||
1265 | ret = tegra_clk_shared_bus_update(c->parent); | ||
1266 | |||
1267 | spin_unlock_irqrestore(&c->parent->spinlock, flags); | ||
1268 | |||
1269 | return ret; | ||
1270 | } | ||
1271 | |||
1272 | static void tegra_clk_shared_bus_disable(struct clk *c) | ||
1273 | { | ||
1274 | unsigned long flags; | ||
1275 | int ret; | ||
1276 | |||
1277 | spin_lock_irqsave(&c->parent->spinlock, flags); | ||
1278 | |||
1279 | c->u.shared_bus_user.enabled = false; | ||
1280 | ret = tegra_clk_shared_bus_update(c->parent); | ||
1281 | WARN_ON_ONCE(ret); | ||
1282 | |||
1283 | spin_unlock_irqrestore(&c->parent->spinlock, flags); | ||
1284 | } | ||
1285 | |||
1286 | static struct clk_ops tegra_clk_shared_bus_ops = { | ||
1287 | .init = tegra_clk_shared_bus_init, | ||
1288 | .enable = tegra_clk_shared_bus_enable, | ||
1289 | .disable = tegra_clk_shared_bus_disable, | ||
1290 | .set_rate = tegra_clk_shared_bus_set_rate, | ||
1291 | .round_rate = tegra_clk_shared_bus_round_rate, | ||
1292 | }; | ||
1293 | |||
1294 | |||
1191 | /* Clock definitions */ | 1295 | /* Clock definitions */ |
1192 | static struct clk tegra_clk_32k = { | 1296 | static struct clk tegra_clk_32k = { |
1193 | .name = "clk_32k", | 1297 | .name = "clk_32k", |
@@ -1863,6 +1967,17 @@ static struct clk_mux_sel mux_pclk[] = { | |||
1863 | }, \ | 1967 | }, \ |
1864 | } | 1968 | } |
1865 | 1969 | ||
1970 | #define SHARED_CLK(_name, _dev, _con, _parent) \ | ||
1971 | { \ | ||
1972 | .name = _name, \ | ||
1973 | .lookup = { \ | ||
1974 | .dev_id = _dev, \ | ||
1975 | .con_id = _con, \ | ||
1976 | }, \ | ||
1977 | .ops = &tegra_clk_shared_bus_ops, \ | ||
1978 | .parent = _parent, \ | ||
1979 | } | ||
1980 | |||
1866 | struct clk tegra_list_clks[] = { | 1981 | struct clk tegra_list_clks[] = { |
1867 | PERIPH_CLK("apbdma", "tegra-dma", NULL, 34, 0, 108000000, mux_pclk, 0), | 1982 | PERIPH_CLK("apbdma", "tegra-dma", NULL, 34, 0, 108000000, mux_pclk, 0), |
1868 | PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET), | 1983 | PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET), |
@@ -2007,6 +2122,7 @@ struct clk *tegra_ptr_clks[] = { | |||
2007 | static void tegra2_init_one_clock(struct clk *c) | 2122 | static void tegra2_init_one_clock(struct clk *c) |
2008 | { | 2123 | { |
2009 | clk_init(c); | 2124 | clk_init(c); |
2125 | INIT_LIST_HEAD(&c->shared_bus_list); | ||
2010 | if (!c->lookup.dev_id && !c->lookup.con_id) | 2126 | if (!c->lookup.dev_id && !c->lookup.con_id) |
2011 | c->lookup.con_id = c->name; | 2127 | c->lookup.con_id = c->name; |
2012 | c->lookup.clk = c; | 2128 | c->lookup.clk = c; |