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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [tlclk.c] - Blame information for rev 65

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

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Telecom Clock driver for Intel NetStructure(tm) MPCBL0010
3
 *
4
 * Copyright (C) 2005 Kontron Canada
5
 *
6
 * All rights reserved.
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or (at
11
 * your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
16
 * NON INFRINGEMENT.  See the GNU General Public License for more
17
 * 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
 * Send feedback to <sebastien.bouchard@ca.kontron.com> and the current
24
 * Maintainer  <mark.gross@intel.com>
25
 *
26
 * Description : This is the TELECOM CLOCK module driver for the ATCA
27
 * MPCBL0010 ATCA computer.
28
 */
29
 
30
#include <linux/module.h>
31
#include <linux/init.h>
32
#include <linux/kernel.h>       /* printk() */
33
#include <linux/fs.h>           /* everything... */
34
#include <linux/errno.h>        /* error codes */
35
#include <linux/slab.h>
36
#include <linux/ioport.h>
37
#include <linux/interrupt.h>
38
#include <linux/spinlock.h>
39
#include <linux/timer.h>
40
#include <linux/sysfs.h>
41
#include <linux/device.h>
42
#include <linux/miscdevice.h>
43
#include <linux/platform_device.h>
44
#include <asm/io.h>             /* inb/outb */
45
#include <asm/uaccess.h>
46
 
47
MODULE_AUTHOR("Sebastien Bouchard <sebastien.bouchard@ca.kontron.com>");
48
MODULE_LICENSE("GPL");
49
 
50
/*Hardware Reset of the PLL */
51
#define RESET_ON        0x00
52
#define RESET_OFF       0x01
53
 
54
/* MODE SELECT */
55
#define NORMAL_MODE     0x00
56
#define HOLDOVER_MODE   0x10
57
#define FREERUN_MODE    0x20
58
 
59
/* FILTER SELECT */
60
#define FILTER_6HZ      0x04
61
#define FILTER_12HZ     0x00
62
 
63
/* SELECT REFERENCE FREQUENCY */
64
#define REF_CLK1_8kHz           0x00
65
#define REF_CLK2_19_44MHz       0x02
66
 
67
/* Select primary or secondary redundant clock */
68
#define PRIMARY_CLOCK   0x00
69
#define SECONDARY_CLOCK 0x01
70
 
71
/* CLOCK TRANSMISSION DEFINE */
72
#define CLK_8kHz        0xff
73
#define CLK_16_384MHz   0xfb
74
 
75
#define CLK_1_544MHz    0x00
76
#define CLK_2_048MHz    0x01
77
#define CLK_4_096MHz    0x02
78
#define CLK_6_312MHz    0x03
79
#define CLK_8_192MHz    0x04
80
#define CLK_19_440MHz   0x06
81
 
82
#define CLK_8_592MHz    0x08
83
#define CLK_11_184MHz   0x09
84
#define CLK_34_368MHz   0x0b
85
#define CLK_44_736MHz   0x0a
86
 
87
/* RECEIVED REFERENCE */
88
#define AMC_B1 0
89
#define AMC_B2 1
90
 
91
/* HARDWARE SWITCHING DEFINE */
92
#define HW_ENABLE       0x80
93
#define HW_DISABLE      0x00
94
 
95
/* HARDWARE SWITCHING MODE DEFINE */
96
#define PLL_HOLDOVER    0x40
97
#define LOST_CLOCK      0x00
98
 
99
/* ALARMS DEFINE */
100
#define UNLOCK_MASK     0x10
101
#define HOLDOVER_MASK   0x20
102
#define SEC_LOST_MASK   0x40
103
#define PRI_LOST_MASK   0x80
104
 
105
/* INTERRUPT CAUSE DEFINE */
106
 
107
#define PRI_LOS_01_MASK         0x01
108
#define PRI_LOS_10_MASK         0x02
109
 
110
#define SEC_LOS_01_MASK         0x04
111
#define SEC_LOS_10_MASK         0x08
112
 
113
#define HOLDOVER_01_MASK        0x10
114
#define HOLDOVER_10_MASK        0x20
115
 
116
#define UNLOCK_01_MASK          0x40
117
#define UNLOCK_10_MASK          0x80
118
 
119
struct tlclk_alarms {
120
        __u32 lost_clocks;
121
        __u32 lost_primary_clock;
122
        __u32 lost_secondary_clock;
123
        __u32 primary_clock_back;
124
        __u32 secondary_clock_back;
125
        __u32 switchover_primary;
126
        __u32 switchover_secondary;
127
        __u32 pll_holdover;
128
        __u32 pll_end_holdover;
129
        __u32 pll_lost_sync;
130
        __u32 pll_sync;
131
};
132
/* Telecom clock I/O register definition */
133
#define TLCLK_BASE 0xa08
134
#define TLCLK_REG0 TLCLK_BASE
135
#define TLCLK_REG1 (TLCLK_BASE+1)
136
#define TLCLK_REG2 (TLCLK_BASE+2)
137
#define TLCLK_REG3 (TLCLK_BASE+3)
138
#define TLCLK_REG4 (TLCLK_BASE+4)
139
#define TLCLK_REG5 (TLCLK_BASE+5)
140
#define TLCLK_REG6 (TLCLK_BASE+6)
141
#define TLCLK_REG7 (TLCLK_BASE+7)
142
 
143
#define SET_PORT_BITS(port, mask, val) outb(((inb(port) & mask) | val), port)
144
 
145
/* 0 = Dynamic allocation of the major device number */
146
#define TLCLK_MAJOR 0
147
 
148
/* sysfs interface definition:
149
Upon loading the driver will create a sysfs directory under
150
/sys/devices/platform/telco_clock.
151
 
152
This directory exports the following interfaces.  There operation is
153
documented in the MCPBL0010 TPS under the Telecom Clock API section, 11.4.
154
alarms                          :
155
current_ref                     :
156
received_ref_clk3a              :
157
received_ref_clk3b              :
158
enable_clk3a_output             :
159
enable_clk3b_output             :
160
enable_clka0_output             :
161
enable_clka1_output             :
162
enable_clkb0_output             :
163
enable_clkb1_output             :
164
filter_select                   :
165
hardware_switching              :
166
hardware_switching_mode         :
167
telclock_version                :
168
mode_select                     :
169
refalign                        :
170
reset                           :
171
select_amcb1_transmit_clock     :
172
select_amcb2_transmit_clock     :
173
select_redundant_clock          :
174
select_ref_frequency            :
175
 
176
All sysfs interfaces are integers in hex format, i.e echo 99 > refalign
177
has the same effect as echo 0x99 > refalign.
178
*/
179
 
180
static unsigned int telclk_interrupt;
181
 
182
static int int_events;          /* Event that generate a interrupt */
183
static int got_event;           /* if events processing have been done */
184
 
185
static void switchover_timeout(unsigned long data);
186
static struct timer_list switchover_timer =
187
        TIMER_INITIALIZER(switchover_timeout , 0, 0);
188
static unsigned long tlclk_timer_data;
189
 
190
static struct tlclk_alarms *alarm_events;
191
 
192
static DEFINE_SPINLOCK(event_lock);
193
 
194
static int tlclk_major = TLCLK_MAJOR;
195
 
196
static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
197
 
198
static DECLARE_WAIT_QUEUE_HEAD(wq);
199
 
200
static unsigned long useflags;
201
static DEFINE_MUTEX(tlclk_mutex);
202
 
203
static int tlclk_open(struct inode *inode, struct file *filp)
204
{
205
        int result;
206
 
207
        if (test_and_set_bit(0, &useflags))
208
                return -EBUSY;
209
                /* this legacy device is always one per system and it doesn't
210
                 * know how to handle multiple concurrent clients.
211
                 */
212
 
213
        /* Make sure there is no interrupt pending while
214
         * initialising interrupt handler */
215
        inb(TLCLK_REG6);
216
 
217
        /* This device is wired through the FPGA IO space of the ATCA blade
218
         * we can't share this IRQ */
219
        result = request_irq(telclk_interrupt, &tlclk_interrupt,
220
                             IRQF_DISABLED, "telco_clock", tlclk_interrupt);
221
        if (result == -EBUSY) {
222
                printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n");
223
                return -EBUSY;
224
        }
225
        inb(TLCLK_REG6);        /* Clear interrupt events */
226
 
227
        return 0;
228
}
229
 
230
static int tlclk_release(struct inode *inode, struct file *filp)
231
{
232
        free_irq(telclk_interrupt, tlclk_interrupt);
233
        clear_bit(0, &useflags);
234
 
235
        return 0;
236
}
237
 
238
static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
239
                loff_t *f_pos)
