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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [ds1620.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620
3
 *   thermometer driver (as used in the Rebel.com NetWinder)
4
 */
5
#include <linux/module.h>
6
#include <linux/miscdevice.h>
7
#include <linux/delay.h>
8
#include <linux/proc_fs.h>
9
#include <linux/capability.h>
10
#include <linux/init.h>
11
 
12
#include <asm/hardware.h>
13
#include <asm/mach-types.h>
14
#include <asm/uaccess.h>
15
#include <asm/therm.h>
16
 
17
#ifdef CONFIG_PROC_FS
18
/* define for /proc interface */
19
#define THERM_USE_PROC
20
#endif
21
 
22
/* Definitions for DS1620 chip */
23
#define THERM_START_CONVERT     0xee
24
#define THERM_RESET             0xaf
25
#define THERM_READ_CONFIG       0xac
26
#define THERM_READ_TEMP         0xaa
27
#define THERM_READ_TL           0xa2
28
#define THERM_READ_TH           0xa1
29
#define THERM_WRITE_CONFIG      0x0c
30
#define THERM_WRITE_TL          0x02
31
#define THERM_WRITE_TH          0x01
32
 
33
#define CFG_CPU                 2
34
#define CFG_1SHOT               1
35
 
36
static const char *fan_state[] = { "off", "on", "on (hardwired)" };
37
 
38
/*
39
 * Start of NetWinder specifics
40
 *  Note!  We have to hold the gpio lock with IRQs disabled over the
41
 *  whole of our transaction to the Dallas chip, since there is a
42
 *  chance that the WaveArtist driver could touch these bits to
43
 *  enable or disable the speaker.
44
 */
45
extern spinlock_t gpio_lock;
46
extern unsigned int system_rev;
47
 
48
static inline void netwinder_ds1620_set_clk(int clk)
49
{
50
        gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0);
51
}
52
 
53
static inline void netwinder_ds1620_set_data(int dat)
54
{
55
        gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0);
56
}
57
 
58
static inline int netwinder_ds1620_get_data(void)
59
{
60
        return gpio_read() & GPIO_DATA;
61
}
62
 
63
static inline void netwinder_ds1620_set_data_dir(int dir)
64
{
65
        gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0);
66
}
67
 
68
static inline void netwinder_ds1620_reset(void)
69
{
70
        cpld_modify(CPLD_DS_ENABLE, 0);
71
        cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE);
72
}
73
 
74
static inline void netwinder_lock(unsigned long *flags)
75
{
76
        spin_lock_irqsave(&gpio_lock, *flags);
77
}
78
 
79
static inline void netwinder_unlock(unsigned long *flags)
80
{
81
        spin_unlock_irqrestore(&gpio_lock, *flags);
82
}
83
 
84
static inline void netwinder_set_fan(int i)
85
{
86
        unsigned long flags;
87
 
88
        spin_lock_irqsave(&gpio_lock, flags);
89
        gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
90
        spin_unlock_irqrestore(&gpio_lock, flags);
91
}
92
 
93
static inline int netwinder_get_fan(void)
94
{
95
        if ((system_rev & 0xf000) == 0x4000)
96
                return FAN_ALWAYS_ON;
97
 
98
        return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF;
99
}
100
 
101
/*
102
 * End of NetWinder specifics
103
 */
104
 
105
static void ds1620_send_bits(int nr, int value)
106
{
107
        int i;
108
 
109
        for (i = 0; i < nr; i++) {
110
                netwinder_ds1620_set_data(value & 1);
111
                netwinder_ds1620_set_clk(0);
112
                udelay(1);
113
                netwinder_ds1620_set_clk(1);
114
                udelay(1);
115
 
116
                value >>= 1;
117
        }
118
}
119
 
120
static unsigned int ds1620_recv_bits(int nr)
121
{
122
        unsigned int value = 0, mask = 1;
123
        int i;
124
 
125
        netwinder_ds1620_set_data(0);
126
 
127
        for (i = 0; i < nr; i++) {
128
                netwinder_ds1620_set_clk(0);
129
                udelay(1);
130
 
131
                if (netwinder_ds1620_get_data())
132
                        value |= mask;
133
 
134
                mask <<= 1;
135
 
136
                netwinder_ds1620_set_clk(1);
137
                udelay(1);
138
        }
139
 
140
        return value;
141
}
142
 
