Hi Sakari, I've submitted V2 yesterday. If possible, can you review that one also ? I'm learning many things from your review comments.
I think in V2, I've addressed most of comments except raw bayer format. For ray bayer format, for now, I intentionally don't support crop since it requires more complexity to meet request from _set_pad_format() while keeping FOV for the resolutions with the same ratio(4:3 or 16:9). Yes, it is hacky but I thought it's OK unless there's a need to support crop. Hm..... I'm thinking drop "bayer order change" since it is not that meaningful. Should I ? For VBLANK, I realized I made wrong comments just after I send it. Yeas, it shouldn't be read-only. So you can see that VBLANK I added in V2 is NOT read-only. Thanks, Hyungwoo > Hi Hyungwoo, > > On Wed, May 24, 2017 at 11:13:50PM +0000, Yang, Hyungwoo wrote: > ... > > > > +static inline int ov13858_write_reg_list(struct ov13858 *ov13858, > > > > > > I'd drop inline. > > > > if it's not mandatory for upstream, I prefer to keep inline for people > > who want to port this with a not-good-compiler. Is it mandatory ? > > I don't think you'd really lose anything if the compiler didn't inline it. > It's a non-issue anyway. > > ... > > > > > +/* > > > > + * Change the bayer order to meet the requested one. > > > > + */ > > > > +static int ov13858_apply_bayer_order(struct ov13858 *ov13858) { > > > > + int ret; > > > > + > > > > + switch (ov13858->cur_bayer_format) { > > > > + case MEDIA_BUS_FMT_SGRBG10_1X10: > > > > + break; > > > > + case MEDIA_BUS_FMT_SRGGB10_1X10: > > > > + return ov13858_increase_offset(ov13858, > > > > OV13858_REG_H_OFFSET); > > > > + case MEDIA_BUS_FMT_SGBRG10_1X10: > > > > + ret = ov13858_increase_offset(ov13858, > > > > OV13858_REG_H_OFFSET); > > > > > > The bayer pixel order is defined by cropping the pixel array. If the > > > sensor can do that, you should implement support for the crop selection > > > rectangle instead. > > > > Sorry, I'm new to imaging world but, as you can see, bayer order in > > this sensor IS DEFINED by both cropping and offset(where you start to > > read). Is there a strict (implicit or explicit) rule or specific > > reason that we should use only crop to apply expected bayer order, > > even though the bayer order in the sensor is defined by both crop and > > offset ? > > > > Anyway, I changed H_/V_OFFSET(0x3810, 0x3812) to > > H_/V_CROP_START(0x3800, > > 0x3802) with no changes in initial values. > > The CROP selection rectangle is the interface to configure crop an area from > the parent rectangle (NATIVE_SIZE in this case). Using the format to change > cropping in pre-defined ways is quite hackish. > > ... > > > > > +/* Exposure control */ > > > > +static int ov13858_update_exposure(struct ov13858 *ov13858, > > > > + struct v4l2_ctrl *ctrl) > > > > +{ > > > > + int ret; > > > > + u32 exposure, new_vts = 0; > > > > + > > > > + exposure = ctrl->val; > > > > + if (exposure > ov13858->cur_mode->vts - 8) > > > > + new_vts = exposure + 8; > > > > + else > > > > + new_vts = ov13858->cur_mode->vts; > > > > > > Instead of changing the vertical blanking interval implicitly, could > > > you do it explicitly though the VBLANK control instead? > > > > > > As you do already control the vertical sync and provide the pixel > > > rate control, how about adding a HBLANK control as well? I suppose > > > it could be added later on as well. And presumably will be read only. > > > > I'll introduce VBLANK control with READ ONLY and the value of the > > control will be updated here. > > HBLANK would be read-only since the register list that you have might contain > dependencies to the horizontal blanking so you can't change that. > The VBLANK control, instead, should not be read-only to allow controlling the > frame rate and also controlling the exposure without affecting the frame rate. > > > > > > > > > > + > > > > + ret = ov13858_group_hold_start(ov13858, 0); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + ret = ov13858_write_reg(ov13858, OV13858_REG_VTS, > > > > + OV13858_REG_VALUE_16BIT, new_vts); > > > > + if (ret) > > > > + return ret; > > > > + > > > > > > If you want group hold for that, too, we need a new callback (or > > > two) for the control handler I believe. > > > > I don't understand wht this means. Can you give me detail ? > > The V4L2 control framework calls the s_ctrl() callback in the driver to set > control values. The driver however doesn't know how many controls there will > be to set or when the last control of the set would be conveyed to the > driver. To use the grouped parameter hold meaningfully this information is > needed. > > ... > > > > > + /* Values of V4L2 controls will be applied only when power is > > > > up */ > > > > + if (atomic_read(&client->dev.power.usage_count) == 0) > > > > > > I wonder if using pm_runtime_active() would work for this. Checking > > > the usage_count directly does not look like something a driver > > > should be doing. > > > > Agree, I really wanted to use any helper(accesor) method for this but > > when I checked the pm_runtime_active() it wasn't good enough. Anyway I > > just found better one for this case. I'll not use using usage_count > > and instread of using pm_runtime_get_sync, I'll use > > pm_runtime_get_if_in_use() > > Ah, that seems much better indeed! > > > > > > > > > > + return 0; > > > > + > > > > + ret = pm_runtime_get_sync(&client->dev); > > > > + if (ret < 0) { > > > > + pm_runtime_put_noidle(&client->dev); > > > > + return ret; > > > > + } > > > > + > > > > + ret = 0; > > > > + switch (ctrl->id) { > > > > + case V4L2_CID_ANALOGUE_GAIN: > > > > + ret = ov13858_update_analog_gain(ov13858, ctrl); > > > > + break; > > > > + case V4L2_CID_EXPOSURE: > > > > + ret = ov13858_update_exposure(ov13858, ctrl); > > > > + break; > > > > + default: > > > > + dev_info(&client->dev, > > > > + "ctrl(id:0x%x,val:0x%x) is not handled\n", > > > > + ctrl->id, ctrl->val); > > > > + break; > > > > + }; > > > > + > > > > + pm_runtime_put(&client->dev); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static const struct v4l2_ctrl_ops ov13858_ctrl_ops = { > > > > + .s_ctrl = ov13858_set_ctrl, > > > > +}; > > > > + > > > > +/* Initialize control handlers */ static int > > > > +ov13858_init_controls(struct ov13858 *ov13858) { > > > > + struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); > > > > + struct v4l2_ctrl_handler *ctrl_hdlr; > > > > + int ret; > > > > + > > > > + ctrl_hdlr = &ov13858->ctrl_handler; > > > > + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 4); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + ctrl_hdlr->lock = &ov13858->mutex; > > > > + ov13858->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, > > > > + &ov13858_ctrl_ops, > > > > + V4L2_CID_LINK_FREQ, > > > > + OV13858_NUM_OF_LINK_FREQS - 1, > > > > + 0, > > > > + link_freq_menu_items); > > > > + ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > > > + > > > > + /* By default, PIXEL_RATE is read only */ > > > > + ov13858->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, > > > > &ov13858_ctrl_ops, > > > > + V4L2_CID_PIXEL_RATE, 0, > > > > + OV13858_GET_PIXEL_RATE(0), 1, > > > > + OV13858_GET_PIXEL_RATE(0)); > > > > + > > > > + v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, > > > > V4L2_CID_ANALOGUE_GAIN, > > > > + OV13858_ANA_GAIN_MIN, OV13858_ANA_GAIN_MAX, > > > > + OV13858_ANA_GAIN_STEP, > > > > OV13858_ANA_GAIN_DEFAULT); > > > > + > > > > + v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, > > > > V4L2_CID_EXPOSURE, > > > > + OV13858_EXP_GAIN_MIN, OV13858_EXP_GAIN_MAX, > > > > + OV13858_EXP_GAIN_STEP, > > > > OV13858_EXP_GAIN_DEFAULT); > > > > > > Are the minimum and maximum values dependent on the register list chosen? > > > > We are going to use the same HTS for all reolutions. > > The supports 4 lines as minimum and MAX_VTS - 8 as maximum. > > > > > > > > > + if (ctrl_hdlr->error) { > > > > + ret = ctrl_hdlr->error; > > > > + dev_err(&client->dev, "%s control init failed (%d)\n", > > > > + __func__, ret); > > > > + goto error; > > > > + } > > > > + > > > > + ov13858->sd.ctrl_handler = ctrl_hdlr; > > > > + > > > > + return 0; > > > > + > > > > +error: > > > > + v4l2_ctrl_handler_free(ctrl_hdlr); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static void ov13858_update_pad_format(struct ov13858 *ov13858, > > > > + const struct ov13858_mode *mode, > > > > + struct v4l2_subdev_format *fmt) { > > > > + fmt->format.width = mode->width; > > > > + fmt->format.height = mode->height; > > > > + fmt->format.code = ov13858->cur_bayer_format; > > > > + fmt->format.field = V4L2_FIELD_NONE; } > > > > + > > > > +static int ov13858_do_get_pad_format(struct ov13858 *ov13858, > > > > + struct v4l2_subdev_pad_config *cfg, > > > > + struct v4l2_subdev_format *fmt) { > > > > + struct v4l2_mbus_framefmt *framefmt; > > > > + struct v4l2_subdev *sd = &ov13858->sd; > > > > + > > > > + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { > > > > + framefmt = v4l2_subdev_get_try_format(sd, cfg, > > > > fmt->pad); > > > > + fmt->format = *framefmt; > > > > > > You could write this as : > > > > > > fmt->format = *v4l2_subdev_get_try_format(&ov13858->sd, cfg, > > > fmt->fmt->pad); > > > > > > > Personally I don't like this since I believe readablity of this kind > > of code is not good. If there's no stric rule for this, I want to keep > > this since believe there's no difference in generated code. > > I don't think the extra local variable assigned and used once really helps, > but ok for me. > > -- > Regards, > > Sakari Ailus > e-mail: sakari.ai...@iki.fi XMPP: sai...@retiisi.org.uk >