240
{
241
        if (count < sizeof(struct tlclk_alarms))
242
                return -EIO;
243
        if (mutex_lock_interruptible(&tlclk_mutex))
244
                return -EINTR;
245
 
246
 
247
        wait_event_interruptible(wq, got_event);
248
        if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) {
249
                mutex_unlock(&tlclk_mutex);
250
                return -EFAULT;
251
        }
252
 
253
        memset(alarm_events, 0, sizeof(struct tlclk_alarms));
254
        got_event = 0;
255
 
256
        mutex_unlock(&tlclk_mutex);
257
        return  sizeof(struct tlclk_alarms);
258
}
259
 
260
static const struct file_operations tlclk_fops = {
261
        .read = tlclk_read,
262
        .open = tlclk_open,
263
        .release = tlclk_release,
264
 
265
};
266
 
267
static struct miscdevice tlclk_miscdev = {
268
        .minor = MISC_DYNAMIC_MINOR,
269
        .name = "telco_clock",
270
        .fops = &tlclk_fops,
271
};
272
 
273
static ssize_t show_current_ref(struct device *d,
274
                struct device_attribute *attr, char *buf)
275
{
276
        unsigned long ret_val;
277
        unsigned long flags;
278
 
279
        spin_lock_irqsave(&event_lock, flags);
280
        ret_val = ((inb(TLCLK_REG1) & 0x08) >> 3);
281
        spin_unlock_irqrestore(&event_lock, flags);
282
 
283
        return sprintf(buf, "0x%lX\n", ret_val);
284
}
285
 
