/* * m5mols_setup_default - set default size & fps in the monitor mode. */ static int m5mols_setup_default(struct v4l2_subdev *sd) { struct m5mols_info *info = to_m5mols(sd); int value; int ret = -EINVAL; value = get_res_preset(sd, default_fmt[M5MOLS_RES_MON].width, default_fmt[M5MOLS_RES_MON].height, M5MOLS_RES_MON); if (value >= 0) ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, (u8)value); if (!ret) ret = i2c_w8_param(sd, CAT1_MONITOR_FPS, m5mols_reg_fps[default_fps.denominator]); if (!ret) ret = m5mols_init_controls(info); if (!ret) ret = m5mols_set_ae_lock(info, false); if (!ret) ret = m5mols_set_awb_lock(info, false); if (!ret) { info->fmt[M5MOLS_RES_MON] = default_fmt[M5MOLS_RES_MON]; info->tpf = default_fps; ret = 0; } return ret; }
/** * m5mols_s_power - Main sensor power control function * * To prevent breaking the lens when the sensor is powered off the Soft-Landing * algorithm is called where available. The Soft-Landing algorithm availability * dependends on the firmware provider. */ static int m5mols_s_power(struct v4l2_subdev *sd, int on) { struct m5mols_info *info = to_m5mols(sd); int ret; if (on) { ret = m5mols_sensor_power(info, true); if (!ret) ret = m5mols_sensor_armboot(sd); if (!ret) ret = m5mols_init_controls(info); if (ret) return ret; info->ffmt[M5MOLS_RESTYPE_MONITOR] = m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; info->ffmt[M5MOLS_RESTYPE_CAPTURE] = m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; return ret; } if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { ret = m5mols_mode(info, REG_MONITOR); if (!ret) ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); if (!ret) ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); if (!ret) ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, REG_AF_IDLE); if (!ret) v4l2_info(sd, "Success soft-landing lens\n"); } ret = m5mols_sensor_power(info, false); if (!ret) { v4l2_ctrl_handler_free(&info->handle); info->ctrl_sync = false; } return ret; }
static int m5mols_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct m5mols_platform_data *pdata = client->dev.platform_data; struct m5mols_info *info; struct v4l2_subdev *sd; int ret; if (pdata == NULL) { dev_err(&client->dev, "No platform data\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_reset)) { dev_err(&client->dev, "No valid RESET GPIO specified\n"); return -EINVAL; } if (!client->irq) { dev_err(&client->dev, "Interrupt not assigned\n"); return -EINVAL; } info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); if (!info) return -ENOMEM; info->pdata = pdata; info->set_power = pdata->set_power; ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); if (ret) { dev_err(&client->dev, "Failed to request gpio: %d\n", ret); goto out_free; } gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); if (ret) { dev_err(&client->dev, "Failed to get regulators: %d\n", ret); goto out_gpio; } sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &m5mols_ops); strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->internal_ops = &m5mols_subdev_internal_ops; info->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &info->pad, 0); if (ret < 0) goto out_reg; sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; init_waitqueue_head(&info->irq_waitq); mutex_init(&info->lock); ret = request_irq(client->irq, m5mols_irq_handler, IRQF_TRIGGER_RISING, MODULE_NAME, sd); if (ret) { dev_err(&client->dev, "Interrupt request failed: %d\n", ret); goto out_me; } info->res_type = M5MOLS_RESTYPE_MONITOR; info->ffmt[0] = m5mols_default_ffmt[0]; info->ffmt[1] = m5mols_default_ffmt[1]; ret = m5mols_sensor_power(info, true); if (ret) goto out_irq; ret = m5mols_fw_start(sd); if (!ret) ret = m5mols_init_controls(sd); ret = m5mols_sensor_power(info, false); if (!ret) return 0; out_irq: free_irq(client->irq, sd); out_me: media_entity_cleanup(&sd->entity); out_reg: regulator_bulk_free(ARRAY_SIZE(supplies), supplies); out_gpio: gpio_free(pdata->gpio_reset); out_free: kfree(info); return ret; }