18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* intel_pch_thermal.c - Intel PCH Thermal driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2015, Intel Corporation. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Tushar Dave <tushar.n.dave@intel.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/acpi.h> 158c2ecf20Sopenharmony_ci#include <linux/thermal.h> 168c2ecf20Sopenharmony_ci#include <linux/units.h> 178c2ecf20Sopenharmony_ci#include <linux/pm.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Intel PCH thermal Device IDs */ 208c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_HSW_1 0x9C24 /* Haswell PCH */ 218c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_HSW_2 0x8C24 /* Haswell PCH */ 228c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */ 238c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */ 248c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */ 258c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */ 268c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */ 278c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */ 288c2ecf20Sopenharmony_ci#define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Wildcat Point-LP PCH Thermal registers */ 318c2ecf20Sopenharmony_ci#define WPT_TEMP 0x0000 /* Temperature */ 328c2ecf20Sopenharmony_ci#define WPT_TSC 0x04 /* Thermal Sensor Control */ 338c2ecf20Sopenharmony_ci#define WPT_TSS 0x06 /* Thermal Sensor Status */ 348c2ecf20Sopenharmony_ci#define WPT_TSEL 0x08 /* Thermal Sensor Enable and Lock */ 358c2ecf20Sopenharmony_ci#define WPT_TSREL 0x0A /* Thermal Sensor Report Enable and Lock */ 368c2ecf20Sopenharmony_ci#define WPT_TSMIC 0x0C /* Thermal Sensor SMI Control */ 378c2ecf20Sopenharmony_ci#define WPT_CTT 0x0010 /* Catastrophic Trip Point */ 388c2ecf20Sopenharmony_ci#define WPT_TAHV 0x0014 /* Thermal Alert High Value */ 398c2ecf20Sopenharmony_ci#define WPT_TALV 0x0018 /* Thermal Alert Low Value */ 408c2ecf20Sopenharmony_ci#define WPT_TL 0x00000040 /* Throttle Value */ 418c2ecf20Sopenharmony_ci#define WPT_PHL 0x0060 /* PCH Hot Level */ 428c2ecf20Sopenharmony_ci#define WPT_PHLC 0x62 /* PHL Control */ 438c2ecf20Sopenharmony_ci#define WPT_TAS 0x80 /* Thermal Alert Status */ 448c2ecf20Sopenharmony_ci#define WPT_TSPIEN 0x82 /* PCI Interrupt Event Enables */ 458c2ecf20Sopenharmony_ci#define WPT_TSGPEN 0x84 /* General Purpose Event Enables */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Wildcat Point-LP PCH Thermal Register bit definitions */ 488c2ecf20Sopenharmony_ci#define WPT_TEMP_TSR 0x01ff /* Temp TS Reading */ 498c2ecf20Sopenharmony_ci#define WPT_TSC_CPDE 0x01 /* Catastrophic Power-Down Enable */ 508c2ecf20Sopenharmony_ci#define WPT_TSS_TSDSS 0x10 /* Thermal Sensor Dynamic Shutdown Status */ 518c2ecf20Sopenharmony_ci#define WPT_TSS_GPES 0x08 /* GPE status */ 528c2ecf20Sopenharmony_ci#define WPT_TSEL_ETS 0x01 /* Enable TS */ 538c2ecf20Sopenharmony_ci#define WPT_TSEL_PLDB 0x80 /* TSEL Policy Lock-Down Bit */ 548c2ecf20Sopenharmony_ci#define WPT_TL_TOL 0x000001FF /* T0 Level */ 558c2ecf20Sopenharmony_ci#define WPT_TL_T1L 0x1ff00000 /* T1 Level */ 568c2ecf20Sopenharmony_ci#define WPT_TL_TTEN 0x20000000 /* TT Enable */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic char driver_name[] = "Intel PCH thermal driver"; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct pch_thermal_device { 618c2ecf20Sopenharmony_ci void __iomem *hw_base; 628c2ecf20Sopenharmony_ci const struct pch_dev_ops *ops; 638c2ecf20Sopenharmony_ci struct pci_dev *pdev; 648c2ecf20Sopenharmony_ci struct thermal_zone_device *tzd; 658c2ecf20Sopenharmony_ci int crt_trip_id; 668c2ecf20Sopenharmony_ci unsigned long crt_temp; 678c2ecf20Sopenharmony_ci int hot_trip_id; 688c2ecf20Sopenharmony_ci unsigned long hot_temp; 698c2ecf20Sopenharmony_ci int psv_trip_id; 708c2ecf20Sopenharmony_ci unsigned long psv_temp; 718c2ecf20Sopenharmony_ci bool bios_enabled; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * On some platforms, there is a companion ACPI device, which adds 788c2ecf20Sopenharmony_ci * passive trip temperature using _PSV method. There is no specific 798c2ecf20Sopenharmony_ci * passive temperature setting in MMIO interface of this PCI device. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, 828c2ecf20Sopenharmony_ci int *nr_trips) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct acpi_device *adev; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci ptd->psv_trip_id = -1; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci adev = ACPI_COMPANION(&ptd->pdev->dev); 898c2ecf20Sopenharmony_ci if (adev) { 908c2ecf20Sopenharmony_ci unsigned long long r; 918c2ecf20Sopenharmony_ci acpi_status status; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(adev->handle, "_PSV", NULL, 948c2ecf20Sopenharmony_ci &r); 958c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 968c2ecf20Sopenharmony_ci unsigned long trip_temp; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci trip_temp = deci_kelvin_to_millicelsius(r); 998c2ecf20Sopenharmony_ci if (trip_temp) { 1008c2ecf20Sopenharmony_ci ptd->psv_temp = trip_temp; 1018c2ecf20Sopenharmony_ci ptd->psv_trip_id = *nr_trips; 1028c2ecf20Sopenharmony_ci ++(*nr_trips); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci#else 1088c2ecf20Sopenharmony_cistatic void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd, 1098c2ecf20Sopenharmony_ci int *nr_trips) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci ptd->psv_trip_id = -1; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci u8 tsel; 1198c2ecf20Sopenharmony_ci u16 trip_temp; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci *nr_trips = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Check if BIOS has already enabled thermal sensor */ 1248c2ecf20Sopenharmony_ci if (WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL)) { 1258c2ecf20Sopenharmony_ci ptd->bios_enabled = true; 1268c2ecf20Sopenharmony_ci goto read_trips; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci tsel = readb(ptd->hw_base + WPT_TSEL); 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * When TSEL's Policy Lock-Down bit is 1, TSEL become RO. 1328c2ecf20Sopenharmony_ci * If so, thermal sensor cannot enable. Bail out. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci if (tsel & WPT_TSEL_PLDB) { 1358c2ecf20Sopenharmony_ci dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n"); 1368c2ecf20Sopenharmony_ci return -ENODEV; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci writeb(tsel|WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL); 1408c2ecf20Sopenharmony_ci if (!(WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL))) { 1418c2ecf20Sopenharmony_ci dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n"); 1428c2ecf20Sopenharmony_ci return -ENODEV; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciread_trips: 1468c2ecf20Sopenharmony_ci ptd->crt_trip_id = -1; 1478c2ecf20Sopenharmony_ci trip_temp = readw(ptd->hw_base + WPT_CTT); 1488c2ecf20Sopenharmony_ci trip_temp &= 0x1FF; 1498c2ecf20Sopenharmony_ci if (trip_temp) { 1508c2ecf20Sopenharmony_ci /* Resolution of 1/2 degree C and an offset of -50C */ 1518c2ecf20Sopenharmony_ci ptd->crt_temp = trip_temp * 1000 / 2 - 50000; 1528c2ecf20Sopenharmony_ci ptd->crt_trip_id = 0; 1538c2ecf20Sopenharmony_ci ++(*nr_trips); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ptd->hot_trip_id = -1; 1578c2ecf20Sopenharmony_ci trip_temp = readw(ptd->hw_base + WPT_PHL); 1588c2ecf20Sopenharmony_ci trip_temp &= 0x1FF; 1598c2ecf20Sopenharmony_ci if (trip_temp) { 1608c2ecf20Sopenharmony_ci /* Resolution of 1/2 degree C and an offset of -50C */ 1618c2ecf20Sopenharmony_ci ptd->hot_temp = trip_temp * 1000 / 2 - 50000; 1628c2ecf20Sopenharmony_ci ptd->hot_trip_id = *nr_trips; 1638c2ecf20Sopenharmony_ci ++(*nr_trips); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci pch_wpt_add_acpi_psv_trip(ptd, nr_trips); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci u16 wpt_temp; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci wpt_temp = WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Resolution of 1/2 degree C and an offset of -50C */ 1788c2ecf20Sopenharmony_ci *temp = (wpt_temp * 1000 / 2 - 50000); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int pch_wpt_suspend(struct pch_thermal_device *ptd) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci u8 tsel; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (ptd->bios_enabled) 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci tsel = readb(ptd->hw_base + WPT_TSEL); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci writeb(tsel & 0xFE, ptd->hw_base + WPT_TSEL); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int pch_wpt_resume(struct pch_thermal_device *ptd) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u8 tsel; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (ptd->bios_enabled) 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci tsel = readb(ptd->hw_base + WPT_TSEL); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci writeb(tsel | WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistruct pch_dev_ops { 2128c2ecf20Sopenharmony_ci int (*hw_init)(struct pch_thermal_device *ptd, int *nr_trips); 2138c2ecf20Sopenharmony_ci int (*get_temp)(struct pch_thermal_device *ptd, int *temp); 2148c2ecf20Sopenharmony_ci int (*suspend)(struct pch_thermal_device *ptd); 2158c2ecf20Sopenharmony_ci int (*resume)(struct pch_thermal_device *ptd); 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* dev ops for Wildcat Point */ 2208c2ecf20Sopenharmony_cistatic const struct pch_dev_ops pch_dev_ops_wpt = { 2218c2ecf20Sopenharmony_ci .hw_init = pch_wpt_init, 2228c2ecf20Sopenharmony_ci .get_temp = pch_wpt_get_temp, 2238c2ecf20Sopenharmony_ci .suspend = pch_wpt_suspend, 2248c2ecf20Sopenharmony_ci .resume = pch_wpt_resume, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = tzd->devdata; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ptd->ops->get_temp(ptd, temp); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int pch_get_trip_type(struct thermal_zone_device *tzd, int trip, 2358c2ecf20Sopenharmony_ci enum thermal_trip_type *type) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = tzd->devdata; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (ptd->crt_trip_id == trip) 2408c2ecf20Sopenharmony_ci *type = THERMAL_TRIP_CRITICAL; 2418c2ecf20Sopenharmony_ci else if (ptd->hot_trip_id == trip) 2428c2ecf20Sopenharmony_ci *type = THERMAL_TRIP_HOT; 2438c2ecf20Sopenharmony_ci else if (ptd->psv_trip_id == trip) 2448c2ecf20Sopenharmony_ci *type = THERMAL_TRIP_PASSIVE; 2458c2ecf20Sopenharmony_ci else 2468c2ecf20Sopenharmony_ci return -EINVAL; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *temp) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = tzd->devdata; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (ptd->crt_trip_id == trip) 2568c2ecf20Sopenharmony_ci *temp = ptd->crt_temp; 2578c2ecf20Sopenharmony_ci else if (ptd->hot_trip_id == trip) 2588c2ecf20Sopenharmony_ci *temp = ptd->hot_temp; 2598c2ecf20Sopenharmony_ci else if (ptd->psv_trip_id == trip) 2608c2ecf20Sopenharmony_ci *temp = ptd->psv_temp; 2618c2ecf20Sopenharmony_ci else 2628c2ecf20Sopenharmony_ci return -EINVAL; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic struct thermal_zone_device_ops tzd_ops = { 2688c2ecf20Sopenharmony_ci .get_temp = pch_thermal_get_temp, 2698c2ecf20Sopenharmony_ci .get_trip_type = pch_get_trip_type, 2708c2ecf20Sopenharmony_ci .get_trip_temp = pch_get_trip_temp, 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cienum board_ids { 2748c2ecf20Sopenharmony_ci board_hsw, 2758c2ecf20Sopenharmony_ci board_wpt, 2768c2ecf20Sopenharmony_ci board_skl, 2778c2ecf20Sopenharmony_ci board_cnl, 2788c2ecf20Sopenharmony_ci board_cml, 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const struct board_info { 2828c2ecf20Sopenharmony_ci const char *name; 2838c2ecf20Sopenharmony_ci const struct pch_dev_ops *ops; 2848c2ecf20Sopenharmony_ci} board_info[] = { 2858c2ecf20Sopenharmony_ci [board_hsw] = { 2868c2ecf20Sopenharmony_ci .name = "pch_haswell", 2878c2ecf20Sopenharmony_ci .ops = &pch_dev_ops_wpt, 2888c2ecf20Sopenharmony_ci }, 2898c2ecf20Sopenharmony_ci [board_wpt] = { 2908c2ecf20Sopenharmony_ci .name = "pch_wildcat_point", 2918c2ecf20Sopenharmony_ci .ops = &pch_dev_ops_wpt, 2928c2ecf20Sopenharmony_ci }, 2938c2ecf20Sopenharmony_ci [board_skl] = { 2948c2ecf20Sopenharmony_ci .name = "pch_skylake", 2958c2ecf20Sopenharmony_ci .ops = &pch_dev_ops_wpt, 2968c2ecf20Sopenharmony_ci }, 2978c2ecf20Sopenharmony_ci [board_cnl] = { 2988c2ecf20Sopenharmony_ci .name = "pch_cannonlake", 2998c2ecf20Sopenharmony_ci .ops = &pch_dev_ops_wpt, 3008c2ecf20Sopenharmony_ci }, 3018c2ecf20Sopenharmony_ci [board_cml] = { 3028c2ecf20Sopenharmony_ci .name = "pch_cometlake", 3038c2ecf20Sopenharmony_ci .ops = &pch_dev_ops_wpt, 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int intel_pch_thermal_probe(struct pci_dev *pdev, 3088c2ecf20Sopenharmony_ci const struct pci_device_id *id) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci enum board_ids board_id = id->driver_data; 3118c2ecf20Sopenharmony_ci const struct board_info *bi = &board_info[board_id]; 3128c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd; 3138c2ecf20Sopenharmony_ci int err; 3148c2ecf20Sopenharmony_ci int nr_trips; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL); 3178c2ecf20Sopenharmony_ci if (!ptd) 3188c2ecf20Sopenharmony_ci return -ENOMEM; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ptd->ops = bi->ops; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ptd); 3238c2ecf20Sopenharmony_ci ptd->pdev = pdev; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 3268c2ecf20Sopenharmony_ci if (err) { 3278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to enable pci device\n"); 3288c2ecf20Sopenharmony_ci return err; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, driver_name); 3328c2ecf20Sopenharmony_ci if (err) { 3338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request pci region\n"); 3348c2ecf20Sopenharmony_ci goto error_disable; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ptd->hw_base = pci_ioremap_bar(pdev, 0); 3388c2ecf20Sopenharmony_ci if (!ptd->hw_base) { 3398c2ecf20Sopenharmony_ci err = -ENOMEM; 3408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to map mem base\n"); 3418c2ecf20Sopenharmony_ci goto error_release; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci err = ptd->ops->hw_init(ptd, &nr_trips); 3458c2ecf20Sopenharmony_ci if (err) 3468c2ecf20Sopenharmony_ci goto error_cleanup; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ptd->tzd = thermal_zone_device_register(bi->name, nr_trips, 0, ptd, 3498c2ecf20Sopenharmony_ci &tzd_ops, NULL, 0, 0); 3508c2ecf20Sopenharmony_ci if (IS_ERR(ptd->tzd)) { 3518c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register thermal zone %s\n", 3528c2ecf20Sopenharmony_ci bi->name); 3538c2ecf20Sopenharmony_ci err = PTR_ERR(ptd->tzd); 3548c2ecf20Sopenharmony_ci goto error_cleanup; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci err = thermal_zone_device_enable(ptd->tzd); 3578c2ecf20Sopenharmony_ci if (err) 3588c2ecf20Sopenharmony_ci goto err_unregister; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cierr_unregister: 3638c2ecf20Sopenharmony_ci thermal_zone_device_unregister(ptd->tzd); 3648c2ecf20Sopenharmony_cierror_cleanup: 3658c2ecf20Sopenharmony_ci iounmap(ptd->hw_base); 3668c2ecf20Sopenharmony_cierror_release: 3678c2ecf20Sopenharmony_ci pci_release_regions(pdev); 3688c2ecf20Sopenharmony_cierror_disable: 3698c2ecf20Sopenharmony_ci pci_disable_device(pdev); 3708c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci device failed to probe\n"); 3718c2ecf20Sopenharmony_ci return err; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void intel_pch_thermal_remove(struct pci_dev *pdev) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = pci_get_drvdata(pdev); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci thermal_zone_device_unregister(ptd->tzd); 3798c2ecf20Sopenharmony_ci iounmap(ptd->hw_base); 3808c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 3818c2ecf20Sopenharmony_ci pci_release_regions(pdev); 3828c2ecf20Sopenharmony_ci pci_disable_device(pdev); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int intel_pch_thermal_suspend(struct device *device) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = dev_get_drvdata(device); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return ptd->ops->suspend(ptd); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int intel_pch_thermal_resume(struct device *device) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct pch_thermal_device *ptd = dev_get_drvdata(device); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return ptd->ops->resume(ptd); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic const struct pci_device_id intel_pch_thermal_id[] = { 4008c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1), 4018c2ecf20Sopenharmony_ci .driver_data = board_hsw, }, 4028c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2), 4038c2ecf20Sopenharmony_ci .driver_data = board_hsw, }, 4048c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT), 4058c2ecf20Sopenharmony_ci .driver_data = board_wpt, }, 4068c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL), 4078c2ecf20Sopenharmony_ci .driver_data = board_skl, }, 4088c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H), 4098c2ecf20Sopenharmony_ci .driver_data = board_skl, }, 4108c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL), 4118c2ecf20Sopenharmony_ci .driver_data = board_cnl, }, 4128c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H), 4138c2ecf20Sopenharmony_ci .driver_data = board_cnl, }, 4148c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP), 4158c2ecf20Sopenharmony_ci .driver_data = board_cnl, }, 4168c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H), 4178c2ecf20Sopenharmony_ci .driver_data = board_cml, }, 4188c2ecf20Sopenharmony_ci { 0, }, 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, intel_pch_thermal_id); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic const struct dev_pm_ops intel_pch_pm_ops = { 4238c2ecf20Sopenharmony_ci .suspend = intel_pch_thermal_suspend, 4248c2ecf20Sopenharmony_ci .resume = intel_pch_thermal_resume, 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic struct pci_driver intel_pch_thermal_driver = { 4288c2ecf20Sopenharmony_ci .name = "intel_pch_thermal", 4298c2ecf20Sopenharmony_ci .id_table = intel_pch_thermal_id, 4308c2ecf20Sopenharmony_ci .probe = intel_pch_thermal_probe, 4318c2ecf20Sopenharmony_ci .remove = intel_pch_thermal_remove, 4328c2ecf20Sopenharmony_ci .driver.pm = &intel_pch_pm_ops, 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cimodule_pci_driver(intel_pch_thermal_driver); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel PCH Thermal driver"); 439