static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
{
	struct atomisp_device *isp = asd->isp;
	struct v4l2_ctrl *ctrl = asd->run_mode;
	struct v4l2_ctrl *c;
	struct v4l2_streamparm p = {0};
	int modes[] = { CI_MODE_NONE,
			CI_MODE_VIDEO,
			CI_MODE_STILL_CAPTURE,
			CI_MODE_CONTINUOUS,
			CI_MODE_PREVIEW };
	s32 mode;

	if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
	    asd->continuous_mode->val)
		mode = ATOMISP_RUN_MODE_PREVIEW;
	else
		mode = ctrl->val;

	c = v4l2_ctrl_find(
		isp->inputs[asd->input_curr].camera->ctrl_handler,
		V4L2_CID_RUN_MODE);

	if (c)
		return v4l2_ctrl_s_ctrl(c, mode);

	/* Fall back to obsolete s_parm */
	p.parm.capture.capturemode = modes[mode];

	return v4l2_subdev_call(
		isp->inputs[asd->input_curr].camera, video, s_parm, &p);
}
Ejemplo n.º 2
0
static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
	struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
	struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
	int ret = 0;

	if (!v4l2_fh_is_singular(&fh->vfh))
		return 0;

	if (led_cdev) {
		mutex_lock(&led_cdev->led_access);

		if (v4l2_flash->ctrls[STROBE_SOURCE])
			ret = v4l2_ctrl_s_ctrl(
				v4l2_flash->ctrls[STROBE_SOURCE],
				V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
		led_sysfs_enable(led_cdev);

		mutex_unlock(&led_cdev->led_access);
	}

	if (led_cdev_ind) {
		mutex_lock(&led_cdev_ind->led_access);
		led_sysfs_enable(led_cdev_ind);
		mutex_unlock(&led_cdev_ind->led_access);
	}

	return ret;
}
Ejemplo n.º 3
0
/**
 * m5mols_do_scenemode() - Change current scenemode
 * @mode:	Desired mode of the scenemode
 *
 * WARNING: The execution order is important. Do not change the order.
 */
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
{
	struct v4l2_subdev *sd = &info->sd;
	struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
	int ret;

	if (mode > REG_SCENE_CANDLE)
		return -EINVAL;

	ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
	if (!ret)
		ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
	if (!ret)
		ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
	if (!ret)
		ret = m5mols_write(sd, AE_MODE, scenemode.metering);
	if (!ret)
		ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
	if (!ret)
		ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
	if (!ret)
		ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
	if (!ret)
		ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
	if (!ret)
		ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
	if (!ret)
		ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
	if (!ret)
		ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
	if (!ret && is_available_af(info))
		ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
	if (!ret && is_available_af(info))
		ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
	if (!ret)
		ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
	if (!ret)
		ret = m5mols_write(sd, AE_ISO, scenemode.iso);
	if (!ret)
		ret = m5mols_set_mode(info, REG_CAPTURE);
	if (!ret)
		ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
	if (!ret)
		ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
	if (!ret)
		ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
	if (!ret)
		ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
	if (!ret)
		ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
	if (!ret)
		ret = m5mols_set_mode(info, REG_MONITOR);

	return ret;
}
Ejemplo n.º 4
0
static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx);

	switch (ctrl->id) {
	case VIVID_CID_RADIO_TX_RDS_BLOCKIO:
		dev->radio_tx_rds_controls = ctrl->val;
		dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
		if (!dev->radio_tx_rds_controls)
			dev->radio_tx_caps |= V4L2_CAP_READWRITE;
		break;
	case V4L2_CID_RDS_TX_PTY:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val);
		break;
	case V4L2_CID_RDS_TX_PS_NAME:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char);
		break;
	case V4L2_CID_RDS_TX_RADIO_TEXT:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char);
		break;
	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val);
		break;
	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val);
		break;
	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
		if (dev->radio_rx_rds_controls)
			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val);
		break;
	}
	return 0;
}
Ejemplo n.º 5
0
static void ivtv_dualwatch(struct ivtv *itv)
{
	struct v4l2_tuner vt;
	u32 new_stereo_mode;
	const u32 dual = 0x02;

	new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
	memset(&vt, 0, sizeof(vt));
	ivtv_call_all(itv, tuner, g_tuner, &vt);
	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
		new_stereo_mode = dual;

	if (new_stereo_mode == itv->dualwatch_stereo_mode)
		return;

	IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
			   itv->dualwatch_stereo_mode, new_stereo_mode);
	if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode))
		IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
