OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [hwmon/] [ds1621.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
    ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
3
             monitoring
4
    Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
5
    based on lm75.c by Frodo Looijaard <frodol@dds.nl>
6
    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
7
    the help of Jean Delvare <khali@linux-fr.org>
8
 
9
    This program is free software; you can redistribute it and/or modify
10
    it under the terms of the GNU General Public License as published by
11
    the Free Software Foundation; either version 2 of the License, or
12
    (at your option) any later version.
13
 
14
    This program is distributed in the hope that it will be useful,
15
    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
    GNU General Public License for more details.
18
 
19
    You should have received a copy of the GNU General Public License
20
    along with this program; if not, write to the Free Software
21
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
*/
23
 
24
#include <linux/module.h>
25
#include <linux/init.h>
26
#include <linux/slab.h>
27
#include <linux/jiffies.h>
28
#include <linux/i2c.h>
29
#include <linux/hwmon.h>
30
#include <linux/hwmon-sysfs.h>
31
#include <linux/err.h>
32
#include <linux/mutex.h>
33
#include <linux/sysfs.h>
34
#include "lm75.h"
35
 
36
/* Addresses to scan */
37
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
38
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
39
 
40
/* Insmod parameters */
41
I2C_CLIENT_INSMOD_1(ds1621);
42
static int polarity = -1;
43
module_param(polarity, int, 0);
44
MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
45
 
46
/* Many DS1621 constants specified below */
47
/* Config register used for detection         */
48
/*  7    6    5    4    3    2    1    0      */
49
/* |Done|THF |TLF |NVB | X  | X  |POL |1SHOT| */
50
#define DS1621_REG_CONFIG_NVB           0x10
51
#define DS1621_REG_CONFIG_POLARITY      0x02
52
#define DS1621_REG_CONFIG_1SHOT         0x01
53
#define DS1621_REG_CONFIG_DONE          0x80
54
 
55
/* The DS1621 registers */
56
static const u8 DS1621_REG_TEMP[3] = {
57
        0xAA,           /* input, word, RO */
58
        0xA2,           /* min, word, RW */
59
        0xA1,           /* max, word, RW */
60
};
61
#define DS1621_REG_CONF                 0xAC /* byte, RW */
62
#define DS1621_COM_START                0xEE /* no data */
63
#define DS1621_COM_STOP                 0x22 /* no data */
64
 
65
/* The DS1621 configuration register */
66
#define DS1621_ALARM_TEMP_HIGH          0x40
67
#define DS1621_ALARM_TEMP_LOW           0x20
68
 
69
/* Conversions */
70
#define ALARMS_FROM_REG(val) ((val) & \
71
                              (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
72
 
73
/* Each client has this additional data */
74
struct ds1621_data {
75
        struct i2c_client client;
76
        struct device *hwmon_dev;
77
        struct mutex update_lock;
78
        char valid;                     /* !=0 if following fields are valid */
79
        unsigned long last_updated;     /* In jiffies */
80
 
81
        u16 temp[3];                    /* Register values, word */
82
        u8 conf;                        /* Register encoding, combined */
83
};
84
 
85
static int ds1621_attach_adapter(struct i2c_adapter *adapter);
86
static int ds1621_detect(struct i2c_adapter *adapter, int address,
87
                         int kind);
88
static void ds1621_init_client(struct i2c_client *client);
89
static int ds1621_detach_client(struct i2c_client *client);
90
static struct ds1621_data *ds1621_update_client(struct device *dev);
91
 
92
/* This is the driver that will be inserted */
93
static struct i2c_driver ds1621_driver = {
94
        .driver = {
95
                .name   = "ds1621",
96
        },
97
        .id             = I2C_DRIVERID_DS1621,
98
        .attach_adapter = ds1621_attach_adapter,
99
        .detach_client  = ds1621_detach_client,
100
};
101
 
102
/* All registers are word-sized, except for the configuration register.
103
   DS1621 uses a high-byte first convention, which is exactly opposite to
104
   the SMBus standard. */
105
static int ds1621_read_value(struct i2c_client *client, u8 reg)
106
{
107
        if (reg == DS1621_REG_CONF)
108
                return i2c_smbus_read_byte_data(client, reg);
109
        else
110
                return swab16(i2c_smbus_read_word_data(client, reg));
111
}
112
 
113
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
114
{
115
        if (reg == DS1621_REG_CONF)
116
                return i2c_smbus_write_byte_data(client, reg, value);
117
        else
118
                return i2c_smbus_write_word_data(client, reg, swab16(value));
119
}
120
 
121
static void ds1621_init_client(struct i2c_client *client)
122
{
123
        int reg = ds1621_read_value(client, DS1621_REG_CONF);
124
        /* switch to continuous conversion mode */
125
        reg &= ~ DS1621_REG_CONFIG_1SHOT;
126
 
127
        /* setup output polarity */
128
        if (polarity == 0)
129
                reg &= ~DS1621_REG_CONFIG_POLARITY;
130
        else if (polarity == 1)
131
                reg |= DS1621_REG_CONFIG_POLARITY;
132
 
133
        ds1621_write_value(client, DS1621_REG_CONF, reg);
134
 
135
        /* start conversion */
136
        i2c_smbus_write_byte(client, DS1621_COM_START);
137
}
138
 
139
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
140
                         char *buf)
141
{
142
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
143
        struct ds1621_data *data = ds1621_update_client(dev);
144
        return sprintf(buf, "%d\n",
145
                       LM75_TEMP_FROM_REG(data->temp[attr->index]));
146
}
147
 
148
static ssize_t set_temp(struct device *dev, struct device_attribute *da,
149
                        const char *buf, size_t count)
150
{
151
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
152
        struct i2c_client *client = to_i2c_client(dev);
153
        struct ds1621_data *data = ds1621_update_client(dev);
154
        u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
155
 
156
        mutex_lock(&data->update_lock);
157
        data->temp[attr->index] = val;
158
        ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
159
                           data->temp[attr->index]);
160
        mutex_unlock(&data->update_lock);
161
        return count;
162
}
163
 
