~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/hwmon/ad7418.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * An hwmon driver for the Analog Devices AD7416/17/18
 
3
 * Copyright (C) 2006-07 Tower Technologies
 
4
 *
 
5
 * Author: Alessandro Zummo <a.zummo@towertech.it>
 
6
 *
 
7
 * Based on lm75.c
 
8
 * Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License,
 
12
 * as published by the Free Software Foundation - version 2.
 
13
 */
 
14
 
 
15
#include <linux/module.h>
 
16
#include <linux/jiffies.h>
 
17
#include <linux/i2c.h>
 
18
#include <linux/hwmon.h>
 
19
#include <linux/hwmon-sysfs.h>
 
20
#include <linux/err.h>
 
21
#include <linux/mutex.h>
 
22
#include <linux/delay.h>
 
23
#include <linux/slab.h>
 
24
 
 
25
#include "lm75.h"
 
26
 
 
27
#define DRV_VERSION "0.4"
 
28
 
 
29
enum chips { ad7416, ad7417, ad7418 };
 
30
 
 
31
/* AD7418 registers */
 
32
#define AD7418_REG_TEMP_IN      0x00
 
33
#define AD7418_REG_CONF         0x01
 
34
#define AD7418_REG_TEMP_HYST    0x02
 
35
#define AD7418_REG_TEMP_OS      0x03
 
36
#define AD7418_REG_ADC          0x04
 
37
#define AD7418_REG_CONF2        0x05
 
38
 
 
39
#define AD7418_REG_ADC_CH(x)    ((x) << 5)
 
40
#define AD7418_CH_TEMP          AD7418_REG_ADC_CH(0)
 
41
 
 
42
static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
 
43
                                        AD7418_REG_TEMP_HYST,
 
44
                                        AD7418_REG_TEMP_OS };
 
45
 
 
46
struct ad7418_data {
 
47
        struct device           *hwmon_dev;
 
48
        struct attribute_group  attrs;
 
49
        enum chips              type;
 
50
        struct mutex            lock;
 
51
        int                     adc_max;        /* number of ADC channels */
 
52
        char                    valid;
 
53
        unsigned long           last_updated;   /* In jiffies */
 
54
        s16                     temp[3];        /* Register values */
 
55
        u16                     in[4];
 
56
};
 
57
 
 
58
static int ad7418_probe(struct i2c_client *client,
 
59
                        const struct i2c_device_id *id);
 
60
static int ad7418_remove(struct i2c_client *client);
 
61
 
 
62
static const struct i2c_device_id ad7418_id[] = {
 
63
        { "ad7416", ad7416 },
 
64
        { "ad7417", ad7417 },
 
65
        { "ad7418", ad7418 },
 
66
        { }
 
67
};
 
68
MODULE_DEVICE_TABLE(i2c, ad7418_id);
 
69
 
 
70
static struct i2c_driver ad7418_driver = {
 
71
        .driver = {
 
72
                .name   = "ad7418",
 
73
        },
 
74
        .probe          = ad7418_probe,
 
75
        .remove         = ad7418_remove,
 
76
        .id_table       = ad7418_id,
 
77
};
 
78
 
 
79
static void ad7418_init_client(struct i2c_client *client)
 
80
{
 
81
        struct ad7418_data *data = i2c_get_clientdata(client);
 
82
 
 
83
        int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
 
84
        if (reg < 0) {
 
85
                dev_err(&client->dev, "cannot read configuration register\n");
 
86
        } else {
 
87
                dev_info(&client->dev, "configuring for mode 1\n");
 
88
                i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
 
89
 
 
90
                if (data->type == ad7417 || data->type == ad7418)
 
91
                        i2c_smbus_write_byte_data(client,
 
92
                                                AD7418_REG_CONF2, 0x00);
 
93
        }
 
94
}
 
95
 
 
96
static struct ad7418_data *ad7418_update_device(struct device *dev)
 
