summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/lm77.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-08 11:31:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-08 11:31:16 -0700
commit3f17ea6dea8ba5668873afa54628a91aaa3fb1c0 (patch)
treeafbeb2accd4c2199ddd705ae943995b143a0af02 /drivers/hwmon/lm77.c
parent1860e379875dfe7271c649058aeddffe5afd9d0d (diff)
parent1a5700bc2d10cd379a795fd2bb377a190af5acd4 (diff)
Merge branch 'next' (accumulated 3.16 merge window patches) into master
Now that 3.15 is released, this merges the 'next' branch into 'master', bringing us to the normal situation where my 'master' branch is the merge window. * accumulated work in next: (6809 commits) ufs: sb mutex merge + mutex_destroy powerpc: update comments for generic idle conversion cris: update comments for generic idle conversion idle: remove cpu_idle() forward declarations nbd: zero from and len fields in NBD_CMD_DISCONNECT. mm: convert some level-less printks to pr_* MAINTAINERS: adi-buildroot-devel is moderated MAINTAINERS: add linux-api for review of API/ABI changes mm/kmemleak-test.c: use pr_fmt for logging fs/dlm/debug_fs.c: replace seq_printf by seq_puts fs/dlm/lockspace.c: convert simple_str to kstr fs/dlm/config.c: convert simple_str to kstr mm: mark remap_file_pages() syscall as deprecated mm: memcontrol: remove unnecessary memcg argument from soft limit functions mm: memcontrol: clean up memcg zoneinfo lookup mm/memblock.c: call kmemleak directly from memblock_(alloc|free) mm/mempool.c: update the kmemleak stack trace for mempool allocations lib/radix-tree.c: update the kmemleak stack trace for radix tree allocations mm: introduce kmemleak_update_trace() mm/kmemleak.c: use %u to print ->checksum ...
Diffstat (limited to 'drivers/hwmon/lm77.c')
-rw-r--r--drivers/hwmon/lm77.c374
1 files changed, 148 insertions, 226 deletions
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 502771c06fd..5ceb443b938 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -19,10 +19,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -47,50 +43,33 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
#define LM77_REG_TEMP_MIN 0x04
#define LM77_REG_TEMP_MAX 0x05
+enum temp_index {
+ t_input = 0,
+ t_crit,
+ t_min,
+ t_max,
+ t_hyst,
+ t_num_temp
+};
+
+static const u8 temp_regs[t_num_temp] = {
+ [t_input] = LM77_REG_TEMP,
+ [t_min] = LM77_REG_TEMP_MIN,
+ [t_max] = LM77_REG_TEMP_MAX,
+ [t_crit] = LM77_REG_TEMP_CRIT,
+ [t_hyst] = LM77_REG_TEMP_HYST,
+};
+
/* Each client has this additional data */
struct lm77_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
- int temp_input; /* Temperatures */
- int temp_crit;
- int temp_min;
- int temp_max;
- int temp_hyst;
+ int temp[t_num_temp]; /* index using temp_index */
u8 alarms;
};
-static int lm77_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm77_init_client(struct i2c_client *client);
-static int lm77_remove(struct i2c_client *client);
-static u16 lm77_read_value(struct i2c_client *client, u8 reg);
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
-
-static struct lm77_data *lm77_update_device(struct device *dev);
-
-
-static const struct i2c_device_id lm77_id[] = {
- { "lm77", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, lm77_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver lm77_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "lm77",
- },
- .probe = lm77_probe,
- .remove = lm77_remove,
- .id_table = lm77_id,
- .detect = lm77_detect,
- .address_list = normal_i2c,
-};
-
/* straight from the datasheet */
#define LM77_TEMP_MIN (-55000)
#define LM77_TEMP_MAX 125000
@@ -110,97 +89,109 @@ static inline int LM77_TEMP_FROM_REG(s16 reg)
return (reg / 8) * 500;
}
-/* sysfs stuff */
-
-/* read routines for temperature limits */
-#define show(value) \
-static ssize_t show_##value(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct lm77_data *data = lm77_update_device(dev); \
- return sprintf(buf, "%d\n", data->value); \
+/*
+ * All registers are word-sized, except for the configuration register.
+ * The LM77 uses the high-byte first convention.
+ */
+static u16 lm77_read_value(struct i2c_client *client, u8 reg)
+{
+ if (reg == LM77_REG_CONF)
+ return i2c_smbus_read_byte_data(client, reg);
+ else
+ return i2c_smbus_read_word_swapped(client, reg);
}
-show(temp_input);
-show(temp_crit);
-show(temp_min);
-show(temp_max);
+static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+ if (reg == LM77_REG_CONF)
+ return i2c_smbus_write_byte_data(client, reg, value);
+ else
+ return i2c_smbus_write_word_swapped(client, reg, value);
+}
-/* read routines for hysteresis values */
-static ssize_t show_temp_crit_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+static struct lm77_data *lm77_update_device(struct device *dev)
{
- struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst);
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ dev_dbg(&client->dev, "Starting lm77 update\n");
+ for (i = 0; i < t_num_temp; i++) {
+ data->temp[i] =
+ LM77_TEMP_FROM_REG(lm77_read_value(client,
+ temp_regs[i]));
+ }
+ data->alarms =
+ lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
}
-static ssize_t show_temp_min_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+/* sysfs stuff */
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst);
+
+ return sprintf(buf, "%d\n", data->temp[attr->index]);
}
-static ssize_t show_temp_max_hyst(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t show_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm77_data *data = lm77_update_device(dev);
- return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst);
-}
+ int nr = attr->index;
+ int temp;
-/* write routines */
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm77_data *data = i2c_get_clientdata(client); \
- long val; \
- int err = kstrtol(buf, 10, &val); \
- if (err) \
- return err; \
- \
- mutex_lock(&data->update_lock); \
- data->value = val; \
- lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \
- mutex_unlock(&data->update_lock); \
- return count; \
-}
+ temp = nr == t_min ? data->temp[nr] + data->temp[t_hyst] :
+ data->temp[nr] - data->temp[t_hyst];
-set(temp_min, LM77_REG_TEMP_MIN);
-set(temp_max, LM77_REG_TEMP_MAX);
+ return sprintf(buf, "%d\n", temp);
+}
-/*
- * hysteresis is stored as a relative value on the chip, so it has to be
- * converted first
- */
-static ssize_t set_temp_crit_hyst(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
- unsigned long val;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int nr = attr->index;
+ long val;
int err;
- err = kstrtoul(buf, 10, &val);
+ err = kstrtol(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock);
- data->temp_hyst = data->temp_crit - val;
- lm77_write_value(client, LM77_REG_TEMP_HYST,
- LM77_TEMP_TO_REG(data->temp_hyst));
+ data->temp[nr] = val;
+ lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
mutex_unlock(&data->update_lock);
return count;
}
-/* preserve hysteresis when setting T_crit */
-static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+/*
+ * hysteresis is stored as a relative value on the chip, so it has to be
+ * converted first.
+ */
+static ssize_t set_temp_hyst(struct device *dev,
+ struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
- int oldcrithyst;
+ struct lm77_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int err;
@@ -209,13 +200,9 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- oldcrithyst = data->temp_crit - data->temp_hyst;
- data->temp_crit = val;
- data->temp_hyst = data->temp_crit - oldcrithyst;
- lm77_write_value(client, LM77_REG_TEMP_CRIT,
- LM77_TEMP_TO_REG(data->temp_crit));
+ data->temp[t_hyst] = data->temp[t_crit] - val;
lm77_write_value(client, LM77_REG_TEMP_HYST,
- LM77_TEMP_TO_REG(data->temp_hyst));
+ LM77_TEMP_TO_REG(data->temp[t_hyst]));
mutex_unlock(&data->update_lock);
return count;
}
@@ -228,43 +215,37 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
-static DEVICE_ATTR(temp1_input, S_IRUGO,
- show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
- show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
- show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
- show_temp_max, set_temp_max);
-
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
- show_temp_crit_hyst, set_temp_crit_hyst);
-static DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
- show_temp_min_hyst, NULL);
-static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
- show_temp_max_hyst, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp,
+ t_max);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst,
+ set_temp_hyst, t_crit);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_hyst, NULL, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
-static struct attribute *lm77_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_crit_hyst.attr,
- &dev_attr_temp1_min_hyst.attr,
- &dev_attr_temp1_max_hyst.attr,
+static struct attribute *lm77_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group lm77_group = {
- .attrs = lm77_attributes,
-};
+ATTRIBUTE_GROUPS(lm77);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
@@ -337,111 +318,52 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info)
return 0;
}
+static void lm77_init_client(struct i2c_client *client)
+{
+ /* Initialize the LM77 chip - turn off shutdown mode */
+ int conf = lm77_read_value(client, LM77_REG_CONF);
+ if (conf & 1)
+ lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
+}
+
static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct lm77_data *data;
- int err;
data = devm_kzalloc(dev, sizeof(struct lm77_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM77 chip */
lm77_init_client(client);
- /* Register sysfs hooks */
- err = sysfs_create_group(&dev->kobj, &lm77_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- return 0;
-
-exit_remove:
- sysfs_remove_group(&dev->kobj, &lm77_group);
- return err;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, lm77_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static int lm77_remove(struct i2c_client *client)
-{
- struct lm77_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm77_group);
- return 0;
-}
-
-/*
- * All registers are word-sized, except for the configuration register.
- * The LM77 uses the high-byte first convention.
- */
-static u16 lm77_read_value(struct i2c_client *client, u8 reg)
-{
- if (reg == LM77_REG_CONF)
- return i2c_smbus_read_byte_data(client, reg);
- else
- return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
- if (reg == LM77_REG_CONF)
- return i2c_smbus_write_byte_data(client, reg, value);
- else
- return i2c_smbus_write_word_swapped(client, reg, value);
-}
-
-static void lm77_init_client(struct i2c_client *client)
-{
- /* Initialize the LM77 chip - turn off shutdown mode */
- int conf = lm77_read_value(client, LM77_REG_CONF);
- if (conf & 1)
- lm77_write_value(client, LM77_REG_CONF, conf & 0xfe);
-}
-
-static struct lm77_data *lm77_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm77_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
- dev_dbg(&client->dev, "Starting lm77 update\n");
- data->temp_input =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP));
- data->temp_hyst =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_HYST));
- data->temp_crit =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_CRIT));
- data->temp_min =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_MIN));
- data->temp_max =
- LM77_TEMP_FROM_REG(lm77_read_value(client,
- LM77_REG_TEMP_MAX));
- data->alarms =
- lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
- data->last_updated = jiffies;
- data->valid = 1;
- }
-
- mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm77_id[] = {
+ { "lm77", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm77_id);
- return data;
-}
+/* This is the driver that will be inserted */
+static struct i2c_driver lm77_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "lm77",
+ },
+ .probe = lm77_probe,
+ .id_table = lm77_id,
+ .detect = lm77_detect,
+ .address_list = normal_i2c,
+};
module_i2c_driver(lm77_driver);