164
static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
165
                           char *buf)
166
{
167
        struct ds1621_data *data = ds1621_update_client(dev);
168
        return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
169
}
170
 
171
static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
172
                          char *buf)
173
{
174
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
175
        struct ds1621_data *data = ds1621_update_client(dev);
176
        return sprintf(buf, "%d\n", !!(data->conf & attr->index));
177
}
178
 
179
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
180
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
181
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
182
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
183
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
184
                DS1621_ALARM_TEMP_LOW);
185
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
186
                DS1621_ALARM_TEMP_HIGH);
187
 
188
static struct attribute *ds1621_attributes[] = {
189
        &sensor_dev_attr_temp1_input.dev_attr.attr,
190
        &sensor_dev_attr_temp1_min.dev_attr.attr,
191
        &sensor_dev_attr_temp1_max.dev_attr.attr,
192
        &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
193
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
194
        &dev_attr_alarms.attr,
195
        NULL
196
};
197
 
198
static const struct attribute_group ds1621_group = {
199
        .attrs = ds1621_attributes,
200
};
201
 
202
 
203
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
204
{
205
        if (!(adapter->class & I2C_CLASS_HWMON))
206
                return 0;
207
        return i2c_probe(adapter, &addr_data, ds1621_detect);
208
}
209
 
210
/* This function is called by i2c_probe */
211
static int ds1621_detect(struct i2c_adapter *adapter, int address,
212
                         int kind)
213
{
214
        int conf, temp;
215
        struct i2c_client *client;
216
        struct ds1621_data *data;
217
        int i, err = 0;
218
 
219
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
220
                                     | I2C_FUNC_SMBUS_WORD_DATA
221
                                     | I2C_FUNC_SMBUS_WRITE_BYTE))
222
                goto exit;
223
 
224
        /* OK. For now, we presume we have a valid client. We now create the
225
           client structure, even though we cannot fill it completely yet.
226
           But it allows us to access ds1621_{read,write}_value. */
227
        if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) {
228
                err = -ENOMEM;
229
                goto exit;
230
        }
231
 
232
        client = &data->client;
233
        i2c_set_clientdata(client, data);
234
        client->addr = address;
235
        client->adapter = adapter;
