static int lm3561_set_flash_sync(struct lm3561_drv_data *data,
				enum lm3561_sync_state setting)
{
	if (setting == LM3561_SYNC_ON)
		return lm3561_set_reg_data(data,
					   LM3561_REG_CFG_1,
					   LM3561_CFG_1_MASK,
					   LM3561_CFG1_STROBE_INPUT_ENABLE);
	else
		return lm3561_set_reg_data(data,
					   LM3561_REG_CFG_1,
					   LM3561_CFG_1_MASK,
					   LM3561_CFG1_STROBE_INPUT_DISABLE);
}
static int lm3561_set_flash_duration(struct lm3561_drv_data *data,
					unsigned long flash_duration)
{
	u8 duration_bits_value;

	if ((flash_duration < lm3561_limits.flash_duration_min) ||
	    (flash_duration > lm3561_limits.flash_duration_max)) {
		dev_err(&data->client->dev,
			"%s(): Value (%luus) should be from %luus to %luus\n",
			__func__, flash_duration,
			lm3561_limits.flash_duration_min,
			lm3561_limits.flash_duration_max);

		if (flash_duration < lm3561_limits.flash_duration_min)
			flash_duration = lm3561_limits.flash_duration_min;
		else if (flash_duration > lm3561_limits.flash_duration_max)
			flash_duration = lm3561_limits.flash_duration_max;

		dev_err(&data->client->dev,
			"%s(): Value is now set to %luus\n",
			__func__, flash_duration);
	}

	/* Convert duration value to register value. (Round-up fraction) */
	duration_bits_value =
		(flash_duration - 1) / lm3561_limits.flash_duration_min;

	return lm3561_set_reg_data(data,
				LM3561_REG_FLASH_DURATION,
				LM3561_FLASH_DURATION_MASK,
				duration_bits_value);
}
static int lm3561_suspend(struct device *dev)
{
	struct lm3561_drv_data *data = dev_get_drvdata(dev);
	struct lm3561_platform_data *pdata = data->client->dev.platform_data;
	int result;

	/* Shutdown in LM3561, bits 1-0 = 0.
	   Strobe is level triggered, bit 2 = 0 */
	result = lm3561_set_reg_data(data,
				     LM3561_REG_ENABLE,
				     LM3561_ENABLE_EN_MASK, 0x00);
	if (result) {
		dev_err(dev, "%s:set_reg_data error\n", __func__);
		goto exit_suspend;
	}

	result = pdata->power ? pdata->power(dev, false) : 0;
	if (result) {
		dev_err(dev, "%s: Failed to HW Disable.\n", __func__);
		goto exit_suspend;
	}

	dev_info(&data->client->dev,
		 "%s: Suspending LM3561 driver.\n", __func__);

exit_suspend:
	return result ? -EBUSY : 0;
}
static int lm3561_flash_mode(struct lm3561_drv_data *data,
				unsigned setting)
{
	int result;


	if (setting)
		result = lm3561_set_reg_data(data,
					LM3561_REG_ENABLE,
					LM3561_ENABLE_EN_MASK,
					LM3561_ENABLE_EN_FLASH_MODE);
	else
		result = lm3561_set_reg_data(data,
					LM3561_REG_ENABLE,
					LM3561_ENABLE_EN_MASK,
					LM3561_ENABLE_EN_SHUTDOWN);

	return result;
}
static int lm3561_torch_mode(struct lm3561_drv_data *data,
				unsigned setting)
{
	int result;


	if (setting) {
		result = lm3561_set_reg_data(data,
					LM3561_REG_ENABLE,
					LM3561_ENABLE_EN_MASK,
					LM3561_ENABLE_EN_TORCH_MODE);

	} else {
		result = lm3561_set_reg_data(data,
					LM3561_REG_ENABLE,
					LM3561_ENABLE_EN_MASK,
					LM3561_ENABLE_EN_SHUTDOWN);
	}

	return result;
}
static int lm3561_init_cfg1_register(struct lm3561_drv_data *data,
					struct lm3561_platform_data *pdata)
{
	int result;

	result = lm3561_set_reg_data(data,
				LM3561_REG_CFG_1,
				LM3561_CFG_1_MASK,
				LM3561_CFG1_STROBE_INPUT_ENABLE);
	if (result)
		return result;

	result = lm3561_set_flash_sync(data, pdata->flash_sync);

