PM / devfreq: exynos: make more PPMU code common
[deliverable/linux.git] / drivers / devfreq / exynos / exynos4_bus.c
CommitLineData
7b405038
MH
1/* drivers/devfreq/exynos4210_memorybus.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 * MyungJoo Ham <myungjoo.ham@samsung.com>
6 *
7 * EXYNOS4 - Memory/Bus clock frequency scaling support in DEVFREQ framework
8 * This version supports EXYNOS4210 only. This changes bus frequencies
9 * and vddint voltages. Exynos4412/4212 should be able to be supported
10 * with minor modifications.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/io.h>
19#include <linux/slab.h>
20#include <linux/mutex.h>
21#include <linux/suspend.h>
e4db1c74 22#include <linux/pm_opp.h>
7b405038
MH
23#include <linux/devfreq.h>
24#include <linux/platform_device.h>
25#include <linux/regulator/consumer.h>
26#include <linux/module.h>
27
ba778b37
CC
28#include <mach/map.h>
29
30#include "exynos_ppmu.h"
31#include "exynos4_bus.h"
32
7b405038
MH
33/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */
34#ifdef CONFIG_EXYNOS_ASV
35extern unsigned int exynos_result_of_asv;
36#endif
37
7b405038
MH
38#define MAX_SAFEVOLT 1200000 /* 1.2V */
39
40enum exynos4_busf_type {
41 TYPE_BUSF_EXYNOS4210,
42 TYPE_BUSF_EXYNOS4x12,
43};
44
45/* Assume that the bus is saturated if the utilization is 40% */
46#define BUS_SATURATION_RATIO 40
47
7b405038
MH
48enum busclk_level_idx {
49 LV_0 = 0,
50 LV_1,
51 LV_2,
52 LV_3,
53 LV_4,
54 _LV_END
55};
ba778b37
CC
56
57enum exynos_ppmu_idx {
58 PPMU_DMC0,
59 PPMU_DMC1,
60 PPMU_END,
61};
62
7b405038
MH
63#define EX4210_LV_MAX LV_2
64#define EX4x12_LV_MAX LV_4
65#define EX4210_LV_NUM (LV_2 + 1)
66#define EX4x12_LV_NUM (LV_4 + 1)
67
8fa938ac
NM
68/**
69 * struct busfreq_opp_info - opp information for bus
70 * @rate: Frequency in hertz
71 * @volt: Voltage in microvolts corresponding to this OPP
72 */
73struct busfreq_opp_info {
74 unsigned long rate;
75 unsigned long volt;
76};
77
7b405038
MH
78struct busfreq_data {
79 enum exynos4_busf_type type;
80 struct device *dev;
81 struct devfreq *devfreq;
82 bool disabled;
83 struct regulator *vdd_int;
84 struct regulator *vdd_mif; /* Exynos4412/4212 only */
8fa938ac 85 struct busfreq_opp_info curr_oppinfo;
f4145270 86 struct busfreq_ppmu_data ppmu_data;
7b405038
MH
87
88 struct notifier_block pm_notifier;
89 struct mutex lock;
90
91 /* Dividers calculated at boot/probe-time */
92 unsigned int dmc_divtable[_LV_END]; /* DMC0 */
93 unsigned int top_divtable[_LV_END];
94};
95
7b405038
MH
96/* 4210 controls clock of mif and voltage of int */
97static struct bus_opp_table exynos4210_busclk_table[] = {
98 {LV_0, 400000, 1150000},
99 {LV_1, 267000, 1050000},
100 {LV_2, 133000, 1025000},
101 {0, 0, 0},
102};
103
104/*
1d6c2c04 105 * MIF is the main control knob clock for Exynos4x12 MIF/INT
7b405038
MH
106 * clock and voltage of both mif/int are controlled.
107 */
108static struct bus_opp_table exynos4x12_mifclk_table[] = {
109 {LV_0, 400000, 1100000},
110 {LV_1, 267000, 1000000},
111 {LV_2, 160000, 950000},
112 {LV_3, 133000, 950000},
113 {LV_4, 100000, 950000},
114 {0, 0, 0},
115};
116
117/*
118 * INT is not the control knob of 4x12. LV_x is not meant to represent
119 * the current performance. (MIF does)
120 */
121static struct bus_opp_table exynos4x12_intclk_table[] = {
122 {LV_0, 200000, 1000000},
123 {LV_1, 160000, 950000},
124 {LV_2, 133000, 925000},
125 {LV_3, 100000, 900000},
126 {0, 0, 0},
127};
128
129/* TODO: asv volt definitions are "__initdata"? */
130/* Some chips have different operating voltages */
131static unsigned int exynos4210_asv_volt[][EX4210_LV_NUM] = {
132 {1150000, 1050000, 1050000},
133 {1125000, 1025000, 1025000},
134 {1100000, 1000000, 1000000},
135 {1075000, 975000, 975000},
136 {1050000, 950000, 950000},
137};
138
139static unsigned int exynos4x12_mif_step_50[][EX4x12_LV_NUM] = {
140 /* 400 267 160 133 100 */
141 {1050000, 950000, 900000, 900000, 900000}, /* ASV0 */
142 {1050000, 950000, 900000, 900000, 900000}, /* ASV1 */
143 {1050000, 950000, 900000, 900000, 900000}, /* ASV2 */
144 {1050000, 900000, 900000, 900000, 900000}, /* ASV3 */
145 {1050000, 900000, 900000, 900000, 850000}, /* ASV4 */
146 {1050000, 900000, 900000, 850000, 850000}, /* ASV5 */
147 {1050000, 900000, 850000, 850000, 850000}, /* ASV6 */
148 {1050000, 900000, 850000, 850000, 850000}, /* ASV7 */
149 {1050000, 900000, 850000, 850000, 850000}, /* ASV8 */
150};
151
152static unsigned int exynos4x12_int_volt[][EX4x12_LV_NUM] = {
153 /* 200 160 133 100 */
154 {1000000, 950000, 925000, 900000}, /* ASV0 */
155 {975000, 925000, 925000, 900000}, /* ASV1 */
156 {950000, 925000, 900000, 875000}, /* ASV2 */
157 {950000, 900000, 900000, 875000}, /* ASV3 */
158 {925000, 875000, 875000, 875000}, /* ASV4 */
159 {900000, 850000, 850000, 850000}, /* ASV5 */
160 {900000, 850000, 850000, 850000}, /* ASV6 */
161 {900000, 850000, 850000, 850000}, /* ASV7 */
162 {900000, 850000, 850000, 850000}, /* ASV8 */
163};
164
165/*** Clock Divider Data for Exynos4210 ***/
166static unsigned int exynos4210_clkdiv_dmc0[][8] = {
167 /*
168 * Clock divider value for following
169 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
170 * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
171 */
172
173 /* DMC L0: 400MHz */
174 { 3, 1, 1, 1, 1, 1, 3, 1 },
175 /* DMC L1: 266.7MHz */
176 { 4, 1, 1, 2, 1, 1, 3, 1 },
177 /* DMC L2: 133MHz */
178 { 5, 1, 1, 5, 1, 1, 3, 1 },
179};
180static unsigned int exynos4210_clkdiv_top[][5] = {
181 /*
182 * Clock divider value for following
183 * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
184 */
185 /* ACLK200 L0: 200MHz */
186 { 3, 7, 4, 5, 1 },
187 /* ACLK200 L1: 160MHz */
188 { 4, 7, 5, 6, 1 },
189 /* ACLK200 L2: 133MHz */
190 { 5, 7, 7, 7, 1 },
191};
192static unsigned int exynos4210_clkdiv_lr_bus[][2] = {
193 /*
194 * Clock divider value for following
195 * { DIVGDL/R, DIVGPL/R }
196 */
197 /* ACLK_GDL/R L1: 200MHz */
198 { 3, 1 },
199 /* ACLK_GDL/R L2: 160MHz */
200 { 4, 1 },
201 /* ACLK_GDL/R L3: 133MHz */
202 { 5, 1 },
203};
204
205/*** Clock Divider Data for Exynos4212/4412 ***/
206static unsigned int exynos4x12_clkdiv_dmc0[][6] = {
207 /*
208 * Clock divider value for following
209 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
210 * DIVDMCP}
211 */
212
213 /* DMC L0: 400MHz */
214 {3, 1, 1, 1, 1, 1},
215 /* DMC L1: 266.7MHz */
216 {4, 1, 1, 2, 1, 1},
217 /* DMC L2: 160MHz */
218 {5, 1, 1, 4, 1, 1},
219 /* DMC L3: 133MHz */
220 {5, 1, 1, 5, 1, 1},
221 /* DMC L4: 100MHz */
222 {7, 1, 1, 7, 1, 1},
223};
224static unsigned int exynos4x12_clkdiv_dmc1[][6] = {
225 /*
226 * Clock divider value for following
227 * { G2DACP, DIVC2C, DIVC2C_ACLK }
228 */
229
230 /* DMC L0: 400MHz */
231 {3, 1, 1},
232 /* DMC L1: 266.7MHz */
233 {4, 2, 1},
234 /* DMC L2: 160MHz */
235 {5, 4, 1},
236 /* DMC L3: 133MHz */
237 {5, 5, 1},
238 /* DMC L4: 100MHz */
239 {7, 7, 1},
240};
241static unsigned int exynos4x12_clkdiv_top[][5] = {
242 /*
243 * Clock divider value for following
244 * { DIVACLK266_GPS, DIVACLK100, DIVACLK160,
245 DIVACLK133, DIVONENAND }
246 */
247
248 /* ACLK_GDL/R L0: 200MHz */
249 {2, 7, 4, 5, 1},
250 /* ACLK_GDL/R L1: 200MHz */
251 {2, 7, 4, 5, 1},
252 /* ACLK_GDL/R L2: 160MHz */
253 {4, 7, 5, 7, 1},
254 /* ACLK_GDL/R L3: 133MHz */
255 {4, 7, 5, 7, 1},
256 /* ACLK_GDL/R L4: 100MHz */
257 {7, 7, 7, 7, 1},
258};
259static unsigned int exynos4x12_clkdiv_lr_bus[][2] = {
260 /*
261 * Clock divider value for following
262 * { DIVGDL/R, DIVGPL/R }
263 */
264
265 /* ACLK_GDL/R L0: 200MHz */
266 {3, 1},
267 /* ACLK_GDL/R L1: 200MHz */
268 {3, 1},
269 /* ACLK_GDL/R L2: 160MHz */
270 {4, 1},
271 /* ACLK_GDL/R L3: 133MHz */
272 {5, 1},
273 /* ACLK_GDL/R L4: 100MHz */
274 {7, 1},
275};
276static unsigned int exynos4x12_clkdiv_sclkip[][3] = {
277 /*
278 * Clock divider value for following
279 * { DIVMFC, DIVJPEG, DIVFIMC0~3}
280 */
281
282 /* SCLK_MFC: 200MHz */
283 {3, 3, 4},
284 /* SCLK_MFC: 200MHz */
285 {3, 3, 4},
286 /* SCLK_MFC: 160MHz */
287 {4, 4, 5},
288 /* SCLK_MFC: 133MHz */
289 {5, 5, 5},
290 /* SCLK_MFC: 100MHz */
291 {7, 7, 7},
292};
293
294
8fa938ac
NM
295static int exynos4210_set_busclk(struct busfreq_data *data,
296 struct busfreq_opp_info *oppi)
7b405038
MH
297{
298 unsigned int index;
299 unsigned int tmp;
300
301 for (index = LV_0; index < EX4210_LV_NUM; index++)
8fa938ac 302 if (oppi->rate == exynos4210_busclk_table[index].clk)
7b405038
MH
303 break;
304
305 if (index == EX4210_LV_NUM)
306 return -EINVAL;
307
308 /* Change Divider - DMC0 */
309 tmp = data->dmc_divtable[index];
310
5fcc9297 311 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
7b405038
MH
312
313 do {
5fcc9297 314 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
7b405038
MH
315 } while (tmp & 0x11111111);
316
317 /* Change Divider - TOP */
318 tmp = data->top_divtable[index];
319
5fcc9297 320 __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
7b405038
MH
321
322 do {
5fcc9297 323 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
7b405038
MH
324 } while (tmp & 0x11111);
325
326 /* Change Divider - LEFTBUS */
5fcc9297 327 tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
7b405038 328
5fcc9297 329 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
7b405038
MH
330
331 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
5fcc9297 332 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
7b405038 333 (exynos4210_clkdiv_lr_bus[index][1] <<
5fcc9297 334 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
7b405038 335
5fcc9297 336 __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
7b405038
MH
337
338 do {
5fcc9297 339 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
7b405038
MH
340 } while (tmp & 0x11);
341
342 /* Change Divider - RIGHTBUS */
5fcc9297 343 tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
7b405038 344
5fcc9297 345 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
7b405038
MH
346
347 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
5fcc9297 348 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
7b405038 349 (exynos4210_clkdiv_lr_bus[index][1] <<
5fcc9297 350 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
7b405038 351
5fcc9297 352 __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
7b405038
MH
353
354 do {
5fcc9297 355 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
7b405038
MH
356 } while (tmp & 0x11);
357
358 return 0;
359}
360
8fa938ac
NM
361static int exynos4x12_set_busclk(struct busfreq_data *data,
362 struct busfreq_opp_info *oppi)
7b405038
MH
363{
364 unsigned int index;
365 unsigned int tmp;
366
367 for (index = LV_0; index < EX4x12_LV_NUM; index++)
8fa938ac 368 if (oppi->rate == exynos4x12_mifclk_table[index].clk)
7b405038
MH
369 break;
370
371 if (index == EX4x12_LV_NUM)
372 return -EINVAL;
373
374 /* Change Divider - DMC0 */
375 tmp = data->dmc_divtable[index];
376
5fcc9297 377 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
7b405038
MH
378
379 do {
5fcc9297 380 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
7b405038
MH
381 } while (tmp & 0x11111111);
382
383 /* Change Divider - DMC1 */
5fcc9297 384 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC1);
7b405038 385
5fcc9297
KK
386 tmp &= ~(EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK |
387 EXYNOS4_CLKDIV_DMC1_C2C_MASK |
388 EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK);
7b405038
MH
389
390 tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
5fcc9297 391 EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT) |
7b405038 392 (exynos4x12_clkdiv_dmc1[index][1] <<
5fcc9297 393 EXYNOS4_CLKDIV_DMC1_C2C_SHIFT) |
7b405038 394 (exynos4x12_clkdiv_dmc1[index][2] <<
5fcc9297 395 EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT));
7b405038 396
5fcc9297 397 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC1);
7b405038
MH
398
399 do {
5fcc9297 400 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC1);
7b405038
MH
401 } while (tmp & 0x111111);
402
403 /* Change Divider - TOP */
5fcc9297 404 tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
7b405038 405
5fcc9297
KK
406 tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK |
407 EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
408 EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
409 EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
410 EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
7b405038
MH
411
412 tmp |= ((exynos4x12_clkdiv_top[index][0] <<
5fcc9297 413 EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
7b405038 414 (exynos4x12_clkdiv_top[index][1] <<
5fcc9297 415 EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
7b405038 416 (exynos4x12_clkdiv_top[index][2] <<
5fcc9297 417 EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
7b405038 418 (exynos4x12_clkdiv_top[index][3] <<
5fcc9297 419 EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
7b405038 420 (exynos4x12_clkdiv_top[index][4] <<
5fcc9297 421 EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
7b405038 422
5fcc9297 423 __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
7b405038
MH
424
425 do {
5fcc9297 426 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
7b405038
MH
427 } while (tmp & 0x11111);
428
429 /* Change Divider - LEFTBUS */
5fcc9297 430 tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
7b405038 431
5fcc9297 432 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
7b405038
MH
433
434 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
5fcc9297 435 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
7b405038 436 (exynos4x12_clkdiv_lr_bus[index][1] <<
5fcc9297 437 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
7b405038 438
5fcc9297 439 __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
7b405038
MH
440
441 do {
5fcc9297 442 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
7b405038
MH
443 } while (tmp & 0x11);
444
445 /* Change Divider - RIGHTBUS */
5fcc9297 446 tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
7b405038 447
5fcc9297 448 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
7b405038
MH
449
450 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
5fcc9297 451 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
7b405038 452 (exynos4x12_clkdiv_lr_bus[index][1] <<
5fcc9297 453 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
7b405038 454
5fcc9297 455 __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
7b405038
MH
456
457 do {
5fcc9297 458 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
7b405038
MH
459 } while (tmp & 0x11);
460
461 /* Change Divider - MFC */
5fcc9297 462 tmp = __raw_readl(EXYNOS4_CLKDIV_MFC);
7b405038 463
5fcc9297 464 tmp &= ~(EXYNOS4_CLKDIV_MFC_MASK);
7b405038
MH
465
466 tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
5fcc9297 467 EXYNOS4_CLKDIV_MFC_SHIFT));
7b405038 468
5fcc9297 469 __raw_writel(tmp, EXYNOS4_CLKDIV_MFC);
7b405038
MH
470
471 do {
5fcc9297 472 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_MFC);
7b405038
MH
473 } while (tmp & 0x1);
474
475 /* Change Divider - JPEG */
5fcc9297 476 tmp = __raw_readl(EXYNOS4_CLKDIV_CAM1);
7b405038 477
5fcc9297 478 tmp &= ~(EXYNOS4_CLKDIV_CAM1_JPEG_MASK);
7b405038
MH
479
480 tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
5fcc9297 481 EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT));
7b405038 482
5fcc9297 483 __raw_writel(tmp, EXYNOS4_CLKDIV_CAM1);
7b405038
MH
484
485 do {
5fcc9297 486 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
7b405038
MH
487 } while (tmp & 0x1);
488
489 /* Change Divider - FIMC0~3 */
5fcc9297 490 tmp = __raw_readl(EXYNOS4_CLKDIV_CAM);
7b405038 491
5fcc9297
KK
492 tmp &= ~(EXYNOS4_CLKDIV_CAM_FIMC0_MASK | EXYNOS4_CLKDIV_CAM_FIMC1_MASK |
493 EXYNOS4_CLKDIV_CAM_FIMC2_MASK | EXYNOS4_CLKDIV_CAM_FIMC3_MASK);
7b405038
MH
494
495 tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
5fcc9297 496 EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT) |
7b405038 497 (exynos4x12_clkdiv_sclkip[index][2] <<
5fcc9297 498 EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT) |
7b405038 499 (exynos4x12_clkdiv_sclkip[index][2] <<
5fcc9297 500 EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT) |
7b405038 501 (exynos4x12_clkdiv_sclkip[index][2] <<
5fcc9297 502 EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT));
7b405038 503
5fcc9297 504 __raw_writel(tmp, EXYNOS4_CLKDIV_CAM);
7b405038
MH
505
506 do {
5fcc9297 507 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
7b405038
MH
508 } while (tmp & 0x1111);
509
510 return 0;
511}
512
7b405038
MH
513static int exynos4x12_get_intspec(unsigned long mifclk)
514{
515 int i = 0;
516
517 while (exynos4x12_intclk_table[i].clk) {
518 if (exynos4x12_intclk_table[i].clk <= mifclk)
519 return i;
520 i++;
521 }
522
523 return -EINVAL;
524}
525
8fa938ac
NM
526static int exynos4_bus_setvolt(struct busfreq_data *data,
527 struct busfreq_opp_info *oppi,
528 struct busfreq_opp_info *oldoppi)
7b405038
MH
529{
530 int err = 0, tmp;
8fa938ac 531 unsigned long volt = oppi->volt;
7b405038
MH
532
533 switch (data->type) {
534 case TYPE_BUSF_EXYNOS4210:
535 /* OPP represents DMC clock + INT voltage */
536 err = regulator_set_voltage(data->vdd_int, volt,
537 MAX_SAFEVOLT);
538 break;
539 case TYPE_BUSF_EXYNOS4x12:
540 /* OPP represents MIF clock + MIF voltage */
541 err = regulator_set_voltage(data->vdd_mif, volt,
542 MAX_SAFEVOLT);
543 if (err)
544 break;
545
8fa938ac 546 tmp = exynos4x12_get_intspec(oppi->rate);
7b405038
MH
547 if (tmp < 0) {
548 err = tmp;
549 regulator_set_voltage(data->vdd_mif,
8fa938ac 550 oldoppi->volt,
7b405038
MH
551 MAX_SAFEVOLT);
552 break;
553 }
554 err = regulator_set_voltage(data->vdd_int,
555 exynos4x12_intclk_table[tmp].volt,
556 MAX_SAFEVOLT);
557 /* Try to recover */
558 if (err)
559 regulator_set_voltage(data->vdd_mif,
8fa938ac 560 oldoppi->volt,
7b405038
MH
561 MAX_SAFEVOLT);
562 break;
563 default:
564 err = -EINVAL;
565 }
566
567 return err;
568}
569
ab5f299f
MH
570static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
571 u32 flags)
7b405038
MH
572{
573 int err = 0;
ab5f299f
MH
574 struct platform_device *pdev = container_of(dev, struct platform_device,
575 dev);
576 struct busfreq_data *data = platform_get_drvdata(pdev);
47d43ba7 577 struct dev_pm_opp *opp;
8fa938ac
NM
578 unsigned long freq;
579 unsigned long old_freq = data->curr_oppinfo.rate;
580 struct busfreq_opp_info new_oppinfo;
ab5f299f 581
8fa938ac
NM
582 rcu_read_lock();
583 opp = devfreq_recommended_opp(dev, _freq, flags);
584 if (IS_ERR(opp)) {
585 rcu_read_unlock();
ab5f299f 586 return PTR_ERR(opp);
8fa938ac 587 }
5d4879cd
NM
588 new_oppinfo.rate = dev_pm_opp_get_freq(opp);
589 new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
8fa938ac
NM
590 rcu_read_unlock();
591 freq = new_oppinfo.rate;
7b405038
MH
592
593 if (old_freq == freq)
594 return 0;
595
61767729 596 dev_dbg(dev, "targeting %lukHz %luuV\n", freq, new_oppinfo.volt);
7b405038
MH
597
598 mutex_lock(&data->lock);
599
600 if (data->disabled)
601 goto out;
602
603 if (old_freq < freq)
8fa938ac
NM
604 err = exynos4_bus_setvolt(data, &new_oppinfo,
605 &data->curr_oppinfo);
7b405038
MH
606 if (err)
607 goto out;
608
609 if (old_freq != freq) {
610 switch (data->type) {
611 case TYPE_BUSF_EXYNOS4210:
8fa938ac 612 err = exynos4210_set_busclk(data, &new_oppinfo);
7b405038
MH
613 break;
614 case TYPE_BUSF_EXYNOS4x12:
8fa938ac 615 err = exynos4x12_set_busclk(data, &new_oppinfo);
7b405038
MH
616 break;
617 default:
618 err = -EINVAL;
619 }
620 }
621 if (err)
622 goto out;
623
624 if (old_freq > freq)
8fa938ac
NM
625 err = exynos4_bus_setvolt(data, &new_oppinfo,
626 &data->curr_oppinfo);
7b405038
MH
627 if (err)
628 goto out;
629
8fa938ac 630 data->curr_oppinfo = new_oppinfo;
7b405038
MH
631out:
632 mutex_unlock(&data->lock);
633 return err;
634}
635
7b405038
MH
636static int exynos4_bus_get_dev_status(struct device *dev,
637 struct devfreq_dev_status *stat)
638{
f0c28b00 639 struct busfreq_data *data = dev_get_drvdata(dev);
f4145270 640 struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
ba778b37 641 int busier;
7b405038 642
26d51853
BZ
643 exynos_read_ppmu(ppmu_data);
644 busier = exynos_get_busier_ppmu(ppmu_data);
8fa938ac 645 stat->current_frequency = data->curr_oppinfo.rate;
7b405038 646
7b405038 647 /* Number of cycles spent on memory access */
f4145270 648 stat->busy_time = ppmu_data->ppmu[busier].count[PPMU_PMNCNT3];
7b405038 649 stat->busy_time *= 100 / BUS_SATURATION_RATIO;
f4145270 650 stat->total_time = ppmu_data->ppmu[busier].ccnt;
7b405038
MH
651
652 /* If the counters have overflown, retry */
f4145270
BZ
653 if (ppmu_data->ppmu[busier].ccnt_overflow ||
654 ppmu_data->ppmu[busier].count_overflow[0])
7b405038
MH
655 return -EAGAIN;
656
657 return 0;
658}
659
7b405038
MH
660static struct devfreq_dev_profile exynos4_devfreq_profile = {
661 .initial_freq = 400000,
662 .polling_ms = 50,
663 .target = exynos4_bus_target,
664 .get_dev_status = exynos4_bus_get_dev_status,
7b405038
MH
665};
666
667static int exynos4210_init_tables(struct busfreq_data *data)
668{
669 u32 tmp;
670 int mgrp;
671 int i, err = 0;
672
5fcc9297 673 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
7b405038 674 for (i = LV_0; i < EX4210_LV_NUM; i++) {
5fcc9297
KK
675 tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
676 EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
677 EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
678 EXYNOS4_CLKDIV_DMC0_DMC_MASK |
679 EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
680 EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
681 EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
682 EXYNOS4_CLKDIV_DMC0_CORETI_MASK);
7b405038
MH
683
684 tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
5fcc9297 685 EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
7b405038 686 (exynos4210_clkdiv_dmc0[i][1] <<
5fcc9297 687 EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
7b405038 688 (exynos4210_clkdiv_dmc0[i][2] <<
5fcc9297 689 EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
7b405038 690 (exynos4210_clkdiv_dmc0[i][3] <<
5fcc9297 691 EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
7b405038 692 (exynos4210_clkdiv_dmc0[i][4] <<
5fcc9297 693 EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
7b405038 694 (exynos4210_clkdiv_dmc0[i][5] <<
5fcc9297 695 EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
7b405038 696 (exynos4210_clkdiv_dmc0[i][6] <<
5fcc9297 697 EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
7b405038 698 (exynos4210_clkdiv_dmc0[i][7] <<
5fcc9297 699 EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));
7b405038
MH
700
701 data->dmc_divtable[i] = tmp;
702 }
703
5fcc9297 704 tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
7b405038 705 for (i = LV_0; i < EX4210_LV_NUM; i++) {
5fcc9297
KK
706 tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
707 EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
708 EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
709 EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
710 EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
7b405038
MH
711
712 tmp |= ((exynos4210_clkdiv_top[i][0] <<
5fcc9297 713 EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
7b405038 714 (exynos4210_clkdiv_top[i][1] <<
5fcc9297 715 EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
7b405038 716 (exynos4210_clkdiv_top[i][2] <<
5fcc9297 717 EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
7b405038 718 (exynos4210_clkdiv_top[i][3] <<
5fcc9297 719 EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
7b405038 720 (exynos4210_clkdiv_top[i][4] <<
5fcc9297 721 EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
7b405038
MH
722
723 data->top_divtable[i] = tmp;
724 }
725
726#ifdef CONFIG_EXYNOS_ASV
727 tmp = exynos4_result_of_asv;
728#else
729 tmp = 0; /* Max voltages for the reliability of the unknown */
730#endif
731
732 pr_debug("ASV Group of Exynos4 is %d\n", tmp);
733 /* Use merged grouping for voltage */
734 switch (tmp) {
735 case 0:
736 mgrp = 0;
737 break;
738 case 1:
739 case 2:
740 mgrp = 1;
741 break;
742 case 3:
743 case 4:
744 mgrp = 2;
745 break;
746 case 5:
747 case 6:
748 mgrp = 3;
749 break;
750 case 7:
751 mgrp = 4;
752 break;
753 default:
754 pr_warn("Unknown ASV Group. Use max voltage.\n");
755 mgrp = 0;
756 }
757
758 for (i = LV_0; i < EX4210_LV_NUM; i++)
759 exynos4210_busclk_table[i].volt = exynos4210_asv_volt[mgrp][i];
760
761 for (i = LV_0; i < EX4210_LV_NUM; i++) {
5d4879cd 762 err = dev_pm_opp_add(data->dev, exynos4210_busclk_table[i].clk,
7b405038
MH
763 exynos4210_busclk_table[i].volt);
764 if (err) {
765 dev_err(data->dev, "Cannot add opp entries.\n");
766 return err;
767 }
768 }
769
770
771 return 0;
772}
773
774static int exynos4x12_init_tables(struct busfreq_data *data)
775{
776 unsigned int i;
777 unsigned int tmp;
778 int ret;
779
780 /* Enable pause function for DREX2 DVFS */
a2b9676d
MH
781 tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
782 tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
783 __raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);
7b405038 784
5fcc9297 785 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
7b405038
MH
786
787 for (i = 0; i < EX4x12_LV_NUM; i++) {
5fcc9297
KK
788 tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
789 EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
790 EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
791 EXYNOS4_CLKDIV_DMC0_DMC_MASK |
792 EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
793 EXYNOS4_CLKDIV_DMC0_DMCP_MASK);
7b405038
MH
794
795 tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
5fcc9297 796 EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
7b405038 797 (exynos4x12_clkdiv_dmc0[i][1] <<
5fcc9297 798 EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
7b405038 799 (exynos4x12_clkdiv_dmc0[i][2] <<
5fcc9297 800 EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
7b405038 801 (exynos4x12_clkdiv_dmc0[i][3] <<
5fcc9297 802 EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
7b405038 803 (exynos4x12_clkdiv_dmc0[i][4] <<
5fcc9297 804 EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
7b405038 805 (exynos4x12_clkdiv_dmc0[i][5] <<
5fcc9297 806 EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));
7b405038
MH
807
808 data->dmc_divtable[i] = tmp;
809 }
810
811#ifdef CONFIG_EXYNOS_ASV
812 tmp = exynos4_result_of_asv;
813#else
814 tmp = 0; /* Max voltages for the reliability of the unknown */
815#endif
816
817 if (tmp > 8)
818 tmp = 0;
819 pr_debug("ASV Group of Exynos4x12 is %d\n", tmp);
820
821 for (i = 0; i < EX4x12_LV_NUM; i++) {
822 exynos4x12_mifclk_table[i].volt =
823 exynos4x12_mif_step_50[tmp][i];
824 exynos4x12_intclk_table[i].volt =
825 exynos4x12_int_volt[tmp][i];
826 }
827
828 for (i = 0; i < EX4x12_LV_NUM; i++) {
5d4879cd 829 ret = dev_pm_opp_add(data->dev, exynos4x12_mifclk_table[i].clk,
7b405038
MH
830 exynos4x12_mifclk_table[i].volt);
831 if (ret) {
832 dev_err(data->dev, "Fail to add opp entries.\n");
833 return ret;
834 }
835 }
836
837 return 0;
838}
839
840static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
841 unsigned long event, void *ptr)
842{
843 struct busfreq_data *data = container_of(this, struct busfreq_data,
844 pm_notifier);
47d43ba7 845 struct dev_pm_opp *opp;
8fa938ac 846 struct busfreq_opp_info new_oppinfo;
7b405038
MH
847 unsigned long maxfreq = ULONG_MAX;
848 int err = 0;
849
850 switch (event) {
851 case PM_SUSPEND_PREPARE:
852 /* Set Fastest and Deactivate DVFS */
853 mutex_lock(&data->lock);
854
855 data->disabled = true;
856
8fa938ac 857 rcu_read_lock();
5d4879cd 858 opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
8fa938ac
NM
859 if (IS_ERR(opp)) {
860 rcu_read_unlock();
861 dev_err(data->dev, "%s: unable to find a min freq\n",
862 __func__);
5751cdc0 863 mutex_unlock(&data->lock);
8fa938ac
NM
864 return PTR_ERR(opp);
865 }
5d4879cd
NM
866 new_oppinfo.rate = dev_pm_opp_get_freq(opp);
867 new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
8fa938ac 868 rcu_read_unlock();
7b405038 869
8fa938ac
NM
870 err = exynos4_bus_setvolt(data, &new_oppinfo,
871 &data->curr_oppinfo);
7b405038
MH
872 if (err)
873 goto unlock;
874
875 switch (data->type) {
876 case TYPE_BUSF_EXYNOS4210:
8fa938ac 877 err = exynos4210_set_busclk(data, &new_oppinfo);
7b405038
MH
878 break;
879 case TYPE_BUSF_EXYNOS4x12:
8fa938ac 880 err = exynos4x12_set_busclk(data, &new_oppinfo);
7b405038
MH
881 break;
882 default:
883 err = -EINVAL;
884 }
885 if (err)
886 goto unlock;
887
8fa938ac 888 data->curr_oppinfo = new_oppinfo;
7b405038
MH
889unlock:
890 mutex_unlock(&data->lock);
891 if (err)
892 return err;
893 return NOTIFY_OK;
894 case PM_POST_RESTORE:
895 case PM_POST_SUSPEND:
896 /* Reactivate */
897 mutex_lock(&data->lock);
898 data->disabled = false;
899 mutex_unlock(&data->lock);
900 return NOTIFY_OK;
901 }
902
903 return NOTIFY_DONE;
904}
905
0fe763c5 906static int exynos4_busfreq_probe(struct platform_device *pdev)
7b405038
MH
907{
908 struct busfreq_data *data;
f4145270 909 struct busfreq_ppmu_data *ppmu_data;
47d43ba7 910 struct dev_pm_opp *opp;
7b405038
MH
911 struct device *dev = &pdev->dev;
912 int err = 0;
913
d7895052 914 data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL);
7b405038
MH
915 if (data == NULL) {
916 dev_err(dev, "Cannot allocate memory.\n");
917 return -ENOMEM;
918 }
919
f4145270
BZ
920 ppmu_data = &data->ppmu_data;
921 ppmu_data->ppmu_end = PPMU_END;
922 ppmu_data->ppmu = devm_kzalloc(dev,
923 sizeof(struct exynos_ppmu) * PPMU_END,
924 GFP_KERNEL);
925 if (!ppmu_data->ppmu) {
926 dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
927 return -ENOMEM;
928 }
929
7b405038 930 data->type = pdev->id_entry->driver_data;
f4145270
BZ
931 ppmu_data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0;
932 ppmu_data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1;
7b405038
MH
933 data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event;
934 data->dev = dev;
935 mutex_init(&data->lock);
936
937 switch (data->type) {
938 case TYPE_BUSF_EXYNOS4210:
939 err = exynos4210_init_tables(data);
940 break;
941 case TYPE_BUSF_EXYNOS4x12:
942 err = exynos4x12_init_tables(data);
943 break;
944 default:
945 dev_err(dev, "Cannot determine the device id %d\n", data->type);
946 err = -EINVAL;
947 }
45c58e93
CC
948 if (err) {
949 dev_err(dev, "Cannot initialize busfreq table %d\n",
950 data->type);
d7895052 951 return err;
45c58e93 952 }
7b405038 953
d7895052 954 data->vdd_int = devm_regulator_get(dev, "vdd_int");
7b405038
MH
955 if (IS_ERR(data->vdd_int)) {
956 dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
d7895052 957 return PTR_ERR(data->vdd_int);
7b405038
MH
958 }
959 if (data->type == TYPE_BUSF_EXYNOS4x12) {
d7895052 960 data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
7b405038
MH
961 if (IS_ERR(data->vdd_mif)) {
962 dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
d7895052 963 return PTR_ERR(data->vdd_mif);
7b405038
MH
964 }
965 }
966
8fa938ac 967 rcu_read_lock();
5d4879cd
NM
968 opp = dev_pm_opp_find_freq_floor(dev,
969 &exynos4_devfreq_profile.initial_freq);
7b405038 970 if (IS_ERR(opp)) {
8fa938ac 971 rcu_read_unlock();
7b405038 972 dev_err(dev, "Invalid initial frequency %lu kHz.\n",
dce9dc3a 973 exynos4_devfreq_profile.initial_freq);
d7895052 974 return PTR_ERR(opp);
7b405038 975 }
5d4879cd
NM
976 data->curr_oppinfo.rate = dev_pm_opp_get_freq(opp);
977 data->curr_oppinfo.volt = dev_pm_opp_get_voltage(opp);
8fa938ac 978 rcu_read_unlock();
7b405038
MH
979
980 platform_set_drvdata(pdev, data);
981
7b405038 982 data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
1b5c1be2 983 "simple_ondemand", NULL);
d7895052
SK
984 if (IS_ERR(data->devfreq))
985 return PTR_ERR(data->devfreq);
7b405038 986
ba778b37
CC
987 /*
988 * Start PPMU (Performance Profiling Monitoring Unit) to check
989 * utilization of each IP in the Exynos4 SoC.
990 */
f4145270 991 busfreq_mon_reset(ppmu_data);
ba778b37 992
45c58e93
CC
993 /* Register opp_notifier for Exynos4 busfreq */
994 err = devfreq_register_opp_notifier(dev, data->devfreq);
995 if (err < 0) {
996 dev_err(dev, "Failed to register opp notifier\n");
997 goto err_notifier_opp;
998 }
7b405038 999
45c58e93 1000 /* Register pm_notifier for Exynos4 busfreq */
7b405038
MH
1001 err = register_pm_notifier(&data->pm_notifier);
1002 if (err) {
1003 dev_err(dev, "Failed to setup pm notifier\n");
45c58e93 1004 goto err_notifier_pm;
7b405038
MH
1005 }
1006
1007 return 0;
45c58e93
CC
1008
1009err_notifier_pm:
1010 devfreq_unregister_opp_notifier(dev, data->devfreq);
1011err_notifier_opp:
1012 devfreq_remove_device(data->devfreq);
1013
1014 return err;
7b405038
MH
1015}
1016
0fe763c5 1017static int exynos4_busfreq_remove(struct platform_device *pdev)
7b405038
MH
1018{
1019 struct busfreq_data *data = platform_get_drvdata(pdev);
1020
45c58e93 1021 /* Unregister all of notifier chain */
7b405038 1022 unregister_pm_notifier(&data->pm_notifier);
45c58e93
CC
1023 devfreq_unregister_opp_notifier(data->dev, data->devfreq);
1024
1025 /* Remove devfreq instance */
7b405038 1026 devfreq_remove_device(data->devfreq);
7b405038
MH
1027
1028 return 0;
1029}
1030
60d6977c 1031#ifdef CONFIG_PM_SLEEP
7b405038
MH
1032static int exynos4_busfreq_resume(struct device *dev)
1033{
f0c28b00 1034 struct busfreq_data *data = dev_get_drvdata(dev);
f4145270 1035 struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
7b405038 1036
f4145270 1037 busfreq_mon_reset(ppmu_data);
7b405038
MH
1038 return 0;
1039}
60d6977c 1040#endif
7b405038 1041
60d6977c 1042static SIMPLE_DEV_PM_OPS(exynos4_busfreq_pm_ops, NULL, exynos4_busfreq_resume);
7b405038
MH
1043
1044static const struct platform_device_id exynos4_busfreq_id[] = {
1045 { "exynos4210-busfreq", TYPE_BUSF_EXYNOS4210 },
1046 { "exynos4412-busfreq", TYPE_BUSF_EXYNOS4x12 },
1047 { "exynos4212-busfreq", TYPE_BUSF_EXYNOS4x12 },
1048 { },
1049};
1050
1051static struct platform_driver exynos4_busfreq_driver = {
1052 .probe = exynos4_busfreq_probe,
0fe763c5 1053 .remove = exynos4_busfreq_remove,
7b405038
MH
1054 .id_table = exynos4_busfreq_id,
1055 .driver = {
1056 .name = "exynos4-busfreq",
1057 .owner = THIS_MODULE,
60d6977c 1058 .pm = &exynos4_busfreq_pm_ops,
7b405038
MH
1059 },
1060};
1061
1062static int __init exynos4_busfreq_init(void)
1063{
1064 return platform_driver_register(&exynos4_busfreq_driver);
1065}
1066late_initcall(exynos4_busfreq_init);
1067
1068static void __exit exynos4_busfreq_exit(void)
1069{
1070 platform_driver_unregister(&exynos4_busfreq_driver);
1071}
1072module_exit(exynos4_busfreq_exit);
1073
1074MODULE_LICENSE("GPL");
1075MODULE_DESCRIPTION("EXYNOS4 busfreq driver with devfreq framework");
1076MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
This page took 0.185507 seconds and 5 git commands to generate.