Beispiel #1
0
static int lm3554_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	int ret;

	media_entity_cleanup(&flash->sd.entity);
	v4l2_ctrl_handler_free(&flash->ctrl_handler);
	v4l2_device_unregister_subdev(sd);

	atomisp_gmin_remove_subdev(sd);

	del_timer_sync(&flash->flash_off_delay);

	ret = lm3554_gpio_uninit(client);
	if (ret < 0)
		goto fail;

	kfree(flash);

	return 0;
fail:
	dev_err(&client->dev, "gpio request/direction_output fail");
	return ret;
}
Beispiel #2
0
static int lm3554_gpio_init(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;
	int ret;

	if (!gpio_is_valid(pdata->gpio_reset))
		return -EINVAL;

	ret = gpio_direction_output(pdata->gpio_reset, 0);
	if (ret < 0)
		goto err_gpio_reset;
	dev_info(&client->dev, "flash led reset successfully\n");

	if (!gpio_is_valid(pdata->gpio_strobe)) {
		ret = -EINVAL;
		goto err_gpio_dir_reset;
	}

	ret = gpio_direction_output(pdata->gpio_strobe, 0);
	if (ret < 0)
		goto err_gpio_strobe;

	return 0;

err_gpio_strobe:
	gpio_free(pdata->gpio_strobe);
err_gpio_dir_reset:
	gpio_direction_output(pdata->gpio_reset, 0);
err_gpio_reset:
	gpio_free(pdata->gpio_reset);

	return ret;
}
static int lm3554_detect(struct v4l2_subdev *sd)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct i2c_adapter *adapter = client->adapter;
	struct lm3554 *flash = to_lm3554(sd);
	int ret;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "lm3554_detect i2c error\n");
		return -ENODEV;
	}

	/* Power up the flash driver and reset it */
	ret = lm3554_s_power(&flash->sd, 1);
	if (ret < 0)
		return ret;

	lm3554_hw_reset(client);

	/* Setup default values. This makes sure that the chip is in a known
	 * state.
	 */
	ret = lm3554_setup(flash);
	if (ret < 0)
		goto fail;

	dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n");
	lm3554_s_power(&flash->sd, 0);
	return 0;

fail:
	lm3554_s_power(&flash->sd, 0);
	return ret;
}
static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val)
{
	struct lm3554 *flash = to_lm3554(sd);

	*val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE;

	return 0;
}
static void lm3554_flash_off_delay(long unsigned int arg)
{
	struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;

	gpio_set_value(pdata->gpio_strobe, 0);
}
static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val)
{
	struct lm3554 *flash = to_lm3554(sd);

	*val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current,
			LM3554_INDICATOR_STEP);

	return 0;
}
static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val)
{
	struct lm3554 *flash = to_lm3554(sd);

	*val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current,
			LM3554_TORCH_STEP);

	return 0;
}
static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity)
{
	struct lm3554 *flash = to_lm3554(sd);

	intensity = LM3554_CLAMP_PERCENTAGE(intensity);
	intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP);

	flash->flash_current = intensity;

	return lm3554_set_flash(flash);
}
static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val)
{
	struct lm3554 *flash = to_lm3554(sd);

	val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT);
	val = val / LM3554_TIMEOUT_STEPSIZE - 1;

	flash->timeout = val;

	return lm3554_set_duration(flash);
}
static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity)
{
	struct lm3554 *flash = to_lm3554(sd);

	intensity = LM3554_CLAMP_PERCENTAGE(intensity);
	intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP);

	flash->indicator_current = intensity;

	return lm3554_set_torch(flash);
}
static void lm3554_hw_reset(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;

	gpio_set_value(pdata->gpio_reset, 0);
	msleep(50);

	gpio_set_value(pdata->gpio_reset, 1);
	msleep(50);
}
static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val)
{
	struct lm3554 *flash = to_lm3554(sd);
	int ret;

	ret = lm3554_read(flash, LM3554_FLAGS_REG);

	if (ret < 0)
		return ret;

	*val = ret;
	return 0;
}
static int lm3554_hw_strobe(struct i2c_client *client, bool strobe)
{
	int ret, timer_pending;
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;

	/*
	 * An abnormal high flash current is observed when strobe off the
	 * flash. Workaround here is firstly set flash current to lower level,
	 * wait a short moment, and then strobe off the flash.
	 */

	timer_pending = del_timer_sync(&flash->flash_off_delay);

	/* Flash off */
	if (!strobe) {
		/* set current to 70mA and wait a while */
		ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0);
		if (ret < 0)
			goto err;
		mod_timer(&flash->flash_off_delay,
			  jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY));
		return 0;
	}

	/* Flash on */

	/*
	 * If timer is killed before run, flash is not strobe off,
	 * so must strobe off here
	 */
	if (timer_pending)
		gpio_set_value(pdata->gpio_strobe, 0);

	/* Restore flash current settings */
	ret = lm3554_set_flash(flash);
	if (ret < 0)
		goto err;

	/* Strobe on Flash */
	gpio_set_value(pdata->gpio_strobe, 1);

	return 0;
