0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/types.h>
0012 #include <linux/kernel.h>
0013 #include <linux/init.h>
0014 #include <linux/err.h>
0015 #include <linux/clk.h>
0016 #include <linux/io.h>
0017 #include <linux/cpufreq.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/reboot.h>
0022 #include <linux/regulator/consumer.h>
0023
0024 static void __iomem *clk_base;
0025 static void __iomem *dmc_base[2];
0026
0027 #define S5P_CLKREG(x) (clk_base + (x))
0028
0029 #define S5P_APLL_LOCK S5P_CLKREG(0x00)
0030 #define S5P_APLL_CON S5P_CLKREG(0x100)
0031 #define S5P_CLK_SRC0 S5P_CLKREG(0x200)
0032 #define S5P_CLK_SRC2 S5P_CLKREG(0x208)
0033 #define S5P_CLK_DIV0 S5P_CLKREG(0x300)
0034 #define S5P_CLK_DIV2 S5P_CLKREG(0x308)
0035 #define S5P_CLK_DIV6 S5P_CLKREG(0x318)
0036 #define S5P_CLKDIV_STAT0 S5P_CLKREG(0x1000)
0037 #define S5P_CLKDIV_STAT1 S5P_CLKREG(0x1004)
0038 #define S5P_CLKMUX_STAT0 S5P_CLKREG(0x1100)
0039 #define S5P_CLKMUX_STAT1 S5P_CLKREG(0x1104)
0040
0041 #define S5P_ARM_MCS_CON S5P_CLKREG(0x6100)
0042
0043
0044 #define S5P_CLKSRC0_MUX200_SHIFT (16)
0045 #define S5P_CLKSRC0_MUX200_MASK (0x1 << S5P_CLKSRC0_MUX200_SHIFT)
0046 #define S5P_CLKSRC0_MUX166_MASK (0x1<<20)
0047 #define S5P_CLKSRC0_MUX133_MASK (0x1<<24)
0048
0049
0050 #define S5P_CLKSRC2_G3D_SHIFT (0)
0051 #define S5P_CLKSRC2_G3D_MASK (0x3 << S5P_CLKSRC2_G3D_SHIFT)
0052 #define S5P_CLKSRC2_MFC_SHIFT (4)
0053 #define S5P_CLKSRC2_MFC_MASK (0x3 << S5P_CLKSRC2_MFC_SHIFT)
0054
0055
0056 #define S5P_CLKDIV0_APLL_SHIFT (0)
0057 #define S5P_CLKDIV0_APLL_MASK (0x7 << S5P_CLKDIV0_APLL_SHIFT)
0058 #define S5P_CLKDIV0_A2M_SHIFT (4)
0059 #define S5P_CLKDIV0_A2M_MASK (0x7 << S5P_CLKDIV0_A2M_SHIFT)
0060 #define S5P_CLKDIV0_HCLK200_SHIFT (8)
0061 #define S5P_CLKDIV0_HCLK200_MASK (0x7 << S5P_CLKDIV0_HCLK200_SHIFT)
0062 #define S5P_CLKDIV0_PCLK100_SHIFT (12)
0063 #define S5P_CLKDIV0_PCLK100_MASK (0x7 << S5P_CLKDIV0_PCLK100_SHIFT)
0064 #define S5P_CLKDIV0_HCLK166_SHIFT (16)
0065 #define S5P_CLKDIV0_HCLK166_MASK (0xF << S5P_CLKDIV0_HCLK166_SHIFT)
0066 #define S5P_CLKDIV0_PCLK83_SHIFT (20)
0067 #define S5P_CLKDIV0_PCLK83_MASK (0x7 << S5P_CLKDIV0_PCLK83_SHIFT)
0068 #define S5P_CLKDIV0_HCLK133_SHIFT (24)
0069 #define S5P_CLKDIV0_HCLK133_MASK (0xF << S5P_CLKDIV0_HCLK133_SHIFT)
0070 #define S5P_CLKDIV0_PCLK66_SHIFT (28)
0071 #define S5P_CLKDIV0_PCLK66_MASK (0x7 << S5P_CLKDIV0_PCLK66_SHIFT)
0072
0073
0074 #define S5P_CLKDIV2_G3D_SHIFT (0)
0075 #define S5P_CLKDIV2_G3D_MASK (0xF << S5P_CLKDIV2_G3D_SHIFT)
0076 #define S5P_CLKDIV2_MFC_SHIFT (4)
0077 #define S5P_CLKDIV2_MFC_MASK (0xF << S5P_CLKDIV2_MFC_SHIFT)
0078
0079
0080 #define S5P_CLKDIV6_ONEDRAM_SHIFT (28)
0081 #define S5P_CLKDIV6_ONEDRAM_MASK (0xF << S5P_CLKDIV6_ONEDRAM_SHIFT)
0082
0083 static struct clk *dmc0_clk;
0084 static struct clk *dmc1_clk;
0085 static DEFINE_MUTEX(set_freq_lock);
0086
0087
0088 #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1)
0089 #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1)
0090
0091
0092 #define SLEEP_FREQ (800 * 1000)
0093
0094
0095 static bool no_cpufreq_access;
0096
0097
0098
0099
0100
0101 struct dram_conf {
0102 unsigned long freq;
0103 unsigned long refresh;
0104 };
0105
0106
0107 static struct dram_conf s5pv210_dram_conf[2];
0108
0109 enum perf_level {
0110 L0, L1, L2, L3, L4,
0111 };
0112
0113 enum s5pv210_mem_type {
0114 LPDDR = 0x1,
0115 LPDDR2 = 0x2,
0116 DDR2 = 0x4,
0117 };
0118
0119 enum s5pv210_dmc_port {
0120 DMC0 = 0,
0121 DMC1,
0122 };
0123
0124 static struct cpufreq_frequency_table s5pv210_freq_table[] = {
0125 {0, L0, 1000*1000},
0126 {0, L1, 800*1000},
0127 {0, L2, 400*1000},
0128 {0, L3, 200*1000},
0129 {0, L4, 100*1000},
0130 {0, 0, CPUFREQ_TABLE_END},
0131 };
0132
0133 static struct regulator *arm_regulator;
0134 static struct regulator *int_regulator;
0135
0136 struct s5pv210_dvs_conf {
0137 int arm_volt;
0138 int int_volt;
0139 };
0140
0141 static const int arm_volt_max = 1350000;
0142 static const int int_volt_max = 1250000;
0143
0144 static struct s5pv210_dvs_conf dvs_conf[] = {
0145 [L0] = {
0146 .arm_volt = 1250000,
0147 .int_volt = 1100000,
0148 },
0149 [L1] = {
0150 .arm_volt = 1200000,
0151 .int_volt = 1100000,
0152 },
0153 [L2] = {
0154 .arm_volt = 1050000,
0155 .int_volt = 1100000,
0156 },
0157 [L3] = {
0158 .arm_volt = 950000,
0159 .int_volt = 1100000,
0160 },
0161 [L4] = {
0162 .arm_volt = 950000,
0163 .int_volt = 1000000,
0164 },
0165 };
0166
0167 static u32 clkdiv_val[5][11] = {
0168
0169
0170
0171
0172
0173
0174
0175
0176 {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
0177
0178
0179 {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
0180
0181
0182 {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
0183
0184
0185 {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
0186
0187
0188 {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
0189 };
0190
0191
0192
0193
0194
0195
0196
0197 static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
0198 {
0199 unsigned long tmp, tmp1;
0200 void __iomem *reg = NULL;
0201
0202 if (ch == DMC0) {
0203 reg = (dmc_base[0] + 0x30);
0204 } else if (ch == DMC1) {
0205 reg = (dmc_base[1] + 0x30);
0206 } else {
0207 pr_err("Cannot find DMC port\n");
0208 return;
0209 }
0210
0211
0212 tmp = s5pv210_dram_conf[ch].freq;
0213
0214 tmp /= freq;
0215
0216 tmp1 = s5pv210_dram_conf[ch].refresh;
0217
0218 tmp1 /= tmp;
0219
0220 writel_relaxed(tmp1, reg);
0221 }
0222
0223 static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
0224 {
0225 unsigned long reg;
0226 unsigned int priv_index;
0227 unsigned int pll_changing = 0;
0228 unsigned int bus_speed_changing = 0;
0229 unsigned int old_freq, new_freq;
0230 int arm_volt, int_volt;
0231 int ret = 0;
0232
0233 mutex_lock(&set_freq_lock);
0234
0235 if (no_cpufreq_access) {
0236 pr_err("Denied access to %s as it is disabled temporarily\n",
0237 __func__);
0238 ret = -EINVAL;
0239 goto exit;
0240 }
0241
0242 old_freq = policy->cur;
0243 new_freq = s5pv210_freq_table[index].frequency;
0244
0245
0246 priv_index = cpufreq_table_find_index_h(policy, old_freq, false);
0247
0248 arm_volt = dvs_conf[index].arm_volt;
0249 int_volt = dvs_conf[index].int_volt;
0250
0251 if (new_freq > old_freq) {
0252 ret = regulator_set_voltage(arm_regulator,
0253 arm_volt, arm_volt_max);
0254 if (ret)
0255 goto exit;
0256
0257 ret = regulator_set_voltage(int_regulator,
0258 int_volt, int_volt_max);
0259 if (ret)
0260 goto exit;
0261 }
0262
0263
0264 if ((index == L0) || (priv_index == L0))
0265 pll_changing = 1;
0266
0267
0268 if ((index == L4) || (priv_index == L4))
0269 bus_speed_changing = 1;
0270
0271 if (bus_speed_changing) {
0272
0273
0274
0275
0276
0277 if (pll_changing)
0278 s5pv210_set_refresh(DMC1, 83000);
0279 else
0280 s5pv210_set_refresh(DMC1, 100000);
0281
0282 s5pv210_set_refresh(DMC0, 83000);
0283 }
0284
0285
0286
0287
0288
0289
0290
0291 if (pll_changing) {
0292
0293
0294
0295
0296 reg = readl_relaxed(S5P_CLK_DIV2);
0297 reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
0298 reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
0299 (3 << S5P_CLKDIV2_MFC_SHIFT);
0300 writel_relaxed(reg, S5P_CLK_DIV2);
0301
0302
0303 do {
0304 reg = readl_relaxed(S5P_CLKDIV_STAT0);
0305 } while (reg & ((1 << 16) | (1 << 17)));
0306
0307
0308
0309
0310
0311 reg = readl_relaxed(S5P_CLK_SRC2);
0312 reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
0313 reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
0314 (1 << S5P_CLKSRC2_MFC_SHIFT);
0315 writel_relaxed(reg, S5P_CLK_SRC2);
0316
0317 do {
0318 reg = readl_relaxed(S5P_CLKMUX_STAT1);
0319 } while (reg & ((1 << 7) | (1 << 3)));
0320
0321
0322
0323
0324
0325
0326 if (!bus_speed_changing)
0327 s5pv210_set_refresh(DMC1, 133000);
0328
0329
0330 reg = readl_relaxed(S5P_CLK_SRC0);
0331 reg &= ~(S5P_CLKSRC0_MUX200_MASK);
0332 reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
0333 writel_relaxed(reg, S5P_CLK_SRC0);
0334
0335 do {
0336 reg = readl_relaxed(S5P_CLKMUX_STAT0);
0337 } while (reg & (0x1 << 18));
0338
0339 }
0340
0341
0342 reg = readl_relaxed(S5P_CLK_DIV0);
0343
0344 reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK |
0345 S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK |
0346 S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK |
0347 S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
0348
0349 reg |= ((clkdiv_val[index][0] << S5P_CLKDIV0_APLL_SHIFT) |
0350 (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT) |
0351 (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT) |
0352 (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT) |
0353 (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT) |
0354 (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT) |
0355 (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) |
0356 (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
0357
0358 writel_relaxed(reg, S5P_CLK_DIV0);
0359
0360 do {
0361 reg = readl_relaxed(S5P_CLKDIV_STAT0);
0362 } while (reg & 0xff);
0363
0364
0365 reg = readl_relaxed(S5P_ARM_MCS_CON);
0366 reg &= ~0x3;
0367 if (index >= L3)
0368 reg |= 0x3;
0369 else
0370 reg |= 0x1;
0371
0372 writel_relaxed(reg, S5P_ARM_MCS_CON);
0373
0374 if (pll_changing) {
0375
0376 writel_relaxed(0x2cf, S5P_APLL_LOCK);
0377
0378
0379
0380
0381
0382
0383 if (index == L0)
0384 writel_relaxed(APLL_VAL_1000, S5P_APLL_CON);
0385 else
0386 writel_relaxed(APLL_VAL_800, S5P_APLL_CON);
0387
0388 do {
0389 reg = readl_relaxed(S5P_APLL_CON);
0390 } while (!(reg & (0x1 << 29)));
0391
0392
0393
0394
0395
0396
0397 reg = readl_relaxed(S5P_CLK_SRC2);
0398 reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
0399 reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) |
0400 (0 << S5P_CLKSRC2_MFC_SHIFT);
0401 writel_relaxed(reg, S5P_CLK_SRC2);
0402
0403 do {
0404 reg = readl_relaxed(S5P_CLKMUX_STAT1);
0405 } while (reg & ((1 << 7) | (1 << 3)));
0406
0407
0408
0409
0410
0411 reg = readl_relaxed(S5P_CLK_DIV2);
0412 reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
0413 reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
0414 (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
0415 writel_relaxed(reg, S5P_CLK_DIV2);
0416
0417
0418 do {
0419 reg = readl_relaxed(S5P_CLKDIV_STAT0);
0420 } while (reg & ((1 << 16) | (1 << 17)));
0421
0422
0423 reg = readl_relaxed(S5P_CLK_SRC0);
0424 reg &= ~(S5P_CLKSRC0_MUX200_MASK);
0425 reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
0426 writel_relaxed(reg, S5P_CLK_SRC0);
0427
0428 do {
0429 reg = readl_relaxed(S5P_CLKMUX_STAT0);
0430 } while (reg & (0x1 << 18));
0431
0432
0433
0434
0435
0436
0437 if (!bus_speed_changing)
0438 s5pv210_set_refresh(DMC1, 200000);
0439 }
0440
0441
0442
0443
0444
0445 if (bus_speed_changing) {
0446 reg = readl_relaxed(S5P_CLK_DIV6);
0447 reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
0448 reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
0449 writel_relaxed(reg, S5P_CLK_DIV6);
0450
0451 do {
0452 reg = readl_relaxed(S5P_CLKDIV_STAT1);
0453 } while (reg & (1 << 15));
0454
0455
0456 if (index != L4) {
0457
0458
0459
0460
0461 s5pv210_set_refresh(DMC0, 166000);
0462 s5pv210_set_refresh(DMC1, 200000);
0463 } else {
0464
0465
0466
0467
0468 s5pv210_set_refresh(DMC0, 83000);
0469 s5pv210_set_refresh(DMC1, 100000);
0470 }
0471 }
0472
0473 if (new_freq < old_freq) {
0474 regulator_set_voltage(int_regulator,
0475 int_volt, int_volt_max);
0476
0477 regulator_set_voltage(arm_regulator,
0478 arm_volt, arm_volt_max);
0479 }
0480
0481 pr_debug("Perf changed[L%d]\n", index);
0482
0483 exit:
0484 mutex_unlock(&set_freq_lock);
0485 return ret;
0486 }
0487
0488 static int check_mem_type(void __iomem *dmc_reg)
0489 {
0490 unsigned long val;
0491
0492 val = readl_relaxed(dmc_reg + 0x4);
0493 val = (val & (0xf << 8));
0494
0495 return val >> 8;
0496 }
0497
0498 static int s5pv210_cpu_init(struct cpufreq_policy *policy)
0499 {
0500 unsigned long mem_type;
0501 int ret;
0502
0503 policy->clk = clk_get(NULL, "armclk");
0504 if (IS_ERR(policy->clk))
0505 return PTR_ERR(policy->clk);
0506
0507 dmc0_clk = clk_get(NULL, "sclk_dmc0");
0508 if (IS_ERR(dmc0_clk)) {
0509 ret = PTR_ERR(dmc0_clk);
0510 goto out_dmc0;
0511 }
0512
0513 dmc1_clk = clk_get(NULL, "hclk_msys");
0514 if (IS_ERR(dmc1_clk)) {
0515 ret = PTR_ERR(dmc1_clk);
0516 goto out_dmc1;
0517 }
0518
0519 if (policy->cpu != 0) {
0520 ret = -EINVAL;
0521 goto out_dmc1;
0522 }
0523
0524
0525
0526
0527
0528 mem_type = check_mem_type(dmc_base[0]);
0529
0530 if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
0531 pr_err("CPUFreq doesn't support this memory type\n");
0532 ret = -EINVAL;
0533 goto out_dmc1;
0534 }
0535
0536
0537 s5pv210_dram_conf[0].refresh = (readl_relaxed(dmc_base[0] + 0x30) * 1000);
0538 s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk);
0539
0540 s5pv210_dram_conf[1].refresh = (readl_relaxed(dmc_base[1] + 0x30) * 1000);
0541 s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
0542
0543 policy->suspend_freq = SLEEP_FREQ;
0544 cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
0545 return 0;
0546
0547 out_dmc1:
0548 clk_put(dmc0_clk);
0549 out_dmc0:
0550 clk_put(policy->clk);
0551 return ret;
0552 }
0553
0554 static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
0555 unsigned long event, void *ptr)
0556 {
0557 int ret;
0558 struct cpufreq_policy *policy;
0559
0560 policy = cpufreq_cpu_get(0);
0561 if (!policy) {
0562 pr_debug("cpufreq: get no policy for cpu0\n");
0563 return NOTIFY_BAD;
0564 }
0565
0566 ret = cpufreq_driver_target(policy, SLEEP_FREQ, 0);
0567 cpufreq_cpu_put(policy);
0568
0569 if (ret < 0)
0570 return NOTIFY_BAD;
0571
0572 no_cpufreq_access = true;
0573 return NOTIFY_DONE;
0574 }
0575
0576 static struct cpufreq_driver s5pv210_driver = {
0577 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0578 .verify = cpufreq_generic_frequency_table_verify,
0579 .target_index = s5pv210_target,
0580 .get = cpufreq_generic_get,
0581 .init = s5pv210_cpu_init,
0582 .name = "s5pv210",
0583 .suspend = cpufreq_generic_suspend,
0584 .resume = cpufreq_generic_suspend,
0585 };
0586
0587 static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
0588 .notifier_call = s5pv210_cpufreq_reboot_notifier_event,
0589 };
0590
0591 static int s5pv210_cpufreq_probe(struct platform_device *pdev)
0592 {
0593 struct device *dev = &pdev->dev;
0594 struct device_node *np;
0595 int id, result = 0;
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605 arm_regulator = regulator_get(NULL, "vddarm");
0606 if (IS_ERR(arm_regulator))
0607 return dev_err_probe(dev, PTR_ERR(arm_regulator),
0608 "failed to get regulator vddarm\n");
0609
0610 int_regulator = regulator_get(NULL, "vddint");
0611 if (IS_ERR(int_regulator)) {
0612 result = dev_err_probe(dev, PTR_ERR(int_regulator),
0613 "failed to get regulator vddint\n");
0614 goto err_int_regulator;
0615 }
0616
0617 np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
0618 if (!np) {
0619 dev_err(dev, "failed to find clock controller DT node\n");
0620 result = -ENODEV;
0621 goto err_clock;
0622 }
0623
0624 clk_base = of_iomap(np, 0);
0625 of_node_put(np);
0626 if (!clk_base) {
0627 dev_err(dev, "failed to map clock registers\n");
0628 result = -EFAULT;
0629 goto err_clock;
0630 }
0631
0632 for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") {
0633 id = of_alias_get_id(np, "dmc");
0634 if (id < 0 || id >= ARRAY_SIZE(dmc_base)) {
0635 dev_err(dev, "failed to get alias of dmc node '%pOFn'\n", np);
0636 of_node_put(np);
0637 result = id;
0638 goto err_clk_base;
0639 }
0640
0641 dmc_base[id] = of_iomap(np, 0);
0642 if (!dmc_base[id]) {
0643 dev_err(dev, "failed to map dmc%d registers\n", id);
0644 of_node_put(np);
0645 result = -EFAULT;
0646 goto err_dmc;
0647 }
0648 }
0649
0650 for (id = 0; id < ARRAY_SIZE(dmc_base); ++id) {
0651 if (!dmc_base[id]) {
0652 dev_err(dev, "failed to find dmc%d node\n", id);
0653 result = -ENODEV;
0654 goto err_dmc;
0655 }
0656 }
0657
0658 register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
0659
0660 return cpufreq_register_driver(&s5pv210_driver);
0661
0662 err_dmc:
0663 for (id = 0; id < ARRAY_SIZE(dmc_base); ++id)
0664 if (dmc_base[id]) {
0665 iounmap(dmc_base[id]);
0666 dmc_base[id] = NULL;
0667 }
0668
0669 err_clk_base:
0670 iounmap(clk_base);
0671
0672 err_clock:
0673 regulator_put(int_regulator);
0674
0675 err_int_regulator:
0676 regulator_put(arm_regulator);
0677
0678 return result;
0679 }
0680
0681 static struct platform_driver s5pv210_cpufreq_platdrv = {
0682 .driver = {
0683 .name = "s5pv210-cpufreq",
0684 },
0685 .probe = s5pv210_cpufreq_probe,
0686 };
0687 builtin_platform_driver(s5pv210_cpufreq_platdrv);