	return result;
}
static int lm3561_init_enable_register(struct lm3561_drv_data *data,
					struct lm3561_platform_data *pdata)
{
	int result;
	u8 value = 0;

	if (pdata->strobe_trigger)
		value |= (1 << STROBE_TRIGGER_SHIFT);

	result = lm3561_set_reg_data(data,
				     LM3561_REG_ENABLE,
				     LM3561_ENABLE_EN_MASK
				     | (1 << STROBE_TRIGGER_SHIFT),
				     value);
	return result;
}
static int lm3561_chip_init(struct lm3561_drv_data *data,
				struct lm3561_platform_data *pdata)
{
	int result;

	result = lm3561_init_enable_register(data, pdata);
	if (result)
		return result;

	result =  lm3561_set_reg_data(data,
				LM3561_REG_FLASH_DURATION,
				LM3561_FLASH_DURATION_CL_MASK,
				data->reg_flash_duration_limit);
	if (result)
		return result;

	result = lm3561_init_cfg1_register(data, pdata);
	if (result)
		return result;

	return result;
}
static int lm3561_set_torch_current(struct lm3561_drv_data *data,
				    unsigned long request_current)
{
	u8 current_bits_value;
	int leds = 1;

	if ((request_current < lm3561_limits.torch_current_min)  ||
	    (request_current > lm3561_limits.torch_current_max)) {
		dev_err(&data->client->dev,
			"%s(): Value (%luuA) should be from %luuA to %luuA\n",
			__func__, request_current,
			lm3561_limits.torch_current_min,
			lm3561_limits.torch_current_max);

		if (request_current < lm3561_limits.torch_current_min)
			request_current = lm3561_limits.torch_current_min;
		else if (request_current > lm3561_limits.torch_current_max)
			request_current = lm3561_limits.torch_current_max;

		dev_err(&data->client->dev,
			"%s(): Value is now set to %luuA\n",
			__func__, request_current);
	}



	/* Convert current value to register value (Round-down fraction) */
	current_bits_value =
		request_current	/
		(lm3561_limits.torch_current_min * leds)  - 1;

	current_bits_value = (current_bits_value << data->torch_current_shift)
		| current_bits_value;

	return lm3561_set_reg_data(data,
				LM3561_REG_TORCH_BRIGHT,
				LM3561_TORCH_BRIGHT_MASK,
				current_bits_value);
}
static int lm3561_check_status(struct lm3561_drv_data *data, u8 *return_status)
{
	u8 status = 0;
	int error;

	*return_status = 0;

	/* set Tx2/GPIO2 Control as flash interrupt input */
	error = lm3561_set_reg_data(data,
				LM3561_REG_GPIO,
				LM3561_GPIO_CTRL_MASK,
				LM3561_GPIO_CTRL_FLASH);
	if (error)
		return error;

	error = lm3561_get_reg_data(data, LM3561_REG_FLAG, &status);
	if (error)
		return error;

	*return_status &= status;

	return error;
}
static int lm3561_set_flash_current(struct lm3561_drv_data *data,
				    unsigned long flash_current)
{
	u8 current_bits_value;
	int leds = 1;

	if ((flash_current < lm3561_limits.flash_current_min) ||
	    (flash_current > lm3561_limits.flash_current_max)) {
		dev_err(&data->client->dev,
			"%s(): Value (%luuA) should be from %luuA to %luuA.\n",
			__func__, flash_current,
			lm3561_limits.flash_current_min,
			lm3561_limits.flash_current_max);

		if (flash_current < lm3561_limits.flash_current_min)
			flash_current = lm3561_limits.flash_current_min;
		else if (flash_current > lm3561_limits.flash_current_max)
			flash_current = lm3561_limits.flash_current_max;

		dev_err(&data->client->dev,
			"%s(): Value is now set to %luuA\n",
			__func__, flash_current);
	}
	/* Convert current value to register value (Round-down fraction) */
	current_bits_value =
		(flash_current - lm3561_limits.flash_current_min * leds)
		/ (lm3561_limits.flash_current_step * leds);

	current_bits_value = (current_bits_value << data->flash_current_shift)
		| current_bits_value;

	return lm3561_set_reg_data(data,
				     LM3561_REG_FLASH_BRIGHT,
				     LM3561_FLASH_BRIGHT_MASK,
				     current_bits_value);
}