diff options
-rw-r--r-- | drivers/media/pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/pci/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/pci/smipcie/Kconfig | 11 | ||||
-rw-r--r-- | drivers/media/pci/smipcie/Makefile | 6 | ||||
-rw-r--r-- | drivers/media/pci/smipcie/smipcie.c | 943 | ||||
-rw-r--r-- | drivers/media/pci/smipcie/smipcie.h | 299 |
6 files changed, 1262 insertions, 1 deletions
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index f8cec8e8cf82..218144a99016 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig | |||
@@ -46,6 +46,7 @@ source "drivers/media/pci/pt3/Kconfig" | |||
46 | source "drivers/media/pci/mantis/Kconfig" | 46 | source "drivers/media/pci/mantis/Kconfig" |
47 | source "drivers/media/pci/ngene/Kconfig" | 47 | source "drivers/media/pci/ngene/Kconfig" |
48 | source "drivers/media/pci/ddbridge/Kconfig" | 48 | source "drivers/media/pci/ddbridge/Kconfig" |
49 | source "drivers/media/pci/smipcie/Kconfig" | ||
49 | endif | 50 | endif |
50 | 51 | ||
51 | endif #MEDIA_PCI_SUPPORT | 52 | endif #MEDIA_PCI_SUPPORT |
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index a12926e4b51f..0baf0d2967ee 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile | |||
@@ -11,7 +11,8 @@ obj-y += ttpci/ \ | |||
11 | mantis/ \ | 11 | mantis/ \ |
12 | ngene/ \ | 12 | ngene/ \ |
13 | ddbridge/ \ | 13 | ddbridge/ \ |
14 | saa7146/ | 14 | saa7146/ \ |
15 | smipcie/ | ||
15 | 16 | ||
16 | obj-$(CONFIG_VIDEO_IVTV) += ivtv/ | 17 | obj-$(CONFIG_VIDEO_IVTV) += ivtv/ |
17 | obj-$(CONFIG_VIDEO_ZORAN) += zoran/ | 18 | obj-$(CONFIG_VIDEO_ZORAN) += zoran/ |
diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig new file mode 100644 index 000000000000..78b76ca85ed4 --- /dev/null +++ b/drivers/media/pci/smipcie/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config DVB_SMIPCIE | ||
2 | tristate "SMI PCIe DVBSky cards" | ||
3 | depends on DVB_CORE && PCI && I2C | ||
4 | select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT | ||
5 | select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT | ||
6 | help | ||
7 | Support for cards with SMI PCIe bridge: | ||
8 | - DVBSky S950 V3 | ||
9 | |||
10 | Say Y or M if you own such a device and want to use it. | ||
11 | If unsure say N. | ||
diff --git a/drivers/media/pci/smipcie/Makefile b/drivers/media/pci/smipcie/Makefile new file mode 100644 index 000000000000..be55481a6e95 --- /dev/null +++ b/drivers/media/pci/smipcie/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o | ||
2 | |||
3 | ccflags-y += -Idrivers/media/tuners | ||
4 | ccflags-y += -Idrivers/media/dvb-core | ||
5 | ccflags-y += -Idrivers/media/dvb-frontends | ||
6 | |||
diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c new file mode 100644 index 000000000000..3522da4fa5d9 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie.c | |||
@@ -0,0 +1,943 @@ | |||
1 | /* | ||
2 | * SMI PCIe driver for DVBSky cards. | ||
3 | * | ||
4 | * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include "smipcie.h" | ||
18 | #include "m88ds3103.h" | ||
19 | #include "m88ts2022.h" | ||
20 | |||
21 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
22 | |||
23 | static int smi_hw_init(struct smi_dev *dev) | ||
24 | { | ||
25 | u32 port_mux, port_ctrl, int_stat; | ||
26 | |||
27 | /* set port mux.*/ | ||
28 | port_mux = smi_read(MUX_MODE_CTRL); | ||
29 | port_mux &= ~(rbPaMSMask); | ||
30 | port_mux |= rbPaMSDtvNoGpio; | ||
31 | port_mux &= ~(rbPbMSMask); | ||
32 | port_mux |= rbPbMSDtvNoGpio; | ||
33 | port_mux &= ~(0x0f0000); | ||
34 | port_mux |= 0x50000; | ||
35 | smi_write(MUX_MODE_CTRL, port_mux); | ||
36 | |||
37 | /* set DTV register.*/ | ||
38 | /* Port A */ | ||
39 | port_ctrl = smi_read(VIDEO_CTRL_STATUS_A); | ||
40 | port_ctrl &= ~0x01; | ||
41 | smi_write(VIDEO_CTRL_STATUS_A, port_ctrl); | ||
42 | port_ctrl = smi_read(MPEG2_CTRL_A); | ||
43 | port_ctrl &= ~0x40; | ||
44 | port_ctrl |= 0x80; | ||
45 | smi_write(MPEG2_CTRL_A, port_ctrl); | ||
46 | /* Port B */ | ||
47 | port_ctrl = smi_read(VIDEO_CTRL_STATUS_B); | ||
48 | port_ctrl &= ~0x01; | ||
49 | smi_write(VIDEO_CTRL_STATUS_B, port_ctrl); | ||
50 | port_ctrl = smi_read(MPEG2_CTRL_B); | ||
51 | port_ctrl &= ~0x40; | ||
52 | port_ctrl |= 0x80; | ||
53 | smi_write(MPEG2_CTRL_B, port_ctrl); | ||
54 | |||
55 | /* disable and clear interrupt.*/ | ||
56 | smi_write(MSI_INT_ENA_CLR, ALL_INT); | ||
57 | int_stat = smi_read(MSI_INT_STATUS); | ||
58 | smi_write(MSI_INT_STATUS_CLR, int_stat); | ||
59 | |||
60 | /* reset demod.*/ | ||
61 | smi_clear(PERIPHERAL_CTRL, 0x0303); | ||
62 | msleep(50); | ||
63 | smi_set(PERIPHERAL_CTRL, 0x0101); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* i2c bit bus.*/ | ||
68 | static void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl) | ||
69 | { | ||
70 | u32 dwCtrl; | ||
71 | |||
72 | dwCtrl = smi_read(sw_ctl); | ||
73 | dwCtrl &= ~0x18; /* disable output.*/ | ||
74 | dwCtrl |= 0x21; /* reset and software mode.*/ | ||
75 | dwCtrl &= ~0xff00; | ||
76 | dwCtrl |= 0x6400; | ||
77 | smi_write(sw_ctl, dwCtrl); | ||
78 | msleep(20); | ||
79 | dwCtrl = smi_read(sw_ctl); | ||
80 | dwCtrl &= ~0x20; | ||
81 | smi_write(sw_ctl, dwCtrl); | ||
82 | } | ||
83 | |||
84 | static void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl) | ||
85 | { | ||
86 | if (state) { | ||
87 | /* set as input.*/ | ||
88 | smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); | ||
89 | } else { | ||
90 | smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT); | ||
91 | /* set as output.*/ | ||
92 | smi_set(sw_ctl, SW_I2C_MSK_DAT_EN); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static void smi_i2c_setscl(void *data, int state, u32 sw_ctl) | ||
97 | { | ||
98 | struct smi_dev *dev = data; | ||
99 | |||
100 | if (state) { | ||
101 | /* set as input.*/ | ||
102 | smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); | ||
103 | } else { | ||
104 | smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT); | ||
105 | /* set as output.*/ | ||
106 | smi_set(sw_ctl, SW_I2C_MSK_CLK_EN); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static int smi_i2c_getsda(void *data, u32 sw_ctl) | ||
111 | { | ||
112 | struct smi_dev *dev = data; | ||
113 | /* set as input.*/ | ||
114 | smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); | ||
115 | udelay(1); | ||
116 | return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0; | ||
117 | } | ||
118 | |||
119 | static int smi_i2c_getscl(void *data, u32 sw_ctl) | ||
120 | { | ||
121 | struct smi_dev *dev = data; | ||
122 | /* set as input.*/ | ||
123 | smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); | ||
124 | udelay(1); | ||
125 | return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0; | ||
126 | } | ||
127 | /* i2c 0.*/ | ||
128 | static void smi_i2c0_setsda(void *data, int state) | ||
129 | { | ||
130 | struct smi_dev *dev = data; | ||
131 | |||
132 | smi_i2c_setsda(dev, state, I2C_A_SW_CTL); | ||
133 | } | ||
134 | |||
135 | static void smi_i2c0_setscl(void *data, int state) | ||
136 | { | ||
137 | struct smi_dev *dev = data; | ||
138 | |||
139 | smi_i2c_setscl(dev, state, I2C_A_SW_CTL); | ||
140 | } | ||
141 | |||
142 | static int smi_i2c0_getsda(void *data) | ||
143 | { | ||
144 | struct smi_dev *dev = data; | ||
145 | |||
146 | return smi_i2c_getsda(dev, I2C_A_SW_CTL); | ||
147 | } | ||
148 | |||
149 | static int smi_i2c0_getscl(void *data) | ||
150 | { | ||
151 | struct smi_dev *dev = data; | ||
152 | |||
153 | return smi_i2c_getscl(dev, I2C_A_SW_CTL); | ||
154 | } | ||
155 | /* i2c 1.*/ | ||
156 | static void smi_i2c1_setsda(void *data, int state) | ||
157 | { | ||
158 | struct smi_dev *dev = data; | ||
159 | |||
160 | smi_i2c_setsda(dev, state, I2C_B_SW_CTL); | ||
161 | } | ||
162 | |||
163 | static void smi_i2c1_setscl(void *data, int state) | ||
164 | { | ||
165 | struct smi_dev *dev = data; | ||
166 | |||
167 | smi_i2c_setscl(dev, state, I2C_B_SW_CTL); | ||
168 | } | ||
169 | |||
170 | static int smi_i2c1_getsda(void *data) | ||
171 | { | ||
172 | struct smi_dev *dev = data; | ||
173 | |||
174 | return smi_i2c_getsda(dev, I2C_B_SW_CTL); | ||
175 | } | ||
176 | |||
177 | static int smi_i2c1_getscl(void *data) | ||
178 | { | ||
179 | struct smi_dev *dev = data; | ||
180 | |||
181 | return smi_i2c_getscl(dev, I2C_B_SW_CTL); | ||
182 | } | ||
183 | |||
184 | static int smi_i2c_init(struct smi_dev *dev) | ||
185 | { | ||
186 | int ret; | ||
187 | |||
188 | /* i2c bus 0 */ | ||
189 | smi_i2c_cfg(dev, I2C_A_SW_CTL); | ||
190 | i2c_set_adapdata(&dev->i2c_bus[0], dev); | ||
191 | strcpy(dev->i2c_bus[0].name, "SMI-I2C0"); | ||
192 | dev->i2c_bus[0].owner = THIS_MODULE; | ||
193 | dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev; | ||
194 | dev->i2c_bus[0].algo_data = &dev->i2c_bit[0]; | ||
195 | dev->i2c_bit[0].data = dev; | ||
196 | dev->i2c_bit[0].setsda = smi_i2c0_setsda; | ||
197 | dev->i2c_bit[0].setscl = smi_i2c0_setscl; | ||
198 | dev->i2c_bit[0].getsda = smi_i2c0_getsda; | ||
199 | dev->i2c_bit[0].getscl = smi_i2c0_getscl; | ||
200 | dev->i2c_bit[0].udelay = 12; | ||
201 | dev->i2c_bit[0].timeout = 10; | ||
202 | /* Raise SCL and SDA */ | ||
203 | smi_i2c0_setsda(dev, 1); | ||
204 | smi_i2c0_setscl(dev, 1); | ||
205 | |||
206 | ret = i2c_bit_add_bus(&dev->i2c_bus[0]); | ||
207 | if (ret < 0) | ||
208 | return ret; | ||
209 | |||
210 | /* i2c bus 1 */ | ||
211 | smi_i2c_cfg(dev, I2C_B_SW_CTL); | ||
212 | i2c_set_adapdata(&dev->i2c_bus[1], dev); | ||
213 | strcpy(dev->i2c_bus[1].name, "SMI-I2C1"); | ||
214 | dev->i2c_bus[1].owner = THIS_MODULE; | ||
215 | dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev; | ||
216 | dev->i2c_bus[1].algo_data = &dev->i2c_bit[1]; | ||
217 | dev->i2c_bit[1].data = dev; | ||
218 | dev->i2c_bit[1].setsda = smi_i2c1_setsda; | ||
219 | dev->i2c_bit[1].setscl = smi_i2c1_setscl; | ||
220 | dev->i2c_bit[1].getsda = smi_i2c1_getsda; | ||
221 | dev->i2c_bit[1].getscl = smi_i2c1_getscl; | ||
222 | dev->i2c_bit[1].udelay = 12; | ||
223 | dev->i2c_bit[1].timeout = 10; | ||
224 | /* Raise SCL and SDA */ | ||
225 | smi_i2c1_setsda(dev, 1); | ||
226 | smi_i2c1_setscl(dev, 1); | ||
227 | |||
228 | ret = i2c_bit_add_bus(&dev->i2c_bus[1]); | ||
229 | if (ret < 0) | ||
230 | i2c_del_adapter(&dev->i2c_bus[0]); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static void smi_i2c_exit(struct smi_dev *dev) | ||
236 | { | ||
237 | i2c_del_adapter(&dev->i2c_bus[0]); | ||
238 | i2c_del_adapter(&dev->i2c_bus[1]); | ||
239 | } | ||
240 | |||
241 | static int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size) | ||
242 | { | ||
243 | int ret; | ||
244 | u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff }; | ||
245 | |||
246 | struct i2c_msg msg[] = { | ||
247 | { .addr = 0x50, .flags = 0, | ||
248 | .buf = b0, .len = 2 }, | ||
249 | { .addr = 0x50, .flags = I2C_M_RD, | ||
250 | .buf = data, .len = size } | ||
251 | }; | ||
252 | |||
253 | ret = i2c_transfer(i2c, msg, 2); | ||
254 | |||
255 | if (ret != 2) { | ||
256 | dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n", | ||
257 | __func__, reg, ret); | ||
258 | return ret; | ||
259 | } | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | /* ts port interrupt operations */ | ||
264 | static void smi_port_disableInterrupt(struct smi_port *port) | ||
265 | { | ||
266 | struct smi_dev *dev = port->dev; | ||
267 | |||
268 | smi_write(MSI_INT_ENA_CLR, | ||
269 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); | ||
270 | } | ||
271 | |||
272 | static void smi_port_enableInterrupt(struct smi_port *port) | ||
273 | { | ||
274 | struct smi_dev *dev = port->dev; | ||
275 | |||
276 | smi_write(MSI_INT_ENA_SET, | ||
277 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); | ||
278 | } | ||
279 | |||
280 | static void smi_port_clearInterrupt(struct smi_port *port) | ||
281 | { | ||
282 | struct smi_dev *dev = port->dev; | ||
283 | |||
284 | smi_write(MSI_INT_STATUS_CLR, | ||
285 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); | ||
286 | } | ||
287 | |||
288 | /* tasklet handler: DMA data to dmx.*/ | ||
289 | static void smi_dma_xfer(unsigned long data) | ||
290 | { | ||
291 | struct smi_port *port = (struct smi_port *) data; | ||
292 | struct smi_dev *dev = port->dev; | ||
293 | u32 intr_status, finishedData, dmaManagement; | ||
294 | u8 dmaChan0State, dmaChan1State; | ||
295 | |||
296 | intr_status = port->_int_status; | ||
297 | dmaManagement = smi_read(port->DMA_MANAGEMENT); | ||
298 | dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4); | ||
299 | dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20); | ||
300 | |||
301 | /* CH-0 DMA interrupt.*/ | ||
302 | if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) { | ||
303 | dev_dbg(&dev->pci_dev->dev, | ||
304 | "Port[%d]-DMA CH0 engine complete successful !\n", | ||
305 | port->idx); | ||
306 | finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE); | ||
307 | finishedData &= 0x003FFFFF; | ||
308 | /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] | ||
309 | * indicate dma total transfer length and | ||
310 | * zero of [21:0] indicate dma total transfer length | ||
311 | * equal to 0x400000 (4MB)*/ | ||
312 | if (finishedData == 0) | ||
313 | finishedData = 0x00400000; | ||
314 | if (finishedData != SMI_TS_DMA_BUF_SIZE) { | ||
315 | dev_dbg(&dev->pci_dev->dev, | ||
316 | "DMA CH0 engine complete length mismatched, finish data=%d !\n", | ||
317 | finishedData); | ||
318 | } | ||
319 | dvb_dmx_swfilter_packets(&port->demux, | ||
320 | port->cpu_addr[0], (finishedData / 188)); | ||
321 | /*dvb_dmx_swfilter(&port->demux, | ||
322 | port->cpu_addr[0], finishedData);*/ | ||
323 | } | ||
324 | /* CH-1 DMA interrupt.*/ | ||
325 | if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) { | ||
326 | dev_dbg(&dev->pci_dev->dev, | ||
327 | "Port[%d]-DMA CH1 engine complete successful !\n", | ||
328 | port->idx); | ||
329 | finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE); | ||
330 | finishedData &= 0x003FFFFF; | ||
331 | /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] | ||
332 | * indicate dma total transfer length and | ||
333 | * zero of [21:0] indicate dma total transfer length | ||
334 | * equal to 0x400000 (4MB)*/ | ||
335 | if (finishedData == 0) | ||
336 | finishedData = 0x00400000; | ||
337 | if (finishedData != SMI_TS_DMA_BUF_SIZE) { | ||
338 | dev_dbg(&dev->pci_dev->dev, | ||
339 | "DMA CH1 engine complete length mismatched, finish data=%d !\n", | ||
340 | finishedData); | ||
341 | } | ||
342 | dvb_dmx_swfilter_packets(&port->demux, | ||
343 | port->cpu_addr[1], (finishedData / 188)); | ||
344 | /*dvb_dmx_swfilter(&port->demux, | ||
345 | port->cpu_addr[1], finishedData);*/ | ||
346 | } | ||
347 | /* restart DMA.*/ | ||
348 | if (intr_status & port->_dmaInterruptCH0) | ||
349 | dmaManagement |= 0x00000002; | ||
350 | if (intr_status & port->_dmaInterruptCH1) | ||
351 | dmaManagement |= 0x00020000; | ||
352 | smi_write(port->DMA_MANAGEMENT, dmaManagement); | ||
353 | /* Re-enable interrupts */ | ||
354 | smi_port_enableInterrupt(port); | ||
355 | } | ||
356 | |||
357 | static void smi_port_dma_free(struct smi_port *port) | ||
358 | { | ||
359 | if (port->cpu_addr[0]) { | ||
360 | pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, | ||
361 | port->cpu_addr[0], port->dma_addr[0]); | ||
362 | port->cpu_addr[0] = NULL; | ||
363 | } | ||
364 | if (port->cpu_addr[1]) { | ||
365 | pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, | ||
366 | port->cpu_addr[1], port->dma_addr[1]); | ||
367 | port->cpu_addr[1] = NULL; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | static int smi_port_init(struct smi_port *port, int dmaChanUsed) | ||
372 | { | ||
373 | dev_dbg(&port->dev->pci_dev->dev, | ||
374 | "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed); | ||
375 | port->enable = 0; | ||
376 | if (port->idx == 0) { | ||
377 | /* Port A */ | ||
378 | port->_dmaInterruptCH0 = dmaChanUsed & 0x01; | ||
379 | port->_dmaInterruptCH1 = dmaChanUsed & 0x02; | ||
380 | |||
381 | port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW; | ||
382 | port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI; | ||
383 | port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE; | ||
384 | port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL; | ||
385 | port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW; | ||
386 | port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI; | ||
387 | port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE; | ||
388 | port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL; | ||
389 | port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT; | ||
390 | } else { | ||
391 | /* Port B */ | ||
392 | port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04; | ||
393 | port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08; | ||
394 | |||
395 | port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW; | ||
396 | port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI; | ||
397 | port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE; | ||
398 | port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL; | ||
399 | port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW; | ||
400 | port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI; | ||
401 | port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE; | ||
402 | port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL; | ||
403 | port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT; | ||
404 | } | ||
405 | |||
406 | if (port->_dmaInterruptCH0) { | ||
407 | port->cpu_addr[0] = pci_alloc_consistent(port->dev->pci_dev, | ||
408 | SMI_TS_DMA_BUF_SIZE, | ||
409 | &port->dma_addr[0]); | ||
410 | if (!port->cpu_addr[0]) { | ||
411 | dev_err(&port->dev->pci_dev->dev, | ||
412 | "Port[%d] DMA CH0 memory allocation failed!\n", | ||
413 | port->idx); | ||
414 | goto err; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | if (port->_dmaInterruptCH1) { | ||
419 | port->cpu_addr[1] = pci_alloc_consistent(port->dev->pci_dev, | ||
420 | SMI_TS_DMA_BUF_SIZE, | ||
421 | &port->dma_addr[1]); | ||
422 | if (!port->cpu_addr[1]) { | ||
423 | dev_err(&port->dev->pci_dev->dev, | ||
424 | "Port[%d] DMA CH1 memory allocation failed!\n", | ||
425 | port->idx); | ||
426 | goto err; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | smi_port_disableInterrupt(port); | ||
431 | tasklet_init(&port->tasklet, smi_dma_xfer, (unsigned long)port); | ||
432 | tasklet_disable(&port->tasklet); | ||
433 | port->enable = 1; | ||
434 | return 0; | ||
435 | err: | ||
436 | smi_port_dma_free(port); | ||
437 | return -ENOMEM; | ||
438 | } | ||
439 | |||
440 | static void smi_port_exit(struct smi_port *port) | ||
441 | { | ||
442 | smi_port_disableInterrupt(port); | ||
443 | tasklet_kill(&port->tasklet); | ||
444 | smi_port_dma_free(port); | ||
445 | port->enable = 0; | ||
446 | } | ||
447 | |||
448 | static void smi_port_irq(struct smi_port *port, u32 int_status) | ||
449 | { | ||
450 | u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; | ||
451 | |||
452 | if (int_status & port_req_irq) { | ||
453 | smi_port_disableInterrupt(port); | ||
454 | port->_int_status = int_status; | ||
455 | smi_port_clearInterrupt(port); | ||
456 | tasklet_schedule(&port->tasklet); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static irqreturn_t smi_irq_handler(int irq, void *dev_id) | ||
461 | { | ||
462 | struct smi_dev *dev = dev_id; | ||
463 | struct smi_port *port0 = &dev->ts_port[0]; | ||
464 | struct smi_port *port1 = &dev->ts_port[1]; | ||
465 | |||
466 | u32 intr_status = smi_read(MSI_INT_STATUS); | ||
467 | |||
468 | /* ts0 interrupt.*/ | ||
469 | if (dev->info->ts_0) | ||
470 | smi_port_irq(port0, intr_status); | ||
471 | |||
472 | /* ts1 interrupt.*/ | ||
473 | if (dev->info->ts_1) | ||
474 | smi_port_irq(port1, intr_status); | ||
475 | |||
476 | return IRQ_HANDLED; | ||
477 | } | ||
478 | |||
479 | static const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = { | ||
480 | .i2c_addr = 0x68, | ||
481 | .clock = 27000000, | ||
482 | .i2c_wr_max = 33, | ||
483 | .clock_out = 0, | ||
484 | .ts_mode = M88DS3103_TS_PARALLEL, | ||
485 | .ts_clk = 16000, | ||
486 | .ts_clk_pol = 1, | ||
487 | .agc = 0x99, | ||
488 | .lnb_hv_pol = 0, | ||
489 | .lnb_en_pol = 1, | ||
490 | }; | ||
491 | |||
492 | static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) | ||
493 | { | ||
494 | int ret = 0; | ||
495 | struct smi_dev *dev = port->dev; | ||
496 | struct i2c_adapter *i2c; | ||
497 | /* tuner I2C module */ | ||
498 | struct i2c_adapter *tuner_i2c_adapter; | ||
499 | struct i2c_client *tuner_client; | ||
500 | struct i2c_board_info tuner_info; | ||
501 | struct m88ts2022_config m88ts2022_config = { | ||
502 | .clock = 27000000, | ||
503 | }; | ||
504 | memset(&tuner_info, 0, sizeof(struct i2c_board_info)); | ||
505 | i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; | ||
506 | |||
507 | /* attach demod */ | ||
508 | port->fe = dvb_attach(m88ds3103_attach, | ||
509 | &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter); | ||
510 | if (!port->fe) { | ||
511 | ret = -ENODEV; | ||
512 | return ret; | ||
513 | } | ||
514 | /* attach tuner */ | ||
515 | m88ts2022_config.fe = port->fe; | ||
516 | strlcpy(tuner_info.type, "m88ts2022", I2C_NAME_SIZE); | ||
517 | tuner_info.addr = 0x60; | ||
518 | tuner_info.platform_data = &m88ts2022_config; | ||
519 | request_module("m88ts2022"); | ||
520 | tuner_client = i2c_new_device(tuner_i2c_adapter, &tuner_info); | ||
521 | if (tuner_client == NULL || tuner_client->dev.driver == NULL) { | ||
522 | ret = -ENODEV; | ||
523 | goto err_tuner_i2c_device; | ||
524 | } | ||
525 | |||
526 | if (!try_module_get(tuner_client->dev.driver->owner)) { | ||
527 | ret = -ENODEV; | ||
528 | goto err_tuner_i2c_module; | ||
529 | } | ||
530 | |||
531 | /* delegate signal strength measurement to tuner */ | ||
532 | port->fe->ops.read_signal_strength = | ||
533 | port->fe->ops.tuner_ops.get_rf_strength; | ||
534 | |||
535 | port->i2c_client_tuner = tuner_client; | ||
536 | return ret; | ||
537 | |||
538 | err_tuner_i2c_module: | ||
539 | i2c_unregister_device(tuner_client); | ||
540 | err_tuner_i2c_device: | ||
541 | dvb_frontend_detach(port->fe); | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | static int smi_fe_init(struct smi_port *port) | ||
546 | { | ||
547 | int ret = 0; | ||
548 | struct smi_dev *dev = port->dev; | ||
549 | struct dvb_adapter *adap = &port->dvb_adapter; | ||
550 | u8 mac_ee[16]; | ||
551 | |||
552 | dev_dbg(&port->dev->pci_dev->dev, | ||
553 | "%s: port %d, fe_type = %d\n", | ||
554 | __func__, port->idx, port->fe_type); | ||
555 | switch (port->fe_type) { | ||
556 | case DVBSKY_FE_M88DS3103: | ||
557 | ret = smi_dvbsky_m88ds3103_fe_attach(port); | ||
558 | break; | ||
559 | } | ||
560 | if (ret < 0) | ||
561 | return ret; | ||
562 | |||
563 | /* register dvb frontend */ | ||
564 | ret = dvb_register_frontend(adap, port->fe); | ||
565 | if (ret < 0) { | ||
566 | i2c_unregister_device(port->i2c_client_tuner); | ||
567 | dvb_frontend_detach(port->fe); | ||
568 | return ret; | ||
569 | } | ||
570 | /* init MAC.*/ | ||
571 | ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); | ||
572 | dev_info(&port->dev->pci_dev->dev, | ||
573 | "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8); | ||
574 | memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | static void smi_fe_exit(struct smi_port *port) | ||
579 | { | ||
580 | struct i2c_client *tuner_client; | ||
581 | |||
582 | dvb_unregister_frontend(port->fe); | ||
583 | /* remove I2C tuner */ | ||
584 | tuner_client = port->i2c_client_tuner; | ||
585 | if (tuner_client) { | ||
586 | module_put(tuner_client->dev.driver->owner); | ||
587 | i2c_unregister_device(tuner_client); | ||
588 | } | ||
589 | dvb_frontend_detach(port->fe); | ||
590 | } | ||
591 | |||
592 | static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, | ||
593 | int (*start_feed)(struct dvb_demux_feed *), | ||
594 | int (*stop_feed)(struct dvb_demux_feed *), | ||
595 | void *priv) | ||
596 | { | ||
597 | dvbdemux->priv = priv; | ||
598 | |||
599 | dvbdemux->filternum = 256; | ||
600 | dvbdemux->feednum = 256; | ||
601 | dvbdemux->start_feed = start_feed; | ||
602 | dvbdemux->stop_feed = stop_feed; | ||
603 | dvbdemux->write_to_decoder = NULL; | ||
604 | dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | | ||
605 | DMX_SECTION_FILTERING | | ||
606 | DMX_MEMORY_BASED_FILTERING); | ||
607 | return dvb_dmx_init(dvbdemux); | ||
608 | } | ||
609 | |||
610 | static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, | ||
611 | struct dvb_demux *dvbdemux, | ||
612 | struct dmx_frontend *hw_frontend, | ||
613 | struct dmx_frontend *mem_frontend, | ||
614 | struct dvb_adapter *dvb_adapter) | ||
615 | { | ||
616 | int ret; | ||
617 | |||
618 | dmxdev->filternum = 256; | ||
619 | dmxdev->demux = &dvbdemux->dmx; | ||
620 | dmxdev->capabilities = 0; | ||
621 | ret = dvb_dmxdev_init(dmxdev, dvb_adapter); | ||
622 | if (ret < 0) | ||
623 | return ret; | ||
624 | |||
625 | hw_frontend->source = DMX_FRONTEND_0; | ||
626 | dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); | ||
627 | mem_frontend->source = DMX_MEMORY_FE; | ||
628 | dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); | ||
629 | return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); | ||
630 | } | ||
631 | |||
632 | static u32 smi_config_DMA(struct smi_port *port) | ||
633 | { | ||
634 | struct smi_dev *dev = port->dev; | ||
635 | u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg; | ||
636 | u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1; | ||
637 | u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188; | ||
638 | u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0; | ||
639 | u64 mem; | ||
640 | |||
641 | dmaManagement = smi_read(port->DMA_MANAGEMENT); | ||
642 | /* Setup Channel-0 */ | ||
643 | if (port->_dmaInterruptCH0) { | ||
644 | totalLength = SMI_TS_DMA_BUF_SIZE; | ||
645 | mem = port->dma_addr[0]; | ||
646 | dmaMemPtrLow = mem & 0xffffffff; | ||
647 | dmaMemPtrHi = mem >> 32; | ||
648 | dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) | ||
649 | | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); | ||
650 | dmaManagement |= dmaChanEnable | (dmaTransStart << 1) | ||
651 | | (chanLatencyTimer << 8); | ||
652 | /* write DMA register, start DMA engine */ | ||
653 | smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow); | ||
654 | smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi); | ||
655 | smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg); | ||
656 | } | ||
657 | /* Setup Channel-1 */ | ||
658 | if (port->_dmaInterruptCH1) { | ||
659 | totalLength = SMI_TS_DMA_BUF_SIZE; | ||
660 | mem = port->dma_addr[1]; | ||
661 | dmaMemPtrLow = mem & 0xffffffff; | ||
662 | dmaMemPtrHi = mem >> 32; | ||
663 | dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) | ||
664 | | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); | ||
665 | dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17) | ||
666 | | (chanLatencyTimer << 24); | ||
667 | /* write DMA register, start DMA engine */ | ||
668 | smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow); | ||
669 | smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi); | ||
670 | smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg); | ||
671 | } | ||
672 | return dmaManagement; | ||
673 | } | ||
674 | |||
675 | static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
676 | { | ||
677 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
678 | struct smi_port *port = dvbdmx->priv; | ||
679 | struct smi_dev *dev = port->dev; | ||
680 | u32 dmaManagement; | ||
681 | |||
682 | if (port->users++ == 0) { | ||
683 | dmaManagement = smi_config_DMA(port); | ||
684 | smi_port_clearInterrupt(port); | ||
685 | smi_port_enableInterrupt(port); | ||
686 | smi_write(port->DMA_MANAGEMENT, dmaManagement); | ||
687 | tasklet_enable(&port->tasklet); | ||
688 | } | ||
689 | return port->users; | ||
690 | } | ||
691 | |||
692 | static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
693 | { | ||
694 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
695 | struct smi_port *port = dvbdmx->priv; | ||
696 | struct smi_dev *dev = port->dev; | ||
697 | |||
698 | if (--port->users) | ||
699 | return port->users; | ||
700 | |||
701 | tasklet_disable(&port->tasklet); | ||
702 | smi_port_disableInterrupt(port); | ||
703 | smi_clear(port->DMA_MANAGEMENT, 0x30003); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static int smi_dvb_init(struct smi_port *port) | ||
708 | { | ||
709 | int ret; | ||
710 | struct dvb_adapter *adap = &port->dvb_adapter; | ||
711 | struct dvb_demux *dvbdemux = &port->demux; | ||
712 | |||
713 | dev_dbg(&port->dev->pci_dev->dev, | ||
714 | "%s, port %d\n", __func__, port->idx); | ||
715 | |||
716 | ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE, | ||
717 | &port->dev->pci_dev->dev, | ||
718 | adapter_nr); | ||
719 | if (ret < 0) { | ||
720 | dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n"); | ||
721 | return ret; | ||
722 | } | ||
723 | ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", | ||
724 | smi_start_feed, | ||
725 | smi_stop_feed, port); | ||
726 | if (ret < 0) | ||
727 | goto err_del_dvb_register_adapter; | ||
728 | |||
729 | ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux, | ||
730 | &port->hw_frontend, | ||
731 | &port->mem_frontend, adap); | ||
732 | if (ret < 0) | ||
733 | goto err_del_dvb_dmx; | ||
734 | |||
735 | ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux); | ||
736 | if (ret < 0) | ||
737 | goto err_del_dvb_dmxdev; | ||
738 | return 0; | ||
739 | err_del_dvb_dmxdev: | ||
740 | dvbdemux->dmx.close(&dvbdemux->dmx); | ||
741 | dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); | ||
742 | dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); | ||
743 | dvb_dmxdev_release(&port->dmxdev); | ||
744 | err_del_dvb_dmx: | ||
745 | dvb_dmx_release(&port->demux); | ||
746 | err_del_dvb_register_adapter: | ||
747 | dvb_unregister_adapter(&port->dvb_adapter); | ||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | static void smi_dvb_exit(struct smi_port *port) | ||
752 | { | ||
753 | struct dvb_demux *dvbdemux = &port->demux; | ||
754 | |||
755 | dvb_net_release(&port->dvbnet); | ||
756 | |||
757 | dvbdemux->dmx.close(&dvbdemux->dmx); | ||
758 | dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); | ||
759 | dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); | ||
760 | dvb_dmxdev_release(&port->dmxdev); | ||
761 | dvb_dmx_release(&port->demux); | ||
762 | |||
763 | dvb_unregister_adapter(&port->dvb_adapter); | ||
764 | } | ||
765 | |||
766 | static int smi_port_attach(struct smi_dev *dev, | ||
767 | struct smi_port *port, int index) | ||
768 | { | ||
769 | int ret, dmachs; | ||
770 | |||
771 | port->dev = dev; | ||
772 | port->idx = index; | ||
773 | port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1; | ||
774 | dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1; | ||
775 | /* port init.*/ | ||
776 | ret = smi_port_init(port, dmachs); | ||
777 | if (ret < 0) | ||
778 | return ret; | ||
779 | /* dvb init.*/ | ||
780 | ret = smi_dvb_init(port); | ||
781 | if (ret < 0) | ||
782 | goto err_del_port_init; | ||
783 | /* fe init.*/ | ||
784 | ret = smi_fe_init(port); | ||
785 | if (ret < 0) | ||
786 | goto err_del_dvb_init; | ||
787 | return 0; | ||
788 | err_del_dvb_init: | ||
789 | smi_dvb_exit(port); | ||
790 | err_del_port_init: | ||
791 | smi_port_exit(port); | ||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | static void smi_port_detach(struct smi_port *port) | ||
796 | { | ||
797 | smi_fe_exit(port); | ||
798 | smi_dvb_exit(port); | ||
799 | smi_port_exit(port); | ||
800 | } | ||
801 | |||
802 | static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
803 | { | ||
804 | struct smi_dev *dev; | ||
805 | int ret = -ENOMEM; | ||
806 | |||
807 | if (pci_enable_device(pdev) < 0) | ||
808 | return -ENODEV; | ||
809 | |||
810 | dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL); | ||
811 | if (!dev) { | ||
812 | ret = -ENOMEM; | ||
813 | goto err_pci_disable_device; | ||
814 | } | ||
815 | |||
816 | dev->pci_dev = pdev; | ||
817 | pci_set_drvdata(pdev, dev); | ||
818 | dev->info = (struct smi_cfg_info *) id->driver_data; | ||
819 | dev_info(&dev->pci_dev->dev, | ||
820 | "card detected: %s\n", dev->info->name); | ||
821 | |||
822 | dev->nr = dev->info->type; | ||
823 | dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0), | ||
824 | pci_resource_len(dev->pci_dev, 0)); | ||
825 | if (!dev->lmmio) { | ||
826 | ret = -ENOMEM; | ||
827 | goto err_kfree; | ||
828 | } | ||
829 | |||
830 | /* should we set to 32bit DMA? */ | ||
831 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
832 | if (ret < 0) | ||
833 | goto err_pci_iounmap; | ||
834 | |||
835 | pci_set_master(pdev); | ||
836 | |||
837 | ret = smi_hw_init(dev); | ||
838 | if (ret < 0) | ||
839 | goto err_pci_iounmap; | ||
840 | |||
841 | ret = smi_i2c_init(dev); | ||
842 | if (ret < 0) | ||
843 | goto err_pci_iounmap; | ||
844 | |||
845 | if (dev->info->ts_0) { | ||
846 | ret = smi_port_attach(dev, &dev->ts_port[0], 0); | ||
847 | if (ret < 0) | ||
848 | goto err_del_i2c_adaptor; | ||
849 | } | ||
850 | |||
851 | if (dev->info->ts_1) { | ||
852 | ret = smi_port_attach(dev, &dev->ts_port[1], 1); | ||
853 | if (ret < 0) | ||
854 | goto err_del_port0_attach; | ||
855 | } | ||
856 | |||
857 | #ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ | ||
858 | if (pci_msi_enabled()) | ||
859 | ret = pci_enable_msi(dev->pci_dev); | ||
860 | if (ret) | ||
861 | dev_info(&dev->pci_dev->dev, "MSI not available.\n"); | ||
862 | #endif | ||
863 | |||
864 | ret = request_irq(dev->pci_dev->irq, smi_irq_handler, | ||
865 | IRQF_SHARED, "SMI_PCIE", dev); | ||
866 | if (ret < 0) | ||
867 | goto err_del_port1_attach; | ||
868 | |||
869 | return 0; | ||
870 | |||
871 | err_del_port1_attach: | ||
872 | if (dev->info->ts_1) | ||
873 | smi_port_detach(&dev->ts_port[1]); | ||
874 | err_del_port0_attach: | ||
875 | if (dev->info->ts_0) | ||
876 | smi_port_detach(&dev->ts_port[0]); | ||
877 | err_del_i2c_adaptor: | ||
878 | smi_i2c_exit(dev); | ||
879 | err_pci_iounmap: | ||
880 | iounmap(dev->lmmio); | ||
881 | err_kfree: | ||
882 | pci_set_drvdata(pdev, 0); | ||
883 | kfree(dev); | ||
884 | err_pci_disable_device: | ||
885 | pci_disable_device(pdev); | ||
886 | return ret; | ||
887 | } | ||
888 | |||
889 | static void smi_remove(struct pci_dev *pdev) | ||
890 | { | ||
891 | struct smi_dev *dev = pci_get_drvdata(pdev); | ||
892 | |||
893 | smi_write(MSI_INT_ENA_CLR, ALL_INT); | ||
894 | free_irq(dev->pci_dev->irq, dev); | ||
895 | #ifdef CONFIG_PCI_MSI | ||
896 | pci_disable_msi(dev->pci_dev); | ||
897 | #endif | ||
898 | if (dev->info->ts_1) | ||
899 | smi_port_detach(&dev->ts_port[1]); | ||
900 | if (dev->info->ts_0) | ||
901 | smi_port_detach(&dev->ts_port[0]); | ||
902 | |||
903 | smi_i2c_exit(dev); | ||
904 | iounmap(dev->lmmio); | ||
905 | pci_set_drvdata(pdev, 0); | ||
906 | pci_disable_device(pdev); | ||
907 | kfree(dev); | ||
908 | } | ||
909 | |||
910 | /* DVBSky cards */ | ||
911 | static struct smi_cfg_info dvbsky_s950_cfg = { | ||
912 | .type = SMI_DVBSKY_S950, | ||
913 | .name = "DVBSky S950 V3", | ||
914 | .ts_0 = SMI_TS_NULL, | ||
915 | .ts_1 = SMI_TS_DMA_BOTH, | ||
916 | .fe_0 = DVBSKY_FE_NULL, | ||
917 | .fe_1 = DVBSKY_FE_M88DS3103, | ||
918 | }; | ||
919 | |||
920 | /* PCI IDs */ | ||
921 | #define SMI_ID(_subvend, _subdev, _driverdata) { \ | ||
922 | .vendor = SMI_VID, .device = SMI_PID, \ | ||
923 | .subvendor = _subvend, .subdevice = _subdev, \ | ||
924 | .driver_data = (unsigned long)&_driverdata } | ||
925 | |||
926 | static const struct pci_device_id smi_id_table[] = { | ||
927 | SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), | ||
928 | {0} | ||
929 | }; | ||
930 | MODULE_DEVICE_TABLE(pci, smi_id_table); | ||
931 | |||
932 | static struct pci_driver smipcie_driver = { | ||
933 | .name = "SMI PCIe driver", | ||
934 | .id_table = smi_id_table, | ||
935 | .probe = smi_probe, | ||
936 | .remove = smi_remove, | ||
937 | }; | ||
938 | |||
939 | module_pci_driver(smipcie_driver); | ||
940 | |||
941 | MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); | ||
942 | MODULE_DESCRIPTION("SMI PCIe driver"); | ||
943 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h new file mode 100644 index 000000000000..10cdf20f4839 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie.h | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * SMI PCIe driver for DVBSky cards. | ||
3 | * | ||
4 | * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _SMI_PCIE_H_ | ||
18 | #define _SMI_PCIE_H_ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/i2c-algo-bit.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/proc_fs.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/dma-mapping.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <media/rc-core.h> | ||
31 | |||
32 | #include "demux.h" | ||
33 | #include "dmxdev.h" | ||
34 | #include "dvb_demux.h" | ||
35 | #include "dvb_frontend.h" | ||
36 | #include "dvb_net.h" | ||
37 | #include "dvbdev.h" | ||
38 | |||
39 | /* -------- Register Base -------- */ | ||
40 | #define MSI_CONTROL_REG_BASE 0x0800 | ||
41 | #define SYSTEM_CONTROL_REG_BASE 0x0880 | ||
42 | #define PCIE_EP_DEBUG_REG_BASE 0x08C0 | ||
43 | #define IR_CONTROL_REG_BASE 0x0900 | ||
44 | #define I2C_A_CONTROL_REG_BASE 0x0940 | ||
45 | #define I2C_B_CONTROL_REG_BASE 0x0980 | ||
46 | #define ATV_PORTA_CONTROL_REG_BASE 0x09C0 | ||
47 | #define DTV_PORTA_CONTROL_REG_BASE 0x0A00 | ||
48 | #define AES_PORTA_CONTROL_REG_BASE 0x0A80 | ||
49 | #define DMA_PORTA_CONTROL_REG_BASE 0x0AC0 | ||
50 | #define ATV_PORTB_CONTROL_REG_BASE 0x0B00 | ||
51 | #define DTV_PORTB_CONTROL_REG_BASE 0x0B40 | ||
52 | #define AES_PORTB_CONTROL_REG_BASE 0x0BC0 | ||
53 | #define DMA_PORTB_CONTROL_REG_BASE 0x0C00 | ||
54 | #define UART_A_REGISTER_BASE 0x0C40 | ||
55 | #define UART_B_REGISTER_BASE 0x0C80 | ||
56 | #define GPS_CONTROL_REG_BASE 0x0CC0 | ||
57 | #define DMA_PORTC_CONTROL_REG_BASE 0x0D00 | ||
58 | #define DMA_PORTD_CONTROL_REG_BASE 0x0D00 | ||
59 | #define AES_RANDOM_DATA_BASE 0x0D80 | ||
60 | #define AES_KEY_IN_BASE 0x0D90 | ||
61 | #define RANDOM_DATA_LIB_BASE 0x0E00 | ||
62 | #define IR_DATA_BUFFER_BASE 0x0F00 | ||
63 | #define PORTA_TS_BUFFER_BASE 0x1000 | ||
64 | #define PORTA_I2S_BUFFER_BASE 0x1400 | ||
65 | #define PORTB_TS_BUFFER_BASE 0x1800 | ||
66 | #define PORTB_I2S_BUFFER_BASE 0x1C00 | ||
67 | |||
68 | /* -------- MSI control and state register -------- */ | ||
69 | #define MSI_DELAY_TIMER (MSI_CONTROL_REG_BASE + 0x00) | ||
70 | #define MSI_INT_STATUS (MSI_CONTROL_REG_BASE + 0x08) | ||
71 | #define MSI_INT_STATUS_CLR (MSI_CONTROL_REG_BASE + 0x0C) | ||
72 | #define MSI_INT_STATUS_SET (MSI_CONTROL_REG_BASE + 0x10) | ||
73 | #define MSI_INT_ENA (MSI_CONTROL_REG_BASE + 0x14) | ||
74 | #define MSI_INT_ENA_CLR (MSI_CONTROL_REG_BASE + 0x18) | ||
75 | #define MSI_INT_ENA_SET (MSI_CONTROL_REG_BASE + 0x1C) | ||
76 | #define MSI_SOFT_RESET (MSI_CONTROL_REG_BASE + 0x20) | ||
77 | #define MSI_CFG_SRC0 (MSI_CONTROL_REG_BASE + 0x24) | ||
78 | |||
79 | /* -------- Hybird Controller System Control register -------- */ | ||
80 | #define MUX_MODE_CTRL (SYSTEM_CONTROL_REG_BASE + 0x00) | ||
81 | #define rbPaMSMask 0x07 | ||
82 | #define rbPaMSDtvNoGpio 0x00 /*[2:0], DTV Simple mode */ | ||
83 | #define rbPaMSDtv4bitGpio 0x01 /*[2:0], DTV TS2 Serial mode)*/ | ||
84 | #define rbPaMSDtv7bitGpio 0x02 /*[2:0], DTV TS0 Serial mode*/ | ||
85 | #define rbPaMS8bitGpio 0x03 /*[2:0], GPIO mode selected;(8bit GPIO)*/ | ||
86 | #define rbPaMSAtv 0x04 /*[2:0], 3'b1xx: ATV mode select*/ | ||
87 | #define rbPbMSMask 0x38 | ||
88 | #define rbPbMSDtvNoGpio 0x00 /*[5:3], DTV Simple mode */ | ||
89 | #define rbPbMSDtv4bitGpio 0x08 /*[5:3], DTV TS2 Serial mode*/ | ||
90 | #define rbPbMSDtv7bitGpio 0x10 /*[5:3], DTV TS0 Serial mode*/ | ||
91 | #define rbPbMS8bitGpio 0x18 /*[5:3], GPIO mode selected;(8bit GPIO)*/ | ||
92 | #define rbPbMSAtv 0x20 /*[5:3], 3'b1xx: ATV mode select*/ | ||
93 | #define rbPaAESEN 0x40 /*[6], port A AES enable bit*/ | ||
94 | #define rbPbAESEN 0x80 /*[7], port B AES enable bit*/ | ||
95 | |||
96 | #define INTERNAL_RST (SYSTEM_CONTROL_REG_BASE + 0x04) | ||
97 | #define PERIPHERAL_CTRL (SYSTEM_CONTROL_REG_BASE + 0x08) | ||
98 | #define GPIO_0to7_CTRL (SYSTEM_CONTROL_REG_BASE + 0x0C) | ||
99 | #define GPIO_8to15_CTRL (SYSTEM_CONTROL_REG_BASE + 0x10) | ||
100 | #define GPIO_16to24_CTRL (SYSTEM_CONTROL_REG_BASE + 0x14) | ||
101 | #define GPIO_INT_SRC_CFG (SYSTEM_CONTROL_REG_BASE + 0x18) | ||
102 | #define SYS_BUF_STATUS (SYSTEM_CONTROL_REG_BASE + 0x1C) | ||
103 | #define PCIE_IP_REG_ACS (SYSTEM_CONTROL_REG_BASE + 0x20) | ||
104 | #define PCIE_IP_REG_ACS_ADDR (SYSTEM_CONTROL_REG_BASE + 0x24) | ||
105 | #define PCIE_IP_REG_ACS_DATA (SYSTEM_CONTROL_REG_BASE + 0x28) | ||
106 | |||
107 | /* -------- IR Control register -------- */ | ||
108 | #define IR_Init_Reg (IR_CONTROL_REG_BASE + 0x00) | ||
109 | #define IR_Idle_Cnt_Low (IR_CONTROL_REG_BASE + 0x04) | ||
110 | #define IR_Idle_Cnt_High (IR_CONTROL_REG_BASE + 0x05) | ||
111 | #define IR_Unit_Cnt_Low (IR_CONTROL_REG_BASE + 0x06) | ||
112 | #define IR_Unit_Cnt_High (IR_CONTROL_REG_BASE + 0x07) | ||
113 | #define IR_Data_Cnt (IR_CONTROL_REG_BASE + 0x08) | ||
114 | #define rbIRen 0x80 | ||
115 | #define rbIRhighidle 0x10 | ||
116 | #define rbIRlowidle 0x00 | ||
117 | #define rbIRVld 0x04 | ||
118 | |||
119 | /* -------- I2C A control and state register -------- */ | ||
120 | #define I2C_A_CTL_STATUS (I2C_A_CONTROL_REG_BASE + 0x00) | ||
121 | #define I2C_A_ADDR (I2C_A_CONTROL_REG_BASE + 0x04) | ||
122 | #define I2C_A_SW_CTL (I2C_A_CONTROL_REG_BASE + 0x08) | ||
123 | #define I2C_A_TIME_OUT_CNT (I2C_A_CONTROL_REG_BASE + 0x0C) | ||
124 | #define I2C_A_FIFO_STATUS (I2C_A_CONTROL_REG_BASE + 0x10) | ||
125 | #define I2C_A_FS_EN (I2C_A_CONTROL_REG_BASE + 0x14) | ||
126 | #define I2C_A_FIFO_DATA (I2C_A_CONTROL_REG_BASE + 0x20) | ||
127 | |||
128 | /* -------- I2C B control and state register -------- */ | ||
129 | #define I2C_B_CTL_STATUS (I2C_B_CONTROL_REG_BASE + 0x00) | ||
130 | #define I2C_B_ADDR (I2C_B_CONTROL_REG_BASE + 0x04) | ||
131 | #define I2C_B_SW_CTL (I2C_B_CONTROL_REG_BASE + 0x08) | ||
132 | #define I2C_B_TIME_OUT_CNT (I2C_B_CONTROL_REG_BASE + 0x0C) | ||
133 | #define I2C_B_FIFO_STATUS (I2C_B_CONTROL_REG_BASE + 0x10) | ||
134 | #define I2C_B_FS_EN (I2C_B_CONTROL_REG_BASE + 0x14) | ||
135 | #define I2C_B_FIFO_DATA (I2C_B_CONTROL_REG_BASE + 0x20) | ||
136 | |||
137 | #define VIDEO_CTRL_STATUS_A (ATV_PORTA_CONTROL_REG_BASE + 0x04) | ||
138 | |||
139 | /* -------- Digital TV control register, Port A -------- */ | ||
140 | #define MPEG2_CTRL_A (DTV_PORTA_CONTROL_REG_BASE + 0x00) | ||
141 | #define SERIAL_IN_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x4C) | ||
142 | #define VLD_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x60) | ||
143 | #define ERR_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x64) | ||
144 | #define BRD_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x68) | ||
145 | |||
146 | /* -------- DMA Control Register, Port A -------- */ | ||
147 | #define DMA_PORTA_CHAN0_ADDR_LOW (DMA_PORTA_CONTROL_REG_BASE + 0x00) | ||
148 | #define DMA_PORTA_CHAN0_ADDR_HI (DMA_PORTA_CONTROL_REG_BASE + 0x04) | ||
149 | #define DMA_PORTA_CHAN0_TRANS_STATE (DMA_PORTA_CONTROL_REG_BASE + 0x08) | ||
150 | #define DMA_PORTA_CHAN0_CONTROL (DMA_PORTA_CONTROL_REG_BASE + 0x0C) | ||
151 | #define DMA_PORTA_CHAN1_ADDR_LOW (DMA_PORTA_CONTROL_REG_BASE + 0x10) | ||
152 | #define DMA_PORTA_CHAN1_ADDR_HI (DMA_PORTA_CONTROL_REG_BASE + 0x14) | ||
153 | #define DMA_PORTA_CHAN1_TRANS_STATE (DMA_PORTA_CONTROL_REG_BASE + 0x18) | ||
154 | #define DMA_PORTA_CHAN1_CONTROL (DMA_PORTA_CONTROL_REG_BASE + 0x1C) | ||
155 | #define DMA_PORTA_MANAGEMENT (DMA_PORTA_CONTROL_REG_BASE + 0x20) | ||
156 | #define VIDEO_CTRL_STATUS_B (ATV_PORTB_CONTROL_REG_BASE + 0x04) | ||
157 | |||
158 | /* -------- Digital TV control register, Port B -------- */ | ||
159 | #define MPEG2_CTRL_B (DTV_PORTB_CONTROL_REG_BASE + 0x00) | ||
160 | #define SERIAL_IN_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x4C) | ||
161 | #define VLD_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x60) | ||
162 | #define ERR_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x64) | ||
163 | #define BRD_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x68) | ||
164 | |||
165 | /* -------- AES control register, Port B -------- */ | ||
166 | #define AES_CTRL_B (AES_PORTB_CONTROL_REG_BASE + 0x00) | ||
167 | #define AES_KEY_BASE_B (AES_PORTB_CONTROL_REG_BASE + 0x04) | ||
168 | |||
169 | /* -------- DMA Control Register, Port B -------- */ | ||
170 | #define DMA_PORTB_CHAN0_ADDR_LOW (DMA_PORTB_CONTROL_REG_BASE + 0x00) | ||
171 | #define DMA_PORTB_CHAN0_ADDR_HI (DMA_PORTB_CONTROL_REG_BASE + 0x04) | ||
172 | #define DMA_PORTB_CHAN0_TRANS_STATE (DMA_PORTB_CONTROL_REG_BASE + 0x08) | ||
173 | #define DMA_PORTB_CHAN0_CONTROL (DMA_PORTB_CONTROL_REG_BASE + 0x0C) | ||
174 | #define DMA_PORTB_CHAN1_ADDR_LOW (DMA_PORTB_CONTROL_REG_BASE + 0x10) | ||
175 | #define DMA_PORTB_CHAN1_ADDR_HI (DMA_PORTB_CONTROL_REG_BASE + 0x14) | ||
176 | #define DMA_PORTB_CHAN1_TRANS_STATE (DMA_PORTB_CONTROL_REG_BASE + 0x18) | ||
177 | #define DMA_PORTB_CHAN1_CONTROL (DMA_PORTB_CONTROL_REG_BASE + 0x1C) | ||
178 | #define DMA_PORTB_MANAGEMENT (DMA_PORTB_CONTROL_REG_BASE + 0x20) | ||
179 | |||
180 | #define DMA_TRANS_UNIT_188 (0x00000007) | ||
181 | |||
182 | /* -------- Macro define of 24 interrupt resource --------*/ | ||
183 | #define DMA_A_CHAN0_DONE_INT (0x00000001) | ||
184 | #define DMA_A_CHAN1_DONE_INT (0x00000002) | ||
185 | #define DMA_B_CHAN0_DONE_INT (0x00000004) | ||
186 | #define DMA_B_CHAN1_DONE_INT (0x00000008) | ||
187 | #define DMA_C_CHAN0_DONE_INT (0x00000010) | ||
188 | #define DMA_C_CHAN1_DONE_INT (0x00000020) | ||
189 | #define DMA_D_CHAN0_DONE_INT (0x00000040) | ||
190 | #define DMA_D_CHAN1_DONE_INT (0x00000080) | ||
191 | #define DATA_BUF_OVERFLOW_INT (0x00000100) | ||
192 | #define UART_0_X_INT (0x00000200) | ||
193 | #define UART_1_X_INT (0x00000400) | ||
194 | #define IR_X_INT (0x00000800) | ||
195 | #define GPIO_0_INT (0x00001000) | ||
196 | #define GPIO_1_INT (0x00002000) | ||
197 | #define GPIO_2_INT (0x00004000) | ||
198 | #define GPIO_3_INT (0x00008000) | ||
199 | #define ALL_INT (0x0000FFFF) | ||
200 | |||
201 | /* software I2C bit mask */ | ||
202 | #define SW_I2C_MSK_MODE 0x01 | ||
203 | #define SW_I2C_MSK_CLK_OUT 0x02 | ||
204 | #define SW_I2C_MSK_DAT_OUT 0x04 | ||
205 | #define SW_I2C_MSK_CLK_EN 0x08 | ||
206 | #define SW_I2C_MSK_DAT_EN 0x10 | ||
207 | #define SW_I2C_MSK_DAT_IN 0x40 | ||
208 | #define SW_I2C_MSK_CLK_IN 0x80 | ||
209 | |||
210 | #define SMI_VID 0x1ADE | ||
211 | #define SMI_PID 0x3038 | ||
212 | #define SMI_TS_DMA_BUF_SIZE (1024 * 188) | ||
213 | |||
214 | struct smi_cfg_info { | ||
215 | #define SMI_DVBSKY_S952 0 | ||
216 | #define SMI_DVBSKY_S950 1 | ||
217 | #define SMI_DVBSKY_T9580 2 | ||
218 | #define SMI_DVBSKY_T982 3 | ||
219 | int type; | ||
220 | char *name; | ||
221 | #define SMI_TS_NULL 0 | ||
222 | #define SMI_TS_DMA_SINGLE 1 | ||
223 | #define SMI_TS_DMA_BOTH 3 | ||
224 | /* SMI_TS_NULL: not use; | ||
225 | * SMI_TS_DMA_SINGLE: use DMA 0 only; | ||
226 | * SMI_TS_DMA_BOTH:use DMA 0 and 1.*/ | ||
227 | int ts_0; | ||
228 | int ts_1; | ||
229 | #define DVBSKY_FE_NULL 0 | ||
230 | #define DVBSKY_FE_M88RS6000 1 | ||
231 | #define DVBSKY_FE_M88DS3103 2 | ||
232 | #define DVBSKY_FE_SIT2 3 | ||
233 | int fe_0; | ||
234 | int fe_1; | ||
235 | }; | ||
236 | |||
237 | struct smi_port { | ||
238 | struct smi_dev *dev; | ||
239 | int idx; | ||
240 | int enable; | ||
241 | int fe_type; | ||
242 | /* regs */ | ||
243 | u32 DMA_CHAN0_ADDR_LOW; | ||
244 | u32 DMA_CHAN0_ADDR_HI; | ||
245 | u32 DMA_CHAN0_TRANS_STATE; | ||
246 | u32 DMA_CHAN0_CONTROL; | ||
247 | u32 DMA_CHAN1_ADDR_LOW; | ||
248 | u32 DMA_CHAN1_ADDR_HI; | ||
249 | u32 DMA_CHAN1_TRANS_STATE; | ||
250 | u32 DMA_CHAN1_CONTROL; | ||
251 | u32 DMA_MANAGEMENT; | ||
252 | /* dma */ | ||
253 | dma_addr_t dma_addr[2]; | ||
254 | u8 *cpu_addr[2]; | ||
255 | u32 _dmaInterruptCH0; | ||
256 | u32 _dmaInterruptCH1; | ||
257 | u32 _int_status; | ||
258 | struct tasklet_struct tasklet; | ||
259 | /* dvb */ | ||
260 | struct dmx_frontend hw_frontend; | ||
261 | struct dmx_frontend mem_frontend; | ||
262 | struct dmxdev dmxdev; | ||
263 | struct dvb_adapter dvb_adapter; | ||
264 | struct dvb_demux demux; | ||
265 | struct dvb_net dvbnet; | ||
266 | int users; | ||
267 | struct dvb_frontend *fe; | ||
268 | /* frontend i2c module */ | ||
269 | struct i2c_client *i2c_client_demod; | ||
270 | struct i2c_client *i2c_client_tuner; | ||
271 | }; | ||
272 | |||
273 | struct smi_dev { | ||
274 | int nr; | ||
275 | struct smi_cfg_info *info; | ||
276 | |||
277 | /* pcie */ | ||
278 | struct pci_dev *pci_dev; | ||
279 | u32 __iomem *lmmio; | ||
280 | |||
281 | /* ts port */ | ||
282 | struct smi_port ts_port[2]; | ||
283 | |||
284 | /* i2c */ | ||
285 | struct i2c_adapter i2c_bus[2]; | ||
286 | struct i2c_algo_bit_data i2c_bit[2]; | ||
287 | }; | ||
288 | |||
289 | #define smi_read(reg) readl(dev->lmmio + ((reg)>>2)) | ||
290 | #define smi_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) | ||
291 | |||
292 | #define smi_andor(reg, mask, value) \ | ||
293 | writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ | ||
294 | ((value) & (mask)), dev->lmmio+((reg)>>2)) | ||
295 | |||
296 | #define smi_set(reg, bit) smi_andor((reg), (bit), (bit)) | ||
297 | #define smi_clear(reg, bit) smi_andor((reg), (bit), 0) | ||
298 | |||
299 | #endif /* #ifndef _SMI_PCIE_H_ */ | ||