1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * adv7343 - ADV7343 Video Encoder Driver 3cb7a01acSMauro Carvalho Chehab * 4cb7a01acSMauro Carvalho Chehab * The encoder hardware does not support SECAM. 5cb7a01acSMauro Carvalho Chehab * 6cb7a01acSMauro Carvalho Chehab * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ 7cb7a01acSMauro Carvalho Chehab * 8cb7a01acSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or 9cb7a01acSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License as 10cb7a01acSMauro Carvalho Chehab * published by the Free Software Foundation version 2. 11cb7a01acSMauro Carvalho Chehab * 12cb7a01acSMauro Carvalho Chehab * This program is distributed .as is. WITHOUT ANY WARRANTY of any 13cb7a01acSMauro Carvalho Chehab * kind, whether express or implied; without even the implied warranty 14cb7a01acSMauro Carvalho Chehab * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15cb7a01acSMauro Carvalho Chehab * GNU General Public License for more details. 16cb7a01acSMauro Carvalho Chehab */ 17cb7a01acSMauro Carvalho Chehab 18cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 19cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 20cb7a01acSMauro Carvalho Chehab #include <linux/ctype.h> 21cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 22cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 23cb7a01acSMauro Carvalho Chehab #include <linux/device.h> 24cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 25cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 26cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 27cb7a01acSMauro Carvalho Chehab #include <linux/uaccess.h> 28cb7a01acSMauro Carvalho Chehab 29cb7a01acSMauro Carvalho Chehab #include <media/adv7343.h> 30cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 31cb7a01acSMauro Carvalho Chehab #include <media/v4l2-chip-ident.h> 32cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 33cb7a01acSMauro Carvalho Chehab 34cb7a01acSMauro Carvalho Chehab #include "adv7343_regs.h" 35cb7a01acSMauro Carvalho Chehab 36cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("ADV7343 video encoder driver"); 37cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 38cb7a01acSMauro Carvalho Chehab 39cb7a01acSMauro Carvalho Chehab static int debug; 40cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0644); 41cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level 0-1"); 42cb7a01acSMauro Carvalho Chehab 43cb7a01acSMauro Carvalho Chehab struct adv7343_state { 44cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 45cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 46cb7a01acSMauro Carvalho Chehab u8 reg00; 47cb7a01acSMauro Carvalho Chehab u8 reg01; 48cb7a01acSMauro Carvalho Chehab u8 reg02; 49cb7a01acSMauro Carvalho Chehab u8 reg35; 50cb7a01acSMauro Carvalho Chehab u8 reg80; 51cb7a01acSMauro Carvalho Chehab u8 reg82; 52cb7a01acSMauro Carvalho Chehab u32 output; 53cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 54cb7a01acSMauro Carvalho Chehab }; 55cb7a01acSMauro Carvalho Chehab 56cb7a01acSMauro Carvalho Chehab static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) 57cb7a01acSMauro Carvalho Chehab { 58cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7343_state, sd); 59cb7a01acSMauro Carvalho Chehab } 60cb7a01acSMauro Carvalho Chehab 61cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 62cb7a01acSMauro Carvalho Chehab { 63cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; 64cb7a01acSMauro Carvalho Chehab } 65cb7a01acSMauro Carvalho Chehab 66cb7a01acSMauro Carvalho Chehab static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) 67cb7a01acSMauro Carvalho Chehab { 68cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 69cb7a01acSMauro Carvalho Chehab 70cb7a01acSMauro Carvalho Chehab return i2c_smbus_write_byte_data(client, reg, value); 71cb7a01acSMauro Carvalho Chehab } 72cb7a01acSMauro Carvalho Chehab 73cb7a01acSMauro Carvalho Chehab static const u8 adv7343_init_reg_val[] = { 74cb7a01acSMauro Carvalho Chehab ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT, 75cb7a01acSMauro Carvalho Chehab ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT, 76cb7a01acSMauro Carvalho Chehab 77cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT, 78cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT, 79cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT, 80cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT, 81cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT, 82cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT, 83cb7a01acSMauro Carvalho Chehab ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT, 84cb7a01acSMauro Carvalho Chehab 85cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT, 86cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT, 87cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT, 88cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT, 89cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT, 90cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT, 91cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT, 92cb7a01acSMauro Carvalho Chehab ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT, 93cb7a01acSMauro Carvalho Chehab 94cb7a01acSMauro Carvalho Chehab ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT, 95cb7a01acSMauro Carvalho Chehab ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT, 96cb7a01acSMauro Carvalho Chehab ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT, 97cb7a01acSMauro Carvalho Chehab }; 98cb7a01acSMauro Carvalho Chehab 99cb7a01acSMauro Carvalho Chehab /* 100cb7a01acSMauro Carvalho Chehab * 2^32 101cb7a01acSMauro Carvalho Chehab * FSC(reg) = FSC (HZ) * -------- 102cb7a01acSMauro Carvalho Chehab * 27000000 103cb7a01acSMauro Carvalho Chehab */ 104cb7a01acSMauro Carvalho Chehab static const struct adv7343_std_info stdinfo[] = { 105cb7a01acSMauro Carvalho Chehab { 106cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 3,579,545.45 Hz */ 107cb7a01acSMauro Carvalho Chehab SD_STD_NTSC, 569408542, V4L2_STD_NTSC, 108cb7a01acSMauro Carvalho Chehab }, { 109cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 3,575,611.00 Hz */ 110cb7a01acSMauro Carvalho Chehab SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, 111cb7a01acSMauro Carvalho Chehab }, { 112cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 3,582,056.00 */ 113cb7a01acSMauro Carvalho Chehab SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, 114cb7a01acSMauro Carvalho Chehab }, { 115cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 4,433,618.75 Hz */ 116cb7a01acSMauro Carvalho Chehab SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, 117cb7a01acSMauro Carvalho Chehab }, { 118cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 4,433,618.75 Hz */ 119cb7a01acSMauro Carvalho Chehab SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, 120cb7a01acSMauro Carvalho Chehab }, { 121cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 4,433,618.75 Hz */ 122cb7a01acSMauro Carvalho Chehab SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, 123cb7a01acSMauro Carvalho Chehab }, { 124cb7a01acSMauro Carvalho Chehab /* FSC(Hz) = 4,433,618.75 Hz */ 125cb7a01acSMauro Carvalho Chehab SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, 126cb7a01acSMauro Carvalho Chehab }, 127cb7a01acSMauro Carvalho Chehab }; 128cb7a01acSMauro Carvalho Chehab 129cb7a01acSMauro Carvalho Chehab static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std) 130cb7a01acSMauro Carvalho Chehab { 131cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 132cb7a01acSMauro Carvalho Chehab struct adv7343_std_info *std_info; 133cb7a01acSMauro Carvalho Chehab int num_std; 134cb7a01acSMauro Carvalho Chehab char *fsc_ptr; 135cb7a01acSMauro Carvalho Chehab u8 reg, val; 136cb7a01acSMauro Carvalho Chehab int err = 0; 137cb7a01acSMauro Carvalho Chehab int i = 0; 138cb7a01acSMauro Carvalho Chehab 139cb7a01acSMauro Carvalho Chehab std_info = (struct adv7343_std_info *)stdinfo; 140cb7a01acSMauro Carvalho Chehab num_std = ARRAY_SIZE(stdinfo); 141cb7a01acSMauro Carvalho Chehab 142cb7a01acSMauro Carvalho Chehab for (i = 0; i < num_std; i++) { 143cb7a01acSMauro Carvalho Chehab if (std_info[i].stdid & std) 144cb7a01acSMauro Carvalho Chehab break; 145cb7a01acSMauro Carvalho Chehab } 146cb7a01acSMauro Carvalho Chehab 147cb7a01acSMauro Carvalho Chehab if (i == num_std) { 148cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 149cb7a01acSMauro Carvalho Chehab "Invalid std or std is not supported: %llx\n", 150cb7a01acSMauro Carvalho Chehab (unsigned long long)std); 151cb7a01acSMauro Carvalho Chehab return -EINVAL; 152cb7a01acSMauro Carvalho Chehab } 153cb7a01acSMauro Carvalho Chehab 154cb7a01acSMauro Carvalho Chehab /* Set the standard */ 155cb7a01acSMauro Carvalho Chehab val = state->reg80 & (~(SD_STD_MASK)); 156cb7a01acSMauro Carvalho Chehab val |= std_info[i].standard_val3; 157cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); 158cb7a01acSMauro Carvalho Chehab if (err < 0) 159cb7a01acSMauro Carvalho Chehab goto setstd_exit; 160cb7a01acSMauro Carvalho Chehab 161cb7a01acSMauro Carvalho Chehab state->reg80 = val; 162cb7a01acSMauro Carvalho Chehab 163cb7a01acSMauro Carvalho Chehab /* Configure the input mode register */ 164cb7a01acSMauro Carvalho Chehab val = state->reg01 & (~((u8) INPUT_MODE_MASK)); 165cb7a01acSMauro Carvalho Chehab val |= SD_INPUT_MODE; 166cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val); 167cb7a01acSMauro Carvalho Chehab if (err < 0) 168cb7a01acSMauro Carvalho Chehab goto setstd_exit; 169cb7a01acSMauro Carvalho Chehab 170cb7a01acSMauro Carvalho Chehab state->reg01 = val; 171cb7a01acSMauro Carvalho Chehab 172cb7a01acSMauro Carvalho Chehab /* Program the sub carrier frequency registers */ 173cb7a01acSMauro Carvalho Chehab fsc_ptr = (unsigned char *)&std_info[i].fsc_val; 174cb7a01acSMauro Carvalho Chehab reg = ADV7343_FSC_REG0; 175cb7a01acSMauro Carvalho Chehab for (i = 0; i < 4; i++, reg++, fsc_ptr++) { 176cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, reg, *fsc_ptr); 177cb7a01acSMauro Carvalho Chehab if (err < 0) 178cb7a01acSMauro Carvalho Chehab goto setstd_exit; 179cb7a01acSMauro Carvalho Chehab } 180cb7a01acSMauro Carvalho Chehab 181cb7a01acSMauro Carvalho Chehab val = state->reg80; 182cb7a01acSMauro Carvalho Chehab 183cb7a01acSMauro Carvalho Chehab /* Filter settings */ 184cb7a01acSMauro Carvalho Chehab if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) 185cb7a01acSMauro Carvalho Chehab val &= 0x03; 186cb7a01acSMauro Carvalho Chehab else if (std & ~V4L2_STD_SECAM) 187cb7a01acSMauro Carvalho Chehab val |= 0x04; 188cb7a01acSMauro Carvalho Chehab 189cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); 190cb7a01acSMauro Carvalho Chehab if (err < 0) 191cb7a01acSMauro Carvalho Chehab goto setstd_exit; 192cb7a01acSMauro Carvalho Chehab 193cb7a01acSMauro Carvalho Chehab state->reg80 = val; 194cb7a01acSMauro Carvalho Chehab 195cb7a01acSMauro Carvalho Chehab setstd_exit: 196cb7a01acSMauro Carvalho Chehab if (err != 0) 197cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "Error setting std, write failed\n"); 198cb7a01acSMauro Carvalho Chehab 199cb7a01acSMauro Carvalho Chehab return err; 200cb7a01acSMauro Carvalho Chehab } 201cb7a01acSMauro Carvalho Chehab 202cb7a01acSMauro Carvalho Chehab static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) 203cb7a01acSMauro Carvalho Chehab { 204cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 205cb7a01acSMauro Carvalho Chehab unsigned char val; 206cb7a01acSMauro Carvalho Chehab int err = 0; 207cb7a01acSMauro Carvalho Chehab 208cb7a01acSMauro Carvalho Chehab if (output_type > ADV7343_SVIDEO_ID) { 209cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 210cb7a01acSMauro Carvalho Chehab "Invalid output type or output type not supported:%d\n", 211cb7a01acSMauro Carvalho Chehab output_type); 212cb7a01acSMauro Carvalho Chehab return -EINVAL; 213cb7a01acSMauro Carvalho Chehab } 214cb7a01acSMauro Carvalho Chehab 215cb7a01acSMauro Carvalho Chehab /* Enable Appropriate DAC */ 216cb7a01acSMauro Carvalho Chehab val = state->reg00 & 0x03; 217cb7a01acSMauro Carvalho Chehab 218cb7a01acSMauro Carvalho Chehab if (output_type == ADV7343_COMPOSITE_ID) 219cb7a01acSMauro Carvalho Chehab val |= ADV7343_COMPOSITE_POWER_VALUE; 220cb7a01acSMauro Carvalho Chehab else if (output_type == ADV7343_COMPONENT_ID) 221cb7a01acSMauro Carvalho Chehab val |= ADV7343_COMPONENT_POWER_VALUE; 222cb7a01acSMauro Carvalho Chehab else 223cb7a01acSMauro Carvalho Chehab val |= ADV7343_SVIDEO_POWER_VALUE; 224cb7a01acSMauro Carvalho Chehab 225cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); 226cb7a01acSMauro Carvalho Chehab if (err < 0) 227cb7a01acSMauro Carvalho Chehab goto setoutput_exit; 228cb7a01acSMauro Carvalho Chehab 229cb7a01acSMauro Carvalho Chehab state->reg00 = val; 230cb7a01acSMauro Carvalho Chehab 231cb7a01acSMauro Carvalho Chehab /* Enable YUV output */ 232cb7a01acSMauro Carvalho Chehab val = state->reg02 | YUV_OUTPUT_SELECT; 233cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_MODE_REG0, val); 234cb7a01acSMauro Carvalho Chehab if (err < 0) 235cb7a01acSMauro Carvalho Chehab goto setoutput_exit; 236cb7a01acSMauro Carvalho Chehab 237cb7a01acSMauro Carvalho Chehab state->reg02 = val; 238cb7a01acSMauro Carvalho Chehab 239cb7a01acSMauro Carvalho Chehab /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ 240cb7a01acSMauro Carvalho Chehab val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); 241cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); 242cb7a01acSMauro Carvalho Chehab if (err < 0) 243cb7a01acSMauro Carvalho Chehab goto setoutput_exit; 244cb7a01acSMauro Carvalho Chehab 245cb7a01acSMauro Carvalho Chehab state->reg82 = val; 246cb7a01acSMauro Carvalho Chehab 247cb7a01acSMauro Carvalho Chehab /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to 248cb7a01acSMauro Carvalho Chehab * zero */ 249cb7a01acSMauro Carvalho Chehab val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI); 250cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val); 251cb7a01acSMauro Carvalho Chehab if (err < 0) 252cb7a01acSMauro Carvalho Chehab goto setoutput_exit; 253cb7a01acSMauro Carvalho Chehab 254cb7a01acSMauro Carvalho Chehab state->reg35 = val; 255cb7a01acSMauro Carvalho Chehab 256cb7a01acSMauro Carvalho Chehab setoutput_exit: 257cb7a01acSMauro Carvalho Chehab if (err != 0) 258cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "Error setting output, write failed\n"); 259cb7a01acSMauro Carvalho Chehab 260cb7a01acSMauro Carvalho Chehab return err; 261cb7a01acSMauro Carvalho Chehab } 262cb7a01acSMauro Carvalho Chehab 263cb7a01acSMauro Carvalho Chehab static int adv7343_log_status(struct v4l2_subdev *sd) 264cb7a01acSMauro Carvalho Chehab { 265cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 266cb7a01acSMauro Carvalho Chehab 267cb7a01acSMauro Carvalho Chehab v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); 268cb7a01acSMauro Carvalho Chehab v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : 269cb7a01acSMauro Carvalho Chehab ((state->output == 1) ? "Component" : "S-Video")); 270cb7a01acSMauro Carvalho Chehab return 0; 271cb7a01acSMauro Carvalho Chehab } 272cb7a01acSMauro Carvalho Chehab 273cb7a01acSMauro Carvalho Chehab static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) 274cb7a01acSMauro Carvalho Chehab { 275cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 276cb7a01acSMauro Carvalho Chehab 277cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 278cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 279cb7a01acSMauro Carvalho Chehab return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, 280cb7a01acSMauro Carvalho Chehab ctrl->val); 281cb7a01acSMauro Carvalho Chehab 282cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 283cb7a01acSMauro Carvalho Chehab return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); 284cb7a01acSMauro Carvalho Chehab 285cb7a01acSMauro Carvalho Chehab case V4L2_CID_GAIN: 286cb7a01acSMauro Carvalho Chehab return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); 287cb7a01acSMauro Carvalho Chehab } 288cb7a01acSMauro Carvalho Chehab return -EINVAL; 289cb7a01acSMauro Carvalho Chehab } 290cb7a01acSMauro Carvalho Chehab 291cb7a01acSMauro Carvalho Chehab static int adv7343_g_chip_ident(struct v4l2_subdev *sd, 292cb7a01acSMauro Carvalho Chehab struct v4l2_dbg_chip_ident *chip) 293cb7a01acSMauro Carvalho Chehab { 294cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 295cb7a01acSMauro Carvalho Chehab 296cb7a01acSMauro Carvalho Chehab return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); 297cb7a01acSMauro Carvalho Chehab } 298cb7a01acSMauro Carvalho Chehab 299cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { 300cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7343_s_ctrl, 301cb7a01acSMauro Carvalho Chehab }; 302cb7a01acSMauro Carvalho Chehab 303cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7343_core_ops = { 304cb7a01acSMauro Carvalho Chehab .log_status = adv7343_log_status, 305cb7a01acSMauro Carvalho Chehab .g_chip_ident = adv7343_g_chip_ident, 306cb7a01acSMauro Carvalho Chehab .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, 307cb7a01acSMauro Carvalho Chehab .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, 308cb7a01acSMauro Carvalho Chehab .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, 309cb7a01acSMauro Carvalho Chehab .g_ctrl = v4l2_subdev_g_ctrl, 310cb7a01acSMauro Carvalho Chehab .s_ctrl = v4l2_subdev_s_ctrl, 311cb7a01acSMauro Carvalho Chehab .queryctrl = v4l2_subdev_queryctrl, 312cb7a01acSMauro Carvalho Chehab .querymenu = v4l2_subdev_querymenu, 313cb7a01acSMauro Carvalho Chehab }; 314cb7a01acSMauro Carvalho Chehab 315cb7a01acSMauro Carvalho Chehab static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) 316cb7a01acSMauro Carvalho Chehab { 317cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 318cb7a01acSMauro Carvalho Chehab int err = 0; 319cb7a01acSMauro Carvalho Chehab 320cb7a01acSMauro Carvalho Chehab if (state->std == std) 321cb7a01acSMauro Carvalho Chehab return 0; 322cb7a01acSMauro Carvalho Chehab 323cb7a01acSMauro Carvalho Chehab err = adv7343_setstd(sd, std); 324cb7a01acSMauro Carvalho Chehab if (!err) 325cb7a01acSMauro Carvalho Chehab state->std = std; 326cb7a01acSMauro Carvalho Chehab 327cb7a01acSMauro Carvalho Chehab return err; 328cb7a01acSMauro Carvalho Chehab } 329cb7a01acSMauro Carvalho Chehab 330cb7a01acSMauro Carvalho Chehab static int adv7343_s_routing(struct v4l2_subdev *sd, 331cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 332cb7a01acSMauro Carvalho Chehab { 333cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 334cb7a01acSMauro Carvalho Chehab int err = 0; 335cb7a01acSMauro Carvalho Chehab 336cb7a01acSMauro Carvalho Chehab if (state->output == output) 337cb7a01acSMauro Carvalho Chehab return 0; 338cb7a01acSMauro Carvalho Chehab 339cb7a01acSMauro Carvalho Chehab err = adv7343_setoutput(sd, output); 340cb7a01acSMauro Carvalho Chehab if (!err) 341cb7a01acSMauro Carvalho Chehab state->output = output; 342cb7a01acSMauro Carvalho Chehab 343cb7a01acSMauro Carvalho Chehab return err; 344cb7a01acSMauro Carvalho Chehab } 345cb7a01acSMauro Carvalho Chehab 346cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7343_video_ops = { 347cb7a01acSMauro Carvalho Chehab .s_std_output = adv7343_s_std_output, 348cb7a01acSMauro Carvalho Chehab .s_routing = adv7343_s_routing, 349cb7a01acSMauro Carvalho Chehab }; 350cb7a01acSMauro Carvalho Chehab 351cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7343_ops = { 352cb7a01acSMauro Carvalho Chehab .core = &adv7343_core_ops, 353cb7a01acSMauro Carvalho Chehab .video = &adv7343_video_ops, 354cb7a01acSMauro Carvalho Chehab }; 355cb7a01acSMauro Carvalho Chehab 356cb7a01acSMauro Carvalho Chehab static int adv7343_initialize(struct v4l2_subdev *sd) 357cb7a01acSMauro Carvalho Chehab { 358cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 359cb7a01acSMauro Carvalho Chehab int err = 0; 360cb7a01acSMauro Carvalho Chehab int i; 361cb7a01acSMauro Carvalho Chehab 362cb7a01acSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) { 363cb7a01acSMauro Carvalho Chehab 364cb7a01acSMauro Carvalho Chehab err = adv7343_write(sd, adv7343_init_reg_val[i], 365cb7a01acSMauro Carvalho Chehab adv7343_init_reg_val[i+1]); 366cb7a01acSMauro Carvalho Chehab if (err) { 367cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "Error initializing\n"); 368cb7a01acSMauro Carvalho Chehab return err; 369cb7a01acSMauro Carvalho Chehab } 370cb7a01acSMauro Carvalho Chehab } 371cb7a01acSMauro Carvalho Chehab 372cb7a01acSMauro Carvalho Chehab /* Configure for default video standard */ 373cb7a01acSMauro Carvalho Chehab err = adv7343_setoutput(sd, state->output); 374cb7a01acSMauro Carvalho Chehab if (err < 0) { 375cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "Error setting output during init\n"); 376cb7a01acSMauro Carvalho Chehab return -EINVAL; 377cb7a01acSMauro Carvalho Chehab } 378cb7a01acSMauro Carvalho Chehab 379cb7a01acSMauro Carvalho Chehab err = adv7343_setstd(sd, state->std); 380cb7a01acSMauro Carvalho Chehab if (err < 0) { 381cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "Error setting std during init\n"); 382cb7a01acSMauro Carvalho Chehab return -EINVAL; 383cb7a01acSMauro Carvalho Chehab } 384cb7a01acSMauro Carvalho Chehab 385cb7a01acSMauro Carvalho Chehab return err; 386cb7a01acSMauro Carvalho Chehab } 387cb7a01acSMauro Carvalho Chehab 388cb7a01acSMauro Carvalho Chehab static int adv7343_probe(struct i2c_client *client, 389cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 390cb7a01acSMauro Carvalho Chehab { 391cb7a01acSMauro Carvalho Chehab struct adv7343_state *state; 392cb7a01acSMauro Carvalho Chehab int err; 393cb7a01acSMauro Carvalho Chehab 394cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 395cb7a01acSMauro Carvalho Chehab return -ENODEV; 396cb7a01acSMauro Carvalho Chehab 397cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n", 398cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 399cb7a01acSMauro Carvalho Chehab 400cb7a01acSMauro Carvalho Chehab state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); 401cb7a01acSMauro Carvalho Chehab if (state == NULL) 402cb7a01acSMauro Carvalho Chehab return -ENOMEM; 403cb7a01acSMauro Carvalho Chehab 404cb7a01acSMauro Carvalho Chehab state->reg00 = 0x80; 405cb7a01acSMauro Carvalho Chehab state->reg01 = 0x00; 406cb7a01acSMauro Carvalho Chehab state->reg02 = 0x20; 407cb7a01acSMauro Carvalho Chehab state->reg35 = 0x00; 408cb7a01acSMauro Carvalho Chehab state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT; 409cb7a01acSMauro Carvalho Chehab state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT; 410cb7a01acSMauro Carvalho Chehab 411cb7a01acSMauro Carvalho Chehab state->output = ADV7343_COMPOSITE_ID; 412cb7a01acSMauro Carvalho Chehab state->std = V4L2_STD_NTSC; 413cb7a01acSMauro Carvalho Chehab 414cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); 415cb7a01acSMauro Carvalho Chehab 416cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->hdl, 2); 417cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, 418cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, 419cb7a01acSMauro Carvalho Chehab ADV7343_BRIGHTNESS_MAX, 1, 420cb7a01acSMauro Carvalho Chehab ADV7343_BRIGHTNESS_DEF); 421cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, 422cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7343_HUE_MIN, 423cb7a01acSMauro Carvalho Chehab ADV7343_HUE_MAX, 1, 424cb7a01acSMauro Carvalho Chehab ADV7343_HUE_DEF); 425cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, 426cb7a01acSMauro Carvalho Chehab V4L2_CID_GAIN, ADV7343_GAIN_MIN, 427cb7a01acSMauro Carvalho Chehab ADV7343_GAIN_MAX, 1, 428cb7a01acSMauro Carvalho Chehab ADV7343_GAIN_DEF); 429cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->hdl; 430cb7a01acSMauro Carvalho Chehab if (state->hdl.error) { 431cb7a01acSMauro Carvalho Chehab int err = state->hdl.error; 432cb7a01acSMauro Carvalho Chehab 433cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->hdl); 434cb7a01acSMauro Carvalho Chehab kfree(state); 435cb7a01acSMauro Carvalho Chehab return err; 436cb7a01acSMauro Carvalho Chehab } 437cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->hdl); 438cb7a01acSMauro Carvalho Chehab 439cb7a01acSMauro Carvalho Chehab err = adv7343_initialize(&state->sd); 440cb7a01acSMauro Carvalho Chehab if (err) { 441cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->hdl); 442cb7a01acSMauro Carvalho Chehab kfree(state); 443cb7a01acSMauro Carvalho Chehab } 444cb7a01acSMauro Carvalho Chehab return err; 445cb7a01acSMauro Carvalho Chehab } 446cb7a01acSMauro Carvalho Chehab 447cb7a01acSMauro Carvalho Chehab static int adv7343_remove(struct i2c_client *client) 448cb7a01acSMauro Carvalho Chehab { 449cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 450cb7a01acSMauro Carvalho Chehab struct adv7343_state *state = to_state(sd); 451cb7a01acSMauro Carvalho Chehab 452cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 453cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->hdl); 454cb7a01acSMauro Carvalho Chehab kfree(state); 455cb7a01acSMauro Carvalho Chehab 456cb7a01acSMauro Carvalho Chehab return 0; 457cb7a01acSMauro Carvalho Chehab } 458cb7a01acSMauro Carvalho Chehab 459cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7343_id[] = { 460cb7a01acSMauro Carvalho Chehab {"adv7343", 0}, 461cb7a01acSMauro Carvalho Chehab {}, 462cb7a01acSMauro Carvalho Chehab }; 463cb7a01acSMauro Carvalho Chehab 464cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, adv7343_id); 465cb7a01acSMauro Carvalho Chehab 466cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7343_driver = { 467cb7a01acSMauro Carvalho Chehab .driver = { 468cb7a01acSMauro Carvalho Chehab .owner = THIS_MODULE, 469cb7a01acSMauro Carvalho Chehab .name = "adv7343", 470cb7a01acSMauro Carvalho Chehab }, 471cb7a01acSMauro Carvalho Chehab .probe = adv7343_probe, 472cb7a01acSMauro Carvalho Chehab .remove = adv7343_remove, 473cb7a01acSMauro Carvalho Chehab .id_table = adv7343_id, 474cb7a01acSMauro Carvalho Chehab }; 475cb7a01acSMauro Carvalho Chehab 476cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7343_driver); 477