2019-01-28 10:23:23 -06:00
// SPDX-License-Identifier: GPL-2.0+
// Copyright IBM Corp 2019
2018-11-08 15:05:29 -06:00
# include <linux/bitops.h>
# include <linux/device.h>
2019-04-10 12:47:26 +02:00
# include <linux/export.h>
2018-11-08 15:05:29 -06:00
# include <linux/hwmon-sysfs.h>
# include <linux/kernel.h>
2022-04-27 09:04:43 -05:00
# include <linux/kstrtox.h>
2018-11-08 15:05:29 -06:00
# include <linux/sysfs.h>
# include "common.h"
/* OCC status register */
# define OCC_STAT_MASTER BIT(7)
/* OCC extended status register */
# define OCC_EXT_STAT_DVFS_OT BIT(7)
# define OCC_EXT_STAT_DVFS_POWER BIT(6)
# define OCC_EXT_STAT_MEM_THROTTLE BIT(5)
# define OCC_EXT_STAT_QUICK_DROP BIT(4)
2022-02-15 09:10:21 -06:00
# define OCC_EXT_STAT_DVFS_VDD BIT(3)
# define OCC_EXT_STAT_GPU_THROTTLE GENMASK(2, 0)
2018-11-08 15:05:29 -06:00
2022-04-27 09:04:43 -05:00
static ssize_t occ_active_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int rc ;
bool active ;
struct occ * occ = dev_get_drvdata ( dev ) ;
rc = kstrtobool ( buf , & active ) ;
if ( rc )
return rc ;
rc = occ_active ( occ , active ) ;
if ( rc )
return rc ;
return count ;
}
2018-11-08 15:05:29 -06:00
static ssize_t occ_sysfs_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
int rc ;
int val = 0 ;
struct occ * occ = dev_get_drvdata ( dev ) ;
struct occ_poll_response_header * header ;
struct sensor_device_attribute * sattr = to_sensor_dev_attr ( attr ) ;
2022-04-27 09:04:43 -05:00
if ( occ - > active ) {
rc = occ_update_response ( occ ) ;
if ( rc )
return rc ;
2018-11-08 15:05:29 -06:00
2022-04-27 09:04:43 -05:00
header = ( struct occ_poll_response_header * ) occ - > resp . data ;
switch ( sattr - > index ) {
case 0 :
val = ! ! ( header - > status & OCC_STAT_MASTER ) ;
break ;
case 1 :
2018-11-08 15:05:29 -06:00
val = 1 ;
2022-04-27 09:04:43 -05:00
break ;
case 2 :
val = ! ! ( header - > ext_status & OCC_EXT_STAT_DVFS_OT ) ;
break ;
case 3 :
val = ! ! ( header - > ext_status & OCC_EXT_STAT_DVFS_POWER ) ;
break ;
case 4 :
val = ! ! ( header - > ext_status &
OCC_EXT_STAT_MEM_THROTTLE ) ;
break ;
case 5 :
val = ! ! ( header - > ext_status & OCC_EXT_STAT_QUICK_DROP ) ;
break ;
case 6 :
val = header - > occ_state ;
break ;
case 7 :
if ( header - > status & OCC_STAT_MASTER )
val = hweight8 ( header - > occs_present ) ;
else
val = 1 ;
break ;
case 8 :
val = header - > ips_status ;
break ;
case 9 :
val = header - > mode ;
break ;
case 10 :
val = ! ! ( header - > ext_status & OCC_EXT_STAT_DVFS_VDD ) ;
break ;
case 11 :
val = header - > ext_status & OCC_EXT_STAT_GPU_THROTTLE ;
break ;
default :
return - EINVAL ;
}
} else {
if ( sattr - > index = = 1 )
val = 0 ;
else if ( sattr - > index < = 11 )
val = - ENODATA ;
else
return - EINVAL ;
2018-11-08 15:05:29 -06:00
}
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-21 20:49:10 -07:00
return sysfs_emit ( buf , " %d \n " , val ) ;
2018-11-08 15:05:29 -06:00
}
2019-04-16 15:43:49 +00:00
static ssize_t occ_error_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct occ * occ = dev_get_drvdata ( dev ) ;
occ_update_response ( occ ) ;
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-21 20:49:10 -07:00
return sysfs_emit ( buf , " %d \n " , occ - > error ) ;
2019-04-16 15:43:49 +00:00
}
2018-11-08 15:05:29 -06:00
static SENSOR_DEVICE_ATTR ( occ_master , 0444 , occ_sysfs_show , NULL , 0 ) ;
2022-04-27 09:04:43 -05:00
static SENSOR_DEVICE_ATTR ( occ_active , 0644 , occ_sysfs_show , occ_active_store ,
1 ) ;
2018-11-08 15:05:29 -06:00
static SENSOR_DEVICE_ATTR ( occ_dvfs_overtemp , 0444 , occ_sysfs_show , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( occ_dvfs_power , 0444 , occ_sysfs_show , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( occ_mem_throttle , 0444 , occ_sysfs_show , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( occ_quick_pwr_drop , 0444 , occ_sysfs_show , NULL , 5 ) ;
static SENSOR_DEVICE_ATTR ( occ_state , 0444 , occ_sysfs_show , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( occs_present , 0444 , occ_sysfs_show , NULL , 7 ) ;
2022-02-15 09:10:19 -06:00
static SENSOR_DEVICE_ATTR ( occ_ips_status , 0444 , occ_sysfs_show , NULL , 8 ) ;
2022-02-15 09:10:20 -06:00
static SENSOR_DEVICE_ATTR ( occ_mode , 0444 , occ_sysfs_show , NULL , 9 ) ;
2022-02-15 09:10:21 -06:00
static SENSOR_DEVICE_ATTR ( occ_dvfs_vdd , 0444 , occ_sysfs_show , NULL , 10 ) ;
static SENSOR_DEVICE_ATTR ( occ_gpu_throttle , 0444 , occ_sysfs_show , NULL , 11 ) ;
2019-04-16 15:43:49 +00:00
static DEVICE_ATTR_RO ( occ_error ) ;
2018-11-08 15:05:29 -06:00
static struct attribute * occ_attributes [ ] = {
& sensor_dev_attr_occ_master . dev_attr . attr ,
& sensor_dev_attr_occ_active . dev_attr . attr ,
& sensor_dev_attr_occ_dvfs_overtemp . dev_attr . attr ,
& sensor_dev_attr_occ_dvfs_power . dev_attr . attr ,
& sensor_dev_attr_occ_mem_throttle . dev_attr . attr ,
& sensor_dev_attr_occ_quick_pwr_drop . dev_attr . attr ,
& sensor_dev_attr_occ_state . dev_attr . attr ,
& sensor_dev_attr_occs_present . dev_attr . attr ,
2022-02-15 09:10:19 -06:00
& sensor_dev_attr_occ_ips_status . dev_attr . attr ,
2022-02-15 09:10:20 -06:00
& sensor_dev_attr_occ_mode . dev_attr . attr ,
2022-02-15 09:10:21 -06:00
& sensor_dev_attr_occ_dvfs_vdd . dev_attr . attr ,
& sensor_dev_attr_occ_gpu_throttle . dev_attr . attr ,
2019-04-16 15:43:49 +00:00
& dev_attr_occ_error . attr ,
2018-11-08 15:05:29 -06:00
NULL
} ;
static const struct attribute_group occ_sysfs = {
. attrs = occ_attributes ,
} ;
void occ_sysfs_poll_done ( struct occ * occ )
{
const char * name ;
struct occ_poll_response_header * header =
( struct occ_poll_response_header * ) occ - > resp . data ;
/*
* On the first poll response , we haven ' t yet created the sysfs
* attributes , so don ' t make any notify calls .
*/
2022-04-27 09:04:43 -05:00
if ( ! occ - > active )
2018-11-08 15:05:29 -06:00
goto done ;
if ( ( header - > status & OCC_STAT_MASTER ) ! =
( occ - > prev_stat & OCC_STAT_MASTER ) ) {
name = sensor_dev_attr_occ_master . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
if ( ( header - > ext_status & OCC_EXT_STAT_DVFS_OT ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_DVFS_OT ) ) {
name = sensor_dev_attr_occ_dvfs_overtemp . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
if ( ( header - > ext_status & OCC_EXT_STAT_DVFS_POWER ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_DVFS_POWER ) ) {
name = sensor_dev_attr_occ_dvfs_power . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
if ( ( header - > ext_status & OCC_EXT_STAT_MEM_THROTTLE ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_MEM_THROTTLE ) ) {
name = sensor_dev_attr_occ_mem_throttle . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
if ( ( header - > ext_status & OCC_EXT_STAT_QUICK_DROP ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_QUICK_DROP ) ) {
name = sensor_dev_attr_occ_quick_pwr_drop . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
2022-02-15 09:10:21 -06:00
if ( ( header - > ext_status & OCC_EXT_STAT_DVFS_VDD ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_DVFS_VDD ) ) {
name = sensor_dev_attr_occ_dvfs_vdd . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
if ( ( header - > ext_status & OCC_EXT_STAT_GPU_THROTTLE ) ! =
( occ - > prev_ext_stat & OCC_EXT_STAT_GPU_THROTTLE ) ) {
name = sensor_dev_attr_occ_gpu_throttle . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
2018-11-08 15:05:29 -06:00
if ( ( header - > status & OCC_STAT_MASTER ) & &
header - > occs_present ! = occ - > prev_occs_present ) {
name = sensor_dev_attr_occs_present . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
2022-02-15 09:10:19 -06:00
if ( header - > ips_status ! = occ - > prev_ips_status ) {
name = sensor_dev_attr_occ_ips_status . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
2022-02-15 09:10:20 -06:00
if ( header - > mode ! = occ - > prev_mode ) {
name = sensor_dev_attr_occ_mode . dev_attr . attr . name ;
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
2018-11-08 15:05:29 -06:00
if ( occ - > error & & occ - > error ! = occ - > prev_error ) {
2019-04-16 15:43:49 +00:00
name = dev_attr_occ_error . attr . name ;
2018-11-08 15:05:29 -06:00
sysfs_notify ( & occ - > bus_dev - > kobj , NULL , name ) ;
}
/* no notifications for OCC state; doesn't indicate error condition */
done :
occ - > prev_error = occ - > error ;
occ - > prev_stat = header - > status ;
occ - > prev_ext_stat = header - > ext_status ;
occ - > prev_occs_present = header - > occs_present ;
2022-02-15 09:10:19 -06:00
occ - > prev_ips_status = header - > ips_status ;
2022-02-15 09:10:20 -06:00
occ - > prev_mode = header - > mode ;
2018-11-08 15:05:29 -06:00
}
int occ_setup_sysfs ( struct occ * occ )
{
return sysfs_create_group ( & occ - > bus_dev - > kobj , & occ_sysfs ) ;
}
2022-04-27 09:04:43 -05:00
void occ_shutdown_sysfs ( struct occ * occ )
2018-11-08 15:05:29 -06:00
{
sysfs_remove_group ( & occ - > bus_dev - > kobj , & occ_sysfs ) ;
}