exynos_tmu.c revision 9c7a87f146a642447db29327bcedfbe2163da172
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 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24#include <linux/clk.h> 25#include <linux/io.h> 26#include <linux/interrupt.h> 27#include <linux/module.h> 28#include <linux/of.h> 29#include <linux/of_address.h> 30#include <linux/of_irq.h> 31#include <linux/platform_device.h> 32#include <linux/regulator/consumer.h> 33 34#include "exynos_thermal_common.h" 35#include "exynos_tmu.h" 36#include "exynos_tmu_data.h" 37 38/** 39 * struct exynos_tmu_data : A structure to hold the private data of the TMU 40 driver 41 * @id: identifier of the one instance of the TMU controller. 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. 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; 65 struct clk *clk, *clk_sec; 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 */ 75static int temp_to_code(struct exynos_tmu_data *data, u8 temp) 76{ 77 struct exynos_tmu_platform_data *pdata = data->pdata; 78 int temp_code; 79 80 switch (pdata->cal_type) { 81 case TYPE_TWO_POINT_TRIMMING: 82 temp_code = (temp - pdata->first_point_trim) * 83 (data->temp_error2 - data->temp_error1) / 84 (pdata->second_point_trim - pdata->first_point_trim) + 85 data->temp_error1; 86 break; 87 case TYPE_ONE_POINT_TRIMMING: 88 temp_code = temp + data->temp_error1 - pdata->first_point_trim; 89 break; 90 default: 91 temp_code = temp + pdata->default_temp_offset; 92 break; 93 } 94 95 return temp_code; 96} 97 98/* 99 * Calculate a temperature value from a temperature code. 100 * The unit of the temperature is degree Celsius. 101 */ 102static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code) 103{ 104 struct exynos_tmu_platform_data *pdata = data->pdata; 105 int temp; 106 107 switch (pdata->cal_type) { 108 case TYPE_TWO_POINT_TRIMMING: 109 temp = (temp_code - data->temp_error1) * 110 (pdata->second_point_trim - pdata->first_point_trim) / 111 (data->temp_error2 - data->temp_error1) + 112 pdata->first_point_trim; 113 break; 114 case TYPE_ONE_POINT_TRIMMING: 115 temp = temp_code - data->temp_error1 + pdata->first_point_trim; 116 break; 117 default: 118 temp = temp_code - pdata->default_temp_offset; 119 break; 120 } 121 122 return temp; 123} 124 125static int exynos_tmu_initialize(struct platform_device *pdev) 126{ 127 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 128 struct exynos_tmu_platform_data *pdata = data->pdata; 129 const struct exynos_tmu_registers *reg = pdata->registers; 130 unsigned int status, trim_info = 0, con; 131 unsigned int rising_threshold = 0, falling_threshold = 0; 132 int ret = 0, threshold_code, i; 133 134 mutex_lock(&data->lock); 135 clk_enable(data->clk); 136 if (!IS_ERR(data->clk_sec)) 137 clk_enable(data->clk_sec); 138 139 if (TMU_SUPPORTS(pdata, READY_STATUS)) { 140 status = readb(data->base + reg->tmu_status); 141 if (!status) { 142 ret = -EBUSY; 143 goto out; 144 } 145 } 146 147 if (TMU_SUPPORTS(pdata, TRIM_RELOAD)) 148 __raw_writel(1, data->base + reg->triminfo_ctrl); 149 150 /* Save trimming info in order to perform calibration */ 151 if (data->soc == SOC_ARCH_EXYNOS5440) { 152 /* 153 * For exynos5440 soc triminfo value is swapped between TMU0 and 154 * TMU2, so the below logic is needed. 155 */ 156 switch (data->id) { 157 case 0: 158 trim_info = readl(data->base + 159 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 160 break; 161 case 1: 162 trim_info = readl(data->base + reg->triminfo_data); 163 break; 164 case 2: 165 trim_info = readl(data->base - 166 EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 167 } 168 } else { 169 /* On exynos5420 the triminfo register is in the shared space */ 170 if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) 171 trim_info = readl(data->base_second + 172 reg->triminfo_data); 173 else 174 trim_info = readl(data->base + reg->triminfo_data); 175 } 176 data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; 177 data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) & 178 EXYNOS_TMU_TEMP_MASK); 179 180 if (!data->temp_error1 || 181 (pdata->min_efuse_value > data->temp_error1) || 182 (data->temp_error1 > pdata->max_efuse_value)) 183 data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK; 184 185 if (!data->temp_error2) 186 data->temp_error2 = 187 (pdata->efuse_value >> reg->triminfo_85_shift) & 188 EXYNOS_TMU_TEMP_MASK; 189 190 rising_threshold = readl(data->base + reg->threshold_th0); 191 192 if (data->soc == SOC_ARCH_EXYNOS4210) { 193 /* Write temperature code for threshold */ 194 threshold_code = temp_to_code(data, pdata->threshold); 195 writeb(threshold_code, 196 data->base + reg->threshold_temp); 197 for (i = 0; i < pdata->non_hw_trigger_levels; i++) 198 writeb(pdata->trigger_levels[i], data->base + 199 reg->threshold_th0 + i * sizeof(reg->threshold_th0)); 200 201 writel(reg->intclr_rise_mask, data->base + reg->tmu_intclear); 202 } else { 203 /* Write temperature code for rising and falling threshold */ 204 for (i = 0; i < pdata->non_hw_trigger_levels; i++) { 205 threshold_code = temp_to_code(data, 206 pdata->trigger_levels[i]); 207 rising_threshold &= ~(0xff << 8 * i); 208 rising_threshold |= threshold_code << 8 * i; 209 if (pdata->threshold_falling) { 210 threshold_code = temp_to_code(data, 211 pdata->trigger_levels[i] - 212 pdata->threshold_falling); 213 falling_threshold |= threshold_code << 8 * i; 214 } 215 } 216 217 writel(rising_threshold, 218 data->base + reg->threshold_th0); 219 writel(falling_threshold, 220 data->base + reg->threshold_th1); 221 222 writel((reg->intclr_rise_mask << reg->intclr_rise_shift) | 223 (reg->intclr_fall_mask << reg->intclr_fall_shift), 224 data->base + reg->tmu_intclear); 225 226 /* if last threshold limit is also present */ 227 i = pdata->max_trigger_level - 1; 228 if (pdata->trigger_levels[i] && 229 (pdata->trigger_type[i] == HW_TRIP)) { 230 threshold_code = temp_to_code(data, 231 pdata->trigger_levels[i]); 232 if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) { 233 /* 1-4 level to be assigned in th0 reg */ 234 rising_threshold &= ~(0xff << 8 * i); 235 rising_threshold |= threshold_code << 8 * i; 236 writel(rising_threshold, 237 data->base + reg->threshold_th0); 238 } else if (i == EXYNOS_MAX_TRIGGER_PER_REG) { 239 /* 5th level to be assigned in th2 reg */ 240 rising_threshold = 241 threshold_code << reg->threshold_th3_l0_shift; 242 writel(rising_threshold, 243 data->base + reg->threshold_th2); 244 } 245 con = readl(data->base + reg->tmu_ctrl); 246 con |= (1 << reg->therm_trip_en_shift); 247 writel(con, data->base + reg->tmu_ctrl); 248 } 249 } 250 /*Clear the PMIN in the common TMU register*/ 251 if (reg->tmu_pmin && !data->id) 252 writel(0, data->base_second + reg->tmu_pmin); 253out: 254 clk_disable(data->clk); 255 mutex_unlock(&data->lock); 256 if (!IS_ERR(data->clk_sec)) 257 clk_disable(data->clk_sec); 258 259 return ret; 260} 261 262static void exynos_tmu_control(struct platform_device *pdev, bool on) 263{ 264 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 265 struct exynos_tmu_platform_data *pdata = data->pdata; 266 const struct exynos_tmu_registers *reg = pdata->registers; 267 unsigned int con, interrupt_en; 268 269 mutex_lock(&data->lock); 270 clk_enable(data->clk); 271 272 con = readl(data->base + reg->tmu_ctrl); 273 274 if (pdata->test_mux) 275 con |= (pdata->test_mux << reg->test_mux_addr_shift); 276 277 con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift); 278 con |= pdata->reference_voltage << reg->buf_vref_sel_shift; 279 280 con &= ~(reg->buf_slope_sel_mask << reg->buf_slope_sel_shift); 281 con |= (pdata->gain << reg->buf_slope_sel_shift); 282 283 if (pdata->noise_cancel_mode) { 284 con &= ~(reg->therm_trip_mode_mask << 285 reg->therm_trip_mode_shift); 286 con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift); 287 } 288 289 if (on) { 290 con |= (1 << reg->core_en_shift); 291 interrupt_en = 292 pdata->trigger_enable[3] << reg->inten_rise3_shift | 293 pdata->trigger_enable[2] << reg->inten_rise2_shift | 294 pdata->trigger_enable[1] << reg->inten_rise1_shift | 295 pdata->trigger_enable[0] << reg->inten_rise0_shift; 296 if (TMU_SUPPORTS(pdata, FALLING_TRIP)) 297 interrupt_en |= 298 interrupt_en << reg->inten_fall0_shift; 299 } else { 300 con &= ~(1 << reg->core_en_shift); 301 interrupt_en = 0; /* Disable all interrupts */ 302 } 303 writel(interrupt_en, data->base + reg->tmu_inten); 304 writel(con, data->base + reg->tmu_ctrl); 305 306 clk_disable(data->clk); 307 mutex_unlock(&data->lock); 308} 309 310static int exynos_tmu_read(struct exynos_tmu_data *data) 311{ 312 struct exynos_tmu_platform_data *pdata = data->pdata; 313 const struct exynos_tmu_registers *reg = pdata->registers; 314 u8 temp_code; 315 int temp; 316 317 mutex_lock(&data->lock); 318 clk_enable(data->clk); 319 320 temp_code = readb(data->base + reg->tmu_cur_temp); 321 322 if (data->soc == SOC_ARCH_EXYNOS4210) 323 /* temp_code should range between 75 and 175 */ 324 if (temp_code < 75 || temp_code > 175) { 325 temp = -ENODATA; 326 goto out; 327 } 328 329 temp = code_to_temp(data, temp_code); 330out: 331 clk_disable(data->clk); 332 mutex_unlock(&data->lock); 333 334 return temp; 335} 336 337#ifdef CONFIG_THERMAL_EMULATION 338static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) 339{ 340 struct exynos_tmu_data *data = drv_data; 341 struct exynos_tmu_platform_data *pdata = data->pdata; 342 const struct exynos_tmu_registers *reg = pdata->registers; 343 unsigned int val; 344 int ret = -EINVAL; 345 346 if (!TMU_SUPPORTS(pdata, EMULATION)) 347 goto out; 348 349 if (temp && temp < MCELSIUS) 350 goto out; 351 352 mutex_lock(&data->lock); 353 clk_enable(data->clk); 354 355 val = readl(data->base + reg->emul_con); 356 357 if (temp) { 358 temp /= MCELSIUS; 359 360 if (TMU_SUPPORTS(pdata, EMUL_TIME)) { 361 val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift); 362 val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift); 363 } 364 val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift); 365 val |= (temp_to_code(data, temp) << reg->emul_temp_shift) | 366 EXYNOS_EMUL_ENABLE; 367 } else { 368 val &= ~EXYNOS_EMUL_ENABLE; 369 } 370 371 writel(val, data->base + reg->emul_con); 372 373 clk_disable(data->clk); 374 mutex_unlock(&data->lock); 375 return 0; 376out: 377 return ret; 378} 379#else 380static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) 381 { return -EINVAL; } 382#endif/*CONFIG_THERMAL_EMULATION*/ 383 384static void exynos_tmu_work(struct work_struct *work) 385{ 386 struct exynos_tmu_data *data = container_of(work, 387 struct exynos_tmu_data, irq_work); 388 struct exynos_tmu_platform_data *pdata = data->pdata; 389 const struct exynos_tmu_registers *reg = pdata->registers; 390 unsigned int val_irq, val_type; 391 392 if (!IS_ERR(data->clk_sec)) 393 clk_enable(data->clk_sec); 394 /* Find which sensor generated this interrupt */ 395 if (reg->tmu_irqstatus) { 396 val_type = readl(data->base_second + reg->tmu_irqstatus); 397 if (!((val_type >> data->id) & 0x1)) 398 goto out; 399 } 400 if (!IS_ERR(data->clk_sec)) 401 clk_disable(data->clk_sec); 402 403 exynos_report_trigger(data->reg_conf); 404 mutex_lock(&data->lock); 405 clk_enable(data->clk); 406 407 /* TODO: take action based on particular interrupt */ 408 val_irq = readl(data->base + reg->tmu_intstat); 409 /* clear the interrupts */ 410 writel(val_irq, data->base + reg->tmu_intclear); 411 412 clk_disable(data->clk); 413 mutex_unlock(&data->lock); 414out: 415 enable_irq(data->irq); 416} 417 418static irqreturn_t exynos_tmu_irq(int irq, void *id) 419{ 420 struct exynos_tmu_data *data = id; 421 422 disable_irq_nosync(irq); 423 schedule_work(&data->irq_work); 424 425 return IRQ_HANDLED; 426} 427 428static const struct of_device_id exynos_tmu_match[] = { 429 { 430 .compatible = "samsung,exynos3250-tmu", 431 .data = (void *)EXYNOS3250_TMU_DRV_DATA, 432 }, 433 { 434 .compatible = "samsung,exynos4210-tmu", 435 .data = (void *)EXYNOS4210_TMU_DRV_DATA, 436 }, 437 { 438 .compatible = "samsung,exynos4412-tmu", 439 .data = (void *)EXYNOS4412_TMU_DRV_DATA, 440 }, 441 { 442 .compatible = "samsung,exynos5250-tmu", 443 .data = (void *)EXYNOS5250_TMU_DRV_DATA, 444 }, 445 { 446 .compatible = "samsung,exynos5260-tmu", 447 .data = (void *)EXYNOS5260_TMU_DRV_DATA, 448 }, 449 { 450 .compatible = "samsung,exynos5420-tmu", 451 .data = (void *)EXYNOS5420_TMU_DRV_DATA, 452 }, 453 { 454 .compatible = "samsung,exynos5420-tmu-ext-triminfo", 455 .data = (void *)EXYNOS5420_TMU_DRV_DATA, 456 }, 457 { 458 .compatible = "samsung,exynos5440-tmu", 459 .data = (void *)EXYNOS5440_TMU_DRV_DATA, 460 }, 461 {}, 462}; 463MODULE_DEVICE_TABLE(of, exynos_tmu_match); 464 465static inline struct exynos_tmu_platform_data *exynos_get_driver_data( 466 struct platform_device *pdev, int id) 467{ 468 struct exynos_tmu_init_data *data_table; 469 struct exynos_tmu_platform_data *tmu_data; 470 const struct of_device_id *match; 471 472 match = of_match_node(exynos_tmu_match, pdev->dev.of_node); 473 if (!match) 474 return NULL; 475 data_table = (struct exynos_tmu_init_data *) match->data; 476 if (!data_table || id >= data_table->tmu_count) 477 return NULL; 478 tmu_data = data_table->tmu_data; 479 return (struct exynos_tmu_platform_data *) (tmu_data + id); 480} 481 482static int exynos_map_dt_data(struct platform_device *pdev) 483{ 484 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 485 struct exynos_tmu_platform_data *pdata; 486 struct resource res; 487 int ret; 488 489 if (!data || !pdev->dev.of_node) 490 return -ENODEV; 491 492 /* 493 * Try enabling the regulator if found 494 * TODO: Add regulator as an SOC feature, so that regulator enable 495 * is a compulsory call. 496 */ 497 data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); 498 if (!IS_ERR(data->regulator)) { 499 ret = regulator_enable(data->regulator); 500 if (ret) { 501 dev_err(&pdev->dev, "failed to enable vtmu\n"); 502 return ret; 503 } 504 } else { 505 dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); 506 } 507 508 data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl"); 509 if (data->id < 0) 510 data->id = 0; 511 512 data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 513 if (data->irq <= 0) { 514 dev_err(&pdev->dev, "failed to get IRQ\n"); 515 return -ENODEV; 516 } 517 518 if (of_address_to_resource(pdev->dev.of_node, 0, &res)) { 519 dev_err(&pdev->dev, "failed to get Resource 0\n"); 520 return -ENODEV; 521 } 522 523 data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); 524 if (!data->base) { 525 dev_err(&pdev->dev, "Failed to ioremap memory\n"); 526 return -EADDRNOTAVAIL; 527 } 528 529 pdata = exynos_get_driver_data(pdev, data->id); 530 if (!pdata) { 531 dev_err(&pdev->dev, "No platform init data supplied.\n"); 532 return -ENODEV; 533 } 534 data->pdata = pdata; 535 /* 536 * Check if the TMU shares some registers and then try to map the 537 * memory of common registers. 538 */ 539 if (!TMU_SUPPORTS(pdata, ADDRESS_MULTIPLE)) 540 return 0; 541 542 if (of_address_to_resource(pdev->dev.of_node, 1, &res)) { 543 dev_err(&pdev->dev, "failed to get Resource 1\n"); 544 return -ENODEV; 545 } 546 547 data->base_second = devm_ioremap(&pdev->dev, res.start, 548 resource_size(&res)); 549 if (!data->base_second) { 550 dev_err(&pdev->dev, "Failed to ioremap memory\n"); 551 return -ENOMEM; 552 } 553 554 return 0; 555} 556 557static int exynos_tmu_probe(struct platform_device *pdev) 558{ 559 struct exynos_tmu_data *data; 560 struct exynos_tmu_platform_data *pdata; 561 struct thermal_sensor_conf *sensor_conf; 562 int ret, i; 563 564 data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data), 565 GFP_KERNEL); 566 if (!data) 567 return -ENOMEM; 568 569 platform_set_drvdata(pdev, data); 570 mutex_init(&data->lock); 571 572 ret = exynos_map_dt_data(pdev); 573 if (ret) 574 return ret; 575 576 pdata = data->pdata; 577 578 INIT_WORK(&data->irq_work, exynos_tmu_work); 579 580 data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); 581 if (IS_ERR(data->clk)) { 582 dev_err(&pdev->dev, "Failed to get clock\n"); 583 return PTR_ERR(data->clk); 584 } 585 586 data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif"); 587 if (IS_ERR(data->clk_sec)) { 588 if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { 589 dev_err(&pdev->dev, "Failed to get triminfo clock\n"); 590 return PTR_ERR(data->clk_sec); 591 } 592 } else { 593 ret = clk_prepare(data->clk_sec); 594 if (ret) { 595 dev_err(&pdev->dev, "Failed to get clock\n"); 596 return ret; 597 } 598 } 599 600 ret = clk_prepare(data->clk); 601 if (ret) { 602 dev_err(&pdev->dev, "Failed to get clock\n"); 603 goto err_clk_sec; 604 } 605 606 if (pdata->type == SOC_ARCH_EXYNOS3250 || 607 pdata->type == SOC_ARCH_EXYNOS4210 || 608 pdata->type == SOC_ARCH_EXYNOS4412 || 609 pdata->type == SOC_ARCH_EXYNOS5250 || 610 pdata->type == SOC_ARCH_EXYNOS5260 || 611 pdata->type == SOC_ARCH_EXYNOS5420_TRIMINFO || 612 pdata->type == SOC_ARCH_EXYNOS5440) 613 data->soc = pdata->type; 614 else { 615 ret = -EINVAL; 616 dev_err(&pdev->dev, "Platform not supported\n"); 617 goto err_clk; 618 } 619 620 ret = exynos_tmu_initialize(pdev); 621 if (ret) { 622 dev_err(&pdev->dev, "Failed to initialize TMU\n"); 623 goto err_clk; 624 } 625 626 exynos_tmu_control(pdev, true); 627 628 /* Allocate a structure to register with the exynos core thermal */ 629 sensor_conf = devm_kzalloc(&pdev->dev, 630 sizeof(struct thermal_sensor_conf), GFP_KERNEL); 631 if (!sensor_conf) { 632 ret = -ENOMEM; 633 goto err_clk; 634 } 635 sprintf(sensor_conf->name, "therm_zone%d", data->id); 636 sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read; 637 sensor_conf->write_emul_temp = 638 (int (*)(void *, unsigned long))exynos_tmu_set_emulation; 639 sensor_conf->driver_data = data; 640 sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] + 641 pdata->trigger_enable[1] + pdata->trigger_enable[2]+ 642 pdata->trigger_enable[3]; 643 644 for (i = 0; i < sensor_conf->trip_data.trip_count; i++) { 645 sensor_conf->trip_data.trip_val[i] = 646 pdata->threshold + pdata->trigger_levels[i]; 647 sensor_conf->trip_data.trip_type[i] = 648 pdata->trigger_type[i]; 649 } 650 651 sensor_conf->trip_data.trigger_falling = pdata->threshold_falling; 652 653 sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count; 654 for (i = 0; i < pdata->freq_tab_count; i++) { 655 sensor_conf->cooling_data.freq_data[i].freq_clip_max = 656 pdata->freq_tab[i].freq_clip_max; 657 sensor_conf->cooling_data.freq_data[i].temp_level = 658 pdata->freq_tab[i].temp_level; 659 } 660 sensor_conf->dev = &pdev->dev; 661 /* Register the sensor with thermal management interface */ 662 ret = exynos_register_thermal(sensor_conf); 663 if (ret) { 664 dev_err(&pdev->dev, "Failed to register thermal interface\n"); 665 goto err_clk; 666 } 667 data->reg_conf = sensor_conf; 668 669 ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, 670 IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); 671 if (ret) { 672 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); 673 goto err_clk; 674 } 675 676 return 0; 677err_clk: 678 clk_unprepare(data->clk); 679err_clk_sec: 680 if (!IS_ERR(data->clk_sec)) 681 clk_unprepare(data->clk_sec); 682 return ret; 683} 684 685static int exynos_tmu_remove(struct platform_device *pdev) 686{ 687 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 688 689 exynos_unregister_thermal(data->reg_conf); 690 691 exynos_tmu_control(pdev, false); 692 693 clk_unprepare(data->clk); 694 if (!IS_ERR(data->clk_sec)) 695 clk_unprepare(data->clk_sec); 696 697 if (!IS_ERR(data->regulator)) 698 regulator_disable(data->regulator); 699 700 return 0; 701} 702 703#ifdef CONFIG_PM_SLEEP 704static int exynos_tmu_suspend(struct device *dev) 705{ 706 exynos_tmu_control(to_platform_device(dev), false); 707 708 return 0; 709} 710 711static int exynos_tmu_resume(struct device *dev) 712{ 713 struct platform_device *pdev = to_platform_device(dev); 714 715 exynos_tmu_initialize(pdev); 716 exynos_tmu_control(pdev, true); 717 718 return 0; 719} 720 721static SIMPLE_DEV_PM_OPS(exynos_tmu_pm, 722 exynos_tmu_suspend, exynos_tmu_resume); 723#define EXYNOS_TMU_PM (&exynos_tmu_pm) 724#else 725#define EXYNOS_TMU_PM NULL 726#endif 727 728static struct platform_driver exynos_tmu_driver = { 729 .driver = { 730 .name = "exynos-tmu", 731 .owner = THIS_MODULE, 732 .pm = EXYNOS_TMU_PM, 733 .of_match_table = exynos_tmu_match, 734 }, 735 .probe = exynos_tmu_probe, 736 .remove = exynos_tmu_remove, 737}; 738 739module_platform_driver(exynos_tmu_driver); 740 741MODULE_DESCRIPTION("EXYNOS TMU Driver"); 742MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); 743MODULE_LICENSE("GPL"); 744MODULE_ALIAS("platform:exynos-tmu"); 745