Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c01b644 authored by Guenter Roeck's avatar Guenter Roeck Committed by Jean Delvare
Browse files

hwmon: (lm90) Add support for update_interval sysfs attribute

parent 1179324c
Loading
Loading
Loading
Loading
+92 −5
Original line number Diff line number Diff line
@@ -151,6 +151,9 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
#define MAX6659_REG_R_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
 */
@@ -197,6 +200,7 @@ struct lm90_params {
	u32 flags;		/* Capabilities */
	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
				/* Upper 8 bits for max6695/96 */
	u8 max_convrate;	/* Maximum conversion rate register value */
};

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
		  | LM90_HAVE_BROKEN_ALERT,
		.alert_alarms = 0x7c,
		.max_convrate = 10,
	},
	[adt7461] = {
		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
		  | LM90_HAVE_BROKEN_ALERT,
		.alert_alarms = 0x7c,
		.max_convrate = 10,
	},
	[lm86] = {
		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
		.alert_alarms = 0x7b,
		.max_convrate = 9,
	},
	[lm90] = {
		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
		.alert_alarms = 0x7b,
		.max_convrate = 9,
	},
	[lm99] = {
		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
		.alert_alarms = 0x7b,
		.max_convrate = 9,
	},
	[max6646] = {
		.flags = LM90_HAVE_LOCAL_EXT,
		.alert_alarms = 0x7c,
		.max_convrate = 6,
	},
	[max6657] = {
		.flags = LM90_HAVE_LOCAL_EXT,
		.alert_alarms = 0x7c,
		.max_convrate = 8,
	},
	[max6659] = {
		.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
		.alert_alarms = 0x7c,
		.max_convrate = 8,
	},
	[max6680] = {
		.flags = LM90_HAVE_OFFSET,
		.alert_alarms = 0x7c,
		.max_convrate = 7,
	},
	[max6696] = {
		.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
		.alert_alarms = 0x187c,
		.max_convrate = 6,
	},
	[w83l771] = {
		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
		.alert_alarms = 0x7c,
		.max_convrate = 8,
	},
};

@@ -261,9 +276,13 @@ struct lm90_data {
	int kind;
	u32 flags;

	int update_interval;	/* in milliseconds */

	u8 config_orig;		/* Original configuration register value */
	u8 convrate_orig;	/* Original conversion rate register value */
	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
				/* Upper 8 bits for max6695/96 */
	u8 max_convrate;	/* Maximum conversion rate */

	/* registers values */
	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)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct lm90_data *data = i2c_get_clientdata(client);
	unsigned long next_update;

	mutex_lock(&data->update_lock);

	if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
	 || !data->valid) {
	next_update = data->last_updated
	  + msecs_to_jiffies(data->update_interval) + 1;
	if (time_after(jiffies, next_update) || !data->valid) {
		u8 h, l;
		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);
}

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(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0);
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 */
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[] = {
	&sensor_dev_attr_temp1_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_max_alarm.dev_attr.attr,
	&dev_attr_alarms.attr,
	&dev_attr_update_interval.attr,
	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)
{
	u8 config;
	u8 config, convrate;
	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.
	 */
	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
				  5); /* 2 Hz */
	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
		dev_warn(&client->dev, "Initialization failed!\n");
		return;
@@ -1266,6 +1348,9 @@ static int lm90_probe(struct i2c_client *new_client,
	/* Set chip capabilities */
	data->flags = lm90_params[data->kind].flags;

	/* Set maximum conversion rate */
	data->max_convrate = lm90_params[data->kind].max_convrate;

	/* Initialize the LM90 chip */
	lm90_init_client(new_client);

@@ -1327,6 +1412,8 @@ static int lm90_remove(struct i2c_client *client)
	lm90_remove_files(client, data);

	/* 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,
				  data->config_orig);