139c5c447SWenyou Yang // SPDX-License-Identifier: GPL-2.0 239c5c447SWenyou Yang // Copyright (c) 2017 Microchip Corporation. 339c5c447SWenyou Yang 439c5c447SWenyou Yang #include <linux/clk.h> 539c5c447SWenyou Yang #include <linux/delay.h> 64852fdcaSArnd Bergmann #include <linux/gpio/consumer.h> 739c5c447SWenyou Yang #include <linux/i2c.h> 839c5c447SWenyou Yang #include <linux/module.h> 939c5c447SWenyou Yang #include <linux/pm_runtime.h> 1039c5c447SWenyou Yang #include <linux/regmap.h> 1139c5c447SWenyou Yang #include <media/v4l2-ctrls.h> 1239c5c447SWenyou Yang #include <media/v4l2-event.h> 1339c5c447SWenyou Yang #include <media/v4l2-image-sizes.h> 1439c5c447SWenyou Yang #include <media/v4l2-subdev.h> 1539c5c447SWenyou Yang 1639c5c447SWenyou Yang #define REG_OUTSIZE_LSB 0x34 1739c5c447SWenyou Yang 1839c5c447SWenyou Yang /* OV7740 register tables */ 1939c5c447SWenyou Yang #define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ 2039c5c447SWenyou Yang #define REG_BGAIN 0x01 /* blue gain */ 2139c5c447SWenyou Yang #define REG_RGAIN 0x02 /* red gain */ 2239c5c447SWenyou Yang #define REG_GGAIN 0x03 /* green gain */ 23f8a7647dSMauro Carvalho Chehab #define REG_REG04 0x04 /* analog setting, don't change*/ 2439c5c447SWenyou Yang #define REG_BAVG 0x05 /* b channel average */ 2539c5c447SWenyou Yang #define REG_GAVG 0x06 /* g channel average */ 2639c5c447SWenyou Yang #define REG_RAVG 0x07 /* r channel average */ 2739c5c447SWenyou Yang 2839c5c447SWenyou Yang #define REG_REG0C 0x0C /* filp enable */ 2939c5c447SWenyou Yang #define REG0C_IMG_FLIP 0x80 3039c5c447SWenyou Yang #define REG0C_IMG_MIRROR 0x40 3139c5c447SWenyou Yang 3239c5c447SWenyou Yang #define REG_REG0E 0x0E /* blc line */ 3339c5c447SWenyou Yang #define REG_HAEC 0x0F /* auto exposure cntrl */ 3439c5c447SWenyou Yang #define REG_AEC 0x10 /* auto exposure cntrl */ 3539c5c447SWenyou Yang 3639c5c447SWenyou Yang #define REG_CLK 0x11 /* Clock control */ 3739c5c447SWenyou Yang #define REG_REG55 0x55 /* Clock PLL DIV/PreDiv */ 3839c5c447SWenyou Yang 3939c5c447SWenyou Yang #define REG_REG12 0x12 4039c5c447SWenyou Yang 4139c5c447SWenyou Yang #define REG_REG13 0x13 /* auto/manual AGC, AEC, Write Balance*/ 4239c5c447SWenyou Yang #define REG13_AEC_EN 0x01 4339c5c447SWenyou Yang #define REG13_AGC_EN 0x04 4439c5c447SWenyou Yang 4539c5c447SWenyou Yang #define REG_REG14 0x14 4639c5c447SWenyou Yang #define REG_CTRL15 0x15 4739c5c447SWenyou Yang #define REG15_GAIN_MSB 0x03 4839c5c447SWenyou Yang 4939c5c447SWenyou Yang #define REG_REG16 0x16 5039c5c447SWenyou Yang 5139c5c447SWenyou Yang #define REG_MIDH 0x1C /* manufacture id byte */ 5239c5c447SWenyou Yang #define REG_MIDL 0x1D /* manufacture id byre */ 5339c5c447SWenyou Yang #define REG_PIDH 0x0A /* Product ID MSB */ 5439c5c447SWenyou Yang #define REG_PIDL 0x0B /* Product ID LSB */ 5539c5c447SWenyou Yang 5639c5c447SWenyou Yang #define REG_84 0x84 /* lots of stuff */ 5739c5c447SWenyou Yang #define REG_REG38 0x38 /* sub-addr */ 5839c5c447SWenyou Yang 5939c5c447SWenyou Yang #define REG_AHSTART 0x17 /* Horiz start high bits */ 6039c5c447SWenyou Yang #define REG_AHSIZE 0x18 6139c5c447SWenyou Yang #define REG_AVSTART 0x19 /* Vert start high bits */ 6239c5c447SWenyou Yang #define REG_AVSIZE 0x1A 6339c5c447SWenyou Yang #define REG_PSHFT 0x1b /* Pixel delay after HREF */ 6439c5c447SWenyou Yang 6539c5c447SWenyou Yang #define REG_HOUTSIZE 0x31 6639c5c447SWenyou Yang #define REG_VOUTSIZE 0x32 6739c5c447SWenyou Yang #define REG_HVSIZEOFF 0x33 6839c5c447SWenyou Yang #define REG_REG34 0x34 /* DSP output size H/V LSB*/ 6939c5c447SWenyou Yang 7039c5c447SWenyou Yang #define REG_ISP_CTRL00 0x80 7139c5c447SWenyou Yang #define ISPCTRL00_AWB_EN 0x10 7239c5c447SWenyou Yang #define ISPCTRL00_AWB_GAIN_EN 0x04 7339c5c447SWenyou Yang 7439c5c447SWenyou Yang #define REG_YGAIN 0xE2 /* ygain for contrast control */ 7539c5c447SWenyou Yang 7639c5c447SWenyou Yang #define REG_YBRIGHT 0xE3 7739c5c447SWenyou Yang #define REG_SGNSET 0xE4 7839c5c447SWenyou Yang #define SGNSET_YBRIGHT_MASK 0x08 7939c5c447SWenyou Yang 8039c5c447SWenyou Yang #define REG_USAT 0xDD 8139c5c447SWenyou Yang #define REG_VSAT 0xDE 8239c5c447SWenyou Yang 8339c5c447SWenyou Yang 8439c5c447SWenyou Yang struct ov7740 { 8539c5c447SWenyou Yang struct v4l2_subdev subdev; 8639c5c447SWenyou Yang #if defined(CONFIG_MEDIA_CONTROLLER) 8739c5c447SWenyou Yang struct media_pad pad; 8839c5c447SWenyou Yang #endif 8939c5c447SWenyou Yang struct v4l2_mbus_framefmt format; 9039c5c447SWenyou Yang const struct ov7740_pixfmt *fmt; /* Current format */ 9139c5c447SWenyou Yang const struct ov7740_framesize *frmsize; 9239c5c447SWenyou Yang struct regmap *regmap; 9339c5c447SWenyou Yang struct clk *xvclk; 9439c5c447SWenyou Yang struct v4l2_ctrl_handler ctrl_handler; 9539c5c447SWenyou Yang struct { 9639c5c447SWenyou Yang /* gain cluster */ 9739c5c447SWenyou Yang struct v4l2_ctrl *auto_gain; 9839c5c447SWenyou Yang struct v4l2_ctrl *gain; 9939c5c447SWenyou Yang }; 10039c5c447SWenyou Yang struct { 10139c5c447SWenyou Yang struct v4l2_ctrl *auto_wb; 10239c5c447SWenyou Yang struct v4l2_ctrl *blue_balance; 10339c5c447SWenyou Yang struct v4l2_ctrl *red_balance; 10439c5c447SWenyou Yang }; 10539c5c447SWenyou Yang struct { 10639c5c447SWenyou Yang struct v4l2_ctrl *hflip; 10739c5c447SWenyou Yang struct v4l2_ctrl *vflip; 10839c5c447SWenyou Yang }; 10939c5c447SWenyou Yang struct { 11039c5c447SWenyou Yang /* exposure cluster */ 11139c5c447SWenyou Yang struct v4l2_ctrl *auto_exposure; 11239c5c447SWenyou Yang struct v4l2_ctrl *exposure; 11339c5c447SWenyou Yang }; 11439c5c447SWenyou Yang struct { 11539c5c447SWenyou Yang /* saturation/hue cluster */ 11639c5c447SWenyou Yang struct v4l2_ctrl *saturation; 11739c5c447SWenyou Yang struct v4l2_ctrl *hue; 11839c5c447SWenyou Yang }; 11939c5c447SWenyou Yang struct v4l2_ctrl *brightness; 12039c5c447SWenyou Yang struct v4l2_ctrl *contrast; 12139c5c447SWenyou Yang 12239c5c447SWenyou Yang struct mutex mutex; /* To serialize asynchronus callbacks */ 12339c5c447SWenyou Yang bool streaming; /* Streaming on/off */ 12439c5c447SWenyou Yang 12539c5c447SWenyou Yang struct gpio_desc *resetb_gpio; 12639c5c447SWenyou Yang struct gpio_desc *pwdn_gpio; 12739c5c447SWenyou Yang }; 12839c5c447SWenyou Yang 12939c5c447SWenyou Yang struct ov7740_pixfmt { 13039c5c447SWenyou Yang u32 mbus_code; 13139c5c447SWenyou Yang enum v4l2_colorspace colorspace; 13239c5c447SWenyou Yang const struct reg_sequence *regs; 13339c5c447SWenyou Yang u32 reg_num; 13439c5c447SWenyou Yang }; 13539c5c447SWenyou Yang 13639c5c447SWenyou Yang struct ov7740_framesize { 13739c5c447SWenyou Yang u16 width; 13839c5c447SWenyou Yang u16 height; 13939c5c447SWenyou Yang const struct reg_sequence *regs; 14039c5c447SWenyou Yang u32 reg_num; 14139c5c447SWenyou Yang }; 14239c5c447SWenyou Yang 14339c5c447SWenyou Yang static const struct reg_sequence ov7740_vga[] = { 14439c5c447SWenyou Yang {0x55, 0x40}, 14539c5c447SWenyou Yang {0x11, 0x02}, 14639c5c447SWenyou Yang 14739c5c447SWenyou Yang {0xd5, 0x10}, 14839c5c447SWenyou Yang {0x0c, 0x12}, 14939c5c447SWenyou Yang {0x0d, 0x34}, 15039c5c447SWenyou Yang {0x17, 0x25}, 15139c5c447SWenyou Yang {0x18, 0xa0}, 15239c5c447SWenyou Yang {0x19, 0x03}, 15339c5c447SWenyou Yang {0x1a, 0xf0}, 15439c5c447SWenyou Yang {0x1b, 0x89}, 15539c5c447SWenyou Yang {0x22, 0x03}, 15639c5c447SWenyou Yang {0x29, 0x18}, 15739c5c447SWenyou Yang {0x2b, 0xf8}, 15839c5c447SWenyou Yang {0x2c, 0x01}, 15939c5c447SWenyou Yang {REG_HOUTSIZE, 0xa0}, 16039c5c447SWenyou Yang {REG_VOUTSIZE, 0xf0}, 16139c5c447SWenyou Yang {0x33, 0xc4}, 16239c5c447SWenyou Yang {REG_OUTSIZE_LSB, 0x0}, 16339c5c447SWenyou Yang {0x35, 0x05}, 16439c5c447SWenyou Yang {0x04, 0x60}, 16539c5c447SWenyou Yang {0x27, 0x80}, 16639c5c447SWenyou Yang {0x3d, 0x0f}, 16739c5c447SWenyou Yang {0x3e, 0x80}, 16839c5c447SWenyou Yang {0x3f, 0x40}, 16939c5c447SWenyou Yang {0x40, 0x7f}, 17039c5c447SWenyou Yang {0x41, 0x6a}, 17139c5c447SWenyou Yang {0x42, 0x29}, 17239c5c447SWenyou Yang {0x44, 0x22}, 17339c5c447SWenyou Yang {0x45, 0x41}, 17439c5c447SWenyou Yang {0x47, 0x02}, 17539c5c447SWenyou Yang {0x49, 0x64}, 17639c5c447SWenyou Yang {0x4a, 0xa1}, 17739c5c447SWenyou Yang {0x4b, 0x40}, 17839c5c447SWenyou Yang {0x4c, 0x1a}, 17939c5c447SWenyou Yang {0x4d, 0x50}, 18039c5c447SWenyou Yang {0x4e, 0x13}, 18139c5c447SWenyou Yang {0x64, 0x00}, 18239c5c447SWenyou Yang {0x67, 0x88}, 18339c5c447SWenyou Yang {0x68, 0x1a}, 18439c5c447SWenyou Yang 18539c5c447SWenyou Yang {0x14, 0x28}, 18639c5c447SWenyou Yang {0x24, 0x3c}, 18739c5c447SWenyou Yang {0x25, 0x30}, 18839c5c447SWenyou Yang {0x26, 0x72}, 18939c5c447SWenyou Yang {0x50, 0x97}, 19039c5c447SWenyou Yang {0x51, 0x1f}, 19139c5c447SWenyou Yang {0x52, 0x00}, 19239c5c447SWenyou Yang {0x53, 0x00}, 19339c5c447SWenyou Yang {0x20, 0x00}, 19439c5c447SWenyou Yang {0x21, 0xcf}, 19539c5c447SWenyou Yang {0x50, 0x4b}, 19639c5c447SWenyou Yang {0x38, 0x14}, 19739c5c447SWenyou Yang {0xe9, 0x00}, 19839c5c447SWenyou Yang {0x56, 0x55}, 19939c5c447SWenyou Yang {0x57, 0xff}, 20039c5c447SWenyou Yang {0x58, 0xff}, 20139c5c447SWenyou Yang {0x59, 0xff}, 20239c5c447SWenyou Yang {0x5f, 0x04}, 20339c5c447SWenyou Yang {0xec, 0x00}, 20439c5c447SWenyou Yang {0x13, 0xff}, 20539c5c447SWenyou Yang 20639c5c447SWenyou Yang {0x81, 0x3f}, 20739c5c447SWenyou Yang {0x82, 0x32}, 20839c5c447SWenyou Yang {0x38, 0x11}, 20939c5c447SWenyou Yang {0x84, 0x70}, 21039c5c447SWenyou Yang {0x85, 0x00}, 21139c5c447SWenyou Yang {0x86, 0x03}, 21239c5c447SWenyou Yang {0x87, 0x01}, 21339c5c447SWenyou Yang {0x88, 0x05}, 21439c5c447SWenyou Yang {0x89, 0x30}, 21539c5c447SWenyou Yang {0x8d, 0x30}, 21639c5c447SWenyou Yang {0x8f, 0x85}, 21739c5c447SWenyou Yang {0x93, 0x30}, 21839c5c447SWenyou Yang {0x95, 0x85}, 21939c5c447SWenyou Yang {0x99, 0x30}, 22039c5c447SWenyou Yang {0x9b, 0x85}, 22139c5c447SWenyou Yang 22239c5c447SWenyou Yang {0x9c, 0x08}, 22339c5c447SWenyou Yang {0x9d, 0x12}, 22439c5c447SWenyou Yang {0x9e, 0x23}, 22539c5c447SWenyou Yang {0x9f, 0x45}, 22639c5c447SWenyou Yang {0xa0, 0x55}, 22739c5c447SWenyou Yang {0xa1, 0x64}, 22839c5c447SWenyou Yang {0xa2, 0x72}, 22939c5c447SWenyou Yang {0xa3, 0x7f}, 23039c5c447SWenyou Yang {0xa4, 0x8b}, 23139c5c447SWenyou Yang {0xa5, 0x95}, 23239c5c447SWenyou Yang {0xa6, 0xa7}, 23339c5c447SWenyou Yang {0xa7, 0xb5}, 23439c5c447SWenyou Yang {0xa8, 0xcb}, 23539c5c447SWenyou Yang {0xa9, 0xdd}, 23639c5c447SWenyou Yang {0xaa, 0xec}, 23739c5c447SWenyou Yang {0xab, 0x1a}, 23839c5c447SWenyou Yang 23939c5c447SWenyou Yang {0xce, 0x78}, 24039c5c447SWenyou Yang {0xcf, 0x6e}, 24139c5c447SWenyou Yang {0xd0, 0x0a}, 24239c5c447SWenyou Yang {0xd1, 0x0c}, 24339c5c447SWenyou Yang {0xd2, 0x84}, 24439c5c447SWenyou Yang {0xd3, 0x90}, 24539c5c447SWenyou Yang {0xd4, 0x1e}, 24639c5c447SWenyou Yang 24739c5c447SWenyou Yang {0x5a, 0x24}, 24839c5c447SWenyou Yang {0x5b, 0x1f}, 24939c5c447SWenyou Yang {0x5c, 0x88}, 25039c5c447SWenyou Yang {0x5d, 0x60}, 25139c5c447SWenyou Yang 25239c5c447SWenyou Yang {0xac, 0x6e}, 25339c5c447SWenyou Yang {0xbe, 0xff}, 25439c5c447SWenyou Yang {0xbf, 0x00}, 25539c5c447SWenyou Yang 25639c5c447SWenyou Yang {0x0f, 0x1d}, 25739c5c447SWenyou Yang {0x0f, 0x1f}, 25839c5c447SWenyou Yang }; 25939c5c447SWenyou Yang 26039c5c447SWenyou Yang static const struct ov7740_framesize ov7740_framesizes[] = { 26139c5c447SWenyou Yang { 26239c5c447SWenyou Yang .width = VGA_WIDTH, 26339c5c447SWenyou Yang .height = VGA_HEIGHT, 26439c5c447SWenyou Yang .regs = ov7740_vga, 26539c5c447SWenyou Yang .reg_num = ARRAY_SIZE(ov7740_vga), 26639c5c447SWenyou Yang }, 26739c5c447SWenyou Yang }; 26839c5c447SWenyou Yang 26939c5c447SWenyou Yang #ifdef CONFIG_VIDEO_ADV_DEBUG 27039c5c447SWenyou Yang static int ov7740_get_register(struct v4l2_subdev *sd, 27139c5c447SWenyou Yang struct v4l2_dbg_register *reg) 27239c5c447SWenyou Yang { 27339c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 27439c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 27539c5c447SWenyou Yang unsigned int val = 0; 27639c5c447SWenyou Yang int ret; 27739c5c447SWenyou Yang 27839c5c447SWenyou Yang ret = regmap_read(regmap, reg->reg & 0xff, &val); 27939c5c447SWenyou Yang reg->val = val; 28039c5c447SWenyou Yang reg->size = 1; 28139c5c447SWenyou Yang 28200d9da50SMauro Carvalho Chehab return ret; 28339c5c447SWenyou Yang } 28439c5c447SWenyou Yang 28539c5c447SWenyou Yang static int ov7740_set_register(struct v4l2_subdev *sd, 28639c5c447SWenyou Yang const struct v4l2_dbg_register *reg) 28739c5c447SWenyou Yang { 28839c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 28939c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 29039c5c447SWenyou Yang 29139c5c447SWenyou Yang regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff); 29239c5c447SWenyou Yang 29339c5c447SWenyou Yang return 0; 29439c5c447SWenyou Yang } 29539c5c447SWenyou Yang #endif 29639c5c447SWenyou Yang 29739c5c447SWenyou Yang static int ov7740_set_power(struct ov7740 *ov7740, int on) 29839c5c447SWenyou Yang { 29939c5c447SWenyou Yang int ret; 30039c5c447SWenyou Yang 30139c5c447SWenyou Yang if (on) { 30239c5c447SWenyou Yang ret = clk_prepare_enable(ov7740->xvclk); 30339c5c447SWenyou Yang if (ret) 30439c5c447SWenyou Yang return ret; 30539c5c447SWenyou Yang 30639c5c447SWenyou Yang if (ov7740->pwdn_gpio) 30739c5c447SWenyou Yang gpiod_direction_output(ov7740->pwdn_gpio, 0); 30839c5c447SWenyou Yang 30939c5c447SWenyou Yang if (ov7740->resetb_gpio) { 31039c5c447SWenyou Yang gpiod_set_value(ov7740->resetb_gpio, 1); 31139c5c447SWenyou Yang usleep_range(500, 1000); 31239c5c447SWenyou Yang gpiod_set_value(ov7740->resetb_gpio, 0); 31339c5c447SWenyou Yang usleep_range(3000, 5000); 31439c5c447SWenyou Yang } 31539c5c447SWenyou Yang } else { 31639c5c447SWenyou Yang clk_disable_unprepare(ov7740->xvclk); 31739c5c447SWenyou Yang 31839c5c447SWenyou Yang if (ov7740->pwdn_gpio) 31939c5c447SWenyou Yang gpiod_direction_output(ov7740->pwdn_gpio, 0); 32039c5c447SWenyou Yang } 32139c5c447SWenyou Yang 32239c5c447SWenyou Yang return 0; 32339c5c447SWenyou Yang } 32439c5c447SWenyou Yang 325fbe57ddeSJulia Lawall static const struct v4l2_subdev_core_ops ov7740_subdev_core_ops = { 32639c5c447SWenyou Yang .log_status = v4l2_ctrl_subdev_log_status, 32739c5c447SWenyou Yang #ifdef CONFIG_VIDEO_ADV_DEBUG 32839c5c447SWenyou Yang .g_register = ov7740_get_register, 32939c5c447SWenyou Yang .s_register = ov7740_set_register, 33039c5c447SWenyou Yang #endif 33139c5c447SWenyou Yang .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 33239c5c447SWenyou Yang .unsubscribe_event = v4l2_event_subdev_unsubscribe, 33339c5c447SWenyou Yang }; 33439c5c447SWenyou Yang 33539c5c447SWenyou Yang static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb) 33639c5c447SWenyou Yang { 33739c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 33839c5c447SWenyou Yang unsigned int value; 33939c5c447SWenyou Yang int ret; 34039c5c447SWenyou Yang 34139c5c447SWenyou Yang ret = regmap_read(regmap, REG_ISP_CTRL00, &value); 34239c5c447SWenyou Yang if (!ret) { 34339c5c447SWenyou Yang if (awb) 34439c5c447SWenyou Yang value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN); 34539c5c447SWenyou Yang else 34639c5c447SWenyou Yang value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN); 34739c5c447SWenyou Yang ret = regmap_write(regmap, REG_ISP_CTRL00, value); 34839c5c447SWenyou Yang if (ret) 34939c5c447SWenyou Yang return ret; 35039c5c447SWenyou Yang } 35139c5c447SWenyou Yang 35239c5c447SWenyou Yang if (!awb) { 35339c5c447SWenyou Yang ret = regmap_write(regmap, REG_BGAIN, 35439c5c447SWenyou Yang ov7740->blue_balance->val); 35539c5c447SWenyou Yang if (ret) 35639c5c447SWenyou Yang return ret; 35739c5c447SWenyou Yang 35839c5c447SWenyou Yang ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val); 35939c5c447SWenyou Yang if (ret) 36039c5c447SWenyou Yang return ret; 36139c5c447SWenyou Yang } 36239c5c447SWenyou Yang 36339c5c447SWenyou Yang return 0; 36439c5c447SWenyou Yang } 36539c5c447SWenyou Yang 36639c5c447SWenyou Yang static int ov7740_set_saturation(struct regmap *regmap, int value) 36739c5c447SWenyou Yang { 36839c5c447SWenyou Yang int ret; 36939c5c447SWenyou Yang 37039c5c447SWenyou Yang ret = regmap_write(regmap, REG_USAT, (unsigned char)value); 37139c5c447SWenyou Yang if (ret) 37239c5c447SWenyou Yang return ret; 37339c5c447SWenyou Yang 37439c5c447SWenyou Yang return regmap_write(regmap, REG_VSAT, (unsigned char)value); 37539c5c447SWenyou Yang } 37639c5c447SWenyou Yang 37739c5c447SWenyou Yang static int ov7740_set_gain(struct regmap *regmap, int value) 37839c5c447SWenyou Yang { 37939c5c447SWenyou Yang int ret; 38039c5c447SWenyou Yang 38139c5c447SWenyou Yang ret = regmap_write(regmap, REG_GAIN, value & 0xff); 38239c5c447SWenyou Yang if (ret) 38339c5c447SWenyou Yang return ret; 38439c5c447SWenyou Yang 38539c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_CTRL15, 38639c5c447SWenyou Yang REG15_GAIN_MSB, (value >> 8) & 0x3); 38739c5c447SWenyou Yang if (!ret) 38839c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0); 38939c5c447SWenyou Yang 39039c5c447SWenyou Yang return ret; 39139c5c447SWenyou Yang } 39239c5c447SWenyou Yang 39339c5c447SWenyou Yang static int ov7740_set_autogain(struct regmap *regmap, int value) 39439c5c447SWenyou Yang { 39539c5c447SWenyou Yang unsigned int reg; 39639c5c447SWenyou Yang int ret; 39739c5c447SWenyou Yang 39839c5c447SWenyou Yang ret = regmap_read(regmap, REG_REG13, ®); 39939c5c447SWenyou Yang if (ret) 40039c5c447SWenyou Yang return ret; 40139c5c447SWenyou Yang if (value) 40239c5c447SWenyou Yang reg |= REG13_AGC_EN; 40339c5c447SWenyou Yang else 40439c5c447SWenyou Yang reg &= ~REG13_AGC_EN; 40539c5c447SWenyou Yang return regmap_write(regmap, REG_REG13, reg); 40639c5c447SWenyou Yang } 40739c5c447SWenyou Yang 40839c5c447SWenyou Yang static int ov7740_set_brightness(struct regmap *regmap, int value) 40939c5c447SWenyou Yang { 41039c5c447SWenyou Yang /* Turn off AEC/AGC */ 41139c5c447SWenyou Yang regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0); 41239c5c447SWenyou Yang regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0); 41339c5c447SWenyou Yang 41439c5c447SWenyou Yang if (value >= 0) { 41539c5c447SWenyou Yang regmap_write(regmap, REG_YBRIGHT, (unsigned char)value); 41639c5c447SWenyou Yang regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0); 41739c5c447SWenyou Yang } else{ 41839c5c447SWenyou Yang regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value)); 41939c5c447SWenyou Yang regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1); 42039c5c447SWenyou Yang } 42139c5c447SWenyou Yang 42239c5c447SWenyou Yang return 0; 42339c5c447SWenyou Yang } 42439c5c447SWenyou Yang 42539c5c447SWenyou Yang static int ov7740_set_contrast(struct regmap *regmap, int value) 42639c5c447SWenyou Yang { 42739c5c447SWenyou Yang return regmap_write(regmap, REG_YGAIN, (unsigned char)value); 42839c5c447SWenyou Yang } 42939c5c447SWenyou Yang 43039c5c447SWenyou Yang static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) 43139c5c447SWenyou Yang { 43239c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 43339c5c447SWenyou Yang unsigned int value0, value1; 43439c5c447SWenyou Yang int ret; 43539c5c447SWenyou Yang 43639c5c447SWenyou Yang if (!ctrl->val) 43739c5c447SWenyou Yang return 0; 43839c5c447SWenyou Yang 43939c5c447SWenyou Yang ret = regmap_read(regmap, REG_GAIN, &value0); 44039c5c447SWenyou Yang if (ret) 44139c5c447SWenyou Yang return ret; 44239c5c447SWenyou Yang ret = regmap_read(regmap, REG_CTRL15, &value1); 44339c5c447SWenyou Yang if (ret) 44439c5c447SWenyou Yang return ret; 44539c5c447SWenyou Yang 44639c5c447SWenyou Yang ov7740->gain->val = (value1 << 8) | (value0 & 0xff); 44739c5c447SWenyou Yang 44839c5c447SWenyou Yang return 0; 44939c5c447SWenyou Yang } 45039c5c447SWenyou Yang 451c4b50cabSAkinobu Mita static int ov7740_get_exp(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) 452c4b50cabSAkinobu Mita { 453c4b50cabSAkinobu Mita struct regmap *regmap = ov7740->regmap; 454c4b50cabSAkinobu Mita unsigned int value0, value1; 455c4b50cabSAkinobu Mita int ret; 456c4b50cabSAkinobu Mita 457c4b50cabSAkinobu Mita if (ctrl->val == V4L2_EXPOSURE_MANUAL) 458c4b50cabSAkinobu Mita return 0; 459c4b50cabSAkinobu Mita 460c4b50cabSAkinobu Mita ret = regmap_read(regmap, REG_AEC, &value0); 461c4b50cabSAkinobu Mita if (ret) 462c4b50cabSAkinobu Mita return ret; 463c4b50cabSAkinobu Mita ret = regmap_read(regmap, REG_HAEC, &value1); 464c4b50cabSAkinobu Mita if (ret) 465c4b50cabSAkinobu Mita return ret; 466c4b50cabSAkinobu Mita 467c4b50cabSAkinobu Mita ov7740->exposure->val = (value1 << 8) | (value0 & 0xff); 468c4b50cabSAkinobu Mita 469c4b50cabSAkinobu Mita return 0; 470c4b50cabSAkinobu Mita } 471c4b50cabSAkinobu Mita 47239c5c447SWenyou Yang static int ov7740_set_exp(struct regmap *regmap, int value) 47339c5c447SWenyou Yang { 47439c5c447SWenyou Yang int ret; 47539c5c447SWenyou Yang 47639c5c447SWenyou Yang /* Turn off AEC/AGC */ 47739c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG13, 47839c5c447SWenyou Yang REG13_AEC_EN | REG13_AGC_EN, 0); 47939c5c447SWenyou Yang if (ret) 48039c5c447SWenyou Yang return ret; 48139c5c447SWenyou Yang 48239c5c447SWenyou Yang ret = regmap_write(regmap, REG_AEC, (unsigned char)value); 48339c5c447SWenyou Yang if (ret) 48439c5c447SWenyou Yang return ret; 48539c5c447SWenyou Yang 48639c5c447SWenyou Yang return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8)); 48739c5c447SWenyou Yang } 48839c5c447SWenyou Yang 48939c5c447SWenyou Yang static int ov7740_set_autoexp(struct regmap *regmap, 49039c5c447SWenyou Yang enum v4l2_exposure_auto_type value) 49139c5c447SWenyou Yang { 49239c5c447SWenyou Yang unsigned int reg; 49339c5c447SWenyou Yang int ret; 49439c5c447SWenyou Yang 49539c5c447SWenyou Yang ret = regmap_read(regmap, REG_REG13, ®); 49639c5c447SWenyou Yang if (!ret) { 49739c5c447SWenyou Yang if (value == V4L2_EXPOSURE_AUTO) 49839c5c447SWenyou Yang reg |= (REG13_AEC_EN | REG13_AGC_EN); 49939c5c447SWenyou Yang else 50039c5c447SWenyou Yang reg &= ~(REG13_AEC_EN | REG13_AGC_EN); 50139c5c447SWenyou Yang ret = regmap_write(regmap, REG_REG13, reg); 50239c5c447SWenyou Yang } 50339c5c447SWenyou Yang 50439c5c447SWenyou Yang return ret; 50539c5c447SWenyou Yang } 50639c5c447SWenyou Yang 50739c5c447SWenyou Yang 50839c5c447SWenyou Yang static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl) 50939c5c447SWenyou Yang { 51039c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(ctrl->handler, 51139c5c447SWenyou Yang struct ov7740, ctrl_handler); 51239c5c447SWenyou Yang int ret; 51339c5c447SWenyou Yang 51439c5c447SWenyou Yang switch (ctrl->id) { 51539c5c447SWenyou Yang case V4L2_CID_AUTOGAIN: 51639c5c447SWenyou Yang ret = ov7740_get_gain(ov7740, ctrl); 51739c5c447SWenyou Yang break; 518c4b50cabSAkinobu Mita case V4L2_CID_EXPOSURE_AUTO: 519c4b50cabSAkinobu Mita ret = ov7740_get_exp(ov7740, ctrl); 520c4b50cabSAkinobu Mita break; 52139c5c447SWenyou Yang default: 52239c5c447SWenyou Yang ret = -EINVAL; 52339c5c447SWenyou Yang break; 52439c5c447SWenyou Yang } 52539c5c447SWenyou Yang return ret; 52639c5c447SWenyou Yang } 52739c5c447SWenyou Yang 52839c5c447SWenyou Yang static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) 52939c5c447SWenyou Yang { 53039c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(ctrl->handler, 53139c5c447SWenyou Yang struct ov7740, ctrl_handler); 53239c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); 53339c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 53439c5c447SWenyou Yang int ret; 535eed6b2e7SAkinobu Mita u8 val; 53639c5c447SWenyou Yang 5374d471563SSakari Ailus if (!pm_runtime_get_if_in_use(&client->dev)) 53839c5c447SWenyou Yang return 0; 53939c5c447SWenyou Yang 54039c5c447SWenyou Yang switch (ctrl->id) { 54139c5c447SWenyou Yang case V4L2_CID_AUTO_WHITE_BALANCE: 54239c5c447SWenyou Yang ret = ov7740_set_white_balance(ov7740, ctrl->val); 54339c5c447SWenyou Yang break; 54439c5c447SWenyou Yang case V4L2_CID_SATURATION: 54539c5c447SWenyou Yang ret = ov7740_set_saturation(regmap, ctrl->val); 54639c5c447SWenyou Yang break; 54739c5c447SWenyou Yang case V4L2_CID_BRIGHTNESS: 54839c5c447SWenyou Yang ret = ov7740_set_brightness(regmap, ctrl->val); 54939c5c447SWenyou Yang break; 55039c5c447SWenyou Yang case V4L2_CID_CONTRAST: 55139c5c447SWenyou Yang ret = ov7740_set_contrast(regmap, ctrl->val); 55239c5c447SWenyou Yang break; 55339c5c447SWenyou Yang case V4L2_CID_VFLIP: 554eed6b2e7SAkinobu Mita val = ctrl->val ? REG0C_IMG_FLIP : 0x00; 55539c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG0C, 55639c5c447SWenyou Yang REG0C_IMG_FLIP, val); 55739c5c447SWenyou Yang break; 55839c5c447SWenyou Yang case V4L2_CID_HFLIP: 55939c5c447SWenyou Yang val = ctrl->val ? REG0C_IMG_MIRROR : 0x00; 56039c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG0C, 56139c5c447SWenyou Yang REG0C_IMG_MIRROR, val); 56239c5c447SWenyou Yang break; 56339c5c447SWenyou Yang case V4L2_CID_AUTOGAIN: 56439c5c447SWenyou Yang if (!ctrl->val) 565cfe7cc38SAkinobu Mita ret = ov7740_set_gain(regmap, ov7740->gain->val); 566cfe7cc38SAkinobu Mita else 56739c5c447SWenyou Yang ret = ov7740_set_autogain(regmap, ctrl->val); 56839c5c447SWenyou Yang break; 56939c5c447SWenyou Yang 57039c5c447SWenyou Yang case V4L2_CID_EXPOSURE_AUTO: 57139c5c447SWenyou Yang if (ctrl->val == V4L2_EXPOSURE_MANUAL) 572cfe7cc38SAkinobu Mita ret = ov7740_set_exp(regmap, ov7740->exposure->val); 573cfe7cc38SAkinobu Mita else 57439c5c447SWenyou Yang ret = ov7740_set_autoexp(regmap, ctrl->val); 57539c5c447SWenyou Yang break; 57639c5c447SWenyou Yang default: 57739c5c447SWenyou Yang ret = -EINVAL; 57839c5c447SWenyou Yang break; 57939c5c447SWenyou Yang } 58039c5c447SWenyou Yang 58139c5c447SWenyou Yang pm_runtime_put(&client->dev); 58239c5c447SWenyou Yang 58339c5c447SWenyou Yang return ret; 58439c5c447SWenyou Yang } 58539c5c447SWenyou Yang 58639c5c447SWenyou Yang static const struct v4l2_ctrl_ops ov7740_ctrl_ops = { 58739c5c447SWenyou Yang .g_volatile_ctrl = ov7740_get_volatile_ctrl, 58839c5c447SWenyou Yang .s_ctrl = ov7740_set_ctrl, 58939c5c447SWenyou Yang }; 59039c5c447SWenyou Yang 59139c5c447SWenyou Yang static int ov7740_start_streaming(struct ov7740 *ov7740) 59239c5c447SWenyou Yang { 59339c5c447SWenyou Yang int ret; 59439c5c447SWenyou Yang 59539c5c447SWenyou Yang if (ov7740->fmt) { 59639c5c447SWenyou Yang ret = regmap_multi_reg_write(ov7740->regmap, 59739c5c447SWenyou Yang ov7740->fmt->regs, 59839c5c447SWenyou Yang ov7740->fmt->reg_num); 59939c5c447SWenyou Yang if (ret) 60039c5c447SWenyou Yang return ret; 60139c5c447SWenyou Yang } 60239c5c447SWenyou Yang 60339c5c447SWenyou Yang if (ov7740->frmsize) { 60439c5c447SWenyou Yang ret = regmap_multi_reg_write(ov7740->regmap, 60539c5c447SWenyou Yang ov7740->frmsize->regs, 60639c5c447SWenyou Yang ov7740->frmsize->reg_num); 60739c5c447SWenyou Yang if (ret) 60839c5c447SWenyou Yang return ret; 60939c5c447SWenyou Yang } 61039c5c447SWenyou Yang 61139c5c447SWenyou Yang return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler); 61239c5c447SWenyou Yang } 61339c5c447SWenyou Yang 61439c5c447SWenyou Yang static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) 61539c5c447SWenyou Yang { 61639c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 61739c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(sd); 61839c5c447SWenyou Yang int ret = 0; 61939c5c447SWenyou Yang 62039c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 62139c5c447SWenyou Yang if (ov7740->streaming == enable) { 62239c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 62339c5c447SWenyou Yang return 0; 62439c5c447SWenyou Yang } 62539c5c447SWenyou Yang 62639c5c447SWenyou Yang if (enable) { 62739c5c447SWenyou Yang ret = pm_runtime_get_sync(&client->dev); 62839c5c447SWenyou Yang if (ret < 0) { 62939c5c447SWenyou Yang pm_runtime_put_noidle(&client->dev); 63039c5c447SWenyou Yang goto err_unlock; 63139c5c447SWenyou Yang } 63239c5c447SWenyou Yang 63339c5c447SWenyou Yang ret = ov7740_start_streaming(ov7740); 63439c5c447SWenyou Yang if (ret) 63539c5c447SWenyou Yang goto err_rpm_put; 63639c5c447SWenyou Yang } else { 63739c5c447SWenyou Yang pm_runtime_put(&client->dev); 63839c5c447SWenyou Yang } 63939c5c447SWenyou Yang 64039c5c447SWenyou Yang ov7740->streaming = enable; 64139c5c447SWenyou Yang 64239c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 64339c5c447SWenyou Yang return ret; 64439c5c447SWenyou Yang 64539c5c447SWenyou Yang err_rpm_put: 64639c5c447SWenyou Yang pm_runtime_put(&client->dev); 64739c5c447SWenyou Yang err_unlock: 64839c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 64939c5c447SWenyou Yang return ret; 65039c5c447SWenyou Yang } 65139c5c447SWenyou Yang 6524471109eSHans Verkuil static int ov7740_g_frame_interval(struct v4l2_subdev *sd, 6534471109eSHans Verkuil struct v4l2_subdev_frame_interval *ival) 65439c5c447SWenyou Yang { 6554471109eSHans Verkuil struct v4l2_fract *tpf = &ival->interval; 65639c5c447SWenyou Yang 65739c5c447SWenyou Yang 65839c5c447SWenyou Yang tpf->numerator = 1; 65939c5c447SWenyou Yang tpf->denominator = 60; 66039c5c447SWenyou Yang 66139c5c447SWenyou Yang return 0; 66239c5c447SWenyou Yang } 66339c5c447SWenyou Yang 6644471109eSHans Verkuil static int ov7740_s_frame_interval(struct v4l2_subdev *sd, 6654471109eSHans Verkuil struct v4l2_subdev_frame_interval *ival) 66639c5c447SWenyou Yang { 6674471109eSHans Verkuil struct v4l2_fract *tpf = &ival->interval; 66839c5c447SWenyou Yang 66939c5c447SWenyou Yang 67039c5c447SWenyou Yang tpf->numerator = 1; 67139c5c447SWenyou Yang tpf->denominator = 60; 67239c5c447SWenyou Yang 67339c5c447SWenyou Yang return 0; 67439c5c447SWenyou Yang } 67539c5c447SWenyou Yang 676fbe57ddeSJulia Lawall static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { 67739c5c447SWenyou Yang .s_stream = ov7740_set_stream, 6784471109eSHans Verkuil .s_frame_interval = ov7740_s_frame_interval, 6794471109eSHans Verkuil .g_frame_interval = ov7740_g_frame_interval, 68039c5c447SWenyou Yang }; 68139c5c447SWenyou Yang 68239c5c447SWenyou Yang static const struct reg_sequence ov7740_format_yuyv[] = { 68339c5c447SWenyou Yang {0x12, 0x00}, 68439c5c447SWenyou Yang {0x36, 0x3f}, 68539c5c447SWenyou Yang {0x80, 0x7f}, 68639c5c447SWenyou Yang {0x83, 0x01}, 68739c5c447SWenyou Yang }; 68839c5c447SWenyou Yang 68939c5c447SWenyou Yang static const struct reg_sequence ov7740_format_bggr8[] = { 69039c5c447SWenyou Yang {0x36, 0x2f}, 69139c5c447SWenyou Yang {0x80, 0x01}, 69239c5c447SWenyou Yang {0x83, 0x04}, 69339c5c447SWenyou Yang }; 69439c5c447SWenyou Yang 69539c5c447SWenyou Yang static const struct ov7740_pixfmt ov7740_formats[] = { 69639c5c447SWenyou Yang { 69739c5c447SWenyou Yang .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, 69839c5c447SWenyou Yang .colorspace = V4L2_COLORSPACE_SRGB, 69939c5c447SWenyou Yang .regs = ov7740_format_yuyv, 70039c5c447SWenyou Yang .reg_num = ARRAY_SIZE(ov7740_format_yuyv), 70139c5c447SWenyou Yang }, 70239c5c447SWenyou Yang { 70339c5c447SWenyou Yang .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 70439c5c447SWenyou Yang .colorspace = V4L2_COLORSPACE_SRGB, 70539c5c447SWenyou Yang .regs = ov7740_format_bggr8, 70639c5c447SWenyou Yang .reg_num = ARRAY_SIZE(ov7740_format_bggr8), 70739c5c447SWenyou Yang } 70839c5c447SWenyou Yang }; 70939c5c447SWenyou Yang #define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats) 71039c5c447SWenyou Yang 71139c5c447SWenyou Yang static int ov7740_enum_mbus_code(struct v4l2_subdev *sd, 71239c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 71339c5c447SWenyou Yang struct v4l2_subdev_mbus_code_enum *code) 71439c5c447SWenyou Yang { 71539c5c447SWenyou Yang if (code->pad || code->index >= N_OV7740_FMTS) 71639c5c447SWenyou Yang return -EINVAL; 71739c5c447SWenyou Yang 71839c5c447SWenyou Yang code->code = ov7740_formats[code->index].mbus_code; 71939c5c447SWenyou Yang 72039c5c447SWenyou Yang return 0; 72139c5c447SWenyou Yang } 72239c5c447SWenyou Yang 72339c5c447SWenyou Yang static int ov7740_enum_frame_interval(struct v4l2_subdev *sd, 72439c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 72539c5c447SWenyou Yang struct v4l2_subdev_frame_interval_enum *fie) 72639c5c447SWenyou Yang { 72739c5c447SWenyou Yang if (fie->pad) 72839c5c447SWenyou Yang return -EINVAL; 72939c5c447SWenyou Yang 73039c5c447SWenyou Yang if (fie->index >= 1) 73139c5c447SWenyou Yang return -EINVAL; 73239c5c447SWenyou Yang 73339c5c447SWenyou Yang if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT)) 73439c5c447SWenyou Yang return -EINVAL; 73539c5c447SWenyou Yang 73639c5c447SWenyou Yang fie->interval.numerator = 1; 73739c5c447SWenyou Yang fie->interval.denominator = 60; 73839c5c447SWenyou Yang 73939c5c447SWenyou Yang return 0; 74039c5c447SWenyou Yang } 74139c5c447SWenyou Yang 74239c5c447SWenyou Yang static int ov7740_enum_frame_size(struct v4l2_subdev *sd, 74339c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 74439c5c447SWenyou Yang struct v4l2_subdev_frame_size_enum *fse) 74539c5c447SWenyou Yang { 74639c5c447SWenyou Yang if (fse->pad) 74739c5c447SWenyou Yang return -EINVAL; 74839c5c447SWenyou Yang 74939c5c447SWenyou Yang if (fse->index > 0) 75039c5c447SWenyou Yang return -EINVAL; 75139c5c447SWenyou Yang 75239c5c447SWenyou Yang fse->min_width = fse->max_width = VGA_WIDTH; 75339c5c447SWenyou Yang fse->min_height = fse->max_height = VGA_HEIGHT; 75439c5c447SWenyou Yang 75539c5c447SWenyou Yang return 0; 75639c5c447SWenyou Yang } 75739c5c447SWenyou Yang 75839c5c447SWenyou Yang static int ov7740_try_fmt_internal(struct v4l2_subdev *sd, 75939c5c447SWenyou Yang struct v4l2_mbus_framefmt *fmt, 76039c5c447SWenyou Yang const struct ov7740_pixfmt **ret_fmt, 76139c5c447SWenyou Yang const struct ov7740_framesize **ret_frmsize) 76239c5c447SWenyou Yang { 76339c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 76439c5c447SWenyou Yang const struct ov7740_framesize *fsize = &ov7740_framesizes[0]; 76539c5c447SWenyou Yang int index, i; 76639c5c447SWenyou Yang 76739c5c447SWenyou Yang for (index = 0; index < N_OV7740_FMTS; index++) { 76839c5c447SWenyou Yang if (ov7740_formats[index].mbus_code == fmt->code) 76939c5c447SWenyou Yang break; 77039c5c447SWenyou Yang } 77139c5c447SWenyou Yang if (index >= N_OV7740_FMTS) { 77239c5c447SWenyou Yang /* default to first format */ 77339c5c447SWenyou Yang index = 0; 77439c5c447SWenyou Yang fmt->code = ov7740_formats[0].mbus_code; 77539c5c447SWenyou Yang } 77639c5c447SWenyou Yang if (ret_fmt != NULL) 77739c5c447SWenyou Yang *ret_fmt = ov7740_formats + index; 77839c5c447SWenyou Yang 77939c5c447SWenyou Yang for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) { 78039c5c447SWenyou Yang if ((fsize->width >= fmt->width) && 78139c5c447SWenyou Yang (fsize->height >= fmt->height)) { 78239c5c447SWenyou Yang fmt->width = fsize->width; 78339c5c447SWenyou Yang fmt->height = fsize->height; 78439c5c447SWenyou Yang break; 78539c5c447SWenyou Yang } 78639c5c447SWenyou Yang 78739c5c447SWenyou Yang fsize++; 78839c5c447SWenyou Yang } 7896e4ab830SAkinobu Mita if (i >= ARRAY_SIZE(ov7740_framesizes)) { 7906e4ab830SAkinobu Mita fsize = &ov7740_framesizes[0]; 7916e4ab830SAkinobu Mita fmt->width = fsize->width; 7926e4ab830SAkinobu Mita fmt->height = fsize->height; 7936e4ab830SAkinobu Mita } 79439c5c447SWenyou Yang if (ret_frmsize != NULL) 79539c5c447SWenyou Yang *ret_frmsize = fsize; 79639c5c447SWenyou Yang 79739c5c447SWenyou Yang fmt->field = V4L2_FIELD_NONE; 79839c5c447SWenyou Yang fmt->colorspace = ov7740_formats[index].colorspace; 79939c5c447SWenyou Yang 80039c5c447SWenyou Yang ov7740->format = *fmt; 80139c5c447SWenyou Yang 80239c5c447SWenyou Yang return 0; 80339c5c447SWenyou Yang } 80439c5c447SWenyou Yang 80539c5c447SWenyou Yang static int ov7740_set_fmt(struct v4l2_subdev *sd, 80639c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 80739c5c447SWenyou Yang struct v4l2_subdev_format *format) 80839c5c447SWenyou Yang { 80939c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 81039c5c447SWenyou Yang const struct ov7740_pixfmt *ovfmt; 81139c5c447SWenyou Yang const struct ov7740_framesize *fsize; 81239c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 81339c5c447SWenyou Yang struct v4l2_mbus_framefmt *mbus_fmt; 81439c5c447SWenyou Yang #endif 81539c5c447SWenyou Yang int ret; 81639c5c447SWenyou Yang 81739c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 81839c5c447SWenyou Yang if (format->pad) { 81939c5c447SWenyou Yang ret = -EINVAL; 82039c5c447SWenyou Yang goto error; 82139c5c447SWenyou Yang } 82239c5c447SWenyou Yang 82339c5c447SWenyou Yang if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 82439c5c447SWenyou Yang ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL); 82539c5c447SWenyou Yang if (ret) 82639c5c447SWenyou Yang goto error; 82739c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 82839c5c447SWenyou Yang mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); 82939c5c447SWenyou Yang *mbus_fmt = format->format; 83039c5c447SWenyou Yang 83139c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 83239c5c447SWenyou Yang return 0; 83339c5c447SWenyou Yang #else 83439c5c447SWenyou Yang ret = -ENOTTY; 83539c5c447SWenyou Yang goto error; 83639c5c447SWenyou Yang #endif 83739c5c447SWenyou Yang } 83839c5c447SWenyou Yang 83939c5c447SWenyou Yang ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize); 84039c5c447SWenyou Yang if (ret) 84139c5c447SWenyou Yang goto error; 84239c5c447SWenyou Yang 84339c5c447SWenyou Yang ov7740->fmt = ovfmt; 84439c5c447SWenyou Yang ov7740->frmsize = fsize; 84539c5c447SWenyou Yang 84639c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 84739c5c447SWenyou Yang return 0; 84839c5c447SWenyou Yang 84939c5c447SWenyou Yang error: 85039c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 85139c5c447SWenyou Yang return ret; 85239c5c447SWenyou Yang } 85339c5c447SWenyou Yang 85439c5c447SWenyou Yang static int ov7740_get_fmt(struct v4l2_subdev *sd, 85539c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 85639c5c447SWenyou Yang struct v4l2_subdev_format *format) 85739c5c447SWenyou Yang { 85839c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 85939c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 86039c5c447SWenyou Yang struct v4l2_mbus_framefmt *mbus_fmt; 86139c5c447SWenyou Yang #endif 86239c5c447SWenyou Yang int ret = 0; 86339c5c447SWenyou Yang 86439c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 86539c5c447SWenyou Yang if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 86639c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 86739c5c447SWenyou Yang mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); 86839c5c447SWenyou Yang format->format = *mbus_fmt; 86939c5c447SWenyou Yang ret = 0; 87039c5c447SWenyou Yang #else 87139c5c447SWenyou Yang ret = -ENOTTY; 87239c5c447SWenyou Yang #endif 87339c5c447SWenyou Yang } else { 87439c5c447SWenyou Yang format->format = ov7740->format; 87539c5c447SWenyou Yang } 87639c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 87739c5c447SWenyou Yang 87839c5c447SWenyou Yang return ret; 87939c5c447SWenyou Yang } 88039c5c447SWenyou Yang 88139c5c447SWenyou Yang static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { 88239c5c447SWenyou Yang .enum_frame_interval = ov7740_enum_frame_interval, 88339c5c447SWenyou Yang .enum_frame_size = ov7740_enum_frame_size, 88439c5c447SWenyou Yang .enum_mbus_code = ov7740_enum_mbus_code, 88539c5c447SWenyou Yang .get_fmt = ov7740_get_fmt, 88639c5c447SWenyou Yang .set_fmt = ov7740_set_fmt, 88739c5c447SWenyou Yang }; 88839c5c447SWenyou Yang 88939c5c447SWenyou Yang static const struct v4l2_subdev_ops ov7740_subdev_ops = { 89039c5c447SWenyou Yang .core = &ov7740_subdev_core_ops, 89139c5c447SWenyou Yang .video = &ov7740_subdev_video_ops, 89239c5c447SWenyou Yang .pad = &ov7740_subdev_pad_ops, 89339c5c447SWenyou Yang }; 89439c5c447SWenyou Yang 89539c5c447SWenyou Yang static void ov7740_get_default_format(struct v4l2_subdev *sd, 89639c5c447SWenyou Yang struct v4l2_mbus_framefmt *format) 89739c5c447SWenyou Yang { 89839c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 89939c5c447SWenyou Yang 90039c5c447SWenyou Yang format->width = ov7740->frmsize->width; 90139c5c447SWenyou Yang format->height = ov7740->frmsize->height; 90239c5c447SWenyou Yang format->colorspace = ov7740->fmt->colorspace; 90339c5c447SWenyou Yang format->code = ov7740->fmt->mbus_code; 90439c5c447SWenyou Yang format->field = V4L2_FIELD_NONE; 90539c5c447SWenyou Yang } 90639c5c447SWenyou Yang 90739c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 90839c5c447SWenyou Yang static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 90939c5c447SWenyou Yang { 91039c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 91139c5c447SWenyou Yang struct v4l2_mbus_framefmt *format = 91239c5c447SWenyou Yang v4l2_subdev_get_try_format(sd, fh->pad, 0); 91339c5c447SWenyou Yang 91439c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 91539c5c447SWenyou Yang ov7740_get_default_format(sd, format); 91639c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 91739c5c447SWenyou Yang 91839c5c447SWenyou Yang return 0; 91939c5c447SWenyou Yang } 92039c5c447SWenyou Yang 92139c5c447SWenyou Yang static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = { 92239c5c447SWenyou Yang .open = ov7740_open, 92339c5c447SWenyou Yang }; 92439c5c447SWenyou Yang #endif 92539c5c447SWenyou Yang 92639c5c447SWenyou Yang static int ov7740_probe_dt(struct i2c_client *client, 92739c5c447SWenyou Yang struct ov7740 *ov7740) 92839c5c447SWenyou Yang { 92939c5c447SWenyou Yang ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", 93039c5c447SWenyou Yang GPIOD_OUT_HIGH); 93139c5c447SWenyou Yang if (IS_ERR(ov7740->resetb_gpio)) { 93239c5c447SWenyou Yang dev_info(&client->dev, "can't get %s GPIO\n", "reset"); 93339c5c447SWenyou Yang return PTR_ERR(ov7740->resetb_gpio); 93439c5c447SWenyou Yang } 93539c5c447SWenyou Yang 93639c5c447SWenyou Yang ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 93739c5c447SWenyou Yang GPIOD_OUT_LOW); 93839c5c447SWenyou Yang if (IS_ERR(ov7740->pwdn_gpio)) { 93939c5c447SWenyou Yang dev_info(&client->dev, "can't get %s GPIO\n", "powerdown"); 94039c5c447SWenyou Yang return PTR_ERR(ov7740->pwdn_gpio); 94139c5c447SWenyou Yang } 94239c5c447SWenyou Yang 94339c5c447SWenyou Yang return 0; 94439c5c447SWenyou Yang } 94539c5c447SWenyou Yang 94639c5c447SWenyou Yang static int ov7740_detect(struct ov7740 *ov7740) 94739c5c447SWenyou Yang { 94839c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 94939c5c447SWenyou Yang unsigned int midh, midl, pidh, pidl; 95039c5c447SWenyou Yang int ret; 95139c5c447SWenyou Yang 95239c5c447SWenyou Yang ret = regmap_read(regmap, REG_MIDH, &midh); 95339c5c447SWenyou Yang if (ret) 95439c5c447SWenyou Yang return ret; 95539c5c447SWenyou Yang if (midh != 0x7f) 95639c5c447SWenyou Yang return -ENODEV; 95739c5c447SWenyou Yang 95839c5c447SWenyou Yang ret = regmap_read(regmap, REG_MIDL, &midl); 95939c5c447SWenyou Yang if (ret) 96039c5c447SWenyou Yang return ret; 96139c5c447SWenyou Yang if (midl != 0xa2) 96239c5c447SWenyou Yang return -ENODEV; 96339c5c447SWenyou Yang 96439c5c447SWenyou Yang ret = regmap_read(regmap, REG_PIDH, &pidh); 96539c5c447SWenyou Yang if (ret) 96639c5c447SWenyou Yang return ret; 96739c5c447SWenyou Yang if (pidh != 0x77) 96839c5c447SWenyou Yang return -ENODEV; 96939c5c447SWenyou Yang 97039c5c447SWenyou Yang ret = regmap_read(regmap, REG_PIDL, &pidl); 97139c5c447SWenyou Yang if (ret) 97239c5c447SWenyou Yang return ret; 97339c5c447SWenyou Yang if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42)) 97439c5c447SWenyou Yang return -ENODEV; 97539c5c447SWenyou Yang 97639c5c447SWenyou Yang return 0; 97739c5c447SWenyou Yang } 97839c5c447SWenyou Yang 97939c5c447SWenyou Yang static int ov7740_init_controls(struct ov7740 *ov7740) 98039c5c447SWenyou Yang { 98139c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); 98239c5c447SWenyou Yang struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler; 98339c5c447SWenyou Yang int ret; 98439c5c447SWenyou Yang 98531b9cb6eSSakari Ailus ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); 98639c5c447SWenyou Yang if (ret < 0) 98739c5c447SWenyou Yang return ret; 98839c5c447SWenyou Yang 98939c5c447SWenyou Yang ctrl_hdlr->lock = &ov7740->mutex; 99039c5c447SWenyou Yang ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 99139c5c447SWenyou Yang V4L2_CID_AUTO_WHITE_BALANCE, 99239c5c447SWenyou Yang 0, 1, 1, 1); 99339c5c447SWenyou Yang ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 99439c5c447SWenyou Yang V4L2_CID_BLUE_BALANCE, 99539c5c447SWenyou Yang 0, 0xff, 1, 0x80); 99639c5c447SWenyou Yang ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 99739c5c447SWenyou Yang V4L2_CID_RED_BALANCE, 99839c5c447SWenyou Yang 0, 0xff, 1, 0x80); 99939c5c447SWenyou Yang 100039c5c447SWenyou Yang ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 100139c5c447SWenyou Yang V4L2_CID_BRIGHTNESS, 100239c5c447SWenyou Yang -255, 255, 1, 0); 100339c5c447SWenyou Yang ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 100439c5c447SWenyou Yang V4L2_CID_CONTRAST, 100539c5c447SWenyou Yang 0, 127, 1, 0x20); 100639c5c447SWenyou Yang ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 100739c5c447SWenyou Yang V4L2_CID_SATURATION, 0, 256, 1, 0x80); 100839c5c447SWenyou Yang ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 100939c5c447SWenyou Yang V4L2_CID_HFLIP, 0, 1, 1, 0); 101039c5c447SWenyou Yang ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 101139c5c447SWenyou Yang V4L2_CID_VFLIP, 0, 1, 1, 0); 1012bad04a55SSakari Ailus 101339c5c447SWenyou Yang ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 101439c5c447SWenyou Yang V4L2_CID_GAIN, 0, 1023, 1, 500); 1015bad04a55SSakari Ailus if (ov7740->gain) 1016bad04a55SSakari Ailus ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 1017bad04a55SSakari Ailus 101839c5c447SWenyou Yang ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 101939c5c447SWenyou Yang V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 1020bad04a55SSakari Ailus 102139c5c447SWenyou Yang ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 102239c5c447SWenyou Yang V4L2_CID_EXPOSURE, 0, 65535, 1, 500); 1023bad04a55SSakari Ailus 102439c5c447SWenyou Yang ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr, 102539c5c447SWenyou Yang &ov7740_ctrl_ops, 102639c5c447SWenyou Yang V4L2_CID_EXPOSURE_AUTO, 102739c5c447SWenyou Yang V4L2_EXPOSURE_MANUAL, 0, 102839c5c447SWenyou Yang V4L2_EXPOSURE_AUTO); 102939c5c447SWenyou Yang 103039c5c447SWenyou Yang v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false); 103139c5c447SWenyou Yang v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); 103239c5c447SWenyou Yang v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, 1033c4b50cabSAkinobu Mita V4L2_EXPOSURE_MANUAL, true); 103439c5c447SWenyou Yang 103580a1f95bSSakari Ailus if (ctrl_hdlr->error) { 103680a1f95bSSakari Ailus ret = ctrl_hdlr->error; 103780a1f95bSSakari Ailus dev_err(&client->dev, "controls initialisation failed (%d)\n", 103880a1f95bSSakari Ailus ret); 103980a1f95bSSakari Ailus goto error; 104080a1f95bSSakari Ailus } 104180a1f95bSSakari Ailus 104239c5c447SWenyou Yang ret = v4l2_ctrl_handler_setup(ctrl_hdlr); 104339c5c447SWenyou Yang if (ret) { 104439c5c447SWenyou Yang dev_err(&client->dev, "%s control init failed (%d)\n", 104539c5c447SWenyou Yang __func__, ret); 104639c5c447SWenyou Yang goto error; 104739c5c447SWenyou Yang } 104839c5c447SWenyou Yang 104939c5c447SWenyou Yang ov7740->subdev.ctrl_handler = ctrl_hdlr; 105039c5c447SWenyou Yang return 0; 105139c5c447SWenyou Yang 105239c5c447SWenyou Yang error: 105339c5c447SWenyou Yang v4l2_ctrl_handler_free(ctrl_hdlr); 105439c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 105539c5c447SWenyou Yang return ret; 105639c5c447SWenyou Yang } 105739c5c447SWenyou Yang 105839c5c447SWenyou Yang static void ov7740_free_controls(struct ov7740 *ov7740) 105939c5c447SWenyou Yang { 106039c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 106139c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 106239c5c447SWenyou Yang } 106339c5c447SWenyou Yang 106439c5c447SWenyou Yang #define OV7740_MAX_REGISTER 0xff 106539c5c447SWenyou Yang static const struct regmap_config ov7740_regmap_config = { 106639c5c447SWenyou Yang .reg_bits = 8, 106739c5c447SWenyou Yang .val_bits = 8, 106839c5c447SWenyou Yang .max_register = OV7740_MAX_REGISTER, 106939c5c447SWenyou Yang }; 107039c5c447SWenyou Yang 107139c5c447SWenyou Yang static int ov7740_probe(struct i2c_client *client, 107239c5c447SWenyou Yang const struct i2c_device_id *id) 107339c5c447SWenyou Yang { 107439c5c447SWenyou Yang struct ov7740 *ov7740; 107539c5c447SWenyou Yang struct v4l2_subdev *sd; 107639c5c447SWenyou Yang int ret; 107739c5c447SWenyou Yang 107839c5c447SWenyou Yang if (!i2c_check_functionality(client->adapter, 107939c5c447SWenyou Yang I2C_FUNC_SMBUS_BYTE_DATA)) { 108039c5c447SWenyou Yang dev_err(&client->dev, 108139c5c447SWenyou Yang "OV7740: I2C-Adapter doesn't support SMBUS\n"); 108239c5c447SWenyou Yang return -EIO; 108339c5c447SWenyou Yang } 108439c5c447SWenyou Yang 108539c5c447SWenyou Yang ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL); 108639c5c447SWenyou Yang if (!ov7740) 108739c5c447SWenyou Yang return -ENOMEM; 108839c5c447SWenyou Yang 108939c5c447SWenyou Yang ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); 109039c5c447SWenyou Yang if (IS_ERR(ov7740->xvclk)) { 109139c5c447SWenyou Yang ret = PTR_ERR(ov7740->xvclk); 109239c5c447SWenyou Yang dev_err(&client->dev, 109339c5c447SWenyou Yang "OV7740: fail to get xvclk: %d\n", ret); 109439c5c447SWenyou Yang return ret; 109539c5c447SWenyou Yang } 109639c5c447SWenyou Yang 109739c5c447SWenyou Yang ret = ov7740_probe_dt(client, ov7740); 109839c5c447SWenyou Yang if (ret) 109939c5c447SWenyou Yang return ret; 110039c5c447SWenyou Yang 110139c5c447SWenyou Yang ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config); 110239c5c447SWenyou Yang if (IS_ERR(ov7740->regmap)) { 110339c5c447SWenyou Yang ret = PTR_ERR(ov7740->regmap); 110439c5c447SWenyou Yang dev_err(&client->dev, "Failed to allocate register map: %d\n", 110539c5c447SWenyou Yang ret); 110639c5c447SWenyou Yang return ret; 110739c5c447SWenyou Yang } 110839c5c447SWenyou Yang 110939c5c447SWenyou Yang sd = &ov7740->subdev; 111039c5c447SWenyou Yang client->flags |= I2C_CLIENT_SCCB; 111139c5c447SWenyou Yang v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops); 111239c5c447SWenyou Yang 111339c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 111439c5c447SWenyou Yang sd->internal_ops = &ov7740_subdev_internal_ops; 111565b0ae5eSSakari Ailus sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 111639c5c447SWenyou Yang #endif 111739c5c447SWenyou Yang 111839c5c447SWenyou Yang #if defined(CONFIG_MEDIA_CONTROLLER) 111939c5c447SWenyou Yang ov7740->pad.flags = MEDIA_PAD_FL_SOURCE; 112039c5c447SWenyou Yang sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; 112139c5c447SWenyou Yang ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad); 112239c5c447SWenyou Yang if (ret) 112339c5c447SWenyou Yang return ret; 112439c5c447SWenyou Yang #endif 112539c5c447SWenyou Yang 112639c5c447SWenyou Yang ret = ov7740_set_power(ov7740, 1); 112739c5c447SWenyou Yang if (ret) 112839c5c447SWenyou Yang return ret; 112939c5c447SWenyou Yang 113012aceee1SAkinobu Mita pm_runtime_set_active(&client->dev); 113112aceee1SAkinobu Mita pm_runtime_enable(&client->dev); 113212aceee1SAkinobu Mita 113339c5c447SWenyou Yang ret = ov7740_detect(ov7740); 113439c5c447SWenyou Yang if (ret) 113539c5c447SWenyou Yang goto error_detect; 113639c5c447SWenyou Yang 113739c5c447SWenyou Yang mutex_init(&ov7740->mutex); 113839c5c447SWenyou Yang 113939c5c447SWenyou Yang ret = ov7740_init_controls(ov7740); 114039c5c447SWenyou Yang if (ret) 114139c5c447SWenyou Yang goto error_init_controls; 114239c5c447SWenyou Yang 114339c5c447SWenyou Yang v4l_info(client, "chip found @ 0x%02x (%s)\n", 114439c5c447SWenyou Yang client->addr << 1, client->adapter->name); 114539c5c447SWenyou Yang 114639c5c447SWenyou Yang ov7740->fmt = &ov7740_formats[0]; 114739c5c447SWenyou Yang ov7740->frmsize = &ov7740_framesizes[0]; 114839c5c447SWenyou Yang 114939c5c447SWenyou Yang ov7740_get_default_format(sd, &ov7740->format); 115039c5c447SWenyou Yang 115139c5c447SWenyou Yang ret = v4l2_async_register_subdev(sd); 115239c5c447SWenyou Yang if (ret) 115339c5c447SWenyou Yang goto error_async_register; 115439c5c447SWenyou Yang 115539c5c447SWenyou Yang pm_runtime_idle(&client->dev); 115639c5c447SWenyou Yang 115739c5c447SWenyou Yang return 0; 115839c5c447SWenyou Yang 115939c5c447SWenyou Yang error_async_register: 116039c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 116139c5c447SWenyou Yang error_init_controls: 116239c5c447SWenyou Yang ov7740_free_controls(ov7740); 116339c5c447SWenyou Yang error_detect: 116412aceee1SAkinobu Mita pm_runtime_disable(&client->dev); 116512aceee1SAkinobu Mita pm_runtime_set_suspended(&client->dev); 116639c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 116739c5c447SWenyou Yang media_entity_cleanup(&ov7740->subdev.entity); 116839c5c447SWenyou Yang 116939c5c447SWenyou Yang return ret; 117039c5c447SWenyou Yang } 117139c5c447SWenyou Yang 117239c5c447SWenyou Yang static int ov7740_remove(struct i2c_client *client) 117339c5c447SWenyou Yang { 117439c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 117539c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 117639c5c447SWenyou Yang 117739c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 117839c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 117939c5c447SWenyou Yang media_entity_cleanup(&ov7740->subdev.entity); 118039c5c447SWenyou Yang v4l2_async_unregister_subdev(sd); 118139c5c447SWenyou Yang ov7740_free_controls(ov7740); 118239c5c447SWenyou Yang 118339c5c447SWenyou Yang pm_runtime_get_sync(&client->dev); 118439c5c447SWenyou Yang pm_runtime_disable(&client->dev); 118539c5c447SWenyou Yang pm_runtime_set_suspended(&client->dev); 118639c5c447SWenyou Yang pm_runtime_put_noidle(&client->dev); 118739c5c447SWenyou Yang 118839c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 118939c5c447SWenyou Yang return 0; 119039c5c447SWenyou Yang } 119139c5c447SWenyou Yang 119239c5c447SWenyou Yang static int __maybe_unused ov7740_runtime_suspend(struct device *dev) 119339c5c447SWenyou Yang { 119439c5c447SWenyou Yang struct i2c_client *client = to_i2c_client(dev); 119539c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 119639c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 119739c5c447SWenyou Yang 119839c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 119939c5c447SWenyou Yang 120039c5c447SWenyou Yang return 0; 120139c5c447SWenyou Yang } 120239c5c447SWenyou Yang 120339c5c447SWenyou Yang static int __maybe_unused ov7740_runtime_resume(struct device *dev) 120439c5c447SWenyou Yang { 120539c5c447SWenyou Yang struct i2c_client *client = to_i2c_client(dev); 120639c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 120739c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 120839c5c447SWenyou Yang 120939c5c447SWenyou Yang return ov7740_set_power(ov7740, 1); 121039c5c447SWenyou Yang } 121139c5c447SWenyou Yang 121239c5c447SWenyou Yang static const struct i2c_device_id ov7740_id[] = { 121339c5c447SWenyou Yang { "ov7740", 0 }, 121439c5c447SWenyou Yang { /* sentinel */ } 121539c5c447SWenyou Yang }; 121639c5c447SWenyou Yang MODULE_DEVICE_TABLE(i2c, ov7740_id); 121739c5c447SWenyou Yang 121839c5c447SWenyou Yang static const struct dev_pm_ops ov7740_pm_ops = { 121939c5c447SWenyou Yang SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL) 122039c5c447SWenyou Yang }; 122139c5c447SWenyou Yang 122239c5c447SWenyou Yang static const struct of_device_id ov7740_of_match[] = { 122339c5c447SWenyou Yang {.compatible = "ovti,ov7740", }, 122439c5c447SWenyou Yang { /* sentinel */ }, 122539c5c447SWenyou Yang }; 122639c5c447SWenyou Yang MODULE_DEVICE_TABLE(of, ov7740_of_match); 122739c5c447SWenyou Yang 122839c5c447SWenyou Yang static struct i2c_driver ov7740_i2c_driver = { 122939c5c447SWenyou Yang .driver = { 123039c5c447SWenyou Yang .name = "ov7740", 123139c5c447SWenyou Yang .pm = &ov7740_pm_ops, 123239c5c447SWenyou Yang .of_match_table = of_match_ptr(ov7740_of_match), 123339c5c447SWenyou Yang }, 123439c5c447SWenyou Yang .probe = ov7740_probe, 123539c5c447SWenyou Yang .remove = ov7740_remove, 123639c5c447SWenyou Yang .id_table = ov7740_id, 123739c5c447SWenyou Yang }; 123839c5c447SWenyou Yang module_i2c_driver(ov7740_i2c_driver); 123939c5c447SWenyou Yang 124039c5c447SWenyou Yang MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor"); 124139c5c447SWenyou Yang MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>"); 124239c5c447SWenyou Yang MODULE_LICENSE("GPL v2"); 1243