Ejemplo n.º 6
0
static void cx18_dualwatch(struct cx18 *cx)
{
	struct v4l2_tuner vt;
	u32 new_stereo_mode;
	const u32 dual = 0x0200;

	new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
	memset(&vt, 0, sizeof(vt));
	cx18_call_all(cx, tuner, g_tuner, &vt);
	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
			(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
		new_stereo_mode = dual;

	if (new_stereo_mode == cx->dualwatch_stereo_mode)
		return;

	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
			   cx->dualwatch_stereo_mode, new_stereo_mode);
	if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
		CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
Ejemplo n.º 7
0
/* auto gain and exposure algorithm based on the knee algorithm described here:
   http://ytse.tricolour.net/docs/LowLightOptimization.html

   Returns 0 if no changes were made, 1 if the gain and or exposure settings
   where changed. */
int gspca_expo_autogain(
			struct gspca_dev *gspca_dev,
			int avg_lum,
			int desired_avg_lum,
			int deadzone,
			int gain_knee,
			int exposure_knee)
{
	s32 gain, orig_gain, exposure, orig_exposure;
	int i, steps, retval = 0;

	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
	        return 0;

	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);

	/* If we are of a multiple of deadzone, do multiple steps to reach the
	   desired lumination fast (with the risc of a slight overshoot) */
	steps = abs(desired_avg_lum - avg_lum) / deadzone;

	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
		avg_lum, desired_avg_lum, steps);

	for (i = 0; i < steps; i++) {
		if (avg_lum > desired_avg_lum) {
			if (gain > gain_knee)
				gain--;
			else if (exposure > exposure_knee)
				exposure--;
			else if (gain > gspca_dev->gain->default_value)
				gain--;
			else if (exposure > gspca_dev->exposure->minimum)
				exposure--;
			else if (gain > gspca_dev->gain->minimum)
				gain--;
			else
				break;
		} else {
			if (gain < gspca_dev->gain->default_value)
				gain++;
			else if (exposure < exposure_knee)
				exposure++;
			else if (gain < gain_knee)
				gain++;
			else if (exposure < gspca_dev->exposure->maximum)
				exposure++;
			else if (gain < gspca_dev->gain->maximum)
				gain++;
			else
				break;
		}
	}

	if (gain != orig_gain) {
	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
		retval = 1;
	}
	if (exposure != orig_exposure) {
	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
		retval = 1;
	}

	if (retval)
		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
			gain, exposure);
	return retval;
}
Ejemplo n.º 8
0
/* Autogain + exposure algorithm for cameras with a coarse exposure control
   (usually this means we can only control the clockdiv to change exposure)
   As changing the clockdiv so that the fps drops from 30 to 15 fps for
   example, will lead to a huge exposure change (it effectively doubles),
   this algorithm normally tries to only adjust the gain (between 40 and
   80 %) and if that does not help, only then changes exposure. This leads
   to a much more stable image then using the knee algorithm which at
   certain points of the knee graph will only try to adjust exposure,
   which leads to oscilating as one exposure step is huge.

   Returns 0 if no changes were made, 1 if the gain and or exposure settings
   where changed. */