err:
	dev_err(&client->dev, "failed to %s flash strobe (%d)\n",
		strobe ? "on" : "off", ret);
	return ret;
}
static int lm3554_resume(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(subdev);
	int rval;

	if (flash->power_count == 0)
		return 0;

	rval = __lm3554_s_power(flash, 1);

	dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");

	return rval;
}
static int lm3554_gpio_init(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;
	int ret;

#ifdef CONFIG_GMIN_INTEL_MID
	if (!gpio_is_valid(pdata->gpio_reset))
		return -EINVAL;
#else
	ret = gpio_request(pdata->gpio_reset, "flash reset");
	if (ret < 0)
		return ret;
#endif

	ret = gpio_direction_output(pdata->gpio_reset, 1);
	if (ret < 0)
		goto err_gpio_reset;

#ifdef CONFIG_GMIN_INTEL_MID
	if (!gpio_is_valid(pdata->gpio_strobe)) {
		ret = -EINVAL;
		goto err_gpio_dir_reset;
	}
#else
	ret = gpio_request(pdata->gpio_strobe, "flash");
	if (ret < 0)
		goto err_gpio_dir_reset;
#endif

	ret = gpio_direction_output(pdata->gpio_strobe, 0);
	if (ret < 0)
		goto err_gpio_strobe;

	return 0;

err_gpio_strobe:
	gpio_free(pdata->gpio_strobe);
err_gpio_dir_reset:
	gpio_direction_output(pdata->gpio_reset, 0);
err_gpio_reset:
	gpio_free(pdata->gpio_reset);

	return ret;
}
static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val)
{
	struct lm3554 *flash = to_lm3554(sd);
	int value;

	value = lm3554_read_status(flash);
	if (value < 0)
		return value;

	if (value & LM3554_FLAG_TIMEOUT)
		*val = ATOMISP_FLASH_STATUS_TIMEOUT;
	else if (value > 0)
		*val = ATOMISP_FLASH_STATUS_HW_ERROR;
	else
		*val = ATOMISP_FLASH_STATUS_OK;

	return 0;
}
static int lm3554_gpio_uninit(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct lm3554 *flash = to_lm3554(sd);
	struct lm3554_platform_data *pdata = flash->pdata;
	int ret;

	ret = gpio_direction_output(pdata->gpio_strobe, 0);
	if (ret < 0)
		return ret;

	ret = gpio_direction_output(pdata->gpio_reset, 0);
	if (ret < 0)
		return ret;

	gpio_free(pdata->gpio_strobe);
	gpio_free(pdata->gpio_reset);
	return 0;
}
static int lm3554_s_power(struct v4l2_subdev *sd, int power)
{
	struct lm3554 *flash = to_lm3554(sd);
	int ret = 0;

	mutex_lock(&flash->power_lock);

	if (flash->power_count == !power) {
		ret = __lm3554_s_power(flash, !!power);
		if (ret < 0)
			goto done;
	}

	flash->power_count += power ? 1 : -1;
	WARN_ON(flash->power_count < 0);

done:
	mutex_unlock(&flash->power_lock);
	return ret;
}
Beispiel #19
0
static int lm3554_detect(struct v4l2_subdev *sd)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct i2c_adapter *adapter = client->adapter;
	struct lm3554 *flash = to_lm3554(sd);
	int ret;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "lm3554_detect i2c error\n");
		return -ENODEV;
	}

	/* Power up the flash driver and reset it */
	ret = lm3554_s_power(&flash->sd, 1);
	if (ret < 0) {
		dev_err(&client->dev, "Failed to power on lm3554 LED flash\n");
	} else {
		dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n");
		lm3554_s_power(&flash->sd, 0);
	}

	return ret;
}
static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode)
{
	struct lm3554 *flash = to_lm3554(sd);
	unsigned int mode;

	switch (new_mode) {
	case ATOMISP_FLASH_MODE_OFF:
		mode = LM3554_MODE_SHUTDOWN;
		break;
	case ATOMISP_FLASH_MODE_FLASH:
		mode = LM3554_MODE_FLASH;
		break;
	case ATOMISP_FLASH_MODE_INDICATOR:
		mode = LM3554_MODE_INDICATOR;
		break;
	case ATOMISP_FLASH_MODE_TORCH:
		mode = LM3554_MODE_TORCH;
		break;
	default:
		return -EINVAL;
	}

	return lm3554_set_mode(flash, mode);
}
static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 * val)
{
	struct lm3554 *flash = to_lm3554(sd);
	*val = flash->mode;
	return 0;
}