hwmon: (lm90) Add support for update_interval sysfs attribute
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
committed by
Jean Delvare
parent
1179324c41
commit
0c01b644f7
@@ -151,6 +151,9 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
|
|||||||
#define MAX6659_REG_R_LOCAL_EMERG 0x17
|
#define MAX6659_REG_R_LOCAL_EMERG 0x17
|
||||||
#define MAX6659_REG_W_LOCAL_EMERG 0x17
|
#define MAX6659_REG_W_LOCAL_EMERG 0x17
|
||||||
|
|
||||||
|
#define LM90_DEF_CONVRATE_RVAL 6 /* Def conversion rate register value */
|
||||||
|
#define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Device flags
|
* Device flags
|
||||||
*/
|
*/
|
||||||
@@ -197,6 +200,7 @@ struct lm90_params {
|
|||||||
u32 flags; /* Capabilities */
|
u32 flags; /* Capabilities */
|
||||||
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
|
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
|
||||||
/* Upper 8 bits for max6695/96 */
|
/* Upper 8 bits for max6695/96 */
|
||||||
|
u8 max_convrate; /* Maximum conversion rate register value */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct lm90_params lm90_params[] = {
|
static const struct lm90_params lm90_params[] = {
|
||||||
@@ -204,48 +208,59 @@ static const struct lm90_params lm90_params[] = {
|
|||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
|
||||||
| LM90_HAVE_BROKEN_ALERT,
|
| LM90_HAVE_BROKEN_ALERT,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 10,
|
||||||
},
|
},
|
||||||
[adt7461] = {
|
[adt7461] = {
|
||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
|
||||||
| LM90_HAVE_BROKEN_ALERT,
|
| LM90_HAVE_BROKEN_ALERT,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 10,
|
||||||
},
|
},
|
||||||
[lm86] = {
|
[lm86] = {
|
||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
||||||
.alert_alarms = 0x7b,
|
.alert_alarms = 0x7b,
|
||||||
|
.max_convrate = 9,
|
||||||
},
|
},
|
||||||
[lm90] = {
|
[lm90] = {
|
||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
||||||
.alert_alarms = 0x7b,
|
.alert_alarms = 0x7b,
|
||||||
|
.max_convrate = 9,
|
||||||
},
|
},
|
||||||
[lm99] = {
|
[lm99] = {
|
||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
||||||
.alert_alarms = 0x7b,
|
.alert_alarms = 0x7b,
|
||||||
|
.max_convrate = 9,
|
||||||
},
|
},
|
||||||
[max6646] = {
|
[max6646] = {
|
||||||
.flags = LM90_HAVE_LOCAL_EXT,
|
.flags = LM90_HAVE_LOCAL_EXT,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 6,
|
||||||
},
|
},
|
||||||
[max6657] = {
|
[max6657] = {
|
||||||
.flags = LM90_HAVE_LOCAL_EXT,
|
.flags = LM90_HAVE_LOCAL_EXT,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 8,
|
||||||
},
|
},
|
||||||
[max6659] = {
|
[max6659] = {
|
||||||
.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
|
.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 8,
|
||||||
},
|
},
|
||||||
[max6680] = {
|
[max6680] = {
|
||||||
.flags = LM90_HAVE_OFFSET,
|
.flags = LM90_HAVE_OFFSET,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 7,
|
||||||
},
|
},
|
||||||
[max6696] = {
|
[max6696] = {
|
||||||
.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
|
.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
|
||||||
| LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
|
| LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
|
||||||
.alert_alarms = 0x187c,
|
.alert_alarms = 0x187c,
|
||||||
|
.max_convrate = 6,
|
||||||
},
|
},
|
||||||
[w83l771] = {
|
[w83l771] = {
|
||||||
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
|
||||||
.alert_alarms = 0x7c,
|
.alert_alarms = 0x7c,
|
||||||
|
.max_convrate = 8,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,9 +276,13 @@ struct lm90_data {
|
|||||||
int kind;
|
int kind;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
|
||||||
|
int update_interval; /* in milliseconds */
|
||||||
|
|
||||||
u8 config_orig; /* Original configuration register value */
|
u8 config_orig; /* Original configuration register value */
|
||||||
|
u8 convrate_orig; /* Original conversion rate register value */
|
||||||
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
|
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
|
||||||
/* Upper 8 bits for max6695/96 */
|
/* Upper 8 bits for max6695/96 */
|
||||||
|
u8 max_convrate; /* Maximum conversion rate */
|
||||||
|
|
||||||
/* registers values */
|
/* registers values */
|
||||||
s8 temp8[8]; /* 0: local low limit
|
s8 temp8[8]; /* 0: local low limit
|
||||||
@@ -385,15 +404,41 @@ static inline void lm90_select_remote_channel(struct i2c_client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set conversion rate.
|
||||||
|
* client->update_lock must be held when calling this function (unless we are
|
||||||
|
* in detection or initialization steps).
|
||||||
|
*/
|
||||||
|
static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
|
||||||
|
unsigned int interval)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int update_interval;
|
||||||
|
|
||||||
|
/* Shift calculations to avoid rounding errors */
|
||||||
|
interval <<= 6;
|
||||||
|
|
||||||
|
/* find the nearest update rate */
|
||||||
|
for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
|
||||||
|
i < data->max_convrate; i++, update_interval >>= 1)
|
||||||
|
if (interval >= update_interval * 3 / 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
|
||||||
|
data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
|
||||||
|
}
|
||||||
|
|
||||||
static struct lm90_data *lm90_update_device(struct device *dev)
|
static struct lm90_data *lm90_update_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm90_data *data = i2c_get_clientdata(client);
|
struct lm90_data *data = i2c_get_clientdata(client);
|
||||||
|
unsigned long next_update;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
|
next_update = data->last_updated
|
||||||
|| !data->valid) {
|
+ msecs_to_jiffies(data->update_interval) + 1;
|
||||||
|
if (time_after(jiffies, next_update) || !data->valid) {
|
||||||
u8 h, l;
|
u8 h, l;
|
||||||
u8 alarms;
|
u8 alarms;
|
||||||
|
|
||||||
@@ -828,6 +873,34 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute
|
|||||||
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
|
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t show_update_interval(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct lm90_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%u\n", data->update_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_update_interval(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct lm90_data *data = i2c_get_clientdata(client);
|
||||||
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = strict_strtoul(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
lm90_set_convrate(client, data, val);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4);
|
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4);
|
||||||
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0);
|
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0);
|
||||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
|
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
|
||||||
@@ -859,6 +932,9 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
|||||||
/* Raw alarm file for compatibility */
|
/* Raw alarm file for compatibility */
|
||||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||||
|
|
||||||
|
static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
|
||||||
|
set_update_interval);
|
||||||
|
|
||||||
static struct attribute *lm90_attributes[] = {
|
static struct attribute *lm90_attributes[] = {
|
||||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||||
@@ -879,6 +955,7 @@ static struct attribute *lm90_attributes[] = {
|
|||||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||||
&dev_attr_alarms.attr,
|
&dev_attr_alarms.attr,
|
||||||
|
&dev_attr_update_interval.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1198,14 +1275,19 @@ static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data)
|
|||||||
|
|
||||||
static void lm90_init_client(struct i2c_client *client)
|
static void lm90_init_client(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
u8 config;
|
u8 config, convrate;
|
||||||
struct lm90_data *data = i2c_get_clientdata(client);
|
struct lm90_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
|
||||||
|
dev_warn(&client->dev, "Failed to read convrate register!\n");
|
||||||
|
convrate = LM90_DEF_CONVRATE_RVAL;
|
||||||
|
}
|
||||||
|
data->convrate_orig = convrate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start the conversions.
|
* Start the conversions.
|
||||||
*/
|
*/
|
||||||
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
|
lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
|
||||||
5); /* 2 Hz */
|
|
||||||
if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
|
if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
|
||||||
dev_warn(&client->dev, "Initialization failed!\n");
|
dev_warn(&client->dev, "Initialization failed!\n");
|
||||||
return;
|
return;
|
||||||
@@ -1266,6 +1348,9 @@ static int lm90_probe(struct i2c_client *new_client,
|
|||||||
/* Set chip capabilities */
|
/* Set chip capabilities */
|
||||||
data->flags = lm90_params[data->kind].flags;
|
data->flags = lm90_params[data->kind].flags;
|
||||||
|
|
||||||
|
/* Set maximum conversion rate */
|
||||||
|
data->max_convrate = lm90_params[data->kind].max_convrate;
|
||||||
|
|
||||||
/* Initialize the LM90 chip */
|
/* Initialize the LM90 chip */
|
||||||
lm90_init_client(new_client);
|
lm90_init_client(new_client);
|
||||||
|
|
||||||
@@ -1327,6 +1412,8 @@ static int lm90_remove(struct i2c_client *client)
|
|||||||
lm90_remove_files(client, data);
|
lm90_remove_files(client, data);
|
||||||
|
|
||||||
/* Restore initial configuration */
|
/* Restore initial configuration */
|
||||||
|
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
|
||||||
|
data->convrate_orig);
|
||||||
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
|
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
|
||||||
data->config_orig);
|
data->config_orig);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user