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 */ 2339c5c447SWenyou Yang #define REG_REG04 0x04 /* analog setting, dont 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 32539c5c447SWenyou Yang static 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 45139c5c447SWenyou Yang static int ov7740_set_exp(struct regmap *regmap, int value) 45239c5c447SWenyou Yang { 45339c5c447SWenyou Yang int ret; 45439c5c447SWenyou Yang 45539c5c447SWenyou Yang /* Turn off AEC/AGC */ 45639c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG13, 45739c5c447SWenyou Yang REG13_AEC_EN | REG13_AGC_EN, 0); 45839c5c447SWenyou Yang if (ret) 45939c5c447SWenyou Yang return ret; 46039c5c447SWenyou Yang 46139c5c447SWenyou Yang ret = regmap_write(regmap, REG_AEC, (unsigned char)value); 46239c5c447SWenyou Yang if (ret) 46339c5c447SWenyou Yang return ret; 46439c5c447SWenyou Yang 46539c5c447SWenyou Yang return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8)); 46639c5c447SWenyou Yang } 46739c5c447SWenyou Yang 46839c5c447SWenyou Yang static int ov7740_set_autoexp(struct regmap *regmap, 46939c5c447SWenyou Yang enum v4l2_exposure_auto_type value) 47039c5c447SWenyou Yang { 47139c5c447SWenyou Yang unsigned int reg; 47239c5c447SWenyou Yang int ret; 47339c5c447SWenyou Yang 47439c5c447SWenyou Yang ret = regmap_read(regmap, REG_REG13, ®); 47539c5c447SWenyou Yang if (!ret) { 47639c5c447SWenyou Yang if (value == V4L2_EXPOSURE_AUTO) 47739c5c447SWenyou Yang reg |= (REG13_AEC_EN | REG13_AGC_EN); 47839c5c447SWenyou Yang else 47939c5c447SWenyou Yang reg &= ~(REG13_AEC_EN | REG13_AGC_EN); 48039c5c447SWenyou Yang ret = regmap_write(regmap, REG_REG13, reg); 48139c5c447SWenyou Yang } 48239c5c447SWenyou Yang 48339c5c447SWenyou Yang return ret; 48439c5c447SWenyou Yang } 48539c5c447SWenyou Yang 48639c5c447SWenyou Yang 48739c5c447SWenyou Yang static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl) 48839c5c447SWenyou Yang { 48939c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(ctrl->handler, 49039c5c447SWenyou Yang struct ov7740, ctrl_handler); 49139c5c447SWenyou Yang int ret; 49239c5c447SWenyou Yang 49339c5c447SWenyou Yang switch (ctrl->id) { 49439c5c447SWenyou Yang case V4L2_CID_AUTOGAIN: 49539c5c447SWenyou Yang ret = ov7740_get_gain(ov7740, ctrl); 49639c5c447SWenyou Yang break; 49739c5c447SWenyou Yang default: 49839c5c447SWenyou Yang ret = -EINVAL; 49939c5c447SWenyou Yang break; 50039c5c447SWenyou Yang } 50139c5c447SWenyou Yang return ret; 50239c5c447SWenyou Yang } 50339c5c447SWenyou Yang 50439c5c447SWenyou Yang static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) 50539c5c447SWenyou Yang { 50639c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(ctrl->handler, 50739c5c447SWenyou Yang struct ov7740, ctrl_handler); 50839c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); 50939c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 51039c5c447SWenyou Yang int ret; 51139c5c447SWenyou Yang u8 val = 0; 51239c5c447SWenyou Yang 51339c5c447SWenyou Yang if (pm_runtime_get_if_in_use(&client->dev) <= 0) 51439c5c447SWenyou Yang return 0; 51539c5c447SWenyou Yang 51639c5c447SWenyou Yang switch (ctrl->id) { 51739c5c447SWenyou Yang case V4L2_CID_AUTO_WHITE_BALANCE: 51839c5c447SWenyou Yang ret = ov7740_set_white_balance(ov7740, ctrl->val); 51939c5c447SWenyou Yang break; 52039c5c447SWenyou Yang case V4L2_CID_SATURATION: 52139c5c447SWenyou Yang ret = ov7740_set_saturation(regmap, ctrl->val); 52239c5c447SWenyou Yang break; 52339c5c447SWenyou Yang case V4L2_CID_BRIGHTNESS: 52439c5c447SWenyou Yang ret = ov7740_set_brightness(regmap, ctrl->val); 52539c5c447SWenyou Yang break; 52639c5c447SWenyou Yang case V4L2_CID_CONTRAST: 52739c5c447SWenyou Yang ret = ov7740_set_contrast(regmap, ctrl->val); 52839c5c447SWenyou Yang break; 52939c5c447SWenyou Yang case V4L2_CID_VFLIP: 53039c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG0C, 53139c5c447SWenyou Yang REG0C_IMG_FLIP, val); 53239c5c447SWenyou Yang break; 53339c5c447SWenyou Yang case V4L2_CID_HFLIP: 53439c5c447SWenyou Yang val = ctrl->val ? REG0C_IMG_MIRROR : 0x00; 53539c5c447SWenyou Yang ret = regmap_update_bits(regmap, REG_REG0C, 53639c5c447SWenyou Yang REG0C_IMG_MIRROR, val); 53739c5c447SWenyou Yang break; 53839c5c447SWenyou Yang case V4L2_CID_AUTOGAIN: 53939c5c447SWenyou Yang if (!ctrl->val) 54039c5c447SWenyou Yang return ov7740_set_gain(regmap, ov7740->gain->val); 54139c5c447SWenyou Yang 54239c5c447SWenyou Yang ret = ov7740_set_autogain(regmap, ctrl->val); 54339c5c447SWenyou Yang break; 54439c5c447SWenyou Yang 54539c5c447SWenyou Yang case V4L2_CID_EXPOSURE_AUTO: 54639c5c447SWenyou Yang if (ctrl->val == V4L2_EXPOSURE_MANUAL) 54739c5c447SWenyou Yang return ov7740_set_exp(regmap, ov7740->exposure->val); 54839c5c447SWenyou Yang 54939c5c447SWenyou Yang ret = ov7740_set_autoexp(regmap, ctrl->val); 55039c5c447SWenyou Yang break; 55139c5c447SWenyou Yang default: 55239c5c447SWenyou Yang ret = -EINVAL; 55339c5c447SWenyou Yang break; 55439c5c447SWenyou Yang } 55539c5c447SWenyou Yang 55639c5c447SWenyou Yang pm_runtime_put(&client->dev); 55739c5c447SWenyou Yang 55839c5c447SWenyou Yang return ret; 55939c5c447SWenyou Yang } 56039c5c447SWenyou Yang 56139c5c447SWenyou Yang static const struct v4l2_ctrl_ops ov7740_ctrl_ops = { 56239c5c447SWenyou Yang .g_volatile_ctrl = ov7740_get_volatile_ctrl, 56339c5c447SWenyou Yang .s_ctrl = ov7740_set_ctrl, 56439c5c447SWenyou Yang }; 56539c5c447SWenyou Yang 56639c5c447SWenyou Yang static int ov7740_start_streaming(struct ov7740 *ov7740) 56739c5c447SWenyou Yang { 56839c5c447SWenyou Yang int ret; 56939c5c447SWenyou Yang 57039c5c447SWenyou Yang if (ov7740->fmt) { 57139c5c447SWenyou Yang ret = regmap_multi_reg_write(ov7740->regmap, 57239c5c447SWenyou Yang ov7740->fmt->regs, 57339c5c447SWenyou Yang ov7740->fmt->reg_num); 57439c5c447SWenyou Yang if (ret) 57539c5c447SWenyou Yang return ret; 57639c5c447SWenyou Yang } 57739c5c447SWenyou Yang 57839c5c447SWenyou Yang if (ov7740->frmsize) { 57939c5c447SWenyou Yang ret = regmap_multi_reg_write(ov7740->regmap, 58039c5c447SWenyou Yang ov7740->frmsize->regs, 58139c5c447SWenyou Yang ov7740->frmsize->reg_num); 58239c5c447SWenyou Yang if (ret) 58339c5c447SWenyou Yang return ret; 58439c5c447SWenyou Yang } 58539c5c447SWenyou Yang 58639c5c447SWenyou Yang return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler); 58739c5c447SWenyou Yang } 58839c5c447SWenyou Yang 58939c5c447SWenyou Yang static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) 59039c5c447SWenyou Yang { 59139c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 59239c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(sd); 59339c5c447SWenyou Yang int ret = 0; 59439c5c447SWenyou Yang 59539c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 59639c5c447SWenyou Yang if (ov7740->streaming == enable) { 59739c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 59839c5c447SWenyou Yang return 0; 59939c5c447SWenyou Yang } 60039c5c447SWenyou Yang 60139c5c447SWenyou Yang if (enable) { 60239c5c447SWenyou Yang ret = pm_runtime_get_sync(&client->dev); 60339c5c447SWenyou Yang if (ret < 0) { 60439c5c447SWenyou Yang pm_runtime_put_noidle(&client->dev); 60539c5c447SWenyou Yang goto err_unlock; 60639c5c447SWenyou Yang } 60739c5c447SWenyou Yang 60839c5c447SWenyou Yang ret = ov7740_start_streaming(ov7740); 60939c5c447SWenyou Yang if (ret) 61039c5c447SWenyou Yang goto err_rpm_put; 61139c5c447SWenyou Yang } else { 61239c5c447SWenyou Yang pm_runtime_put(&client->dev); 61339c5c447SWenyou Yang } 61439c5c447SWenyou Yang 61539c5c447SWenyou Yang ov7740->streaming = enable; 61639c5c447SWenyou Yang 61739c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 61839c5c447SWenyou Yang return ret; 61939c5c447SWenyou Yang 62039c5c447SWenyou Yang err_rpm_put: 62139c5c447SWenyou Yang pm_runtime_put(&client->dev); 62239c5c447SWenyou Yang err_unlock: 62339c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 62439c5c447SWenyou Yang return ret; 62539c5c447SWenyou Yang } 62639c5c447SWenyou Yang 6274471109eSHans Verkuil static int ov7740_g_frame_interval(struct v4l2_subdev *sd, 6284471109eSHans Verkuil struct v4l2_subdev_frame_interval *ival) 62939c5c447SWenyou Yang { 6304471109eSHans Verkuil struct v4l2_fract *tpf = &ival->interval; 63139c5c447SWenyou Yang 63239c5c447SWenyou Yang 63339c5c447SWenyou Yang tpf->numerator = 1; 63439c5c447SWenyou Yang tpf->denominator = 60; 63539c5c447SWenyou Yang 63639c5c447SWenyou Yang return 0; 63739c5c447SWenyou Yang } 63839c5c447SWenyou Yang 6394471109eSHans Verkuil static int ov7740_s_frame_interval(struct v4l2_subdev *sd, 6404471109eSHans Verkuil struct v4l2_subdev_frame_interval *ival) 64139c5c447SWenyou Yang { 6424471109eSHans Verkuil struct v4l2_fract *tpf = &ival->interval; 64339c5c447SWenyou Yang 64439c5c447SWenyou Yang 64539c5c447SWenyou Yang tpf->numerator = 1; 64639c5c447SWenyou Yang tpf->denominator = 60; 64739c5c447SWenyou Yang 64839c5c447SWenyou Yang return 0; 64939c5c447SWenyou Yang } 65039c5c447SWenyou Yang 65139c5c447SWenyou Yang static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { 65239c5c447SWenyou Yang .s_stream = ov7740_set_stream, 6534471109eSHans Verkuil .s_frame_interval = ov7740_s_frame_interval, 6544471109eSHans Verkuil .g_frame_interval = ov7740_g_frame_interval, 65539c5c447SWenyou Yang }; 65639c5c447SWenyou Yang 65739c5c447SWenyou Yang static const struct reg_sequence ov7740_format_yuyv[] = { 65839c5c447SWenyou Yang {0x12, 0x00}, 65939c5c447SWenyou Yang {0x36, 0x3f}, 66039c5c447SWenyou Yang {0x80, 0x7f}, 66139c5c447SWenyou Yang {0x83, 0x01}, 66239c5c447SWenyou Yang }; 66339c5c447SWenyou Yang 66439c5c447SWenyou Yang static const struct reg_sequence ov7740_format_bggr8[] = { 66539c5c447SWenyou Yang {0x36, 0x2f}, 66639c5c447SWenyou Yang {0x80, 0x01}, 66739c5c447SWenyou Yang {0x83, 0x04}, 66839c5c447SWenyou Yang }; 66939c5c447SWenyou Yang 67039c5c447SWenyou Yang static const struct ov7740_pixfmt ov7740_formats[] = { 67139c5c447SWenyou Yang { 67239c5c447SWenyou Yang .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, 67339c5c447SWenyou Yang .colorspace = V4L2_COLORSPACE_SRGB, 67439c5c447SWenyou Yang .regs = ov7740_format_yuyv, 67539c5c447SWenyou Yang .reg_num = ARRAY_SIZE(ov7740_format_yuyv), 67639c5c447SWenyou Yang }, 67739c5c447SWenyou Yang { 67839c5c447SWenyou Yang .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, 67939c5c447SWenyou Yang .colorspace = V4L2_COLORSPACE_SRGB, 68039c5c447SWenyou Yang .regs = ov7740_format_bggr8, 68139c5c447SWenyou Yang .reg_num = ARRAY_SIZE(ov7740_format_bggr8), 68239c5c447SWenyou Yang } 68339c5c447SWenyou Yang }; 68439c5c447SWenyou Yang #define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats) 68539c5c447SWenyou Yang 68639c5c447SWenyou Yang static int ov7740_enum_mbus_code(struct v4l2_subdev *sd, 68739c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 68839c5c447SWenyou Yang struct v4l2_subdev_mbus_code_enum *code) 68939c5c447SWenyou Yang { 69039c5c447SWenyou Yang if (code->pad || code->index >= N_OV7740_FMTS) 69139c5c447SWenyou Yang return -EINVAL; 69239c5c447SWenyou Yang 69339c5c447SWenyou Yang code->code = ov7740_formats[code->index].mbus_code; 69439c5c447SWenyou Yang 69539c5c447SWenyou Yang return 0; 69639c5c447SWenyou Yang } 69739c5c447SWenyou Yang 69839c5c447SWenyou Yang static int ov7740_enum_frame_interval(struct v4l2_subdev *sd, 69939c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 70039c5c447SWenyou Yang struct v4l2_subdev_frame_interval_enum *fie) 70139c5c447SWenyou Yang { 70239c5c447SWenyou Yang if (fie->pad) 70339c5c447SWenyou Yang return -EINVAL; 70439c5c447SWenyou Yang 70539c5c447SWenyou Yang if (fie->index >= 1) 70639c5c447SWenyou Yang return -EINVAL; 70739c5c447SWenyou Yang 70839c5c447SWenyou Yang if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT)) 70939c5c447SWenyou Yang return -EINVAL; 71039c5c447SWenyou Yang 71139c5c447SWenyou Yang fie->interval.numerator = 1; 71239c5c447SWenyou Yang fie->interval.denominator = 60; 71339c5c447SWenyou Yang 71439c5c447SWenyou Yang return 0; 71539c5c447SWenyou Yang } 71639c5c447SWenyou Yang 71739c5c447SWenyou Yang static int ov7740_enum_frame_size(struct v4l2_subdev *sd, 71839c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 71939c5c447SWenyou Yang struct v4l2_subdev_frame_size_enum *fse) 72039c5c447SWenyou Yang { 72139c5c447SWenyou Yang if (fse->pad) 72239c5c447SWenyou Yang return -EINVAL; 72339c5c447SWenyou Yang 72439c5c447SWenyou Yang if (fse->index > 0) 72539c5c447SWenyou Yang return -EINVAL; 72639c5c447SWenyou Yang 72739c5c447SWenyou Yang fse->min_width = fse->max_width = VGA_WIDTH; 72839c5c447SWenyou Yang fse->min_height = fse->max_height = VGA_HEIGHT; 72939c5c447SWenyou Yang 73039c5c447SWenyou Yang return 0; 73139c5c447SWenyou Yang } 73239c5c447SWenyou Yang 73339c5c447SWenyou Yang static int ov7740_try_fmt_internal(struct v4l2_subdev *sd, 73439c5c447SWenyou Yang struct v4l2_mbus_framefmt *fmt, 73539c5c447SWenyou Yang const struct ov7740_pixfmt **ret_fmt, 73639c5c447SWenyou Yang const struct ov7740_framesize **ret_frmsize) 73739c5c447SWenyou Yang { 73839c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 73939c5c447SWenyou Yang const struct ov7740_framesize *fsize = &ov7740_framesizes[0]; 74039c5c447SWenyou Yang int index, i; 74139c5c447SWenyou Yang 74239c5c447SWenyou Yang for (index = 0; index < N_OV7740_FMTS; index++) { 74339c5c447SWenyou Yang if (ov7740_formats[index].mbus_code == fmt->code) 74439c5c447SWenyou Yang break; 74539c5c447SWenyou Yang } 74639c5c447SWenyou Yang if (index >= N_OV7740_FMTS) { 74739c5c447SWenyou Yang /* default to first format */ 74839c5c447SWenyou Yang index = 0; 74939c5c447SWenyou Yang fmt->code = ov7740_formats[0].mbus_code; 75039c5c447SWenyou Yang } 75139c5c447SWenyou Yang if (ret_fmt != NULL) 75239c5c447SWenyou Yang *ret_fmt = ov7740_formats + index; 75339c5c447SWenyou Yang 75439c5c447SWenyou Yang for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) { 75539c5c447SWenyou Yang if ((fsize->width >= fmt->width) && 75639c5c447SWenyou Yang (fsize->height >= fmt->height)) { 75739c5c447SWenyou Yang fmt->width = fsize->width; 75839c5c447SWenyou Yang fmt->height = fsize->height; 75939c5c447SWenyou Yang break; 76039c5c447SWenyou Yang } 76139c5c447SWenyou Yang 76239c5c447SWenyou Yang fsize++; 76339c5c447SWenyou Yang } 76439c5c447SWenyou Yang 76539c5c447SWenyou Yang if (ret_frmsize != NULL) 76639c5c447SWenyou Yang *ret_frmsize = fsize; 76739c5c447SWenyou Yang 76839c5c447SWenyou Yang fmt->field = V4L2_FIELD_NONE; 76939c5c447SWenyou Yang fmt->colorspace = ov7740_formats[index].colorspace; 77039c5c447SWenyou Yang 77139c5c447SWenyou Yang ov7740->format = *fmt; 77239c5c447SWenyou Yang 77339c5c447SWenyou Yang return 0; 77439c5c447SWenyou Yang } 77539c5c447SWenyou Yang 77639c5c447SWenyou Yang static int ov7740_set_fmt(struct v4l2_subdev *sd, 77739c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 77839c5c447SWenyou Yang struct v4l2_subdev_format *format) 77939c5c447SWenyou Yang { 78039c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 78139c5c447SWenyou Yang const struct ov7740_pixfmt *ovfmt; 78239c5c447SWenyou Yang const struct ov7740_framesize *fsize; 78339c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 78439c5c447SWenyou Yang struct v4l2_mbus_framefmt *mbus_fmt; 78539c5c447SWenyou Yang #endif 78639c5c447SWenyou Yang int ret; 78739c5c447SWenyou Yang 78839c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 78939c5c447SWenyou Yang if (format->pad) { 79039c5c447SWenyou Yang ret = -EINVAL; 79139c5c447SWenyou Yang goto error; 79239c5c447SWenyou Yang } 79339c5c447SWenyou Yang 79439c5c447SWenyou Yang if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 79539c5c447SWenyou Yang ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL); 79639c5c447SWenyou Yang if (ret) 79739c5c447SWenyou Yang goto error; 79839c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 79939c5c447SWenyou Yang mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); 80039c5c447SWenyou Yang *mbus_fmt = format->format; 80139c5c447SWenyou Yang 80239c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 80339c5c447SWenyou Yang return 0; 80439c5c447SWenyou Yang #else 80539c5c447SWenyou Yang ret = -ENOTTY; 80639c5c447SWenyou Yang goto error; 80739c5c447SWenyou Yang #endif 80839c5c447SWenyou Yang } 80939c5c447SWenyou Yang 81039c5c447SWenyou Yang ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize); 81139c5c447SWenyou Yang if (ret) 81239c5c447SWenyou Yang goto error; 81339c5c447SWenyou Yang 81439c5c447SWenyou Yang ov7740->fmt = ovfmt; 81539c5c447SWenyou Yang ov7740->frmsize = fsize; 81639c5c447SWenyou Yang 81739c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 81839c5c447SWenyou Yang return 0; 81939c5c447SWenyou Yang 82039c5c447SWenyou Yang error: 82139c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 82239c5c447SWenyou Yang return ret; 82339c5c447SWenyou Yang } 82439c5c447SWenyou Yang 82539c5c447SWenyou Yang static int ov7740_get_fmt(struct v4l2_subdev *sd, 82639c5c447SWenyou Yang struct v4l2_subdev_pad_config *cfg, 82739c5c447SWenyou Yang struct v4l2_subdev_format *format) 82839c5c447SWenyou Yang { 82939c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 83039c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 83139c5c447SWenyou Yang struct v4l2_mbus_framefmt *mbus_fmt; 83239c5c447SWenyou Yang #endif 83339c5c447SWenyou Yang int ret = 0; 83439c5c447SWenyou Yang 83539c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 83639c5c447SWenyou Yang if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 83739c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 83839c5c447SWenyou Yang mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); 83939c5c447SWenyou Yang format->format = *mbus_fmt; 84039c5c447SWenyou Yang ret = 0; 84139c5c447SWenyou Yang #else 84239c5c447SWenyou Yang ret = -ENOTTY; 84339c5c447SWenyou Yang #endif 84439c5c447SWenyou Yang } else { 84539c5c447SWenyou Yang format->format = ov7740->format; 84639c5c447SWenyou Yang } 84739c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 84839c5c447SWenyou Yang 84939c5c447SWenyou Yang return ret; 85039c5c447SWenyou Yang } 85139c5c447SWenyou Yang 85239c5c447SWenyou Yang static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { 85339c5c447SWenyou Yang .enum_frame_interval = ov7740_enum_frame_interval, 85439c5c447SWenyou Yang .enum_frame_size = ov7740_enum_frame_size, 85539c5c447SWenyou Yang .enum_mbus_code = ov7740_enum_mbus_code, 85639c5c447SWenyou Yang .get_fmt = ov7740_get_fmt, 85739c5c447SWenyou Yang .set_fmt = ov7740_set_fmt, 85839c5c447SWenyou Yang }; 85939c5c447SWenyou Yang 86039c5c447SWenyou Yang static const struct v4l2_subdev_ops ov7740_subdev_ops = { 86139c5c447SWenyou Yang .core = &ov7740_subdev_core_ops, 86239c5c447SWenyou Yang .video = &ov7740_subdev_video_ops, 86339c5c447SWenyou Yang .pad = &ov7740_subdev_pad_ops, 86439c5c447SWenyou Yang }; 86539c5c447SWenyou Yang 86639c5c447SWenyou Yang static void ov7740_get_default_format(struct v4l2_subdev *sd, 86739c5c447SWenyou Yang struct v4l2_mbus_framefmt *format) 86839c5c447SWenyou Yang { 86939c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 87039c5c447SWenyou Yang 87139c5c447SWenyou Yang format->width = ov7740->frmsize->width; 87239c5c447SWenyou Yang format->height = ov7740->frmsize->height; 87339c5c447SWenyou Yang format->colorspace = ov7740->fmt->colorspace; 87439c5c447SWenyou Yang format->code = ov7740->fmt->mbus_code; 87539c5c447SWenyou Yang format->field = V4L2_FIELD_NONE; 87639c5c447SWenyou Yang } 87739c5c447SWenyou Yang 87839c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 87939c5c447SWenyou Yang static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 88039c5c447SWenyou Yang { 88139c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 88239c5c447SWenyou Yang struct v4l2_mbus_framefmt *format = 88339c5c447SWenyou Yang v4l2_subdev_get_try_format(sd, fh->pad, 0); 88439c5c447SWenyou Yang 88539c5c447SWenyou Yang mutex_lock(&ov7740->mutex); 88639c5c447SWenyou Yang ov7740_get_default_format(sd, format); 88739c5c447SWenyou Yang mutex_unlock(&ov7740->mutex); 88839c5c447SWenyou Yang 88939c5c447SWenyou Yang return 0; 89039c5c447SWenyou Yang } 89139c5c447SWenyou Yang 89239c5c447SWenyou Yang static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = { 89339c5c447SWenyou Yang .open = ov7740_open, 89439c5c447SWenyou Yang }; 89539c5c447SWenyou Yang #endif 89639c5c447SWenyou Yang 89739c5c447SWenyou Yang static int ov7740_probe_dt(struct i2c_client *client, 89839c5c447SWenyou Yang struct ov7740 *ov7740) 89939c5c447SWenyou Yang { 90039c5c447SWenyou Yang ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", 90139c5c447SWenyou Yang GPIOD_OUT_HIGH); 90239c5c447SWenyou Yang if (IS_ERR(ov7740->resetb_gpio)) { 90339c5c447SWenyou Yang dev_info(&client->dev, "can't get %s GPIO\n", "reset"); 90439c5c447SWenyou Yang return PTR_ERR(ov7740->resetb_gpio); 90539c5c447SWenyou Yang } 90639c5c447SWenyou Yang 90739c5c447SWenyou Yang ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 90839c5c447SWenyou Yang GPIOD_OUT_LOW); 90939c5c447SWenyou Yang if (IS_ERR(ov7740->pwdn_gpio)) { 91039c5c447SWenyou Yang dev_info(&client->dev, "can't get %s GPIO\n", "powerdown"); 91139c5c447SWenyou Yang return PTR_ERR(ov7740->pwdn_gpio); 91239c5c447SWenyou Yang } 91339c5c447SWenyou Yang 91439c5c447SWenyou Yang return 0; 91539c5c447SWenyou Yang } 91639c5c447SWenyou Yang 91739c5c447SWenyou Yang static int ov7740_detect(struct ov7740 *ov7740) 91839c5c447SWenyou Yang { 91939c5c447SWenyou Yang struct regmap *regmap = ov7740->regmap; 92039c5c447SWenyou Yang unsigned int midh, midl, pidh, pidl; 92139c5c447SWenyou Yang int ret; 92239c5c447SWenyou Yang 92339c5c447SWenyou Yang ret = regmap_read(regmap, REG_MIDH, &midh); 92439c5c447SWenyou Yang if (ret) 92539c5c447SWenyou Yang return ret; 92639c5c447SWenyou Yang if (midh != 0x7f) 92739c5c447SWenyou Yang return -ENODEV; 92839c5c447SWenyou Yang 92939c5c447SWenyou Yang ret = regmap_read(regmap, REG_MIDL, &midl); 93039c5c447SWenyou Yang if (ret) 93139c5c447SWenyou Yang return ret; 93239c5c447SWenyou Yang if (midl != 0xa2) 93339c5c447SWenyou Yang return -ENODEV; 93439c5c447SWenyou Yang 93539c5c447SWenyou Yang ret = regmap_read(regmap, REG_PIDH, &pidh); 93639c5c447SWenyou Yang if (ret) 93739c5c447SWenyou Yang return ret; 93839c5c447SWenyou Yang if (pidh != 0x77) 93939c5c447SWenyou Yang return -ENODEV; 94039c5c447SWenyou Yang 94139c5c447SWenyou Yang ret = regmap_read(regmap, REG_PIDL, &pidl); 94239c5c447SWenyou Yang if (ret) 94339c5c447SWenyou Yang return ret; 94439c5c447SWenyou Yang if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42)) 94539c5c447SWenyou Yang return -ENODEV; 94639c5c447SWenyou Yang 94739c5c447SWenyou Yang return 0; 94839c5c447SWenyou Yang } 94939c5c447SWenyou Yang 95039c5c447SWenyou Yang static int ov7740_init_controls(struct ov7740 *ov7740) 95139c5c447SWenyou Yang { 95239c5c447SWenyou Yang struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); 95339c5c447SWenyou Yang struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler; 95439c5c447SWenyou Yang int ret; 95539c5c447SWenyou Yang 95639c5c447SWenyou Yang ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2); 95739c5c447SWenyou Yang if (ret < 0) 95839c5c447SWenyou Yang return ret; 95939c5c447SWenyou Yang 96039c5c447SWenyou Yang ctrl_hdlr->lock = &ov7740->mutex; 96139c5c447SWenyou Yang ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 96239c5c447SWenyou Yang V4L2_CID_AUTO_WHITE_BALANCE, 96339c5c447SWenyou Yang 0, 1, 1, 1); 96439c5c447SWenyou Yang ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 96539c5c447SWenyou Yang V4L2_CID_BLUE_BALANCE, 96639c5c447SWenyou Yang 0, 0xff, 1, 0x80); 96739c5c447SWenyou Yang ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 96839c5c447SWenyou Yang V4L2_CID_RED_BALANCE, 96939c5c447SWenyou Yang 0, 0xff, 1, 0x80); 97039c5c447SWenyou Yang 97139c5c447SWenyou Yang ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 97239c5c447SWenyou Yang V4L2_CID_BRIGHTNESS, 97339c5c447SWenyou Yang -255, 255, 1, 0); 97439c5c447SWenyou Yang ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 97539c5c447SWenyou Yang V4L2_CID_CONTRAST, 97639c5c447SWenyou Yang 0, 127, 1, 0x20); 97739c5c447SWenyou Yang ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 97839c5c447SWenyou Yang V4L2_CID_SATURATION, 0, 256, 1, 0x80); 97939c5c447SWenyou Yang ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 98039c5c447SWenyou Yang V4L2_CID_HFLIP, 0, 1, 1, 0); 98139c5c447SWenyou Yang ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 98239c5c447SWenyou Yang V4L2_CID_VFLIP, 0, 1, 1, 0); 98339c5c447SWenyou Yang ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 98439c5c447SWenyou Yang V4L2_CID_GAIN, 0, 1023, 1, 500); 98539c5c447SWenyou Yang ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 98639c5c447SWenyou Yang V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 98739c5c447SWenyou Yang ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, 98839c5c447SWenyou Yang V4L2_CID_EXPOSURE, 0, 65535, 1, 500); 98939c5c447SWenyou Yang ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr, 99039c5c447SWenyou Yang &ov7740_ctrl_ops, 99139c5c447SWenyou Yang V4L2_CID_EXPOSURE_AUTO, 99239c5c447SWenyou Yang V4L2_EXPOSURE_MANUAL, 0, 99339c5c447SWenyou Yang V4L2_EXPOSURE_AUTO); 99439c5c447SWenyou Yang 99539c5c447SWenyou Yang ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 99639c5c447SWenyou Yang ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 99739c5c447SWenyou Yang 99839c5c447SWenyou Yang v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false); 99939c5c447SWenyou Yang v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); 100039c5c447SWenyou Yang v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, 100139c5c447SWenyou Yang V4L2_EXPOSURE_MANUAL, false); 100239c5c447SWenyou Yang v4l2_ctrl_cluster(2, &ov7740->hflip); 100339c5c447SWenyou Yang 100439c5c447SWenyou Yang ret = v4l2_ctrl_handler_setup(ctrl_hdlr); 100539c5c447SWenyou Yang if (ret) { 100639c5c447SWenyou Yang dev_err(&client->dev, "%s control init failed (%d)\n", 100739c5c447SWenyou Yang __func__, ret); 100839c5c447SWenyou Yang goto error; 100939c5c447SWenyou Yang } 101039c5c447SWenyou Yang 101139c5c447SWenyou Yang ov7740->subdev.ctrl_handler = ctrl_hdlr; 101239c5c447SWenyou Yang return 0; 101339c5c447SWenyou Yang 101439c5c447SWenyou Yang error: 101539c5c447SWenyou Yang v4l2_ctrl_handler_free(ctrl_hdlr); 101639c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 101739c5c447SWenyou Yang return ret; 101839c5c447SWenyou Yang } 101939c5c447SWenyou Yang 102039c5c447SWenyou Yang static void ov7740_free_controls(struct ov7740 *ov7740) 102139c5c447SWenyou Yang { 102239c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 102339c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 102439c5c447SWenyou Yang } 102539c5c447SWenyou Yang 102639c5c447SWenyou Yang #define OV7740_MAX_REGISTER 0xff 102739c5c447SWenyou Yang static const struct regmap_config ov7740_regmap_config = { 102839c5c447SWenyou Yang .reg_bits = 8, 102939c5c447SWenyou Yang .val_bits = 8, 103039c5c447SWenyou Yang .max_register = OV7740_MAX_REGISTER, 103139c5c447SWenyou Yang }; 103239c5c447SWenyou Yang 103339c5c447SWenyou Yang static int ov7740_probe(struct i2c_client *client, 103439c5c447SWenyou Yang const struct i2c_device_id *id) 103539c5c447SWenyou Yang { 103639c5c447SWenyou Yang struct ov7740 *ov7740; 103739c5c447SWenyou Yang struct v4l2_subdev *sd; 103839c5c447SWenyou Yang int ret; 103939c5c447SWenyou Yang 104039c5c447SWenyou Yang if (!i2c_check_functionality(client->adapter, 104139c5c447SWenyou Yang I2C_FUNC_SMBUS_BYTE_DATA)) { 104239c5c447SWenyou Yang dev_err(&client->dev, 104339c5c447SWenyou Yang "OV7740: I2C-Adapter doesn't support SMBUS\n"); 104439c5c447SWenyou Yang return -EIO; 104539c5c447SWenyou Yang } 104639c5c447SWenyou Yang 104739c5c447SWenyou Yang ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL); 104839c5c447SWenyou Yang if (!ov7740) 104939c5c447SWenyou Yang return -ENOMEM; 105039c5c447SWenyou Yang 105139c5c447SWenyou Yang ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); 105239c5c447SWenyou Yang if (IS_ERR(ov7740->xvclk)) { 105339c5c447SWenyou Yang ret = PTR_ERR(ov7740->xvclk); 105439c5c447SWenyou Yang dev_err(&client->dev, 105539c5c447SWenyou Yang "OV7740: fail to get xvclk: %d\n", ret); 105639c5c447SWenyou Yang return ret; 105739c5c447SWenyou Yang } 105839c5c447SWenyou Yang 105939c5c447SWenyou Yang ret = ov7740_probe_dt(client, ov7740); 106039c5c447SWenyou Yang if (ret) 106139c5c447SWenyou Yang return ret; 106239c5c447SWenyou Yang 106339c5c447SWenyou Yang ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config); 106439c5c447SWenyou Yang if (IS_ERR(ov7740->regmap)) { 106539c5c447SWenyou Yang ret = PTR_ERR(ov7740->regmap); 106639c5c447SWenyou Yang dev_err(&client->dev, "Failed to allocate register map: %d\n", 106739c5c447SWenyou Yang ret); 106839c5c447SWenyou Yang return ret; 106939c5c447SWenyou Yang } 107039c5c447SWenyou Yang 107139c5c447SWenyou Yang sd = &ov7740->subdev; 107239c5c447SWenyou Yang client->flags |= I2C_CLIENT_SCCB; 107339c5c447SWenyou Yang v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops); 107439c5c447SWenyou Yang 107539c5c447SWenyou Yang #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API 107639c5c447SWenyou Yang sd->internal_ops = &ov7740_subdev_internal_ops; 107739c5c447SWenyou Yang sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 107839c5c447SWenyou Yang #endif 107939c5c447SWenyou Yang 108039c5c447SWenyou Yang #if defined(CONFIG_MEDIA_CONTROLLER) 108139c5c447SWenyou Yang ov7740->pad.flags = MEDIA_PAD_FL_SOURCE; 108239c5c447SWenyou Yang sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; 108339c5c447SWenyou Yang ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad); 108439c5c447SWenyou Yang if (ret) 108539c5c447SWenyou Yang return ret; 108639c5c447SWenyou Yang #endif 108739c5c447SWenyou Yang 108839c5c447SWenyou Yang ret = ov7740_set_power(ov7740, 1); 108939c5c447SWenyou Yang if (ret) 109039c5c447SWenyou Yang return ret; 109139c5c447SWenyou Yang 109239c5c447SWenyou Yang ret = ov7740_detect(ov7740); 109339c5c447SWenyou Yang if (ret) 109439c5c447SWenyou Yang goto error_detect; 109539c5c447SWenyou Yang 109639c5c447SWenyou Yang mutex_init(&ov7740->mutex); 109739c5c447SWenyou Yang 109839c5c447SWenyou Yang ret = ov7740_init_controls(ov7740); 109939c5c447SWenyou Yang if (ret) 110039c5c447SWenyou Yang goto error_init_controls; 110139c5c447SWenyou Yang 110239c5c447SWenyou Yang v4l_info(client, "chip found @ 0x%02x (%s)\n", 110339c5c447SWenyou Yang client->addr << 1, client->adapter->name); 110439c5c447SWenyou Yang 110539c5c447SWenyou Yang ov7740->fmt = &ov7740_formats[0]; 110639c5c447SWenyou Yang ov7740->frmsize = &ov7740_framesizes[0]; 110739c5c447SWenyou Yang 110839c5c447SWenyou Yang ov7740_get_default_format(sd, &ov7740->format); 110939c5c447SWenyou Yang 111039c5c447SWenyou Yang ret = v4l2_async_register_subdev(sd); 111139c5c447SWenyou Yang if (ret) 111239c5c447SWenyou Yang goto error_async_register; 111339c5c447SWenyou Yang 111439c5c447SWenyou Yang pm_runtime_set_active(&client->dev); 111539c5c447SWenyou Yang pm_runtime_enable(&client->dev); 111639c5c447SWenyou Yang pm_runtime_idle(&client->dev); 111739c5c447SWenyou Yang 111839c5c447SWenyou Yang return 0; 111939c5c447SWenyou Yang 112039c5c447SWenyou Yang error_async_register: 112139c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 112239c5c447SWenyou Yang error_init_controls: 112339c5c447SWenyou Yang ov7740_free_controls(ov7740); 112439c5c447SWenyou Yang error_detect: 112539c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 112639c5c447SWenyou Yang media_entity_cleanup(&ov7740->subdev.entity); 112739c5c447SWenyou Yang 112839c5c447SWenyou Yang return ret; 112939c5c447SWenyou Yang } 113039c5c447SWenyou Yang 113139c5c447SWenyou Yang static int ov7740_remove(struct i2c_client *client) 113239c5c447SWenyou Yang { 113339c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 113439c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 113539c5c447SWenyou Yang 113639c5c447SWenyou Yang mutex_destroy(&ov7740->mutex); 113739c5c447SWenyou Yang v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); 113839c5c447SWenyou Yang media_entity_cleanup(&ov7740->subdev.entity); 113939c5c447SWenyou Yang v4l2_async_unregister_subdev(sd); 114039c5c447SWenyou Yang ov7740_free_controls(ov7740); 114139c5c447SWenyou Yang 114239c5c447SWenyou Yang pm_runtime_get_sync(&client->dev); 114339c5c447SWenyou Yang pm_runtime_disable(&client->dev); 114439c5c447SWenyou Yang pm_runtime_set_suspended(&client->dev); 114539c5c447SWenyou Yang pm_runtime_put_noidle(&client->dev); 114639c5c447SWenyou Yang 114739c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 114839c5c447SWenyou Yang return 0; 114939c5c447SWenyou Yang } 115039c5c447SWenyou Yang 115139c5c447SWenyou Yang static int __maybe_unused ov7740_runtime_suspend(struct device *dev) 115239c5c447SWenyou Yang { 115339c5c447SWenyou Yang struct i2c_client *client = to_i2c_client(dev); 115439c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 115539c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 115639c5c447SWenyou Yang 115739c5c447SWenyou Yang ov7740_set_power(ov7740, 0); 115839c5c447SWenyou Yang 115939c5c447SWenyou Yang return 0; 116039c5c447SWenyou Yang } 116139c5c447SWenyou Yang 116239c5c447SWenyou Yang static int __maybe_unused ov7740_runtime_resume(struct device *dev) 116339c5c447SWenyou Yang { 116439c5c447SWenyou Yang struct i2c_client *client = to_i2c_client(dev); 116539c5c447SWenyou Yang struct v4l2_subdev *sd = i2c_get_clientdata(client); 116639c5c447SWenyou Yang struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); 116739c5c447SWenyou Yang 116839c5c447SWenyou Yang return ov7740_set_power(ov7740, 1); 116939c5c447SWenyou Yang } 117039c5c447SWenyou Yang 117139c5c447SWenyou Yang static const struct i2c_device_id ov7740_id[] = { 117239c5c447SWenyou Yang { "ov7740", 0 }, 117339c5c447SWenyou Yang { /* sentinel */ } 117439c5c447SWenyou Yang }; 117539c5c447SWenyou Yang MODULE_DEVICE_TABLE(i2c, ov7740_id); 117639c5c447SWenyou Yang 117739c5c447SWenyou Yang static const struct dev_pm_ops ov7740_pm_ops = { 117839c5c447SWenyou Yang SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL) 117939c5c447SWenyou Yang }; 118039c5c447SWenyou Yang 118139c5c447SWenyou Yang static const struct of_device_id ov7740_of_match[] = { 118239c5c447SWenyou Yang {.compatible = "ovti,ov7740", }, 118339c5c447SWenyou Yang { /* sentinel */ }, 118439c5c447SWenyou Yang }; 118539c5c447SWenyou Yang MODULE_DEVICE_TABLE(of, ov7740_of_match); 118639c5c447SWenyou Yang 118739c5c447SWenyou Yang static struct i2c_driver ov7740_i2c_driver = { 118839c5c447SWenyou Yang .driver = { 118939c5c447SWenyou Yang .name = "ov7740", 119039c5c447SWenyou Yang .pm = &ov7740_pm_ops, 119139c5c447SWenyou Yang .of_match_table = of_match_ptr(ov7740_of_match), 119239c5c447SWenyou Yang }, 119339c5c447SWenyou Yang .probe = ov7740_probe, 119439c5c447SWenyou Yang .remove = ov7740_remove, 119539c5c447SWenyou Yang .id_table = ov7740_id, 119639c5c447SWenyou Yang }; 119739c5c447SWenyou Yang module_i2c_driver(ov7740_i2c_driver); 119839c5c447SWenyou Yang 119939c5c447SWenyou Yang MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor"); 120039c5c447SWenyou Yang MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>"); 120139c5c447SWenyou Yang MODULE_LICENSE("GPL v2"); 1202