static int da7280_haptics_upload_effect()

in misc/da7280.c [505:657]


static int da7280_haptics_upload_effect(struct input_dev *dev,
					struct ff_effect *effect,
					struct ff_effect *old)
{
	struct da7280_haptic *haptics = input_get_drvdata(dev);
	s16 data[DA7280_SNP_MEM_SIZE] = { 0 };
	unsigned int val;
	int tmp, i, num;
	int error;

	/* The effect should be uploaded when haptic is not working */
	if (haptics->active)
		return -EBUSY;

	switch (effect->type) {
	/* DRO/PWM modes support this type */
	case FF_CONSTANT:
		haptics->op_mode = haptics->const_op_mode;
		if (haptics->op_mode == DA7280_DRO_MODE) {
			tmp = effect->u.constant.level * 254;
			haptics->level = tmp / 0x7FFF;
			break;
		}

		haptics->gain =	effect->u.constant.level <= 0 ?
					0 : effect->u.constant.level;
		break;

	/* RTWM/ETWM modes support this type */
	case FF_PERIODIC:
		if (effect->u.periodic.waveform != FF_CUSTOM) {
			dev_err(haptics->dev,
				"Device can only accept FF_CUSTOM waveform\n");
			return -EINVAL;
		}

		/*
		 * Load the data and check the length.
		 * the data will be patterns in this case: 4 < X <= 100,
		 * and will be saved into the waveform memory inside DA728x.
		 * If X = 2, the data will be PS_SEQ_ID and PS_SEQ_LOOP.
		 * If X = 3, the 1st data will be GPIX_SEQUENCE_ID .
		 */
		if (effect->u.periodic.custom_len == DA7280_CUSTOM_DATA_LEN)
			goto set_seq_id_loop;

		if (effect->u.periodic.custom_len == DA7280_CUSTOM_GP_DATA_LEN)
			goto set_gpix_seq_id;

		if (effect->u.periodic.custom_len < DA7280_CUSTOM_DATA_LEN ||
		    effect->u.periodic.custom_len > DA7280_SNP_MEM_SIZE) {
			dev_err(haptics->dev, "Invalid waveform data size\n");
			return -EINVAL;
		}

		if (copy_from_user(data, effect->u.periodic.custom_data,
				   sizeof(s16) *
				   effect->u.periodic.custom_len))
			return -EFAULT;

		memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE);

		for (i = 0; i < effect->u.periodic.custom_len; i++) {
			if (data[i] < 0 || data[i] > 0xff) {
				dev_err(haptics->dev,
					"Invalid waveform data %d at offset %d\n",
					data[i], i);
				return -EINVAL;
			}
			haptics->snp_mem[i] = (u8)data[i];
		}

		error = da7280_haptic_mem_update(haptics);
		if (error) {
			dev_err(haptics->dev,
				"Failed to upload waveform: %d\n", error);
			return error;
		}
		break;

set_seq_id_loop:
		if (copy_from_user(data, effect->u.periodic.custom_data,
				   sizeof(s16) * DA7280_CUSTOM_DATA_LEN))
			return -EFAULT;

		if (data[DA7280_CUSTOM_SEQ_ID_IDX] < 0 ||
		    data[DA7280_CUSTOM_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX ||
		    data[DA7280_CUSTOM_SEQ_LOOP_IDX] < 0 ||
		    data[DA7280_CUSTOM_SEQ_LOOP_IDX] > DA7280_SEQ_LOOP_MAX) {
			dev_err(haptics->dev,
				"Invalid custom id (%d) or loop (%d)\n",
				data[DA7280_CUSTOM_SEQ_ID_IDX],
				data[DA7280_CUSTOM_SEQ_LOOP_IDX]);
			return -EINVAL;
		}

		haptics->ps_seq_id = data[DA7280_CUSTOM_SEQ_ID_IDX] & 0x0f;
		haptics->ps_seq_loop = data[DA7280_CUSTOM_SEQ_LOOP_IDX] & 0x0f;
		haptics->op_mode = haptics->periodic_op_mode;

		val = FIELD_PREP(DA7280_PS_SEQ_ID_MASK, haptics->ps_seq_id) |
			FIELD_PREP(DA7280_PS_SEQ_LOOP_MASK,
				   haptics->ps_seq_loop);
		error = regmap_write(haptics->regmap, DA7280_SEQ_CTL2, val);
		if (error) {
			dev_err(haptics->dev,
				"Failed to update PS sequence: %d\n", error);
			return error;
		}
		break;

set_gpix_seq_id:
		if (copy_from_user(data, effect->u.periodic.custom_data,
				   sizeof(s16) * DA7280_CUSTOM_GP_DATA_LEN))
			return -EFAULT;

		if (data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] < 0 ||
		    data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX ||
		    data[DA7280_CUSTOM_GPI_NUM_IDX] < 0 ||
		    data[DA7280_CUSTOM_GPI_NUM_IDX] > DA7280_GPI_SEQ_ID_MAX) {
			dev_err(haptics->dev,
				"Invalid custom GPI id (%d) or num (%d)\n",
				data[DA7280_CUSTOM_GPI_SEQ_ID_IDX],
				data[DA7280_CUSTOM_GPI_NUM_IDX]);
			return -EINVAL;
		}

		num = data[DA7280_CUSTOM_GPI_NUM_IDX] & 0x0f;
		haptics->gpi_ctl[num].seq_id =
			data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] & 0x0f;
		haptics->op_mode = haptics->periodic_op_mode;

		val = FIELD_PREP(DA7280_GPI0_SEQUENCE_ID_MASK,
				 haptics->gpi_ctl[num].seq_id);
		error = regmap_update_bits(haptics->regmap,
					   DA7280_GPI_0_CTL + num,
					   DA7280_GPI0_SEQUENCE_ID_MASK,
					   val);
		if (error) {
			dev_err(haptics->dev,
				"Failed to update GPI sequence: %d\n", error);
			return error;
		}
		break;

	default:
		dev_err(haptics->dev, "Unsupported effect type: %d\n",
			effect->type);
		return -EINVAL;
	}

	return 0;
}