int gspca_coarse_grained_expo_autogain(
			struct gspca_dev *gspca_dev,
			int avg_lum,
			int desired_avg_lum,
			int deadzone)
{
	s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure;
	int steps, retval = 0;

	if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
	        return 0;

	orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
	orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);

	gain_low  = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
		    5 * 2 + gspca_dev->gain->minimum;
	gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
		    5 * 4 + gspca_dev->gain->minimum;

	/* If we are of a multiple of deadzone, do multiple steps to reach the
	   desired lumination fast (with the risc of a slight overshoot) */
	steps = (desired_avg_lum - avg_lum) / deadzone;

	PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
		avg_lum, desired_avg_lum, steps);

	if ((gain + steps) > gain_high &&
	    exposure < gspca_dev->exposure->maximum) {
		gain = gain_high;
		gspca_dev->exp_too_low_cnt++;
		gspca_dev->exp_too_high_cnt = 0;
	} else if ((gain + steps) < gain_low &&
		   exposure > gspca_dev->exposure->minimum) {
		gain = gain_low;
		gspca_dev->exp_too_high_cnt++;
		gspca_dev->exp_too_low_cnt = 0;
	} else {
		gain += steps;
		if (gain > gspca_dev->gain->maximum)
			gain = gspca_dev->gain->maximum;
		else if (gain < gspca_dev->gain->minimum)
			gain = gspca_dev->gain->minimum;
		gspca_dev->exp_too_high_cnt = 0;
		gspca_dev->exp_too_low_cnt = 0;
	}

	if (gspca_dev->exp_too_high_cnt > 3) {
		exposure--;
		gspca_dev->exp_too_high_cnt = 0;
	} else if (gspca_dev->exp_too_low_cnt > 3) {
		exposure++;
		gspca_dev->exp_too_low_cnt = 0;
	}

	if (gain != orig_gain) {
	        v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
		retval = 1;
	}
	if (exposure != orig_exposure) {
	        v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
		retval = 1;
	}

	if (retval)
		PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
			gain, exposure);
	return retval;
}
static int ap1302_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct ap1302_device *dev;
	int ret;
	unsigned int i;

	dev_info(&client->dev, "ap1302 probe called.\n");

	/* allocate device & init sub device */
	dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		dev_err(&client->dev, "%s: out of memory\n", __func__);
		return -ENOMEM;
	}

	mutex_init(&dev->input_lock);

	v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops);

	ret = ap1302_request_firmware(&(dev->sd));
	if (ret) {
		dev_err(&client->dev, "Cannot request ap1302 firmware.\n");
		goto out_free;
	}

	dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config);
	if (IS_ERR(dev->regmap16)) {
		ret = PTR_ERR(dev->regmap16);
		dev_err(&client->dev,
			"Failed to allocate 16bit register map: %d\n", ret);
		return ret;
	}

	dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config);
	if (IS_ERR(dev->regmap32)) {
		ret = PTR_ERR(dev->regmap32);
		dev_err(&client->dev,
			"Failed to allocate 32bit register map: %d\n", ret);
		return ret;
	}

	if (client->dev.platform_data) {
		ret = ap1302_s_config(&dev->sd, client->dev.platform_data);
		if (ret)
			goto out_free;
	}

	dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	dev->pad.flags = MEDIA_PAD_FL_SOURCE;
	dev->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;

	dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res);
	dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res;
	dev->cntx_res[CONTEXT_SNAPSHOT].res_num =
		ARRAY_SIZE(ap1302_snapshot_res);
	dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res;
	dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res);
	dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res;

	ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls));
	if (ret) {
		ap1302_remove(client);
		return ret;
	}

	for (i = 0; i < ARRAY_SIZE(ctrls); i++)
		v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);

	if (dev->ctrl_handler.error) {
		ap1302_remove(client);
		return dev->ctrl_handler.error;
	}

	/* Use same lock for controls as for everything else. */
	dev->ctrl_handler.lock = &dev->input_lock;
	dev->sd.ctrl_handler = &dev->ctrl_handler;
	v4l2_ctrl_handler_setup(&dev->ctrl_handler);

	dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE);
	v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW);

	ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
	if (ret)
		ap1302_remove(client);
	return ret;
out_free:
	v4l2_device_unregister_subdev(&dev->sd);
	return ret;
}