143
static void ds1620_out(int cmd, int bits, int value)
144
{
145
        unsigned long flags;
146
 
147
        netwinder_lock(&flags);
148
        netwinder_ds1620_set_clk(1);
149
        netwinder_ds1620_set_data_dir(0);
150
        netwinder_ds1620_reset();
151
 
152
        udelay(1);
153
 
154
        ds1620_send_bits(8, cmd);
155
        if (bits)
156
                ds1620_send_bits(bits, value);
157
 
158
        udelay(1);
159
 
160
        netwinder_ds1620_reset();
161
        netwinder_unlock(&flags);
162
 
163
        msleep(20);
164
}
165
 
166
static unsigned int ds1620_in(int cmd, int bits)
167
{
168
        unsigned long flags;
169
        unsigned int value;
170
 
171
        netwinder_lock(&flags);
172
        netwinder_ds1620_set_clk(1);
173
        netwinder_ds1620_set_data_dir(0);
174
        netwinder_ds1620_reset();
175
 
176
        udelay(1);
177
 
178
        ds1620_send_bits(8, cmd);
179
 
180
        netwinder_ds1620_set_data_dir(1);
181
        value = ds1620_recv_bits(bits);
182
 
183
        netwinder_ds1620_reset();
184
        netwinder_unlock(&flags);
185
 
186
        return value;
187
}
188
 
189
static int cvt_9_to_int(unsigned int val)
190
{
191
        if (val & 0x100)
192
                val |= 0xfffffe00;
193
 
194
        return val;
195
}
196
 
197
static void ds1620_write_state(struct therm *therm)
198
{
199
        ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
200
        ds1620_out(THERM_WRITE_TL, 9, therm->lo);
201
        ds1620_out(THERM_WRITE_TH, 9, therm->hi);
202
        ds1620_out(THERM_START_CONVERT, 0, 0);
203
}
204
 
205
static void ds1620_read_state(struct therm *therm)
206
{
207
        therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9));
208
        therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9));
209
}
210
 
211
static ssize_t
212
ds1620_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
213
{
214
        signed int cur_temp;
215
        signed char cur_temp_degF;
216
 
217
        cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1;
218
 
219
        /* convert to Fahrenheit, as per wdt.c */
220
        cur_temp_degF = (cur_temp * 9) / 5 + 32;
221
 
222
        if (copy_to_user(buf, &cur_temp_degF, 1))
223
                return -EFAULT;
224
 
225
        return 1;
226
}
227
 
228
static int
229
ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
230
{
231
        struct therm therm;
232
        union {
233
                struct therm __user *therm;
234
                int __user *i;
235
        } uarg;
236
        int i;
237
 
238
        uarg.i = (int __user *)arg;
239
 
240
        switch(cmd) {
241
        case CMD_SET_THERMOSTATE:
242
        case CMD_SET_THERMOSTATE2:
243
                if (!capable(CAP_SYS_ADMIN))
244
                        return -EPERM;
245
 
246
                if (cmd == CMD_SET_THERMOSTATE) {
247
                        if (get_user(therm.hi, uarg.i))
248
                                return -EFAULT;
249
                        therm.lo = therm.hi - 3;
250
                } else {
251
                        if (copy_from_user(&therm, uarg.therm, sizeof(therm)))
252
                                return -EFAULT;
253
                }
254
 
255
                therm.lo <<= 1;
256
                therm.hi <<= 1;
257
 
258
                ds1620_write_state(&therm);
259
                break;
260
 
261
        case CMD_GET_THERMOSTATE:
262
        case CMD_GET_THERMOSTATE2:
263
                ds1620_read_state(&therm);
264
 
265
                therm.lo >>= 1;
266
                therm.hi >>= 1;
267
 
268
                if (cmd == CMD_GET_THERMOSTATE) {
269
                        if (put_user(therm.hi, uarg.i))
270
                                return -EFAULT;
271
                } else {
272
                        if (copy_to_user(uarg.therm, &therm, sizeof(therm)))
273
                                return -EFAULT;
274
                }
275
                break;
276
 
277
        case CMD_GET_TEMPERATURE:
278
        case CMD_GET_TEMPERATURE2:
279
                i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
280
 
281
                if (cmd == CMD_GET_TEMPERATURE)
282
                        i >>= 1;
283
 
284
                return put_user(i, uarg.i) ? -EFAULT : 0;
285
 
286
        case CMD_GET_STATUS:
287
                i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3;
288
 
289
                return put_user(i, uarg.i) ? -EFAULT : 0;
290
 
291
        case CMD_GET_FAN:
292
                i = netwinder_get_fan();
293
 
294
                return put_user(i, uarg.i) ? -EFAULT : 0;
295
 
296
        case CMD_SET_FAN:
297
                if (!capable(CAP_SYS_ADMIN))
298
                        return -EPERM;
299
 
300
                if (get_user(i, uarg.i))
301
                        return -EFAULT;
302
 
303
                netwinder_set_fan(i);
304
                break;
305
 
306
        default:
307
                return -ENOIOCTLCMD;
308
        }
309
 
310
        return 0;
311
}
312
 