286
static DEVICE_ATTR(current_ref, S_IRUGO, show_current_ref, NULL);
287
 
288
 
289
static ssize_t show_telclock_version(struct device *d,
290
                struct device_attribute *attr, char *buf)
291
{
292
        unsigned long ret_val;
293
        unsigned long flags;
294
 
295
        spin_lock_irqsave(&event_lock, flags);
296
        ret_val = inb(TLCLK_REG5);
297
        spin_unlock_irqrestore(&event_lock, flags);
298
 
299
        return sprintf(buf, "0x%lX\n", ret_val);
300
}
301
 
302
static DEVICE_ATTR(telclock_version, S_IRUGO,
303
                show_telclock_version, NULL);
304
 
305
static ssize_t show_alarms(struct device *d,
306
                struct device_attribute *attr,  char *buf)
307
{
308
        unsigned long ret_val;
309
        unsigned long flags;
310
 
311
        spin_lock_irqsave(&event_lock, flags);
312
        ret_val = (inb(TLCLK_REG2) & 0xf0);
313
        spin_unlock_irqrestore(&event_lock, flags);
314
 
315
        return sprintf(buf, "0x%lX\n", ret_val);
316
}
317
 
318
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
319
 
320
static ssize_t store_received_ref_clk3a(struct device *d,
321
                 struct device_attribute *attr, const char *buf, size_t count)
322
{
323
        unsigned long tmp;
324
        unsigned char val;
325
        unsigned long flags;
326
 
327
        sscanf(buf, "%lX", &tmp);
328
        dev_dbg(d, ": tmp = 0x%lX\n", tmp);
329
 
330
        val = (unsigned char)tmp;
331
        spin_lock_irqsave(&event_lock, flags);
332
        SET_PORT_BITS(TLCLK_REG1, 0xef, val);
333
        spin_unlock_irqrestore(&event_lock, flags);
334
 
335
        return strnlen(buf, count);
336
}
337
 
338
static DEVICE_ATTR(received_ref_clk3a, (S_IWUSR|S_IWGRP), NULL,
339
                store_received_ref_clk3a);
340
 
341
 
342
static ssize_t store_received_ref_clk3b(struct device *d,
343
                 struct device_attribute *attr, const char *buf, size_t count)
344
{
345
        unsigned long tmp;
346
        unsigned char val;
347
        unsigned long flags;
348
 
349
        sscanf(buf, "%lX", &tmp);
350
        dev_dbg(d, ": tmp = 0x%lX\n", tmp);
351
 
352
        val = (unsigned char)tmp;
353
        spin_lock_irqsave(&event_lock, flags);
354
        SET_PORT_BITS(TLCLK_REG1, 0xdf, val << 1);
355
        spin_unlock_irqrestore(&event_lock, flags);
356
 
357
        return strnlen(buf, count);
358
}
359
 
