aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChris Verges <kg4ysn@gmail.com>2013-01-05 04:41:19 -0500
committerGuenter Roeck <linux@roeck-us.net>2013-02-06 12:57:57 -0500
commit8c14d126ae2efbcd094b24e5413b8cbe1d2c01e4 (patch)
treeac4ee5056c7889dda4a08d248f655f8b43e10c6b /drivers
parent91bba688016be0ba87ecb9d80d6490c2ebc63b0d (diff)
hwmon: (lm73) Add 'update_interval' attribute
The LM73 supports four A/D conversion resolutions. The default used by the existing lm73 driver is the chip's default, 11-bit (0.25 C/LSB). This patch enables changing of this resolution from userspace via the update_interval sysfs attribute. Full details on usage are included in Documentation/hwmon/lm73. Signed-off-by: Chris Verges <kg4ysn@gmail.com> [linux@roeck-us.net: cleanup] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/lm73.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
index dad83fea807d..0b19f03950e0 100644
--- a/drivers/hwmon/lm73.c
+++ b/drivers/hwmon/lm73.c
@@ -39,8 +39,24 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
39#define LM73_TEMP_MIN (-256000 / 250) 39#define LM73_TEMP_MIN (-256000 / 250)
40#define LM73_TEMP_MAX (255750 / 250) 40#define LM73_TEMP_MAX (255750 / 250)
41 41
42/*-----------------------------------------------------------------------*/ 42#define LM73_CTRL_RES_SHIFT 5
43#define LM73_CTRL_RES_MASK (BIT(5) | BIT(6))
44#define LM73_CTRL_TO_MASK BIT(7)
45
46static const unsigned short lm73_convrates[] = {
47 14, /* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
48 28, /* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
49 56, /* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
50 112, /* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
51};
52
53struct lm73_data {
54 struct device *hwmon_dev;
55 struct mutex lock;
56 u8 ctrl; /* control register value */
57};
43 58
59/*-----------------------------------------------------------------------*/
44 60
45static ssize_t set_temp(struct device *dev, struct device_attribute *da, 61static ssize_t set_temp(struct device *dev, struct device_attribute *da,
46 const char *buf, size_t count) 62 const char *buf, size_t count)
@@ -78,6 +94,51 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
78 return scnprintf(buf, PAGE_SIZE, "%d\n", temp); 94 return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
79} 95}
80 96
97static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
98 const char *buf, size_t count)
99{
100 struct i2c_client *client = to_i2c_client(dev);
101 struct lm73_data *data = i2c_get_clientdata(client);
102 unsigned long convrate;
103 s32 err;
104 int res = 0;
105
106 err = kstrtoul(buf, 10, &convrate);
107 if (err < 0)
108 return err;
109
110 /*
111 * Convert the desired conversion rate into register bits.
112 * res is already initialized, and everything past the second-to-last
113 * value in the array is treated as belonging to the last value
114 * in the array.
115 */
116 while (res < (ARRAY_SIZE(lm73_convrates) - 1) &&
117 convrate > lm73_convrates[res])
118 res++;
119
120 mutex_lock(&data->lock);
121 data->ctrl &= LM73_CTRL_TO_MASK;
122 data->ctrl |= res << LM73_CTRL_RES_SHIFT;
123 err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl);
124 mutex_unlock(&data->lock);
125
126 if (err < 0)
127 return err;
128
129 return count;
130}
131
132static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
133 char *buf)
134{
135 struct i2c_client *client = to_i2c_client(dev);
136 struct lm73_data *data = i2c_get_clientdata(client);
137 int res;
138
139 res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
140 return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
141}
81 142
82/*-----------------------------------------------------------------------*/ 143/*-----------------------------------------------------------------------*/
83 144
@@ -89,13 +150,14 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
89 show_temp, set_temp, LM73_REG_MIN); 150 show_temp, set_temp, LM73_REG_MIN);
90static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, 151static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
91 show_temp, NULL, LM73_REG_INPUT); 152 show_temp, NULL, LM73_REG_INPUT);
92 153static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
154 show_convrate, set_convrate, 0);
93 155
94static struct attribute *lm73_attributes[] = { 156static struct attribute *lm73_attributes[] = {
95 &sensor_dev_attr_temp1_input.dev_attr.attr, 157 &sensor_dev_attr_temp1_input.dev_attr.attr,
96 &sensor_dev_attr_temp1_max.dev_attr.attr, 158 &sensor_dev_attr_temp1_max.dev_attr.attr,
97 &sensor_dev_attr_temp1_min.dev_attr.attr, 159 &sensor_dev_attr_temp1_min.dev_attr.attr,
98 160 &sensor_dev_attr_update_interval.dev_attr.attr,
99 NULL 161 NULL
100}; 162};
101 163
@@ -110,23 +172,36 @@ static const struct attribute_group lm73_group = {
110static int 172static int
111lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) 173lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
112{ 174{
113 struct device *hwmon_dev;
114 int status; 175 int status;
176 struct lm73_data *data;
177 int ctrl;
178
179 data = devm_kzalloc(&client->dev, sizeof(struct lm73_data),
180 GFP_KERNEL);
181 if (!data)
182 return -ENOMEM;
183
184 i2c_set_clientdata(client, data);
185 mutex_init(&data->lock);
186
187 ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
188 if (ctrl < 0)
189 return ctrl;
190 data->ctrl = ctrl;
115 191
116 /* Register sysfs hooks */ 192 /* Register sysfs hooks */
117 status = sysfs_create_group(&client->dev.kobj, &lm73_group); 193 status = sysfs_create_group(&client->dev.kobj, &lm73_group);
118 if (status) 194 if (status)
119 return status; 195 return status;
120 196
121 hwmon_dev = hwmon_device_register(&client->dev); 197 data->hwmon_dev = hwmon_device_register(&client->dev);
122 if (IS_ERR(hwmon_dev)) { 198 if (IS_ERR(data->hwmon_dev)) {
123 status = PTR_ERR(hwmon_dev); 199 status = PTR_ERR(data->hwmon_dev);
124 goto exit_remove; 200 goto exit_remove;
125 } 201 }
126 i2c_set_clientdata(client, hwmon_dev);
127 202
128 dev_info(&client->dev, "%s: sensor '%s'\n", 203 dev_info(&client->dev, "%s: sensor '%s'\n",
129 dev_name(hwmon_dev), client->name); 204 dev_name(data->hwmon_dev), client->name);
130 205
131 return 0; 206 return 0;
132 207
@@ -137,9 +212,9 @@ exit_remove:
137 212
138static int lm73_remove(struct i2c_client *client) 213static int lm73_remove(struct i2c_client *client)
139{ 214{
140 struct device *hwmon_dev = i2c_get_clientdata(client); 215 struct lm73_data *data = i2c_get_clientdata(client);
141 216
142 hwmon_device_unregister(hwmon_dev); 217 hwmon_device_unregister(data->hwmon_dev);
143 sysfs_remove_group(&client->dev.kobj, &lm73_group); 218 sysfs_remove_group(&client->dev.kobj, &lm73_group);
144 return 0; 219 return 0;
145} 220}