exynos_tmu.c (9025d563cd9bd141a7b7f2095b6a760cd9d83a4e) | exynos_tmu.c (14a11dc7e0dbf4acdd9c7b703ebd088f14def739) |
---|---|
1/* 2 * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit) 3 * 4 * Copyright (C) 2011 Samsung Electronics 5 * Donggeun Kim <dg77.kim@samsung.com> 6 * Amit Daniel Kachhap <amit.kachhap@linaro.org> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 33 unchanged lines hidden (view full) --- 42 * @pdata: pointer to the tmu platform/configuration data 43 * @base: base address of the single instance of the TMU controller. 44 * @base_second: base address of the common registers of the TMU controller. 45 * @irq: irq number of the TMU controller. 46 * @soc: id of the SOC type. 47 * @irq_work: pointer to the irq work structure. 48 * @lock: lock to implement synchronization. 49 * @clk: pointer to the clock structure. | 1/* 2 * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit) 3 * 4 * Copyright (C) 2011 Samsung Electronics 5 * Donggeun Kim <dg77.kim@samsung.com> 6 * Amit Daniel Kachhap <amit.kachhap@linaro.org> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 33 unchanged lines hidden (view full) --- 42 * @pdata: pointer to the tmu platform/configuration data 43 * @base: base address of the single instance of the TMU controller. 44 * @base_second: base address of the common registers of the TMU controller. 45 * @irq: irq number of the TMU controller. 46 * @soc: id of the SOC type. 47 * @irq_work: pointer to the irq work structure. 48 * @lock: lock to implement synchronization. 49 * @clk: pointer to the clock structure. |
50 * @clk_sec: pointer to the clock structure for accessing the base_second. |
|
50 * @temp_error1: fused value of the first point trim. 51 * @temp_error2: fused value of the second point trim. 52 * @regulator: pointer to the TMU regulator structure. 53 * @reg_conf: pointer to structure to register with core thermal. 54 */ 55struct exynos_tmu_data { 56 int id; 57 struct exynos_tmu_platform_data *pdata; 58 void __iomem *base; 59 void __iomem *base_second; 60 int irq; 61 enum soc_type soc; 62 struct work_struct irq_work; 63 struct mutex lock; | 51 * @temp_error1: fused value of the first point trim. 52 * @temp_error2: fused value of the second point trim. 53 * @regulator: pointer to the TMU regulator structure. 54 * @reg_conf: pointer to structure to register with core thermal. 55 */ 56struct exynos_tmu_data { 57 int id; 58 struct exynos_tmu_platform_data *pdata; 59 void __iomem *base; 60 void __iomem *base_second; 61 int irq; 62 enum soc_type soc; 63 struct work_struct irq_work; 64 struct mutex lock; |
64 struct clk *clk; | 65 struct clk *clk, *clk_sec; |
65 u8 temp_error1, temp_error2; 66 struct regulator *regulator; 67 struct thermal_sensor_conf *reg_conf; 68}; 69 70/* 71 * TMU treats temperature as a mapped temperature code. 72 * The temperature is converted differently depending on the calibration type. --- 74 unchanged lines hidden (view full) --- 147 struct exynos_tmu_platform_data *pdata = data->pdata; 148 const struct exynos_tmu_registers *reg = pdata->registers; 149 unsigned int status, trim_info = 0, con; 150 unsigned int rising_threshold = 0, falling_threshold = 0; 151 int ret = 0, threshold_code, i, trigger_levs = 0; 152 153 mutex_lock(&data->lock); 154 clk_enable(data->clk); | 66 u8 temp_error1, temp_error2; 67 struct regulator *regulator; 68 struct thermal_sensor_conf *reg_conf; 69}; 70 71/* 72 * TMU treats temperature as a mapped temperature code. 73 * The temperature is converted differently depending on the calibration type. --- 74 unchanged lines hidden (view full) --- 148 struct exynos_tmu_platform_data *pdata = data->pdata; 149 const struct exynos_tmu_registers *reg = pdata->registers; 150 unsigned int status, trim_info = 0, con; 151 unsigned int rising_threshold = 0, falling_threshold = 0; 152 int ret = 0, threshold_code, i, trigger_levs = 0; 153 154 mutex_lock(&data->lock); 155 clk_enable(data->clk); |
156 if (!IS_ERR(data->clk_sec)) 157 clk_enable(data->clk_sec); |
|
155 156 if (TMU_SUPPORTS(pdata, READY_STATUS)) { 157 status = readb(data->base + reg->tmu_status); 158 if (!status) { 159 ret = -EBUSY; 160 goto out; 161 } 162 } --- 18 unchanged lines hidden (view full) --- 181 case 1: 182 trim_info = readl(data->base + reg->triminfo_data); 183 break; 184 case 2: 185 trim_info = readl(data->base - 186 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 187 } 188 } else { | 158 159 if (TMU_SUPPORTS(pdata, READY_STATUS)) { 160 status = readb(data->base + reg->tmu_status); 161 if (!status) { 162 ret = -EBUSY; 163 goto out; 164 } 165 } --- 18 unchanged lines hidden (view full) --- 184 case 1: 185 trim_info = readl(data->base + reg->triminfo_data); 186 break; 187 case 2: 188 trim_info = readl(data->base - 189 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 190 } 191 } else { |
189 trim_info = readl(data->base + reg->triminfo_data); | 192 /* On exynos5420 the triminfo register is in the shared space */ 193 if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) 194 trim_info = readl(data->base_second + 195 reg->triminfo_data); 196 else 197 trim_info = readl(data->base + reg->triminfo_data); |
190 } 191 data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; 192 data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) & 193 EXYNOS_TMU_TEMP_MASK); 194 195 if (!data->temp_error1 || 196 (pdata->min_efuse_value > data->temp_error1) || 197 (data->temp_error1 > pdata->max_efuse_value)) --- 99 unchanged lines hidden (view full) --- 297 } 298 } 299 /*Clear the PMIN in the common TMU register*/ 300 if (reg->tmu_pmin && !data->id) 301 writel(0, data->base_second + reg->tmu_pmin); 302out: 303 clk_disable(data->clk); 304 mutex_unlock(&data->lock); | 198 } 199 data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; 200 data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) & 201 EXYNOS_TMU_TEMP_MASK); 202 203 if (!data->temp_error1 || 204 (pdata->min_efuse_value > data->temp_error1) || 205 (data->temp_error1 > pdata->max_efuse_value)) --- 99 unchanged lines hidden (view full) --- 305 } 306 } 307 /*Clear the PMIN in the common TMU register*/ 308 if (reg->tmu_pmin && !data->id) 309 writel(0, data->base_second + reg->tmu_pmin); 310out: 311 clk_disable(data->clk); 312 mutex_unlock(&data->lock); |
313 if (!IS_ERR(data->clk_sec)) 314 clk_disable(data->clk_sec); |
|
305 306 return ret; 307} 308 309static void exynos_tmu_control(struct platform_device *pdev, bool on) 310{ 311 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 312 struct exynos_tmu_platform_data *pdata = data->pdata; --- 135 unchanged lines hidden (view full) --- 448static void exynos_tmu_work(struct work_struct *work) 449{ 450 struct exynos_tmu_data *data = container_of(work, 451 struct exynos_tmu_data, irq_work); 452 struct exynos_tmu_platform_data *pdata = data->pdata; 453 const struct exynos_tmu_registers *reg = pdata->registers; 454 unsigned int val_irq, val_type; 455 | 315 316 return ret; 317} 318 319static void exynos_tmu_control(struct platform_device *pdev, bool on) 320{ 321 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 322 struct exynos_tmu_platform_data *pdata = data->pdata; --- 135 unchanged lines hidden (view full) --- 458static void exynos_tmu_work(struct work_struct *work) 459{ 460 struct exynos_tmu_data *data = container_of(work, 461 struct exynos_tmu_data, irq_work); 462 struct exynos_tmu_platform_data *pdata = data->pdata; 463 const struct exynos_tmu_registers *reg = pdata->registers; 464 unsigned int val_irq, val_type; 465 |
466 if (!IS_ERR(data->clk_sec)) 467 clk_enable(data->clk_sec); |
|
456 /* Find which sensor generated this interrupt */ 457 if (reg->tmu_irqstatus) { 458 val_type = readl(data->base_second + reg->tmu_irqstatus); 459 if (!((val_type >> data->id) & 0x1)) 460 goto out; 461 } | 468 /* Find which sensor generated this interrupt */ 469 if (reg->tmu_irqstatus) { 470 val_type = readl(data->base_second + reg->tmu_irqstatus); 471 if (!((val_type >> data->id) & 0x1)) 472 goto out; 473 } |
474 if (!IS_ERR(data->clk_sec)) 475 clk_disable(data->clk_sec); |
|
462 463 exynos_report_trigger(data->reg_conf); 464 mutex_lock(&data->lock); 465 clk_enable(data->clk); 466 467 /* TODO: take action based on particular interrupt */ 468 val_irq = readl(data->base + reg->tmu_intstat); 469 /* clear the interrupts */ --- 24 unchanged lines hidden (view full) --- 494 .compatible = "samsung,exynos4412-tmu", 495 .data = (void *)EXYNOS4412_TMU_DRV_DATA, 496 }, 497 { 498 .compatible = "samsung,exynos5250-tmu", 499 .data = (void *)EXYNOS5250_TMU_DRV_DATA, 500 }, 501 { | 476 477 exynos_report_trigger(data->reg_conf); 478 mutex_lock(&data->lock); 479 clk_enable(data->clk); 480 481 /* TODO: take action based on particular interrupt */ 482 val_irq = readl(data->base + reg->tmu_intstat); 483 /* clear the interrupts */ --- 24 unchanged lines hidden (view full) --- 508 .compatible = "samsung,exynos4412-tmu", 509 .data = (void *)EXYNOS4412_TMU_DRV_DATA, 510 }, 511 { 512 .compatible = "samsung,exynos5250-tmu", 513 .data = (void *)EXYNOS5250_TMU_DRV_DATA, 514 }, 515 { |
516 .compatible = "samsung,exynos5420-tmu", 517 .data = (void *)EXYNOS5420_TMU_DRV_DATA, 518 }, 519 { 520 .compatible = "samsung,exynos5420-tmu-ext-triminfo", 521 .data = (void *)EXYNOS5420_TMU_DRV_DATA, 522 }, 523 { |
|
502 .compatible = "samsung,exynos5440-tmu", 503 .data = (void *)EXYNOS5440_TMU_DRV_DATA, 504 }, 505 {}, 506}; 507MODULE_DEVICE_TABLE(of, exynos_tmu_match); 508 509static inline struct exynos_tmu_platform_data *exynos_get_driver_data( --- 114 unchanged lines hidden (view full) --- 624 INIT_WORK(&data->irq_work, exynos_tmu_work); 625 626 data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); 627 if (IS_ERR(data->clk)) { 628 dev_err(&pdev->dev, "Failed to get clock\n"); 629 return PTR_ERR(data->clk); 630 } 631 | 524 .compatible = "samsung,exynos5440-tmu", 525 .data = (void *)EXYNOS5440_TMU_DRV_DATA, 526 }, 527 {}, 528}; 529MODULE_DEVICE_TABLE(of, exynos_tmu_match); 530 531static inline struct exynos_tmu_platform_data *exynos_get_driver_data( --- 114 unchanged lines hidden (view full) --- 646 INIT_WORK(&data->irq_work, exynos_tmu_work); 647 648 data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); 649 if (IS_ERR(data->clk)) { 650 dev_err(&pdev->dev, "Failed to get clock\n"); 651 return PTR_ERR(data->clk); 652 } 653 |
654 data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif"); 655 if (IS_ERR(data->clk_sec)) { 656 if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { 657 dev_err(&pdev->dev, "Failed to get triminfo clock\n"); 658 return PTR_ERR(data->clk_sec); 659 } 660 } else { 661 ret = clk_prepare(data->clk_sec); 662 if (ret) { 663 dev_err(&pdev->dev, "Failed to get clock\n"); 664 return ret; 665 } 666 } 667 |
|
632 ret = clk_prepare(data->clk); | 668 ret = clk_prepare(data->clk); |
633 if (ret) 634 return ret; | 669 if (ret) { 670 dev_err(&pdev->dev, "Failed to get clock\n"); 671 goto err_clk_sec; 672 } |
635 636 if (pdata->type == SOC_ARCH_EXYNOS4210 || 637 pdata->type == SOC_ARCH_EXYNOS4412 || 638 pdata->type == SOC_ARCH_EXYNOS5250 || | 673 674 if (pdata->type == SOC_ARCH_EXYNOS4210 || 675 pdata->type == SOC_ARCH_EXYNOS4412 || 676 pdata->type == SOC_ARCH_EXYNOS5250 || |
677 pdata->type == SOC_ARCH_EXYNOS5420_TRIMINFO || |
|
639 pdata->type == SOC_ARCH_EXYNOS5440) 640 data->soc = pdata->type; 641 else { 642 ret = -EINVAL; 643 dev_err(&pdev->dev, "Platform not supported\n"); 644 goto err_clk; 645 } 646 --- 52 unchanged lines hidden (view full) --- 699 if (ret) { 700 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); 701 goto err_clk; 702 } 703 704 return 0; 705err_clk: 706 clk_unprepare(data->clk); | 678 pdata->type == SOC_ARCH_EXYNOS5440) 679 data->soc = pdata->type; 680 else { 681 ret = -EINVAL; 682 dev_err(&pdev->dev, "Platform not supported\n"); 683 goto err_clk; 684 } 685 --- 52 unchanged lines hidden (view full) --- 738 if (ret) { 739 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); 740 goto err_clk; 741 } 742 743 return 0; 744err_clk: 745 clk_unprepare(data->clk); |
746err_clk_sec: 747 if (!IS_ERR(data->clk_sec)) 748 clk_unprepare(data->clk_sec); |
|
707 return ret; 708} 709 710static int exynos_tmu_remove(struct platform_device *pdev) 711{ 712 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 713 714 exynos_tmu_control(pdev, false); 715 716 exynos_unregister_thermal(data->reg_conf); 717 718 clk_unprepare(data->clk); | 749 return ret; 750} 751 752static int exynos_tmu_remove(struct platform_device *pdev) 753{ 754 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 755 756 exynos_tmu_control(pdev, false); 757 758 exynos_unregister_thermal(data->reg_conf); 759 760 clk_unprepare(data->clk); |
761 if (!IS_ERR(data->clk_sec)) 762 clk_unprepare(data->clk_sec); |
|
719 720 if (!IS_ERR(data->regulator)) 721 regulator_disable(data->regulator); 722 723 return 0; 724} 725 726#ifdef CONFIG_PM_SLEEP --- 41 unchanged lines hidden --- | 763 764 if (!IS_ERR(data->regulator)) 765 regulator_disable(data->regulator); 766 767 return 0; 768} 769 770#ifdef CONFIG_PM_SLEEP --- 41 unchanged lines hidden --- |