360
static DEVICE_ATTR(received_ref_clk3b, (S_IWUSR|S_IWGRP), NULL,
361
                store_received_ref_clk3b);
362
 
363
 
364
static ssize_t store_enable_clk3b_output(struct device *d,
365
                 struct device_attribute *attr, const char *buf, size_t count)
366
{
367
        unsigned long tmp;
368
        unsigned char val;
369
        unsigned long flags;
370
 
371
        sscanf(buf, "%lX", &tmp);
372
        dev_dbg(d, ": tmp = 0x%lX\n", tmp);
373
 
374
        val = (unsigned char)tmp;
375
        spin_lock_irqsave(&event_lock, flags);
376
        SET_PORT_BITS(TLCLK_REG3, 0x7f, val << 7);
377
        spin_unlock_irqrestore(&event_lock, flags);
378
 
379
        return strnlen(buf, count);
380
}
381
 
382
static DEVICE_ATTR(enable_clk3b_output, (S_IWUSR|S_IWGRP), NULL,
383
                store_enable_clk3b_output);
384
 
385
static ssize_t store_enable_clk3a_output(struct device *d,
386
                 struct device_attribute *attr, const char *buf, size_t count)
387
{
388
        unsigned long flags;
389
        unsigned long tmp;
390
        unsigned char val;
391
 
392
        sscanf(buf, "%lX", &tmp);
393
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
394
 
395
        val = (unsigned char)tmp;
396
        spin_lock_irqsave(&event_lock, flags);
397
        SET_PORT_BITS(TLCLK_REG3, 0xbf, val << 6);
398
        spin_unlock_irqrestore(&event_lock, flags);
399
 
400
        return strnlen(buf, count);
401
}
402
 
403
static DEVICE_ATTR(enable_clk3a_output, (S_IWUSR|S_IWGRP), NULL,
404
                store_enable_clk3a_output);
405
 
406
static ssize_t store_enable_clkb1_output(struct device *d,
407
                 struct device_attribute *attr, const char *buf, size_t count)
408
{
409
        unsigned long flags;
410
        unsigned long tmp;
411
        unsigned char val;
412
 
413
        sscanf(buf, "%lX", &tmp);
414
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
415
 
416
        val = (unsigned char)tmp;
417
        spin_lock_irqsave(&event_lock, flags);
418
        SET_PORT_BITS(TLCLK_REG2, 0xf7, val << 3);
419
        spin_unlock_irqrestore(&event_lock, flags);
420
 
421
        return strnlen(buf, count);
422
}
423
 
424
static DEVICE_ATTR(enable_clkb1_output, (S_IWUSR|S_IWGRP), NULL,
425
                store_enable_clkb1_output);
426
 
427
 
428
static ssize_t store_enable_clka1_output(struct device *d,
429
                 struct device_attribute *attr, const char *buf, size_t count)
430
{
431
        unsigned long flags;
432
        unsigned long tmp;
433
        unsigned char val;
434
 
435
        sscanf(buf, "%lX", &tmp);
436
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
437
 
438
        val = (unsigned char)tmp;
439
        spin_lock_irqsave(&event_lock, flags);
440
        SET_PORT_BITS(TLCLK_REG2, 0xfb, val << 2);
441
        spin_unlock_irqrestore(&event_lock, flags);
442
 
443
        return strnlen(buf, count);
444
}
445
 
446
static DEVICE_ATTR(enable_clka1_output, (S_IWUSR|S_IWGRP), NULL,
447
                store_enable_clka1_output);
448
 
449
static ssize_t store_enable_clkb0_output(struct device *d,
450
                 struct device_attribute *attr, const char *buf, size_t count)
451
{
452
        unsigned long flags;
453
        unsigned long tmp;
454
        unsigned char val;
455
 
456
        sscanf(buf, "%lX", &tmp);
457
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
458
 
459
        val = (unsigned char)tmp;
460
        spin_lock_irqsave(&event_lock, flags);
461
        SET_PORT_BITS(TLCLK_REG2, 0xfd, val << 1);
462
        spin_unlock_irqrestore(&event_lock, flags);
463
 
464
        return strnlen(buf, count);
465
}
466
 
