1185 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2017 Microchip Corporation.3 4#include <linux/clk.h>5#include <linux/delay.h>6#include <linux/gpio/consumer.h>7#include <linux/i2c.h>8#include <linux/module.h>9#include <linux/pm_runtime.h>10#include <linux/regmap.h>11#include <media/v4l2-ctrls.h>12#include <media/v4l2-event.h>13#include <media/v4l2-image-sizes.h>14#include <media/v4l2-subdev.h>15 16#define REG_OUTSIZE_LSB 0x3417 18/* OV7740 register tables */19#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */20#define REG_BGAIN 0x01 /* blue gain */21#define REG_RGAIN 0x02 /* red gain */22#define REG_GGAIN 0x03 /* green gain */23#define REG_REG04 0x04 /* analog setting, don't change*/24#define REG_BAVG 0x05 /* b channel average */25#define REG_GAVG 0x06 /* g channel average */26#define REG_RAVG 0x07 /* r channel average */27 28#define REG_REG0C 0x0C /* filp enable */29#define REG0C_IMG_FLIP 0x8030#define REG0C_IMG_MIRROR 0x4031 32#define REG_REG0E 0x0E /* blc line */33#define REG_HAEC 0x0F /* auto exposure cntrl */34#define REG_AEC 0x10 /* auto exposure cntrl */35 36#define REG_CLK 0x11 /* Clock control */37#define REG_REG55 0x55 /* Clock PLL DIV/PreDiv */38 39#define REG_REG12 0x1240 41#define REG_REG13 0x13 /* auto/manual AGC, AEC, Write Balance*/42#define REG13_AEC_EN 0x0143#define REG13_AGC_EN 0x0444 45#define REG_REG14 0x1446#define REG_CTRL15 0x1547#define REG15_GAIN_MSB 0x0348 49#define REG_REG16 0x1650 51#define REG_MIDH 0x1C /* manufacture id byte */52#define REG_MIDL 0x1D /* manufacture id byre */53#define REG_PIDH 0x0A /* Product ID MSB */54#define REG_PIDL 0x0B /* Product ID LSB */55 56#define REG_84 0x84 /* lots of stuff */57#define REG_REG38 0x38 /* sub-addr */58 59#define REG_AHSTART 0x17 /* Horiz start high bits */60#define REG_AHSIZE 0x1861#define REG_AVSTART 0x19 /* Vert start high bits */62#define REG_AVSIZE 0x1A63#define REG_PSHFT 0x1b /* Pixel delay after HREF */64 65#define REG_HOUTSIZE 0x3166#define REG_VOUTSIZE 0x3267#define REG_HVSIZEOFF 0x3368#define REG_REG34 0x34 /* DSP output size H/V LSB*/69 70#define REG_ISP_CTRL00 0x8071#define ISPCTRL00_AWB_EN 0x1072#define ISPCTRL00_AWB_GAIN_EN 0x0473 74#define REG_YGAIN 0xE2 /* ygain for contrast control */75 76#define REG_YBRIGHT 0xE377#define REG_SGNSET 0xE478#define SGNSET_YBRIGHT_MASK 0x0879 80#define REG_USAT 0xDD81#define REG_VSAT 0xDE82 83 84struct ov7740 {85 struct v4l2_subdev subdev;86 struct media_pad pad;87 struct v4l2_mbus_framefmt format;88 const struct ov7740_pixfmt *fmt; /* Current format */89 const struct ov7740_framesize *frmsize;90 struct regmap *regmap;91 struct clk *xvclk;92 struct v4l2_ctrl_handler ctrl_handler;93 struct {94 /* gain cluster */95 struct v4l2_ctrl *auto_gain;96 struct v4l2_ctrl *gain;97 };98 struct {99 struct v4l2_ctrl *auto_wb;100 struct v4l2_ctrl *blue_balance;101 struct v4l2_ctrl *red_balance;102 };103 struct {104 struct v4l2_ctrl *hflip;105 struct v4l2_ctrl *vflip;106 };107 struct {108 /* exposure cluster */109 struct v4l2_ctrl *auto_exposure;110 struct v4l2_ctrl *exposure;111 };112 struct {113 /* saturation/hue cluster */114 struct v4l2_ctrl *saturation;115 struct v4l2_ctrl *hue;116 };117 struct v4l2_ctrl *brightness;118 struct v4l2_ctrl *contrast;119 120 struct mutex mutex; /* To serialize asynchronus callbacks */121 122 struct gpio_desc *resetb_gpio;123 struct gpio_desc *pwdn_gpio;124};125 126struct ov7740_pixfmt {127 u32 mbus_code;128 enum v4l2_colorspace colorspace;129 const struct reg_sequence *regs;130 u32 reg_num;131};132 133struct ov7740_framesize {134 u16 width;135 u16 height;136 const struct reg_sequence *regs;137 u32 reg_num;138};139 140static const struct reg_sequence ov7740_vga[] = {141 {0x55, 0x40},142 {0x11, 0x02},143 144 {0xd5, 0x10},145 {0x0c, 0x12},146 {0x0d, 0x34},147 {0x17, 0x25},148 {0x18, 0xa0},149 {0x19, 0x03},150 {0x1a, 0xf0},151 {0x1b, 0x89},152 {0x22, 0x03},153 {0x29, 0x18},154 {0x2b, 0xf8},155 {0x2c, 0x01},156 {REG_HOUTSIZE, 0xa0},157 {REG_VOUTSIZE, 0xf0},158 {0x33, 0xc4},159 {REG_OUTSIZE_LSB, 0x0},160 {0x35, 0x05},161 {0x04, 0x60},162 {0x27, 0x80},163 {0x3d, 0x0f},164 {0x3e, 0x80},165 {0x3f, 0x40},166 {0x40, 0x7f},167 {0x41, 0x6a},168 {0x42, 0x29},169 {0x44, 0x22},170 {0x45, 0x41},171 {0x47, 0x02},172 {0x49, 0x64},173 {0x4a, 0xa1},174 {0x4b, 0x40},175 {0x4c, 0x1a},176 {0x4d, 0x50},177 {0x4e, 0x13},178 {0x64, 0x00},179 {0x67, 0x88},180 {0x68, 0x1a},181 182 {0x14, 0x28},183 {0x24, 0x3c},184 {0x25, 0x30},185 {0x26, 0x72},186 {0x50, 0x97},187 {0x51, 0x1f},188 {0x52, 0x00},189 {0x53, 0x00},190 {0x20, 0x00},191 {0x21, 0xcf},192 {0x50, 0x4b},193 {0x38, 0x14},194 {0xe9, 0x00},195 {0x56, 0x55},196 {0x57, 0xff},197 {0x58, 0xff},198 {0x59, 0xff},199 {0x5f, 0x04},200 {0xec, 0x00},201 {0x13, 0xff},202 203 {0x81, 0x3f},204 {0x82, 0x32},205 {0x38, 0x11},206 {0x84, 0x70},207 {0x85, 0x00},208 {0x86, 0x03},209 {0x87, 0x01},210 {0x88, 0x05},211 {0x89, 0x30},212 {0x8d, 0x30},213 {0x8f, 0x85},214 {0x93, 0x30},215 {0x95, 0x85},216 {0x99, 0x30},217 {0x9b, 0x85},218 219 {0x9c, 0x08},220 {0x9d, 0x12},221 {0x9e, 0x23},222 {0x9f, 0x45},223 {0xa0, 0x55},224 {0xa1, 0x64},225 {0xa2, 0x72},226 {0xa3, 0x7f},227 {0xa4, 0x8b},228 {0xa5, 0x95},229 {0xa6, 0xa7},230 {0xa7, 0xb5},231 {0xa8, 0xcb},232 {0xa9, 0xdd},233 {0xaa, 0xec},234 {0xab, 0x1a},235 236 {0xce, 0x78},237 {0xcf, 0x6e},238 {0xd0, 0x0a},239 {0xd1, 0x0c},240 {0xd2, 0x84},241 {0xd3, 0x90},242 {0xd4, 0x1e},243 244 {0x5a, 0x24},245 {0x5b, 0x1f},246 {0x5c, 0x88},247 {0x5d, 0x60},248 249 {0xac, 0x6e},250 {0xbe, 0xff},251 {0xbf, 0x00},252 253 {0x0f, 0x1d},254 {0x0f, 0x1f},255};256 257static const struct ov7740_framesize ov7740_framesizes[] = {258 {259 .width = VGA_WIDTH,260 .height = VGA_HEIGHT,261 .regs = ov7740_vga,262 .reg_num = ARRAY_SIZE(ov7740_vga),263 },264};265 266#ifdef CONFIG_VIDEO_ADV_DEBUG267static int ov7740_get_register(struct v4l2_subdev *sd,268 struct v4l2_dbg_register *reg)269{270 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);271 struct regmap *regmap = ov7740->regmap;272 unsigned int val = 0;273 int ret;274 275 ret = regmap_read(regmap, reg->reg & 0xff, &val);276 reg->val = val;277 reg->size = 1;278 279 return ret;280}281 282static int ov7740_set_register(struct v4l2_subdev *sd,283 const struct v4l2_dbg_register *reg)284{285 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);286 struct regmap *regmap = ov7740->regmap;287 288 regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff);289 290 return 0;291}292#endif293 294static int ov7740_set_power(struct ov7740 *ov7740, int on)295{296 int ret;297 298 if (on) {299 ret = clk_prepare_enable(ov7740->xvclk);300 if (ret)301 return ret;302 303 if (ov7740->pwdn_gpio)304 gpiod_direction_output(ov7740->pwdn_gpio, 0);305 306 if (ov7740->resetb_gpio) {307 gpiod_set_value(ov7740->resetb_gpio, 1);308 usleep_range(500, 1000);309 gpiod_set_value(ov7740->resetb_gpio, 0);310 usleep_range(3000, 5000);311 }312 } else {313 clk_disable_unprepare(ov7740->xvclk);314 315 if (ov7740->pwdn_gpio)316 gpiod_direction_output(ov7740->pwdn_gpio, 0);317 }318 319 return 0;320}321 322static const struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {323 .log_status = v4l2_ctrl_subdev_log_status,324#ifdef CONFIG_VIDEO_ADV_DEBUG325 .g_register = ov7740_get_register,326 .s_register = ov7740_set_register,327#endif328 .subscribe_event = v4l2_ctrl_subdev_subscribe_event,329 .unsubscribe_event = v4l2_event_subdev_unsubscribe,330};331 332static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb)333{334 struct regmap *regmap = ov7740->regmap;335 unsigned int value;336 int ret;337 338 ret = regmap_read(regmap, REG_ISP_CTRL00, &value);339 if (!ret) {340 if (awb)341 value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);342 else343 value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);344 ret = regmap_write(regmap, REG_ISP_CTRL00, value);345 if (ret)346 return ret;347 }348 349 if (!awb) {350 ret = regmap_write(regmap, REG_BGAIN,351 ov7740->blue_balance->val);352 if (ret)353 return ret;354 355 ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val);356 if (ret)357 return ret;358 }359 360 return 0;361}362 363static int ov7740_set_saturation(struct regmap *regmap, int value)364{365 int ret;366 367 ret = regmap_write(regmap, REG_USAT, (unsigned char)value);368 if (ret)369 return ret;370 371 return regmap_write(regmap, REG_VSAT, (unsigned char)value);372}373 374static int ov7740_set_gain(struct regmap *regmap, int value)375{376 int ret;377 378 ret = regmap_write(regmap, REG_GAIN, value & 0xff);379 if (ret)380 return ret;381 382 ret = regmap_update_bits(regmap, REG_CTRL15,383 REG15_GAIN_MSB, (value >> 8) & 0x3);384 if (!ret)385 ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);386 387 return ret;388}389 390static int ov7740_set_autogain(struct regmap *regmap, int value)391{392 unsigned int reg;393 int ret;394 395 ret = regmap_read(regmap, REG_REG13, ®);396 if (ret)397 return ret;398 if (value)399 reg |= REG13_AGC_EN;400 else401 reg &= ~REG13_AGC_EN;402 return regmap_write(regmap, REG_REG13, reg);403}404 405static int ov7740_set_brightness(struct regmap *regmap, int value)406{407 /* Turn off AEC/AGC */408 regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0);409 regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);410 411 if (value >= 0) {412 regmap_write(regmap, REG_YBRIGHT, (unsigned char)value);413 regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0);414 } else{415 regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value));416 regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1);417 }418 419 return 0;420}421 422static int ov7740_set_contrast(struct regmap *regmap, int value)423{424 return regmap_write(regmap, REG_YGAIN, (unsigned char)value);425}426 427static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)428{429 struct regmap *regmap = ov7740->regmap;430 unsigned int value0, value1;431 int ret;432 433 if (!ctrl->val)434 return 0;435 436 ret = regmap_read(regmap, REG_GAIN, &value0);437 if (ret)438 return ret;439 ret = regmap_read(regmap, REG_CTRL15, &value1);440 if (ret)441 return ret;442 443 ov7740->gain->val = (value1 << 8) | (value0 & 0xff);444 445 return 0;446}447 448static int ov7740_get_exp(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)449{450 struct regmap *regmap = ov7740->regmap;451 unsigned int value0, value1;452 int ret;453 454 if (ctrl->val == V4L2_EXPOSURE_MANUAL)455 return 0;456 457 ret = regmap_read(regmap, REG_AEC, &value0);458 if (ret)459 return ret;460 ret = regmap_read(regmap, REG_HAEC, &value1);461 if (ret)462 return ret;463 464 ov7740->exposure->val = (value1 << 8) | (value0 & 0xff);465 466 return 0;467}468 469static int ov7740_set_exp(struct regmap *regmap, int value)470{471 int ret;472 473 /* Turn off AEC/AGC */474 ret = regmap_update_bits(regmap, REG_REG13,475 REG13_AEC_EN | REG13_AGC_EN, 0);476 if (ret)477 return ret;478 479 ret = regmap_write(regmap, REG_AEC, (unsigned char)value);480 if (ret)481 return ret;482 483 return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8));484}485 486static int ov7740_set_autoexp(struct regmap *regmap,487 enum v4l2_exposure_auto_type value)488{489 unsigned int reg;490 int ret;491 492 ret = regmap_read(regmap, REG_REG13, ®);493 if (!ret) {494 if (value == V4L2_EXPOSURE_AUTO)495 reg |= (REG13_AEC_EN | REG13_AGC_EN);496 else497 reg &= ~(REG13_AEC_EN | REG13_AGC_EN);498 ret = regmap_write(regmap, REG_REG13, reg);499 }500 501 return ret;502}503 504 505static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl)506{507 struct ov7740 *ov7740 = container_of(ctrl->handler,508 struct ov7740, ctrl_handler);509 int ret;510 511 switch (ctrl->id) {512 case V4L2_CID_AUTOGAIN:513 ret = ov7740_get_gain(ov7740, ctrl);514 break;515 case V4L2_CID_EXPOSURE_AUTO:516 ret = ov7740_get_exp(ov7740, ctrl);517 break;518 default:519 ret = -EINVAL;520 break;521 }522 return ret;523}524 525static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)526{527 struct ov7740 *ov7740 = container_of(ctrl->handler,528 struct ov7740, ctrl_handler);529 struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);530 struct regmap *regmap = ov7740->regmap;531 int ret;532 u8 val;533 534 if (!pm_runtime_get_if_in_use(&client->dev))535 return 0;536 537 switch (ctrl->id) {538 case V4L2_CID_AUTO_WHITE_BALANCE:539 ret = ov7740_set_white_balance(ov7740, ctrl->val);540 break;541 case V4L2_CID_SATURATION:542 ret = ov7740_set_saturation(regmap, ctrl->val);543 break;544 case V4L2_CID_BRIGHTNESS:545 ret = ov7740_set_brightness(regmap, ctrl->val);546 break;547 case V4L2_CID_CONTRAST:548 ret = ov7740_set_contrast(regmap, ctrl->val);549 break;550 case V4L2_CID_VFLIP:551 val = ctrl->val ? REG0C_IMG_FLIP : 0x00;552 ret = regmap_update_bits(regmap, REG_REG0C,553 REG0C_IMG_FLIP, val);554 break;555 case V4L2_CID_HFLIP:556 val = ctrl->val ? REG0C_IMG_MIRROR : 0x00;557 ret = regmap_update_bits(regmap, REG_REG0C,558 REG0C_IMG_MIRROR, val);559 break;560 case V4L2_CID_AUTOGAIN:561 if (!ctrl->val)562 ret = ov7740_set_gain(regmap, ov7740->gain->val);563 else564 ret = ov7740_set_autogain(regmap, ctrl->val);565 break;566 567 case V4L2_CID_EXPOSURE_AUTO:568 if (ctrl->val == V4L2_EXPOSURE_MANUAL)569 ret = ov7740_set_exp(regmap, ov7740->exposure->val);570 else571 ret = ov7740_set_autoexp(regmap, ctrl->val);572 break;573 default:574 ret = -EINVAL;575 break;576 }577 578 pm_runtime_put(&client->dev);579 580 return ret;581}582 583static const struct v4l2_ctrl_ops ov7740_ctrl_ops = {584 .g_volatile_ctrl = ov7740_get_volatile_ctrl,585 .s_ctrl = ov7740_set_ctrl,586};587 588static int ov7740_start_streaming(struct ov7740 *ov7740)589{590 int ret;591 592 if (ov7740->fmt) {593 ret = regmap_multi_reg_write(ov7740->regmap,594 ov7740->fmt->regs,595 ov7740->fmt->reg_num);596 if (ret)597 return ret;598 }599 600 if (ov7740->frmsize) {601 ret = regmap_multi_reg_write(ov7740->regmap,602 ov7740->frmsize->regs,603 ov7740->frmsize->reg_num);604 if (ret)605 return ret;606 }607 608 return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler);609}610 611static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)612{613 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);614 struct i2c_client *client = v4l2_get_subdevdata(sd);615 int ret = 0;616 617 mutex_lock(&ov7740->mutex);618 619 if (enable) {620 ret = pm_runtime_resume_and_get(&client->dev);621 if (ret < 0)622 goto err_unlock;623 624 ret = ov7740_start_streaming(ov7740);625 if (ret)626 goto err_rpm_put;627 } else {628 pm_runtime_put(&client->dev);629 }630 631 mutex_unlock(&ov7740->mutex);632 return ret;633 634err_rpm_put:635 pm_runtime_put(&client->dev);636err_unlock:637 mutex_unlock(&ov7740->mutex);638 return ret;639}640 641static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {642 .s_stream = ov7740_set_stream,643};644 645static const struct reg_sequence ov7740_format_yuyv[] = {646 {0x12, 0x00},647 {0x36, 0x3f},648 {0x80, 0x7f},649 {0x83, 0x01},650};651 652static const struct reg_sequence ov7740_format_bggr8[] = {653 {0x36, 0x2f},654 {0x80, 0x01},655 {0x83, 0x04},656};657 658static const struct ov7740_pixfmt ov7740_formats[] = {659 {660 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,661 .colorspace = V4L2_COLORSPACE_SRGB,662 .regs = ov7740_format_yuyv,663 .reg_num = ARRAY_SIZE(ov7740_format_yuyv),664 },665 {666 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,667 .colorspace = V4L2_COLORSPACE_SRGB,668 .regs = ov7740_format_bggr8,669 .reg_num = ARRAY_SIZE(ov7740_format_bggr8),670 }671};672#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)673 674static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,675 struct v4l2_subdev_state *sd_state,676 struct v4l2_subdev_mbus_code_enum *code)677{678 if (code->pad || code->index >= N_OV7740_FMTS)679 return -EINVAL;680 681 code->code = ov7740_formats[code->index].mbus_code;682 683 return 0;684}685 686static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,687 struct v4l2_subdev_state *sd_state,688 struct v4l2_subdev_frame_interval_enum *fie)689{690 if (fie->pad)691 return -EINVAL;692 693 if (fie->index >= 1)694 return -EINVAL;695 696 if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT))697 return -EINVAL;698 699 fie->interval.numerator = 1;700 fie->interval.denominator = 60;701 702 return 0;703}704 705static int ov7740_enum_frame_size(struct v4l2_subdev *sd,706 struct v4l2_subdev_state *sd_state,707 struct v4l2_subdev_frame_size_enum *fse)708{709 if (fse->pad)710 return -EINVAL;711 712 if (fse->index > 0)713 return -EINVAL;714 715 fse->min_width = fse->max_width = VGA_WIDTH;716 fse->min_height = fse->max_height = VGA_HEIGHT;717 718 return 0;719}720 721static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,722 struct v4l2_mbus_framefmt *fmt,723 const struct ov7740_pixfmt **ret_fmt,724 const struct ov7740_framesize **ret_frmsize)725{726 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);727 const struct ov7740_framesize *fsize = &ov7740_framesizes[0];728 int index, i;729 730 for (index = 0; index < N_OV7740_FMTS; index++) {731 if (ov7740_formats[index].mbus_code == fmt->code)732 break;733 }734 if (index >= N_OV7740_FMTS) {735 /* default to first format */736 index = 0;737 fmt->code = ov7740_formats[0].mbus_code;738 }739 if (ret_fmt != NULL)740 *ret_fmt = ov7740_formats + index;741 742 for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) {743 if ((fsize->width >= fmt->width) &&744 (fsize->height >= fmt->height)) {745 fmt->width = fsize->width;746 fmt->height = fsize->height;747 break;748 }749 750 fsize++;751 }752 if (i >= ARRAY_SIZE(ov7740_framesizes)) {753 fsize = &ov7740_framesizes[0];754 fmt->width = fsize->width;755 fmt->height = fsize->height;756 }757 if (ret_frmsize != NULL)758 *ret_frmsize = fsize;759 760 fmt->field = V4L2_FIELD_NONE;761 fmt->colorspace = ov7740_formats[index].colorspace;762 763 ov7740->format = *fmt;764 765 return 0;766}767 768static int ov7740_set_fmt(struct v4l2_subdev *sd,769 struct v4l2_subdev_state *sd_state,770 struct v4l2_subdev_format *format)771{772 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);773 const struct ov7740_pixfmt *ovfmt;774 const struct ov7740_framesize *fsize;775 struct v4l2_mbus_framefmt *mbus_fmt;776 int ret;777 778 mutex_lock(&ov7740->mutex);779 if (format->pad) {780 ret = -EINVAL;781 goto error;782 }783 784 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {785 ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL);786 if (ret)787 goto error;788 789 mbus_fmt = v4l2_subdev_state_get_format(sd_state, format->pad);790 *mbus_fmt = format->format;791 mutex_unlock(&ov7740->mutex);792 return 0;793 }794 795 ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize);796 if (ret)797 goto error;798 799 ov7740->fmt = ovfmt;800 ov7740->frmsize = fsize;801 802 mutex_unlock(&ov7740->mutex);803 return 0;804 805error:806 mutex_unlock(&ov7740->mutex);807 return ret;808}809 810static int ov7740_get_fmt(struct v4l2_subdev *sd,811 struct v4l2_subdev_state *sd_state,812 struct v4l2_subdev_format *format)813{814 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);815 struct v4l2_mbus_framefmt *mbus_fmt;816 817 mutex_lock(&ov7740->mutex);818 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {819 mbus_fmt = v4l2_subdev_state_get_format(sd_state, 0);820 format->format = *mbus_fmt;821 } else {822 format->format = ov7740->format;823 }824 mutex_unlock(&ov7740->mutex);825 826 return 0;827}828 829static int ov7740_get_frame_interval(struct v4l2_subdev *sd,830 struct v4l2_subdev_state *sd_state,831 struct v4l2_subdev_frame_interval *ival)832{833 struct v4l2_fract *tpf = &ival->interval;834 835 tpf->numerator = 1;836 tpf->denominator = 60;837 838 return 0;839}840 841static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {842 .enum_frame_interval = ov7740_enum_frame_interval,843 .enum_frame_size = ov7740_enum_frame_size,844 .enum_mbus_code = ov7740_enum_mbus_code,845 .get_fmt = ov7740_get_fmt,846 .set_fmt = ov7740_set_fmt,847 .get_frame_interval = ov7740_get_frame_interval,848 .set_frame_interval = ov7740_get_frame_interval,849};850 851static const struct v4l2_subdev_ops ov7740_subdev_ops = {852 .core = &ov7740_subdev_core_ops,853 .video = &ov7740_subdev_video_ops,854 .pad = &ov7740_subdev_pad_ops,855};856 857static void ov7740_get_default_format(struct v4l2_subdev *sd,858 struct v4l2_mbus_framefmt *format)859{860 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);861 862 format->width = ov7740->frmsize->width;863 format->height = ov7740->frmsize->height;864 format->colorspace = ov7740->fmt->colorspace;865 format->code = ov7740->fmt->mbus_code;866 format->field = V4L2_FIELD_NONE;867}868 869static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)870{871 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);872 struct v4l2_mbus_framefmt *format =873 v4l2_subdev_state_get_format(fh->state, 0);874 875 mutex_lock(&ov7740->mutex);876 ov7740_get_default_format(sd, format);877 mutex_unlock(&ov7740->mutex);878 879 return 0;880}881 882static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = {883 .open = ov7740_open,884};885 886static int ov7740_probe_dt(struct i2c_client *client,887 struct ov7740 *ov7740)888{889 ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset",890 GPIOD_OUT_HIGH);891 if (IS_ERR(ov7740->resetb_gpio)) {892 dev_info(&client->dev, "can't get %s GPIO\n", "reset");893 return PTR_ERR(ov7740->resetb_gpio);894 }895 896 ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",897 GPIOD_OUT_LOW);898 if (IS_ERR(ov7740->pwdn_gpio)) {899 dev_info(&client->dev, "can't get %s GPIO\n", "powerdown");900 return PTR_ERR(ov7740->pwdn_gpio);901 }902 903 return 0;904}905 906static int ov7740_detect(struct ov7740 *ov7740)907{908 struct regmap *regmap = ov7740->regmap;909 unsigned int midh, midl, pidh, pidl;910 int ret;911 912 ret = regmap_read(regmap, REG_MIDH, &midh);913 if (ret)914 return ret;915 if (midh != 0x7f)916 return -ENODEV;917 918 ret = regmap_read(regmap, REG_MIDL, &midl);919 if (ret)920 return ret;921 if (midl != 0xa2)922 return -ENODEV;923 924 ret = regmap_read(regmap, REG_PIDH, &pidh);925 if (ret)926 return ret;927 if (pidh != 0x77)928 return -ENODEV;929 930 ret = regmap_read(regmap, REG_PIDL, &pidl);931 if (ret)932 return ret;933 if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42))934 return -ENODEV;935 936 return 0;937}938 939static int ov7740_init_controls(struct ov7740 *ov7740)940{941 struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);942 struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;943 int ret;944 945 ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);946 if (ret < 0)947 return ret;948 949 ctrl_hdlr->lock = &ov7740->mutex;950 ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,951 V4L2_CID_AUTO_WHITE_BALANCE,952 0, 1, 1, 1);953 ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,954 V4L2_CID_BLUE_BALANCE,955 0, 0xff, 1, 0x80);956 ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,957 V4L2_CID_RED_BALANCE,958 0, 0xff, 1, 0x80);959 960 ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,961 V4L2_CID_BRIGHTNESS,962 -255, 255, 1, 0);963 ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,964 V4L2_CID_CONTRAST,965 0, 127, 1, 0x20);966 ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,967 V4L2_CID_SATURATION, 0, 256, 1, 0x80);968 ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,969 V4L2_CID_HFLIP, 0, 1, 1, 0);970 ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,971 V4L2_CID_VFLIP, 0, 1, 1, 0);972 973 ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,974 V4L2_CID_GAIN, 0, 1023, 1, 500);975 976 ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,977 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);978 979 ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,980 V4L2_CID_EXPOSURE, 0, 65535, 1, 500);981 982 ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,983 &ov7740_ctrl_ops,984 V4L2_CID_EXPOSURE_AUTO,985 V4L2_EXPOSURE_MANUAL, 0,986 V4L2_EXPOSURE_AUTO);987 988 v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);989 v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);990 v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,991 V4L2_EXPOSURE_MANUAL, true);992 993 if (ctrl_hdlr->error) {994 ret = ctrl_hdlr->error;995 dev_err(&client->dev, "controls initialisation failed (%d)\n",996 ret);997 goto error;998 }999 1000 ret = v4l2_ctrl_handler_setup(ctrl_hdlr);1001 if (ret) {1002 dev_err(&client->dev, "%s control init failed (%d)\n",1003 __func__, ret);1004 goto error;1005 }1006 1007 ov7740->subdev.ctrl_handler = ctrl_hdlr;1008 return 0;1009 1010error:1011 v4l2_ctrl_handler_free(ctrl_hdlr);1012 mutex_destroy(&ov7740->mutex);1013 return ret;1014}1015 1016static void ov7740_free_controls(struct ov7740 *ov7740)1017{1018 v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);1019 mutex_destroy(&ov7740->mutex);1020}1021 1022#define OV7740_MAX_REGISTER 0xff1023static const struct regmap_config ov7740_regmap_config = {1024 .reg_bits = 8,1025 .val_bits = 8,1026 .max_register = OV7740_MAX_REGISTER,1027};1028 1029static int ov7740_probe(struct i2c_client *client)1030{1031 struct ov7740 *ov7740;1032 struct v4l2_subdev *sd;1033 int ret;1034 1035 ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);1036 if (!ov7740)1037 return -ENOMEM;1038 1039 ov7740->xvclk = devm_clk_get(&client->dev, "xvclk");1040 if (IS_ERR(ov7740->xvclk)) {1041 ret = PTR_ERR(ov7740->xvclk);1042 dev_err(&client->dev,1043 "OV7740: fail to get xvclk: %d\n", ret);1044 return ret;1045 }1046 1047 ret = ov7740_probe_dt(client, ov7740);1048 if (ret)1049 return ret;1050 1051 ov7740->regmap = devm_regmap_init_sccb(client, &ov7740_regmap_config);1052 if (IS_ERR(ov7740->regmap)) {1053 ret = PTR_ERR(ov7740->regmap);1054 dev_err(&client->dev, "Failed to allocate register map: %d\n",1055 ret);1056 return ret;1057 }1058 1059 sd = &ov7740->subdev;1060 v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);1061 1062 sd->internal_ops = &ov7740_subdev_internal_ops;1063 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;1064 1065 ov7740->pad.flags = MEDIA_PAD_FL_SOURCE;1066 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;1067 ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad);1068 if (ret)1069 return ret;1070 1071 ret = ov7740_set_power(ov7740, 1);1072 if (ret)1073 return ret;1074 1075 pm_runtime_set_active(&client->dev);1076 pm_runtime_enable(&client->dev);1077 1078 ret = ov7740_detect(ov7740);1079 if (ret)1080 goto error_detect;1081 1082 mutex_init(&ov7740->mutex);1083 1084 ret = ov7740_init_controls(ov7740);1085 if (ret)1086 goto error_init_controls;1087 1088 v4l_info(client, "chip found @ 0x%02x (%s)\n",1089 client->addr << 1, client->adapter->name);1090 1091 ov7740->fmt = &ov7740_formats[0];1092 ov7740->frmsize = &ov7740_framesizes[0];1093 1094 ov7740_get_default_format(sd, &ov7740->format);1095 1096 ret = v4l2_async_register_subdev(sd);1097 if (ret)1098 goto error_async_register;1099 1100 pm_runtime_idle(&client->dev);1101 1102 return 0;1103 1104error_async_register:1105 v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);1106error_init_controls:1107 ov7740_free_controls(ov7740);1108error_detect:1109 pm_runtime_disable(&client->dev);1110 pm_runtime_set_suspended(&client->dev);1111 ov7740_set_power(ov7740, 0);1112 media_entity_cleanup(&ov7740->subdev.entity);1113 1114 return ret;1115}1116 1117static void ov7740_remove(struct i2c_client *client)1118{1119 struct v4l2_subdev *sd = i2c_get_clientdata(client);1120 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);1121 1122 mutex_destroy(&ov7740->mutex);1123 v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);1124 media_entity_cleanup(&ov7740->subdev.entity);1125 v4l2_async_unregister_subdev(sd);1126 ov7740_free_controls(ov7740);1127 1128 pm_runtime_get_sync(&client->dev);1129 pm_runtime_disable(&client->dev);1130 pm_runtime_set_suspended(&client->dev);1131 pm_runtime_put_noidle(&client->dev);1132 1133 ov7740_set_power(ov7740, 0);1134}1135 1136static int __maybe_unused ov7740_runtime_suspend(struct device *dev)1137{1138 struct v4l2_subdev *sd = dev_get_drvdata(dev);1139 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);1140 1141 ov7740_set_power(ov7740, 0);1142 1143 return 0;1144}1145 1146static int __maybe_unused ov7740_runtime_resume(struct device *dev)1147{1148 struct v4l2_subdev *sd = dev_get_drvdata(dev);1149 struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);1150 1151 return ov7740_set_power(ov7740, 1);1152}1153 1154static const struct i2c_device_id ov7740_id[] = {1155 { "ov7740" },1156 { /* sentinel */ }1157};1158MODULE_DEVICE_TABLE(i2c, ov7740_id);1159 1160static const struct dev_pm_ops ov7740_pm_ops = {1161 SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL)1162};1163 1164static const struct of_device_id ov7740_of_match[] = {1165 {.compatible = "ovti,ov7740", },1166 { /* sentinel */ },1167};1168MODULE_DEVICE_TABLE(of, ov7740_of_match);1169 1170static struct i2c_driver ov7740_i2c_driver = {1171 .driver = {1172 .name = "ov7740",1173 .pm = &ov7740_pm_ops,1174 .of_match_table = ov7740_of_match,1175 },1176 .probe = ov7740_probe,1177 .remove = ov7740_remove,1178 .id_table = ov7740_id,1179};1180module_i2c_driver(ov7740_i2c_driver);1181 1182MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor");1183MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");1184MODULE_LICENSE("GPL v2");1185