18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * adv7393 - ADV7393 Video Encoder Driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * The encoder hardware does not support SECAM. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/ 78c2ecf20Sopenharmony_ci * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on ADV7343 driver, 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 148c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 158c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is distributed .as is. WITHOUT ANY WARRANTY of any 188c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 198c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 208c2ecf20Sopenharmony_ci * GNU General Public License for more details. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/ctype.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/i2c.h> 288c2ecf20Sopenharmony_ci#include <linux/device.h> 298c2ecf20Sopenharmony_ci#include <linux/delay.h> 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 328c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <media/i2c/adv7393.h> 358c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 368c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "adv7393_regs.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADV7393 video encoder driver"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic bool debug; 448c2ecf20Sopenharmony_cimodule_param(debug, bool, 0644); 458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level 0-1"); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct adv7393_state { 488c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 498c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler hdl; 508c2ecf20Sopenharmony_ci u8 reg00; 518c2ecf20Sopenharmony_ci u8 reg01; 528c2ecf20Sopenharmony_ci u8 reg02; 538c2ecf20Sopenharmony_ci u8 reg35; 548c2ecf20Sopenharmony_ci u8 reg80; 558c2ecf20Sopenharmony_ci u8 reg82; 568c2ecf20Sopenharmony_ci u32 output; 578c2ecf20Sopenharmony_ci v4l2_std_id std; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic inline struct adv7393_state *to_state(struct v4l2_subdev *sd) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return container_of(sd, struct adv7393_state, sd); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci return &container_of(ctrl->handler, struct adv7393_state, hdl)->sd; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic inline int adv7393_write(struct v4l2_subdev *sd, u8 reg, u8 value) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(client, reg, value); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const u8 adv7393_init_reg_val[] = { 788c2ecf20Sopenharmony_ci ADV7393_SOFT_RESET, ADV7393_SOFT_RESET_DEFAULT, 798c2ecf20Sopenharmony_ci ADV7393_POWER_MODE_REG, ADV7393_POWER_MODE_REG_DEFAULT, 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG1, ADV7393_HD_MODE_REG1_DEFAULT, 828c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG2, ADV7393_HD_MODE_REG2_DEFAULT, 838c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG3, ADV7393_HD_MODE_REG3_DEFAULT, 848c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG4, ADV7393_HD_MODE_REG4_DEFAULT, 858c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG5, ADV7393_HD_MODE_REG5_DEFAULT, 868c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG6, ADV7393_HD_MODE_REG6_DEFAULT, 878c2ecf20Sopenharmony_ci ADV7393_HD_MODE_REG7, ADV7393_HD_MODE_REG7_DEFAULT, 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG1, ADV7393_SD_MODE_REG1_DEFAULT, 908c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG2, ADV7393_SD_MODE_REG2_DEFAULT, 918c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG3, ADV7393_SD_MODE_REG3_DEFAULT, 928c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG4, ADV7393_SD_MODE_REG4_DEFAULT, 938c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG5, ADV7393_SD_MODE_REG5_DEFAULT, 948c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG6, ADV7393_SD_MODE_REG6_DEFAULT, 958c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG7, ADV7393_SD_MODE_REG7_DEFAULT, 968c2ecf20Sopenharmony_ci ADV7393_SD_MODE_REG8, ADV7393_SD_MODE_REG8_DEFAULT, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci ADV7393_SD_TIMING_REG0, ADV7393_SD_TIMING_REG0_DEFAULT, 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ADV7393_SD_HUE_ADJUST, ADV7393_SD_HUE_ADJUST_DEFAULT, 1018c2ecf20Sopenharmony_ci ADV7393_SD_CGMS_WSS0, ADV7393_SD_CGMS_WSS0_DEFAULT, 1028c2ecf20Sopenharmony_ci ADV7393_SD_BRIGHTNESS_WSS, ADV7393_SD_BRIGHTNESS_WSS_DEFAULT, 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * 2^32 1078c2ecf20Sopenharmony_ci * FSC(reg) = FSC (HZ) * -------- 1088c2ecf20Sopenharmony_ci * 27000000 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic const struct adv7393_std_info stdinfo[] = { 1118c2ecf20Sopenharmony_ci { 1128c2ecf20Sopenharmony_ci /* FSC(Hz) = 4,433,618.75 Hz */ 1138c2ecf20Sopenharmony_ci SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, 1148c2ecf20Sopenharmony_ci }, { 1158c2ecf20Sopenharmony_ci /* FSC(Hz) = 3,579,545.45 Hz */ 1168c2ecf20Sopenharmony_ci SD_STD_NTSC, 569408542, V4L2_STD_NTSC, 1178c2ecf20Sopenharmony_ci }, { 1188c2ecf20Sopenharmony_ci /* FSC(Hz) = 3,575,611.00 Hz */ 1198c2ecf20Sopenharmony_ci SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, 1208c2ecf20Sopenharmony_ci }, { 1218c2ecf20Sopenharmony_ci /* FSC(Hz) = 3,582,056.00 Hz */ 1228c2ecf20Sopenharmony_ci SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, 1238c2ecf20Sopenharmony_ci }, { 1248c2ecf20Sopenharmony_ci /* FSC(Hz) = 4,433,618.75 Hz */ 1258c2ecf20Sopenharmony_ci SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, 1268c2ecf20Sopenharmony_ci }, { 1278c2ecf20Sopenharmony_ci /* FSC(Hz) = 4,433,618.75 Hz */ 1288c2ecf20Sopenharmony_ci SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, 1298c2ecf20Sopenharmony_ci }, { 1308c2ecf20Sopenharmony_ci /* FSC(Hz) = 4,433,618.75 Hz */ 1318c2ecf20Sopenharmony_ci SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int adv7393_setstd(struct v4l2_subdev *sd, v4l2_std_id std) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 1388c2ecf20Sopenharmony_ci const struct adv7393_std_info *std_info; 1398c2ecf20Sopenharmony_ci int num_std; 1408c2ecf20Sopenharmony_ci u8 reg; 1418c2ecf20Sopenharmony_ci u32 val; 1428c2ecf20Sopenharmony_ci int err = 0; 1438c2ecf20Sopenharmony_ci int i; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci num_std = ARRAY_SIZE(stdinfo); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci for (i = 0; i < num_std; i++) { 1488c2ecf20Sopenharmony_ci if (stdinfo[i].stdid & std) 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (i == num_std) { 1538c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 1548c2ecf20Sopenharmony_ci "Invalid std or std is not supported: %llx\n", 1558c2ecf20Sopenharmony_ci (unsigned long long)std); 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci std_info = &stdinfo[i]; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Set the standard */ 1628c2ecf20Sopenharmony_ci val = state->reg80 & ~SD_STD_MASK; 1638c2ecf20Sopenharmony_ci val |= std_info->standard_val3; 1648c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_SD_MODE_REG1, val); 1658c2ecf20Sopenharmony_ci if (err < 0) 1668c2ecf20Sopenharmony_ci goto setstd_exit; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci state->reg80 = val; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Configure the input mode register */ 1718c2ecf20Sopenharmony_ci val = state->reg01 & ~INPUT_MODE_MASK; 1728c2ecf20Sopenharmony_ci val |= SD_INPUT_MODE; 1738c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_MODE_SELECT_REG, val); 1748c2ecf20Sopenharmony_ci if (err < 0) 1758c2ecf20Sopenharmony_ci goto setstd_exit; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci state->reg01 = val; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Program the sub carrier frequency registers */ 1808c2ecf20Sopenharmony_ci val = std_info->fsc_val; 1818c2ecf20Sopenharmony_ci for (reg = ADV7393_FSC_REG0; reg <= ADV7393_FSC_REG3; reg++) { 1828c2ecf20Sopenharmony_ci err = adv7393_write(sd, reg, val); 1838c2ecf20Sopenharmony_ci if (err < 0) 1848c2ecf20Sopenharmony_ci goto setstd_exit; 1858c2ecf20Sopenharmony_ci val >>= 8; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci val = state->reg82; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Pedestal settings */ 1918c2ecf20Sopenharmony_ci if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) 1928c2ecf20Sopenharmony_ci val |= SD_PEDESTAL_EN; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci val &= SD_PEDESTAL_DI; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val); 1978c2ecf20Sopenharmony_ci if (err < 0) 1988c2ecf20Sopenharmony_ci goto setstd_exit; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci state->reg82 = val; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cisetstd_exit: 2038c2ecf20Sopenharmony_ci if (err != 0) 2048c2ecf20Sopenharmony_ci v4l2_err(sd, "Error setting std, write failed\n"); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return err; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int adv7393_setoutput(struct v4l2_subdev *sd, u32 output_type) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 2128c2ecf20Sopenharmony_ci u8 val; 2138c2ecf20Sopenharmony_ci int err = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (output_type > ADV7393_SVIDEO_ID) { 2168c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, 2178c2ecf20Sopenharmony_ci "Invalid output type or output type not supported:%d\n", 2188c2ecf20Sopenharmony_ci output_type); 2198c2ecf20Sopenharmony_ci return -EINVAL; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Enable Appropriate DAC */ 2238c2ecf20Sopenharmony_ci val = state->reg00 & 0x03; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (output_type == ADV7393_COMPOSITE_ID) 2268c2ecf20Sopenharmony_ci val |= ADV7393_COMPOSITE_POWER_VALUE; 2278c2ecf20Sopenharmony_ci else if (output_type == ADV7393_COMPONENT_ID) 2288c2ecf20Sopenharmony_ci val |= ADV7393_COMPONENT_POWER_VALUE; 2298c2ecf20Sopenharmony_ci else 2308c2ecf20Sopenharmony_ci val |= ADV7393_SVIDEO_POWER_VALUE; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_POWER_MODE_REG, val); 2338c2ecf20Sopenharmony_ci if (err < 0) 2348c2ecf20Sopenharmony_ci goto setoutput_exit; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci state->reg00 = val; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Enable YUV output */ 2398c2ecf20Sopenharmony_ci val = state->reg02 | YUV_OUTPUT_SELECT; 2408c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_MODE_REG0, val); 2418c2ecf20Sopenharmony_ci if (err < 0) 2428c2ecf20Sopenharmony_ci goto setoutput_exit; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci state->reg02 = val; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* configure SD DAC Output 1 bit */ 2478c2ecf20Sopenharmony_ci val = state->reg82; 2488c2ecf20Sopenharmony_ci if (output_type == ADV7393_COMPONENT_ID) 2498c2ecf20Sopenharmony_ci val &= SD_DAC_OUT1_DI; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci val |= SD_DAC_OUT1_EN; 2528c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val); 2538c2ecf20Sopenharmony_ci if (err < 0) 2548c2ecf20Sopenharmony_ci goto setoutput_exit; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci state->reg82 = val; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* configure ED/HD Color DAC Swap bit to zero */ 2598c2ecf20Sopenharmony_ci val = state->reg35 & HD_DAC_SWAP_DI; 2608c2ecf20Sopenharmony_ci err = adv7393_write(sd, ADV7393_HD_MODE_REG6, val); 2618c2ecf20Sopenharmony_ci if (err < 0) 2628c2ecf20Sopenharmony_ci goto setoutput_exit; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci state->reg35 = val; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cisetoutput_exit: 2678c2ecf20Sopenharmony_ci if (err != 0) 2688c2ecf20Sopenharmony_ci v4l2_err(sd, "Error setting output, write failed\n"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return err; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int adv7393_log_status(struct v4l2_subdev *sd) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); 2788c2ecf20Sopenharmony_ci v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : 2798c2ecf20Sopenharmony_ci ((state->output == 1) ? "Component" : "S-Video")); 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int adv7393_s_ctrl(struct v4l2_ctrl *ctrl) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_sd(ctrl); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci switch (ctrl->id) { 2888c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 2898c2ecf20Sopenharmony_ci return adv7393_write(sd, ADV7393_SD_BRIGHTNESS_WSS, 2908c2ecf20Sopenharmony_ci ctrl->val & SD_BRIGHTNESS_VALUE_MASK); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 2938c2ecf20Sopenharmony_ci return adv7393_write(sd, ADV7393_SD_HUE_ADJUST, 2948c2ecf20Sopenharmony_ci ctrl->val - ADV7393_HUE_MIN); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci case V4L2_CID_GAIN: 2978c2ecf20Sopenharmony_ci return adv7393_write(sd, ADV7393_DAC123_OUTPUT_LEVEL, 2988c2ecf20Sopenharmony_ci ctrl->val); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci return -EINVAL; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops adv7393_ctrl_ops = { 3048c2ecf20Sopenharmony_ci .s_ctrl = adv7393_s_ctrl, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops adv7393_core_ops = { 3088c2ecf20Sopenharmony_ci .log_status = adv7393_log_status, 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 3148c2ecf20Sopenharmony_ci int err = 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (state->std == std) 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci err = adv7393_setstd(sd, std); 3208c2ecf20Sopenharmony_ci if (!err) 3218c2ecf20Sopenharmony_ci state->std = std; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int adv7393_s_routing(struct v4l2_subdev *sd, 3278c2ecf20Sopenharmony_ci u32 input, u32 output, u32 config) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 3308c2ecf20Sopenharmony_ci int err = 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (state->output == output) 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci err = adv7393_setoutput(sd, output); 3368c2ecf20Sopenharmony_ci if (!err) 3378c2ecf20Sopenharmony_ci state->output = output; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops adv7393_video_ops = { 3438c2ecf20Sopenharmony_ci .s_std_output = adv7393_s_std_output, 3448c2ecf20Sopenharmony_ci .s_routing = adv7393_s_routing, 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops adv7393_ops = { 3488c2ecf20Sopenharmony_ci .core = &adv7393_core_ops, 3498c2ecf20Sopenharmony_ci .video = &adv7393_video_ops, 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int adv7393_initialize(struct v4l2_subdev *sd) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 3558c2ecf20Sopenharmony_ci int err = 0; 3568c2ecf20Sopenharmony_ci int i; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adv7393_init_reg_val); i += 2) { 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci err = adv7393_write(sd, adv7393_init_reg_val[i], 3618c2ecf20Sopenharmony_ci adv7393_init_reg_val[i+1]); 3628c2ecf20Sopenharmony_ci if (err) { 3638c2ecf20Sopenharmony_ci v4l2_err(sd, "Error initializing\n"); 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Configure for default video standard */ 3698c2ecf20Sopenharmony_ci err = adv7393_setoutput(sd, state->output); 3708c2ecf20Sopenharmony_ci if (err < 0) { 3718c2ecf20Sopenharmony_ci v4l2_err(sd, "Error setting output during init\n"); 3728c2ecf20Sopenharmony_ci return -EINVAL; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci err = adv7393_setstd(sd, state->std); 3768c2ecf20Sopenharmony_ci if (err < 0) { 3778c2ecf20Sopenharmony_ci v4l2_err(sd, "Error setting std during init\n"); 3788c2ecf20Sopenharmony_ci return -EINVAL; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return err; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int adv7393_probe(struct i2c_client *client, 3858c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct adv7393_state *state; 3888c2ecf20Sopenharmony_ci int err; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 3918c2ecf20Sopenharmony_ci return -ENODEV; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci v4l_info(client, "chip found @ 0x%x (%s)\n", 3948c2ecf20Sopenharmony_ci client->addr << 1, client->adapter->name); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 3978c2ecf20Sopenharmony_ci if (state == NULL) 3988c2ecf20Sopenharmony_ci return -ENOMEM; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci state->reg00 = ADV7393_POWER_MODE_REG_DEFAULT; 4018c2ecf20Sopenharmony_ci state->reg01 = 0x00; 4028c2ecf20Sopenharmony_ci state->reg02 = 0x20; 4038c2ecf20Sopenharmony_ci state->reg35 = ADV7393_HD_MODE_REG6_DEFAULT; 4048c2ecf20Sopenharmony_ci state->reg80 = ADV7393_SD_MODE_REG1_DEFAULT; 4058c2ecf20Sopenharmony_ci state->reg82 = ADV7393_SD_MODE_REG2_DEFAULT; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci state->output = ADV7393_COMPOSITE_ID; 4088c2ecf20Sopenharmony_ci state->std = V4L2_STD_NTSC; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&state->sd, client, &adv7393_ops); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&state->hdl, 3); 4138c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, 4148c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, ADV7393_BRIGHTNESS_MIN, 4158c2ecf20Sopenharmony_ci ADV7393_BRIGHTNESS_MAX, 1, 4168c2ecf20Sopenharmony_ci ADV7393_BRIGHTNESS_DEF); 4178c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, 4188c2ecf20Sopenharmony_ci V4L2_CID_HUE, ADV7393_HUE_MIN, 4198c2ecf20Sopenharmony_ci ADV7393_HUE_MAX, 1, 4208c2ecf20Sopenharmony_ci ADV7393_HUE_DEF); 4218c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, 4228c2ecf20Sopenharmony_ci V4L2_CID_GAIN, ADV7393_GAIN_MIN, 4238c2ecf20Sopenharmony_ci ADV7393_GAIN_MAX, 1, 4248c2ecf20Sopenharmony_ci ADV7393_GAIN_DEF); 4258c2ecf20Sopenharmony_ci state->sd.ctrl_handler = &state->hdl; 4268c2ecf20Sopenharmony_ci if (state->hdl.error) { 4278c2ecf20Sopenharmony_ci int err = state->hdl.error; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&state->hdl); 4308c2ecf20Sopenharmony_ci return err; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&state->hdl); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci err = adv7393_initialize(&state->sd); 4358c2ecf20Sopenharmony_ci if (err) 4368c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&state->hdl); 4378c2ecf20Sopenharmony_ci return err; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int adv7393_remove(struct i2c_client *client) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 4438c2ecf20Sopenharmony_ci struct adv7393_state *state = to_state(sd); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(sd); 4468c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&state->hdl); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic const struct i2c_device_id adv7393_id[] = { 4528c2ecf20Sopenharmony_ci {"adv7393", 0}, 4538c2ecf20Sopenharmony_ci {}, 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adv7393_id); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic struct i2c_driver adv7393_driver = { 4588c2ecf20Sopenharmony_ci .driver = { 4598c2ecf20Sopenharmony_ci .name = "adv7393", 4608c2ecf20Sopenharmony_ci }, 4618c2ecf20Sopenharmony_ci .probe = adv7393_probe, 4628c2ecf20Sopenharmony_ci .remove = adv7393_remove, 4638c2ecf20Sopenharmony_ci .id_table = adv7393_id, 4648c2ecf20Sopenharmony_ci}; 4658c2ecf20Sopenharmony_cimodule_i2c_driver(adv7393_driver); 466