2006-01-10 01:26:14 +03:00
/*
* f71805f . c - driver for the Fintek F71805F / FG Super - I / O chip integrated
* hardware monitoring features
2006-09-24 22:52:15 +04:00
* Copyright ( C ) 2005 - 2006 Jean Delvare < khali @ linux - fr . org >
2006-01-10 01:26:14 +03:00
*
* The F71805F / FG is a LPC Super - I / O chip made by Fintek . It integrates
* complete hardware monitoring features : voltage , fan and temperature
* sensors , and manual and automatic fan speed control .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# 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>
2006-01-19 01:20:53 +03:00
# include <linux/mutex.h>
2006-09-24 23:16:40 +04:00
# include <linux/sysfs.h>
2006-01-10 01:26:14 +03:00
# include <asm/io.h>
static struct platform_device * pdev ;
# define DRVNAME "f71805f"
/*
* Super - I / O constants and functions
*/
# define F71805F_LD_HWM 0x04
# define SIO_REG_LDSEL 0x07 /* Logical device select */
# define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
# define SIO_REG_DEVREV 0x22 /* Device revision */
# define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
# define SIO_REG_ENABLE 0x30 /* Logical device enable */
# define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
# define SIO_FINTEK_ID 0x1934
# define SIO_F71805F_ID 0x0406
static inline int
superio_inb ( int base , int reg )
{
outb ( reg , base ) ;
return inb ( base + 1 ) ;
}
static int
superio_inw ( int base , int reg )
{
int val ;
outb ( reg + + , base ) ;
val = inb ( base + 1 ) < < 8 ;
outb ( reg , base ) ;
val | = inb ( base + 1 ) ;
return val ;
}
static inline void
superio_select ( int base , int ld )
{
outb ( SIO_REG_LDSEL , base ) ;
outb ( ld , base + 1 ) ;
}
static inline void
superio_enter ( int base )
{
outb ( 0x87 , base ) ;
outb ( 0x87 , base ) ;
}
static inline void
superio_exit ( int base )
{
outb ( 0xaa , base ) ;
}
/*
* ISA constants
*/
# define REGION_LENGTH 2
# define ADDR_REG_OFFSET 0
# define DATA_REG_OFFSET 1
/*
* Registers
*/
/* in nr from 0 to 8 (8-bit values) */
# define F71805F_REG_IN(nr) (0x10 + (nr))
# define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr))
# define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr))
/* fan nr from 0 to 2 (12-bit values, two registers) */
# define F71805F_REG_FAN(nr) (0x20 + 2 * (nr))
# define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr))
2006-12-12 20:18:27 +03:00
# define F71805F_REG_FAN_TARGET(nr) (0x69 + 16 * (nr))
2006-01-10 01:26:14 +03:00
# define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr))
2006-12-12 20:18:27 +03:00
# define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr))
2006-12-12 20:18:26 +03:00
# define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr))
2006-01-10 01:26:14 +03:00
/* temp nr from 0 to 2 (8-bit values) */
# define F71805F_REG_TEMP(nr) (0x1B + (nr))
# define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr))
# define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr))
# define F71805F_REG_TEMP_MODE 0x01
# define F71805F_REG_START 0x00
/* status nr from 0 to 2 */
# define F71805F_REG_STATUS(nr) (0x36 + (nr))
2006-12-12 20:18:26 +03:00
/* individual register bits */
# define FAN_CTRL_SKIP 0x80
2006-12-12 20:18:27 +03:00
# define FAN_CTRL_DC_MODE 0x10
2006-12-12 20:18:27 +03:00
# define FAN_CTRL_LATCH_FULL 0x08
2006-12-12 20:18:26 +03:00
# define FAN_CTRL_MODE_MASK 0x03
# define FAN_CTRL_MODE_SPEED 0x00
# define FAN_CTRL_MODE_TEMPERATURE 0x01
# define FAN_CTRL_MODE_MANUAL 0x02
2006-12-12 20:18:26 +03:00
2006-01-10 01:26:14 +03:00
/*
* Data structures and manipulation thereof
*/
struct f71805f_data {
unsigned short addr ;
const char * name ;
2006-01-19 01:20:53 +03:00
struct mutex lock ;
2006-01-10 01:26:14 +03:00
struct class_device * class_dev ;
2006-01-19 01:20:53 +03:00
struct mutex update_lock ;
2006-01-10 01:26:14 +03:00
char valid ; /* !=0 if following fields are valid */
unsigned long last_updated ; /* In jiffies */
unsigned long last_limits ; /* In jiffies */
/* Register values */
u8 in [ 9 ] ;
u8 in_high [ 9 ] ;
u8 in_low [ 9 ] ;
u16 fan [ 3 ] ;
u16 fan_low [ 3 ] ;
2006-12-12 20:18:27 +03:00
u16 fan_target [ 3 ] ;
2006-12-12 20:18:26 +03:00
u8 fan_ctrl [ 3 ] ;
2006-12-12 20:18:26 +03:00
u8 pwm [ 3 ] ;
2006-12-12 20:18:27 +03:00
u8 pwm_freq [ 3 ] ;
2006-01-10 01:26:14 +03:00
u8 temp [ 3 ] ;
u8 temp_high [ 3 ] ;
u8 temp_hyst [ 3 ] ;
u8 temp_mode ;
2006-09-24 22:52:15 +04:00
unsigned long alarms ;
2006-01-10 01:26:14 +03:00
} ;
static inline long in_from_reg ( u8 reg )
{
return ( reg * 8 ) ;
}
/* The 2 least significant bits are not used */
static inline u8 in_to_reg ( long val )
{
if ( val < = 0 )
return 0 ;
if ( val > = 2016 )
return 0xfc ;
return ( ( ( val + 16 ) / 32 ) < < 2 ) ;
}
/* in0 is downscaled by a factor 2 internally */
static inline long in0_from_reg ( u8 reg )
{
return ( reg * 16 ) ;
}
static inline u8 in0_to_reg ( long val )
{
if ( val < = 0 )
return 0 ;
if ( val > = 4032 )
return 0xfc ;
return ( ( ( val + 32 ) / 64 ) < < 2 ) ;
}
/* The 4 most significant bits are not used */
static inline long fan_from_reg ( u16 reg )
{
reg & = 0xfff ;
if ( ! reg | | reg = = 0xfff )
return 0 ;
return ( 1500000 / reg ) ;
}
static inline u16 fan_to_reg ( long rpm )
{
/* If the low limit is set below what the chip can measure,
store the largest possible 12 - bit value in the registers ,
so that no alarm will ever trigger . */
if ( rpm < 367 )
return 0xfff ;
return ( 1500000 / rpm ) ;
}
2006-12-12 20:18:27 +03:00
static inline unsigned long pwm_freq_from_reg ( u8 reg )
{
unsigned long clock = ( reg & 0x80 ) ? 48000000UL : 1000000UL ;
reg & = 0x7f ;
if ( reg = = 0 )
reg + + ;
return clock / ( reg < < 8 ) ;
}
static inline u8 pwm_freq_to_reg ( unsigned long val )
{
if ( val > = 187500 ) /* The highest we can do */
return 0x80 ;
if ( val > = 1475 ) /* Use 48 MHz clock */
return 0x80 | ( 48000000UL / ( val < < 8 ) ) ;
if ( val < 31 ) /* The lowest we can do */
return 0x7f ;
else /* Use 1 MHz clock */
return 1000000UL / ( val < < 8 ) ;
}
2006-12-12 20:18:27 +03:00
static inline int pwm_mode_from_reg ( u8 reg )
{
return ! ( reg & FAN_CTRL_DC_MODE ) ;
}
2006-01-10 01:26:14 +03:00
static inline long temp_from_reg ( u8 reg )
{
return ( reg * 1000 ) ;
}
static inline u8 temp_to_reg ( long val )
{
if ( val < 0 )
val = 0 ;
else if ( val > 1000 * 0xff )
val = 0xff ;
return ( ( val + 500 ) / 1000 ) ;
}
/*
* Device I / O access
*/
static u8 f71805f_read8 ( struct f71805f_data * data , u8 reg )
{
u8 val ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
outb ( reg , data - > addr + ADDR_REG_OFFSET ) ;
val = inb ( data - > addr + DATA_REG_OFFSET ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
return val ;
}
static void f71805f_write8 ( struct f71805f_data * data , u8 reg , u8 val )
{
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
outb ( reg , data - > addr + ADDR_REG_OFFSET ) ;
outb ( val , data - > addr + DATA_REG_OFFSET ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
}
/* It is important to read the MSB first, because doing so latches the
value of the LSB , so we are sure both bytes belong to the same value . */
static u16 f71805f_read16 ( struct f71805f_data * data , u8 reg )
{
u16 val ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
outb ( reg , data - > addr + ADDR_REG_OFFSET ) ;
val = inb ( data - > addr + DATA_REG_OFFSET ) < < 8 ;
outb ( + + reg , data - > addr + ADDR_REG_OFFSET ) ;
val | = inb ( data - > addr + DATA_REG_OFFSET ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
return val ;
}
static void f71805f_write16 ( struct f71805f_data * data , u8 reg , u16 val )
{
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
outb ( reg , data - > addr + ADDR_REG_OFFSET ) ;
outb ( val > > 8 , data - > addr + DATA_REG_OFFSET ) ;
outb ( + + reg , data - > addr + ADDR_REG_OFFSET ) ;
outb ( val & 0xff , data - > addr + DATA_REG_OFFSET ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
}
static struct f71805f_data * f71805f_update_device ( struct device * dev )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
int nr ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
/* Limit registers cache is refreshed after 60 seconds */
if ( time_after ( jiffies , data - > last_updated + 60 * HZ )
| | ! data - > valid ) {
for ( nr = 0 ; nr < 9 ; nr + + ) {
data - > in_high [ nr ] = f71805f_read8 ( data ,
F71805F_REG_IN_HIGH ( nr ) ) ;
data - > in_low [ nr ] = f71805f_read8 ( data ,
F71805F_REG_IN_LOW ( nr ) ) ;
}
for ( nr = 0 ; nr < 3 ; nr + + ) {
2006-12-12 20:18:26 +03:00
if ( data - > fan_ctrl [ nr ] & FAN_CTRL_SKIP )
continue ;
data - > fan_low [ nr ] = f71805f_read16 ( data ,
F71805F_REG_FAN_LOW ( nr ) ) ;
2006-12-12 20:18:27 +03:00
data - > fan_target [ nr ] = f71805f_read16 ( data ,
F71805F_REG_FAN_TARGET ( nr ) ) ;
2006-12-12 20:18:27 +03:00
data - > pwm_freq [ nr ] = f71805f_read8 ( data ,
F71805F_REG_PWM_FREQ ( nr ) ) ;
2006-01-10 01:26:14 +03:00
}
for ( nr = 0 ; nr < 3 ; nr + + ) {
data - > temp_high [ nr ] = f71805f_read8 ( data ,
F71805F_REG_TEMP_HIGH ( nr ) ) ;
data - > temp_hyst [ nr ] = f71805f_read8 ( data ,
F71805F_REG_TEMP_HYST ( nr ) ) ;
}
data - > temp_mode = f71805f_read8 ( data , F71805F_REG_TEMP_MODE ) ;
data - > last_limits = jiffies ;
}
/* Measurement registers cache is refreshed after 1 second */
if ( time_after ( jiffies , data - > last_updated + HZ )
| | ! data - > valid ) {
for ( nr = 0 ; nr < 9 ; nr + + ) {
data - > in [ nr ] = f71805f_read8 ( data ,
F71805F_REG_IN ( nr ) ) ;
}
for ( nr = 0 ; nr < 3 ; nr + + ) {
2006-12-12 20:18:26 +03:00
if ( data - > fan_ctrl [ nr ] & FAN_CTRL_SKIP )
continue ;
data - > fan [ nr ] = f71805f_read16 ( data ,
F71805F_REG_FAN ( nr ) ) ;
2006-12-12 20:18:26 +03:00
data - > fan_ctrl [ nr ] = f71805f_read8 ( data ,
F71805F_REG_FAN_CTRL ( nr ) ) ;
data - > pwm [ nr ] = f71805f_read8 ( data ,
F71805F_REG_PWM_DUTY ( nr ) ) ;
2006-01-10 01:26:14 +03:00
}
for ( nr = 0 ; nr < 3 ; nr + + ) {
data - > temp [ nr ] = f71805f_read8 ( data ,
F71805F_REG_TEMP ( nr ) ) ;
}
2006-09-24 22:52:15 +04:00
data - > alarms = f71805f_read8 ( data , F71805F_REG_STATUS ( 0 ) )
+ ( f71805f_read8 ( data , F71805F_REG_STATUS ( 1 ) ) < < 8 )
+ ( f71805f_read8 ( data , F71805F_REG_STATUS ( 2 ) ) < < 16 ) ;
2006-01-10 01:26:14 +03:00
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return data ;
}
/*
* Sysfs interface
*/
static ssize_t show_in0 ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , in0_from_reg ( data - > in [ 0 ] ) ) ;
}
static ssize_t show_in0_max ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , in0_from_reg ( data - > in_high [ 0 ] ) ) ;
}
static ssize_t show_in0_min ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , in0_from_reg ( data - > in_low [ 0 ] ) ) ;
}
static ssize_t set_in0_max ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > in_high [ 0 ] = in0_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_IN_HIGH ( 0 ) , data - > in_high [ 0 ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t set_in0_min ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > in_low [ 0 ] = in0_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_IN_LOW ( 0 ) , data - > in_low [ 0 ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t show_in ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , in_from_reg ( data - > in [ nr ] ) ) ;
}
static ssize_t show_in_max ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , in_from_reg ( data - > in_high [ nr ] ) ) ;
}
static ssize_t show_in_min ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , in_from_reg ( data - > in_low [ nr ] ) ) ;
}
static ssize_t set_in_max ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > in_high [ nr ] = in_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_IN_HIGH ( nr ) , data - > in_high [ nr ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t set_in_min ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > in_low [ nr ] = in_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_IN_LOW ( nr ) , data - > in_low [ nr ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t show_fan ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , fan_from_reg ( data - > fan [ nr ] ) ) ;
}
static ssize_t show_fan_min ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , fan_from_reg ( data - > fan_low [ nr ] ) ) ;
}
2006-12-12 20:18:27 +03:00
static ssize_t show_fan_target ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , fan_from_reg ( data - > fan_target [ nr ] ) ) ;
}
2006-01-10 01:26:14 +03:00
static ssize_t set_fan_min ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > fan_low [ nr ] = fan_to_reg ( val ) ;
f71805f_write16 ( data , F71805F_REG_FAN_LOW ( nr ) , data - > fan_low [ nr ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
2006-12-12 20:18:27 +03:00
static ssize_t set_fan_target ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
mutex_lock ( & data - > update_lock ) ;
data - > fan_target [ nr ] = fan_to_reg ( val ) ;
f71805f_write16 ( data , F71805F_REG_FAN_TARGET ( nr ) ,
data - > fan_target [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2006-12-12 20:18:26 +03:00
static ssize_t show_pwm ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %d \n " , ( int ) data - > pwm [ nr ] ) ;
}
static ssize_t show_pwm_enable ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
int mode ;
switch ( data - > fan_ctrl [ nr ] & FAN_CTRL_MODE_MASK ) {
case FAN_CTRL_MODE_SPEED :
mode = 3 ;
break ;
case FAN_CTRL_MODE_TEMPERATURE :
mode = 2 ;
break ;
default : /* MANUAL */
mode = 1 ;
}
return sprintf ( buf , " %d \n " , mode ) ;
}
2006-12-12 20:18:27 +03:00
static ssize_t show_pwm_freq ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %lu \n " , pwm_freq_from_reg ( data - > pwm_freq [ nr ] ) ) ;
}
2006-12-12 20:18:27 +03:00
static ssize_t show_pwm_mode ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %d \n " , pwm_mode_from_reg ( data - > fan_ctrl [ nr ] ) ) ;
}
2006-12-12 20:18:26 +03:00
static ssize_t set_pwm ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
if ( val > 255 )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
data - > pwm [ nr ] = val ;
f71805f_write8 ( data , F71805F_REG_PWM_DUTY ( nr ) , data - > pwm [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
static struct attribute * f71805f_attr_pwm [ ] ;
static ssize_t set_pwm_enable ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
u8 reg ;
if ( val < 1 | | val > 3 )
return - EINVAL ;
if ( val > 1 ) { /* Automatic mode, user can't set PWM value */
if ( sysfs_chmod_file ( & dev - > kobj , f71805f_attr_pwm [ nr ] ,
S_IRUGO ) )
dev_dbg ( dev , " chmod -w pwm%d failed \n " , nr + 1 ) ;
}
mutex_lock ( & data - > update_lock ) ;
reg = f71805f_read8 ( data , F71805F_REG_FAN_CTRL ( nr ) )
& ~ FAN_CTRL_MODE_MASK ;
switch ( val ) {
case 1 :
reg | = FAN_CTRL_MODE_MANUAL ;
break ;
case 2 :
reg | = FAN_CTRL_MODE_TEMPERATURE ;
break ;
case 3 :
reg | = FAN_CTRL_MODE_SPEED ;
break ;
}
data - > fan_ctrl [ nr ] = reg ;
f71805f_write8 ( data , F71805F_REG_FAN_CTRL ( nr ) , reg ) ;
mutex_unlock ( & data - > update_lock ) ;
if ( val = = 1 ) { /* Manual mode, user can set PWM value */
if ( sysfs_chmod_file ( & dev - > kobj , f71805f_attr_pwm [ nr ] ,
S_IRUGO | S_IWUSR ) )
dev_dbg ( dev , " chmod +w pwm%d failed \n " , nr + 1 ) ;
}
return count ;
}
2006-12-12 20:18:27 +03:00
static ssize_t set_pwm_freq ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
mutex_lock ( & data - > update_lock ) ;
data - > pwm_freq [ nr ] = pwm_freq_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_PWM_FREQ ( nr ) , data - > pwm_freq [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2006-01-10 01:26:14 +03:00
static ssize_t show_temp ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , temp_from_reg ( data - > temp [ nr ] ) ) ;
}
static ssize_t show_temp_max ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , temp_from_reg ( data - > temp_high [ nr ] ) ) ;
}
static ssize_t show_temp_hyst ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
return sprintf ( buf , " %ld \n " , temp_from_reg ( data - > temp_hyst [ nr ] ) ) ;
}
static ssize_t show_temp_type ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
/* 3 is diode, 4 is thermistor */
return sprintf ( buf , " %u \n " , ( data - > temp_mode & ( 1 < < nr ) ) ? 3 : 4 ) ;
}
static ssize_t set_temp_max ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > temp_high [ nr ] = temp_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_TEMP_HIGH ( nr ) , data - > temp_high [ nr ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t set_temp_hyst ( struct device * dev , struct device_attribute
* devattr , const char * buf , size_t count )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int nr = attr - > index ;
long val = simple_strtol ( buf , NULL , 10 ) ;
2006-01-19 01:20:53 +03:00
mutex_lock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
data - > temp_hyst [ nr ] = temp_to_reg ( val ) ;
f71805f_write8 ( data , F71805F_REG_TEMP_HYST ( nr ) , data - > temp_hyst [ nr ] ) ;
2006-01-19 01:20:53 +03:00
mutex_unlock ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
return count ;
}
static ssize_t show_alarms_in ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
2006-09-24 22:52:15 +04:00
return sprintf ( buf , " %lu \n " , data - > alarms & 0x1ff ) ;
2006-01-10 01:26:14 +03:00
}
static ssize_t show_alarms_fan ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
2006-09-24 22:52:15 +04:00
return sprintf ( buf , " %lu \n " , ( data - > alarms > > 16 ) & 0x07 ) ;
2006-01-10 01:26:14 +03:00
}
static ssize_t show_alarms_temp ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
2006-09-24 22:52:15 +04:00
return sprintf ( buf , " %lu \n " , ( data - > alarms > > 11 ) & 0x07 ) ;
}
static ssize_t show_alarm ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = f71805f_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( devattr ) ;
int bitnr = attr - > index ;
return sprintf ( buf , " %lu \n " , ( data - > alarms > > bitnr ) & 1 ) ;
2006-01-10 01:26:14 +03:00
}
static ssize_t show_name ( struct device * dev , struct device_attribute
* devattr , char * buf )
{
struct f71805f_data * data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %s \n " , data - > name ) ;
}
2006-09-24 23:16:40 +04:00
static DEVICE_ATTR ( in0_input , S_IRUGO , show_in0 , NULL ) ;
static DEVICE_ATTR ( in0_max , S_IRUGO | S_IWUSR , show_in0_max , set_in0_max ) ;
static DEVICE_ATTR ( in0_min , S_IRUGO | S_IWUSR , show_in0_min , set_in0_min ) ;
static SENSOR_DEVICE_ATTR ( in1_input , S_IRUGO , show_in , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( in1_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 1 ) ;
static SENSOR_DEVICE_ATTR ( in1_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 1 ) ;
static SENSOR_DEVICE_ATTR ( in2_input , S_IRUGO , show_in , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( in2_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 2 ) ;
static SENSOR_DEVICE_ATTR ( in2_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 2 ) ;
static SENSOR_DEVICE_ATTR ( in3_input , S_IRUGO , show_in , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( in3_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 3 ) ;
static SENSOR_DEVICE_ATTR ( in3_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 3 ) ;
static SENSOR_DEVICE_ATTR ( in4_input , S_IRUGO , show_in , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( in4_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 4 ) ;
static SENSOR_DEVICE_ATTR ( in4_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 4 ) ;
static SENSOR_DEVICE_ATTR ( in5_input , S_IRUGO , show_in , NULL , 5 ) ;
static SENSOR_DEVICE_ATTR ( in5_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 5 ) ;
static SENSOR_DEVICE_ATTR ( in5_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 5 ) ;
static SENSOR_DEVICE_ATTR ( in6_input , S_IRUGO , show_in , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( in6_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 6 ) ;
static SENSOR_DEVICE_ATTR ( in6_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 6 ) ;
static SENSOR_DEVICE_ATTR ( in7_input , S_IRUGO , show_in , NULL , 7 ) ;
static SENSOR_DEVICE_ATTR ( in7_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 7 ) ;
static SENSOR_DEVICE_ATTR ( in7_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 7 ) ;
static SENSOR_DEVICE_ATTR ( in8_input , S_IRUGO , show_in , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( in8_max , S_IRUGO | S_IWUSR ,
show_in_max , set_in_max , 8 ) ;
static SENSOR_DEVICE_ATTR ( in8_min , S_IRUGO | S_IWUSR ,
show_in_min , set_in_min , 8 ) ;
static SENSOR_DEVICE_ATTR ( fan1_input , S_IRUGO , show_fan , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( fan1_min , S_IRUGO | S_IWUSR ,
show_fan_min , set_fan_min , 0 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( fan1_target , S_IRUGO | S_IWUSR ,
show_fan_target , set_fan_target , 0 ) ;
2006-09-24 23:16:40 +04:00
static SENSOR_DEVICE_ATTR ( fan2_input , S_IRUGO , show_fan , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( fan2_min , S_IRUGO | S_IWUSR ,
show_fan_min , set_fan_min , 1 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( fan2_target , S_IRUGO | S_IWUSR ,
show_fan_target , set_fan_target , 1 ) ;
2006-09-24 23:16:40 +04:00
static SENSOR_DEVICE_ATTR ( fan3_input , S_IRUGO , show_fan , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( fan3_min , S_IRUGO | S_IWUSR ,
show_fan_min , set_fan_min , 2 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( fan3_target , S_IRUGO | S_IWUSR ,
show_fan_target , set_fan_target , 2 ) ;
2006-09-24 23:16:40 +04:00
static SENSOR_DEVICE_ATTR ( temp1_input , S_IRUGO , show_temp , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp1_max , S_IRUGO | S_IWUSR ,
show_temp_max , set_temp_max , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp1_max_hyst , S_IRUGO | S_IWUSR ,
show_temp_hyst , set_temp_hyst , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp1_type , S_IRUGO , show_temp_type , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp2_input , S_IRUGO , show_temp , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_max , S_IRUGO | S_IWUSR ,
show_temp_max , set_temp_max , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_max_hyst , S_IRUGO | S_IWUSR ,
show_temp_hyst , set_temp_hyst , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_type , S_IRUGO , show_temp_type , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp3_input , S_IRUGO , show_temp , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( temp3_max , S_IRUGO | S_IWUSR ,
show_temp_max , set_temp_max , 2 ) ;
static SENSOR_DEVICE_ATTR ( temp3_max_hyst , S_IRUGO | S_IWUSR ,
show_temp_hyst , set_temp_hyst , 2 ) ;
static SENSOR_DEVICE_ATTR ( temp3_type , S_IRUGO , show_temp_type , NULL , 2 ) ;
2006-12-12 20:18:26 +03:00
/* pwm (value) files are created read-only, write permission is
then added or removed dynamically as needed */
static SENSOR_DEVICE_ATTR ( pwm1 , S_IRUGO , show_pwm , set_pwm , 0 ) ;
static SENSOR_DEVICE_ATTR ( pwm1_enable , S_IRUGO | S_IWUSR ,
show_pwm_enable , set_pwm_enable , 0 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm1_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , set_pwm_freq , 0 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm1_mode , S_IRUGO , show_pwm_mode , NULL , 0 ) ;
2006-12-12 20:18:26 +03:00
static SENSOR_DEVICE_ATTR ( pwm2 , S_IRUGO , show_pwm , set_pwm , 1 ) ;
static SENSOR_DEVICE_ATTR ( pwm2_enable , S_IRUGO | S_IWUSR ,
show_pwm_enable , set_pwm_enable , 1 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm2_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , set_pwm_freq , 1 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm2_mode , S_IRUGO , show_pwm_mode , NULL , 1 ) ;
2006-12-12 20:18:26 +03:00
static SENSOR_DEVICE_ATTR ( pwm3 , S_IRUGO , show_pwm , set_pwm , 2 ) ;
static SENSOR_DEVICE_ATTR ( pwm3_enable , S_IRUGO | S_IWUSR ,
show_pwm_enable , set_pwm_enable , 2 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm3_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , set_pwm_freq , 2 ) ;
2006-12-12 20:18:27 +03:00
static SENSOR_DEVICE_ATTR ( pwm3_mode , S_IRUGO , show_pwm_mode , NULL , 2 ) ;
2006-12-12 20:18:26 +03:00
2006-09-24 23:16:40 +04:00
static SENSOR_DEVICE_ATTR ( in0_alarm , S_IRUGO , show_alarm , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( in1_alarm , S_IRUGO , show_alarm , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( in2_alarm , S_IRUGO , show_alarm , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( in3_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( in4_alarm , S_IRUGO , show_alarm , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( in5_alarm , S_IRUGO , show_alarm , NULL , 5 ) ;
static SENSOR_DEVICE_ATTR ( in6_alarm , S_IRUGO , show_alarm , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( in7_alarm , S_IRUGO , show_alarm , NULL , 7 ) ;
static SENSOR_DEVICE_ATTR ( in8_alarm , S_IRUGO , show_alarm , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( temp1_alarm , S_IRUGO , show_alarm , NULL , 11 ) ;
static SENSOR_DEVICE_ATTR ( temp2_alarm , S_IRUGO , show_alarm , NULL , 12 ) ;
static SENSOR_DEVICE_ATTR ( temp3_alarm , S_IRUGO , show_alarm , NULL , 13 ) ;
static SENSOR_DEVICE_ATTR ( fan1_alarm , S_IRUGO , show_alarm , NULL , 16 ) ;
static SENSOR_DEVICE_ATTR ( fan2_alarm , S_IRUGO , show_alarm , NULL , 17 ) ;
static SENSOR_DEVICE_ATTR ( fan3_alarm , S_IRUGO , show_alarm , NULL , 18 ) ;
static DEVICE_ATTR ( alarms_in , S_IRUGO , show_alarms_in , NULL ) ;
static DEVICE_ATTR ( alarms_fan , S_IRUGO , show_alarms_fan , NULL ) ;
static DEVICE_ATTR ( alarms_temp , S_IRUGO , show_alarms_temp , NULL ) ;
static DEVICE_ATTR ( name , S_IRUGO , show_name , NULL ) ;
static struct attribute * f71805f_attributes [ ] = {
& dev_attr_in0_input . attr ,
& dev_attr_in0_max . attr ,
& dev_attr_in0_min . attr ,
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in1_max . dev_attr . attr ,
& sensor_dev_attr_in1_min . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in2_max . dev_attr . attr ,
& sensor_dev_attr_in2_min . dev_attr . attr ,
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in3_max . dev_attr . attr ,
& sensor_dev_attr_in3_min . dev_attr . attr ,
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in4_max . dev_attr . attr ,
& sensor_dev_attr_in4_min . dev_attr . attr ,
& sensor_dev_attr_in5_input . dev_attr . attr ,
& sensor_dev_attr_in5_max . dev_attr . attr ,
& sensor_dev_attr_in5_min . dev_attr . attr ,
& sensor_dev_attr_in6_input . dev_attr . attr ,
& sensor_dev_attr_in6_max . dev_attr . attr ,
& sensor_dev_attr_in6_min . dev_attr . attr ,
& sensor_dev_attr_in7_input . dev_attr . attr ,
& sensor_dev_attr_in7_max . dev_attr . attr ,
& sensor_dev_attr_in7_min . dev_attr . attr ,
& sensor_dev_attr_in8_input . dev_attr . attr ,
& sensor_dev_attr_in8_max . dev_attr . attr ,
& sensor_dev_attr_in8_min . dev_attr . attr ,
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp1_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp1_type . dev_attr . attr ,
& sensor_dev_attr_temp2_input . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
& sensor_dev_attr_temp2_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp2_type . dev_attr . attr ,
& sensor_dev_attr_temp3_input . dev_attr . attr ,
& sensor_dev_attr_temp3_max . dev_attr . attr ,
& sensor_dev_attr_temp3_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp3_type . dev_attr . attr ,
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
& sensor_dev_attr_in6_alarm . dev_attr . attr ,
& sensor_dev_attr_in7_alarm . dev_attr . attr ,
& sensor_dev_attr_in8_alarm . dev_attr . attr ,
& dev_attr_alarms_in . attr ,
& sensor_dev_attr_temp1_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_alarm . dev_attr . attr ,
& sensor_dev_attr_temp3_alarm . dev_attr . attr ,
& dev_attr_alarms_temp . attr ,
& dev_attr_alarms_fan . attr ,
& dev_attr_name . attr ,
NULL
2006-01-10 01:29:11 +03:00
} ;
2006-09-24 23:16:40 +04:00
static const struct attribute_group f71805f_group = {
. attrs = f71805f_attributes ,
2006-01-10 01:29:11 +03:00
} ;
2006-12-12 20:18:27 +03:00
static struct attribute * f71805f_attributes_fan [ 3 ] [ 8 ] = {
2006-09-24 23:16:40 +04:00
{
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan1_min . dev_attr . attr ,
& sensor_dev_attr_fan1_alarm . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_fan1_target . dev_attr . attr ,
2006-12-12 20:18:26 +03:00
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm1_enable . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_pwm1_mode . dev_attr . attr ,
2006-09-24 23:16:40 +04:00
NULL
} , {
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan2_min . dev_attr . attr ,
& sensor_dev_attr_fan2_alarm . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_fan2_target . dev_attr . attr ,
2006-12-12 20:18:26 +03:00
& sensor_dev_attr_pwm2 . dev_attr . attr ,
& sensor_dev_attr_pwm2_enable . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_pwm2_mode . dev_attr . attr ,
2006-09-24 23:16:40 +04:00
NULL
} , {
& sensor_dev_attr_fan3_input . dev_attr . attr ,
& sensor_dev_attr_fan3_min . dev_attr . attr ,
& sensor_dev_attr_fan3_alarm . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_fan3_target . dev_attr . attr ,
2006-12-12 20:18:26 +03:00
& sensor_dev_attr_pwm3 . dev_attr . attr ,
& sensor_dev_attr_pwm3_enable . dev_attr . attr ,
2006-12-12 20:18:27 +03:00
& sensor_dev_attr_pwm3_mode . dev_attr . attr ,
2006-09-24 23:16:40 +04:00
NULL
}
} ;
static const struct attribute_group f71805f_group_fan [ 3 ] = {
{ . attrs = f71805f_attributes_fan [ 0 ] } ,
{ . attrs = f71805f_attributes_fan [ 1 ] } ,
{ . attrs = f71805f_attributes_fan [ 2 ] } ,
2006-01-10 01:29:11 +03:00
} ;
2006-01-10 01:26:14 +03:00
2006-12-12 20:18:27 +03:00
/* We don't include pwm_freq files in the arrays above, because they must be
created conditionally ( only if pwm_mode is 1 = = PWM ) */
static struct attribute * f71805f_attributes_pwm_freq [ ] = {
& sensor_dev_attr_pwm1_freq . dev_attr . attr ,
& sensor_dev_attr_pwm2_freq . dev_attr . attr ,
& sensor_dev_attr_pwm3_freq . dev_attr . attr ,
NULL
} ;
static const struct attribute_group f71805f_group_pwm_freq = {
. attrs = f71805f_attributes_pwm_freq ,
} ;
2006-12-12 20:18:26 +03:00
/* We also need an indexed access to pwmN files to toggle writability */
static struct attribute * f71805f_attr_pwm [ ] = {
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm2 . dev_attr . attr ,
& sensor_dev_attr_pwm3 . dev_attr . attr ,
} ;
2006-01-10 01:26:14 +03:00
/*
* Device registration and initialization
*/
static void __devinit f71805f_init_device ( struct f71805f_data * data )
{
u8 reg ;
int i ;
reg = f71805f_read8 ( data , F71805F_REG_START ) ;
if ( ( reg & 0x41 ) ! = 0x01 ) {
printk ( KERN_DEBUG DRVNAME " : Starting monitoring "
" operations \n " ) ;
f71805f_write8 ( data , F71805F_REG_START , ( reg | 0x01 ) & ~ 0x40 ) ;
}
/* Fan monitoring can be disabled. If it is, we won't be polling
the register values , and won ' t create the related sysfs files . */
for ( i = 0 ; i < 3 ; i + + ) {
2006-12-12 20:18:26 +03:00
data - > fan_ctrl [ i ] = f71805f_read8 ( data ,
F71805F_REG_FAN_CTRL ( i ) ) ;
2006-12-12 20:18:27 +03:00
/* Clear latch full bit, else "speed mode" fan speed control
doesn ' t work */
if ( data - > fan_ctrl [ i ] & FAN_CTRL_LATCH_FULL ) {
data - > fan_ctrl [ i ] & = ~ FAN_CTRL_LATCH_FULL ;
f71805f_write8 ( data , F71805F_REG_FAN_CTRL ( i ) ,
data - > fan_ctrl [ i ] ) ;
}
2006-01-10 01:26:14 +03:00
}
}
static int __devinit f71805f_probe ( struct platform_device * pdev )
{
struct f71805f_data * data ;
struct resource * res ;
2006-01-10 01:29:11 +03:00
int i , err ;
2006-01-10 01:26:14 +03:00
if ( ! ( data = kzalloc ( sizeof ( struct f71805f_data ) , GFP_KERNEL ) ) ) {
err = - ENOMEM ;
printk ( KERN_ERR DRVNAME " : Out of memory \n " ) ;
goto exit ;
}
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
data - > addr = res - > start ;
2006-01-19 01:20:53 +03:00
mutex_init ( & data - > lock ) ;
2006-01-10 01:26:14 +03:00
data - > name = " f71805f " ;
2006-01-19 01:20:53 +03:00
mutex_init ( & data - > update_lock ) ;
2006-01-10 01:26:14 +03:00
platform_set_drvdata ( pdev , data ) ;
/* Initialize the F71805F chip */
f71805f_init_device ( data ) ;
/* Register sysfs interface files */
2006-09-24 23:16:40 +04:00
if ( ( err = sysfs_create_group ( & pdev - > dev . kobj , & f71805f_group ) ) )
goto exit_free ;
for ( i = 0 ; i < 3 ; i + + ) {
2006-12-12 20:18:26 +03:00
if ( data - > fan_ctrl [ i ] & FAN_CTRL_SKIP )
2006-01-10 01:29:11 +03:00
continue ;
2006-09-24 23:16:40 +04:00
if ( ( err = sysfs_create_group ( & pdev - > dev . kobj ,
& f71805f_group_fan [ i ] ) ) )
goto exit_remove_files ;
2006-12-12 20:18:27 +03:00
/* If control mode is PWM, create pwm_freq file */
if ( ! ( data - > fan_ctrl [ i ] & FAN_CTRL_DC_MODE ) ) {
if ( ( err = sysfs_create_file ( & pdev - > dev . kobj ,
f71805f_attributes_pwm_freq [ i ] ) ) )
goto exit_remove_files ;
}
2006-12-12 20:18:26 +03:00
/* If PWM is in manual mode, add write permission */
if ( data - > fan_ctrl [ i ] & FAN_CTRL_MODE_MANUAL ) {
if ( ( err = sysfs_chmod_file ( & pdev - > dev . kobj ,
f71805f_attr_pwm [ i ] ,
S_IRUGO | S_IWUSR ) ) ) {
dev_err ( & pdev - > dev , " chmod +w pwm%d failed \n " ,
i + 1 ) ;
goto exit_remove_files ;
}
}
2006-09-24 23:16:40 +04:00
}
data - > class_dev = hwmon_device_register ( & pdev - > dev ) ;
if ( IS_ERR ( data - > class_dev ) ) {
err = PTR_ERR ( data - > class_dev ) ;
dev_err ( & pdev - > dev , " Class registration failed (%d) \n " , err ) ;
goto exit_remove_files ;
2006-01-10 01:26:14 +03:00
}
return 0 ;
2006-09-24 23:16:40 +04:00
exit_remove_files :
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group ) ;
for ( i = 0 ; i < 3 ; i + + )
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group_fan [ i ] ) ;
2006-12-12 20:18:27 +03:00
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group_pwm_freq ) ;
2006-01-10 01:26:14 +03:00
exit_free :
2006-09-24 23:16:40 +04:00
platform_set_drvdata ( pdev , NULL ) ;
2006-01-10 01:26:14 +03:00
kfree ( data ) ;
exit :
return err ;
}
static int __devexit f71805f_remove ( struct platform_device * pdev )
{
struct f71805f_data * data = platform_get_drvdata ( pdev ) ;
2006-09-24 23:16:40 +04:00
int i ;
2006-01-10 01:26:14 +03:00
platform_set_drvdata ( pdev , NULL ) ;
hwmon_device_unregister ( data - > class_dev ) ;
2006-09-24 23:16:40 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group ) ;
for ( i = 0 ; i < 3 ; i + + )
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group_fan [ i ] ) ;
2006-12-12 20:18:27 +03:00
sysfs_remove_group ( & pdev - > dev . kobj , & f71805f_group_pwm_freq ) ;
2006-01-10 01:26:14 +03:00
kfree ( data ) ;
return 0 ;
}
static struct platform_driver f71805f_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = DRVNAME ,
} ,
. probe = f71805f_probe ,
. remove = __devexit_p ( f71805f_remove ) ,
} ;
static int __init f71805f_device_add ( unsigned short address )
{
2006-03-23 18:40:23 +03:00
struct resource res = {
. start = address ,
. end = address + REGION_LENGTH - 1 ,
. flags = IORESOURCE_IO ,
} ;
2006-01-10 01:26:14 +03:00
int err ;
pdev = platform_device_alloc ( DRVNAME , address ) ;
if ( ! pdev ) {
err = - ENOMEM ;
printk ( KERN_ERR DRVNAME " : Device allocation failed \n " ) ;
goto exit ;
}
2006-03-23 18:40:23 +03:00
res . name = pdev - > name ;
err = platform_device_add_resources ( pdev , & res , 1 ) ;
2006-01-10 01:26:14 +03:00
if ( err ) {
printk ( KERN_ERR DRVNAME " : Device resource addition failed "
" (%d) \n " , err ) ;
goto exit_device_put ;
}
err = platform_device_add ( pdev ) ;
if ( err ) {
printk ( KERN_ERR DRVNAME " : Device addition failed (%d) \n " ,
err ) ;
goto exit_device_put ;
}
return 0 ;
exit_device_put :
platform_device_put ( pdev ) ;
exit :
return err ;
}
static int __init f71805f_find ( int sioaddr , unsigned short * address )
{
int err = - ENODEV ;
u16 devid ;
superio_enter ( sioaddr ) ;
devid = superio_inw ( sioaddr , SIO_REG_MANID ) ;
if ( devid ! = SIO_FINTEK_ID )
goto exit ;
devid = superio_inw ( sioaddr , SIO_REG_DEVID ) ;
if ( devid ! = SIO_F71805F_ID ) {
printk ( KERN_INFO DRVNAME " : Unsupported Fintek device, "
" skipping \n " ) ;
goto exit ;
}
superio_select ( sioaddr , F71805F_LD_HWM ) ;
if ( ! ( superio_inb ( sioaddr , SIO_REG_ENABLE ) & 0x01 ) ) {
printk ( KERN_WARNING DRVNAME " : Device not activated, "
" skipping \n " ) ;
goto exit ;
}
* address = superio_inw ( sioaddr , SIO_REG_ADDR ) ;
if ( * address = = 0 ) {
printk ( KERN_WARNING DRVNAME " : Base address not set, "
" skipping \n " ) ;
goto exit ;
}
err = 0 ;
printk ( KERN_INFO DRVNAME " : Found F71805F chip at %#x, revision %u \n " ,
* address , superio_inb ( sioaddr , SIO_REG_DEVREV ) ) ;
exit :
superio_exit ( sioaddr ) ;
return err ;
}
static int __init f71805f_init ( void )
{
int err ;
unsigned short address ;
if ( f71805f_find ( 0x2e , & address )
& & f71805f_find ( 0x4e , & address ) )
return - ENODEV ;
err = platform_driver_register ( & f71805f_driver ) ;
if ( err )
goto exit ;
/* Sets global pdev as a side effect */
err = f71805f_device_add ( address ) ;
if ( err )
goto exit_driver ;
return 0 ;
exit_driver :
platform_driver_unregister ( & f71805f_driver ) ;
exit :
return err ;
}
static void __exit f71805f_exit ( void )
{
platform_device_unregister ( pdev ) ;
platform_driver_unregister ( & f71805f_driver ) ;
}
MODULE_AUTHOR ( " Jean Delvare <khali@linux-fr> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " F71805F hardware monitoring driver " ) ;
module_init ( f71805f_init ) ;
module_exit ( f71805f_exit ) ;