162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Support for a cx23417 mpeg encoder via cx231xx host port.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *    (c) 2004 Jelle Foks <jelle@foks.us>
762306a36Sopenharmony_ci *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
862306a36Sopenharmony_ci *    (c) 2008 Steven Toth <stoth@linuxtv.org>
962306a36Sopenharmony_ci *      - CX23885/7/8 support
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "cx231xx.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/moduleparam.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/fs.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci#include <linux/device.h>
2262306a36Sopenharmony_ci#include <linux/firmware.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci#include <linux/vmalloc.h>
2562306a36Sopenharmony_ci#include <media/v4l2-common.h>
2662306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
2762306a36Sopenharmony_ci#include <media/v4l2-event.h>
2862306a36Sopenharmony_ci#include <media/drv-intf/cx2341x.h>
2962306a36Sopenharmony_ci#include <media/tuner.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define CX231xx_FIRM_IMAGE_SIZE 376836
3262306a36Sopenharmony_ci#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* for polaris ITVC */
3562306a36Sopenharmony_ci#define ITVC_WRITE_DIR          0x03FDFC00
3662306a36Sopenharmony_ci#define ITVC_READ_DIR            0x0001FC00
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE0          0x00
3962306a36Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE1          0x08
4062306a36Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE2          0x10
4162306a36Sopenharmony_ci#define  MCI_MEMORY_DATA_BYTE3          0x18
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE2       0x20
4462306a36Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE1       0x28
4562306a36Sopenharmony_ci#define  MCI_MEMORY_ADDRESS_BYTE0       0x30
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE0        0x40
4862306a36Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE1        0x48
4962306a36Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE2        0x50
5062306a36Sopenharmony_ci#define  MCI_REGISTER_DATA_BYTE3        0x58
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define  MCI_REGISTER_ADDRESS_BYTE0     0x60
5362306a36Sopenharmony_ci#define  MCI_REGISTER_ADDRESS_BYTE1     0x68
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define  MCI_REGISTER_MODE              0x70
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Read and write modes for polaris ITVC */
5862306a36Sopenharmony_ci#define  MCI_MODE_REGISTER_READ         0x000
5962306a36Sopenharmony_ci#define  MCI_MODE_REGISTER_WRITE        0x100
6062306a36Sopenharmony_ci#define  MCI_MODE_MEMORY_READ           0x000
6162306a36Sopenharmony_ci#define  MCI_MODE_MEMORY_WRITE          0x4000
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic unsigned int mpeglines = 128;
6462306a36Sopenharmony_cimodule_param(mpeglines, int, 0644);
6562306a36Sopenharmony_ciMODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic unsigned int mpeglinesize = 512;
6862306a36Sopenharmony_cimodule_param(mpeglinesize, int, 0644);
6962306a36Sopenharmony_ciMODULE_PARM_DESC(mpeglinesize,
7062306a36Sopenharmony_ci	"number of bytes in each line of an MPEG buffer, range 512-1024");
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic unsigned int v4l_debug = 1;
7362306a36Sopenharmony_cimodule_param(v4l_debug, int, 0644);
7462306a36Sopenharmony_ciMODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define dprintk(level, fmt, arg...)	\
7762306a36Sopenharmony_ci	do {				\
7862306a36Sopenharmony_ci		if (v4l_debug >= level) \
7962306a36Sopenharmony_ci			printk(KERN_DEBUG pr_fmt(fmt), ## arg); \
8062306a36Sopenharmony_ci	} while (0)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic struct cx231xx_tvnorm cx231xx_tvnorms[] = {
8362306a36Sopenharmony_ci	{
8462306a36Sopenharmony_ci		.name      = "NTSC-M",
8562306a36Sopenharmony_ci		.id        = V4L2_STD_NTSC_M,
8662306a36Sopenharmony_ci	}, {
8762306a36Sopenharmony_ci		.name      = "NTSC-JP",
8862306a36Sopenharmony_ci		.id        = V4L2_STD_NTSC_M_JP,
8962306a36Sopenharmony_ci	}, {
9062306a36Sopenharmony_ci		.name      = "PAL-BG",
9162306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_BG,
9262306a36Sopenharmony_ci	}, {
9362306a36Sopenharmony_ci		.name      = "PAL-DK",
9462306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_DK,
9562306a36Sopenharmony_ci	}, {
9662306a36Sopenharmony_ci		.name      = "PAL-I",
9762306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_I,
9862306a36Sopenharmony_ci	}, {
9962306a36Sopenharmony_ci		.name      = "PAL-M",
10062306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_M,
10162306a36Sopenharmony_ci	}, {
10262306a36Sopenharmony_ci		.name      = "PAL-N",
10362306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_N,
10462306a36Sopenharmony_ci	}, {
10562306a36Sopenharmony_ci		.name      = "PAL-Nc",
10662306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_Nc,
10762306a36Sopenharmony_ci	}, {
10862306a36Sopenharmony_ci		.name      = "PAL-60",
10962306a36Sopenharmony_ci		.id        = V4L2_STD_PAL_60,
11062306a36Sopenharmony_ci	}, {
11162306a36Sopenharmony_ci		.name      = "SECAM-L",
11262306a36Sopenharmony_ci		.id        = V4L2_STD_SECAM_L,
11362306a36Sopenharmony_ci	}, {
11462306a36Sopenharmony_ci		.name      = "SECAM-DK",
11562306a36Sopenharmony_ci		.id        = V4L2_STD_SECAM_DK,
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cienum cx231xx_capture_type {
12262306a36Sopenharmony_ci	CX231xx_MPEG_CAPTURE,
12362306a36Sopenharmony_ci	CX231xx_RAW_CAPTURE,
12462306a36Sopenharmony_ci	CX231xx_RAW_PASSTHRU_CAPTURE
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cienum cx231xx_capture_bits {
12862306a36Sopenharmony_ci	CX231xx_RAW_BITS_NONE             = 0x00,
12962306a36Sopenharmony_ci	CX231xx_RAW_BITS_YUV_CAPTURE      = 0x01,
13062306a36Sopenharmony_ci	CX231xx_RAW_BITS_PCM_CAPTURE      = 0x02,
13162306a36Sopenharmony_ci	CX231xx_RAW_BITS_VBI_CAPTURE      = 0x04,
13262306a36Sopenharmony_ci	CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
13362306a36Sopenharmony_ci	CX231xx_RAW_BITS_TO_HOST_CAPTURE  = 0x10
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cienum cx231xx_capture_end {
13762306a36Sopenharmony_ci	CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
13862306a36Sopenharmony_ci	CX231xx_END_NOW, /* stop immediately, no irq */
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cienum cx231xx_framerate {
14262306a36Sopenharmony_ci	CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
14362306a36Sopenharmony_ci	CX231xx_FRAMERATE_PAL_25   /* PAL: 25fps */
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cienum cx231xx_stream_port {
14762306a36Sopenharmony_ci	CX231xx_OUTPUT_PORT_MEMORY,
14862306a36Sopenharmony_ci	CX231xx_OUTPUT_PORT_STREAMING,
14962306a36Sopenharmony_ci	CX231xx_OUTPUT_PORT_SERIAL
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cienum cx231xx_data_xfer_status {
15362306a36Sopenharmony_ci	CX231xx_MORE_BUFFERS_FOLLOW,
15462306a36Sopenharmony_ci	CX231xx_LAST_BUFFER,
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cienum cx231xx_picture_mask {
15862306a36Sopenharmony_ci	CX231xx_PICTURE_MASK_NONE,
15962306a36Sopenharmony_ci	CX231xx_PICTURE_MASK_I_FRAMES,
16062306a36Sopenharmony_ci	CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
16162306a36Sopenharmony_ci	CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cienum cx231xx_vbi_mode_bits {
16562306a36Sopenharmony_ci	CX231xx_VBI_BITS_SLICED,
16662306a36Sopenharmony_ci	CX231xx_VBI_BITS_RAW,
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cienum cx231xx_vbi_insertion_bits {
17062306a36Sopenharmony_ci	CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
17162306a36Sopenharmony_ci	CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
17262306a36Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
17362306a36Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
17462306a36Sopenharmony_ci	CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cienum cx231xx_dma_unit {
17862306a36Sopenharmony_ci	CX231xx_DMA_BYTES,
17962306a36Sopenharmony_ci	CX231xx_DMA_FRAMES,
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cienum cx231xx_dma_transfer_status_bits {
18362306a36Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
18462306a36Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
18562306a36Sopenharmony_ci	CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cienum cx231xx_pause {
18962306a36Sopenharmony_ci	CX231xx_PAUSE_ENCODING,
19062306a36Sopenharmony_ci	CX231xx_RESUME_ENCODING,
19162306a36Sopenharmony_ci};
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cienum cx231xx_copyright {
19462306a36Sopenharmony_ci	CX231xx_COPYRIGHT_OFF,
19562306a36Sopenharmony_ci	CX231xx_COPYRIGHT_ON,
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cienum cx231xx_notification_type {
19962306a36Sopenharmony_ci	CX231xx_NOTIFICATION_REFRESH,
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cienum cx231xx_notification_status {
20362306a36Sopenharmony_ci	CX231xx_NOTIFICATION_OFF,
20462306a36Sopenharmony_ci	CX231xx_NOTIFICATION_ON,
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cienum cx231xx_notification_mailbox {
20862306a36Sopenharmony_ci	CX231xx_NOTIFICATION_NO_MAILBOX = -1,
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cienum cx231xx_field1_lines {
21262306a36Sopenharmony_ci	CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
21362306a36Sopenharmony_ci	CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
21462306a36Sopenharmony_ci	CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cienum cx231xx_field2_lines {
21862306a36Sopenharmony_ci	CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
21962306a36Sopenharmony_ci	CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
22062306a36Sopenharmony_ci	CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cienum cx231xx_custom_data_type {
22462306a36Sopenharmony_ci	CX231xx_CUSTOM_EXTENSION_USR_DATA,
22562306a36Sopenharmony_ci	CX231xx_CUSTOM_PRIVATE_PACKET,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cienum cx231xx_mute {
22962306a36Sopenharmony_ci	CX231xx_UNMUTE,
23062306a36Sopenharmony_ci	CX231xx_MUTE,
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cienum cx231xx_mute_video_mask {
23462306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
23562306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
23662306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cienum cx231xx_mute_video_shift {
24062306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_V_SHIFT = 8,
24162306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_U_SHIFT = 16,
24262306a36Sopenharmony_ci	CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/* defines below are from ivtv-driver.h */
24662306a36Sopenharmony_ci#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/* Firmware API commands */
24962306a36Sopenharmony_ci#define IVTV_API_STD_TIMEOUT 500
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/* Registers */
25262306a36Sopenharmony_ci/* IVTV_REG_OFFSET */
25362306a36Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
25462306a36Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
25562306a36Sopenharmony_ci#define IVTV_REG_SPU (0x9050)
25662306a36Sopenharmony_ci#define IVTV_REG_HW_BLOCKS (0x9054)
25762306a36Sopenharmony_ci#define IVTV_REG_VPU (0x9058)
25862306a36Sopenharmony_ci#define IVTV_REG_APU (0xA064)
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/*
26162306a36Sopenharmony_ci * Bit definitions for MC417_RWD and MC417_OEN registers
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * bits 31-16
26462306a36Sopenharmony_ci *+-----------+
26562306a36Sopenharmony_ci *| Reserved  |
26662306a36Sopenharmony_ci *|+-----------+
26762306a36Sopenharmony_ci *|  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
26862306a36Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
26962306a36Sopenharmony_ci *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
27062306a36Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
27162306a36Sopenharmony_ci *| bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
27262306a36Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
27362306a36Sopenharmony_ci *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
27462306a36Sopenharmony_ci *|+-------+-------+-------+-------+-------+-------+-------+-------+
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_ci#define MC417_MIWR	0x8000
27762306a36Sopenharmony_ci#define MC417_MIRD	0x4000
27862306a36Sopenharmony_ci#define MC417_MICS	0x2000
27962306a36Sopenharmony_ci#define MC417_MIRDY	0x1000
28062306a36Sopenharmony_ci#define MC417_MIADDR	0x0F00
28162306a36Sopenharmony_ci#define MC417_MIDATA	0x00FF
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* Bit definitions for MC417_CTL register ****
28562306a36Sopenharmony_ci *bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
28662306a36Sopenharmony_ci *+--------+-------------+--------+--------------+------------+
28762306a36Sopenharmony_ci *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
28862306a36Sopenharmony_ci *+--------+-------------+--------+--------------+------------+
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_ci#define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
29162306a36Sopenharmony_ci#define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
29262306a36Sopenharmony_ci#define MC417_UART_GPIO_EN	0x00000001
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/* Values for speed control */
29562306a36Sopenharmony_ci#define MC417_SPD_CTL_SLOW	0x1
29662306a36Sopenharmony_ci#define MC417_SPD_CTL_MEDIUM	0x0
29762306a36Sopenharmony_ci#define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/* Values for GPIO select */
30062306a36Sopenharmony_ci#define MC417_GPIO_SEL_GPIO3	0x3
30162306a36Sopenharmony_ci#define MC417_GPIO_SEL_GPIO2	0x2
30262306a36Sopenharmony_ci#define MC417_GPIO_SEL_GPIO1	0x1
30362306a36Sopenharmony_ci#define MC417_GPIO_SEL_GPIO0	0x0
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci#define CX23417_GPIO_MASK 0xFC0003FF
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int set_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 value)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	int status = 0;
31162306a36Sopenharmony_ci	u32 _gpio_direction = 0;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
31462306a36Sopenharmony_ci	_gpio_direction = _gpio_direction | gpio_direction;
31562306a36Sopenharmony_ci	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
31662306a36Sopenharmony_ci			 (u8 *)&value, 4, 0, 0);
31762306a36Sopenharmony_ci	return status;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int get_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 *val_ptr)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	int status = 0;
32362306a36Sopenharmony_ci	u32 _gpio_direction = 0;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
32662306a36Sopenharmony_ci	_gpio_direction = _gpio_direction | gpio_direction;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
32962306a36Sopenharmony_ci		 (u8 *)val_ptr, 4, 0, 1);
33062306a36Sopenharmony_ci	return status;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int wait_for_mci_complete(struct cx231xx *dev)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	u32 gpio;
33662306a36Sopenharmony_ci	u32 gpio_direction = 0;
33762306a36Sopenharmony_ci	u8 count = 0;
33862306a36Sopenharmony_ci	get_itvc_reg(dev, gpio_direction, &gpio);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	while (!(gpio&0x020000)) {
34162306a36Sopenharmony_ci		msleep(10);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		get_itvc_reg(dev, gpio_direction, &gpio);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		if (count++ > 100) {
34662306a36Sopenharmony_ci			dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
34762306a36Sopenharmony_ci			return -EIO;
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	u32 temp;
35662306a36Sopenharmony_ci	int status = 0;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE0 | ((value & 0x000000FF) << 8);
35962306a36Sopenharmony_ci	temp = temp << 10;
36062306a36Sopenharmony_ci	status = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
36162306a36Sopenharmony_ci	if (status < 0)
36262306a36Sopenharmony_ci		return status;
36362306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
36462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*write data byte 1;*/
36762306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE1 | (value & 0x0000FF00);
36862306a36Sopenharmony_ci	temp = temp << 10;
36962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
37062306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
37162306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/*write data byte 2;*/
37462306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
37562306a36Sopenharmony_ci	temp = temp << 10;
37662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
37762306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
37862306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/*write data byte 3;*/
38162306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
38262306a36Sopenharmony_ci	temp = temp << 10;
38362306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
38462306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
38562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/*write address byte 0;*/
38862306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x000000FF) << 8);
38962306a36Sopenharmony_ci	temp = temp << 10;
39062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
39162306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
39262306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*write address byte 1;*/
39562306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0x0000FF00);
39662306a36Sopenharmony_ci	temp = temp << 10;
39762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
39862306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
39962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/*Write that the mode is write.*/
40262306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
40362306a36Sopenharmony_ci	temp = temp << 10;
40462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
40562306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
40662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return wait_for_mci_complete(dev);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	/*write address byte 0;*/
41462306a36Sopenharmony_ci	u32 temp;
41562306a36Sopenharmony_ci	u32 return_value = 0;
41662306a36Sopenharmony_ci	int ret = 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
41962306a36Sopenharmony_ci	temp = temp << 10;
42062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
42162306a36Sopenharmony_ci	temp = temp | ((0x05) << 10);
42262306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/*write address byte 1;*/
42562306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
42662306a36Sopenharmony_ci	temp = temp << 10;
42762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
42862306a36Sopenharmony_ci	temp = temp | ((0x05) << 10);
42962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*write that the mode is read;*/
43262306a36Sopenharmony_ci	temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
43362306a36Sopenharmony_ci	temp = temp << 10;
43462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
43562306a36Sopenharmony_ci	temp = temp | ((0x05) << 10);
43662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/*wait for the MIRDY line to be asserted ,
43962306a36Sopenharmony_ci	signalling that the read is done;*/
44062306a36Sopenharmony_ci	ret = wait_for_mci_complete(dev);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/*switch the DATA- GPIO to input mode;*/
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/*Read data byte 0;*/
44562306a36Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
44662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
44762306a36Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
44862306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
44962306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
45062306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 18);
45162306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* Read data byte 1;*/
45462306a36Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
45562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
45662306a36Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
45762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
45862306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 10);
46162306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/*Read data byte 2;*/
46462306a36Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
46562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
46662306a36Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
46762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
46862306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
46962306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 2);
47062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/*Read data byte 3;*/
47362306a36Sopenharmony_ci	temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
47462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
47562306a36Sopenharmony_ci	temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
47662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
47762306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
47862306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) << 6);
47962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	*value  = return_value;
48262306a36Sopenharmony_ci	return ret;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	/*write data byte 0;*/
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	u32 temp;
49062306a36Sopenharmony_ci	int ret = 0;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
49362306a36Sopenharmony_ci	temp = temp << 10;
49462306a36Sopenharmony_ci	ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
49562306a36Sopenharmony_ci	if (ret < 0)
49662306a36Sopenharmony_ci		return ret;
49762306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
49862306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/*write data byte 1;*/
50162306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
50262306a36Sopenharmony_ci	temp = temp << 10;
50362306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
50462306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
50562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*write data byte 2;*/
50862306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
50962306a36Sopenharmony_ci	temp = temp << 10;
51062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
51162306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
51262306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/*write data byte 3;*/
51562306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
51662306a36Sopenharmony_ci	temp = temp << 10;
51762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
51862306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
51962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* write address byte 2;*/
52262306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
52362306a36Sopenharmony_ci		((address & 0x003F0000) >> 8);
52462306a36Sopenharmony_ci	temp = temp << 10;
52562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
52662306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
52762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* write address byte 1;*/
53062306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
53162306a36Sopenharmony_ci	temp = temp << 10;
53262306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
53362306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
53462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* write address byte 0;*/
53762306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
53862306a36Sopenharmony_ci	temp = temp << 10;
53962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
54062306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
54162306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/*wait for MIRDY line;*/
54462306a36Sopenharmony_ci	wait_for_mci_complete(dev);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	u32 temp = 0;
55262306a36Sopenharmony_ci	u32 return_value = 0;
55362306a36Sopenharmony_ci	int ret = 0;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/*write address byte 2;*/
55662306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
55762306a36Sopenharmony_ci		((address & 0x003F0000) >> 8);
55862306a36Sopenharmony_ci	temp = temp << 10;
55962306a36Sopenharmony_ci	ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
56062306a36Sopenharmony_ci	if (ret < 0)
56162306a36Sopenharmony_ci		return ret;
56262306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
56362306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/*write address byte 1*/
56662306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
56762306a36Sopenharmony_ci	temp = temp << 10;
56862306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
56962306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
57062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/*write address byte 0*/
57362306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
57462306a36Sopenharmony_ci	temp = temp << 10;
57562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
57662306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
57762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/*Wait for MIRDY line*/
58062306a36Sopenharmony_ci	ret = wait_for_mci_complete(dev);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/*Read data byte 3;*/
58462306a36Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE3) << 10;
58562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
58662306a36Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE3) << 10);
58762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
58862306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
58962306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) << 6);
59062306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/*Read data byte 2;*/
59362306a36Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE2) << 10;
59462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
59562306a36Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE2) << 10);
59662306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
59762306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
59862306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 2);
59962306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Read data byte 1;*/
60262306a36Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE1) << 10;
60362306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
60462306a36Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE1) << 10);
60562306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
60662306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
60762306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 10);
60862306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/*Read data byte 0;*/
61162306a36Sopenharmony_ci	temp = (0x82 | MCI_MEMORY_DATA_BYTE0) << 10;
61262306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
61362306a36Sopenharmony_ci	temp = ((0x81 | MCI_MEMORY_DATA_BYTE0) << 10);
61462306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, temp);
61562306a36Sopenharmony_ci	get_itvc_reg(dev, ITVC_READ_DIR, &temp);
61662306a36Sopenharmony_ci	return_value |= ((temp & 0x03FC0000) >> 18);
61762306a36Sopenharmony_ci	set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	*value  = return_value;
62062306a36Sopenharmony_ci	return ret;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/* MPEG encoder API */
62662306a36Sopenharmony_cistatic char *cmd_to_str(int cmd)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	switch (cmd) {
62962306a36Sopenharmony_ci	case CX2341X_ENC_PING_FW:
63062306a36Sopenharmony_ci		return "PING_FW";
63162306a36Sopenharmony_ci	case CX2341X_ENC_START_CAPTURE:
63262306a36Sopenharmony_ci		return "START_CAPTURE";
63362306a36Sopenharmony_ci	case CX2341X_ENC_STOP_CAPTURE:
63462306a36Sopenharmony_ci		return "STOP_CAPTURE";
63562306a36Sopenharmony_ci	case CX2341X_ENC_SET_AUDIO_ID:
63662306a36Sopenharmony_ci		return "SET_AUDIO_ID";
63762306a36Sopenharmony_ci	case CX2341X_ENC_SET_VIDEO_ID:
63862306a36Sopenharmony_ci		return "SET_VIDEO_ID";
63962306a36Sopenharmony_ci	case CX2341X_ENC_SET_PCR_ID:
64062306a36Sopenharmony_ci		return "SET_PCR_PID";
64162306a36Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_RATE:
64262306a36Sopenharmony_ci		return "SET_FRAME_RATE";
64362306a36Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_SIZE:
64462306a36Sopenharmony_ci		return "SET_FRAME_SIZE";
64562306a36Sopenharmony_ci	case CX2341X_ENC_SET_BIT_RATE:
64662306a36Sopenharmony_ci		return "SET_BIT_RATE";
64762306a36Sopenharmony_ci	case CX2341X_ENC_SET_GOP_PROPERTIES:
64862306a36Sopenharmony_ci		return "SET_GOP_PROPERTIES";
64962306a36Sopenharmony_ci	case CX2341X_ENC_SET_ASPECT_RATIO:
65062306a36Sopenharmony_ci		return "SET_ASPECT_RATIO";
65162306a36Sopenharmony_ci	case CX2341X_ENC_SET_DNR_FILTER_MODE:
65262306a36Sopenharmony_ci		return "SET_DNR_FILTER_PROPS";
65362306a36Sopenharmony_ci	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
65462306a36Sopenharmony_ci		return "SET_DNR_FILTER_PROPS";
65562306a36Sopenharmony_ci	case CX2341X_ENC_SET_CORING_LEVELS:
65662306a36Sopenharmony_ci		return "SET_CORING_LEVELS";
65762306a36Sopenharmony_ci	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
65862306a36Sopenharmony_ci		return "SET_SPATIAL_FILTER_TYPE";
65962306a36Sopenharmony_ci	case CX2341X_ENC_SET_VBI_LINE:
66062306a36Sopenharmony_ci		return "SET_VBI_LINE";
66162306a36Sopenharmony_ci	case CX2341X_ENC_SET_STREAM_TYPE:
66262306a36Sopenharmony_ci		return "SET_STREAM_TYPE";
66362306a36Sopenharmony_ci	case CX2341X_ENC_SET_OUTPUT_PORT:
66462306a36Sopenharmony_ci		return "SET_OUTPUT_PORT";
66562306a36Sopenharmony_ci	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
66662306a36Sopenharmony_ci		return "SET_AUDIO_PROPERTIES";
66762306a36Sopenharmony_ci	case CX2341X_ENC_HALT_FW:
66862306a36Sopenharmony_ci		return "HALT_FW";
66962306a36Sopenharmony_ci	case CX2341X_ENC_GET_VERSION:
67062306a36Sopenharmony_ci		return "GET_VERSION";
67162306a36Sopenharmony_ci	case CX2341X_ENC_SET_GOP_CLOSURE:
67262306a36Sopenharmony_ci		return "SET_GOP_CLOSURE";
67362306a36Sopenharmony_ci	case CX2341X_ENC_GET_SEQ_END:
67462306a36Sopenharmony_ci		return "GET_SEQ_END";
67562306a36Sopenharmony_ci	case CX2341X_ENC_SET_PGM_INDEX_INFO:
67662306a36Sopenharmony_ci		return "SET_PGM_INDEX_INFO";
67762306a36Sopenharmony_ci	case CX2341X_ENC_SET_VBI_CONFIG:
67862306a36Sopenharmony_ci		return "SET_VBI_CONFIG";
67962306a36Sopenharmony_ci	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
68062306a36Sopenharmony_ci		return "SET_DMA_BLOCK_SIZE";
68162306a36Sopenharmony_ci	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
68262306a36Sopenharmony_ci		return "GET_PREV_DMA_INFO_MB_10";
68362306a36Sopenharmony_ci	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
68462306a36Sopenharmony_ci		return "GET_PREV_DMA_INFO_MB_9";
68562306a36Sopenharmony_ci	case CX2341X_ENC_SCHED_DMA_TO_HOST:
68662306a36Sopenharmony_ci		return "SCHED_DMA_TO_HOST";
68762306a36Sopenharmony_ci	case CX2341X_ENC_INITIALIZE_INPUT:
68862306a36Sopenharmony_ci		return "INITIALIZE_INPUT";
68962306a36Sopenharmony_ci	case CX2341X_ENC_SET_FRAME_DROP_RATE:
69062306a36Sopenharmony_ci		return "SET_FRAME_DROP_RATE";
69162306a36Sopenharmony_ci	case CX2341X_ENC_PAUSE_ENCODER:
69262306a36Sopenharmony_ci		return "PAUSE_ENCODER";
69362306a36Sopenharmony_ci	case CX2341X_ENC_REFRESH_INPUT:
69462306a36Sopenharmony_ci		return "REFRESH_INPUT";
69562306a36Sopenharmony_ci	case CX2341X_ENC_SET_COPYRIGHT:
69662306a36Sopenharmony_ci		return "SET_COPYRIGHT";
69762306a36Sopenharmony_ci	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
69862306a36Sopenharmony_ci		return "SET_EVENT_NOTIFICATION";
69962306a36Sopenharmony_ci	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
70062306a36Sopenharmony_ci		return "SET_NUM_VSYNC_LINES";
70162306a36Sopenharmony_ci	case CX2341X_ENC_SET_PLACEHOLDER:
70262306a36Sopenharmony_ci		return "SET_PLACEHOLDER";
70362306a36Sopenharmony_ci	case CX2341X_ENC_MUTE_VIDEO:
70462306a36Sopenharmony_ci		return "MUTE_VIDEO";
70562306a36Sopenharmony_ci	case CX2341X_ENC_MUTE_AUDIO:
70662306a36Sopenharmony_ci		return "MUTE_AUDIO";
70762306a36Sopenharmony_ci	case CX2341X_ENC_MISC:
70862306a36Sopenharmony_ci		return "MISC";
70962306a36Sopenharmony_ci	default:
71062306a36Sopenharmony_ci		return "UNKNOWN";
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic int cx231xx_mbox_func(void *priv, u32 command, int in, int out,
71562306a36Sopenharmony_ci			     u32 data[CX2341X_MBOX_MAX_DATA])
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	struct cx231xx *dev = priv;
71862306a36Sopenharmony_ci	unsigned long timeout;
71962306a36Sopenharmony_ci	u32 value, flag, retval = 0;
72062306a36Sopenharmony_ci	int i;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
72362306a36Sopenharmony_ci		cmd_to_str(command));
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* this may not be 100% safe if we can't read any memory location
72662306a36Sopenharmony_ci	   without side effects */
72762306a36Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
72862306a36Sopenharmony_ci	if (value != 0x12345678) {
72962306a36Sopenharmony_ci		dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
73062306a36Sopenharmony_ci			value, cmd_to_str(command));
73162306a36Sopenharmony_ci		return -EIO;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* This read looks at 32 bits, but flag is only 8 bits.
73562306a36Sopenharmony_ci	 * Seems we also bail if CMD or TIMEOUT bytes are set???
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
73862306a36Sopenharmony_ci	if (flag) {
73962306a36Sopenharmony_ci		dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
74062306a36Sopenharmony_ci				flag, cmd_to_str(command));
74162306a36Sopenharmony_ci		return -EBUSY;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	flag |= 1; /* tell 'em we're working on it */
74562306a36Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* write command + args + fill remaining with zeros */
74862306a36Sopenharmony_ci	/* command code */
74962306a36Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
75062306a36Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
75162306a36Sopenharmony_ci		IVTV_API_STD_TIMEOUT); /* timeout */
75262306a36Sopenharmony_ci	for (i = 0; i < in; i++) {
75362306a36Sopenharmony_ci		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
75462306a36Sopenharmony_ci		dprintk(3, "API Input %d = %d\n", i, data[i]);
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	for (; i < CX2341X_MBOX_MAX_DATA; i++)
75762306a36Sopenharmony_ci		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	flag |= 3; /* tell 'em we're done writing */
76062306a36Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* wait for firmware to handle the API command */
76362306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(10);
76462306a36Sopenharmony_ci	for (;;) {
76562306a36Sopenharmony_ci		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
76662306a36Sopenharmony_ci		if (0 != (flag & 4))
76762306a36Sopenharmony_ci			break;
76862306a36Sopenharmony_ci		if (time_after(jiffies, timeout)) {
76962306a36Sopenharmony_ci			dprintk(3, "ERROR: API Mailbox timeout\n");
77062306a36Sopenharmony_ci			return -EIO;
77162306a36Sopenharmony_ci		}
77262306a36Sopenharmony_ci		udelay(10);
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* read output values */
77662306a36Sopenharmony_ci	for (i = 0; i < out; i++) {
77762306a36Sopenharmony_ci		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
77862306a36Sopenharmony_ci		dprintk(3, "API Output %d = %d\n", i, data[i]);
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
78262306a36Sopenharmony_ci	dprintk(3, "API result = %d\n", retval);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	flag = 0;
78562306a36Sopenharmony_ci	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	return 0;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci/* We don't need to call the API often, so using just one
79162306a36Sopenharmony_ci * mailbox will probably suffice
79262306a36Sopenharmony_ci */
79362306a36Sopenharmony_cistatic int cx231xx_api_cmd(struct cx231xx *dev, u32 command,
79462306a36Sopenharmony_ci		u32 inputcnt, u32 outputcnt, ...)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	u32 data[CX2341X_MBOX_MAX_DATA];
79762306a36Sopenharmony_ci	va_list vargs;
79862306a36Sopenharmony_ci	int i, err;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	va_start(vargs, outputcnt);
80362306a36Sopenharmony_ci	for (i = 0; i < inputcnt; i++)
80462306a36Sopenharmony_ci		data[i] = va_arg(vargs, int);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
80762306a36Sopenharmony_ci	for (i = 0; i < outputcnt; i++) {
80862306a36Sopenharmony_ci		int *vptr = va_arg(vargs, int *);
80962306a36Sopenharmony_ci		*vptr = data[i];
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci	va_end(vargs);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return err;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int cx231xx_find_mailbox(struct cx231xx *dev)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	u32 signature[4] = {
82062306a36Sopenharmony_ci		0x12345678, 0x34567812, 0x56781234, 0x78123456
82162306a36Sopenharmony_ci	};
82262306a36Sopenharmony_ci	int signaturecnt = 0;
82362306a36Sopenharmony_ci	u32 value;
82462306a36Sopenharmony_ci	int i;
82562306a36Sopenharmony_ci	int ret = 0;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	dprintk(2, "%s()\n", __func__);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
83062306a36Sopenharmony_ci		ret = mc417_memory_read(dev, i, &value);
83162306a36Sopenharmony_ci		if (ret < 0)
83262306a36Sopenharmony_ci			return ret;
83362306a36Sopenharmony_ci		if (value == signature[signaturecnt])
83462306a36Sopenharmony_ci			signaturecnt++;
83562306a36Sopenharmony_ci		else
83662306a36Sopenharmony_ci			signaturecnt = 0;
83762306a36Sopenharmony_ci		if (4 == signaturecnt) {
83862306a36Sopenharmony_ci			dprintk(1, "Mailbox signature found at 0x%x\n", i + 1);
83962306a36Sopenharmony_ci			return i + 1;
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	dprintk(3, "Mailbox signature values not found!\n");
84362306a36Sopenharmony_ci	return -EIO;
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value,
84762306a36Sopenharmony_ci		u32 *p_fw_image)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u32 temp = 0;
85062306a36Sopenharmony_ci	int i = 0;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
85362306a36Sopenharmony_ci	temp = temp << 10;
85462306a36Sopenharmony_ci	*p_fw_image = temp;
85562306a36Sopenharmony_ci	p_fw_image++;
85662306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
85762306a36Sopenharmony_ci	*p_fw_image = temp;
85862306a36Sopenharmony_ci	p_fw_image++;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/*write data byte 1;*/
86162306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
86262306a36Sopenharmony_ci	temp = temp << 10;
86362306a36Sopenharmony_ci	*p_fw_image = temp;
86462306a36Sopenharmony_ci	p_fw_image++;
86562306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
86662306a36Sopenharmony_ci	*p_fw_image = temp;
86762306a36Sopenharmony_ci	p_fw_image++;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	/*write data byte 2;*/
87062306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
87162306a36Sopenharmony_ci	temp = temp << 10;
87262306a36Sopenharmony_ci	*p_fw_image = temp;
87362306a36Sopenharmony_ci	p_fw_image++;
87462306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
87562306a36Sopenharmony_ci	*p_fw_image = temp;
87662306a36Sopenharmony_ci	p_fw_image++;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/*write data byte 3;*/
87962306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
88062306a36Sopenharmony_ci	temp = temp << 10;
88162306a36Sopenharmony_ci	*p_fw_image = temp;
88262306a36Sopenharmony_ci	p_fw_image++;
88362306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
88462306a36Sopenharmony_ci	*p_fw_image = temp;
88562306a36Sopenharmony_ci	p_fw_image++;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* write address byte 2;*/
88862306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
88962306a36Sopenharmony_ci		((address & 0x003F0000) >> 8);
89062306a36Sopenharmony_ci	temp = temp << 10;
89162306a36Sopenharmony_ci	*p_fw_image = temp;
89262306a36Sopenharmony_ci	p_fw_image++;
89362306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
89462306a36Sopenharmony_ci	*p_fw_image = temp;
89562306a36Sopenharmony_ci	p_fw_image++;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* write address byte 1;*/
89862306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
89962306a36Sopenharmony_ci	temp = temp << 10;
90062306a36Sopenharmony_ci	*p_fw_image = temp;
90162306a36Sopenharmony_ci	p_fw_image++;
90262306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
90362306a36Sopenharmony_ci	*p_fw_image = temp;
90462306a36Sopenharmony_ci	p_fw_image++;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	/* write address byte 0;*/
90762306a36Sopenharmony_ci	temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
90862306a36Sopenharmony_ci	temp = temp << 10;
90962306a36Sopenharmony_ci	*p_fw_image = temp;
91062306a36Sopenharmony_ci	p_fw_image++;
91162306a36Sopenharmony_ci	temp = temp | (0x05 << 10);
91262306a36Sopenharmony_ci	*p_fw_image = temp;
91362306a36Sopenharmony_ci	p_fw_image++;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
91662306a36Sopenharmony_ci		*p_fw_image = 0xFFFFFFFF;
91762306a36Sopenharmony_ci		p_fw_image++;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic int cx231xx_load_firmware(struct cx231xx *dev)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	static const unsigned char magic[8] = {
92562306a36Sopenharmony_ci		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
92662306a36Sopenharmony_ci	};
92762306a36Sopenharmony_ci	const struct firmware *firmware;
92862306a36Sopenharmony_ci	int i, retval = 0;
92962306a36Sopenharmony_ci	u32 value = 0;
93062306a36Sopenharmony_ci	u32 gpio_output = 0;
93162306a36Sopenharmony_ci	/*u32 checksum = 0;*/
93262306a36Sopenharmony_ci	/*u32 *dataptr;*/
93362306a36Sopenharmony_ci	u32 transfer_size = 0;
93462306a36Sopenharmony_ci	u32 fw_data = 0;
93562306a36Sopenharmony_ci	u32 address = 0;
93662306a36Sopenharmony_ci	/*u32 current_fw[800];*/
93762306a36Sopenharmony_ci	u32 *p_current_fw, *p_fw;
93862306a36Sopenharmony_ci	u32 *p_fw_data;
93962306a36Sopenharmony_ci	int frame = 0;
94062306a36Sopenharmony_ci	u16 _buffer_size = 4096;
94162306a36Sopenharmony_ci	u8 *p_buffer;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	p_current_fw = vmalloc(1884180 * 4);
94462306a36Sopenharmony_ci	p_fw = p_current_fw;
94562306a36Sopenharmony_ci	if (p_current_fw == NULL) {
94662306a36Sopenharmony_ci		dprintk(2, "FAIL!!!\n");
94762306a36Sopenharmony_ci		return -ENOMEM;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	p_buffer = vmalloc(4096);
95162306a36Sopenharmony_ci	if (p_buffer == NULL) {
95262306a36Sopenharmony_ci		dprintk(2, "FAIL!!!\n");
95362306a36Sopenharmony_ci		vfree(p_current_fw);
95462306a36Sopenharmony_ci		return -ENOMEM;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	dprintk(2, "%s()\n", __func__);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* Save GPIO settings before reset of APU */
96062306a36Sopenharmony_ci	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
96162306a36Sopenharmony_ci	retval |= mc417_memory_read(dev, 0x900C, &value);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	retval  = mc417_register_write(dev,
96462306a36Sopenharmony_ci		IVTV_REG_VPU, 0xFFFFFFED);
96562306a36Sopenharmony_ci	retval |= mc417_register_write(dev,
96662306a36Sopenharmony_ci		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
96762306a36Sopenharmony_ci	retval |= mc417_register_write(dev,
96862306a36Sopenharmony_ci		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
96962306a36Sopenharmony_ci	retval |= mc417_register_write(dev,
97062306a36Sopenharmony_ci		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
97162306a36Sopenharmony_ci	retval |= mc417_register_write(dev,
97262306a36Sopenharmony_ci		IVTV_REG_APU, 0);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (retval != 0) {
97562306a36Sopenharmony_ci		dev_err(dev->dev,
97662306a36Sopenharmony_ci			"%s: Error with mc417_register_write\n", __func__);
97762306a36Sopenharmony_ci		vfree(p_current_fw);
97862306a36Sopenharmony_ci		vfree(p_buffer);
97962306a36Sopenharmony_ci		return retval;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
98362306a36Sopenharmony_ci				  dev->dev);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (retval != 0) {
98662306a36Sopenharmony_ci		dev_err(dev->dev,
98762306a36Sopenharmony_ci			"ERROR: Hotplug firmware request failed (%s).\n",
98862306a36Sopenharmony_ci			CX231xx_FIRM_IMAGE_NAME);
98962306a36Sopenharmony_ci		dev_err(dev->dev,
99062306a36Sopenharmony_ci			"Please fix your hotplug setup, the board will not work without firmware loaded!\n");
99162306a36Sopenharmony_ci		vfree(p_current_fw);
99262306a36Sopenharmony_ci		vfree(p_buffer);
99362306a36Sopenharmony_ci		return retval;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
99762306a36Sopenharmony_ci		dev_err(dev->dev,
99862306a36Sopenharmony_ci			"ERROR: Firmware size mismatch (have %zd, expected %d)\n",
99962306a36Sopenharmony_ci			firmware->size, CX231xx_FIRM_IMAGE_SIZE);
100062306a36Sopenharmony_ci		release_firmware(firmware);
100162306a36Sopenharmony_ci		vfree(p_current_fw);
100262306a36Sopenharmony_ci		vfree(p_buffer);
100362306a36Sopenharmony_ci		return -EINVAL;
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (0 != memcmp(firmware->data, magic, 8)) {
100762306a36Sopenharmony_ci		dev_err(dev->dev,
100862306a36Sopenharmony_ci			"ERROR: Firmware magic mismatch, wrong file?\n");
100962306a36Sopenharmony_ci		release_firmware(firmware);
101062306a36Sopenharmony_ci		vfree(p_current_fw);
101162306a36Sopenharmony_ci		vfree(p_buffer);
101262306a36Sopenharmony_ci		return -EINVAL;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	initGPIO(dev);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* transfer to the chip */
101862306a36Sopenharmony_ci	dprintk(2, "Loading firmware to GPIO...\n");
101962306a36Sopenharmony_ci	p_fw_data = (u32 *)firmware->data;
102062306a36Sopenharmony_ci	dprintk(2, "firmware->size=%zd\n", firmware->size);
102162306a36Sopenharmony_ci	for (transfer_size = 0; transfer_size < firmware->size;
102262306a36Sopenharmony_ci		 transfer_size += 4) {
102362306a36Sopenharmony_ci		fw_data = *p_fw_data;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		mci_write_memory_to_gpio(dev, address, fw_data, p_current_fw);
102662306a36Sopenharmony_ci		address = address + 1;
102762306a36Sopenharmony_ci		p_current_fw += 20;
102862306a36Sopenharmony_ci		p_fw_data += 1;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	/*download the firmware by ep5-out*/
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
103462306a36Sopenharmony_ci	     frame++) {
103562306a36Sopenharmony_ci		for (i = 0; i < _buffer_size; i++) {
103662306a36Sopenharmony_ci			*(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
103762306a36Sopenharmony_ci			i++;
103862306a36Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
103962306a36Sopenharmony_ci			i++;
104062306a36Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
104162306a36Sopenharmony_ci			i++;
104262306a36Sopenharmony_ci			*(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
104362306a36Sopenharmony_ci		}
104462306a36Sopenharmony_ci		cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	p_current_fw = p_fw;
104862306a36Sopenharmony_ci	vfree(p_current_fw);
104962306a36Sopenharmony_ci	p_current_fw = NULL;
105062306a36Sopenharmony_ci	vfree(p_buffer);
105162306a36Sopenharmony_ci	uninitGPIO(dev);
105262306a36Sopenharmony_ci	release_firmware(firmware);
105362306a36Sopenharmony_ci	dprintk(1, "Firmware upload successful.\n");
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
105662306a36Sopenharmony_ci		IVTV_CMD_HW_BLOCKS_RST);
105762306a36Sopenharmony_ci	if (retval < 0) {
105862306a36Sopenharmony_ci		dev_err(dev->dev,
105962306a36Sopenharmony_ci			"%s: Error with mc417_register_write\n",
106062306a36Sopenharmony_ci			__func__);
106162306a36Sopenharmony_ci		return retval;
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci	/* F/W power up disturbs the GPIOs, restore state */
106462306a36Sopenharmony_ci	retval |= mc417_register_write(dev, 0x9020, gpio_output);
106562306a36Sopenharmony_ci	retval |= mc417_register_write(dev, 0x900C, value);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
106862306a36Sopenharmony_ci	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (retval < 0) {
107162306a36Sopenharmony_ci		dev_err(dev->dev,
107262306a36Sopenharmony_ci			"%s: Error with mc417_register_write\n",
107362306a36Sopenharmony_ci			__func__);
107462306a36Sopenharmony_ci		return retval;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic void cx231xx_codec_settings(struct cx231xx *dev)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* assign frame size */
108462306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
108562306a36Sopenharmony_ci				dev->ts1.height, dev->ts1.width);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.width = dev->ts1.width;
108862306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.height = dev->ts1.height;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	cx2341x_handler_setup(&dev->mpeg_ctrl_handler);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
109362306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic int cx231xx_initialize_codec(struct cx231xx *dev)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	int version;
109962306a36Sopenharmony_ci	int retval;
110062306a36Sopenharmony_ci	u32 i;
110162306a36Sopenharmony_ci	u32 val = 0;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
110462306a36Sopenharmony_ci	cx231xx_disable656(dev);
110562306a36Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
110662306a36Sopenharmony_ci	if (retval < 0) {
110762306a36Sopenharmony_ci		dprintk(2, "%s: PING OK\n", __func__);
110862306a36Sopenharmony_ci		retval = cx231xx_load_firmware(dev);
110962306a36Sopenharmony_ci		if (retval < 0) {
111062306a36Sopenharmony_ci			dev_err(dev->dev,
111162306a36Sopenharmony_ci				"%s: f/w load failed\n", __func__);
111262306a36Sopenharmony_ci			return retval;
111362306a36Sopenharmony_ci		}
111462306a36Sopenharmony_ci		retval = cx231xx_find_mailbox(dev);
111562306a36Sopenharmony_ci		if (retval < 0) {
111662306a36Sopenharmony_ci			dev_err(dev->dev, "%s: mailbox < 0, error\n",
111762306a36Sopenharmony_ci				__func__);
111862306a36Sopenharmony_ci			return retval;
111962306a36Sopenharmony_ci		}
112062306a36Sopenharmony_ci		dev->cx23417_mailbox = retval;
112162306a36Sopenharmony_ci		retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
112262306a36Sopenharmony_ci		if (retval < 0) {
112362306a36Sopenharmony_ci			dev_err(dev->dev,
112462306a36Sopenharmony_ci				"ERROR: cx23417 firmware ping failed!\n");
112562306a36Sopenharmony_ci			return retval;
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci		retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
112862306a36Sopenharmony_ci			&version);
112962306a36Sopenharmony_ci		if (retval < 0) {
113062306a36Sopenharmony_ci			dev_err(dev->dev,
113162306a36Sopenharmony_ci				"ERROR: cx23417 firmware get encoder: version failed!\n");
113262306a36Sopenharmony_ci			return retval;
113362306a36Sopenharmony_ci		}
113462306a36Sopenharmony_ci		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
113562306a36Sopenharmony_ci		msleep(200);
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	for (i = 0; i < 1; i++) {
113962306a36Sopenharmony_ci		retval = mc417_register_read(dev, 0x20f8, &val);
114062306a36Sopenharmony_ci		dprintk(3, "***before enable656() VIM Capture Lines = %d ***\n",
114162306a36Sopenharmony_ci				 val);
114262306a36Sopenharmony_ci		if (retval < 0)
114362306a36Sopenharmony_ci			return retval;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	cx231xx_enable656(dev);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/* stop mpeg capture */
114962306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, 1, 3, 4);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	cx231xx_codec_settings(dev);
115262306a36Sopenharmony_ci	msleep(60);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci/*	cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
115562306a36Sopenharmony_ci		CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
115662306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
115762306a36Sopenharmony_ci		CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115862306a36Sopenharmony_ci		0, 0);
115962306a36Sopenharmony_ci*/
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci#if 0
116262306a36Sopenharmony_ci	/* TODO */
116362306a36Sopenharmony_ci	u32 data[7];
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* Setup to capture VBI */
116662306a36Sopenharmony_ci	data[0] = 0x0001BD00;
116762306a36Sopenharmony_ci	data[1] = 1;          /* frames per interrupt */
116862306a36Sopenharmony_ci	data[2] = 4;          /* total bufs */
116962306a36Sopenharmony_ci	data[3] = 0x91559155; /* start codes */
117062306a36Sopenharmony_ci	data[4] = 0x206080C0; /* stop codes */
117162306a36Sopenharmony_ci	data[5] = 6;          /* lines */
117262306a36Sopenharmony_ci	data[6] = 64;         /* BPL */
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
117562306a36Sopenharmony_ci		data[2], data[3], data[4], data[5], data[6]);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	for (i = 2; i <= 24; i++) {
117862306a36Sopenharmony_ci		int valid;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci		valid = ((i >= 19) && (i <= 21));
118162306a36Sopenharmony_ci		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
118262306a36Sopenharmony_ci				valid, 0 , 0, 0);
118362306a36Sopenharmony_ci		cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
118462306a36Sopenharmony_ci				i | 0x80000000, valid, 0, 0, 0);
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci#endif
118762306a36Sopenharmony_ci/*	cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
118862306a36Sopenharmony_ci	msleep(60);
118962306a36Sopenharmony_ci*/
119062306a36Sopenharmony_ci	/* initialize the video input */
119162306a36Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
119262306a36Sopenharmony_ci	if (retval < 0)
119362306a36Sopenharmony_ci		return retval;
119462306a36Sopenharmony_ci	msleep(60);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	/* Enable VIP style pixel invalidation so we work with scaled mode */
119762306a36Sopenharmony_ci	mc417_memory_write(dev, 2120, 0x00000080);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	/* start capturing to the host interface */
120062306a36Sopenharmony_ci	retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
120162306a36Sopenharmony_ci		CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
120262306a36Sopenharmony_ci	if (retval < 0)
120362306a36Sopenharmony_ci		return retval;
120462306a36Sopenharmony_ci	msleep(10);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	for (i = 0; i < 1; i++) {
120762306a36Sopenharmony_ci		mc417_register_read(dev, 0x20f8, &val);
120862306a36Sopenharmony_ci		dprintk(3, "***VIM Capture Lines =%d ***\n", val);
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	return 0;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic int queue_setup(struct vb2_queue *vq,
121762306a36Sopenharmony_ci		       unsigned int *nbuffers, unsigned int *nplanes,
121862306a36Sopenharmony_ci		       unsigned int sizes[], struct device *alloc_devs[])
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
122162306a36Sopenharmony_ci	unsigned int size = mpeglinesize * mpeglines;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	dev->ts1.ts_packet_size  = mpeglinesize;
122462306a36Sopenharmony_ci	dev->ts1.ts_packet_count = mpeglines;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF)
122762306a36Sopenharmony_ci		*nbuffers = CX231XX_MIN_BUF - vq->num_buffers;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (*nplanes)
123062306a36Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
123162306a36Sopenharmony_ci	*nplanes = 1;
123262306a36Sopenharmony_ci	sizes[0] = mpeglinesize * mpeglines;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return 0;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
123862306a36Sopenharmony_ci		struct cx231xx_dmaqueue *dma_q)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	void *vbuf;
124162306a36Sopenharmony_ci	struct cx231xx_buffer *buf;
124262306a36Sopenharmony_ci	u32 tail_data = 0;
124362306a36Sopenharmony_ci	char *p_data;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (dma_q->mpeg_buffer_done == 0) {
124662306a36Sopenharmony_ci		if (list_empty(&dma_q->active))
124762306a36Sopenharmony_ci			return;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		buf = list_entry(dma_q->active.next,
125062306a36Sopenharmony_ci				struct cx231xx_buffer, list);
125162306a36Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = buf;
125262306a36Sopenharmony_ci		dma_q->mpeg_buffer_done = 1;
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci	/* Fill buffer */
125562306a36Sopenharmony_ci	buf = dev->video_mode.isoc_ctl.buf;
125662306a36Sopenharmony_ci	vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if ((dma_q->mpeg_buffer_completed+len) <
125962306a36Sopenharmony_ci			mpeglines*mpeglinesize) {
126062306a36Sopenharmony_ci		if (dma_q->add_ps_package_head ==
126162306a36Sopenharmony_ci				CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
126262306a36Sopenharmony_ci			memcpy(vbuf+dma_q->mpeg_buffer_completed,
126362306a36Sopenharmony_ci					dma_q->ps_head, 3);
126462306a36Sopenharmony_ci			dma_q->mpeg_buffer_completed =
126562306a36Sopenharmony_ci				dma_q->mpeg_buffer_completed + 3;
126662306a36Sopenharmony_ci			dma_q->add_ps_package_head =
126762306a36Sopenharmony_ci				CX231XX_NONEED_PS_PACKAGE_HEAD;
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci		memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
127062306a36Sopenharmony_ci		dma_q->mpeg_buffer_completed =
127162306a36Sopenharmony_ci			dma_q->mpeg_buffer_completed + len;
127262306a36Sopenharmony_ci	} else {
127362306a36Sopenharmony_ci		dma_q->mpeg_buffer_done = 0;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		tail_data =
127662306a36Sopenharmony_ci			mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
127762306a36Sopenharmony_ci		memcpy(vbuf+dma_q->mpeg_buffer_completed,
127862306a36Sopenharmony_ci				data, tail_data);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci		buf->vb.vb2_buf.timestamp = ktime_get_ns();
128162306a36Sopenharmony_ci		buf->vb.sequence = dma_q->sequence++;
128262306a36Sopenharmony_ci		list_del(&buf->list);
128362306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
128462306a36Sopenharmony_ci		dma_q->mpeg_buffer_completed = 0;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci		if (len - tail_data > 0) {
128762306a36Sopenharmony_ci			p_data = data + tail_data;
128862306a36Sopenharmony_ci			dma_q->left_data_count = len - tail_data;
128962306a36Sopenharmony_ci			memcpy(dma_q->p_left_data,
129062306a36Sopenharmony_ci					p_data, len - tail_data);
129162306a36Sopenharmony_ci		}
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic void buffer_filled(char *data, int len, struct urb *urb,
129662306a36Sopenharmony_ci		struct cx231xx_dmaqueue *dma_q)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	void *vbuf;
129962306a36Sopenharmony_ci	struct cx231xx_buffer *buf;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	if (list_empty(&dma_q->active))
130262306a36Sopenharmony_ci		return;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* Fill buffer */
130762306a36Sopenharmony_ci	vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
130862306a36Sopenharmony_ci	memcpy(vbuf, data, len);
130962306a36Sopenharmony_ci	buf->vb.sequence = dma_q->sequence++;
131062306a36Sopenharmony_ci	buf->vb.vb2_buf.timestamp = ktime_get_ns();
131162306a36Sopenharmony_ci	list_del(&buf->list);
131262306a36Sopenharmony_ci	vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
131862306a36Sopenharmony_ci	unsigned char *p_buffer;
131962306a36Sopenharmony_ci	u32 buffer_size = 0;
132062306a36Sopenharmony_ci	u32 i = 0;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
132362306a36Sopenharmony_ci		if (dma_q->left_data_count > 0) {
132462306a36Sopenharmony_ci			buffer_copy(dev, dma_q->p_left_data,
132562306a36Sopenharmony_ci				    dma_q->left_data_count, urb, dma_q);
132662306a36Sopenharmony_ci			dma_q->mpeg_buffer_completed = dma_q->left_data_count;
132762306a36Sopenharmony_ci			dma_q->left_data_count = 0;
132862306a36Sopenharmony_ci		}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		p_buffer = urb->transfer_buffer +
133162306a36Sopenharmony_ci				urb->iso_frame_desc[i].offset;
133262306a36Sopenharmony_ci		buffer_size = urb->iso_frame_desc[i].actual_length;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		if (buffer_size > 0)
133562306a36Sopenharmony_ci			buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	return 0;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct cx231xx_dmaqueue *dma_q = urb->context;
134462306a36Sopenharmony_ci	unsigned char *p_buffer, *buffer;
134562306a36Sopenharmony_ci	u32 buffer_size = 0;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	p_buffer = urb->transfer_buffer;
134862306a36Sopenharmony_ci	buffer_size = urb->actual_length;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	buffer = kmalloc(buffer_size, GFP_ATOMIC);
135162306a36Sopenharmony_ci	if (!buffer)
135262306a36Sopenharmony_ci		return -ENOMEM;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	memcpy(buffer, dma_q->ps_head, 3);
135562306a36Sopenharmony_ci	memcpy(buffer+3, p_buffer, buffer_size-3);
135662306a36Sopenharmony_ci	memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	p_buffer = buffer;
135962306a36Sopenharmony_ci	buffer_filled(p_buffer, buffer_size, urb, dma_q);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	kfree(buffer);
136262306a36Sopenharmony_ci	return 0;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	struct cx231xx_buffer *buf =
136862306a36Sopenharmony_ci	    container_of(vb, struct cx231xx_buffer, vb.vb2_buf);
136962306a36Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue);
137062306a36Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
137162306a36Sopenharmony_ci	unsigned long flags;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
137462306a36Sopenharmony_ci	list_add_tail(&buf->list, &vidq->active);
137562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic void return_all_buffers(struct cx231xx *dev,
137962306a36Sopenharmony_ci			       enum vb2_buffer_state state)
138062306a36Sopenharmony_ci{
138162306a36Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
138262306a36Sopenharmony_ci	struct cx231xx_buffer *buf, *node;
138362306a36Sopenharmony_ci	unsigned long flags;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
138662306a36Sopenharmony_ci	list_for_each_entry_safe(buf, node, &vidq->active, list) {
138762306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, state);
138862306a36Sopenharmony_ci		list_del(&buf->list);
138962306a36Sopenharmony_ci	}
139062306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic int start_streaming(struct vb2_queue *vq, unsigned int count)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
139662306a36Sopenharmony_ci	struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
139762306a36Sopenharmony_ci	int ret = 0;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	vidq->sequence = 0;
140062306a36Sopenharmony_ci	dev->mode_tv = 1;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
140362306a36Sopenharmony_ci	cx231xx_set_gpio_value(dev, 2, 0);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	cx231xx_initialize_codec(dev);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	cx231xx_start_TS1(dev);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
141062306a36Sopenharmony_ci	cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
141162306a36Sopenharmony_ci	if (dev->USE_ISO)
141262306a36Sopenharmony_ci		ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
141362306a36Sopenharmony_ci					CX231XX_NUM_BUFS,
141462306a36Sopenharmony_ci					dev->ts1_mode.max_pkt_size,
141562306a36Sopenharmony_ci					cx231xx_isoc_copy);
141662306a36Sopenharmony_ci	else
141762306a36Sopenharmony_ci		ret = cx231xx_init_bulk(dev, 320, 5,
141862306a36Sopenharmony_ci					dev->ts1_mode.max_pkt_size,
141962306a36Sopenharmony_ci					cx231xx_bulk_copy);
142062306a36Sopenharmony_ci	if (ret)
142162306a36Sopenharmony_ci		return_all_buffers(dev, VB2_BUF_STATE_QUEUED);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	call_all(dev, video, s_stream, 1);
142462306a36Sopenharmony_ci	return ret;
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic void stop_streaming(struct vb2_queue *vq)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	struct cx231xx *dev = vb2_get_drv_priv(vq);
143062306a36Sopenharmony_ci	unsigned long flags;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	call_all(dev, video, s_stream, 0);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	cx231xx_stop_TS1(dev);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* do this before setting alternate! */
143762306a36Sopenharmony_ci	if (dev->USE_ISO)
143862306a36Sopenharmony_ci		cx231xx_uninit_isoc(dev);
143962306a36Sopenharmony_ci	else
144062306a36Sopenharmony_ci		cx231xx_uninit_bulk(dev);
144162306a36Sopenharmony_ci	cx231xx_set_mode(dev, CX231XX_SUSPEND);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
144462306a36Sopenharmony_ci			CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
144562306a36Sopenharmony_ci			CX231xx_RAW_BITS_NONE);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	spin_lock_irqsave(&dev->video_mode.slock, flags);
144862306a36Sopenharmony_ci	if (dev->USE_ISO)
144962306a36Sopenharmony_ci		dev->video_mode.isoc_ctl.buf = NULL;
145062306a36Sopenharmony_ci	else
145162306a36Sopenharmony_ci		dev->video_mode.bulk_ctl.buf = NULL;
145262306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->video_mode.slock, flags);
145362306a36Sopenharmony_ci	return_all_buffers(dev, VB2_BUF_STATE_ERROR);
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_cistatic struct vb2_ops cx231xx_video_qops = {
145762306a36Sopenharmony_ci	.queue_setup		= queue_setup,
145862306a36Sopenharmony_ci	.buf_queue		= buffer_queue,
145962306a36Sopenharmony_ci	.start_streaming	= start_streaming,
146062306a36Sopenharmony_ci	.stop_streaming		= stop_streaming,
146162306a36Sopenharmony_ci	.wait_prepare		= vb2_ops_wait_prepare,
146262306a36Sopenharmony_ci	.wait_finish		= vb2_ops_wait_finish,
146362306a36Sopenharmony_ci};
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cistatic int vidioc_g_pixelaspect(struct file *file, void *priv,
146862306a36Sopenharmony_ci				int type, struct v4l2_fract *f)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
147162306a36Sopenharmony_ci	bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
147462306a36Sopenharmony_ci		return -EINVAL;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	f->numerator = is_50hz ? 54 : 11;
147762306a36Sopenharmony_ci	f->denominator = is_50hz ? 59 : 10;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	return 0;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic int vidioc_g_selection(struct file *file, void *priv,
148362306a36Sopenharmony_ci			      struct v4l2_selection *s)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
148862306a36Sopenharmony_ci		return -EINVAL;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	switch (s->target) {
149162306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
149262306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
149362306a36Sopenharmony_ci		s->r.left = 0;
149462306a36Sopenharmony_ci		s->r.top = 0;
149562306a36Sopenharmony_ci		s->r.width = dev->ts1.width;
149662306a36Sopenharmony_ci		s->r.height = dev->ts1.height;
149762306a36Sopenharmony_ci		break;
149862306a36Sopenharmony_ci	default:
149962306a36Sopenharmony_ci		return -EINVAL;
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci	return 0;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	*norm = dev->encodernorm.id;
150962306a36Sopenharmony_ci	return 0;
151062306a36Sopenharmony_ci}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
151362306a36Sopenharmony_ci{
151462306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
151562306a36Sopenharmony_ci	unsigned int i;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
151862306a36Sopenharmony_ci		if (id & cx231xx_tvnorms[i].id)
151962306a36Sopenharmony_ci			break;
152062306a36Sopenharmony_ci	if (i == ARRAY_SIZE(cx231xx_tvnorms))
152162306a36Sopenharmony_ci		return -EINVAL;
152262306a36Sopenharmony_ci	dev->encodernorm = cx231xx_tvnorms[i];
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	if (dev->encodernorm.id & 0xb000) {
152562306a36Sopenharmony_ci		dprintk(3, "encodernorm set to NTSC\n");
152662306a36Sopenharmony_ci		dev->norm = V4L2_STD_NTSC;
152762306a36Sopenharmony_ci		dev->ts1.height = 480;
152862306a36Sopenharmony_ci		cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
152962306a36Sopenharmony_ci	} else {
153062306a36Sopenharmony_ci		dprintk(3, "encodernorm set to PAL\n");
153162306a36Sopenharmony_ci		dev->norm = V4L2_STD_PAL_B;
153262306a36Sopenharmony_ci		dev->ts1.height = 576;
153362306a36Sopenharmony_ci		cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci	call_all(dev, video, s_std, dev->norm);
153662306a36Sopenharmony_ci	/* do mode control overrides */
153762306a36Sopenharmony_ci	cx231xx_do_mode_ctrl_overrides(dev);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
154062306a36Sopenharmony_ci	return 0;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic int vidioc_s_ctrl(struct file *file, void *priv,
154462306a36Sopenharmony_ci				struct v4l2_control *ctl)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
154762306a36Sopenharmony_ci	struct v4l2_subdev *sd;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	dprintk(3, "enter vidioc_s_ctrl()\n");
155062306a36Sopenharmony_ci	/* Update the A/V core */
155162306a36Sopenharmony_ci	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev)
155262306a36Sopenharmony_ci		v4l2_s_ctrl(NULL, sd->ctrl_handler, ctl);
155362306a36Sopenharmony_ci	dprintk(3, "exit vidioc_s_ctrl()\n");
155462306a36Sopenharmony_ci	return 0;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
155862306a36Sopenharmony_ci					struct v4l2_fmtdesc *f)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci	if (f->index != 0)
156162306a36Sopenharmony_ci		return -EINVAL;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	f->pixelformat = V4L2_PIX_FMT_MPEG;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	return 0;
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
156962306a36Sopenharmony_ci				struct v4l2_format *f)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
157462306a36Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
157562306a36Sopenharmony_ci	f->fmt.pix.bytesperline = 0;
157662306a36Sopenharmony_ci	f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
157762306a36Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
157862306a36Sopenharmony_ci	f->fmt.pix.width = dev->ts1.width;
157962306a36Sopenharmony_ci	f->fmt.pix.height = dev->ts1.height;
158062306a36Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
158162306a36Sopenharmony_ci	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
158262306a36Sopenharmony_ci		dev->ts1.width, dev->ts1.height);
158362306a36Sopenharmony_ci	dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
158462306a36Sopenharmony_ci	return 0;
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
158862306a36Sopenharmony_ci				struct v4l2_format *f)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
159362306a36Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
159462306a36Sopenharmony_ci	f->fmt.pix.bytesperline = 0;
159562306a36Sopenharmony_ci	f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
159662306a36Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
159762306a36Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
159862306a36Sopenharmony_ci	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
159962306a36Sopenharmony_ci		dev->ts1.width, dev->ts1.height);
160062306a36Sopenharmony_ci	dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
160162306a36Sopenharmony_ci	return 0;
160262306a36Sopenharmony_ci}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_cistatic int vidioc_log_status(struct file *file, void *priv)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	struct cx231xx *dev = video_drvdata(file);
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	call_all(dev, core, log_status);
160962306a36Sopenharmony_ci	return v4l2_ctrl_log_status(file, priv);
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic const struct v4l2_file_operations mpeg_fops = {
161362306a36Sopenharmony_ci	.owner	       = THIS_MODULE,
161462306a36Sopenharmony_ci	.open	       = v4l2_fh_open,
161562306a36Sopenharmony_ci	.release       = vb2_fop_release,
161662306a36Sopenharmony_ci	.read	       = vb2_fop_read,
161762306a36Sopenharmony_ci	.poll          = vb2_fop_poll,
161862306a36Sopenharmony_ci	.mmap	       = vb2_fop_mmap,
161962306a36Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
162062306a36Sopenharmony_ci};
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
162362306a36Sopenharmony_ci	.vidioc_s_std		 = vidioc_s_std,
162462306a36Sopenharmony_ci	.vidioc_g_std		 = vidioc_g_std,
162562306a36Sopenharmony_ci	.vidioc_g_tuner          = cx231xx_g_tuner,
162662306a36Sopenharmony_ci	.vidioc_s_tuner          = cx231xx_s_tuner,
162762306a36Sopenharmony_ci	.vidioc_g_frequency      = cx231xx_g_frequency,
162862306a36Sopenharmony_ci	.vidioc_s_frequency      = cx231xx_s_frequency,
162962306a36Sopenharmony_ci	.vidioc_enum_input	 = cx231xx_enum_input,
163062306a36Sopenharmony_ci	.vidioc_g_input		 = cx231xx_g_input,
163162306a36Sopenharmony_ci	.vidioc_s_input		 = cx231xx_s_input,
163262306a36Sopenharmony_ci	.vidioc_s_ctrl		 = vidioc_s_ctrl,
163362306a36Sopenharmony_ci	.vidioc_g_pixelaspect	 = vidioc_g_pixelaspect,
163462306a36Sopenharmony_ci	.vidioc_g_selection	 = vidioc_g_selection,
163562306a36Sopenharmony_ci	.vidioc_querycap	 = cx231xx_querycap,
163662306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
163762306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
163862306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
163962306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
164062306a36Sopenharmony_ci	.vidioc_reqbufs		 = vb2_ioctl_reqbufs,
164162306a36Sopenharmony_ci	.vidioc_querybuf	 = vb2_ioctl_querybuf,
164262306a36Sopenharmony_ci	.vidioc_qbuf		 = vb2_ioctl_qbuf,
164362306a36Sopenharmony_ci	.vidioc_dqbuf		 = vb2_ioctl_dqbuf,
164462306a36Sopenharmony_ci	.vidioc_streamon	 = vb2_ioctl_streamon,
164562306a36Sopenharmony_ci	.vidioc_streamoff	 = vb2_ioctl_streamoff,
164662306a36Sopenharmony_ci	.vidioc_log_status	 = vidioc_log_status,
164762306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
164862306a36Sopenharmony_ci	.vidioc_g_register	 = cx231xx_g_register,
164962306a36Sopenharmony_ci	.vidioc_s_register	 = cx231xx_s_register,
165062306a36Sopenharmony_ci#endif
165162306a36Sopenharmony_ci	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
165262306a36Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
165362306a36Sopenharmony_ci};
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_cistatic struct video_device cx231xx_mpeg_template = {
165662306a36Sopenharmony_ci	.name          = "cx231xx",
165762306a36Sopenharmony_ci	.fops          = &mpeg_fops,
165862306a36Sopenharmony_ci	.ioctl_ops     = &mpeg_ioctl_ops,
165962306a36Sopenharmony_ci	.minor         = -1,
166062306a36Sopenharmony_ci	.tvnorms       = V4L2_STD_ALL,
166162306a36Sopenharmony_ci};
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_civoid cx231xx_417_unregister(struct cx231xx *dev)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
166662306a36Sopenharmony_ci	dprintk(3, "%s()\n", __func__);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (video_is_registered(&dev->v4l_device)) {
166962306a36Sopenharmony_ci		video_unregister_device(&dev->v4l_device);
167062306a36Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
167162306a36Sopenharmony_ci	}
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_cistatic int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
167762306a36Sopenharmony_ci	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
167862306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
167962306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
168062306a36Sopenharmony_ci	};
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* fix videodecoder resolution */
168362306a36Sopenharmony_ci	format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
168462306a36Sopenharmony_ci	format.format.height = cxhdl->height;
168562306a36Sopenharmony_ci	format.format.code = MEDIA_BUS_FMT_FIXED;
168662306a36Sopenharmony_ci	v4l2_subdev_call(dev->sd_cx25840, pad, set_fmt, NULL, &format);
168762306a36Sopenharmony_ci	return 0;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistatic int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	static const u32 freqs[3] = { 44100, 48000, 32000 };
169362306a36Sopenharmony_ci	struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	/* The audio clock of the digitizer must match the codec sample
169662306a36Sopenharmony_ci	   rate otherwise you get some very strange effects. */
169762306a36Sopenharmony_ci	if (idx < ARRAY_SIZE(freqs))
169862306a36Sopenharmony_ci		call_all(dev, audio, s_clock_freq, freqs[idx]);
169962306a36Sopenharmony_ci	return 0;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic const struct cx2341x_handler_ops cx231xx_ops = {
170362306a36Sopenharmony_ci	/* needed for the video clock freq */
170462306a36Sopenharmony_ci	.s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
170562306a36Sopenharmony_ci	/* needed for setting up the video resolution */
170662306a36Sopenharmony_ci	.s_video_encoding = cx231xx_s_video_encoding,
170762306a36Sopenharmony_ci};
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic void cx231xx_video_dev_init(
171062306a36Sopenharmony_ci	struct cx231xx *dev,
171162306a36Sopenharmony_ci	struct usb_device *usbdev,
171262306a36Sopenharmony_ci	struct video_device *vfd,
171362306a36Sopenharmony_ci	const struct video_device *template,
171462306a36Sopenharmony_ci	const char *type)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
171762306a36Sopenharmony_ci	*vfd = *template;
171862306a36Sopenharmony_ci	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
171962306a36Sopenharmony_ci		type, cx231xx_boards[dev->model].name);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	vfd->v4l2_dev = &dev->v4l2_dev;
172262306a36Sopenharmony_ci	vfd->lock = &dev->lock;
172362306a36Sopenharmony_ci	vfd->release = video_device_release_empty;
172462306a36Sopenharmony_ci	vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
172562306a36Sopenharmony_ci	video_set_drvdata(vfd, dev);
172662306a36Sopenharmony_ci	if (dev->tuner_type == TUNER_ABSENT) {
172762306a36Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
172862306a36Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
172962306a36Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
173062306a36Sopenharmony_ci		v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ciint cx231xx_417_register(struct cx231xx *dev)
173562306a36Sopenharmony_ci{
173662306a36Sopenharmony_ci	/* FIXME: Port1 hardcoded here */
173762306a36Sopenharmony_ci	int err;
173862306a36Sopenharmony_ci	struct cx231xx_tsport *tsport = &dev->ts1;
173962306a36Sopenharmony_ci	struct vb2_queue *q;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Set default TV standard */
174462306a36Sopenharmony_ci	dev->encodernorm = cx231xx_tvnorms[0];
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	if (dev->encodernorm.id & V4L2_STD_525_60)
174762306a36Sopenharmony_ci		tsport->height = 480;
174862306a36Sopenharmony_ci	else
174962306a36Sopenharmony_ci		tsport->height = 576;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	tsport->width = 720;
175262306a36Sopenharmony_ci	err = cx2341x_handler_init(&dev->mpeg_ctrl_handler, 50);
175362306a36Sopenharmony_ci	if (err) {
175462306a36Sopenharmony_ci		dprintk(3, "%s: can't init cx2341x controls\n", dev->name);
175562306a36Sopenharmony_ci		return err;
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.func = cx231xx_mbox_func;
175862306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.priv = dev;
175962306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
176062306a36Sopenharmony_ci	if (dev->sd_cx25840)
176162306a36Sopenharmony_ci		v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
176262306a36Sopenharmony_ci				dev->sd_cx25840->ctrl_handler, NULL, false);
176362306a36Sopenharmony_ci	if (dev->mpeg_ctrl_handler.hdl.error) {
176462306a36Sopenharmony_ci		err = dev->mpeg_ctrl_handler.hdl.error;
176562306a36Sopenharmony_ci		dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
176662306a36Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
176762306a36Sopenharmony_ci		return err;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci	dev->norm = V4L2_STD_NTSC;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	dev->mpeg_ctrl_handler.port = CX2341X_PORT_SERIAL;
177262306a36Sopenharmony_ci	cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/* Allocate and initialize V4L video device */
177562306a36Sopenharmony_ci	cx231xx_video_dev_init(dev, dev->udev,
177662306a36Sopenharmony_ci			&dev->v4l_device, &cx231xx_mpeg_template, "mpeg");
177762306a36Sopenharmony_ci	q = &dev->mpegq;
177862306a36Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
177962306a36Sopenharmony_ci	q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ;
178062306a36Sopenharmony_ci	q->drv_priv = dev;
178162306a36Sopenharmony_ci	q->buf_struct_size = sizeof(struct cx231xx_buffer);
178262306a36Sopenharmony_ci	q->ops = &cx231xx_video_qops;
178362306a36Sopenharmony_ci	q->mem_ops = &vb2_vmalloc_memops;
178462306a36Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
178562306a36Sopenharmony_ci	q->min_buffers_needed = 1;
178662306a36Sopenharmony_ci	q->lock = &dev->lock;
178762306a36Sopenharmony_ci	err = vb2_queue_init(q);
178862306a36Sopenharmony_ci	if (err)
178962306a36Sopenharmony_ci		return err;
179062306a36Sopenharmony_ci	dev->v4l_device.queue = q;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	err = video_register_device(&dev->v4l_device,
179362306a36Sopenharmony_ci		VFL_TYPE_VIDEO, -1);
179462306a36Sopenharmony_ci	if (err < 0) {
179562306a36Sopenharmony_ci		dprintk(3, "%s: can't register mpeg device\n", dev->name);
179662306a36Sopenharmony_ci		v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
179762306a36Sopenharmony_ci		return err;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	dprintk(3, "%s: registered device video%d [mpeg]\n",
180162306a36Sopenharmony_ci	       dev->name, dev->v4l_device.num);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	return 0;
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ciMODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
1807