/* si4713_g_ctrl - get the value of a control */
static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct si4713_device *sdev = to_si4713_device(sd);
	int rval = 0;

	if (!sdev)
		return -ENODEV;

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE,
						&sdev->mute);

		if (rval < 0)
			goto unlock;
	}

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
		ctrl->value = get_mute(sdev->mute);
		break;
	}

unlock:
	mutex_unlock(&sdev->mutex);
	return rval;
}
/* si4713_g_modulator - get modulator attributes */
static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
{
	struct si4713_device *sdev = to_si4713_device(sd);
	int rval = 0;

	if (!sdev) {
		rval = -ENODEV;
		goto exit;
	}

	if (vm->index > 0) {
		rval = -EINVAL;
		goto exit;
	}

	strncpy(vm->name, "FM Modulator", 32);
	vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
						V4L2_TUNER_CAP_RDS;

	/* Report current frequency range limits */
	vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
	vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH);

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		u32 comp_en = 0;

		rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE,
						&comp_en);
		if (rval < 0)
			goto unlock;

		sdev->stereo = get_status_bit(comp_en, 1, 1 << 1);
		sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2);
	}

	/* Report current audio mode: mono or stereo */
	if (sdev->stereo)
		vm->txsubchans = V4L2_TUNER_SUB_STEREO;
	else
		vm->txsubchans = V4L2_TUNER_SUB_MONO;

	/* Report rds feature status */
	if (sdev->rds_info.enabled)
		vm->txsubchans |= V4L2_TUNER_SUB_RDS;
	else
		vm->txsubchans &= ~V4L2_TUNER_SUB_RDS;

unlock:
	mutex_unlock(&sdev->mutex);
exit:
	return rval;
}
/* si4713_s_modulator - set modulator attributes */
static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
{
	struct si4713_device *sdev = to_si4713_device(sd);
	int rval = 0;
	u16 stereo, rds;
	u32 p;

	if (!sdev)
		return -ENODEV;

	if (vm->index > 0)
		return -EINVAL;

	/* Set audio mode: mono or stereo */
	if (vm->txsubchans & V4L2_TUNER_SUB_STEREO)
		stereo = 1;
	else if (vm->txsubchans & V4L2_TUNER_SUB_MONO)
		stereo = 0;
	else
		return -EINVAL;

	rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS);

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		rval = si4713_read_property(sdev,
						SI4713_TX_COMPONENT_ENABLE, &p);
		if (rval < 0)
			goto unlock;

		p = set_bits(p, stereo, 1, 1 << 1);
		p = set_bits(p, rds, 2, 1 << 2);

		rval = si4713_write_property(sdev,
						SI4713_TX_COMPONENT_ENABLE, p);
		if (rval < 0)
			goto unlock;
	}

	sdev->stereo = stereo;
	sdev->rds_info.enabled = rds;

unlock:
	mutex_unlock(&sdev->mutex);
	return rval;
}
static int si4713_read_econtrol_integers(struct si4713_device *sdev,
				struct v4l2_ext_control *control)
{
	s32 rval;
	u32 *shadow = NULL, val = 0;
	s32 bit = 0, mask = 0;
	u16 property = 0;
	int mul = 0;
	unsigned long *table = NULL;
	int size = 0;

	rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
			&mask, &property, &mul, &table, &size);
	if (rval < 0)
		goto exit;

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		rval = si4713_read_property(sdev, property, &val);
		if (rval < 0)
			goto unlock;

		/* Keep negative values for threshold */
		if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD)
			*shadow = (s16)val;
		else if (mask)
			*shadow = get_status_bit(val, bit, mask);
		else if (mul)
			*shadow = val * mul;
		else
			*shadow = dev_to_usecs(val, table, size);
	}

	control->value = *shadow;

unlock:
	mutex_unlock(&sdev->mutex);
