aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/smsc47b397.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/smsc47b397.c')
-rw-r--r--drivers/hwmon/smsc47b397.c228
1 files changed, 134 insertions, 94 deletions
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 72b0e2d8650c..943abbd95ab5 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -30,16 +30,17 @@
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/ioport.h> 31#include <linux/ioport.h>
32#include <linux/jiffies.h> 32#include <linux/jiffies.h>
33#include <linux/i2c.h> 33#include <linux/platform_device.h>
34#include <linux/i2c-isa.h>
35#include <linux/hwmon.h> 34#include <linux/hwmon.h>
35#include <linux/hwmon-sysfs.h>
36#include <linux/err.h> 36#include <linux/err.h>
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/mutex.h> 38#include <linux/mutex.h>
39#include <asm/io.h> 39#include <asm/io.h>
40 40
41/* Address is autodetected, there is no default value */ 41static struct platform_device *pdev;
42static unsigned short address; 42
43#define DRVNAME "smsc47b397"
43 44
44/* Super-I/0 registers and commands */ 45/* Super-I/0 registers and commands */
45 46
@@ -91,7 +92,8 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
91#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) 92#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr))
92 93
93struct smsc47b397_data { 94struct smsc47b397_data {
94 struct i2c_client client; 95 unsigned short addr;
96 const char *name;
95 struct class_device *class_dev; 97 struct class_device *class_dev;
96 struct mutex lock; 98 struct mutex lock;
97 99
@@ -104,45 +106,43 @@ struct smsc47b397_data {
104 u8 temp[4]; 106 u8 temp[4];
105}; 107};
106 108
107static int smsc47b397_read_value(struct i2c_client *client, u8 reg) 109static int smsc47b397_read_value(struct smsc47b397_data* data, u8 reg)
108{ 110{
109 struct smsc47b397_data *data = i2c_get_clientdata(client);
110 int res; 111 int res;
111 112
112 mutex_lock(&data->lock); 113 mutex_lock(&data->lock);
113 outb(reg, client->addr); 114 outb(reg, data->addr);
114 res = inb_p(client->addr + 1); 115 res = inb_p(data->addr + 1);
115 mutex_unlock(&data->lock); 116 mutex_unlock(&data->lock);
116 return res; 117 return res;
117} 118}
118 119
119static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) 120static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
120{ 121{
121 struct i2c_client *client = to_i2c_client(dev); 122 struct smsc47b397_data *data = dev_get_drvdata(dev);
122 struct smsc47b397_data *data = i2c_get_clientdata(client);
123 int i; 123 int i;
124 124
125 mutex_lock(&data->update_lock); 125 mutex_lock(&data->update_lock);
126 126
127 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { 127 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
128 dev_dbg(&client->dev, "starting device update...\n"); 128 dev_dbg(dev, "starting device update...\n");
129 129
130 /* 4 temperature inputs, 4 fan inputs */ 130 /* 4 temperature inputs, 4 fan inputs */
131 for (i = 0; i < 4; i++) { 131 for (i = 0; i < 4; i++) {
132 data->temp[i] = smsc47b397_read_value(client, 132 data->temp[i] = smsc47b397_read_value(data,
133 SMSC47B397_REG_TEMP(i)); 133 SMSC47B397_REG_TEMP(i));
134 134
135 /* must read LSB first */ 135 /* must read LSB first */
136 data->fan[i] = smsc47b397_read_value(client, 136 data->fan[i] = smsc47b397_read_value(data,
137 SMSC47B397_REG_FAN_LSB(i)); 137 SMSC47B397_REG_FAN_LSB(i));
138 data->fan[i] |= smsc47b397_read_value(client, 138 data->fan[i] |= smsc47b397_read_value(data,
139 SMSC47B397_REG_FAN_MSB(i)) << 8; 139 SMSC47B397_REG_FAN_MSB(i)) << 8;
140 } 140 }
141 141
142 data->last_updated = jiffies; 142 data->last_updated = jiffies;
143 data->valid = 1; 143 data->valid = 1;
144 144
145 dev_dbg(&client->dev, "... device update complete\n"); 145 dev_dbg(dev, "... device update complete\n");
146 } 146 }
147 147
148 mutex_unlock(&data->update_lock); 148 mutex_unlock(&data->update_lock);
@@ -157,24 +157,18 @@ static int temp_from_reg(u8 reg)
157 return (s8)reg * 1000; 157 return (s8)reg * 1000;
158} 158}
159 159
160/* 0 <= nr <= 3 */ 160static ssize_t show_temp(struct device *dev, struct device_attribute
161static ssize_t show_temp(struct device *dev, char *buf, int nr) 161 *devattr, char *buf)
162{ 162{
163 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
163 struct smsc47b397_data *data = smsc47b397_update_device(dev); 164 struct smsc47b397_data *data = smsc47b397_update_device(dev);
164 return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); 165 return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
165} 166}
166 167
167#define sysfs_temp(num) \ 168static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
168static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ 169static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
169{ \ 170static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
170 return show_temp(dev, buf, num-1); \ 171static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
171} \
172static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL)
173
174sysfs_temp(1);
175sysfs_temp(2);
176sysfs_temp(3);
177sysfs_temp(4);
178 172
179/* FAN: 1 RPM/bit 173/* FAN: 1 RPM/bit
180 REG: count of 90kHz pulses / revolution */ 174 REG: count of 90kHz pulses / revolution */
@@ -183,35 +177,37 @@ static int fan_from_reg(u16 reg)
183 return 90000 * 60 / reg; 177 return 90000 * 60 / reg;
184} 178}
185 179
186/* 0 <= nr <= 3 */ 180static ssize_t show_fan(struct device *dev, struct device_attribute
187static ssize_t show_fan(struct device *dev, char *buf, int nr) 181 *devattr, char *buf)
188{ 182{
189 struct smsc47b397_data *data = smsc47b397_update_device(dev); 183 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
190 return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); 184 struct smsc47b397_data *data = smsc47b397_update_device(dev);
185 return sprintf(buf, "%d\n", fan_from_reg(data->fan[attr->index]));
191} 186}
187static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
188static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
189static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
190static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
192 191
193#define sysfs_fan(num) \ 192static ssize_t show_name(struct device *dev, struct device_attribute
194static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ 193 *devattr, char *buf)
195{ \ 194{
196 return show_fan(dev, buf, num-1); \ 195 struct smsc47b397_data *data = dev_get_drvdata(dev);
197} \ 196 return sprintf(buf, "%s\n", data->name);
198static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) 197}
199 198static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
200sysfs_fan(1);
201sysfs_fan(2);
202sysfs_fan(3);
203sysfs_fan(4);
204 199
205static struct attribute *smsc47b397_attributes[] = { 200static struct attribute *smsc47b397_attributes[] = {
206 &dev_attr_temp1_input.attr, 201 &sensor_dev_attr_temp1_input.dev_attr.attr,
207 &dev_attr_temp2_input.attr, 202 &sensor_dev_attr_temp2_input.dev_attr.attr,
208 &dev_attr_temp3_input.attr, 203 &sensor_dev_attr_temp3_input.dev_attr.attr,
209 &dev_attr_temp4_input.attr, 204 &sensor_dev_attr_temp4_input.dev_attr.attr,
210 &dev_attr_fan1_input.attr, 205 &sensor_dev_attr_fan1_input.dev_attr.attr,
211 &dev_attr_fan2_input.attr, 206 &sensor_dev_attr_fan2_input.dev_attr.attr,
212 &dev_attr_fan3_input.attr, 207 &sensor_dev_attr_fan3_input.dev_attr.attr,
213 &dev_attr_fan4_input.attr, 208 &sensor_dev_attr_fan4_input.dev_attr.attr,
214 209
210 &dev_attr_name.attr,
215 NULL 211 NULL
216}; 212};
217 213
@@ -219,44 +215,44 @@ static const struct attribute_group smsc47b397_group = {
219 .attrs = smsc47b397_attributes, 215 .attrs = smsc47b397_attributes,
220}; 216};
221 217
222static int smsc47b397_detach_client(struct i2c_client *client) 218static int __devexit smsc47b397_remove(struct platform_device *pdev)
223{ 219{
224 struct smsc47b397_data *data = i2c_get_clientdata(client); 220 struct smsc47b397_data *data = platform_get_drvdata(pdev);
225 int err; 221 struct resource *res;
226 222
227 hwmon_device_unregister(data->class_dev); 223 hwmon_device_unregister(data->class_dev);
228 sysfs_remove_group(&client->dev.kobj, &smsc47b397_group); 224 sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
229 225 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
230 if ((err = i2c_detach_client(client))) 226 release_region(res->start, SMSC_EXTENT);
231 return err;
232
233 release_region(client->addr, SMSC_EXTENT);
234 kfree(data); 227 kfree(data);
235 228
236 return 0; 229 return 0;
237} 230}
238 231
239static int smsc47b397_detect(struct i2c_adapter *adapter); 232static int smsc47b397_probe(struct platform_device *pdev);
240 233
241static struct i2c_driver smsc47b397_driver = { 234static struct platform_driver smsc47b397_driver = {
242 .driver = { 235 .driver = {
243 .owner = THIS_MODULE, 236 .owner = THIS_MODULE,
244 .name = "smsc47b397", 237 .name = DRVNAME,
245 }, 238 },
246 .attach_adapter = smsc47b397_detect, 239 .probe = smsc47b397_probe,
247 .detach_client = smsc47b397_detach_client, 240 .remove = __devexit_p(smsc47b397_remove),
248}; 241};
249 242
250static int smsc47b397_detect(struct i2c_adapter *adapter) 243static int __devinit smsc47b397_probe(struct platform_device *pdev)
251{ 244{
252 struct i2c_client *new_client; 245 struct device *dev = &pdev->dev;
253 struct smsc47b397_data *data; 246 struct smsc47b397_data *data;
247 struct resource *res;
254 int err = 0; 248 int err = 0;
255 249
256 if (!request_region(address, SMSC_EXTENT, 250 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
251 if (!request_region(res->start, SMSC_EXTENT,
257 smsc47b397_driver.driver.name)) { 252 smsc47b397_driver.driver.name)) {
258 dev_err(&adapter->dev, "Region 0x%x already in use!\n", 253 dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
259 address); 254 (unsigned long)res->start,
255 (unsigned long)res->start + SMSC_EXTENT - 1);
260 return -EBUSY; 256 return -EBUSY;
261 } 257 }
262 258
@@ -265,25 +261,16 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
265 goto error_release; 261 goto error_release;
266 } 262 }
267 263
268 new_client = &data->client; 264 data->addr = res->start;
269 i2c_set_clientdata(new_client, data); 265 data->name = "smsc47b397";
270 new_client->addr = address;
271 mutex_init(&data->lock); 266 mutex_init(&data->lock);
272 new_client->adapter = adapter;
273 new_client->driver = &smsc47b397_driver;
274 new_client->flags = 0;
275
276 strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE);
277
278 mutex_init(&data->update_lock); 267 mutex_init(&data->update_lock);
268 platform_set_drvdata(pdev, data);
279 269
280 if ((err = i2c_attach_client(new_client))) 270 if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
281 goto error_free; 271 goto error_free;
282 272
283 if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group))) 273 data->class_dev = hwmon_device_register(dev);
284 goto error_detach;
285
286 data->class_dev = hwmon_device_register(&new_client->dev);
287 if (IS_ERR(data->class_dev)) { 274 if (IS_ERR(data->class_dev)) {
288 err = PTR_ERR(data->class_dev); 275 err = PTR_ERR(data->class_dev);
289 goto error_remove; 276 goto error_remove;
@@ -292,13 +279,50 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
292 return 0; 279 return 0;
293 280
294error_remove: 281error_remove:
295 sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group); 282 sysfs_remove_group(&dev->kobj, &smsc47b397_group);
296error_detach:
297 i2c_detach_client(new_client);
298error_free: 283error_free:
299 kfree(data); 284 kfree(data);
300error_release: 285error_release:
301 release_region(address, SMSC_EXTENT); 286 release_region(res->start, SMSC_EXTENT);
287 return err;
288}
289
290static int __init smsc47b397_device_add(unsigned short address)
291{
292 struct resource res = {
293 .start = address,
294 .end = address + SMSC_EXTENT - 1,
295 .name = DRVNAME,
296 .flags = IORESOURCE_IO,
297 };
298 int err;
299
300 pdev = platform_device_alloc(DRVNAME, address);
301 if (!pdev) {
302 err = -ENOMEM;
303 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
304 goto exit;
305 }
306
307 err = platform_device_add_resources(pdev, &res, 1);
308 if (err) {
309 printk(KERN_ERR DRVNAME ": Device resource addition failed "
310 "(%d)\n", err);
311 goto exit_device_put;
312 }
313
314 err = platform_device_add(pdev);
315 if (err) {
316 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
317 err);
318 goto exit_device_put;
319 }
320
321 return 0;
322
323exit_device_put:
324 platform_device_put(pdev);
325exit:
302 return err; 326 return err;
303} 327}
304 328
@@ -320,7 +344,7 @@ static int __init smsc47b397_find(unsigned short *addr)
320 *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) 344 *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
321 | superio_inb(SUPERIO_REG_BASE_LSB); 345 | superio_inb(SUPERIO_REG_BASE_LSB);
322 346
323 printk(KERN_INFO "smsc47b397: found SMSC %s " 347 printk(KERN_INFO DRVNAME ": found SMSC %s "
324 "(base address 0x%04x, revision %u)\n", 348 "(base address 0x%04x, revision %u)\n",
325 id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev); 349 id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
326 350
@@ -330,17 +354,33 @@ static int __init smsc47b397_find(unsigned short *addr)
330 354
331static int __init smsc47b397_init(void) 355static int __init smsc47b397_init(void)
332{ 356{
357 unsigned short address;
333 int ret; 358 int ret;
334 359
335 if ((ret = smsc47b397_find(&address))) 360 if ((ret = smsc47b397_find(&address)))
336 return ret; 361 return ret;
337 362
338 return i2c_isa_add_driver(&smsc47b397_driver); 363 ret = platform_driver_register(&smsc47b397_driver);
364 if (ret)
365 goto exit;
366
367 /* Sets global pdev as a side effect */
368 ret = smsc47b397_device_add(address);
369 if (ret)
370 goto exit_driver;
371
372 return 0;
373
374exit_driver:
375 platform_driver_unregister(&smsc47b397_driver);
376exit:
377 return ret;
339} 378}
340 379
341static void __exit smsc47b397_exit(void) 380static void __exit smsc47b397_exit(void)
342{ 381{
343 i2c_isa_del_driver(&smsc47b397_driver); 382 platform_device_unregister(pdev);
383 platform_driver_unregister(&smsc47b397_driver);
344} 384}
345 385
346MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 386MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");