18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Support for a cx23417 mpeg encoder via cx231xx host port.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *    (c) 2004 Jelle Foks <jelle@foks.us>
78c2ecf20Sopenharmony_ci *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
88c2ecf20Sopenharmony_ci *    (c) 2008 Steven Toth <stoth@linuxtv.org>
98c2ecf20Sopenharmony_ci *      - CX23885/7/8 support
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "cx231xx.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
188c2ecf20Sopenharmony_ci#include <linux/init.h>
198c2ecf20Sopenharmony_ci#include <linux/fs.h>
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include <linux/device.h>
228c2ecf20Sopenharmony_ci#include <linux/firmware.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
258c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
268c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
278c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
288c2ecf20Sopenharmony_ci#include <media/drv-intf/cx2341x.h>
298c2ecf20Sopenharmony_ci#include <media/tuner.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define CX231xx_FIRM_IMAGE_SIZE 376836
328c2ecf20Sopenharmony_ci#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* for polaris ITVC */
358c2ecf20Sopenharmony_ci#define ITVC_WRITE_DIR          0x03FDFC00
368c2ecf20Sopenharmony_ci#define ITVC_READ_DIR            0x0001FC00
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE0          0x00
398c2ecf20Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE1          0x08
408c2ecf20Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE2          0x10
418c2ecf20Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE3          0x18
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE2       0x20
448c2ecf20Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE1       0x28
458c2ecf20Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE0       0x30
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE0        0x40
488c2ecf20Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE1        0x48
498c2ecf20Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE2        0x50
508c2ecf20Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE3        0x58
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define  MCI_REGISTER_ADDRESS_BYTE0     0x60
538c2ecf20Sopenharmony_ci#define  MCI_REGISTER_ADDRESS_BYTE1     0x68
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define  MCI_REGISTER_MODE              0x70
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Read and write modes for polaris ITVC */
588c2ecf20Sopenharmony_ci#define  MCI_MODE_REGISTER_READ         0x000
598c2ecf20Sopenharmony_ci#define  MCI_MODE_REGISTER_WRITE        0x100
608c2ecf20Sopenharmony_ci#define  MCI_MODE_MEMORY_READ           0x000
618c2ecf20Sopenharmony_ci#define  MCI_MODE_MEMORY_WRITE          0x4000
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic unsigned int mpeglines = 128;
648c2ecf20Sopenharmony_cimodule_param(mpeglines, int, 0644);
658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic unsigned int mpeglinesize = 512;
688c2ecf20Sopenharmony_cimodule_param(mpeglinesize, int, 0644);
698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpeglinesize,
708c2ecf20Sopenharmony_ci	"number of bytes in each line of an MPEG buffer, range 512-1024");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic unsigned int v4l_debug = 1;
738c2ecf20Sopenharmony_cimodule_param(v4l_debug, int, 0644);
748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...)	\
778c2ecf20Sopenharmony_ci	do {				\
788c2ecf20Sopenharmony_ci		if (v4l_debug >= level) \
798c2ecf20Sopenharmony_ci			printk(KERN_DEBUG pr_fmt(fmt), ## arg); \
808c2ecf20Sopenharmony_ci	} while (0)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic struct cx231xx_tvnorm cx231xx_tvnorms[] = {
838c2ecf20Sopenharmony_ci	{
848c2ecf20Sopenharmony_ci		.name      = "NTSC-M",
858c2ecf20Sopenharmony_ci		.id        = V4L2_STD_NTSC_M,
868c2ecf20Sopenharmony_ci	}, {
878c2ecf20Sopenharmony_ci		.name      = "NTSC-JP",
888c2ecf20Sopenharmony_ci		.id        = V4L2_STD_NTSC_M_JP,
898c2ecf20Sopenharmony_ci	}, {
908c2ecf20Sopenharmony_ci		.name      = "PAL-BG",
918c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_BG,
928c2ecf20Sopenharmony_ci	}, {
938c2ecf20Sopenharmony_ci		.name      = "PAL-DK",
948c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_DK,
958c2ecf20Sopenharmony_ci	}, {
968c2ecf20Sopenharmony_ci		.name      = "PAL-I",
978c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_I,
988c2ecf20Sopenharmony_ci	}, {
998c2ecf20Sopenharmony_ci		.name      = "PAL-M",
1008c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_M,
1018c2ecf20Sopenharmony_ci	}, {
1028c2ecf20Sopenharmony_ci		.name      = "PAL-N",
1038c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_N,
1048c2ecf20Sopenharmony_ci	}, {
1058c2ecf20Sopenharmony_ci		.name      = "PAL-Nc",
1068c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_Nc,
1078c2ecf20Sopenharmony_ci	}, {
1088c2ecf20Sopenharmony_ci		.name      = "PAL-60",
1098c2ecf20Sopenharmony_ci		.id        = V4L2_STD_PAL_60,
1108c2ecf20Sopenharmony_ci	}, {
1118c2ecf20Sopenharmony_ci		.name      = "SECAM-L",
1128c2ecf20Sopenharmony_ci		.id        = V4L2_STD_SECAM_L,
1138c2ecf20Sopenharmony_ci	}, {
1148c2ecf20Sopenharmony_ci		.name      = "SECAM-DK",
1158c2ecf20Sopenharmony_ci		.id        = V4L2_STD_SECAM_DK,
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cienum cx231xx_capture_type {
1228c2ecf20Sopenharmony_ci	CX231xx_MPEG_CAPTURE,
1238c2ecf20Sopenharmony_ci	CX231xx_RAW_CAPTURE,
1248c2ecf20Sopenharmony_ci	CX231xx_RAW_PASSTHRU_CAPTURE
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cienum cx231xx_capture_bits {
1288c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_NONE             = 0x00,
1298c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_YUV_CAPTURE      = 0x01,
1308c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_PCM_CAPTURE      = 0x02,
1318c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_VBI_CAPTURE      = 0x04,
1328c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
1338c2ecf20Sopenharmony_ci	CX231xx_RAW_BITS_TO_HOST_CAPTURE  = 0x10
1348c2ecf20Sopenharmony_ci};
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cienum cx231xx_capture_end {
1378c2ecf20Sopenharmony_ci	CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
1388c2ecf20Sopenharmony_ci	CX231xx_END_NOW, /* stop immediately, no irq */
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cienum cx231xx_framerate {
1428c2ecf20Sopenharmony_ci	CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
1438c2ecf20Sopenharmony_ci	CX231xx_FRAMERATE_PAL_25   /* PAL: 25fps */
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cienum cx231xx_stream_port {
1478c2ecf20Sopenharmony_ci	CX231xx_OUTPUT_PORT_MEMORY,
1488c2ecf20Sopenharmony_ci	CX231xx_OUTPUT_PORT_STREAMING,
1498c2ecf20Sopenharmony_ci	CX231xx_OUTPUT_PORT_SERIAL
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cienum cx231xx_data_xfer_status {
1538c2ecf20Sopenharmony_ci	CX231xx_MORE_BUFFERS_FOLLOW,
1548c2ecf20Sopenharmony_ci	CX231xx_LAST_BUFFER,
1558c2ecf20Sopenharmony_ci};
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cienum cx231xx_picture_mask {
1588c2ecf20Sopenharmony_ci	CX231xx_PICTURE_MASK_NONE,
1598c2ecf20Sopenharmony_ci	CX231xx_PICTURE_MASK_I_FRAMES,
1608c2ecf20Sopenharmony_ci	CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
1618c2ecf20Sopenharmony_ci	CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cienum cx231xx_vbi_mode_bits {
1658c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_SLICED,
1668c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_RAW,
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cienum cx231xx_vbi_insertion_bits {
1708c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
1718c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
1728c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
1738c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
1748c2ecf20Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cienum cx231xx_dma_unit {
1788c2ecf20Sopenharmony_ci	CX231xx_DMA_BYTES,
1798c2ecf20Sopenharmony_ci	CX231xx_DMA_FRAMES,
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cienum cx231xx_dma_transfer_status_bits {
1838c2ecf20Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
1848c2ecf20Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
1858c2ecf20Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cienum cx231xx_pause {
1898c2ecf20Sopenharmony_ci	CX231xx_PAUSE_ENCODING,
1908c2ecf20Sopenharmony_ci	CX231xx_RESUME_ENCODING,
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cienum cx231xx_copyright {
1948c2ecf20Sopenharmony_ci	CX231xx_COPYRIGHT_OFF,
1958c2ecf20Sopenharmony_ci	CX231xx_COPYRIGHT_ON,
1968c2ecf20Sopenharmony_ci};
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cienum cx231xx_notification_type {
1998c2ecf20Sopenharmony_ci	CX231xx_NOTIFICATION_REFRESH,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cienum cx231xx_notification_status {
2038c2ecf20Sopenharmony_ci	CX231xx_NOTIFICATION_OFF,
2048c2ecf20Sopenharmony_ci	CX231xx_NOTIFICATION_ON,
2058c2ecf20Sopenharmony_ci};
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cienum cx231xx_notification_mailbox {
2088c2ecf20Sopenharmony_ci	CX231xx_NOTIFICATION_NO_MAILBOX = -1,
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cienum cx231xx_field1_lines {
2128c2ecf20Sopenharmony_ci	CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
2138c2ecf20Sopenharmony_ci	CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
2148c2ecf20Sopenharmony_ci	CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
2158c2ecf20Sopenharmony_ci};
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cienum cx231xx_field2_lines {
2188c2ecf20Sopenharmony_ci	CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
2198c2ecf20Sopenharmony_ci	CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
2208c2ecf20Sopenharmony_ci	CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cienum cx231xx_custom_data_type {
2248c2ecf20Sopenharmony_ci	CX231xx_CUSTOM_EXTENSION_USR_DATA,
2258c2ecf20Sopenharmony_ci	CX231xx_CUSTOM_PRIVATE_PACKET,
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cienum cx231xx_mute {
2298c2ecf20Sopenharmony_ci	CX231xx_UNMUTE,
2308c2ecf20Sopenharmony_ci	CX231xx_MUTE,
2318c2ecf20Sopenharmony_ci};
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cienum cx231xx_mute_video_mask {
2348c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
2358c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
2368c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cienum cx231xx_mute_video_shift {
2408c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_V_SHIFT = 8,
2418c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_U_SHIFT = 16,
2428c2ecf20Sopenharmony_ci	CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/* defines below are from ivtv-driver.h */
2468c2ecf20Sopenharmony_ci#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/* Firmware API commands */
2498c2ecf20Sopenharmony_ci#define IVTV_API_STD_TIMEOUT 500
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Registers */
2528c2ecf20Sopenharmony_ci/* IVTV_REG_OFFSET */
2538c2ecf20Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
2548c2ecf20Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
2558c2ecf20Sopenharmony_ci#define IVTV_REG_SPU (0x9050)
2568c2ecf20Sopenharmony_ci#define IVTV_REG_HW_BLOCKS (0x9054)
2578c2ecf20Sopenharmony_ci#define IVTV_REG_VPU (0x9058)
2588c2ecf20Sopenharmony_ci#define IVTV_REG_APU (0xA064)
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/*
2618c2ecf20Sopenharmony_ci * Bit definitions for MC417_RWD and MC417_OEN registers
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * bits 31-16
2648c2ecf20Sopenharmony_ci *+-----------+
2658c2ecf20Sopenharmony_ci *| Reserved  |
2668c2ecf20Sopenharmony_ci *|+-----------+
2678c2ecf20Sopenharmony_ci *|  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
2688c2ecf20Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
2698c2ecf20Sopenharmony_ci *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
2708c2ecf20Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
2718c2ecf20Sopenharmony_ci *| bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
2728c2ecf20Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
2738c2ecf20Sopenharmony_ci *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
2748c2ecf20Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
2758c2ecf20Sopenharmony_ci */
2768c2ecf20Sopenharmony_ci#define MC417_MIWR	0x8000
2778c2ecf20Sopenharmony_ci#define MC417_MIRD	0x4000
2788c2ecf20Sopenharmony_ci#define MC417_MICS	0x2000
2798c2ecf20Sopenharmony_ci#define MC417_MIRDY	0x1000
2808c2ecf20Sopenharmony_ci#define MC417_MIADDR	0x0F00
2818c2ecf20Sopenharmony_ci#define MC417_MIDATA	0x00FF
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/* Bit definitions for MC417_CTL register ****
2858c2ecf20Sopenharmony_ci *bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
2868c2ecf20Sopenharmony_ci *+--------+-------------+--------+--------------+------------+
2878c2ecf20Sopenharmony_ci *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
2888c2ecf20Sopenharmony_ci *+--------+-------------+--------+--------------+------------+
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_ci#define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
2918c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
2928c2ecf20Sopenharmony_ci#define MC417_UART_GPIO_EN	0x00000001
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/* Values for speed control */
2958c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_SLOW	0x1
2968c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_MEDIUM	0x0
2978c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/* Values for GPIO select */
3008c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO3	0x3
3018c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO2	0x2
3028c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO1	0x1
3038c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO0	0x0
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci#define CX23417_GPIO_MASK 0xFC0003FF
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int set_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 value)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	int status = 0;
3118c2ecf20Sopenharmony_ci	u32 _gpio_direction = 0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
3148c2ecf20Sopenharmony_ci	_gpio_direction = _gpio_direction | gpio_direction;
3158c2ecf20Sopenharmony_ci	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
3168c2ecf20Sopenharmony_ci			 (u8 *)&value, 4, 0, 0);
3178c2ecf20Sopenharmony_ci	return status;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int get_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 *val_ptr)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	int status = 0;
3238c2ecf20Sopenharmony_ci	u32 _gpio_direction = 0;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
3268c2ecf20Sopenharmony_ci	_gpio_direction = _gpio_direction | gpio_direction;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
3298c2ecf20Sopenharmony_ci		 (u8 *)val_ptr, 4, 0, 1);
3308c2ecf20Sopenharmony_ci	return status;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int wait_for_mci_complete(struct cx231xx *dev)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	u32 gpio;
3368c2ecf20Sopenharmony_ci	u32 gpio_direction = 0;
3378c2ecf20Sopenharmony_ci	u8 count = 0;
3388c2ecf20Sopenharmony_ci	get_itvc_reg(dev, gpio_direction, &gpio);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	while (!(gpio&0x020000)) {
3418c2ecf20Sopenharmony_ci		msleep(10);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		get_itvc_reg(dev, gpio_direction, &gpio);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		if (count++ > 100) {
3468c2ecf20Sopenharmony_ci			dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
3478c2ecf20Sopenharmony_ci			return -EIO;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	u32 temp;
3568c2ecf20Sopenharmony_ci	int status = 0;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE0 | ((value & 0x000000FF) << 8);
3598c2ecf20Sopenharmony_ci	temp = temp << 10;
3608c2ecf20Sopenharmony_ci	status = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3618c2ecf20Sopenharmony_ci	if (status < 0)
3628c2ecf20Sopenharmony_ci		return status;
3638c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3648c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/*write data byte 1;*/
3678c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE1 | (value & 0x0000FF00);
3688c2ecf20Sopenharmony_ci	temp = temp << 10;
3698c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3708c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3718c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/*write data byte 2;*/
3748c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
3758c2ecf20Sopenharmony_ci	temp = temp << 10;
3768c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3778c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3788c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/*write data byte 3;*/
3818c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
3828c2ecf20Sopenharmony_ci	temp = temp << 10;
3838c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3848c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3858c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/*write address byte 0;*/
3888c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x000000FF) << 8);
3898c2ecf20Sopenharmony_ci	temp = temp << 10;
3908c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3918c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3928c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/*write address byte 1;*/
3958c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0x0000FF00);
3968c2ecf20Sopenharmony_ci	temp = temp << 10;
3978c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
3988c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
3998c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/*Write that the mode is write.*/
4028c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
4038c2ecf20Sopenharmony_ci	temp = temp << 10;
4048c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4058c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
4068c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return wait_for_mci_complete(dev);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	/*write address byte 0;*/
4148c2ecf20Sopenharmony_ci	u32 temp;
4158c2ecf20Sopenharmony_ci	u32 return_value = 0;
4168c2ecf20Sopenharmony_ci	int ret = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
4198c2ecf20Sopenharmony_ci	temp = temp << 10;
4208c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4218c2ecf20Sopenharmony_ci	temp = temp | ((0x05) << 10);
4228c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/*write address byte 1;*/
4258c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
4268c2ecf20Sopenharmony_ci	temp = temp << 10;
4278c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4288c2ecf20Sopenharmony_ci	temp = temp | ((0x05) << 10);
4298c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/*write that the mode is read;*/
4328c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
4338c2ecf20Sopenharmony_ci	temp = temp << 10;
4348c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4358c2ecf20Sopenharmony_ci	temp = temp | ((0x05) << 10);
4368c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/*wait for the MIRDY line to be asserted ,
4398c2ecf20Sopenharmony_ci	signalling that the read is done;*/
4408c2ecf20Sopenharmony_ci	ret = wait_for_mci_complete(dev);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/*switch the DATA- GPIO to input mode;*/
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/*Read data byte 0;*/
4458c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
4468c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4478c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
4488c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4498c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
4508c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 18);
4518c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Read data byte 1;*/
4548c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
4558c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4568c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
4578c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4588c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 10);
4618c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/*Read data byte 2;*/
4648c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
4658c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4668c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
4678c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4688c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
4698c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 2);
4708c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/*Read data byte 3;*/
4738c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
4748c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4758c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
4768c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
4778c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
4788c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) << 6);
4798c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	*value  = return_value;
4828c2ecf20Sopenharmony_ci	return ret;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	/*write data byte 0;*/
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	u32 temp;
4908c2ecf20Sopenharmony_ci	int ret = 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
4938c2ecf20Sopenharmony_ci	temp = temp << 10;
4948c2ecf20Sopenharmony_ci	ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4958c2ecf20Sopenharmony_ci	if (ret < 0)
4968c2ecf20Sopenharmony_ci		return ret;
4978c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
4988c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/*write data byte 1;*/
5018c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
5028c2ecf20Sopenharmony_ci	temp = temp << 10;
5038c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5048c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5058c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/*write data byte 2;*/
5088c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
5098c2ecf20Sopenharmony_ci	temp = temp << 10;
5108c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5118c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5128c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/*write data byte 3;*/
5158c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
5168c2ecf20Sopenharmony_ci	temp = temp << 10;
5178c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5188c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5198c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* write address byte 2;*/
5228c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
5238c2ecf20Sopenharmony_ci		((address & 0x003F0000) >> 8);
5248c2ecf20Sopenharmony_ci	temp = temp << 10;
5258c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5268c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5278c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* write address byte 1;*/
5308c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
5318c2ecf20Sopenharmony_ci	temp = temp << 10;
5328c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5338c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5348c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* write address byte 0;*/
5378c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
5388c2ecf20Sopenharmony_ci	temp = temp << 10;
5398c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5408c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5418c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/*wait for MIRDY line;*/
5448c2ecf20Sopenharmony_ci	wait_for_mci_complete(dev);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return 0;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	u32 temp = 0;
5528c2ecf20Sopenharmony_ci	u32 return_value = 0;
5538c2ecf20Sopenharmony_ci	int ret = 0;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	/*write address byte 2;*/
5568c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
5578c2ecf20Sopenharmony_ci		((address & 0x003F0000) >> 8);
5588c2ecf20Sopenharmony_ci	temp = temp << 10;
5598c2ecf20Sopenharmony_ci	ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5608c2ecf20Sopenharmony_ci	if (ret < 0)
5618c2ecf20Sopenharmony_ci		return ret;
5628c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5638c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/*write address byte 1*/
5668c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
5678c2ecf20Sopenharmony_ci	temp = temp << 10;
5688c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5698c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5708c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/*write address byte 0*/
5738c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
5748c2ecf20Sopenharmony_ci	temp = temp << 10;
5758c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5768c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
5778c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/*Wait for MIRDY line*/
5808c2ecf20Sopenharmony_ci	ret = wait_for_mci_complete(dev);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	/*Read data byte 3;*/
5848c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE3) << 10;
5858c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
5868c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE3) << 10);
5878c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
5888c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
5898c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) << 6);
5908c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/*Read data byte 2;*/
5938c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE2) << 10;
5948c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
5958c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE2) << 10);
5968c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
5978c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
5988c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 2);
5998c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	/* Read data byte 1;*/
6028c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE1) << 10;
6038c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
6048c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE1) << 10);
6058c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
6068c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
6078c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 10);
6088c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/*Read data byte 0;*/
6118c2ecf20Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE0) << 10;
6128c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
6138c2ecf20Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE0) << 10);
6148c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
6158c2ecf20Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
6168c2ecf20Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 18);
6178c2ecf20Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	*value  = return_value;
6208c2ecf20Sopenharmony_ci	return ret;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/* MPEG encoder API */
6268c2ecf20Sopenharmony_cistatic char *cmd_to_str(int cmd)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	switch (cmd) {
6298c2ecf20Sopenharmony_ci	case CX2341X_ENC_PING_FW:
6308c2ecf20Sopenharmony_ci		return "PING_FW";
6318c2ecf20Sopenharmony_ci	case CX2341X_ENC_START_CAPTURE:
6328c2ecf20Sopenharmony_ci		return "START_CAPTURE";
6338c2ecf20Sopenharmony_ci	case CX2341X_ENC_STOP_CAPTURE:
6348c2ecf20Sopenharmony_ci		return "STOP_CAPTURE";
6358c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_AUDIO_ID:
6368c2ecf20Sopenharmony_ci		return "SET_AUDIO_ID";
6378c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_VIDEO_ID:
6388c2ecf20Sopenharmony_ci		return "SET_VIDEO_ID";
6398c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_PCR_ID:
6408c2ecf20Sopenharmony_ci		return "SET_PCR_PID";
6418c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_RATE:
6428c2ecf20Sopenharmony_ci		return "SET_FRAME_RATE";
6438c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_SIZE:
6448c2ecf20Sopenharmony_ci		return "SET_FRAME_SIZE";
6458c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_BIT_RATE:
6468c2ecf20Sopenharmony_ci		return "SET_BIT_RATE";
6478c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_GOP_PROPERTIES:
6488c2ecf20Sopenharmony_ci		return "SET_GOP_PROPERTIES";
6498c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_ASPECT_RATIO:
6508c2ecf20Sopenharmony_ci		return "SET_ASPECT_RATIO";
6518c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_DNR_FILTER_MODE:
6528c2ecf20Sopenharmony_ci		return "SET_DNR_FILTER_PROPS";
6538c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
6548c2ecf20Sopenharmony_ci		return "SET_DNR_FILTER_PROPS";
6558c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_CORING_LEVELS:
6568c2ecf20Sopenharmony_ci		return "SET_CORING_LEVELS";
6578c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
6588c2ecf20Sopenharmony_ci		return "SET_SPATIAL_FILTER_TYPE";
6598c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_VBI_LINE:
6608c2ecf20Sopenharmony_ci		return "SET_VBI_LINE";
6618c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_STREAM_TYPE:
6628c2ecf20Sopenharmony_ci		return "SET_STREAM_TYPE";
6638c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_OUTPUT_PORT:
6648c2ecf20Sopenharmony_ci		return "SET_OUTPUT_PORT";
6658c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
6668c2ecf20Sopenharmony_ci		return "SET_AUDIO_PROPERTIES";
6678c2ecf20Sopenharmony_ci	case CX2341X_ENC_HALT_FW:
6688c2ecf20Sopenharmony_ci		return "HALT_FW";
6698c2ecf20Sopenharmony_ci	case CX2341X_ENC_GET_VERSION:
6708c2ecf20Sopenharmony_ci		return "GET_VERSION";
6718c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_GOP_CLOSURE:
6728c2ecf20Sopenharmony_ci		return "SET_GOP_CLOSURE";
6738c2ecf20Sopenharmony_ci	case CX2341X_ENC_GET_SEQ_END:
6748c2ecf20Sopenharmony_ci		return "GET_SEQ_END";
6758c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_PGM_INDEX_INFO:
6768c2ecf20Sopenharmony_ci		return "SET_PGM_INDEX_INFO";
6778c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_VBI_CONFIG:
6788c2ecf20Sopenharmony_ci		return "SET_VBI_CONFIG";
6798c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
6808c2ecf20Sopenharmony_ci		return "SET_DMA_BLOCK_SIZE";
6818c2ecf20Sopenharmony_ci	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
6828c2ecf20Sopenharmony_ci		return "GET_PREV_DMA_INFO_MB_10";
6838c2ecf20Sopenharmony_ci	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
6848c2ecf20Sopenharmony_ci		return "GET_PREV_DMA_INFO_MB_9";
6858c2ecf20Sopenharmony_ci	case CX2341X_ENC_SCHED_DMA_TO_HOST:
6868c2ecf20Sopenharmony_ci		return "SCHED_DMA_TO_HOST";
6878c2ecf20Sopenharmony_ci	case CX2341X_ENC_INITIALIZE_INPUT:
6888c2ecf20Sopenharmony_ci		return "INITIALIZE_INPUT";
6898c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_DROP_RATE:
6908c2ecf20Sopenharmony_ci		return "SET_FRAME_DROP_RATE";
6918c2ecf20Sopenharmony_ci	case CX2341X_ENC_PAUSE_ENCODER:
6928c2ecf20Sopenharmony_ci		return "PAUSE_ENCODER";
6938c2ecf20Sopenharmony_ci	case CX2341X_ENC_REFRESH_INPUT:
6948c2ecf20Sopenharmony_ci		return "REFRESH_INPUT";
6958c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_COPYRIGHT:
6968c2ecf20Sopenharmony_ci		return "SET_COPYRIGHT";
6978c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
6988c2ecf20Sopenharmony_ci		return "SET_EVENT_NOTIFICATION";
6998c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
7008c2ecf20Sopenharmony_ci		return "SET_NUM_VSYNC_LINES";
7018c2ecf20Sopenharmony_ci	case CX2341X_ENC_SET_PLACEHOLDER:
7028c2ecf20Sopenharmony_ci		return "SET_PLACEHOLDER";
7038c2ecf20Sopenharmony_ci	case CX2341X_ENC_MUTE_VIDEO:
7048c2ecf20Sopenharmony_ci		return "MUTE_VIDEO";
7058c2ecf20Sopenharmony_ci	case CX2341X_ENC_MUTE_AUDIO:
7068c2ecf20Sopenharmony_ci		return "MUTE_AUDIO";
7078c2ecf20Sopenharmony_ci	case CX2341X_ENC_MISC:
7088c2ecf20Sopenharmony_ci		return "MISC";
7098c2ecf20Sopenharmony_ci	default:
7108c2ecf20Sopenharmony_ci		return "UNKNOWN";
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic int cx231xx_mbox_func(void *priv, u32 command, int in, int out,
7158c2ecf20Sopenharmony_ci			     u32 data[CX2341X_MBOX_MAX_DATA])
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	struct cx231xx *dev = priv;
7188c2ecf20Sopenharmony_ci	unsigned long timeout;
7198c2ecf20Sopenharmony_ci	u32 value, flag, retval = 0;
7208c2ecf20Sopenharmony_ci	int i;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
7238c2ecf20Sopenharmony_ci		cmd_to_str(command));
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/* this may not be 100% safe if we can't read any memory location
7268c2ecf20Sopenharmony_ci	   without side effects */
7278c2ecf20Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
7288c2ecf20Sopenharmony_ci	if (value != 0x12345678) {
7298c2ecf20Sopenharmony_ci		dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
7308c2ecf20Sopenharmony_ci			value, cmd_to_str(command));
7318c2ecf20Sopenharmony_ci		return -EIO;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* This read looks at 32 bits, but flag is only 8 bits.
7358c2ecf20Sopenharmony_ci	 * Seems we also bail if CMD or TIMEOUT bytes are set???
7368c2ecf20Sopenharmony_ci	 */
7378c2ecf20Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
7388c2ecf20Sopenharmony_ci	if (flag) {
7398c2ecf20Sopenharmony_ci		dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
7408c2ecf20Sopenharmony_ci				flag, cmd_to_str(command));
7418c2ecf20Sopenharmony_ci		return -EBUSY;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	flag |= 1; /* tell 'em we're working on it */
7458c2ecf20Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* write command + args + fill remaining with zeros */
7488c2ecf20Sopenharmony_ci	/* command code */
7498c2ecf20Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
7508c2ecf20Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
7518c2ecf20Sopenharmony_ci		IVTV_API_STD_TIMEOUT); /* timeout */
7528c2ecf20Sopenharmony_ci	for (i = 0; i < in; i++) {
7538c2ecf20Sopenharmony_ci		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
7548c2ecf20Sopenharmony_ci		dprintk(3, "API Input %d = %d\n", i, data[i]);
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci	for (; i < CX2341X_MBOX_MAX_DATA; i++)
7578c2ecf20Sopenharmony_ci		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	flag |= 3; /* tell 'em we're done writing */
7608c2ecf20Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* wait for firmware to handle the API command */
7638c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(10);
7648c2ecf20Sopenharmony_ci	for (;;) {
7658c2ecf20Sopenharmony_ci		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
7668c2ecf20Sopenharmony_ci		if (0 != (flag & 4))
7678c2ecf20Sopenharmony_ci			break;
7688c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
7698c2ecf20Sopenharmony_ci			dprintk(3, "ERROR: API Mailbox timeout\n");
7708c2ecf20Sopenharmony_ci			return -EIO;
7718c2ecf20Sopenharmony_ci		}
7728c2ecf20Sopenharmony_ci		udelay(10);
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/* read output values */
7768c2ecf20Sopenharmony_ci	for (i = 0; i < out; i++) {
7778c2ecf20Sopenharmony_ci		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
7788c2ecf20Sopenharmony_ci		dprintk(3, "API Output %d = %d\n", i, data[i]);
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
7828c2ecf20Sopenharmony_ci	dprintk(3, "API result = %d\n", retval);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	flag = 0;
7858c2ecf20Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	return 0;
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci/* We don't need to call the API often, so using just one
7918c2ecf20Sopenharmony_ci * mailbox will probably suffice
7928c2ecf20Sopenharmony_ci */
7938c2ecf20Sopenharmony_cistatic int cx231xx_api_cmd(struct cx231xx *dev, u32 command,
7948c2ecf20Sopenharmony_ci		u32 inputcnt, u32 outputcnt, ...)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
7978c2ecf20Sopenharmony_ci	va_list vargs;
7988c2ecf20Sopenharmony_ci	int i, err;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	va_start(vargs, outputcnt);
8038c2ecf20Sopenharmony_ci	for (i = 0; i < inputcnt; i++)
8048c2ecf20Sopenharmony_ci		data[i] = va_arg(vargs, int);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
8078c2ecf20Sopenharmony_ci	for (i = 0; i < outputcnt; i++) {
8088c2ecf20Sopenharmony_ci		int *vptr = va_arg(vargs, int *);
8098c2ecf20Sopenharmony_ci		*vptr = data[i];
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci	va_end(vargs);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return err;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic int cx231xx_find_mailbox(struct cx231xx *dev)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	u32 signature[4] = {
8208c2ecf20Sopenharmony_ci		0x12345678, 0x34567812, 0x56781234, 0x78123456
8218c2ecf20Sopenharmony_ci	};
8228c2ecf20Sopenharmony_ci	int signaturecnt = 0;
8238c2ecf20Sopenharmony_ci	u32 value;
8248c2ecf20Sopenharmony_ci	int i;
8258c2ecf20Sopenharmony_ci	int ret = 0;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	dprintk(2, "%s()\n", __func__);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
8308c2ecf20Sopenharmony_ci		ret = mc417_memory_read(dev, i, &value);
8318c2ecf20Sopenharmony_ci		if (ret < 0)
8328c2ecf20Sopenharmony_ci			return ret;
8338c2ecf20Sopenharmony_ci		if (value == signature[signaturecnt])
8348c2ecf20Sopenharmony_ci			signaturecnt++;
8358c2ecf20Sopenharmony_ci		else
8368c2ecf20Sopenharmony_ci			signaturecnt = 0;
8378c2ecf20Sopenharmony_ci		if (4 == signaturecnt) {
8388c2ecf20Sopenharmony_ci			dprintk(1, "Mailbox signature found at 0x%x\n", i + 1);
8398c2ecf20Sopenharmony_ci			return i + 1;
8408c2ecf20Sopenharmony_ci		}
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci	dprintk(3, "Mailbox signature values not found!\n");
8438c2ecf20Sopenharmony_ci	return -EIO;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value,
8478c2ecf20Sopenharmony_ci		u32 *p_fw_image)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	u32 temp = 0;
8508c2ecf20Sopenharmony_ci	int i = 0;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
8538c2ecf20Sopenharmony_ci	temp = temp << 10;
8548c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8558c2ecf20Sopenharmony_ci	p_fw_image++;
8568c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
8578c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8588c2ecf20Sopenharmony_ci	p_fw_image++;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	/*write data byte 1;*/
8618c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
8628c2ecf20Sopenharmony_ci	temp = temp << 10;
8638c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8648c2ecf20Sopenharmony_ci	p_fw_image++;
8658c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
8668c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8678c2ecf20Sopenharmony_ci	p_fw_image++;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/*write data byte 2;*/
8708c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
8718c2ecf20Sopenharmony_ci	temp = temp << 10;
8728c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8738c2ecf20Sopenharmony_ci	p_fw_image++;
8748c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
8758c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8768c2ecf20Sopenharmony_ci	p_fw_image++;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/*write data byte 3;*/
8798c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
8808c2ecf20Sopenharmony_ci	temp = temp << 10;
8818c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8828c2ecf20Sopenharmony_ci	p_fw_image++;
8838c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
8848c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8858c2ecf20Sopenharmony_ci	p_fw_image++;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	/* write address byte 2;*/
8888c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
8898c2ecf20Sopenharmony_ci		((address & 0x003F0000) >> 8);
8908c2ecf20Sopenharmony_ci	temp = temp << 10;
8918c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8928c2ecf20Sopenharmony_ci	p_fw_image++;
8938c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
8948c2ecf20Sopenharmony_ci	*p_fw_image = temp;
8958c2ecf20Sopenharmony_ci	p_fw_image++;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/* write address byte 1;*/
8988c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
8998c2ecf20Sopenharmony_ci	temp = temp << 10;
9008c2ecf20Sopenharmony_ci	*p_fw_image = temp;
9018c2ecf20Sopenharmony_ci	p_fw_image++;
9028c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
9038c2ecf20Sopenharmony_ci	*p_fw_image = temp;
9048c2ecf20Sopenharmony_ci	p_fw_image++;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* write address byte 0;*/
9078c2ecf20Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
9088c2ecf20Sopenharmony_ci	temp = temp << 10;
9098c2ecf20Sopenharmony_ci	*p_fw_image = temp;
9108c2ecf20Sopenharmony_ci	p_fw_image++;
9118c2ecf20Sopenharmony_ci	temp = temp | (0x05 << 10);
9128c2ecf20Sopenharmony_ci	*p_fw_image = temp;
9138c2ecf20Sopenharmony_ci	p_fw_image++;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
9168c2ecf20Sopenharmony_ci		*p_fw_image = 0xFFFFFFFF;
9178c2ecf20Sopenharmony_ci		p_fw_image++;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cistatic int cx231xx_load_firmware(struct cx231xx *dev)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	static const unsigned char magic[8] = {
9258c2ecf20Sopenharmony_ci		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
9268c2ecf20Sopenharmony_ci	};
9278c2ecf20Sopenharmony_ci	const struct firmware *firmware;
9288c2ecf20Sopenharmony_ci	int i, retval = 0;
9298c2ecf20Sopenharmony_ci	u32 value = 0;
9308c2ecf20Sopenharmony_ci	u32 gpio_output = 0;
9318c2ecf20Sopenharmony_ci	/*u32 checksum = 0;*/
9328c2ecf20Sopenharmony_ci	/*u32 *dataptr;*/
9338c2ecf20Sopenharmony_ci	u32 transfer_size = 0;
9348c2ecf20Sopenharmony_ci	u32 fw_data = 0;
9358c2ecf20Sopenharmony_ci	u32 address = 0;
9368c2ecf20Sopenharmony_ci	/*u32 current_fw[800];*/
9378c2ecf20Sopenharmony_ci	u32 *p_current_fw, *p_fw;
9388c2ecf20Sopenharmony_ci	u32 *p_fw_data;
9398c2ecf20Sopenharmony_ci	int frame = 0;
9408c2ecf20Sopenharmony_ci	u16 _buffer_size = 4096;
9418c2ecf20Sopenharmony_ci	u8 *p_buffer;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	p_current_fw = vmalloc(1884180 * 4);
9448c2ecf20Sopenharmony_ci	p_fw = p_current_fw;
9458c2ecf20Sopenharmony_ci	if (p_current_fw == NULL) {
9468c2ecf20Sopenharmony_ci		dprintk(2, "FAIL!!!\n");
9478c2ecf20Sopenharmony_ci		return -ENOMEM;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	p_buffer = vmalloc(4096);
9518c2ecf20Sopenharmony_ci	if (p_buffer == NULL) {
9528c2ecf20Sopenharmony_ci		dprintk(2, "FAIL!!!\n");
9538c2ecf20Sopenharmony_ci		vfree(p_current_fw);
9548c2ecf20Sopenharmony_ci		return -ENOMEM;
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	dprintk(2, "%s()\n", __func__);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	/* Save GPIO settings before reset of APU */
9608c2ecf20Sopenharmony_ci	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
9618c2ecf20Sopenharmony_ci	retval |= mc417_memory_read(dev, 0x900C, &value);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	retval  = mc417_register_write(dev,
9648c2ecf20Sopenharmony_ci		IVTV_REG_VPU, 0xFFFFFFED);
9658c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev,
9668c2ecf20Sopenharmony_ci		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
9678c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev,
9688c2ecf20Sopenharmony_ci		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
9698c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev,
9708c2ecf20Sopenharmony_ci		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
9718c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev,
9728c2ecf20Sopenharmony_ci		IVTV_REG_APU, 0);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (retval != 0) {
9758c2ecf20Sopenharmony_ci		dev_err(dev->dev,
9768c2ecf20Sopenharmony_ci			"%s: Error with mc417_register_write\n", __func__);
9778c2ecf20Sopenharmony_ci		vfree(p_current_fw);
9788c2ecf20Sopenharmony_ci		vfree(p_buffer);
9798c2ecf20Sopenharmony_ci		return retval;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
9838c2ecf20Sopenharmony_ci				  dev->dev);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (retval != 0) {
9868c2ecf20Sopenharmony_ci		dev_err(dev->dev,
9878c2ecf20Sopenharmony_ci			"ERROR: Hotplug firmware request failed (%s).\n",
9888c2ecf20Sopenharmony_ci			CX231xx_FIRM_IMAGE_NAME);
9898c2ecf20Sopenharmony_ci		dev_err(dev->dev,
9908c2ecf20Sopenharmony_ci			"Please fix your hotplug setup, the board will not work without firmware loaded!\n");
9918c2ecf20Sopenharmony_ci		vfree(p_current_fw);
9928c2ecf20Sopenharmony_ci		vfree(p_buffer);
9938c2ecf20Sopenharmony_ci		return retval;
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
9978c2ecf20Sopenharmony_ci		dev_err(dev->dev,
9988c2ecf20Sopenharmony_ci			"ERROR: Firmware size mismatch (have %zd, expected %d)\n",
9998c2ecf20Sopenharmony_ci			firmware->size, CX231xx_FIRM_IMAGE_SIZE);
10008c2ecf20Sopenharmony_ci		release_firmware(firmware);
10018c2ecf20Sopenharmony_ci		vfree(p_current_fw);
10028c2ecf20Sopenharmony_ci		vfree(p_buffer);
10038c2ecf20Sopenharmony_ci		return -EINVAL;
10048c2ecf20Sopenharmony_ci	}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	if (0 != memcmp(firmware->data, magic, 8)) {
10078c2ecf20Sopenharmony_ci		dev_err(dev->dev,
10088c2ecf20Sopenharmony_ci			"ERROR: Firmware magic mismatch, wrong file?\n");
10098c2ecf20Sopenharmony_ci		release_firmware(firmware);
10108c2ecf20Sopenharmony_ci		vfree(p_current_fw);
10118c2ecf20Sopenharmony_ci		vfree(p_buffer);
10128c2ecf20Sopenharmony_ci		return -EINVAL;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	initGPIO(dev);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/* transfer to the chip */
10188c2ecf20Sopenharmony_ci	dprintk(2, "Loading firmware to GPIO...\n");
10198c2ecf20Sopenharmony_ci	p_fw_data = (u32 *)firmware->data;
10208c2ecf20Sopenharmony_ci	dprintk(2, "firmware->size=%zd\n", firmware->size);
10218c2ecf20Sopenharmony_ci	for (transfer_size = 0; transfer_size < firmware->size;
10228c2ecf20Sopenharmony_ci		 transfer_size += 4) {
10238c2ecf20Sopenharmony_ci		fw_data = *p_fw_data;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		mci_write_memory_to_gpio(dev, address, fw_data, p_current_fw);
10268c2ecf20Sopenharmony_ci		address = address + 1;
10278c2ecf20Sopenharmony_ci		p_current_fw += 20;
10288c2ecf20Sopenharmony_ci		p_fw_data += 1;
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/*download the firmware by ep5-out*/
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
10348c2ecf20Sopenharmony_ci	     frame++) {
10358c2ecf20Sopenharmony_ci		for (i = 0; i < _buffer_size; i++) {
10368c2ecf20Sopenharmony_ci			*(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
10378c2ecf20Sopenharmony_ci			i++;
10388c2ecf20Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
10398c2ecf20Sopenharmony_ci			i++;
10408c2ecf20Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
10418c2ecf20Sopenharmony_ci			i++;
10428c2ecf20Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
10438c2ecf20Sopenharmony_ci		}
10448c2ecf20Sopenharmony_ci		cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	p_current_fw = p_fw;
10488c2ecf20Sopenharmony_ci	vfree(p_current_fw);
10498c2ecf20Sopenharmony_ci	p_current_fw = NULL;
10508c2ecf20Sopenharmony_ci	vfree(p_buffer);
10518c2ecf20Sopenharmony_ci	uninitGPIO(dev);
10528c2ecf20Sopenharmony_ci	release_firmware(firmware);
10538c2ecf20Sopenharmony_ci	dprintk(1, "Firmware upload successful.\n");
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
10568c2ecf20Sopenharmony_ci		IVTV_CMD_HW_BLOCKS_RST);
10578c2ecf20Sopenharmony_ci	if (retval < 0) {
10588c2ecf20Sopenharmony_ci		dev_err(dev->dev,
10598c2ecf20Sopenharmony_ci			"%s: Error with mc417_register_write\n",
10608c2ecf20Sopenharmony_ci			__func__);
10618c2ecf20Sopenharmony_ci		return retval;
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci	/* F/W power up disturbs the GPIOs, restore state */
10648c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev, 0x9020, gpio_output);
10658c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev, 0x900C, value);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
10688c2ecf20Sopenharmony_ci	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (retval < 0) {
10718c2ecf20Sopenharmony_ci		dev_err(dev->dev,
10728c2ecf20Sopenharmony_ci			"%s: Error with mc417_register_write\n",
10738c2ecf20Sopenharmony_ci			__func__);
10748c2ecf20Sopenharmony_ci		return retval;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci	return 0;
10778c2ecf20Sopenharmony_ci}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_cistatic void cx231xx_codec_settings(struct cx231xx *dev)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	/* assign frame size */
10848c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
10858c2ecf20Sopenharmony_ci				dev->ts1.height, dev->ts1.width);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.width = dev->ts1.width;
10888c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.height = dev->ts1.height;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	cx2341x_handler_setup(&dev->mpeg_ctrl_handler);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
10938c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic int cx231xx_initialize_codec(struct cx231xx *dev)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	int version;
10998c2ecf20Sopenharmony_ci	int retval;
11008c2ecf20Sopenharmony_ci	u32 i;
11018c2ecf20Sopenharmony_ci	u32 val = 0;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
11048c2ecf20Sopenharmony_ci	cx231xx_disable656(dev);
11058c2ecf20Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
11068c2ecf20Sopenharmony_ci	if (retval < 0) {
11078c2ecf20Sopenharmony_ci		dprintk(2, "%s: PING OK\n", __func__);
11088c2ecf20Sopenharmony_ci		retval = cx231xx_load_firmware(dev);
11098c2ecf20Sopenharmony_ci		if (retval < 0) {
11108c2ecf20Sopenharmony_ci			dev_err(dev->dev,
11118c2ecf20Sopenharmony_ci				"%s: f/w load failed\n", __func__);
11128c2ecf20Sopenharmony_ci			return retval;
11138c2ecf20Sopenharmony_ci		}
11148c2ecf20Sopenharmony_ci		retval = cx231xx_find_mailbox(dev);
11158c2ecf20Sopenharmony_ci		if (retval < 0) {
11168c2ecf20Sopenharmony_ci			dev_err(dev->dev, "%s: mailbox < 0, error\n",
11178c2ecf20Sopenharmony_ci				__func__);
11188c2ecf20Sopenharmony_ci			return retval;
11198c2ecf20Sopenharmony_ci		}
11208c2ecf20Sopenharmony_ci		dev->cx23417_mailbox = retval;
11218c2ecf20Sopenharmony_ci		retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
11228c2ecf20Sopenharmony_ci		if (retval < 0) {
11238c2ecf20Sopenharmony_ci			dev_err(dev->dev,
11248c2ecf20Sopenharmony_ci				"ERROR: cx23417 firmware ping failed!\n");
11258c2ecf20Sopenharmony_ci			return retval;
11268c2ecf20Sopenharmony_ci		}
11278c2ecf20Sopenharmony_ci		retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
11288c2ecf20Sopenharmony_ci			&version);
11298c2ecf20Sopenharmony_ci		if (retval < 0) {
11308c2ecf20Sopenharmony_ci			dev_err(dev->dev,
11318c2ecf20Sopenharmony_ci				"ERROR: cx23417 firmware get encoder: version failed!\n");
11328c2ecf20Sopenharmony_ci			return retval;
11338c2ecf20Sopenharmony_ci		}
11348c2ecf20Sopenharmony_ci		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
11358c2ecf20Sopenharmony_ci		msleep(200);
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	for (i = 0; i < 1; i++) {
11398c2ecf20Sopenharmony_ci		retval = mc417_register_read(dev, 0x20f8, &val);
11408c2ecf20Sopenharmony_ci		dprintk(3, "***before enable656() VIM Capture Lines = %d ***\n",
11418c2ecf20Sopenharmony_ci				 val);
11428c2ecf20Sopenharmony_ci		if (retval < 0)
11438c2ecf20Sopenharmony_ci			return retval;
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	cx231xx_enable656(dev);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/* stop mpeg capture */
11498c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, 1, 3, 4);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	cx231xx_codec_settings(dev);
11528c2ecf20Sopenharmony_ci	msleep(60);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/*	cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
11558c2ecf20Sopenharmony_ci		CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
11568c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
11578c2ecf20Sopenharmony_ci		CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11588c2ecf20Sopenharmony_ci		0, 0);
11598c2ecf20Sopenharmony_ci*/
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci#if 0
11628c2ecf20Sopenharmony_ci	/* TODO */
11638c2ecf20Sopenharmony_ci	u32 data[7];
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	/* Setup to capture VBI */
11668c2ecf20Sopenharmony_ci	data[0] = 0x0001BD00;
11678c2ecf20Sopenharmony_ci	data[1] = 1;          /* frames per interrupt */
11688c2ecf20Sopenharmony_ci	data[2] = 4;          /* total bufs */
11698c2ecf20Sopenharmony_ci	data[3] = 0x91559155; /* start codes */
11708c2ecf20Sopenharmony_ci	data[4] = 0x206080C0; /* stop codes */
11718c2ecf20Sopenharmony_ci	data[5] = 6;          /* lines */
11728c2ecf20Sopenharmony_ci	data[6] = 64;         /* BPL */
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
11758c2ecf20Sopenharmony_ci		data[2], data[3], data[4], data[5], data[6]);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	for (i = 2; i <= 24; i++) {
11788c2ecf20Sopenharmony_ci		int valid;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci		valid = ((i >= 19) && (i <= 21));
11818c2ecf20Sopenharmony_ci		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
11828c2ecf20Sopenharmony_ci				valid, 0 , 0, 0);
11838c2ecf20Sopenharmony_ci		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
11848c2ecf20Sopenharmony_ci				i | 0x80000000, valid, 0, 0, 0);
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci#endif
11878c2ecf20Sopenharmony_ci/*	cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
11888c2ecf20Sopenharmony_ci	msleep(60);
11898c2ecf20Sopenharmony_ci*/
11908c2ecf20Sopenharmony_ci	/* initialize the video input */
11918c2ecf20Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
11928c2ecf20Sopenharmony_ci	if (retval < 0)
11938c2ecf20Sopenharmony_ci		return retval;
11948c2ecf20Sopenharmony_ci	msleep(60);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	/* Enable VIP style pixel invalidation so we work with scaled mode */
11978c2ecf20Sopenharmony_ci	mc417_memory_write(dev, 2120, 0x00000080);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	/* start capturing to the host interface */
12008c2ecf20Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
12018c2ecf20Sopenharmony_ci		CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
12028c2ecf20Sopenharmony_ci	if (retval < 0)
12038c2ecf20Sopenharmony_ci		return retval;
12048c2ecf20Sopenharmony_ci	msleep(10);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	for (i = 0; i < 1; i++) {
12078c2ecf20Sopenharmony_ci		mc417_register_read(dev, 0x20f8, &val);
12088c2ecf20Sopenharmony_ci		dprintk(3, "***VIM Capture Lines =%d ***\n", val);
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return 0;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_cistatic int queue_setup(struct vb2_queue *vq,
12178c2ecf20Sopenharmony_ci		       unsigned int *nbuffers, unsigned int *nplanes,
12188c2ecf20Sopenharmony_ci		       unsigned int sizes[], struct device *alloc_devs[])
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
12218c2ecf20Sopenharmony_ci	unsigned int size = mpeglinesize * mpeglines;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	dev->ts1.ts_packet_size  = mpeglinesize;
12248c2ecf20Sopenharmony_ci	dev->ts1.ts_packet_count = mpeglines;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF)
12278c2ecf20Sopenharmony_ci		*nbuffers = CX231XX_MIN_BUF - vq->num_buffers;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	if (*nplanes)
12308c2ecf20Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
12318c2ecf20Sopenharmony_ci	*nplanes = 1;
12328c2ecf20Sopenharmony_ci	sizes[0] = mpeglinesize * mpeglines;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	return 0;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
12388c2ecf20Sopenharmony_ci		struct cx231xx_dmaqueue *dma_q)
12398c2ecf20Sopenharmony_ci{
12408c2ecf20Sopenharmony_ci	void *vbuf;
12418c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf;
12428c2ecf20Sopenharmony_ci	u32 tail_data = 0;
12438c2ecf20Sopenharmony_ci	char *p_data;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	if (dma_q->mpeg_buffer_done == 0) {
12468c2ecf20Sopenharmony_ci		if (list_empty(&dma_q->active))
12478c2ecf20Sopenharmony_ci			return;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci		buf = list_entry(dma_q->active.next,
12508c2ecf20Sopenharmony_ci				struct cx231xx_buffer, list);
12518c2ecf20Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = buf;
12528c2ecf20Sopenharmony_ci		dma_q->mpeg_buffer_done = 1;
12538c2ecf20Sopenharmony_ci	}
12548c2ecf20Sopenharmony_ci	/* Fill buffer */
12558c2ecf20Sopenharmony_ci	buf = dev->video_mode.isoc_ctl.buf;
12568c2ecf20Sopenharmony_ci	vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	if ((dma_q->mpeg_buffer_completed+len) <
12598c2ecf20Sopenharmony_ci			mpeglines*mpeglinesize) {
12608c2ecf20Sopenharmony_ci		if (dma_q->add_ps_package_head ==
12618c2ecf20Sopenharmony_ci				CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
12628c2ecf20Sopenharmony_ci			memcpy(vbuf+dma_q->mpeg_buffer_completed,
12638c2ecf20Sopenharmony_ci					dma_q->ps_head, 3);
12648c2ecf20Sopenharmony_ci			dma_q->mpeg_buffer_completed =
12658c2ecf20Sopenharmony_ci				dma_q->mpeg_buffer_completed + 3;
12668c2ecf20Sopenharmony_ci			dma_q->add_ps_package_head =
12678c2ecf20Sopenharmony_ci				CX231XX_NONEED_PS_PACKAGE_HEAD;
12688c2ecf20Sopenharmony_ci		}
12698c2ecf20Sopenharmony_ci		memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
12708c2ecf20Sopenharmony_ci		dma_q->mpeg_buffer_completed =
12718c2ecf20Sopenharmony_ci			dma_q->mpeg_buffer_completed + len;
12728c2ecf20Sopenharmony_ci	} else {
12738c2ecf20Sopenharmony_ci		dma_q->mpeg_buffer_done = 0;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci		tail_data =
12768c2ecf20Sopenharmony_ci			mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
12778c2ecf20Sopenharmony_ci		memcpy(vbuf+dma_q->mpeg_buffer_completed,
12788c2ecf20Sopenharmony_ci				data, tail_data);
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci		buf->vb.vb2_buf.timestamp = ktime_get_ns();
12818c2ecf20Sopenharmony_ci		buf->vb.sequence = dma_q->sequence++;
12828c2ecf20Sopenharmony_ci		list_del(&buf->list);
12838c2ecf20Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
12848c2ecf20Sopenharmony_ci		dma_q->mpeg_buffer_completed = 0;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		if (len - tail_data > 0) {
12878c2ecf20Sopenharmony_ci			p_data = data + tail_data;
12888c2ecf20Sopenharmony_ci			dma_q->left_data_count = len - tail_data;
12898c2ecf20Sopenharmony_ci			memcpy(dma_q->p_left_data,
12908c2ecf20Sopenharmony_ci					p_data, len - tail_data);
12918c2ecf20Sopenharmony_ci		}
12928c2ecf20Sopenharmony_ci	}
12938c2ecf20Sopenharmony_ci}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_cistatic void buffer_filled(char *data, int len, struct urb *urb,
12968c2ecf20Sopenharmony_ci		struct cx231xx_dmaqueue *dma_q)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	void *vbuf;
12998c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (list_empty(&dma_q->active))
13028c2ecf20Sopenharmony_ci		return;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	/* Fill buffer */
13078c2ecf20Sopenharmony_ci	vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
13088c2ecf20Sopenharmony_ci	memcpy(vbuf, data, len);
13098c2ecf20Sopenharmony_ci	buf->vb.sequence = dma_q->sequence++;
13108c2ecf20Sopenharmony_ci	buf->vb.vb2_buf.timestamp = ktime_get_ns();
13118c2ecf20Sopenharmony_ci	list_del(&buf->list);
13128c2ecf20Sopenharmony_ci	vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_cistatic int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
13188c2ecf20Sopenharmony_ci	unsigned char *p_buffer;
13198c2ecf20Sopenharmony_ci	u32 buffer_size = 0;
13208c2ecf20Sopenharmony_ci	u32 i = 0;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
13238c2ecf20Sopenharmony_ci		if (dma_q->left_data_count > 0) {
13248c2ecf20Sopenharmony_ci			buffer_copy(dev, dma_q->p_left_data,
13258c2ecf20Sopenharmony_ci				    dma_q->left_data_count, urb, dma_q);
13268c2ecf20Sopenharmony_ci			dma_q->mpeg_buffer_completed = dma_q->left_data_count;
13278c2ecf20Sopenharmony_ci			dma_q->left_data_count = 0;
13288c2ecf20Sopenharmony_ci		}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci		p_buffer = urb->transfer_buffer +
13318c2ecf20Sopenharmony_ci				urb->iso_frame_desc[i].offset;
13328c2ecf20Sopenharmony_ci		buffer_size = urb->iso_frame_desc[i].actual_length;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		if (buffer_size > 0)
13358c2ecf20Sopenharmony_ci			buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	return 0;
13398c2ecf20Sopenharmony_ci}
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_cistatic int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
13428c2ecf20Sopenharmony_ci{
13438c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
13448c2ecf20Sopenharmony_ci	unsigned char *p_buffer, *buffer;
13458c2ecf20Sopenharmony_ci	u32 buffer_size = 0;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	p_buffer = urb->transfer_buffer;
13488c2ecf20Sopenharmony_ci	buffer_size = urb->actual_length;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	buffer = kmalloc(buffer_size, GFP_ATOMIC);
13518c2ecf20Sopenharmony_ci	if (!buffer)
13528c2ecf20Sopenharmony_ci		return -ENOMEM;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	memcpy(buffer, dma_q->ps_head, 3);
13558c2ecf20Sopenharmony_ci	memcpy(buffer+3, p_buffer, buffer_size-3);
13568c2ecf20Sopenharmony_ci	memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	p_buffer = buffer;
13598c2ecf20Sopenharmony_ci	buffer_filled(p_buffer, buffer_size, urb, dma_q);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	kfree(buffer);
13628c2ecf20Sopenharmony_ci	return 0;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb)
13668c2ecf20Sopenharmony_ci{
13678c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf =
13688c2ecf20Sopenharmony_ci	    container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
13698c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
13708c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
13718c2ecf20Sopenharmony_ci	unsigned long flags;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
13748c2ecf20Sopenharmony_ci	list_add_tail(&buf->list, &vidq->active);
13758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_cistatic void return_all_buffers(struct cx231xx *dev,
13798c2ecf20Sopenharmony_ci			       enum vb2_buffer_state state)
13808c2ecf20Sopenharmony_ci{
13818c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
13828c2ecf20Sopenharmony_ci	struct cx231xx_buffer *buf, *node;
13838c2ecf20Sopenharmony_ci	unsigned long flags;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
13868c2ecf20Sopenharmony_ci	list_for_each_entry_safe(buf, node, &vidq->active, list) {
13878c2ecf20Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, state);
13888c2ecf20Sopenharmony_ci		list_del(&buf->list);
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic int start_streaming(struct vb2_queue *vq, unsigned int count)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
13968c2ecf20Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
13978c2ecf20Sopenharmony_ci	int ret = 0;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	vidq->sequence = 0;
14008c2ecf20Sopenharmony_ci	dev->mode_tv = 1;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
14038c2ecf20Sopenharmony_ci	cx231xx_set_gpio_value(dev, 2, 0);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	cx231xx_initialize_codec(dev);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	cx231xx_start_TS1(dev);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
14108c2ecf20Sopenharmony_ci	cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
14118c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
14128c2ecf20Sopenharmony_ci		ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
14138c2ecf20Sopenharmony_ci					CX231XX_NUM_BUFS,
14148c2ecf20Sopenharmony_ci					dev->ts1_mode.max_pkt_size,
14158c2ecf20Sopenharmony_ci					cx231xx_isoc_copy);
14168c2ecf20Sopenharmony_ci	else
14178c2ecf20Sopenharmony_ci		ret = cx231xx_init_bulk(dev, 320, 5,
14188c2ecf20Sopenharmony_ci					dev->ts1_mode.max_pkt_size,
14198c2ecf20Sopenharmony_ci					cx231xx_bulk_copy);
14208c2ecf20Sopenharmony_ci	if (ret)
14218c2ecf20Sopenharmony_ci		return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	call_all(dev, video, s_stream, 1);
14248c2ecf20Sopenharmony_ci	return ret;
14258c2ecf20Sopenharmony_ci}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_cistatic void stop_streaming(struct vb2_queue *vq)
14288c2ecf20Sopenharmony_ci{
14298c2ecf20Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
14308c2ecf20Sopenharmony_ci	unsigned long flags;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	call_all(dev, video, s_stream, 0);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	cx231xx_stop_TS1(dev);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* do this before setting alternate! */
14378c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
14388c2ecf20Sopenharmony_ci		cx231xx_uninit_isoc(dev);
14398c2ecf20Sopenharmony_ci	else
14408c2ecf20Sopenharmony_ci		cx231xx_uninit_bulk(dev);
14418c2ecf20Sopenharmony_ci	cx231xx_set_mode(dev, CX231XX_SUSPEND);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
14448c2ecf20Sopenharmony_ci			CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
14458c2ecf20Sopenharmony_ci			CX231xx_RAW_BITS_NONE);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
14488c2ecf20Sopenharmony_ci	if (dev->USE_ISO)
14498c2ecf20Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = NULL;
14508c2ecf20Sopenharmony_ci	else
14518c2ecf20Sopenharmony_ci		dev->video_mode.bulk_ctl.buf = NULL;
14528c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
14538c2ecf20Sopenharmony_ci	return_all_buffers(dev, VB2_BUF_STATE_ERROR);
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic struct vb2_ops cx231xx_video_qops = {
14578c2ecf20Sopenharmony_ci	.queue_setup		= queue_setup,
14588c2ecf20Sopenharmony_ci	.buf_queue		= buffer_queue,
14598c2ecf20Sopenharmony_ci	.start_streaming	= start_streaming,
14608c2ecf20Sopenharmony_ci	.stop_streaming		= stop_streaming,
14618c2ecf20Sopenharmony_ci	.wait_prepare		= vb2_ops_wait_prepare,
14628c2ecf20Sopenharmony_ci	.wait_finish		= vb2_ops_wait_finish,
14638c2ecf20Sopenharmony_ci};
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_cistatic int vidioc_g_pixelaspect(struct file *file, void *priv,
14688c2ecf20Sopenharmony_ci				int type, struct v4l2_fract *f)
14698c2ecf20Sopenharmony_ci{
14708c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14718c2ecf20Sopenharmony_ci	bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
14748c2ecf20Sopenharmony_ci		return -EINVAL;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	f->numerator = is_50hz ? 54 : 11;
14778c2ecf20Sopenharmony_ci	f->denominator = is_50hz ? 59 : 10;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	return 0;
14808c2ecf20Sopenharmony_ci}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_cistatic int vidioc_g_selection(struct file *file, void *priv,
14838c2ecf20Sopenharmony_ci			      struct v4l2_selection *s)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
14888c2ecf20Sopenharmony_ci		return -EINVAL;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	switch (s->target) {
14918c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
14928c2ecf20Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
14938c2ecf20Sopenharmony_ci		s->r.left = 0;
14948c2ecf20Sopenharmony_ci		s->r.top = 0;
14958c2ecf20Sopenharmony_ci		s->r.width = dev->ts1.width;
14968c2ecf20Sopenharmony_ci		s->r.height = dev->ts1.height;
14978c2ecf20Sopenharmony_ci		break;
14988c2ecf20Sopenharmony_ci	default:
14998c2ecf20Sopenharmony_ci		return -EINVAL;
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci	return 0;
15028c2ecf20Sopenharmony_ci}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
15058c2ecf20Sopenharmony_ci{
15068c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	*norm = dev->encodernorm.id;
15098c2ecf20Sopenharmony_ci	return 0;
15108c2ecf20Sopenharmony_ci}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
15138c2ecf20Sopenharmony_ci{
15148c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
15158c2ecf20Sopenharmony_ci	unsigned int i;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
15188c2ecf20Sopenharmony_ci		if (id & cx231xx_tvnorms[i].id)
15198c2ecf20Sopenharmony_ci			break;
15208c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(cx231xx_tvnorms))
15218c2ecf20Sopenharmony_ci		return -EINVAL;
15228c2ecf20Sopenharmony_ci	dev->encodernorm = cx231xx_tvnorms[i];
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	if (dev->encodernorm.id & 0xb000) {
15258c2ecf20Sopenharmony_ci		dprintk(3, "encodernorm set to NTSC\n");
15268c2ecf20Sopenharmony_ci		dev->norm = V4L2_STD_NTSC;
15278c2ecf20Sopenharmony_ci		dev->ts1.height = 480;
15288c2ecf20Sopenharmony_ci		cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
15298c2ecf20Sopenharmony_ci	} else {
15308c2ecf20Sopenharmony_ci		dprintk(3, "encodernorm set to PAL\n");
15318c2ecf20Sopenharmony_ci		dev->norm = V4L2_STD_PAL_B;
15328c2ecf20Sopenharmony_ci		dev->ts1.height = 576;
15338c2ecf20Sopenharmony_ci		cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
15348c2ecf20Sopenharmony_ci	}
15358c2ecf20Sopenharmony_ci	call_all(dev, video, s_std, dev->norm);
15368c2ecf20Sopenharmony_ci	/* do mode control overrides */
15378c2ecf20Sopenharmony_ci	cx231xx_do_mode_ctrl_overrides(dev);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
15408c2ecf20Sopenharmony_ci	return 0;
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cistatic int vidioc_s_ctrl(struct file *file, void *priv,
15448c2ecf20Sopenharmony_ci				struct v4l2_control *ctl)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
15478c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	dprintk(3, "enter vidioc_s_ctrl()\n");
15508c2ecf20Sopenharmony_ci	/* Update the A/V core */
15518c2ecf20Sopenharmony_ci	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev)
15528c2ecf20Sopenharmony_ci		v4l2_s_ctrl(NULL, sd->ctrl_handler, ctl);
15538c2ecf20Sopenharmony_ci	dprintk(3, "exit vidioc_s_ctrl()\n");
15548c2ecf20Sopenharmony_ci	return 0;
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
15588c2ecf20Sopenharmony_ci					struct v4l2_fmtdesc *f)
15598c2ecf20Sopenharmony_ci{
15608c2ecf20Sopenharmony_ci	if (f->index != 0)
15618c2ecf20Sopenharmony_ci		return -EINVAL;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	f->pixelformat = V4L2_PIX_FMT_MPEG;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	return 0;
15668c2ecf20Sopenharmony_ci}
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
15698c2ecf20Sopenharmony_ci				struct v4l2_format *f)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
15748c2ecf20Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
15758c2ecf20Sopenharmony_ci	f->fmt.pix.bytesperline = 0;
15768c2ecf20Sopenharmony_ci	f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
15778c2ecf20Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
15788c2ecf20Sopenharmony_ci	f->fmt.pix.width = dev->ts1.width;
15798c2ecf20Sopenharmony_ci	f->fmt.pix.height = dev->ts1.height;
15808c2ecf20Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
15818c2ecf20Sopenharmony_ci	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
15828c2ecf20Sopenharmony_ci		dev->ts1.width, dev->ts1.height);
15838c2ecf20Sopenharmony_ci	dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
15848c2ecf20Sopenharmony_ci	return 0;
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
15888c2ecf20Sopenharmony_ci				struct v4l2_format *f)
15898c2ecf20Sopenharmony_ci{
15908c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
15938c2ecf20Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
15948c2ecf20Sopenharmony_ci	f->fmt.pix.bytesperline = 0;
15958c2ecf20Sopenharmony_ci	f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
15968c2ecf20Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
15978c2ecf20Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
15988c2ecf20Sopenharmony_ci	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
15998c2ecf20Sopenharmony_ci		dev->ts1.width, dev->ts1.height);
16008c2ecf20Sopenharmony_ci	dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
16018c2ecf20Sopenharmony_ci	return 0;
16028c2ecf20Sopenharmony_ci}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_cistatic int vidioc_log_status(struct file *file, void *priv)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	call_all(dev, core, log_status);
16098c2ecf20Sopenharmony_ci	return v4l2_ctrl_log_status(file, priv);
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations mpeg_fops = {
16138c2ecf20Sopenharmony_ci	.owner	       = THIS_MODULE,
16148c2ecf20Sopenharmony_ci	.open	       = v4l2_fh_open,
16158c2ecf20Sopenharmony_ci	.release       = vb2_fop_release,
16168c2ecf20Sopenharmony_ci	.read	       = vb2_fop_read,
16178c2ecf20Sopenharmony_ci	.poll          = vb2_fop_poll,
16188c2ecf20Sopenharmony_ci	.mmap	       = vb2_fop_mmap,
16198c2ecf20Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
16208c2ecf20Sopenharmony_ci};
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
16238c2ecf20Sopenharmony_ci	.vidioc_s_std		 = vidioc_s_std,
16248c2ecf20Sopenharmony_ci	.vidioc_g_std		 = vidioc_g_std,
16258c2ecf20Sopenharmony_ci	.vidioc_g_tuner          = cx231xx_g_tuner,
16268c2ecf20Sopenharmony_ci	.vidioc_s_tuner          = cx231xx_s_tuner,
16278c2ecf20Sopenharmony_ci	.vidioc_g_frequency      = cx231xx_g_frequency,
16288c2ecf20Sopenharmony_ci	.vidioc_s_frequency      = cx231xx_s_frequency,
16298c2ecf20Sopenharmony_ci	.vidioc_enum_input	 = cx231xx_enum_input,
16308c2ecf20Sopenharmony_ci	.vidioc_g_input		 = cx231xx_g_input,
16318c2ecf20Sopenharmony_ci	.vidioc_s_input		 = cx231xx_s_input,
16328c2ecf20Sopenharmony_ci	.vidioc_s_ctrl		 = vidioc_s_ctrl,
16338c2ecf20Sopenharmony_ci	.vidioc_g_pixelaspect	 = vidioc_g_pixelaspect,
16348c2ecf20Sopenharmony_ci	.vidioc_g_selection	 = vidioc_g_selection,
16358c2ecf20Sopenharmony_ci	.vidioc_querycap	 = cx231xx_querycap,
16368c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
16378c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
16388c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
16398c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
16408c2ecf20Sopenharmony_ci	.vidioc_reqbufs		 = vb2_ioctl_reqbufs,
16418c2ecf20Sopenharmony_ci	.vidioc_querybuf	 = vb2_ioctl_querybuf,
16428c2ecf20Sopenharmony_ci	.vidioc_qbuf		 = vb2_ioctl_qbuf,
16438c2ecf20Sopenharmony_ci	.vidioc_dqbuf		 = vb2_ioctl_dqbuf,
16448c2ecf20Sopenharmony_ci	.vidioc_streamon	 = vb2_ioctl_streamon,
16458c2ecf20Sopenharmony_ci	.vidioc_streamoff	 = vb2_ioctl_streamoff,
16468c2ecf20Sopenharmony_ci	.vidioc_log_status	 = vidioc_log_status,
16478c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
16488c2ecf20Sopenharmony_ci	.vidioc_g_register	 = cx231xx_g_register,
16498c2ecf20Sopenharmony_ci	.vidioc_s_register	 = cx231xx_s_register,
16508c2ecf20Sopenharmony_ci#endif
16518c2ecf20Sopenharmony_ci	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
16528c2ecf20Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
16538c2ecf20Sopenharmony_ci};
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_cistatic struct video_device cx231xx_mpeg_template = {
16568c2ecf20Sopenharmony_ci	.name          = "cx231xx",
16578c2ecf20Sopenharmony_ci	.fops          = &mpeg_fops,
16588c2ecf20Sopenharmony_ci	.ioctl_ops     = &mpeg_ioctl_ops,
16598c2ecf20Sopenharmony_ci	.minor         = -1,
16608c2ecf20Sopenharmony_ci	.tvnorms       = V4L2_STD_ALL,
16618c2ecf20Sopenharmony_ci};
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_civoid cx231xx_417_unregister(struct cx231xx *dev)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
16668c2ecf20Sopenharmony_ci	dprintk(3, "%s()\n", __func__);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	if (video_is_registered(&dev->v4l_device)) {
16698c2ecf20Sopenharmony_ci		video_unregister_device(&dev->v4l_device);
16708c2ecf20Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci}
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_cistatic int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
16778c2ecf20Sopenharmony_ci	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
16788c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format = {
16798c2ecf20Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
16808c2ecf20Sopenharmony_ci	};
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	/* fix videodecoder resolution */
16838c2ecf20Sopenharmony_ci	format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
16848c2ecf20Sopenharmony_ci	format.format.height = cxhdl->height;
16858c2ecf20Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_FIXED;
16868c2ecf20Sopenharmony_ci	v4l2_subdev_call(dev->sd_cx25840, pad, set_fmt, NULL, &format);
16878c2ecf20Sopenharmony_ci	return 0;
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_cistatic int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	static const u32 freqs[3] = { 44100, 48000, 32000 };
16938c2ecf20Sopenharmony_ci	struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	/* The audio clock of the digitizer must match the codec sample
16968c2ecf20Sopenharmony_ci	   rate otherwise you get some very strange effects. */
16978c2ecf20Sopenharmony_ci	if (idx < ARRAY_SIZE(freqs))
16988c2ecf20Sopenharmony_ci		call_all(dev, audio, s_clock_freq, freqs[idx]);
16998c2ecf20Sopenharmony_ci	return 0;
17008c2ecf20Sopenharmony_ci}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_cistatic const struct cx2341x_handler_ops cx231xx_ops = {
17038c2ecf20Sopenharmony_ci	/* needed for the video clock freq */
17048c2ecf20Sopenharmony_ci	.s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
17058c2ecf20Sopenharmony_ci	/* needed for setting up the video resolution */
17068c2ecf20Sopenharmony_ci	.s_video_encoding = cx231xx_s_video_encoding,
17078c2ecf20Sopenharmony_ci};
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_cistatic void cx231xx_video_dev_init(
17108c2ecf20Sopenharmony_ci	struct cx231xx *dev,
17118c2ecf20Sopenharmony_ci	struct usb_device *usbdev,
17128c2ecf20Sopenharmony_ci	struct video_device *vfd,
17138c2ecf20Sopenharmony_ci	const struct video_device *template,
17148c2ecf20Sopenharmony_ci	const char *type)
17158c2ecf20Sopenharmony_ci{
17168c2ecf20Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
17178c2ecf20Sopenharmony_ci	*vfd = *template;
17188c2ecf20Sopenharmony_ci	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
17198c2ecf20Sopenharmony_ci		type, cx231xx_boards[dev->model].name);
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	vfd->v4l2_dev = &dev->v4l2_dev;
17228c2ecf20Sopenharmony_ci	vfd->lock = &dev->lock;
17238c2ecf20Sopenharmony_ci	vfd->release = video_device_release_empty;
17248c2ecf20Sopenharmony_ci	vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
17258c2ecf20Sopenharmony_ci	video_set_drvdata(vfd, dev);
17268c2ecf20Sopenharmony_ci	if (dev->tuner_type == TUNER_ABSENT) {
17278c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
17288c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
17298c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
17308c2ecf20Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ciint cx231xx_417_register(struct cx231xx *dev)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	/* FIXME: Port1 hardcoded here */
17378c2ecf20Sopenharmony_ci	int err;
17388c2ecf20Sopenharmony_ci	struct cx231xx_tsport *tsport = &dev->ts1;
17398c2ecf20Sopenharmony_ci	struct vb2_queue *q;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	/* Set default TV standard */
17448c2ecf20Sopenharmony_ci	dev->encodernorm = cx231xx_tvnorms[0];
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	if (dev->encodernorm.id & V4L2_STD_525_60)
17478c2ecf20Sopenharmony_ci		tsport->height = 480;
17488c2ecf20Sopenharmony_ci	else
17498c2ecf20Sopenharmony_ci		tsport->height = 576;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	tsport->width = 720;
17528c2ecf20Sopenharmony_ci	err = cx2341x_handler_init(&dev->mpeg_ctrl_handler, 50);
17538c2ecf20Sopenharmony_ci	if (err) {
17548c2ecf20Sopenharmony_ci		dprintk(3, "%s: can't init cx2341x controls\n", dev->name);
17558c2ecf20Sopenharmony_ci		return err;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.func = cx231xx_mbox_func;
17588c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.priv = dev;
17598c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
17608c2ecf20Sopenharmony_ci	if (dev->sd_cx25840)
17618c2ecf20Sopenharmony_ci		v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
17628c2ecf20Sopenharmony_ci				dev->sd_cx25840->ctrl_handler, NULL, false);
17638c2ecf20Sopenharmony_ci	if (dev->mpeg_ctrl_handler.hdl.error) {
17648c2ecf20Sopenharmony_ci		err = dev->mpeg_ctrl_handler.hdl.error;
17658c2ecf20Sopenharmony_ci		dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
17668c2ecf20Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
17678c2ecf20Sopenharmony_ci		return err;
17688c2ecf20Sopenharmony_ci	}
17698c2ecf20Sopenharmony_ci	dev->norm = V4L2_STD_NTSC;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	dev->mpeg_ctrl_handler.port = CX2341X_PORT_SERIAL;
17728c2ecf20Sopenharmony_ci	cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	/* Allocate and initialize V4L video device */
17758c2ecf20Sopenharmony_ci	cx231xx_video_dev_init(dev, dev->udev,
17768c2ecf20Sopenharmony_ci			&dev->v4l_device, &cx231xx_mpeg_template, "mpeg");
17778c2ecf20Sopenharmony_ci	q = &dev->mpegq;
17788c2ecf20Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
17798c2ecf20Sopenharmony_ci	q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
17808c2ecf20Sopenharmony_ci	q->drv_priv = dev;
17818c2ecf20Sopenharmony_ci	q->buf_struct_size = sizeof(struct cx231xx_buffer);
17828c2ecf20Sopenharmony_ci	q->ops = &cx231xx_video_qops;
17838c2ecf20Sopenharmony_ci	q->mem_ops = &vb2_vmalloc_memops;
17848c2ecf20Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
17858c2ecf20Sopenharmony_ci	q->min_buffers_needed = 1;
17868c2ecf20Sopenharmony_ci	q->lock = &dev->lock;
17878c2ecf20Sopenharmony_ci	err = vb2_queue_init(q);
17888c2ecf20Sopenharmony_ci	if (err)
17898c2ecf20Sopenharmony_ci		return err;
17908c2ecf20Sopenharmony_ci	dev->v4l_device.queue = q;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	err = video_register_device(&dev->v4l_device,
17938c2ecf20Sopenharmony_ci		VFL_TYPE_VIDEO, -1);
17948c2ecf20Sopenharmony_ci	if (err < 0) {
17958c2ecf20Sopenharmony_ci		dprintk(3, "%s: can't register mpeg device\n", dev->name);
17968c2ecf20Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
17978c2ecf20Sopenharmony_ci		return err;
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	dprintk(3, "%s: registered device video%d [mpeg]\n",
18018c2ecf20Sopenharmony_ci	       dev->name, dev->v4l_device.num);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	return 0;
18048c2ecf20Sopenharmony_ci}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ciMODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
1807