97
{
 
98
        struct i2c_client *client = to_i2c_client(dev);
 
99
        struct ad7418_data *data = i2c_get_clientdata(client);
 
100
 
 
101
        mutex_lock(&data->lock);
 
102
 
 
103
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 
104
                || !data->valid) {
 
105
                u8 cfg;
 
106
                int i, ch;
 
107
 
 
108
                /* read config register and clear channel bits */
 
109
                cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
 
110
                cfg &= 0x1F;
 
111
 
 
112
                i2c_smbus_write_byte_data(client, AD7418_REG_CONF,
 
113
                                                cfg | AD7418_CH_TEMP);
 
114
                udelay(30);
 
115
 
 
116
                for (i = 0; i < 3; i++) {
 
117
                        data->temp[i] =
 
118
                                i2c_smbus_read_word_swapped(client,
 
119
                                                AD7418_REG_TEMP[i]);
 
120
                }
 
121
 
 
122
                for (i = 0, ch = 4; i < data->adc_max; i++, ch--) {
 
123
                        i2c_smbus_write_byte_data(client,
 
124
                                        AD7418_REG_CONF,
 
125
                                        cfg | AD7418_REG_ADC_CH(ch));
 
126
 
 
127
                        udelay(15);
 
128
                        data->in[data->adc_max - 1 - i] =
 
129
                                i2c_smbus_read_word_swapped(client,
 
130
                                                AD7418_REG_ADC);
 
131
                }
 
132
 
 
133
                /* restore old configuration value */
 
134
                i2c_smbus_write_word_swapped(client, AD7418_REG_CONF, cfg);
 
135
 
 
136
                data->last_updated = jiffies;
 
137
                data->valid = 1;
 
138
        }
 
139
 
 
140
        mutex_unlock(&data->lock);
 
141
 
 
142
        return data;
 
143
}
 
144
 
 
145
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 
146
                        char *buf)
 
147
{
 
148
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 
149
        struct ad7418_data *data = ad7418_update_device(dev);
 
150
        return sprintf(buf, "%d\n",
 
151
                LM75_TEMP_FROM_REG(data->temp[attr->index]));
 
152
}
 
153
 
 
154
static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
 
155
                        char *buf)
 
156
{
 
157
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 
158
        struct ad7418_data *data = ad7418_update_device(dev);
 
159
 
 
160
        return sprintf(buf, "%d\n",
 
161
                ((data->in[attr->index] >> 6) * 2500 + 512) / 1024);
 
162
}
 
163
 
 
164
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
 
165
                        const char *buf, size_t count)
 
166
{
 
167
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 
168
        struct i2c_client *client = to_i2c_client(dev);
 
169
        struct ad7418_data *data = i2c_get_clientdata(client);
 
170
        long temp = simple_strtol(buf, NULL, 10);
 
171
 
 
172
        mutex_lock(&data->lock);
 
173
        data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
 
174
        i2c_smbus_write_word_swapped(client,
 
175
                                     AD7418_REG_TEMP[attr->index],
 
176
                                     data->temp[attr->index]);
 
177
        mutex_unlock(&data->lock);
 
178
        return count;
 
179
}
 
180
 
 
181
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 
182
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
 
183
                                show_temp, set_temp, 1);
 
184
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
 
185
                                show_temp, set_temp, 2);
 
186
 
 
187
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0);
 
188
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
 
189
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
 
190
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
 
191
 
 
192
static struct attribute *ad7416_attributes[] = {
 
193
        &sensor_dev_attr_temp1_max.dev_attr.attr,
 
194
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 
195
        &sensor_dev_attr_temp1_input.dev_attr.attr,
 
196
        NULL
 
197
};
 
