camera: porting dw9781c ois

porting: (CR)
milanf: dw9781c ois bringup

Change-Id: Ibc40c253f4e4d04df41feeda4af41829b53e906c
Signed-off-by: Qiang Guo <guoqiang8@lenovo.com>
Reviewed-on: https://gerrit.mot.com/2078610
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Shanghui Zhang <zhangsh@motorola.com>
Reviewed-by: Bolei Shang <shangbl1@lenovo.com>
Reviewed-by: XiaoFeng Wang <wangxf32@lenovo.com>
Reviewed-by: Quanlin Zhu <zhuql3@motorola.com>
Reviewed-by: Zhuoran Xu <xuzr3@motorola.com>
Reviewed-by: Ji Zhao <zhaoji1@lenovo.com>
Submit-Approved: Jira Key
This commit is contained in:
Qiang Guo 2021-09-28 18:02:51 +08:00 • committed by zhaoji1
commit d43c0f4f90
3 changed files with 381 additions and 8 deletions

View file

@ -162,6 +162,7 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \
cam_sensor_module/cam_ois/cam_ois_dev.o \
cam_sensor_module/cam_ois/cam_ois_core.o \
cam_sensor_module/cam_ois/cam_ois_soc.o \
cam_sensor_module/cam_ois/cam_ois_dw9781.o \
cam_sensor_module/cam_sensor/cam_sensor_dev.o \
cam_sensor_module/cam_sensor/cam_sensor_core.o \
cam_sensor_module/cam_sensor/cam_sensor_soc.o \

View file

@ -15,6 +15,9 @@
#include "cam_common_util.h"
#include "cam_packet_util.h"
extern int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize);
extern void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize);
int32_t cam_ois_construct_default_power_setting(
struct cam_sensor_power_ctrl_t *power_info)
{
@ -302,6 +305,13 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl,
i2c_list->i2c_settings.addr_type,
i2c_list->i2c_settings.data_type,
i2c_list->i2c_settings.reg_setting[i].delay);
if (rc == 1) {
CAM_ERR(CAM_OIS,
"i2c poll fails addr:data %x:%x",
i2c_list->i2c_settings.reg_setting[i].reg_addr,
i2c_list->i2c_settings.reg_setting[i].reg_data);
return rc;
}
if (rc < 0) {
CAM_ERR(CAM_OIS,
"i2c poll apply setting Fail");
@ -390,6 +400,15 @@ static int cam_ois_fw_prog_download(struct cam_ois_ctrl_t *o_ctrl)
return rc;
}
if (strstr(o_ctrl->ois_name, "dw9781")) {
if (!dw9781c_check_fw_download(&(o_ctrl->io_master_info), fw->data, fw->size)) {
CAM_INFO(CAM_OIS, "Skip firmware download.");
release_firmware(fw);
return 0;
}
CAM_INFO(CAM_OIS, "Firmware download started.");
}
total_bytes = fw->size;
if(o_ctrl->ois_fw_txn_data_sz == 0)
txn_data_size = total_bytes;
@ -407,31 +426,55 @@ static int cam_ois_fw_prog_download(struct cam_ois_ctrl_t *o_ctrl)
return -ENOMEM;
}
CAM_DBG(CAM_OIS, "fw len: %d, addr_type: %d, data_type: %d, chunck: %d, ois_fw_data_type:%d", total_bytes,
i2c_reg_setting.addr_type,
i2c_reg_setting.data_type,
txn_data_size,
o_ctrl->ois_fw_data_type);
i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (vaddr);
for (total_idx = 0, ptr = (uint8_t *)fw->data; total_idx < total_bytes;) {
for(packet_idx = 0;
(packet_idx < txn_data_size) && (total_idx + packet_idx < total_bytes);
packet_idx++, ptr++)
for (packet_idx = 0;
(packet_idx < (txn_data_size/o_ctrl->ois_fw_data_type)) && (total_idx + (packet_idx*o_ctrl->ois_fw_data_type) < total_bytes);
packet_idx ++, ptr += o_ctrl->ois_fw_data_type)
{
int regAddrOffset = 0;
if(o_ctrl->ois_fw_inc_addr == 1)
regAddrOffset = total_idx + packet_idx;
regAddrOffset = total_idx/o_ctrl->ois_fw_data_type + packet_idx;
i2c_reg_setting.reg_setting[packet_idx].reg_addr =
o_ctrl->opcode.prog + regAddrOffset;
i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr;
if (o_ctrl->ois_fw_data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
i2c_reg_setting.reg_setting[packet_idx].reg_data = (uint32_t)(*ptr << 8) | *(ptr+1);
} else {
i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr;
}
i2c_reg_setting.reg_setting[packet_idx].delay = 0;
i2c_reg_setting.reg_setting[packet_idx].data_mask = 0;
CAM_DBG(CAM_OIS, "OIS_FW Reg:[0x%04x]: 0x%04x P:0x%x",
i2c_reg_setting.reg_setting[packet_idx].reg_addr,
i2c_reg_setting.reg_setting[packet_idx].reg_data,
(ptr-(uint8_t *)fw->data));
}
i2c_reg_setting.size = packet_idx;
rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
&i2c_reg_setting, 1);
if (o_ctrl->ois_fw_inc_addr == 1) {
rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
&i2c_reg_setting, 0);
} else {
rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
&i2c_reg_setting, 1);
}
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
goto release_firmware;
}
total_idx += packet_idx;
total_idx += packet_idx*o_ctrl->ois_fw_data_type;
CAM_DBG(CAM_OIS, "packet_idx: %d, total_idx: %d", packet_idx, total_idx);
}
if (strstr(o_ctrl->ois_name, "dw9781")) {
dw9781_post_firmware_download(&(o_ctrl->io_master_info), fw->data, fw->size);
}
release_firmware:
@ -461,6 +504,11 @@ static int cam_ois_fw_coeff_download(struct cam_ois_ctrl_t *o_ctrl)
return -EINVAL;
}
if (strstr(o_ctrl->ois_name, "dw9781")) {
CAM_DBG(CAM_OIS, "not need download coeff fw!");
return 0;
}
snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name);
fw_name_coeff = name_coeff;

