These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3501.c
1 /* Watchdog Related Defines */
2
3 #define ADDIDATA_TIMER                  0
4 #define ADDIDATA_WATCHDOG               2
5
6 /*
7  * (*insn_config) for the timer subdevice
8  *
9  * Configures The Timer, Counter or Watchdog
10  * Data Pointer contains configuration parameters as below
11  *      data[0] : 0 Configure As Timer
12  *                1 Configure As Counter
13  *                2 Configure As Watchdog
14  *      data[1] : 1 Enable  Interrupt
15  *                0 Disable Interrupt
16  *      data[2] : Time Unit
17  *      data[3] : Reload Value
18  */
19 static int apci3501_config_insn_timer(struct comedi_device *dev,
20                                       struct comedi_subdevice *s,
21                                       struct comedi_insn *insn,
22                                       unsigned int *data)
23 {
24         struct apci3501_private *devpriv = dev->private;
25         unsigned int ctrl;
26
27         if (data[0] != ADDIDATA_WATCHDOG &&
28             data[0] != ADDIDATA_TIMER)
29                 return -EINVAL;
30
31         devpriv->tsk_Current = current;
32
33         devpriv->timer_mode = data[0];
34
35         /* first, disable the watchdog or stop the timer */
36         if (devpriv->timer_mode == ADDIDATA_WATCHDOG) {
37                 ctrl = 0;
38         } else {
39                 ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
40                 ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
41                           ADDI_TCW_CTRL_ENA);
42         }
43         outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
44
45         /* enable/disable the timer interrupt */
46         ctrl = (data[1] == 1) ? ADDI_TCW_CTRL_IRQ_ENA : 0;
47         outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
48
49         outl(data[2], devpriv->tcw + ADDI_TCW_TIMEBASE_REG);
50         outl(data[3], devpriv->tcw + ADDI_TCW_RELOAD_REG);
51
52         ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
53         if (devpriv->timer_mode == ADDIDATA_WATCHDOG) {
54                 /* Set the mode (e2->e0) NOTE: this doesn't look correct */
55                 ctrl |= ~(ADDI_TCW_CTRL_CNT_UP | ADDI_TCW_CTRL_EXT_CLK_MASK |
56                           ADDI_TCW_CTRL_MODE_MASK | ADDI_TCW_CTRL_GATE |
57                           ADDI_TCW_CTRL_TRIG | ADDI_TCW_CTRL_TIMER_ENA |
58                           ADDI_TCW_CTRL_RESET_ENA | ADDI_TCW_CTRL_WARN_ENA |
59                           ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_ENA);
60         } else {
61                 /* mode 2 */
62                 ctrl &= ~(ADDI_TCW_CTRL_CNTR_ENA | ADDI_TCW_CTRL_MODE_MASK |
63                           ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
64                           ADDI_TCW_CTRL_TIMER_ENA | ADDI_TCW_CTRL_RESET_ENA |
65                           ADDI_TCW_CTRL_WARN_ENA | ADDI_TCW_CTRL_ENA);
66                 ctrl |= ADDI_TCW_CTRL_MODE(2) | ADDI_TCW_CTRL_TIMER_ENA;
67         }
68         outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
69
70         return insn->n;
71 }
72
73 /*
74  * (*insn_write) for the timer subdevice
75  *
76  * Start / Stop The Selected Timer , Counter or Watchdog
77  * Data Pointer contains configuration parameters as below
78  *      data[0] : 0 Timer
79  *                1 Counter
80  *                2 Watchdog
81  *      data[1] : 1 Start
82  *                0 Stop
83  *                2 Trigger
84  */
85 static int apci3501_write_insn_timer(struct comedi_device *dev,
86                                      struct comedi_subdevice *s,
87                                      struct comedi_insn *insn,
88                                      unsigned int *data)
89 {
90         struct apci3501_private *devpriv = dev->private;
91         unsigned int ctrl;
92
93         if (devpriv->timer_mode == ADDIDATA_WATCHDOG ||
94             devpriv->timer_mode == ADDIDATA_TIMER) {
95                 ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
96                 ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG);
97
98                 if (data[1] == 1) {             /* enable */
99                         ctrl |= ADDI_TCW_CTRL_ENA;
100                 } else if (data[1] == 0) {      /* stop */
101                         if (devpriv->timer_mode == ADDIDATA_WATCHDOG)
102                                 ctrl = 0;
103                         else
104                                 ctrl &= ~ADDI_TCW_CTRL_ENA;
105                 } else if (data[1] == 2) {      /* trigger */
106                         ctrl |= ADDI_TCW_CTRL_TRIG;
107                 }
108                 outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
109         }
110
111         inl(devpriv->tcw + ADDI_TCW_STATUS_REG);
112         return insn->n;
113 }
114
115 /*
116  * (*insn_read) for the timer subdevice
117  *
118  * Read The Selected Timer, Counter or Watchdog
119  * Data Pointer contains configuration parameters as below
120  *      data[0] : 0 Timer
121  *                1 Counter
122  *                2 Watchdog
123  *      data[1] : Timer Counter Watchdog Number
124  */
125 static int apci3501_read_insn_timer(struct comedi_device *dev,
126                                     struct comedi_subdevice *s,
127                                     struct comedi_insn *insn,
128                                     unsigned int *data)
129 {
130         struct apci3501_private *devpriv = dev->private;
131
132         if (devpriv->timer_mode != ADDIDATA_TIMER &&
133             devpriv->timer_mode != ADDIDATA_WATCHDOG)
134                 return -EINVAL;
135
136         data[0] = inl(devpriv->tcw + ADDI_TCW_STATUS_REG) &
137                   ADDI_TCW_STATUS_OVERFLOW;
138         data[1] = inl(devpriv->tcw + ADDI_TCW_VAL_REG);
139
140         return insn->n;
141 }