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 304ca5f468SJonathan 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; 444ca5f468SJonathan Cameron int id; 451236441fSMark M. Hoffman 464ca5f468SJonathan Cameron id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); 474ca5f468SJonathan Cameron if (id < 0) 484ca5f468SJonathan 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 534ca5f468SJonathan Cameron if (IS_ERR(hwdev)) 544ca5f468SJonathan Cameron ida_simple_remove(&hwmon_ida, id); 551236441fSMark M. Hoffman 561beeffe4STony Jones return hwdev; 571236441fSMark M. Hoffman } 58*839a9eefSFrans Meulenbroeks EXPORT_SYMBOL_GPL(hwmon_device_register); 591236441fSMark M. Hoffman 601236441fSMark M. Hoffman /** 611236441fSMark M. Hoffman * hwmon_device_unregister - removes the previously registered class device 621236441fSMark M. Hoffman * 631beeffe4STony Jones * @dev: the class device to destroy 641236441fSMark M. Hoffman */ 651beeffe4STony Jones void hwmon_device_unregister(struct device *dev) 661236441fSMark M. Hoffman { 671236441fSMark M. Hoffman int id; 681236441fSMark M. Hoffman 69739cf3a2SKay Sievers if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) { 701beeffe4STony Jones device_unregister(dev); 714ca5f468SJonathan Cameron ida_simple_remove(&hwmon_ida, id); 721236441fSMark M. Hoffman } else 731beeffe4STony Jones dev_dbg(dev->parent, 741236441fSMark M. Hoffman "hwmon_device_unregister() failed: bad class ID!\n"); 751236441fSMark M. Hoffman } 76*839a9eefSFrans Meulenbroeks EXPORT_SYMBOL_GPL(hwmon_device_unregister); 771236441fSMark M. Hoffman 782958b1ecSJean Delvare static void __init hwmon_pci_quirks(void) 792958b1ecSJean Delvare { 802958b1ecSJean Delvare #if defined CONFIG_X86 && defined CONFIG_PCI 812958b1ecSJean Delvare struct pci_dev *sb; 822958b1ecSJean Delvare u16 base; 832958b1ecSJean Delvare u8 enable; 842958b1ecSJean Delvare 852958b1ecSJean Delvare /* Open access to 0x295-0x296 on MSI MS-7031 */ 862958b1ecSJean Delvare sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); 872958b1ecSJean Delvare if (sb && 882958b1ecSJean Delvare (sb->subsystem_vendor == 0x1462 && /* MSI */ 892958b1ecSJean Delvare sb->subsystem_device == 0x0031)) { /* MS-7031 */ 902958b1ecSJean Delvare 912958b1ecSJean Delvare pci_read_config_byte(sb, 0x48, &enable); 922958b1ecSJean Delvare pci_read_config_word(sb, 0x64, &base); 932958b1ecSJean Delvare 942958b1ecSJean Delvare if (base == 0 && !(enable & BIT(2))) { 952958b1ecSJean Delvare dev_info(&sb->dev, 962958b1ecSJean Delvare "Opening wide generic port at 0x295\n"); 972958b1ecSJean Delvare pci_write_config_word(sb, 0x64, 0x295); 982958b1ecSJean Delvare pci_write_config_byte(sb, 0x48, enable | BIT(2)); 992958b1ecSJean Delvare } 1002958b1ecSJean Delvare } 1012958b1ecSJean Delvare #endif 1022958b1ecSJean Delvare } 1032958b1ecSJean Delvare 1041236441fSMark M. Hoffman static int __init hwmon_init(void) 1051236441fSMark M. Hoffman { 1062958b1ecSJean Delvare hwmon_pci_quirks(); 1072958b1ecSJean Delvare 1081236441fSMark M. Hoffman hwmon_class = class_create(THIS_MODULE, "hwmon"); 1091236441fSMark M. Hoffman if (IS_ERR(hwmon_class)) { 110c95df1aeSJoe Perches pr_err("couldn't create sysfs class\n"); 1111236441fSMark M. Hoffman return PTR_ERR(hwmon_class); 1121236441fSMark M. Hoffman } 1131236441fSMark M. Hoffman return 0; 1141236441fSMark M. Hoffman } 1151236441fSMark M. Hoffman 1161236441fSMark M. Hoffman static void __exit hwmon_exit(void) 1171236441fSMark M. Hoffman { 1181236441fSMark M. Hoffman class_destroy(hwmon_class); 1191236441fSMark M. Hoffman } 1201236441fSMark M. Hoffman 12137f54ee5SDavid Brownell subsys_initcall(hwmon_init); 1221236441fSMark M. Hoffman module_exit(hwmon_exit); 1231236441fSMark M. Hoffman 1241236441fSMark M. Hoffman MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 1251236441fSMark M. Hoffman MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); 1261236441fSMark M. Hoffman MODULE_LICENSE("GPL"); 1271236441fSMark M. Hoffman 128