18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Support for a cx23417 mpeg encoder via cx23885 host port. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (c) 2004 Jelle Foks <jelle@foks.us> 78c2ecf20Sopenharmony_ci * (c) 2004 Gerd Knorr <kraxel@bytesex.org> 88c2ecf20Sopenharmony_ci * (c) 2008 Steven Toth <stoth@linuxtv.org> 98c2ecf20Sopenharmony_ci * - CX23885/7/8 support 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "cx23885.h" 158c2ecf20Sopenharmony_ci#include "cx23885-ioctl.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/fs.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/device.h> 238c2ecf20Sopenharmony_ci#include <linux/firmware.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 278c2ecf20Sopenharmony_ci#include <media/drv-intf/cx2341x.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define CX23885_FIRM_IMAGE_SIZE 376836 308c2ecf20Sopenharmony_ci#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic unsigned int mpegbufs = 32; 338c2ecf20Sopenharmony_cimodule_param(mpegbufs, int, 0644); 348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); 358c2ecf20Sopenharmony_cistatic unsigned int mpeglines = 32; 368c2ecf20Sopenharmony_cimodule_param(mpeglines, int, 0644); 378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); 388c2ecf20Sopenharmony_cistatic unsigned int mpeglinesize = 512; 398c2ecf20Sopenharmony_cimodule_param(mpeglinesize, int, 0644); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpeglinesize, 418c2ecf20Sopenharmony_ci "number of bytes in each line of an MPEG buffer, range 512-1024"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic unsigned int v4l_debug; 448c2ecf20Sopenharmony_cimodule_param(v4l_debug, int, 0644); 458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...)\ 488c2ecf20Sopenharmony_ci do { if (v4l_debug >= level) \ 498c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: 417:" fmt), \ 508c2ecf20Sopenharmony_ci __func__, ##arg); \ 518c2ecf20Sopenharmony_ci } while (0) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct cx23885_tvnorm cx23885_tvnorms[] = { 548c2ecf20Sopenharmony_ci { 558c2ecf20Sopenharmony_ci .name = "NTSC-M", 568c2ecf20Sopenharmony_ci .id = V4L2_STD_NTSC_M, 578c2ecf20Sopenharmony_ci }, { 588c2ecf20Sopenharmony_ci .name = "NTSC-JP", 598c2ecf20Sopenharmony_ci .id = V4L2_STD_NTSC_M_JP, 608c2ecf20Sopenharmony_ci }, { 618c2ecf20Sopenharmony_ci .name = "PAL-BG", 628c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_BG, 638c2ecf20Sopenharmony_ci }, { 648c2ecf20Sopenharmony_ci .name = "PAL-DK", 658c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_DK, 668c2ecf20Sopenharmony_ci }, { 678c2ecf20Sopenharmony_ci .name = "PAL-I", 688c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_I, 698c2ecf20Sopenharmony_ci }, { 708c2ecf20Sopenharmony_ci .name = "PAL-M", 718c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_M, 728c2ecf20Sopenharmony_ci }, { 738c2ecf20Sopenharmony_ci .name = "PAL-N", 748c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_N, 758c2ecf20Sopenharmony_ci }, { 768c2ecf20Sopenharmony_ci .name = "PAL-Nc", 778c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_Nc, 788c2ecf20Sopenharmony_ci }, { 798c2ecf20Sopenharmony_ci .name = "PAL-60", 808c2ecf20Sopenharmony_ci .id = V4L2_STD_PAL_60, 818c2ecf20Sopenharmony_ci }, { 828c2ecf20Sopenharmony_ci .name = "SECAM-L", 838c2ecf20Sopenharmony_ci .id = V4L2_STD_SECAM_L, 848c2ecf20Sopenharmony_ci }, { 858c2ecf20Sopenharmony_ci .name = "SECAM-DK", 868c2ecf20Sopenharmony_ci .id = V4L2_STD_SECAM_DK, 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 918c2ecf20Sopenharmony_cienum cx23885_capture_type { 928c2ecf20Sopenharmony_ci CX23885_MPEG_CAPTURE, 938c2ecf20Sopenharmony_ci CX23885_RAW_CAPTURE, 948c2ecf20Sopenharmony_ci CX23885_RAW_PASSTHRU_CAPTURE 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_cienum cx23885_capture_bits { 978c2ecf20Sopenharmony_ci CX23885_RAW_BITS_NONE = 0x00, 988c2ecf20Sopenharmony_ci CX23885_RAW_BITS_YUV_CAPTURE = 0x01, 998c2ecf20Sopenharmony_ci CX23885_RAW_BITS_PCM_CAPTURE = 0x02, 1008c2ecf20Sopenharmony_ci CX23885_RAW_BITS_VBI_CAPTURE = 0x04, 1018c2ecf20Sopenharmony_ci CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08, 1028c2ecf20Sopenharmony_ci CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_cienum cx23885_capture_end { 1058c2ecf20Sopenharmony_ci CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */ 1068c2ecf20Sopenharmony_ci CX23885_END_NOW, /* stop immediately, no irq */ 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_cienum cx23885_framerate { 1098c2ecf20Sopenharmony_ci CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */ 1108c2ecf20Sopenharmony_ci CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */ 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_cienum cx23885_stream_port { 1138c2ecf20Sopenharmony_ci CX23885_OUTPUT_PORT_MEMORY, 1148c2ecf20Sopenharmony_ci CX23885_OUTPUT_PORT_STREAMING, 1158c2ecf20Sopenharmony_ci CX23885_OUTPUT_PORT_SERIAL 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_cienum cx23885_data_xfer_status { 1188c2ecf20Sopenharmony_ci CX23885_MORE_BUFFERS_FOLLOW, 1198c2ecf20Sopenharmony_ci CX23885_LAST_BUFFER, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_cienum cx23885_picture_mask { 1228c2ecf20Sopenharmony_ci CX23885_PICTURE_MASK_NONE, 1238c2ecf20Sopenharmony_ci CX23885_PICTURE_MASK_I_FRAMES, 1248c2ecf20Sopenharmony_ci CX23885_PICTURE_MASK_I_P_FRAMES = 0x3, 1258c2ecf20Sopenharmony_ci CX23885_PICTURE_MASK_ALL_FRAMES = 0x7, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_cienum cx23885_vbi_mode_bits { 1288c2ecf20Sopenharmony_ci CX23885_VBI_BITS_SLICED, 1298c2ecf20Sopenharmony_ci CX23885_VBI_BITS_RAW, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_cienum cx23885_vbi_insertion_bits { 1328c2ecf20Sopenharmony_ci CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, 1338c2ecf20Sopenharmony_ci CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, 1348c2ecf20Sopenharmony_ci CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, 1358c2ecf20Sopenharmony_ci CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, 1368c2ecf20Sopenharmony_ci CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_cienum cx23885_dma_unit { 1398c2ecf20Sopenharmony_ci CX23885_DMA_BYTES, 1408c2ecf20Sopenharmony_ci CX23885_DMA_FRAMES, 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_cienum cx23885_dma_transfer_status_bits { 1438c2ecf20Sopenharmony_ci CX23885_DMA_TRANSFER_BITS_DONE = 0x01, 1448c2ecf20Sopenharmony_ci CX23885_DMA_TRANSFER_BITS_ERROR = 0x04, 1458c2ecf20Sopenharmony_ci CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_cienum cx23885_pause { 1488c2ecf20Sopenharmony_ci CX23885_PAUSE_ENCODING, 1498c2ecf20Sopenharmony_ci CX23885_RESUME_ENCODING, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_cienum cx23885_copyright { 1528c2ecf20Sopenharmony_ci CX23885_COPYRIGHT_OFF, 1538c2ecf20Sopenharmony_ci CX23885_COPYRIGHT_ON, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_cienum cx23885_notification_type { 1568c2ecf20Sopenharmony_ci CX23885_NOTIFICATION_REFRESH, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_cienum cx23885_notification_status { 1598c2ecf20Sopenharmony_ci CX23885_NOTIFICATION_OFF, 1608c2ecf20Sopenharmony_ci CX23885_NOTIFICATION_ON, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_cienum cx23885_notification_mailbox { 1638c2ecf20Sopenharmony_ci CX23885_NOTIFICATION_NO_MAILBOX = -1, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_cienum cx23885_field1_lines { 1668c2ecf20Sopenharmony_ci CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */ 1678c2ecf20Sopenharmony_ci CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */ 1688c2ecf20Sopenharmony_ci CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */ 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_cienum cx23885_field2_lines { 1718c2ecf20Sopenharmony_ci CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */ 1728c2ecf20Sopenharmony_ci CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */ 1738c2ecf20Sopenharmony_ci CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */ 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_cienum cx23885_custom_data_type { 1768c2ecf20Sopenharmony_ci CX23885_CUSTOM_EXTENSION_USR_DATA, 1778c2ecf20Sopenharmony_ci CX23885_CUSTOM_PRIVATE_PACKET, 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_cienum cx23885_mute { 1808c2ecf20Sopenharmony_ci CX23885_UNMUTE, 1818c2ecf20Sopenharmony_ci CX23885_MUTE, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_cienum cx23885_mute_video_mask { 1848c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00, 1858c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000, 1868c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_cienum cx23885_mute_video_shift { 1898c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_V_SHIFT = 8, 1908c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_U_SHIFT = 16, 1918c2ecf20Sopenharmony_ci CX23885_MUTE_VIDEO_Y_SHIFT = 24, 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* defines below are from ivtv-driver.h */ 1958c2ecf20Sopenharmony_ci#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* Firmware API commands */ 1988c2ecf20Sopenharmony_ci#define IVTV_API_STD_TIMEOUT 500 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/* Registers */ 2018c2ecf20Sopenharmony_ci/* IVTV_REG_OFFSET */ 2028c2ecf20Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) 2038c2ecf20Sopenharmony_ci#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) 2048c2ecf20Sopenharmony_ci#define IVTV_REG_SPU (0x9050) 2058c2ecf20Sopenharmony_ci#define IVTV_REG_HW_BLOCKS (0x9054) 2068c2ecf20Sopenharmony_ci#define IVTV_REG_VPU (0x9058) 2078c2ecf20Sopenharmony_ci#define IVTV_REG_APU (0xA064) 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/**** Bit definitions for MC417_RWD and MC417_OEN registers *** 2108c2ecf20Sopenharmony_ci bits 31-16 2118c2ecf20Sopenharmony_ci+-----------+ 2128c2ecf20Sopenharmony_ci| Reserved | 2138c2ecf20Sopenharmony_ci+-----------+ 2148c2ecf20Sopenharmony_ci bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 2158c2ecf20Sopenharmony_ci+-------+-------+-------+-------+-------+-------+-------+-------+ 2168c2ecf20Sopenharmony_ci| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| 2178c2ecf20Sopenharmony_ci+-------+-------+-------+-------+-------+-------+-------+-------+ 2188c2ecf20Sopenharmony_ci bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 2198c2ecf20Sopenharmony_ci+-------+-------+-------+-------+-------+-------+-------+-------+ 2208c2ecf20Sopenharmony_ci|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| 2218c2ecf20Sopenharmony_ci+-------+-------+-------+-------+-------+-------+-------+-------+ 2228c2ecf20Sopenharmony_ci***/ 2238c2ecf20Sopenharmony_ci#define MC417_MIWR 0x8000 2248c2ecf20Sopenharmony_ci#define MC417_MIRD 0x4000 2258c2ecf20Sopenharmony_ci#define MC417_MICS 0x2000 2268c2ecf20Sopenharmony_ci#define MC417_MIRDY 0x1000 2278c2ecf20Sopenharmony_ci#define MC417_MIADDR 0x0F00 2288c2ecf20Sopenharmony_ci#define MC417_MIDATA 0x00FF 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* MIADDR* nibble definitions */ 2318c2ecf20Sopenharmony_ci#define MCI_MEMORY_DATA_BYTE0 0x000 2328c2ecf20Sopenharmony_ci#define MCI_MEMORY_DATA_BYTE1 0x100 2338c2ecf20Sopenharmony_ci#define MCI_MEMORY_DATA_BYTE2 0x200 2348c2ecf20Sopenharmony_ci#define MCI_MEMORY_DATA_BYTE3 0x300 2358c2ecf20Sopenharmony_ci#define MCI_MEMORY_ADDRESS_BYTE2 0x400 2368c2ecf20Sopenharmony_ci#define MCI_MEMORY_ADDRESS_BYTE1 0x500 2378c2ecf20Sopenharmony_ci#define MCI_MEMORY_ADDRESS_BYTE0 0x600 2388c2ecf20Sopenharmony_ci#define MCI_REGISTER_DATA_BYTE0 0x800 2398c2ecf20Sopenharmony_ci#define MCI_REGISTER_DATA_BYTE1 0x900 2408c2ecf20Sopenharmony_ci#define MCI_REGISTER_DATA_BYTE2 0xA00 2418c2ecf20Sopenharmony_ci#define MCI_REGISTER_DATA_BYTE3 0xB00 2428c2ecf20Sopenharmony_ci#define MCI_REGISTER_ADDRESS_BYTE0 0xC00 2438c2ecf20Sopenharmony_ci#define MCI_REGISTER_ADDRESS_BYTE1 0xD00 2448c2ecf20Sopenharmony_ci#define MCI_REGISTER_MODE 0xE00 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* Read and write modes */ 2478c2ecf20Sopenharmony_ci#define MCI_MODE_REGISTER_READ 0 2488c2ecf20Sopenharmony_ci#define MCI_MODE_REGISTER_WRITE 1 2498c2ecf20Sopenharmony_ci#define MCI_MODE_MEMORY_READ 0 2508c2ecf20Sopenharmony_ci#define MCI_MODE_MEMORY_WRITE 0x40 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/*** Bit definitions for MC417_CTL register **** 2538c2ecf20Sopenharmony_ci bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 2548c2ecf20Sopenharmony_ci+--------+-------------+--------+--------------+------------+ 2558c2ecf20Sopenharmony_ci|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| 2568c2ecf20Sopenharmony_ci+--------+-------------+--------+--------------+------------+ 2578c2ecf20Sopenharmony_ci***/ 2588c2ecf20Sopenharmony_ci#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) 2598c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) 2608c2ecf20Sopenharmony_ci#define MC417_UART_GPIO_EN 0x00000001 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* Values for speed control */ 2638c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_SLOW 0x1 2648c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_MEDIUM 0x0 2658c2ecf20Sopenharmony_ci#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Values for GPIO select */ 2688c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO3 0x3 2698c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO2 0x2 2708c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO1 0x1 2718c2ecf20Sopenharmony_ci#define MC417_GPIO_SEL_GPIO0 0x0 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid cx23885_mc417_init(struct cx23885_dev *dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci u32 regval; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci dprintk(2, "%s()\n", __func__); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Configure MC417_CTL register to defaults. */ 2808c2ecf20Sopenharmony_ci regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) | 2818c2ecf20Sopenharmony_ci MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) | 2828c2ecf20Sopenharmony_ci MC417_UART_GPIO_EN; 2838c2ecf20Sopenharmony_ci cx_write(MC417_CTL, regval); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Configure MC417_OEN to defaults. */ 2868c2ecf20Sopenharmony_ci regval = MC417_MIRDY; 2878c2ecf20Sopenharmony_ci cx_write(MC417_OEN, regval); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Configure MC417_RWD to defaults. */ 2908c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS; 2918c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int mc417_wait_ready(struct cx23885_dev *dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci u32 mi_ready; 2978c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (;;) { 3008c2ecf20Sopenharmony_ci mi_ready = cx_read(MC417_RWD) & MC417_MIRDY; 3018c2ecf20Sopenharmony_ci if (mi_ready != 0) 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 3048c2ecf20Sopenharmony_ci return -1; 3058c2ecf20Sopenharmony_ci udelay(1); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciint mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci u32 regval; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Enable MC417 GPIO outputs except for MC417_MIRDY, 3148c2ecf20Sopenharmony_ci * which is an input. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Write data byte 0 */ 3198c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 | 3208c2ecf20Sopenharmony_ci (value & 0x000000FF); 3218c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Transition CS/WR to effect write transaction across bus. */ 3248c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3258c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Write data byte 1 */ 3288c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 | 3298c2ecf20Sopenharmony_ci ((value >> 8) & 0x000000FF); 3308c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3318c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3328c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Write data byte 2 */ 3358c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 | 3368c2ecf20Sopenharmony_ci ((value >> 16) & 0x000000FF); 3378c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3388c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3398c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Write data byte 3 */ 3428c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 | 3438c2ecf20Sopenharmony_ci ((value >> 24) & 0x000000FF); 3448c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3458c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3468c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Write address byte 0 */ 3498c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | 3508c2ecf20Sopenharmony_ci (address & 0xFF); 3518c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3528c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3538c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Write address byte 1 */ 3568c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | 3578c2ecf20Sopenharmony_ci ((address >> 8) & 0xFF); 3588c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3598c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3608c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Indicate that this is a write. */ 3638c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | 3648c2ecf20Sopenharmony_ci MCI_MODE_REGISTER_WRITE; 3658c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3668c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3678c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Wait for the trans to complete (MC417_MIRDY asserted). */ 3708c2ecf20Sopenharmony_ci return mc417_wait_ready(dev); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciint mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int retval; 3768c2ecf20Sopenharmony_ci u32 regval; 3778c2ecf20Sopenharmony_ci u32 tempval; 3788c2ecf20Sopenharmony_ci u32 dataval; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Enable MC417 GPIO outputs except for MC417_MIRDY, 3818c2ecf20Sopenharmony_ci * which is an input. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Write address byte 0 */ 3868c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | 3878c2ecf20Sopenharmony_ci ((address & 0x00FF)); 3888c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3898c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3908c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Write address byte 1 */ 3938c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | 3948c2ecf20Sopenharmony_ci ((address >> 8) & 0xFF); 3958c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3968c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 3978c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Indicate that this is a register read. */ 4008c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | 4018c2ecf20Sopenharmony_ci MCI_MODE_REGISTER_READ; 4028c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4038c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 4048c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Wait for the trans to complete (MC417_MIRDY asserted). */ 4078c2ecf20Sopenharmony_ci retval = mc417_wait_ready(dev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* switch the DAT0-7 GPIO[10:3] to input mode */ 4108c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Read data byte 0 */ 4138c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; 4148c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Transition RD to effect read transaction across bus. 4178c2ecf20Sopenharmony_ci * Transition 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)? 4188c2ecf20Sopenharmony_ci * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its 4198c2ecf20Sopenharmony_ci * input only...) 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; 4228c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Collect byte */ 4258c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 4268c2ecf20Sopenharmony_ci dataval = tempval & 0x000000FF; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Bring CS and RD high. */ 4298c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 4308c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Read data byte 1 */ 4338c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; 4348c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4358c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; 4368c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4378c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 4388c2ecf20Sopenharmony_ci dataval |= ((tempval & 0x000000FF) << 8); 4398c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 4408c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* Read data byte 2 */ 4438c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; 4448c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4458c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; 4468c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4478c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 4488c2ecf20Sopenharmony_ci dataval |= ((tempval & 0x000000FF) << 16); 4498c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 4508c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Read data byte 3 */ 4538c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; 4548c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4558c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; 4568c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4578c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 4588c2ecf20Sopenharmony_ci dataval |= ((tempval & 0x000000FF) << 24); 4598c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 4608c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci *value = dataval; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return retval; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ciint mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci u32 regval; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Enable MC417 GPIO outputs except for MC417_MIRDY, 4728c2ecf20Sopenharmony_ci * which is an input. 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Write data byte 0 */ 4778c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 | 4788c2ecf20Sopenharmony_ci (value & 0x000000FF); 4798c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Transition CS/WR to effect write transaction across bus. */ 4828c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 4838c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Write data byte 1 */ 4868c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 | 4878c2ecf20Sopenharmony_ci ((value >> 8) & 0x000000FF); 4888c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4898c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 4908c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Write data byte 2 */ 4938c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 | 4948c2ecf20Sopenharmony_ci ((value >> 16) & 0x000000FF); 4958c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4968c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 4978c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* Write data byte 3 */ 5008c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 | 5018c2ecf20Sopenharmony_ci ((value >> 24) & 0x000000FF); 5028c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5038c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5048c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* Write address byte 2 */ 5078c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | 5088c2ecf20Sopenharmony_ci MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F); 5098c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5108c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5118c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Write address byte 1 */ 5148c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | 5158c2ecf20Sopenharmony_ci ((address >> 8) & 0xFF); 5168c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5178c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5188c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Write address byte 0 */ 5218c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | 5228c2ecf20Sopenharmony_ci (address & 0xFF); 5238c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5248c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5258c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* Wait for the trans to complete (MC417_MIRDY asserted). */ 5288c2ecf20Sopenharmony_ci return mc417_wait_ready(dev); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ciint mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci int retval; 5348c2ecf20Sopenharmony_ci u32 regval; 5358c2ecf20Sopenharmony_ci u32 tempval; 5368c2ecf20Sopenharmony_ci u32 dataval; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Enable MC417 GPIO outputs except for MC417_MIRDY, 5398c2ecf20Sopenharmony_ci * which is an input. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Write address byte 2 */ 5448c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | 5458c2ecf20Sopenharmony_ci MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F); 5468c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5478c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5488c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Write address byte 1 */ 5518c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | 5528c2ecf20Sopenharmony_ci ((address >> 8) & 0xFF); 5538c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5548c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5558c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Write address byte 0 */ 5588c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | 5598c2ecf20Sopenharmony_ci (address & 0xFF); 5608c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5618c2ecf20Sopenharmony_ci regval |= MC417_MICS | MC417_MIWR; 5628c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Wait for the trans to complete (MC417_MIRDY asserted). */ 5658c2ecf20Sopenharmony_ci retval = mc417_wait_ready(dev); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* switch the DAT0-7 GPIO[10:3] to input mode */ 5688c2ecf20Sopenharmony_ci cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* Read data byte 3 */ 5718c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; 5728c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Transition RD to effect read transaction across bus. */ 5758c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; 5768c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Collect byte */ 5798c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 5808c2ecf20Sopenharmony_ci dataval = ((tempval & 0x000000FF) << 24); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Bring CS and RD high. */ 5838c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 5848c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Read data byte 2 */ 5878c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; 5888c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5898c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; 5908c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5918c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 5928c2ecf20Sopenharmony_ci dataval |= ((tempval & 0x000000FF) << 16); 5938c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 5948c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Read data byte 1 */ 5978c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; 5988c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 5998c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; 6008c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 6018c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 6028c2ecf20Sopenharmony_ci dataval |= ((tempval & 0x000000FF) << 8); 6038c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 6048c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Read data byte 0 */ 6078c2ecf20Sopenharmony_ci regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; 6088c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 6098c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; 6108c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 6118c2ecf20Sopenharmony_ci tempval = cx_read(MC417_RWD); 6128c2ecf20Sopenharmony_ci dataval |= (tempval & 0x000000FF); 6138c2ecf20Sopenharmony_ci regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; 6148c2ecf20Sopenharmony_ci cx_write(MC417_RWD, regval); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci *value = dataval; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return retval; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_civoid mc417_gpio_set(struct cx23885_dev *dev, u32 mask) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci u32 val; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* Set the gpio value */ 6268c2ecf20Sopenharmony_ci mc417_register_read(dev, 0x900C, &val); 6278c2ecf20Sopenharmony_ci val |= (mask & 0x000ffff); 6288c2ecf20Sopenharmony_ci mc417_register_write(dev, 0x900C, val); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_civoid mc417_gpio_clear(struct cx23885_dev *dev, u32 mask) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci u32 val; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Clear the gpio value */ 6368c2ecf20Sopenharmony_ci mc417_register_read(dev, 0x900C, &val); 6378c2ecf20Sopenharmony_ci val &= ~(mask & 0x0000ffff); 6388c2ecf20Sopenharmony_ci mc417_register_write(dev, 0x900C, val); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_civoid mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci u32 val; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Enable GPIO direction bits */ 6468c2ecf20Sopenharmony_ci mc417_register_read(dev, 0x9020, &val); 6478c2ecf20Sopenharmony_ci if (asoutput) 6488c2ecf20Sopenharmony_ci val |= (mask & 0x0000ffff); 6498c2ecf20Sopenharmony_ci else 6508c2ecf20Sopenharmony_ci val &= ~(mask & 0x0000ffff); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci mc417_register_write(dev, 0x9020, val); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/* MPEG encoder API */ 6578c2ecf20Sopenharmony_cistatic char *cmd_to_str(int cmd) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci switch (cmd) { 6608c2ecf20Sopenharmony_ci case CX2341X_ENC_PING_FW: 6618c2ecf20Sopenharmony_ci return "PING_FW"; 6628c2ecf20Sopenharmony_ci case CX2341X_ENC_START_CAPTURE: 6638c2ecf20Sopenharmony_ci return "START_CAPTURE"; 6648c2ecf20Sopenharmony_ci case CX2341X_ENC_STOP_CAPTURE: 6658c2ecf20Sopenharmony_ci return "STOP_CAPTURE"; 6668c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_AUDIO_ID: 6678c2ecf20Sopenharmony_ci return "SET_AUDIO_ID"; 6688c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_VIDEO_ID: 6698c2ecf20Sopenharmony_ci return "SET_VIDEO_ID"; 6708c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_PCR_ID: 6718c2ecf20Sopenharmony_ci return "SET_PCR_ID"; 6728c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_FRAME_RATE: 6738c2ecf20Sopenharmony_ci return "SET_FRAME_RATE"; 6748c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_FRAME_SIZE: 6758c2ecf20Sopenharmony_ci return "SET_FRAME_SIZE"; 6768c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_BIT_RATE: 6778c2ecf20Sopenharmony_ci return "SET_BIT_RATE"; 6788c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_GOP_PROPERTIES: 6798c2ecf20Sopenharmony_ci return "SET_GOP_PROPERTIES"; 6808c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_ASPECT_RATIO: 6818c2ecf20Sopenharmony_ci return "SET_ASPECT_RATIO"; 6828c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_DNR_FILTER_MODE: 6838c2ecf20Sopenharmony_ci return "SET_DNR_FILTER_MODE"; 6848c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_DNR_FILTER_PROPS: 6858c2ecf20Sopenharmony_ci return "SET_DNR_FILTER_PROPS"; 6868c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_CORING_LEVELS: 6878c2ecf20Sopenharmony_ci return "SET_CORING_LEVELS"; 6888c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: 6898c2ecf20Sopenharmony_ci return "SET_SPATIAL_FILTER_TYPE"; 6908c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_VBI_LINE: 6918c2ecf20Sopenharmony_ci return "SET_VBI_LINE"; 6928c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_STREAM_TYPE: 6938c2ecf20Sopenharmony_ci return "SET_STREAM_TYPE"; 6948c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_OUTPUT_PORT: 6958c2ecf20Sopenharmony_ci return "SET_OUTPUT_PORT"; 6968c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_AUDIO_PROPERTIES: 6978c2ecf20Sopenharmony_ci return "SET_AUDIO_PROPERTIES"; 6988c2ecf20Sopenharmony_ci case CX2341X_ENC_HALT_FW: 6998c2ecf20Sopenharmony_ci return "HALT_FW"; 7008c2ecf20Sopenharmony_ci case CX2341X_ENC_GET_VERSION: 7018c2ecf20Sopenharmony_ci return "GET_VERSION"; 7028c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_GOP_CLOSURE: 7038c2ecf20Sopenharmony_ci return "SET_GOP_CLOSURE"; 7048c2ecf20Sopenharmony_ci case CX2341X_ENC_GET_SEQ_END: 7058c2ecf20Sopenharmony_ci return "GET_SEQ_END"; 7068c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_PGM_INDEX_INFO: 7078c2ecf20Sopenharmony_ci return "SET_PGM_INDEX_INFO"; 7088c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_VBI_CONFIG: 7098c2ecf20Sopenharmony_ci return "SET_VBI_CONFIG"; 7108c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_DMA_BLOCK_SIZE: 7118c2ecf20Sopenharmony_ci return "SET_DMA_BLOCK_SIZE"; 7128c2ecf20Sopenharmony_ci case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: 7138c2ecf20Sopenharmony_ci return "GET_PREV_DMA_INFO_MB_10"; 7148c2ecf20Sopenharmony_ci case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: 7158c2ecf20Sopenharmony_ci return "GET_PREV_DMA_INFO_MB_9"; 7168c2ecf20Sopenharmony_ci case CX2341X_ENC_SCHED_DMA_TO_HOST: 7178c2ecf20Sopenharmony_ci return "SCHED_DMA_TO_HOST"; 7188c2ecf20Sopenharmony_ci case CX2341X_ENC_INITIALIZE_INPUT: 7198c2ecf20Sopenharmony_ci return "INITIALIZE_INPUT"; 7208c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_FRAME_DROP_RATE: 7218c2ecf20Sopenharmony_ci return "SET_FRAME_DROP_RATE"; 7228c2ecf20Sopenharmony_ci case CX2341X_ENC_PAUSE_ENCODER: 7238c2ecf20Sopenharmony_ci return "PAUSE_ENCODER"; 7248c2ecf20Sopenharmony_ci case CX2341X_ENC_REFRESH_INPUT: 7258c2ecf20Sopenharmony_ci return "REFRESH_INPUT"; 7268c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_COPYRIGHT: 7278c2ecf20Sopenharmony_ci return "SET_COPYRIGHT"; 7288c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_EVENT_NOTIFICATION: 7298c2ecf20Sopenharmony_ci return "SET_EVENT_NOTIFICATION"; 7308c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_NUM_VSYNC_LINES: 7318c2ecf20Sopenharmony_ci return "SET_NUM_VSYNC_LINES"; 7328c2ecf20Sopenharmony_ci case CX2341X_ENC_SET_PLACEHOLDER: 7338c2ecf20Sopenharmony_ci return "SET_PLACEHOLDER"; 7348c2ecf20Sopenharmony_ci case CX2341X_ENC_MUTE_VIDEO: 7358c2ecf20Sopenharmony_ci return "MUTE_VIDEO"; 7368c2ecf20Sopenharmony_ci case CX2341X_ENC_MUTE_AUDIO: 7378c2ecf20Sopenharmony_ci return "MUTE_AUDIO"; 7388c2ecf20Sopenharmony_ci case CX2341X_ENC_MISC: 7398c2ecf20Sopenharmony_ci return "MISC"; 7408c2ecf20Sopenharmony_ci default: 7418c2ecf20Sopenharmony_ci return "UNKNOWN"; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int cx23885_mbox_func(void *priv, 7468c2ecf20Sopenharmony_ci u32 command, 7478c2ecf20Sopenharmony_ci int in, 7488c2ecf20Sopenharmony_ci int out, 7498c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct cx23885_dev *dev = priv; 7528c2ecf20Sopenharmony_ci unsigned long timeout; 7538c2ecf20Sopenharmony_ci u32 value, flag, retval = 0; 7548c2ecf20Sopenharmony_ci int i; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, 7578c2ecf20Sopenharmony_ci cmd_to_str(command)); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* this may not be 100% safe if we can't read any memory location 7608c2ecf20Sopenharmony_ci without side effects */ 7618c2ecf20Sopenharmony_ci mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); 7628c2ecf20Sopenharmony_ci if (value != 0x12345678) { 7638c2ecf20Sopenharmony_ci pr_err("Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", 7648c2ecf20Sopenharmony_ci value, cmd_to_str(command)); 7658c2ecf20Sopenharmony_ci return -1; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* This read looks at 32 bits, but flag is only 8 bits. 7698c2ecf20Sopenharmony_ci * Seems we also bail if CMD or TIMEOUT bytes are set??? 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci mc417_memory_read(dev, dev->cx23417_mailbox, &flag); 7728c2ecf20Sopenharmony_ci if (flag) { 7738c2ecf20Sopenharmony_ci pr_err("ERROR: Mailbox appears to be in use (%x), cmd = %s\n", 7748c2ecf20Sopenharmony_ci flag, cmd_to_str(command)); 7758c2ecf20Sopenharmony_ci return -1; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci flag |= 1; /* tell 'em we're working on it */ 7798c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox, flag); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* write command + args + fill remaining with zeros */ 7828c2ecf20Sopenharmony_ci /* command code */ 7838c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); 7848c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox + 3, 7858c2ecf20Sopenharmony_ci IVTV_API_STD_TIMEOUT); /* timeout */ 7868c2ecf20Sopenharmony_ci for (i = 0; i < in; i++) { 7878c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); 7888c2ecf20Sopenharmony_ci dprintk(3, "API Input %d = %d\n", i, data[i]); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci for (; i < CX2341X_MBOX_MAX_DATA; i++) 7918c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci flag |= 3; /* tell 'em we're done writing */ 7948c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox, flag); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* wait for firmware to handle the API command */ 7978c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(10); 7988c2ecf20Sopenharmony_ci for (;;) { 7998c2ecf20Sopenharmony_ci mc417_memory_read(dev, dev->cx23417_mailbox, &flag); 8008c2ecf20Sopenharmony_ci if (0 != (flag & 4)) 8018c2ecf20Sopenharmony_ci break; 8028c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 8038c2ecf20Sopenharmony_ci pr_err("ERROR: API Mailbox timeout\n"); 8048c2ecf20Sopenharmony_ci return -1; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci udelay(10); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* read output values */ 8108c2ecf20Sopenharmony_ci for (i = 0; i < out; i++) { 8118c2ecf20Sopenharmony_ci mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); 8128c2ecf20Sopenharmony_ci dprintk(3, "API Output %d = %d\n", i, data[i]); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); 8168c2ecf20Sopenharmony_ci dprintk(3, "API result = %d\n", retval); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci flag = 0; 8198c2ecf20Sopenharmony_ci mc417_memory_write(dev, dev->cx23417_mailbox, flag); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return retval; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/* We don't need to call the API often, so using just one 8258c2ecf20Sopenharmony_ci * mailbox will probably suffice 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_cistatic int cx23885_api_cmd(struct cx23885_dev *dev, 8288c2ecf20Sopenharmony_ci u32 command, 8298c2ecf20Sopenharmony_ci u32 inputcnt, 8308c2ecf20Sopenharmony_ci u32 outputcnt, 8318c2ecf20Sopenharmony_ci ...) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 8348c2ecf20Sopenharmony_ci va_list vargs; 8358c2ecf20Sopenharmony_ci int i, err; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci va_start(vargs, outputcnt); 8408c2ecf20Sopenharmony_ci for (i = 0; i < inputcnt; i++) 8418c2ecf20Sopenharmony_ci data[i] = va_arg(vargs, int); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data); 8448c2ecf20Sopenharmony_ci for (i = 0; i < outputcnt; i++) { 8458c2ecf20Sopenharmony_ci int *vptr = va_arg(vargs, int *); 8468c2ecf20Sopenharmony_ci *vptr = data[i]; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci va_end(vargs); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return err; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci return cx23885_mbox_func(priv, cmd, in, out, data); 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int cx23885_find_mailbox(struct cx23885_dev *dev) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci u32 signature[4] = { 8618c2ecf20Sopenharmony_ci 0x12345678, 0x34567812, 0x56781234, 0x78123456 8628c2ecf20Sopenharmony_ci }; 8638c2ecf20Sopenharmony_ci int signaturecnt = 0; 8648c2ecf20Sopenharmony_ci u32 value; 8658c2ecf20Sopenharmony_ci int i; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci dprintk(2, "%s()\n", __func__); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) { 8708c2ecf20Sopenharmony_ci mc417_memory_read(dev, i, &value); 8718c2ecf20Sopenharmony_ci if (value == signature[signaturecnt]) 8728c2ecf20Sopenharmony_ci signaturecnt++; 8738c2ecf20Sopenharmony_ci else 8748c2ecf20Sopenharmony_ci signaturecnt = 0; 8758c2ecf20Sopenharmony_ci if (4 == signaturecnt) { 8768c2ecf20Sopenharmony_ci dprintk(1, "Mailbox signature found at 0x%x\n", i+1); 8778c2ecf20Sopenharmony_ci return i+1; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci pr_err("Mailbox signature values not found!\n"); 8818c2ecf20Sopenharmony_ci return -1; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int cx23885_load_firmware(struct cx23885_dev *dev) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci static const unsigned char magic[8] = { 8878c2ecf20Sopenharmony_ci 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa 8888c2ecf20Sopenharmony_ci }; 8898c2ecf20Sopenharmony_ci const struct firmware *firmware; 8908c2ecf20Sopenharmony_ci int i, retval = 0; 8918c2ecf20Sopenharmony_ci u32 value = 0; 8928c2ecf20Sopenharmony_ci u32 gpio_output = 0; 8938c2ecf20Sopenharmony_ci u32 gpio_value; 8948c2ecf20Sopenharmony_ci u32 checksum = 0; 8958c2ecf20Sopenharmony_ci u32 *dataptr; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci dprintk(2, "%s()\n", __func__); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* Save GPIO settings before reset of APU */ 9008c2ecf20Sopenharmony_ci retval |= mc417_memory_read(dev, 0x9020, &gpio_output); 9018c2ecf20Sopenharmony_ci retval |= mc417_memory_read(dev, 0x900C, &gpio_value); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci retval = mc417_register_write(dev, 9048c2ecf20Sopenharmony_ci IVTV_REG_VPU, 0xFFFFFFED); 9058c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 9068c2ecf20Sopenharmony_ci IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); 9078c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 9088c2ecf20Sopenharmony_ci IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); 9098c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 9108c2ecf20Sopenharmony_ci IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); 9118c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 9128c2ecf20Sopenharmony_ci IVTV_REG_APU, 0); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (retval != 0) { 9158c2ecf20Sopenharmony_ci pr_err("%s: Error with mc417_register_write\n", 9168c2ecf20Sopenharmony_ci __func__); 9178c2ecf20Sopenharmony_ci return -1; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME, 9218c2ecf20Sopenharmony_ci &dev->pci->dev); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (retval != 0) { 9248c2ecf20Sopenharmony_ci pr_err("ERROR: Hotplug firmware request failed (%s).\n", 9258c2ecf20Sopenharmony_ci CX23885_FIRM_IMAGE_NAME); 9268c2ecf20Sopenharmony_ci pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n"); 9278c2ecf20Sopenharmony_ci return -1; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { 9318c2ecf20Sopenharmony_ci pr_err("ERROR: Firmware size mismatch (have %zu, expected %d)\n", 9328c2ecf20Sopenharmony_ci firmware->size, CX23885_FIRM_IMAGE_SIZE); 9338c2ecf20Sopenharmony_ci release_firmware(firmware); 9348c2ecf20Sopenharmony_ci return -1; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (0 != memcmp(firmware->data, magic, 8)) { 9388c2ecf20Sopenharmony_ci pr_err("ERROR: Firmware magic mismatch, wrong file?\n"); 9398c2ecf20Sopenharmony_ci release_firmware(firmware); 9408c2ecf20Sopenharmony_ci return -1; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* transfer to the chip */ 9448c2ecf20Sopenharmony_ci dprintk(2, "Loading firmware ...\n"); 9458c2ecf20Sopenharmony_ci dataptr = (u32 *)firmware->data; 9468c2ecf20Sopenharmony_ci for (i = 0; i < (firmware->size >> 2); i++) { 9478c2ecf20Sopenharmony_ci value = *dataptr; 9488c2ecf20Sopenharmony_ci checksum += ~value; 9498c2ecf20Sopenharmony_ci if (mc417_memory_write(dev, i, value) != 0) { 9508c2ecf20Sopenharmony_ci pr_err("ERROR: Loading firmware failed!\n"); 9518c2ecf20Sopenharmony_ci release_firmware(firmware); 9528c2ecf20Sopenharmony_ci return -1; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci dataptr++; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci /* read back to verify with the checksum */ 9588c2ecf20Sopenharmony_ci dprintk(1, "Verifying firmware ...\n"); 9598c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 9608c2ecf20Sopenharmony_ci if (mc417_memory_read(dev, i, &value) != 0) { 9618c2ecf20Sopenharmony_ci pr_err("ERROR: Reading firmware failed!\n"); 9628c2ecf20Sopenharmony_ci release_firmware(firmware); 9638c2ecf20Sopenharmony_ci return -1; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci checksum -= ~value; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci if (checksum) { 9688c2ecf20Sopenharmony_ci pr_err("ERROR: Firmware load failed (checksum mismatch).\n"); 9698c2ecf20Sopenharmony_ci release_firmware(firmware); 9708c2ecf20Sopenharmony_ci return -1; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci release_firmware(firmware); 9738c2ecf20Sopenharmony_ci dprintk(1, "Firmware upload successful.\n"); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, 9768c2ecf20Sopenharmony_ci IVTV_CMD_HW_BLOCKS_RST); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* F/W power up disturbs the GPIOs, restore state */ 9798c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 0x9020, gpio_output); 9808c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 0x900C, gpio_value); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); 9838c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Hardcoded GPIO's here */ 9868c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 0x9020, 0x4000); 9878c2ecf20Sopenharmony_ci retval |= mc417_register_write(dev, 0x900C, 0x4000); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci mc417_register_read(dev, 0x9020, &gpio_output); 9908c2ecf20Sopenharmony_ci mc417_register_read(dev, 0x900C, &gpio_value); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (retval < 0) 9938c2ecf20Sopenharmony_ci pr_err("%s: Error with mc417_register_write\n", 9948c2ecf20Sopenharmony_ci __func__); 9958c2ecf20Sopenharmony_ci return 0; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_civoid cx23885_417_check_encoder(struct cx23885_dev *dev) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci u32 status, seq; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci status = seq = 0; 10038c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); 10048c2ecf20Sopenharmony_ci dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic void cx23885_codec_settings(struct cx23885_dev *dev) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* Dynamically change the height based on video standard */ 10128c2ecf20Sopenharmony_ci if (dev->encodernorm.id & V4L2_STD_525_60) 10138c2ecf20Sopenharmony_ci dev->ts1.height = 480; 10148c2ecf20Sopenharmony_ci else 10158c2ecf20Sopenharmony_ci dev->ts1.height = 576; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* assign frame size */ 10188c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, 10198c2ecf20Sopenharmony_ci dev->ts1.height, dev->ts1.width); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci dev->cxhdl.width = dev->ts1.width; 10228c2ecf20Sopenharmony_ci dev->cxhdl.height = dev->ts1.height; 10238c2ecf20Sopenharmony_ci dev->cxhdl.is_50hz = 10248c2ecf20Sopenharmony_ci (dev->encodernorm.id & V4L2_STD_625_50) != 0; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci cx2341x_handler_setup(&dev->cxhdl); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); 10298c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci int version; 10358c2ecf20Sopenharmony_ci int retval; 10368c2ecf20Sopenharmony_ci u32 i, data[7]; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ 10418c2ecf20Sopenharmony_ci if (retval < 0) { 10428c2ecf20Sopenharmony_ci dprintk(2, "%s() PING OK\n", __func__); 10438c2ecf20Sopenharmony_ci retval = cx23885_load_firmware(dev); 10448c2ecf20Sopenharmony_ci if (retval < 0) { 10458c2ecf20Sopenharmony_ci pr_err("%s() f/w load failed\n", __func__); 10468c2ecf20Sopenharmony_ci return retval; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci retval = cx23885_find_mailbox(dev); 10498c2ecf20Sopenharmony_ci if (retval < 0) { 10508c2ecf20Sopenharmony_ci pr_err("%s() mailbox < 0, error\n", 10518c2ecf20Sopenharmony_ci __func__); 10528c2ecf20Sopenharmony_ci return -1; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci dev->cx23417_mailbox = retval; 10558c2ecf20Sopenharmony_ci retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); 10568c2ecf20Sopenharmony_ci if (retval < 0) { 10578c2ecf20Sopenharmony_ci pr_err("ERROR: cx23417 firmware ping failed!\n"); 10588c2ecf20Sopenharmony_ci return -1; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, 10618c2ecf20Sopenharmony_ci &version); 10628c2ecf20Sopenharmony_ci if (retval < 0) { 10638c2ecf20Sopenharmony_ci pr_err("ERROR: cx23417 firmware get encoder :version failed!\n"); 10648c2ecf20Sopenharmony_ci return -1; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci dprintk(1, "cx23417 firmware version is 0x%08x\n", version); 10678c2ecf20Sopenharmony_ci msleep(200); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci cx23885_codec_settings(dev); 10718c2ecf20Sopenharmony_ci msleep(60); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, 10748c2ecf20Sopenharmony_ci CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115); 10758c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, 10768c2ecf20Sopenharmony_ci CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10778c2ecf20Sopenharmony_ci 0, 0); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* Setup to capture VBI */ 10808c2ecf20Sopenharmony_ci data[0] = 0x0001BD00; 10818c2ecf20Sopenharmony_ci data[1] = 1; /* frames per interrupt */ 10828c2ecf20Sopenharmony_ci data[2] = 4; /* total bufs */ 10838c2ecf20Sopenharmony_ci data[3] = 0x91559155; /* start codes */ 10848c2ecf20Sopenharmony_ci data[4] = 0x206080C0; /* stop codes */ 10858c2ecf20Sopenharmony_ci data[5] = 6; /* lines */ 10868c2ecf20Sopenharmony_ci data[6] = 64; /* BPL */ 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], 10898c2ecf20Sopenharmony_ci data[2], data[3], data[4], data[5], data[6]); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci for (i = 2; i <= 24; i++) { 10928c2ecf20Sopenharmony_ci int valid; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci valid = ((i >= 19) && (i <= 21)); 10958c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, 10968c2ecf20Sopenharmony_ci valid, 0 , 0, 0); 10978c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, 10988c2ecf20Sopenharmony_ci i | 0x80000000, valid, 0, 0, 0); 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE); 11028c2ecf20Sopenharmony_ci msleep(60); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* initialize the video input */ 11058c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); 11068c2ecf20Sopenharmony_ci msleep(60); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* Enable VIP style pixel invalidation so we work with scaled mode */ 11098c2ecf20Sopenharmony_ci mc417_memory_write(dev, 2120, 0x00000080); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* start capturing to the host interface */ 11128c2ecf20Sopenharmony_ci if (startencoder) { 11138c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 11148c2ecf20Sopenharmony_ci CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); 11158c2ecf20Sopenharmony_ci msleep(10); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return 0; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int queue_setup(struct vb2_queue *q, 11248c2ecf20Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 11258c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct cx23885_dev *dev = q->drv_priv; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci dev->ts1.ts_packet_size = mpeglinesize; 11308c2ecf20Sopenharmony_ci dev->ts1.ts_packet_count = mpeglines; 11318c2ecf20Sopenharmony_ci *num_planes = 1; 11328c2ecf20Sopenharmony_ci sizes[0] = mpeglinesize * mpeglines; 11338c2ecf20Sopenharmony_ci *num_buffers = mpegbufs; 11348c2ecf20Sopenharmony_ci return 0; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int buffer_prepare(struct vb2_buffer *vb) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 11408c2ecf20Sopenharmony_ci struct cx23885_dev *dev = vb->vb2_queue->drv_priv; 11418c2ecf20Sopenharmony_ci struct cx23885_buffer *buf = 11428c2ecf20Sopenharmony_ci container_of(vbuf, struct cx23885_buffer, vb); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return cx23885_buf_prepare(buf, &dev->ts1); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic void buffer_finish(struct vb2_buffer *vb) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 11508c2ecf20Sopenharmony_ci struct cx23885_dev *dev = vb->vb2_queue->drv_priv; 11518c2ecf20Sopenharmony_ci struct cx23885_buffer *buf = container_of(vbuf, 11528c2ecf20Sopenharmony_ci struct cx23885_buffer, vb); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci cx23885_free_buffer(dev, buf); 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic void buffer_queue(struct vb2_buffer *vb) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 11608c2ecf20Sopenharmony_ci struct cx23885_dev *dev = vb->vb2_queue->drv_priv; 11618c2ecf20Sopenharmony_ci struct cx23885_buffer *buf = container_of(vbuf, 11628c2ecf20Sopenharmony_ci struct cx23885_buffer, vb); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci cx23885_buf_queue(&dev->ts1, buf); 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci struct cx23885_dev *dev = q->drv_priv; 11708c2ecf20Sopenharmony_ci struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq; 11718c2ecf20Sopenharmony_ci unsigned long flags; 11728c2ecf20Sopenharmony_ci int ret; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci ret = cx23885_initialize_codec(dev, 1); 11758c2ecf20Sopenharmony_ci if (ret == 0) { 11768c2ecf20Sopenharmony_ci struct cx23885_buffer *buf = list_entry(dmaq->active.next, 11778c2ecf20Sopenharmony_ci struct cx23885_buffer, queue); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci cx23885_start_dma(&dev->ts1, dmaq, buf); 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 11838c2ecf20Sopenharmony_ci while (!list_empty(&dmaq->active)) { 11848c2ecf20Sopenharmony_ci struct cx23885_buffer *buf = list_entry(dmaq->active.next, 11858c2ecf20Sopenharmony_ci struct cx23885_buffer, queue); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci list_del(&buf->queue); 11888c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 11918c2ecf20Sopenharmony_ci return ret; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic void cx23885_stop_streaming(struct vb2_queue *q) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct cx23885_dev *dev = q->drv_priv; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* stop mpeg capture */ 11998c2ecf20Sopenharmony_ci cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, 12008c2ecf20Sopenharmony_ci CX23885_END_NOW, CX23885_MPEG_CAPTURE, 12018c2ecf20Sopenharmony_ci CX23885_RAW_BITS_NONE); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci msleep(500); 12048c2ecf20Sopenharmony_ci cx23885_417_check_encoder(dev); 12058c2ecf20Sopenharmony_ci cx23885_cancel_buffers(&dev->ts1); 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic const struct vb2_ops cx23885_qops = { 12098c2ecf20Sopenharmony_ci .queue_setup = queue_setup, 12108c2ecf20Sopenharmony_ci .buf_prepare = buffer_prepare, 12118c2ecf20Sopenharmony_ci .buf_finish = buffer_finish, 12128c2ecf20Sopenharmony_ci .buf_queue = buffer_queue, 12138c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 12148c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 12158c2ecf20Sopenharmony_ci .start_streaming = cx23885_start_streaming, 12168c2ecf20Sopenharmony_ci .stop_streaming = cx23885_stop_streaming, 12178c2ecf20Sopenharmony_ci}; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci *id = dev->tvnorm; 12268c2ecf20Sopenharmony_ci return 0; 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) 12308c2ecf20Sopenharmony_ci{ 12318c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 12328c2ecf20Sopenharmony_ci unsigned int i; 12338c2ecf20Sopenharmony_ci int ret; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) 12368c2ecf20Sopenharmony_ci if (id & cx23885_tvnorms[i].id) 12378c2ecf20Sopenharmony_ci break; 12388c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(cx23885_tvnorms)) 12398c2ecf20Sopenharmony_ci return -EINVAL; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci ret = cx23885_set_tvnorm(dev, id); 12428c2ecf20Sopenharmony_ci if (!ret) 12438c2ecf20Sopenharmony_ci dev->encodernorm = cx23885_tvnorms[i]; 12448c2ecf20Sopenharmony_ci return ret; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *priv, 12488c2ecf20Sopenharmony_ci struct v4l2_input *i) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 12518c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12528c2ecf20Sopenharmony_ci return cx23885_enum_input(dev, i); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *priv, unsigned int *i) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci return cx23885_get_input(file, priv, i); 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *priv, unsigned int i) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci return cx23885_set_input(file, priv, i); 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic int vidioc_g_tuner(struct file *file, void *priv, 12668c2ecf20Sopenharmony_ci struct v4l2_tuner *t) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (dev->tuner_type == TUNER_ABSENT) 12718c2ecf20Sopenharmony_ci return -EINVAL; 12728c2ecf20Sopenharmony_ci if (0 != t->index) 12738c2ecf20Sopenharmony_ci return -EINVAL; 12748c2ecf20Sopenharmony_ci strscpy(t->name, "Television", sizeof(t->name)); 12758c2ecf20Sopenharmony_ci call_all(dev, tuner, g_tuner, t); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int vidioc_s_tuner(struct file *file, void *priv, 12838c2ecf20Sopenharmony_ci const struct v4l2_tuner *t) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (dev->tuner_type == TUNER_ABSENT) 12888c2ecf20Sopenharmony_ci return -EINVAL; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* Update the A/V core */ 12918c2ecf20Sopenharmony_ci call_all(dev, tuner, s_tuner, t); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int vidioc_g_frequency(struct file *file, void *priv, 12978c2ecf20Sopenharmony_ci struct v4l2_frequency *f) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (dev->tuner_type == TUNER_ABSENT) 13028c2ecf20Sopenharmony_ci return -EINVAL; 13038c2ecf20Sopenharmony_ci f->type = V4L2_TUNER_ANALOG_TV; 13048c2ecf20Sopenharmony_ci f->frequency = dev->freq; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci call_all(dev, tuner, g_frequency, f); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci return 0; 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_cistatic int vidioc_s_frequency(struct file *file, void *priv, 13128c2ecf20Sopenharmony_ci const struct v4l2_frequency *f) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci return cx23885_set_frequency(file, priv, f); 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 13188c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 13218c2ecf20Sopenharmony_ci struct cx23885_tsport *tsport = &dev->ts1; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci strscpy(cap->driver, dev->name, sizeof(cap->driver)); 13248c2ecf20Sopenharmony_ci strscpy(cap->card, cx23885_boards[tsport->dev->board].name, 13258c2ecf20Sopenharmony_ci sizeof(cap->card)); 13268c2ecf20Sopenharmony_ci sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); 13278c2ecf20Sopenharmony_ci cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 13288c2ecf20Sopenharmony_ci V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | 13298c2ecf20Sopenharmony_ci V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS; 13308c2ecf20Sopenharmony_ci if (dev->tuner_type != TUNER_ABSENT) 13318c2ecf20Sopenharmony_ci cap->capabilities |= V4L2_CAP_TUNER; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return 0; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 13378c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci if (f->index != 0) 13408c2ecf20Sopenharmony_ci return -EINVAL; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_MPEG; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci return 0; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 13488c2ecf20Sopenharmony_ci struct v4l2_format *f) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 13538c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 13548c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = 13558c2ecf20Sopenharmony_ci dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; 13568c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = 0; 13578c2ecf20Sopenharmony_ci f->fmt.pix.width = dev->ts1.width; 13588c2ecf20Sopenharmony_ci f->fmt.pix.height = dev->ts1.height; 13598c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 13608c2ecf20Sopenharmony_ci dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", 13618c2ecf20Sopenharmony_ci dev->ts1.width, dev->ts1.height); 13628c2ecf20Sopenharmony_ci return 0; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 13668c2ecf20Sopenharmony_ci struct v4l2_format *f) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 13718c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 13728c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = 13738c2ecf20Sopenharmony_ci dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; 13748c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = 0; 13758c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 13768c2ecf20Sopenharmony_ci dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", 13778c2ecf20Sopenharmony_ci dev->ts1.width, dev->ts1.height); 13788c2ecf20Sopenharmony_ci return 0; 13798c2ecf20Sopenharmony_ci} 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 13828c2ecf20Sopenharmony_ci struct v4l2_format *f) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 13878c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 13888c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = 13898c2ecf20Sopenharmony_ci dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; 13908c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = 0; 13918c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 13928c2ecf20Sopenharmony_ci dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", 13938c2ecf20Sopenharmony_ci f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); 13948c2ecf20Sopenharmony_ci return 0; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int vidioc_log_status(struct file *file, void *priv) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct cx23885_dev *dev = video_drvdata(file); 14008c2ecf20Sopenharmony_ci char name[32 + 2]; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s/2", dev->name); 14038c2ecf20Sopenharmony_ci call_all(dev, core, log_status); 14048c2ecf20Sopenharmony_ci v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); 14058c2ecf20Sopenharmony_ci return 0; 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations mpeg_fops = { 14098c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14108c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 14118c2ecf20Sopenharmony_ci .release = vb2_fop_release, 14128c2ecf20Sopenharmony_ci .read = vb2_fop_read, 14138c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 14148c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 14158c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 14168c2ecf20Sopenharmony_ci}; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops mpeg_ioctl_ops = { 14198c2ecf20Sopenharmony_ci .vidioc_g_std = vidioc_g_std, 14208c2ecf20Sopenharmony_ci .vidioc_s_std = vidioc_s_std, 14218c2ecf20Sopenharmony_ci .vidioc_enum_input = vidioc_enum_input, 14228c2ecf20Sopenharmony_ci .vidioc_g_input = vidioc_g_input, 14238c2ecf20Sopenharmony_ci .vidioc_s_input = vidioc_s_input, 14248c2ecf20Sopenharmony_ci .vidioc_g_tuner = vidioc_g_tuner, 14258c2ecf20Sopenharmony_ci .vidioc_s_tuner = vidioc_s_tuner, 14268c2ecf20Sopenharmony_ci .vidioc_g_frequency = vidioc_g_frequency, 14278c2ecf20Sopenharmony_ci .vidioc_s_frequency = vidioc_s_frequency, 14288c2ecf20Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 14298c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 14308c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 14318c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 14328c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 14338c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 14348c2ecf20Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 14358c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 14368c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 14378c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 14388c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 14398c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 14408c2ecf20Sopenharmony_ci .vidioc_log_status = vidioc_log_status, 14418c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 14428c2ecf20Sopenharmony_ci .vidioc_g_chip_info = cx23885_g_chip_info, 14438c2ecf20Sopenharmony_ci .vidioc_g_register = cx23885_g_register, 14448c2ecf20Sopenharmony_ci .vidioc_s_register = cx23885_s_register, 14458c2ecf20Sopenharmony_ci#endif 14468c2ecf20Sopenharmony_ci}; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic struct video_device cx23885_mpeg_template = { 14498c2ecf20Sopenharmony_ci .name = "cx23885", 14508c2ecf20Sopenharmony_ci .fops = &mpeg_fops, 14518c2ecf20Sopenharmony_ci .ioctl_ops = &mpeg_ioctl_ops, 14528c2ecf20Sopenharmony_ci .tvnorms = CX23885_NORMS, 14538c2ecf20Sopenharmony_ci}; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_civoid cx23885_417_unregister(struct cx23885_dev *dev) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (dev->v4l_device) { 14608c2ecf20Sopenharmony_ci if (video_is_registered(dev->v4l_device)) 14618c2ecf20Sopenharmony_ci video_unregister_device(dev->v4l_device); 14628c2ecf20Sopenharmony_ci else 14638c2ecf20Sopenharmony_ci video_device_release(dev->v4l_device); 14648c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&dev->cxhdl.hdl); 14658c2ecf20Sopenharmony_ci dev->v4l_device = NULL; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic struct video_device *cx23885_video_dev_alloc( 14708c2ecf20Sopenharmony_ci struct cx23885_tsport *tsport, 14718c2ecf20Sopenharmony_ci struct pci_dev *pci, 14728c2ecf20Sopenharmony_ci struct video_device *template, 14738c2ecf20Sopenharmony_ci char *type) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct video_device *vfd; 14768c2ecf20Sopenharmony_ci struct cx23885_dev *dev = tsport->dev; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci vfd = video_device_alloc(); 14818c2ecf20Sopenharmony_ci if (NULL == vfd) 14828c2ecf20Sopenharmony_ci return NULL; 14838c2ecf20Sopenharmony_ci *vfd = *template; 14848c2ecf20Sopenharmony_ci snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", 14858c2ecf20Sopenharmony_ci cx23885_boards[tsport->dev->board].name, type); 14868c2ecf20Sopenharmony_ci vfd->v4l2_dev = &dev->v4l2_dev; 14878c2ecf20Sopenharmony_ci vfd->release = video_device_release; 14888c2ecf20Sopenharmony_ci return vfd; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ciint cx23885_417_register(struct cx23885_dev *dev) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci /* FIXME: Port1 hardcoded here */ 14948c2ecf20Sopenharmony_ci int err = -ENODEV; 14958c2ecf20Sopenharmony_ci struct cx23885_tsport *tsport = &dev->ts1; 14968c2ecf20Sopenharmony_ci struct vb2_queue *q; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER) 15018c2ecf20Sopenharmony_ci return err; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci /* Set default TV standard */ 15048c2ecf20Sopenharmony_ci dev->encodernorm = cx23885_tvnorms[0]; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (dev->encodernorm.id & V4L2_STD_525_60) 15078c2ecf20Sopenharmony_ci tsport->height = 480; 15088c2ecf20Sopenharmony_ci else 15098c2ecf20Sopenharmony_ci tsport->height = 576; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci tsport->width = 720; 15128c2ecf20Sopenharmony_ci dev->cxhdl.port = CX2341X_PORT_SERIAL; 15138c2ecf20Sopenharmony_ci err = cx2341x_handler_init(&dev->cxhdl, 50); 15148c2ecf20Sopenharmony_ci if (err) 15158c2ecf20Sopenharmony_ci return err; 15168c2ecf20Sopenharmony_ci dev->cxhdl.priv = dev; 15178c2ecf20Sopenharmony_ci dev->cxhdl.func = cx23885_api_func; 15188c2ecf20Sopenharmony_ci cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576); 15198c2ecf20Sopenharmony_ci v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL, false); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* Allocate and initialize V4L video device */ 15228c2ecf20Sopenharmony_ci dev->v4l_device = cx23885_video_dev_alloc(tsport, 15238c2ecf20Sopenharmony_ci dev->pci, &cx23885_mpeg_template, "mpeg"); 15248c2ecf20Sopenharmony_ci q = &dev->vb2_mpegq; 15258c2ecf20Sopenharmony_ci q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 15268c2ecf20Sopenharmony_ci q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; 15278c2ecf20Sopenharmony_ci q->gfp_flags = GFP_DMA32; 15288c2ecf20Sopenharmony_ci q->min_buffers_needed = 2; 15298c2ecf20Sopenharmony_ci q->drv_priv = dev; 15308c2ecf20Sopenharmony_ci q->buf_struct_size = sizeof(struct cx23885_buffer); 15318c2ecf20Sopenharmony_ci q->ops = &cx23885_qops; 15328c2ecf20Sopenharmony_ci q->mem_ops = &vb2_dma_sg_memops; 15338c2ecf20Sopenharmony_ci q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 15348c2ecf20Sopenharmony_ci q->lock = &dev->lock; 15358c2ecf20Sopenharmony_ci q->dev = &dev->pci->dev; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci err = vb2_queue_init(q); 15388c2ecf20Sopenharmony_ci if (err < 0) 15398c2ecf20Sopenharmony_ci return err; 15408c2ecf20Sopenharmony_ci video_set_drvdata(dev->v4l_device, dev); 15418c2ecf20Sopenharmony_ci dev->v4l_device->lock = &dev->lock; 15428c2ecf20Sopenharmony_ci dev->v4l_device->queue = q; 15438c2ecf20Sopenharmony_ci dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE | 15448c2ecf20Sopenharmony_ci V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; 15458c2ecf20Sopenharmony_ci if (dev->tuner_type != TUNER_ABSENT) 15468c2ecf20Sopenharmony_ci dev->v4l_device->device_caps |= V4L2_CAP_TUNER; 15478c2ecf20Sopenharmony_ci err = video_register_device(dev->v4l_device, 15488c2ecf20Sopenharmony_ci VFL_TYPE_VIDEO, -1); 15498c2ecf20Sopenharmony_ci if (err < 0) { 15508c2ecf20Sopenharmony_ci pr_info("%s: can't register mpeg device\n", dev->name); 15518c2ecf20Sopenharmony_ci return err; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci pr_info("%s: registered device %s [mpeg]\n", 15558c2ecf20Sopenharmony_ci dev->name, video_device_node_name(dev->v4l_device)); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci /* ST: Configure the encoder parameters, but don't begin 15588c2ecf20Sopenharmony_ci * encoding, this resolves an issue where the first time the 15598c2ecf20Sopenharmony_ci * encoder is started video can be choppy. 15608c2ecf20Sopenharmony_ci */ 15618c2ecf20Sopenharmony_ci cx23885_initialize_codec(dev, 0); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ciMODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME); 1567