1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Mantis PCI bridge driver |
4 | |
5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
6 | |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/spinlock.h> |
11 | #include <asm/io.h> |
12 | |
13 | #include <linux/signal.h> |
14 | #include <linux/sched.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/pci.h> |
17 | |
18 | #include <media/dmxdev.h> |
19 | #include <media/dvbdev.h> |
20 | #include <media/dvb_demux.h> |
21 | #include <media/dvb_frontend.h> |
22 | #include <media/dvb_net.h> |
23 | |
24 | #include "mantis_common.h" |
25 | #include "mantis_reg.h" |
26 | #include "mantis_uart.h" |
27 | #include "mantis_input.h" |
28 | |
29 | struct mantis_uart_params { |
30 | enum mantis_baud baud_rate; |
31 | enum mantis_parity parity; |
32 | }; |
33 | |
34 | static struct { |
35 | char string[7]; |
36 | } rates[5] = { |
37 | { "9600" }, |
38 | { "19200" }, |
39 | { "38400" }, |
40 | { "57600" }, |
41 | { "115200" } |
42 | }; |
43 | |
44 | static struct { |
45 | char string[5]; |
46 | } parity[3] = { |
47 | { "NONE" }, |
48 | { "ODD" }, |
49 | { "EVEN" } |
50 | }; |
51 | |
52 | static void mantis_uart_read(struct mantis_pci *mantis) |
53 | { |
54 | struct mantis_hwconfig *config = mantis->hwconfig; |
55 | int i, scancode = 0, err = 0; |
56 | |
57 | /* get data */ |
58 | dprintk(MANTIS_DEBUG, 1, "UART Reading ..." ); |
59 | for (i = 0; i < (config->bytes + 1); i++) { |
60 | int data = mmread(MANTIS_UART_RXD); |
61 | |
62 | dprintk(MANTIS_DEBUG, 0, " <%02x>" , data); |
63 | |
64 | scancode = (scancode << 8) | (data & 0x3f); |
65 | err |= data; |
66 | |
67 | if (data & (1 << 7)) |
68 | dprintk(MANTIS_ERROR, 1, "UART framing error" ); |
69 | |
70 | if (data & (1 << 6)) |
71 | dprintk(MANTIS_ERROR, 1, "UART parity error" ); |
72 | } |
73 | dprintk(MANTIS_DEBUG, 0, "\n" ); |
74 | |
75 | if ((err & 0xC0) == 0) |
76 | mantis_input_process(mantis, scancode); |
77 | } |
78 | |
79 | static void mantis_uart_work(struct work_struct *work) |
80 | { |
81 | struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); |
82 | u32 stat; |
83 | unsigned long timeout; |
84 | |
85 | stat = mmread(MANTIS_UART_STAT); |
86 | |
87 | if (stat & MANTIS_UART_RXFIFO_FULL) |
88 | dprintk(MANTIS_ERROR, 1, "RX Fifo FULL" ); |
89 | |
90 | /* |
91 | * MANTIS_UART_RXFIFO_DATA is only set if at least |
92 | * config->bytes + 1 bytes are in the FIFO. |
93 | */ |
94 | |
95 | /* FIXME: is 10ms good enough ? */ |
96 | timeout = jiffies + msecs_to_jiffies(m: 10); |
97 | while (stat & MANTIS_UART_RXFIFO_DATA) { |
98 | mantis_uart_read(mantis); |
99 | stat = mmread(MANTIS_UART_STAT); |
100 | |
101 | if (!time_is_after_jiffies(timeout)) |
102 | break; |
103 | } |
104 | |
105 | /* re-enable UART (RX) interrupt */ |
106 | mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); |
107 | } |
108 | |
109 | static int mantis_uart_setup(struct mantis_pci *mantis, |
110 | struct mantis_uart_params *params) |
111 | { |
112 | u32 reg; |
113 | |
114 | mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); |
115 | |
116 | reg = mmread(MANTIS_UART_BAUD); |
117 | |
118 | switch (params->baud_rate) { |
119 | case MANTIS_BAUD_9600: |
120 | reg |= 0xd8; |
121 | break; |
122 | case MANTIS_BAUD_19200: |
123 | reg |= 0x6c; |
124 | break; |
125 | case MANTIS_BAUD_38400: |
126 | reg |= 0x36; |
127 | break; |
128 | case MANTIS_BAUD_57600: |
129 | reg |= 0x23; |
130 | break; |
131 | case MANTIS_BAUD_115200: |
132 | reg |= 0x11; |
133 | break; |
134 | default: |
135 | return -EINVAL; |
136 | } |
137 | |
138 | mmwrite(reg, MANTIS_UART_BAUD); |
139 | |
140 | return 0; |
141 | } |
142 | |
143 | int mantis_uart_init(struct mantis_pci *mantis) |
144 | { |
145 | struct mantis_hwconfig *config = mantis->hwconfig; |
146 | struct mantis_uart_params params; |
147 | |
148 | /* default parity: */ |
149 | params.baud_rate = config->baud_rate; |
150 | params.parity = config->parity; |
151 | dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s" , |
152 | rates[params.baud_rate].string, |
153 | parity[params.parity].string); |
154 | |
155 | INIT_WORK(&mantis->uart_work, mantis_uart_work); |
156 | |
157 | /* disable interrupt */ |
158 | mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); |
159 | |
160 | mantis_uart_setup(mantis, params: ¶ms); |
161 | |
162 | /* default 1 byte */ |
163 | mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); |
164 | |
165 | /* flush buffer */ |
166 | mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); |
167 | |
168 | /* enable interrupt */ |
169 | mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); |
170 | mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); |
171 | |
172 | schedule_work(work: &mantis->uart_work); |
173 | dprintk(MANTIS_DEBUG, 1, "UART successfully initialized" ); |
174 | |
175 | return 0; |
176 | } |
177 | EXPORT_SYMBOL_GPL(mantis_uart_init); |
178 | |
179 | void mantis_uart_exit(struct mantis_pci *mantis) |
180 | { |
181 | /* disable interrupt */ |
182 | mantis_mask_ints(mantis, MANTIS_INT_IRQ1); |
183 | mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); |
184 | flush_work(work: &mantis->uart_work); |
185 | } |
186 | EXPORT_SYMBOL_GPL(mantis_uart_exit); |
187 | |