exit:
	return rval;
}
示例#5
0
/* si4713_s_ctrl - set the value of a control */
static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct si4713_device *sdev =
		container_of(ctrl->handler, struct si4713_device, ctrl_handler);
	u32 val = 0;
	s32 bit = 0, mask = 0;
	u16 property = 0;
	int mul = 0;
	unsigned long *table = NULL;
	int size = 0;
	bool force = false;
	int c;
	int ret = 0;

	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
		return -EINVAL;
	if (ctrl->is_new) {
		if (ctrl->val) {
			ret = si4713_set_mute(sdev, ctrl->val);
			if (!ret)
				ret = si4713_set_power_state(sdev, POWER_DOWN);
			return ret;
		}
		ret = si4713_set_power_state(sdev, POWER_UP);
		if (!ret)
			ret = si4713_set_mute(sdev, ctrl->val);
		if (!ret)
			ret = si4713_setup(sdev);
		if (ret)
			return ret;
		force = true;
	}

	if (!sdev->power_state)
		return 0;

	for (c = 1; !ret && c < ctrl->ncontrols; c++) {
		ctrl = ctrl->cluster[c];

		if (!force && !ctrl->is_new)
			continue;

		switch (ctrl->id) {
		case V4L2_CID_RDS_TX_PS_NAME:
			ret = si4713_set_rds_ps_name(sdev, ctrl->string);
			break;

		case V4L2_CID_RDS_TX_RADIO_TEXT:
			ret = si4713_set_rds_radio_text(sdev, ctrl->string);
			break;

		case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
			/* don't handle this control if we force setting all
			 * controls since in that case it will be handled by
			 * V4L2_CID_TUNE_POWER_LEVEL. */
			if (force)
				break;
			/* fall through */
		case V4L2_CID_TUNE_POWER_LEVEL:
			ret = si4713_tx_tune_power(sdev,
				sdev->tune_pwr_level->val, sdev->tune_ant_cap->val);
			if (!ret) {
				/* Make sure we don't set this twice */
				sdev->tune_ant_cap->is_new = false;
				sdev->tune_pwr_level->is_new = false;
			}
			break;

		default:
			ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
					&mask, &property, &mul, &table, &size);
			if (ret < 0)
				break;

			val = ctrl->val;
			if (mul) {
				val = val / mul;
			} else if (table) {
				ret = usecs_to_dev(val, table, size);
				if (ret < 0)
					break;
				val = ret;
				ret = 0;
			}

			if (mask) {
				ret = si4713_read_property(sdev, property, &val);
				if (ret < 0)
					break;
				val = set_bits(val, ctrl->val, bit, mask);
			}

			ret = si4713_write_property(sdev, property, val);
			if (ret < 0)
				break;
			if (mask)
				val = ctrl->val;
			break;
		}
	}

	return ret;
}
static int si4713_write_econtrol_integers(struct si4713_device *sdev,
					struct v4l2_ext_control *control)
{
	s32 rval;
	u32 *shadow = NULL, val = 0;
	s32 bit = 0, mask = 0;
	u16 property = 0;
	int mul = 0;
	unsigned long *table = NULL;
	int size = 0;

	rval = validate_range(&sdev->sd, control);
	if (rval < 0)
		goto exit;

	rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
			&mask, &property, &mul, &table, &size);
	if (rval < 0)
		goto exit;

	val = control->value;
	if (mul) {
		val = control->value / mul;
	} else if (table) {
		rval = usecs_to_dev(control->value, table, size);
		if (rval < 0)
			goto exit;
		val = rval;
		rval = 0;
	}

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		if (mask) {
			rval = si4713_read_property(sdev, property, &val);
			if (rval < 0)
				goto unlock;
			val = set_bits(val, control->value, bit, mask);
		}

		rval = si4713_write_property(sdev, property, val);
		if (rval < 0)
			goto unlock;
		if (mask)
			val = control->value;
	}

	if (mul) {
		*shadow = val * mul;
	} else if (table) {
		rval = dev_to_usecs(val, table, size);
		if (rval < 0)
			goto unlock;
		*shadow = rval;
		rval = 0;
	} else {
		*shadow = val;
	}

unlock:
	mutex_unlock(&sdev->mutex);
exit:
	return rval;
}