313
#ifdef THERM_USE_PROC
314
static int
315
proc_therm_ds1620_read(char *buf, char **start, off_t offset,
316
                       int len, int *eof, void *unused)
317
{
318
        struct therm th;
319
        int temp;
320
 
321
        ds1620_read_state(&th);
322
        temp =  cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
323
 
324
        len = sprintf(buf, "Thermostat: HI %i.%i, LOW %i.%i; "
325
                      "temperature: %i.%i C, fan %s\n",
326
                      th.hi >> 1, th.hi & 1 ? 5 : 0,
327
                      th.lo >> 1, th.lo & 1 ? 5 : 0,
328
                      temp  >> 1, temp  & 1 ? 5 : 0,
329
                      fan_state[netwinder_get_fan()]);
330
 
331
        return len;
332
}
333
 
334
static struct proc_dir_entry *proc_therm_ds1620;
335
#endif
336
 
337
static const struct file_operations ds1620_fops = {
338
        .owner          = THIS_MODULE,
339
        .open           = nonseekable_open,
340
        .read           = ds1620_read,
341
        .ioctl          = ds1620_ioctl,
342
};
343
 
344
static struct miscdevice ds1620_miscdev = {
345
        TEMP_MINOR,
346
        "temp",
347
        &ds1620_fops
348
};
349
 
350
static int __init ds1620_init(void)
351
{
352
        int ret;
353
        struct therm th, th_start;
354
 
355
        if (!machine_is_netwinder())
356
                return -ENODEV;
357
 
358
        ds1620_out(THERM_RESET, 0, 0);
359
        ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
360
        ds1620_out(THERM_START_CONVERT, 0, 0);
361
 
362
        /*
363
         * Trigger the fan to start by setting
364
         * temperature high point low.  This kicks
365
         * the fan into action.
366
         */
367
        ds1620_read_state(&th);
368
        th_start.lo = 0;
369
        th_start.hi = 1;
370
        ds1620_write_state(&th_start);
371
 
372
        msleep(2000);
373
 
374
        ds1620_write_state(&th);
375
 
376
        ret = misc_register(&ds1620_miscdev);
377
        if (ret < 0)
378
                return ret;
379
 
380
#ifdef THERM_USE_PROC
381
        proc_therm_ds1620 = create_proc_entry("therm", 0, NULL);
382
        if (proc_therm_ds1620)
383
                proc_therm_ds1620->read_proc = proc_therm_ds1620_read;
384
        else
385
                printk(KERN_ERR "therm: unable to register /proc/therm\n");
386
#endif
387
 
388
        ds1620_read_state(&th);
389
        ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
390
 
391
        printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, "
392
               "current %i.%i C, fan %s.\n",
393
               th.hi >> 1, th.hi & 1 ? 5 : 0,
394
               th.lo >> 1, th.lo & 1 ? 5 : 0,
395
               ret   >> 1, ret   & 1 ? 5 : 0,
396
               fan_state[netwinder_get_fan()]);
397
 
398
        return 0;
399
}
400
 
401
static void __exit ds1620_exit(void)
402
{
403
#ifdef THERM_USE_PROC
404
        remove_proc_entry("therm", NULL);
405
#endif
406
        misc_deregister(&ds1620_miscdev);
407
}
408
 
409
module_init(ds1620_init);
410
module_exit(ds1620_exit);
411
 
412
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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