467
static DEVICE_ATTR(enable_clkb0_output, (S_IWUSR|S_IWGRP), NULL,
468
                store_enable_clkb0_output);
469
 
470
static ssize_t store_enable_clka0_output(struct device *d,
471
                 struct device_attribute *attr, const char *buf, size_t count)
472
{
473
        unsigned long flags;
474
        unsigned long tmp;
475
        unsigned char val;
476
 
477
        sscanf(buf, "%lX", &tmp);
478
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
479
 
480
        val = (unsigned char)tmp;
481
        spin_lock_irqsave(&event_lock, flags);
482
        SET_PORT_BITS(TLCLK_REG2, 0xfe, val);
483
        spin_unlock_irqrestore(&event_lock, flags);
484
 
485
        return strnlen(buf, count);
486
}
487
 
488
static DEVICE_ATTR(enable_clka0_output, (S_IWUSR|S_IWGRP), NULL,
489
                store_enable_clka0_output);
490
 
491
static ssize_t store_select_amcb2_transmit_clock(struct device *d,
492
                struct device_attribute *attr, const char *buf, size_t count)
493
{
494
        unsigned long flags;
495
        unsigned long tmp;
496
        unsigned char val;
497
 
498
        sscanf(buf, "%lX", &tmp);
499
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
500
 
501
        val = (unsigned char)tmp;
502
        spin_lock_irqsave(&event_lock, flags);
503
                if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) {
504
                        SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x28);
505
                        SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val);
506
                } else if (val >= CLK_8_592MHz) {
507
                        SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x38);
508
                        switch (val) {
509
                        case CLK_8_592MHz:
510
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
511
                                break;
512
                        case CLK_11_184MHz:
513
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
514
                                break;
515
                        case CLK_34_368MHz:
516
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
517
                                break;
518
                        case CLK_44_736MHz:
519
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
520
                                break;
521
                        }
522
                } else
523
                        SET_PORT_BITS(TLCLK_REG3, 0xc7, val << 3);
524
 
525
        spin_unlock_irqrestore(&event_lock, flags);
526
 
527
        return strnlen(buf, count);
528
}
529
 
530
static DEVICE_ATTR(select_amcb2_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
531
        store_select_amcb2_transmit_clock);
532
 
533
static ssize_t store_select_amcb1_transmit_clock(struct device *d,
534
                 struct device_attribute *attr, const char *buf, size_t count)
535
{
536
        unsigned long tmp;
537
        unsigned char val;
538
        unsigned long flags;
539
 
540
        sscanf(buf, "%lX", &tmp);
541
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
542
 
543
        val = (unsigned char)tmp;
544
        spin_lock_irqsave(&event_lock, flags);
545
                if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) {
546
                        SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x5);
547
                        SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val);
548
                } else if (val >= CLK_8_592MHz) {
549
                        SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
550
                        switch (val) {
551
                        case CLK_8_592MHz:
552
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
553
                                break;
554
                        case CLK_11_184MHz:
555
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
556
                                break;
557
                        case CLK_34_368MHz:
558
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
559
                                break;
560
                        case CLK_44_736MHz:
561
                                SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
562
                                break;
563
                        }
564
                } else
565
                        SET_PORT_BITS(TLCLK_REG3, 0xf8, val);
566
        spin_unlock_irqrestore(&event_lock, flags);
567
 
568
        return strnlen(buf, count);
569
}
570
 
571
static DEVICE_ATTR(select_amcb1_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
572
                store_select_amcb1_transmit_clock);
573
 
574
static ssize_t store_select_redundant_clock(struct device *d,
575
                 struct device_attribute *attr, const char *buf, size_t count)
576
{
577
        unsigned long tmp;
578
        unsigned char val;
579
        unsigned long flags;
580
 
581
        sscanf(buf, "%lX", &tmp);
582
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
583
 
584
        val = (unsigned char)tmp;
585
        spin_lock_irqsave(&event_lock, flags);
586
        SET_PORT_BITS(TLCLK_REG1, 0xfe, val);
587
        spin_unlock_irqrestore(&event_lock, flags);
588
 
589
        return strnlen(buf, count);
590
}
591
 
592
static DEVICE_ATTR(select_redundant_clock, (S_IWUSR|S_IWGRP), NULL,
593
                store_select_redundant_clock);
