2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-01-24 16:16:21 +03:00
/*
* i5500_temp - Driver for Intel 5500 / 5520 / X58 chipset thermal sensor
*
* Copyright ( C ) 2012 , 2014 Jean Delvare < jdelvare @ suse . de >
*/
2021-08-23 20:07:24 +03:00
# include <linux/bitops.h>
2015-01-24 16:16:21 +03:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
2015-01-24 16:16:21 +03:00
# include <linux/device.h>
2015-01-24 16:16:21 +03:00
# 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
2021-08-23 20:07:24 +03:00
static umode_t i5500_is_visible ( const void * drvdata , enum hwmon_sensor_types type , u32 attr ,
int channel )
2015-01-24 16:16:21 +03:00
{
2021-08-23 20:07:24 +03:00
return 0444 ;
2015-01-24 16:16:21 +03:00
}
2021-08-23 20:07:24 +03:00
static int i5500_read ( struct device * dev , enum hwmon_sensor_types type , u32 attr , int channel ,
long * val )
2015-01-24 16:16:21 +03:00
{
2015-01-24 16:16:21 +03:00
struct pci_dev * pdev = to_pci_dev ( dev - > parent ) ;
2015-01-24 16:16:21 +03:00
u16 tsthr ;
2021-08-23 20:07:24 +03:00
s8 tsfsc ;
u8 ctsts ;
2015-01-24 16:16:21 +03:00
2021-08-23 20:07:24 +03:00
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 ;
}
2015-01-24 16:16:21 +03:00
2021-08-23 20:07:24 +03:00
return - EOPNOTSUPP ;
2015-01-24 16:16:21 +03:00
}
2021-08-23 20:07:24 +03:00
static const struct hwmon_ops i5500_ops = {
. is_visible = i5500_is_visible ,
. read = i5500_read ,
} ;
2015-01-24 16:16:21 +03:00
2023-04-06 23:30:13 +03:00
static const struct hwmon_channel_info * const i5500_info [ ] = {
2021-08-23 20:07:24 +03:00
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
) ,
2015-01-24 16:16:21 +03:00
NULL
} ;
2021-08-23 20:07:24 +03:00
static const struct hwmon_chip_info i5500_chip_info = {
. ops = & i5500_ops ,
. info = i5500_info ,
} ;
2015-01-24 16:16:21 +03:00
2015-01-24 16:16:21 +03:00
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 ;
2015-01-24 16:16:21 +03:00
struct device * hwmon_dev ;
2015-01-24 16:16:21 +03:00
u32 tstimer ;
s8 tsfsc ;
2015-01-24 16:16:21 +03:00
2022-11-12 15:56:06 +03:00
err = pcim_enable_device ( pdev ) ;
2015-01-24 16:16:21 +03:00
if ( err ) {
dev_err ( & pdev - > dev , " Failed to enable device \n " ) ;
2015-01-24 16:16:21 +03:00
return err ;
2015-01-24 16:16:21 +03:00
}
2015-01-24 16:16:21 +03:00
pci_read_config_byte ( pdev , REG_TSFSC , & tsfsc ) ;
pci_read_config_dword ( pdev , REG_TSTIMER , & tstimer ) ;
if ( tsfsc = = 0x7F & & tstimer = = 0x07D30D40 ) {
2015-01-24 16:16:22 +03:00
dev_notice ( & pdev - > dev , " Sensor seems to be disabled \n " ) ;
2015-01-24 16:16:21 +03:00
return - ENODEV ;
}
2021-08-23 20:07:24 +03:00
hwmon_dev = devm_hwmon_device_register_with_info ( & pdev - > dev , " intel5500 " , NULL ,
& i5500_chip_info , NULL ) ;
2015-01-24 16:16:21 +03:00
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
2015-01-24 16:16:21 +03:00
}
static struct pci_driver i5500_temp_driver = {
. name = " i5500_temp " ,
. id_table = i5500_temp_ids ,
. probe = i5500_temp_probe ,
} ;
2015-01-24 16:16:22 +03:00
module_pci_driver ( i5500_temp_driver ) ;
2015-01-24 16:16:21 +03:00
MODULE_AUTHOR ( " Jean Delvare <jdelvare@suse.de> " ) ;
MODULE_DESCRIPTION ( " Intel 5500/5520/X58 chipset thermal sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;