236
        client->driver = &ds1621_driver;
237
 
238
        /* Now, we do the remaining detection. It is lousy. */
239
        if (kind < 0) {
240
                /* The NVB bit should be low if no EEPROM write has been
241
                   requested during the latest 10ms, which is highly
242
                   improbable in our case. */
243
                conf = ds1621_read_value(client, DS1621_REG_CONF);
244
                if (conf & DS1621_REG_CONFIG_NVB)
245
                        goto exit_free;
246
                /* The 7 lowest bits of a temperature should always be 0. */
247
                for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
248
                        temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
249
                        if (temp & 0x007f)
250
                                goto exit_free;
251
                }
252
        }
253
 
254
        /* Fill in remaining client fields and put it into the global list */
255
        strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
256
        mutex_init(&data->update_lock);
257
 
258
        /* Tell the I2C layer a new client has arrived */
259
        if ((err = i2c_attach_client(client)))
260
                goto exit_free;
261
 
262
        /* Initialize the DS1621 chip */
263
        ds1621_init_client(client);
264
 
265
        /* Register sysfs hooks */
266
        if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
267
                goto exit_detach;
268
 
269
        data->hwmon_dev = hwmon_device_register(&client->dev);
270
        if (IS_ERR(data->hwmon_dev)) {
271
                err = PTR_ERR(data->hwmon_dev);
272
                goto exit_remove_files;
273
        }
274
 
275
        return 0;
276
 
277
      exit_remove_files:
278
        sysfs_remove_group(&client->dev.kobj, &ds1621_group);
279
      exit_detach:
280
        i2c_detach_client(client);
281
      exit_free:
282
        kfree(data);
283
      exit:
284
        return err;
285
}
286
 
287
static int ds1621_detach_client(struct i2c_client *client)
288
{
289
        struct ds1621_data *data = i2c_get_clientdata(client);
290
        int err;
291
 
292
        hwmon_device_unregister(data->hwmon_dev);
293
        sysfs_remove_group(&client->dev.kobj, &ds1621_group);
294
 
295
        if ((err = i2c_detach_client(client)))
296
                return err;
297
 
298
        kfree(data);
299
 
300
        return 0;
301
}
302
 
303
 
304
static struct ds1621_data *ds1621_update_client(struct device *dev)
305
{
306
        struct i2c_client *client = to_i2c_client(dev);
307
        struct ds1621_data *data = i2c_get_clientdata(client);
308
        u8 new_conf;
309
 
310
        mutex_lock(&data->update_lock);
311
 
312
        if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
313
            || !data->valid) {
314
                int i;
315
 
316
                dev_dbg(&client->dev, "Starting ds1621 update\n");
317
 
318
                data->conf = ds1621_read_value(client, DS1621_REG_CONF);
319
 
320
                for (i = 0; i < ARRAY_SIZE(data->temp); i++)
321
                        data->temp[i] = ds1621_read_value(client,
322
                                                          DS1621_REG_TEMP[i]);
323
 
324
                /* reset alarms if necessary */
325
                new_conf = data->conf;
326
                if (data->temp[0] > data->temp[1])       /* input > min */
327
                        new_conf &= ~DS1621_ALARM_TEMP_LOW;
328
                if (data->temp[0] < data->temp[2])       /* input < max */
329
                        new_conf &= ~DS1621_ALARM_TEMP_HIGH;
330
                if (data->conf != new_conf)
331
                        ds1621_write_value(client, DS1621_REG_CONF,
332
                                           new_conf);
333
 
334
                data->last_updated = jiffies;
335
                data->valid = 1;
336
        }
337
 
338
        mutex_unlock(&data->update_lock);
339
 
340
        return data;
341
}
342
 
343
static int __init ds1621_init(void)
344
{
345
        return i2c_add_driver(&ds1621_driver);
346
}
347
 
348
static void __exit ds1621_exit(void)
349
{
350
        i2c_del_driver(&ds1621_driver);
351
}
352
 
353
 
354
MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
355
MODULE_DESCRIPTION("DS1621 driver");
356
MODULE_LICENSE("GPL");
357
 
358
module_init(ds1621_init);
359
module_exit(ds1621_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.