594
 
595
static ssize_t store_select_ref_frequency(struct device *d,
596
                 struct device_attribute *attr, const char *buf, size_t count)
597
{
598
        unsigned long tmp;
599
        unsigned char val;
600
        unsigned long flags;
601
 
602
        sscanf(buf, "%lX", &tmp);
603
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
604
 
605
        val = (unsigned char)tmp;
606
        spin_lock_irqsave(&event_lock, flags);
607
        SET_PORT_BITS(TLCLK_REG1, 0xfd, val);
608
        spin_unlock_irqrestore(&event_lock, flags);
609
 
610
        return strnlen(buf, count);
611
}
612
 
613
static DEVICE_ATTR(select_ref_frequency, (S_IWUSR|S_IWGRP), NULL,
614
                store_select_ref_frequency);
615
 
616
static ssize_t store_filter_select(struct device *d,
617
                 struct device_attribute *attr, const char *buf, size_t count)
618
{
619
        unsigned long tmp;
620
        unsigned char val;
621
        unsigned long flags;
622
 
623
        sscanf(buf, "%lX", &tmp);
624
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
625
 
626
        val = (unsigned char)tmp;
627
        spin_lock_irqsave(&event_lock, flags);
628
        SET_PORT_BITS(TLCLK_REG0, 0xfb, val);
629
        spin_unlock_irqrestore(&event_lock, flags);
630
 
631
        return strnlen(buf, count);
632
}
633
 
634
static DEVICE_ATTR(filter_select, (S_IWUSR|S_IWGRP), NULL, store_filter_select);
635
 
636
static ssize_t store_hardware_switching_mode(struct device *d,
637
                 struct device_attribute *attr, const char *buf, size_t count)
638
{
639
        unsigned long tmp;
640
        unsigned char val;
641
        unsigned long flags;
642
 
643
        sscanf(buf, "%lX", &tmp);
644
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
645
 
646
        val = (unsigned char)tmp;
647
        spin_lock_irqsave(&event_lock, flags);
648
        SET_PORT_BITS(TLCLK_REG0, 0xbf, val);
649
        spin_unlock_irqrestore(&event_lock, flags);
650
 
651
        return strnlen(buf, count);
652
}
653
 
654
static DEVICE_ATTR(hardware_switching_mode, (S_IWUSR|S_IWGRP), NULL,
655
                store_hardware_switching_mode);
656
 
657
static ssize_t store_hardware_switching(struct device *d,
658
                 struct device_attribute *attr, const char *buf, size_t count)
659
{
660
        unsigned long tmp;
661
        unsigned char val;
662
        unsigned long flags;
663
 
664
        sscanf(buf, "%lX", &tmp);
665
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
666
 
667
        val = (unsigned char)tmp;
668
        spin_lock_irqsave(&event_lock, flags);
669
        SET_PORT_BITS(TLCLK_REG0, 0x7f, val);
670
        spin_unlock_irqrestore(&event_lock, flags);
671
 
672
        return strnlen(buf, count);
673
}
674
 
675
static DEVICE_ATTR(hardware_switching, (S_IWUSR|S_IWGRP), NULL,
676
                store_hardware_switching);
677
 
678
static ssize_t store_refalign (struct device *d,
679
                 struct device_attribute *attr, const char *buf, size_t count)
680
{
681
        unsigned long tmp;
682
        unsigned long flags;
683
 
684
        sscanf(buf, "%lX", &tmp);
685
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
686
        spin_lock_irqsave(&event_lock, flags);
687
        SET_PORT_BITS(TLCLK_REG0, 0xf7, 0);
688
        SET_PORT_BITS(TLCLK_REG0, 0xf7, 0x08);
689
        SET_PORT_BITS(TLCLK_REG0, 0xf7, 0);
690
        spin_unlock_irqrestore(&event_lock, flags);
691
 
692
        return strnlen(buf, count);
693
}
694
 
695
static DEVICE_ATTR(refalign, (S_IWUSR|S_IWGRP), NULL, store_refalign);
696
 
697
static ssize_t store_mode_select (struct device *d,
698
                 struct device_attribute *attr, const char *buf, size_t count)
