On 01/28/15 10:17, Laurent Pinchart wrote: > Expose the module as two controls, one for the 3x3 multiplier matrix and > one for the 3x1 offset vector. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> > --- > drivers/staging/media/omap4iss/iss_ipipe.c | 129 ++++++++++++++++++++++++++++- > drivers/staging/media/omap4iss/iss_ipipe.h | 17 ++++ > 2 files changed, 144 insertions(+), 2 deletions(-) > > diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c > index 73b165e..624c5d2 100644 > --- a/drivers/staging/media/omap4iss/iss_ipipe.c > +++ b/drivers/staging/media/omap4iss/iss_ipipe.c > @@ -119,6 +119,105 @@ static void ipipe_configure(struct iss_ipipe_device *ipipe) > } > > /* ----------------------------------------------------------------------------- > + * V4L2 controls > + */ > + > +#define OMAP4ISS_IPIPE_CID_BASE (V4L2_CID_USER_BASE | 0xf000) Private control ranges should be reserved in uapi/linux/v4l2-controls.h. See e.g. V4L2_CID_USER_SAA7134_BASE. > +#define OMAP4ISS_IPIPE_CID_RGB2RGB_MULT (OMAP4ISS_IPIPE_CID_BASE + 0) > +#define OMAP4ISS_IPIPE_CID_RGB2RGB_OFFSET (OMAP4ISS_IPIPE_CID_BASE + 1) Can you give some information how the values are interpreted? That should be documented anyway, but I would like to see how this compares to the adv drivers. This is something that we might want to make available as standard controls. I will have to think about that a bit more. Regards, Hans > + > +/* > + * ipipe_s_ctrl - Handle set control subdev method > + * @ctrl: pointer to v4l2 control structure > + */ > +static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl) > +{ > + struct iss_ipipe_device *ipipe = > + container_of(ctrl->handler, struct iss_ipipe_device, ctrls); > + struct iss_device *iss = to_iss_device(ipipe); > + unsigned int i; > + > + mutex_lock(&ipipe->lock); > + > + if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) > + goto done; > + > + switch (ctrl->id) { > + case OMAP4ISS_IPIPE_CID_RGB2RGB_MULT: > + case OMAP4ISS_IPIPE_CID_RGB2RGB_OFFSET: > + ctrl = ipipe->rgb2rgb_mult; > + for (i = 0; i < ctrl->elems; ++i) > + iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, > + IPIPE_RGB1_MUL_RR + 4 * i, > + ctrl->p_new.p_s16[i]); > + > + ctrl = ipipe->rgb2rgb_offset; > + for (i = 0; i < ctrl->elems; ++i) > + iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, > + IPIPE_RGB1_OFT_OR + 4 * i, > + ctrl->p_new.p_s16[i]); > + break; > + } > + > +done: > + mutex_unlock(&ipipe->lock); > + return 0; > +} > + > +static const struct v4l2_ctrl_ops ipipe_ctrl_ops = { > + .s_ctrl = ipipe_s_ctrl, > +}; > + > +static void ipipe_ctrl_type_init(const struct v4l2_ctrl *ctrl, > + union v4l2_ctrl_ptr ptr) > +{ > + unsigned int i; > + > + switch (ctrl->id) { > + case OMAP4ISS_IPIPE_CID_RGB2RGB_MULT: > + /* > + * Initialize the diagonal to 1.0 and all other elements to > + * 0.0. > + */ > + for (i = 0; i < ctrl->elems; ++i) > + ptr.p_s16[i] = (i % 4) ? 0 : 256; > + break; > + } > +} > + > +static const struct v4l2_ctrl_type_ops ipipe_ctrl_type_ops = { > + .equal = v4l2_ctrl_type_std_equal, > + .init = ipipe_ctrl_type_init, > + .log = v4l2_ctrl_type_std_log, > + .validate = v4l2_ctrl_type_std_validate, > +}; > + > +static const struct v4l2_ctrl_config ipipe_ctrls[] = { > + { > + .ops = &ipipe_ctrl_ops, > + .type_ops = &ipipe_ctrl_type_ops, > + .id = OMAP4ISS_IPIPE_CID_RGB2RGB_MULT, > + .name = "RGB2RGB Multiplier", > + .type = V4L2_CTRL_TYPE_S16, > + .def = 0, > + .min = -2048, > + .max = 2047, > + .step = 1, > + .dims = { 3, 3 }, > + }, { > + .ops = &ipipe_ctrl_ops, > + .id = OMAP4ISS_IPIPE_CID_RGB2RGB_OFFSET, > + .name = "RGB2RGB Offset", > + .type = V4L2_CTRL_TYPE_S16, > + .def = 0, > + .min = -4096, > + .max = 4095, > + .step = 1, > + .dims = { 3 }, > + }, > +}; > + > +/* ----------------------------------------------------------------------------- > * V4L2 subdev operations > */ > > @@ -133,9 +232,11 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) > struct iss_device *iss = to_iss_device(ipipe); > int ret = 0; > > + mutex_lock(&ipipe->lock); > + > if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) { > if (enable == ISS_PIPELINE_STREAM_STOPPED) > - return 0; > + goto done; > > omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); > > @@ -161,7 +262,7 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) > > case ISS_PIPELINE_STREAM_STOPPED: > if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) > - return 0; > + goto done; > if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait, > &ipipe->stopping)) > ret = -ETIMEDOUT; > @@ -172,6 +273,13 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) > } > > ipipe->state = enable; > + > +done: > + mutex_unlock(&ipipe->lock); > + > + if (enable == ISS_PIPELINE_STREAM_CONTINUOUS) > + v4l2_ctrl_handler_setup(ipipe->subdev.ctrl_handler); > + > return ret; > } > > @@ -501,6 +609,20 @@ static int ipipe_init_entities(struct iss_ipipe_device *ipipe) > v4l2_set_subdevdata(sd, ipipe); > sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; > > + v4l2_ctrl_handler_init(&ipipe->ctrls, 2); > + > + ipipe->rgb2rgb_mult = v4l2_ctrl_new_custom(&ipipe->ctrls, > + &ipipe_ctrls[0], NULL); > + ipipe->rgb2rgb_offset = v4l2_ctrl_new_custom(&ipipe->ctrls, > + &ipipe_ctrls[1], NULL); > + > + if (ipipe->ctrls.error) > + return ipipe->ctrls.error; > + > + v4l2_ctrl_cluster(2, &ipipe->rgb2rgb_mult); > + > + sd->ctrl_handler = &ipipe->ctrls; > + > pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; > pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; > > @@ -554,6 +676,7 @@ int omap4iss_ipipe_init(struct iss_device *iss) > > ipipe->state = ISS_PIPELINE_STREAM_STOPPED; > init_waitqueue_head(&ipipe->wait); > + mutex_init(&ipipe->lock); > > return ipipe_init_entities(ipipe); > } > @@ -566,5 +689,7 @@ void omap4iss_ipipe_cleanup(struct iss_device *iss) > { > struct iss_ipipe_device *ipipe = &iss->ipipe; > > + v4l2_ctrl_handler_free(&ipipe->ctrls); > media_entity_cleanup(&ipipe->subdev.entity); > + mutex_destroy(&ipipe->lock); > } > diff --git a/drivers/staging/media/omap4iss/iss_ipipe.h b/drivers/staging/media/omap4iss/iss_ipipe.h > index c22d904..7684271 100644 > --- a/drivers/staging/media/omap4iss/iss_ipipe.h > +++ b/drivers/staging/media/omap4iss/iss_ipipe.h > @@ -14,6 +14,10 @@ > #ifndef OMAP4_ISS_IPIPE_H > #define OMAP4_ISS_IPIPE_H > > +#include <linux/mutex.h> > + > +#include <media/v4l2-ctrls.h> > + > #include "iss_video.h" > > enum ipipe_input_entity { > @@ -34,9 +38,13 @@ enum ipipe_input_entity { > * @subdev: V4L2 subdevice > * @pads: Sink and source media entity pads > * @formats: Active video formats > + * @ctrls: Control handler > + * @rgb2rgb_mult: RGB to RGB matrix multiplier control > + * @rgb2rgb_offset: RGB to RGB matrix offset control > * @input: Active input > * @output: Active outputs > * @error: A hardware error occurred during capture > + * @lock: Protects the state field > * @state: Streaming state > * @wait: Wait queue used to stop the module > * @stopping: Stopping state > @@ -46,10 +54,19 @@ struct iss_ipipe_device { > struct media_pad pads[IPIPE_PADS_NUM]; > struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM]; > > + struct v4l2_ctrl_handler ctrls; > + struct { > + /* RGB2RGB cluster */ > + struct v4l2_ctrl *rgb2rgb_mult; > + struct v4l2_ctrl *rgb2rgb_offset; > + }; > + > enum ipipe_input_entity input; > unsigned int output; > unsigned int error; > > + struct mutex lock; > + bool streaming; > enum iss_pipeline_stream_state state; > wait_queue_head_t wait; > atomic_t stopping; > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html