From: Sakari Ailus Date: Mon, 11 Sep 2017 22:46:32 +0000 (+0200) Subject: media: staging: atomisp: Add driver prefix to Kconfig option and module names X-Git-Tag: v4.15-rc1~91^2~133 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=90ebe55ab88635a19af06d923bb70ef236123399;p=linux-block.git media: staging: atomisp: Add driver prefix to Kconfig option and module names By adding the "atomisp-" prefix to module names (and "ATOMISP_" to Kconfig options), the staging drivers for e.g. sensors are labelled as being specific to atomisp, which they effectively are. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 57505b7a25ca..09b1a97ce560 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -5,7 +5,7 @@ source "drivers/staging/media/atomisp/i2c/ov5693/Kconfig" source "drivers/staging/media/atomisp/i2c/imx/Kconfig" -config VIDEO_OV2722 +config VIDEO_ATOMISP_OV2722 tristate "OVT ov2722 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -16,7 +16,7 @@ config VIDEO_OV2722 It currently only works with the atomisp driver. -config VIDEO_GC2235 +config VIDEO_ATOMISP_GC2235 tristate "Galaxy gc2235 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -27,7 +27,7 @@ config VIDEO_GC2235 It currently only works with the atomisp driver. -config VIDEO_OV8858 +config VIDEO_ATOMISP_OV8858 tristate "Omnivision ov8858 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP ---help--- @@ -38,7 +38,7 @@ config VIDEO_OV8858 It currently only works with the atomisp driver. -config VIDEO_MSRLIST_HELPER +config VIDEO_ATOMISP_MSRLIST_HELPER tristate "Helper library to load, parse and apply large register lists." depends on I2C ---help--- @@ -48,7 +48,7 @@ config VIDEO_MSRLIST_HELPER To compile this driver as a module, choose M here: the module will be called libmsrlisthelper. -config VIDEO_MT9M114 +config VIDEO_ATOMISP_MT9M114 tristate "Aptina mt9m114 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -59,7 +59,7 @@ config VIDEO_MT9M114 It currently only works with the atomisp driver. -config VIDEO_AP1302 +config VIDEO_ATOMISP_AP1302 tristate "AP1302 external ISP support" depends on I2C && VIDEO_V4L2 select REGMAP_I2C @@ -71,14 +71,14 @@ config VIDEO_AP1302 It currently only works with the atomisp driver. -config VIDEO_GC0310 +config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Galaxycore GC0310 0.3MP sensor. -config VIDEO_OV2680 +config VIDEO_ATOMISP_OV2680 tristate "Omnivision OV2680 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -93,7 +93,7 @@ config VIDEO_OV2680 # Kconfig for flash drivers # -config VIDEO_LM3554 +config VIDEO_ATOMISP_LM3554 tristate "LM3554 flash light driver" depends on VIDEO_V4L2 && I2C ---help--- diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index be13fab92175..3d27c75f5fc5 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -2,22 +2,22 @@ # Makefile for sensor drivers # -obj-$(CONFIG_VIDEO_IMX) += imx/ -obj-$(CONFIG_VIDEO_OV5693) += ov5693/ -obj-$(CONFIG_VIDEO_MT9M114) += mt9m114.o -obj-$(CONFIG_VIDEO_GC2235) += gc2235.o -obj-$(CONFIG_VIDEO_OV2722) += ov2722.o -obj-$(CONFIG_VIDEO_OV2680) += ov2680.o -obj-$(CONFIG_VIDEO_GC0310) += gc0310.o +obj-$(CONFIG_VIDEO_ATOMISP_IMX) += imx/ +obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += ov5693/ +obj-$(CONFIG_VIDEO_ATOMISP_MT9M114) += atomisp-mt9m114.o +obj-$(CONFIG_VIDEO_ATOMISP_GC2235) += atomisp-gc2235.o +obj-$(CONFIG_VIDEO_ATOMISP_OV2722) += atomisp-ov2722.o +obj-$(CONFIG_VIDEO_ATOMISP_OV2680) += atomisp-ov2680.o +obj-$(CONFIG_VIDEO_ATOMISP_GC0310) += atomisp-gc0310.o -obj-$(CONFIG_VIDEO_MSRLIST_HELPER) += libmsrlisthelper.o +obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o -obj-$(CONFIG_VIDEO_AP1302) += ap1302.o +obj-$(CONFIG_VIDEO_ATOMISP_AP1302) += atomisp-ap1302.o # Makefile for flash drivers # -obj-$(CONFIG_VIDEO_LM3554) += lm3554.o +obj-$(CONFIG_VIDEO_ATOMISP_LM3554) += atomisp-lm3554.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/ap1302.c b/drivers/staging/media/atomisp/i2c/ap1302.c deleted file mode 100644 index 2f772a020c8b..000000000000 --- a/drivers/staging/media/atomisp/i2c/ap1302.c +++ /dev/null @@ -1,1255 +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) { - dev_err(&client->dev, "%s: out of memory\n", __func__); - 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"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c new file mode 100644 index 000000000000..2f772a020c8b --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c @@ -0,0 +1,1255 @@ +/* + * + * 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) { + dev_err(&client->dev, "%s: out of memory\n", __func__); + 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"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c new file mode 100644 index 000000000000..35ed51ffe944 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -0,0 +1,1490 @@ +/* + * Support for GalaxyCore GC0310 VGA camera sensor. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" + +#include "gc0310.h" + +/* i2c read/write stuff */ +static int gc0310_read_reg(struct i2c_client *client, + u16 data_length, u8 reg, u8 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[1]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != GC0310_8BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == GC0310_8BIT) + *val = (u8)data[0]; + + return 0; +} + +static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int gc0310_write_reg(struct i2c_client *client, u16 data_length, + u8 reg, u8 val) +{ + int ret; + unsigned char data[2] = {0}; + u8 *wreg = (u8 *)data; + const u16 len = data_length + sizeof(u8); /* 8-bit address + data */ + + if (data_length != GC0310_8BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = (u8)(reg & 0xff); + + if (data_length == GC0310_8BIT) + data[1] = (u8)(val); + + ret = gc0310_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * gc0310_write_reg_array - Initializes a list of GC0310 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and + * __gc0310_write_reg_is_consecutive() are internal functions to + * gc0310_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __gc0310_flush_reg_array(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ + ctrl->buffer.addr = (u8)(ctrl->buffer.addr); + ctrl->index = 0; + + return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __gc0310_buf_reg_array(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl, + const struct gc0310_reg *next) +{ + int size; + + switch (next->type) { + case GC0310_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE) + return __gc0310_flush_reg_array(client, ctrl); + + return 0; +} + +static int __gc0310_write_reg_is_consecutive(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl, + const struct gc0310_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int gc0310_write_reg_array(struct i2c_client *client, + const struct gc0310_reg *reglist) +{ + const struct gc0310_reg *next = reglist; + struct gc0310_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != GC0310_TOK_TERM; next++) { + switch (next->type & GC0310_TOK_MASK) { + case GC0310_TOK_DELAY: + err = __gc0310_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__gc0310_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __gc0310_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __gc0310_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __gc0310_flush_reg_array(client, &ctrl); +} +static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; + return 0; +} + +static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; + return 0; +} + +static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | + (GC0310_F_NUMBER_DEM << 16) | + (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; + return 0; +} + +static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + *val = gc0310_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + *val = gc0310_res[dev->fmt_idx].bin_factor_y; + + return 0; +} + +static int gc0310_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct gc0310_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + u16 val; + u8 reg_val; + int ret; + unsigned int hori_blanking; + unsigned int vert_blanking; + unsigned int sh_delay; + + if (!info) + return -EINVAL; + + /* pixel clock calculattion */ + dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz + buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; + pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); + + /* get integration time */ + buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + GC0310_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + GC0310_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + /* Getting crop_horizontal_start */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_CROP_START_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_CROP_START_L, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = val | (reg_val & 0xFF); + pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start); + + /* Getting crop_vertical_start */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_CROP_START_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_CROP_START_L, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = val | (reg_val & 0xFF); + pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start); + + /* Getting output_width */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_OUTSIZE_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_width = val | (reg_val & 0xFF); + pr_info("output_width=%d\n", buf->output_width); + + /* Getting output_height */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_OUTSIZE_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_height = val | (reg_val & 0xFF); + pr_info("output_height=%d\n", buf->output_height); + + buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; + buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; + pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end); + pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end); + + /* Getting line_length_pck */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_BLANKING_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_BLANKING_L, ®_val); + if (ret) + return ret; + hori_blanking = val | (reg_val & 0xFF); + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SH_DELAY, ®_val); + if (ret) + return ret; + sh_delay = reg_val; + buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; + pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck); + + /* Getting frame_length_lines */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_BLANKING_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_BLANKING_L, ®_val); + if (ret) + return ret; + vert_blanking = val | (reg_val & 0xFF); + buf->frame_length_lines = buf->output_height + vert_blanking; + pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines); + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 again, dgain; + + if (gain < 0x20) + gain = 0x20; + if (gain > 0x80) + gain = 0x80; + + if (gain >= 0x20 && gain < 0x40) { + again = 0x0; /* sqrt(2) */ + dgain = gain; + } else { + again = 0x2; /* 2 * sqrt(2) */ + dgain = gain / 2; + } + + pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); + + /* set analog gain */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AGC_ADJ, again); + if (ret) + return ret; + + /* set digital gain */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_DGC_ADJ, dgain); + if (ret) + return ret; + + return 0; +} + +static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); + + /* set exposure */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_L, + coarse_itg & 0xff); + if (ret) + return ret; + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_H, + (coarse_itg >> 8) & 0x0f); + if (ret) + return ret; + + ret = gc0310_set_gain(sd, gain); + if (ret) + return ret; + + return ret; +} + +static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __gc0310_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long gc0310_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return gc0310_set_exposure(sd, exp, gain, digitgain); +} + +/* TO DO */ +static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value) +{ + return 0; +} + +/* TO DO */ +static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value) +{ + return 0; +} + +static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return gc0310_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 reg_v; + int ret; + + /* get exposure */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_L, + ®_v); + if (ret) + goto err; + + *value = reg_v; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_H, + ®_v); + if (ret) + goto err; + + *value = *value + (reg_v << 8); +err: + return ret; +} + +static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *dev = + container_of(ctrl->handler, struct gc0310_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = gc0310_v_flip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = gc0310_h_flip(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *dev = + container_of(ctrl->handler, struct gc0310_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = gc0310_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = gc0310_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = gc0310_s_ctrl, + .g_volatile_ctrl = gc0310_g_volatile_ctrl +}; + +struct v4l2_ctrl_config gc0310_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = GC0310_FOCAL_LENGTH_DEFAULT, + .max = GC0310_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = GC0310_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = GC0310_F_NUMBER_DEFAULT, + .max = GC0310_F_NUMBER_DEFAULT, + .step = 0x01, + .def = GC0310_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = GC0310_F_NUMBER_RANGE, + .max = GC0310_F_NUMBER_RANGE, + .step = 0x01, + .def = GC0310_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = GC0310_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = GC0310_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int gc0310_init(struct v4l2_subdev *sd) +{ + int ret; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct gc0310_device *dev = to_gc0310_sensor(sd); + + pr_info("%s S\n", __func__); + mutex_lock(&dev->input_lock); + + /* set inital registers */ + ret = gc0310_write_reg_array(client, gc0310_reset_register); + + /* restore settings */ + gc0310_res = gc0310_res_preview; + N_RES = N_RES_PREVIEW; + + mutex_unlock(&dev->input_lock); + + pr_info("%s E\n", __func__); + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = 0; + struct gc0310_device *dev = to_gc0310_sensor(sd); + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + /* The upstream module driver (written to Crystal + * Cove) had this logic to pulse the rails low first. + * This appears to break things on the MRD7 with the + * X-Powers PMIC... + * + * ret = dev->platform_data->v1p8_ctrl(sd, 0); + * ret |= dev->platform_data->v2p8_ctrl(sd, 0); + * mdelay(50); + */ + ret |= dev->platform_data->v1p8_ctrl(sd, 1); + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + usleep_range(10000, 15000); + } + + if (!flag || ret) { + ret |= dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct gc0310_device *dev = to_gc0310_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* GPIO0 == "reset" (active low), GPIO1 == "power down" */ + if (flag) { + /* Pulse reset, then release power down */ + ret = dev->platform_data->gpio0_ctrl(sd, 0); + usleep_range(5000, 10000); + ret |= dev->platform_data->gpio0_ctrl(sd, 1); + usleep_range(10000, 15000); + ret |= dev->platform_data->gpio1_ctrl(sd, 0); + usleep_range(10000, 15000); + } else { + ret = dev->platform_data->gpio1_ctrl(sd, 1); + ret |= dev->platform_data->gpio0_ctrl(sd, 0); + } + return ret; +} + + +static int power_down(struct v4l2_subdev *sd); + +static int power_up(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s S\n", __func__); + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_gpio; + } + + msleep(100); + + pr_info("%s E\n", __func__); + return 0; + +fail_gpio: + dev->platform_data->flisclk_ctrl(sd, 0); +fail_clk: + power_ctrl(sd, 0); +fail_power: + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int gc0310_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) + return gc0310_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct gc0310_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); + + if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct gc0310_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &gc0310_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != gc0310_res[i].width) + continue; + if (h != gc0310_res[i].height) + continue; + + return i; + } + + return -1; +} + + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + pr_info("%s S\n", __func__); + + ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "gc0310 write register err.\n"); + return ret; + } + + pr_info("%s E\n", __func__); + return ret; +} + +static int gc0310_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 gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *gc0310_info = NULL; + int ret = 0; + int idx = 0; + pr_info("%s S\n", __func__); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + gc0310_info = v4l2_get_subdev_hostdata(sd); + if (!gc0310_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = gc0310_res[N_RES - 1].width; + fmt->height = gc0310_res[N_RES - 1].height; + } else { + fmt->width = gc0310_res[idx].width; + fmt->height = gc0310_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__, + gc0310_res[dev->fmt_idx].desc); + ret = startup(sd); + if (ret) { + dev_err(&client->dev, "gc0310 startup err\n"); + goto err; + } + + ret = gc0310_get_intg_factor(client, gc0310_info, + &gc0310_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + pr_info("%s E\n", __func__); +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc0310_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 gc0310_device *dev = to_gc0310_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = gc0310_res[dev->fmt_idx].width; + fmt->height = gc0310_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; + + return 0; +} + +static int gc0310_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u8 high, low; + int ret; + u16 id; + + pr_info("%s S\n", __func__); + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "read sensor_id_high failed\n"); + return -ENODEV; + } + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SC_CMMN_CHIP_ID_L, &low); + if (ret) { + dev_err(&client->dev, "read sensor_id_low failed\n"); + return -ENODEV; + } + id = ((((u16) high) << 8) | (u16) low); + pr_info("sensor ID = 0x%x\n", id); + + if (id != GC0310_ID) { + dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID); + return -ENODEV; + } + + dev_dbg(&client->dev, "detect gc0310 success\n"); + + pr_info("%s E\n", __func__); + + return 0; +} + +static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s S enable=%d\n", __func__, enable); + mutex_lock(&dev->input_lock); + + if (enable) { + /* enable per frame MIPI and sensor ctrl reset */ + ret = gc0310_write_reg(client, GC0310_8BIT, + 0xFE, 0x30); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + } + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM, + enable ? GC0310_START_STREAMING : + GC0310_STOP_STREAMING); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + mutex_unlock(&dev->input_lock); + pr_info("%s E\n", __func__); + return ret; +} + + +static int gc0310_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + pr_info("%s S\n", __func__); + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = gc0310_detect(client); + if (ret) { + dev_err(&client->dev, "gc0310_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + pr_info("%s E\n", __func__); + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc0310_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + gc0310_res[dev->fmt_idx].fps; + } + return 0; +} + +static int gc0310_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + gc0310_res = gc0310_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + gc0310_res = gc0310_res_still; + N_RES = N_RES_STILL; + break; + default: + gc0310_res = gc0310_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int gc0310_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = gc0310_res[dev->fmt_idx].fps; + + return 0; +} + +static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; + return 0; +} + +static int gc0310_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = gc0310_res[index].width; + fse->min_height = gc0310_res[index].height; + fse->max_width = gc0310_res[index].width; + fse->max_height = gc0310_res[index].height; + + return 0; + +} + + +static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = gc0310_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { + .g_skip_frames = gc0310_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops gc0310_video_ops = { + .s_stream = gc0310_s_stream, + .g_parm = gc0310_g_parm, + .s_parm = gc0310_s_parm, + .g_frame_interval = gc0310_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops gc0310_core_ops = { + .s_power = gc0310_s_power, + .ioctl = gc0310_ioctl, +}; + +static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { + .enum_mbus_code = gc0310_enum_mbus_code, + .enum_frame_size = gc0310_enum_frame_size, + .get_fmt = gc0310_get_fmt, + .set_fmt = gc0310_set_fmt, +}; + +static const struct v4l2_subdev_ops gc0310_ops = { + .core = &gc0310_core_ops, + .video = &gc0310_video_ops, + .pad = &gc0310_pad_ops, + .sensor = &gc0310_sensor_ops, +}; + +static int gc0310_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *dev = to_gc0310_sensor(sd); + dev_dbg(&client->dev, "gc0310_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int gc0310_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gc0310_device *dev; + int ret; + void *pdata; + unsigned int i; + + pr_info("%s S\n", __func__); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops); + + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_8, + atomisp_bayer_order_grbg); + else + pdata = client->dev.platform_data; + + if (!pdata) { + ret = -EINVAL; + goto out_free; + } + + ret = gc0310_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(gc0310_controls)); + if (ret) { + gc0310_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + gc0310_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; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + gc0310_remove(client); + + pr_info("%s E\n", __func__); + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +static const struct acpi_device_id gc0310_acpi_match[] = { + {"XXGC0310"}, + {"INT0310"}, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); + +MODULE_DEVICE_TABLE(i2c, gc0310_id); +static struct i2c_driver gc0310_driver = { + .driver = { + .name = GC0310_NAME, + .acpi_match_table = ACPI_PTR(gc0310_acpi_match), + }, + .probe = gc0310_probe, + .remove = gc0310_remove, + .id_table = gc0310_id, +}; + +static int init_gc0310(void) +{ + return i2c_add_driver(&gc0310_driver); +} + +static void exit_gc0310(void) +{ + + i2c_del_driver(&gc0310_driver); +} + +module_init(init_gc0310); +module_exit(exit_gc0310); + +MODULE_AUTHOR("Lai, Angie "); +MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c new file mode 100644 index 000000000000..e43d31ea9676 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -0,0 +1,1219 @@ +/* + * Support for GalaxyCore GC2235 2M camera sensor. + * + * Copyright (c) 2014 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include +#include + +#include "gc2235.h" + +/* i2c read/write stuff */ +static int gc2235_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != GC2235_8BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == GC2235_8BIT) + *val = (u8)data[0]; + + return 0; +} + +static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int gc2235_write_reg(struct i2c_client *client, u16 data_length, + u8 reg, u8 val) +{ + int ret; + unsigned char data[4] = {0}; + const u16 len = data_length + sizeof(u8); /* 16-bit address + data */ + + if (data_length != GC2235_8BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + data[0] = reg; + data[1] = val; + + ret = gc2235_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +static int __gc2235_flush_reg_array(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ + ctrl->index = 0; + + return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __gc2235_buf_reg_array(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl, + const struct gc2235_reg *next) +{ + int size; + + if (next->type != GC2235_8BIT) + return -EINVAL; + + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE) + return __gc2235_flush_reg_array(client, ctrl); + + return 0; +} +static int __gc2235_write_reg_is_consecutive(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl, + const struct gc2235_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} +static int gc2235_write_reg_array(struct i2c_client *client, + const struct gc2235_reg *reglist) +{ + const struct gc2235_reg *next = reglist; + struct gc2235_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != GC2235_TOK_TERM; next++) { + switch (next->type & GC2235_TOK_MASK) { + case GC2235_TOK_DELAY: + err = __gc2235_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__gc2235_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __gc2235_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __gc2235_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __gc2235_flush_reg_array(client, &ctrl); +} + +static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; + return 0; +} + +static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; + return 0; +} + +static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | + (GC2235_F_NUMBER_DEM << 16) | + (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; + return 0; +} + + +static int gc2235_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct gc2235_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + u16 reg_val, reg_val_h, dummy; + int ret; + + if (!info) + return -EINVAL; + + /* pixel clock calculattion */ + buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; + + /* get integration time */ + buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + GC2235_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + GC2235_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_CROP_START_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_CROP_START_L, ®_val); + if (ret) + return ret; + + buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_CROP_START_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_CROP_START_L, ®_val); + if (ret) + return ret; + + buf->crop_vertical_start = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_OUTSIZE_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_width = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_OUTSIZE_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_height = (reg_val_h << 8) | reg_val; + + buf->crop_horizontal_end = buf->crop_horizontal_start + + buf->output_width - 1; + buf->crop_vertical_end = buf->crop_vertical_start + + buf->output_height - 1; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_HB_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_HB_L, ®_val); + if (ret) + return ret; + + dummy = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SH_DELAY_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SH_DELAY_L, ®_val); + +#if 0 + buf->line_length_pck = buf->output_width + 16 + dummy + + (((u16)reg_val_h << 8) | (u16)reg_val) + 4; +#endif + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_VB_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_VB_L, ®_val); + if (ret) + return ret; + +#if 0 + buf->frame_length_lines = buf->output_height + 32 + + (((u16)reg_val_h << 8) | (u16)reg_val); +#endif + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 coarse_integration = (u16)coarse_itg; + int ret = 0; + u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0; + expo_coarse_h = coarse_integration >> 8; + expo_coarse_l = coarse_integration & 0xff; + + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_H, expo_coarse_h); + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_L, expo_coarse_l); + + if (gain <= 0x58) { + gain_val = 0x40; + gain_val2 = 0x58; + } else if (gain < 256) { + gain_val = 0x40; + gain_val2 = gain; + } else { + gain_val2 = 64 * gain / 256; + gain_val = 0xff; + } + + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_GLOBAL_GAIN, (u8)gain_val); + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_PRE_GAIN, (u8)gain_val2); + + return ret; +} + + +static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __gc2235_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long gc2235_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return gc2235_set_exposure(sd, exp, gain, digitgain); +} +static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return gc2235_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + + *value = reg_v; +err: + return ret; +} + +static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc2235_device *dev = + container_of(ctrl->handler, struct gc2235_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = gc2235_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = gc2235_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .g_volatile_ctrl = gc2235_g_volatile_ctrl +}; + +static struct v4l2_ctrl_config gc2235_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = GC2235_FOCAL_LENGTH_DEFAULT, + .max = GC2235_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = GC2235_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = GC2235_F_NUMBER_DEFAULT, + .max = GC2235_F_NUMBER_DEFAULT, + .step = 0x01, + .def = GC2235_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = GC2235_F_NUMBER_RANGE, + .max = GC2235_F_NUMBER_RANGE, + .step = 0x01, + .def = GC2235_F_NUMBER_RANGE, + .flags = 0, + }, +}; + +static int __gc2235_init(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* restore settings */ + gc2235_res = gc2235_res_preview; + N_RES = N_RES_PREVIEW; + + return gc2235_write_reg_array(client, gc2235_init_settings); +} + +static int is_init; + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = -1; + struct gc2235_device *dev = to_gc2235_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + usleep_range(60, 90); + if (ret == 0) + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + } else { + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + int ret = -1; + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + usleep_range(60, 90); + return dev->platform_data->gpio0_ctrl(sd, flag); +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + msleep(5); + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int gc2235_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + if (on == 0) + ret = power_down(sd); + else { + ret = power_up(sd); + if (!ret) + ret = __gc2235_init(sd); + is_init = 1; + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct gc2235_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct gc2235_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &gc2235_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != gc2235_res[i].width) + continue; + if (h != gc2235_res[i].height) + continue; + + return i; + } + + return -1; +} + +static int startup(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + if (is_init == 0) { + /* force gc2235 to do a reset in res change, otherwise it + * can not output normal after switching res. and it is not + * necessary for first time run up after power on, for the sack + * of performance + */ + power_down(sd); + power_up(sd); + gc2235_write_reg_array(client, gc2235_init_settings); + } + + ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "gc2235 write register err.\n"); + return ret; + } + is_init = 0; + + return ret; +} + +static int gc2235_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 gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *gc2235_info = NULL; + int ret = 0; + int idx; + + gc2235_info = v4l2_get_subdev_hostdata(sd); + if (!gc2235_info) + return -EINVAL; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = gc2235_res[N_RES - 1].width; + fmt->height = gc2235_res[N_RES - 1].height; + } else { + fmt->width = gc2235_res[idx].width; + fmt->height = gc2235_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + ret = startup(sd); + if (ret) { + dev_err(&client->dev, "gc2235 startup err\n"); + goto err; + } + + ret = gc2235_get_intg_factor(client, gc2235_info, + &gc2235_res[dev->fmt_idx]); + if (ret) + dev_err(&client->dev, "failed to get integration_factor\n"); + +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc2235_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 gc2235_device *dev = to_gc2235_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = gc2235_res[dev->fmt_idx].width; + fmt->height = gc2235_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int gc2235_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SENSOR_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SENSOR_ID_L, &low); + id = ((high << 8) | low); + + if (id != GC2235_ID) { + dev_err(&client->dev, "sensor ID error, 0x%x\n", id); + return -ENODEV; + } + + dev_info(&client->dev, "detect gc2235 success\n"); + return 0; +} + +static int gc2235_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + mutex_lock(&dev->input_lock); + + if (enable) + ret = gc2235_write_reg_array(client, gc2235_stream_on); + else + ret = gc2235_write_reg_array(client, gc2235_stream_off); + + mutex_unlock(&dev->input_lock); + return ret; +} + + +static int gc2235_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = gc2235_detect(client); + if (ret) { + dev_err(&client->dev, "gc2235_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc2235_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + gc2235_res[dev->fmt_idx].fps; + } + return 0; +} + +static int gc2235_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + gc2235_res = gc2235_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + gc2235_res = gc2235_res_still; + N_RES = N_RES_STILL; + break; + default: + gc2235_res = gc2235_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int gc2235_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = gc2235_res[dev->fmt_idx].fps; + + return 0; +} + +static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int gc2235_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = gc2235_res[index].width; + fse->min_height = gc2235_res[index].height; + fse->max_width = gc2235_res[index].width; + fse->max_height = gc2235_res[index].height; + + return 0; + +} + +static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = gc2235_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = { + .g_skip_frames = gc2235_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops gc2235_video_ops = { + .s_stream = gc2235_s_stream, + .g_parm = gc2235_g_parm, + .s_parm = gc2235_s_parm, + .g_frame_interval = gc2235_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops gc2235_core_ops = { + .s_power = gc2235_s_power, + .ioctl = gc2235_ioctl, +}; + +static const struct v4l2_subdev_pad_ops gc2235_pad_ops = { + .enum_mbus_code = gc2235_enum_mbus_code, + .enum_frame_size = gc2235_enum_frame_size, + .get_fmt = gc2235_get_fmt, + .set_fmt = gc2235_set_fmt, +}; + +static const struct v4l2_subdev_ops gc2235_ops = { + .core = &gc2235_core_ops, + .video = &gc2235_video_ops, + .pad = &gc2235_pad_ops, + .sensor = &gc2235_sensor_ops, +}; + +static int gc2235_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc2235_device *dev = to_gc2235_sensor(sd); + dev_dbg(&client->dev, "gc2235_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int gc2235_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gc2235_device *dev; + void *gcpdev; + int ret; + unsigned int i; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops); + + gcpdev = client->dev.platform_data; + if (ACPI_COMPANION(&client->dev)) + gcpdev = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + + ret = gc2235_s_config(&dev->sd, client->irq, gcpdev); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(gc2235_controls)); + if (ret) { + gc2235_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + gc2235_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; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + gc2235_remove(client); + + if (ACPI_HANDLE(&client->dev)) + ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA); + + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + + return ret; +} + +static const struct acpi_device_id gc2235_acpi_match[] = { + { "INT33F8" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match); +MODULE_DEVICE_TABLE(i2c, gc2235_id); +static struct i2c_driver gc2235_driver = { + .driver = { + .name = GC2235_NAME, + .acpi_match_table = ACPI_PTR(gc2235_acpi_match), + }, + .probe = gc2235_probe, + .remove = gc2235_remove, + .id_table = gc2235_id, +}; + +static int init_gc2235(void) +{ + return i2c_add_driver(&gc2235_driver); +} + +static void exit_gc2235(void) +{ + + i2c_del_driver(&gc2235_driver); +} + +module_init(init_gc2235); +module_exit(exit_gc2235); + +MODULE_AUTHOR("Shuguang Gong "); +MODULE_DESCRIPTION("A low-level driver for GC2235 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c new file mode 100644 index 000000000000..decb65cfd7c9 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c @@ -0,0 +1,209 @@ +/* + * 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. + * + */ +#include +#include +#include +#include +#include "../include/linux/libmsrlisthelper.h" +#include +#include + +/* Tagged binary data container structure definitions. */ +struct tbd_header { + uint32_t tag; /*!< Tag identifier, also checks endianness */ + uint32_t size; /*!< Container size including this header */ + uint32_t version; /*!< Version, format 0xYYMMDDVV */ + uint32_t revision; /*!< Revision, format 0xYYMMDDVV */ + uint32_t config_bits; /*!< Configuration flag bits set */ + uint32_t checksum; /*!< Global checksum, header included */ +} __packed; + +struct tbd_record_header { + uint32_t size; /*!< Size of record including header */ + uint8_t format_id; /*!< tbd_format_t enumeration values used */ + uint8_t packing_key; /*!< Packing method; 0 = no packing */ + uint16_t class_id; /*!< tbd_class_t enumeration values used */ +} __packed; + +struct tbd_data_record_header { + uint16_t next_offset; + uint16_t flags; + uint16_t data_offset; + uint16_t data_size; +} __packed; + +#define TBD_CLASS_DRV_ID 2 + +static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, + unsigned int size) +{ + /* The configuration data contains any number of sequences where + * the first byte (that is, uint8_t) that marks the number of bytes + * in the sequence to follow, is indeed followed by the indicated + * number of bytes of actual data to be written to sensor. + * By convention, the first two bytes of actual data should be + * understood as an address in the sensor address space (hibyte + * followed by lobyte) where the remaining data in the sequence + * will be written. */ + + uint8_t *ptr = bufptr; + while (ptr < bufptr + size) { + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + }; + int ret; + + /* How many bytes */ + msg.len = *ptr++; + /* Where the bytes are located */ + msg.buf = ptr; + ptr += msg.len; + + if (ptr > bufptr + size) + /* Accessing data beyond bounds is not tolerated */ + return -EINVAL; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "i2c write error: %d", ret); + return ret; + } + } + return 0; +} + +static int parse_and_apply(struct i2c_client *client, uint8_t *buffer, + unsigned int size) +{ + uint8_t *endptr8 = buffer + size; + struct tbd_data_record_header *header = + (struct tbd_data_record_header *)buffer; + + /* There may be any number of datasets present */ + unsigned int dataset = 0; + + do { + /* In below, four variables are read from buffer */ + if ((uint8_t *)header + sizeof(*header) > endptr8) + return -EINVAL; + + /* All data should be located within given buffer */ + if ((uint8_t *)header + header->data_offset + + header->data_size > endptr8) + return -EINVAL; + + /* We have a new valid dataset */ + dataset++; + /* See whether there is MSR data */ + /* If yes, update the reg info */ + if (header->data_size && (header->flags & 1)) { + int ret; + + dev_info(&client->dev, + "New MSR data for sensor driver (dataset %02d) size:%d\n", + dataset, header->data_size); + ret = set_msr_configuration(client, + buffer + header->data_offset, + header->data_size); + if (ret) + return ret; + } + header = (struct tbd_data_record_header *)(buffer + + header->next_offset); + } while (header->next_offset); + + return 0; +} + +int apply_msr_data(struct i2c_client *client, const struct firmware *fw) +{ + struct tbd_header *header; + struct tbd_record_header *record; + + if (!fw) { + dev_warn(&client->dev, "Drv data is not loaded.\n"); + return -EINVAL; + } + + if (sizeof(*header) > fw->size) + return -EINVAL; + + header = (struct tbd_header *)fw->data; + /* Check that we have drvb block. */ + if (memcmp(&header->tag, "DRVB", 4)) + return -EINVAL; + + /* Check the size */ + if (header->size != fw->size) + return -EINVAL; + + if (sizeof(*header) + sizeof(*record) > fw->size) + return -EINVAL; + + record = (struct tbd_record_header *)(header + 1); + /* Check that class id mathes tbd's drv id. */ + if (record->class_id != TBD_CLASS_DRV_ID) + return -EINVAL; + + /* Size 0 shall not be treated as an error */ + if (!record->size) + return 0; + + return parse_and_apply(client, (uint8_t *)(record + 1), record->size); +} +EXPORT_SYMBOL_GPL(apply_msr_data); + +int load_msr_list(struct i2c_client *client, char *name, + const struct firmware **fw) +{ + int ret = request_firmware(fw, name, &client->dev); + if (ret) { + dev_err(&client->dev, + "Error %d while requesting firmware %s\n", + ret, name); + return ret; + } + dev_info(&client->dev, "Received %lu bytes drv data\n", + (unsigned long)(*fw)->size); + + return 0; +} +EXPORT_SYMBOL_GPL(load_msr_list); + +void release_msr_list(struct i2c_client *client, const struct firmware *fw) +{ + release_firmware(fw); +} +EXPORT_SYMBOL_GPL(release_msr_list); + +static int init_msrlisthelper(void) +{ + return 0; +} + +static void exit_msrlisthelper(void) +{ +} + +module_init(init_msrlisthelper); +module_exit(exit_msrlisthelper); + +MODULE_AUTHOR("Jukka Kaartinen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c new file mode 100644 index 000000000000..679176f7c542 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -0,0 +1,1009 @@ +/* + * LED flash driver for LM3554 + * + * Copyright (c) 2010-2012 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../include/media/lm3554.h" +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include "../include/linux/atomisp.h" + +/* Registers */ + +#define LM3554_TORCH_BRIGHTNESS_REG 0xA0 +#define LM3554_TORCH_MODE_SHIFT 0 +#define LM3554_TORCH_CURRENT_SHIFT 3 +#define LM3554_INDICATOR_CURRENT_SHIFT 6 + +#define LM3554_FLASH_BRIGHTNESS_REG 0xB0 +#define LM3554_FLASH_MODE_SHIFT 0 +#define LM3554_FLASH_CURRENT_SHIFT 3 +#define LM3554_STROBE_SENSITIVITY_SHIFT 7 + +#define LM3554_FLASH_DURATION_REG 0xC0 +#define LM3554_FLASH_TIMEOUT_SHIFT 0 +#define LM3554_CURRENT_LIMIT_SHIFT 5 + +#define LM3554_FLAGS_REG 0xD0 +#define LM3554_FLAG_TIMEOUT (1 << 0) +#define LM3554_FLAG_THERMAL_SHUTDOWN (1 << 1) +#define LM3554_FLAG_LED_FAULT (1 << 2) +#define LM3554_FLAG_TX1_INTERRUPT (1 << 3) +#define LM3554_FLAG_TX2_INTERRUPT (1 << 4) +#define LM3554_FLAG_LED_THERMAL_FAULT (1 << 5) +#define LM3554_FLAG_UNUSED (1 << 6) +#define LM3554_FLAG_INPUT_VOLTAGE_LOW (1 << 7) + +#define LM3554_CONFIG_REG_1 0xE0 +#define LM3554_ENVM_TX2_SHIFT 5 +#define LM3554_TX2_POLARITY_SHIFT 6 + +struct lm3554 { + struct v4l2_subdev sd; + + struct mutex power_lock; + struct v4l2_ctrl_handler ctrl_handler; + int power_count; + + unsigned int mode; + int timeout; + u8 torch_current; + u8 indicator_current; + u8 flash_current; + + struct timer_list flash_off_delay; + struct lm3554_platform_data *pdata; +}; + +#define to_lm3554(p_sd) container_of(p_sd, struct lm3554, sd) + +/* Return negative errno else zero on success */ +static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + ret = i2c_smbus_write_byte_data(client, addr, val); + + dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, + ret < 0 ? "fail" : "ok"); + + return ret; +} + +/* Return negative errno else a data byte received from the device. */ +static int lm3554_read(struct lm3554 *flash, u8 addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + ret = i2c_smbus_read_byte_data(client, addr); + + dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret, + ret < 0 ? "fail" : "ok"); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode) +{ + u8 val; + int ret; + + val = (mode << LM3554_FLASH_MODE_SHIFT) | + (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); + + ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); + if (ret == 0) + flash->mode = mode; + return ret; +} + +static int lm3554_set_torch(struct lm3554 *flash) +{ + u8 val; + + val = (flash->mode << LM3554_TORCH_MODE_SHIFT) | + (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) | + (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT); + + return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val); +} + +static int lm3554_set_flash(struct lm3554 *flash) +{ + u8 val; + + val = (flash->mode << LM3554_FLASH_MODE_SHIFT) | + (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); + + return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); +} + +static int lm3554_set_duration(struct lm3554 *flash) +{ + u8 val; + + val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) | + (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT); + + return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val); +} + +static int lm3554_set_config1(struct lm3554 *flash) +{ + u8 val; + + val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) | + (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT); + return lm3554_write(flash, LM3554_CONFIG_REG_1, val); +} + +/* ----------------------------------------------------------------------------- + * Hardware trigger + */ +static void lm3554_flash_off_delay(long unsigned int arg) +{ + struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + + gpio_set_value(pdata->gpio_strobe, 0); +} + +static int lm3554_hw_strobe(struct i2c_client *client, bool strobe) +{ + int ret, timer_pending; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + + /* + * An abnormal high flash current is observed when strobe off the + * flash. Workaround here is firstly set flash current to lower level, + * wait a short moment, and then strobe off the flash. + */ + + timer_pending = del_timer_sync(&flash->flash_off_delay); + + /* Flash off */ + if (!strobe) { + /* set current to 70mA and wait a while */ + ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0); + if (ret < 0) + goto err; + mod_timer(&flash->flash_off_delay, + jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY)); + return 0; + } + + /* Flash on */ + + /* + * If timer is killed before run, flash is not strobe off, + * so must strobe off here + */ + if (timer_pending) + gpio_set_value(pdata->gpio_strobe, 0); + + /* Restore flash current settings */ + ret = lm3554_set_flash(flash); + if (ret < 0) + goto err; + + /* Strobe on Flash */ + gpio_set_value(pdata->gpio_strobe, 1); + + return 0; +err: + dev_err(&client->dev, "failed to %s flash strobe (%d)\n", + strobe ? "on" : "off", ret); + return ret; +} + +/* ----------------------------------------------------------------------------- + * V4L2 controls + */ + +static int lm3554_read_status(struct lm3554 *flash) +{ + int ret; + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + + /* NOTE: reading register clear fault status */ + ret = lm3554_read(flash, LM3554_FLAGS_REG); + if (ret < 0) + return ret; + + /* + * Accordingly to datasheet we read back '1' in bit 6. + * Clear it first. + */ + ret &= ~LM3554_FLAG_UNUSED; + + /* + * Do not take TX1/TX2 signal as an error + * because MSIC will not turn off flash, but turn to + * torch mode according to gsm modem signal by hardware. + */ + ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT); + + if (ret > 0) + dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret); + + return ret; +} + +static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val) +{ + struct lm3554 *flash = to_lm3554(sd); + + val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT); + val = val / LM3554_TIMEOUT_STEPSIZE - 1; + + flash->timeout = val; + + return lm3554_set_duration(flash); +} + +static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE; + + return 0; +} + +static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP); + + flash->flash_current = intensity; + + return lm3554_set_flash(flash); +} + +static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current, + LM3554_FLASH_STEP); + + return 0; +} + +static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP); + + flash->torch_current = intensity; + + return lm3554_set_torch(flash); +} + +static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current, + LM3554_TORCH_STEP); + + return 0; +} + +static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP); + + flash->indicator_current = intensity; + + return lm3554_set_torch(flash); +} + +static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current, + LM3554_INDICATOR_STEP); + + return 0; +} + +static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return lm3554_hw_strobe(client, val); +} + +static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode) +{ + struct lm3554 *flash = to_lm3554(sd); + unsigned int mode; + + switch (new_mode) { + case ATOMISP_FLASH_MODE_OFF: + mode = LM3554_MODE_SHUTDOWN; + break; + case ATOMISP_FLASH_MODE_FLASH: + mode = LM3554_MODE_FLASH; + break; + case ATOMISP_FLASH_MODE_INDICATOR: + mode = LM3554_MODE_INDICATOR; + break; + case ATOMISP_FLASH_MODE_TORCH: + mode = LM3554_MODE_TORCH; + break; + default: + return -EINVAL; + } + + return lm3554_set_mode(flash, mode); +} + +static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + *val = flash->mode; + return 0; +} + +static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + int value; + + value = lm3554_read_status(flash); + if (value < 0) + return value; + + if (value & LM3554_FLAG_TIMEOUT) + *val = ATOMISP_FLASH_STATUS_TIMEOUT; + else if (value > 0) + *val = ATOMISP_FLASH_STATUS_HW_ERROR; + else + *val = ATOMISP_FLASH_STATUS_OK; + + return 0; +} + +#ifndef CSS15 +static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + int ret; + + ret = lm3554_read(flash, LM3554_FLAGS_REG); + + if (ret < 0) + return ret; + + *val = ret; + return 0; +} +#endif + +static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3554 *dev = + container_of(ctrl->handler, struct lm3554, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FLASH_TIMEOUT: + ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_INTENSITY: + ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_TORCH_INTENSITY: + ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_STROBE: + ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_MODE: + ret = lm3554_s_flash_mode(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3554 *dev = + container_of(ctrl->handler, struct lm3554, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FLASH_TIMEOUT: + ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_INTENSITY: + ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_TORCH_INTENSITY: + ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_MODE: + ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_STATUS: + ret = lm3554_g_flash_status(&dev->sd, &ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_FLASH_STATUS_REGISTER: + ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val); + break; +#endif + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = lm3554_s_ctrl, + .g_volatile_ctrl = lm3554_g_volatile_ctrl +}; + +static const struct v4l2_ctrl_config lm3554_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_TIMEOUT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Timeout", + .min = 0x0, + .max = LM3554_MAX_TIMEOUT, + .step = 0x01, + .def = LM3554_DEFAULT_TIMEOUT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_FLASH_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_TORCH_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Torch Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_TORCH_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_INDICATOR_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Indicator Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STROBE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Strobe", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_MODE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Mode", + .min = 0, + .max = 100, + .step = 1, + .def = ATOMISP_FLASH_MODE_OFF, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STATUS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Status", + .min = 0, + .max = 100, + .step = 1, + .def = ATOMISP_FLASH_STATUS_OK, + .flags = 0, + }, +#ifndef CSS15 + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STATUS_REGISTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Status Register", + .min = 0, + .max = 100, + .step = 1, + .def = 0, + .flags = 0, + }, +#endif +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +/* Put device into known state. */ +static int lm3554_setup(struct lm3554 *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + /* clear the flags register */ + ret = lm3554_read(flash, LM3554_FLAGS_REG); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Fault info: %02x\n", ret); + + ret = lm3554_set_config1(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_duration(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_torch(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_flash(flash); + if (ret < 0) + return ret; + + /* read status */ + ret = lm3554_read_status(flash); + if (ret < 0) + return ret; + + return ret ? -EIO : 0; +} + +static int __lm3554_s_power(struct lm3554 *flash, int power) +{ + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + /*initialize flash driver*/ + gpio_set_value(pdata->gpio_reset, power); + usleep_range(100, 100 + 1); + + if (power) { + /* Setup default values. This makes sure that the chip + * is in a known state. + */ + ret = lm3554_setup(flash); + if (ret < 0) { + __lm3554_s_power(flash, 0); + return ret; + } + } + + return 0; +} + +static int lm3554_s_power(struct v4l2_subdev *sd, int power) +{ + struct lm3554 *flash = to_lm3554(sd); + int ret = 0; + + mutex_lock(&flash->power_lock); + + if (flash->power_count == !power) { + ret = __lm3554_s_power(flash, !!power); + if (ret < 0) + goto done; + } + + flash->power_count += power ? 1 : -1; + WARN_ON(flash->power_count < 0); + +done: + mutex_unlock(&flash->power_lock); + return ret; +} + +static const struct v4l2_subdev_core_ops lm3554_core_ops = { + .s_power = lm3554_s_power, +}; + +static const struct v4l2_subdev_ops lm3554_ops = { + .core = &lm3554_core_ops, +}; + +static int lm3554_detect(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_adapter *adapter = client->adapter; + struct lm3554 *flash = to_lm3554(sd); + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "lm3554_detect i2c error\n"); + return -ENODEV; + } + + /* Power up the flash driver and reset it */ + ret = lm3554_s_power(&flash->sd, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed to power on lm3554 LED flash\n"); + } else { + dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n"); + lm3554_s_power(&flash->sd, 0); + } + + return ret; +} + +static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return lm3554_s_power(sd, 1); +} + +static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return lm3554_s_power(sd, 0); +} + +static const struct v4l2_subdev_internal_ops lm3554_internal_ops = { + .registered = lm3554_detect, + .open = lm3554_open, + .close = lm3554_close, +}; + +/* ----------------------------------------------------------------------------- + * I2C driver + */ +#ifdef CONFIG_PM + +static int lm3554_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __lm3554_s_power(flash, 0); + + dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); + + return rval; +} + +static int lm3554_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __lm3554_s_power(flash, 1); + + dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); + + return rval; +} + +#else + +#define lm3554_suspend NULL +#define lm3554_resume NULL + +#endif /* CONFIG_PM */ + +static int lm3554_gpio_init(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + if (!gpio_is_valid(pdata->gpio_reset)) + return -EINVAL; + + ret = gpio_direction_output(pdata->gpio_reset, 0); + if (ret < 0) + goto err_gpio_reset; + dev_info(&client->dev, "flash led reset successfully\n"); + + if (!gpio_is_valid(pdata->gpio_strobe)) { + ret = -EINVAL; + goto err_gpio_dir_reset; + } + + ret = gpio_direction_output(pdata->gpio_strobe, 0); + if (ret < 0) + goto err_gpio_strobe; + + return 0; + +err_gpio_strobe: + gpio_free(pdata->gpio_strobe); +err_gpio_dir_reset: + gpio_direction_output(pdata->gpio_reset, 0); +err_gpio_reset: + gpio_free(pdata->gpio_reset); + + return ret; +} + +static int lm3554_gpio_uninit(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + ret = gpio_direction_output(pdata->gpio_strobe, 0); + if (ret < 0) + return ret; + + ret = gpio_direction_output(pdata->gpio_reset, 0); + if (ret < 0) + return ret; + + gpio_free(pdata->gpio_strobe); + gpio_free(pdata->gpio_reset); + return 0; +} + +static void *lm3554_platform_data_func(struct i2c_client *client) +{ + static struct lm3554_platform_data platform_data; + + if (ACPI_COMPANION(&client->dev)) { + platform_data.gpio_reset = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 2, GPIOD_OUT_LOW)); + platform_data.gpio_strobe = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 0, GPIOD_OUT_LOW)); + platform_data.gpio_torch = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 1, GPIOD_OUT_LOW)); + } else { + platform_data.gpio_reset = -1; + platform_data.gpio_strobe = -1; + platform_data.gpio_torch = -1; + } + + dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n", + platform_data.gpio_reset, platform_data.gpio_strobe, + platform_data.gpio_torch); + + /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input: + * ENVM/TX pin asserted, flash forced into torch; + * ENVM/TX pin desserted, flash set back; + */ + platform_data.envm_tx2 = 1; + platform_data.tx2_polarity = 0; + + /* set peak current limit to be 1000mA */ + platform_data.current_limit = 0; + + return &platform_data; +} + +static int lm3554_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct lm3554 *flash; + unsigned int i; + int ret; + + flash = kzalloc(sizeof(*flash), GFP_KERNEL); + if (!flash) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + flash->pdata = client->dev.platform_data; + + if (!flash->pdata || ACPI_COMPANION(&client->dev)) + flash->pdata = lm3554_platform_data_func(client); + + v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops); + flash->sd.internal_ops = &lm3554_internal_ops; + flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + flash->mode = ATOMISP_FLASH_MODE_OFF; + flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1; + ret = + v4l2_ctrl_handler_init(&flash->ctrl_handler, + ARRAY_SIZE(lm3554_controls)); + if (ret) { + dev_err(&client->dev, "error initialize a ctrl_handler.\n"); + goto fail2; + } + + for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++) + v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i], + NULL); + + if (flash->ctrl_handler.error) { + + dev_err(&client->dev, "ctrl_handler error.\n"); + goto fail2; + } + + flash->sd.ctrl_handler = &flash->ctrl_handler; + err = media_entity_pads_init(&flash->sd.entity, 0, NULL); + if (err) { + dev_err(&client->dev, "error initialize a media entity.\n"); + goto fail1; + } + + flash->sd.entity.function = MEDIA_ENT_F_FLASH; + + mutex_init(&flash->power_lock); + + setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay, + (unsigned long)client); + + err = lm3554_gpio_init(client); + if (err) { + dev_err(&client->dev, "gpio request/direction_output fail"); + goto fail2; + } + if (ACPI_HANDLE(&client->dev)) + err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); + return 0; +fail2: + media_entity_cleanup(&flash->sd.entity); + v4l2_ctrl_handler_free(&flash->ctrl_handler); +fail1: + v4l2_device_unregister_subdev(&flash->sd); + kfree(flash); + + return err; +} + +static int lm3554_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + int ret; + + media_entity_cleanup(&flash->sd.entity); + v4l2_ctrl_handler_free(&flash->ctrl_handler); + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + del_timer_sync(&flash->flash_off_delay); + + ret = lm3554_gpio_uninit(client); + if (ret < 0) + goto fail; + + kfree(flash); + + return 0; +fail: + dev_err(&client->dev, "gpio request/direction_output fail"); + return ret; +} + +static const struct i2c_device_id lm3554_id[] = { + {LM3554_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, lm3554_id); + +static const struct dev_pm_ops lm3554_pm_ops = { + .suspend = lm3554_suspend, + .resume = lm3554_resume, +}; + +static const struct acpi_device_id lm3554_acpi_match[] = { + { "INTCF1C" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match); + +static struct i2c_driver lm3554_driver = { + .driver = { + .name = LM3554_NAME, + .pm = &lm3554_pm_ops, + .acpi_match_table = ACPI_PTR(lm3554_acpi_match), + }, + .probe = lm3554_probe, + .remove = lm3554_remove, + .id_table = lm3554_id, +}; + +static __init int init_lm3554(void) +{ + return i2c_add_driver(&lm3554_driver); +} + +static __exit void exit_lm3554(void) +{ + i2c_del_driver(&lm3554_driver); +} + +module_init(init_lm3554); +module_exit(exit_lm3554); +MODULE_AUTHOR("Jing Tao "); +MODULE_DESCRIPTION("LED flash driver for LM3554"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c new file mode 100644 index 000000000000..3c837cb8859c --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -0,0 +1,1963 @@ +/* + * Support for mt9m114 Camera Sensor. + * + * Copyright (c) 2010 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include + +#include "mt9m114.h" + +#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd) + +/* + * TODO: use debug parameter to actually define when debug messages should + * be printed. + */ +static int debug; +static int aaalock; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value); +static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value); +static int mt9m114_wait_state(struct i2c_client *client, int timeout); + +static int +mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[4]; + + if (!client->adapter) { + v4l2_err(client, "%s error, no client->adapter\n", __func__); + return -ENODEV; + } + + if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT + && data_length != MISENSOR_32BIT) { + v4l2_err(client, "%s error, invalid data length\n", __func__); + return -EINVAL; + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = MSG_LEN_OFFSET; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u16) (reg >> 8); + data[1] = (u16) (reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = 0; + /* high byte comes first */ + if (data_length == MISENSOR_8BIT) + *val = data[0]; + else if (data_length == MISENSOR_16BIT) + *val = data[1] + (data[0] << 8); + else + *val = data[3] + (data[2] << 8) + + (data[1] << 16) + (data[0] << 24); + + return 0; + } + + dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); + return err; +} + +static int +mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val) +{ + int num_msg; + struct i2c_msg msg; + unsigned char data[6] = {0}; + u16 *wreg; + int retry = 0; + + if (!client->adapter) { + v4l2_err(client, "%s error, no client->adapter\n", __func__); + return -ENODEV; + } + + if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT + && data_length != MISENSOR_32BIT) { + v4l2_err(client, "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + +again: + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2 + data_length; + msg.buf = data; + + /* high byte goes out first */ + wreg = (u16 *)data; + *wreg = cpu_to_be16(reg); + + if (data_length == MISENSOR_8BIT) { + data[2] = (u8)(val); + } else if (data_length == MISENSOR_16BIT) { + u16 *wdata = (u16 *)&data[2]; + *wdata = be16_to_cpu((u16)val); + } else { + /* MISENSOR_32BIT */ + u32 *wdata = (u32 *)&data[2]; + *wdata = be32_to_cpu(val); + } + + num_msg = i2c_transfer(client->adapter, &msg, 1); + + /* + * HACK: Need some delay here for Rev 2 sensors otherwise some + * registers do not seem to load correctly. + */ + mdelay(1); + + if (num_msg >= 0) + return 0; + + dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, num_msg); + if (retry <= I2C_RETRY_COUNT) { + dev_dbg(&client->dev, "retrying... %d", retry); + retry++; + msleep(20); + goto again; + } + + return num_msg; +} + +/** + * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor + * device + * @client: i2c driver client structure + * @data_length: 8/16/32-bits length + * @reg: register address + * @mask: masked out bits + * @set: bits set + * + * Read/modify/write a value to a register in the sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int +misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg, + u32 mask, u32 set) +{ + int err; + u32 val; + + /* Exit when no mask */ + if (mask == 0) + return 0; + + /* @mask must not exceed data length */ + switch (data_length) { + case MISENSOR_8BIT: + if (mask & ~0xff) + return -EINVAL; + break; + case MISENSOR_16BIT: + if (mask & ~0xffff) + return -EINVAL; + break; + case MISENSOR_32BIT: + break; + default: + /* Wrong @data_length */ + return -EINVAL; + } + + err = mt9m114_read_reg(client, data_length, reg, &val); + if (err) { + v4l2_err(client, "misensor_rmw_reg error exit, read failed\n"); + return -EINVAL; + } + + val &= ~mask; + + /* + * Perform the OR function if the @set exists. + * Shift @set value to target bit location. @set should set only + * bits included in @mask. + * + * REVISIT: This function expects @set to be non-shifted. Its shift + * value is then defined to be equal to mask's LSB position. + * How about to inform values in their right offset position and avoid + * this unneeded shift operation? + */ + set <<= ffs(mask) - 1; + val |= set & mask; + + err = mt9m114_write_reg(client, data_length, reg, val); + if (err) { + v4l2_err(client, "misensor_rmw_reg error exit, write failed\n"); + return -EINVAL; + } + + return 0; +} + + +static int __mt9m114_flush_reg_array(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + int retry = 0; + + if (ctrl->index == 0) + return 0; + +again: + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2 + ctrl->index; + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + msg.buf = (u8 *)&ctrl->buffer; + + ret = i2c_transfer(client->adapter, &msg, num_msg); + if (ret != num_msg) { + if (++retry <= I2C_RETRY_COUNT) { + dev_dbg(&client->dev, "retrying... %d\n", retry); + msleep(20); + goto again; + } + dev_err(&client->dev, "%s: i2c transfer error\n", __func__); + return -EIO; + } + + ctrl->index = 0; + + /* + * REVISIT: Previously we had a delay after writing data to sensor. + * But it was removed as our tests have shown it is not necessary + * anymore. + */ + + return 0; +} + +static int __mt9m114_buf_reg_array(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl, + const struct misensor_reg *next) +{ + u16 *data16; + u32 *data32; + int err; + + /* Insufficient buffer? Let's flush and get more free space. */ + if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) { + err = __mt9m114_flush_reg_array(client, ctrl); + if (err) + return err; + } + + switch (next->length) { + case MISENSOR_8BIT: + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case MISENSOR_16BIT: + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + case MISENSOR_32BIT: + data32 = (u32 *)&ctrl->buffer.data[ctrl->index]; + *data32 = cpu_to_be32(next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += next->length; + + return 0; +} + +static int +__mt9m114_write_reg_is_consecutive(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl, + const struct misensor_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +/* + * mt9m114_write_reg_array - Initializes a list of mt9m114 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * @poll: completion polling requirement + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and + * __mt9m114_write_reg_is_consecutive() are internal functions to + * mt9m114_write_reg_array() and should be not used anywhere else. + * + */ +static int mt9m114_write_reg_array(struct i2c_client *client, + const struct misensor_reg *reglist, + int poll) +{ + const struct misensor_reg *next = reglist; + struct mt9m114_write_ctrl ctrl; + int err; + + if (poll == PRE_POLLING) { + err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); + if (err) + return err; + } + + ctrl.index = 0; + for (; next->length != MISENSOR_TOK_TERM; next++) { + switch (next->length & MISENSOR_TOK_MASK) { + case MISENSOR_TOK_DELAY: + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + case MISENSOR_TOK_RMW: + err = __mt9m114_flush_reg_array(client, &ctrl); + err |= misensor_rmw_reg(client, + next->length & + ~MISENSOR_TOK_RMW, + next->reg, next->val, + next->val2); + if (err) { + dev_err(&client->dev, "%s read err. aborted\n", + __func__); + return -EINVAL; + } + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__mt9m114_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __mt9m114_buf_reg_array(client, &ctrl, next); + if (err) { + v4l2_err(client, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + + if (poll == POST_POLLING) + return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); + + return 0; +} + +static int mt9m114_wait_state(struct i2c_client *client, int timeout) +{ + int ret; + unsigned int val; + + while (timeout-- > 0) { + ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val); + if (ret) + return ret; + if ((val & 0x2) == 0) + return 0; + msleep(20); + } + + return -EINVAL; + +} + +static int mt9m114_set_suspend(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + return mt9m114_write_reg_array(client, + mt9m114_standby_reg, POST_POLLING); +} + +static int mt9m114_init_common(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING); +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret) + ret = dev->platform_data->v2p8_ctrl(sd, 0); + } + } else { + ret = dev->platform_data->v2p8_ctrl(sd, 0); + ret = dev->platform_data->v1p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* Note: current modules wire only one GPIO signal (RESET#), + * but the schematic wires up two to the connector. BIOS + * versions have been unfortunately inconsistent with which + * ACPI index RESET# is on, so hit both */ + + if (flag) { + ret = dev->platform_data->gpio0_ctrl(sd, 0); + ret = dev->platform_data->gpio1_ctrl(sd, 0); + msleep(60); + ret |= dev->platform_data->gpio0_ctrl(sd, 1); + ret |= dev->platform_data->gpio1_ctrl(sd, 1); + } else { + ret = dev->platform_data->gpio0_ctrl(sd, 0); + ret = dev->platform_data->gpio1_ctrl(sd, 0); + } + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) + dev_err(&client->dev, "gpio failed 1\n"); + /* + * according to DS, 44ms is needed between power up and first i2c + * commend + */ + msleep(50); + + return 0; + +fail_clk: + dev->platform_data->flisclk_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 1\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + /*according to DS, 20ms is needed after power down*/ + msleep(20); + + return ret; +} + +static int mt9m114_s_power(struct v4l2_subdev *sd, int power) +{ + if (power == 0) + return power_down(sd); + else { + if (power_up(sd)) + return -EINVAL; + + return mt9m114_init_common(sd); + } +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 600 +static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h) +{ + unsigned int w_ratio; + unsigned int h_ratio; + int match; + + if (w == 0) + return -1; + w_ratio = (res->width << 13) / w; + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + const struct mt9m114_res_struct *tmp_res = NULL; + + for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) { + tmp_res = &mt9m114_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int mt9m114_try_res(u32 *w, u32 *h) +{ + int idx = 0; + + if ((*w > MT9M114_RES_960P_SIZE_H) + || (*h > MT9M114_RES_960P_SIZE_V)) { + *w = MT9M114_RES_960P_SIZE_H; + *h = MT9M114_RES_960P_SIZE_V; + } else { + idx = nearest_resolution_index(*w, *h); + + /* + * nearest_resolution_index() doesn't return smaller + * resolutions. If it fails, it means the requested + * resolution is higher than wecan support. Fallback + * to highest possible resolution in this case. + */ + if (idx == -1) + idx = ARRAY_SIZE(mt9m114_res) - 1; + + *w = mt9m114_res[idx].width; + *h = mt9m114_res[idx].height; + } + + return 0; +} + +static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h) +{ + int index; + + for (index = 0; index < N_RES; index++) { + if ((mt9m114_res[index].width == w) && + (mt9m114_res[index].height == h)) + break; + } + + /* No mode found */ + if (index >= N_RES) + return NULL; + + return &mt9m114_res[index]; +} + +static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + unsigned short hsize; + unsigned short vsize; + + switch (dev->res) { + case MT9M114_RES_736P: + hsize = MT9M114_RES_736P_SIZE_H; + vsize = MT9M114_RES_736P_SIZE_V; + break; + case MT9M114_RES_864P: + hsize = MT9M114_RES_864P_SIZE_H; + vsize = MT9M114_RES_864P_SIZE_V; + break; + case MT9M114_RES_960P: + hsize = MT9M114_RES_960P_SIZE_H; + vsize = MT9M114_RES_960P_SIZE_V; + break; + default: + v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__, + dev->res); + return -EINVAL; + } + + if (h_size != NULL) + *h_size = hsize; + if (v_size != NULL) + *v_size = vsize; + + return 0; +} + +static int mt9m114_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct mt9m114_res_struct *res) +{ + struct atomisp_sensor_mode_data *buf = &info->data; + u32 reg_val; + int ret; + + if (info == NULL) + return -EINVAL; + + ret = mt9m114_read_reg(client, MISENSOR_32BIT, + REG_PIXEL_CLK, ®_val); + if (ret) + return ret; + buf->vt_pix_clk_freq_mhz = reg_val; + + /* get integration time */ + buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + MT9M114_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + MT9M114_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; + + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_H_START, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_V_START, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_H_END, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_V_END, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_WIDTH, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_HEIGHT, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_TIMING_HTS, ®_val); + if (ret) + return ret; + buf->line_length_pck = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_TIMING_VTS, ®_val); + if (ret) + return ret; + buf->frame_length_lines = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static int mt9m114_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + int width, height; + int ret; + if (format->pad) + return -EINVAL; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + ret = mt9m114_res2size(sd, &width, &height); + if (ret) + return ret; + fmt->width = width; + fmt->height = height; + + return 0; +} + +static int mt9m114_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 i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct mt9m114_res_struct *res_index; + u32 width = fmt->width; + u32 height = fmt->height; + struct camera_mipi_info *mt9m114_info = NULL; + + int ret; + if (format->pad) + return -EINVAL; + dev->streamon = 0; + dev->first_exp = MT9M114_DEFAULT_FIRST_EXP; + + mt9m114_info = v4l2_get_subdev_hostdata(sd); + if (mt9m114_info == NULL) + return -EINVAL; + + mt9m114_try_res(&width, &height); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + return 0; + } + res_index = mt9m114_to_res(width, height); + + /* Sanity check */ + if (unlikely(!res_index)) { + WARN_ON(1); + return -EINVAL; + } + + switch (res_index->res) { + case MT9M114_RES_736P: + ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING); + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + case MT9M114_RES_864P: + ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING); + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + case MT9M114_RES_960P: + ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING); + /* set sensor read_mode to Normal */ + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + default: + v4l2_err(sd, "set resolution: %d failed!\n", res_index->res); + return -EINVAL; + } + + if (ret) + return -EINVAL; + + ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING); + if (ret < 0) + return ret; + + if (mt9m114_set_suspend(sd)) + return -EINVAL; + + if (dev->res != res_index->res) { + int index; + + /* Switch to different size */ + if (width <= 640) { + dev->nctx = 0x00; /* Set for context A */ + } else { + /* + * Context B is used for resolutions larger than 640x480 + * Using YUV for Context B. + */ + dev->nctx = 0x01; /* set for context B */ + } + + /* + * Marked current sensor res as being "used" + * + * REVISIT: We don't need to use an "used" field on each mode + * list entry to know which mode is selected. If this + * information is really necessary, how about to use a single + * variable on sensor dev struct? + */ + for (index = 0; index < N_RES; index++) { + if ((width == mt9m114_res[index].width) && + (height == mt9m114_res[index].height)) { + mt9m114_res[index].used = true; + continue; + } + mt9m114_res[index].used = false; + } + } + ret = mt9m114_get_intg_factor(c, mt9m114_info, + &mt9m114_res[res_index->res]); + if (ret) { + dev_err(&c->dev, "failed to get integration_factor\n"); + return -EINVAL; + } + /* + * mt9m114 - we don't poll for context switch + * because it does not happen with streaming disabled. + */ + dev->res = res_index->res; + + fmt->width = width; + fmt->height = height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + return 0; +} + +/* TODO: Update to SOC functions, remove exposure and gain */ +static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; + return 0; +} + +static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for mt9m114*/ + *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; + return 0; +} + +static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | + (MT9M114_F_NUMBER_DEM << 16) | + (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; + return 0; +} + +/* Horizontal flip the image. */ +static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int ret; + u32 data; + ret = mt9m114_read_reg(c, MISENSOR_16BIT, + (u32)MISENSOR_READ_MODE, &data); + if (ret) + return ret; + *val = !!(data & MISENSOR_HFLIP_MASK); + + return 0; +} + +static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int ret; + u32 data; + + ret = mt9m114_read_reg(c, MISENSOR_16BIT, + (u32)MISENSOR_READ_MODE, &data); + if (ret) + return ret; + *val = !!(data & MISENSOR_VFLIP_MASK); + + return 0; +} + +static long mt9m114_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + int ret = 0; + unsigned int coarse_integration = 0; + unsigned int fine_integration = 0; + unsigned int FLines = 0; + unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */ + unsigned int AnalogGain, DigitalGain; + u32 AnalogGainToWrite = 0; + u16 exposure_local[3]; + + dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__, + exposure->integration_time[0], exposure->gain[0], + exposure->gain[1]); + + coarse_integration = exposure->integration_time[0]; + /* fine_integration = ExposureTime.FineIntegrationTime; */ + /* FrameLengthLines = ExposureTime.FrameLengthLines; */ + FLines = mt9m114_res[dev->res].lines_per_frame; + AnalogGain = exposure->gain[0]; + DigitalGain = exposure->gain[1]; + if (!dev->streamon) { + /*Save the first exposure values while stream is off*/ + dev->first_exp = coarse_integration; + dev->first_gain = AnalogGain; + dev->first_diggain = DigitalGain; + } + /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) + + ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */ + + /* set frame length */ + if (FLines < coarse_integration + 6) + FLines = coarse_integration + 6; + if (FLines < FrameLengthLines) + FLines = FrameLengthLines; + ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines); + if (ret) { + v4l2_err(client, "%s: fail to set FLines\n", __func__); + return -EINVAL; + } + + /* set coarse/fine integration */ + exposure_local[0] = REG_EXPO_COARSE; + exposure_local[1] = (u16)coarse_integration; + exposure_local[2] = (u16)fine_integration; + /* 3A provide real exposure time. + should not translate to any value here. */ + ret = mt9m114_write_reg(client, MISENSOR_16BIT, + REG_EXPO_COARSE, (u16)(coarse_integration)); + if (ret) { + v4l2_err(client, "%s: fail to set exposure time\n", __func__); + return -EINVAL; + } + + /* + // set analog/digital gain + switch(AnalogGain) + { + case 0: + AnalogGainToWrite = 0x0; + break; + case 1: + AnalogGainToWrite = 0x20; + break; + case 2: + AnalogGainToWrite = 0x60; + break; + case 4: + AnalogGainToWrite = 0xA0; + break; + case 8: + AnalogGainToWrite = 0xE0; + break; + default: + AnalogGainToWrite = 0x20; + break; + } + */ + if (DigitalGain >= 16 || DigitalGain <= 1) + DigitalGain = 1; + /* AnalogGainToWrite = + (u16)((DigitalGain << 12) | AnalogGainToWrite); */ + AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain); + ret = mt9m114_write_reg(client, MISENSOR_16BIT, + REG_GAIN, AnalogGainToWrite); + if (ret) { + v4l2_err(client, "%s: fail to set AnalogGainToWrite\n", + __func__); + return -EINVAL; + } + + return ret; +} + +static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return mt9m114_s_exposure(sd, arg); + default: + return -EINVAL; + } + + return 0; +} + +/* This returns the exposure time being used. This should only be used + for filling in EXIF data, not for actual image processing. */ +static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u32 coarse; + int ret; + + /* the fine integration time is currently not calculated */ + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_EXPO_COARSE, &coarse); + if (ret) + return ret; + + *value = coarse; + return 0; +} +#ifndef CSS15 +/* + * This function will return the sensor supported max exposure zone number. + * the sensor which supports max exposure zone number is 1. + */ +static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val) +{ + *val = 1; + + return 0; +} + +/* + * set exposure metering, average/center_weighted/spot/matrix. + */ +static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + switch (val) { + case V4L2_EXPOSURE_METERING_SPOT: + ret = mt9m114_write_reg_array(client, mt9m114_exp_average, + NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_average reg err.\n"); + return ret; + } + break; + case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: + default: + ret = mt9m114_write_reg_array(client, mt9m114_exp_center, + NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_default reg err"); + return ret; + } + } + + return 0; +} + +/* + * This function is for touch exposure feature. + */ +static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct misensor_reg exp_reg; + int width, height; + int grid_width, grid_height; + int grid_left, grid_top, grid_right, grid_bottom; + int win_left, win_top, win_right, win_bottom; + int i, j; + int ret; + + if (sel->which != V4L2_SUBDEV_FORMAT_TRY && + sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + grid_left = sel->r.left; + grid_top = sel->r.top; + grid_right = sel->r.left + sel->r.width - 1; + grid_bottom = sel->r.top + sel->r.height - 1; + + ret = mt9m114_res2size(sd, &width, &height); + if (ret) + return ret; + + grid_width = width / 5; + grid_height = height / 5; + + if (grid_width && grid_height) { + win_left = grid_left / grid_width; + win_top = grid_top / grid_height; + win_right = grid_right / grid_width; + win_bottom = grid_bottom / grid_height; + } else { + dev_err(&client->dev, "Incorrect exp grid.\n"); + return -EINVAL; + } + + win_left = clamp_t(int, win_left, 0, 4); + win_top = clamp_t(int, win_top, 0, 4); + win_right = clamp_t(int, win_right, 0, 4); + win_bottom = clamp_t(int, win_bottom, 0, 4); + + ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_average reg err.\n"); + return ret; + } + + for (i = win_top; i <= win_bottom; i++) { + for (j = win_left; j <= win_right; j++) { + exp_reg = mt9m114_exp_win[i][j]; + + ret = mt9m114_write_reg(client, exp_reg.length, + exp_reg.reg, exp_reg.val); + if (ret) { + dev_err(&client->dev, "write exp_reg err.\n"); + return ret; + } + } + } + + return 0; +} +#endif + +static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + *val = mt9m114_res[dev->res].bin_factor_x; + + return 0; +} + +static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + *val = mt9m114_res[dev->res].bin_factor_y; + + return 0; +} + +static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + s32 luma = 0x37; + int err; + + /* EV value only support -2 to 2 + * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17 + */ + if (val < -2 || val > 2) + return -EINVAL; + luma += 0x10 * val; + dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma); + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); + if (err) { + dev_err(&c->dev, "%s logic addr access error\n", __func__); + return err; + } + err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma); + if (err) { + dev_err(&c->dev, "%s write target_average_luma failed\n", + __func__); + return err; + } + udelay(10); + + return 0; +} + +static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int err; + u32 luma; + + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); + if (err) { + dev_err(&c->dev, "%s logic addr access error\n", __func__); + return err; + } + err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma); + if (err) { + dev_err(&c->dev, "%s read target_average_luma failed\n", + __func__); + return err; + } + luma -= 0x17; + luma /= 0x10; + *val = (s32)luma - 2; + dev_dbg(&c->dev, "%s val:%d\n", __func__, *val); + + return 0; +} + +/* Fake interface + * mt9m114 now can not support 3a_lock +*/ +static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val) +{ + aaalock = val; + return 0; +} + +static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val) +{ + if (aaalock) + return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE + | V4L2_LOCK_FOCUS; + return 0; +} + +static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114_device *dev = + container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = mt9m114_t_vflip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = mt9m114_t_hflip(&dev->sd, ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_EXPOSURE_METERING: + ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val); + break; +#endif + case V4L2_CID_EXPOSURE: + ret = mt9m114_s_ev(&dev->sd, ctrl->val); + break; + case V4L2_CID_3A_LOCK: + ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114_device *dev = + container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ret = mt9m114_g_vflip(&dev->sd, &ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = mt9m114_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_EXPOSURE_ZONE_NUM: + ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); + break; +#endif + case V4L2_CID_BIN_FACTOR_HORZ: + ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + case V4L2_CID_EXPOSURE: + ret = mt9m114_g_ev(&dev->sd, &ctrl->val); + break; + case V4L2_CID_3A_LOCK: + ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = mt9m114_s_ctrl, + .g_volatile_ctrl = mt9m114_g_volatile_ctrl +}; + +static struct v4l2_ctrl_config mt9m114_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .name = "Image v-Flip", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .name = "Image h-Flip", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .name = "focal length", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_FOCAL_LENGTH_DEFAULT, + .max = MT9M114_FOCAL_LENGTH_DEFAULT, + .step = 1, + .def = MT9M114_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .name = "f-number", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_F_NUMBER_DEFAULT, + .max = MT9M114_F_NUMBER_DEFAULT, + .step = 1, + .def = MT9M114_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .name = "f-number range", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_F_NUMBER_RANGE, + .max = MT9M114_F_NUMBER_RANGE, + .step = 1, + .def = MT9M114_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .name = "exposure", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xffff, + .step = 1, + .def = 0, + .flags = 0, + }, +#ifndef CSS15 + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ZONE_NUM, + .name = "one-time exposure zone number", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xffff, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_METERING, + .name = "metering", + .type = V4L2_CTRL_TYPE_MENU, + .min = 0, + .max = 3, + .step = 0, + .def = 1, + .flags = 0, + }, +#endif + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .name = "horizontal binning factor", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = MT9M114_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .name = "vertical binning factor", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = MT9M114_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE, + .name = "exposure biasx", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -2, + .max = 2, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_3A_LOCK, + .name = "3a lock", + .type = V4L2_CTRL_TYPE_BITMASK, + .min = 0, + .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u32 retvalue; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "%s: i2c error", __func__); + return -ENODEV; + } + mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); + dev->real_model_id = retvalue; + + if (retvalue != MT9M114_MOD_ID) { + dev_err(&client->dev, "%s: failed: client->addr = %x\n", + __func__, client->addr); + return -ENODEV; + } + + return 0; +} + +static int +mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + v4l2_err(client, "mt9m114 platform init err\n"); + return ret; + } + } + ret = power_up(sd); + if (ret) { + v4l2_err(client, "mt9m114 power-up err"); + return ret; + } + + /* config & detect sensor */ + ret = mt9m114_detect(dev, client); + if (ret) { + v4l2_err(client, "mt9m114_detect err s_config.\n"); + goto fail_detect; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + ret = mt9m114_set_suspend(sd); + if (ret) { + v4l2_err(client, "mt9m114 suspend err"); + return ret; + } + + ret = power_down(sd); + if (ret) { + v4l2_err(client, "mt9m114 power down err"); + return ret; + } + + return ret; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_detect: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); + return ret; +} + +/* Horizontal flip the image. */ +static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + int err; + /* set for direct mode */ + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); + if (value) { + /* enable H flip ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN); + + dev->bpat = MT9M114_BPAT_GRGRBGBG; + } else { + /* disable H flip ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS); + + dev->bpat = MT9M114_BPAT_BGBGGRGR; + } + + err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); + udelay(10); + + return !!err; +} + +/* Vertically flip the image */ +static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int err; + /* set for direct mode */ + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); + if (value >= 1) { + /* enable H flip - ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN); + } else { + /* disable H flip - ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS); + } + + err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); + udelay(10); + + return !!err; +} +static int mt9m114_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + return 0; +} + +static int mt9m114_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = mt9m114_res[dev->res].fps; + + return 0; +} + +static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable) +{ + int ret; + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct atomisp_exposure exposure; + + if (enable) { + ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, + POST_POLLING); + if (ret < 0) + return ret; + + if (dev->first_exp > MT9M114_MAX_FIRST_EXP) { + exposure.integration_time[0] = dev->first_exp; + exposure.gain[0] = dev->first_gain; + exposure.gain[1] = dev->first_diggain; + mt9m114_s_exposure(sd, &exposure); + } + dev->streamon = 1; + + } else { + dev->streamon = 0; + ret = mt9m114_set_suspend(sd); + } + + return ret; +} + +static int mt9m114_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_SGRBG10_1X10; + + return 0; +} + +static int mt9m114_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + + unsigned int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = mt9m114_res[index].width; + fse->min_height = mt9m114_res[index].height; + fse->max_width = mt9m114_res[index].width; + fse->max_height = mt9m114_res[index].height; + + return 0; +} + +static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + int index; + struct mt9m114_device *snr = to_mt9m114_sensor(sd); + + if (frames == NULL) + return -EINVAL; + + for (index = 0; index < N_RES; index++) { + if (mt9m114_res[index].res == snr->res) + break; + } + + if (index >= N_RES) + return -EINVAL; + + *frames = mt9m114_res[index].skip_frames; + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9m114_video_ops = { + .s_parm = mt9m114_s_parm, + .s_stream = mt9m114_s_stream, + .g_frame_interval = mt9m114_g_frame_interval, +}; + +static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { + .g_skip_frames = mt9m114_g_skip_frames, +}; + +static const struct v4l2_subdev_core_ops mt9m114_core_ops = { + .s_power = mt9m114_s_power, + .ioctl = mt9m114_ioctl, +}; + +/* REVISIT: Do we need pad operations? */ +static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = { + .enum_mbus_code = mt9m114_enum_mbus_code, + .enum_frame_size = mt9m114_enum_frame_size, + .get_fmt = mt9m114_get_fmt, + .set_fmt = mt9m114_set_fmt, +#ifndef CSS15 + .set_selection = mt9m114_s_exposure_selection, +#endif +}; + +static const struct v4l2_subdev_ops mt9m114_ops = { + .core = &mt9m114_core_ops, + .video = &mt9m114_video_ops, + .pad = &mt9m114_pad_ops, + .sensor = &mt9m114_sensor_ops, +}; + +static const struct media_entity_operations mt9m114_entity_ops = { + .link_setup = NULL, +}; + +static int mt9m114_remove(struct i2c_client *client) +{ + struct mt9m114_device *dev; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + dev = container_of(sd, struct mt9m114_device, sd); + dev->platform_data->csi_cfg(sd, 0); + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + return 0; +} + +static int mt9m114_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mt9m114_device *dev; + int ret = 0; + unsigned int i; + void *pdata; + + /* Setup sensor configuration structure */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); + pdata = client->dev.platform_data; + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + if (pdata) + ret = mt9m114_s_config(&dev->sd, client->irq, pdata); + if (!pdata || ret) { + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; + } + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) { + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + /* Coverity CID 298095 - return on error */ + return ret; + } + + /*TODO add format code here*/ + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(mt9m114_controls)); + if (ret) { + mt9m114_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + mt9m114_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; + + /* REVISIT: Do we need media controller? */ + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) { + mt9m114_remove(client); + return ret; + } + return 0; +} + +MODULE_DEVICE_TABLE(i2c, mt9m114_id); + +static const struct acpi_device_id mt9m114_acpi_match[] = { + { "INT33F0" }, + { "CRMT1040" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match); + +static struct i2c_driver mt9m114_driver = { + .driver = { + .name = "mt9m114", + .acpi_match_table = ACPI_PTR(mt9m114_acpi_match), + }, + .probe = mt9m114_probe, + .remove = mt9m114_remove, + .id_table = mt9m114_id, +}; + +static __init int init_mt9m114(void) +{ + return i2c_add_driver(&mt9m114_driver); +} + +static __exit void exit_mt9m114(void) +{ + i2c_del_driver(&mt9m114_driver); +} + +module_init(init_mt9m114); +module_exit(exit_mt9m114); + +MODULE_AUTHOR("Shuguang Gong "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c new file mode 100644 index 000000000000..51b7d61df0f5 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -0,0 +1,1557 @@ +/* + * Support for OmniVision OV2680 1080p HD camera sensor. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" + +#include "ov2680.h" + +static int h_flag = 0; +static int v_flag = 0; +static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { + atomisp_bayer_order_bggr, + atomisp_bayer_order_grbg, + atomisp_bayer_order_gbrg, + atomisp_bayer_order_rggb, +}; + +/* i2c read/write stuff */ +static int ov2680_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV2680_8BIT && data_length != OV2680_16BIT + && data_length != OV2680_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0 , sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV2680_8BIT) + *val = (u8)data[0]; + else if (data_length == OV2680_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + //dev_dbg(&client->dev, "++++i2c read adr%x = %x\n", reg,*val); + return 0; +} + +static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + //dev_dbg(&client->dev, "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]); + return ret == num_msg ? 0 : -EIO; +} + +static int ov2680_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV2680_8BIT) { + data[2] = (u8)(val); + } else { + /* OV2680_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov2680_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov2680_write_reg_array - Initializes a list of OV2680 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and + * __ov2680_write_reg_is_consecutive() are internal functions to + * ov2680_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov2680_flush_reg_array(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov2680_buf_reg_array(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl, + const struct ov2680_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV2680_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV2680_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE) + return __ov2680_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov2680_write_reg_is_consecutive(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl, + const struct ov2680_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov2680_write_reg_array(struct i2c_client *client, + const struct ov2680_reg *reglist) +{ + const struct ov2680_reg *next = reglist; + struct ov2680_write_ctrl ctrl; + int err; + dev_dbg(&client->dev, "++++write reg array\n"); + ctrl.index = 0; + for (; next->type != OV2680_TOK_TERM; next++) { + switch (next->type & OV2680_TOK_MASK) { + case OV2680_TOK_DELAY: + err = __ov2680_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + dev_dbg(&client->dev, "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val); + if (!__ov2680_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov2680_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov2680_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov2680_flush_reg_array(client, &ctrl); +} +static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + + *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for ov2680*/ + + *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; + return 0; +} + +static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | + (OV2680_F_NUMBER_DEM << 16) | + (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; + return 0; +} + +static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); + *val = ov2680_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + *val = ov2680_res[dev->fmt_idx].bin_factor_y; + dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); + return 0; +} + + +static int ov2680_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov2680_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + unsigned int pix_clk_freq_hz; + u16 reg_val; + int ret; + dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); + if (!info) + return -EINVAL; + + /* pixel clock */ + pix_clk_freq_hz = res->pix_clk_freq * 1000000; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV2680_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV2680_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + (res->bin_factor_x * 2) : 1; + buf->binning_factor_y = res->bin_factor_y ? + (res->bin_factor_y * 2) : 1; + return 0; +} + +static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2680_device *dev = to_ov2680_sensor(sd); + u16 vts,hts; + int ret,exp_val; + + dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); + + hts = ov2680_res[dev->fmt_idx].pixels_per_line; + vts = ov2680_res[dev->fmt_idx].lines_per_frame; + + /* group hold */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0x00); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_GROUP_ACCESS); + return ret; + } + + /* Increase the VTS to match exposure + MARGIN */ + if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) + vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; + + ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_TIMING_VTS_H); + return ret; + } + + /* set exposure */ + + /* Lower four bit should be 0*/ + exp_val = coarse_itg << 4; + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_L, exp_val & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_L); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_M); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_H); + return ret; + } + + /* Analog gain */ + ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_AGC_H); + return ret; + } + /* Digital gain */ + if (digitgain) { + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_RED_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_GREEN_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_BLUE_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + } + + /* End group */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0x10); + if (ret) + return ret; + + /* Delay launch group */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0xa0); + if (ret) + return ret; + return ret; +} + +static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov2680_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + u16 coarse_itg = exposure->integration_time[0]; + u16 analog_gain = exposure->gain[0]; + u16 digital_gain = exposure->gain[1]; + + /* we should not accept the invalid value below */ + if (analog_gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK + return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); +} + + + + + +static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov2680_s_exposure(sd, arg); + + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code) +{ + switch (code) { + case atomisp_bayer_order_rggb: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case atomisp_bayer_order_grbg: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case atomisp_bayer_order_bggr: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case atomisp_bayer_order_gbrg: + return MEDIA_BUS_FMT_SGBRG10_1X10; + } + return 0; +} + +static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct camera_mipi_info *ov2680_info = NULL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u16 val; + u8 index; + dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); + ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val); + if (ret) + return ret; + if (value) { + val |= OV2680_FLIP_MIRROR_BIT_ENABLE; + } else { + val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; + } + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_FLIP_REG, val); + if (ret) + return ret; + index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (ov2680_info) { + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; + dev->format.code = ov2680_translate_bayer_order( + ov2680_info->raw_bayer_order); + } + return ret; +} + +static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct camera_mipi_info *ov2680_info = NULL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u16 val; + u8 index; + dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); + + ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val); + if (ret) + return ret; + if (value) { + val |= OV2680_FLIP_MIRROR_BIT_ENABLE; + } else { + val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; + } + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_MIRROR_REG, val); + if (ret) + return ret; + index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (ov2680_info) { + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; + dev->format.code = ov2680_translate_bayer_order( + ov2680_info->raw_bayer_order); + } + return ret; +} + +static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *dev = + container_of(ctrl->handler, struct ov2680_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = ov2680_v_flip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = ov2680_h_flip(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *dev = + container_of(ctrl->handler, struct ov2680_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov2680_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov2680_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = ov2680_s_ctrl, + .g_volatile_ctrl = ov2680_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov2680_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV2680_FOCAL_LENGTH_DEFAULT, + .max = OV2680_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV2680_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV2680_F_NUMBER_DEFAULT, + .max = OV2680_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV2680_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV2680_F_NUMBER_RANGE, + .max = OV2680_F_NUMBER_RANGE, + .step = 0x01, + .def = OV2680_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = OV2680_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = OV2680_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, +}; + +static int ov2680_init_registers(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01); + ret |= ov2680_write_reg_array(client, ov2680_global_setting); + + return ret; +} + +static int ov2680_init(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + int ret; + + mutex_lock(&dev->input_lock); + + /* restore settings */ + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; + + ret = ov2680_init_registers(sd); + + mutex_unlock(&dev->input_lock); + + return ret; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = 0; + struct ov2680_device *dev = to_ov2680_sensor(sd); + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret |= dev->platform_data->v1p8_ctrl(sd, 1); + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + usleep_range(10000, 15000); + } + + if (!flag || ret) { + ret |= dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct ov2680_device *dev = to_ov2680_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* The OV2680 documents only one GPIO input (#XSHUTDN), but + * existing integrations often wire two (reset/power_down) + * because that is the way other sensors work. There is no + * way to tell how it is wired internally, so existing + * firmwares expose both and we drive them symmetrically. */ + if (flag) { + ret = dev->platform_data->gpio0_ctrl(sd, 1); + usleep_range(10000, 15000); + /* Ignore return from second gpio, it may not be there */ + dev->platform_data->gpio1_ctrl(sd, 1); + usleep_range(10000, 15000); + } else { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->gpio0_ctrl(sd, 0); + } + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + h_flag = 0; + v_flag = 0; + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int ov2680_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + if (on == 0){ + ret = power_down(sd); + } else { + ret = power_up(sd); + if (!ret) + return ov2680_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 600 +static int distance(struct ov2680_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); + + + if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct ov2680_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov2680_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov2680_res[i].width) + continue; + if (h != ov2680_res[i].height) + continue; + + return i; + } + + return -1; +} + +static int ov2680_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 ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov2680_info = NULL; + int ret = 0; + int idx = 0; + dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n"); + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (!ov2680_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov2680_res[N_RES - 1].width; + fmt->height = ov2680_res[N_RES - 1].height; + } else { + fmt->width = ov2680_res[idx].width; + fmt->height = ov2680_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n", + dev->fmt_idx); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx, + fmt->width, fmt->height); + dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n", + dev->fmt_idx, fmt->width, fmt->height); + + ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs); + if (ret) + dev_err(&client->dev, "ov2680 write resolution register err\n"); + + ret = ov2680_get_intg_factor(client, ov2680_info, + &ov2680_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + /*recall flip functions to avoid flip registers + * were overridden by default setting + */ + if (h_flag) + ov2680_h_flip(sd, h_flag); + if (v_flag) + ov2680_v_flip(sd, v_flag); + + v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx); + + /*ret = startup(sd); + * if (ret) + * dev_err(&client->dev, "ov2680 startup err\n"); + */ +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2680_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 ov2680_device *dev = to_ov2680_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = ov2680_res[dev->fmt_idx].width; + fmt->height = ov2680_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2680_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_CHIP_ID_L, &low); + id = ((((u16) high) << 8) | (u16) low); + + if (id != OV2680_ID) { + dev_err(&client->dev, "sensor ID error 0x%x\n", id); + return -ENODEV; + } + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); + + return 0; +} + +static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + if(enable ) + dev_dbg(&client->dev, "ov2680_s_stream one \n"); + else + dev_dbg(&client->dev, "ov2680_s_stream off \n"); + + ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM, + enable ? OV2680_START_STREAMING : + OV2680_STOP_STREAMING); +#if 0 + /* restore settings */ + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; +#endif + + //otp valid at stream on state + //if(!dev->otp_data) + // dev->otp_data = ov2680_otp_read(sd); + + mutex_unlock(&dev->input_lock); + + return ret; +} + + +static int ov2680_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov2680_detect(client); + if (ret) { + dev_err(&client->dev, "ov2680_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2680_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov2680_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov2680_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev->run_mode = param->parm.capture.capturemode; + + v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode); + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov2680_res = ov2680_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov2680_res = ov2680_res_still; + N_RES = N_RES_STILL; + break; + default: + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov2680_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov2680_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov2680_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov2680_res[index].width; + fse->min_height = ov2680_res[index].height; + fse->max_width = ov2680_res[index].width; + fse->max_height = ov2680_res[index].height; + + return 0; + +} + +static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = ov2680_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov2680_video_ops = { + .s_stream = ov2680_s_stream, + .g_parm = ov2680_g_parm, + .s_parm = ov2680_s_parm, + .g_frame_interval = ov2680_g_frame_interval, +}; + +static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { + .g_skip_frames = ov2680_g_skip_frames, +}; + +static const struct v4l2_subdev_core_ops ov2680_core_ops = { + .s_power = ov2680_s_power, + .ioctl = ov2680_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { + .enum_mbus_code = ov2680_enum_mbus_code, + .enum_frame_size = ov2680_enum_frame_size, + .get_fmt = ov2680_get_fmt, + .set_fmt = ov2680_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2680_ops = { + .core = &ov2680_core_ops, + .video = &ov2680_video_ops, + .pad = &ov2680_pad_ops, + .sensor = &ov2680_sensor_ops, +}; + +static int ov2680_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2680_device *dev = to_ov2680_sensor(sd); + dev_dbg(&client->dev, "ov2680_remove...\n"); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int ov2680_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov2680_device *dev; + int ret; + void *pdata; + unsigned int i; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops); + + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); + else + pdata = client->dev.platform_data; + + if (!pdata) { + ret = -EINVAL; + goto out_free; + } + + ret = ov2680_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(ov2680_controls)); + if (ret) { + ov2680_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + ov2680_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; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + { + ov2680_remove(client); + dev_dbg(&client->dev, "+++ remove ov2680 \n"); + } + return ret; +out_free: + dev_dbg(&client->dev, "+++ out free \n"); + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +static const struct acpi_device_id ov2680_acpi_match[] = { + {"XXOV2680"}, + {"OVTI2680"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); + + +MODULE_DEVICE_TABLE(i2c, ov2680_id); +static struct i2c_driver ov2680_driver = { + .driver = { + .owner = THIS_MODULE, + .name = OV2680_NAME, + .acpi_match_table = ACPI_PTR(ov2680_acpi_match), + + }, + .probe = ov2680_probe, + .remove = ov2680_remove, + .id_table = ov2680_id, +}; + +static int init_ov2680(void) +{ + return i2c_add_driver(&ov2680_driver); +} + +static void exit_ov2680(void) +{ + + i2c_del_driver(&ov2680_driver); +} + +module_init(init_ov2680); +module_exit(exit_ov2680); + +MODULE_AUTHOR("Jacky Wang "); +MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c new file mode 100644 index 000000000000..10094ac56561 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -0,0 +1,1373 @@ +/* + * Support for OmniVision OV2722 1080p HD camera sensor. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include +#include + +#include "ov2722.h" + +/* i2c read/write stuff */ +static int ov2722_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV2722_8BIT && data_length != OV2722_16BIT + && data_length != OV2722_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0 , sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV2722_8BIT) + *val = (u8)data[0]; + else if (data_length == OV2722_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + + return 0; +} + +static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int ov2722_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV2722_8BIT) { + data[2] = (u8)(val); + } else { + /* OV2722_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov2722_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov2722_write_reg_array - Initializes a list of OV2722 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and + * __ov2722_write_reg_is_consecutive() are internal functions to + * ov2722_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov2722_flush_reg_array(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov2722_buf_reg_array(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl, + const struct ov2722_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV2722_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV2722_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE) + return __ov2722_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov2722_write_reg_is_consecutive(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl, + const struct ov2722_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov2722_write_reg_array(struct i2c_client *client, + const struct ov2722_reg *reglist) +{ + const struct ov2722_reg *next = reglist; + struct ov2722_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != OV2722_TOK_TERM; next++) { + switch (next->type & OV2722_TOK_MASK) { + case OV2722_TOK_DELAY: + err = __ov2722_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__ov2722_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov2722_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov2722_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov2722_flush_reg_array(client, &ctrl); +} +static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; + return 0; +} + +static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | + (OV2722_F_NUMBER_DEM << 16) | + (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; + return 0; +} + +static int ov2722_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov2722_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2722_device *dev = NULL; + struct atomisp_sensor_mode_data *buf = &info->data; + const unsigned int ext_clk_freq_hz = 19200000; + const unsigned int pll_invariant_div = 10; + unsigned int pix_clk_freq_hz; + u16 pre_pll_clk_div; + u16 pll_multiplier; + u16 op_pix_clk_div; + u16 reg_val; + int ret; + + if (!info) + return -EINVAL; + + dev = to_ov2722_sensor(sd); + + /* pixel clock calculattion */ + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); + if (ret) + return ret; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); + if (ret) + return ret; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); + if (ret) + return ret; + + pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; + if (0 == pre_pll_clk_div) + return -EINVAL; + + pll_multiplier = pll_multiplier & 0x7f; + op_pix_clk_div = op_pix_clk_div & 0x03; + pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier + * op_pix_clk_div / pll_invariant_div; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV2722_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV2722_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_CROP_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_CROP_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_CROP_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_CROP_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_OUTSIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_OUTSIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2722_device *dev = to_ov2722_sensor(sd); + u16 hts, vts; + int ret; + + dev_dbg(&client->dev, "set_exposure without group hold\n"); + + /* clear VTS_DIFF on manual mode */ + ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0); + if (ret) + return ret; + + hts = dev->pixels_per_line; + vts = dev->lines_per_frame; + + if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts) + vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN; + + coarse_itg <<= 4; + digitgain <<= 2; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_VTS_H, vts); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_HTS_H, hts); + if (ret) + return ret; + + /* set exposure */ + ret = ov2722_write_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_L, + coarse_itg & 0xff); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_AEC_PK_EXPO_H, + (coarse_itg >> 8) & 0xfff); + if (ret) + return ret; + + /* set analog gain */ + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_AGC_ADJ_H, gain); + if (ret) + return ret; + + /* set digital gain */ + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_R_H, digitgain); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_G_H, digitgain); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_B_H, digitgain); + + return ret; +} + +static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov2722_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov2722_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return ov2722_set_exposure(sd, exp, gain, digitgain); +} + +static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov2722_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_L, + ®_v); + if (ret) + goto err; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2722_device *dev = + container_of(ctrl->handler, struct ov2722_device, ctrl_handler); + int ret = 0; + unsigned int val; + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov2722_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov2722_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_LINK_FREQ: + val = ov2722_res[dev->fmt_idx].mipi_freq; + if (val == 0) + return -EINVAL; + + ctrl->val = val * 1000; /* To Hz */ + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .g_volatile_ctrl = ov2722_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov2722_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV2722_FOCAL_LENGTH_DEFAULT, + .max = OV2722_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV2722_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV2722_F_NUMBER_DEFAULT, + .max = OV2722_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV2722_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV2722_F_NUMBER_RANGE, + .max = OV2722_F_NUMBER_RANGE, + .step = 0x01, + .def = OV2722_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_LINK_FREQ, + .name = "Link Frequency", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 1500000 * 1000, + .step = 1, + .def = 1, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, +}; + +static int ov2722_init(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + mutex_lock(&dev->input_lock); + + /* restore settings */ + ov2722_res = ov2722_res_preview; + N_RES = N_RES_PREVIEW; + + mutex_unlock(&dev->input_lock); + + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = -1; + struct ov2722_device *dev = to_ov2722_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + if (ret) + dev->platform_data->v1p8_ctrl(sd, 0); + } + } else { + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + int ret = -1; + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* Note: the GPIO order is asymmetric: always RESET# + * before PWDN# when turning it on or off. + */ + ret = dev->platform_data->gpio0_ctrl(sd, flag); + /* + *ov2722 PWDN# active high when pull down,opposite to the convention + */ + ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int ov2722_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) + return ov2722_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct ov2722_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct ov2722_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov2722_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov2722_res[i].width) + continue; + if (h != ov2722_res[i].height) + continue; + + return i; + } + + return -1; +} + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + ret = ov2722_write_reg(client, OV2722_8BIT, + OV2722_SW_RESET, 0x01); + if (ret) { + dev_err(&client->dev, "ov2722 reset err.\n"); + return ret; + } + + ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "ov2722 write register err.\n"); + return ret; + } + + return ret; +} + +static int ov2722_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 ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov2722_info = NULL; + int ret = 0; + int idx; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + ov2722_info = v4l2_get_subdev_hostdata(sd); + if (!ov2722_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov2722_res[N_RES - 1].width; + fmt->height = ov2722_res[N_RES - 1].height; + } else { + fmt->width = ov2722_res[idx].width; + fmt->height = ov2722_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line; + dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame; + + ret = startup(sd); + if (ret) { + int i = 0; + dev_err(&client->dev, "ov2722 startup err, retry to power up\n"); + for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) { + dev_err(&client->dev, + "ov2722 retry to power up %d/%d times, result: ", + i + 1, OV2722_POWER_UP_RETRY_NUM); + power_down(sd); + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "power up failed, continue\n"); + continue; + } + ret = startup(sd); + if (ret) { + dev_err(&client->dev, " startup FAILED!\n"); + } else { + dev_err(&client->dev, " startup SUCCESS!\n"); + break; + } + } + if (ret) { + dev_err(&client->dev, "ov2722 startup err\n"); + goto err; + } + } + + ret = ov2722_get_intg_factor(client, ov2722_info, + &ov2722_res[dev->fmt_idx]); + if (ret) + dev_err(&client->dev, "failed to get integration_factor\n"); + +err: + mutex_unlock(&dev->input_lock); + return ret; +} +static int ov2722_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 ov2722_device *dev = to_ov2722_sensor(sd); + + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + + fmt->width = ov2722_res[dev->fmt_idx].width; + fmt->height = ov2722_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2722_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_L, &low); + id = (high << 8) | low; + + if ((id != OV2722_ID) && (id != OV2720_ID)) { + dev_err(&client->dev, "sensor ID error\n"); + return -ENODEV; + } + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); + dev_dbg(&client->dev, "detect ov2722 success\n"); + return 0; +} + +static int ov2722_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + + ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM, + enable ? OV2722_START_STREAMING : + OV2722_STOP_STREAMING); + + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2722_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov2722_detect(client); + if (ret) { + dev_err(&client->dev, "ov2722_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2722_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov2722_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov2722_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov2722_res = ov2722_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov2722_res = ov2722_res_still; + N_RES = N_RES_STILL; + break; + default: + ov2722_res = ov2722_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov2722_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov2722_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov2722_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov2722_res[index].width; + fse->min_height = ov2722_res[index].height; + fse->max_width = ov2722_res[index].width; + fse->max_height = ov2722_res[index].height; + + return 0; + +} + + +static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = ov2722_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = { + .g_skip_frames = ov2722_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops ov2722_video_ops = { + .s_stream = ov2722_s_stream, + .g_parm = ov2722_g_parm, + .s_parm = ov2722_s_parm, + .g_frame_interval = ov2722_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops ov2722_core_ops = { + .s_power = ov2722_s_power, + .ioctl = ov2722_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov2722_pad_ops = { + .enum_mbus_code = ov2722_enum_mbus_code, + .enum_frame_size = ov2722_enum_frame_size, + .get_fmt = ov2722_get_fmt, + .set_fmt = ov2722_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2722_ops = { + .core = &ov2722_core_ops, + .video = &ov2722_video_ops, + .pad = &ov2722_pad_ops, + .sensor = &ov2722_sensor_ops, +}; + +static int ov2722_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2722_device *dev = to_ov2722_sensor(sd); + dev_dbg(&client->dev, "ov2722_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + media_entity_cleanup(&dev->sd.entity); + kfree(dev); + + return 0; +} + +static int __ov2722_init_ctrl_handler(struct ov2722_device *dev) +{ + struct v4l2_ctrl_handler *hdl; + unsigned int i; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls)); + for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i], + NULL); + + dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ); + + if (dev->ctrl_handler.error || !dev->link_freq) + return dev->ctrl_handler.error; + + dev->sd.ctrl_handler = hdl; + + return 0; +} + +static int ov2722_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov2722_device *dev; + void *ovpdev; + int ret; + struct acpi_device *adev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops); + + ovpdev = client->dev.platform_data; + adev = ACPI_COMPANION(&client->dev); + if (adev) { + adev->power.flags.power_resources = 0; + ovpdev = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + } + + ret = ov2722_s_config(&dev->sd, client->irq, ovpdev); + if (ret) + goto out_free; + + ret = __ov2722_init_ctrl_handler(dev); + if (ret) + goto out_ctrl_handler_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + ov2722_remove(client); + + if (ACPI_HANDLE(&client->dev)) + ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA); + + return ret; + +out_ctrl_handler_free: + v4l2_ctrl_handler_free(&dev->ctrl_handler); + +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +MODULE_DEVICE_TABLE(i2c, ov2722_id); + +static const struct acpi_device_id ov2722_acpi_match[] = { + { "INT33FB" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match); + +static struct i2c_driver ov2722_driver = { + .driver = { + .name = OV2722_NAME, + .acpi_match_table = ACPI_PTR(ov2722_acpi_match), + }, + .probe = ov2722_probe, + .remove = ov2722_remove, + .id_table = ov2722_id, +}; + +static int init_ov2722(void) +{ + return i2c_add_driver(&ov2722_driver); +} + +static void exit_ov2722(void) +{ + + i2c_del_driver(&ov2722_driver); +} + +module_init(init_ov2722); +module_exit(exit_ov2722); + +MODULE_AUTHOR("Wei Liu "); +MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/gc0310.c b/drivers/staging/media/atomisp/i2c/gc0310.c deleted file mode 100644 index 35ed51ffe944..000000000000 --- a/drivers/staging/media/atomisp/i2c/gc0310.c +++ /dev/null @@ -1,1490 +0,0 @@ -/* - * Support for GalaxyCore GC0310 VGA camera sensor. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" - -#include "gc0310.h" - -/* i2c read/write stuff */ -static int gc0310_read_reg(struct i2c_client *client, - u16 data_length, u8 reg, u8 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[1]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != GC0310_8BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == GC0310_8BIT) - *val = (u8)data[0]; - - return 0; -} - -static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int gc0310_write_reg(struct i2c_client *client, u16 data_length, - u8 reg, u8 val) -{ - int ret; - unsigned char data[2] = {0}; - u8 *wreg = (u8 *)data; - const u16 len = data_length + sizeof(u8); /* 8-bit address + data */ - - if (data_length != GC0310_8BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = (u8)(reg & 0xff); - - if (data_length == GC0310_8BIT) - data[1] = (u8)(val); - - ret = gc0310_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * gc0310_write_reg_array - Initializes a list of GC0310 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and - * __gc0310_write_reg_is_consecutive() are internal functions to - * gc0310_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __gc0310_flush_reg_array(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ - ctrl->buffer.addr = (u8)(ctrl->buffer.addr); - ctrl->index = 0; - - return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __gc0310_buf_reg_array(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl, - const struct gc0310_reg *next) -{ - int size; - - switch (next->type) { - case GC0310_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE) - return __gc0310_flush_reg_array(client, ctrl); - - return 0; -} - -static int __gc0310_write_reg_is_consecutive(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl, - const struct gc0310_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int gc0310_write_reg_array(struct i2c_client *client, - const struct gc0310_reg *reglist) -{ - const struct gc0310_reg *next = reglist; - struct gc0310_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != GC0310_TOK_TERM; next++) { - switch (next->type & GC0310_TOK_MASK) { - case GC0310_TOK_DELAY: - err = __gc0310_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__gc0310_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __gc0310_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __gc0310_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __gc0310_flush_reg_array(client, &ctrl); -} -static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | - (GC0310_F_NUMBER_DEM << 16) | - (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = gc0310_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = gc0310_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int gc0310_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc0310_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 val; - u8 reg_val; - int ret; - unsigned int hori_blanking; - unsigned int vert_blanking; - unsigned int sh_delay; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; - pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); - - /* get integration time */ - buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC0310_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC0310_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - /* Getting crop_horizontal_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = val | (reg_val & 0xFF); - pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start); - - /* Getting crop_vertical_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = val | (reg_val & 0xFF); - pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start); - - /* Getting output_width */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = val | (reg_val & 0xFF); - pr_info("output_width=%d\n", buf->output_width); - - /* Getting output_height */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = val | (reg_val & 0xFF); - pr_info("output_height=%d\n", buf->output_height); - - buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; - pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end); - pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end); - - /* Getting line_length_pck */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_L, ®_val); - if (ret) - return ret; - hori_blanking = val | (reg_val & 0xFF); - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SH_DELAY, ®_val); - if (ret) - return ret; - sh_delay = reg_val; - buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; - pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck); - - /* Getting frame_length_lines */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_L, ®_val); - if (ret) - return ret; - vert_blanking = val | (reg_val & 0xFF); - buf->frame_length_lines = buf->output_height + vert_blanking; - pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines); - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 again, dgain; - - if (gain < 0x20) - gain = 0x20; - if (gain > 0x80) - gain = 0x80; - - if (gain >= 0x20 && gain < 0x40) { - again = 0x0; /* sqrt(2) */ - dgain = gain; - } else { - again = 0x2; /* 2 * sqrt(2) */ - dgain = gain / 2; - } - - pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); - - /* set analog gain */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AGC_ADJ, again); - if (ret) - return ret; - - /* set digital gain */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_DGC_ADJ, dgain); - if (ret) - return ret; - - return 0; -} - -static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); - - /* set exposure */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_L, - coarse_itg & 0xff); - if (ret) - return ret; - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_H, - (coarse_itg >> 8) & 0x0f); - if (ret) - return ret; - - ret = gc0310_set_gain(sd, gain); - if (ret) - return ret; - - return ret; -} - -static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __gc0310_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long gc0310_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return gc0310_set_exposure(sd, exp, gain, digitgain); -} - -/* TO DO */ -static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -/* TO DO */ -static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return gc0310_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 reg_v; - int ret; - - /* get exposure */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_L, - ®_v); - if (ret) - goto err; - - *value = reg_v; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_H, - ®_v); - if (ret) - goto err; - - *value = *value + (reg_v << 8); -err: - return ret; -} - -static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc0310_device *dev = - container_of(ctrl->handler, struct gc0310_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = gc0310_v_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = gc0310_h_flip(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc0310_device *dev = - container_of(ctrl->handler, struct gc0310_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = gc0310_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc0310_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = gc0310_s_ctrl, - .g_volatile_ctrl = gc0310_g_volatile_ctrl -}; - -struct v4l2_ctrl_config gc0310_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC0310_FOCAL_LENGTH_DEFAULT, - .max = GC0310_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC0310_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC0310_F_NUMBER_DEFAULT, - .max = GC0310_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC0310_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC0310_F_NUMBER_RANGE, - .max = GC0310_F_NUMBER_RANGE, - .step = 0x01, - .def = GC0310_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int gc0310_init(struct v4l2_subdev *sd) -{ - int ret; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct gc0310_device *dev = to_gc0310_sensor(sd); - - pr_info("%s S\n", __func__); - mutex_lock(&dev->input_lock); - - /* set inital registers */ - ret = gc0310_write_reg_array(client, gc0310_reset_register); - - /* restore settings */ - gc0310_res = gc0310_res_preview; - N_RES = N_RES_PREVIEW; - - mutex_unlock(&dev->input_lock); - - pr_info("%s E\n", __func__); - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct gc0310_device *dev = to_gc0310_sensor(sd); - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - /* The upstream module driver (written to Crystal - * Cove) had this logic to pulse the rails low first. - * This appears to break things on the MRD7 with the - * X-Powers PMIC... - * - * ret = dev->platform_data->v1p8_ctrl(sd, 0); - * ret |= dev->platform_data->v2p8_ctrl(sd, 0); - * mdelay(50); - */ - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } - - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct gc0310_device *dev = to_gc0310_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* GPIO0 == "reset" (active low), GPIO1 == "power down" */ - if (flag) { - /* Pulse reset, then release power down */ - ret = dev->platform_data->gpio0_ctrl(sd, 0); - usleep_range(5000, 10000); - ret |= dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - ret |= dev->platform_data->gpio1_ctrl(sd, 0); - usleep_range(10000, 15000); - } else { - ret = dev->platform_data->gpio1_ctrl(sd, 1); - ret |= dev->platform_data->gpio0_ctrl(sd, 0); - } - return ret; -} - - -static int power_down(struct v4l2_subdev *sd); - -static int power_up(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s S\n", __func__); - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_gpio; - } - - msleep(100); - - pr_info("%s E\n", __func__); - return 0; - -fail_gpio: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - power_ctrl(sd, 0); -fail_power: - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int gc0310_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) - return gc0310_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct gc0310_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); - - if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct gc0310_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &gc0310_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != gc0310_res[i].width) - continue; - if (h != gc0310_res[i].height) - continue; - - return i; - } - - return -1; -} - - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - pr_info("%s S\n", __func__); - - ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "gc0310 write register err.\n"); - return ret; - } - - pr_info("%s E\n", __func__); - return ret; -} - -static int gc0310_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 gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *gc0310_info = NULL; - int ret = 0; - int idx = 0; - pr_info("%s S\n", __func__); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - gc0310_info = v4l2_get_subdev_hostdata(sd); - if (!gc0310_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = gc0310_res[N_RES - 1].width; - fmt->height = gc0310_res[N_RES - 1].height; - } else { - fmt->width = gc0310_res[idx].width; - fmt->height = gc0310_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__, - gc0310_res[dev->fmt_idx].desc); - ret = startup(sd); - if (ret) { - dev_err(&client->dev, "gc0310 startup err\n"); - goto err; - } - - ret = gc0310_get_intg_factor(client, gc0310_info, - &gc0310_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - pr_info("%s E\n", __func__); -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc0310_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 gc0310_device *dev = to_gc0310_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = gc0310_res[dev->fmt_idx].width; - fmt->height = gc0310_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; - - return 0; -} - -static int gc0310_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u8 high, low; - int ret; - u16 id; - - pr_info("%s S\n", __func__); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "read sensor_id_high failed\n"); - return -ENODEV; - } - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SC_CMMN_CHIP_ID_L, &low); - if (ret) { - dev_err(&client->dev, "read sensor_id_low failed\n"); - return -ENODEV; - } - id = ((((u16) high) << 8) | (u16) low); - pr_info("sensor ID = 0x%x\n", id); - - if (id != GC0310_ID) { - dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID); - return -ENODEV; - } - - dev_dbg(&client->dev, "detect gc0310 success\n"); - - pr_info("%s E\n", __func__); - - return 0; -} - -static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s S enable=%d\n", __func__, enable); - mutex_lock(&dev->input_lock); - - if (enable) { - /* enable per frame MIPI and sensor ctrl reset */ - ret = gc0310_write_reg(client, GC0310_8BIT, - 0xFE, 0x30); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - } - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM, - enable ? GC0310_START_STREAMING : - GC0310_STOP_STREAMING); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - mutex_unlock(&dev->input_lock); - pr_info("%s E\n", __func__); - return ret; -} - - -static int gc0310_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - pr_info("%s S\n", __func__); - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = gc0310_detect(client); - if (ret) { - dev_err(&client->dev, "gc0310_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - pr_info("%s E\n", __func__); - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc0310_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc0310_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc0310_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc0310_res = gc0310_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc0310_res = gc0310_res_still; - N_RES = N_RES_STILL; - break; - default: - gc0310_res = gc0310_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int gc0310_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = gc0310_res[dev->fmt_idx].fps; - - return 0; -} - -static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SGRBG8_1X8; - return 0; -} - -static int gc0310_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = gc0310_res[index].width; - fse->min_height = gc0310_res[index].height; - fse->max_width = gc0310_res[index].width; - fse->max_height = gc0310_res[index].height; - - return 0; - -} - - -static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = gc0310_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { - .g_skip_frames = gc0310_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops gc0310_video_ops = { - .s_stream = gc0310_s_stream, - .g_parm = gc0310_g_parm, - .s_parm = gc0310_s_parm, - .g_frame_interval = gc0310_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops gc0310_core_ops = { - .s_power = gc0310_s_power, - .ioctl = gc0310_ioctl, -}; - -static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { - .enum_mbus_code = gc0310_enum_mbus_code, - .enum_frame_size = gc0310_enum_frame_size, - .get_fmt = gc0310_get_fmt, - .set_fmt = gc0310_set_fmt, -}; - -static const struct v4l2_subdev_ops gc0310_ops = { - .core = &gc0310_core_ops, - .video = &gc0310_video_ops, - .pad = &gc0310_pad_ops, - .sensor = &gc0310_sensor_ops, -}; - -static int gc0310_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - dev_dbg(&client->dev, "gc0310_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int gc0310_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct gc0310_device *dev; - int ret; - void *pdata; - unsigned int i; - - pr_info("%s S\n", __func__); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops); - - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_8, - atomisp_bayer_order_grbg); - else - pdata = client->dev.platform_data; - - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = gc0310_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(gc0310_controls)); - if (ret) { - gc0310_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - gc0310_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; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - gc0310_remove(client); - - pr_info("%s E\n", __func__); - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id gc0310_acpi_match[] = { - {"XXGC0310"}, - {"INT0310"}, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); - -MODULE_DEVICE_TABLE(i2c, gc0310_id); -static struct i2c_driver gc0310_driver = { - .driver = { - .name = GC0310_NAME, - .acpi_match_table = ACPI_PTR(gc0310_acpi_match), - }, - .probe = gc0310_probe, - .remove = gc0310_remove, - .id_table = gc0310_id, -}; - -static int init_gc0310(void) -{ - return i2c_add_driver(&gc0310_driver); -} - -static void exit_gc0310(void) -{ - - i2c_del_driver(&gc0310_driver); -} - -module_init(init_gc0310); -module_exit(exit_gc0310); - -MODULE_AUTHOR("Lai, Angie "); -MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/gc2235.c b/drivers/staging/media/atomisp/i2c/gc2235.c deleted file mode 100644 index e43d31ea9676..000000000000 --- a/drivers/staging/media/atomisp/i2c/gc2235.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Support for GalaxyCore GC2235 2M camera sensor. - * - * Copyright (c) 2014 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include -#include - -#include "gc2235.h" - -/* i2c read/write stuff */ -static int gc2235_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != GC2235_8BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == GC2235_8BIT) - *val = (u8)data[0]; - - return 0; -} - -static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int gc2235_write_reg(struct i2c_client *client, u16 data_length, - u8 reg, u8 val) -{ - int ret; - unsigned char data[4] = {0}; - const u16 len = data_length + sizeof(u8); /* 16-bit address + data */ - - if (data_length != GC2235_8BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - data[0] = reg; - data[1] = val; - - ret = gc2235_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -static int __gc2235_flush_reg_array(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ - ctrl->index = 0; - - return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __gc2235_buf_reg_array(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl, - const struct gc2235_reg *next) -{ - int size; - - if (next->type != GC2235_8BIT) - return -EINVAL; - - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE) - return __gc2235_flush_reg_array(client, ctrl); - - return 0; -} -static int __gc2235_write_reg_is_consecutive(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl, - const struct gc2235_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} -static int gc2235_write_reg_array(struct i2c_client *client, - const struct gc2235_reg *reglist) -{ - const struct gc2235_reg *next = reglist; - struct gc2235_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != GC2235_TOK_TERM; next++) { - switch (next->type & GC2235_TOK_MASK) { - case GC2235_TOK_DELAY: - err = __gc2235_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__gc2235_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __gc2235_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __gc2235_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __gc2235_flush_reg_array(client, &ctrl); -} - -static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; - return 0; -} - -static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | - (GC2235_F_NUMBER_DEM << 16) | - (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; - return 0; -} - - -static int gc2235_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc2235_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 reg_val, reg_val_h, dummy; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; - - /* get integration time */ - buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC2235_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC2235_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_vertical_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = (reg_val_h << 8) | reg_val; - - buf->crop_horizontal_end = buf->crop_horizontal_start + - buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + - buf->output_height - 1; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_L, ®_val); - if (ret) - return ret; - - dummy = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_L, ®_val); - -#if 0 - buf->line_length_pck = buf->output_width + 16 + dummy + - (((u16)reg_val_h << 8) | (u16)reg_val) + 4; -#endif - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_L, ®_val); - if (ret) - return ret; - -#if 0 - buf->frame_length_lines = buf->output_height + 32 + - (((u16)reg_val_h << 8) | (u16)reg_val); -#endif - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 coarse_integration = (u16)coarse_itg; - int ret = 0; - u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0; - expo_coarse_h = coarse_integration >> 8; - expo_coarse_l = coarse_integration & 0xff; - - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_H, expo_coarse_h); - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_L, expo_coarse_l); - - if (gain <= 0x58) { - gain_val = 0x40; - gain_val2 = 0x58; - } else if (gain < 256) { - gain_val = 0x40; - gain_val2 = gain; - } else { - gain_val2 = 64 * gain / 256; - gain_val = 0xff; - } - - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_GLOBAL_GAIN, (u8)gain_val); - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_PRE_GAIN, (u8)gain_val2); - - return ret; -} - - -static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __gc2235_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long gc2235_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return gc2235_set_exposure(sd, exp, gain, digitgain); -} -static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return gc2235_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - - *value = reg_v; -err: - return ret; -} - -static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc2235_device *dev = - container_of(ctrl->handler, struct gc2235_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = gc2235_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc2235_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .g_volatile_ctrl = gc2235_g_volatile_ctrl -}; - -static struct v4l2_ctrl_config gc2235_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC2235_FOCAL_LENGTH_DEFAULT, - .max = GC2235_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC2235_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC2235_F_NUMBER_DEFAULT, - .max = GC2235_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC2235_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC2235_F_NUMBER_RANGE, - .max = GC2235_F_NUMBER_RANGE, - .step = 0x01, - .def = GC2235_F_NUMBER_RANGE, - .flags = 0, - }, -}; - -static int __gc2235_init(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* restore settings */ - gc2235_res = gc2235_res_preview; - N_RES = N_RES_PREVIEW; - - return gc2235_write_reg_array(client, gc2235_init_settings); -} - -static int is_init; - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = -1; - struct gc2235_device *dev = to_gc2235_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - usleep_range(60, 90); - if (ret == 0) - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - } else { - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - int ret = -1; - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); - usleep_range(60, 90); - return dev->platform_data->gpio0_ctrl(sd, flag); -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - msleep(5); - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int gc2235_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - if (on == 0) - ret = power_down(sd); - else { - ret = power_up(sd); - if (!ret) - ret = __gc2235_init(sd); - is_init = 1; - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct gc2235_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct gc2235_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &gc2235_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != gc2235_res[i].width) - continue; - if (h != gc2235_res[i].height) - continue; - - return i; - } - - return -1; -} - -static int startup(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - if (is_init == 0) { - /* force gc2235 to do a reset in res change, otherwise it - * can not output normal after switching res. and it is not - * necessary for first time run up after power on, for the sack - * of performance - */ - power_down(sd); - power_up(sd); - gc2235_write_reg_array(client, gc2235_init_settings); - } - - ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "gc2235 write register err.\n"); - return ret; - } - is_init = 0; - - return ret; -} - -static int gc2235_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 gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *gc2235_info = NULL; - int ret = 0; - int idx; - - gc2235_info = v4l2_get_subdev_hostdata(sd); - if (!gc2235_info) - return -EINVAL; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = gc2235_res[N_RES - 1].width; - fmt->height = gc2235_res[N_RES - 1].height; - } else { - fmt->width = gc2235_res[idx].width; - fmt->height = gc2235_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - ret = startup(sd); - if (ret) { - dev_err(&client->dev, "gc2235 startup err\n"); - goto err; - } - - ret = gc2235_get_intg_factor(client, gc2235_info, - &gc2235_res[dev->fmt_idx]); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc2235_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 gc2235_device *dev = to_gc2235_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = gc2235_res[dev->fmt_idx].width; - fmt->height = gc2235_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - return 0; -} - -static int gc2235_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_L, &low); - id = ((high << 8) | low); - - if (id != GC2235_ID) { - dev_err(&client->dev, "sensor ID error, 0x%x\n", id); - return -ENODEV; - } - - dev_info(&client->dev, "detect gc2235 success\n"); - return 0; -} - -static int gc2235_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - mutex_lock(&dev->input_lock); - - if (enable) - ret = gc2235_write_reg_array(client, gc2235_stream_on); - else - ret = gc2235_write_reg_array(client, gc2235_stream_off); - - mutex_unlock(&dev->input_lock); - return ret; -} - - -static int gc2235_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = gc2235_detect(client); - if (ret) { - dev_err(&client->dev, "gc2235_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc2235_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc2235_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc2235_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc2235_res = gc2235_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc2235_res = gc2235_res_still; - N_RES = N_RES_STILL; - break; - default: - gc2235_res = gc2235_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int gc2235_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = gc2235_res[dev->fmt_idx].fps; - - return 0; -} - -static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int gc2235_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = gc2235_res[index].width; - fse->min_height = gc2235_res[index].height; - fse->max_width = gc2235_res[index].width; - fse->max_height = gc2235_res[index].height; - - return 0; - -} - -static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = gc2235_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = { - .g_skip_frames = gc2235_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops gc2235_video_ops = { - .s_stream = gc2235_s_stream, - .g_parm = gc2235_g_parm, - .s_parm = gc2235_s_parm, - .g_frame_interval = gc2235_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops gc2235_core_ops = { - .s_power = gc2235_s_power, - .ioctl = gc2235_ioctl, -}; - -static const struct v4l2_subdev_pad_ops gc2235_pad_ops = { - .enum_mbus_code = gc2235_enum_mbus_code, - .enum_frame_size = gc2235_enum_frame_size, - .get_fmt = gc2235_get_fmt, - .set_fmt = gc2235_set_fmt, -}; - -static const struct v4l2_subdev_ops gc2235_ops = { - .core = &gc2235_core_ops, - .video = &gc2235_video_ops, - .pad = &gc2235_pad_ops, - .sensor = &gc2235_sensor_ops, -}; - -static int gc2235_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - dev_dbg(&client->dev, "gc2235_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int gc2235_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct gc2235_device *dev; - void *gcpdev; - int ret; - unsigned int i; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops); - - gcpdev = client->dev.platform_data; - if (ACPI_COMPANION(&client->dev)) - gcpdev = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - - ret = gc2235_s_config(&dev->sd, client->irq, gcpdev); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(gc2235_controls)); - if (ret) { - gc2235_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - gc2235_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; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - gc2235_remove(client); - - if (ACPI_HANDLE(&client->dev)) - ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA); - - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - - return ret; -} - -static const struct acpi_device_id gc2235_acpi_match[] = { - { "INT33F8" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match); -MODULE_DEVICE_TABLE(i2c, gc2235_id); -static struct i2c_driver gc2235_driver = { - .driver = { - .name = GC2235_NAME, - .acpi_match_table = ACPI_PTR(gc2235_acpi_match), - }, - .probe = gc2235_probe, - .remove = gc2235_remove, - .id_table = gc2235_id, -}; - -static int init_gc2235(void) -{ - return i2c_add_driver(&gc2235_driver); -} - -static void exit_gc2235(void) -{ - - i2c_del_driver(&gc2235_driver); -} - -module_init(init_gc2235); -module_exit(exit_gc2235); - -MODULE_AUTHOR("Shuguang Gong "); -MODULE_DESCRIPTION("A low-level driver for GC2235 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/imx/Kconfig b/drivers/staging/media/atomisp/i2c/imx/Kconfig index a39eeb3b6ad4..c4356c1a8aca 100644 --- a/drivers/staging/media/atomisp/i2c/imx/Kconfig +++ b/drivers/staging/media/atomisp/i2c/imx/Kconfig @@ -1,6 +1,6 @@ -config VIDEO_IMX +config VIDEO_ATOMISP_IMX tristate "sony imx sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_MSRLIST_HELPER && m + depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP_MSRLIST_HELPER && m ---help--- This is a Video4Linux2 sensor-level driver for the Sony IMX RAW sensor. diff --git a/drivers/staging/media/atomisp/i2c/imx/Makefile b/drivers/staging/media/atomisp/i2c/imx/Makefile index b6578f09546e..f3e2891cdfec 100644 --- a/drivers/staging/media/atomisp/i2c/imx/Makefile +++ b/drivers/staging/media/atomisp/i2c/imx/Makefile @@ -1,9 +1,9 @@ -obj-$(CONFIG_VIDEO_IMX) += imx1x5.o +obj-$(CONFIG_VIDEO_ATOMISP_IMX) += atomisp-imx1x5.o -imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o +atomisp-imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o -ov8858_driver-objs := ../ov8858.o dw9718.o vcm.o -obj-$(CONFIG_VIDEO_OV8858) += ov8858_driver.o +atomisp-ov8858-objs := ../ov8858.o dw9718.o vcm.o +obj-$(CONFIG_VIDEO_ATOMISP_OV8858) += atomisp-ov8858.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c deleted file mode 100644 index decb65cfd7c9..000000000000 --- a/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c +++ /dev/null @@ -1,209 +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. - * - */ -#include -#include -#include -#include -#include "../include/linux/libmsrlisthelper.h" -#include -#include - -/* Tagged binary data container structure definitions. */ -struct tbd_header { - uint32_t tag; /*!< Tag identifier, also checks endianness */ - uint32_t size; /*!< Container size including this header */ - uint32_t version; /*!< Version, format 0xYYMMDDVV */ - uint32_t revision; /*!< Revision, format 0xYYMMDDVV */ - uint32_t config_bits; /*!< Configuration flag bits set */ - uint32_t checksum; /*!< Global checksum, header included */ -} __packed; - -struct tbd_record_header { - uint32_t size; /*!< Size of record including header */ - uint8_t format_id; /*!< tbd_format_t enumeration values used */ - uint8_t packing_key; /*!< Packing method; 0 = no packing */ - uint16_t class_id; /*!< tbd_class_t enumeration values used */ -} __packed; - -struct tbd_data_record_header { - uint16_t next_offset; - uint16_t flags; - uint16_t data_offset; - uint16_t data_size; -} __packed; - -#define TBD_CLASS_DRV_ID 2 - -static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, - unsigned int size) -{ - /* The configuration data contains any number of sequences where - * the first byte (that is, uint8_t) that marks the number of bytes - * in the sequence to follow, is indeed followed by the indicated - * number of bytes of actual data to be written to sensor. - * By convention, the first two bytes of actual data should be - * understood as an address in the sensor address space (hibyte - * followed by lobyte) where the remaining data in the sequence - * will be written. */ - - uint8_t *ptr = bufptr; - while (ptr < bufptr + size) { - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - }; - int ret; - - /* How many bytes */ - msg.len = *ptr++; - /* Where the bytes are located */ - msg.buf = ptr; - ptr += msg.len; - - if (ptr > bufptr + size) - /* Accessing data beyond bounds is not tolerated */ - return -EINVAL; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "i2c write error: %d", ret); - return ret; - } - } - return 0; -} - -static int parse_and_apply(struct i2c_client *client, uint8_t *buffer, - unsigned int size) -{ - uint8_t *endptr8 = buffer + size; - struct tbd_data_record_header *header = - (struct tbd_data_record_header *)buffer; - - /* There may be any number of datasets present */ - unsigned int dataset = 0; - - do { - /* In below, four variables are read from buffer */ - if ((uint8_t *)header + sizeof(*header) > endptr8) - return -EINVAL; - - /* All data should be located within given buffer */ - if ((uint8_t *)header + header->data_offset + - header->data_size > endptr8) - return -EINVAL; - - /* We have a new valid dataset */ - dataset++; - /* See whether there is MSR data */ - /* If yes, update the reg info */ - if (header->data_size && (header->flags & 1)) { - int ret; - - dev_info(&client->dev, - "New MSR data for sensor driver (dataset %02d) size:%d\n", - dataset, header->data_size); - ret = set_msr_configuration(client, - buffer + header->data_offset, - header->data_size); - if (ret) - return ret; - } - header = (struct tbd_data_record_header *)(buffer + - header->next_offset); - } while (header->next_offset); - - return 0; -} - -int apply_msr_data(struct i2c_client *client, const struct firmware *fw) -{ - struct tbd_header *header; - struct tbd_record_header *record; - - if (!fw) { - dev_warn(&client->dev, "Drv data is not loaded.\n"); - return -EINVAL; - } - - if (sizeof(*header) > fw->size) - return -EINVAL; - - header = (struct tbd_header *)fw->data; - /* Check that we have drvb block. */ - if (memcmp(&header->tag, "DRVB", 4)) - return -EINVAL; - - /* Check the size */ - if (header->size != fw->size) - return -EINVAL; - - if (sizeof(*header) + sizeof(*record) > fw->size) - return -EINVAL; - - record = (struct tbd_record_header *)(header + 1); - /* Check that class id mathes tbd's drv id. */ - if (record->class_id != TBD_CLASS_DRV_ID) - return -EINVAL; - - /* Size 0 shall not be treated as an error */ - if (!record->size) - return 0; - - return parse_and_apply(client, (uint8_t *)(record + 1), record->size); -} -EXPORT_SYMBOL_GPL(apply_msr_data); - -int load_msr_list(struct i2c_client *client, char *name, - const struct firmware **fw) -{ - int ret = request_firmware(fw, name, &client->dev); - if (ret) { - dev_err(&client->dev, - "Error %d while requesting firmware %s\n", - ret, name); - return ret; - } - dev_info(&client->dev, "Received %lu bytes drv data\n", - (unsigned long)(*fw)->size); - - return 0; -} -EXPORT_SYMBOL_GPL(load_msr_list); - -void release_msr_list(struct i2c_client *client, const struct firmware *fw) -{ - release_firmware(fw); -} -EXPORT_SYMBOL_GPL(release_msr_list); - -static int init_msrlisthelper(void) -{ - return 0; -} - -static void exit_msrlisthelper(void) -{ -} - -module_init(init_msrlisthelper); -module_exit(exit_msrlisthelper); - -MODULE_AUTHOR("Jukka Kaartinen "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/lm3554.c b/drivers/staging/media/atomisp/i2c/lm3554.c deleted file mode 100644 index 679176f7c542..000000000000 --- a/drivers/staging/media/atomisp/i2c/lm3554.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * LED flash driver for LM3554 - * - * Copyright (c) 2010-2012 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. - * - */ -#include -#include -#include -#include -#include -#include - -#include "../include/media/lm3554.h" -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include "../include/linux/atomisp.h" - -/* Registers */ - -#define LM3554_TORCH_BRIGHTNESS_REG 0xA0 -#define LM3554_TORCH_MODE_SHIFT 0 -#define LM3554_TORCH_CURRENT_SHIFT 3 -#define LM3554_INDICATOR_CURRENT_SHIFT 6 - -#define LM3554_FLASH_BRIGHTNESS_REG 0xB0 -#define LM3554_FLASH_MODE_SHIFT 0 -#define LM3554_FLASH_CURRENT_SHIFT 3 -#define LM3554_STROBE_SENSITIVITY_SHIFT 7 - -#define LM3554_FLASH_DURATION_REG 0xC0 -#define LM3554_FLASH_TIMEOUT_SHIFT 0 -#define LM3554_CURRENT_LIMIT_SHIFT 5 - -#define LM3554_FLAGS_REG 0xD0 -#define LM3554_FLAG_TIMEOUT (1 << 0) -#define LM3554_FLAG_THERMAL_SHUTDOWN (1 << 1) -#define LM3554_FLAG_LED_FAULT (1 << 2) -#define LM3554_FLAG_TX1_INTERRUPT (1 << 3) -#define LM3554_FLAG_TX2_INTERRUPT (1 << 4) -#define LM3554_FLAG_LED_THERMAL_FAULT (1 << 5) -#define LM3554_FLAG_UNUSED (1 << 6) -#define LM3554_FLAG_INPUT_VOLTAGE_LOW (1 << 7) - -#define LM3554_CONFIG_REG_1 0xE0 -#define LM3554_ENVM_TX2_SHIFT 5 -#define LM3554_TX2_POLARITY_SHIFT 6 - -struct lm3554 { - struct v4l2_subdev sd; - - struct mutex power_lock; - struct v4l2_ctrl_handler ctrl_handler; - int power_count; - - unsigned int mode; - int timeout; - u8 torch_current; - u8 indicator_current; - u8 flash_current; - - struct timer_list flash_off_delay; - struct lm3554_platform_data *pdata; -}; - -#define to_lm3554(p_sd) container_of(p_sd, struct lm3554, sd) - -/* Return negative errno else zero on success */ -static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - ret = i2c_smbus_write_byte_data(client, addr, val); - - dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, - ret < 0 ? "fail" : "ok"); - - return ret; -} - -/* Return negative errno else a data byte received from the device. */ -static int lm3554_read(struct lm3554 *flash, u8 addr) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - ret = i2c_smbus_read_byte_data(client, addr); - - dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret, - ret < 0 ? "fail" : "ok"); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Hardware configuration - */ - -static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode) -{ - u8 val; - int ret; - - val = (mode << LM3554_FLASH_MODE_SHIFT) | - (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); - - ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); - if (ret == 0) - flash->mode = mode; - return ret; -} - -static int lm3554_set_torch(struct lm3554 *flash) -{ - u8 val; - - val = (flash->mode << LM3554_TORCH_MODE_SHIFT) | - (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) | - (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT); - - return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val); -} - -static int lm3554_set_flash(struct lm3554 *flash) -{ - u8 val; - - val = (flash->mode << LM3554_FLASH_MODE_SHIFT) | - (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); - - return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); -} - -static int lm3554_set_duration(struct lm3554 *flash) -{ - u8 val; - - val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) | - (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT); - - return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val); -} - -static int lm3554_set_config1(struct lm3554 *flash) -{ - u8 val; - - val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) | - (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT); - return lm3554_write(flash, LM3554_CONFIG_REG_1, val); -} - -/* ----------------------------------------------------------------------------- - * Hardware trigger - */ -static void lm3554_flash_off_delay(long unsigned int arg) -{ - struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - - gpio_set_value(pdata->gpio_strobe, 0); -} - -static int lm3554_hw_strobe(struct i2c_client *client, bool strobe) -{ - int ret, timer_pending; - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - - /* - * An abnormal high flash current is observed when strobe off the - * flash. Workaround here is firstly set flash current to lower level, - * wait a short moment, and then strobe off the flash. - */ - - timer_pending = del_timer_sync(&flash->flash_off_delay); - - /* Flash off */ - if (!strobe) { - /* set current to 70mA and wait a while */ - ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0); - if (ret < 0) - goto err; - mod_timer(&flash->flash_off_delay, - jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY)); - return 0; - } - - /* Flash on */ - - /* - * If timer is killed before run, flash is not strobe off, - * so must strobe off here - */ - if (timer_pending) - gpio_set_value(pdata->gpio_strobe, 0); - - /* Restore flash current settings */ - ret = lm3554_set_flash(flash); - if (ret < 0) - goto err; - - /* Strobe on Flash */ - gpio_set_value(pdata->gpio_strobe, 1); - - return 0; -err: - dev_err(&client->dev, "failed to %s flash strobe (%d)\n", - strobe ? "on" : "off", ret); - return ret; -} - -/* ----------------------------------------------------------------------------- - * V4L2 controls - */ - -static int lm3554_read_status(struct lm3554 *flash) -{ - int ret; - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - - /* NOTE: reading register clear fault status */ - ret = lm3554_read(flash, LM3554_FLAGS_REG); - if (ret < 0) - return ret; - - /* - * Accordingly to datasheet we read back '1' in bit 6. - * Clear it first. - */ - ret &= ~LM3554_FLAG_UNUSED; - - /* - * Do not take TX1/TX2 signal as an error - * because MSIC will not turn off flash, but turn to - * torch mode according to gsm modem signal by hardware. - */ - ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT); - - if (ret > 0) - dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret); - - return ret; -} - -static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val) -{ - struct lm3554 *flash = to_lm3554(sd); - - val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT); - val = val / LM3554_TIMEOUT_STEPSIZE - 1; - - flash->timeout = val; - - return lm3554_set_duration(flash); -} - -static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE; - - return 0; -} - -static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP); - - flash->flash_current = intensity; - - return lm3554_set_flash(flash); -} - -static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current, - LM3554_FLASH_STEP); - - return 0; -} - -static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP); - - flash->torch_current = intensity; - - return lm3554_set_torch(flash); -} - -static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current, - LM3554_TORCH_STEP); - - return 0; -} - -static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP); - - flash->indicator_current = intensity; - - return lm3554_set_torch(flash); -} - -static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current, - LM3554_INDICATOR_STEP); - - return 0; -} - -static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return lm3554_hw_strobe(client, val); -} - -static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode) -{ - struct lm3554 *flash = to_lm3554(sd); - unsigned int mode; - - switch (new_mode) { - case ATOMISP_FLASH_MODE_OFF: - mode = LM3554_MODE_SHUTDOWN; - break; - case ATOMISP_FLASH_MODE_FLASH: - mode = LM3554_MODE_FLASH; - break; - case ATOMISP_FLASH_MODE_INDICATOR: - mode = LM3554_MODE_INDICATOR; - break; - case ATOMISP_FLASH_MODE_TORCH: - mode = LM3554_MODE_TORCH; - break; - default: - return -EINVAL; - } - - return lm3554_set_mode(flash, mode); -} - -static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - *val = flash->mode; - return 0; -} - -static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - int value; - - value = lm3554_read_status(flash); - if (value < 0) - return value; - - if (value & LM3554_FLAG_TIMEOUT) - *val = ATOMISP_FLASH_STATUS_TIMEOUT; - else if (value > 0) - *val = ATOMISP_FLASH_STATUS_HW_ERROR; - else - *val = ATOMISP_FLASH_STATUS_OK; - - return 0; -} - -#ifndef CSS15 -static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - int ret; - - ret = lm3554_read(flash, LM3554_FLAGS_REG); - - if (ret < 0) - return ret; - - *val = ret; - return 0; -} -#endif - -static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct lm3554 *dev = - container_of(ctrl->handler, struct lm3554, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FLASH_TIMEOUT: - ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_INTENSITY: - ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_TORCH_INTENSITY: - ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_STROBE: - ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_MODE: - ret = lm3554_s_flash_mode(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct lm3554 *dev = - container_of(ctrl->handler, struct lm3554, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FLASH_TIMEOUT: - ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_INTENSITY: - ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_TORCH_INTENSITY: - ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_MODE: - ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_STATUS: - ret = lm3554_g_flash_status(&dev->sd, &ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_FLASH_STATUS_REGISTER: - ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val); - break; -#endif - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = lm3554_s_ctrl, - .g_volatile_ctrl = lm3554_g_volatile_ctrl -}; - -static const struct v4l2_ctrl_config lm3554_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_TIMEOUT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Timeout", - .min = 0x0, - .max = LM3554_MAX_TIMEOUT, - .step = 0x01, - .def = LM3554_DEFAULT_TIMEOUT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_FLASH_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_TORCH_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Torch Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_TORCH_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_INDICATOR_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Indicator Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STROBE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Strobe", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_MODE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Mode", - .min = 0, - .max = 100, - .step = 1, - .def = ATOMISP_FLASH_MODE_OFF, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STATUS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Status", - .min = 0, - .max = 100, - .step = 1, - .def = ATOMISP_FLASH_STATUS_OK, - .flags = 0, - }, -#ifndef CSS15 - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STATUS_REGISTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Status Register", - .min = 0, - .max = 100, - .step = 1, - .def = 0, - .flags = 0, - }, -#endif -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev core operations - */ - -/* Put device into known state. */ -static int lm3554_setup(struct lm3554 *flash) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - /* clear the flags register */ - ret = lm3554_read(flash, LM3554_FLAGS_REG); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Fault info: %02x\n", ret); - - ret = lm3554_set_config1(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_duration(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_torch(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_flash(flash); - if (ret < 0) - return ret; - - /* read status */ - ret = lm3554_read_status(flash); - if (ret < 0) - return ret; - - return ret ? -EIO : 0; -} - -static int __lm3554_s_power(struct lm3554 *flash, int power) -{ - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - /*initialize flash driver*/ - gpio_set_value(pdata->gpio_reset, power); - usleep_range(100, 100 + 1); - - if (power) { - /* Setup default values. This makes sure that the chip - * is in a known state. - */ - ret = lm3554_setup(flash); - if (ret < 0) { - __lm3554_s_power(flash, 0); - return ret; - } - } - - return 0; -} - -static int lm3554_s_power(struct v4l2_subdev *sd, int power) -{ - struct lm3554 *flash = to_lm3554(sd); - int ret = 0; - - mutex_lock(&flash->power_lock); - - if (flash->power_count == !power) { - ret = __lm3554_s_power(flash, !!power); - if (ret < 0) - goto done; - } - - flash->power_count += power ? 1 : -1; - WARN_ON(flash->power_count < 0); - -done: - mutex_unlock(&flash->power_lock); - return ret; -} - -static const struct v4l2_subdev_core_ops lm3554_core_ops = { - .s_power = lm3554_s_power, -}; - -static const struct v4l2_subdev_ops lm3554_ops = { - .core = &lm3554_core_ops, -}; - -static int lm3554_detect(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_adapter *adapter = client->adapter; - struct lm3554 *flash = to_lm3554(sd); - int ret; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "lm3554_detect i2c error\n"); - return -ENODEV; - } - - /* Power up the flash driver and reset it */ - ret = lm3554_s_power(&flash->sd, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed to power on lm3554 LED flash\n"); - } else { - dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n"); - lm3554_s_power(&flash->sd, 0); - } - - return ret; -} - -static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return lm3554_s_power(sd, 1); -} - -static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return lm3554_s_power(sd, 0); -} - -static const struct v4l2_subdev_internal_ops lm3554_internal_ops = { - .registered = lm3554_detect, - .open = lm3554_open, - .close = lm3554_close, -}; - -/* ----------------------------------------------------------------------------- - * I2C driver - */ -#ifdef CONFIG_PM - -static int lm3554_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __lm3554_s_power(flash, 0); - - dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); - - return rval; -} - -static int lm3554_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __lm3554_s_power(flash, 1); - - dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); - - return rval; -} - -#else - -#define lm3554_suspend NULL -#define lm3554_resume NULL - -#endif /* CONFIG_PM */ - -static int lm3554_gpio_init(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - if (!gpio_is_valid(pdata->gpio_reset)) - return -EINVAL; - - ret = gpio_direction_output(pdata->gpio_reset, 0); - if (ret < 0) - goto err_gpio_reset; - dev_info(&client->dev, "flash led reset successfully\n"); - - if (!gpio_is_valid(pdata->gpio_strobe)) { - ret = -EINVAL; - goto err_gpio_dir_reset; - } - - ret = gpio_direction_output(pdata->gpio_strobe, 0); - if (ret < 0) - goto err_gpio_strobe; - - return 0; - -err_gpio_strobe: - gpio_free(pdata->gpio_strobe); -err_gpio_dir_reset: - gpio_direction_output(pdata->gpio_reset, 0); -err_gpio_reset: - gpio_free(pdata->gpio_reset); - - return ret; -} - -static int lm3554_gpio_uninit(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - ret = gpio_direction_output(pdata->gpio_strobe, 0); - if (ret < 0) - return ret; - - ret = gpio_direction_output(pdata->gpio_reset, 0); - if (ret < 0) - return ret; - - gpio_free(pdata->gpio_strobe); - gpio_free(pdata->gpio_reset); - return 0; -} - -static void *lm3554_platform_data_func(struct i2c_client *client) -{ - static struct lm3554_platform_data platform_data; - - if (ACPI_COMPANION(&client->dev)) { - platform_data.gpio_reset = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 2, GPIOD_OUT_LOW)); - platform_data.gpio_strobe = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 0, GPIOD_OUT_LOW)); - platform_data.gpio_torch = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 1, GPIOD_OUT_LOW)); - } else { - platform_data.gpio_reset = -1; - platform_data.gpio_strobe = -1; - platform_data.gpio_torch = -1; - } - - dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n", - platform_data.gpio_reset, platform_data.gpio_strobe, - platform_data.gpio_torch); - - /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input: - * ENVM/TX pin asserted, flash forced into torch; - * ENVM/TX pin desserted, flash set back; - */ - platform_data.envm_tx2 = 1; - platform_data.tx2_polarity = 0; - - /* set peak current limit to be 1000mA */ - platform_data.current_limit = 0; - - return &platform_data; -} - -static int lm3554_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct lm3554 *flash; - unsigned int i; - int ret; - - flash = kzalloc(sizeof(*flash), GFP_KERNEL); - if (!flash) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - flash->pdata = client->dev.platform_data; - - if (!flash->pdata || ACPI_COMPANION(&client->dev)) - flash->pdata = lm3554_platform_data_func(client); - - v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops); - flash->sd.internal_ops = &lm3554_internal_ops; - flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - flash->mode = ATOMISP_FLASH_MODE_OFF; - flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1; - ret = - v4l2_ctrl_handler_init(&flash->ctrl_handler, - ARRAY_SIZE(lm3554_controls)); - if (ret) { - dev_err(&client->dev, "error initialize a ctrl_handler.\n"); - goto fail2; - } - - for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++) - v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i], - NULL); - - if (flash->ctrl_handler.error) { - - dev_err(&client->dev, "ctrl_handler error.\n"); - goto fail2; - } - - flash->sd.ctrl_handler = &flash->ctrl_handler; - err = media_entity_pads_init(&flash->sd.entity, 0, NULL); - if (err) { - dev_err(&client->dev, "error initialize a media entity.\n"); - goto fail1; - } - - flash->sd.entity.function = MEDIA_ENT_F_FLASH; - - mutex_init(&flash->power_lock); - - setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay, - (unsigned long)client); - - err = lm3554_gpio_init(client); - if (err) { - dev_err(&client->dev, "gpio request/direction_output fail"); - goto fail2; - } - if (ACPI_HANDLE(&client->dev)) - err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); - return 0; -fail2: - media_entity_cleanup(&flash->sd.entity); - v4l2_ctrl_handler_free(&flash->ctrl_handler); -fail1: - v4l2_device_unregister_subdev(&flash->sd); - kfree(flash); - - return err; -} - -static int lm3554_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - int ret; - - media_entity_cleanup(&flash->sd.entity); - v4l2_ctrl_handler_free(&flash->ctrl_handler); - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - del_timer_sync(&flash->flash_off_delay); - - ret = lm3554_gpio_uninit(client); - if (ret < 0) - goto fail; - - kfree(flash); - - return 0; -fail: - dev_err(&client->dev, "gpio request/direction_output fail"); - return ret; -} - -static const struct i2c_device_id lm3554_id[] = { - {LM3554_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, lm3554_id); - -static const struct dev_pm_ops lm3554_pm_ops = { - .suspend = lm3554_suspend, - .resume = lm3554_resume, -}; - -static const struct acpi_device_id lm3554_acpi_match[] = { - { "INTCF1C" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match); - -static struct i2c_driver lm3554_driver = { - .driver = { - .name = LM3554_NAME, - .pm = &lm3554_pm_ops, - .acpi_match_table = ACPI_PTR(lm3554_acpi_match), - }, - .probe = lm3554_probe, - .remove = lm3554_remove, - .id_table = lm3554_id, -}; - -static __init int init_lm3554(void) -{ - return i2c_add_driver(&lm3554_driver); -} - -static __exit void exit_lm3554(void) -{ - i2c_del_driver(&lm3554_driver); -} - -module_init(init_lm3554); -module_exit(exit_lm3554); -MODULE_AUTHOR("Jing Tao "); -MODULE_DESCRIPTION("LED flash driver for LM3554"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.c b/drivers/staging/media/atomisp/i2c/mt9m114.c deleted file mode 100644 index 3c837cb8859c..000000000000 --- a/drivers/staging/media/atomisp/i2c/mt9m114.c +++ /dev/null @@ -1,1963 +0,0 @@ -/* - * Support for mt9m114 Camera Sensor. - * - * Copyright (c) 2010 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include - -#include "mt9m114.h" - -#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd) - -/* - * TODO: use debug parameter to actually define when debug messages should - * be printed. - */ -static int debug; -static int aaalock; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value); -static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value); -static int mt9m114_wait_state(struct i2c_client *client, int timeout); - -static int -mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[4]; - - if (!client->adapter) { - v4l2_err(client, "%s error, no client->adapter\n", __func__); - return -ENODEV; - } - - if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT - && data_length != MISENSOR_32BIT) { - v4l2_err(client, "%s error, invalid data length\n", __func__); - return -EINVAL; - } - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = MSG_LEN_OFFSET; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u16) (reg >> 8); - data[1] = (u16) (reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - - if (err >= 0) { - *val = 0; - /* high byte comes first */ - if (data_length == MISENSOR_8BIT) - *val = data[0]; - else if (data_length == MISENSOR_16BIT) - *val = data[1] + (data[0] << 8); - else - *val = data[3] + (data[2] << 8) + - (data[1] << 16) + (data[0] << 24); - - return 0; - } - - dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); - return err; -} - -static int -mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val) -{ - int num_msg; - struct i2c_msg msg; - unsigned char data[6] = {0}; - u16 *wreg; - int retry = 0; - - if (!client->adapter) { - v4l2_err(client, "%s error, no client->adapter\n", __func__); - return -ENODEV; - } - - if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT - && data_length != MISENSOR_32BIT) { - v4l2_err(client, "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - memset(&msg, 0, sizeof(msg)); - -again: - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2 + data_length; - msg.buf = data; - - /* high byte goes out first */ - wreg = (u16 *)data; - *wreg = cpu_to_be16(reg); - - if (data_length == MISENSOR_8BIT) { - data[2] = (u8)(val); - } else if (data_length == MISENSOR_16BIT) { - u16 *wdata = (u16 *)&data[2]; - *wdata = be16_to_cpu((u16)val); - } else { - /* MISENSOR_32BIT */ - u32 *wdata = (u32 *)&data[2]; - *wdata = be32_to_cpu(val); - } - - num_msg = i2c_transfer(client->adapter, &msg, 1); - - /* - * HACK: Need some delay here for Rev 2 sensors otherwise some - * registers do not seem to load correctly. - */ - mdelay(1); - - if (num_msg >= 0) - return 0; - - dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, num_msg); - if (retry <= I2C_RETRY_COUNT) { - dev_dbg(&client->dev, "retrying... %d", retry); - retry++; - msleep(20); - goto again; - } - - return num_msg; -} - -/** - * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor - * device - * @client: i2c driver client structure - * @data_length: 8/16/32-bits length - * @reg: register address - * @mask: masked out bits - * @set: bits set - * - * Read/modify/write a value to a register in the sensor device. - * Returns zero if successful, or non-zero otherwise. - */ -static int -misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg, - u32 mask, u32 set) -{ - int err; - u32 val; - - /* Exit when no mask */ - if (mask == 0) - return 0; - - /* @mask must not exceed data length */ - switch (data_length) { - case MISENSOR_8BIT: - if (mask & ~0xff) - return -EINVAL; - break; - case MISENSOR_16BIT: - if (mask & ~0xffff) - return -EINVAL; - break; - case MISENSOR_32BIT: - break; - default: - /* Wrong @data_length */ - return -EINVAL; - } - - err = mt9m114_read_reg(client, data_length, reg, &val); - if (err) { - v4l2_err(client, "misensor_rmw_reg error exit, read failed\n"); - return -EINVAL; - } - - val &= ~mask; - - /* - * Perform the OR function if the @set exists. - * Shift @set value to target bit location. @set should set only - * bits included in @mask. - * - * REVISIT: This function expects @set to be non-shifted. Its shift - * value is then defined to be equal to mask's LSB position. - * How about to inform values in their right offset position and avoid - * this unneeded shift operation? - */ - set <<= ffs(mask) - 1; - val |= set & mask; - - err = mt9m114_write_reg(client, data_length, reg, val); - if (err) { - v4l2_err(client, "misensor_rmw_reg error exit, write failed\n"); - return -EINVAL; - } - - return 0; -} - - -static int __mt9m114_flush_reg_array(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - int retry = 0; - - if (ctrl->index == 0) - return 0; - -again: - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2 + ctrl->index; - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - msg.buf = (u8 *)&ctrl->buffer; - - ret = i2c_transfer(client->adapter, &msg, num_msg); - if (ret != num_msg) { - if (++retry <= I2C_RETRY_COUNT) { - dev_dbg(&client->dev, "retrying... %d\n", retry); - msleep(20); - goto again; - } - dev_err(&client->dev, "%s: i2c transfer error\n", __func__); - return -EIO; - } - - ctrl->index = 0; - - /* - * REVISIT: Previously we had a delay after writing data to sensor. - * But it was removed as our tests have shown it is not necessary - * anymore. - */ - - return 0; -} - -static int __mt9m114_buf_reg_array(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl, - const struct misensor_reg *next) -{ - u16 *data16; - u32 *data32; - int err; - - /* Insufficient buffer? Let's flush and get more free space. */ - if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) { - err = __mt9m114_flush_reg_array(client, ctrl); - if (err) - return err; - } - - switch (next->length) { - case MISENSOR_8BIT: - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case MISENSOR_16BIT: - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - case MISENSOR_32BIT: - data32 = (u32 *)&ctrl->buffer.data[ctrl->index]; - *data32 = cpu_to_be32(next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += next->length; - - return 0; -} - -static int -__mt9m114_write_reg_is_consecutive(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl, - const struct misensor_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -/* - * mt9m114_write_reg_array - Initializes a list of mt9m114 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * @poll: completion polling requirement - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and - * __mt9m114_write_reg_is_consecutive() are internal functions to - * mt9m114_write_reg_array() and should be not used anywhere else. - * - */ -static int mt9m114_write_reg_array(struct i2c_client *client, - const struct misensor_reg *reglist, - int poll) -{ - const struct misensor_reg *next = reglist; - struct mt9m114_write_ctrl ctrl; - int err; - - if (poll == PRE_POLLING) { - err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); - if (err) - return err; - } - - ctrl.index = 0; - for (; next->length != MISENSOR_TOK_TERM; next++) { - switch (next->length & MISENSOR_TOK_MASK) { - case MISENSOR_TOK_DELAY: - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - case MISENSOR_TOK_RMW: - err = __mt9m114_flush_reg_array(client, &ctrl); - err |= misensor_rmw_reg(client, - next->length & - ~MISENSOR_TOK_RMW, - next->reg, next->val, - next->val2); - if (err) { - dev_err(&client->dev, "%s read err. aborted\n", - __func__); - return -EINVAL; - } - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__mt9m114_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __mt9m114_buf_reg_array(client, &ctrl, next); - if (err) { - v4l2_err(client, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - - if (poll == POST_POLLING) - return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); - - return 0; -} - -static int mt9m114_wait_state(struct i2c_client *client, int timeout) -{ - int ret; - unsigned int val; - - while (timeout-- > 0) { - ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val); - if (ret) - return ret; - if ((val & 0x2) == 0) - return 0; - msleep(20); - } - - return -EINVAL; - -} - -static int mt9m114_set_suspend(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - return mt9m114_write_reg_array(client, - mt9m114_standby_reg, POST_POLLING); -} - -static int mt9m114_init_common(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING); -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret) - ret = dev->platform_data->v2p8_ctrl(sd, 0); - } - } else { - ret = dev->platform_data->v2p8_ctrl(sd, 0); - ret = dev->platform_data->v1p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* Note: current modules wire only one GPIO signal (RESET#), - * but the schematic wires up two to the connector. BIOS - * versions have been unfortunately inconsistent with which - * ACPI index RESET# is on, so hit both */ - - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 0); - ret = dev->platform_data->gpio1_ctrl(sd, 0); - msleep(60); - ret |= dev->platform_data->gpio0_ctrl(sd, 1); - ret |= dev->platform_data->gpio1_ctrl(sd, 1); - } else { - ret = dev->platform_data->gpio0_ctrl(sd, 0); - ret = dev->platform_data->gpio1_ctrl(sd, 0); - } - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) - dev_err(&client->dev, "gpio failed 1\n"); - /* - * according to DS, 44ms is needed between power up and first i2c - * commend - */ - msleep(50); - - return 0; - -fail_clk: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 1\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - /*according to DS, 20ms is needed after power down*/ - msleep(20); - - return ret; -} - -static int mt9m114_s_power(struct v4l2_subdev *sd, int power) -{ - if (power == 0) - return power_down(sd); - else { - if (power_up(sd)) - return -EINVAL; - - return mt9m114_init_common(sd); - } -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 600 -static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h) -{ - unsigned int w_ratio; - unsigned int h_ratio; - int match; - - if (w == 0) - return -1; - w_ratio = (res->width << 13) / w; - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - const struct mt9m114_res_struct *tmp_res = NULL; - - for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) { - tmp_res = &mt9m114_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int mt9m114_try_res(u32 *w, u32 *h) -{ - int idx = 0; - - if ((*w > MT9M114_RES_960P_SIZE_H) - || (*h > MT9M114_RES_960P_SIZE_V)) { - *w = MT9M114_RES_960P_SIZE_H; - *h = MT9M114_RES_960P_SIZE_V; - } else { - idx = nearest_resolution_index(*w, *h); - - /* - * nearest_resolution_index() doesn't return smaller - * resolutions. If it fails, it means the requested - * resolution is higher than wecan support. Fallback - * to highest possible resolution in this case. - */ - if (idx == -1) - idx = ARRAY_SIZE(mt9m114_res) - 1; - - *w = mt9m114_res[idx].width; - *h = mt9m114_res[idx].height; - } - - return 0; -} - -static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h) -{ - int index; - - for (index = 0; index < N_RES; index++) { - if ((mt9m114_res[index].width == w) && - (mt9m114_res[index].height == h)) - break; - } - - /* No mode found */ - if (index >= N_RES) - return NULL; - - return &mt9m114_res[index]; -} - -static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - unsigned short hsize; - unsigned short vsize; - - switch (dev->res) { - case MT9M114_RES_736P: - hsize = MT9M114_RES_736P_SIZE_H; - vsize = MT9M114_RES_736P_SIZE_V; - break; - case MT9M114_RES_864P: - hsize = MT9M114_RES_864P_SIZE_H; - vsize = MT9M114_RES_864P_SIZE_V; - break; - case MT9M114_RES_960P: - hsize = MT9M114_RES_960P_SIZE_H; - vsize = MT9M114_RES_960P_SIZE_V; - break; - default: - v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__, - dev->res); - return -EINVAL; - } - - if (h_size != NULL) - *h_size = hsize; - if (v_size != NULL) - *v_size = vsize; - - return 0; -} - -static int mt9m114_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct mt9m114_res_struct *res) -{ - struct atomisp_sensor_mode_data *buf = &info->data; - u32 reg_val; - int ret; - - if (info == NULL) - return -EINVAL; - - ret = mt9m114_read_reg(client, MISENSOR_32BIT, - REG_PIXEL_CLK, ®_val); - if (ret) - return ret; - buf->vt_pix_clk_freq_mhz = reg_val; - - /* get integration time */ - buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - MT9M114_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - MT9M114_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; - - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_START, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_START, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_END, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_END, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_WIDTH, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_HEIGHT, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_HTS, ®_val); - if (ret) - return ret; - buf->line_length_pck = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_VTS, ®_val); - if (ret) - return ret; - buf->frame_length_lines = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static int mt9m114_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - int width, height; - int ret; - if (format->pad) - return -EINVAL; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - ret = mt9m114_res2size(sd, &width, &height); - if (ret) - return ret; - fmt->width = width; - fmt->height = height; - - return 0; -} - -static int mt9m114_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 i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct mt9m114_res_struct *res_index; - u32 width = fmt->width; - u32 height = fmt->height; - struct camera_mipi_info *mt9m114_info = NULL; - - int ret; - if (format->pad) - return -EINVAL; - dev->streamon = 0; - dev->first_exp = MT9M114_DEFAULT_FIRST_EXP; - - mt9m114_info = v4l2_get_subdev_hostdata(sd); - if (mt9m114_info == NULL) - return -EINVAL; - - mt9m114_try_res(&width, &height); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - return 0; - } - res_index = mt9m114_to_res(width, height); - - /* Sanity check */ - if (unlikely(!res_index)) { - WARN_ON(1); - return -EINVAL; - } - - switch (res_index->res) { - case MT9M114_RES_736P: - ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING); - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - case MT9M114_RES_864P: - ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING); - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - case MT9M114_RES_960P: - ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING); - /* set sensor read_mode to Normal */ - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - default: - v4l2_err(sd, "set resolution: %d failed!\n", res_index->res); - return -EINVAL; - } - - if (ret) - return -EINVAL; - - ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING); - if (ret < 0) - return ret; - - if (mt9m114_set_suspend(sd)) - return -EINVAL; - - if (dev->res != res_index->res) { - int index; - - /* Switch to different size */ - if (width <= 640) { - dev->nctx = 0x00; /* Set for context A */ - } else { - /* - * Context B is used for resolutions larger than 640x480 - * Using YUV for Context B. - */ - dev->nctx = 0x01; /* set for context B */ - } - - /* - * Marked current sensor res as being "used" - * - * REVISIT: We don't need to use an "used" field on each mode - * list entry to know which mode is selected. If this - * information is really necessary, how about to use a single - * variable on sensor dev struct? - */ - for (index = 0; index < N_RES; index++) { - if ((width == mt9m114_res[index].width) && - (height == mt9m114_res[index].height)) { - mt9m114_res[index].used = true; - continue; - } - mt9m114_res[index].used = false; - } - } - ret = mt9m114_get_intg_factor(c, mt9m114_info, - &mt9m114_res[res_index->res]); - if (ret) { - dev_err(&c->dev, "failed to get integration_factor\n"); - return -EINVAL; - } - /* - * mt9m114 - we don't poll for context switch - * because it does not happen with streaming disabled. - */ - dev->res = res_index->res; - - fmt->width = width; - fmt->height = height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - return 0; -} - -/* TODO: Update to SOC functions, remove exposure and gain */ -static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; - return 0; -} - -static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for mt9m114*/ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; - return 0; -} - -static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | - (MT9M114_F_NUMBER_DEM << 16) | - (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; - return 0; -} - -/* Horizontal flip the image. */ -static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int ret; - u32 data; - ret = mt9m114_read_reg(c, MISENSOR_16BIT, - (u32)MISENSOR_READ_MODE, &data); - if (ret) - return ret; - *val = !!(data & MISENSOR_HFLIP_MASK); - - return 0; -} - -static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int ret; - u32 data; - - ret = mt9m114_read_reg(c, MISENSOR_16BIT, - (u32)MISENSOR_READ_MODE, &data); - if (ret) - return ret; - *val = !!(data & MISENSOR_VFLIP_MASK); - - return 0; -} - -static long mt9m114_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - int ret = 0; - unsigned int coarse_integration = 0; - unsigned int fine_integration = 0; - unsigned int FLines = 0; - unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */ - unsigned int AnalogGain, DigitalGain; - u32 AnalogGainToWrite = 0; - u16 exposure_local[3]; - - dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__, - exposure->integration_time[0], exposure->gain[0], - exposure->gain[1]); - - coarse_integration = exposure->integration_time[0]; - /* fine_integration = ExposureTime.FineIntegrationTime; */ - /* FrameLengthLines = ExposureTime.FrameLengthLines; */ - FLines = mt9m114_res[dev->res].lines_per_frame; - AnalogGain = exposure->gain[0]; - DigitalGain = exposure->gain[1]; - if (!dev->streamon) { - /*Save the first exposure values while stream is off*/ - dev->first_exp = coarse_integration; - dev->first_gain = AnalogGain; - dev->first_diggain = DigitalGain; - } - /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) + - ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */ - - /* set frame length */ - if (FLines < coarse_integration + 6) - FLines = coarse_integration + 6; - if (FLines < FrameLengthLines) - FLines = FrameLengthLines; - ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines); - if (ret) { - v4l2_err(client, "%s: fail to set FLines\n", __func__); - return -EINVAL; - } - - /* set coarse/fine integration */ - exposure_local[0] = REG_EXPO_COARSE; - exposure_local[1] = (u16)coarse_integration; - exposure_local[2] = (u16)fine_integration; - /* 3A provide real exposure time. - should not translate to any value here. */ - ret = mt9m114_write_reg(client, MISENSOR_16BIT, - REG_EXPO_COARSE, (u16)(coarse_integration)); - if (ret) { - v4l2_err(client, "%s: fail to set exposure time\n", __func__); - return -EINVAL; - } - - /* - // set analog/digital gain - switch(AnalogGain) - { - case 0: - AnalogGainToWrite = 0x0; - break; - case 1: - AnalogGainToWrite = 0x20; - break; - case 2: - AnalogGainToWrite = 0x60; - break; - case 4: - AnalogGainToWrite = 0xA0; - break; - case 8: - AnalogGainToWrite = 0xE0; - break; - default: - AnalogGainToWrite = 0x20; - break; - } - */ - if (DigitalGain >= 16 || DigitalGain <= 1) - DigitalGain = 1; - /* AnalogGainToWrite = - (u16)((DigitalGain << 12) | AnalogGainToWrite); */ - AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain); - ret = mt9m114_write_reg(client, MISENSOR_16BIT, - REG_GAIN, AnalogGainToWrite); - if (ret) { - v4l2_err(client, "%s: fail to set AnalogGainToWrite\n", - __func__); - return -EINVAL; - } - - return ret; -} - -static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return mt9m114_s_exposure(sd, arg); - default: - return -EINVAL; - } - - return 0; -} - -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ -static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 coarse; - int ret; - - /* the fine integration time is currently not calculated */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_EXPO_COARSE, &coarse); - if (ret) - return ret; - - *value = coarse; - return 0; -} -#ifndef CSS15 -/* - * This function will return the sensor supported max exposure zone number. - * the sensor which supports max exposure zone number is 1. - */ -static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val) -{ - *val = 1; - - return 0; -} - -/* - * set exposure metering, average/center_weighted/spot/matrix. - */ -static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (val) { - case V4L2_EXPOSURE_METERING_SPOT: - ret = mt9m114_write_reg_array(client, mt9m114_exp_average, - NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_average reg err.\n"); - return ret; - } - break; - case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: - default: - ret = mt9m114_write_reg_array(client, mt9m114_exp_center, - NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_default reg err"); - return ret; - } - } - - return 0; -} - -/* - * This function is for touch exposure feature. - */ -static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct misensor_reg exp_reg; - int width, height; - int grid_width, grid_height; - int grid_left, grid_top, grid_right, grid_bottom; - int win_left, win_top, win_right, win_bottom; - int i, j; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_TRY && - sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - grid_left = sel->r.left; - grid_top = sel->r.top; - grid_right = sel->r.left + sel->r.width - 1; - grid_bottom = sel->r.top + sel->r.height - 1; - - ret = mt9m114_res2size(sd, &width, &height); - if (ret) - return ret; - - grid_width = width / 5; - grid_height = height / 5; - - if (grid_width && grid_height) { - win_left = grid_left / grid_width; - win_top = grid_top / grid_height; - win_right = grid_right / grid_width; - win_bottom = grid_bottom / grid_height; - } else { - dev_err(&client->dev, "Incorrect exp grid.\n"); - return -EINVAL; - } - - win_left = clamp_t(int, win_left, 0, 4); - win_top = clamp_t(int, win_top, 0, 4); - win_right = clamp_t(int, win_right, 0, 4); - win_bottom = clamp_t(int, win_bottom, 0, 4); - - ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_average reg err.\n"); - return ret; - } - - for (i = win_top; i <= win_bottom; i++) { - for (j = win_left; j <= win_right; j++) { - exp_reg = mt9m114_exp_win[i][j]; - - ret = mt9m114_write_reg(client, exp_reg.length, - exp_reg.reg, exp_reg.val); - if (ret) { - dev_err(&client->dev, "write exp_reg err.\n"); - return ret; - } - } - } - - return 0; -} -#endif - -static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_x; - - return 0; -} - -static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_y; - - return 0; -} - -static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - s32 luma = 0x37; - int err; - - /* EV value only support -2 to 2 - * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17 - */ - if (val < -2 || val > 2) - return -EINVAL; - luma += 0x10 * val; - dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma); - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); - if (err) { - dev_err(&c->dev, "%s logic addr access error\n", __func__); - return err; - } - err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma); - if (err) { - dev_err(&c->dev, "%s write target_average_luma failed\n", - __func__); - return err; - } - udelay(10); - - return 0; -} - -static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int err; - u32 luma; - - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); - if (err) { - dev_err(&c->dev, "%s logic addr access error\n", __func__); - return err; - } - err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma); - if (err) { - dev_err(&c->dev, "%s read target_average_luma failed\n", - __func__); - return err; - } - luma -= 0x17; - luma /= 0x10; - *val = (s32)luma - 2; - dev_dbg(&c->dev, "%s val:%d\n", __func__, *val); - - return 0; -} - -/* Fake interface - * mt9m114 now can not support 3a_lock -*/ -static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val) -{ - aaalock = val; - return 0; -} - -static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val) -{ - if (aaalock) - return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE - | V4L2_LOCK_FOCUS; - return 0; -} - -static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m114_device *dev = - container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = mt9m114_t_vflip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = mt9m114_t_hflip(&dev->sd, ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_EXPOSURE_METERING: - ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val); - break; -#endif - case V4L2_CID_EXPOSURE: - ret = mt9m114_s_ev(&dev->sd, ctrl->val); - break; - case V4L2_CID_3A_LOCK: - ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m114_device *dev = - container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ret = mt9m114_g_vflip(&dev->sd, &ctrl->val); - break; - case V4L2_CID_HFLIP: - ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = mt9m114_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_EXPOSURE_ZONE_NUM: - ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); - break; -#endif - case V4L2_CID_BIN_FACTOR_HORZ: - ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - case V4L2_CID_EXPOSURE: - ret = mt9m114_g_ev(&dev->sd, &ctrl->val); - break; - case V4L2_CID_3A_LOCK: - ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = mt9m114_s_ctrl, - .g_volatile_ctrl = mt9m114_g_volatile_ctrl -}; - -static struct v4l2_ctrl_config mt9m114_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .name = "Image v-Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .name = "Image h-Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .name = "focal length", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_FOCAL_LENGTH_DEFAULT, - .max = MT9M114_FOCAL_LENGTH_DEFAULT, - .step = 1, - .def = MT9M114_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .name = "f-number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_DEFAULT, - .max = MT9M114_F_NUMBER_DEFAULT, - .step = 1, - .def = MT9M114_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .name = "f-number range", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_RANGE, - .max = MT9M114_F_NUMBER_RANGE, - .step = 1, - .def = MT9M114_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .name = "exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 0xffff, - .step = 1, - .def = 0, - .flags = 0, - }, -#ifndef CSS15 - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ZONE_NUM, - .name = "one-time exposure zone number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 0xffff, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_METERING, - .name = "metering", - .type = V4L2_CTRL_TYPE_MENU, - .min = 0, - .max = 3, - .step = 0, - .def = 1, - .flags = 0, - }, -#endif - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .name = "horizontal binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .name = "vertical binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE, - .name = "exposure biasx", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = -2, - .max = 2, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_3A_LOCK, - .name = "3a lock", - .type = V4L2_CTRL_TYPE_BITMASK, - .min = 0, - .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u32 retvalue; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "%s: i2c error", __func__); - return -ENODEV; - } - mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); - dev->real_model_id = retvalue; - - if (retvalue != MT9M114_MOD_ID) { - dev_err(&client->dev, "%s: failed: client->addr = %x\n", - __func__, client->addr); - return -ENODEV; - } - - return 0; -} - -static int -mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - v4l2_err(client, "mt9m114 platform init err\n"); - return ret; - } - } - ret = power_up(sd); - if (ret) { - v4l2_err(client, "mt9m114 power-up err"); - return ret; - } - - /* config & detect sensor */ - ret = mt9m114_detect(dev, client); - if (ret) { - v4l2_err(client, "mt9m114_detect err s_config.\n"); - goto fail_detect; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - ret = mt9m114_set_suspend(sd); - if (ret) { - v4l2_err(client, "mt9m114 suspend err"); - return ret; - } - - ret = power_down(sd); - if (ret) { - v4l2_err(client, "mt9m114 power down err"); - return ret; - } - - return ret; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_detect: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); - return ret; -} - -/* Horizontal flip the image. */ -static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - int err; - /* set for direct mode */ - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); - if (value) { - /* enable H flip ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN); - - dev->bpat = MT9M114_BPAT_GRGRBGBG; - } else { - /* disable H flip ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS); - - dev->bpat = MT9M114_BPAT_BGBGGRGR; - } - - err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); - udelay(10); - - return !!err; -} - -/* Vertically flip the image */ -static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int err; - /* set for direct mode */ - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); - if (value >= 1) { - /* enable H flip - ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN); - } else { - /* disable H flip - ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS); - } - - err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); - udelay(10); - - return !!err; -} -static int mt9m114_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - return 0; -} - -static int mt9m114_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = mt9m114_res[dev->res].fps; - - return 0; -} - -static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable) -{ - int ret; - struct i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct atomisp_exposure exposure; - - if (enable) { - ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, - POST_POLLING); - if (ret < 0) - return ret; - - if (dev->first_exp > MT9M114_MAX_FIRST_EXP) { - exposure.integration_time[0] = dev->first_exp; - exposure.gain[0] = dev->first_gain; - exposure.gain[1] = dev->first_diggain; - mt9m114_s_exposure(sd, &exposure); - } - dev->streamon = 1; - - } else { - dev->streamon = 0; - ret = mt9m114_set_suspend(sd); - } - - return ret; -} - -static int mt9m114_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_SGRBG10_1X10; - - return 0; -} - -static int mt9m114_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - - unsigned int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = mt9m114_res[index].width; - fse->min_height = mt9m114_res[index].height; - fse->max_width = mt9m114_res[index].width; - fse->max_height = mt9m114_res[index].height; - - return 0; -} - -static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - int index; - struct mt9m114_device *snr = to_mt9m114_sensor(sd); - - if (frames == NULL) - return -EINVAL; - - for (index = 0; index < N_RES; index++) { - if (mt9m114_res[index].res == snr->res) - break; - } - - if (index >= N_RES) - return -EINVAL; - - *frames = mt9m114_res[index].skip_frames; - - return 0; -} - -static const struct v4l2_subdev_video_ops mt9m114_video_ops = { - .s_parm = mt9m114_s_parm, - .s_stream = mt9m114_s_stream, - .g_frame_interval = mt9m114_g_frame_interval, -}; - -static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { - .g_skip_frames = mt9m114_g_skip_frames, -}; - -static const struct v4l2_subdev_core_ops mt9m114_core_ops = { - .s_power = mt9m114_s_power, - .ioctl = mt9m114_ioctl, -}; - -/* REVISIT: Do we need pad operations? */ -static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = { - .enum_mbus_code = mt9m114_enum_mbus_code, - .enum_frame_size = mt9m114_enum_frame_size, - .get_fmt = mt9m114_get_fmt, - .set_fmt = mt9m114_set_fmt, -#ifndef CSS15 - .set_selection = mt9m114_s_exposure_selection, -#endif -}; - -static const struct v4l2_subdev_ops mt9m114_ops = { - .core = &mt9m114_core_ops, - .video = &mt9m114_video_ops, - .pad = &mt9m114_pad_ops, - .sensor = &mt9m114_sensor_ops, -}; - -static const struct media_entity_operations mt9m114_entity_ops = { - .link_setup = NULL, -}; - -static int mt9m114_remove(struct i2c_client *client) -{ - struct mt9m114_device *dev; - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - dev = container_of(sd, struct mt9m114_device, sd); - dev->platform_data->csi_cfg(sd, 0); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - return 0; -} - -static int mt9m114_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mt9m114_device *dev; - int ret = 0; - unsigned int i; - void *pdata; - - /* Setup sensor configuration structure */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); - pdata = client->dev.platform_data; - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - if (pdata) - ret = mt9m114_s_config(&dev->sd, client->irq, pdata); - if (!pdata || ret) { - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; - } - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) { - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - /* Coverity CID 298095 - return on error */ - return ret; - } - - /*TODO add format code here*/ - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(mt9m114_controls)); - if (ret) { - mt9m114_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - mt9m114_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; - - /* REVISIT: Do we need media controller? */ - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) { - mt9m114_remove(client); - return ret; - } - return 0; -} - -MODULE_DEVICE_TABLE(i2c, mt9m114_id); - -static const struct acpi_device_id mt9m114_acpi_match[] = { - { "INT33F0" }, - { "CRMT1040" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match); - -static struct i2c_driver mt9m114_driver = { - .driver = { - .name = "mt9m114", - .acpi_match_table = ACPI_PTR(mt9m114_acpi_match), - }, - .probe = mt9m114_probe, - .remove = mt9m114_remove, - .id_table = mt9m114_id, -}; - -static __init int init_mt9m114(void) -{ - return i2c_add_driver(&mt9m114_driver); -} - -static __exit void exit_mt9m114(void) -{ - i2c_del_driver(&mt9m114_driver); -} - -module_init(init_mt9m114); -module_exit(exit_mt9m114); - -MODULE_AUTHOR("Shuguang Gong "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c deleted file mode 100644 index 51b7d61df0f5..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov2680.c +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * Support for OmniVision OV2680 1080p HD camera sensor. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" - -#include "ov2680.h" - -static int h_flag = 0; -static int v_flag = 0; -static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { - atomisp_bayer_order_bggr, - atomisp_bayer_order_grbg, - atomisp_bayer_order_gbrg, - atomisp_bayer_order_rggb, -}; - -/* i2c read/write stuff */ -static int ov2680_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV2680_8BIT && data_length != OV2680_16BIT - && data_length != OV2680_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0 , sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV2680_8BIT) - *val = (u8)data[0]; - else if (data_length == OV2680_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - //dev_dbg(&client->dev, "++++i2c read adr%x = %x\n", reg,*val); - return 0; -} - -static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - //dev_dbg(&client->dev, "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]); - return ret == num_msg ? 0 : -EIO; -} - -static int ov2680_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV2680_8BIT) { - data[2] = (u8)(val); - } else { - /* OV2680_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov2680_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov2680_write_reg_array - Initializes a list of OV2680 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and - * __ov2680_write_reg_is_consecutive() are internal functions to - * ov2680_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov2680_flush_reg_array(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov2680_buf_reg_array(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl, - const struct ov2680_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV2680_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV2680_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE) - return __ov2680_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov2680_write_reg_is_consecutive(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl, - const struct ov2680_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov2680_write_reg_array(struct i2c_client *client, - const struct ov2680_reg *reglist) -{ - const struct ov2680_reg *next = reglist; - struct ov2680_write_ctrl ctrl; - int err; - dev_dbg(&client->dev, "++++write reg array\n"); - ctrl.index = 0; - for (; next->type != OV2680_TOK_TERM; next++) { - switch (next->type & OV2680_TOK_MASK) { - case OV2680_TOK_DELAY: - err = __ov2680_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - dev_dbg(&client->dev, "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val); - if (!__ov2680_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov2680_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov2680_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov2680_flush_reg_array(client, &ctrl); -} -static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - - *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for ov2680*/ - - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; - return 0; -} - -static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | - (OV2680_F_NUMBER_DEM << 16) | - (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; - return 0; -} - -static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); - *val = ov2680_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - *val = ov2680_res[dev->fmt_idx].bin_factor_y; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); - return 0; -} - - -static int ov2680_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2680_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2680_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2680_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - (res->bin_factor_x * 2) : 1; - buf->binning_factor_y = res->bin_factor_y ? - (res->bin_factor_y * 2) : 1; - return 0; -} - -static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts,hts; - int ret,exp_val; - - dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); - - hts = ov2680_res[dev->fmt_idx].pixels_per_line; - vts = ov2680_res[dev->fmt_idx].lines_per_frame; - - /* group hold */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_GROUP_ACCESS); - return ret; - } - - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_TIMING_VTS_H); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_L); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_M); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_AGC_H); - return ret; - } - /* Digital gain */ - if (digitgain) { - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov2680_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK - return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - - - - - -static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2680_s_exposure(sd, arg); - - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code) -{ - switch (code) { - case atomisp_bayer_order_rggb: - return MEDIA_BUS_FMT_SRGGB10_1X10; - case atomisp_bayer_order_grbg: - return MEDIA_BUS_FMT_SGRBG10_1X10; - case atomisp_bayer_order_bggr: - return MEDIA_BUS_FMT_SBGGR10_1X10; - case atomisp_bayer_order_gbrg: - return MEDIA_BUS_FMT_SGBRG10_1X10; - } - return 0; -} - -static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - u8 index; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val); - if (ret) - return ret; - if (value) { - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - } else { - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - } - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_FLIP_REG, val); - if (ret) - return ret; - index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - dev->format.code = ov2680_translate_bayer_order( - ov2680_info->raw_bayer_order); - } - return ret; -} - -static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - u8 index; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - - ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val); - if (ret) - return ret; - if (value) { - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - } else { - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - } - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_MIRROR_REG, val); - if (ret) - return ret; - index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - dev->format.code = ov2680_translate_bayer_order( - ov2680_info->raw_bayer_order); - } - return ret; -} - -static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_v_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_h_flip(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2680_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2680_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov2680_s_ctrl, - .g_volatile_ctrl = ov2680_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov2680_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2680_FOCAL_LENGTH_DEFAULT, - .max = OV2680_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2680_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2680_F_NUMBER_DEFAULT, - .max = OV2680_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2680_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2680_F_NUMBER_RANGE, - .max = OV2680_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2680_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, -}; - -static int ov2680_init_registers(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01); - ret |= ov2680_write_reg_array(client, ov2680_global_setting); - - return ret; -} - -static int ov2680_init(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - int ret; - - mutex_lock(&dev->input_lock); - - /* restore settings */ - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; - - ret = ov2680_init_registers(sd); - - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct ov2680_device *dev = to_ov2680_sensor(sd); - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } - - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov2680_device *dev = to_ov2680_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* The OV2680 documents only one GPIO input (#XSHUTDN), but - * existing integrations often wire two (reset/power_down) - * because that is the way other sensors work. There is no - * way to tell how it is wired internally, so existing - * firmwares expose both and we drive them symmetrically. */ - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - /* Ignore return from second gpio, it may not be there */ - dev->platform_data->gpio1_ctrl(sd, 1); - usleep_range(10000, 15000); - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->gpio0_ctrl(sd, 0); - } - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - h_flag = 0; - v_flag = 0; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int ov2680_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - if (on == 0){ - ret = power_down(sd); - } else { - ret = power_up(sd); - if (!ret) - return ov2680_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 600 -static int distance(struct ov2680_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); - - - if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct ov2680_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov2680_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov2680_res[i].width) - continue; - if (h != ov2680_res[i].height) - continue; - - return i; - } - - return -1; -} - -static int ov2680_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 ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2680_info = NULL; - int ret = 0; - int idx = 0; - dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n"); - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (!ov2680_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov2680_res[N_RES - 1].width; - fmt->height = ov2680_res[N_RES - 1].height; - } else { - fmt->width = ov2680_res[idx].width; - fmt->height = ov2680_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n", - dev->fmt_idx); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx, - fmt->width, fmt->height); - dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n", - dev->fmt_idx, fmt->width, fmt->height); - - ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs); - if (ret) - dev_err(&client->dev, "ov2680 write resolution register err\n"); - - ret = ov2680_get_intg_factor(client, ov2680_info, - &ov2680_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - /*recall flip functions to avoid flip registers - * were overridden by default setting - */ - if (h_flag) - ov2680_h_flip(sd, h_flag); - if (v_flag) - ov2680_v_flip(sd, v_flag); - - v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx); - - /*ret = startup(sd); - * if (ret) - * dev_err(&client->dev, "ov2680 startup err\n"); - */ -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2680_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 ov2680_device *dev = to_ov2680_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = ov2680_res[dev->fmt_idx].width; - fmt->height = ov2680_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov2680_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_CHIP_ID_L, &low); - id = ((((u16) high) << 8) | (u16) low); - - if (id != OV2680_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); - - return 0; -} - -static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - if(enable ) - dev_dbg(&client->dev, "ov2680_s_stream one \n"); - else - dev_dbg(&client->dev, "ov2680_s_stream off \n"); - - ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : - OV2680_STOP_STREAMING); -#if 0 - /* restore settings */ - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; -#endif - - //otp valid at stream on state - //if(!dev->otp_data) - // dev->otp_data = ov2680_otp_read(sd); - - mutex_unlock(&dev->input_lock); - - return ret; -} - - -static int ov2680_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov2680_detect(client); - if (ret) { - dev_err(&client->dev, "ov2680_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2680_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2680_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2680_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - dev->run_mode = param->parm.capture.capturemode; - - v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode); - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2680_res = ov2680_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2680_res = ov2680_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov2680_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov2680_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov2680_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov2680_res[index].width; - fse->min_height = ov2680_res[index].height; - fse->max_width = ov2680_res[index].width; - fse->max_height = ov2680_res[index].height; - - return 0; - -} - -static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = ov2680_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_video_ops ov2680_video_ops = { - .s_stream = ov2680_s_stream, - .g_parm = ov2680_g_parm, - .s_parm = ov2680_s_parm, - .g_frame_interval = ov2680_g_frame_interval, -}; - -static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { - .g_skip_frames = ov2680_g_skip_frames, -}; - -static const struct v4l2_subdev_core_ops ov2680_core_ops = { - .s_power = ov2680_s_power, - .ioctl = ov2680_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { - .enum_mbus_code = ov2680_enum_mbus_code, - .enum_frame_size = ov2680_enum_frame_size, - .get_fmt = ov2680_get_fmt, - .set_fmt = ov2680_set_fmt, -}; - -static const struct v4l2_subdev_ops ov2680_ops = { - .core = &ov2680_core_ops, - .video = &ov2680_video_ops, - .pad = &ov2680_pad_ops, - .sensor = &ov2680_sensor_ops, -}; - -static int ov2680_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); - dev_dbg(&client->dev, "ov2680_remove...\n"); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int ov2680_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov2680_device *dev; - int ret; - void *pdata; - unsigned int i; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops); - - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - else - pdata = client->dev.platform_data; - - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = ov2680_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov2680_controls)); - if (ret) { - ov2680_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov2680_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; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - { - ov2680_remove(client); - dev_dbg(&client->dev, "+++ remove ov2680 \n"); - } - return ret; -out_free: - dev_dbg(&client->dev, "+++ out free \n"); - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id ov2680_acpi_match[] = { - {"XXOV2680"}, - {"OVTI2680"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); - - -MODULE_DEVICE_TABLE(i2c, ov2680_id); -static struct i2c_driver ov2680_driver = { - .driver = { - .owner = THIS_MODULE, - .name = OV2680_NAME, - .acpi_match_table = ACPI_PTR(ov2680_acpi_match), - - }, - .probe = ov2680_probe, - .remove = ov2680_remove, - .id_table = ov2680_id, -}; - -static int init_ov2680(void) -{ - return i2c_add_driver(&ov2680_driver); -} - -static void exit_ov2680(void) -{ - - i2c_del_driver(&ov2680_driver); -} - -module_init(init_ov2680); -module_exit(exit_ov2680); - -MODULE_AUTHOR("Jacky Wang "); -MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/media/atomisp/i2c/ov2722.c b/drivers/staging/media/atomisp/i2c/ov2722.c deleted file mode 100644 index 10094ac56561..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov2722.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - * Support for OmniVision OV2722 1080p HD camera sensor. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include -#include - -#include "ov2722.h" - -/* i2c read/write stuff */ -static int ov2722_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV2722_8BIT && data_length != OV2722_16BIT - && data_length != OV2722_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0 , sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV2722_8BIT) - *val = (u8)data[0]; - else if (data_length == OV2722_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - - return 0; -} - -static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int ov2722_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV2722_8BIT) { - data[2] = (u8)(val); - } else { - /* OV2722_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov2722_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov2722_write_reg_array - Initializes a list of OV2722 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and - * __ov2722_write_reg_is_consecutive() are internal functions to - * ov2722_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov2722_flush_reg_array(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov2722_buf_reg_array(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl, - const struct ov2722_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV2722_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV2722_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE) - return __ov2722_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov2722_write_reg_is_consecutive(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl, - const struct ov2722_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov2722_write_reg_array(struct i2c_client *client, - const struct ov2722_reg *reglist) -{ - const struct ov2722_reg *next = reglist; - struct ov2722_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV2722_TOK_TERM; next++) { - switch (next->type & OV2722_TOK_MASK) { - case OV2722_TOK_DELAY: - err = __ov2722_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov2722_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov2722_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov2722_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov2722_flush_reg_array(client, &ctrl); -} -static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | - (OV2722_F_NUMBER_DEM << 16) | - (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2722_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = NULL; - struct atomisp_sensor_mode_data *buf = &info->data; - const unsigned int ext_clk_freq_hz = 19200000; - const unsigned int pll_invariant_div = 10; - unsigned int pix_clk_freq_hz; - u16 pre_pll_clk_div; - u16 pll_multiplier; - u16 op_pix_clk_div; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - dev = to_ov2722_sensor(sd); - - /* pixel clock calculattion */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); - if (ret) - return ret; - - pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; - if (0 == pre_pll_clk_div) - return -EINVAL; - - pll_multiplier = pll_multiplier & 0x7f; - op_pix_clk_div = op_pix_clk_div & 0x03; - pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier - * op_pix_clk_div / pll_invariant_div; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2722_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2722_device *dev = to_ov2722_sensor(sd); - u16 hts, vts; - int ret; - - dev_dbg(&client->dev, "set_exposure without group hold\n"); - - /* clear VTS_DIFF on manual mode */ - ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0); - if (ret) - return ret; - - hts = dev->pixels_per_line; - vts = dev->lines_per_frame; - - if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts) - vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - coarse_itg <<= 4; - digitgain <<= 2; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_VTS_H, vts); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_HTS_H, hts); - if (ret) - return ret; - - /* set exposure */ - ret = ov2722_write_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_L, - coarse_itg & 0xff); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_AEC_PK_EXPO_H, - (coarse_itg >> 8) & 0xfff); - if (ret) - return ret; - - /* set analog gain */ - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_AGC_ADJ_H, gain); - if (ret) - return ret; - - /* set digital gain */ - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_R_H, digitgain); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_G_H, digitgain); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_B_H, digitgain); - - return ret; -} - -static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov2722_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov2722_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return ov2722_set_exposure(sd, exp, gain, digitgain); -} - -static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2722_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_L, - ®_v); - if (ret) - goto err; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2722_device *dev = - container_of(ctrl->handler, struct ov2722_device, ctrl_handler); - int ret = 0; - unsigned int val; - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2722_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2722_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_LINK_FREQ: - val = ov2722_res[dev->fmt_idx].mipi_freq; - if (val == 0) - return -EINVAL; - - ctrl->val = val * 1000; /* To Hz */ - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .g_volatile_ctrl = ov2722_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov2722_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2722_FOCAL_LENGTH_DEFAULT, - .max = OV2722_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2722_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2722_F_NUMBER_DEFAULT, - .max = OV2722_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2722_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2722_F_NUMBER_RANGE, - .max = OV2722_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2722_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_LINK_FREQ, - .name = "Link Frequency", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 1500000 * 1000, - .step = 1, - .def = 1, - .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, - }, -}; - -static int ov2722_init(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - mutex_lock(&dev->input_lock); - - /* restore settings */ - ov2722_res = ov2722_res_preview; - N_RES = N_RES_PREVIEW; - - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = -1; - struct ov2722_device *dev = to_ov2722_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - if (ret) - dev->platform_data->v1p8_ctrl(sd, 0); - } - } else { - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - int ret = -1; - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* Note: the GPIO order is asymmetric: always RESET# - * before PWDN# when turning it on or off. - */ - ret = dev->platform_data->gpio0_ctrl(sd, flag); - /* - *ov2722 PWDN# active high when pull down,opposite to the convention - */ - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int ov2722_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) - return ov2722_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct ov2722_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct ov2722_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov2722_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov2722_res[i].width) - continue; - if (h != ov2722_res[i].height) - continue; - - return i; - } - - return -1; -} - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - ret = ov2722_write_reg(client, OV2722_8BIT, - OV2722_SW_RESET, 0x01); - if (ret) { - dev_err(&client->dev, "ov2722 reset err.\n"); - return ret; - } - - ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "ov2722 write register err.\n"); - return ret; - } - - return ret; -} - -static int ov2722_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 ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2722_info = NULL; - int ret = 0; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - ov2722_info = v4l2_get_subdev_hostdata(sd); - if (!ov2722_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov2722_res[N_RES - 1].width; - fmt->height = ov2722_res[N_RES - 1].height; - } else { - fmt->width = ov2722_res[idx].width; - fmt->height = ov2722_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line; - dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame; - - ret = startup(sd); - if (ret) { - int i = 0; - dev_err(&client->dev, "ov2722 startup err, retry to power up\n"); - for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) { - dev_err(&client->dev, - "ov2722 retry to power up %d/%d times, result: ", - i + 1, OV2722_POWER_UP_RETRY_NUM); - power_down(sd); - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "power up failed, continue\n"); - continue; - } - ret = startup(sd); - if (ret) { - dev_err(&client->dev, " startup FAILED!\n"); - } else { - dev_err(&client->dev, " startup SUCCESS!\n"); - break; - } - } - if (ret) { - dev_err(&client->dev, "ov2722 startup err\n"); - goto err; - } - } - - ret = ov2722_get_intg_factor(client, ov2722_info, - &ov2722_res[dev->fmt_idx]); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - -err: - mutex_unlock(&dev->input_lock); - return ret; -} -static int ov2722_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 ov2722_device *dev = to_ov2722_sensor(sd); - - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - fmt->width = ov2722_res[dev->fmt_idx].width; - fmt->height = ov2722_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov2722_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_L, &low); - id = (high << 8) | low; - - if ((id != OV2722_ID) && (id != OV2720_ID)) { - dev_err(&client->dev, "sensor ID error\n"); - return -ENODEV; - } - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_dbg(&client->dev, "detect ov2722 success\n"); - return 0; -} - -static int ov2722_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - - ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM, - enable ? OV2722_START_STREAMING : - OV2722_STOP_STREAMING); - - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2722_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov2722_detect(client); - if (ret) { - dev_err(&client->dev, "ov2722_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2722_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2722_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2722_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2722_res = ov2722_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2722_res = ov2722_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2722_res = ov2722_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov2722_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov2722_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov2722_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov2722_res[index].width; - fse->min_height = ov2722_res[index].height; - fse->max_width = ov2722_res[index].width; - fse->max_height = ov2722_res[index].height; - - return 0; - -} - - -static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = ov2722_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = { - .g_skip_frames = ov2722_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops ov2722_video_ops = { - .s_stream = ov2722_s_stream, - .g_parm = ov2722_g_parm, - .s_parm = ov2722_s_parm, - .g_frame_interval = ov2722_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov2722_core_ops = { - .s_power = ov2722_s_power, - .ioctl = ov2722_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov2722_pad_ops = { - .enum_mbus_code = ov2722_enum_mbus_code, - .enum_frame_size = ov2722_enum_frame_size, - .get_fmt = ov2722_get_fmt, - .set_fmt = ov2722_set_fmt, -}; - -static const struct v4l2_subdev_ops ov2722_ops = { - .core = &ov2722_core_ops, - .video = &ov2722_video_ops, - .pad = &ov2722_pad_ops, - .sensor = &ov2722_sensor_ops, -}; - -static int ov2722_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = to_ov2722_sensor(sd); - dev_dbg(&client->dev, "ov2722_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - media_entity_cleanup(&dev->sd.entity); - kfree(dev); - - return 0; -} - -static int __ov2722_init_ctrl_handler(struct ov2722_device *dev) -{ - struct v4l2_ctrl_handler *hdl; - unsigned int i; - hdl = &dev->ctrl_handler; - v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls)); - for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i], - NULL); - - dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ); - - if (dev->ctrl_handler.error || !dev->link_freq) - return dev->ctrl_handler.error; - - dev->sd.ctrl_handler = hdl; - - return 0; -} - -static int ov2722_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov2722_device *dev; - void *ovpdev; - int ret; - struct acpi_device *adev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops); - - ovpdev = client->dev.platform_data; - adev = ACPI_COMPANION(&client->dev); - if (adev) { - adev->power.flags.power_resources = 0; - ovpdev = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - } - - ret = ov2722_s_config(&dev->sd, client->irq, ovpdev); - if (ret) - goto out_free; - - ret = __ov2722_init_ctrl_handler(dev); - if (ret) - goto out_ctrl_handler_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ov2722_remove(client); - - if (ACPI_HANDLE(&client->dev)) - ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA); - - return ret; - -out_ctrl_handler_free: - v4l2_ctrl_handler_free(&dev->ctrl_handler); - -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -MODULE_DEVICE_TABLE(i2c, ov2722_id); - -static const struct acpi_device_id ov2722_acpi_match[] = { - { "INT33FB" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match); - -static struct i2c_driver ov2722_driver = { - .driver = { - .name = OV2722_NAME, - .acpi_match_table = ACPI_PTR(ov2722_acpi_match), - }, - .probe = ov2722_probe, - .remove = ov2722_remove, - .id_table = ov2722_id, -}; - -static int init_ov2722(void) -{ - return i2c_add_driver(&ov2722_driver); -} - -static void exit_ov2722(void) -{ - - i2c_del_driver(&ov2722_driver); -} - -module_init(init_ov2722); -module_exit(exit_ov2722); - -MODULE_AUTHOR("Wei Liu "); -MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig index 9e8d32521e7e..5fe4113bbf08 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +++ b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig @@ -1,4 +1,4 @@ -config VIDEO_OV5693 +config VIDEO_ATOMISP_OV5693 tristate "Omnivision ov5693 sensor support" depends on I2C && VIDEO_V4L2 ---help--- diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Makefile b/drivers/staging/media/atomisp/i2c/ov5693/Makefile index 4e3833aaec05..2de70003658a 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Makefile +++ b/drivers/staging/media/atomisp/i2c/ov5693/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_VIDEO_OV5693) += ov5693.o +obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += atomisp-ov5693.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c new file mode 100644 index 000000000000..219501167584 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -0,0 +1,2059 @@ +/* + * Support for OmniVision OV5693 1080p HD camera sensor. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../include/linux/atomisp_gmin_platform.h" + +#include "ov5693.h" +#include "ad5823.h" + +#define __cci_delay(t) \ + do { \ + if ((t) < 10) { \ + usleep_range((t) * 1000, ((t) + 1) * 1000); \ + } else { \ + msleep((t)); \ + } \ + } while (0) + +/* Value 30ms reached through experimentation on byt ecs. + * The DS specifies a much lower value but when using a smaller value + * the I2C bus sometimes locks up permanently when starting the camera. + * This issue could not be reproduced on cht, so we can reduce the + * delay value to a lower value when insmod. + */ +static uint up_delay = 30; +module_param(up_delay, uint, 0644); +MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693"); + +static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg; + u8 buf[2]; + + buf[0] = reg; + buf[1] = val; + + msg.addr = VCM_ADDR; + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[0]; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err != 1) { + dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n", + __func__, err); + return -EIO; + } + return 0; +} + +static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val) +{ + struct i2c_msg msg; + u8 buf[2]; + buf[0] = reg; + buf[1] = val; + msg.addr = AD5823_VCM_ADDR; + msg.flags = 0; + msg.len = 0x02; + msg.buf = &buf[0]; + + if (i2c_transfer(client->adapter, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + buf[0] = reg; + buf[1] = 0; + + msg[0].addr = AD5823_VCM_ADDR; + msg[0].flags = 0; + msg[0].len = 0x01; + msg[0].buf = &buf[0]; + + msg[1].addr = 0x0c; + msg[1].flags = I2C_M_RD; + msg[1].len = 0x01; + msg[1].buf = &buf[1]; + *val = 0; + if (i2c_transfer(client->adapter, msg, 2) != 2) + return -EIO; + *val = buf[1]; + return 0; +} + + +static const uint32_t ov5693_embedded_effective_size = 28; + +/* i2c read/write stuff */ +static int ov5693_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV5693_8BIT && data_length != OV5693_16BIT + && data_length != OV5693_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV5693_8BIT) + *val = (u8)data[0]; + else if (data_length == OV5693_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + + return 0; +} + +static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int vcm_dw_i2c_write(struct i2c_client *client, u16 data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + u16 val; + + val = cpu_to_be16(data); + msg.addr = VCM_ADDR; + msg.flags = 0; + msg.len = OV5693_16BIT; + msg.buf = (u8 *)&val; + + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +/* Theory: per datasheet, the two VCMs both allow for a 2-byte read. + * The DW9714 doesn't actually specify what this does (it has a + * two-byte write-only protocol, but specifies the read sequence as + * legal), but it returns the same data (zeroes) always, after an + * undocumented initial NAK. The AD5823 has a one-byte address + * register to which all writes go, and subsequent reads will cycle + * through the 8 bytes of registers. Notably, the default values (the + * device is always power-cycled affirmatively, so we can rely on + * these) in AD5823 are not pairwise repetitions of the same 16 bit + * word. So all we have to do is sequentially read two bytes at a + * time and see if we detect a difference in any of the first four + * pairs. */ +static int vcm_detect(struct i2c_client *client) +{ + int i, ret; + struct i2c_msg msg; + u16 data0 = 0, data; + for (i = 0; i < 4; i++) { + msg.addr = VCM_ADDR; + msg.flags = I2C_M_RD; + msg.len = sizeof(data); + msg.buf = (u8 *)&data; + ret = i2c_transfer(client->adapter, &msg, 1); + + /* DW9714 always fails the first read and returns + * zeroes for subsequent ones */ + if (i == 0 && ret == -EREMOTEIO) { + data0 = 0; + continue; + } + + if (i == 0) + data0 = data; + + if (data != data0) + return VCM_AD5823; + } + return ret == 1 ? VCM_DW9714 : ret; +} + +static int ov5693_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV5693_8BIT) { + data[2] = (u8)(val); + } else { + /* OV5693_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov5693_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov5693_write_reg_array - Initializes a list of OV5693 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and + * __ov5693_write_reg_is_consecutive() are internal functions to + * ov5693_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov5693_flush_reg_array(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov5693_buf_reg_array(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl, + const struct ov5693_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV5693_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV5693_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) + return __ov5693_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl, + const struct ov5693_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov5693_write_reg_array(struct i2c_client *client, + const struct ov5693_reg *reglist) +{ + const struct ov5693_reg *next = reglist; + struct ov5693_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != OV5693_TOK_TERM; next++) { + switch (next->type & OV5693_TOK_MASK) { + case OV5693_TOK_DELAY: + err = __ov5693_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__ov5693_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov5693_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov5693_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, + "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov5693_flush_reg_array(client, &ctrl); +} +static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; + return 0; +} + +static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | + (OV5693_F_NUMBER_DEM << 16) | + (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; + return 0; +} + +static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + *val = ov5693_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + *val = ov5693_res[dev->fmt_idx].bin_factor_y; + + return 0; +} + +static int ov5693_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov5693_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + unsigned int pix_clk_freq_hz; + u16 reg_val; + int ret; + + if (info == NULL) + return -EINVAL; + + /* pixel clock */ + pix_clk_freq_hz = res->pix_clk_freq * 1000000; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV5693_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV5693_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + u16 vts, hts; + int ret, exp_val; + + hts = ov5693_res[dev->fmt_idx].pixels_per_line; + vts = ov5693_res[dev->fmt_idx].lines_per_frame; + /*If coarse_itg is larger than 1<<15, can not write to reg directly. + The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts + to the reg. */ + if (coarse_itg > (1 << 15)) { + hts = hts * 2; + coarse_itg = (int)coarse_itg / 2; + } + /* group hold */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0x00); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_GROUP_ACCESS); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_HTS_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_HTS_L, hts & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_HTS_L); + return ret; + } + /* Increase the VTS to match exposure + MARGIN */ + if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN) + vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN; + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_VTS_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_VTS_L, vts & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_VTS_L); + return ret; + } + + /* set exposure */ + + /* Lower four bit should be 0*/ + exp_val = coarse_itg << 4; + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_L, exp_val & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_L); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_M); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_H); + return ret; + } + + /* Analog gain */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_AGC_L, gain & 0xff); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_AGC_L); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_AGC_H, (gain >> 8) & 0xff); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_AGC_H); + return ret; + } + + /* Digital gain */ + if (digitgain) { + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_RED_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_GREEN_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_BLUE_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + } + + /* End group */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0x10); + if (ret) + return ret; + + /* Delay launch group */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0xa0); + if (ret) + return ret; + return ret; +} + +static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov5693_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov5693_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + u16 coarse_itg = exposure->integration_time[0]; + u16 analog_gain = exposure->gain[0]; + u16 digital_gain = exposure->gain[1]; + + /* we should not accept the invalid value below */ + if (analog_gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain); +} + +static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, + u16 addr, u8 *buf) +{ + u16 index; + int ret; + u16 *pVal = NULL; + + for (index = 0; index <= size; index++) { + pVal = (u16 *) (buf + index); + ret = + ov5693_read_reg(client, OV5693_8BIT, addr + index, + pVal); + if (ret) + return ret; + } + + return 0; +} + +static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + int ret; + int i; + u8 *b = buf; + dev->otp_size = 0; + for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { + /*set bank NO and OTP read mode. */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no + if (ret) { + dev_err(&client->dev, "failed to prepare OTP page\n"); + return ret; + } + //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); + + /*enable read */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1 + if (ret) { + dev_err(&client->dev, + "failed to set OTP reading mode page"); + return ret; + } + //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); + + /* Reading the OTP data array */ + ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, + OV5693_OTP_START_ADDR, + b); + if (ret) { + dev_err(&client->dev, "failed to read OTP data\n"); + return ret; + } + + //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); + + //Intel OTP map, try to read 320byts first. + if (21 == i) { + if ((*b) == 0) { + dev->otp_size = 320; + break; + } else { + b = buf; + continue; + } + } else if (24 == i) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. + if ((*b) == 0) { + dev->otp_size = 32; + break; + } else { + b = buf; + continue; + } + } else if (27 == i) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. + if ((*b) == 0) { + dev->otp_size = 32; + break; + } else { + dev->otp_size = 0; // no OTP data. + break; + } + } + + b = b + OV5693_OTP_BANK_SIZE; + } + return 0; +} + +/* + * Read otp data and store it into a kmalloced buffer. + * The caller must kfree the buffer when no more needed. + * @size: set to the size of the returned otp data. + */ +static void *ov5693_otp_read(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 *buf; + int ret; + + buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + //otp valid after mipi on and sw stream on + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_STREAM, OV5693_START_STREAMING); + + ret = __ov5693_otp_read(sd, buf); + + //mipi off and sw stream off after otp read + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_STREAM, OV5693_STOP_STREAMING); + + /* Driver has failed to find valid data */ + if (ret) { + dev_err(&client->dev, "sensor found no valid OTP data\n"); + return ERR_PTR(ret); + } + + return buf; +} + +static int ov5693_g_priv_int_data(struct v4l2_subdev *sd, + struct v4l2_private_int_data *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + u8 __user *to = priv->data; + u32 read_size = priv->size; + int ret; + + /* No need to copy data if size is 0 */ + if (!read_size) + goto out; + + if (IS_ERR(dev->otp_data)) { + dev_err(&client->dev, "OTP data not available"); + return PTR_ERR(dev->otp_data); + } + + /* Correct read_size value only if bigger than maximum */ + if (read_size > OV5693_OTP_DATA_SIZE) + read_size = OV5693_OTP_DATA_SIZE; + + ret = copy_to_user(to, dev->otp_data, read_size); + if (ret) { + dev_err(&client->dev, "%s: failed to copy OTP data to user\n", + __func__); + return -EFAULT; + } + + pr_debug("%s read_size:%d\n", __func__, read_size); + +out: + /* Return correct size */ + priv->size = dev->otp_size; + + return 0; + +} + +static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov5693_s_exposure(sd, arg); + case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: + return ov5693_g_priv_int_data(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + for filling in EXIF data, not for actual image processing. */ +static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = -EINVAL; + u8 vcm_code; + + ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); + if (ret) + return ret; + + /* set reg VCM_CODE_MSB Bit[1:0] */ + vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | + ((val >> 8) & ~VCM_CODE_MSB_MASK); + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code); + if (ret) + return ret; + + /* set reg VCM_CODE_LSB Bit[7:0] */ + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff)); + if (ret) + return ret; + + /* set required vcm move time */ + vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF + - AD5823_HIGH_FREQ_RANGE; + ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code); + + return ret; +} + +int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) +{ + value = min(value, AD5823_MAX_FOCUS_POS); + return ad5823_t_focus_vcm(sd, value); +} + +static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value); + value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS); + if (dev->vcm == VCM_DW9714) { + if (dev->vcm_update) { + ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF); + if (ret) + return ret; + ret = vcm_dw_i2c_write(client, DIRECT_VCM); + if (ret) + return ret; + ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON); + if (ret) + return ret; + dev->vcm_update = false; + } + ret = vcm_dw_i2c_write(client, + vcm_val(value, VCM_DEFAULT_S)); + } else if (dev->vcm == VCM_AD5823) { + ad5823_t_focus_abs(sd, value); + } + if (ret == 0) { + dev->number_of_steps = value - dev->focus; + dev->focus = value; + getnstimeofday(&(dev->timestamp_t_focus_abs)); + } else + dev_err(&client->dev, + "%s: i2c failed. ret %d\n", __func__, ret); + + return ret; +} + +static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + return ov5693_t_focus_abs(sd, dev->focus + value); +} + +#define DELAY_PER_STEP_NS 1000000 +#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) +static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value) +{ + u32 status = 0; + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct timespec temptime; + const struct timespec timedelay = { + 0, + min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS, + (u32)DELAY_MAX_PER_STEP_NS), + }; + + getnstimeofday(&temptime); + temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs)); + if (timespec_compare(&temptime, &timedelay) <= 0) { + status |= ATOMISP_FOCUS_STATUS_MOVING; + status |= ATOMISP_FOCUS_HP_IN_PROGRESS; + } else { + status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; + status |= ATOMISP_FOCUS_HP_COMPLETE; + } + + *value = status; + + return 0; +} + +static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + s32 val; + + ov5693_q_focus_status(sd, &val); + + if (val & ATOMISP_FOCUS_STATUS_MOVING) + *value = dev->focus - dev->number_of_steps; + else + *value = dev->focus; + + return 0; +} + +static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->number_of_steps = value; + dev->vcm_update = true; + return 0; +} + +static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->number_of_steps = value; + dev->vcm_update = true; + return 0; +} + +static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *dev = + container_of(ctrl->handler, struct ov5693_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FOCUS_ABSOLUTE: + dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n", + __func__, ctrl->val); + ret = ov5693_t_focus_abs(&dev->sd, ctrl->val); + break; + case V4L2_CID_FOCUS_RELATIVE: + dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n", + __func__, ctrl->val); + ret = ov5693_t_focus_rel(&dev->sd, ctrl->val); + break; + case V4L2_CID_VCM_SLEW: + ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val); + break; + case V4L2_CID_VCM_TIMEING: + ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *dev = + container_of(ctrl->handler, struct ov5693_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov5693_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov5693_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCUS_ABSOLUTE: + ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCUS_STATUS: + ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = ov5693_s_ctrl, + .g_volatile_ctrl = ov5693_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov5693_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV5693_FOCAL_LENGTH_DEFAULT, + .max = OV5693_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV5693_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV5693_F_NUMBER_DEFAULT, + .max = OV5693_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV5693_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV5693_F_NUMBER_RANGE, + .max = OV5693_F_NUMBER_RANGE, + .step = 0x01, + .def = OV5693_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus move absolute", + .min = 0, + .max = OV5693_VCM_MAX_FOCUS_POS, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus move relative", + .min = OV5693_VCM_MAX_FOCUS_NEG, + .max = OV5693_VCM_MAX_FOCUS_POS, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_STATUS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus status", + .min = 0, + .max = 100, /* allow enum to grow in the future */ + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VCM_SLEW, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vcm slew", + .min = 0, + .max = OV5693_VCM_SLEW_STEP_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VCM_TIMEING, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vcm step time", + .min = 0, + .max = OV5693_VCM_SLEW_TIME_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = OV5693_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = OV5693_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int ov5693_init(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s\n", __func__); + mutex_lock(&dev->input_lock); + dev->vcm_update = false; + + if (dev->vcm == VCM_AD5823) { + ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */ + if (ret) + dev_err(&client->dev, + "vcm reset failed\n"); + /*change the mode*/ + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, + AD5823_RING_CTRL_ENABLE); + if (ret) + dev_err(&client->dev, + "vcm enable ringing failed\n"); + ret = ad5823_i2c_write(client, AD5823_REG_MODE, + AD5823_ARC_RES1); + if (ret) + dev_err(&client->dev, + "vcm change mode failed\n"); + } + + /*change initial focus value for ad5823*/ + if (dev->vcm == VCM_AD5823) { + dev->focus = AD5823_INIT_FOCUS_POS; + ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS); + } else { + dev->focus = 0; + ov5693_t_focus_abs(sd, 0); + } + + mutex_unlock(&dev->input_lock); + + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct ov5693_device *dev = to_ov5693_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + /* This driver assumes "internal DVDD, PWDNB tied to DOVDD". + * In this set up only gpio0 (XSHUTDN) should be available + * but in some products (for example ECS) gpio1 (PWDNB) is + * also available. If gpio1 is available we emulate it being + * tied to DOVDD here. */ + if (flag) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + dev->platform_data->gpio1_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret) { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->v2p8_ctrl(sd, 0); + } + } + } else { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + return dev->platform_data->gpio0_ctrl(sd, flag); +} + +static int __power_up(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + /* add this delay time to 10~11ms*/ + usleep_range(10000, 11000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + __cci_delay(up_delay); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + dev->focus = OV5693_INVALID_CONFIG; + if (NULL == dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + static const int retry_count = 4; + int i, ret; + + for (i = 0; i < retry_count; i++) { + ret = __power_up(sd); + if (!ret) + return 0; + + power_down(sd); + } + return ret; +} + +static int ov5693_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + pr_info("%s: on %d\n", __func__, on); + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) { + ret = ov5693_init(sd); + /* restore settings */ + ov5693_res = ov5693_res_preview; + N_RES = N_RES_PREVIEW; + } + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between res_w/res_h and w/h. + * distance = (res_w/res_h - w/h) / (w/h) * 8192 + * res->width/height smaller than w/h wouldn't be considered. + * The gap of ratio larger than 1/8 wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 +static int distance(struct ov5693_resolution *res, u32 w, u32 h) +{ + int ratio; + int distance; + + if (w == 0 || h == 0 || + res->width < w || res->height < h) + return -1; + + ratio = res->width << 13; + ratio /= w; + ratio *= h; + ratio /= res->height; + + distance = abs(ratio - 8192); + + if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) + return -1; + + return distance; +} + +/* Return the nearest higher resolution index + * Firstly try to find the approximate aspect ratio resolution + * If we find multiple same AR resolutions, choose the + * minimal size. + */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + int min_res_w = INT_MAX; + struct ov5693_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov5693_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + min_res_w = ov5693_res[i].width; + continue; + } + if (dist == min_dist && ov5693_res[i].width < min_res_w) + idx = i; + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov5693_res[i].width) + continue; + if (h != ov5693_res[i].height) + continue; + + return i; + } + + return -1; +} + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_RESET, 0x01); + if (ret) { + dev_err(&client->dev, "ov5693 reset err.\n"); + return ret; + } + + ret = ov5693_write_reg_array(client, ov5693_global_setting); + if (ret) { + dev_err(&client->dev, "ov5693 write register err.\n"); + return ret; + } + + ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "ov5693 write register err.\n"); + return ret; + } + + return ret; +} + +static int ov5693_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 ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov5693_info = NULL; + int ret = 0; + int idx; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + ov5693_info = v4l2_get_subdev_hostdata(sd); + if (ov5693_info == NULL) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov5693_res[N_RES - 1].width; + fmt->height = ov5693_res[N_RES - 1].height; + } else { + fmt->width = ov5693_res[idx].width; + fmt->height = ov5693_res[idx].height; + } + + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + ret = startup(sd); + if (ret) { + int i = 0; + dev_err(&client->dev, "ov5693 startup err, retry to power up\n"); + for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) { + dev_err(&client->dev, + "ov5693 retry to power up %d/%d times, result: ", + i+1, OV5693_POWER_UP_RETRY_NUM); + power_down(sd); + ret = power_up(sd); + if (!ret) { + mutex_unlock(&dev->input_lock); + ov5693_init(sd); + mutex_lock(&dev->input_lock); + } else { + dev_err(&client->dev, "power up failed, continue\n"); + continue; + } + ret = startup(sd); + if (ret) { + dev_err(&client->dev, " startup FAILED!\n"); + } else { + dev_err(&client->dev, " startup SUCCESS!\n"); + break; + } + } + } + + /* + * After sensor settings are set to HW, sometimes stream is started. + * This would cause ISP timeout because ISP is not ready to receive + * data yet. So add stop streaming here. + */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, + OV5693_STOP_STREAMING); + if (ret) + dev_warn(&client->dev, "ov5693 stream off err\n"); + + ret = ov5693_get_intg_factor(client, ov5693_info, + &ov5693_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + ov5693_info->metadata_width = fmt->width * 10 / 8; + ov5693_info->metadata_height = 1; + ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; + +err: + mutex_unlock(&dev->input_lock); + return ret; +} +static int ov5693_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 ov5693_device *dev = to_ov5693_sensor(sd); + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = ov5693_res[dev->fmt_idx].width; + fmt->height = ov5693_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov5693_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_CHIP_ID_L, &low); + id = ((((u16) high) << 8) | (u16) low); + + if (id != OV5693_ID) { + dev_err(&client->dev, "sensor ID error 0x%x\n", id); + return -ENODEV; + } + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); + dev_dbg(&client->dev, "detect ov5693 success\n"); + return 0; +} + +static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, + enable ? OV5693_START_STREAMING : + OV5693_STOP_STREAMING); + + mutex_unlock(&dev->input_lock); + + return ret; +} + + +static int ov5693_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (platform_data == NULL) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-up err.\n"); + goto fail_power_on; + } + + if (!dev->vcm) + dev->vcm = vcm_detect(client); + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov5693_detect(client); + if (ret) { + dev_err(&client->dev, "ov5693_detect err s_config.\n"); + goto fail_csi_cfg; + } + + dev->otp_data = ov5693_otp_read(sd); + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return ret; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov5693_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov5693_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov5693_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov5693_res = ov5693_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov5693_res = ov5693_res_still; + N_RES = N_RES_STILL; + break; + default: + ov5693_res = ov5693_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov5693_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov5693_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov5693_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov5693_res[index].width; + fse->min_height = ov5693_res[index].height; + fse->max_width = ov5693_res[index].width; + fse->max_height = ov5693_res[index].height; + + return 0; + +} + +static const struct v4l2_subdev_video_ops ov5693_video_ops = { + .s_stream = ov5693_s_stream, + .g_parm = ov5693_g_parm, + .s_parm = ov5693_s_parm, + .g_frame_interval = ov5693_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops ov5693_core_ops = { + .s_power = ov5693_s_power, + .ioctl = ov5693_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { + .enum_mbus_code = ov5693_enum_mbus_code, + .enum_frame_size = ov5693_enum_frame_size, + .get_fmt = ov5693_get_fmt, + .set_fmt = ov5693_set_fmt, +}; + +static const struct v4l2_subdev_ops ov5693_ops = { + .core = &ov5693_core_ops, + .video = &ov5693_video_ops, + .pad = &ov5693_pad_ops, +}; + +static int ov5693_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev_dbg(&client->dev, "ov5693_remove...\n"); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int ov5693_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov5693_device *dev; + int i2c; + int ret = 0; + void *pdata = client->dev.platform_data; + struct acpi_device *adev; + unsigned int i; + + /* Firmware workaround: Some modules use a "secondary default" + * address of 0x10 which doesn't appear on schematics, and + * some BIOS versions haven't gotten the memo. Work around + * via config. */ + i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1); + if (i2c != -1) { + dev_info(&client->dev, + "Overriding firmware-provided I2C address (0x%x) with 0x%x\n", + client->addr, i2c); + client->addr = i2c; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops); + + adev = ACPI_COMPANION(&client->dev); + if (adev) { + adev->power.flags.power_resources = 0; + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); + } + + if (!pdata) + goto out_free; + + ret = ov5693_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(ov5693_controls)); + if (ret) { + ov5693_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + ov5693_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; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + ov5693_remove(client); + + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +MODULE_DEVICE_TABLE(i2c, ov5693_id); + +static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); + +static struct i2c_driver ov5693_driver = { + .driver = { + .name = OV5693_NAME, + .acpi_match_table = ACPI_PTR(ov5693_acpi_match), + }, + .probe = ov5693_probe, + .remove = ov5693_remove, + .id_table = ov5693_id, +}; + +static int init_ov5693(void) +{ + return i2c_add_driver(&ov5693_driver); +} + +static void exit_ov5693(void) +{ + + i2c_del_driver(&ov5693_driver); +} + +module_init(init_ov5693); +module_exit(exit_ov5693); + +MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c deleted file mode 100644 index 219501167584..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c +++ /dev/null @@ -1,2059 +0,0 @@ -/* - * Support for OmniVision OV5693 1080p HD camera sensor. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../include/linux/atomisp_gmin_platform.h" - -#include "ov5693.h" -#include "ad5823.h" - -#define __cci_delay(t) \ - do { \ - if ((t) < 10) { \ - usleep_range((t) * 1000, ((t) + 1) * 1000); \ - } else { \ - msleep((t)); \ - } \ - } while (0) - -/* Value 30ms reached through experimentation on byt ecs. - * The DS specifies a much lower value but when using a smaller value - * the I2C bus sometimes locks up permanently when starting the camera. - * This issue could not be reproduced on cht, so we can reduce the - * delay value to a lower value when insmod. - */ -static uint up_delay = 30; -module_param(up_delay, uint, 0644); -MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693"); - -static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - int err; - struct i2c_msg msg; - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; - - err = i2c_transfer(client->adapter, &msg, 1); - if (err != 1) { - dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n", - __func__, err); - return -EIO; - } - return 0; -} - -static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2]; - buf[0] = reg; - buf[1] = val; - msg.addr = AD5823_VCM_ADDR; - msg.flags = 0; - msg.len = 0x02; - msg.buf = &buf[0]; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - buf[0] = reg; - buf[1] = 0; - - msg[0].addr = AD5823_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 0x01; - msg[0].buf = &buf[0]; - - msg[1].addr = 0x0c; - msg[1].flags = I2C_M_RD; - msg[1].len = 0x01; - msg[1].buf = &buf[1]; - *val = 0; - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - return 0; -} - - -static const uint32_t ov5693_embedded_effective_size = 28; - -/* i2c read/write stuff */ -static int ov5693_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT - && data_length != OV5693_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV5693_8BIT) - *val = (u8)data[0]; - else if (data_length == OV5693_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - - return 0; -} - -static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int vcm_dw_i2c_write(struct i2c_client *client, u16 data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - u16 val; - - val = cpu_to_be16(data); - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = OV5693_16BIT; - msg.buf = (u8 *)&val; - - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -/* Theory: per datasheet, the two VCMs both allow for a 2-byte read. - * The DW9714 doesn't actually specify what this does (it has a - * two-byte write-only protocol, but specifies the read sequence as - * legal), but it returns the same data (zeroes) always, after an - * undocumented initial NAK. The AD5823 has a one-byte address - * register to which all writes go, and subsequent reads will cycle - * through the 8 bytes of registers. Notably, the default values (the - * device is always power-cycled affirmatively, so we can rely on - * these) in AD5823 are not pairwise repetitions of the same 16 bit - * word. So all we have to do is sequentially read two bytes at a - * time and see if we detect a difference in any of the first four - * pairs. */ -static int vcm_detect(struct i2c_client *client) -{ - int i, ret; - struct i2c_msg msg; - u16 data0 = 0, data; - for (i = 0; i < 4; i++) { - msg.addr = VCM_ADDR; - msg.flags = I2C_M_RD; - msg.len = sizeof(data); - msg.buf = (u8 *)&data; - ret = i2c_transfer(client->adapter, &msg, 1); - - /* DW9714 always fails the first read and returns - * zeroes for subsequent ones */ - if (i == 0 && ret == -EREMOTEIO) { - data0 = 0; - continue; - } - - if (i == 0) - data0 = data; - - if (data != data0) - return VCM_AD5823; - } - return ret == 1 ? VCM_DW9714 : ret; -} - -static int ov5693_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV5693_8BIT) { - data[2] = (u8)(val); - } else { - /* OV5693_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov5693_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov5693_write_reg_array - Initializes a list of OV5693 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and - * __ov5693_write_reg_is_consecutive() are internal functions to - * ov5693_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov5693_flush_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov5693_buf_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV5693_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV5693_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) - return __ov5693_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov5693_write_reg_array(struct i2c_client *client, - const struct ov5693_reg *reglist) -{ - const struct ov5693_reg *next = reglist; - struct ov5693_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV5693_TOK_TERM; next++) { - switch (next->type & OV5693_TOK_MASK) { - case OV5693_TOK_DELAY: - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov5693_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov5693_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, - "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov5693_flush_reg_array(client, &ctrl); -} -static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | - (OV5693_F_NUMBER_DEM << 16) | - (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int ov5693_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov5693_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - - if (info == NULL) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV5693_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV5693_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - u16 vts, hts; - int ret, exp_val; - - hts = ov5693_res[dev->fmt_idx].pixels_per_line; - vts = ov5693_res[dev->fmt_idx].lines_per_frame; - /*If coarse_itg is larger than 1<<15, can not write to reg directly. - The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts - to the reg. */ - if (coarse_itg > (1 << 15)) { - hts = hts * 2; - coarse_itg = (int)coarse_itg / 2; - } - /* group hold */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_GROUP_ACCESS); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_L, hts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_L); - return ret; - } - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN) - vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_L, vts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_L); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_M); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_L, gain & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_H, (gain >> 8) & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_H); - return ret; - } - - /* Digital gain */ - if (digitgain) { - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov5693_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov5693_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - -static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, - u16 addr, u8 *buf) -{ - u16 index; - int ret; - u16 *pVal = NULL; - - for (index = 0; index <= size; index++) { - pVal = (u16 *) (buf + index); - ret = - ov5693_read_reg(client, OV5693_8BIT, addr + index, - pVal); - if (ret) - return ret; - } - - return 0; -} - -static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - int i; - u8 *b = buf; - dev->otp_size = 0; - for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { - /*set bank NO and OTP read mode. */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no - if (ret) { - dev_err(&client->dev, "failed to prepare OTP page\n"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); - - /*enable read */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1 - if (ret) { - dev_err(&client->dev, - "failed to set OTP reading mode page"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); - - /* Reading the OTP data array */ - ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, - OV5693_OTP_START_ADDR, - b); - if (ret) { - dev_err(&client->dev, "failed to read OTP data\n"); - return ret; - } - - //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); - - //Intel OTP map, try to read 320byts first. - if (21 == i) { - if ((*b) == 0) { - dev->otp_size = 320; - break; - } else { - b = buf; - continue; - } - } else if (24 == i) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - b = buf; - continue; - } - } else if (27 == i) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - dev->otp_size = 0; // no OTP data. - break; - } - } - - b = b + OV5693_OTP_BANK_SIZE; - } - return 0; -} - -/* - * Read otp data and store it into a kmalloced buffer. - * The caller must kfree the buffer when no more needed. - * @size: set to the size of the returned otp data. - */ -static void *ov5693_otp_read(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - - buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - //otp valid after mipi on and sw stream on - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_START_STREAMING); - - ret = __ov5693_otp_read(sd, buf); - - //mipi off and sw stream off after otp read - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_STOP_STREAMING); - - /* Driver has failed to find valid data */ - if (ret) { - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); - } - - return buf; -} - -static int ov5693_g_priv_int_data(struct v4l2_subdev *sd, - struct v4l2_private_int_data *priv) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - u8 __user *to = priv->data; - u32 read_size = priv->size; - int ret; - - /* No need to copy data if size is 0 */ - if (!read_size) - goto out; - - if (IS_ERR(dev->otp_data)) { - dev_err(&client->dev, "OTP data not available"); - return PTR_ERR(dev->otp_data); - } - - /* Correct read_size value only if bigger than maximum */ - if (read_size > OV5693_OTP_DATA_SIZE) - read_size = OV5693_OTP_DATA_SIZE; - - ret = copy_to_user(to, dev->otp_data, read_size); - if (ret) { - dev_err(&client->dev, "%s: failed to copy OTP data to user\n", - __func__); - return -EFAULT; - } - - pr_debug("%s read_size:%d\n", __func__, read_size); - -out: - /* Return correct size */ - priv->size = dev->otp_size; - - return 0; - -} - -static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov5693_s_exposure(sd, arg); - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - return ov5693_g_priv_int_data(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ -static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -EINVAL; - u8 vcm_code; - - ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_MSB Bit[1:0] */ - vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | - ((val >> 8) & ~VCM_CODE_MSB_MASK); - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_LSB Bit[7:0] */ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff)); - if (ret) - return ret; - - /* set required vcm move time */ - vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF - - AD5823_HIGH_FREQ_RANGE; - ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code); - - return ret; -} - -int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - value = min(value, AD5823_MAX_FOCUS_POS); - return ad5823_t_focus_vcm(sd, value); -} - -static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value); - value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS); - if (dev->vcm == VCM_DW9714) { - if (dev->vcm_update) { - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, DIRECT_VCM); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dev->vcm_update = false; - } - ret = vcm_dw_i2c_write(client, - vcm_val(value, VCM_DEFAULT_S)); - } else if (dev->vcm == VCM_AD5823) { - ad5823_t_focus_abs(sd, value); - } - if (ret == 0) { - dev->number_of_steps = value - dev->focus; - dev->focus = value; - getnstimeofday(&(dev->timestamp_t_focus_abs)); - } else - dev_err(&client->dev, - "%s: i2c failed. ret %d\n", __func__, ret); - - return ret; -} - -static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - return ov5693_t_focus_abs(sd, dev->focus + value); -} - -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) -static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct timespec temptime; - const struct timespec timedelay = { - 0, - min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS, - (u32)DELAY_MAX_PER_STEP_NS), - }; - - getnstimeofday(&temptime); - temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs)); - if (timespec_compare(&temptime, &timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - - *value = status; - - return 0; -} - -static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - s32 val; - - ov5693_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = dev->focus - dev->number_of_steps; - else - *value = dev->focus; - - return 0; -} - -static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FOCUS_ABSOLUTE: - dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_abs(&dev->sd, ctrl->val); - break; - case V4L2_CID_FOCUS_RELATIVE: - dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_rel(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_SLEW: - ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_TIMEING: - ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov5693_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov5693_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_STATUS: - ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov5693_s_ctrl, - .g_volatile_ctrl = ov5693_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov5693_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV5693_FOCAL_LENGTH_DEFAULT, - .max = OV5693_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV5693_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV5693_F_NUMBER_DEFAULT, - .max = OV5693_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV5693_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV5693_F_NUMBER_RANGE, - .max = OV5693_F_NUMBER_RANGE, - .step = 0x01, - .def = OV5693_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move absolute", - .min = 0, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_RELATIVE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move relative", - .min = OV5693_VCM_MAX_FOCUS_NEG, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_STATUS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus status", - .min = 0, - .max = 100, /* allow enum to grow in the future */ - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_SLEW, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm slew", - .min = 0, - .max = OV5693_VCM_SLEW_STEP_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_TIMEING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm step time", - .min = 0, - .max = OV5693_VCM_SLEW_TIME_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int ov5693_init(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s\n", __func__); - mutex_lock(&dev->input_lock); - dev->vcm_update = false; - - if (dev->vcm == VCM_AD5823) { - ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */ - if (ret) - dev_err(&client->dev, - "vcm reset failed\n"); - /*change the mode*/ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, - AD5823_RING_CTRL_ENABLE); - if (ret) - dev_err(&client->dev, - "vcm enable ringing failed\n"); - ret = ad5823_i2c_write(client, AD5823_REG_MODE, - AD5823_ARC_RES1); - if (ret) - dev_err(&client->dev, - "vcm change mode failed\n"); - } - - /*change initial focus value for ad5823*/ - if (dev->vcm == VCM_AD5823) { - dev->focus = AD5823_INIT_FOCUS_POS; - ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS); - } else { - dev->focus = 0; - ov5693_t_focus_abs(sd, 0); - } - - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - /* This driver assumes "internal DVDD, PWDNB tied to DOVDD". - * In this set up only gpio0 (XSHUTDN) should be available - * but in some products (for example ECS) gpio1 (PWDNB) is - * also available. If gpio1 is available we emulate it being - * tied to DOVDD here. */ - if (flag) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - dev->platform_data->gpio1_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret) { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v2p8_ctrl(sd, 0); - } - } - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - return dev->platform_data->gpio0_ctrl(sd, flag); -} - -static int __power_up(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - /* add this delay time to 10~11ms*/ - usleep_range(10000, 11000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - __cci_delay(up_delay); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev->focus = OV5693_INVALID_CONFIG; - if (NULL == dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - static const int retry_count = 4; - int i, ret; - - for (i = 0; i < retry_count; i++) { - ret = __power_up(sd); - if (!ret) - return 0; - - power_down(sd); - } - return ret; -} - -static int ov5693_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - pr_info("%s: on %d\n", __func__, on); - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) { - ret = ov5693_init(sd); - /* restore settings */ - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between res_w/res_h and w/h. - * distance = (res_w/res_h - w/h) / (w/h) * 8192 - * res->width/height smaller than w/h wouldn't be considered. - * The gap of ratio larger than 1/8 wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 -static int distance(struct ov5693_resolution *res, u32 w, u32 h) -{ - int ratio; - int distance; - - if (w == 0 || h == 0 || - res->width < w || res->height < h) - return -1; - - ratio = res->width << 13; - ratio /= w; - ratio *= h; - ratio /= res->height; - - distance = abs(ratio - 8192); - - if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) - return -1; - - return distance; -} - -/* Return the nearest higher resolution index - * Firstly try to find the approximate aspect ratio resolution - * If we find multiple same AR resolutions, choose the - * minimal size. - */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - int min_res_w = INT_MAX; - struct ov5693_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov5693_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - min_res_w = ov5693_res[i].width; - continue; - } - if (dist == min_dist && ov5693_res[i].width < min_res_w) - idx = i; - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov5693_res[i].width) - continue; - if (h != ov5693_res[i].height) - continue; - - return i; - } - - return -1; -} - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_RESET, 0x01); - if (ret) { - dev_err(&client->dev, "ov5693 reset err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_global_setting); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - return ret; -} - -static int ov5693_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 ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov5693_info = NULL; - int ret = 0; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - ov5693_info = v4l2_get_subdev_hostdata(sd); - if (ov5693_info == NULL) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov5693_res[N_RES - 1].width; - fmt->height = ov5693_res[N_RES - 1].height; - } else { - fmt->width = ov5693_res[idx].width; - fmt->height = ov5693_res[idx].height; - } - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - ret = startup(sd); - if (ret) { - int i = 0; - dev_err(&client->dev, "ov5693 startup err, retry to power up\n"); - for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) { - dev_err(&client->dev, - "ov5693 retry to power up %d/%d times, result: ", - i+1, OV5693_POWER_UP_RETRY_NUM); - power_down(sd); - ret = power_up(sd); - if (!ret) { - mutex_unlock(&dev->input_lock); - ov5693_init(sd); - mutex_lock(&dev->input_lock); - } else { - dev_err(&client->dev, "power up failed, continue\n"); - continue; - } - ret = startup(sd); - if (ret) { - dev_err(&client->dev, " startup FAILED!\n"); - } else { - dev_err(&client->dev, " startup SUCCESS!\n"); - break; - } - } - } - - /* - * After sensor settings are set to HW, sometimes stream is started. - * This would cause ISP timeout because ISP is not ready to receive - * data yet. So add stop streaming here. - */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - OV5693_STOP_STREAMING); - if (ret) - dev_warn(&client->dev, "ov5693 stream off err\n"); - - ret = ov5693_get_intg_factor(client, ov5693_info, - &ov5693_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - ov5693_info->metadata_width = fmt->width * 10 / 8; - ov5693_info->metadata_height = 1; - ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; - -err: - mutex_unlock(&dev->input_lock); - return ret; -} -static int ov5693_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 ov5693_device *dev = to_ov5693_sensor(sd); - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = ov5693_res[dev->fmt_idx].width; - fmt->height = ov5693_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov5693_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_L, &low); - id = ((((u16) high) << 8) | (u16) low); - - if (id != OV5693_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_dbg(&client->dev, "detect ov5693 success\n"); - return 0; -} - -static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - enable ? OV5693_START_STREAMING : - OV5693_STOP_STREAMING); - - mutex_unlock(&dev->input_lock); - - return ret; -} - - -static int ov5693_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (platform_data == NULL) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-up err.\n"); - goto fail_power_on; - } - - if (!dev->vcm) - dev->vcm = vcm_detect(client); - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov5693_detect(client); - if (ret) { - dev_err(&client->dev, "ov5693_detect err s_config.\n"); - goto fail_csi_cfg; - } - - dev->otp_data = ov5693_otp_read(sd); - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return ret; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov5693_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov5693_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov5693_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov5693_res = ov5693_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov5693_res = ov5693_res_still; - N_RES = N_RES_STILL; - break; - default: - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov5693_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov5693_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov5693_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov5693_res[index].width; - fse->min_height = ov5693_res[index].height; - fse->max_width = ov5693_res[index].width; - fse->max_height = ov5693_res[index].height; - - return 0; - -} - -static const struct v4l2_subdev_video_ops ov5693_video_ops = { - .s_stream = ov5693_s_stream, - .g_parm = ov5693_g_parm, - .s_parm = ov5693_s_parm, - .g_frame_interval = ov5693_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov5693_core_ops = { - .s_power = ov5693_s_power, - .ioctl = ov5693_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { - .enum_mbus_code = ov5693_enum_mbus_code, - .enum_frame_size = ov5693_enum_frame_size, - .get_fmt = ov5693_get_fmt, - .set_fmt = ov5693_set_fmt, -}; - -static const struct v4l2_subdev_ops ov5693_ops = { - .core = &ov5693_core_ops, - .video = &ov5693_video_ops, - .pad = &ov5693_pad_ops, -}; - -static int ov5693_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev_dbg(&client->dev, "ov5693_remove...\n"); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int ov5693_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov5693_device *dev; - int i2c; - int ret = 0; - void *pdata = client->dev.platform_data; - struct acpi_device *adev; - unsigned int i; - - /* Firmware workaround: Some modules use a "secondary default" - * address of 0x10 which doesn't appear on schematics, and - * some BIOS versions haven't gotten the memo. Work around - * via config. */ - i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1); - if (i2c != -1) { - dev_info(&client->dev, - "Overriding firmware-provided I2C address (0x%x) with 0x%x\n", - client->addr, i2c); - client->addr = i2c; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops); - - adev = ACPI_COMPANION(&client->dev); - if (adev) { - adev->power.flags.power_resources = 0; - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - } - - if (!pdata) - goto out_free; - - ret = ov5693_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov5693_controls)); - if (ret) { - ov5693_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov5693_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; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ov5693_remove(client); - - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -MODULE_DEVICE_TABLE(i2c, ov5693_id); - -static const struct acpi_device_id ov5693_acpi_match[] = { - {"INT33BE"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); - -static struct i2c_driver ov5693_driver = { - .driver = { - .name = OV5693_NAME, - .acpi_match_table = ACPI_PTR(ov5693_acpi_match), - }, - .probe = ov5693_probe, - .remove = ov5693_remove, - .id_table = ov5693_id, -}; - -static int init_ov5693(void) -{ - return i2c_add_driver(&ov5693_driver); -} - -static void exit_ov5693(void) -{ - - i2c_del_driver(&ov5693_driver); -} - -module_init(init_ov5693); -module_exit(exit_ov5693); - -MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); -MODULE_LICENSE("GPL");