11236441fSMark M. Hoffman /* 21236441fSMark M. Hoffman hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring 31236441fSMark M. Hoffman 41236441fSMark M. Hoffman This file defines the sysfs class "hwmon", for use by sensors drivers. 51236441fSMark M. Hoffman 61236441fSMark M. Hoffman Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> 71236441fSMark M. Hoffman 81236441fSMark M. Hoffman This program is free software; you can redistribute it and/or modify 91236441fSMark M. Hoffman it under the terms of the GNU General Public License as published by 101236441fSMark M. Hoffman the Free Software Foundation; version 2 of the License. 111236441fSMark M. Hoffman */ 121236441fSMark M. Hoffman 13c95df1aeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14c95df1aeSJoe Perches 151236441fSMark M. Hoffman #include <linux/module.h> 161236441fSMark M. Hoffman #include <linux/device.h> 171236441fSMark M. Hoffman #include <linux/err.h> 181236441fSMark M. Hoffman #include <linux/kdev_t.h> 191236441fSMark M. Hoffman #include <linux/idr.h> 201236441fSMark M. Hoffman #include <linux/hwmon.h> 218c65b4a6STim Schmielau #include <linux/gfp.h> 22ded2b666SMark M. Hoffman #include <linux/spinlock.h> 232958b1ecSJean Delvare #include <linux/pci.h> 241236441fSMark M. Hoffman 251236441fSMark M. Hoffman #define HWMON_ID_PREFIX "hwmon" 261236441fSMark M. Hoffman #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 271236441fSMark M. Hoffman 281236441fSMark M. Hoffman static struct class *hwmon_class; 291236441fSMark M. Hoffman 30*4ca5f468SJonathan Cameron static DEFINE_IDA(hwmon_ida); 311236441fSMark M. Hoffman 321236441fSMark M. Hoffman /** 331beeffe4STony Jones * hwmon_device_register - register w/ hwmon 341236441fSMark M. Hoffman * @dev: the device to register 351236441fSMark M. Hoffman * 361beeffe4STony Jones * hwmon_device_unregister() must be called when the device is no 371236441fSMark M. Hoffman * longer needed. 381236441fSMark M. Hoffman * 391beeffe4STony Jones * Returns the pointer to the new device. 401236441fSMark M. Hoffman */ 411beeffe4STony Jones struct device *hwmon_device_register(struct device *dev) 421236441fSMark M. Hoffman { 431beeffe4STony Jones struct device *hwdev; 44*4ca5f468SJonathan Cameron int id; 451236441fSMark M. Hoffman 46*4ca5f468SJonathan Cameron id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); 47*4ca5f468SJonathan Cameron if (id < 0) 48*4ca5f468SJonathan Cameron return ERR_PTR(id); 491236441fSMark M. Hoffman 50a9b12619SGreg Kroah-Hartman hwdev = device_create(hwmon_class, dev, MKDEV(0, 0), NULL, 512871f552SGreg Kroah-Hartman HWMON_ID_FORMAT, id); 521236441fSMark M. Hoffman 53*4ca5f468SJonathan Cameron if (IS_ERR(hwdev)) 54*4ca5f468SJonathan Cameron ida_simple_remove(&hwmon_ida, id); 551236441fSMark M. Hoffman 561beeffe4STony Jones return hwdev; 571236441fSMark M. Hoffman } 581236441fSMark M. Hoffman 591236441fSMark M. Hoffman /** 601236441fSMark M. Hoffman * hwmon_device_unregister - removes the previously registered class device 611236441fSMark M. Hoffman * 621beeffe4STony Jones * @dev: the class device to destroy 631236441fSMark M. Hoffman */ 641beeffe4STony Jones void hwmon_device_unregister(struct device *dev) 651236441fSMark M. Hoffman { 661236441fSMark M. Hoffman int id; 671236441fSMark M. Hoffman 68739cf3a2SKay Sievers if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) { 691beeffe4STony Jones device_unregister(dev); 70*4ca5f468SJonathan Cameron ida_simple_remove(&hwmon_ida, id); 711236441fSMark M. Hoffman } else 721beeffe4STony Jones dev_dbg(dev->parent, 731236441fSMark M. Hoffman "hwmon_device_unregister() failed: bad class ID!\n"); 741236441fSMark M. Hoffman } 751236441fSMark M. Hoffman 762958b1ecSJean Delvare static void __init hwmon_pci_quirks(void) 772958b1ecSJean Delvare { 782958b1ecSJean Delvare #if defined CONFIG_X86 && defined CONFIG_PCI 792958b1ecSJean Delvare struct pci_dev *sb; 802958b1ecSJean Delvare u16 base; 812958b1ecSJean Delvare u8 enable; 822958b1ecSJean Delvare 832958b1ecSJean Delvare /* Open access to 0x295-0x296 on MSI MS-7031 */ 842958b1ecSJean Delvare sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); 852958b1ecSJean Delvare if (sb && 862958b1ecSJean Delvare (sb->subsystem_vendor == 0x1462 && /* MSI */ 872958b1ecSJean Delvare sb->subsystem_device == 0x0031)) { /* MS-7031 */ 882958b1ecSJean Delvare 892958b1ecSJean Delvare pci_read_config_byte(sb, 0x48, &enable); 902958b1ecSJean Delvare pci_read_config_word(sb, 0x64, &base); 912958b1ecSJean Delvare 922958b1ecSJean Delvare if (base == 0 && !(enable & BIT(2))) { 932958b1ecSJean Delvare dev_info(&sb->dev, 942958b1ecSJean Delvare "Opening wide generic port at 0x295\n"); 952958b1ecSJean Delvare pci_write_config_word(sb, 0x64, 0x295); 962958b1ecSJean Delvare pci_write_config_byte(sb, 0x48, enable | BIT(2)); 972958b1ecSJean Delvare } 982958b1ecSJean Delvare } 992958b1ecSJean Delvare #endif 1002958b1ecSJean Delvare } 1012958b1ecSJean Delvare 1021236441fSMark M. Hoffman static int __init hwmon_init(void) 1031236441fSMark M. Hoffman { 1042958b1ecSJean Delvare hwmon_pci_quirks(); 1052958b1ecSJean Delvare 1061236441fSMark M. Hoffman hwmon_class = class_create(THIS_MODULE, "hwmon"); 1071236441fSMark M. Hoffman if (IS_ERR(hwmon_class)) { 108c95df1aeSJoe Perches pr_err("couldn't create sysfs class\n"); 1091236441fSMark M. Hoffman return PTR_ERR(hwmon_class); 1101236441fSMark M. Hoffman } 1111236441fSMark M. Hoffman return 0; 1121236441fSMark M. Hoffman } 1131236441fSMark M. Hoffman 1141236441fSMark M. Hoffman static void __exit hwmon_exit(void) 1151236441fSMark M. Hoffman { 1161236441fSMark M. Hoffman class_destroy(hwmon_class); 1171236441fSMark M. Hoffman } 1181236441fSMark M. Hoffman 11937f54ee5SDavid Brownell subsys_initcall(hwmon_init); 1201236441fSMark M. Hoffman module_exit(hwmon_exit); 1211236441fSMark M. Hoffman 1221236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_register); 1231236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_unregister); 1241236441fSMark M. Hoffman 1251236441fSMark M. Hoffman MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 1261236441fSMark M. Hoffman MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); 1271236441fSMark M. Hoffman MODULE_LICENSE("GPL"); 1281236441fSMark M. Hoffman 129