2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-04-06 19:57:20 +04:00
/*
* nct6683 - Driver for the hardware monitoring functionality of
2021-03-04 13:44:21 +03:00
* Nuvoton NCT6683D / NCT6686D / NCT6687D eSIO
2014-04-06 19:57:20 +04:00
*
* Copyright ( C ) 2013 Guenter Roeck < linux @ roeck - us . net >
*
* Derived from nct6775 driver
* Copyright ( C ) 2012 , 2013 Guenter Roeck < linux @ roeck - us . net >
*
* Supports the following chips :
*
* Chip # vin # fan # pwm # temp chip ID
* nct6683d 21 ( 1 ) 16 8 32 ( 1 ) 0xc730
2021-03-04 13:44:21 +03:00
* nct6686d 21 ( 1 ) 16 8 32 ( 1 ) 0xd440
2020-12-02 05:50:57 +03:00
* nct6687d 21 ( 1 ) 16 8 32 ( 1 ) 0xd590
2014-04-06 19:57:20 +04:00
*
* Notes :
* ( 1 ) Total number of vin and temp inputs is 32.
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/acpi.h>
2015-02-19 20:21:29 +03:00
# include <linux/delay.h>
2014-04-06 19:57:20 +04:00
# include <linux/err.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/jiffies.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
2021-03-04 13:44:21 +03:00
enum kinds { nct6683 , nct6686 , nct6687 } ;
2014-04-06 19:57:20 +04:00
static bool force ;
module_param ( force , bool , 0 ) ;
2015-02-19 20:21:29 +03:00
MODULE_PARM_DESC ( force , " Set to one to enable support for unknown vendors " ) ;
2014-04-06 19:57:20 +04:00
static const char * const nct6683_device_names [ ] = {
" nct6683 " ,
2021-03-04 13:44:21 +03:00
" nct6686 " ,
2020-12-02 05:50:57 +03:00
" nct6687 " ,
2014-04-06 19:57:20 +04:00
} ;
static const char * const nct6683_chip_names [ ] = {
" NCT6683D " ,
2021-03-04 13:44:21 +03:00
" NCT6686D " ,
2020-12-02 05:50:57 +03:00
" NCT6687D " ,
2014-04-06 19:57:20 +04:00
} ;
# define DRVNAME "nct6683"
/*
* Super - I / O constants and functions
*/
# define NCT6683_LD_ACPI 0x0a
# define NCT6683_LD_HWM 0x0b
# define NCT6683_LD_VID 0x0d
# define SIO_REG_LDSEL 0x07 /* Logical device select */
# define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
# define SIO_REG_ENABLE 0x30 /* Logical device enable */
# define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
# define SIO_NCT6681_ID 0xb270 /* for later */
# define SIO_NCT6683_ID 0xc730
2021-03-04 13:44:21 +03:00
# define SIO_NCT6686_ID 0xd440
2020-12-02 05:50:57 +03:00
# define SIO_NCT6687_ID 0xd590
2014-04-06 19:57:20 +04:00
# define SIO_ID_MASK 0xFFF0
static inline void
superio_outb ( int ioreg , int reg , int val )
{
outb ( reg , ioreg ) ;
outb ( val , ioreg + 1 ) ;
}
static inline int
superio_inb ( int ioreg , int reg )
{
outb ( reg , ioreg ) ;
return inb ( ioreg + 1 ) ;
}
static inline void
superio_select ( int ioreg , int ld )
{
outb ( SIO_REG_LDSEL , ioreg ) ;
outb ( ld , ioreg + 1 ) ;
}
static inline int
superio_enter ( int ioreg )
{
/*
* Try to reserve < ioreg > and < ioreg + 1 > for exclusive access .
*/
if ( ! request_muxed_region ( ioreg , 2 , DRVNAME ) )
return - EBUSY ;
outb ( 0x87 , ioreg ) ;
outb ( 0x87 , ioreg ) ;
return 0 ;
}
static inline void
superio_exit ( int ioreg )
{
outb ( 0xaa , ioreg ) ;
outb ( 0x02 , ioreg ) ;
outb ( 0x02 , ioreg + 1 ) ;
release_region ( ioreg , 2 ) ;
}
/*
* ISA constants
*/
# define IOREGION_ALIGNMENT (~7)
# define IOREGION_OFFSET 4 /* Use EC port 1 */
# define IOREGION_LENGTH 4
# define EC_PAGE_REG 0
# define EC_INDEX_REG 1
# define EC_DATA_REG 2
# define EC_EVENT_REG 3
/* Common and NCT6683 specific data */
# define NCT6683_NUM_REG_MON 32
# define NCT6683_NUM_REG_FAN 16
# define NCT6683_NUM_REG_PWM 8
# define NCT6683_REG_MON(x) (0x100 + (x) * 2)
# define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2)
# define NCT6683_REG_PWM(x) (0x160 + (x))
2015-02-19 20:21:29 +03:00
# define NCT6683_REG_PWM_WRITE(x) (0xa28 + (x))
2014-04-06 19:57:20 +04:00
# define NCT6683_REG_MON_STS(x) (0x174 + (x))
# define NCT6683_REG_IDLE(x) (0x178 + (x))
# define NCT6683_REG_FAN_STS(x) (0x17c + (x))
# define NCT6683_REG_FAN_ERRSTS 0x17e
# define NCT6683_REG_FAN_INITSTS 0x17f
# define NCT6683_HWM_CFG 0x180
# define NCT6683_REG_MON_CFG(x) (0x1a0 + (x))
# define NCT6683_REG_FANIN_CFG(x) (0x1c0 + (x))
# define NCT6683_REG_FANOUT_CFG(x) (0x1d0 + (x))
# define NCT6683_REG_INTEL_TEMP_MAX(x) (0x901 + (x) * 16)
# define NCT6683_REG_INTEL_TEMP_CRIT(x) (0x90d + (x) * 16)
# define NCT6683_REG_TEMP_HYST(x) (0x330 + (x)) /* 8 bit */
# define NCT6683_REG_TEMP_MAX(x) (0x350 + (x)) /* 8 bit */
# define NCT6683_REG_MON_HIGH(x) (0x370 + (x) * 2) /* 8 bit */
# define NCT6683_REG_MON_LOW(x) (0x371 + (x) * 2) /* 8 bit */
# define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */
2015-02-19 20:21:29 +03:00
# define NCT6683_REG_FAN_CFG_CTRL 0xa01
# define NCT6683_FAN_CFG_REQ 0x80
# define NCT6683_FAN_CFG_DONE 0x40
2014-04-06 19:57:20 +04:00
# define NCT6683_REG_CUSTOMER_ID 0x602
# define NCT6683_CUSTOMER_ID_INTEL 0x805
2015-02-19 20:21:29 +03:00
# define NCT6683_CUSTOMER_ID_MITAC 0xa0e
2020-12-02 05:50:57 +03:00
# define NCT6683_CUSTOMER_ID_MSI 0x201
2021-01-19 08:12:41 +03:00
# define NCT6683_CUSTOMER_ID_ASROCK 0xe2c
2021-09-21 19:58:59 +03:00
# define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b
2014-04-06 19:57:20 +04:00
# define NCT6683_REG_BUILD_YEAR 0x604
# define NCT6683_REG_BUILD_MONTH 0x605
# define NCT6683_REG_BUILD_DAY 0x606
# define NCT6683_REG_SERIAL 0x607
# define NCT6683_REG_VERSION_HI 0x608
# define NCT6683_REG_VERSION_LO 0x609
# define NCT6683_REG_CR_CASEOPEN 0xe8
# define NCT6683_CR_CASEOPEN_MASK (1 << 7)
# define NCT6683_REG_CR_BEEP 0xe0
# define NCT6683_CR_BEEP_MASK (1 << 6)
static const char * const nct6683_mon_label [ ] = {
NULL , /* disabled */
" Local " ,
" Diode 0 (curr) " ,
" Diode 1 (curr) " ,
" Diode 2 (curr) " ,
" Diode 0 (volt) " ,
" Diode 1 (volt) " ,
" Diode 2 (volt) " ,
" Thermistor 14 " ,
" Thermistor 15 " ,
" Thermistor 16 " ,
" Thermistor 0 " ,
" Thermistor 1 " ,
" Thermistor 2 " ,
" Thermistor 3 " ,
" Thermistor 4 " ,
" Thermistor 5 " , /* 0x10 */
" Thermistor 6 " ,
" Thermistor 7 " ,
" Thermistor 8 " ,
" Thermistor 9 " ,
" Thermistor 10 " ,
" Thermistor 11 " ,
" Thermistor 12 " ,
" Thermistor 13 " ,
NULL , NULL , NULL , NULL , NULL , NULL , NULL ,
" PECI 0.0 " , /* 0x20 */
" PECI 1.0 " ,
" PECI 2.0 " ,
" PECI 3.0 " ,
" PECI 0.1 " ,
" PECI 1.1 " ,
" PECI 2.1 " ,
" PECI 3.1 " ,
" PECI DIMM 0 " ,
" PECI DIMM 1 " ,
" PECI DIMM 2 " ,
" PECI DIMM 3 " ,
NULL , NULL , NULL , NULL ,
" PCH CPU " , /* 0x30 */
" PCH CHIP " ,
" PCH CHIP CPU MAX " ,
" PCH MCH " ,
" PCH DIMM 0 " ,
" PCH DIMM 1 " ,
" PCH DIMM 2 " ,
" PCH DIMM 3 " ,
" SMBus 0 " ,
" SMBus 1 " ,
" SMBus 2 " ,
" SMBus 3 " ,
" SMBus 4 " ,
" SMBus 5 " ,
" DIMM 0 " ,
" DIMM 1 " ,
" DIMM 2 " , /* 0x40 */
" DIMM 3 " ,
" AMD TSI Addr 90h " ,
" AMD TSI Addr 92h " ,
" AMD TSI Addr 94h " ,
" AMD TSI Addr 96h " ,
" AMD TSI Addr 98h " ,
" AMD TSI Addr 9ah " ,
" AMD TSI Addr 9ch " ,
" AMD TSI Addr 9dh " ,
NULL , NULL , NULL , NULL , NULL , NULL ,
" Virtual 0 " , /* 0x50 */
" Virtual 1 " ,
" Virtual 2 " ,
" Virtual 3 " ,
" Virtual 4 " ,
" Virtual 5 " ,
" Virtual 6 " ,
" Virtual 7 " ,
NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL ,
" VCC " , /* 0x60 voltage sensors */
" VSB " ,
" AVSB " ,
" VTT " ,
" VBAT " ,
" VREF " ,
" VIN0 " ,
" VIN1 " ,
" VIN2 " ,
" VIN3 " ,
" VIN4 " ,
" VIN5 " ,
" VIN6 " ,
" VIN7 " ,
" VIN8 " ,
" VIN9 " ,
" VIN10 " ,
" VIN11 " ,
" VIN12 " ,
" VIN13 " ,
" VIN14 " ,
" VIN15 " ,
" VIN16 " ,
} ;
# define NUM_MON_LABELS ARRAY_SIZE(nct6683_mon_label)
# define MON_VOLTAGE_START 0x60
/* ------------------------------------------------------- */
struct nct6683_data {
int addr ; /* IO base of EC space */
int sioreg ; /* SIO register */
enum kinds kind ;
u16 customer_id ;
struct device * hwmon_dev ;
const struct attribute_group * groups [ 6 ] ;
int temp_num ; /* number of temperature attributes */
u8 temp_index [ NCT6683_NUM_REG_MON ] ;
u8 temp_src [ NCT6683_NUM_REG_MON ] ;
u8 in_num ; /* number of voltage attributes */
u8 in_index [ NCT6683_NUM_REG_MON ] ;
u8 in_src [ NCT6683_NUM_REG_MON ] ;
struct mutex update_lock ; /* used to protect sensor updates */
bool valid ; /* true if following fields are valid */
unsigned long last_updated ; /* In jiffies */
/* Voltage attribute values */
u8 in [ 3 ] [ NCT6683_NUM_REG_MON ] ; /* [0]=in, [1]=in_max, [2]=in_min */
/* Temperature attribute values */
s16 temp_in [ NCT6683_NUM_REG_MON ] ;
s8 temp [ 4 ] [ NCT6683_NUM_REG_MON ] ; /* [0]=min, [1]=max, [2]=hyst,
* [ 3 ] = crit
*/
/* Fan attribute values */
unsigned int rpm [ NCT6683_NUM_REG_FAN ] ;
u16 fan_min [ NCT6683_NUM_REG_FAN ] ;
u8 fanin_cfg [ NCT6683_NUM_REG_FAN ] ;
u8 fanout_cfg [ NCT6683_NUM_REG_FAN ] ;
u16 have_fan ; /* some fan inputs can be disabled */
u8 have_pwm ;
u8 pwm [ NCT6683_NUM_REG_PWM ] ;
# ifdef CONFIG_PM
/* Remember extra register values over suspend/resume */
u8 hwm_cfg ;
# endif
} ;
struct nct6683_sio_data {
int sioreg ;
enum kinds kind ;
} ;
struct sensor_device_template {
struct device_attribute dev_attr ;
union {
struct {
u8 nr ;
u8 index ;
} s ;
int index ;
} u ;
bool s2 ; /* true if both index and nr are used */
} ;
struct sensor_device_attr_u {
union {
struct sensor_device_attribute a1 ;
struct sensor_device_attribute_2 a2 ;
} u ;
char name [ 32 ] ;
} ;
# define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
. attr = { . name = _template , . mode = _mode } , \
. show = _show , \
. store = _store , \
}
# define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
{ . dev_attr = __TEMPLATE_ATTR ( _template , _mode , _show , _store ) , \
. u . index = _index , \
. s2 = false }
# define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
_nr , _index ) \
{ . dev_attr = __TEMPLATE_ATTR ( _template , _mode , _show , _store ) , \
. u . s . index = _index , \
. u . s . nr = _nr , \
. s2 = true }
# define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
static struct sensor_device_template sensor_dev_template_ # # _name \
= SENSOR_DEVICE_TEMPLATE ( _template , _mode , _show , _store , \
_index )
# define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
_nr , _index ) \
static struct sensor_device_template sensor_dev_template_ # # _name \
= SENSOR_DEVICE_TEMPLATE_2 ( _template , _mode , _show , _store , \
_nr , _index )
struct sensor_template_group {
struct sensor_device_template * * templates ;
umode_t ( * is_visible ) ( struct kobject * , struct attribute * , int ) ;
int base ;
} ;
static struct attribute_group *
2015-12-12 19:36:39 +03:00
nct6683_create_attr_group ( struct device * dev ,
const struct sensor_template_group * tg ,
2014-04-06 19:57:20 +04:00
int repeat )
{
struct sensor_device_attribute_2 * a2 ;
struct sensor_device_attribute * a ;
struct sensor_device_template * * t ;
struct sensor_device_attr_u * su ;
struct attribute_group * group ;
struct attribute * * attrs ;
int i , j , count ;
if ( repeat < = 0 )
return ERR_PTR ( - EINVAL ) ;
t = tg - > templates ;
for ( count = 0 ; * t ; t + + , count + + )
;
if ( count = = 0 )
return ERR_PTR ( - EINVAL ) ;
group = devm_kzalloc ( dev , sizeof ( * group ) , GFP_KERNEL ) ;
if ( group = = NULL )
return ERR_PTR ( - ENOMEM ) ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
attrs = devm_kcalloc ( dev , repeat * count + 1 , sizeof ( * attrs ) ,
2014-04-06 19:57:20 +04:00
GFP_KERNEL ) ;
if ( attrs = = NULL )
return ERR_PTR ( - ENOMEM ) ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
su = devm_kzalloc ( dev , array3_size ( repeat , count , sizeof ( * su ) ) ,
2014-04-06 19:57:20 +04:00
GFP_KERNEL ) ;
if ( su = = NULL )
return ERR_PTR ( - ENOMEM ) ;
group - > attrs = attrs ;
group - > is_visible = tg - > is_visible ;
for ( i = 0 ; i < repeat ; i + + ) {
t = tg - > templates ;
for ( j = 0 ; * t ! = NULL ; j + + ) {
snprintf ( su - > name , sizeof ( su - > name ) ,
( * t ) - > dev_attr . attr . name , tg - > base + i ) ;
if ( ( * t ) - > s2 ) {
a2 = & su - > u . a2 ;
2015-05-28 19:12:23 +03:00
sysfs_attr_init ( & a2 - > dev_attr . attr ) ;
2014-04-06 19:57:20 +04:00
a2 - > dev_attr . attr . name = su - > name ;
a2 - > nr = ( * t ) - > u . s . nr + i ;
a2 - > index = ( * t ) - > u . s . index ;
a2 - > dev_attr . attr . mode =
( * t ) - > dev_attr . attr . mode ;
a2 - > dev_attr . show = ( * t ) - > dev_attr . show ;
a2 - > dev_attr . store = ( * t ) - > dev_attr . store ;
* attrs = & a2 - > dev_attr . attr ;
} else {
a = & su - > u . a1 ;
2015-05-28 19:12:23 +03:00
sysfs_attr_init ( & a - > dev_attr . attr ) ;
2014-04-06 19:57:20 +04:00
a - > dev_attr . attr . name = su - > name ;
a - > index = ( * t ) - > u . index + i ;
a - > dev_attr . attr . mode =
( * t ) - > dev_attr . attr . mode ;
a - > dev_attr . show = ( * t ) - > dev_attr . show ;
a - > dev_attr . store = ( * t ) - > dev_attr . store ;
* attrs = & a - > dev_attr . attr ;
}
attrs + + ;
su + + ;
t + + ;
}
}
return group ;
}
/* LSB is 16 mV, except for the following sources, where it is 32 mV */
# define MON_SRC_VCC 0x60
# define MON_SRC_VSB 0x61
# define MON_SRC_AVSB 0x62
# define MON_SRC_VBAT 0x64
static inline long in_from_reg ( u16 reg , u8 src )
{
int scale = 16 ;
if ( src = = MON_SRC_VCC | | src = = MON_SRC_VSB | | src = = MON_SRC_AVSB | |
src = = MON_SRC_VBAT )
scale < < = 1 ;
return reg * scale ;
}
static u16 nct6683_read ( struct nct6683_data * data , u16 reg )
{
int res ;
outb_p ( 0xff , data - > addr + EC_PAGE_REG ) ; /* unlock */
outb_p ( reg > > 8 , data - > addr + EC_PAGE_REG ) ;
outb_p ( reg & 0xff , data - > addr + EC_INDEX_REG ) ;
res = inb_p ( data - > addr + EC_DATA_REG ) ;
return res ;
}
static u16 nct6683_read16 ( struct nct6683_data * data , u16 reg )
{
return ( nct6683_read ( data , reg ) < < 8 ) | nct6683_read ( data , reg + 1 ) ;
}
static void nct6683_write ( struct nct6683_data * data , u16 reg , u16 value )
{
outb_p ( 0xff , data - > addr + EC_PAGE_REG ) ; /* unlock */
outb_p ( reg > > 8 , data - > addr + EC_PAGE_REG ) ;
outb_p ( reg & 0xff , data - > addr + EC_INDEX_REG ) ;
outb_p ( value & 0xff , data - > addr + EC_DATA_REG ) ;
}
static int get_in_reg ( struct nct6683_data * data , int nr , int index )
{
int ch = data - > in_index [ index ] ;
int reg = - EINVAL ;
switch ( nr ) {
case 0 :
reg = NCT6683_REG_MON ( ch ) ;
break ;
case 1 :
if ( data - > customer_id ! = NCT6683_CUSTOMER_ID_INTEL )
reg = NCT6683_REG_MON_LOW ( ch ) ;
break ;
case 2 :
if ( data - > customer_id ! = NCT6683_CUSTOMER_ID_INTEL )
reg = NCT6683_REG_MON_HIGH ( ch ) ;
break ;
default :
break ;
}
return reg ;
}
static int get_temp_reg ( struct nct6683_data * data , int nr , int index )
{
int ch = data - > temp_index [ index ] ;
int reg = - EINVAL ;
switch ( data - > customer_id ) {
case NCT6683_CUSTOMER_ID_INTEL :
switch ( nr ) {
default :
case 1 : /* max */
reg = NCT6683_REG_INTEL_TEMP_MAX ( ch ) ;
break ;
case 3 : /* crit */
reg = NCT6683_REG_INTEL_TEMP_CRIT ( ch ) ;
break ;
}
break ;
2015-02-19 20:21:29 +03:00
case NCT6683_CUSTOMER_ID_MITAC :
2014-04-06 19:57:20 +04:00
default :
switch ( nr ) {
default :
case 0 : /* min */
reg = NCT6683_REG_MON_LOW ( ch ) ;
break ;
case 1 : /* max */
reg = NCT6683_REG_TEMP_MAX ( ch ) ;
break ;
case 2 : /* hyst */
reg = NCT6683_REG_TEMP_HYST ( ch ) ;
break ;
case 3 : /* crit */
reg = NCT6683_REG_MON_HIGH ( ch ) ;
break ;
}
break ;
}
return reg ;
}
static void nct6683_update_pwm ( struct device * dev )
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int i ;
for ( i = 0 ; i < NCT6683_NUM_REG_PWM ; i + + ) {
if ( ! ( data - > have_pwm & ( 1 < < i ) ) )
continue ;
data - > pwm [ i ] = nct6683_read ( data , NCT6683_REG_PWM ( i ) ) ;
}
}
static struct nct6683_data * nct6683_update_device ( struct device * dev )
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int i , j ;
mutex_lock ( & data - > update_lock ) ;
if ( time_after ( jiffies , data - > last_updated + HZ ) | | ! data - > valid ) {
/* Measured voltages and limits */
for ( i = 0 ; i < data - > in_num ; i + + ) {
for ( j = 0 ; j < 3 ; j + + ) {
int reg = get_in_reg ( data , j , i ) ;
if ( reg > = 0 )
data - > in [ j ] [ i ] =
nct6683_read ( data , reg ) ;
}
}
/* Measured temperatures and limits */
for ( i = 0 ; i < data - > temp_num ; i + + ) {
u8 ch = data - > temp_index [ i ] ;
data - > temp_in [ i ] = nct6683_read16 ( data ,
NCT6683_REG_MON ( ch ) ) ;
for ( j = 0 ; j < 4 ; j + + ) {
int reg = get_temp_reg ( data , j , i ) ;
if ( reg > = 0 )
data - > temp [ j ] [ i ] =
nct6683_read ( data , reg ) ;
}
}
/* Measured fan speeds and limits */
for ( i = 0 ; i < ARRAY_SIZE ( data - > rpm ) ; i + + ) {
if ( ! ( data - > have_fan & ( 1 < < i ) ) )
continue ;
data - > rpm [ i ] = nct6683_read16 ( data ,
NCT6683_REG_FAN_RPM ( i ) ) ;
data - > fan_min [ i ] = nct6683_read16 ( data ,
NCT6683_REG_FAN_MIN ( i ) ) ;
}
nct6683_update_pwm ( dev ) ;
data - > last_updated = jiffies ;
data - > valid = true ;
}
mutex_unlock ( & data - > update_lock ) ;
return data ;
}
/*
* Sysfs callback functions
*/
static ssize_t
show_in_label ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int nr = sattr - > index ;
return sprintf ( buf , " %s \n " , nct6683_mon_label [ data - > in_src [ nr ] ] ) ;
}
static ssize_t
show_in_reg ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int index = sattr - > index ;
int nr = sattr - > nr ;
return sprintf ( buf , " %ld \n " ,
in_from_reg ( data - > in [ index ] [ nr ] , data - > in_index [ index ] ) ) ;
}
static umode_t nct6683_in_is_visible ( struct kobject * kobj ,
struct attribute * attr , int index )
{
2020-06-13 11:06:44 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2014-04-06 19:57:20 +04:00
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int nr = index % 4 ; /* attribute */
/*
* Voltage limits exist for Intel boards ,
* but register location and encoding is unknown
*/
if ( ( nr = = 2 | | nr = = 3 ) & &
data - > customer_id = = NCT6683_CUSTOMER_ID_INTEL )
return 0 ;
return attr - > mode ;
}
SENSOR_TEMPLATE ( in_label , " in%d_label " , S_IRUGO , show_in_label , NULL , 0 ) ;
SENSOR_TEMPLATE_2 ( in_input , " in%d_input " , S_IRUGO , show_in_reg , NULL , 0 , 0 ) ;
SENSOR_TEMPLATE_2 ( in_min , " in%d_min " , S_IRUGO , show_in_reg , NULL , 0 , 1 ) ;
SENSOR_TEMPLATE_2 ( in_max , " in%d_max " , S_IRUGO , show_in_reg , NULL , 0 , 2 ) ;
static struct sensor_device_template * nct6683_attributes_in_template [ ] = {
& sensor_dev_template_in_label ,
& sensor_dev_template_in_input ,
& sensor_dev_template_in_min ,
& sensor_dev_template_in_max ,
NULL
} ;
2015-12-12 19:36:39 +03:00
static const struct sensor_template_group nct6683_in_template_group = {
2014-04-06 19:57:20 +04:00
. templates = nct6683_attributes_in_template ,
. is_visible = nct6683_in_is_visible ,
} ;
static ssize_t
show_fan ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > rpm [ sattr - > index ] ) ;
}
static ssize_t
show_fan_min ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct nct6683_data * data = nct6683_update_device ( dev ) ;
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
int nr = sattr - > index ;
return sprintf ( buf , " %d \n " , data - > fan_min [ nr ] ) ;
}
static ssize_t
show_fan_pulses ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
( ( data - > fanin_cfg [ sattr - > index ] > > 5 ) & 0x03 ) + 1 ) ;
}
static umode_t nct6683_fan_is_visible ( struct kobject * kobj ,
struct attribute * attr , int index )
{
2020-06-13 11:06:44 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2014-04-06 19:57:20 +04:00
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int fan = index / 3 ; /* fan index */
int nr = index % 3 ; /* attribute index */
if ( ! ( data - > have_fan & ( 1 < < fan ) ) )
return 0 ;
/*
* Intel may have minimum fan speed limits ,
* but register location and encoding are unknown .
*/
if ( nr = = 2 & & data - > customer_id = = NCT6683_CUSTOMER_ID_INTEL )
return 0 ;
return attr - > mode ;
}
SENSOR_TEMPLATE ( fan_input , " fan%d_input " , S_IRUGO , show_fan , NULL , 0 ) ;
SENSOR_TEMPLATE ( fan_pulses , " fan%d_pulses " , S_IRUGO , show_fan_pulses , NULL , 0 ) ;
SENSOR_TEMPLATE ( fan_min , " fan%d_min " , S_IRUGO , show_fan_min , NULL , 0 ) ;
/*
* nct6683_fan_is_visible uses the index into the following array
* to determine if attributes should be created or not .
* Any change in order or content must be matched .
*/
static struct sensor_device_template * nct6683_attributes_fan_template [ ] = {
& sensor_dev_template_fan_input ,
& sensor_dev_template_fan_pulses ,
& sensor_dev_template_fan_min ,
NULL
} ;
2015-12-12 19:36:39 +03:00
static const struct sensor_template_group nct6683_fan_template_group = {
2014-04-06 19:57:20 +04:00
. templates = nct6683_attributes_fan_template ,
. is_visible = nct6683_fan_is_visible ,
. base = 1 ,
} ;
static ssize_t
show_temp_label ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int nr = sattr - > index ;
return sprintf ( buf , " %s \n " , nct6683_mon_label [ data - > temp_src [ nr ] ] ) ;
}
static ssize_t
show_temp8 ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int index = sattr - > index ;
int nr = sattr - > nr ;
return sprintf ( buf , " %d \n " , data - > temp [ index ] [ nr ] * 1000 ) ;
}
static ssize_t
show_temp_hyst ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int nr = sattr - > index ;
int temp = data - > temp [ 1 ] [ nr ] - data - > temp [ 2 ] [ nr ] ;
return sprintf ( buf , " %d \n " , temp * 1000 ) ;
}
static ssize_t
show_temp16 ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
struct nct6683_data * data = nct6683_update_device ( dev ) ;
int index = sattr - > index ;
return sprintf ( buf , " %d \n " , ( data - > temp_in [ index ] / 128 ) * 500 ) ;
}
/*
* Temperature sensor type is determined by temperature source
* and can not be modified .
* 0x02 . .0 x07 : Thermal diode
* 0x08 . .0 x18 : Thermistor
* 0x20 . .0 x2b : Intel PECI
* 0x42 . .0 x49 : AMD TSI
* Others are unspecified ( not visible )
*/
static int get_temp_type ( u8 src )
{
if ( src > = 0x02 & & src < = 0x07 )
return 3 ; /* thermal diode */
else if ( src > = 0x08 & & src < = 0x18 )
return 4 ; /* thermistor */
else if ( src > = 0x20 & & src < = 0x2b )
return 6 ; /* PECI */
else if ( src > = 0x42 & & src < = 0x49 )
return 5 ;
return 0 ;
}
static ssize_t
show_temp_type ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct nct6683_data * data = nct6683_update_device ( dev ) ;
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
int nr = sattr - > index ;
return sprintf ( buf , " %d \n " , get_temp_type ( data - > temp_src [ nr ] ) ) ;
}
static umode_t nct6683_temp_is_visible ( struct kobject * kobj ,
struct attribute * attr , int index )
{
2020-06-13 11:06:44 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2014-04-06 19:57:20 +04:00
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int temp = index / 7 ; /* temp index */
int nr = index % 7 ; /* attribute index */
/*
* Intel does not have low temperature limits or temperature hysteresis
* registers , or at least register location and encoding is unknown .
*/
if ( ( nr = = 2 | | nr = = 4 ) & &
data - > customer_id = = NCT6683_CUSTOMER_ID_INTEL )
return 0 ;
if ( nr = = 6 & & get_temp_type ( data - > temp_src [ temp ] ) = = 0 )
return 0 ; /* type */
return attr - > mode ;
}
SENSOR_TEMPLATE ( temp_input , " temp%d_input " , S_IRUGO , show_temp16 , NULL , 0 ) ;
SENSOR_TEMPLATE ( temp_label , " temp%d_label " , S_IRUGO , show_temp_label , NULL , 0 ) ;
SENSOR_TEMPLATE_2 ( temp_min , " temp%d_min " , S_IRUGO , show_temp8 , NULL , 0 , 0 ) ;
SENSOR_TEMPLATE_2 ( temp_max , " temp%d_max " , S_IRUGO , show_temp8 , NULL , 0 , 1 ) ;
SENSOR_TEMPLATE ( temp_max_hyst , " temp%d_max_hyst " , S_IRUGO , show_temp_hyst , NULL ,
0 ) ;
SENSOR_TEMPLATE_2 ( temp_crit , " temp%d_crit " , S_IRUGO , show_temp8 , NULL , 0 , 3 ) ;
SENSOR_TEMPLATE ( temp_type , " temp%d_type " , S_IRUGO , show_temp_type , NULL , 0 ) ;
/*
* nct6683_temp_is_visible uses the index into the following array
* to determine if attributes should be created or not .
* Any change in order or content must be matched .
*/
static struct sensor_device_template * nct6683_attributes_temp_template [ ] = {
& sensor_dev_template_temp_input ,
& sensor_dev_template_temp_label ,
& sensor_dev_template_temp_min , /* 2 */
& sensor_dev_template_temp_max , /* 3 */
& sensor_dev_template_temp_max_hyst , /* 4 */
& sensor_dev_template_temp_crit , /* 5 */
& sensor_dev_template_temp_type , /* 6 */
NULL
} ;
2015-12-12 19:36:39 +03:00
static const struct sensor_template_group nct6683_temp_template_group = {
2014-04-06 19:57:20 +04:00
. templates = nct6683_attributes_temp_template ,
. is_visible = nct6683_temp_is_visible ,
. base = 1 ,
} ;
static ssize_t
show_pwm ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct nct6683_data * data = nct6683_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
int index = sattr - > index ;
return sprintf ( buf , " %d \n " , data - > pwm [ index ] ) ;
}
2015-02-19 20:21:29 +03:00
static ssize_t
store_pwm ( struct device * dev , struct device_attribute * attr , const char * buf ,
size_t count )
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int index = sattr - > index ;
unsigned long val ;
if ( kstrtoul ( buf , 10 , & val ) | | val > 255 )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
nct6683_write ( data , NCT6683_REG_FAN_CFG_CTRL , NCT6683_FAN_CFG_REQ ) ;
usleep_range ( 1000 , 2000 ) ;
nct6683_write ( data , NCT6683_REG_PWM_WRITE ( index ) , val ) ;
nct6683_write ( data , NCT6683_REG_FAN_CFG_CTRL , NCT6683_FAN_CFG_DONE ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
SENSOR_TEMPLATE ( pwm , " pwm%d " , S_IRUGO , show_pwm , store_pwm , 0 ) ;
2014-04-06 19:57:20 +04:00
static umode_t nct6683_pwm_is_visible ( struct kobject * kobj ,
struct attribute * attr , int index )
{
2020-06-13 11:06:44 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2014-04-06 19:57:20 +04:00
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int pwm = index ; /* pwm index */
if ( ! ( data - > have_pwm & ( 1 < < pwm ) ) )
return 0 ;
2015-02-19 20:21:29 +03:00
/* Only update pwm values for Mitac boards */
if ( data - > customer_id = = NCT6683_CUSTOMER_ID_MITAC )
return attr - > mode | S_IWUSR ;
2014-04-06 19:57:20 +04:00
return attr - > mode ;
}
static struct sensor_device_template * nct6683_attributes_pwm_template [ ] = {
& sensor_dev_template_pwm ,
NULL
} ;
2015-12-12 19:36:39 +03:00
static const struct sensor_template_group nct6683_pwm_template_group = {
2014-04-06 19:57:20 +04:00
. templates = nct6683_attributes_pwm_template ,
. is_visible = nct6683_pwm_is_visible ,
. base = 1 ,
} ;
static ssize_t
2016-12-22 15:05:01 +03:00
beep_enable_show ( struct device * dev , struct device_attribute * attr , char * buf )
2014-04-06 19:57:20 +04:00
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int ret ;
u8 reg ;
mutex_lock ( & data - > update_lock ) ;
ret = superio_enter ( data - > sioreg ) ;
if ( ret )
goto error ;
superio_select ( data - > sioreg , NCT6683_LD_HWM ) ;
reg = superio_inb ( data - > sioreg , NCT6683_REG_CR_BEEP ) ;
superio_exit ( data - > sioreg ) ;
mutex_unlock ( & data - > update_lock ) ;
return sprintf ( buf , " %u \n " , ! ! ( reg & NCT6683_CR_BEEP_MASK ) ) ;
error :
mutex_unlock ( & data - > update_lock ) ;
return ret ;
}
static ssize_t
2016-12-22 15:05:01 +03:00
beep_enable_store ( struct device * dev , struct device_attribute * attr ,
2014-04-06 19:57:20 +04:00
const char * buf , size_t count )
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
unsigned long val ;
u8 reg ;
int ret ;
if ( kstrtoul ( buf , 10 , & val ) | | ( val ! = 0 & & val ! = 1 ) )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
ret = superio_enter ( data - > sioreg ) ;
if ( ret ) {
count = ret ;
goto error ;
}
superio_select ( data - > sioreg , NCT6683_LD_HWM ) ;
reg = superio_inb ( data - > sioreg , NCT6683_REG_CR_BEEP ) ;
if ( val )
reg | = NCT6683_CR_BEEP_MASK ;
else
reg & = ~ NCT6683_CR_BEEP_MASK ;
superio_outb ( data - > sioreg , NCT6683_REG_CR_BEEP , reg ) ;
superio_exit ( data - > sioreg ) ;
error :
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
/* Case open detection */
static ssize_t
2016-12-22 15:05:01 +03:00
intrusion0_alarm_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2014-04-06 19:57:20 +04:00
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
int ret ;
u8 reg ;
mutex_lock ( & data - > update_lock ) ;
ret = superio_enter ( data - > sioreg ) ;
if ( ret )
goto error ;
superio_select ( data - > sioreg , NCT6683_LD_ACPI ) ;
reg = superio_inb ( data - > sioreg , NCT6683_REG_CR_CASEOPEN ) ;
superio_exit ( data - > sioreg ) ;
mutex_unlock ( & data - > update_lock ) ;
return sprintf ( buf , " %u \n " , ! ( reg & NCT6683_CR_CASEOPEN_MASK ) ) ;
error :
mutex_unlock ( & data - > update_lock ) ;
return ret ;
}
static ssize_t
2016-12-22 15:05:01 +03:00
intrusion0_alarm_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2014-04-06 19:57:20 +04:00
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
unsigned long val ;
u8 reg ;
int ret ;
if ( kstrtoul ( buf , 10 , & val ) | | val ! = 0 )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
/*
* Use CR registers to clear caseopen status .
* Caseopen is activ low , clear by writing 1 into the register .
*/
ret = superio_enter ( data - > sioreg ) ;
if ( ret ) {
count = ret ;
goto error ;
}
superio_select ( data - > sioreg , NCT6683_LD_ACPI ) ;
reg = superio_inb ( data - > sioreg , NCT6683_REG_CR_CASEOPEN ) ;
reg | = NCT6683_CR_CASEOPEN_MASK ;
superio_outb ( data - > sioreg , NCT6683_REG_CR_CASEOPEN , reg ) ;
reg & = ~ NCT6683_CR_CASEOPEN_MASK ;
superio_outb ( data - > sioreg , NCT6683_REG_CR_CASEOPEN , reg ) ;
superio_exit ( data - > sioreg ) ;
data - > valid = false ; /* Force cache refresh */
error :
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2016-12-22 15:05:01 +03:00
static DEVICE_ATTR_RW ( intrusion0_alarm ) ;
static DEVICE_ATTR_RW ( beep_enable ) ;
2014-04-06 19:57:20 +04:00
static struct attribute * nct6683_attributes_other [ ] = {
& dev_attr_intrusion0_alarm . attr ,
& dev_attr_beep_enable . attr ,
NULL
} ;
static const struct attribute_group nct6683_group_other = {
. attrs = nct6683_attributes_other ,
} ;
/* Get the monitoring functions started */
static inline void nct6683_init_device ( struct nct6683_data * data )
{
u8 tmp ;
/* Start hardware monitoring if needed */
tmp = nct6683_read ( data , NCT6683_HWM_CFG ) ;
if ( ! ( tmp & 0x80 ) )
nct6683_write ( data , NCT6683_HWM_CFG , tmp | 0x80 ) ;
}
/*
* There are a total of 24 fan inputs . Each can be configured as input
* or as output . A maximum of 16 inputs and 8 outputs is configurable .
*/
static void
nct6683_setup_fans ( struct nct6683_data * data )
{
int i ;
u8 reg ;
for ( i = 0 ; i < NCT6683_NUM_REG_FAN ; i + + ) {
reg = nct6683_read ( data , NCT6683_REG_FANIN_CFG ( i ) ) ;
if ( reg & 0x80 )
data - > have_fan | = 1 < < i ;
data - > fanin_cfg [ i ] = reg ;
}
for ( i = 0 ; i < NCT6683_NUM_REG_PWM ; i + + ) {
reg = nct6683_read ( data , NCT6683_REG_FANOUT_CFG ( i ) ) ;
if ( reg & 0x80 )
data - > have_pwm | = 1 < < i ;
data - > fanout_cfg [ i ] = reg ;
}
}
/*
* Translation from monitoring register to temperature and voltage attributes
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*
* There are a total of 32 monitoring registers . Each can be assigned to either
* a temperature or voltage monitoring source .
* NCT6683_REG_MON_CFG ( x ) defines assignment for each monitoring source .
*
* Temperature and voltage attribute mapping is determined by walking through
* the NCT6683_REG_MON_CFG registers . If the assigned source is
* a temperature , temp_index [ n ] is set to the monitor register index , and
* temp_src [ n ] is set to the temperature source . If the assigned source is
* a voltage , the respective values are stored in in_index [ ] and in_src [ ] ,
* respectively .
*/
static void nct6683_setup_sensors ( struct nct6683_data * data )
{
u8 reg ;
int i ;
data - > temp_num = 0 ;
data - > in_num = 0 ;
for ( i = 0 ; i < NCT6683_NUM_REG_MON ; i + + ) {
reg = nct6683_read ( data , NCT6683_REG_MON_CFG ( i ) ) & 0x7f ;
/* Ignore invalid assignments */
if ( reg > = NUM_MON_LABELS )
continue ;
/* Skip if disabled or reserved */
if ( nct6683_mon_label [ reg ] = = NULL )
continue ;
if ( reg < MON_VOLTAGE_START ) {
data - > temp_index [ data - > temp_num ] = i ;
data - > temp_src [ data - > temp_num ] = reg ;
data - > temp_num + + ;
} else {
data - > in_index [ data - > in_num ] = i ;
data - > in_src [ data - > in_num ] = reg ;
data - > in_num + + ;
}
}
}
static int nct6683_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct nct6683_sio_data * sio_data = dev - > platform_data ;
struct attribute_group * group ;
struct nct6683_data * data ;
struct device * hwmon_dev ;
struct resource * res ;
int groups = 0 ;
2015-02-19 20:21:29 +03:00
char build [ 16 ] ;
2014-04-06 19:57:20 +04:00
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( ! devm_request_region ( dev , res - > start , IOREGION_LENGTH , DRVNAME ) )
return - EBUSY ;
data = devm_kzalloc ( dev , sizeof ( struct nct6683_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > kind = sio_data - > kind ;
data - > sioreg = sio_data - > sioreg ;
data - > addr = res - > start ;
mutex_init ( & data - > update_lock ) ;
platform_set_drvdata ( pdev , data ) ;
data - > customer_id = nct6683_read16 ( data , NCT6683_REG_CUSTOMER_ID ) ;
2015-02-19 20:21:29 +03:00
/* By default only instantiate driver if the customer ID is known */
switch ( data - > customer_id ) {
case NCT6683_CUSTOMER_ID_INTEL :
break ;
case NCT6683_CUSTOMER_ID_MITAC :
break ;
2020-12-02 05:50:57 +03:00
case NCT6683_CUSTOMER_ID_MSI :
break ;
2021-01-19 08:12:41 +03:00
case NCT6683_CUSTOMER_ID_ASROCK :
break ;
2021-09-21 19:58:59 +03:00
case NCT6683_CUSTOMER_ID_ASROCK2 :
break ;
2015-02-19 20:21:29 +03:00
default :
if ( ! force )
return - ENODEV ;
}
2014-04-06 19:57:20 +04:00
nct6683_init_device ( data ) ;
nct6683_setup_fans ( data ) ;
nct6683_setup_sensors ( data ) ;
/* Register sysfs hooks */
if ( data - > have_pwm ) {
group = nct6683_create_attr_group ( dev ,
& nct6683_pwm_template_group ,
fls ( data - > have_pwm ) ) ;
if ( IS_ERR ( group ) )
return PTR_ERR ( group ) ;
data - > groups [ groups + + ] = group ;
}
if ( data - > in_num ) {
group = nct6683_create_attr_group ( dev ,
& nct6683_in_template_group ,
data - > in_num ) ;
if ( IS_ERR ( group ) )
return PTR_ERR ( group ) ;
data - > groups [ groups + + ] = group ;
}
if ( data - > have_fan ) {
group = nct6683_create_attr_group ( dev ,
& nct6683_fan_template_group ,
fls ( data - > have_fan ) ) ;
if ( IS_ERR ( group ) )
return PTR_ERR ( group ) ;
data - > groups [ groups + + ] = group ;
}
if ( data - > temp_num ) {
group = nct6683_create_attr_group ( dev ,
& nct6683_temp_template_group ,
data - > temp_num ) ;
if ( IS_ERR ( group ) )
return PTR_ERR ( group ) ;
data - > groups [ groups + + ] = group ;
}
data - > groups [ groups + + ] = & nct6683_group_other ;
2015-02-19 20:21:29 +03:00
if ( data - > customer_id = = NCT6683_CUSTOMER_ID_INTEL )
scnprintf ( build , sizeof ( build ) , " %02x/%02x/%02x " ,
nct6683_read ( data , NCT6683_REG_BUILD_MONTH ) ,
nct6683_read ( data , NCT6683_REG_BUILD_DAY ) ,
nct6683_read ( data , NCT6683_REG_BUILD_YEAR ) ) ;
else
scnprintf ( build , sizeof ( build ) , " %02d/%02d/%02d " ,
nct6683_read ( data , NCT6683_REG_BUILD_MONTH ) ,
nct6683_read ( data , NCT6683_REG_BUILD_DAY ) ,
nct6683_read ( data , NCT6683_REG_BUILD_YEAR ) ) ;
dev_info ( dev , " %s EC firmware version %d.%d build %s \n " ,
2014-04-06 19:57:20 +04:00
nct6683_chip_names [ data - > kind ] ,
nct6683_read ( data , NCT6683_REG_VERSION_HI ) ,
nct6683_read ( data , NCT6683_REG_VERSION_LO ) ,
2015-02-19 20:21:29 +03:00
build ) ;
2014-04-06 19:57:20 +04:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev ,
nct6683_device_names [ data - > kind ] , data , data - > groups ) ;
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
}
# ifdef CONFIG_PM
static int nct6683_suspend ( struct device * dev )
{
struct nct6683_data * data = nct6683_update_device ( dev ) ;
mutex_lock ( & data - > update_lock ) ;
data - > hwm_cfg = nct6683_read ( data , NCT6683_HWM_CFG ) ;
mutex_unlock ( & data - > update_lock ) ;
return 0 ;
}
static int nct6683_resume ( struct device * dev )
{
struct nct6683_data * data = dev_get_drvdata ( dev ) ;
mutex_lock ( & data - > update_lock ) ;
nct6683_write ( data , NCT6683_HWM_CFG , data - > hwm_cfg ) ;
/* Force re-reading all values */
data - > valid = false ;
mutex_unlock ( & data - > update_lock ) ;
return 0 ;
}
static const struct dev_pm_ops nct6683_dev_pm_ops = {
. suspend = nct6683_suspend ,
. resume = nct6683_resume ,
. freeze = nct6683_suspend ,
. restore = nct6683_resume ,
} ;
# define NCT6683_DEV_PM_OPS (&nct6683_dev_pm_ops)
# else
# define NCT6683_DEV_PM_OPS NULL
# endif /* CONFIG_PM */
static struct platform_driver nct6683_driver = {
. driver = {
. name = DRVNAME ,
. pm = NCT6683_DEV_PM_OPS ,
} ,
. probe = nct6683_probe ,
} ;
static int __init nct6683_find ( int sioaddr , struct nct6683_sio_data * sio_data )
{
int addr ;
u16 val ;
int err ;
err = superio_enter ( sioaddr ) ;
if ( err )
return err ;
val = ( superio_inb ( sioaddr , SIO_REG_DEVID ) < < 8 )
| superio_inb ( sioaddr , SIO_REG_DEVID + 1 ) ;
switch ( val & SIO_ID_MASK ) {
case SIO_NCT6683_ID :
sio_data - > kind = nct6683 ;
break ;
2021-03-04 13:44:21 +03:00
case SIO_NCT6686_ID :
sio_data - > kind = nct6686 ;
break ;
2020-12-02 05:50:57 +03:00
case SIO_NCT6687_ID :
sio_data - > kind = nct6687 ;
break ;
2014-04-06 19:57:20 +04:00
default :
if ( val ! = 0xffff )
pr_debug ( " unsupported chip ID: 0x%04x \n " , val ) ;
goto fail ;
}
/* We have a known chip, find the HWM I/O address */
superio_select ( sioaddr , NCT6683_LD_HWM ) ;
val = ( superio_inb ( sioaddr , SIO_REG_ADDR ) < < 8 )
| superio_inb ( sioaddr , SIO_REG_ADDR + 1 ) ;
addr = val & IOREGION_ALIGNMENT ;
if ( addr = = 0 ) {
pr_err ( " EC base I/O port unconfigured \n " ) ;
goto fail ;
}
/* Activate logical device if needed */
val = superio_inb ( sioaddr , SIO_REG_ENABLE ) ;
if ( ! ( val & 0x01 ) ) {
2018-04-23 04:16:54 +03:00
pr_warn ( " Forcibly enabling EC access. Data may be unusable. \n " ) ;
superio_outb ( sioaddr , SIO_REG_ENABLE , val | 0x01 ) ;
2014-04-06 19:57:20 +04:00
}
superio_exit ( sioaddr ) ;
pr_info ( " Found %s or compatible chip at %#x:%#x \n " ,
nct6683_chip_names [ sio_data - > kind ] , sioaddr , addr ) ;
sio_data - > sioreg = sioaddr ;
return addr ;
fail :
superio_exit ( sioaddr ) ;
return - ENODEV ;
}
/*
* when Super - I / O functions move to a separate file , the Super - I / O
* bus will manage the lifetime of the device and this module will only keep
* track of the nct6683 driver . But since we use platform_device_alloc ( ) , we
* must keep track of the device
*/
static struct platform_device * pdev [ 2 ] ;
static int __init sensors_nct6683_init ( void )
{
struct nct6683_sio_data sio_data ;
int sioaddr [ 2 ] = { 0x2e , 0x4e } ;
struct resource res ;
bool found = false ;
int address ;
int i , err ;
err = platform_driver_register ( & nct6683_driver ) ;
if ( err )
return err ;
/*
* initialize sio_data - > kind and sio_data - > sioreg .
*
* when Super - I / O functions move to a separate file , the Super - I / O
* driver will probe 0x2e and 0x4e and auto - detect the presence of a
* nct6683 hardware monitor , and call probe ( )
*/
for ( i = 0 ; i < ARRAY_SIZE ( pdev ) ; i + + ) {
address = nct6683_find ( sioaddr [ i ] , & sio_data ) ;
if ( address < = 0 )
continue ;
found = true ;
pdev [ i ] = platform_device_alloc ( DRVNAME , address ) ;
if ( ! pdev [ i ] ) {
err = - ENOMEM ;
2014-05-24 19:04:22 +04:00
goto exit_device_unregister ;
2014-04-06 19:57:20 +04:00
}
err = platform_device_add_data ( pdev [ i ] , & sio_data ,
sizeof ( struct nct6683_sio_data ) ) ;
if ( err )
goto exit_device_put ;
memset ( & res , 0 , sizeof ( res ) ) ;
res . name = DRVNAME ;
res . start = address + IOREGION_OFFSET ;
res . end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1 ;
res . flags = IORESOURCE_IO ;
err = acpi_check_resource_conflict ( & res ) ;
if ( err ) {
platform_device_put ( pdev [ i ] ) ;
pdev [ i ] = NULL ;
continue ;
}
err = platform_device_add_resources ( pdev [ i ] , & res , 1 ) ;
if ( err )
goto exit_device_put ;
/* platform_device_add calls probe() */
err = platform_device_add ( pdev [ i ] ) ;
if ( err )
goto exit_device_put ;
}
if ( ! found ) {
err = - ENODEV ;
goto exit_unregister ;
}
return 0 ;
exit_device_put :
2014-05-24 19:04:22 +04:00
platform_device_put ( pdev [ i ] ) ;
exit_device_unregister :
while ( - - i > = 0 ) {
2014-04-06 19:57:20 +04:00
if ( pdev [ i ] )
2014-05-24 19:04:22 +04:00
platform_device_unregister ( pdev [ i ] ) ;
2014-04-06 19:57:20 +04:00
}
exit_unregister :
platform_driver_unregister ( & nct6683_driver ) ;
return err ;
}
static void __exit sensors_nct6683_exit ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( pdev ) ; i + + ) {
if ( pdev [ i ] )
platform_device_unregister ( pdev [ i ] ) ;
}
platform_driver_unregister ( & nct6683_driver ) ;
}
MODULE_AUTHOR ( " Guenter Roeck <linux@roeck-us.net> " ) ;
MODULE_DESCRIPTION ( " NCT6683D driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( sensors_nct6683_init ) ;
module_exit ( sensors_nct6683_exit ) ;