xref: /OK3568_Linux_fs/kernel/drivers/media/pci/cx23885/cx23885-417.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Support for a cx23417 mpeg encoder via cx23885 host port.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *    (c) 2004 Jelle Foks <jelle@foks.us>
7*4882a593Smuzhiyun  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
8*4882a593Smuzhiyun  *    (c) 2008 Steven Toth <stoth@linuxtv.org>
9*4882a593Smuzhiyun  *      - CX23885/7/8 support
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *  Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "cx23885.h"
15*4882a593Smuzhiyun #include "cx23885-ioctl.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/moduleparam.h>
19*4882a593Smuzhiyun #include <linux/init.h>
20*4882a593Smuzhiyun #include <linux/fs.h>
21*4882a593Smuzhiyun #include <linux/delay.h>
22*4882a593Smuzhiyun #include <linux/device.h>
23*4882a593Smuzhiyun #include <linux/firmware.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <media/v4l2-common.h>
26*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
27*4882a593Smuzhiyun #include <media/drv-intf/cx2341x.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define CX23885_FIRM_IMAGE_SIZE 376836
30*4882a593Smuzhiyun #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun static unsigned int mpegbufs = 32;
33*4882a593Smuzhiyun module_param(mpegbufs, int, 0644);
34*4882a593Smuzhiyun MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
35*4882a593Smuzhiyun static unsigned int mpeglines = 32;
36*4882a593Smuzhiyun module_param(mpeglines, int, 0644);
37*4882a593Smuzhiyun MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
38*4882a593Smuzhiyun static unsigned int mpeglinesize = 512;
39*4882a593Smuzhiyun module_param(mpeglinesize, int, 0644);
40*4882a593Smuzhiyun MODULE_PARM_DESC(mpeglinesize,
41*4882a593Smuzhiyun 	"number of bytes in each line of an MPEG buffer, range 512-1024");
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static unsigned int v4l_debug;
44*4882a593Smuzhiyun module_param(v4l_debug, int, 0644);
45*4882a593Smuzhiyun MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define dprintk(level, fmt, arg...)\
48*4882a593Smuzhiyun 	do { if (v4l_debug >= level) \
49*4882a593Smuzhiyun 		printk(KERN_DEBUG pr_fmt("%s: 417:" fmt), \
50*4882a593Smuzhiyun 			__func__, ##arg); \
51*4882a593Smuzhiyun 	} while (0)
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static struct cx23885_tvnorm cx23885_tvnorms[] = {
54*4882a593Smuzhiyun 	{
55*4882a593Smuzhiyun 		.name      = "NTSC-M",
56*4882a593Smuzhiyun 		.id        = V4L2_STD_NTSC_M,
57*4882a593Smuzhiyun 	}, {
58*4882a593Smuzhiyun 		.name      = "NTSC-JP",
59*4882a593Smuzhiyun 		.id        = V4L2_STD_NTSC_M_JP,
60*4882a593Smuzhiyun 	}, {
61*4882a593Smuzhiyun 		.name      = "PAL-BG",
62*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_BG,
63*4882a593Smuzhiyun 	}, {
64*4882a593Smuzhiyun 		.name      = "PAL-DK",
65*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_DK,
66*4882a593Smuzhiyun 	}, {
67*4882a593Smuzhiyun 		.name      = "PAL-I",
68*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_I,
69*4882a593Smuzhiyun 	}, {
70*4882a593Smuzhiyun 		.name      = "PAL-M",
71*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_M,
72*4882a593Smuzhiyun 	}, {
73*4882a593Smuzhiyun 		.name      = "PAL-N",
74*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_N,
75*4882a593Smuzhiyun 	}, {
76*4882a593Smuzhiyun 		.name      = "PAL-Nc",
77*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_Nc,
78*4882a593Smuzhiyun 	}, {
79*4882a593Smuzhiyun 		.name      = "PAL-60",
80*4882a593Smuzhiyun 		.id        = V4L2_STD_PAL_60,
81*4882a593Smuzhiyun 	}, {
82*4882a593Smuzhiyun 		.name      = "SECAM-L",
83*4882a593Smuzhiyun 		.id        = V4L2_STD_SECAM_L,
84*4882a593Smuzhiyun 	}, {
85*4882a593Smuzhiyun 		.name      = "SECAM-DK",
86*4882a593Smuzhiyun 		.id        = V4L2_STD_SECAM_DK,
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
91*4882a593Smuzhiyun enum cx23885_capture_type {
92*4882a593Smuzhiyun 	CX23885_MPEG_CAPTURE,
93*4882a593Smuzhiyun 	CX23885_RAW_CAPTURE,
94*4882a593Smuzhiyun 	CX23885_RAW_PASSTHRU_CAPTURE
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun enum cx23885_capture_bits {
97*4882a593Smuzhiyun 	CX23885_RAW_BITS_NONE             = 0x00,
98*4882a593Smuzhiyun 	CX23885_RAW_BITS_YUV_CAPTURE      = 0x01,
99*4882a593Smuzhiyun 	CX23885_RAW_BITS_PCM_CAPTURE      = 0x02,
100*4882a593Smuzhiyun 	CX23885_RAW_BITS_VBI_CAPTURE      = 0x04,
101*4882a593Smuzhiyun 	CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
102*4882a593Smuzhiyun 	CX23885_RAW_BITS_TO_HOST_CAPTURE  = 0x10
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun enum cx23885_capture_end {
105*4882a593Smuzhiyun 	CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
106*4882a593Smuzhiyun 	CX23885_END_NOW, /* stop immediately, no irq */
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun enum cx23885_framerate {
109*4882a593Smuzhiyun 	CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
110*4882a593Smuzhiyun 	CX23885_FRAMERATE_PAL_25   /* PAL: 25fps */
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun enum cx23885_stream_port {
113*4882a593Smuzhiyun 	CX23885_OUTPUT_PORT_MEMORY,
114*4882a593Smuzhiyun 	CX23885_OUTPUT_PORT_STREAMING,
115*4882a593Smuzhiyun 	CX23885_OUTPUT_PORT_SERIAL
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun enum cx23885_data_xfer_status {
118*4882a593Smuzhiyun 	CX23885_MORE_BUFFERS_FOLLOW,
119*4882a593Smuzhiyun 	CX23885_LAST_BUFFER,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun enum cx23885_picture_mask {
122*4882a593Smuzhiyun 	CX23885_PICTURE_MASK_NONE,
123*4882a593Smuzhiyun 	CX23885_PICTURE_MASK_I_FRAMES,
124*4882a593Smuzhiyun 	CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
125*4882a593Smuzhiyun 	CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun enum cx23885_vbi_mode_bits {
128*4882a593Smuzhiyun 	CX23885_VBI_BITS_SLICED,
129*4882a593Smuzhiyun 	CX23885_VBI_BITS_RAW,
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun enum cx23885_vbi_insertion_bits {
132*4882a593Smuzhiyun 	CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
133*4882a593Smuzhiyun 	CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
134*4882a593Smuzhiyun 	CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
135*4882a593Smuzhiyun 	CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
136*4882a593Smuzhiyun 	CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun enum cx23885_dma_unit {
139*4882a593Smuzhiyun 	CX23885_DMA_BYTES,
140*4882a593Smuzhiyun 	CX23885_DMA_FRAMES,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun enum cx23885_dma_transfer_status_bits {
143*4882a593Smuzhiyun 	CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
144*4882a593Smuzhiyun 	CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
145*4882a593Smuzhiyun 	CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun enum cx23885_pause {
148*4882a593Smuzhiyun 	CX23885_PAUSE_ENCODING,
149*4882a593Smuzhiyun 	CX23885_RESUME_ENCODING,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun enum cx23885_copyright {
152*4882a593Smuzhiyun 	CX23885_COPYRIGHT_OFF,
153*4882a593Smuzhiyun 	CX23885_COPYRIGHT_ON,
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun enum cx23885_notification_type {
156*4882a593Smuzhiyun 	CX23885_NOTIFICATION_REFRESH,
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun enum cx23885_notification_status {
159*4882a593Smuzhiyun 	CX23885_NOTIFICATION_OFF,
160*4882a593Smuzhiyun 	CX23885_NOTIFICATION_ON,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun enum cx23885_notification_mailbox {
163*4882a593Smuzhiyun 	CX23885_NOTIFICATION_NO_MAILBOX = -1,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun enum cx23885_field1_lines {
166*4882a593Smuzhiyun 	CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
167*4882a593Smuzhiyun 	CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
168*4882a593Smuzhiyun 	CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun enum cx23885_field2_lines {
171*4882a593Smuzhiyun 	CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
172*4882a593Smuzhiyun 	CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
173*4882a593Smuzhiyun 	CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun enum cx23885_custom_data_type {
176*4882a593Smuzhiyun 	CX23885_CUSTOM_EXTENSION_USR_DATA,
177*4882a593Smuzhiyun 	CX23885_CUSTOM_PRIVATE_PACKET,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun enum cx23885_mute {
180*4882a593Smuzhiyun 	CX23885_UNMUTE,
181*4882a593Smuzhiyun 	CX23885_MUTE,
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun enum cx23885_mute_video_mask {
184*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
185*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
186*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun enum cx23885_mute_video_shift {
189*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_V_SHIFT = 8,
190*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_U_SHIFT = 16,
191*4882a593Smuzhiyun 	CX23885_MUTE_VIDEO_Y_SHIFT = 24,
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /* defines below are from ivtv-driver.h */
195*4882a593Smuzhiyun #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /* Firmware API commands */
198*4882a593Smuzhiyun #define IVTV_API_STD_TIMEOUT 500
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun /* Registers */
201*4882a593Smuzhiyun /* IVTV_REG_OFFSET */
202*4882a593Smuzhiyun #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
203*4882a593Smuzhiyun #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
204*4882a593Smuzhiyun #define IVTV_REG_SPU (0x9050)
205*4882a593Smuzhiyun #define IVTV_REG_HW_BLOCKS (0x9054)
206*4882a593Smuzhiyun #define IVTV_REG_VPU (0x9058)
207*4882a593Smuzhiyun #define IVTV_REG_APU (0xA064)
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /**** Bit definitions for MC417_RWD and MC417_OEN registers  ***
210*4882a593Smuzhiyun   bits 31-16
211*4882a593Smuzhiyun +-----------+
212*4882a593Smuzhiyun | Reserved  |
213*4882a593Smuzhiyun +-----------+
214*4882a593Smuzhiyun   bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
215*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
216*4882a593Smuzhiyun | MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
217*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
218*4882a593Smuzhiyun  bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
219*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
220*4882a593Smuzhiyun |MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
221*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
222*4882a593Smuzhiyun ***/
223*4882a593Smuzhiyun #define MC417_MIWR	0x8000
224*4882a593Smuzhiyun #define MC417_MIRD	0x4000
225*4882a593Smuzhiyun #define MC417_MICS	0x2000
226*4882a593Smuzhiyun #define MC417_MIRDY	0x1000
227*4882a593Smuzhiyun #define MC417_MIADDR	0x0F00
228*4882a593Smuzhiyun #define MC417_MIDATA	0x00FF
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun /* MIADDR* nibble definitions */
231*4882a593Smuzhiyun #define  MCI_MEMORY_DATA_BYTE0          0x000
232*4882a593Smuzhiyun #define  MCI_MEMORY_DATA_BYTE1          0x100
233*4882a593Smuzhiyun #define  MCI_MEMORY_DATA_BYTE2          0x200
234*4882a593Smuzhiyun #define  MCI_MEMORY_DATA_BYTE3          0x300
235*4882a593Smuzhiyun #define  MCI_MEMORY_ADDRESS_BYTE2       0x400
236*4882a593Smuzhiyun #define  MCI_MEMORY_ADDRESS_BYTE1       0x500
237*4882a593Smuzhiyun #define  MCI_MEMORY_ADDRESS_BYTE0       0x600
238*4882a593Smuzhiyun #define  MCI_REGISTER_DATA_BYTE0        0x800
239*4882a593Smuzhiyun #define  MCI_REGISTER_DATA_BYTE1        0x900
240*4882a593Smuzhiyun #define  MCI_REGISTER_DATA_BYTE2        0xA00
241*4882a593Smuzhiyun #define  MCI_REGISTER_DATA_BYTE3        0xB00
242*4882a593Smuzhiyun #define  MCI_REGISTER_ADDRESS_BYTE0     0xC00
243*4882a593Smuzhiyun #define  MCI_REGISTER_ADDRESS_BYTE1     0xD00
244*4882a593Smuzhiyun #define  MCI_REGISTER_MODE              0xE00
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun /* Read and write modes */
247*4882a593Smuzhiyun #define  MCI_MODE_REGISTER_READ         0
248*4882a593Smuzhiyun #define  MCI_MODE_REGISTER_WRITE        1
249*4882a593Smuzhiyun #define  MCI_MODE_MEMORY_READ           0
250*4882a593Smuzhiyun #define  MCI_MODE_MEMORY_WRITE          0x40
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /*** Bit definitions for MC417_CTL register ****
253*4882a593Smuzhiyun  bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
254*4882a593Smuzhiyun +--------+-------------+--------+--------------+------------+
255*4882a593Smuzhiyun |Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
256*4882a593Smuzhiyun +--------+-------------+--------+--------------+------------+
257*4882a593Smuzhiyun ***/
258*4882a593Smuzhiyun #define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
259*4882a593Smuzhiyun #define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
260*4882a593Smuzhiyun #define MC417_UART_GPIO_EN	0x00000001
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun /* Values for speed control */
263*4882a593Smuzhiyun #define MC417_SPD_CTL_SLOW	0x1
264*4882a593Smuzhiyun #define MC417_SPD_CTL_MEDIUM	0x0
265*4882a593Smuzhiyun #define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun /* Values for GPIO select */
268*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO3	0x3
269*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO2	0x2
270*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO1	0x1
271*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO0	0x0
272*4882a593Smuzhiyun 
cx23885_mc417_init(struct cx23885_dev * dev)273*4882a593Smuzhiyun void cx23885_mc417_init(struct cx23885_dev *dev)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	u32 regval;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	dprintk(2, "%s()\n", __func__);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/* Configure MC417_CTL register to defaults. */
280*4882a593Smuzhiyun 	regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST)	|
281*4882a593Smuzhiyun 		 MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3)	|
282*4882a593Smuzhiyun 		 MC417_UART_GPIO_EN;
283*4882a593Smuzhiyun 	cx_write(MC417_CTL, regval);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* Configure MC417_OEN to defaults. */
286*4882a593Smuzhiyun 	regval = MC417_MIRDY;
287*4882a593Smuzhiyun 	cx_write(MC417_OEN, regval);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/* Configure MC417_RWD to defaults. */
290*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
291*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
mc417_wait_ready(struct cx23885_dev * dev)294*4882a593Smuzhiyun static int mc417_wait_ready(struct cx23885_dev *dev)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	u32 mi_ready;
297*4882a593Smuzhiyun 	unsigned long timeout = jiffies + msecs_to_jiffies(1);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	for (;;) {
300*4882a593Smuzhiyun 		mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
301*4882a593Smuzhiyun 		if (mi_ready != 0)
302*4882a593Smuzhiyun 			return 0;
303*4882a593Smuzhiyun 		if (time_after(jiffies, timeout))
304*4882a593Smuzhiyun 			return -1;
305*4882a593Smuzhiyun 		udelay(1);
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
mc417_register_write(struct cx23885_dev * dev,u16 address,u32 value)309*4882a593Smuzhiyun int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	u32 regval;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
314*4882a593Smuzhiyun 	 * which is an input.
315*4882a593Smuzhiyun 	 */
316*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* Write data byte 0 */
319*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
320*4882a593Smuzhiyun 		(value & 0x000000FF);
321*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	/* Transition CS/WR to effect write transaction across bus. */
324*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
325*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* Write data byte 1 */
328*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
329*4882a593Smuzhiyun 		((value >> 8) & 0x000000FF);
330*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
331*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
332*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* Write data byte 2 */
335*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
336*4882a593Smuzhiyun 		((value >> 16) & 0x000000FF);
337*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
338*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
339*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/* Write data byte 3 */
342*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
343*4882a593Smuzhiyun 		((value >> 24) & 0x000000FF);
344*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
345*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
346*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Write address byte 0 */
349*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
350*4882a593Smuzhiyun 		(address & 0xFF);
351*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
352*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
353*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/* Write address byte 1 */
356*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
357*4882a593Smuzhiyun 		((address >> 8) & 0xFF);
358*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
359*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
360*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	/* Indicate that this is a write. */
363*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
364*4882a593Smuzhiyun 		MCI_MODE_REGISTER_WRITE;
365*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
366*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
367*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	/* Wait for the trans to complete (MC417_MIRDY asserted). */
370*4882a593Smuzhiyun 	return mc417_wait_ready(dev);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
mc417_register_read(struct cx23885_dev * dev,u16 address,u32 * value)373*4882a593Smuzhiyun int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	int retval;
376*4882a593Smuzhiyun 	u32 regval;
377*4882a593Smuzhiyun 	u32 tempval;
378*4882a593Smuzhiyun 	u32 dataval;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
381*4882a593Smuzhiyun 	 * which is an input.
382*4882a593Smuzhiyun 	 */
383*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	/* Write address byte 0 */
386*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
387*4882a593Smuzhiyun 		((address & 0x00FF));
388*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
389*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
390*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	/* Write address byte 1 */
393*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
394*4882a593Smuzhiyun 		((address >> 8) & 0xFF);
395*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
396*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
397*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Indicate that this is a register read. */
400*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
401*4882a593Smuzhiyun 		MCI_MODE_REGISTER_READ;
402*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
403*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
404*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	/* Wait for the trans to complete (MC417_MIRDY asserted). */
407*4882a593Smuzhiyun 	retval = mc417_wait_ready(dev);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* switch the DAT0-7 GPIO[10:3] to input mode */
410*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	/* Read data byte 0 */
413*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
414*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	/* Transition RD to effect read transaction across bus.
417*4882a593Smuzhiyun 	 * Transition 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
418*4882a593Smuzhiyun 	 * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
419*4882a593Smuzhiyun 	 * input only...)
420*4882a593Smuzhiyun 	 */
421*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
422*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* Collect byte */
425*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
426*4882a593Smuzhiyun 	dataval = tempval & 0x000000FF;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	/* Bring CS and RD high. */
429*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
430*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	/* Read data byte 1 */
433*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
434*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
435*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
436*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
437*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
438*4882a593Smuzhiyun 	dataval |= ((tempval & 0x000000FF) << 8);
439*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
440*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	/* Read data byte 2 */
443*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
444*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
445*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
446*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
447*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
448*4882a593Smuzhiyun 	dataval |= ((tempval & 0x000000FF) << 16);
449*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
450*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	/* Read data byte 3 */
453*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
454*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
455*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
456*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
457*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
458*4882a593Smuzhiyun 	dataval |= ((tempval & 0x000000FF) << 24);
459*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
460*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	*value  = dataval;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	return retval;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
mc417_memory_write(struct cx23885_dev * dev,u32 address,u32 value)467*4882a593Smuzhiyun int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	u32 regval;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
472*4882a593Smuzhiyun 	 * which is an input.
473*4882a593Smuzhiyun 	 */
474*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	/* Write data byte 0 */
477*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
478*4882a593Smuzhiyun 		(value & 0x000000FF);
479*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	/* Transition CS/WR to effect write transaction across bus. */
482*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
483*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	/* Write data byte 1 */
486*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
487*4882a593Smuzhiyun 		((value >> 8) & 0x000000FF);
488*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
489*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
490*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* Write data byte 2 */
493*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
494*4882a593Smuzhiyun 		((value >> 16) & 0x000000FF);
495*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
496*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
497*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/* Write data byte 3 */
500*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
501*4882a593Smuzhiyun 		((value >> 24) & 0x000000FF);
502*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
503*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
504*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	/* Write address byte 2 */
507*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
508*4882a593Smuzhiyun 		MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
509*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
510*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
511*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	/* Write address byte 1 */
514*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
515*4882a593Smuzhiyun 		((address >> 8) & 0xFF);
516*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
517*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
518*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* Write address byte 0 */
521*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
522*4882a593Smuzhiyun 		(address & 0xFF);
523*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
524*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
525*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	/* Wait for the trans to complete (MC417_MIRDY asserted). */
528*4882a593Smuzhiyun 	return mc417_wait_ready(dev);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
mc417_memory_read(struct cx23885_dev * dev,u32 address,u32 * value)531*4882a593Smuzhiyun int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	int retval;
534*4882a593Smuzhiyun 	u32 regval;
535*4882a593Smuzhiyun 	u32 tempval;
536*4882a593Smuzhiyun 	u32 dataval;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
539*4882a593Smuzhiyun 	 * which is an input.
540*4882a593Smuzhiyun 	 */
541*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* Write address byte 2 */
544*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
545*4882a593Smuzhiyun 		MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
546*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
547*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
548*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	/* Write address byte 1 */
551*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
552*4882a593Smuzhiyun 		((address >> 8) & 0xFF);
553*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
554*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
555*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/* Write address byte 0 */
558*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
559*4882a593Smuzhiyun 		(address & 0xFF);
560*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
561*4882a593Smuzhiyun 	regval |= MC417_MICS | MC417_MIWR;
562*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/* Wait for the trans to complete (MC417_MIRDY asserted). */
565*4882a593Smuzhiyun 	retval = mc417_wait_ready(dev);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* switch the DAT0-7 GPIO[10:3] to input mode */
568*4882a593Smuzhiyun 	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* Read data byte 3 */
571*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
572*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/* Transition RD to effect read transaction across bus. */
575*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
576*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	/* Collect byte */
579*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
580*4882a593Smuzhiyun 	dataval = ((tempval & 0x000000FF) << 24);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	/* Bring CS and RD high. */
583*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
584*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	/* Read data byte 2 */
587*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
588*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
589*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
590*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
591*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
592*4882a593Smuzhiyun 	dataval |= ((tempval & 0x000000FF) << 16);
593*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
594*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/* Read data byte 1 */
597*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
598*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
599*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
600*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
601*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
602*4882a593Smuzhiyun 	dataval |= ((tempval & 0x000000FF) << 8);
603*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
604*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* Read data byte 0 */
607*4882a593Smuzhiyun 	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
608*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
609*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
610*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
611*4882a593Smuzhiyun 	tempval = cx_read(MC417_RWD);
612*4882a593Smuzhiyun 	dataval |= (tempval & 0x000000FF);
613*4882a593Smuzhiyun 	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
614*4882a593Smuzhiyun 	cx_write(MC417_RWD, regval);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	*value  = dataval;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return retval;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
mc417_gpio_set(struct cx23885_dev * dev,u32 mask)621*4882a593Smuzhiyun void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	u32 val;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	/* Set the gpio value */
626*4882a593Smuzhiyun 	mc417_register_read(dev, 0x900C, &val);
627*4882a593Smuzhiyun 	val |= (mask & 0x000ffff);
628*4882a593Smuzhiyun 	mc417_register_write(dev, 0x900C, val);
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
mc417_gpio_clear(struct cx23885_dev * dev,u32 mask)631*4882a593Smuzhiyun void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	u32 val;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	/* Clear the gpio value */
636*4882a593Smuzhiyun 	mc417_register_read(dev, 0x900C, &val);
637*4882a593Smuzhiyun 	val &= ~(mask & 0x0000ffff);
638*4882a593Smuzhiyun 	mc417_register_write(dev, 0x900C, val);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
mc417_gpio_enable(struct cx23885_dev * dev,u32 mask,int asoutput)641*4882a593Smuzhiyun void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	u32 val;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	/* Enable GPIO direction bits */
646*4882a593Smuzhiyun 	mc417_register_read(dev, 0x9020, &val);
647*4882a593Smuzhiyun 	if (asoutput)
648*4882a593Smuzhiyun 		val |= (mask & 0x0000ffff);
649*4882a593Smuzhiyun 	else
650*4882a593Smuzhiyun 		val &= ~(mask & 0x0000ffff);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	mc417_register_write(dev, 0x9020, val);
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun /* MPEG encoder API */
cmd_to_str(int cmd)657*4882a593Smuzhiyun static char *cmd_to_str(int cmd)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	switch (cmd) {
660*4882a593Smuzhiyun 	case CX2341X_ENC_PING_FW:
661*4882a593Smuzhiyun 		return  "PING_FW";
662*4882a593Smuzhiyun 	case CX2341X_ENC_START_CAPTURE:
663*4882a593Smuzhiyun 		return  "START_CAPTURE";
664*4882a593Smuzhiyun 	case CX2341X_ENC_STOP_CAPTURE:
665*4882a593Smuzhiyun 		return  "STOP_CAPTURE";
666*4882a593Smuzhiyun 	case CX2341X_ENC_SET_AUDIO_ID:
667*4882a593Smuzhiyun 		return  "SET_AUDIO_ID";
668*4882a593Smuzhiyun 	case CX2341X_ENC_SET_VIDEO_ID:
669*4882a593Smuzhiyun 		return  "SET_VIDEO_ID";
670*4882a593Smuzhiyun 	case CX2341X_ENC_SET_PCR_ID:
671*4882a593Smuzhiyun 		return  "SET_PCR_ID";
672*4882a593Smuzhiyun 	case CX2341X_ENC_SET_FRAME_RATE:
673*4882a593Smuzhiyun 		return  "SET_FRAME_RATE";
674*4882a593Smuzhiyun 	case CX2341X_ENC_SET_FRAME_SIZE:
675*4882a593Smuzhiyun 		return  "SET_FRAME_SIZE";
676*4882a593Smuzhiyun 	case CX2341X_ENC_SET_BIT_RATE:
677*4882a593Smuzhiyun 		return  "SET_BIT_RATE";
678*4882a593Smuzhiyun 	case CX2341X_ENC_SET_GOP_PROPERTIES:
679*4882a593Smuzhiyun 		return  "SET_GOP_PROPERTIES";
680*4882a593Smuzhiyun 	case CX2341X_ENC_SET_ASPECT_RATIO:
681*4882a593Smuzhiyun 		return  "SET_ASPECT_RATIO";
682*4882a593Smuzhiyun 	case CX2341X_ENC_SET_DNR_FILTER_MODE:
683*4882a593Smuzhiyun 		return  "SET_DNR_FILTER_MODE";
684*4882a593Smuzhiyun 	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
685*4882a593Smuzhiyun 		return  "SET_DNR_FILTER_PROPS";
686*4882a593Smuzhiyun 	case CX2341X_ENC_SET_CORING_LEVELS:
687*4882a593Smuzhiyun 		return  "SET_CORING_LEVELS";
688*4882a593Smuzhiyun 	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
689*4882a593Smuzhiyun 		return  "SET_SPATIAL_FILTER_TYPE";
690*4882a593Smuzhiyun 	case CX2341X_ENC_SET_VBI_LINE:
691*4882a593Smuzhiyun 		return  "SET_VBI_LINE";
692*4882a593Smuzhiyun 	case CX2341X_ENC_SET_STREAM_TYPE:
693*4882a593Smuzhiyun 		return  "SET_STREAM_TYPE";
694*4882a593Smuzhiyun 	case CX2341X_ENC_SET_OUTPUT_PORT:
695*4882a593Smuzhiyun 		return  "SET_OUTPUT_PORT";
696*4882a593Smuzhiyun 	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
697*4882a593Smuzhiyun 		return  "SET_AUDIO_PROPERTIES";
698*4882a593Smuzhiyun 	case CX2341X_ENC_HALT_FW:
699*4882a593Smuzhiyun 		return  "HALT_FW";
700*4882a593Smuzhiyun 	case CX2341X_ENC_GET_VERSION:
701*4882a593Smuzhiyun 		return  "GET_VERSION";
702*4882a593Smuzhiyun 	case CX2341X_ENC_SET_GOP_CLOSURE:
703*4882a593Smuzhiyun 		return  "SET_GOP_CLOSURE";
704*4882a593Smuzhiyun 	case CX2341X_ENC_GET_SEQ_END:
705*4882a593Smuzhiyun 		return  "GET_SEQ_END";
706*4882a593Smuzhiyun 	case CX2341X_ENC_SET_PGM_INDEX_INFO:
707*4882a593Smuzhiyun 		return  "SET_PGM_INDEX_INFO";
708*4882a593Smuzhiyun 	case CX2341X_ENC_SET_VBI_CONFIG:
709*4882a593Smuzhiyun 		return  "SET_VBI_CONFIG";
710*4882a593Smuzhiyun 	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
711*4882a593Smuzhiyun 		return  "SET_DMA_BLOCK_SIZE";
712*4882a593Smuzhiyun 	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
713*4882a593Smuzhiyun 		return  "GET_PREV_DMA_INFO_MB_10";
714*4882a593Smuzhiyun 	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
715*4882a593Smuzhiyun 		return  "GET_PREV_DMA_INFO_MB_9";
716*4882a593Smuzhiyun 	case CX2341X_ENC_SCHED_DMA_TO_HOST:
717*4882a593Smuzhiyun 		return  "SCHED_DMA_TO_HOST";
718*4882a593Smuzhiyun 	case CX2341X_ENC_INITIALIZE_INPUT:
719*4882a593Smuzhiyun 		return  "INITIALIZE_INPUT";
720*4882a593Smuzhiyun 	case CX2341X_ENC_SET_FRAME_DROP_RATE:
721*4882a593Smuzhiyun 		return  "SET_FRAME_DROP_RATE";
722*4882a593Smuzhiyun 	case CX2341X_ENC_PAUSE_ENCODER:
723*4882a593Smuzhiyun 		return  "PAUSE_ENCODER";
724*4882a593Smuzhiyun 	case CX2341X_ENC_REFRESH_INPUT:
725*4882a593Smuzhiyun 		return  "REFRESH_INPUT";
726*4882a593Smuzhiyun 	case CX2341X_ENC_SET_COPYRIGHT:
727*4882a593Smuzhiyun 		return  "SET_COPYRIGHT";
728*4882a593Smuzhiyun 	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
729*4882a593Smuzhiyun 		return  "SET_EVENT_NOTIFICATION";
730*4882a593Smuzhiyun 	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
731*4882a593Smuzhiyun 		return  "SET_NUM_VSYNC_LINES";
732*4882a593Smuzhiyun 	case CX2341X_ENC_SET_PLACEHOLDER:
733*4882a593Smuzhiyun 		return  "SET_PLACEHOLDER";
734*4882a593Smuzhiyun 	case CX2341X_ENC_MUTE_VIDEO:
735*4882a593Smuzhiyun 		return  "MUTE_VIDEO";
736*4882a593Smuzhiyun 	case CX2341X_ENC_MUTE_AUDIO:
737*4882a593Smuzhiyun 		return  "MUTE_AUDIO";
738*4882a593Smuzhiyun 	case CX2341X_ENC_MISC:
739*4882a593Smuzhiyun 		return  "MISC";
740*4882a593Smuzhiyun 	default:
741*4882a593Smuzhiyun 		return "UNKNOWN";
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun 
cx23885_mbox_func(void * priv,u32 command,int in,int out,u32 data[CX2341X_MBOX_MAX_DATA])745*4882a593Smuzhiyun static int cx23885_mbox_func(void *priv,
746*4882a593Smuzhiyun 			     u32 command,
747*4882a593Smuzhiyun 			     int in,
748*4882a593Smuzhiyun 			     int out,
749*4882a593Smuzhiyun 			     u32 data[CX2341X_MBOX_MAX_DATA])
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun 	struct cx23885_dev *dev = priv;
752*4882a593Smuzhiyun 	unsigned long timeout;
753*4882a593Smuzhiyun 	u32 value, flag, retval = 0;
754*4882a593Smuzhiyun 	int i;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
757*4882a593Smuzhiyun 		cmd_to_str(command));
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	/* this may not be 100% safe if we can't read any memory location
760*4882a593Smuzhiyun 	   without side effects */
761*4882a593Smuzhiyun 	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
762*4882a593Smuzhiyun 	if (value != 0x12345678) {
763*4882a593Smuzhiyun 		pr_err("Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
764*4882a593Smuzhiyun 			value, cmd_to_str(command));
765*4882a593Smuzhiyun 		return -1;
766*4882a593Smuzhiyun 	}
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	/* This read looks at 32 bits, but flag is only 8 bits.
769*4882a593Smuzhiyun 	 * Seems we also bail if CMD or TIMEOUT bytes are set???
770*4882a593Smuzhiyun 	 */
771*4882a593Smuzhiyun 	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
772*4882a593Smuzhiyun 	if (flag) {
773*4882a593Smuzhiyun 		pr_err("ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
774*4882a593Smuzhiyun 		       flag, cmd_to_str(command));
775*4882a593Smuzhiyun 		return -1;
776*4882a593Smuzhiyun 	}
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	flag |= 1; /* tell 'em we're working on it */
779*4882a593Smuzhiyun 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/* write command + args + fill remaining with zeros */
782*4882a593Smuzhiyun 	/* command code */
783*4882a593Smuzhiyun 	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
784*4882a593Smuzhiyun 	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
785*4882a593Smuzhiyun 		IVTV_API_STD_TIMEOUT); /* timeout */
786*4882a593Smuzhiyun 	for (i = 0; i < in; i++) {
787*4882a593Smuzhiyun 		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
788*4882a593Smuzhiyun 		dprintk(3, "API Input %d = %d\n", i, data[i]);
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 	for (; i < CX2341X_MBOX_MAX_DATA; i++)
791*4882a593Smuzhiyun 		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	flag |= 3; /* tell 'em we're done writing */
794*4882a593Smuzhiyun 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	/* wait for firmware to handle the API command */
797*4882a593Smuzhiyun 	timeout = jiffies + msecs_to_jiffies(10);
798*4882a593Smuzhiyun 	for (;;) {
799*4882a593Smuzhiyun 		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
800*4882a593Smuzhiyun 		if (0 != (flag & 4))
801*4882a593Smuzhiyun 			break;
802*4882a593Smuzhiyun 		if (time_after(jiffies, timeout)) {
803*4882a593Smuzhiyun 			pr_err("ERROR: API Mailbox timeout\n");
804*4882a593Smuzhiyun 			return -1;
805*4882a593Smuzhiyun 		}
806*4882a593Smuzhiyun 		udelay(10);
807*4882a593Smuzhiyun 	}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	/* read output values */
810*4882a593Smuzhiyun 	for (i = 0; i < out; i++) {
811*4882a593Smuzhiyun 		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
812*4882a593Smuzhiyun 		dprintk(3, "API Output %d = %d\n", i, data[i]);
813*4882a593Smuzhiyun 	}
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
816*4882a593Smuzhiyun 	dprintk(3, "API result = %d\n", retval);
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	flag = 0;
819*4882a593Smuzhiyun 	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	return retval;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun /* We don't need to call the API often, so using just one
825*4882a593Smuzhiyun  * mailbox will probably suffice
826*4882a593Smuzhiyun  */
cx23885_api_cmd(struct cx23885_dev * dev,u32 command,u32 inputcnt,u32 outputcnt,...)827*4882a593Smuzhiyun static int cx23885_api_cmd(struct cx23885_dev *dev,
828*4882a593Smuzhiyun 			   u32 command,
829*4882a593Smuzhiyun 			   u32 inputcnt,
830*4882a593Smuzhiyun 			   u32 outputcnt,
831*4882a593Smuzhiyun 			   ...)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun 	u32 data[CX2341X_MBOX_MAX_DATA];
834*4882a593Smuzhiyun 	va_list vargs;
835*4882a593Smuzhiyun 	int i, err;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	va_start(vargs, outputcnt);
840*4882a593Smuzhiyun 	for (i = 0; i < inputcnt; i++)
841*4882a593Smuzhiyun 		data[i] = va_arg(vargs, int);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
844*4882a593Smuzhiyun 	for (i = 0; i < outputcnt; i++) {
845*4882a593Smuzhiyun 		int *vptr = va_arg(vargs, int *);
846*4882a593Smuzhiyun 		*vptr = data[i];
847*4882a593Smuzhiyun 	}
848*4882a593Smuzhiyun 	va_end(vargs);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	return err;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
cx23885_api_func(void * priv,u32 cmd,int in,int out,u32 data[CX2341X_MBOX_MAX_DATA])853*4882a593Smuzhiyun static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	return cx23885_mbox_func(priv, cmd, in, out, data);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
cx23885_find_mailbox(struct cx23885_dev * dev)858*4882a593Smuzhiyun static int cx23885_find_mailbox(struct cx23885_dev *dev)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun 	u32 signature[4] = {
861*4882a593Smuzhiyun 		0x12345678, 0x34567812, 0x56781234, 0x78123456
862*4882a593Smuzhiyun 	};
863*4882a593Smuzhiyun 	int signaturecnt = 0;
864*4882a593Smuzhiyun 	u32 value;
865*4882a593Smuzhiyun 	int i;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	dprintk(2, "%s()\n", __func__);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
870*4882a593Smuzhiyun 		mc417_memory_read(dev, i, &value);
871*4882a593Smuzhiyun 		if (value == signature[signaturecnt])
872*4882a593Smuzhiyun 			signaturecnt++;
873*4882a593Smuzhiyun 		else
874*4882a593Smuzhiyun 			signaturecnt = 0;
875*4882a593Smuzhiyun 		if (4 == signaturecnt) {
876*4882a593Smuzhiyun 			dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
877*4882a593Smuzhiyun 			return i+1;
878*4882a593Smuzhiyun 		}
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 	pr_err("Mailbox signature values not found!\n");
881*4882a593Smuzhiyun 	return -1;
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun 
cx23885_load_firmware(struct cx23885_dev * dev)884*4882a593Smuzhiyun static int cx23885_load_firmware(struct cx23885_dev *dev)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun 	static const unsigned char magic[8] = {
887*4882a593Smuzhiyun 		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
888*4882a593Smuzhiyun 	};
889*4882a593Smuzhiyun 	const struct firmware *firmware;
890*4882a593Smuzhiyun 	int i, retval = 0;
891*4882a593Smuzhiyun 	u32 value = 0;
892*4882a593Smuzhiyun 	u32 gpio_output = 0;
893*4882a593Smuzhiyun 	u32 gpio_value;
894*4882a593Smuzhiyun 	u32 checksum = 0;
895*4882a593Smuzhiyun 	u32 *dataptr;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	dprintk(2, "%s()\n", __func__);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	/* Save GPIO settings before reset of APU */
900*4882a593Smuzhiyun 	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
901*4882a593Smuzhiyun 	retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	retval  = mc417_register_write(dev,
904*4882a593Smuzhiyun 		IVTV_REG_VPU, 0xFFFFFFED);
905*4882a593Smuzhiyun 	retval |= mc417_register_write(dev,
906*4882a593Smuzhiyun 		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
907*4882a593Smuzhiyun 	retval |= mc417_register_write(dev,
908*4882a593Smuzhiyun 		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
909*4882a593Smuzhiyun 	retval |= mc417_register_write(dev,
910*4882a593Smuzhiyun 		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
911*4882a593Smuzhiyun 	retval |= mc417_register_write(dev,
912*4882a593Smuzhiyun 		IVTV_REG_APU, 0);
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	if (retval != 0) {
915*4882a593Smuzhiyun 		pr_err("%s: Error with mc417_register_write\n",
916*4882a593Smuzhiyun 			__func__);
917*4882a593Smuzhiyun 		return -1;
918*4882a593Smuzhiyun 	}
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
921*4882a593Smuzhiyun 				  &dev->pci->dev);
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	if (retval != 0) {
924*4882a593Smuzhiyun 		pr_err("ERROR: Hotplug firmware request failed (%s).\n",
925*4882a593Smuzhiyun 		       CX23885_FIRM_IMAGE_NAME);
926*4882a593Smuzhiyun 		pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
927*4882a593Smuzhiyun 		return -1;
928*4882a593Smuzhiyun 	}
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
931*4882a593Smuzhiyun 		pr_err("ERROR: Firmware size mismatch (have %zu, expected %d)\n",
932*4882a593Smuzhiyun 		       firmware->size, CX23885_FIRM_IMAGE_SIZE);
933*4882a593Smuzhiyun 		release_firmware(firmware);
934*4882a593Smuzhiyun 		return -1;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	if (0 != memcmp(firmware->data, magic, 8)) {
938*4882a593Smuzhiyun 		pr_err("ERROR: Firmware magic mismatch, wrong file?\n");
939*4882a593Smuzhiyun 		release_firmware(firmware);
940*4882a593Smuzhiyun 		return -1;
941*4882a593Smuzhiyun 	}
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	/* transfer to the chip */
944*4882a593Smuzhiyun 	dprintk(2, "Loading firmware ...\n");
945*4882a593Smuzhiyun 	dataptr = (u32 *)firmware->data;
946*4882a593Smuzhiyun 	for (i = 0; i < (firmware->size >> 2); i++) {
947*4882a593Smuzhiyun 		value = *dataptr;
948*4882a593Smuzhiyun 		checksum += ~value;
949*4882a593Smuzhiyun 		if (mc417_memory_write(dev, i, value) != 0) {
950*4882a593Smuzhiyun 			pr_err("ERROR: Loading firmware failed!\n");
951*4882a593Smuzhiyun 			release_firmware(firmware);
952*4882a593Smuzhiyun 			return -1;
953*4882a593Smuzhiyun 		}
954*4882a593Smuzhiyun 		dataptr++;
955*4882a593Smuzhiyun 	}
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	/* read back to verify with the checksum */
958*4882a593Smuzhiyun 	dprintk(1, "Verifying firmware ...\n");
959*4882a593Smuzhiyun 	for (i--; i >= 0; i--) {
960*4882a593Smuzhiyun 		if (mc417_memory_read(dev, i, &value) != 0) {
961*4882a593Smuzhiyun 			pr_err("ERROR: Reading firmware failed!\n");
962*4882a593Smuzhiyun 			release_firmware(firmware);
963*4882a593Smuzhiyun 			return -1;
964*4882a593Smuzhiyun 		}
965*4882a593Smuzhiyun 		checksum -= ~value;
966*4882a593Smuzhiyun 	}
967*4882a593Smuzhiyun 	if (checksum) {
968*4882a593Smuzhiyun 		pr_err("ERROR: Firmware load failed (checksum mismatch).\n");
969*4882a593Smuzhiyun 		release_firmware(firmware);
970*4882a593Smuzhiyun 		return -1;
971*4882a593Smuzhiyun 	}
972*4882a593Smuzhiyun 	release_firmware(firmware);
973*4882a593Smuzhiyun 	dprintk(1, "Firmware upload successful.\n");
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
976*4882a593Smuzhiyun 		IVTV_CMD_HW_BLOCKS_RST);
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	/* F/W power up disturbs the GPIOs, restore state */
979*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, 0x9020, gpio_output);
980*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, 0x900C, gpio_value);
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
983*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	/* Hardcoded GPIO's here */
986*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, 0x9020, 0x4000);
987*4882a593Smuzhiyun 	retval |= mc417_register_write(dev, 0x900C, 0x4000);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	mc417_register_read(dev, 0x9020, &gpio_output);
990*4882a593Smuzhiyun 	mc417_register_read(dev, 0x900C, &gpio_value);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	if (retval < 0)
993*4882a593Smuzhiyun 		pr_err("%s: Error with mc417_register_write\n",
994*4882a593Smuzhiyun 			__func__);
995*4882a593Smuzhiyun 	return 0;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun 
cx23885_417_check_encoder(struct cx23885_dev * dev)998*4882a593Smuzhiyun void cx23885_417_check_encoder(struct cx23885_dev *dev)
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun 	u32 status, seq;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	status = seq = 0;
1003*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
1004*4882a593Smuzhiyun 	dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun 
cx23885_codec_settings(struct cx23885_dev * dev)1007*4882a593Smuzhiyun static void cx23885_codec_settings(struct cx23885_dev *dev)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	/* Dynamically change the height based on video standard */
1012*4882a593Smuzhiyun 	if (dev->encodernorm.id & V4L2_STD_525_60)
1013*4882a593Smuzhiyun 		dev->ts1.height = 480;
1014*4882a593Smuzhiyun 	else
1015*4882a593Smuzhiyun 		dev->ts1.height = 576;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	/* assign frame size */
1018*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
1019*4882a593Smuzhiyun 				dev->ts1.height, dev->ts1.width);
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	dev->cxhdl.width = dev->ts1.width;
1022*4882a593Smuzhiyun 	dev->cxhdl.height = dev->ts1.height;
1023*4882a593Smuzhiyun 	dev->cxhdl.is_50hz =
1024*4882a593Smuzhiyun 		(dev->encodernorm.id & V4L2_STD_625_50) != 0;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	cx2341x_handler_setup(&dev->cxhdl);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
1029*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun 
cx23885_initialize_codec(struct cx23885_dev * dev,int startencoder)1032*4882a593Smuzhiyun static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun 	int version;
1035*4882a593Smuzhiyun 	int retval;
1036*4882a593Smuzhiyun 	u32 i, data[7];
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
1041*4882a593Smuzhiyun 	if (retval < 0) {
1042*4882a593Smuzhiyun 		dprintk(2, "%s() PING OK\n", __func__);
1043*4882a593Smuzhiyun 		retval = cx23885_load_firmware(dev);
1044*4882a593Smuzhiyun 		if (retval < 0) {
1045*4882a593Smuzhiyun 			pr_err("%s() f/w load failed\n", __func__);
1046*4882a593Smuzhiyun 			return retval;
1047*4882a593Smuzhiyun 		}
1048*4882a593Smuzhiyun 		retval = cx23885_find_mailbox(dev);
1049*4882a593Smuzhiyun 		if (retval < 0) {
1050*4882a593Smuzhiyun 			pr_err("%s() mailbox < 0, error\n",
1051*4882a593Smuzhiyun 				__func__);
1052*4882a593Smuzhiyun 			return -1;
1053*4882a593Smuzhiyun 		}
1054*4882a593Smuzhiyun 		dev->cx23417_mailbox = retval;
1055*4882a593Smuzhiyun 		retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
1056*4882a593Smuzhiyun 		if (retval < 0) {
1057*4882a593Smuzhiyun 			pr_err("ERROR: cx23417 firmware ping failed!\n");
1058*4882a593Smuzhiyun 			return -1;
1059*4882a593Smuzhiyun 		}
1060*4882a593Smuzhiyun 		retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
1061*4882a593Smuzhiyun 			&version);
1062*4882a593Smuzhiyun 		if (retval < 0) {
1063*4882a593Smuzhiyun 			pr_err("ERROR: cx23417 firmware get encoder :version failed!\n");
1064*4882a593Smuzhiyun 			return -1;
1065*4882a593Smuzhiyun 		}
1066*4882a593Smuzhiyun 		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
1067*4882a593Smuzhiyun 		msleep(200);
1068*4882a593Smuzhiyun 	}
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	cx23885_codec_settings(dev);
1071*4882a593Smuzhiyun 	msleep(60);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
1074*4882a593Smuzhiyun 		CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
1075*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
1076*4882a593Smuzhiyun 		CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1077*4882a593Smuzhiyun 		0, 0);
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	/* Setup to capture VBI */
1080*4882a593Smuzhiyun 	data[0] = 0x0001BD00;
1081*4882a593Smuzhiyun 	data[1] = 1;          /* frames per interrupt */
1082*4882a593Smuzhiyun 	data[2] = 4;          /* total bufs */
1083*4882a593Smuzhiyun 	data[3] = 0x91559155; /* start codes */
1084*4882a593Smuzhiyun 	data[4] = 0x206080C0; /* stop codes */
1085*4882a593Smuzhiyun 	data[5] = 6;          /* lines */
1086*4882a593Smuzhiyun 	data[6] = 64;         /* BPL */
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
1089*4882a593Smuzhiyun 		data[2], data[3], data[4], data[5], data[6]);
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	for (i = 2; i <= 24; i++) {
1092*4882a593Smuzhiyun 		int valid;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 		valid = ((i >= 19) && (i <= 21));
1095*4882a593Smuzhiyun 		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
1096*4882a593Smuzhiyun 				valid, 0 , 0, 0);
1097*4882a593Smuzhiyun 		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
1098*4882a593Smuzhiyun 				i | 0x80000000, valid, 0, 0, 0);
1099*4882a593Smuzhiyun 	}
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
1102*4882a593Smuzhiyun 	msleep(60);
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	/* initialize the video input */
1105*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
1106*4882a593Smuzhiyun 	msleep(60);
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	/* Enable VIP style pixel invalidation so we work with scaled mode */
1109*4882a593Smuzhiyun 	mc417_memory_write(dev, 2120, 0x00000080);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	/* start capturing to the host interface */
1112*4882a593Smuzhiyun 	if (startencoder) {
1113*4882a593Smuzhiyun 		cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
1114*4882a593Smuzhiyun 			CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
1115*4882a593Smuzhiyun 		msleep(10);
1116*4882a593Smuzhiyun 	}
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	return 0;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
1122*4882a593Smuzhiyun 
queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])1123*4882a593Smuzhiyun static int queue_setup(struct vb2_queue *q,
1124*4882a593Smuzhiyun 			   unsigned int *num_buffers, unsigned int *num_planes,
1125*4882a593Smuzhiyun 			   unsigned int sizes[], struct device *alloc_devs[])
1126*4882a593Smuzhiyun {
1127*4882a593Smuzhiyun 	struct cx23885_dev *dev = q->drv_priv;
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	dev->ts1.ts_packet_size  = mpeglinesize;
1130*4882a593Smuzhiyun 	dev->ts1.ts_packet_count = mpeglines;
1131*4882a593Smuzhiyun 	*num_planes = 1;
1132*4882a593Smuzhiyun 	sizes[0] = mpeglinesize * mpeglines;
1133*4882a593Smuzhiyun 	*num_buffers = mpegbufs;
1134*4882a593Smuzhiyun 	return 0;
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun 
buffer_prepare(struct vb2_buffer * vb)1137*4882a593Smuzhiyun static int buffer_prepare(struct vb2_buffer *vb)
1138*4882a593Smuzhiyun {
1139*4882a593Smuzhiyun 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1140*4882a593Smuzhiyun 	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1141*4882a593Smuzhiyun 	struct cx23885_buffer *buf =
1142*4882a593Smuzhiyun 		container_of(vbuf, struct cx23885_buffer, vb);
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	return cx23885_buf_prepare(buf, &dev->ts1);
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun 
buffer_finish(struct vb2_buffer * vb)1147*4882a593Smuzhiyun static void buffer_finish(struct vb2_buffer *vb)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1150*4882a593Smuzhiyun 	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1151*4882a593Smuzhiyun 	struct cx23885_buffer *buf = container_of(vbuf,
1152*4882a593Smuzhiyun 		struct cx23885_buffer, vb);
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	cx23885_free_buffer(dev, buf);
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun 
buffer_queue(struct vb2_buffer * vb)1157*4882a593Smuzhiyun static void buffer_queue(struct vb2_buffer *vb)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1160*4882a593Smuzhiyun 	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1161*4882a593Smuzhiyun 	struct cx23885_buffer   *buf = container_of(vbuf,
1162*4882a593Smuzhiyun 		struct cx23885_buffer, vb);
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	cx23885_buf_queue(&dev->ts1, buf);
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun 
cx23885_start_streaming(struct vb2_queue * q,unsigned int count)1167*4882a593Smuzhiyun static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun 	struct cx23885_dev *dev = q->drv_priv;
1170*4882a593Smuzhiyun 	struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
1171*4882a593Smuzhiyun 	unsigned long flags;
1172*4882a593Smuzhiyun 	int ret;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	ret = cx23885_initialize_codec(dev, 1);
1175*4882a593Smuzhiyun 	if (ret == 0) {
1176*4882a593Smuzhiyun 		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
1177*4882a593Smuzhiyun 			struct cx23885_buffer, queue);
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 		cx23885_start_dma(&dev->ts1, dmaq, buf);
1180*4882a593Smuzhiyun 		return 0;
1181*4882a593Smuzhiyun 	}
1182*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->slock, flags);
1183*4882a593Smuzhiyun 	while (!list_empty(&dmaq->active)) {
1184*4882a593Smuzhiyun 		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
1185*4882a593Smuzhiyun 			struct cx23885_buffer, queue);
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 		list_del(&buf->queue);
1188*4882a593Smuzhiyun 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
1189*4882a593Smuzhiyun 	}
1190*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->slock, flags);
1191*4882a593Smuzhiyun 	return ret;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun 
cx23885_stop_streaming(struct vb2_queue * q)1194*4882a593Smuzhiyun static void cx23885_stop_streaming(struct vb2_queue *q)
1195*4882a593Smuzhiyun {
1196*4882a593Smuzhiyun 	struct cx23885_dev *dev = q->drv_priv;
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	/* stop mpeg capture */
1199*4882a593Smuzhiyun 	cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
1200*4882a593Smuzhiyun 			CX23885_END_NOW, CX23885_MPEG_CAPTURE,
1201*4882a593Smuzhiyun 			CX23885_RAW_BITS_NONE);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	msleep(500);
1204*4882a593Smuzhiyun 	cx23885_417_check_encoder(dev);
1205*4882a593Smuzhiyun 	cx23885_cancel_buffers(&dev->ts1);
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun static const struct vb2_ops cx23885_qops = {
1209*4882a593Smuzhiyun 	.queue_setup    = queue_setup,
1210*4882a593Smuzhiyun 	.buf_prepare  = buffer_prepare,
1211*4882a593Smuzhiyun 	.buf_finish = buffer_finish,
1212*4882a593Smuzhiyun 	.buf_queue    = buffer_queue,
1213*4882a593Smuzhiyun 	.wait_prepare = vb2_ops_wait_prepare,
1214*4882a593Smuzhiyun 	.wait_finish = vb2_ops_wait_finish,
1215*4882a593Smuzhiyun 	.start_streaming = cx23885_start_streaming,
1216*4882a593Smuzhiyun 	.stop_streaming = cx23885_stop_streaming,
1217*4882a593Smuzhiyun };
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
1220*4882a593Smuzhiyun 
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * id)1221*4882a593Smuzhiyun static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	*id = dev->tvnorm;
1226*4882a593Smuzhiyun 	return 0;
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun 
vidioc_s_std(struct file * file,void * priv,v4l2_std_id id)1229*4882a593Smuzhiyun static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1232*4882a593Smuzhiyun 	unsigned int i;
1233*4882a593Smuzhiyun 	int ret;
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
1236*4882a593Smuzhiyun 		if (id & cx23885_tvnorms[i].id)
1237*4882a593Smuzhiyun 			break;
1238*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(cx23885_tvnorms))
1239*4882a593Smuzhiyun 		return -EINVAL;
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	ret = cx23885_set_tvnorm(dev, id);
1242*4882a593Smuzhiyun 	if (!ret)
1243*4882a593Smuzhiyun 		dev->encodernorm = cx23885_tvnorms[i];
1244*4882a593Smuzhiyun 	return ret;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
vidioc_enum_input(struct file * file,void * priv,struct v4l2_input * i)1247*4882a593Smuzhiyun static int vidioc_enum_input(struct file *file, void *priv,
1248*4882a593Smuzhiyun 	struct v4l2_input *i)
1249*4882a593Smuzhiyun {
1250*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1251*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1252*4882a593Smuzhiyun 	return cx23885_enum_input(dev, i);
1253*4882a593Smuzhiyun }
1254*4882a593Smuzhiyun 
vidioc_g_input(struct file * file,void * priv,unsigned int * i)1255*4882a593Smuzhiyun static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1256*4882a593Smuzhiyun {
1257*4882a593Smuzhiyun 	return cx23885_get_input(file, priv, i);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun 
vidioc_s_input(struct file * file,void * priv,unsigned int i)1260*4882a593Smuzhiyun static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	return cx23885_set_input(file, priv, i);
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
vidioc_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)1265*4882a593Smuzhiyun static int vidioc_g_tuner(struct file *file, void *priv,
1266*4882a593Smuzhiyun 				struct v4l2_tuner *t)
1267*4882a593Smuzhiyun {
1268*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	if (dev->tuner_type == TUNER_ABSENT)
1271*4882a593Smuzhiyun 		return -EINVAL;
1272*4882a593Smuzhiyun 	if (0 != t->index)
1273*4882a593Smuzhiyun 		return -EINVAL;
1274*4882a593Smuzhiyun 	strscpy(t->name, "Television", sizeof(t->name));
1275*4882a593Smuzhiyun 	call_all(dev, tuner, g_tuner, t);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	return 0;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun 
vidioc_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)1282*4882a593Smuzhiyun static int vidioc_s_tuner(struct file *file, void *priv,
1283*4882a593Smuzhiyun 				const struct v4l2_tuner *t)
1284*4882a593Smuzhiyun {
1285*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	if (dev->tuner_type == TUNER_ABSENT)
1288*4882a593Smuzhiyun 		return -EINVAL;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	/* Update the A/V core */
1291*4882a593Smuzhiyun 	call_all(dev, tuner, s_tuner, t);
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	return 0;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun 
vidioc_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)1296*4882a593Smuzhiyun static int vidioc_g_frequency(struct file *file, void *priv,
1297*4882a593Smuzhiyun 				struct v4l2_frequency *f)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	if (dev->tuner_type == TUNER_ABSENT)
1302*4882a593Smuzhiyun 		return -EINVAL;
1303*4882a593Smuzhiyun 	f->type = V4L2_TUNER_ANALOG_TV;
1304*4882a593Smuzhiyun 	f->frequency = dev->freq;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	call_all(dev, tuner, g_frequency, f);
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	return 0;
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun 
vidioc_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)1311*4882a593Smuzhiyun static int vidioc_s_frequency(struct file *file, void *priv,
1312*4882a593Smuzhiyun 	const struct v4l2_frequency *f)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun 	return cx23885_set_frequency(file, priv, f);
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1317*4882a593Smuzhiyun static int vidioc_querycap(struct file *file, void  *priv,
1318*4882a593Smuzhiyun 				struct v4l2_capability *cap)
1319*4882a593Smuzhiyun {
1320*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1321*4882a593Smuzhiyun 	struct cx23885_tsport  *tsport = &dev->ts1;
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	strscpy(cap->driver, dev->name, sizeof(cap->driver));
1324*4882a593Smuzhiyun 	strscpy(cap->card, cx23885_boards[tsport->dev->board].name,
1325*4882a593Smuzhiyun 		sizeof(cap->card));
1326*4882a593Smuzhiyun 	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
1327*4882a593Smuzhiyun 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
1328*4882a593Smuzhiyun 			    V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE |
1329*4882a593Smuzhiyun 			    V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS;
1330*4882a593Smuzhiyun 	if (dev->tuner_type != TUNER_ABSENT)
1331*4882a593Smuzhiyun 		cap->capabilities |= V4L2_CAP_TUNER;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	return 0;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun 
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)1336*4882a593Smuzhiyun static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
1337*4882a593Smuzhiyun 					struct v4l2_fmtdesc *f)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun 	if (f->index != 0)
1340*4882a593Smuzhiyun 		return -EINVAL;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	f->pixelformat = V4L2_PIX_FMT_MPEG;
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	return 0;
1345*4882a593Smuzhiyun }
1346*4882a593Smuzhiyun 
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1347*4882a593Smuzhiyun static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
1348*4882a593Smuzhiyun 				struct v4l2_format *f)
1349*4882a593Smuzhiyun {
1350*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
1353*4882a593Smuzhiyun 	f->fmt.pix.bytesperline = 0;
1354*4882a593Smuzhiyun 	f->fmt.pix.sizeimage    =
1355*4882a593Smuzhiyun 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1356*4882a593Smuzhiyun 	f->fmt.pix.colorspace   = 0;
1357*4882a593Smuzhiyun 	f->fmt.pix.width        = dev->ts1.width;
1358*4882a593Smuzhiyun 	f->fmt.pix.height       = dev->ts1.height;
1359*4882a593Smuzhiyun 	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
1360*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
1361*4882a593Smuzhiyun 		dev->ts1.width, dev->ts1.height);
1362*4882a593Smuzhiyun 	return 0;
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun 
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1365*4882a593Smuzhiyun static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1366*4882a593Smuzhiyun 				struct v4l2_format *f)
1367*4882a593Smuzhiyun {
1368*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
1371*4882a593Smuzhiyun 	f->fmt.pix.bytesperline = 0;
1372*4882a593Smuzhiyun 	f->fmt.pix.sizeimage    =
1373*4882a593Smuzhiyun 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1374*4882a593Smuzhiyun 	f->fmt.pix.colorspace   = 0;
1375*4882a593Smuzhiyun 	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
1376*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
1377*4882a593Smuzhiyun 		dev->ts1.width, dev->ts1.height);
1378*4882a593Smuzhiyun 	return 0;
1379*4882a593Smuzhiyun }
1380*4882a593Smuzhiyun 
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1381*4882a593Smuzhiyun static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1382*4882a593Smuzhiyun 				struct v4l2_format *f)
1383*4882a593Smuzhiyun {
1384*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
1387*4882a593Smuzhiyun 	f->fmt.pix.bytesperline = 0;
1388*4882a593Smuzhiyun 	f->fmt.pix.sizeimage    =
1389*4882a593Smuzhiyun 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1390*4882a593Smuzhiyun 	f->fmt.pix.colorspace   = 0;
1391*4882a593Smuzhiyun 	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
1392*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
1393*4882a593Smuzhiyun 		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
1394*4882a593Smuzhiyun 	return 0;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun 
vidioc_log_status(struct file * file,void * priv)1397*4882a593Smuzhiyun static int vidioc_log_status(struct file *file, void *priv)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun 	struct cx23885_dev *dev = video_drvdata(file);
1400*4882a593Smuzhiyun 	char name[32 + 2];
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	snprintf(name, sizeof(name), "%s/2", dev->name);
1403*4882a593Smuzhiyun 	call_all(dev, core, log_status);
1404*4882a593Smuzhiyun 	v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
1405*4882a593Smuzhiyun 	return 0;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun static const struct v4l2_file_operations mpeg_fops = {
1409*4882a593Smuzhiyun 	.owner	       = THIS_MODULE,
1410*4882a593Smuzhiyun 	.open           = v4l2_fh_open,
1411*4882a593Smuzhiyun 	.release        = vb2_fop_release,
1412*4882a593Smuzhiyun 	.read           = vb2_fop_read,
1413*4882a593Smuzhiyun 	.poll		= vb2_fop_poll,
1414*4882a593Smuzhiyun 	.unlocked_ioctl = video_ioctl2,
1415*4882a593Smuzhiyun 	.mmap           = vb2_fop_mmap,
1416*4882a593Smuzhiyun };
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
1419*4882a593Smuzhiyun 	.vidioc_g_std		 = vidioc_g_std,
1420*4882a593Smuzhiyun 	.vidioc_s_std		 = vidioc_s_std,
1421*4882a593Smuzhiyun 	.vidioc_enum_input	 = vidioc_enum_input,
1422*4882a593Smuzhiyun 	.vidioc_g_input		 = vidioc_g_input,
1423*4882a593Smuzhiyun 	.vidioc_s_input		 = vidioc_s_input,
1424*4882a593Smuzhiyun 	.vidioc_g_tuner		 = vidioc_g_tuner,
1425*4882a593Smuzhiyun 	.vidioc_s_tuner		 = vidioc_s_tuner,
1426*4882a593Smuzhiyun 	.vidioc_g_frequency	 = vidioc_g_frequency,
1427*4882a593Smuzhiyun 	.vidioc_s_frequency	 = vidioc_s_frequency,
1428*4882a593Smuzhiyun 	.vidioc_querycap	 = vidioc_querycap,
1429*4882a593Smuzhiyun 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1430*4882a593Smuzhiyun 	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
1431*4882a593Smuzhiyun 	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
1432*4882a593Smuzhiyun 	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
1433*4882a593Smuzhiyun 	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
1434*4882a593Smuzhiyun 	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
1435*4882a593Smuzhiyun 	.vidioc_querybuf      = vb2_ioctl_querybuf,
1436*4882a593Smuzhiyun 	.vidioc_qbuf          = vb2_ioctl_qbuf,
1437*4882a593Smuzhiyun 	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
1438*4882a593Smuzhiyun 	.vidioc_streamon      = vb2_ioctl_streamon,
1439*4882a593Smuzhiyun 	.vidioc_streamoff     = vb2_ioctl_streamoff,
1440*4882a593Smuzhiyun 	.vidioc_log_status	 = vidioc_log_status,
1441*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
1442*4882a593Smuzhiyun 	.vidioc_g_chip_info	 = cx23885_g_chip_info,
1443*4882a593Smuzhiyun 	.vidioc_g_register	 = cx23885_g_register,
1444*4882a593Smuzhiyun 	.vidioc_s_register	 = cx23885_s_register,
1445*4882a593Smuzhiyun #endif
1446*4882a593Smuzhiyun };
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun static struct video_device cx23885_mpeg_template = {
1449*4882a593Smuzhiyun 	.name          = "cx23885",
1450*4882a593Smuzhiyun 	.fops          = &mpeg_fops,
1451*4882a593Smuzhiyun 	.ioctl_ops     = &mpeg_ioctl_ops,
1452*4882a593Smuzhiyun 	.tvnorms       = CX23885_NORMS,
1453*4882a593Smuzhiyun };
1454*4882a593Smuzhiyun 
cx23885_417_unregister(struct cx23885_dev * dev)1455*4882a593Smuzhiyun void cx23885_417_unregister(struct cx23885_dev *dev)
1456*4882a593Smuzhiyun {
1457*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	if (dev->v4l_device) {
1460*4882a593Smuzhiyun 		if (video_is_registered(dev->v4l_device))
1461*4882a593Smuzhiyun 			video_unregister_device(dev->v4l_device);
1462*4882a593Smuzhiyun 		else
1463*4882a593Smuzhiyun 			video_device_release(dev->v4l_device);
1464*4882a593Smuzhiyun 		v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
1465*4882a593Smuzhiyun 		dev->v4l_device = NULL;
1466*4882a593Smuzhiyun 	}
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun 
cx23885_video_dev_alloc(struct cx23885_tsport * tsport,struct pci_dev * pci,struct video_device * template,char * type)1469*4882a593Smuzhiyun static struct video_device *cx23885_video_dev_alloc(
1470*4882a593Smuzhiyun 	struct cx23885_tsport *tsport,
1471*4882a593Smuzhiyun 	struct pci_dev *pci,
1472*4882a593Smuzhiyun 	struct video_device *template,
1473*4882a593Smuzhiyun 	char *type)
1474*4882a593Smuzhiyun {
1475*4882a593Smuzhiyun 	struct video_device *vfd;
1476*4882a593Smuzhiyun 	struct cx23885_dev *dev = tsport->dev;
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	vfd = video_device_alloc();
1481*4882a593Smuzhiyun 	if (NULL == vfd)
1482*4882a593Smuzhiyun 		return NULL;
1483*4882a593Smuzhiyun 	*vfd = *template;
1484*4882a593Smuzhiyun 	snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
1485*4882a593Smuzhiyun 		cx23885_boards[tsport->dev->board].name, type);
1486*4882a593Smuzhiyun 	vfd->v4l2_dev = &dev->v4l2_dev;
1487*4882a593Smuzhiyun 	vfd->release = video_device_release;
1488*4882a593Smuzhiyun 	return vfd;
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun 
cx23885_417_register(struct cx23885_dev * dev)1491*4882a593Smuzhiyun int cx23885_417_register(struct cx23885_dev *dev)
1492*4882a593Smuzhiyun {
1493*4882a593Smuzhiyun 	/* FIXME: Port1 hardcoded here */
1494*4882a593Smuzhiyun 	int err = -ENODEV;
1495*4882a593Smuzhiyun 	struct cx23885_tsport *tsport = &dev->ts1;
1496*4882a593Smuzhiyun 	struct vb2_queue *q;
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	dprintk(1, "%s()\n", __func__);
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
1501*4882a593Smuzhiyun 		return err;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	/* Set default TV standard */
1504*4882a593Smuzhiyun 	dev->encodernorm = cx23885_tvnorms[0];
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	if (dev->encodernorm.id & V4L2_STD_525_60)
1507*4882a593Smuzhiyun 		tsport->height = 480;
1508*4882a593Smuzhiyun 	else
1509*4882a593Smuzhiyun 		tsport->height = 576;
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	tsport->width = 720;
1512*4882a593Smuzhiyun 	dev->cxhdl.port = CX2341X_PORT_SERIAL;
1513*4882a593Smuzhiyun 	err = cx2341x_handler_init(&dev->cxhdl, 50);
1514*4882a593Smuzhiyun 	if (err)
1515*4882a593Smuzhiyun 		return err;
1516*4882a593Smuzhiyun 	dev->cxhdl.priv = dev;
1517*4882a593Smuzhiyun 	dev->cxhdl.func = cx23885_api_func;
1518*4882a593Smuzhiyun 	cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
1519*4882a593Smuzhiyun 	v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL, false);
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	/* Allocate and initialize V4L video device */
1522*4882a593Smuzhiyun 	dev->v4l_device = cx23885_video_dev_alloc(tsport,
1523*4882a593Smuzhiyun 		dev->pci, &cx23885_mpeg_template, "mpeg");
1524*4882a593Smuzhiyun 	q = &dev->vb2_mpegq;
1525*4882a593Smuzhiyun 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1526*4882a593Smuzhiyun 	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
1527*4882a593Smuzhiyun 	q->gfp_flags = GFP_DMA32;
1528*4882a593Smuzhiyun 	q->min_buffers_needed = 2;
1529*4882a593Smuzhiyun 	q->drv_priv = dev;
1530*4882a593Smuzhiyun 	q->buf_struct_size = sizeof(struct cx23885_buffer);
1531*4882a593Smuzhiyun 	q->ops = &cx23885_qops;
1532*4882a593Smuzhiyun 	q->mem_ops = &vb2_dma_sg_memops;
1533*4882a593Smuzhiyun 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1534*4882a593Smuzhiyun 	q->lock = &dev->lock;
1535*4882a593Smuzhiyun 	q->dev = &dev->pci->dev;
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	err = vb2_queue_init(q);
1538*4882a593Smuzhiyun 	if (err < 0)
1539*4882a593Smuzhiyun 		return err;
1540*4882a593Smuzhiyun 	video_set_drvdata(dev->v4l_device, dev);
1541*4882a593Smuzhiyun 	dev->v4l_device->lock = &dev->lock;
1542*4882a593Smuzhiyun 	dev->v4l_device->queue = q;
1543*4882a593Smuzhiyun 	dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE |
1544*4882a593Smuzhiyun 				       V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1545*4882a593Smuzhiyun 	if (dev->tuner_type != TUNER_ABSENT)
1546*4882a593Smuzhiyun 		dev->v4l_device->device_caps |= V4L2_CAP_TUNER;
1547*4882a593Smuzhiyun 	err = video_register_device(dev->v4l_device,
1548*4882a593Smuzhiyun 		VFL_TYPE_VIDEO, -1);
1549*4882a593Smuzhiyun 	if (err < 0) {
1550*4882a593Smuzhiyun 		pr_info("%s: can't register mpeg device\n", dev->name);
1551*4882a593Smuzhiyun 		return err;
1552*4882a593Smuzhiyun 	}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	pr_info("%s: registered device %s [mpeg]\n",
1555*4882a593Smuzhiyun 	       dev->name, video_device_node_name(dev->v4l_device));
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	/* ST: Configure the encoder parameters, but don't begin
1558*4882a593Smuzhiyun 	 * encoding, this resolves an issue where the first time the
1559*4882a593Smuzhiyun 	 * encoder is started video can be choppy.
1560*4882a593Smuzhiyun 	 */
1561*4882a593Smuzhiyun 	cx23885_initialize_codec(dev, 0);
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun 	return 0;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME);
1567