Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | // SPDX-License-Identifier: GPL-2.0-or-later /* * i5500_temp - Driver for Intel 5500/5520/X58 chipset thermal sensor * * Copyright (C) 2012, 2014 Jean Delvare <jdelvare@suse.de> */ #include <linux/bitops.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/device.h> #include <linux/pci.h> #include <linux/hwmon.h> #include <linux/err.h> #include <linux/mutex.h> /* Register definitions from datasheet */ #define REG_TSTHRCATA 0xE2 #define REG_TSCTRL 0xE8 #define REG_TSTHRRPEX 0xEB #define REG_TSTHRLO 0xEC #define REG_TSTHRHI 0xEE #define REG_CTHINT 0xF0 #define REG_TSFSC 0xF3 #define REG_CTSTS 0xF4 #define REG_TSTHRRQPI 0xF5 #define REG_CTCTRL 0xF7 #define REG_TSTIMER 0xF8 static umode_t i5500_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) { return 0444; } static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { struct pci_dev *pdev = to_pci_dev(dev->parent); u16 tsthr; s8 tsfsc; u8 ctsts; switch (type) { case hwmon_temp: switch (attr) { /* Sensor resolution : 0.5 degree C */ case hwmon_temp_input: pci_read_config_word(pdev, REG_TSTHRHI, &tsthr); pci_read_config_byte(pdev, REG_TSFSC, &tsfsc); *val = (tsthr - tsfsc) * 500; return 0; case hwmon_temp_max: pci_read_config_word(pdev, REG_TSTHRHI, &tsthr); *val = tsthr * 500; return 0; case hwmon_temp_max_hyst: pci_read_config_word(pdev, REG_TSTHRLO, &tsthr); *val = tsthr * 500; return 0; case hwmon_temp_crit: pci_read_config_word(pdev, REG_TSTHRCATA, &tsthr); *val = tsthr * 500; return 0; case hwmon_temp_max_alarm: pci_read_config_byte(pdev, REG_CTSTS, &ctsts); *val = !!(ctsts & BIT(1)); return 0; case hwmon_temp_crit_alarm: pci_read_config_byte(pdev, REG_CTSTS, &ctsts); *val = !!(ctsts & BIT(0)); return 0; default: break; } break; default: break; } return -EOPNOTSUPP; } static const struct hwmon_ops i5500_ops = { .is_visible = i5500_is_visible, .read = i5500_read, }; static const struct hwmon_channel_info * const i5500_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM ), NULL }; static const struct hwmon_chip_info i5500_chip_info = { .ops = &i5500_ops, .info = i5500_info, }; static const struct pci_device_id i5500_temp_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) }, { 0 }, }; MODULE_DEVICE_TABLE(pci, i5500_temp_ids); static int i5500_temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; struct device *hwmon_dev; u32 tstimer; s8 tsfsc; err = pcim_enable_device(pdev); if (err) { dev_err(&pdev->dev, "Failed to enable device\n"); return err; } pci_read_config_byte(pdev, REG_TSFSC, &tsfsc); pci_read_config_dword(pdev, REG_TSTIMER, &tstimer); if (tsfsc == 0x7F && tstimer == 0x07D30D40) { dev_notice(&pdev->dev, "Sensor seems to be disabled\n"); return -ENODEV; } hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "intel5500", NULL, &i5500_chip_info, NULL); return PTR_ERR_OR_ZERO(hwmon_dev); } static struct pci_driver i5500_temp_driver = { .name = "i5500_temp", .id_table = i5500_temp_ids, .probe = i5500_temp_probe, }; module_pci_driver(i5500_temp_driver); MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("Intel 5500/5520/X58 chipset thermal sensor driver"); MODULE_LICENSE("GPL"); |