699
{
700
        unsigned long tmp;
701
        unsigned char val;
702
        unsigned long flags;
703
 
704
        sscanf(buf, "%lX", &tmp);
705
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
706
 
707
        val = (unsigned char)tmp;
708
        spin_lock_irqsave(&event_lock, flags);
709
        SET_PORT_BITS(TLCLK_REG0, 0xcf, val);
710
        spin_unlock_irqrestore(&event_lock, flags);
711
 
712
        return strnlen(buf, count);
713
}
714
 
715
static DEVICE_ATTR(mode_select, (S_IWUSR|S_IWGRP), NULL, store_mode_select);
716
 
717
static ssize_t store_reset (struct device *d,
718
                 struct device_attribute *attr, const char *buf, size_t count)
719
{
720
        unsigned long tmp;
721
        unsigned char val;
722
        unsigned long flags;
723
 
724
        sscanf(buf, "%lX", &tmp);
725
        dev_dbg(d, "tmp = 0x%lX\n", tmp);
726
 
727
        val = (unsigned char)tmp;
728
        spin_lock_irqsave(&event_lock, flags);
729
        SET_PORT_BITS(TLCLK_REG4, 0xfd, val);
730
        spin_unlock_irqrestore(&event_lock, flags);
731
 
732
        return strnlen(buf, count);
733
}
734
 
735
static DEVICE_ATTR(reset, (S_IWUSR|S_IWGRP), NULL, store_reset);
736
 
737
static struct attribute *tlclk_sysfs_entries[] = {
738
        &dev_attr_current_ref.attr,
739
        &dev_attr_telclock_version.attr,
740
        &dev_attr_alarms.attr,
741
        &dev_attr_received_ref_clk3a.attr,
742
        &dev_attr_received_ref_clk3b.attr,
743
        &dev_attr_enable_clk3a_output.attr,
744
        &dev_attr_enable_clk3b_output.attr,
745
        &dev_attr_enable_clkb1_output.attr,
746
        &dev_attr_enable_clka1_output.attr,
747
        &dev_attr_enable_clkb0_output.attr,
748
        &dev_attr_enable_clka0_output.attr,
749
        &dev_attr_select_amcb1_transmit_clock.attr,
750
        &dev_attr_select_amcb2_transmit_clock.attr,
751
        &dev_attr_select_redundant_clock.attr,
752
        &dev_attr_select_ref_frequency.attr,
753
        &dev_attr_filter_select.attr,
754
        &dev_attr_hardware_switching_mode.attr,
755
        &dev_attr_hardware_switching.attr,
756
        &dev_attr_refalign.attr,
757
        &dev_attr_mode_select.attr,
758
        &dev_attr_reset.attr,
759
        NULL
760
};
761
 
762
static struct attribute_group tlclk_attribute_group = {
763
        .name = NULL,           /* put in device directory */
764
        .attrs = tlclk_sysfs_entries,
765
};
766
 
767
static struct platform_device *tlclk_device;
768
 
769
static int __init tlclk_init(void)
770
{
771
        int ret;
772
 
773
        ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops);
774
        if (ret < 0) {
775
                printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major);
776
                return ret;
777
        }
778
        tlclk_major = ret;
779
        alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
780
        if (!alarm_events)
781
                goto out1;
782
 
783
        /* Read telecom clock IRQ number (Set by BIOS) */
784
        if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
785
                printk(KERN_ERR "tlclk: request_region 0x%X failed.\n",
786
                        TLCLK_BASE);
787
                ret = -EBUSY;
788
                goto out2;
789
        }
790
        telclk_interrupt = (inb(TLCLK_REG7) & 0x0f);
791
 
792
        if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */
793
                printk(KERN_ERR "telclk_interrup = 0x%x non-mcpbl0010 hw.\n",
794
                        telclk_interrupt);
795
                ret = -ENXIO;
796
                goto out3;
797
        }
798
 
799
        init_timer(&switchover_timer);
800
 
801
        ret = misc_register(&tlclk_miscdev);
802
        if (ret < 0) {
803
                printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret);
804
                goto out3;
805
        }
806
 
807
        tlclk_device = platform_device_register_simple("telco_clock",
808
                                -1, NULL, 0);
809
        if (IS_ERR(tlclk_device)) {
810
                printk(KERN_ERR "tlclk: platform_device_register failed.\n");
811
                ret = PTR_ERR(tlclk_device);
812
                goto out4;
813
        }
814
 
815
        ret = sysfs_create_group(&tlclk_device->dev.kobj,
816
                        &tlclk_attribute_group);
