blob: 300da319b0650d1b6dcc74eff20c7d4f129f0f2b [file] [log] [blame]
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001/*
2 * Driver for the Conexant CX25821 PCIe bridge
3 *
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03004 * Copyright (C) 2009 Conexant Systems Inc.
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03005 * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
6 * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
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
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 *
17 * GNU General Public License for more 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
24#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030026#include "cx25821.h"
27#include "cx25821-sram.h"
28#include "cx25821-video.h"
29
30MODULE_DESCRIPTION("Driver for Athena cards");
31MODULE_AUTHOR("Shu Lin - Hiep Huynh");
32MODULE_LICENSE("GPL");
33
34struct list_head cx25821_devlist;
Olimpiu Pascariude2c4342010-03-21 14:18:19 -030035EXPORT_SYMBOL(cx25821_devlist);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030036
37static unsigned int debug;
38module_param(debug, int, 0644);
39MODULE_PARM_DESC(debug, "enable debug messages");
40
Mauro Carvalho Chehab53e712d2009-09-13 11:39:12 -030041static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030042module_param_array(card, int, NULL, 0444);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030043MODULE_PARM_DESC(card, "card type");
44
Ruslan Pisareve4115bb2010-09-27 10:01:36 -030045static unsigned int cx25821_devcount;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030046
47static DEFINE_MUTEX(devlist);
48LIST_HEAD(cx25821_devlist);
49
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030050struct sram_channel cx25821_sram_channels[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030051 [SRAM_CH00] = {
52 .i = SRAM_CH00,
53 .name = "VID A",
54 .cmds_start = VID_A_DOWN_CMDS,
55 .ctrl_start = VID_A_IQ,
56 .cdt = VID_A_CDT,
57 .fifo_start = VID_A_DOWN_CLUSTER_1,
58 .fifo_size = (VID_CLUSTER_SIZE << 2),
59 .ptr1_reg = DMA1_PTR1,
60 .ptr2_reg = DMA1_PTR2,
61 .cnt1_reg = DMA1_CNT1,
62 .cnt2_reg = DMA1_CNT2,
63 .int_msk = VID_A_INT_MSK,
64 .int_stat = VID_A_INT_STAT,
65 .int_mstat = VID_A_INT_MSTAT,
66 .dma_ctl = VID_DST_A_DMA_CTL,
67 .gpcnt_ctl = VID_DST_A_GPCNT_CTL,
68 .gpcnt = VID_DST_A_GPCNT,
69 .vip_ctl = VID_DST_A_VIP_CTL,
70 .pix_frmt = VID_DST_A_PIX_FRMT,
71 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030072
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030073 [SRAM_CH01] = {
74 .i = SRAM_CH01,
75 .name = "VID B",
76 .cmds_start = VID_B_DOWN_CMDS,
77 .ctrl_start = VID_B_IQ,
78 .cdt = VID_B_CDT,
79 .fifo_start = VID_B_DOWN_CLUSTER_1,
80 .fifo_size = (VID_CLUSTER_SIZE << 2),
81 .ptr1_reg = DMA2_PTR1,
82 .ptr2_reg = DMA2_PTR2,
83 .cnt1_reg = DMA2_CNT1,
84 .cnt2_reg = DMA2_CNT2,
85 .int_msk = VID_B_INT_MSK,
86 .int_stat = VID_B_INT_STAT,
87 .int_mstat = VID_B_INT_MSTAT,
88 .dma_ctl = VID_DST_B_DMA_CTL,
89 .gpcnt_ctl = VID_DST_B_GPCNT_CTL,
90 .gpcnt = VID_DST_B_GPCNT,
91 .vip_ctl = VID_DST_B_VIP_CTL,
92 .pix_frmt = VID_DST_B_PIX_FRMT,
93 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -030094
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030095 [SRAM_CH02] = {
96 .i = SRAM_CH02,
97 .name = "VID C",
98 .cmds_start = VID_C_DOWN_CMDS,
99 .ctrl_start = VID_C_IQ,
100 .cdt = VID_C_CDT,
101 .fifo_start = VID_C_DOWN_CLUSTER_1,
102 .fifo_size = (VID_CLUSTER_SIZE << 2),
103 .ptr1_reg = DMA3_PTR1,
104 .ptr2_reg = DMA3_PTR2,
105 .cnt1_reg = DMA3_CNT1,
106 .cnt2_reg = DMA3_CNT2,
107 .int_msk = VID_C_INT_MSK,
108 .int_stat = VID_C_INT_STAT,
109 .int_mstat = VID_C_INT_MSTAT,
110 .dma_ctl = VID_DST_C_DMA_CTL,
111 .gpcnt_ctl = VID_DST_C_GPCNT_CTL,
112 .gpcnt = VID_DST_C_GPCNT,
113 .vip_ctl = VID_DST_C_VIP_CTL,
114 .pix_frmt = VID_DST_C_PIX_FRMT,
115 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300116
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300117 [SRAM_CH03] = {
118 .i = SRAM_CH03,
119 .name = "VID D",
120 .cmds_start = VID_D_DOWN_CMDS,
121 .ctrl_start = VID_D_IQ,
122 .cdt = VID_D_CDT,
123 .fifo_start = VID_D_DOWN_CLUSTER_1,
124 .fifo_size = (VID_CLUSTER_SIZE << 2),
125 .ptr1_reg = DMA4_PTR1,
126 .ptr2_reg = DMA4_PTR2,
127 .cnt1_reg = DMA4_CNT1,
128 .cnt2_reg = DMA4_CNT2,
129 .int_msk = VID_D_INT_MSK,
130 .int_stat = VID_D_INT_STAT,
131 .int_mstat = VID_D_INT_MSTAT,
132 .dma_ctl = VID_DST_D_DMA_CTL,
133 .gpcnt_ctl = VID_DST_D_GPCNT_CTL,
134 .gpcnt = VID_DST_D_GPCNT,
135 .vip_ctl = VID_DST_D_VIP_CTL,
136 .pix_frmt = VID_DST_D_PIX_FRMT,
137 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300138
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300139 [SRAM_CH04] = {
140 .i = SRAM_CH04,
141 .name = "VID E",
142 .cmds_start = VID_E_DOWN_CMDS,
143 .ctrl_start = VID_E_IQ,
144 .cdt = VID_E_CDT,
145 .fifo_start = VID_E_DOWN_CLUSTER_1,
146 .fifo_size = (VID_CLUSTER_SIZE << 2),
147 .ptr1_reg = DMA5_PTR1,
148 .ptr2_reg = DMA5_PTR2,
149 .cnt1_reg = DMA5_CNT1,
150 .cnt2_reg = DMA5_CNT2,
151 .int_msk = VID_E_INT_MSK,
152 .int_stat = VID_E_INT_STAT,
153 .int_mstat = VID_E_INT_MSTAT,
154 .dma_ctl = VID_DST_E_DMA_CTL,
155 .gpcnt_ctl = VID_DST_E_GPCNT_CTL,
156 .gpcnt = VID_DST_E_GPCNT,
157 .vip_ctl = VID_DST_E_VIP_CTL,
158 .pix_frmt = VID_DST_E_PIX_FRMT,
159 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300160
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300161 [SRAM_CH05] = {
162 .i = SRAM_CH05,
163 .name = "VID F",
164 .cmds_start = VID_F_DOWN_CMDS,
165 .ctrl_start = VID_F_IQ,
166 .cdt = VID_F_CDT,
167 .fifo_start = VID_F_DOWN_CLUSTER_1,
168 .fifo_size = (VID_CLUSTER_SIZE << 2),
169 .ptr1_reg = DMA6_PTR1,
170 .ptr2_reg = DMA6_PTR2,
171 .cnt1_reg = DMA6_CNT1,
172 .cnt2_reg = DMA6_CNT2,
173 .int_msk = VID_F_INT_MSK,
174 .int_stat = VID_F_INT_STAT,
175 .int_mstat = VID_F_INT_MSTAT,
176 .dma_ctl = VID_DST_F_DMA_CTL,
177 .gpcnt_ctl = VID_DST_F_GPCNT_CTL,
178 .gpcnt = VID_DST_F_GPCNT,
179 .vip_ctl = VID_DST_F_VIP_CTL,
180 .pix_frmt = VID_DST_F_PIX_FRMT,
181 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300182
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300183 [SRAM_CH06] = {
184 .i = SRAM_CH06,
185 .name = "VID G",
186 .cmds_start = VID_G_DOWN_CMDS,
187 .ctrl_start = VID_G_IQ,
188 .cdt = VID_G_CDT,
189 .fifo_start = VID_G_DOWN_CLUSTER_1,
190 .fifo_size = (VID_CLUSTER_SIZE << 2),
191 .ptr1_reg = DMA7_PTR1,
192 .ptr2_reg = DMA7_PTR2,
193 .cnt1_reg = DMA7_CNT1,
194 .cnt2_reg = DMA7_CNT2,
195 .int_msk = VID_G_INT_MSK,
196 .int_stat = VID_G_INT_STAT,
197 .int_mstat = VID_G_INT_MSTAT,
198 .dma_ctl = VID_DST_G_DMA_CTL,
199 .gpcnt_ctl = VID_DST_G_GPCNT_CTL,
200 .gpcnt = VID_DST_G_GPCNT,
201 .vip_ctl = VID_DST_G_VIP_CTL,
202 .pix_frmt = VID_DST_G_PIX_FRMT,
203 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300204
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300205 [SRAM_CH07] = {
206 .i = SRAM_CH07,
207 .name = "VID H",
208 .cmds_start = VID_H_DOWN_CMDS,
209 .ctrl_start = VID_H_IQ,
210 .cdt = VID_H_CDT,
211 .fifo_start = VID_H_DOWN_CLUSTER_1,
212 .fifo_size = (VID_CLUSTER_SIZE << 2),
213 .ptr1_reg = DMA8_PTR1,
214 .ptr2_reg = DMA8_PTR2,
215 .cnt1_reg = DMA8_CNT1,
216 .cnt2_reg = DMA8_CNT2,
217 .int_msk = VID_H_INT_MSK,
218 .int_stat = VID_H_INT_STAT,
219 .int_mstat = VID_H_INT_MSTAT,
220 .dma_ctl = VID_DST_H_DMA_CTL,
221 .gpcnt_ctl = VID_DST_H_GPCNT_CTL,
222 .gpcnt = VID_DST_H_GPCNT,
223 .vip_ctl = VID_DST_H_VIP_CTL,
224 .pix_frmt = VID_DST_H_PIX_FRMT,
225 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300226
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300227 [SRAM_CH08] = {
228 .name = "audio from",
229 .cmds_start = AUD_A_DOWN_CMDS,
230 .ctrl_start = AUD_A_IQ,
231 .cdt = AUD_A_CDT,
232 .fifo_start = AUD_A_DOWN_CLUSTER_1,
233 .fifo_size = AUDIO_CLUSTER_SIZE * 3,
234 .ptr1_reg = DMA17_PTR1,
235 .ptr2_reg = DMA17_PTR2,
236 .cnt1_reg = DMA17_CNT1,
237 .cnt2_reg = DMA17_CNT2,
238 },
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300239
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300240 [SRAM_CH09] = {
241 .i = SRAM_CH09,
242 .name = "VID Upstream I",
243 .cmds_start = VID_I_UP_CMDS,
244 .ctrl_start = VID_I_IQ,
245 .cdt = VID_I_CDT,
246 .fifo_start = VID_I_UP_CLUSTER_1,
247 .fifo_size = (VID_CLUSTER_SIZE << 2),
248 .ptr1_reg = DMA15_PTR1,
249 .ptr2_reg = DMA15_PTR2,
250 .cnt1_reg = DMA15_CNT1,
251 .cnt2_reg = DMA15_CNT2,
252 .int_msk = VID_I_INT_MSK,
253 .int_stat = VID_I_INT_STAT,
254 .int_mstat = VID_I_INT_MSTAT,
255 .dma_ctl = VID_SRC_I_DMA_CTL,
256 .gpcnt_ctl = VID_SRC_I_GPCNT_CTL,
257 .gpcnt = VID_SRC_I_GPCNT,
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300258
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300259 .vid_fmt_ctl = VID_SRC_I_FMT_CTL,
260 .vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1,
261 .vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2,
262 .vid_cdt_size = VID_SRC_I_CDT_SZ,
263 .irq_bit = 8,
264 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300265
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300266 [SRAM_CH10] = {
267 .i = SRAM_CH10,
268 .name = "VID Upstream J",
269 .cmds_start = VID_J_UP_CMDS,
270 .ctrl_start = VID_J_IQ,
271 .cdt = VID_J_CDT,
272 .fifo_start = VID_J_UP_CLUSTER_1,
273 .fifo_size = (VID_CLUSTER_SIZE << 2),
274 .ptr1_reg = DMA16_PTR1,
275 .ptr2_reg = DMA16_PTR2,
276 .cnt1_reg = DMA16_CNT1,
277 .cnt2_reg = DMA16_CNT2,
278 .int_msk = VID_J_INT_MSK,
279 .int_stat = VID_J_INT_STAT,
280 .int_mstat = VID_J_INT_MSTAT,
281 .dma_ctl = VID_SRC_J_DMA_CTL,
282 .gpcnt_ctl = VID_SRC_J_GPCNT_CTL,
283 .gpcnt = VID_SRC_J_GPCNT,
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300284
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300285 .vid_fmt_ctl = VID_SRC_J_FMT_CTL,
286 .vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1,
287 .vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2,
288 .vid_cdt_size = VID_SRC_J_CDT_SZ,
289 .irq_bit = 9,
290 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300291
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300292 [SRAM_CH11] = {
293 .i = SRAM_CH11,
294 .name = "Audio Upstream Channel B",
295 .cmds_start = AUD_B_UP_CMDS,
296 .ctrl_start = AUD_B_IQ,
297 .cdt = AUD_B_CDT,
298 .fifo_start = AUD_B_UP_CLUSTER_1,
299 .fifo_size = (AUDIO_CLUSTER_SIZE * 3),
300 .ptr1_reg = DMA22_PTR1,
301 .ptr2_reg = DMA22_PTR2,
302 .cnt1_reg = DMA22_CNT1,
303 .cnt2_reg = DMA22_CNT2,
304 .int_msk = AUD_B_INT_MSK,
305 .int_stat = AUD_B_INT_STAT,
306 .int_mstat = AUD_B_INT_MSTAT,
307 .dma_ctl = AUD_INT_DMA_CTL,
308 .gpcnt_ctl = AUD_B_GPCNT_CTL,
309 .gpcnt = AUD_B_GPCNT,
310 .aud_length = AUD_B_LNGTH,
311 .aud_cfg = AUD_B_CFG,
312 .fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN,
313 .fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN,
314 .irq_bit = 11,
315 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300316};
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300317EXPORT_SYMBOL(cx25821_sram_channels);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300318
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300319struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00];
320struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01];
321struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02];
322struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03];
323struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04];
324struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05];
325struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06];
326struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07];
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300327struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09];
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300328struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10];
329struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11];
330
331struct cx25821_dmaqueue mpegq;
332
333static int cx25821_risc_decode(u32 risc)
334{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300335 static char *instr[16] = {
336 [RISC_SYNC >> 28] = "sync",
337 [RISC_WRITE >> 28] = "write",
338 [RISC_WRITEC >> 28] = "writec",
339 [RISC_READ >> 28] = "read",
340 [RISC_READC >> 28] = "readc",
341 [RISC_JUMP >> 28] = "jump",
342 [RISC_SKIP >> 28] = "skip",
343 [RISC_WRITERM >> 28] = "writerm",
344 [RISC_WRITECM >> 28] = "writecm",
345 [RISC_WRITECR >> 28] = "writecr",
346 };
347 static int incr[16] = {
348 [RISC_WRITE >> 28] = 3,
349 [RISC_JUMP >> 28] = 3,
350 [RISC_SKIP >> 28] = 1,
351 [RISC_SYNC >> 28] = 1,
352 [RISC_WRITERM >> 28] = 3,
353 [RISC_WRITECM >> 28] = 3,
354 [RISC_WRITECR >> 28] = 4,
355 };
356 static char *bits[] = {
357 "12", "13", "14", "resync",
358 "cnt0", "cnt1", "18", "19",
359 "20", "21", "22", "23",
360 "irq1", "irq2", "eol", "sol",
361 };
362 int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300363
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300364 printk("0x%08x [ %s", risc,
365 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
366 for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) {
367 if (risc & (1 << (i + 12)))
368 printk(" %s", bits[i]);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300369 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300370 printk(" count=%d ]\n", risc & 0xfff);
371 return incr[risc >> 28] ? incr[risc >> 28] : 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300372}
373
374static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
375{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300376 struct cx25821_i2c *bus = i2c_adap->algo_data;
377 struct cx25821_dev *dev = bus->dev;
378 return cx_read(bus->reg_stat) & 0x01;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300379}
380
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300381void cx_i2c_read_print(struct cx25821_dev *dev, u32 reg, const char *reg_string)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300382{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300383 int tmp = 0;
384 u32 value = 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300385
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300386 value = cx25821_i2c_read(&dev->i2c_bus[0], reg, &tmp);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300387}
388
389static void cx25821_registers_init(struct cx25821_dev *dev)
390{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300391 u32 tmp;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300392
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300393 /* enable RUN_RISC in Pecos */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300394 cx_write(DEV_CNTRL2, 0x20);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300395
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300396 /* Set the master PCI interrupt masks to enable video, audio, MBIF,
397 * and GPIO interrupts
398 * I2C interrupt masking is handled by the I2C objects themselves. */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300399 cx_write(PCI_INT_MSK, 0x2001FFFF);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300400
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300401 tmp = cx_read(RDR_TLCTL0);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300402 tmp &= ~FLD_CFG_RCB_CK_EN; /* Clear the RCB_CK_EN bit */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300403 cx_write(RDR_TLCTL0, tmp);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300404
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300405 /* PLL-A setting for the Audio Master Clock */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300406 cx_write(PLL_A_INT_FRAC, 0x9807A58B);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300407
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300408 /* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300409 cx_write(PLL_A_POST_STAT_BIST, 0x8000019C);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300410
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300411 /* clear reset bit [31] */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300412 tmp = cx_read(PLL_A_INT_FRAC);
413 cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300414
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300415 /* PLL-B setting for Mobilygen Host Bus Interface */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300416 cx_write(PLL_B_INT_FRAC, 0x9883A86F);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300417
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300418 /* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300419 cx_write(PLL_B_POST_STAT_BIST, 0x8000018D);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300420
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300421 /* clear reset bit [31] */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300422 tmp = cx_read(PLL_B_INT_FRAC);
423 cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300424
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300425 /* PLL-C setting for video upstream channel */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300426 cx_write(PLL_C_INT_FRAC, 0x96A0EA3F);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300427
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300428 /* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300429 cx_write(PLL_C_POST_STAT_BIST, 0x80000103);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300430
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300431 /* clear reset bit [31] */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300432 tmp = cx_read(PLL_C_INT_FRAC);
433 cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300434
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300435 /* PLL-D setting for audio upstream channel */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300436 cx_write(PLL_D_INT_FRAC, 0x98757F5B);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300437
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300438 /* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300439 cx_write(PLL_D_POST_STAT_BIST, 0x80000113);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300440
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300441 /* clear reset bit [31] */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300442 tmp = cx_read(PLL_D_INT_FRAC);
443 cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300444
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300445 /* This selects the PLL C clock source for the video upstream channel
446 * I and J */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300447 tmp = cx_read(VID_CH_CLK_SEL);
448 cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300449
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300450 /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
451 * channel A-C
452 * select 656/VIP DST for downstream Channel A - C */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300453 tmp = cx_read(VID_CH_MODE_SEL);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300454 /* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300455 cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300456
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300457 /* enables 656 port I and J as output */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300458 tmp = cx_read(CLK_RST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300459 /* use external ALT_PLL_REF pin as its reference clock instead */
460 tmp |= FLD_USE_ALT_PLL_REF;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300461 cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300462
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300463 mdelay(100);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300464}
465
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300466int cx25821_sram_channel_setup(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300467 struct sram_channel *ch,
468 unsigned int bpl, u32 risc)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300469{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300470 unsigned int i, lines;
471 u32 cdt;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300472
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300473 if (ch->cmds_start == 0) {
474 cx_write(ch->ptr1_reg, 0);
475 cx_write(ch->ptr2_reg, 0);
476 cx_write(ch->cnt2_reg, 0);
477 cx_write(ch->cnt1_reg, 0);
478 return 0;
479 }
480
481 bpl = (bpl + 7) & ~7; /* alignment */
482 cdt = ch->cdt;
483 lines = ch->fifo_size / bpl;
484
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300485 if (lines > 4)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300486 lines = 4;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300487
488 BUG_ON(lines < 2);
489
490 cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
491 cx_write(8 + 4, 8);
492 cx_write(8 + 8, 0);
493
494 /* write CDT */
495 for (i = 0; i < lines; i++) {
496 cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
497 cx_write(cdt + 16 * i + 4, 0);
498 cx_write(cdt + 16 * i + 8, 0);
499 cx_write(cdt + 16 * i + 12, 0);
500 }
501
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300502 /* init the first cdt buffer */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300503 for (i = 0; i < 128; i++)
504 cx_write(ch->fifo_start + 4 * i, i);
505
506 /* write CMDS */
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300507 if (ch->jumponly)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300508 cx_write(ch->cmds_start + 0, 8);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300509 else
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300510 cx_write(ch->cmds_start + 0, risc);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300511
512 cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
513 cx_write(ch->cmds_start + 8, cdt);
514 cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
515 cx_write(ch->cmds_start + 16, ch->ctrl_start);
516
517 if (ch->jumponly)
518 cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
519 else
520 cx_write(ch->cmds_start + 20, 64 >> 2);
521
522 for (i = 24; i < 80; i += 4)
523 cx_write(ch->cmds_start + i, 0);
524
525 /* fill registers */
526 cx_write(ch->ptr1_reg, ch->fifo_start);
527 cx_write(ch->ptr2_reg, cdt);
528 cx_write(ch->cnt2_reg, (lines * 16) >> 3);
529 cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
530
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300531 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300532}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300533EXPORT_SYMBOL(cx25821_sram_channel_setup);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300534
535int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300536 struct sram_channel *ch,
537 unsigned int bpl, u32 risc)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300538{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300539 unsigned int i, lines;
540 u32 cdt;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300541
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300542 if (ch->cmds_start == 0) {
543 cx_write(ch->ptr1_reg, 0);
544 cx_write(ch->ptr2_reg, 0);
545 cx_write(ch->cnt2_reg, 0);
546 cx_write(ch->cnt1_reg, 0);
547 return 0;
548 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300549
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300550 bpl = (bpl + 7) & ~7; /* alignment */
551 cdt = ch->cdt;
552 lines = ch->fifo_size / bpl;
553
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300554 if (lines > 3)
555 lines = 3; /* for AUDIO */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300556
557 BUG_ON(lines < 2);
558
559 cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
560 cx_write(8 + 4, 8);
561 cx_write(8 + 8, 0);
562
563 /* write CDT */
564 for (i = 0; i < lines; i++) {
565 cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
566 cx_write(cdt + 16 * i + 4, 0);
567 cx_write(cdt + 16 * i + 8, 0);
568 cx_write(cdt + 16 * i + 12, 0);
569 }
570
571 /* write CMDS */
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300572 if (ch->jumponly)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300573 cx_write(ch->cmds_start + 0, 8);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300574 else
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300575 cx_write(ch->cmds_start + 0, risc);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300576
577 cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
578 cx_write(ch->cmds_start + 8, cdt);
579 cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
580 cx_write(ch->cmds_start + 16, ch->ctrl_start);
581
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300582 /* IQ size */
583 if (ch->jumponly)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300584 cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300585 else
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300586 cx_write(ch->cmds_start + 20, 64 >> 2);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300587
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300588 /* zero out */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300589 for (i = 24; i < 80; i += 4)
590 cx_write(ch->cmds_start + i, 0);
591
592 /* fill registers */
593 cx_write(ch->ptr1_reg, ch->fifo_start);
594 cx_write(ch->ptr2_reg, cdt);
595 cx_write(ch->cnt2_reg, (lines * 16) >> 3);
596 cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
597
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300598 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300599}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300600EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300601
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300602void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
603{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300604 static char *name[] = {
605 "init risc lo",
606 "init risc hi",
607 "cdt base",
608 "cdt size",
609 "iq base",
610 "iq size",
611 "risc pc lo",
612 "risc pc hi",
613 "iq wr ptr",
614 "iq rd ptr",
615 "cdt current",
616 "pci target lo",
617 "pci target hi",
618 "line / byte",
619 };
620 u32 risc;
621 unsigned int i, j, n;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300622
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300623 printk(KERN_WARNING "%s: %s - dma channel status dump\n", dev->name,
624 ch->name);
625 for (i = 0; i < ARRAY_SIZE(name); i++)
626 printk(KERN_WARNING "cmds + 0x%2x: %-15s: 0x%08x\n", i * 4,
627 name[i], cx_read(ch->cmds_start + 4 * i));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300628
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300629 j = i * 4;
630 for (i = 0; i < 4;) {
631 risc = cx_read(ch->cmds_start + 4 * (i + 14));
632 printk(KERN_WARNING "cmds + 0x%2x: risc%d: ", j + i * 4, i);
633 i += cx25821_risc_decode(risc);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300634 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300635
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300636 for (i = 0; i < (64 >> 2); i += n) {
637 risc = cx_read(ch->ctrl_start + 4 * i);
638 /* No consideration for bits 63-32 */
639
640 printk(KERN_WARNING "ctrl + 0x%2x (0x%08x): iq %x: ", i * 4,
641 ch->ctrl_start + 4 * i, i);
642 n = cx25821_risc_decode(risc);
643 for (j = 1; j < n; j++) {
644 risc = cx_read(ch->ctrl_start + 4 * (i + j));
645 printk(KERN_WARNING
646 "ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
647 4 * (i + j), i + j, risc, j);
648 }
649 }
650
651 printk(KERN_WARNING " : fifo: 0x%08x -> 0x%x\n",
652 ch->fifo_start, ch->fifo_start + ch->fifo_size);
653 printk(KERN_WARNING " : ctrl: 0x%08x -> 0x%x\n",
654 ch->ctrl_start, ch->ctrl_start + 6 * 16);
655 printk(KERN_WARNING " : ptr1_reg: 0x%08x\n",
656 cx_read(ch->ptr1_reg));
657 printk(KERN_WARNING " : ptr2_reg: 0x%08x\n",
658 cx_read(ch->ptr2_reg));
659 printk(KERN_WARNING " : cnt1_reg: 0x%08x\n",
660 cx_read(ch->cnt1_reg));
661 printk(KERN_WARNING " : cnt2_reg: 0x%08x\n",
662 cx_read(ch->cnt2_reg));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300663}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300664EXPORT_SYMBOL(cx25821_sram_channel_dump);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300665
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300666void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
667 struct sram_channel *ch)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300668{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300669 static char *name[] = {
670 "init risc lo",
671 "init risc hi",
672 "cdt base",
673 "cdt size",
674 "iq base",
675 "iq size",
676 "risc pc lo",
677 "risc pc hi",
678 "iq wr ptr",
679 "iq rd ptr",
680 "cdt current",
681 "pci target lo",
682 "pci target hi",
683 "line / byte",
684 };
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300685
686 u32 risc, value, tmp;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300687 unsigned int i, j, n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300688
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300689 printk(KERN_INFO "\n%s: %s - dma Audio channel status dump\n",
690 dev->name, ch->name);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300691
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300692 for (i = 0; i < ARRAY_SIZE(name); i++)
693 printk(KERN_INFO "%s: cmds + 0x%2x: %-15s: 0x%08x\n",
694 dev->name, i * 4, name[i],
695 cx_read(ch->cmds_start + 4 * i));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300696
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300697 j = i * 4;
698 for (i = 0; i < 4;) {
699 risc = cx_read(ch->cmds_start + 4 * (i + 14));
700 printk(KERN_WARNING "cmds + 0x%2x: risc%d: ", j + i * 4, i);
701 i += cx25821_risc_decode(risc);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300702 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300703
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300704 for (i = 0; i < (64 >> 2); i += n) {
705 risc = cx_read(ch->ctrl_start + 4 * i);
706 /* No consideration for bits 63-32 */
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300707
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300708 printk(KERN_WARNING "ctrl + 0x%2x (0x%08x): iq %x: ", i * 4,
709 ch->ctrl_start + 4 * i, i);
710 n = cx25821_risc_decode(risc);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300711
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300712 for (j = 1; j < n; j++) {
713 risc = cx_read(ch->ctrl_start + 4 * (i + j));
714 printk(KERN_WARNING
715 "ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n",
716 4 * (i + j), i + j, risc, j);
717 }
718 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300719
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300720 printk(KERN_WARNING " : fifo: 0x%08x -> 0x%x\n",
721 ch->fifo_start, ch->fifo_start + ch->fifo_size);
722 printk(KERN_WARNING " : ctrl: 0x%08x -> 0x%x\n",
723 ch->ctrl_start, ch->ctrl_start + 6 * 16);
724 printk(KERN_WARNING " : ptr1_reg: 0x%08x\n",
725 cx_read(ch->ptr1_reg));
726 printk(KERN_WARNING " : ptr2_reg: 0x%08x\n",
727 cx_read(ch->ptr2_reg));
728 printk(KERN_WARNING " : cnt1_reg: 0x%08x\n",
729 cx_read(ch->cnt1_reg));
730 printk(KERN_WARNING " : cnt2_reg: 0x%08x\n",
731 cx_read(ch->cnt2_reg));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300732
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300733 for (i = 0; i < 4; i++) {
734 risc = cx_read(ch->cmds_start + 56 + (i * 4));
735 printk(KERN_WARNING "instruction %d = 0x%x\n", i, risc);
736 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300737
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300738 /* read data from the first cdt buffer */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300739 risc = cx_read(AUD_A_CDT);
740 printk(KERN_WARNING "\nread cdt loc=0x%x\n", risc);
741 for (i = 0; i < 8; i++) {
742 n = cx_read(risc + i * 4);
743 printk(KERN_WARNING "0x%x ", n);
744 }
745 printk(KERN_WARNING "\n\n");
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300746
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300747 value = cx_read(CLK_RST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300748 CX25821_INFO(" CLK_RST = 0x%x\n\n", value);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300749
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300750 value = cx_read(PLL_A_POST_STAT_BIST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300751 CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300752 value = cx_read(PLL_A_INT_FRAC);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300753 CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300754
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300755 value = cx_read(PLL_B_POST_STAT_BIST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300756 CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300757 value = cx_read(PLL_B_INT_FRAC);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300758 CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300759
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300760 value = cx_read(PLL_C_POST_STAT_BIST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300761 CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300762 value = cx_read(PLL_C_INT_FRAC);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300763 CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300764
765 value = cx_read(PLL_D_POST_STAT_BIST);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300766 CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300767 value = cx_read(PLL_D_INT_FRAC);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300768 CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300769
770 value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300771 CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300772}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300773EXPORT_SYMBOL(cx25821_sram_channel_dump_audio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300774
775static void cx25821_shutdown(struct cx25821_dev *dev)
776{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300777 int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300778
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300779 /* disable RISC controller */
780 cx_write(DEV_CNTRL2, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300781
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300782 /* Disable Video A/B activity */
783 for (i = 0; i < VID_CHANNEL_NUM; i++) {
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300784 cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
785 cx_write(dev->channels[i].sram_channels->int_msk, 0);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300786 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300787
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300788 for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
789 i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
790 cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
791 cx_write(dev->channels[i].sram_channels->int_msk, 0);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300792 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300793
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300794 /* Disable Audio activity */
795 cx_write(AUD_INT_DMA_CTL, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300796
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300797 /* Disable Serial port */
798 cx_write(UART_CTL, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300799
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300800 /* Disable Interrupts */
801 cx_write(PCI_INT_MSK, 0);
802 cx_write(AUD_A_INT_MSK, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300803}
804
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300805void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
806 u32 format)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300807{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300808 if (channel_select <= 7 && channel_select >= 0) {
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300809 cx_write(dev->channels[channel_select].
810 sram_channels->pix_frmt, format);
811 dev->channels[channel_select].pixel_formats = format;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300812 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300813}
814
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300815static void cx25821_set_vip_mode(struct cx25821_dev *dev,
816 struct sram_channel *ch)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300817{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300818 cx_write(ch->pix_frmt, PIXEL_FRMT_422);
819 cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300820}
821
822static void cx25821_initialize(struct cx25821_dev *dev)
823{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300824 int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300825
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300826 dprintk(1, "%s()\n", __func__);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300827
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300828 cx25821_shutdown(dev);
829 cx_write(PCI_INT_STAT, 0xffffffff);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300830
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300831 for (i = 0; i < VID_CHANNEL_NUM; i++)
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300832 cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300833
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300834 cx_write(AUD_A_INT_STAT, 0xffffffff);
835 cx_write(AUD_B_INT_STAT, 0xffffffff);
836 cx_write(AUD_C_INT_STAT, 0xffffffff);
837 cx_write(AUD_D_INT_STAT, 0xffffffff);
838 cx_write(AUD_E_INT_STAT, 0xffffffff);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300839
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300840 cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300841 cx_write(PAD_CTRL, 0x12); /* for I2C */
842 cx25821_registers_init(dev); /* init Pecos registers */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300843 mdelay(100);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300844
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300845 for (i = 0; i < VID_CHANNEL_NUM; i++) {
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300846 cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
847 cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
848 1440, 0);
849 dev->channels[i].pixel_formats = PIXEL_FRMT_422;
850 dev->channels[i].use_cif_resolution = FALSE;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300851 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300852
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300853 /* Probably only affect Downstream */
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300854 for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
855 i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
856 cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300857 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300858
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300859 cx25821_sram_channel_setup_audio(dev,
860 dev->channels[SRAM_CH08].sram_channels,
861 128, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300862
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300863 cx25821_gpio_init(dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300864}
865
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -0300866static int cx25821_get_resources(struct cx25821_dev *dev)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300867{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300868 if (request_mem_region
869 (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0),
870 dev->name))
871 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300872
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300873 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
874 dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300875
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300876 return -EBUSY;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300877}
878
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300879static void cx25821_dev_checkrevision(struct cx25821_dev *dev)
880{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300881 dev->hwrevision = cx_read(RDR_CFG2) & 0xff;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300882
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300883 printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", __func__,
884 dev->hwrevision);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300885}
886
887static void cx25821_iounmap(struct cx25821_dev *dev)
888{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300889 if (dev == NULL)
890 return;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300891
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300892 /* Releasing IO memory */
893 if (dev->lmmio != NULL) {
894 CX25821_INFO("Releasing lmmio.\n");
895 iounmap(dev->lmmio);
896 dev->lmmio = NULL;
897 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300898}
899
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300900static int cx25821_dev_setup(struct cx25821_dev *dev)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300901{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300902 int io_size = 0, i;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300903
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300904 printk(KERN_INFO "\n***********************************\n");
905 printk(KERN_INFO "cx25821 set up\n");
906 printk(KERN_INFO "***********************************\n\n");
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300907
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300908 mutex_init(&dev->lock);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300909
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300910 atomic_inc(&dev->refcount);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300911
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300912 dev->nr = ++cx25821_devcount;
913 sprintf(dev->name, "cx25821[%d]", dev->nr);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300914
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300915 mutex_lock(&devlist);
916 list_add_tail(&dev->devlist, &cx25821_devlist);
917 mutex_unlock(&devlist);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300918
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300919 strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown");
920 strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821");
921
922 if (dev->pci->device != 0x8210) {
923 printk(KERN_INFO
924 "%s() Exiting. Incorrect Hardware device = 0x%02x\n",
925 __func__, dev->pci->device);
926 return -1;
927 } else {
928 printk(KERN_INFO "Athena Hardware device = 0x%02x\n",
929 dev->pci->device);
930 }
931
932 /* Apply a sensible clock frequency for the PCIe bridge */
933 dev->clk_freq = 28000000;
Ruslan Pisareve4115bb2010-09-27 10:01:36 -0300934 for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
935 dev->channels[i].sram_channels = &cx25821_sram_channels[i];
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300936
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300937 if (dev->nr > 1)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300938 CX25821_INFO("dev->nr > 1!");
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300939
940 /* board config */
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300941 dev->board = 1; /* card[dev->nr]; */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300942 dev->_max_num_decoders = MAX_DECODERS;
943
944 dev->pci_bus = dev->pci->bus->number;
945 dev->pci_slot = PCI_SLOT(dev->pci->devfn);
946 dev->pci_irqmask = 0x001f00;
947
948 /* External Master 1 Bus */
949 dev->i2c_bus[0].nr = 0;
950 dev->i2c_bus[0].dev = dev;
951 dev->i2c_bus[0].reg_stat = I2C1_STAT;
952 dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
953 dev->i2c_bus[0].reg_addr = I2C1_ADDR;
954 dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
955 dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
956 dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300957
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -0300958 if (cx25821_get_resources(dev) < 0) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300959 printk(KERN_ERR "%s No more PCIe resources for "
960 "subsystem: %04x:%04x\n",
961 dev->name, dev->pci->subsystem_vendor,
962 dev->pci->subsystem_device);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300963
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300964 cx25821_devcount--;
Kulikov Vasiliyc37c6d22010-08-06 23:52:57 +0400965 return -EBUSY;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300966 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300967
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300968 /* PCIe stuff */
969 dev->base_io_addr = pci_resource_start(dev->pci, 0);
970 io_size = pci_resource_len(dev->pci, 0);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300971
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300972 if (!dev->base_io_addr) {
973 CX25821_ERR("No PCI Memory resources, exiting!\n");
974 return -ENODEV;
975 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300976
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300977 dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300978
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300979 if (!dev->lmmio) {
980 CX25821_ERR
981 ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
982 cx25821_iounmap(dev);
983 return -ENOMEM;
984 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300985
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300986 dev->bmmio = (u8 __iomem *) dev->lmmio;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300987
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300988 printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300989 dev->name, dev->pci->subsystem_vendor,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300990 dev->pci->subsystem_device, cx25821_boards[dev->board].name,
991 dev->board, card[dev->nr] == dev->board ?
992 "insmod option" : "autodetected");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300993
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300994 /* init hardware */
995 cx25821_initialize(dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300996
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300997 cx25821_i2c_register(&dev->i2c_bus[0]);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -0300998/* cx25821_i2c_register(&dev->i2c_bus[1]);
999 * cx25821_i2c_register(&dev->i2c_bus[2]); */
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001000
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001001 CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
1002 dev->i2c_bus[0].i2c_rc);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001003
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001004 cx25821_card_setup(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001005
Ruslan Pisareve4115bb2010-09-27 10:01:36 -03001006 if (medusa_video_init(dev) < 0)
1007 CX25821_ERR("%s() Failed to initialize medusa!\n"
1008 , __func__);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001009
Ruslan Pisareve4115bb2010-09-27 10:01:36 -03001010 cx25821_video_register(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001011
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001012 /* register IOCTL device */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001013 dev->ioctl_dev =
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001014 cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001015 "video");
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001016
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001017 if (video_register_device
1018 (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
1019 cx25821_videoioctl_unregister(dev);
1020 printk(KERN_ERR
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001021 "%s() Failed to register video adapter for IOCTL, so \
1022 unregistering videoioctl device.\n", __func__);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001023 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001024
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001025 cx25821_dev_checkrevision(dev);
1026 CX25821_INFO("cx25821 setup done!\n");
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001027
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001028 return 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001029}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001030
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001031void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev,
1032 struct upstream_user_struct *up_data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001033{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001034 dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001035
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001036 dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
1037 medusa_set_videostandard(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001038
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001039 cx25821_vidupstream_init_ch1(dev, dev->channel_select,
1040 dev->pixel_format);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001041}
1042
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001043void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev,
1044 struct upstream_user_struct *up_data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001045{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001046 dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001047
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001048 dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
1049 medusa_set_videostandard(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001050
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001051 cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2,
1052 dev->pixel_format_ch2);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001053}
1054
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001055void cx25821_start_upstream_audio(struct cx25821_dev *dev,
1056 struct upstream_user_struct *up_data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001057{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001058 cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001059}
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001060
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001061void cx25821_dev_unregister(struct cx25821_dev *dev)
1062{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001063 int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001064
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001065 if (!dev->base_io_addr)
1066 return;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001067
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001068 cx25821_free_mem_upstream_ch1(dev);
1069 cx25821_free_mem_upstream_ch2(dev);
1070 cx25821_free_mem_upstream_audio(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001071
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001072 release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001073
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001074 if (!atomic_dec_and_test(&dev->refcount))
1075 return;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001076
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001077 for (i = 0; i < VID_CHANNEL_NUM; i++)
1078 cx25821_video_unregister(dev, i);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001079
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001080 for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
1081 i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
1082 cx25821_video_unregister(dev, i);
1083 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001084
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001085 cx25821_videoioctl_unregister(dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001086
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001087 cx25821_i2c_unregister(&dev->i2c_bus[0]);
1088 cx25821_iounmap(dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001089}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001090EXPORT_SYMBOL(cx25821_dev_unregister);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001091
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001092static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
1093 unsigned int offset, u32 sync_line,
1094 unsigned int bpl, unsigned int padding,
1095 unsigned int lines)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001096{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001097 struct scatterlist *sg;
1098 unsigned int line, todo;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001099
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001100 /* sync instruction */
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001101 if (sync_line != NO_SYNC_LINE)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001102 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001103
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001104 /* scan lines */
1105 sg = sglist;
1106 for (line = 0; line < lines; line++) {
1107 while (offset && offset >= sg_dma_len(sg)) {
1108 offset -= sg_dma_len(sg);
1109 sg++;
1110 }
1111 if (bpl <= sg_dma_len(sg) - offset) {
1112 /* fits into current chunk */
1113 *(rp++) =
1114 cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl);
1115 *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1116 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1117 offset += bpl;
1118 } else {
1119 /* scanline needs to be split */
1120 todo = bpl;
1121 *(rp++) =
1122 cpu_to_le32(RISC_WRITE | RISC_SOL |
1123 (sg_dma_len(sg) - offset));
1124 *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1125 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1126 todo -= (sg_dma_len(sg) - offset);
1127 offset = 0;
1128 sg++;
1129 while (todo > sg_dma_len(sg)) {
1130 *(rp++) =
1131 cpu_to_le32(RISC_WRITE | sg_dma_len(sg));
1132 *(rp++) = cpu_to_le32(sg_dma_address(sg));
1133 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1134 todo -= sg_dma_len(sg);
1135 sg++;
1136 }
1137 *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
1138 *(rp++) = cpu_to_le32(sg_dma_address(sg));
1139 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1140 offset += todo;
1141 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001142
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001143 offset += padding;
1144 }
1145
1146 return rp;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001147}
1148
1149int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001150 struct scatterlist *sglist, unsigned int top_offset,
1151 unsigned int bottom_offset, unsigned int bpl,
1152 unsigned int padding, unsigned int lines)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001153{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001154 u32 instructions;
1155 u32 fields;
1156 __le32 *rp;
1157 int rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001158
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001159 fields = 0;
1160 if (UNSET != top_offset)
1161 fields++;
1162 if (UNSET != bottom_offset)
1163 fields++;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001164
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001165 /* estimate risc mem: worst case is one write per page border +
1166 one write per scan line + syncs + jump (all 2 dwords). Padding
1167 can cause next bpl to start close to a page border. First DMA
1168 region may be smaller than PAGE_SIZE */
1169 /* write and jump need and extra dword */
1170 instructions =
1171 fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
1172 instructions += 2;
1173 rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001174
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001175 if (rc < 0)
1176 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001177
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001178 /* write risc instructions */
1179 rp = risc->cpu;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001180
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001181 if (UNSET != top_offset) {
1182 rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding,
1183 lines);
1184 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001185
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001186 if (UNSET != bottom_offset) {
1187 rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl,
1188 padding, lines);
1189 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001190
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001191 /* save pointer to jmp instruction address */
1192 risc->jmp = rp;
1193 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001194
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001195 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001196}
1197
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001198static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
1199 unsigned int offset, u32 sync_line,
1200 unsigned int bpl, unsigned int padding,
1201 unsigned int lines, unsigned int lpi)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001202{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001203 struct scatterlist *sg;
1204 unsigned int line, todo, sol;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001205
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001206 /* sync instruction */
1207 if (sync_line != NO_SYNC_LINE)
1208 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001209
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001210 /* scan lines */
1211 sg = sglist;
1212 for (line = 0; line < lines; line++) {
1213 while (offset && offset >= sg_dma_len(sg)) {
1214 offset -= sg_dma_len(sg);
1215 sg++;
1216 }
1217
1218 if (lpi && line > 0 && !(line % lpi))
1219 sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
1220 else
1221 sol = RISC_SOL;
1222
1223 if (bpl <= sg_dma_len(sg) - offset) {
1224 /* fits into current chunk */
1225 *(rp++) =
1226 cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl);
1227 *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1228 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1229 offset += bpl;
1230 } else {
1231 /* scanline needs to be split */
1232 todo = bpl;
1233 *(rp++) = cpu_to_le32(RISC_WRITE | sol |
1234 (sg_dma_len(sg) - offset));
1235 *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1236 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1237 todo -= (sg_dma_len(sg) - offset);
1238 offset = 0;
1239 sg++;
1240 while (todo > sg_dma_len(sg)) {
1241 *(rp++) = cpu_to_le32(RISC_WRITE |
1242 sg_dma_len(sg));
1243 *(rp++) = cpu_to_le32(sg_dma_address(sg));
1244 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1245 todo -= sg_dma_len(sg);
1246 sg++;
1247 }
1248 *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
1249 *(rp++) = cpu_to_le32(sg_dma_address(sg));
1250 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1251 offset += todo;
1252 }
1253 offset += padding;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001254 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001255
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001256 return rp;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001257}
1258
1259int cx25821_risc_databuffer_audio(struct pci_dev *pci,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001260 struct btcx_riscmem *risc,
1261 struct scatterlist *sglist,
1262 unsigned int bpl,
1263 unsigned int lines, unsigned int lpi)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001264{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001265 u32 instructions;
1266 __le32 *rp;
1267 int rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001268
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001269 /* estimate risc mem: worst case is one write per page border +
1270 one write per scan line + syncs + jump (all 2 dwords). Here
1271 there is no padding and no sync. First DMA region may be smaller
1272 than PAGE_SIZE */
1273 /* Jump and write need an extra dword */
1274 instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
1275 instructions += 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001276
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001277 rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
1278 if (rc < 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001279 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001280
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001281 /* write risc instructions */
1282 rp = risc->cpu;
1283 rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0,
1284 lines, lpi);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001285
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001286 /* save pointer to jmp instruction address */
1287 risc->jmp = rp;
1288 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
1289 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001290}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001291EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001292
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001293int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
1294 u32 reg, u32 mask, u32 value)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001295{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001296 __le32 *rp;
1297 int rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001298
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001299 rc = btcx_riscmem_alloc(pci, risc, 4 * 16);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001300
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001301 if (rc < 0)
1302 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001303
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001304 /* write risc instructions */
1305 rp = risc->cpu;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001306
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001307 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1);
1308 *(rp++) = cpu_to_le32(reg);
1309 *(rp++) = cpu_to_le32(value);
1310 *(rp++) = cpu_to_le32(mask);
1311 *(rp++) = cpu_to_le32(RISC_JUMP);
1312 *(rp++) = cpu_to_le32(risc->dma);
1313 *(rp++) = cpu_to_le32(0); /* bits 63-32 */
1314 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001315}
1316
1317void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
1318{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001319 struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001320
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001321 BUG_ON(in_interrupt());
Hans Verkuil0e0809a2010-09-26 09:01:26 -03001322 videobuf_waiton(q, &buf->vb, 0, 0);
Laurent Pinchart95268402010-05-11 10:36:30 -03001323 videobuf_dma_unmap(q->dev, dma);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001324 videobuf_dma_free(dma);
1325 btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
1326 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001327}
1328
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001329static irqreturn_t cx25821_irq(int irq, void *dev_id)
1330{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001331 struct cx25821_dev *dev = dev_id;
1332 u32 pci_status, pci_mask;
1333 u32 vid_status;
1334 int i, handled = 0;
1335 u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001336
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001337 pci_status = cx_read(PCI_INT_STAT);
1338 pci_mask = cx_read(PCI_INT_MSK);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001339
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001340 if (pci_status == 0)
1341 goto out;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001342
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001343 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1344 if (pci_status & mask[i]) {
Ruslan Pisareve4115bb2010-09-27 10:01:36 -03001345 vid_status = cx_read(dev->channels[i].
1346 sram_channels->int_stat);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001347
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001348 if (vid_status)
1349 handled +=
Ruslan Pisareve4115bb2010-09-27 10:01:36 -03001350 cx25821_video_irq(dev, i, vid_status);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001351
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001352 cx_write(PCI_INT_STAT, mask[i]);
1353 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001354 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001355
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001356out:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001357 return IRQ_RETVAL(handled);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001358}
1359
1360void cx25821_print_irqbits(char *name, char *tag, char **strings,
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001361 int len, u32 bits, u32 mask)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001362{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001363 unsigned int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001364
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001365 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001366
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001367 for (i = 0; i < len; i++) {
1368 if (!(bits & (1 << i)))
1369 continue;
1370 if (strings[i])
1371 printk(" %s", strings[i]);
1372 else
1373 printk(" %d", i);
1374 if (!(mask & (1 << i)))
1375 continue;
1376 printk("*");
1377 }
1378 printk("\n");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001379}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001380EXPORT_SYMBOL(cx25821_print_irqbits);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001381
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001382struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001383{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001384 struct cx25821_dev *dev = pci_get_drvdata(pci);
1385 return dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001386}
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001387EXPORT_SYMBOL(cx25821_dev_get);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001388
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001389static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
1390 const struct pci_device_id *pci_id)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001391{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001392 struct cx25821_dev *dev;
1393 int err = 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001394
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001395 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1396 if (NULL == dev)
1397 return -ENOMEM;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001398
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001399 err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
1400 if (err < 0)
1401 goto fail_free;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001402
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001403 /* pci init */
1404 dev->pci = pci_dev;
1405 if (pci_enable_device(pci_dev)) {
1406 err = -EIO;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001407
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001408 printk(KERN_INFO "pci enable failed! ");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001409
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001410 goto fail_unregister_device;
1411 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001412
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001413 printk(KERN_INFO "cx25821 Athena pci enable !\n");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001414
Kulikov Vasiliyc37c6d22010-08-06 23:52:57 +04001415 err = cx25821_dev_setup(dev);
1416 if (err) {
1417 if (err == -EBUSY)
1418 goto fail_unregister_device;
1419 else
1420 goto fail_unregister_pci;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001421 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001422
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001423 /* print pci info */
1424 pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
1425 pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
1426 printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
1427 "latency: %d, mmio: 0x%llx\n", dev->name,
1428 pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
1429 dev->pci_lat, (unsigned long long)dev->base_io_addr);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001430
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001431 pci_set_master(pci_dev);
1432 if (!pci_dma_supported(pci_dev, 0xffffffff)) {
1433 printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
1434 err = -EIO;
1435 goto fail_irq;
1436 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001437
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001438 err =
1439 request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED | IRQF_DISABLED,
1440 dev->name, dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001441
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001442 if (err < 0) {
1443 printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
1444 pci_dev->irq);
1445 goto fail_irq;
1446 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001447
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001448 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001449
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001450fail_irq:
1451 printk(KERN_INFO "cx25821 cx25821_initdev() can't get IRQ !\n");
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001452 cx25821_dev_unregister(dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001453
Kulikov Vasiliyc37c6d22010-08-06 23:52:57 +04001454fail_unregister_pci:
1455 pci_disable_device(pci_dev);
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001456fail_unregister_device:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001457 v4l2_device_unregister(&dev->v4l2_dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001458
Olimpiu Pascariude2c4342010-03-21 14:18:19 -03001459fail_free:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001460 kfree(dev);
1461 return err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001462}
1463
1464static void __devexit cx25821_finidev(struct pci_dev *pci_dev)
1465{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001466 struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
1467 struct cx25821_dev *dev = get_cx25821(v4l2_dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001468
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001469 cx25821_shutdown(dev);
1470 pci_disable_device(pci_dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001471
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001472 /* unregister stuff */
1473 if (pci_dev->irq)
1474 free_irq(pci_dev->irq, dev);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001475
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001476 mutex_lock(&devlist);
1477 list_del(&dev->devlist);
1478 mutex_unlock(&devlist);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001479
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001480 cx25821_dev_unregister(dev);
1481 v4l2_device_unregister(v4l2_dev);
1482 kfree(dev);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001483}
1484
1485static struct pci_device_id cx25821_pci_tbl[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001486 {
1487 /* CX25821 Athena */
1488 .vendor = 0x14f1,
1489 .device = 0x8210,
1490 .subvendor = 0x14f1,
1491 .subdevice = 0x0920,
1492 },
1493 {
1494 /* --- end of list --- */
1495 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001496};
1497
1498MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl);
1499
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001500static struct pci_driver cx25821_pci_driver = {
1501 .name = "cx25821",
1502 .id_table = cx25821_pci_tbl,
1503 .probe = cx25821_initdev,
1504 .remove = __devexit_p(cx25821_finidev),
1505 /* TODO */
1506 .suspend = NULL,
1507 .resume = NULL,
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001508};
1509
Peter Huewe64ed20162009-09-29 01:40:59 +02001510static int __init cx25821_init(void)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001511{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001512 INIT_LIST_HEAD(&cx25821_devlist);
1513 printk(KERN_INFO "cx25821 driver version %d.%d.%d loaded\n",
1514 (CX25821_VERSION_CODE >> 16) & 0xff,
1515 (CX25821_VERSION_CODE >> 8) & 0xff, CX25821_VERSION_CODE & 0xff);
1516 return pci_register_driver(&cx25821_pci_driver);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001517}
1518
Peter Huewe64ed20162009-09-29 01:40:59 +02001519static void __exit cx25821_fini(void)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001520{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001521 pci_unregister_driver(&cx25821_pci_driver);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001522}
1523
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001524EXPORT_SYMBOL(cx25821_set_gpiopin_direction);
1525
1526module_init(cx25821_init);
1527module_exit(cx25821_fini);