summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/hwmon/Kconfig1
-rw-r--r--drivers/hwmon/lm83.c176
2 files changed, 112 insertions, 65 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8df25f1079ba..01ab80a2cc4a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1288,6 +1288,7 @@ config SENSORS_LM80
config SENSORS_LM83
tristate "National Semiconductor LM83 and compatibles"
depends on I2C
+ select REGMAP
help
If you say yes here you get support for National Semiconductor
LM82 and LM83 sensor chips.
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index fdd89cc481fa..c9605957e400 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -21,11 +21,11 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
@@ -77,7 +77,7 @@ enum chips { lm83, lm82 };
(val) < 0 ? ((val) - 500) / 1000 : \
((val) + 500) / 1000)
-static const u8 LM83_REG_R_TEMP[] = {
+static const u8 LM83_REG_TEMP[] = {
LM83_REG_R_LOCAL_TEMP,
LM83_REG_R_REMOTE1_TEMP,
LM83_REG_R_REMOTE2_TEMP,
@@ -89,62 +89,82 @@ static const u8 LM83_REG_R_TEMP[] = {
LM83_REG_R_TCRIT,
};
-static const u8 LM83_REG_W_HIGH[] = {
- LM83_REG_W_LOCAL_HIGH,
- LM83_REG_W_REMOTE1_HIGH,
- LM83_REG_W_REMOTE2_HIGH,
- LM83_REG_W_REMOTE3_HIGH,
- LM83_REG_W_TCRIT,
-};
-
/*
* Client data (each client gets its own)
*/
struct lm83_data {
- struct i2c_client *client;
+ struct regmap *regmap;
const struct attribute_group *groups[3];
- struct mutex update_lock;
- bool valid; /* false until following fields are valid */
- unsigned long last_updated; /* in jiffies */
-
- /* registers values */
- s8 temp[9]; /* 0..3: input 1-4,
- 4..7: high limit 1-4,
- 8 : critical limit */
- u16 alarms; /* bitvector, combined */
};
-static struct lm83_data *lm83_update_device(struct device *dev)
+/* regmap code */
+
+static int lm83_regmap_reg_read(void *context, unsigned int reg, unsigned int *val)
{
- struct lm83_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
- int nr;
-
- dev_dbg(&client->dev, "Updating lm83 data.\n");
- for (nr = 0; nr < 9; nr++) {
- data->temp[nr] =
- i2c_smbus_read_byte_data(client,
- LM83_REG_R_TEMP[nr]);
- }
- data->alarms =
- i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
- + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
- << 8);
-
- data->last_updated = jiffies;
- data->valid = true;
+ struct i2c_client *client = context;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return 0;
+}
+
+/*
+ * The regmap write function maps read register addresses to write register
+ * addresses. This is necessary for regmap register caching to work.
+ * An alternative would be to clear the regmap cache whenever a register is
+ * written, but that would be much more expensive.
+ */
+static int lm83_regmap_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *client = context;
+
+ switch (reg) {
+ case LM83_REG_R_CONFIG:
+ case LM83_REG_R_LOCAL_HIGH:
+ case LM83_REG_R_REMOTE2_HIGH:
+ reg += 0x06;
+ break;
+ case LM83_REG_R_REMOTE1_HIGH:
+ case LM83_REG_R_REMOTE3_HIGH:
+ case LM83_REG_R_TCRIT:
+ reg += 0x18;
+ break;
+ default:
+ break;
}
- mutex_unlock(&data->update_lock);
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
- return data;
+static bool lm83_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LM83_REG_R_LOCAL_TEMP:
+ case LM83_REG_R_REMOTE1_TEMP:
+ case LM83_REG_R_REMOTE2_TEMP:
+ case LM83_REG_R_REMOTE3_TEMP:
+ case LM83_REG_R_STATUS1:
+ case LM83_REG_R_STATUS2:
+ return true;
+ default:
+ return false;
+ }
}
+static const struct regmap_config lm83_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = lm83_regmap_is_volatile,
+ .reg_read = lm83_regmap_reg_read,
+ .reg_write = lm83_regmap_reg_write,
+};
+
/*
* Sysfs stuff
*/
@@ -153,8 +173,15 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct lm83_data *data = lm83_update_device(dev);
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+ struct lm83_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(data->regmap, LM83_REG_TEMP[attr->index], &regval);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG((s8)regval));
}
static ssize_t temp_store(struct device *dev,
@@ -163,38 +190,57 @@ static ssize_t temp_store(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm83_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
+ unsigned int regval;
long val;
- int nr = attr->index;
int err;
err = kstrtol(buf, 10, &val);
if (err < 0)
return err;
- mutex_lock(&data->update_lock);
- data->temp[nr] = TEMP_TO_REG(val);
- i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
- data->temp[nr]);
- mutex_unlock(&data->update_lock);
- return count;
+ regval = TEMP_TO_REG(val);
+ err = regmap_write(data->regmap, LM83_REG_TEMP[attr->index], regval);
+ return err ? : count;
}
static ssize_t alarms_show(struct device *dev, struct device_attribute *dummy,
char *buf)
{
- struct lm83_data *data = lm83_update_device(dev);
- return sprintf(buf, "%d\n", data->alarms);
+ struct lm83_data *data = dev_get_drvdata(dev);
+ unsigned int alarms, regval;
+ int err;
+
+ err = regmap_read(data->regmap, LM83_REG_R_STATUS1, &regval);
+ if (err < 0)
+ return err;
+ alarms = regval;
+ err = regmap_read(data->regmap, LM83_REG_R_STATUS2, &regval);
+ if (err < 0)
+ return err;
+ alarms |= regval << 8;
+
+ return sprintf(buf, "%u\n", alarms);
}
static ssize_t alarm_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct lm83_data *data = lm83_update_device(dev);
+ struct lm83_data *data = dev_get_drvdata(dev);
int bitnr = attr->index;
-
- return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+ unsigned int alarm;
+ int reg, err;
+
+ if (bitnr < 8) {
+ reg = LM83_REG_R_STATUS1;
+ } else {
+ reg = LM83_REG_R_STATUS2;
+ bitnr -= 8;
+ }
+ err = regmap_read(data->regmap, reg, &alarm);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "%d\n", (alarm >> bitnr) & 1);
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
@@ -326,16 +372,17 @@ MODULE_DEVICE_TABLE(i2c, lm83_id);
static int lm83_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct device *hwmon_dev;
struct lm83_data *data;
- data = devm_kzalloc(&client->dev, sizeof(struct lm83_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm83_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->client = client;
- mutex_init(&data->update_lock);
+ data->regmap = devm_regmap_init(dev, NULL, client, &lm83_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
/*
* Register sysfs hooks
@@ -347,8 +394,7 @@ static int lm83_probe(struct i2c_client *client)
if (i2c_match_id(lm83_id, client)->driver_data == lm83)
data->groups[1] = &lm83_group_opt;
- hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
- client->name,
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, data->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}