1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support 4 * 5 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. 6 * Author : Chanwoo Choi <cw00.choi@samsung.com> 7 * 8 * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/of_address.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 #include <linux/suspend.h> 19 #include <linux/devfreq-event.h> 20 21 #include "exynos-ppmu.h" 22 23 struct exynos_ppmu_data { 24 struct clk *clk; 25 }; 26 27 struct exynos_ppmu { 28 struct devfreq_event_dev **edev; 29 struct devfreq_event_desc *desc; 30 unsigned int num_events; 31 32 struct device *dev; 33 struct regmap *regmap; 34 35 struct exynos_ppmu_data ppmu; 36 }; 37 38 #define PPMU_EVENT(name) \ 39 { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \ 40 { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \ 41 { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \ 42 { "ppmu-event3-"#name, PPMU_PMNCNT3 } 43 44 static struct __exynos_ppmu_events { 45 char *name; 46 int id; 47 } ppmu_events[] = { 48 /* For Exynos3250, Exynos4 and Exynos5260 */ 49 PPMU_EVENT(g3d), 50 PPMU_EVENT(fsys), 51 52 /* For Exynos4 SoCs and Exynos3250 */ 53 PPMU_EVENT(dmc0), 54 PPMU_EVENT(dmc1), 55 PPMU_EVENT(cpu), 56 PPMU_EVENT(rightbus), 57 PPMU_EVENT(leftbus), 58 PPMU_EVENT(lcd0), 59 PPMU_EVENT(camif), 60 61 /* Only for Exynos3250 and Exynos5260 */ 62 PPMU_EVENT(mfc), 63 64 /* Only for Exynos4 SoCs */ 65 PPMU_EVENT(mfc-left), 66 PPMU_EVENT(mfc-right), 67 68 /* Only for Exynos5260 SoCs */ 69 PPMU_EVENT(drex0-s0), 70 PPMU_EVENT(drex0-s1), 71 PPMU_EVENT(drex1-s0), 72 PPMU_EVENT(drex1-s1), 73 PPMU_EVENT(eagle), 74 PPMU_EVENT(kfc), 75 PPMU_EVENT(isp), 76 PPMU_EVENT(fimc), 77 PPMU_EVENT(gscl), 78 PPMU_EVENT(mscl), 79 PPMU_EVENT(fimd0x), 80 PPMU_EVENT(fimd1x), 81 82 /* Only for Exynos5433 SoCs */ 83 PPMU_EVENT(d0-cpu), 84 PPMU_EVENT(d0-general), 85 PPMU_EVENT(d0-rt), 86 PPMU_EVENT(d1-cpu), 87 PPMU_EVENT(d1-general), 88 PPMU_EVENT(d1-rt), 89 }; 90 91 static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) 92 { 93 int i; 94 95 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) 96 if (!strcmp(edev->desc->name, ppmu_events[i].name)) 97 return ppmu_events[i].id; 98 99 return -EINVAL; 100 } 101 102 /* 103 * The devfreq-event ops structure for PPMU v1.1 104 */ 105 static int exynos_ppmu_disable(struct devfreq_event_dev *edev) 106 { 107 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 108 int ret; 109 u32 pmnc; 110 111 /* Disable all counters */ 112 ret = regmap_write(info->regmap, PPMU_CNTENC, 113 PPMU_CCNT_MASK | 114 PPMU_PMCNT0_MASK | 115 PPMU_PMCNT1_MASK | 116 PPMU_PMCNT2_MASK | 117 PPMU_PMCNT3_MASK); 118 if (ret < 0) 119 return ret; 120 121 /* Disable PPMU */ 122 ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); 123 if (ret < 0) 124 return ret; 125 126 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 127 ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); 128 if (ret < 0) 129 return ret; 130 131 return 0; 132 } 133 134 static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) 135 { 136 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 137 int id = exynos_ppmu_find_ppmu_id(edev); 138 int ret; 139 u32 pmnc, cntens; 140 141 if (id < 0) 142 return id; 143 144 /* Enable specific counter */ 145 ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens); 146 if (ret < 0) 147 return ret; 148 149 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 150 ret = regmap_write(info->regmap, PPMU_CNTENS, cntens); 151 if (ret < 0) 152 return ret; 153 154 /* Set the event of Read/Write data count */ 155 ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id), 156 PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT); 157 if (ret < 0) 158 return ret; 159 160 /* Reset cycle counter/performance counter and enable PPMU */ 161 ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); 162 if (ret < 0) 163 return ret; 164 165 pmnc &= ~(PPMU_PMNC_ENABLE_MASK 166 | PPMU_PMNC_COUNTER_RESET_MASK 167 | PPMU_PMNC_CC_RESET_MASK); 168 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 169 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 170 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 171 ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); 172 if (ret < 0) 173 return ret; 174 175 return 0; 176 } 177 178 static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, 179 struct devfreq_event_data *edata) 180 { 181 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 182 int id = exynos_ppmu_find_ppmu_id(edev); 183 unsigned int total_count, load_count; 184 unsigned int pmcnt3_high, pmcnt3_low; 185 unsigned int pmnc, cntenc; 186 int ret; 187 188 if (id < 0) 189 return -EINVAL; 190 191 /* Disable PPMU */ 192 ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); 193 if (ret < 0) 194 return ret; 195 196 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 197 ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); 198 if (ret < 0) 199 return ret; 200 201 /* Read cycle count */ 202 ret = regmap_read(info->regmap, PPMU_CCNT, &total_count); 203 if (ret < 0) 204 return ret; 205 edata->total_count = total_count; 206 207 /* Read performance count */ 208 switch (id) { 209 case PPMU_PMNCNT0: 210 case PPMU_PMNCNT1: 211 case PPMU_PMNCNT2: 212 ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count); 213 if (ret < 0) 214 return ret; 215 edata->load_count = load_count; 216 break; 217 case PPMU_PMNCNT3: 218 ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high); 219 if (ret < 0) 220 return ret; 221 222 ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low); 223 if (ret < 0) 224 return ret; 225 226 edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low); 227 break; 228 default: 229 return -EINVAL; 230 } 231 232 /* Disable specific counter */ 233 ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc); 234 if (ret < 0) 235 return ret; 236 237 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 238 ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc); 239 if (ret < 0) 240 return ret; 241 242 dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, 243 edata->load_count, edata->total_count); 244 245 return 0; 246 } 247 248 static const struct devfreq_event_ops exynos_ppmu_ops = { 249 .disable = exynos_ppmu_disable, 250 .set_event = exynos_ppmu_set_event, 251 .get_event = exynos_ppmu_get_event, 252 }; 253 254 /* 255 * The devfreq-event ops structure for PPMU v2.0 256 */ 257 static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) 258 { 259 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 260 int ret; 261 u32 pmnc, clear; 262 263 /* Disable all counters */ 264 clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK 265 | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); 266 ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear); 267 if (ret < 0) 268 return ret; 269 270 ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear); 271 if (ret < 0) 272 return ret; 273 274 ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear); 275 if (ret < 0) 276 return ret; 277 278 ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear); 279 if (ret < 0) 280 return ret; 281 282 ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0); 283 if (ret < 0) 284 return ret; 285 286 ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0); 287 if (ret < 0) 288 return ret; 289 290 ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0); 291 if (ret < 0) 292 return ret; 293 294 ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0); 295 if (ret < 0) 296 return ret; 297 298 ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0); 299 if (ret < 0) 300 return ret; 301 302 ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0); 303 if (ret < 0) 304 return ret; 305 306 ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0); 307 if (ret < 0) 308 return ret; 309 310 ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0); 311 if (ret < 0) 312 return ret; 313 314 ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0); 315 if (ret < 0) 316 return ret; 317 318 ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0); 319 if (ret < 0) 320 return ret; 321 322 ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0); 323 if (ret < 0) 324 return ret; 325 326 ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0); 327 if (ret < 0) 328 return ret; 329 330 ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0); 331 if (ret < 0) 332 return ret; 333 334 ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0); 335 if (ret < 0) 336 return ret; 337 338 /* Disable PPMU */ 339 ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); 340 if (ret < 0) 341 return ret; 342 343 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 344 ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); 345 if (ret < 0) 346 return ret; 347 348 return 0; 349 } 350 351 static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) 352 { 353 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 354 unsigned int pmnc, cntens; 355 int id = exynos_ppmu_find_ppmu_id(edev); 356 int ret; 357 358 /* Enable all counters */ 359 ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens); 360 if (ret < 0) 361 return ret; 362 363 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 364 ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens); 365 if (ret < 0) 366 return ret; 367 368 /* Set the event of Read/Write data count */ 369 switch (id) { 370 case PPMU_PMNCNT0: 371 case PPMU_PMNCNT1: 372 case PPMU_PMNCNT2: 373 ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), 374 PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT); 375 if (ret < 0) 376 return ret; 377 break; 378 case PPMU_PMNCNT3: 379 ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), 380 PPMU_V2_EVT3_RW_DATA_CNT); 381 if (ret < 0) 382 return ret; 383 break; 384 } 385 386 /* Reset cycle counter/performance counter and enable PPMU */ 387 ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); 388 if (ret < 0) 389 return ret; 390 391 pmnc &= ~(PPMU_PMNC_ENABLE_MASK 392 | PPMU_PMNC_COUNTER_RESET_MASK 393 | PPMU_PMNC_CC_RESET_MASK 394 | PPMU_PMNC_CC_DIVIDER_MASK 395 | PPMU_V2_PMNC_START_MODE_MASK); 396 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 397 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 398 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 399 pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); 400 401 ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); 402 if (ret < 0) 403 return ret; 404 405 return 0; 406 } 407 408 static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, 409 struct devfreq_event_data *edata) 410 { 411 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 412 int id = exynos_ppmu_find_ppmu_id(edev); 413 int ret; 414 unsigned int pmnc, cntenc; 415 unsigned int pmcnt_high, pmcnt_low; 416 unsigned int total_count, count; 417 unsigned long load_count = 0; 418 419 /* Disable PPMU */ 420 ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); 421 if (ret < 0) 422 return ret; 423 424 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 425 ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); 426 if (ret < 0) 427 return ret; 428 429 /* Read cycle count and performance count */ 430 ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count); 431 if (ret < 0) 432 return ret; 433 edata->total_count = total_count; 434 435 switch (id) { 436 case PPMU_PMNCNT0: 437 case PPMU_PMNCNT1: 438 case PPMU_PMNCNT2: 439 ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count); 440 if (ret < 0) 441 return ret; 442 load_count = count; 443 break; 444 case PPMU_PMNCNT3: 445 ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH, 446 &pmcnt_high); 447 if (ret < 0) 448 return ret; 449 450 ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low); 451 if (ret < 0) 452 return ret; 453 454 load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low; 455 break; 456 } 457 edata->load_count = load_count; 458 459 /* Disable all counters */ 460 ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc); 461 if (ret < 0) 462 return 0; 463 464 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 465 ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc); 466 if (ret < 0) 467 return ret; 468 469 dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, 470 edata->load_count, edata->total_count); 471 return 0; 472 } 473 474 static const struct devfreq_event_ops exynos_ppmu_v2_ops = { 475 .disable = exynos_ppmu_v2_disable, 476 .set_event = exynos_ppmu_v2_set_event, 477 .get_event = exynos_ppmu_v2_get_event, 478 }; 479 480 static const struct of_device_id exynos_ppmu_id_match[] = { 481 { 482 .compatible = "samsung,exynos-ppmu", 483 .data = (void *)&exynos_ppmu_ops, 484 }, { 485 .compatible = "samsung,exynos-ppmu-v2", 486 .data = (void *)&exynos_ppmu_v2_ops, 487 }, 488 { /* sentinel */ }, 489 }; 490 MODULE_DEVICE_TABLE(of, exynos_ppmu_id_match); 491 492 static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np) 493 { 494 const struct of_device_id *match; 495 496 match = of_match_node(exynos_ppmu_id_match, np); 497 return (struct devfreq_event_ops *)match->data; 498 } 499 500 static int of_get_devfreq_events(struct device_node *np, 501 struct exynos_ppmu *info) 502 { 503 struct devfreq_event_desc *desc; 504 struct devfreq_event_ops *event_ops; 505 struct device *dev = info->dev; 506 struct device_node *events_np, *node; 507 int i, j, count; 508 509 events_np = of_get_child_by_name(np, "events"); 510 if (!events_np) { 511 dev_err(dev, 512 "failed to get child node of devfreq-event devices\n"); 513 return -EINVAL; 514 } 515 event_ops = exynos_bus_get_ops(np); 516 517 count = of_get_child_count(events_np); 518 desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL); 519 if (!desc) 520 return -ENOMEM; 521 info->num_events = count; 522 523 j = 0; 524 for_each_child_of_node(events_np, node) { 525 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { 526 if (!ppmu_events[i].name) 527 continue; 528 529 if (of_node_name_eq(node, ppmu_events[i].name)) 530 break; 531 } 532 533 if (i == ARRAY_SIZE(ppmu_events)) { 534 dev_warn(dev, 535 "don't know how to configure events : %pOFn\n", 536 node); 537 continue; 538 } 539 540 desc[j].ops = event_ops; 541 desc[j].driver_data = info; 542 543 of_property_read_string(node, "event-name", &desc[j].name); 544 545 j++; 546 } 547 info->desc = desc; 548 549 of_node_put(events_np); 550 551 return 0; 552 } 553 554 static struct regmap_config exynos_ppmu_regmap_config = { 555 .reg_bits = 32, 556 .val_bits = 32, 557 .reg_stride = 4, 558 }; 559 560 static int exynos_ppmu_parse_dt(struct platform_device *pdev, 561 struct exynos_ppmu *info) 562 { 563 struct device *dev = info->dev; 564 struct device_node *np = dev->of_node; 565 struct resource *res; 566 void __iomem *base; 567 int ret = 0; 568 569 if (!np) { 570 dev_err(dev, "failed to find devicetree node\n"); 571 return -EINVAL; 572 } 573 574 /* Maps the memory mapped IO to control PPMU register */ 575 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 576 base = devm_ioremap_resource(dev, res); 577 if (IS_ERR(base)) 578 return PTR_ERR(base); 579 580 exynos_ppmu_regmap_config.max_register = resource_size(res) - 4; 581 info->regmap = devm_regmap_init_mmio(dev, base, 582 &exynos_ppmu_regmap_config); 583 if (IS_ERR(info->regmap)) { 584 dev_err(dev, "failed to initialize regmap\n"); 585 return PTR_ERR(info->regmap); 586 } 587 588 info->ppmu.clk = devm_clk_get(dev, "ppmu"); 589 if (IS_ERR(info->ppmu.clk)) { 590 info->ppmu.clk = NULL; 591 dev_warn(dev, "cannot get PPMU clock\n"); 592 } 593 594 ret = of_get_devfreq_events(np, info); 595 if (ret < 0) { 596 dev_err(dev, "failed to parse exynos ppmu dt node\n"); 597 return ret; 598 } 599 600 return 0; 601 } 602 603 static int exynos_ppmu_probe(struct platform_device *pdev) 604 { 605 struct exynos_ppmu *info; 606 struct devfreq_event_dev **edev; 607 struct devfreq_event_desc *desc; 608 int i, ret = 0, size; 609 610 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 611 if (!info) 612 return -ENOMEM; 613 614 info->dev = &pdev->dev; 615 616 /* Parse dt data to get resource */ 617 ret = exynos_ppmu_parse_dt(pdev, info); 618 if (ret < 0) { 619 dev_err(&pdev->dev, 620 "failed to parse devicetree for resource\n"); 621 return ret; 622 } 623 desc = info->desc; 624 625 size = sizeof(struct devfreq_event_dev *) * info->num_events; 626 info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); 627 if (!info->edev) 628 return -ENOMEM; 629 630 edev = info->edev; 631 platform_set_drvdata(pdev, info); 632 633 for (i = 0; i < info->num_events; i++) { 634 edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]); 635 if (IS_ERR(edev[i])) { 636 ret = PTR_ERR(edev[i]); 637 dev_err(&pdev->dev, 638 "failed to add devfreq-event device\n"); 639 return PTR_ERR(edev[i]); 640 } 641 642 pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n", 643 dev_name(&pdev->dev), desc[i].name); 644 } 645 646 ret = clk_prepare_enable(info->ppmu.clk); 647 if (ret) { 648 dev_err(&pdev->dev, "failed to prepare ppmu clock\n"); 649 return ret; 650 } 651 652 return 0; 653 } 654 655 static int exynos_ppmu_remove(struct platform_device *pdev) 656 { 657 struct exynos_ppmu *info = platform_get_drvdata(pdev); 658 659 clk_disable_unprepare(info->ppmu.clk); 660 661 return 0; 662 } 663 664 static struct platform_driver exynos_ppmu_driver = { 665 .probe = exynos_ppmu_probe, 666 .remove = exynos_ppmu_remove, 667 .driver = { 668 .name = "exynos-ppmu", 669 .of_match_table = exynos_ppmu_id_match, 670 }, 671 }; 672 module_platform_driver(exynos_ppmu_driver); 673 674 MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver"); 675 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 676 MODULE_LICENSE("GPL"); 677