blob: 2a778191e7844d95e352b61029f53857d60c44ed [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 <ddk/debug.h>
#include "imx227.h"
#include "src/camera/drivers/sensors/imx227/constants.h"
#include "src/camera/drivers/sensors/imx227/imx227_id.h"
#include "src/camera/drivers/sensors/imx227/imx227_modes.h"
#include "src/camera/drivers/sensors/imx227/imx227_otp_config.h"
#include "src/camera/drivers/sensors/imx227/imx227_seq.h"
namespace camera {
namespace {
const int32_t kModeSelectReg = 0x0100;
// Extension Values
const uint16_t kFrameLengthLinesReg = 0x0340;
const uint16_t kLineLengthPckReg = 0x0342;
const int32_t kLog2GainShift = 18;
const int32_t kSensorExpNumber = 1;
const uint32_t kMasterClock = 288000000;
const uint32_t kDefaultMaxIntegrationTimeInLines = kMaxCoarseIntegrationTimeFor15fpsInLines;
const uint16_t kEndOfSequence = 0x0000;
} // namespace
// Gets the register value from the sequence table.
// |id| : Index of the sequence table.
// |address| : Address of the register.
static fit::result<uint8_t, zx_status_t> GetRegisterValueFromSequence(uint8_t index,
uint16_t address) {
if (index >= kSEQUENCE_TABLE.size()) {
return fit::error(ZX_ERR_INVALID_ARGS);
}
const InitSeqFmt* sequence = kSEQUENCE_TABLE[index];
while (true) {
uint16_t register_address = sequence->address;
uint16_t register_value = sequence->value;
uint16_t register_len = sequence->len;
if (register_address == kEndOfSequence && register_value == 0 && register_len == 0) {
break;
}
if (address == register_address) {
return fit::ok(register_value);
}
sequence++;
}
return fit::error(ZX_ERR_NOT_FOUND);
}
// |ZX_PROTOCOL_CAMERA_SENSOR2|
zx_status_t Imx227Device::CameraSensor2Init() {
std::lock_guard guard(lock_);
HwInit();
initialized_ = true;
return ZX_OK;
}
void Imx227Device::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;
initialized_ = false;
}
zx_status_t Imx227Device::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 Imx227Device::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 Imx227Device::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 Imx227Device::CameraSensor2StartStreaming() {
if (is_streaming_) {
return ZX_OK;
}
std::lock_guard guard(lock_);
if (!IsSensorInitialized()) {
return ZX_ERR_BAD_STATE;
}
zxlogf(DEBUG, "%s Camera Sensor Start Streaming", __func__);
is_streaming_ = true;
Write8(kModeSelectReg, 0x01);
return ZX_OK;
}
void Imx227Device::CameraSensor2StopStreaming() {
if (!IsSensorInitialized() || !is_streaming_) {
return;
}
std::lock_guard guard(lock_);
is_streaming_ = false;
Write8(kModeSelectReg, 0x00);
HwDeInit();
}
zx_status_t Imx227Device::CameraSensor2GetAnalogGain(float* out_gain) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetAnalogGain(float gain, float* out_gain) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2GetDigitalGain(float* out_gain) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetDigitalGain(float gain, float* out_gain) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2GetIntegrationTime(float* out_int_time) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetIntegrationTime(float int_time, float* out_int_time) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2Update() { return ZX_ERR_NOT_SUPPORTED; }
zx_status_t Imx227Device::CameraSensor2GetOtpSize(uint32_t* out_size) {
*out_size = OTP_TOTAL_SIZE;
return ZX_OK;
}
zx_status_t Imx227Device::CameraSensor2GetOtpData(uint32_t byte_count, uint32_t offset,
const uint8_t* buf_list, size_t buf_count) {
if ((byte_count + offset) > OTP_TOTAL_SIZE) {
return ZX_ERR_OUT_OF_RANGE;
}
if (buf_count < byte_count) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
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;
}
zx_status_t status =
vmo.read(static_cast<void*>(const_cast<uint8_t*>(buf_list)), offset, byte_count);
if (status != ZX_OK) {
zxlogf(ERROR, "%s; Reading from VMO failed.", __func__);
}
return status;
}
zx_status_t Imx227Device::CameraSensor2GetTestPatternMode(uint16_t* out_value) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetTestPatternMode(uint16_t mode) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2GetTestPatternData(color_val_t* out_data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetTestPatternData(const color_val_t* data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2GetTestCursorData(rect_t* out_data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2SetTestCursorData(const rect_t* data) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t Imx227Device::CameraSensor2GetExtensionValue(uint64_t id,
extension_value_data_type_t* out_value) {
std::lock_guard guard(lock_);
switch (id) {
case TOTAL_RESOLUTION: {
auto hmax_result =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kLineLengthPckReg);
auto vmax_result =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kFrameLengthLinesReg);
if (hmax_result.is_error() || vmax_result.is_error()) {
return ZX_ERR_INTERNAL;
}
out_value->dimension_value = dimensions_t{
.x = static_cast<float>(hmax_result.value()),
.y = static_cast<float>(vmax_result.value()),
};
break;
}
case ACTIVE_RESOLUTION:
out_value->dimension_value = available_modes[current_mode_].resolution_in;
break;
case PIXELS_PER_LINE: {
auto hmax_result =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kLineLengthPckReg);
if (hmax_result.is_error()) {
return ZX_ERR_INTERNAL;
}
out_value->uint_value = hmax_result.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 hmax_result =
GetRegisterValueFromSequence(available_modes[current_mode_].idx, kLineLengthPckReg);
if (hmax_result.is_error()) {
return ZX_ERR_INTERNAL;
}
out_value->uint_value = kMasterClock / hmax_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 Imx227Device::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