817
        if (ret) {
818
                printk(KERN_ERR "tlclk: failed to create sysfs device attributes.\n");
819
                goto out5;
820
        }
821
 
822
        return 0;
823
out5:
824
        platform_device_unregister(tlclk_device);
825
out4:
826
        misc_deregister(&tlclk_miscdev);
827
out3:
828
        release_region(TLCLK_BASE, 8);
829
out2:
830
        kfree(alarm_events);
831
out1:
832
        unregister_chrdev(tlclk_major, "telco_clock");
833
        return ret;
834
}
835
 
836
static void __exit tlclk_cleanup(void)
837
{
838
        sysfs_remove_group(&tlclk_device->dev.kobj, &tlclk_attribute_group);
839
        platform_device_unregister(tlclk_device);
840
        misc_deregister(&tlclk_miscdev);
841
        unregister_chrdev(tlclk_major, "telco_clock");
842
 
843
        release_region(TLCLK_BASE, 8);
844
        del_timer_sync(&switchover_timer);
845
        kfree(alarm_events);
846
 
847
}
848
 
849
static void switchover_timeout(unsigned long data)
850
{
851
        unsigned long flags = *(unsigned long *) data;
852
 
853
        if ((flags & 1)) {
854
                if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
855
                        alarm_events->switchover_primary++;
856
        } else {
857
                if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
858
                        alarm_events->switchover_secondary++;
859
        }
860
 
861
        /* Alarm processing is done, wake up read task */
862
        del_timer(&switchover_timer);
863
        got_event = 1;
864
        wake_up(&wq);
865
}
866
 
867
static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
868
{
869
        unsigned long flags;
870
 
871
        spin_lock_irqsave(&event_lock, flags);
872
        /* Read and clear interrupt events */
873
        int_events = inb(TLCLK_REG6);
874
 
875
        /* Primary_Los changed from 0 to 1 ? */
876
        if (int_events & PRI_LOS_01_MASK) {
877
                if (inb(TLCLK_REG2) & SEC_LOST_MASK)
878
                        alarm_events->lost_clocks++;
879
                else
880
                        alarm_events->lost_primary_clock++;
881
        }
882
 
883
        /* Primary_Los changed from 1 to 0 ? */
884
        if (int_events & PRI_LOS_10_MASK) {
885
                alarm_events->primary_clock_back++;
886
                SET_PORT_BITS(TLCLK_REG1, 0xFE, 1);
887
        }
888
        /* Secondary_Los changed from 0 to 1 ? */
889
        if (int_events & SEC_LOS_01_MASK) {
890
                if (inb(TLCLK_REG2) & PRI_LOST_MASK)
891
                        alarm_events->lost_clocks++;
892
                else
893
                        alarm_events->lost_secondary_clock++;
894
        }
895
        /* Secondary_Los changed from 1 to 0 ? */
896
        if (int_events & SEC_LOS_10_MASK) {
897
                alarm_events->secondary_clock_back++;
898
                SET_PORT_BITS(TLCLK_REG1, 0xFE, 0);
899
        }
900
        if (int_events & HOLDOVER_10_MASK)
901
                alarm_events->pll_end_holdover++;
902
 
903
        if (int_events & UNLOCK_01_MASK)
904
                alarm_events->pll_lost_sync++;
905
 
906
        if (int_events & UNLOCK_10_MASK)
907
                alarm_events->pll_sync++;
908
 
909
        /* Holdover changed from 0 to 1 ? */
910
        if (int_events & HOLDOVER_01_MASK) {
911
                alarm_events->pll_holdover++;
912
 
913
                /* TIMEOUT in ~10ms */
914
                switchover_timer.expires = jiffies + msecs_to_jiffies(10);
915
                tlclk_timer_data = inb(TLCLK_REG1);
916
                switchover_timer.data = (unsigned long) &tlclk_timer_data;
917
                mod_timer(&switchover_timer, switchover_timer.expires);
918
        } else {
919
                got_event = 1;
920
                wake_up(&wq);
921
        }
922
        spin_unlock_irqrestore(&event_lock, flags);
923
 
924
        return IRQ_HANDLED;
925
}
926
 
927
module_init(tlclk_init);
928
module_exit(tlclk_cleanup);

powered by: WebSVN 2.1.0

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