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; }
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; }
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; }