From d4870725b99a622e6d05ef62b6a648a3e28adfc3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:24:57 -0400 Subject: [PATCH] media: staging: atomisp: Remove AP1302 sensor support This sensor is not used by any known ACPI-enabled platform (and no kernel users for it so far). Just remove it for good until we get a platform which actually uses it. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 12 - drivers/staging/media/atomisp/i2c/Makefile | 2 - drivers/staging/media/atomisp/i2c/ap1302.h | 198 ---- drivers/staging/media/atomisp/i2c/atomisp-ap1302.c | 1253 -------------------- 4 files changed, 1465 deletions(-) delete mode 100644 drivers/staging/media/atomisp/i2c/ap1302.h delete mode 100644 drivers/staging/media/atomisp/i2c/atomisp-ap1302.c diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 1273c3beb1ec..7aa5d77b5def 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -58,18 +58,6 @@ config VIDEO_ATOMISP_MT9M114 It currently only works with the atomisp driver. -config VIDEO_ATOMISP_AP1302 - tristate "AP1302 external ISP support" - depends on I2C && VIDEO_V4L2 - select REGMAP_I2C - ---help--- - This is a Video4Linux2 sensor-level driver for the external - ISP AP1302. - - AP1302 is an exteral ISP. - - It currently only works with the atomisp driver. - config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index ae19c691a73f..ae43dc84c229 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -11,8 +11,6 @@ obj-$(CONFIG_VIDEO_ATOMISP_GC0310) += atomisp-gc0310.o obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o -obj-$(CONFIG_VIDEO_ATOMISP_AP1302) += atomisp-ap1302.o - # Makefile for flash drivers # diff --git a/drivers/staging/media/atomisp/i2c/ap1302.h b/drivers/staging/media/atomisp/i2c/ap1302.h deleted file mode 100644 index 4d0b181a9671..000000000000 --- a/drivers/staging/media/atomisp/i2c/ap1302.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __AP1302_H__ -#define __AP1302_H__ - -#include "../include/linux/atomisp_platform.h" -#include -#include -#include -#include - -#define AP1302_NAME "ap1302" -#define AP1302_CHIP_ID 0x265 -#define AP1302_I2C_MAX_LEN 65534 -#define AP1302_FW_WINDOW_OFFSET 0x8000 -#define AP1302_FW_WINDOW_SIZE 0x2000 - -#define AP1302_REG16 2 -#define AP1302_REG32 4 - -#define REG_CHIP_VERSION 0x0000 -#define REG_CHIP_REV 0x0050 -#define REG_MF_ID 0x0004 -#define REG_ERROR 0x0006 -#define REG_CTRL 0x1000 -#define REG_DZ_TGT_FCT 0x1010 -#define REG_SFX_MODE 0x1016 -#define REG_SS_HEAD_PT0 0x1174 -#define REG_AE_BV_OFF 0x5014 -#define REG_AE_BV_BIAS 0x5016 -#define REG_AWB_CTRL 0x5100 -#define REG_FLICK_CTRL 0x5440 -#define REG_SCENE_CTRL 0x5454 -#define REG_BOOTDATA_STAGE 0x6002 -#define REG_SENSOR_SELECT 0x600C -#define REG_SYS_START 0x601A -#define REG_SIP_CRC 0xF052 - -#define REG_PREVIEW_BASE 0x2000 -#define REG_SNAPSHOT_BASE 0x3000 -#define REG_VIDEO_BASE 0x4000 -#define CNTX_WIDTH 0x00 -#define CNTX_HEIGHT 0x02 -#define CNTX_ROI_X0 0x04 -#define CNTX_ROI_Y0 0x06 -#define CNTX_ROI_X1 0x08 -#define CNTX_ROI_Y1 0x0A -#define CNTX_ASPECT 0x0C -#define CNTX_LOCK 0x0E -#define CNTX_ENABLE 0x10 -#define CNTX_OUT_FMT 0x12 -#define CNTX_SENSOR_MODE 0x14 -#define CNTX_MIPI_CTRL 0x16 -#define CNTX_MIPI_II_CTRL 0x18 -#define CNTX_LINE_TIME 0x1C -#define CNTX_MAX_FPS 0x20 -#define CNTX_AE_USG 0x22 -#define CNTX_AE_UPPER_ET 0x24 -#define CNTX_AE_MAX_ET 0x28 -#define CNTX_SS 0x2C -#define CNTX_S1_SENSOR_MODE 0x2E -#define CNTX_HINF_CTRL 0x30 - -#define CTRL_CNTX_MASK 0x03 -#define CTRL_CNTX_OFFSET 0x00 -#define HINF_CTRL_LANE_MASK 0x07 -#define HINF_CTRL_LANE_OFFSET 0x00 -#define MIPI_CTRL_IMGVC_MASK 0xC0 -#define MIPI_CTRL_IMGVC_OFFSET 0x06 -#define MIPI_CTRL_IMGTYPE_AUTO 0x3F -#define MIPI_CTRL_SSVC_MASK 0xC000 -#define MIPI_CTRL_SSVC_OFFSET 0x0E -#define MIPI_CTRL_SSTYPE_MASK 0x3F00 -#define MIPI_CTRL_SSTYPE_OFFSET 0x08 -#define OUT_FMT_IIS_MASK 0x30 -#define OUT_FMT_IIS_OFFSET 0x08 -#define OUT_FMT_SS_MASK 0x1000 -#define OUT_FMT_SS_OFFSET 0x12 -#define OUT_FMT_TYPE_MASK 0xFF -#define SENSOR_SELECT_MASK 0x03 -#define SENSOR_SELECT_OFFSET 0x00 -#define AWB_CTRL_MODE_MASK 0x0F -#define AWB_CTRL_MODE_OFFSET 0x00 -#define AWB_CTRL_FLASH_MASK 0x100 - -#define AP1302_FMT_UYVY422 0x50 - -#define AP1302_SYS_ACTIVATE 0x8010 -#define AP1302_SYS_SWITCH 0x8140 -#define AP1302_SENSOR_PRI 0x01 -#define AP1302_SENSOR_SEC 0x02 -#define AP1302_SS_CTRL 0x31 - -#define AP1302_MAX_RATIO_MISMATCH 10 /* Unit in percentage */ -#define AP1302_MAX_EV 2 -#define AP1302_MIN_EV -2 - -enum ap1302_contexts { - CONTEXT_PREVIEW = 0, - CONTEXT_SNAPSHOT, - CONTEXT_VIDEO, - CONTEXT_NUM -}; - -/* The context registers are defined according to preview/video registers. - Preview and video context have the same register definition. - But snapshot context does not have register S1_SENSOR_MODE. - When setting snapshot registers, if the offset exceeds - S1_SENSOR_MODE, the actual offset needs to minus 2. */ -struct ap1302_context_config { - u16 width; - u16 height; - u16 roi_x0; - u16 roi_y0; - u16 roi_x1; - u16 roi_y1; - u16 aspect_factor; - u16 lock; - u16 enable; - u16 out_fmt; - u16 sensor_mode; - u16 mipi_ctrl; - u16 mipi_ii_ctrl; - u16 padding; - u32 line_time; - u16 max_fps; - u16 ae_usg; - u32 ae_upper_et; - u32 ae_max_et; - u16 ss; - u16 s1_sensor_mode; - u16 hinf_ctrl; - u32 reserved; -}; - -struct ap1302_res_struct { - u16 width; - u16 height; - u16 fps; -}; - -struct ap1302_context_res { - u32 res_num; - u32 cur_res; - struct ap1302_res_struct *res_table; -}; - -struct ap1302_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct camera_sensor_platform_data *platform_data; - const struct firmware *fw; - struct mutex input_lock; /* serialize sensor's ioctl */ - struct v4l2_mbus_framefmt format; - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *run_mode; - struct ap1302_context_config cntx_config[CONTEXT_NUM]; - struct ap1302_context_res cntx_res[CONTEXT_NUM]; - enum ap1302_contexts cur_context; - unsigned int num_lanes; - struct regmap *regmap16; - struct regmap *regmap32; - bool sys_activated; - bool power_on; -}; - -struct ap1302_firmware { - u32 crc; - u32 pll_init_size; - u32 total_size; - u32 reserved; -}; - -struct ap1302_context_info { - u16 offset; - u16 len; - char *name; -}; - -#endif diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c deleted file mode 100644 index bfbf85122c3b..000000000000 --- a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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 "../include/linux/atomisp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ap1302.h" - -#define to_ap1302_device(sub_dev) \ - container_of(sub_dev, struct ap1302_device, sd) - -/* Static definitions */ -static struct regmap_config ap1302_reg16_config = { - .reg_bits = 16, - .val_bits = 16, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static struct regmap_config ap1302_reg32_config = { - .reg_bits = 16, - .val_bits = 32, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static enum ap1302_contexts ap1302_cntx_mapping[] = { - CONTEXT_PREVIEW, /* Invalid atomisp run mode */ - CONTEXT_VIDEO, /* ATOMISP_RUN_MODE_VIDEO */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_STILL_CAPTURE */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */ - CONTEXT_PREVIEW, /* ATOMISP_RUN_MODE_PREVIEW */ -}; - -static struct ap1302_res_struct ap1302_preview_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_snapshot_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_video_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static enum ap1302_contexts stream_to_context[] = { - CONTEXT_SNAPSHOT, - CONTEXT_PREVIEW, - CONTEXT_PREVIEW, - CONTEXT_VIDEO -}; - -static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = { - {0, 0, 0}, /* Preview: No aux streams. */ - {1, 0, 2}, /* Snapshot: 1 for postview. 2 for video */ - {1, 0, 0}, /* Video: 1 for preview. */ -}; - -static struct ap1302_context_info context_info[] = { - {CNTX_WIDTH, AP1302_REG16, "width"}, - {CNTX_HEIGHT, AP1302_REG16, "height"}, - {CNTX_ROI_X0, AP1302_REG16, "roi_x0"}, - {CNTX_ROI_X1, AP1302_REG16, "roi_x1"}, - {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"}, - {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"}, - {CNTX_ASPECT, AP1302_REG16, "aspect"}, - {CNTX_LOCK, AP1302_REG16, "lock"}, - {CNTX_ENABLE, AP1302_REG16, "enable"}, - {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"}, - {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"}, - {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"}, - {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"}, - {CNTX_LINE_TIME, AP1302_REG32, "line_time"}, - {CNTX_MAX_FPS, AP1302_REG16, "max_fps"}, - {CNTX_AE_USG, AP1302_REG16, "ae_usg"}, - {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"}, - {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"}, - {CNTX_SS, AP1302_REG16, "ss"}, - {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"}, - {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"}, -}; - -/* This array stores the description list for metadata. - The metadata contains exposure settings and face - detection results. */ -static u16 ap1302_ss_list[] = { - 0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */ - 0x0186, - 0xb002, /* 0x71c0 is for F-number */ - 0x71c0, - 0xb010, /* From 0x03dc with size 0x10 are face general infos. */ - 0x03dc, - 0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */ - 0x03e4, - 0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */ - 0x0604, - 0x0000 -}; - -/* End of static definitions */ - -static int ap1302_i2c_read_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, void *val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (len == AP1302_REG16) - ret = regmap_read(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_read(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n", - reg, *(u16 *)val); - else - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n", - reg, *(u32 *)val); - return ret; -} - -static int ap1302_i2c_write_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, u32 val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - if (len == AP1302_REG16) - ret = regmap_write(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_write(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n", - reg, (u16)val); - else - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n", - reg, (u32)val); - return ret; -} - -static u16 -ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset) -{ - u16 reg_addr; - /* The register offset is defined according to preview/video registers. - Preview and video context have the same register definition. - But snapshot context does not have register S1_SENSOR_MODE. - When setting snapshot registers, if the offset exceeds - S1_SENSOR_MODE, the actual offset needs to minus 2. */ - if (context == CONTEXT_SNAPSHOT) { - if (offset == CNTX_S1_SENSOR_MODE) - return 0; - if (offset > CNTX_S1_SENSOR_MODE) - offset -= 2; - } - if (context == CONTEXT_PREVIEW) - reg_addr = REG_PREVIEW_BASE + offset; - else if (context == CONTEXT_VIDEO) - reg_addr = REG_VIDEO_BASE + offset; - else - reg_addr = REG_SNAPSHOT_BASE + offset; - return reg_addr; -} - -static int ap1302_read_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_read_reg(sd, reg_addr, len, - ((u8 *)&dev->cntx_config[context]) + offset); -} - -static int ap1302_write_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_write_reg(sd, reg_addr, len, - *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset)); -} - -static int ap1302_dump_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int i; - dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context); - for (i = 0; i < ARRAY_SIZE(context_info); i++) { - struct ap1302_context_info *info = &context_info[i]; - u8 *var = (u8 *)&dev->cntx_config[context] + info->offset; - /* Snapshot context does not have s1_sensor_mode register. */ - if (context == CONTEXT_SNAPSHOT && - info->offset == CNTX_S1_SENSOR_MODE) - continue; - ap1302_read_context_reg(sd, context, info->offset, info->len); - if (info->len == AP1302_REG16) - dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n", - info->name, *(u16 *)var, *(u16 *)var); - else - dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n", - info->name, *(u32 *)var, *(u32 *)var); - } - return 0; -} - -static int ap1302_request_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev); - if (ret) - dev_err(&client->dev, - "ap1302_request_firmware failed. ret=%d\n", ret); - return ret; -} - -/* When loading firmware, host writes firmware data from address 0x8000. - When the address reaches 0x9FFF, the next address should return to 0x8000. - This function handles this address window and load firmware data to AP1302. - win_pos indicates the offset within this window. Firmware loading procedure - may call this function several times. win_pos records the current position - that has been written to.*/ -static int ap1302_write_fw_window(struct v4l2_subdev *sd, - u16 *win_pos, const u8 *buf, u32 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 pos; - u32 sub_len; - for (pos = 0; pos < len; pos += sub_len) { - if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos) - sub_len = len - pos; - else - sub_len = AP1302_FW_WINDOW_SIZE - *win_pos; - ret = regmap_raw_write(dev->regmap16, - *win_pos + AP1302_FW_WINDOW_OFFSET, - buf + pos, sub_len); - if (ret) - return ret; - *win_pos += sub_len; - if (*win_pos >= AP1302_FW_WINDOW_SIZE) - *win_pos = 0; - } - return 0; -} - -static int ap1302_load_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - const struct ap1302_firmware *fw; - const u8 *fw_data; - u16 reg_val = 0; - u16 win_pos = 0; - int ret; - - dev_info(&client->dev, "Start to load firmware.\n"); - if (!dev->fw) { - dev_err(&client->dev, "firmware not requested.\n"); - return -EINVAL; - } - fw = (const struct ap1302_firmware *) dev->fw->data; - if (dev->fw->size != (sizeof(*fw) + fw->total_size)) { - dev_err(&client->dev, "firmware size does not match.\n"); - return -EINVAL; - } - /* The fw binary contains a header of struct ap1302_firmware. - Following the header is the bootdata of AP1302. - The bootdata pointer can be referenced as &fw[1]. */ - fw_data = (u8 *)&fw[1]; - - /* Clear crc register. */ - ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF); - if (ret) - return ret; - - /* Load FW data for PLL init stage. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size); - if (ret) - return ret; - - /* Write 2 to bootdata_stage register to apply basic_init_hp - settings and enable PLL. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0x0002); - if (ret) - return ret; - - /* Wait 1ms for PLL to lock. */ - msleep(20); - - /* Load the rest of bootdata content. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size, - fw->total_size - fw->pll_init_size); - if (ret) - return ret; - - /* Check crc. */ - ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, ®_val); - if (ret) - return ret; - if (reg_val != fw->crc) { - dev_err(&client->dev, - "crc does not match. T:0x%04X F:0x%04X\n", - fw->crc, reg_val); - return -EAGAIN; - } - - /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that - the whole bootdata content has been loaded. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0xFFFF); - if (ret) - return ret; - dev_info(&client->dev, "Load firmware successfully.\n"); - - return 0; -} - -static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret, i; - u16 ss_ptr; - - dev_info(&client->dev, "ap1302_s_power is called.\n"); - ret = dev->platform_data->power_ctrl(sd, on); - if (ret) { - dev_err(&client->dev, - "ap1302_s_power error. on=%d ret=%d\n", on, ret); - return ret; - } - dev->power_on = on; - if (!on || !load_fw) - return 0; - /* Load firmware after power on. */ - ret = ap1302_load_firmware(sd); - if (ret) { - dev_err(&client->dev, - "ap1302_load_firmware failed. ret=%d\n", ret); - return ret; - } - ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr); - if (ret) - return ret; - for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) { - ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2, - AP1302_REG16, ap1302_ss_list[i]); - if (ret) - return ret; - } - return ret; -} - -static int ap1302_s_power(struct v4l2_subdev *sd, int on) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ap1302_s_power(sd, on, 1); - dev->sys_activated = 0; - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *mipi_info; - u16 reg_val = 0; - int ret; - - dev_info(&client->dev, "ap1302_s_config is called.\n"); - if (pdata == NULL) - return -ENODEV; - - dev->platform_data = pdata; - - mutex_lock(&dev->input_lock); - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) - goto fail_power; - } - - ret = __ap1302_s_power(sd, 1, 0); - if (ret) - goto fail_power; - - /* Detect for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, ®_val); - if (ret || (reg_val != AP1302_CHIP_ID)) { - dev_err(&client->dev, - "Chip version does no match. ret=%d ver=0x%04x\n", - ret, reg_val); - goto fail_config; - } - dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val); - - /* Detect revision for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, ®_val); - if (ret) - goto fail_config; - dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val); - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_config; - - mipi_info = v4l2_get_subdev_hostdata(sd); - if (!mipi_info) - goto fail_config; - dev->num_lanes = mipi_info->num_lanes; - - ret = __ap1302_s_power(sd, 0, 0); - if (ret) - goto fail_power; - - mutex_unlock(&dev->input_lock); - - return ret; - -fail_config: - __ap1302_s_power(sd, 0, 0); -fail_power: - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "ap1302_s_config failed\n"); - return ret; -} - -static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - return dev->cur_context; -} - -static int ap1302_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_UYVY8_1X16; - - return 0; -} - -static int ap1302_match_resolution(struct ap1302_context_res *res, - struct v4l2_mbus_framefmt *fmt) -{ - s32 w0, h0, mismatch, distance; - s32 w1 = fmt->width; - s32 h1 = fmt->height; - s32 min_distance = INT_MAX; - s32 i, idx = -1; - - if (w1 == 0 || h1 == 0) - return -1; - - for (i = 0; i < res->res_num; i++) { - w0 = res->res_table[i].width; - h0 = res->res_table[i].height; - if (w0 < w1 || h0 < h1) - continue; - mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0; - if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100) - continue; - distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1; - if (distance < min_distance) { - min_distance = distance; - idx = i; - } - } - - return idx; -} - -static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd, - enum ap1302_contexts context, - struct v4l2_mbus_framefmt *fmt) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct ap1302_res_struct *res_table; - s32 res_num, idx = -1; - - res_table = dev->cntx_res[context].res_table; - res_num = dev->cntx_res[context].res_num; - - if ((fmt->width <= res_table[res_num - 1].width) && - (fmt->height <= res_table[res_num - 1].height)) - idx = ap1302_match_resolution(&dev->cntx_res[context], fmt); - if (idx == -1) - idx = res_num - 1; - - fmt->width = res_table[idx].width; - fmt->height = res_table[idx].height; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - return idx; -} - - -static int ap1302_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) - -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - s32 cur_res; - if (format->pad) - return -EINVAL; - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt->width = res_table[cur_res].width; - fmt->height = res_table[cur_res].height; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct atomisp_input_stream_info *stream_info = - (struct atomisp_input_stream_info *)fmt->reserved; - enum ap1302_contexts context, main_context; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - mutex_lock(&dev->input_lock); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - context = ap1302_get_context(sd); - ap1302_try_mbus_fmt_locked(sd, context, fmt); - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - context = stream_to_context[stream_info->stream]; - dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n", - stream_info->stream, context); - dev->cntx_res[context].cur_res = - ap1302_try_mbus_fmt_locked(sd, context, fmt); - dev->cntx_config[context].width = fmt->width; - dev->cntx_config[context].height = fmt->height; - ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16); - ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16); - ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK; - dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422; - ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - - main_context = ap1302_get_context(sd); - if (context == main_context) { - ap1302_read_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_SSVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK; - dev->cntx_config[context].mipi_ctrl |= - (0x12 << MIPI_CTRL_SSTYPE_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - ap1302_read_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - dev->cntx_config[context].ss = AP1302_SS_CTRL; - ap1302_write_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - } else { - /* Configure aux stream */ - ap1302_read_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ii_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - if (stream_info->enable) { - ap1302_read_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt |= - (aux_stream_config[main_context][context] - << OUT_FMT_IIS_OFFSET); - ap1302_write_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - } - } - stream_info->ch_id = context; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - u32 cur_res; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - interval->interval.denominator = res_table[cur_res].fps; - interval->interval.numerator = 1; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - int index = fse->index; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - if (index >= dev->cntx_res[context].res_num) { - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - res_table = dev->cntx_res[context].res_table; - fse->min_width = res_table[index].width; - fse->min_height = res_table[index].height; - fse->max_width = res_table[index].width; - fse->max_height = res_table[index].height; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - *frames = 0; - return 0; -} - -static int ap1302_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - enum ap1302_contexts context; - u32 reg_val; - int ret; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n", - context, enable); - /* Switch context */ - ap1302_i2c_read_reg(sd, REG_CTRL, - AP1302_REG16, ®_val); - reg_val &= ~CTRL_CNTX_MASK; - reg_val |= (context<dev, "Start stream. context=%d\n", context); - ap1302_dump_context_reg(sd, context); - if (!dev->sys_activated) { - reg_val = AP1302_SYS_ACTIVATE; - dev->sys_activated = 1; - } else { - reg_val = AP1302_SYS_SWITCH; - } - } else { - dev_info(&client->dev, "Stop stream. context=%d\n", context); - reg_val = AP1302_SYS_SWITCH; - } - ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val); - if (ret) - dev_err(&client->dev, - "AP1302 set stream failed. enable=%d\n", enable); - mutex_unlock(&dev->input_lock); - return ret; -} - -static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300}; - -static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val) -{ - val -= AP1302_MIN_EV; - return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16, - ap1302_ev_values[val]); -} - -static u16 ap1302_wb_values[] = { - 0, /* V4L2_WHITE_BALANCE_MANUAL */ - 0xf, /* V4L2_WHITE_BALANCE_AUTO */ - 0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */ - 0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */ - 0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */ - 0x1, /* V4L2_WHITE_BALANCE_HORIZON */ - 0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */ - 0xf, /* V4L2_WHITE_BALANCE_FLASH */ - 0x6, /* V4L2_WHITE_BALANCE_CLOUDY */ - 0x6, /* V4L2_WHITE_BALANCE_SHADE */ -}; - -static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val) -{ - int ret = 0; - u16 reg_val; - - ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, ®_val); - if (ret) - return ret; - reg_val &= ~AWB_CTRL_MODE_MASK; - reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET; - if (val == V4L2_WHITE_BALANCE_FLASH) - reg_val |= AWB_CTRL_FLASH_MASK; - else - reg_val &= ~AWB_CTRL_FLASH_MASK; - ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val); - return ret; -} - -static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16, - val * 4 + 0x100); - return 0; -} - -static u16 ap1302_sfx_values[] = { - 0x00, /* V4L2_COLORFX_NONE */ - 0x03, /* V4L2_COLORFX_BW */ - 0x0d, /* V4L2_COLORFX_SEPIA */ - 0x07, /* V4L2_COLORFX_NEGATIVE */ - 0x04, /* V4L2_COLORFX_EMBOSS */ - 0x0f, /* V4L2_COLORFX_SKETCH */ - 0x08, /* V4L2_COLORFX_SKY_BLUE */ - 0x09, /* V4L2_COLORFX_GRASS_GREEN */ - 0x0a, /* V4L2_COLORFX_SKIN_WHITEN */ - 0x00, /* V4L2_COLORFX_VIVID */ - 0x00, /* V4L2_COLORFX_AQUA */ - 0x00, /* V4L2_COLORFX_ART_FREEZE */ - 0x00, /* V4L2_COLORFX_SILHOUETTE */ - 0x10, /* V4L2_COLORFX_SOLARIZATION */ - 0x02, /* V4L2_COLORFX_ANTIQUE */ - 0x00, /* V4L2_COLORFX_SET_CBCR */ -}; - -static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16, - ap1302_sfx_values[val]); - return 0; -} - -static u16 ap1302_scene_mode_values[] = { - 0x00, /* V4L2_SCENE_MODE_NONE */ - 0x07, /* V4L2_SCENE_MODE_BACKLIGHT */ - 0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */ - 0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ - 0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */ - 0x00, /* V4L2_SCENE_MODE_FALL_COLORS */ - 0x0d, /* V4L2_SCENE_MODE_FIREWORKS */ - 0x02, /* V4L2_SCENE_MODE_LANDSCAPE */ - 0x05, /* V4L2_SCENE_MODE_NIGHT */ - 0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */ - 0x01, /* V4L2_SCENE_MODE_PORTRAIT */ - 0x03, /* V4L2_SCENE_MODE_SPORTS */ - 0x0e, /* V4L2_SCENE_MODE_SUNSET */ - 0x0b, /* V4L2_SCENE_MODE_TEXT */ -}; - -static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16, - ap1302_scene_mode_values[val]); - return 0; -} - -static u16 ap1302_flicker_values[] = { - 0x0, /* OFF */ - 0x3201, /* 50HZ */ - 0x3c01, /* 60HZ */ - 0x2 /* AUTO */ -}; - -static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16, - ap1302_flicker_values[val]); - return 0; -} - -static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ap1302_device *dev = container_of( - ctrl->handler, struct ap1302_device, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_RUN_MODE: - dev->cur_context = ap1302_cntx_mapping[ctrl->val]; - break; - case V4L2_CID_EXPOSURE: - ap1302_set_exposure_off(&dev->sd, ctrl->val); - break; - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: - ap1302_set_wb_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_ZOOM_ABSOLUTE: - ap1302_set_zoom(&dev->sd, ctrl->val); - break; - case V4L2_CID_COLORFX: - ap1302_set_special_effect(&dev->sd, ctrl->val); - break; - case V4L2_CID_SCENE_MODE: - ap1302_set_scene_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - ap1302_set_flicker_freq(&dev->sd, ctrl->val); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ap1302_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 reg_val; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, ®_val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - if (ret) - return ret; - - reg->val = reg_val; - - return 0; -} - -static int ap1302_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - return ret; -} - -static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - long ret = 0; - switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - ret = ap1302_g_register(sd, arg); - break; - case VIDIOC_DBG_S_REGISTER: - ret = ap1302_s_register(sd, arg); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ap1302_s_ctrl, -}; - -static const char * const ctrl_run_mode_menu[] = { - NULL, - "Video", - "Still capture", - "Continuous capture", - "Preview", -}; - -static const struct v4l2_ctrl_config ctrls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_RUN_MODE, - .name = "Run Mode", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .def = 4, - .max = 4, - .qmenu = ctrl_run_mode_menu, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE, - .name = "Exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = AP1302_MIN_EV, - .def = 0, - .max = AP1302_MAX_EV, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - .name = "White Balance", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 9, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_ZOOM_ABSOLUTE, - .name = "Zoom Absolute", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 1024, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_COLORFX, - .name = "Color Special Effect", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 15, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_SCENE_MODE, - .name = "Scene Mode", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 13, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .name = "Light frequency filter", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 3, - .max = 3, - .step = 1, - }, -}; - -static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { - .g_skip_frames = ap1302_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops ap1302_video_ops = { - .s_stream = ap1302_s_stream, - .g_frame_interval = ap1302_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ap1302_core_ops = { - .s_power = ap1302_s_power, - .ioctl = ap1302_ioctl, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ap1302_g_register, - .s_register = ap1302_s_register, -#endif -}; - -static const struct v4l2_subdev_pad_ops ap1302_pad_ops = { - .enum_mbus_code = ap1302_enum_mbus_code, - .enum_frame_size = ap1302_enum_frame_size, - .get_fmt = ap1302_get_fmt, - .set_fmt = ap1302_set_fmt, -}; - -static const struct v4l2_subdev_ops ap1302_ops = { - .core = &ap1302_core_ops, - .pad = &ap1302_pad_ops, - .video = &ap1302_video_ops, - .sensor = &ap1302_sensor_ops -}; - -static int ap1302_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ap1302_device *dev = to_ap1302_device(sd); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - release_firmware(dev->fw); - - media_entity_cleanup(&dev->sd.entity); - dev->platform_data->csi_cfg(sd, 0); - v4l2_device_unregister_subdev(sd); - - return 0; -} - -static int ap1302_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ap1302_device *dev; - int ret; - unsigned int i; - - dev_info(&client->dev, "ap1302 probe called.\n"); - - /* allocate device & init sub device */ - dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - mutex_init(&dev->input_lock); - - v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops); - - ret = ap1302_request_firmware(&(dev->sd)); - if (ret) { - dev_err(&client->dev, "Cannot request ap1302 firmware.\n"); - goto out_free; - } - - dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config); - if (IS_ERR(dev->regmap16)) { - ret = PTR_ERR(dev->regmap16); - dev_err(&client->dev, - "Failed to allocate 16bit register map: %d\n", ret); - return ret; - } - - dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config); - if (IS_ERR(dev->regmap32)) { - ret = PTR_ERR(dev->regmap32); - dev_err(&client->dev, - "Failed to allocate 32bit register map: %d\n", ret); - return ret; - } - - if (client->dev.platform_data) { - ret = ap1302_s_config(&dev->sd, client->dev.platform_data); - if (ret) - goto out_free; - } - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res); - dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res; - dev->cntx_res[CONTEXT_SNAPSHOT].res_num = - ARRAY_SIZE(ap1302_snapshot_res); - dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res; - dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res); - dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res; - - ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls)); - if (ret) { - ap1302_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ctrls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); - - if (dev->ctrl_handler.error) { - ap1302_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - - dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE); - v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ap1302_remove(client); - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - return ret; -} - -static const struct i2c_device_id ap1302_id[] = { - {AP1302_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, ap1302_id); - -static struct i2c_driver ap1302_driver = { - .driver = { - .name = AP1302_NAME, - }, - .probe = ap1302_probe, - .remove = ap1302_remove, - .id_table = ap1302_id, -}; - -module_i2c_driver(ap1302_driver); - -MODULE_AUTHOR("Tianshu Qiu "); -MODULE_DESCRIPTION("AP1302 Driver"); -MODULE_LICENSE("GPL"); -- 2.11.0