18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * saa7127 - Philips SAA7127/SAA7129 video encoder driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2000-2001 Gillem <htoa@gmx.net> 108c2ecf20Sopenharmony_ci * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This driver is designed for the Hauppauge 250/350 Linux driver 178c2ecf20Sopenharmony_ci * from the ivtv Project 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com> 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Dual output support: 228c2ecf20Sopenharmony_ci * Copyright (C) 2004 Eric Varsanyi 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * NTSC Tuning and 7.5 IRE Setup 258c2ecf20Sopenharmony_ci * Copyright (C) 2004 Chris Kennedy <c@groovy.org> 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * VBI additions & cleanup: 288c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl> 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Note: the saa7126 is identical to the saa7127, and the saa7128 is 318c2ecf20Sopenharmony_ci * identical to the saa7129, except that the saa7126 and saa7128 have 328c2ecf20Sopenharmony_ci * macrovision anti-taping support. This driver will almost certainly 338c2ecf20Sopenharmony_ci * work fine for those chips, except of course for the missing anti-taping 348c2ecf20Sopenharmony_ci * support. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/module.h> 408c2ecf20Sopenharmony_ci#include <linux/slab.h> 418c2ecf20Sopenharmony_ci#include <linux/i2c.h> 428c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 438c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 448c2ecf20Sopenharmony_ci#include <media/i2c/saa7127.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int debug; 478c2ecf20Sopenharmony_cistatic int test_image; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); 508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 538c2ecf20Sopenharmony_cimodule_param(test_image, int, 0644); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "debug level (0-2)"); 558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(test_image, "test_image (0-1)"); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * SAA7127 registers 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SAA7127_REG_STATUS 0x00 638c2ecf20Sopenharmony_ci#define SAA7127_REG_WIDESCREEN_CONFIG 0x26 648c2ecf20Sopenharmony_ci#define SAA7127_REG_WIDESCREEN_ENABLE 0x27 658c2ecf20Sopenharmony_ci#define SAA7127_REG_BURST_START 0x28 668c2ecf20Sopenharmony_ci#define SAA7127_REG_BURST_END 0x29 678c2ecf20Sopenharmony_ci#define SAA7127_REG_COPYGEN_0 0x2a 688c2ecf20Sopenharmony_ci#define SAA7127_REG_COPYGEN_1 0x2b 698c2ecf20Sopenharmony_ci#define SAA7127_REG_COPYGEN_2 0x2c 708c2ecf20Sopenharmony_ci#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d 718c2ecf20Sopenharmony_ci#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38 728c2ecf20Sopenharmony_ci#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39 738c2ecf20Sopenharmony_ci#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a 748c2ecf20Sopenharmony_ci#define SAA7129_REG_FADE_KEY_COL2 0x4f 758c2ecf20Sopenharmony_ci#define SAA7127_REG_CHROMA_PHASE 0x5a 768c2ecf20Sopenharmony_ci#define SAA7127_REG_GAINU 0x5b 778c2ecf20Sopenharmony_ci#define SAA7127_REG_GAINV 0x5c 788c2ecf20Sopenharmony_ci#define SAA7127_REG_BLACK_LEVEL 0x5d 798c2ecf20Sopenharmony_ci#define SAA7127_REG_BLANKING_LEVEL 0x5e 808c2ecf20Sopenharmony_ci#define SAA7127_REG_VBI_BLANKING 0x5f 818c2ecf20Sopenharmony_ci#define SAA7127_REG_DAC_CONTROL 0x61 828c2ecf20Sopenharmony_ci#define SAA7127_REG_BURST_AMP 0x62 838c2ecf20Sopenharmony_ci#define SAA7127_REG_SUBC3 0x63 848c2ecf20Sopenharmony_ci#define SAA7127_REG_SUBC2 0x64 858c2ecf20Sopenharmony_ci#define SAA7127_REG_SUBC1 0x65 868c2ecf20Sopenharmony_ci#define SAA7127_REG_SUBC0 0x66 878c2ecf20Sopenharmony_ci#define SAA7127_REG_LINE_21_ODD_0 0x67 888c2ecf20Sopenharmony_ci#define SAA7127_REG_LINE_21_ODD_1 0x68 898c2ecf20Sopenharmony_ci#define SAA7127_REG_LINE_21_EVEN_0 0x69 908c2ecf20Sopenharmony_ci#define SAA7127_REG_LINE_21_EVEN_1 0x6a 918c2ecf20Sopenharmony_ci#define SAA7127_REG_RCV_PORT_CONTROL 0x6b 928c2ecf20Sopenharmony_ci#define SAA7127_REG_VTRIG 0x6c 938c2ecf20Sopenharmony_ci#define SAA7127_REG_HTRIG_HI 0x6d 948c2ecf20Sopenharmony_ci#define SAA7127_REG_MULTI 0x6e 958c2ecf20Sopenharmony_ci#define SAA7127_REG_CLOSED_CAPTION 0x6f 968c2ecf20Sopenharmony_ci#define SAA7127_REG_RCV2_OUTPUT_START 0x70 978c2ecf20Sopenharmony_ci#define SAA7127_REG_RCV2_OUTPUT_END 0x71 988c2ecf20Sopenharmony_ci#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72 998c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_REQUEST_H_START 0x73 1008c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74 1018c2ecf20Sopenharmony_ci#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75 1028c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76 1038c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77 1048c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78 1058c2ecf20Sopenharmony_ci#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79 1068c2ecf20Sopenharmony_ci#define SAA7127_REG_FIRST_ACTIVE 0x7a 1078c2ecf20Sopenharmony_ci#define SAA7127_REG_LAST_ACTIVE 0x7b 1088c2ecf20Sopenharmony_ci#define SAA7127_REG_MSB_VERTICAL 0x7c 1098c2ecf20Sopenharmony_ci#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e 1108c2ecf20Sopenharmony_ci#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci ********************************************************************** 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Arrays with configuration parameters for the SAA7127 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci ********************************************************************** 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistruct i2c_reg_value { 1218c2ecf20Sopenharmony_ci unsigned char reg; 1228c2ecf20Sopenharmony_ci unsigned char value; 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic const struct i2c_reg_value saa7129_init_config_extra[] = { 1268c2ecf20Sopenharmony_ci { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, 1278c2ecf20Sopenharmony_ci { SAA7127_REG_VTRIG, 0xfa }, 1288c2ecf20Sopenharmony_ci { 0, 0 } 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic const struct i2c_reg_value saa7127_init_config_common[] = { 1328c2ecf20Sopenharmony_ci { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, 1338c2ecf20Sopenharmony_ci { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, 1348c2ecf20Sopenharmony_ci { SAA7127_REG_COPYGEN_0, 0x77 }, 1358c2ecf20Sopenharmony_ci { SAA7127_REG_COPYGEN_1, 0x41 }, 1368c2ecf20Sopenharmony_ci { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ 1378c2ecf20Sopenharmony_ci { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf }, 1388c2ecf20Sopenharmony_ci { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, 1398c2ecf20Sopenharmony_ci { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, 1408c2ecf20Sopenharmony_ci { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ 1418c2ecf20Sopenharmony_ci { SAA7127_REG_LINE_21_ODD_0, 0x77 }, 1428c2ecf20Sopenharmony_ci { SAA7127_REG_LINE_21_ODD_1, 0x41 }, 1438c2ecf20Sopenharmony_ci { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, 1448c2ecf20Sopenharmony_ci { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, 1458c2ecf20Sopenharmony_ci { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, 1468c2ecf20Sopenharmony_ci { SAA7127_REG_VTRIG, 0xf9 }, 1478c2ecf20Sopenharmony_ci { SAA7127_REG_HTRIG_HI, 0x00 }, 1488c2ecf20Sopenharmony_ci { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, 1498c2ecf20Sopenharmony_ci { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, 1508c2ecf20Sopenharmony_ci { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, 1518c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, 1528c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, 1538c2ecf20Sopenharmony_ci { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, 1548c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, 1558c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, 1568c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, 1578c2ecf20Sopenharmony_ci { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, 1588c2ecf20Sopenharmony_ci { SAA7127_REG_FIRST_ACTIVE, 0x1a }, 1598c2ecf20Sopenharmony_ci { SAA7127_REG_LAST_ACTIVE, 0x01 }, 1608c2ecf20Sopenharmony_ci { SAA7127_REG_MSB_VERTICAL, 0xc0 }, 1618c2ecf20Sopenharmony_ci { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, 1628c2ecf20Sopenharmony_ci { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, 1638c2ecf20Sopenharmony_ci { 0, 0 } 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define SAA7127_60HZ_DAC_CONTROL 0x15 1678c2ecf20Sopenharmony_cistatic const struct i2c_reg_value saa7127_init_config_60hz[] = { 1688c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_START, 0x19 }, 1698c2ecf20Sopenharmony_ci /* BURST_END is also used as a chip ID in saa7127_probe */ 1708c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_END, 0x1d }, 1718c2ecf20Sopenharmony_ci { SAA7127_REG_CHROMA_PHASE, 0xa3 }, 1728c2ecf20Sopenharmony_ci { SAA7127_REG_GAINU, 0x98 }, 1738c2ecf20Sopenharmony_ci { SAA7127_REG_GAINV, 0xd3 }, 1748c2ecf20Sopenharmony_ci { SAA7127_REG_BLACK_LEVEL, 0x39 }, 1758c2ecf20Sopenharmony_ci { SAA7127_REG_BLANKING_LEVEL, 0x2e }, 1768c2ecf20Sopenharmony_ci { SAA7127_REG_VBI_BLANKING, 0x2e }, 1778c2ecf20Sopenharmony_ci { SAA7127_REG_DAC_CONTROL, 0x15 }, 1788c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_AMP, 0x4d }, 1798c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC3, 0x1f }, 1808c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC2, 0x7c }, 1818c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC1, 0xf0 }, 1828c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC0, 0x21 }, 1838c2ecf20Sopenharmony_ci { SAA7127_REG_MULTI, 0x90 }, 1848c2ecf20Sopenharmony_ci { SAA7127_REG_CLOSED_CAPTION, 0x11 }, 1858c2ecf20Sopenharmony_ci { 0, 0 } 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02 1898c2ecf20Sopenharmony_cistatic struct i2c_reg_value saa7127_init_config_50hz_pal[] = { 1908c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_START, 0x21 }, 1918c2ecf20Sopenharmony_ci /* BURST_END is also used as a chip ID in saa7127_probe */ 1928c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_END, 0x1d }, 1938c2ecf20Sopenharmony_ci { SAA7127_REG_CHROMA_PHASE, 0x3f }, 1948c2ecf20Sopenharmony_ci { SAA7127_REG_GAINU, 0x7d }, 1958c2ecf20Sopenharmony_ci { SAA7127_REG_GAINV, 0xaf }, 1968c2ecf20Sopenharmony_ci { SAA7127_REG_BLACK_LEVEL, 0x33 }, 1978c2ecf20Sopenharmony_ci { SAA7127_REG_BLANKING_LEVEL, 0x35 }, 1988c2ecf20Sopenharmony_ci { SAA7127_REG_VBI_BLANKING, 0x35 }, 1998c2ecf20Sopenharmony_ci { SAA7127_REG_DAC_CONTROL, 0x02 }, 2008c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_AMP, 0x2f }, 2018c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC3, 0xcb }, 2028c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC2, 0x8a }, 2038c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC1, 0x09 }, 2048c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC0, 0x2a }, 2058c2ecf20Sopenharmony_ci { SAA7127_REG_MULTI, 0xa0 }, 2068c2ecf20Sopenharmony_ci { SAA7127_REG_CLOSED_CAPTION, 0x00 }, 2078c2ecf20Sopenharmony_ci { 0, 0 } 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08 2118c2ecf20Sopenharmony_cistatic struct i2c_reg_value saa7127_init_config_50hz_secam[] = { 2128c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_START, 0x21 }, 2138c2ecf20Sopenharmony_ci /* BURST_END is also used as a chip ID in saa7127_probe */ 2148c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_END, 0x1d }, 2158c2ecf20Sopenharmony_ci { SAA7127_REG_CHROMA_PHASE, 0x3f }, 2168c2ecf20Sopenharmony_ci { SAA7127_REG_GAINU, 0x6a }, 2178c2ecf20Sopenharmony_ci { SAA7127_REG_GAINV, 0x81 }, 2188c2ecf20Sopenharmony_ci { SAA7127_REG_BLACK_LEVEL, 0x33 }, 2198c2ecf20Sopenharmony_ci { SAA7127_REG_BLANKING_LEVEL, 0x35 }, 2208c2ecf20Sopenharmony_ci { SAA7127_REG_VBI_BLANKING, 0x35 }, 2218c2ecf20Sopenharmony_ci { SAA7127_REG_DAC_CONTROL, 0x08 }, 2228c2ecf20Sopenharmony_ci { SAA7127_REG_BURST_AMP, 0x2f }, 2238c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC3, 0xb2 }, 2248c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC2, 0x3b }, 2258c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC1, 0xa3 }, 2268c2ecf20Sopenharmony_ci { SAA7127_REG_SUBC0, 0x28 }, 2278c2ecf20Sopenharmony_ci { SAA7127_REG_MULTI, 0x90 }, 2288c2ecf20Sopenharmony_ci { SAA7127_REG_CLOSED_CAPTION, 0x00 }, 2298c2ecf20Sopenharmony_ci { 0, 0 } 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/* 2338c2ecf20Sopenharmony_ci ********************************************************************** 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci * Encoder Struct, holds the configuration state of the encoder 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci ********************************************************************** 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cienum saa712x_model { 2418c2ecf20Sopenharmony_ci SAA7127, 2428c2ecf20Sopenharmony_ci SAA7129, 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistruct saa7127_state { 2468c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 2478c2ecf20Sopenharmony_ci v4l2_std_id std; 2488c2ecf20Sopenharmony_ci enum saa712x_model ident; 2498c2ecf20Sopenharmony_ci enum saa7127_input_type input_type; 2508c2ecf20Sopenharmony_ci enum saa7127_output_type output_type; 2518c2ecf20Sopenharmony_ci int video_enable; 2528c2ecf20Sopenharmony_ci int wss_enable; 2538c2ecf20Sopenharmony_ci u16 wss_mode; 2548c2ecf20Sopenharmony_ci int cc_enable; 2558c2ecf20Sopenharmony_ci u16 cc_data; 2568c2ecf20Sopenharmony_ci int xds_enable; 2578c2ecf20Sopenharmony_ci u16 xds_data; 2588c2ecf20Sopenharmony_ci int vps_enable; 2598c2ecf20Sopenharmony_ci u8 vps_data[5]; 2608c2ecf20Sopenharmony_ci u8 reg_2d; 2618c2ecf20Sopenharmony_ci u8 reg_3a; 2628c2ecf20Sopenharmony_ci u8 reg_3a_cb; /* colorbar bit */ 2638c2ecf20Sopenharmony_ci u8 reg_61; 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic inline struct saa7127_state *to_state(struct v4l2_subdev *sd) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci return container_of(sd, struct saa7127_state, sd); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const char * const output_strs[] = 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci "S-Video + Composite", 2748c2ecf20Sopenharmony_ci "Composite", 2758c2ecf20Sopenharmony_ci "S-Video", 2768c2ecf20Sopenharmony_ci "RGB", 2778c2ecf20Sopenharmony_ci "YUV C", 2788c2ecf20Sopenharmony_ci "YUV V" 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const char * const wss_strs[] = { 2828c2ecf20Sopenharmony_ci "invalid", 2838c2ecf20Sopenharmony_ci "letterbox 14:9 center", 2848c2ecf20Sopenharmony_ci "letterbox 14:9 top", 2858c2ecf20Sopenharmony_ci "invalid", 2868c2ecf20Sopenharmony_ci "letterbox 16:9 top", 2878c2ecf20Sopenharmony_ci "invalid", 2888c2ecf20Sopenharmony_ci "invalid", 2898c2ecf20Sopenharmony_ci "16:9 full format anamorphic", 2908c2ecf20Sopenharmony_ci "4:3 full format", 2918c2ecf20Sopenharmony_ci "invalid", 2928c2ecf20Sopenharmony_ci "invalid", 2938c2ecf20Sopenharmony_ci "letterbox 16:9 center", 2948c2ecf20Sopenharmony_ci "invalid", 2958c2ecf20Sopenharmony_ci "letterbox >16:9 center", 2968c2ecf20Sopenharmony_ci "14:9 full format center", 2978c2ecf20Sopenharmony_ci "invalid", 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int saa7127_read(struct v4l2_subdev *sd, u8 reg) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return i2c_smbus_read_byte_data(client, reg); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 3148c2ecf20Sopenharmony_ci int i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 3178c2ecf20Sopenharmony_ci if (i2c_smbus_write_byte_data(client, reg, val) == 0) 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci v4l2_err(sd, "I2C Write Problem\n"); 3218c2ecf20Sopenharmony_ci return -1; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int saa7127_write_inittab(struct v4l2_subdev *sd, 3278c2ecf20Sopenharmony_ci const struct i2c_reg_value *regs) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci while (regs->reg != 0) { 3308c2ecf20Sopenharmony_ci saa7127_write(sd, regs->reg, regs->value); 3318c2ecf20Sopenharmony_ci regs++; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 3418c2ecf20Sopenharmony_ci int enable = (data->line != 0); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (enable && (data->field != 0 || data->line != 16)) 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci if (state->vps_enable != enable) { 3468c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off"); 3478c2ecf20Sopenharmony_ci saa7127_write(sd, 0x54, enable << 7); 3488c2ecf20Sopenharmony_ci state->vps_enable = enable; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (!enable) 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci state->vps_data[0] = data->data[2]; 3548c2ecf20Sopenharmony_ci state->vps_data[1] = data->data[8]; 3558c2ecf20Sopenharmony_ci state->vps_data[2] = data->data[9]; 3568c2ecf20Sopenharmony_ci state->vps_data[3] = data->data[10]; 3578c2ecf20Sopenharmony_ci state->vps_data[4] = data->data[11]; 3588c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Set VPS data %*ph\n", 5, state->vps_data); 3598c2ecf20Sopenharmony_ci saa7127_write(sd, 0x55, state->vps_data[0]); 3608c2ecf20Sopenharmony_ci saa7127_write(sd, 0x56, state->vps_data[1]); 3618c2ecf20Sopenharmony_ci saa7127_write(sd, 0x57, state->vps_data[2]); 3628c2ecf20Sopenharmony_ci saa7127_write(sd, 0x58, state->vps_data[3]); 3638c2ecf20Sopenharmony_ci saa7127_write(sd, 0x59, state->vps_data[4]); 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 3728c2ecf20Sopenharmony_ci u16 cc = data->data[1] << 8 | data->data[0]; 3738c2ecf20Sopenharmony_ci int enable = (data->line != 0); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (enable && (data->field != 0 || data->line != 21)) 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci if (state->cc_enable != enable) { 3788c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 3798c2ecf20Sopenharmony_ci "Turn CC %s\n", enable ? "on" : "off"); 3808c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, 3818c2ecf20Sopenharmony_ci (state->xds_enable << 7) | (enable << 6) | 0x11); 3828c2ecf20Sopenharmony_ci state->cc_enable = enable; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci if (!enable) 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc); 3888c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); 3898c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8); 3908c2ecf20Sopenharmony_ci state->cc_data = cc; 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 3998c2ecf20Sopenharmony_ci u16 xds = data->data[1] << 8 | data->data[0]; 4008c2ecf20Sopenharmony_ci int enable = (data->line != 0); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (enable && (data->field != 1 || data->line != 21)) 4038c2ecf20Sopenharmony_ci return -EINVAL; 4048c2ecf20Sopenharmony_ci if (state->xds_enable != enable) { 4058c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off"); 4068c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, 4078c2ecf20Sopenharmony_ci (enable << 7) | (state->cc_enable << 6) | 0x11); 4088c2ecf20Sopenharmony_ci state->xds_enable = enable; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci if (!enable) 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds); 4148c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); 4158c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); 4168c2ecf20Sopenharmony_ci state->xds_data = xds; 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 4258c2ecf20Sopenharmony_ci int enable = (data->line != 0); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (enable && (data->field != 0 || data->line != 23)) 4288c2ecf20Sopenharmony_ci return -EINVAL; 4298c2ecf20Sopenharmony_ci if (state->wss_enable != enable) { 4308c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off"); 4318c2ecf20Sopenharmony_ci saa7127_write(sd, 0x27, enable << 7); 4328c2ecf20Sopenharmony_ci state->wss_enable = enable; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci if (!enable) 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci saa7127_write(sd, 0x26, data->data[0]); 4388c2ecf20Sopenharmony_ci saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f)); 4398c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 4408c2ecf20Sopenharmony_ci "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); 4418c2ecf20Sopenharmony_ci state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (enable) { 4528c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Enable Video Output\n"); 4538c2ecf20Sopenharmony_ci saa7127_write(sd, 0x2d, state->reg_2d); 4548c2ecf20Sopenharmony_ci saa7127_write(sd, 0x61, state->reg_61); 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Disable Video Output\n"); 4578c2ecf20Sopenharmony_ci saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0)); 4588c2ecf20Sopenharmony_ci saa7127_write(sd, 0x61, (state->reg_61 | 0xc0)); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci state->video_enable = enable; 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 4698c2ecf20Sopenharmony_ci const struct i2c_reg_value *inittab; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (std & V4L2_STD_525_60) { 4728c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n"); 4738c2ecf20Sopenharmony_ci inittab = saa7127_init_config_60hz; 4748c2ecf20Sopenharmony_ci state->reg_61 = SAA7127_60HZ_DAC_CONTROL; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci } else if (state->ident == SAA7129 && 4778c2ecf20Sopenharmony_ci (std & V4L2_STD_SECAM) && 4788c2ecf20Sopenharmony_ci !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) { 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* If and only if SECAM, with a SAA712[89] */ 4818c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 4828c2ecf20Sopenharmony_ci "Selecting 50 Hz SECAM video Standard\n"); 4838c2ecf20Sopenharmony_ci inittab = saa7127_init_config_50hz_secam; 4848c2ecf20Sopenharmony_ci state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci } else { 4878c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n"); 4888c2ecf20Sopenharmony_ci inittab = saa7127_init_config_50hz_pal; 4898c2ecf20Sopenharmony_ci state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Write Table */ 4938c2ecf20Sopenharmony_ci saa7127_write_inittab(sd, inittab); 4948c2ecf20Sopenharmony_ci state->std = std; 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int saa7127_set_output_type(struct v4l2_subdev *sd, int output) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci switch (output) { 5058c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_RGB: 5068c2ecf20Sopenharmony_ci state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */ 5078c2ecf20Sopenharmony_ci state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_COMPOSITE: 5118c2ecf20Sopenharmony_ci if (state->ident == SAA7129) 5128c2ecf20Sopenharmony_ci state->reg_2d = 0x20; /* CVBS only */ 5138c2ecf20Sopenharmony_ci else 5148c2ecf20Sopenharmony_ci state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */ 5158c2ecf20Sopenharmony_ci state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_SVIDEO: 5198c2ecf20Sopenharmony_ci if (state->ident == SAA7129) 5208c2ecf20Sopenharmony_ci state->reg_2d = 0x18; /* Y + C */ 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */ 5238c2ecf20Sopenharmony_ci state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_YUV_V: 5278c2ecf20Sopenharmony_ci state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */ 5288c2ecf20Sopenharmony_ci state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_YUV_C: 5328c2ecf20Sopenharmony_ci state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */ 5338c2ecf20Sopenharmony_ci state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci case SAA7127_OUTPUT_TYPE_BOTH: 5378c2ecf20Sopenharmony_ci if (state->ident == SAA7129) 5388c2ecf20Sopenharmony_ci state->reg_2d = 0x38; 5398c2ecf20Sopenharmony_ci else 5408c2ecf20Sopenharmony_ci state->reg_2d = 0xbf; 5418c2ecf20Sopenharmony_ci state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci default: 5458c2ecf20Sopenharmony_ci return -EINVAL; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 5488c2ecf20Sopenharmony_ci "Selecting %s output type\n", output_strs[output]); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Configure Encoder */ 5518c2ecf20Sopenharmony_ci saa7127_write(sd, 0x2d, state->reg_2d); 5528c2ecf20Sopenharmony_ci saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); 5538c2ecf20Sopenharmony_ci state->output_type = output; 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int saa7127_set_input_type(struct v4l2_subdev *sd, int input) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci switch (input) { 5648c2ecf20Sopenharmony_ci case SAA7127_INPUT_TYPE_NORMAL: /* avia */ 5658c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n"); 5668c2ecf20Sopenharmony_ci state->reg_3a_cb = 0; 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ 5708c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n"); 5718c2ecf20Sopenharmony_ci state->reg_3a_cb = 0x80; 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci default: 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); 5788c2ecf20Sopenharmony_ci state->input_type = input; 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (state->std == std) 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci return saa7127_set_std(sd, std); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int saa7127_s_routing(struct v4l2_subdev *sd, 5948c2ecf20Sopenharmony_ci u32 input, u32 output, u32 config) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 5978c2ecf20Sopenharmony_ci int rc = 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (state->input_type != input) 6008c2ecf20Sopenharmony_ci rc = saa7127_set_input_type(sd, input); 6018c2ecf20Sopenharmony_ci if (rc == 0 && state->output_type != output) 6028c2ecf20Sopenharmony_ci rc = saa7127_set_output_type(sd, output); 6038c2ecf20Sopenharmony_ci return rc; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int saa7127_s_stream(struct v4l2_subdev *sd, int enable) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (state->video_enable == enable) 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci return saa7127_set_video_enable(sd, enable); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci memset(fmt->service_lines, 0, sizeof(fmt->service_lines)); 6208c2ecf20Sopenharmony_ci if (state->vps_enable) 6218c2ecf20Sopenharmony_ci fmt->service_lines[0][16] = V4L2_SLICED_VPS; 6228c2ecf20Sopenharmony_ci if (state->wss_enable) 6238c2ecf20Sopenharmony_ci fmt->service_lines[0][23] = V4L2_SLICED_WSS_625; 6248c2ecf20Sopenharmony_ci if (state->cc_enable) { 6258c2ecf20Sopenharmony_ci fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 6268c2ecf20Sopenharmony_ci fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci fmt->service_set = 6298c2ecf20Sopenharmony_ci (state->vps_enable ? V4L2_SLICED_VPS : 0) | 6308c2ecf20Sopenharmony_ci (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) | 6318c2ecf20Sopenharmony_ci (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0); 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci switch (data->id) { 6388c2ecf20Sopenharmony_ci case V4L2_SLICED_WSS_625: 6398c2ecf20Sopenharmony_ci return saa7127_set_wss(sd, data); 6408c2ecf20Sopenharmony_ci case V4L2_SLICED_VPS: 6418c2ecf20Sopenharmony_ci return saa7127_set_vps(sd, data); 6428c2ecf20Sopenharmony_ci case V4L2_SLICED_CAPTION_525: 6438c2ecf20Sopenharmony_ci if (data->field == 0) 6448c2ecf20Sopenharmony_ci return saa7127_set_cc(sd, data); 6458c2ecf20Sopenharmony_ci return saa7127_set_xds(sd, data); 6468c2ecf20Sopenharmony_ci default: 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 6538c2ecf20Sopenharmony_cistatic int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci reg->val = saa7127_read(sd, reg->reg & 0xff); 6568c2ecf20Sopenharmony_ci reg->size = 1; 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff); 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci#endif 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int saa7127_log_status(struct v4l2_subdev *sd) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct saa7127_state *state = to_state(sd); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); 6728c2ecf20Sopenharmony_ci v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal"); 6738c2ecf20Sopenharmony_ci v4l2_info(sd, "Output: %s\n", state->video_enable ? 6748c2ecf20Sopenharmony_ci output_strs[state->output_type] : "disabled"); 6758c2ecf20Sopenharmony_ci v4l2_info(sd, "WSS: %s\n", state->wss_enable ? 6768c2ecf20Sopenharmony_ci wss_strs[state->wss_mode] : "disabled"); 6778c2ecf20Sopenharmony_ci v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); 6788c2ecf20Sopenharmony_ci v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled"); 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops saa7127_core_ops = { 6858c2ecf20Sopenharmony_ci .log_status = saa7127_log_status, 6868c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 6878c2ecf20Sopenharmony_ci .g_register = saa7127_g_register, 6888c2ecf20Sopenharmony_ci .s_register = saa7127_s_register, 6898c2ecf20Sopenharmony_ci#endif 6908c2ecf20Sopenharmony_ci}; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops saa7127_video_ops = { 6938c2ecf20Sopenharmony_ci .s_std_output = saa7127_s_std_output, 6948c2ecf20Sopenharmony_ci .s_routing = saa7127_s_routing, 6958c2ecf20Sopenharmony_ci .s_stream = saa7127_s_stream, 6968c2ecf20Sopenharmony_ci}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = { 6998c2ecf20Sopenharmony_ci .s_vbi_data = saa7127_s_vbi_data, 7008c2ecf20Sopenharmony_ci .g_sliced_fmt = saa7127_g_sliced_fmt, 7018c2ecf20Sopenharmony_ci}; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops saa7127_ops = { 7048c2ecf20Sopenharmony_ci .core = &saa7127_core_ops, 7058c2ecf20Sopenharmony_ci .video = &saa7127_video_ops, 7068c2ecf20Sopenharmony_ci .vbi = &saa7127_vbi_ops, 7078c2ecf20Sopenharmony_ci}; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic int saa7127_probe(struct i2c_client *client, 7128c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct saa7127_state *state; 7158c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 7168c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Check if the adapter supports the needed features */ 7198c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 7208c2ecf20Sopenharmony_ci return -EIO; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", 7238c2ecf20Sopenharmony_ci client->addr << 1); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 7268c2ecf20Sopenharmony_ci if (state == NULL) 7278c2ecf20Sopenharmony_ci return -ENOMEM; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci sd = &state->sd; 7308c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(sd, client, &saa7127_ops); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* First test register 0: Bits 5-7 are a version ID (should be 0), 7338c2ecf20Sopenharmony_ci and bit 2 should also be 0. 7348c2ecf20Sopenharmony_ci This is rather general, so the second test is more specific and 7358c2ecf20Sopenharmony_ci looks at the 'ending point of burst in clock cycles' which is 7368c2ecf20Sopenharmony_ci 0x1d after a reset and not expected to ever change. */ 7378c2ecf20Sopenharmony_ci if ((saa7127_read(sd, 0) & 0xe4) != 0 || 7388c2ecf20Sopenharmony_ci (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) { 7398c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "saa7127 not found\n"); 7408c2ecf20Sopenharmony_ci return -ENODEV; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (id->driver_data) { /* Chip type is already known */ 7448c2ecf20Sopenharmony_ci state->ident = id->driver_data; 7458c2ecf20Sopenharmony_ci } else { /* Needs detection */ 7468c2ecf20Sopenharmony_ci int read_result; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* Detect if it's an saa7129 */ 7498c2ecf20Sopenharmony_ci read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2); 7508c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa); 7518c2ecf20Sopenharmony_ci if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { 7528c2ecf20Sopenharmony_ci saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 7538c2ecf20Sopenharmony_ci read_result); 7548c2ecf20Sopenharmony_ci state->ident = SAA7129; 7558c2ecf20Sopenharmony_ci strscpy(client->name, "saa7129", I2C_NAME_SIZE); 7568c2ecf20Sopenharmony_ci } else { 7578c2ecf20Sopenharmony_ci state->ident = SAA7127; 7588c2ecf20Sopenharmony_ci strscpy(client->name, "saa7127", I2C_NAME_SIZE); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 7638c2ecf20Sopenharmony_ci client->addr << 1, client->adapter->name); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Configuring encoder\n"); 7668c2ecf20Sopenharmony_ci saa7127_write_inittab(sd, saa7127_init_config_common); 7678c2ecf20Sopenharmony_ci saa7127_set_std(sd, V4L2_STD_NTSC); 7688c2ecf20Sopenharmony_ci saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH); 7698c2ecf20Sopenharmony_ci saa7127_set_vps(sd, &vbi); 7708c2ecf20Sopenharmony_ci saa7127_set_wss(sd, &vbi); 7718c2ecf20Sopenharmony_ci saa7127_set_cc(sd, &vbi); 7728c2ecf20Sopenharmony_ci saa7127_set_xds(sd, &vbi); 7738c2ecf20Sopenharmony_ci if (test_image == 1) 7748c2ecf20Sopenharmony_ci /* The Encoder has an internal Colorbar generator */ 7758c2ecf20Sopenharmony_ci /* This can be used for debugging */ 7768c2ecf20Sopenharmony_ci saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE); 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL); 7798c2ecf20Sopenharmony_ci saa7127_set_video_enable(sd, 1); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (state->ident == SAA7129) 7828c2ecf20Sopenharmony_ci saa7127_write_inittab(sd, saa7129_init_config_extra); 7838c2ecf20Sopenharmony_ci return 0; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic int saa7127_remove(struct i2c_client *client) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(sd); 7938c2ecf20Sopenharmony_ci /* Turn off TV output */ 7948c2ecf20Sopenharmony_ci saa7127_set_video_enable(sd, 0); 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic const struct i2c_device_id saa7127_id[] = { 8018c2ecf20Sopenharmony_ci { "saa7127_auto", 0 }, /* auto-detection */ 8028c2ecf20Sopenharmony_ci { "saa7126", SAA7127 }, 8038c2ecf20Sopenharmony_ci { "saa7127", SAA7127 }, 8048c2ecf20Sopenharmony_ci { "saa7128", SAA7129 }, 8058c2ecf20Sopenharmony_ci { "saa7129", SAA7129 }, 8068c2ecf20Sopenharmony_ci { } 8078c2ecf20Sopenharmony_ci}; 8088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, saa7127_id); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic struct i2c_driver saa7127_driver = { 8118c2ecf20Sopenharmony_ci .driver = { 8128c2ecf20Sopenharmony_ci .name = "saa7127", 8138c2ecf20Sopenharmony_ci }, 8148c2ecf20Sopenharmony_ci .probe = saa7127_probe, 8158c2ecf20Sopenharmony_ci .remove = saa7127_remove, 8168c2ecf20Sopenharmony_ci .id_table = saa7127_id, 8178c2ecf20Sopenharmony_ci}; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cimodule_i2c_driver(saa7127_driver); 820