View file

@ -0,0 +1,324 @@
/*
* Copyright (C) 2021 Motorola Mobility LLC.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include "cam_ois_core.h"
#include "cam_ois_soc.h"
#include "cam_sensor_util.h"
#include "cam_debug_util.h"
#include "cam_common_util.h"
#define DW9781C_CHIP_ID_ADDRESS 0x7000
#define DW9781C_CHECKSUM_ADDRESS 0x7007
#define DW9781C_CHIP_ID 0x9781
#define FW_VER_CURR_ADDR 0x7001
#define FW_TYPE_ADDR 0x700D
#define SET_FW 0x8001
#define EOK 0
#define FW_VERSION_OFFSET 10235
#define FW_CHECKSUM_OFFSET 10234
typedef struct
{
unsigned int driverIc;
unsigned int size;
const uint16_t *fwContentPtr;
uint16_t version;
uint16_t checksum;
} FirmwareContex;
static FirmwareContex g_dw9781FirmwareContext;
static int32_t dw9781_cci_write(struct camera_io_master * io_master_info, uint16_t reg, uint16_t val)
{
int32_t rc = 0;
struct cam_sensor_i2c_reg_array reg_setting;
struct cam_sensor_i2c_reg_setting wr_setting;
reg_setting.reg_addr = reg;
reg_setting.reg_data = val;
reg_setting.delay = 0;
reg_setting.data_mask = 0;
wr_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
wr_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD;
wr_setting.reg_setting = &reg_setting;
wr_setting.size = 1;
wr_setting.delay = 0;
rc = camera_io_dev_write(io_master_info, &wr_setting);
return rc;
}
static int32_t dw9781_cci_read(struct camera_io_master * io_master_info, uint16_t reg, uint16_t *val)
{
int32_t rc = 0;
uint32_t regVal = 0;
rc = camera_io_dev_read(io_master_info, reg, &regVal, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_WORD);
if (!rc) {
*val = (uint16_t)regVal;
}
return rc;
}
static void dw9781_delay_ms(uint32_t ms)
{
usleep_range(ms*1000, ms*1000+10);
return;
}
void dw9781_ois_reset(struct camera_io_master * io_master_info)
{
CAM_DBG(CAM_OIS, "[dw9781c_ois_reset] ois reset");
dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* DW9781_DBGc reset */
dw9781_delay_ms(4);
dw9781_cci_write(io_master_info, 0xD001, 0x0001); /* Active mode (DSP ON) */
dw9781_delay_ms(25); /* ST gyro - over wait 25ms, default Servo On */
dw9781_cci_write(io_master_info, 0xEBF1, 0x56FA); /* User protection release */
}
void dw9781_ois_ready_check(struct camera_io_master * io_master_info)
{
uint16_t fw_flag;
dw9781_cci_write(io_master_info, 0xD001, 0x0000); /* dsp off mode */
dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC); /* All protection(1) */
dw9781_cci_write(io_master_info, 0xF053, 0x70BD); /* All protection(2) */
dw9781_cci_read(io_master_info, 0xA7F9, &fw_flag); /* check checksum flag */
CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag : 0x%04x", fw_flag);
if(fw_flag == 0xCC33)
{
CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag is ok");
dw9781_ois_reset(io_master_info); /* ois reset */
} else {
dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* dw9781c reset */
dw9781_delay_ms(4);
CAM_ERR(CAM_OIS, "[dw9781c_ois_ready_check] previous firmware download fail");
}
}
void dw9781_all_protection_release(struct camera_io_master * io_master_info)
{
CAM_DBG(CAM_OIS, "[dw9781c_all_protection_release] execution");
/* release all protection */
dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC);
dw9781_delay_ms(1);
dw9781_cci_write(io_master_info, 0xF053, 0x70BD);
dw9781_delay_ms(1);
}
static uint16_t dw9781_fw_checksum_verify(struct camera_io_master * io_master_info)
{
uint16_t data;
/* FW checksum command */
dw9781_cci_write(io_master_info, 0x7011, 0x2000);
/* command start */
dw9781_cci_write(io_master_info, 0x7010, 0x8000);
dw9781_delay_ms(10);
/* calc the checksum to write the 0x7005 */
dw9781_cci_read(io_master_info, 0x7005, &data);
CAM_DBG(CAM_OIS, "F/W Checksum calculated value : 0x%04X", data);
return data;
}
static int dw9781_erase_mtp_rewritefw(struct camera_io_master * io_master_info)
{
CAM_DBG(CAM_OIS, "dw9781c erase for rewritefw starting..");
/* 512 byte page */
dw9781_cci_write(io_master_info, 0xde03, 0x0027);
/* page erase */
dw9781_cci_write(io_master_info, 0xde04, 0x0008);
dw9781_delay_ms(10);
CAM_DBG(CAM_OIS, "dw9781c checksum flag erase : 0xCC33");
return 0;
}
static void dw9781_erase_mtp(struct camera_io_master * io_master_info)
{
CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] start erasing firmware flash");
/* 12c level adjust */
dw9781_cci_write(io_master_info, 0xd005, 0x0001);
dw9781_cci_write(io_master_info, 0xdd03, 0x0002);
dw9781_cci_write(io_master_info, 0xdd04, 0x0002);
/* 4k Sector_0 Erase*/
dw9781_cci_write(io_master_info, 0xde03, 0x0000);
dw9781_cci_write(io_master_info, 0xde04, 0x0002);
dw9781_delay_ms(10);
/* 4k Sector_1 Erase*/
dw9781_cci_write(io_master_info, 0xde03, 0x0008);
dw9781_cci_write(io_master_info, 0xde04, 0x0002);
dw9781_delay_ms(10);
/* 4k Sector_2 Erase*/
dw9781_cci_write(io_master_info, 0xde03, 0x0010);
dw9781_cci_write(io_master_info, 0xde04, 0x0002);
dw9781_delay_ms(10);
/* 4k Sector_3 Erase*/
dw9781_cci_write(io_master_info, 0xde03, 0x0018);
dw9781_cci_write(io_master_info, 0xde04, 0x0002);
dw9781_delay_ms(10);
/* 4k Sector_4 Erase*/
dw9781_cci_write(io_master_info, 0xde03, 0x0020);
dw9781_cci_write(io_master_info, 0xde04, 0x0002);
dw9781_delay_ms(10);
CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] complete erasing firmware flash");
}
static int dw9781_prepare_fw_download(struct camera_io_master * io_master_info)
{
/* step 1: MTP Erase and DSP Disable for firmware 0x8000 write */
/* step 2: MTP setup */
/* step 3: firmware sequential write to flash */
/* step 4: firmware sequential read from flash */
/* step 5: firmware verify */
dw9781_cci_write(io_master_info, 0xd001, 0x0000);
dw9781_all_protection_release(io_master_info);
dw9781_erase_mtp(io_master_info);
CAM_DBG(CAM_OIS, "[dw9781c_download_fw] start firmware download");
return 0;
}
int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize)
{
uint8_t ret;
uint8_t needDownload = 0;
uint16_t fwchecksum = 0;
uint16_t first_chip_id = 0;
uint16_t chip_checksum = 0;
uint16_t second_chip_id = 0;
uint16_t fw_version_current = 0;
uint16_t fw_version_latest = 0;
if (io_master_info == NULL) {
printk("FATAL: OIS CCI context error!!!");
return -1;
}
if (fwData == NULL || fwSize < FW_VERSION_OFFSET*sizeof(uint16_t)) {
printk("FATAL: firmware buffer(%p) is NULL or size(%d) abnormal!!!", fwData, fwSize);
return -1;
}
g_dw9781FirmwareContext.driverIc = 0x9781;
g_dw9781FirmwareContext.fwContentPtr = (const uint16_t *)fwData;
g_dw9781FirmwareContext.size = fwSize;
g_dw9781FirmwareContext.version = *(g_dw9781FirmwareContext.fwContentPtr+FW_VERSION_OFFSET);
g_dw9781FirmwareContext.version = ((g_dw9781FirmwareContext.version << 8) & 0xff00) |
((g_dw9781FirmwareContext.version >> 8) & 0xff);
g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET);
g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) |
((g_dw9781FirmwareContext.checksum >> 8) & 0xff);
dw9781_ois_ready_check(io_master_info);
dw9781_cci_read(io_master_info, DW9781C_CHIP_ID_ADDRESS, &first_chip_id);
dw9781_cci_read(io_master_info, 0x7001, &chip_checksum);
CAM_DBG(CAM_OIS, "[dw9781c] FW_VER_PHONE_MAKER : 0x%x", chip_checksum);
dw9781_cci_read(io_master_info, 0x7002, &chip_checksum);
CAM_DBG(CAM_OIS, "[dw9781c] FW_DATE_PHONE_MAKER : 0x%x", chip_checksum);
CAM_DBG(CAM_OIS, "[dw9781c] first_chip_id : 0x%x", first_chip_id);
if (first_chip_id != DW9781C_CHIP_ID) { /* first_chip_id verification failed */
dw9781_all_protection_release(io_master_info);
dw9781_cci_read(io_master_info, 0xd060, &second_chip_id); /* second_chip_id: 0x0020 */
if ( second_chip_id == 0x0020 ) /* Check the second_chip_id*/
{
CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x",
g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version);
needDownload = 1;
ret = dw9781_prepare_fw_download(io_master_info); /* Need to forced update OIS firmware again. */
} else {
dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */
CAM_ERR(CAM_OIS, "[dw9781c] second_chip_id check fail");
CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode");
return needDownload;
}
} else {
dw9781_cci_read(io_master_info, FW_VER_CURR_ADDR, &fw_version_current);
fw_version_latest = g_dw9781FirmwareContext.version; /*Firmware version read from file content.*/
CAM_DBG(CAM_OIS, "[dw9781c] fw_version_current = 0x%x, fw_version_latest = 0x%x",
fw_version_current, fw_version_latest);
/* download firmware, check if need update, download firmware to flash */
if (((fw_version_current & 0xFF) != (fw_version_latest & 0xFF))) {
fwchecksum = dw9781_fw_checksum_verify(io_master_info);
if(fwchecksum != g_dw9781FirmwareContext.checksum)
{
needDownload = 1;
CAM_DBG(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X",
g_dw9781FirmwareContext.checksum, fwchecksum);
}
if (needDownload)
{
CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x needDownload %d",
g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version, needDownload);
ret = dw9781_prepare_fw_download(io_master_info);
CAM_DBG(CAM_OIS, "[dw9781c] flash download::vendor_dw9781c");
if (ret != EOK) {
dw9781_erase_mtp_rewritefw(io_master_info);
dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shut download mode */
CAM_ERR(CAM_OIS, "[dw9781c] firmware download error, ret = 0x%x", ret);
CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode");
needDownload = 1;
}
} else {
CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download");
}
} else {
CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download");
}
}
return needDownload;
}
EXPORT_SYMBOL(dw9781c_check_fw_download);
void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize)
{
uint16_t fwchecksum = 0;
g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET);
g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) |
((g_dw9781FirmwareContext.checksum >> 8) & 0xff);
dw9781_ois_ready_check(io_master_info);
fwchecksum = dw9781_fw_checksum_verify(io_master_info);
if(fwchecksum != g_dw9781FirmwareContext.checksum)
{
CAM_ERR(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X", g_dw9781FirmwareContext.checksum, fwchecksum);
dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */
dw9781_delay_ms(100);
dw9781_cci_write(io_master_info, 0xd000, 0x0001); /* Standby mode */
dw9781_delay_ms(100);
dw9781_all_protection_release(io_master_info); /* Disable write protect */
dw9781_erase_mtp_rewritefw(io_master_info);
dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */
CAM_ERR(CAM_OIS, "[dw9781c] firmware download error");
CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode");
} else {
CAM_DBG(CAM_OIS, "[dw9781c] Firmware download succes...");
}
return;
}
EXPORT_SYMBOL(dw9781_post_firmware_download);