18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * adv7180.c Analog Devices ADV7180 video decoder driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2009 Intel Corporation 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Cogent Embedded, Inc. 68c2ecf20Sopenharmony_ci * Copyright (C) 2013 Renesas Solutions Corp. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 188c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 198c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 208c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 228c2ecf20Sopenharmony_ci#include <linux/mutex.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 268c2ecf20Sopenharmony_ci#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 278c2ecf20Sopenharmony_ci#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 288c2ecf20Sopenharmony_ci#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 298c2ecf20Sopenharmony_ci#define ADV7180_STD_NTSC_J 0x4 308c2ecf20Sopenharmony_ci#define ADV7180_STD_NTSC_M 0x5 318c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL60 0x6 328c2ecf20Sopenharmony_ci#define ADV7180_STD_NTSC_443 0x7 338c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_BG 0x8 348c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_N 0x9 358c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_M 0xa 368c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_M_PED 0xb 378c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_COMB_N 0xc 388c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_COMB_N_PED 0xd 398c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_SECAM 0xe 408c2ecf20Sopenharmony_ci#define ADV7180_STD_PAL_SECAM_PED 0xf 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define ADV7180_REG_INPUT_CONTROL 0x0000 438c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define ADV7182_REG_INPUT_VIDSEL 0x0002 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define ADV7180_REG_OUTPUT_CONTROL 0x0003 488c2ecf20Sopenharmony_ci#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 498c2ecf20Sopenharmony_ci#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define ADV7180_REG_AUTODETECT_ENABLE 0x0007 528c2ecf20Sopenharmony_ci#define ADV7180_AUTODETECT_DEFAULT 0x7f 538c2ecf20Sopenharmony_ci/* Contrast */ 548c2ecf20Sopenharmony_ci#define ADV7180_REG_CON 0x0008 /*Unsigned */ 558c2ecf20Sopenharmony_ci#define ADV7180_CON_MIN 0 568c2ecf20Sopenharmony_ci#define ADV7180_CON_DEF 128 578c2ecf20Sopenharmony_ci#define ADV7180_CON_MAX 255 588c2ecf20Sopenharmony_ci/* Brightness*/ 598c2ecf20Sopenharmony_ci#define ADV7180_REG_BRI 0x000a /*Signed */ 608c2ecf20Sopenharmony_ci#define ADV7180_BRI_MIN -128 618c2ecf20Sopenharmony_ci#define ADV7180_BRI_DEF 0 628c2ecf20Sopenharmony_ci#define ADV7180_BRI_MAX 127 638c2ecf20Sopenharmony_ci/* Hue */ 648c2ecf20Sopenharmony_ci#define ADV7180_REG_HUE 0x000b /*Signed, inverted */ 658c2ecf20Sopenharmony_ci#define ADV7180_HUE_MIN -127 668c2ecf20Sopenharmony_ci#define ADV7180_HUE_DEF 0 678c2ecf20Sopenharmony_ci#define ADV7180_HUE_MAX 128 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define ADV7180_REG_CTRL 0x000e 708c2ecf20Sopenharmony_ci#define ADV7180_CTRL_IRQ_SPACE 0x20 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define ADV7180_REG_PWR_MAN 0x0f 738c2ecf20Sopenharmony_ci#define ADV7180_PWR_MAN_ON 0x04 748c2ecf20Sopenharmony_ci#define ADV7180_PWR_MAN_OFF 0x24 758c2ecf20Sopenharmony_ci#define ADV7180_PWR_MAN_RES 0x80 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define ADV7180_REG_STATUS1 0x0010 788c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_IN_LOCK 0x01 798c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_MASK 0x70 808c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 818c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 828c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_PAL_M 0x20 838c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_PAL_60 0x30 848c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 858c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_SECAM 0x50 868c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 878c2ecf20Sopenharmony_ci#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define ADV7180_REG_IDENT 0x0011 908c2ecf20Sopenharmony_ci#define ADV7180_ID_7180 0x18 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define ADV7180_REG_STATUS3 0x0013 938c2ecf20Sopenharmony_ci#define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 948c2ecf20Sopenharmony_ci#define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 958c2ecf20Sopenharmony_ci#define ADV7180_REG_CTRL_2 0x001d 968c2ecf20Sopenharmony_ci#define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 978c2ecf20Sopenharmony_ci#define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d 988c2ecf20Sopenharmony_ci#define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e 998c2ecf20Sopenharmony_ci#define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f 1008c2ecf20Sopenharmony_ci#define ADV7180_REG_LOCK_CNT 0x0051 1018c2ecf20Sopenharmony_ci#define ADV7180_REG_CVBS_TRIM 0x0052 1028c2ecf20Sopenharmony_ci#define ADV7180_REG_CLAMP_ADJ 0x005a 1038c2ecf20Sopenharmony_ci#define ADV7180_REG_RES_CIR 0x005f 1048c2ecf20Sopenharmony_ci#define ADV7180_REG_DIFF_MODE 0x0060 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define ADV7180_REG_ICONF1 0x2040 1078c2ecf20Sopenharmony_ci#define ADV7180_ICONF1_ACTIVE_LOW 0x01 1088c2ecf20Sopenharmony_ci#define ADV7180_ICONF1_PSYNC_ONLY 0x10 1098c2ecf20Sopenharmony_ci#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 1108c2ecf20Sopenharmony_ci/* Saturation */ 1118c2ecf20Sopenharmony_ci#define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 1128c2ecf20Sopenharmony_ci#define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 1138c2ecf20Sopenharmony_ci#define ADV7180_SAT_MIN 0 1148c2ecf20Sopenharmony_ci#define ADV7180_SAT_DEF 128 1158c2ecf20Sopenharmony_ci#define ADV7180_SAT_MAX 255 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define ADV7180_IRQ1_LOCK 0x01 1188c2ecf20Sopenharmony_ci#define ADV7180_IRQ1_UNLOCK 0x02 1198c2ecf20Sopenharmony_ci#define ADV7180_REG_ISR1 0x2042 1208c2ecf20Sopenharmony_ci#define ADV7180_REG_ICR1 0x2043 1218c2ecf20Sopenharmony_ci#define ADV7180_REG_IMR1 0x2044 1228c2ecf20Sopenharmony_ci#define ADV7180_REG_IMR2 0x2048 1238c2ecf20Sopenharmony_ci#define ADV7180_IRQ3_AD_CHANGE 0x08 1248c2ecf20Sopenharmony_ci#define ADV7180_REG_ISR3 0x204A 1258c2ecf20Sopenharmony_ci#define ADV7180_REG_ICR3 0x204B 1268c2ecf20Sopenharmony_ci#define ADV7180_REG_IMR3 0x204C 1278c2ecf20Sopenharmony_ci#define ADV7180_REG_IMR4 0x2050 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define ADV7180_REG_NTSC_V_BIT_END 0x00E6 1308c2ecf20Sopenharmony_ci#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 1338c2ecf20Sopenharmony_ci#define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define ADV7180_REG_ACE_CTRL1 0x4080 1368c2ecf20Sopenharmony_ci#define ADV7180_REG_ACE_CTRL5 0x4084 1378c2ecf20Sopenharmony_ci#define ADV7180_REG_FLCONTROL 0x40e0 1388c2ecf20Sopenharmony_ci#define ADV7180_FLCONTROL_FL_ENABLE 0x1 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define ADV7180_REG_RST_CLAMP 0x809c 1418c2ecf20Sopenharmony_ci#define ADV7180_REG_AGC_ADJ1 0x80b6 1428c2ecf20Sopenharmony_ci#define ADV7180_REG_AGC_ADJ2 0x80c0 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define ADV7180_CSI_REG_PWRDN 0x00 1458c2ecf20Sopenharmony_ci#define ADV7180_CSI_PWRDN 0x80 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN1 0x00 1488c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN2 0x01 1498c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN3 0x02 1508c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN4 0x03 1518c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN5 0x04 1528c2ecf20Sopenharmony_ci#define ADV7180_INPUT_CVBS_AIN6 0x05 1538c2ecf20Sopenharmony_ci#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 1548c2ecf20Sopenharmony_ci#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 1558c2ecf20Sopenharmony_ci#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 1568c2ecf20Sopenharmony_ci#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 1578c2ecf20Sopenharmony_ci#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN1 0x00 1608c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN2 0x01 1618c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN3 0x02 1628c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN4 0x03 1638c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN5 0x04 1648c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN6 0x05 1658c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN7 0x06 1668c2ecf20Sopenharmony_ci#define ADV7182_INPUT_CVBS_AIN8 0x07 1678c2ecf20Sopenharmony_ci#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 1688c2ecf20Sopenharmony_ci#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 1698c2ecf20Sopenharmony_ci#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 1708c2ecf20Sopenharmony_ci#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 1718c2ecf20Sopenharmony_ci#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 1728c2ecf20Sopenharmony_ci#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 1738c2ecf20Sopenharmony_ci#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 1748c2ecf20Sopenharmony_ci#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 1758c2ecf20Sopenharmony_ci#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 1768c2ecf20Sopenharmony_ci#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 1798c2ecf20Sopenharmony_ci#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* Initial number of frames to skip to avoid possible garbage */ 1848c2ecf20Sopenharmony_ci#define ADV7180_NUM_OF_SKIP_FRAMES 2 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct adv7180_state; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define ADV7180_FLAG_RESET_POWERED BIT(0) 1898c2ecf20Sopenharmony_ci#define ADV7180_FLAG_V2 BIT(1) 1908c2ecf20Sopenharmony_ci#define ADV7180_FLAG_MIPI_CSI2 BIT(2) 1918c2ecf20Sopenharmony_ci#define ADV7180_FLAG_I2P BIT(3) 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistruct adv7180_chip_info { 1948c2ecf20Sopenharmony_ci unsigned int flags; 1958c2ecf20Sopenharmony_ci unsigned int valid_input_mask; 1968c2ecf20Sopenharmony_ci int (*set_std)(struct adv7180_state *st, unsigned int std); 1978c2ecf20Sopenharmony_ci int (*select_input)(struct adv7180_state *st, unsigned int input); 1988c2ecf20Sopenharmony_ci int (*init)(struct adv7180_state *state); 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistruct adv7180_state { 2028c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrl_hdl; 2038c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 2048c2ecf20Sopenharmony_ci struct media_pad pad; 2058c2ecf20Sopenharmony_ci struct mutex mutex; /* mutual excl. when accessing chip */ 2068c2ecf20Sopenharmony_ci int irq; 2078c2ecf20Sopenharmony_ci struct gpio_desc *pwdn_gpio; 2088c2ecf20Sopenharmony_ci v4l2_std_id curr_norm; 2098c2ecf20Sopenharmony_ci bool powered; 2108c2ecf20Sopenharmony_ci bool streaming; 2118c2ecf20Sopenharmony_ci u8 input; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci struct i2c_client *client; 2148c2ecf20Sopenharmony_ci unsigned int register_page; 2158c2ecf20Sopenharmony_ci struct i2c_client *csi_client; 2168c2ecf20Sopenharmony_ci struct i2c_client *vpp_client; 2178c2ecf20Sopenharmony_ci const struct adv7180_chip_info *chip_info; 2188c2ecf20Sopenharmony_ci enum v4l2_field field; 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 2218c2ecf20Sopenharmony_ci struct adv7180_state, \ 2228c2ecf20Sopenharmony_ci ctrl_hdl)->sd) 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int adv7180_select_page(struct adv7180_state *state, unsigned int page) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if (state->register_page != page) { 2278c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, 2288c2ecf20Sopenharmony_ci page); 2298c2ecf20Sopenharmony_ci state->register_page = page; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int adv7180_write(struct adv7180_state *state, unsigned int reg, 2368c2ecf20Sopenharmony_ci unsigned int value) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci lockdep_assert_held(&state->mutex); 2398c2ecf20Sopenharmony_ci adv7180_select_page(state, reg >> 8); 2408c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int adv7180_read(struct adv7180_state *state, unsigned int reg) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci lockdep_assert_held(&state->mutex); 2468c2ecf20Sopenharmony_ci adv7180_select_page(state, reg >> 8); 2478c2ecf20Sopenharmony_ci return i2c_smbus_read_byte_data(state->client, reg & 0xff); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, 2518c2ecf20Sopenharmony_ci unsigned int value) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(state->csi_client, reg, value); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int adv7180_set_video_standard(struct adv7180_state *state, 2578c2ecf20Sopenharmony_ci unsigned int std) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci return state->chip_info->set_std(state, std); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, 2638c2ecf20Sopenharmony_ci unsigned int value) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(state->vpp_client, reg, value); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic v4l2_std_id adv7180_std_to_v4l2(u8 status1) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci /* in case V4L2_IN_ST_NO_SIGNAL */ 2718c2ecf20Sopenharmony_ci if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 2728c2ecf20Sopenharmony_ci return V4L2_STD_UNKNOWN; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { 2758c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_NTSM_M_J: 2768c2ecf20Sopenharmony_ci return V4L2_STD_NTSC; 2778c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_NTSC_4_43: 2788c2ecf20Sopenharmony_ci return V4L2_STD_NTSC_443; 2798c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_PAL_M: 2808c2ecf20Sopenharmony_ci return V4L2_STD_PAL_M; 2818c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_PAL_60: 2828c2ecf20Sopenharmony_ci return V4L2_STD_PAL_60; 2838c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_PAL_B_G: 2848c2ecf20Sopenharmony_ci return V4L2_STD_PAL; 2858c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_SECAM: 2868c2ecf20Sopenharmony_ci return V4L2_STD_SECAM; 2878c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_PAL_COMB: 2888c2ecf20Sopenharmony_ci return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 2898c2ecf20Sopenharmony_ci case ADV7180_STATUS1_AUTOD_SECAM_525: 2908c2ecf20Sopenharmony_ci return V4L2_STD_SECAM; 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci return V4L2_STD_UNKNOWN; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int v4l2_std_to_adv7180(v4l2_std_id std) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci if (std == V4L2_STD_PAL_60) 2998c2ecf20Sopenharmony_ci return ADV7180_STD_PAL60; 3008c2ecf20Sopenharmony_ci if (std == V4L2_STD_NTSC_443) 3018c2ecf20Sopenharmony_ci return ADV7180_STD_NTSC_443; 3028c2ecf20Sopenharmony_ci if (std == V4L2_STD_PAL_N) 3038c2ecf20Sopenharmony_ci return ADV7180_STD_PAL_N; 3048c2ecf20Sopenharmony_ci if (std == V4L2_STD_PAL_M) 3058c2ecf20Sopenharmony_ci return ADV7180_STD_PAL_M; 3068c2ecf20Sopenharmony_ci if (std == V4L2_STD_PAL_Nc) 3078c2ecf20Sopenharmony_ci return ADV7180_STD_PAL_COMB_N; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (std & V4L2_STD_PAL) 3108c2ecf20Sopenharmony_ci return ADV7180_STD_PAL_BG; 3118c2ecf20Sopenharmony_ci if (std & V4L2_STD_NTSC) 3128c2ecf20Sopenharmony_ci return ADV7180_STD_NTSC_M; 3138c2ecf20Sopenharmony_ci if (std & V4L2_STD_SECAM) 3148c2ecf20Sopenharmony_ci return ADV7180_STD_PAL_SECAM; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic u32 adv7180_status_to_v4l2(u8 status1) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 3228c2ecf20Sopenharmony_ci return V4L2_IN_ST_NO_SIGNAL; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int __adv7180_status(struct adv7180_state *state, u32 *status, 3288c2ecf20Sopenharmony_ci v4l2_std_id *std) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int status1 = adv7180_read(state, ADV7180_REG_STATUS1); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (status1 < 0) 3338c2ecf20Sopenharmony_ci return status1; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (status) 3368c2ecf20Sopenharmony_ci *status = adv7180_status_to_v4l2(status1); 3378c2ecf20Sopenharmony_ci if (std) 3388c2ecf20Sopenharmony_ci *std = adv7180_std_to_v4l2(status1); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic inline struct adv7180_state *to_state(struct v4l2_subdev *sd) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci return container_of(sd, struct adv7180_state, sd); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 3518c2ecf20Sopenharmony_ci int err = mutex_lock_interruptible(&state->mutex); 3528c2ecf20Sopenharmony_ci if (err) 3538c2ecf20Sopenharmony_ci return err; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (state->streaming) { 3568c2ecf20Sopenharmony_ci err = -EBUSY; 3578c2ecf20Sopenharmony_ci goto unlock; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci err = adv7180_set_video_standard(state, 3618c2ecf20Sopenharmony_ci ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 3628c2ecf20Sopenharmony_ci if (err) 3638c2ecf20Sopenharmony_ci goto unlock; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci msleep(100); 3668c2ecf20Sopenharmony_ci __adv7180_status(state, NULL, std); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci err = v4l2_std_to_adv7180(state->curr_norm); 3698c2ecf20Sopenharmony_ci if (err < 0) 3708c2ecf20Sopenharmony_ci goto unlock; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci err = adv7180_set_video_standard(state, err); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciunlock: 3758c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, 3808c2ecf20Sopenharmony_ci u32 output, u32 config) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 3838c2ecf20Sopenharmony_ci int ret = mutex_lock_interruptible(&state->mutex); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (ret) 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { 3898c2ecf20Sopenharmony_ci ret = -EINVAL; 3908c2ecf20Sopenharmony_ci goto out; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci ret = state->chip_info->select_input(state, input); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (ret == 0) 3968c2ecf20Sopenharmony_ci state->input = input; 3978c2ecf20Sopenharmony_ciout: 3988c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 3998c2ecf20Sopenharmony_ci return ret; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 4058c2ecf20Sopenharmony_ci int ret = mutex_lock_interruptible(&state->mutex); 4068c2ecf20Sopenharmony_ci if (ret) 4078c2ecf20Sopenharmony_ci return ret; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = __adv7180_status(state, status, NULL); 4108c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int adv7180_program_std(struct adv7180_state *state) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ret = v4l2_std_to_adv7180(state->curr_norm); 4198c2ecf20Sopenharmony_ci if (ret < 0) 4208c2ecf20Sopenharmony_ci return ret; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = adv7180_set_video_standard(state, ret); 4238c2ecf20Sopenharmony_ci if (ret < 0) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 4318c2ecf20Sopenharmony_ci int ret = mutex_lock_interruptible(&state->mutex); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (ret) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Make sure we can support this std */ 4378c2ecf20Sopenharmony_ci ret = v4l2_std_to_adv7180(std); 4388c2ecf20Sopenharmony_ci if (ret < 0) 4398c2ecf20Sopenharmony_ci goto out; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci state->curr_norm = std; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ret = adv7180_program_std(state); 4448c2ecf20Sopenharmony_ciout: 4458c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci *norm = state->curr_norm; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int adv7180_g_frame_interval(struct v4l2_subdev *sd, 4598c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_interval *fi) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (state->curr_norm & V4L2_STD_525_60) { 4648c2ecf20Sopenharmony_ci fi->interval.numerator = 1001; 4658c2ecf20Sopenharmony_ci fi->interval.denominator = 30000; 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci fi->interval.numerator = 1; 4688c2ecf20Sopenharmony_ci fi->interval.denominator = 25; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void adv7180_set_power_pin(struct adv7180_state *state, bool on) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci if (!state->pwdn_gpio) 4778c2ecf20Sopenharmony_ci return; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (on) { 4808c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(state->pwdn_gpio, 0); 4818c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 4828c2ecf20Sopenharmony_ci } else { 4838c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(state->pwdn_gpio, 1); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int adv7180_set_power(struct adv7180_state *state, bool on) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci u8 val; 4908c2ecf20Sopenharmony_ci int ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (on) 4938c2ecf20Sopenharmony_ci val = ADV7180_PWR_MAN_ON; 4948c2ecf20Sopenharmony_ci else 4958c2ecf20Sopenharmony_ci val = ADV7180_PWR_MAN_OFF; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); 4988c2ecf20Sopenharmony_ci if (ret) 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 5028c2ecf20Sopenharmony_ci if (on) { 5038c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0xDE, 0x02); 5048c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0xD2, 0xF7); 5058c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0xD8, 0x65); 5068c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0xE0, 0x09); 5078c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x2C, 0x00); 5088c2ecf20Sopenharmony_ci if (state->field == V4L2_FIELD_NONE) 5098c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x1D, 0x80); 5108c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x00, 0x00); 5118c2ecf20Sopenharmony_ci } else { 5128c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x00, 0x80); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int adv7180_s_power(struct v4l2_subdev *sd, int on) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 5228c2ecf20Sopenharmony_ci int ret; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&state->mutex); 5258c2ecf20Sopenharmony_ci if (ret) 5268c2ecf20Sopenharmony_ci return ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = adv7180_set_power(state, on); 5298c2ecf20Sopenharmony_ci if (ret == 0) 5308c2ecf20Sopenharmony_ci state->powered = on; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 5338c2ecf20Sopenharmony_ci return ret; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_adv7180_sd(ctrl); 5398c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 5408c2ecf20Sopenharmony_ci int ret = mutex_lock_interruptible(&state->mutex); 5418c2ecf20Sopenharmony_ci int val; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (ret) 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci val = ctrl->val; 5468c2ecf20Sopenharmony_ci switch (ctrl->id) { 5478c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 5488c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_BRI, val); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 5518c2ecf20Sopenharmony_ci /*Hue is inverted according to HSL chart */ 5528c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_HUE, -val); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 5558c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_CON, val); 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 5588c2ecf20Sopenharmony_ci /* 5598c2ecf20Sopenharmony_ci *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE 5608c2ecf20Sopenharmony_ci *Let's not confuse the user, everybody understands saturation 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); 5638c2ecf20Sopenharmony_ci if (ret < 0) 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case V4L2_CID_ADV_FAST_SWITCH: 5688c2ecf20Sopenharmony_ci if (ctrl->val) { 5698c2ecf20Sopenharmony_ci /* ADI required write */ 5708c2ecf20Sopenharmony_ci adv7180_write(state, 0x80d9, 0x44); 5718c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_FLCONTROL, 5728c2ecf20Sopenharmony_ci ADV7180_FLCONTROL_FL_ENABLE); 5738c2ecf20Sopenharmony_ci } else { 5748c2ecf20Sopenharmony_ci /* ADI required write */ 5758c2ecf20Sopenharmony_ci adv7180_write(state, 0x80d9, 0xc4); 5768c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci default: 5808c2ecf20Sopenharmony_ci ret = -EINVAL; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops adv7180_ctrl_ops = { 5888c2ecf20Sopenharmony_ci .s_ctrl = adv7180_s_ctrl, 5898c2ecf20Sopenharmony_ci}; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { 5928c2ecf20Sopenharmony_ci .ops = &adv7180_ctrl_ops, 5938c2ecf20Sopenharmony_ci .id = V4L2_CID_ADV_FAST_SWITCH, 5948c2ecf20Sopenharmony_ci .name = "Fast Switching", 5958c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_BOOLEAN, 5968c2ecf20Sopenharmony_ci .min = 0, 5978c2ecf20Sopenharmony_ci .max = 1, 5988c2ecf20Sopenharmony_ci .step = 1, 5998c2ecf20Sopenharmony_ci}; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int adv7180_init_controls(struct adv7180_state *state) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 6068c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, 6078c2ecf20Sopenharmony_ci ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); 6088c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 6098c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, ADV7180_CON_MIN, 6108c2ecf20Sopenharmony_ci ADV7180_CON_MAX, 1, ADV7180_CON_DEF); 6118c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 6128c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, ADV7180_SAT_MIN, 6138c2ecf20Sopenharmony_ci ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); 6148c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 6158c2ecf20Sopenharmony_ci V4L2_CID_HUE, ADV7180_HUE_MIN, 6168c2ecf20Sopenharmony_ci ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); 6178c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci state->sd.ctrl_handler = &state->ctrl_hdl; 6208c2ecf20Sopenharmony_ci if (state->ctrl_hdl.error) { 6218c2ecf20Sopenharmony_ci int err = state->ctrl_hdl.error; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&state->ctrl_hdl); 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&state->ctrl_hdl); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_cistatic void adv7180_exit_controls(struct adv7180_state *state) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&state->ctrl_hdl); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int adv7180_enum_mbus_code(struct v4l2_subdev *sd, 6368c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 6378c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci if (code->index != 0) 6408c2ecf20Sopenharmony_ci return -EINVAL; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci code->code = MEDIA_BUS_FMT_UYVY8_2X8; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int adv7180_mbus_fmt(struct v4l2_subdev *sd, 6488c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 6538c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 6548c2ecf20Sopenharmony_ci fmt->width = 720; 6558c2ecf20Sopenharmony_ci fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (state->field == V4L2_FIELD_ALTERNATE) 6588c2ecf20Sopenharmony_ci fmt->height /= 2; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int adv7180_set_field_mode(struct adv7180_state *state) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (state->field == V4L2_FIELD_NONE) { 6698c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 6708c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x01, 0x20); 6718c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x02, 0x28); 6728c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x03, 0x38); 6738c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x04, 0x30); 6748c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x05, 0x30); 6758c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x06, 0x80); 6768c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x07, 0x70); 6778c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x08, 0x50); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0xa3, 0x00); 6808c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0x5b, 0x00); 6818c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0x55, 0x80); 6828c2ecf20Sopenharmony_ci } else { 6838c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 6848c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x01, 0x18); 6858c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x02, 0x18); 6868c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x03, 0x30); 6878c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x04, 0x20); 6888c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x05, 0x28); 6898c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x06, 0x40); 6908c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x07, 0x58); 6918c2ecf20Sopenharmony_ci adv7180_csi_write(state, 0x08, 0x30); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0xa3, 0x70); 6948c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0x5b, 0x80); 6958c2ecf20Sopenharmony_ci adv7180_vpp_write(state, 0x55, 0x00); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int adv7180_get_pad_format(struct v4l2_subdev *sd, 7028c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7038c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 7088c2ecf20Sopenharmony_ci format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); 7098c2ecf20Sopenharmony_ci } else { 7108c2ecf20Sopenharmony_ci adv7180_mbus_fmt(sd, &format->format); 7118c2ecf20Sopenharmony_ci format->format.field = state->field; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int adv7180_set_pad_format(struct v4l2_subdev *sd, 7188c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7198c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 7228c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *framefmt; 7238c2ecf20Sopenharmony_ci int ret; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci switch (format->format.field) { 7268c2ecf20Sopenharmony_ci case V4L2_FIELD_NONE: 7278c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_I2P) 7288c2ecf20Sopenharmony_ci break; 7298c2ecf20Sopenharmony_ci fallthrough; 7308c2ecf20Sopenharmony_ci default: 7318c2ecf20Sopenharmony_ci format->format.field = V4L2_FIELD_ALTERNATE; 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci ret = adv7180_mbus_fmt(sd, &format->format); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 7388c2ecf20Sopenharmony_ci if (state->field != format->format.field) { 7398c2ecf20Sopenharmony_ci state->field = format->format.field; 7408c2ecf20Sopenharmony_ci adv7180_set_power(state, false); 7418c2ecf20Sopenharmony_ci adv7180_set_field_mode(state); 7428c2ecf20Sopenharmony_ci adv7180_set_power(state, true); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); 7468c2ecf20Sopenharmony_ci *framefmt = format->format; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int adv7180_init_cfg(struct v4l2_subdev *sd, 7538c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct v4l2_subdev_format fmt = { 7568c2ecf20Sopenharmony_ci .which = cfg ? V4L2_SUBDEV_FORMAT_TRY 7578c2ecf20Sopenharmony_ci : V4L2_SUBDEV_FORMAT_ACTIVE, 7588c2ecf20Sopenharmony_ci }; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return adv7180_set_pad_format(sd, cfg, &fmt); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int adv7180_get_mbus_config(struct v4l2_subdev *sd, 7648c2ecf20Sopenharmony_ci unsigned int pad, 7658c2ecf20Sopenharmony_ci struct v4l2_mbus_config *cfg) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 7708c2ecf20Sopenharmony_ci cfg->type = V4L2_MBUS_CSI2_DPHY; 7718c2ecf20Sopenharmony_ci cfg->flags = V4L2_MBUS_CSI2_1_LANE | 7728c2ecf20Sopenharmony_ci V4L2_MBUS_CSI2_CHANNEL_0 | 7738c2ecf20Sopenharmony_ci V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 7748c2ecf20Sopenharmony_ci } else { 7758c2ecf20Sopenharmony_ci /* 7768c2ecf20Sopenharmony_ci * The ADV7180 sensor supports BT.601/656 output modes. 7778c2ecf20Sopenharmony_ci * The BT.656 is default and not yet configurable by s/w. 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | 7808c2ecf20Sopenharmony_ci V4L2_MBUS_DATA_ACTIVE_HIGH; 7818c2ecf20Sopenharmony_ci cfg->type = V4L2_MBUS_BT656; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return 0; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci *frames = ADV7180_NUM_OF_SKIP_FRAMES; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (state->curr_norm & V4L2_STD_525_60) { 7998c2ecf20Sopenharmony_ci aspect->numerator = 11; 8008c2ecf20Sopenharmony_ci aspect->denominator = 10; 8018c2ecf20Sopenharmony_ci } else { 8028c2ecf20Sopenharmony_ci aspect->numerator = 54; 8038c2ecf20Sopenharmony_ci aspect->denominator = 59; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return 0; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci *norm = V4L2_STD_ALL; 8128c2ecf20Sopenharmony_ci return 0; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int adv7180_s_stream(struct v4l2_subdev *sd, int enable) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 8188c2ecf20Sopenharmony_ci int ret; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* It's always safe to stop streaming, no need to take the lock */ 8218c2ecf20Sopenharmony_ci if (!enable) { 8228c2ecf20Sopenharmony_ci state->streaming = enable; 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* Must wait until querystd released the lock */ 8278c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&state->mutex); 8288c2ecf20Sopenharmony_ci if (ret) 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci state->streaming = enable; 8318c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int adv7180_subscribe_event(struct v4l2_subdev *sd, 8368c2ecf20Sopenharmony_ci struct v4l2_fh *fh, 8378c2ecf20Sopenharmony_ci struct v4l2_event_subscription *sub) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci switch (sub->type) { 8408c2ecf20Sopenharmony_ci case V4L2_EVENT_SOURCE_CHANGE: 8418c2ecf20Sopenharmony_ci return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 8428c2ecf20Sopenharmony_ci case V4L2_EVENT_CTRL: 8438c2ecf20Sopenharmony_ci return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 8448c2ecf20Sopenharmony_ci default: 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops adv7180_video_ops = { 8508c2ecf20Sopenharmony_ci .s_std = adv7180_s_std, 8518c2ecf20Sopenharmony_ci .g_std = adv7180_g_std, 8528c2ecf20Sopenharmony_ci .g_frame_interval = adv7180_g_frame_interval, 8538c2ecf20Sopenharmony_ci .querystd = adv7180_querystd, 8548c2ecf20Sopenharmony_ci .g_input_status = adv7180_g_input_status, 8558c2ecf20Sopenharmony_ci .s_routing = adv7180_s_routing, 8568c2ecf20Sopenharmony_ci .g_pixelaspect = adv7180_g_pixelaspect, 8578c2ecf20Sopenharmony_ci .g_tvnorms = adv7180_g_tvnorms, 8588c2ecf20Sopenharmony_ci .s_stream = adv7180_s_stream, 8598c2ecf20Sopenharmony_ci}; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops adv7180_core_ops = { 8628c2ecf20Sopenharmony_ci .s_power = adv7180_s_power, 8638c2ecf20Sopenharmony_ci .subscribe_event = adv7180_subscribe_event, 8648c2ecf20Sopenharmony_ci .unsubscribe_event = v4l2_event_subdev_unsubscribe, 8658c2ecf20Sopenharmony_ci}; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops adv7180_pad_ops = { 8688c2ecf20Sopenharmony_ci .init_cfg = adv7180_init_cfg, 8698c2ecf20Sopenharmony_ci .enum_mbus_code = adv7180_enum_mbus_code, 8708c2ecf20Sopenharmony_ci .set_fmt = adv7180_set_pad_format, 8718c2ecf20Sopenharmony_ci .get_fmt = adv7180_get_pad_format, 8728c2ecf20Sopenharmony_ci .get_mbus_config = adv7180_get_mbus_config, 8738c2ecf20Sopenharmony_ci}; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = { 8768c2ecf20Sopenharmony_ci .g_skip_frames = adv7180_get_skip_frames, 8778c2ecf20Sopenharmony_ci}; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops adv7180_ops = { 8808c2ecf20Sopenharmony_ci .core = &adv7180_core_ops, 8818c2ecf20Sopenharmony_ci .video = &adv7180_video_ops, 8828c2ecf20Sopenharmony_ci .pad = &adv7180_pad_ops, 8838c2ecf20Sopenharmony_ci .sensor = &adv7180_sensor_ops, 8848c2ecf20Sopenharmony_ci}; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic irqreturn_t adv7180_irq(int irq, void *devid) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct adv7180_state *state = devid; 8898c2ecf20Sopenharmony_ci u8 isr3; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci mutex_lock(&state->mutex); 8928c2ecf20Sopenharmony_ci isr3 = adv7180_read(state, ADV7180_REG_ISR3); 8938c2ecf20Sopenharmony_ci /* clear */ 8948c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_ICR3, isr3); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (isr3 & ADV7180_IRQ3_AD_CHANGE) { 8978c2ecf20Sopenharmony_ci static const struct v4l2_event src_ch = { 8988c2ecf20Sopenharmony_ci .type = V4L2_EVENT_SOURCE_CHANGE, 8998c2ecf20Sopenharmony_ci .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 9008c2ecf20Sopenharmony_ci }; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci v4l2_subdev_notify_event(&state->sd, &src_ch); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int adv7180_init(struct adv7180_state *state) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci int ret; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* ITU-R BT.656-4 compatible */ 9148c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 9158c2ecf20Sopenharmony_ci ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 9168c2ecf20Sopenharmony_ci if (ret < 0) 9178c2ecf20Sopenharmony_ci return ret; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* Manually set V bit end position in NTSC mode */ 9208c2ecf20Sopenharmony_ci return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 9218c2ecf20Sopenharmony_ci ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int adv7180_set_std(struct adv7180_state *state, unsigned int std) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 9278c2ecf20Sopenharmony_ci (std << 4) | state->input); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int adv7180_select_input(struct adv7180_state *state, unsigned int input) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci int ret; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 9358c2ecf20Sopenharmony_ci if (ret < 0) 9368c2ecf20Sopenharmony_ci return ret; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 9398c2ecf20Sopenharmony_ci ret |= input; 9408c2ecf20Sopenharmony_ci return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int adv7182_init(struct adv7180_state *state) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 9468c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 9478c2ecf20Sopenharmony_ci ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_I2P) 9508c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, 9518c2ecf20Sopenharmony_ci ADV7180_DEFAULT_VPP_I2C_ADDR << 1); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_V2) { 9548c2ecf20Sopenharmony_ci /* ADI recommended writes for improved video quality */ 9558c2ecf20Sopenharmony_ci adv7180_write(state, 0x0080, 0x51); 9568c2ecf20Sopenharmony_ci adv7180_write(state, 0x0081, 0x51); 9578c2ecf20Sopenharmony_ci adv7180_write(state, 0x0082, 0x68); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* ADI required writes */ 9618c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 9628c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e); 9638c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); 9648c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_V2) 9678c2ecf20Sopenharmony_ci adv7180_write(state, 9688c2ecf20Sopenharmony_ci ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 9698c2ecf20Sopenharmony_ci 0x17); 9708c2ecf20Sopenharmony_ci else 9718c2ecf20Sopenharmony_ci adv7180_write(state, 9728c2ecf20Sopenharmony_ci ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 9738c2ecf20Sopenharmony_ci 0x07); 9748c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); 9758c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci adv7180_write(state, 0x0013, 0x00); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return 0; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic int adv7182_set_std(struct adv7180_state *state, unsigned int std) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cienum adv7182_input_type { 9898c2ecf20Sopenharmony_ci ADV7182_INPUT_TYPE_CVBS, 9908c2ecf20Sopenharmony_ci ADV7182_INPUT_TYPE_DIFF_CVBS, 9918c2ecf20Sopenharmony_ci ADV7182_INPUT_TYPE_SVIDEO, 9928c2ecf20Sopenharmony_ci ADV7182_INPUT_TYPE_YPBPR, 9938c2ecf20Sopenharmony_ci}; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic enum adv7182_input_type adv7182_get_input_type(unsigned int input) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci switch (input) { 9988c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN1: 9998c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN2: 10008c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN3: 10018c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN4: 10028c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN5: 10038c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN6: 10048c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN7: 10058c2ecf20Sopenharmony_ci case ADV7182_INPUT_CVBS_AIN8: 10068c2ecf20Sopenharmony_ci return ADV7182_INPUT_TYPE_CVBS; 10078c2ecf20Sopenharmony_ci case ADV7182_INPUT_SVIDEO_AIN1_AIN2: 10088c2ecf20Sopenharmony_ci case ADV7182_INPUT_SVIDEO_AIN3_AIN4: 10098c2ecf20Sopenharmony_ci case ADV7182_INPUT_SVIDEO_AIN5_AIN6: 10108c2ecf20Sopenharmony_ci case ADV7182_INPUT_SVIDEO_AIN7_AIN8: 10118c2ecf20Sopenharmony_ci return ADV7182_INPUT_TYPE_SVIDEO; 10128c2ecf20Sopenharmony_ci case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: 10138c2ecf20Sopenharmony_ci case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: 10148c2ecf20Sopenharmony_ci return ADV7182_INPUT_TYPE_YPBPR; 10158c2ecf20Sopenharmony_ci case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: 10168c2ecf20Sopenharmony_ci case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: 10178c2ecf20Sopenharmony_ci case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: 10188c2ecf20Sopenharmony_ci case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: 10198c2ecf20Sopenharmony_ci return ADV7182_INPUT_TYPE_DIFF_CVBS; 10208c2ecf20Sopenharmony_ci default: /* Will never happen */ 10218c2ecf20Sopenharmony_ci return 0; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci/* ADI recommended writes to registers 0x52, 0x53, 0x54 */ 10268c2ecf20Sopenharmony_cistatic unsigned int adv7182_lbias_settings[][3] = { 10278c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, 10288c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 10298c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 10308c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 10318c2ecf20Sopenharmony_ci}; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic unsigned int adv7280_lbias_settings[][3] = { 10348c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 10358c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 10368c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 10378c2ecf20Sopenharmony_ci [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 10388c2ecf20Sopenharmony_ci}; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int adv7182_select_input(struct adv7180_state *state, unsigned int input) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci enum adv7182_input_type input_type; 10438c2ecf20Sopenharmony_ci unsigned int *lbias; 10448c2ecf20Sopenharmony_ci unsigned int i; 10458c2ecf20Sopenharmony_ci int ret; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); 10488c2ecf20Sopenharmony_ci if (ret) 10498c2ecf20Sopenharmony_ci return ret; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* Reset clamp circuitry - ADI recommended writes */ 10528c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00); 10538c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci input_type = adv7182_get_input_type(input); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci switch (input_type) { 10588c2ecf20Sopenharmony_ci case ADV7182_INPUT_TYPE_CVBS: 10598c2ecf20Sopenharmony_ci case ADV7182_INPUT_TYPE_DIFF_CVBS: 10608c2ecf20Sopenharmony_ci /* ADI recommends to use the SH1 filter */ 10618c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41); 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci default: 10648c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_V2) 10698c2ecf20Sopenharmony_ci lbias = adv7280_lbias_settings[input_type]; 10708c2ecf20Sopenharmony_ci else 10718c2ecf20Sopenharmony_ci lbias = adv7182_lbias_settings[input_type]; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) 10748c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 10778c2ecf20Sopenharmony_ci /* ADI required writes to make differential CVBS work */ 10788c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8); 10798c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90); 10808c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0); 10818c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08); 10828c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0); 10838c2ecf20Sopenharmony_ci } else { 10848c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0); 10858c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0); 10868c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10); 10878c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c); 10888c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7180_info = { 10958c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_RESET_POWERED, 10968c2ecf20Sopenharmony_ci /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 10978c2ecf20Sopenharmony_ci * all inputs and let the card driver take care of validation 10988c2ecf20Sopenharmony_ci */ 10998c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | 11008c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_CVBS_AIN2) | 11018c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_CVBS_AIN3) | 11028c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_CVBS_AIN4) | 11038c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_CVBS_AIN5) | 11048c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_CVBS_AIN6) | 11058c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | 11068c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | 11078c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | 11088c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | 11098c2ecf20Sopenharmony_ci BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), 11108c2ecf20Sopenharmony_ci .init = adv7180_init, 11118c2ecf20Sopenharmony_ci .set_std = adv7180_set_std, 11128c2ecf20Sopenharmony_ci .select_input = adv7180_select_input, 11138c2ecf20Sopenharmony_ci}; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7182_info = { 11168c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 11178c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 11188c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 11198c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 11208c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 11218c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 11228c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 11238c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 11248c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), 11258c2ecf20Sopenharmony_ci .init = adv7182_init, 11268c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 11278c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 11288c2ecf20Sopenharmony_ci}; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7280_info = { 11318c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 11328c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 11338c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 11348c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 11358c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 11368c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 11378c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 11388c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), 11398c2ecf20Sopenharmony_ci .init = adv7182_init, 11408c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 11418c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 11428c2ecf20Sopenharmony_ci}; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7280_m_info = { 11458c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 11468c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 11478c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 11488c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 11498c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 11508c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN5) | 11518c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN6) | 11528c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 11538c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 11548c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 11558c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 11568c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 11578c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 11588c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 11598c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), 11608c2ecf20Sopenharmony_ci .init = adv7182_init, 11618c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 11628c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 11638c2ecf20Sopenharmony_ci}; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7281_info = { 11668c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 11678c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 11688c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 11698c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 11708c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 11718c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 11728c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 11738c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 11748c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 11758c2ecf20Sopenharmony_ci .init = adv7182_init, 11768c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 11778c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 11788c2ecf20Sopenharmony_ci}; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7281_m_info = { 11818c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 11828c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 11838c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 11848c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 11858c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 11868c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 11878c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 11888c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 11898c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 11908c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 11918c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 11928c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 11938c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 11948c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 11958c2ecf20Sopenharmony_ci .init = adv7182_init, 11968c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 11978c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7281_ma_info = { 12018c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 12028c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 12038c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 12048c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 12058c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 12068c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN5) | 12078c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN6) | 12088c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 12098c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 12108c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 12118c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 12128c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 12138c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 12148c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 12158c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | 12168c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 12178c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 12188c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | 12198c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 12208c2ecf20Sopenharmony_ci .init = adv7182_init, 12218c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 12228c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 12238c2ecf20Sopenharmony_ci}; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7282_info = { 12268c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 12278c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 12288c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 12298c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 12308c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 12318c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 12328c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 12338c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 12348c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 12358c2ecf20Sopenharmony_ci .init = adv7182_init, 12368c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 12378c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 12388c2ecf20Sopenharmony_ci}; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic const struct adv7180_chip_info adv7282_m_info = { 12418c2ecf20Sopenharmony_ci .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 12428c2ecf20Sopenharmony_ci .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 12438c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN2) | 12448c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN3) | 12458c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN4) | 12468c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN7) | 12478c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_CVBS_AIN8) | 12488c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 12498c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 12508c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 12518c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 12528c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 12538c2ecf20Sopenharmony_ci BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 12548c2ecf20Sopenharmony_ci .init = adv7182_init, 12558c2ecf20Sopenharmony_ci .set_std = adv7182_set_std, 12568c2ecf20Sopenharmony_ci .select_input = adv7182_select_input, 12578c2ecf20Sopenharmony_ci}; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic int init_device(struct adv7180_state *state) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci int ret; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci mutex_lock(&state->mutex); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci adv7180_set_power_pin(state, true); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); 12688c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci ret = state->chip_info->init(state); 12718c2ecf20Sopenharmony_ci if (ret) 12728c2ecf20Sopenharmony_ci goto out_unlock; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci ret = adv7180_program_std(state); 12758c2ecf20Sopenharmony_ci if (ret) 12768c2ecf20Sopenharmony_ci goto out_unlock; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci adv7180_set_field_mode(state); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* register for interrupts */ 12818c2ecf20Sopenharmony_ci if (state->irq > 0) { 12828c2ecf20Sopenharmony_ci /* config the Interrupt pin to be active low */ 12838c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_ICONF1, 12848c2ecf20Sopenharmony_ci ADV7180_ICONF1_ACTIVE_LOW | 12858c2ecf20Sopenharmony_ci ADV7180_ICONF1_PSYNC_ONLY); 12868c2ecf20Sopenharmony_ci if (ret < 0) 12878c2ecf20Sopenharmony_ci goto out_unlock; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_IMR1, 0); 12908c2ecf20Sopenharmony_ci if (ret < 0) 12918c2ecf20Sopenharmony_ci goto out_unlock; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_IMR2, 0); 12948c2ecf20Sopenharmony_ci if (ret < 0) 12958c2ecf20Sopenharmony_ci goto out_unlock; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* enable AD change interrupts interrupts */ 12988c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_IMR3, 12998c2ecf20Sopenharmony_ci ADV7180_IRQ3_AD_CHANGE); 13008c2ecf20Sopenharmony_ci if (ret < 0) 13018c2ecf20Sopenharmony_ci goto out_unlock; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci ret = adv7180_write(state, ADV7180_REG_IMR4, 0); 13048c2ecf20Sopenharmony_ci if (ret < 0) 13058c2ecf20Sopenharmony_ci goto out_unlock; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ciout_unlock: 13098c2ecf20Sopenharmony_ci mutex_unlock(&state->mutex); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci return ret; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic int adv7180_probe(struct i2c_client *client, 13158c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct adv7180_state *state; 13188c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 13198c2ecf20Sopenharmony_ci int ret; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* Check if the adapter supports the needed features */ 13228c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 13238c2ecf20Sopenharmony_ci return -EIO; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 13268c2ecf20Sopenharmony_ci if (state == NULL) 13278c2ecf20Sopenharmony_ci return -ENOMEM; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci state->client = client; 13308c2ecf20Sopenharmony_ci state->field = V4L2_FIELD_ALTERNATE; 13318c2ecf20Sopenharmony_ci state->chip_info = (struct adv7180_chip_info *)id->driver_data; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 13348c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 13358c2ecf20Sopenharmony_ci if (IS_ERR(state->pwdn_gpio)) { 13368c2ecf20Sopenharmony_ci ret = PTR_ERR(state->pwdn_gpio); 13378c2ecf20Sopenharmony_ci v4l_err(client, "request for power pin failed: %d\n", ret); 13388c2ecf20Sopenharmony_ci return ret; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 13428c2ecf20Sopenharmony_ci state->csi_client = i2c_new_dummy_device(client->adapter, 13438c2ecf20Sopenharmony_ci ADV7180_DEFAULT_CSI_I2C_ADDR); 13448c2ecf20Sopenharmony_ci if (IS_ERR(state->csi_client)) 13458c2ecf20Sopenharmony_ci return PTR_ERR(state->csi_client); 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_I2P) { 13498c2ecf20Sopenharmony_ci state->vpp_client = i2c_new_dummy_device(client->adapter, 13508c2ecf20Sopenharmony_ci ADV7180_DEFAULT_VPP_I2C_ADDR); 13518c2ecf20Sopenharmony_ci if (IS_ERR(state->vpp_client)) { 13528c2ecf20Sopenharmony_ci ret = PTR_ERR(state->vpp_client); 13538c2ecf20Sopenharmony_ci goto err_unregister_csi_client; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci state->irq = client->irq; 13588c2ecf20Sopenharmony_ci mutex_init(&state->mutex); 13598c2ecf20Sopenharmony_ci state->curr_norm = V4L2_STD_NTSC; 13608c2ecf20Sopenharmony_ci if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 13618c2ecf20Sopenharmony_ci state->powered = true; 13628c2ecf20Sopenharmony_ci else 13638c2ecf20Sopenharmony_ci state->powered = false; 13648c2ecf20Sopenharmony_ci state->input = 0; 13658c2ecf20Sopenharmony_ci sd = &state->sd; 13668c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 13678c2ecf20Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci ret = adv7180_init_controls(state); 13708c2ecf20Sopenharmony_ci if (ret) 13718c2ecf20Sopenharmony_ci goto err_unregister_vpp_client; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci state->pad.flags = MEDIA_PAD_FL_SOURCE; 13748c2ecf20Sopenharmony_ci sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 13758c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&sd->entity, 1, &state->pad); 13768c2ecf20Sopenharmony_ci if (ret) 13778c2ecf20Sopenharmony_ci goto err_free_ctrl; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci ret = init_device(state); 13808c2ecf20Sopenharmony_ci if (ret) 13818c2ecf20Sopenharmony_ci goto err_media_entity_cleanup; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (state->irq) { 13848c2ecf20Sopenharmony_ci ret = request_threaded_irq(client->irq, NULL, adv7180_irq, 13858c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 13868c2ecf20Sopenharmony_ci KBUILD_MODNAME, state); 13878c2ecf20Sopenharmony_ci if (ret) 13888c2ecf20Sopenharmony_ci goto err_media_entity_cleanup; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev(sd); 13928c2ecf20Sopenharmony_ci if (ret) 13938c2ecf20Sopenharmony_ci goto err_free_irq; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci v4l_info(client, "chip found @ 0x%02x (%s)\n", 13968c2ecf20Sopenharmony_ci client->addr, client->adapter->name); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci return 0; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cierr_free_irq: 14018c2ecf20Sopenharmony_ci if (state->irq > 0) 14028c2ecf20Sopenharmony_ci free_irq(client->irq, state); 14038c2ecf20Sopenharmony_cierr_media_entity_cleanup: 14048c2ecf20Sopenharmony_ci media_entity_cleanup(&sd->entity); 14058c2ecf20Sopenharmony_cierr_free_ctrl: 14068c2ecf20Sopenharmony_ci adv7180_exit_controls(state); 14078c2ecf20Sopenharmony_cierr_unregister_vpp_client: 14088c2ecf20Sopenharmony_ci i2c_unregister_device(state->vpp_client); 14098c2ecf20Sopenharmony_cierr_unregister_csi_client: 14108c2ecf20Sopenharmony_ci i2c_unregister_device(state->csi_client); 14118c2ecf20Sopenharmony_ci mutex_destroy(&state->mutex); 14128c2ecf20Sopenharmony_ci return ret; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic int adv7180_remove(struct i2c_client *client) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 14188c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(sd); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (state->irq > 0) 14238c2ecf20Sopenharmony_ci free_irq(client->irq, state); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci media_entity_cleanup(&sd->entity); 14268c2ecf20Sopenharmony_ci adv7180_exit_controls(state); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci i2c_unregister_device(state->vpp_client); 14298c2ecf20Sopenharmony_ci i2c_unregister_device(state->csi_client); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci adv7180_set_power_pin(state, false); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci mutex_destroy(&state->mutex); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic const struct i2c_device_id adv7180_id[] = { 14398c2ecf20Sopenharmony_ci { "adv7180", (kernel_ulong_t)&adv7180_info }, 14408c2ecf20Sopenharmony_ci { "adv7180cp", (kernel_ulong_t)&adv7180_info }, 14418c2ecf20Sopenharmony_ci { "adv7180st", (kernel_ulong_t)&adv7180_info }, 14428c2ecf20Sopenharmony_ci { "adv7182", (kernel_ulong_t)&adv7182_info }, 14438c2ecf20Sopenharmony_ci { "adv7280", (kernel_ulong_t)&adv7280_info }, 14448c2ecf20Sopenharmony_ci { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, 14458c2ecf20Sopenharmony_ci { "adv7281", (kernel_ulong_t)&adv7281_info }, 14468c2ecf20Sopenharmony_ci { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 14478c2ecf20Sopenharmony_ci { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 14488c2ecf20Sopenharmony_ci { "adv7282", (kernel_ulong_t)&adv7282_info }, 14498c2ecf20Sopenharmony_ci { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, 14508c2ecf20Sopenharmony_ci {}, 14518c2ecf20Sopenharmony_ci}; 14528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adv7180_id); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 14558c2ecf20Sopenharmony_cistatic int adv7180_suspend(struct device *dev) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 14588c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 14598c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return adv7180_set_power(state, false); 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic int adv7180_resume(struct device *dev) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 14678c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 14688c2ecf20Sopenharmony_ci struct adv7180_state *state = to_state(sd); 14698c2ecf20Sopenharmony_ci int ret; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci ret = init_device(state); 14728c2ecf20Sopenharmony_ci if (ret < 0) 14738c2ecf20Sopenharmony_ci return ret; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci ret = adv7180_set_power(state, state->powered); 14768c2ecf20Sopenharmony_ci if (ret) 14778c2ecf20Sopenharmony_ci return ret; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci return 0; 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); 14838c2ecf20Sopenharmony_ci#define ADV7180_PM_OPS (&adv7180_pm_ops) 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci#else 14868c2ecf20Sopenharmony_ci#define ADV7180_PM_OPS NULL 14878c2ecf20Sopenharmony_ci#endif 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 14908c2ecf20Sopenharmony_cistatic const struct of_device_id adv7180_of_id[] = { 14918c2ecf20Sopenharmony_ci { .compatible = "adi,adv7180", }, 14928c2ecf20Sopenharmony_ci { .compatible = "adi,adv7180cp", }, 14938c2ecf20Sopenharmony_ci { .compatible = "adi,adv7180st", }, 14948c2ecf20Sopenharmony_ci { .compatible = "adi,adv7182", }, 14958c2ecf20Sopenharmony_ci { .compatible = "adi,adv7280", }, 14968c2ecf20Sopenharmony_ci { .compatible = "adi,adv7280-m", }, 14978c2ecf20Sopenharmony_ci { .compatible = "adi,adv7281", }, 14988c2ecf20Sopenharmony_ci { .compatible = "adi,adv7281-m", }, 14998c2ecf20Sopenharmony_ci { .compatible = "adi,adv7281-ma", }, 15008c2ecf20Sopenharmony_ci { .compatible = "adi,adv7282", }, 15018c2ecf20Sopenharmony_ci { .compatible = "adi,adv7282-m", }, 15028c2ecf20Sopenharmony_ci { }, 15038c2ecf20Sopenharmony_ci}; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adv7180_of_id); 15068c2ecf20Sopenharmony_ci#endif 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cistatic struct i2c_driver adv7180_driver = { 15098c2ecf20Sopenharmony_ci .driver = { 15108c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 15118c2ecf20Sopenharmony_ci .pm = ADV7180_PM_OPS, 15128c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(adv7180_of_id), 15138c2ecf20Sopenharmony_ci }, 15148c2ecf20Sopenharmony_ci .probe = adv7180_probe, 15158c2ecf20Sopenharmony_ci .remove = adv7180_remove, 15168c2ecf20Sopenharmony_ci .id_table = adv7180_id, 15178c2ecf20Sopenharmony_ci}; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cimodule_i2c_driver(adv7180_driver); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); 15228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mocean Laboratories"); 15238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1524