2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-03-21 19:59:36 +03:00
/***************************************************************************
2012-03-18 16:05:08 +04:00
* Copyright ( C ) 2010 - 2012 Hans de Goede < hdegoede @ redhat . com > *
2011-03-21 19:59:36 +03:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/platform_device.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/err.h>
# include <linux/mutex.h>
2011-07-25 23:46:09 +04:00
# include "sch56xx-common.h"
2011-03-21 19:59:36 +03:00
# define DRVNAME "sch5627"
# define DEVNAME DRVNAME /* We only support one model */
# define SCH5627_HWMON_ID 0xa5
# define SCH5627_COMPANY_ID 0x5c
# define SCH5627_PRIMARY_ID 0xa0
# define SCH5627_REG_BUILD_CODE 0x39
# define SCH5627_REG_BUILD_ID 0x3a
# define SCH5627_REG_HWMON_ID 0x3c
# define SCH5627_REG_HWMON_REV 0x3d
# define SCH5627_REG_COMPANY_ID 0x3e
# define SCH5627_REG_PRIMARY_ID 0x3f
# define SCH5627_REG_CTRL 0x40
# define SCH5627_NO_TEMPS 8
# define SCH5627_NO_FANS 4
# define SCH5627_NO_IN 5
static const u16 SCH5627_REG_TEMP_MSB [ SCH5627_NO_TEMPS ] = {
0x2B , 0x26 , 0x27 , 0x28 , 0x29 , 0x2A , 0x180 , 0x181 } ;
static const u16 SCH5627_REG_TEMP_LSN [ SCH5627_NO_TEMPS ] = {
0xE2 , 0xE1 , 0xE1 , 0xE5 , 0xE5 , 0xE6 , 0x182 , 0x182 } ;
static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE [ SCH5627_NO_TEMPS ] = {
0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 } ;
static const u16 SCH5627_REG_TEMP_HIGH [ SCH5627_NO_TEMPS ] = {
0x61 , 0x57 , 0x59 , 0x5B , 0x5D , 0x5F , 0x184 , 0x186 } ;
static const u16 SCH5627_REG_TEMP_ABS [ SCH5627_NO_TEMPS ] = {
0x9B , 0x96 , 0x97 , 0x98 , 0x99 , 0x9A , 0x1A8 , 0x1A9 } ;
static const u16 SCH5627_REG_FAN [ SCH5627_NO_FANS ] = {
0x2C , 0x2E , 0x30 , 0x32 } ;
static const u16 SCH5627_REG_FAN_MIN [ SCH5627_NO_FANS ] = {
0x62 , 0x64 , 0x66 , 0x68 } ;
static const u16 SCH5627_REG_IN_MSB [ SCH5627_NO_IN ] = {
0x22 , 0x23 , 0x24 , 0x25 , 0x189 } ;
static const u16 SCH5627_REG_IN_LSN [ SCH5627_NO_IN ] = {
0xE4 , 0xE4 , 0xE3 , 0xE3 , 0x18A } ;
static const u16 SCH5627_REG_IN_HIGH_NIBBLE [ SCH5627_NO_IN ] = {
1 , 0 , 1 , 0 , 1 } ;
static const u16 SCH5627_REG_IN_FACTOR [ SCH5627_NO_IN ] = {
10745 , 3660 , 9765 , 10745 , 3660 } ;
static const char * const SCH5627_IN_LABELS [ SCH5627_NO_IN ] = {
" VCC " , " VTT " , " VBAT " , " VTR " , " V_IN " } ;
struct sch5627_data {
unsigned short addr ;
struct device * hwmon_dev ;
2012-03-18 16:05:08 +04:00
struct sch56xx_watchdog_data * watchdog ;
2011-05-25 22:43:33 +04:00
u8 control ;
2011-03-21 19:59:36 +03:00
u8 temp_max [ SCH5627_NO_TEMPS ] ;
u8 temp_crit [ SCH5627_NO_TEMPS ] ;
u16 fan_min [ SCH5627_NO_FANS ] ;
struct mutex update_lock ;
2011-05-25 22:43:33 +04:00
unsigned long last_battery ; /* In jiffies */
2011-03-21 19:59:36 +03:00
char valid ; /* !=0 if following fields are valid */
unsigned long last_updated ; /* In jiffies */
u16 temp [ SCH5627_NO_TEMPS ] ;
u16 fan [ SCH5627_NO_FANS ] ;
u16 in [ SCH5627_NO_IN ] ;
} ;
static struct sch5627_data * sch5627_update_device ( struct device * dev )
{
struct sch5627_data * data = dev_get_drvdata ( dev ) ;
struct sch5627_data * ret = data ;
int i , val ;
mutex_lock ( & data - > update_lock ) ;
2011-05-25 22:43:33 +04:00
/* Trigger a Vbat voltage measurement every 5 minutes */
if ( time_after ( jiffies , data - > last_battery + 300 * HZ ) ) {
2011-07-25 23:46:09 +04:00
sch56xx_write_virtual_reg ( data - > addr , SCH5627_REG_CTRL ,
2011-05-25 22:43:33 +04:00
data - > control | 0x10 ) ;
data - > last_battery = jiffies ;
}
2011-03-21 19:59:36 +03:00
/* Cache the values for 1 second */
if ( time_after ( jiffies , data - > last_updated + HZ ) | | ! data - > valid ) {
for ( i = 0 ; i < SCH5627_NO_TEMPS ; i + + ) {
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg12 ( data - > addr ,
2011-03-21 19:59:36 +03:00
SCH5627_REG_TEMP_MSB [ i ] ,
SCH5627_REG_TEMP_LSN [ i ] ,
SCH5627_REG_TEMP_HIGH_NIBBLE [ i ] ) ;
if ( unlikely ( val < 0 ) ) {
ret = ERR_PTR ( val ) ;
goto abort ;
}
data - > temp [ i ] = val ;
}
for ( i = 0 ; i < SCH5627_NO_FANS ; i + + ) {
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg16 ( data - > addr ,
2011-03-21 19:59:36 +03:00
SCH5627_REG_FAN [ i ] ) ;
if ( unlikely ( val < 0 ) ) {
ret = ERR_PTR ( val ) ;
goto abort ;
}
data - > fan [ i ] = val ;
}
for ( i = 0 ; i < SCH5627_NO_IN ; i + + ) {
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg12 ( data - > addr ,
2011-03-21 19:59:36 +03:00
SCH5627_REG_IN_MSB [ i ] ,
SCH5627_REG_IN_LSN [ i ] ,
SCH5627_REG_IN_HIGH_NIBBLE [ i ] ) ;
if ( unlikely ( val < 0 ) ) {
ret = ERR_PTR ( val ) ;
goto abort ;
}
data - > in [ i ] = val ;
}
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
abort :
mutex_unlock ( & data - > update_lock ) ;
return ret ;
}
2012-11-19 22:22:35 +04:00
static int sch5627_read_limits ( struct sch5627_data * data )
2011-03-21 19:59:36 +03:00
{
int i , val ;
for ( i = 0 ; i < SCH5627_NO_TEMPS ; i + + ) {
/*
* Note what SMSC calls ABS , is what lm_sensors calls max
* ( aka high ) , and HIGH is what lm_sensors calls crit .
*/
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr ,
SCH5627_REG_TEMP_ABS [ i ] ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 )
return val ;
data - > temp_max [ i ] = val ;
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr ,
SCH5627_REG_TEMP_HIGH [ i ] ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 )
return val ;
data - > temp_crit [ i ] = val ;
}
for ( i = 0 ; i < SCH5627_NO_FANS ; i + + ) {
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg16 ( data - > addr ,
SCH5627_REG_FAN_MIN [ i ] ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 )
return val ;
data - > fan_min [ i ] = val ;
}
return 0 ;
}
static int reg_to_temp ( u16 reg )
{
return ( reg * 625 ) / 10 - 64000 ;
}
static int reg_to_temp_limit ( u8 reg )
{
return ( reg - 64 ) * 1000 ;
}
static int reg_to_rpm ( u16 reg )
{
if ( reg = = 0 )
return - EIO ;
if ( reg = = 0xffff )
return 0 ;
return 5400540 / reg ;
}
2016-12-22 15:05:26 +03:00
static ssize_t name_show ( struct device * dev , struct device_attribute * devattr ,
2011-03-21 19:59:36 +03:00
char * buf )
{
return snprintf ( buf , PAGE_SIZE , " %s \n " , DEVNAME ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t temp_show ( struct device * dev , struct device_attribute * devattr ,
char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = sch5627_update_device ( dev ) ;
int val ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
val = reg_to_temp ( data - > temp [ attr - > index ] ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t temp_fault_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = sch5627_update_device ( dev ) ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , data - > temp [ attr - > index ] = = 0 ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t temp_max_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = dev_get_drvdata ( dev ) ;
int val ;
val = reg_to_temp_limit ( data - > temp_max [ attr - > index ] ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t temp_crit_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = dev_get_drvdata ( dev ) ;
int val ;
val = reg_to_temp_limit ( data - > temp_crit [ attr - > index ] ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t fan_show ( struct device * dev , struct device_attribute * devattr ,
char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = sch5627_update_device ( dev ) ;
int val ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
val = reg_to_rpm ( data - > fan [ attr - > index ] ) ;
if ( val < 0 )
return val ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t fan_fault_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = sch5627_update_device ( dev ) ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " ,
data - > fan [ attr - > index ] = = 0xffff ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t fan_min_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = dev_get_drvdata ( dev ) ;
int val = reg_to_rpm ( data - > fan_min [ attr - > index ] ) ;
if ( val < 0 )
return val ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t in_show ( struct device * dev , struct device_attribute * devattr ,
char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
struct sch5627_data * data = sch5627_update_device ( dev ) ;
int val ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
val = DIV_ROUND_CLOSEST (
data - > in [ attr - > index ] * SCH5627_REG_IN_FACTOR [ attr - > index ] ,
10000 ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
}
2018-12-11 01:02:19 +03:00
static ssize_t in_label_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2011-03-21 19:59:36 +03:00
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
SCH5627_IN_LABELS [ attr - > index ] ) ;
}
2016-12-22 15:05:26 +03:00
static DEVICE_ATTR_RO ( name ) ;
2018-12-11 01:02:19 +03:00
static SENSOR_DEVICE_ATTR_RO ( temp1_input , temp , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_input , temp , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp3_input , temp , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp4_input , temp , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp5_input , temp , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp6_input , temp , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp7_input , temp , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp8_input , temp , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_fault , temp_fault , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_fault , temp_fault , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp3_fault , temp_fault , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp4_fault , temp_fault , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp5_fault , temp_fault , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp6_fault , temp_fault , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp7_fault , temp_fault , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp8_fault , temp_fault , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_max , temp_max , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_max , temp_max , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp3_max , temp_max , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp4_max , temp_max , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp5_max , temp_max , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp6_max , temp_max , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp7_max , temp_max , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp8_max , temp_max , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_crit , temp_crit , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_crit , temp_crit , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp3_crit , temp_crit , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp4_crit , temp_crit , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp5_crit , temp_crit , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp6_crit , temp_crit , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp7_crit , temp_crit , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp8_crit , temp_crit , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan1_input , fan , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan2_input , fan , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan3_input , fan , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan4_input , fan , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan1_fault , fan_fault , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan2_fault , fan_fault , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan3_fault , fan_fault , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan4_fault , fan_fault , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan1_min , fan_min , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan2_min , fan_min , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan3_min , fan_min , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( fan4_min , fan_min , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in0_input , in , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_input , in , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_input , in , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_input , in , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in4_input , in , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( in0_label , in_label , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_label , in_label , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_label , in_label , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_label , in_label , 3 ) ;
2011-03-21 19:59:36 +03:00
static struct attribute * sch5627_attributes [ ] = {
& dev_attr_name . attr ,
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp2_input . dev_attr . attr ,
& sensor_dev_attr_temp3_input . dev_attr . attr ,
& sensor_dev_attr_temp4_input . dev_attr . attr ,
& sensor_dev_attr_temp5_input . dev_attr . attr ,
& sensor_dev_attr_temp6_input . dev_attr . attr ,
& sensor_dev_attr_temp7_input . dev_attr . attr ,
& sensor_dev_attr_temp8_input . dev_attr . attr ,
& sensor_dev_attr_temp1_fault . dev_attr . attr ,
& sensor_dev_attr_temp2_fault . dev_attr . attr ,
& sensor_dev_attr_temp3_fault . dev_attr . attr ,
& sensor_dev_attr_temp4_fault . dev_attr . attr ,
& sensor_dev_attr_temp5_fault . dev_attr . attr ,
& sensor_dev_attr_temp6_fault . dev_attr . attr ,
& sensor_dev_attr_temp7_fault . dev_attr . attr ,
& sensor_dev_attr_temp8_fault . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
& sensor_dev_attr_temp3_max . dev_attr . attr ,
& sensor_dev_attr_temp4_max . dev_attr . attr ,
& sensor_dev_attr_temp5_max . dev_attr . attr ,
& sensor_dev_attr_temp6_max . dev_attr . attr ,
& sensor_dev_attr_temp7_max . dev_attr . attr ,
& sensor_dev_attr_temp8_max . dev_attr . attr ,
& sensor_dev_attr_temp1_crit . dev_attr . attr ,
& sensor_dev_attr_temp2_crit . dev_attr . attr ,
& sensor_dev_attr_temp3_crit . dev_attr . attr ,
& sensor_dev_attr_temp4_crit . dev_attr . attr ,
& sensor_dev_attr_temp5_crit . dev_attr . attr ,
& sensor_dev_attr_temp6_crit . dev_attr . attr ,
& sensor_dev_attr_temp7_crit . dev_attr . attr ,
& sensor_dev_attr_temp8_crit . dev_attr . attr ,
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan3_input . dev_attr . attr ,
& sensor_dev_attr_fan4_input . dev_attr . attr ,
& sensor_dev_attr_fan1_fault . dev_attr . attr ,
& sensor_dev_attr_fan2_fault . dev_attr . attr ,
& sensor_dev_attr_fan3_fault . dev_attr . attr ,
& sensor_dev_attr_fan4_fault . dev_attr . attr ,
& sensor_dev_attr_fan1_min . dev_attr . attr ,
& sensor_dev_attr_fan2_min . dev_attr . attr ,
& sensor_dev_attr_fan3_min . dev_attr . attr ,
& sensor_dev_attr_fan4_min . dev_attr . attr ,
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in0_label . dev_attr . attr ,
& sensor_dev_attr_in1_label . dev_attr . attr ,
& sensor_dev_attr_in2_label . dev_attr . attr ,
& sensor_dev_attr_in3_label . dev_attr . attr ,
/* No in4_label as in4 is a generic input pin */
NULL
} ;
static const struct attribute_group sch5627_group = {
. attrs = sch5627_attributes ,
} ;
static int sch5627_remove ( struct platform_device * pdev )
{
struct sch5627_data * data = platform_get_drvdata ( pdev ) ;
2012-03-18 16:05:08 +04:00
if ( data - > watchdog )
sch56xx_watchdog_unregister ( data - > watchdog ) ;
2011-03-21 19:59:36 +03:00
if ( data - > hwmon_dev )
hwmon_device_unregister ( data - > hwmon_dev ) ;
sysfs_remove_group ( & pdev - > dev . kobj , & sch5627_group ) ;
return 0 ;
}
2012-11-19 22:22:35 +04:00
static int sch5627_probe ( struct platform_device * pdev )
2011-03-21 19:59:36 +03:00
{
struct sch5627_data * data ;
int err , build_code , build_id , hwmon_rev , val ;
2012-06-02 22:20:21 +04:00
data = devm_kzalloc ( & pdev - > dev , sizeof ( struct sch5627_data ) ,
GFP_KERNEL ) ;
2011-03-21 19:59:36 +03:00
if ( ! data )
return - ENOMEM ;
data - > addr = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) - > start ;
mutex_init ( & data - > update_lock ) ;
platform_set_drvdata ( pdev , data ) ;
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr , SCH5627_REG_HWMON_ID ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 ) {
err = val ;
goto error ;
}
if ( val ! = SCH5627_HWMON_ID ) {
pr_err ( " invalid %s id: 0x%02X (expected 0x%02X) \n " , " hwmon " ,
val , SCH5627_HWMON_ID ) ;
err = - ENODEV ;
goto error ;
}
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr , SCH5627_REG_COMPANY_ID ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 ) {
err = val ;
goto error ;
}
if ( val ! = SCH5627_COMPANY_ID ) {
pr_err ( " invalid %s id: 0x%02X (expected 0x%02X) \n " , " company " ,
val , SCH5627_COMPANY_ID ) ;
err = - ENODEV ;
goto error ;
}
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr , SCH5627_REG_PRIMARY_ID ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 ) {
err = val ;
goto error ;
}
if ( val ! = SCH5627_PRIMARY_ID ) {
pr_err ( " invalid %s id: 0x%02X (expected 0x%02X) \n " , " primary " ,
val , SCH5627_PRIMARY_ID ) ;
err = - ENODEV ;
goto error ;
}
2011-07-25 23:46:09 +04:00
build_code = sch56xx_read_virtual_reg ( data - > addr ,
SCH5627_REG_BUILD_CODE ) ;
2011-03-21 19:59:36 +03:00
if ( build_code < 0 ) {
err = build_code ;
goto error ;
}
2011-07-25 23:46:09 +04:00
build_id = sch56xx_read_virtual_reg16 ( data - > addr ,
SCH5627_REG_BUILD_ID ) ;
2011-03-21 19:59:36 +03:00
if ( build_id < 0 ) {
err = build_id ;
goto error ;
}
2011-07-25 23:46:09 +04:00
hwmon_rev = sch56xx_read_virtual_reg ( data - > addr ,
SCH5627_REG_HWMON_REV ) ;
2011-03-21 19:59:36 +03:00
if ( hwmon_rev < 0 ) {
err = hwmon_rev ;
goto error ;
}
2011-07-25 23:46:09 +04:00
val = sch56xx_read_virtual_reg ( data - > addr , SCH5627_REG_CTRL ) ;
2011-03-21 19:59:36 +03:00
if ( val < 0 ) {
err = val ;
goto error ;
}
2011-05-25 22:43:33 +04:00
data - > control = val ;
if ( ! ( data - > control & 0x01 ) ) {
2011-03-21 19:59:36 +03:00
pr_err ( " hardware monitoring not enabled \n " ) ;
err = - ENODEV ;
goto error ;
}
2011-05-25 22:43:33 +04:00
/* Trigger a Vbat voltage measurement, so that we get a valid reading
the first time we read Vbat */
2011-07-25 23:46:09 +04:00
sch56xx_write_virtual_reg ( data - > addr , SCH5627_REG_CTRL ,
2011-05-25 22:43:33 +04:00
data - > control | 0x10 ) ;
data - > last_battery = jiffies ;
2011-03-21 19:59:36 +03:00
/*
* Read limits , we do this only once as reading a register on
* the sch5627 is quite expensive ( and they don ' t change ) .
*/
err = sch5627_read_limits ( data ) ;
if ( err )
goto error ;
2011-07-25 23:46:09 +04:00
pr_info ( " found %s chip at %#hx \n " , DEVNAME , data - > addr ) ;
2011-03-21 19:59:36 +03:00
pr_info ( " firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X \n " ,
build_code , build_id , hwmon_rev ) ;
/* Register sysfs interface files */
err = sysfs_create_group ( & pdev - > dev . kobj , & sch5627_group ) ;
if ( err )
goto error ;
data - > hwmon_dev = hwmon_device_register ( & pdev - > dev ) ;
if ( IS_ERR ( data - > hwmon_dev ) ) {
err = PTR_ERR ( data - > hwmon_dev ) ;
data - > hwmon_dev = NULL ;
goto error ;
}
2012-03-18 16:05:08 +04:00
/* Note failing to register the watchdog is not a fatal error */
2012-05-22 13:40:24 +04:00
data - > watchdog = sch56xx_watchdog_register ( & pdev - > dev , data - > addr ,
2012-03-18 16:05:08 +04:00
( build_code < < 24 ) | ( build_id < < 8 ) | hwmon_rev ,
& data - > update_lock , 1 ) ;
2011-03-21 19:59:36 +03:00
return 0 ;
error :
sch5627_remove ( pdev ) ;
return err ;
}
static struct platform_driver sch5627_driver = {
. driver = {
. name = DRVNAME ,
} ,
. probe = sch5627_probe ,
. remove = sch5627_remove ,
} ;
2011-11-25 11:31:00 +04:00
module_platform_driver ( sch5627_driver ) ;
2011-03-21 19:59:36 +03:00
MODULE_DESCRIPTION ( " SMSC SCH5627 Hardware Monitoring Driver " ) ;
2011-07-03 15:32:53 +04:00
MODULE_AUTHOR ( " Hans de Goede <hdegoede@redhat.com> " ) ;
2011-03-21 19:59:36 +03:00
MODULE_LICENSE ( " GPL " ) ;