198
 
 
199
static struct attribute *ad7417_attributes[] = {
 
200
        &sensor_dev_attr_temp1_max.dev_attr.attr,
 
201
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 
202
        &sensor_dev_attr_temp1_input.dev_attr.attr,
 
203
        &sensor_dev_attr_in1_input.dev_attr.attr,
 
204
        &sensor_dev_attr_in2_input.dev_attr.attr,
 
205
        &sensor_dev_attr_in3_input.dev_attr.attr,
 
206
        &sensor_dev_attr_in4_input.dev_attr.attr,
 
207
        NULL
 
208
};
 
209
 
 
210
static struct attribute *ad7418_attributes[] = {
 
211
        &sensor_dev_attr_temp1_max.dev_attr.attr,
 
212
        &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 
213
        &sensor_dev_attr_temp1_input.dev_attr.attr,
 
214
        &sensor_dev_attr_in1_input.dev_attr.attr,
 
215
        NULL
 
216
};
 
217
 
 
218
static int ad7418_probe(struct i2c_client *client,
 
219
                         const struct i2c_device_id *id)
 
220
{
 
221
        struct i2c_adapter *adapter = client->adapter;
 
222
        struct ad7418_data *data;
 
223
        int err;
 
224
 
 
225
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 
226
                                        I2C_FUNC_SMBUS_WORD_DATA)) {
 
227
                err = -EOPNOTSUPP;
 
228
                goto exit;
 
229
        }
 
230
 
 
231
        if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
 
232
                err = -ENOMEM;
 
233
                goto exit;
 
234
        }
 
235
 
 
236
        i2c_set_clientdata(client, data);
 
237
 
 
238
        mutex_init(&data->lock);
 
239
        data->type = id->driver_data;
 
240
 
 
241
        switch (data->type) {
 
242
        case ad7416:
 
243
                data->adc_max = 0;
 
244
                data->attrs.attrs = ad7416_attributes;
 
245
                break;
 
246
 
 
247
        case ad7417:
 
248
                data->adc_max = 4;
 
249
                data->attrs.attrs = ad7417_attributes;
 
250
                break;
 
251
 
 
252
        case ad7418:
 
253
                data->adc_max = 1;
 
254
                data->attrs.attrs = ad7418_attributes;
 
255
                break;
 
256
        }
 
257
 
 
258
        dev_info(&client->dev, "%s chip found\n", client->name);
 
259
 
 
260
        /* Initialize the AD7418 chip */
 
261
        ad7418_init_client(client);
 
262
 
 
263
        /* Register sysfs hooks */
 
264
        if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
 
265
                goto exit_free;
 
266
 
 
267
        data->hwmon_dev = hwmon_device_register(&client->dev);
 
268
        if (IS_ERR(data->hwmon_dev)) {
 
269
                err = PTR_ERR(data->hwmon_dev);
 
270
                goto exit_remove;
 
271
        }
 
272
 
 
273
        return 0;
 
274
 
 
275
exit_remove:
 
276
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
 
277
exit_free:
 
278
        kfree(data);
 
279
exit:
 
280
        return err;
 
281
}
 
282
 
 
283
static int ad7418_remove(struct i2c_client *client)
 
284
{
 
285
        struct ad7418_data *data = i2c_get_clientdata(client);
 
286
        hwmon_device_unregister(data->hwmon_dev);
 
287
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
 
288
        kfree(data);
 
289
        return 0;
 
290
}
 
291
 
 
292
static int __init ad7418_init(void)
 
293
{
 
294
        return i2c_add_driver(&ad7418_driver);
 
295
}
 
296
 
 
297
static void __exit ad7418_exit(void)
 
298
{
 
299
        i2c_del_driver(&ad7418_driver);
 
300
}
 
301
 
 
302
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 
303
MODULE_DESCRIPTION("AD7416/17/18 driver");
 
304
MODULE_LICENSE("GPL");
 
305
MODULE_VERSION(DRV_VERSION);
 
306
 
 
307
module_init(ad7418_init);
 
308
module_exit(ad7418_exit);