blob: 1760debbe9720baf4c5fc123fdc1f2a16d73e177 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/trace/event.h>
#include <ddk/debug.h>
#include "imx355.h"
#include "src/camera/drivers/sensors/imx355/constants.h"
#include "src/camera/drivers/sensors/imx355/imx355_id.h"
#include "src/camera/drivers/sensors/imx355/imx355_modes.h"
#include "src/camera/drivers/sensors/imx355/imx355_otp_config.h"
#include "src/camera/drivers/sensors/imx355/imx355_seq.h"
#include "src/camera/drivers/sensors/imx355/mipi_ccs_regs.h"
namespace camera {
// |ZX_PROTOCOL_CAMERA_SENSOR2|
zx_status_t Imx355Device::CameraSensor2Init() {
std::lock_guard guard(lock_);
HwInit();
return ZX_OK;
}
void Imx355Device::CameraSensor2DeInit() {
std::lock_guard guard(lock_);
mipi_.DeInit();
HwDeInit();
// The reference code has this sleep. It is most likely needed for the clock to stabalize.
// There is no other way to tell whether the sensor has successfully powered down.
zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
is_streaming_ = false;
}
zx_status_t Imx355Device::CameraSensor2GetSensorId(uint32_t* out_id) {
std::lock_guard guard(lock_);
auto result = Read16(kSensorModelIdReg);
if (result.is_error()) {
return result.take_error();
}
if (result.value() != kSensorModelIdDefault) {
zxlogf(ERROR, "Sensor not online, read %d instead", result.value());
return ZX_ERR_INTERNAL;
}
*out_id = result.take_value();
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2GetAvailableModes(operating_mode_t* out_modes_list,
size_t modes_count,
size_t* out_modes_actual) {
std::lock_guard guard(lock_);
if (modes_count > available_modes.size()) {
return ZX_ERR_INVALID_ARGS;
}
for (size_t i = 0; i < available_modes.size(); i++) {
out_modes_list[i] = available_modes[i];
}
*out_modes_actual = available_modes.size();
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetMode(uint32_t mode) {
std::lock_guard guard(lock_);
HwInit();
if (mode > num_modes_) {
return ZX_ERR_INVALID_ARGS;
}
if (!ValidateSensorID()) {
return ZX_ERR_INTERNAL;
}
InitSensor(available_modes[mode].idx);
InitMipiCsi(mode);
current_mode_ = mode;
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2StartStreaming() {
if (is_streaming_) {
return ZX_OK;
}
std::lock_guard guard(lock_);
zxlogf(DEBUG, "%s Camera Sensor Start Streaming", __func__);
is_streaming_ = true;
auto status = Write8(kModeSelectReg, 0x01);
return status;
}
void Imx355Device::CameraSensor2StopStreaming() {
if (!is_streaming_) {
return;
}
std::lock_guard guard(lock_);
is_streaming_ = false;
Write8(kModeSelectReg, 0x00);
HwDeInit();
}
zx_status_t Imx355Device::CameraSensor2GetAnalogGain(float* out_gain) {
std::lock_guard guard(lock_);
auto status = ReadGainConstants();
if (status != ZX_OK) {
return status;
}
auto result = Read16(kAnalogGainCodeGlobalReg);
if (result.is_error()) {
return result.error();
}
*out_gain = AnalogRegValueToTotalGain(result.value());
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetAnalogGain(float gain, float* out_gain) {
std::lock_guard guard(lock_);
auto status = ReadGainConstants();
if (status != ZX_OK) {
return status;
}
auto new_analog_gain = AnalogTotalGainToRegValue(gain);
if (new_analog_gain != analog_gain_.gain_code_global_) {
analog_gain_.gain_code_global_ = new_analog_gain;
analog_gain_.update_gain_ = true;
}
*out_gain = AnalogRegValueToTotalGain(analog_gain_.gain_code_global_);
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2GetDigitalGain(float* out_gain) {
std::lock_guard guard(lock_);
auto status = ReadGainConstants();
if (status) {
return status;
}
auto result = Read16(kDigitalGainGlobalReg);
if (result.is_error()) {
return result.error();
}
*out_gain = DigitalRegValueToTotalGain(result.value());
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetDigitalGain(float gain, float* out_gain) {
std::lock_guard guard(lock_);
auto status = ReadGainConstants();
if (status) {
return status;
}
auto new_digital_gain = DigitalTotalGainToRegValue(gain);
if (new_digital_gain != digital_gain_.gain_) {
digital_gain_.gain_ = new_digital_gain;
digital_gain_.update_gain_ = true;
}
*out_gain = DigitalRegValueToTotalGain(digital_gain_.gain_);
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2GetIntegrationTime(float* out_int_time) {
std::lock_guard guard(lock_);
auto result_cit = Read16(kCoarseIntegrationTimeReg);
auto result_lps = GetLinesPerSecond();
if (result_cit.is_error() || result_lps.is_error()) {
return ZX_ERR_INTERNAL;
}
*out_int_time = static_cast<float>(result_cit.value()) / result_lps.value();
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetIntegrationTime(float int_time, float* out_int_time) {
std::lock_guard guard(lock_);
auto result = GetLinesPerSecond();
if (result.is_error()) {
return result.error();
}
uint16_t new_coarse_integration_time = int_time * result.value();
if (new_coarse_integration_time != integration_time_.coarse_integration_time_) {
integration_time_.coarse_integration_time_ = new_coarse_integration_time;
integration_time_.update_integration_time_ = true;
}
*out_int_time = int_time;
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2Update() {
TRACE_DURATION("camera", "Imx355Device::CameraSensor2Update");
std::lock_guard guard(lock_);
auto status = SetGroupedParameterHold(true);
if (analog_gain_.update_gain_) {
status = Write16(kAnalogGainCodeGlobalReg, analog_gain_.gain_code_global_);
if (status != ZX_OK) {
return status;
}
analog_gain_.update_gain_ = false;
}
if (digital_gain_.update_gain_) {
status = Write16(kDigitalGainGlobalReg, digital_gain_.gain_);
if (status) {
return status;
}
digital_gain_.update_gain_ = false;
}
if (integration_time_.update_integration_time_) {
status = Write16(kCoarseIntegrationTimeReg, integration_time_.coarse_integration_time_);
if (status) {
return status;
}
integration_time_.update_integration_time_ = false;
}
status = SetGroupedParameterHold(false);
return status;
}
zx_status_t Imx355Device::CameraSensor2GetOtpSize(uint32_t* out_size) {
*out_size = OTP_TOTAL_SIZE;
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2GetOtpData(uint32_t byte_count, uint32_t offset,
zx::vmo* out_otp_data) {
if ((byte_count + offset) > OTP_TOTAL_SIZE) {
return ZX_ERR_OUT_OF_RANGE;
}
auto result = OtpRead();
if (result.is_error()) {
return result.error();
}
auto vmo = result.take_value();
if (!OtpValidate(vmo)) {
zxlogf(ERROR, "%s; OTP validation failed.", __func__);
return ZX_ERR_INTERNAL;
}
*out_otp_data = std::move(vmo);
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2GetTestPatternMode(uint16_t* out_value) {
std::lock_guard guard(lock_);
auto result = Read16(kTestPatternReg);
if (result.is_error()) {
zxlogf(ERROR, "%s; Reading the mode failed.", __func__);
return result.error();
}
*out_value = result.value();
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetTestPatternMode(uint16_t mode) {
std::lock_guard guard(lock_);
if (mode > kNumTestPatternModes) {
zxlogf(ERROR, "%s; Invalid mode entered.", __func__);
return ZX_ERR_INVALID_ARGS;
}
zx_status_t status = Write16(kTestPatternReg, mode);
if (status != ZX_OK) {
zxlogf(ERROR, "%s; Writing the mode failed.", __func__);
}
return status;
}
zx_status_t Imx355Device::CameraSensor2GetTestPatternData(color_val_t* out_data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx355Device::CameraSensor2SetTestPatternData(const color_val_t* data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx355Device::CameraSensor2GetTestCursorData(rect_t* out_data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx355Device::CameraSensor2SetTestCursorData(const rect_t* data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx355Device::CameraSensor2GetExtensionValue(uint64_t id,
extension_value_data_type_t* out_value) {
std::lock_guard guard(lock_);
switch (id) {
case TOTAL_RESOLUTION: {
auto hmax_result_hi =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kLineLengthPckReg);
auto hmax_result_lo =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kLineLengthPckReg + 1);
auto vmax_result_hi =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kFrameLengthLinesReg);
auto vmax_result_lo = GetRegisterValueFromSequence(available_modes[current_mode_].idx,
kFrameLengthLinesReg + 1);
if (hmax_result_hi.is_error() || hmax_result_lo.is_error() || vmax_result_hi.is_error() ||
vmax_result_lo.is_error()) {
return ZX_ERR_INTERNAL;
}
out_value->dimension_value = dimensions_t{
.x = static_cast<float>(hmax_result_hi.value() << 8 | hmax_result_lo.value()),
.y = static_cast<float>(vmax_result_hi.value() << 8 | vmax_result_lo.value()),
};
break;
}
case ACTIVE_RESOLUTION:
out_value->dimension_value = available_modes[current_mode_].resolution_in;
break;
case PIXELS_PER_LINE: {
auto hmax_result_hi =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kOutputSizeXReg);
auto hmax_result_lo =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kOutputSizeXReg + 1);
if (hmax_result_hi.is_error() || hmax_result_lo.is_error()) {
return ZX_ERR_INTERNAL;
}
out_value->uint_value = hmax_result_hi.value() << 8 | hmax_result_lo.value();
break;
}
case AGAIN_LOG2_MAX:
case DGAIN_LOG2_MAX:
out_value->int_value = 3 << kLog2GainShift;
break;
case AGAIN_ACCURACY:
out_value->int_value = 1 << kLog2GainShift;
break;
case INT_TIME_MIN:
out_value->uint_value = 1;
break;
case INT_TIME_MAX:
case INT_TIME_LONG_MAX:
case INT_TIME_LIMIT:
out_value->uint_value = kDefaultMaxIntegrationTimeInLines;
break;
case DAY_LIGHT_INT_TIME_MAX:
out_value->uint_value = 0;
break;
case INT_TIME_APPLY_DELAY:
out_value->int_value = 2;
break;
case ISP_EXPOSURE_CHANNEL_DELAY:
out_value->int_value = 0;
break;
case X_OFFSET:
case Y_OFFSET:
out_value->int_value = 0;
break;
case LINES_PER_SECOND: {
auto result = GetLinesPerSecond();
if (result.is_error()) {
return result.error();
}
out_value->uint_value = result.value();
break;
}
case SENSOR_EXP_NUMBER:
out_value->int_value = kSensorExpNumber;
break;
case MODE:
out_value->uint_value = current_mode_;
break;
case FRAME_RATE_COARSE_INT_LUT:
std::copy(std::begin(frame_rate_to_integration_time_lut),
std::end(frame_rate_to_integration_time_lut), out_value->frame_rate_info_value);
break;
default:
return ZX_ERR_NOT_SUPPORTED;
}
return ZX_OK;
}
zx_status_t Imx355Device::CameraSensor2SetExtensionValue(uint64_t id,
const extension_value_data_type_t* value,
extension_value_data_type_t* out_value) {
return ZX_ERR_NOT_SUPPORTED;
}
} // namespace camera