1/* 2 * intel_soc_dts_thermal.c 3 * Copyright (c) 2014, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 */ 15 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18#include <linux/module.h> 19#include <linux/interrupt.h> 20#include <asm/cpu_device_id.h> 21#include "intel_soc_dts_iosf.h" 22 23#define CRITICAL_OFFSET_FROM_TJ_MAX 5000 24 25static int crit_offset = CRITICAL_OFFSET_FROM_TJ_MAX; 26module_param(crit_offset, int, 0644); 27MODULE_PARM_DESC(crit_offset, 28 "Critical Temperature offset from tj max in millidegree Celsius."); 29 30/* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ 31#define BYT_SOC_DTS_APIC_IRQ 86 32 33static int soc_dts_thres_irq; 34static struct intel_soc_dts_sensors *soc_dts; 35 36static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) 37{ 38 pr_debug("proc_thermal_interrupt\n"); 39 intel_soc_dts_iosf_interrupt_handler(soc_dts); 40 41 return IRQ_HANDLED; 42} 43 44static const struct x86_cpu_id soc_thermal_ids[] = { 45 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, 46 {} 47}; 48MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); 49 50static int __init intel_soc_thermal_init(void) 51{ 52 int err = 0; 53 const struct x86_cpu_id *match_cpu; 54 55 match_cpu = x86_match_cpu(soc_thermal_ids); 56 if (!match_cpu) 57 return -ENODEV; 58 59 /* Create a zone with 2 trips with marked as read only */ 60 soc_dts = intel_soc_dts_iosf_init(INTEL_SOC_DTS_INTERRUPT_APIC, 2, 1); 61 if (IS_ERR(soc_dts)) { 62 err = PTR_ERR(soc_dts); 63 return err; 64 } 65 66 soc_dts_thres_irq = (int)match_cpu->driver_data; 67 68 if (soc_dts_thres_irq) { 69 err = request_threaded_irq(soc_dts_thres_irq, NULL, 70 soc_irq_thread_fn, 71 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 72 "soc_dts", soc_dts); 73 if (err) { 74 pr_err("request_threaded_irq ret %d\n", err); 75 goto error_irq; 76 } 77 } 78 79 err = intel_soc_dts_iosf_add_read_only_critical_trip(soc_dts, 80 crit_offset); 81 if (err) 82 goto error_trips; 83 84 return 0; 85 86error_trips: 87 if (soc_dts_thres_irq) 88 free_irq(soc_dts_thres_irq, soc_dts); 89error_irq: 90 intel_soc_dts_iosf_exit(soc_dts); 91 92 return err; 93} 94 95static void __exit intel_soc_thermal_exit(void) 96{ 97 if (soc_dts_thres_irq) 98 free_irq(soc_dts_thres_irq, soc_dts); 99 intel_soc_dts_iosf_exit(soc_dts); 100} 101 102module_init(intel_soc_thermal_init) 103module_exit(intel_soc_thermal_exit) 104 105MODULE_DESCRIPTION("Intel SoC DTS Thermal Driver"); 106MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 107MODULE_LICENSE("GPL v2"); 108