/* * Support for OmniVision ov8830 1080p HD camera sensor. * * Copyright (c) 2011 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 #include #include #include #include #include "ov8830.h" #include "ov8835.h" #define OV8830_BIN_FACTOR_MAX 2 #define to_ov8830_sensor(sd) container_of(sd, struct ov8830_device, sd) static int ov8830_read_reg(struct i2c_client *client, u16 len, u16 reg, u16 *val) { struct i2c_msg msg[2]; u16 data[OV8830_SHORT_MAX]; int err, i; if (!client->adapter) { v4l2_err(client, "%s error, no client->adapter\n", __func__); return -ENODEV; } /* @len should be even when > 1 */ if (len > OV8830_BYTE_MAX) { v4l2_err(client, "%s error, invalid data length\n", __func__); return -EINVAL; } memset(msg, 0, sizeof(msg)); memset(data, 0, sizeof(data)); msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = I2C_MSG_LENGTH; msg[0].buf = (u8 *)data; /* high byte goes first */ data[0] = cpu_to_be16(reg); msg[1].addr = client->addr; msg[1].len = len; msg[1].flags = I2C_M_RD; msg[1].buf = (u8 *)data; err = i2c_transfer(client->adapter, msg, 2); if (err < 0) goto error; /* high byte comes first */ if (len == OV8830_8BIT) { *val = (u8)data[0]; } else { /* 16-bit access is default when len > 1 */ for (i = 0; i < (len >> 1); i++) val[i] = be16_to_cpu(data[i]); } return 0; error: dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); return err; } static int ov8830_i2c_write(struct i2c_client *client, u16 len, u8 *data) { struct i2c_msg msg; const int num_msg = 1; int ret; int retry = 0; again: msg.addr = client->addr; msg.flags = 0; msg.len = len; msg.buf = data; ret = i2c_transfer(client->adapter, &msg, 1); /* * It is said that Rev 2 sensor needs some delay here otherwise * registers do not seem to load correctly. But tests show that * removing the delay would not cause any in-stablility issue and the * delay will cause serious performance down, so, removed previous * mdelay(1) here. */ if (ret == num_msg) return 0; if (retry <= I2C_RETRY_COUNT) { dev_err(&client->dev, "retrying i2c write transfer... %d", retry); retry++; msleep(20); goto again; } return ret; } static int ov8830_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val) { int ret; unsigned char data[4] = {0}; u16 *wreg; const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ if (!client->adapter) { v4l2_err(client, "%s error, no client->adapter\n", __func__); return -ENODEV; } if (data_length != OV8830_8BIT && data_length != OV8830_16BIT) { v4l2_err(client, "%s error, invalid data_length\n", __func__); return -EINVAL; } /* high byte goes out first */ wreg = (u16 *)data; *wreg = cpu_to_be16(reg); if (data_length == OV8830_8BIT) { data[2] = (u8)(val); } else { /* OV8830_16BIT */ u16 *wdata = (u16 *)&data[2]; *wdata = be16_to_cpu(val); } ret = ov8830_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; } /* * ov8830_write_reg_array - Initializes a list of MT9M114 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(). * * __ov8830_flush_reg_array, __ov8830_buf_reg_array() and * __ov8830_write_reg_is_consecutive() are internal functions to * ov8830_write_reg_array_fast() and should be not used anywhere else. * */ static int __ov8830_flush_reg_array(struct i2c_client *client, struct ov8830_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 ov8830_i2c_write(client, size, (u8 *)&ctrl->buffer); } static int __ov8830_buf_reg_array(struct i2c_client *client, struct ov8830_write_ctrl *ctrl, const struct ov8830_reg *next) { int size; u16 *data16; switch (next->type) { case OV8830_8BIT: size = 1; ctrl->buffer.data[ctrl->index] = (u8)next->val; break; case OV8830_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.sreg; 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) >= OV8830_MAX_WRITE_BUF_SIZE) __ov8830_flush_reg_array(client, ctrl); return 0; } static int __ov8830_write_reg_is_consecutive(struct i2c_client *client, struct ov8830_write_ctrl *ctrl, const struct ov8830_reg *next) { if (ctrl->index == 0) return 1; return ctrl->buffer.addr + ctrl->index == next->reg.sreg; } static int ov8830_write_reg_array(struct i2c_client *client, const struct ov8830_reg *reglist) { const struct ov8830_reg *next = reglist; struct ov8830_write_ctrl ctrl; int err; ctrl.index = 0; for (; next->type != OV8830_TOK_TERM; next++) { switch (next->type & OV8830_TOK_MASK) { case OV8830_TOK_DELAY: err = __ov8830_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 (!__ov8830_write_reg_is_consecutive(client, &ctrl, next)) { err = __ov8830_flush_reg_array(client, &ctrl); if (err) return err; } err = __ov8830_buf_reg_array(client, &ctrl, next); if (err) { v4l2_err(client, "%s: write error, aborted\n", __func__); return err; } break; } } return __ov8830_flush_reg_array(client, &ctrl); } static int drv201_write8(struct v4l2_subdev *sd, int reg, int val) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct drv201_device *dev = to_drv201_device(sd); struct i2c_msg msg; memset(&msg, 0 , sizeof(msg)); msg.addr = DRV201_I2C_ADDR; msg.len = 2; msg.buf = dev->buffer; msg.buf[0] = reg; msg.buf[1] = val; return i2c_transfer(client->adapter, &msg, 1); } static int drv201_write16(struct v4l2_subdev *sd, int reg, int val) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct drv201_device *dev = to_drv201_device(sd); struct i2c_msg msg; memset(&msg, 0 , sizeof(msg)); msg.addr = DRV201_I2C_ADDR; msg.len = 3; msg.buf = dev->buffer; msg.buf[0] = reg; msg.buf[1] = val >> 8; msg.buf[2] = val & 0xFF; return i2c_transfer(client->adapter, &msg, 1); } static int drv201_read8(struct v4l2_subdev *sd, int reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct drv201_device *dev = to_drv201_device(sd); struct i2c_msg msg[2]; int r; memset(msg, 0 , sizeof(msg)); msg[0].addr = DRV201_I2C_ADDR; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = dev->buffer; msg[0].buf[0] = reg; msg[1].addr = DRV201_I2C_ADDR; msg[1].flags = I2C_M_RD; msg[1].len = 1; msg[1].buf = dev->buffer; r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); if (r != ARRAY_SIZE(msg)) return -EIO; return dev->buffer[0]; } static int drv201_init(struct v4l2_subdev *sd) { struct drv201_device *dev = to_drv201_device(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); dev->platform_data = camera_get_af_platform_data(); if (!dev->platform_data) { v4l2_err(client, "failed to get platform data\n"); return -ENXIO; } return 0; } static int drv201_power_up(struct v4l2_subdev *sd) { /* Transition time required from shutdown to standby state */ const int WAKEUP_DELAY_US = 100; const int DEFAULT_CONTROL_VAL = 0x02; struct drv201_device *dev = to_drv201_device(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int r; /* Enable power */ r = dev->platform_data->power_ctrl(sd, 1); if (r) return r; udelay(1); /* Wait for VBAT to stabilize */ /* jiggle SCL pin to wake up device */ drv201_write8(sd, DRV201_CONTROL, 1); usleep_range(WAKEUP_DELAY_US, WAKEUP_DELAY_US * 10); /* Reset device */ r = drv201_write8(sd, DRV201_CONTROL, 1); if (r < 0) goto fail_powerdown; /* Detect device */ r = drv201_read8(sd, DRV201_CONTROL); if (r < 0) goto fail_powerdown; if (r != DEFAULT_CONTROL_VAL) { r = -ENXIO; goto fail_powerdown; } /* Use the liner mode to reduce the noise */ r = drv201_write8(sd, DRV201_MODE, DRV201_MODE_LINEAR); if (r < 0) goto fail_powerdown; /* VCM RESONANCE FREQUENCY REGISTER (VCM_FREQ) */ r = drv201_write8(sd, DRV201_VCM_FREQ, DRV201_DEFAULT_VCM_FREQ); if (r < 0) goto fail_powerdown; dev->focus = DRV201_MAX_FOCUS_POS; dev->initialized = true; v4l2_info(client, "detected drv201\n"); return 0; fail_powerdown: dev->platform_data->power_ctrl(sd, 0); return r; } static int drv201_power_down(struct v4l2_subdev *sd) { struct drv201_device *dev = to_drv201_device(sd); return dev->platform_data->power_ctrl(sd, 0); } static int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value) { struct drv201_device *dev = to_drv201_device(sd); int r; if (!dev->initialized) return -ENODEV; value = clamp(value, 0, DRV201_MAX_FOCUS_POS); r = drv201_write16(sd, DRV201_VCM_CURRENT, value); if (r < 0) return r; getnstimeofday(&dev->focus_time); dev->focus = value; return 0; } /* Start group hold for the following register writes */ static int ov8830_grouphold_start(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); const int group = 0; return ov8830_write_reg(client, OV8830_8BIT, OV8830_GROUP_ACCESS, group | OV8830_GROUP_ACCESS_HOLD_START); } /* End group hold and delay launch it */ static int ov8830_grouphold_launch(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); const int group = 0; int ret; /* End group */ ret = ov8830_write_reg(client, OV8830_8BIT, OV8830_GROUP_ACCESS, group | OV8830_GROUP_ACCESS_HOLD_END); if (ret) return ret; /* Delay launch group (during next vertical blanking) */ return ov8830_write_reg(client, OV8830_8BIT, OV8830_GROUP_ACCESS, group | OV8830_GROUP_ACCESS_DELAY_LAUNCH); } /* * Read EEPROM data from the le24l042cs chip and store * it into a kmalloced buffer. On error return NULL. * The caller must kfree the buffer when no more needed. * @size: set to the size of the returned EEPROM data. */ static void *le24l042cs_read(struct i2c_client *client, u32 *size) { static const unsigned int LE24L042CS_I2C_ADDR = 0xA0 >> 1; static const unsigned int LE24L042CS_EEPROM_SIZE = 512; static const unsigned int MAX_READ_SIZE = OV8830_MAX_WRITE_BUF_SIZE; struct i2c_msg msg[2]; int addr; char *buffer; buffer = kmalloc(LE24L042CS_EEPROM_SIZE, GFP_KERNEL); if (!buffer) return NULL; memset(msg, 0, sizeof(msg)); for (addr = 0; addr < LE24L042CS_EEPROM_SIZE; addr += MAX_READ_SIZE) { unsigned int i2c_addr = LE24L042CS_I2C_ADDR; unsigned char addr_buf; int r; i2c_addr |= (addr >> 8) & 1; addr_buf = addr & 0xFF; msg[0].addr = i2c_addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = &addr_buf; msg[1].addr = i2c_addr; msg[1].flags = I2C_M_RD; msg[1].len = min(MAX_READ_SIZE, LE24L042CS_EEPROM_SIZE - addr); msg[1].buf = &buffer[addr]; r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); if (r != ARRAY_SIZE(msg)) { kfree(buffer); dev_err(&client->dev, "read failed at 0x%03x\n", addr); return NULL; } } if (size) *size = LE24L042CS_EEPROM_SIZE; return buffer; } static int ov8830_g_priv_int_data(struct v4l2_subdev *sd, struct v4l2_private_int_data *priv) { u32 size; void *b = le24l042cs_read(v4l2_get_subdevdata(sd), &size); int r = 0; if (!b) return -EIO; if (copy_to_user(priv->data, b, min_t(__u32, priv->size, size))) r = -EFAULT; priv->size = size; kfree(b); return r; } static int __ov8830_get_max_fps_index( const struct ov8830_fps_setting *fps_settings) { int i; for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { if (fps_settings[i].fps == 0) break; } return i - 1; } static int __ov8830_update_frame_timing(struct v4l2_subdev *sd, int exposure, u16 *hts, u16 *vts) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; /* Increase the VTS to match exposure + 14 */ if (exposure > *vts - OV8830_INTEGRATION_TIME_MARGIN) *vts = (u16) exposure + OV8830_INTEGRATION_TIME_MARGIN; ret = ov8830_write_reg(client, OV8830_16BIT, OV8830_TIMING_HTS, *hts); if (ret) return ret; return ov8830_write_reg(client, OV8830_16BIT, OV8830_TIMING_VTS, *vts); } static int __ov8830_set_exposure(struct v4l2_subdev *sd, int exposure, int gain, int dig_gain, u16 *hts, u16 *vts) { struct i2c_client *client = v4l2_get_subdevdata(sd); int exp_val, ret; dev_dbg(&client->dev, "set exposure:0x%x, gain:0x%x, dig_gain:0x%x", exposure, gain, dig_gain); if (!(exposure && gain)) { return 0; } /* Update frame timings. Expsure must be minimum < vts-14 */ ret = __ov8830_update_frame_timing(sd, exposure, hts, vts); if (ret) return ret; /* For OV8835, the low 4 bits are fraction bits and must be kept 0 */ exp_val = exposure << 4; ret = ov8830_write_reg(client, OV8830_8BIT, OV8830_LONG_EXPO+2, exp_val & 0xFF); if (ret) return ret; ret = ov8830_write_reg(client, OV8830_8BIT, OV8830_LONG_EXPO+1, (exp_val >> 8) & 0xFF); if (ret) return ret; ret = ov8830_write_reg(client, OV8830_8BIT, OV8830_LONG_EXPO, (exp_val >> 16) & 0x0F); if (ret) return ret; /* Digital gain : to all MWB channel gains */ if (dig_gain) { ret = ov8830_write_reg(client, OV8830_16BIT, OV8830_MWB_RED_GAIN_H, dig_gain); if (ret) return ret; ret = ov8830_write_reg(client, OV8830_16BIT, OV8830_MWB_GREEN_GAIN_H, dig_gain); if (ret) return ret; ret = ov8830_write_reg(client, OV8830_16BIT, OV8830_MWB_BLUE_GAIN_H, dig_gain); if (ret) return ret; } /* set global gain */ return ov8830_write_reg(client, OV8830_8BIT, OV8830_AGC_ADJ, gain); } static int ov8830_set_exposure(struct v4l2_subdev *sd, int exposure, int gain, int dig_gain) { struct ov8830_device *dev = to_ov8830_sensor(sd); const struct ov8830_resolution *res; u16 hts, vts; int ret; mutex_lock(&dev->input_lock); /* Validate exposure: cannot exceed 16bit value */ exposure = clamp_t(int, exposure, 0, OV8830_MAX_EXPOSURE_VALUE); /* Validate gain: must not exceed maximum 8bit value */ gain = clamp_t(int, gain, 0, OV8830_MAX_GAIN_VALUE); /* Validate digital gain: must not exceed 12 bit value*/ dig_gain = clamp_t(int, dig_gain, 0, OV8830_MWB_GAIN_MAX); /* Group hold is valid only if sensor is streaming. */ if (dev->streaming) { ret = ov8830_grouphold_start(sd); if (ret) goto out; } res = &dev->curr_res_table[dev->fmt_idx]; hts = res->fps_options[dev->fps_index].pixels_per_line; vts = res->fps_options[dev->fps_index].lines_per_frame; ret = __ov8830_set_exposure(sd, exposure, gain, dig_gain, &hts, &vts); if (ret) goto out; /* Updated the device variable. These are the current values. */ dev->gain = gain; dev->exposure = exposure; dev->digital_gain = dig_gain; out: /* Group hold launch - delayed launch */ if (dev->streaming) ret = ov8830_grouphold_launch(sd); mutex_unlock(&dev->input_lock); return ret; } static int ov8830_s_exposure(struct v4l2_subdev *sd, struct atomisp_exposure *exposure) { return ov8830_set_exposure(sd, exposure->integration_time[0], exposure->gain[0], exposure->gain[1]); } static long ov8830_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct i2c_client *client = v4l2_get_subdevdata(sd); switch (cmd) { case ATOMISP_IOC_S_EXPOSURE: return ov8830_s_exposure(sd, (struct atomisp_exposure *)arg); case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: return ov8830_g_priv_int_data(sd, arg); default: dev_err(&client->dev, "%s: invalid ioctl cmd\n", __func__); return -EINVAL; } return 0; } static int ov8830_init_registers(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov8830_device *dev = to_ov8830_sensor(sd); if (dev->sensor_id == OV8835_CHIP_ID) dev->basic_settings_list = ov8835_basic_settings; else dev->basic_settings_list = ov8830_BasicSettings; return ov8830_write_reg_array(client, dev->basic_settings_list); } static int ov8830_init(struct v4l2_subdev *sd, u32 val) { struct ov8830_device *dev = to_ov8830_sensor(sd); int ret; mutex_lock(&dev->input_lock); ret = ov8830_init_registers(sd); mutex_unlock(&dev->input_lock); return ret; } static void ov8830_uninit(struct v4l2_subdev *sd) { struct ov8830_device *dev = to_ov8830_sensor(sd); dev->exposure = 0; dev->gain = 0; dev->digital_gain = 0; } static int power_up(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov8830_device *dev = to_ov8830_sensor(sd); int ret; /* Enable power */ ret = dev->platform_data->power_ctrl(sd, 1); if (ret) goto fail_power; /* Release reset */ ret = dev->platform_data->gpio_ctrl(sd, 1); if (ret) dev_err(&client->dev, "gpio failed 1\n"); /* Enable clock */ ret = dev->platform_data->flisclk_ctrl(sd, 1); if (ret) goto fail_clk; /* Minumum delay is 8192 clock cycles before first i2c transaction, * which is 1.37 ms at the lowest allowed clock rate 6 MHz */ msleep(2); return 0; fail_clk: dev->platform_data->flisclk_ctrl(sd, 0); fail_power: dev->platform_data->power_ctrl(sd, 0); dev_err(&client->dev, "sensor power-up failed\n"); return ret; } static int power_down(struct v4l2_subdev *sd) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; ret = dev->platform_data->flisclk_ctrl(sd, 0); if (ret) dev_err(&client->dev, "flisclk failed\n"); /* gpio ctrl */ ret = dev->platform_data->gpio_ctrl(sd, 0); if (ret) dev_err(&client->dev, "gpio failed 1\n"); /* power control */ ret = dev->platform_data->power_ctrl(sd, 0); if (ret) dev_err(&client->dev, "vprog failed.\n"); return ret; } static int __ov8830_s_power(struct v4l2_subdev *sd, int on) { struct ov8830_device *dev = to_ov8830_sensor(sd); int ret, r; if (on == 0) { ov8830_uninit(sd); ret = power_down(sd); r = drv201_power_down(sd); if (ret == 0) ret = r; dev->power = 0; } else { ret = power_up(sd); if (ret) return ret; ret = drv201_power_up(sd); if (ret) { power_down(sd); return ret; } dev->power = 1; /* Initalise sensor settings */ ret = ov8830_init_registers(sd); } return ret; } static int ov8830_s_power(struct v4l2_subdev *sd, int on) { int ret; struct ov8830_device *dev = to_ov8830_sensor(sd); mutex_lock(&dev->input_lock); ret = __ov8830_s_power(sd, on); mutex_unlock(&dev->input_lock); /* * FIXME: Compatibility with old behaviour: return to preview * when the device is power cycled. */ if (!ret && on) v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); return ret; } static int ov8830_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV8830, 0); return 0; } /* Return value of the specified register, first try getting it from * the register list and if not found, get from the sensor via i2c. */ static int ov8830_get_register(struct v4l2_subdev *sd, int reg, const struct ov8830_reg *reglist) { struct i2c_client *client = v4l2_get_subdevdata(sd); const struct ov8830_reg *next; u16 val; /* Try if the values is in the register list */ for (next = reglist; next->type != OV8830_TOK_TERM; next++) { if (next->type != OV8830_8BIT) { v4l2_err(sd, "only 8-bit registers supported\n"); return -ENXIO; } if (next->reg.sreg == reg) return next->val; } /* If not, read from sensor */ if (ov8830_read_reg(client, OV8830_8BIT, reg, &val)) { v4l2_err(sd, "failed to read register 0x%04X\n", reg); return -EIO; } return val; } static int ov8830_get_register_16bit(struct v4l2_subdev *sd, int reg, const struct ov8830_reg *reglist, unsigned int *value) { int high, low; high = ov8830_get_register(sd, reg, reglist); if (high < 0) return high; low = ov8830_get_register(sd, reg + 1, reglist); if (low < 0) return low; *value = ((u8) high << 8) | (u8) low; return 0; } static int ov8830_get_intg_factor(struct v4l2_subdev *sd, struct camera_mipi_info *info, const struct ov8830_reg *reglist) { const int ext_clk = 19200000; /* MHz */ struct atomisp_sensor_mode_data *m = &info->data; struct ov8830_device *dev = to_ov8830_sensor(sd); const struct ov8830_resolution *res = &dev->curr_res_table[dev->fmt_idx]; int pll2_prediv; int pll2_multiplier; int pll2_divs; int pll2_seld5; int t1, t2, t3; int sclk; int ret; memset(&info->data, 0, sizeof(info->data)); pll2_prediv = ov8830_get_register(sd, OV8830_PLL_PLL10, reglist); pll2_multiplier = ov8830_get_register(sd, OV8830_PLL_PLL11, reglist); pll2_divs = ov8830_get_register(sd, OV8830_PLL_PLL12, reglist); pll2_seld5 = ov8830_get_register(sd, OV8830_PLL_PLL13, reglist); if (pll2_prediv < 0 || pll2_multiplier < 0 || pll2_divs < 0 || pll2_seld5 < 0) return -EIO; pll2_prediv &= 0x07; pll2_multiplier &= 0x3F; pll2_divs = (pll2_divs & 0x0F) + 1; pll2_seld5 &= 0x03; if (pll2_prediv <= 0) return -EIO; t1 = ext_clk / pll2_prediv; t2 = t1 * pll2_multiplier; t3 = t2 / pll2_divs; sclk = t3; if (pll2_seld5 == 0) sclk = t3; else if (pll2_seld5 == 3) sclk = t3 * 2 / 5; else sclk = t3 / pll2_seld5; m->vt_pix_clk_freq_mhz = sclk; /* HTS and VTS */ m->frame_length_lines = res->fps_options[dev->fps_index].lines_per_frame; m->line_length_pck = res->fps_options[dev->fps_index].pixels_per_line; m->coarse_integration_time_min = 0; m->coarse_integration_time_max_margin = OV8830_INTEGRATION_TIME_MARGIN; /* OV Sensor do not use fine integration time. */ m->fine_integration_time_min = 0; m->fine_integration_time_max_margin = 0; /* * read_mode indicate whether binning is used for calculating * the correct exposure value from the user side. So adapt the * read mode values accordingly. */ m->read_mode = res->bin_factor_x ? OV8830_READ_MODE_BINNING_ON : OV8830_READ_MODE_BINNING_OFF; ret = ov8830_get_register(sd, OV8830_TIMING_X_INC, res->regs); if (ret < 0) return ret; m->binning_factor_x = ((ret >> 4) + 1) / 2; ret = ov8830_get_register(sd, OV8830_TIMING_Y_INC, res->regs); if (ret < 0) return ret; m->binning_factor_y = ((ret >> 4) + 1) / 2; /* Get the cropping and output resolution to ISP for this mode. */ ret = ov8830_get_register_16bit(sd, OV8830_HORIZONTAL_START_H, res->regs, &m->crop_horizontal_start); if (ret) return ret; ret = ov8830_get_register_16bit(sd, OV8830_VERTICAL_START_H, res->regs, &m->crop_vertical_start); if (ret) return ret; ret = ov8830_get_register_16bit(sd, OV8830_HORIZONTAL_END_H, res->regs, &m->crop_horizontal_end); if (ret) return ret; ret = ov8830_get_register_16bit(sd, OV8830_VERTICAL_END_H, res->regs, &m->crop_vertical_end); if (ret) return ret; ret = ov8830_get_register_16bit(sd, OV8830_HORIZONTAL_OUTPUT_SIZE_H, res->regs, &m->output_width); if (ret) return ret; return ov8830_get_register_16bit(sd, OV8830_VERTICAL_OUTPUT_SIZE_H, res->regs, &m->output_height); } static int __ov8830_s_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct camera_mipi_info *info = v4l2_get_subdev_hostdata(sd); const struct ov8830_resolution *res = res = &dev->curr_res_table[dev->fmt_idx]; int i; int ret; int fps; u16 hts; u16 vts; if (!interval->interval.numerator) interval->interval.numerator = 1; fps = interval->interval.denominator / interval->interval.numerator; /* Ignore if we are already using the required FPS. */ if (fps == res->fps_options[dev->fps_index].fps) return 0; dev->fps_index = 0; /* Go through the supported FPS list */ for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { if (!res->fps_options[i].fps) break; if (abs(res->fps_options[i].fps - fps) < abs(res->fps_options[dev->fps_index].fps - fps)) dev->fps_index = i; } /* Get the new Frame timing values for new exposure */ hts = res->fps_options[dev->fps_index].pixels_per_line; vts = res->fps_options[dev->fps_index].lines_per_frame; /* update frametiming. Conside the curren exposure/gain as well */ ret = __ov8830_set_exposure(sd, dev->exposure, dev->gain, dev->digital_gain, &hts, &vts); if (ret) return ret; /* Update the new values so that user side knows the current settings */ ret = ov8830_get_intg_factor(sd, info, dev->basic_settings_list); if (ret) return ret; interval->interval.denominator = res->fps_options[dev->fps_index].fps; interval->interval.numerator = 1; return 0; } /* * 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. */ /* tune this value so that the DVS resolutions get selected properly, * but make sure 16:9 does not match 4:3. */ #define LARGEST_ALLOWED_RATIO_MISMATCH 500 static int distance(struct ov8830_resolution const *res, const u32 w, const u32 h) { unsigned int w_ratio = ((res->width<<13)/w); unsigned int h_ratio = ((res->height<<13)/h); int 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; } /* * Returns the nearest higher resolution index. * @w: width * @h: height * matching is done based on enveloping resolution and * aspect ratio. If the aspect ratio cannot be matched * to any index, -1 is returned. */ static int nearest_resolution_index(struct v4l2_subdev *sd, int w, int h) { int i; int idx = -1; int dist; int min_dist = INT_MAX; const struct ov8830_resolution *tmp_res = NULL; struct ov8830_device *dev = to_ov8830_sensor(sd); for (i = 0; i < dev->entries_curr_table; i++) { tmp_res = &dev->curr_res_table[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(struct v4l2_subdev *sd, int w, int h) { int i; struct ov8830_device *dev = to_ov8830_sensor(sd); for (i = 0; i < dev->entries_curr_table; i++) { if (w != dev->curr_res_table[i].width) continue; if (h != dev->curr_res_table[i].height) continue; /* Found it */ return i; } return -1; } static int __ov8830_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { int idx; struct ov8830_device *dev = to_ov8830_sensor(sd); if (!fmt) return -EINVAL; if ((fmt->width > OV8830_RES_WIDTH_MAX) || (fmt->height > OV8830_RES_HEIGHT_MAX)) { fmt->width = OV8830_RES_WIDTH_MAX; fmt->height = OV8830_RES_HEIGHT_MAX; } else { idx = nearest_resolution_index(sd, fmt->width, fmt->height); /* * nearest_resolution_index() doesn't return smaller resolutions. * If it fails, it means the requested resolution is higher than we * can support. Fallback to highest possible resolution in this case. */ if (idx == -1) idx = dev->entries_curr_table - 1; fmt->width = dev->curr_res_table[idx].width; fmt->height = dev->curr_res_table[idx].height; } fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10; return 0; } static int ov8830_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct ov8830_device *dev = to_ov8830_sensor(sd); int r; mutex_lock(&dev->input_lock); r = __ov8830_try_mbus_fmt(sd, fmt); mutex_unlock(&dev->input_lock); return r; } static int ov8830_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct camera_mipi_info *ov8830_info = NULL; struct i2c_client *client = v4l2_get_subdevdata(sd); u16 hts, vts; int ret; const struct ov8830_resolution *res; ov8830_info = v4l2_get_subdev_hostdata(sd); if (ov8830_info == NULL) return -EINVAL; mutex_lock(&dev->input_lock); ret = __ov8830_try_mbus_fmt(sd, fmt); if (ret) goto out; dev->fmt_idx = get_resolution_index(sd, fmt->width, fmt->height); /* Sanity check */ if (unlikely(dev->fmt_idx == -1)) { ret = -EINVAL; goto out; } /* Sets the default FPS */ dev->fps_index = 0; /* Get the current resolution setting */ res = &dev->curr_res_table[dev->fmt_idx]; /* Write the selected resolution table values to the registers */ ret = ov8830_write_reg_array(client, res->regs); if (ret) goto out; /* Frame timing registers are updates as part of exposure */ hts = res->fps_options[dev->fps_index].pixels_per_line; vts = res->fps_options[dev->fps_index].lines_per_frame; /* * update hts, vts, exposure and gain as one block. Note that the vts * will be changed according to the exposure used. But the maximum vts * dev->curr_res_table[dev->fmt_idx] should not be changed at all. */ ret = __ov8830_set_exposure(sd, dev->exposure, dev->gain, dev->digital_gain, &hts, &vts); if (ret) goto out; ret = ov8830_get_intg_factor(sd, ov8830_info, dev->basic_settings_list); out: mutex_unlock(&dev->input_lock); return ret; } static int ov8830_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct ov8830_device *dev = to_ov8830_sensor(sd); if (!fmt) return -EINVAL; mutex_lock(&dev->input_lock); fmt->width = dev->curr_res_table[dev->fmt_idx].width; fmt->height = dev->curr_res_table[dev->fmt_idx].height; fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10; mutex_unlock(&dev->input_lock); return 0; } static int ov8830_detect(struct i2c_client *client, u16 *id, u8 *revision) { struct i2c_adapter *adapter = client->adapter; u16 id35; int ret, s_ret; /* i2c check */ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; /* check sensor chip ID - are same for both 8830 and 8835 modules */ ret = ov8830_read_reg(client, OV8830_16BIT, OV8830_CHIP_ID_HIGH, id); if (ret) return ret; /* This always reads as 0x8830, even on 8835. */ dev_info(&client->dev, "chip_id = 0x%4.4x\n", *id); if (*id != OV8830_CHIP_ID) return -ENODEV; /* * Check which module is attached OV8835 or OV8830. * We need to support OV8830 for a while. * * For correctly identifying the OV8835 module, sensor needs * to start streaming, OTP read enabled and wait for about 10ms * before reading the OTB Bank 0 for OV8835 module identification. * * TODO/FIXME Revisit OTP support is added or OV8830 not needed anymore. */ ret = ov8830_write_reg_array(client, ov8835_module_detection); if (ret) return ret; msleep(20); ret = ov8830_read_reg(client, OV8830_8BIT, OV8830_OTP_BANK0_PID, &id35); if (ret) goto out; /* OTP BANK0 read will return 0x35 for OV8835 else 0*/ if (id35 == 0x35) *id = OV8835_CHIP_ID; dev_info(&client->dev, "sensor is ov%4.4x\n", *id); /* REVISIT: HACK: Driver is currently forcing revision to 0 */ *revision = 0; out: /* Stream off now. */ s_ret = ov8830_write_reg(client, OV8830_8BIT, OV8830_STREAM_MODE, 0); return ret ? ret : s_ret; } /* * ov8830 stream on/off */ static int ov8830_s_stream(struct v4l2_subdev *sd, int enable) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; mutex_lock(&dev->input_lock); ret = ov8830_write_reg(client, OV8830_8BIT, 0x0100, enable ? 1 : 0); if (ret != 0) { mutex_unlock(&dev->input_lock); v4l2_err(client, "failed to set streaming\n"); return ret; } dev->streaming = enable; mutex_unlock(&dev->input_lock); return 0; } /* * ov8830 enum frame size, frame intervals */ static int ov8830_enum_framesizes(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize) { unsigned int index = fsize->index; struct ov8830_device *dev = to_ov8830_sensor(sd); mutex_lock(&dev->input_lock); if (index >= dev->entries_curr_table) { mutex_unlock(&dev->input_lock); return -EINVAL; } fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = dev->curr_res_table[index].width; fsize->discrete.height = dev->curr_res_table[index].height; fsize->reserved[0] = dev->curr_res_table[index].used; mutex_unlock(&dev->input_lock); return 0; } static int ov8830_enum_frameintervals(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival) { unsigned int index = fival->index; int fmt_index; struct ov8830_device *dev = to_ov8830_sensor(sd); const struct ov8830_resolution *res; mutex_lock(&dev->input_lock); /* * since the isp will donwscale the resolution to the right size, * find the nearest one that will allow the isp to do so important to * ensure that the resolution requested is padded correctly by the * requester, which is the atomisp driver in this case. */ fmt_index = nearest_resolution_index(sd, fival->width, fival->height); if (-1 == fmt_index) fmt_index = dev->entries_curr_table - 1; res = &dev->curr_res_table[fmt_index]; /* Check if this index is supported */ if (index > __ov8830_get_max_fps_index(res->fps_options)) { mutex_unlock(&dev->input_lock); return -EINVAL; } fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete.numerator = 1; fival->discrete.denominator = res->fps_options[index].fps; mutex_unlock(&dev->input_lock); return 0; } static int ov8830_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { *code = V4L2_MBUS_FMT_SBGGR10_1X10; return 0; } static int ov8830_s_config(struct v4l2_subdev *sd, int irq, void *pdata) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); u8 sensor_revision; u16 sensor_id; int ret; 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) { mutex_unlock(&dev->input_lock); v4l2_err(client, "ov8830 platform init err\n"); return ret; } } ret = __ov8830_s_power(sd, 1); if (ret) { mutex_unlock(&dev->input_lock); v4l2_err(client, "ov8830 power-up err.\n"); return ret; } ret = dev->platform_data->csi_cfg(sd, 1); if (ret) goto fail_csi_cfg; /* config & detect sensor */ ret = ov8830_detect(client, &sensor_id, &sensor_revision); if (ret) { v4l2_err(client, "ov8830_detect err s_config.\n"); goto fail_detect; } dev->sensor_id = sensor_id; dev->sensor_revision = sensor_revision; /* power off sensor */ ret = __ov8830_s_power(sd, 0); mutex_unlock(&dev->input_lock); if (ret) { v4l2_err(client, "ov8830 power-down err.\n"); return ret; } return 0; fail_detect: dev->platform_data->csi_cfg(sd, 0); fail_csi_cfg: __ov8830_s_power(sd, 0); mutex_unlock(&dev->input_lock); dev_err(&client->dev, "sensor power-gating failed\n"); return ret; } static int ov8830_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) { if (code->index) return -EINVAL; code->code = V4L2_MBUS_FMT_SBGGR10_1X10; return 0; } static int ov8830_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; struct ov8830_device *dev = to_ov8830_sensor(sd); mutex_lock(&dev->input_lock); if (index >= dev->entries_curr_table) { mutex_unlock(&dev->input_lock); return -EINVAL; } fse->min_width = dev->curr_res_table[index].width; fse->min_height = dev->curr_res_table[index].height; fse->max_width = dev->curr_res_table[index].width; fse->max_height = dev->curr_res_table[index].height; mutex_unlock(&dev->input_lock); return 0; } static struct v4l2_mbus_framefmt * __ov8830_get_pad_format(struct ov8830_device *sensor, struct v4l2_subdev_fh *fh, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(fh, pad); return &sensor->format; } static int ov8830_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) { struct ov8830_device *dev = to_ov8830_sensor(sd); fmt->format = *__ov8830_get_pad_format(dev, fh, fmt->pad, fmt->which); return 0; } static int ov8830_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) { struct ov8830_device *dev = to_ov8830_sensor(sd); struct v4l2_mbus_framefmt *format = __ov8830_get_pad_format(dev, fh, fmt->pad, fmt->which); *format = fmt->format; return 0; } static int ov8830_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov8830_device *dev = container_of( ctrl->handler, struct ov8830_device, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); /* input_lock is taken by the control framework, so it * doesn't need to be taken here. */ /* We only handle V4L2_CID_RUN_MODE for now. */ switch (ctrl->id) { case V4L2_CID_RUN_MODE: switch (ctrl->val) { case ATOMISP_RUN_MODE_VIDEO: dev->curr_res_table = dev->sensor_id == OV8835_CHIP_ID ? ov8835_res_video : ov8830_res_video; dev->entries_curr_table = dev->sensor_id == OV8835_CHIP_ID ? ARRAY_SIZE(ov8835_res_video) : ARRAY_SIZE(ov8830_res_video); break; case ATOMISP_RUN_MODE_STILL_CAPTURE: dev->curr_res_table = dev->sensor_id == OV8835_CHIP_ID ? ov8835_res_still : ov8830_res_still; dev->entries_curr_table = dev->sensor_id == OV8835_CHIP_ID ? ARRAY_SIZE(ov8835_res_still) : ARRAY_SIZE(ov8830_res_still); break; default: dev->curr_res_table = dev->sensor_id == OV8835_CHIP_ID ? ov8835_res_preview : ov8830_res_preview; dev->entries_curr_table = dev->sensor_id == OV8835_CHIP_ID ? ARRAY_SIZE(ov8835_res_preview) : ARRAY_SIZE(ov8830_res_preview); } dev->fmt_idx = 0; dev->fps_index = 0; return 0; case V4L2_CID_TEST_PATTERN: return ov8830_write_reg(client, OV8830_16BIT, 0x3070, ctrl->val); case V4L2_CID_FOCUS_ABSOLUTE: return drv201_t_focus_abs(&dev->sd, ctrl->val); } return -EINVAL; /* Should not happen. */ } static int ov8830_g_ctrl(struct v4l2_ctrl *ctrl) { struct ov8830_device *dev = container_of( ctrl->handler, struct ov8830_device, ctrl_handler); switch (ctrl->id) { case V4L2_CID_FOCUS_STATUS: { static const struct timespec move_time = { /* The time required for focus motor to move the lens */ .tv_sec = 0, .tv_nsec = 60000000, }; struct drv201_device *drv201 = to_drv201_device(&dev->sd); struct timespec current_time, finish_time, delta_time; getnstimeofday(¤t_time); finish_time = timespec_add(drv201->focus_time, move_time); delta_time = timespec_sub(current_time, finish_time); if (delta_time.tv_sec >= 0 && delta_time.tv_nsec >= 0) { /* VCM motor is not moving */ ctrl->val = ATOMISP_FOCUS_HP_COMPLETE | ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; } else { /* VCM motor is still moving */ ctrl->val = ATOMISP_FOCUS_STATUS_MOVING | ATOMISP_FOCUS_HP_IN_PROGRESS; } return 0; } case V4L2_CID_BIN_FACTOR_HORZ: case V4L2_CID_BIN_FACTOR_VERT: { uint16_t reg = ctrl->id == V4L2_CID_BIN_FACTOR_VERT ? OV8830_TIMING_X_INC : OV8830_TIMING_Y_INC; int r = ov8830_get_register( &dev->sd, reg, dev->curr_res_table[dev->fmt_idx].regs); if (r < 0) return r; ctrl->val = fls((r >> 4) + (r & 0xf)) - 2; return 0; } } return 0; } static int ov8830_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { struct ov8830_device *dev = to_ov8830_sensor(sd); const struct ov8830_resolution *res; mutex_lock(&dev->input_lock); /* Return the currently selected settings' maximum frame interval */ res = &dev->curr_res_table[dev->fmt_idx]; interval->interval.numerator = 1; interval->interval.denominator = res->fps_options[dev->fps_index].fps; mutex_unlock(&dev->input_lock); return 0; } static int ov8830_s_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { struct ov8830_device *dev = to_ov8830_sensor(sd); int ret; mutex_lock(&dev->input_lock); ret = __ov8830_s_frame_interval(sd, interval); mutex_unlock(&dev->input_lock); return ret; } static int ov8830_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) { struct ov8830_device *dev = to_ov8830_sensor(sd); mutex_lock(&dev->input_lock); *frames = dev->curr_res_table[dev->fmt_idx].skip_frames; mutex_unlock(&dev->input_lock); return 0; } static const struct v4l2_subdev_video_ops ov8830_video_ops = { .s_stream = ov8830_s_stream, .enum_framesizes = ov8830_enum_framesizes, .enum_frameintervals = ov8830_enum_frameintervals, .enum_mbus_fmt = ov8830_enum_mbus_fmt, .try_mbus_fmt = ov8830_try_mbus_fmt, .g_mbus_fmt = ov8830_g_mbus_fmt, .s_mbus_fmt = ov8830_s_mbus_fmt, .g_frame_interval = ov8830_g_frame_interval, .s_frame_interval = ov8830_s_frame_interval, }; static const struct v4l2_subdev_sensor_ops ov8830_sensor_ops = { .g_skip_frames = ov8830_g_skip_frames, }; static const struct v4l2_subdev_core_ops ov8830_core_ops = { .g_chip_ident = ov8830_g_chip_ident, .queryctrl = v4l2_subdev_queryctrl, .g_ctrl = v4l2_subdev_g_ctrl, .s_ctrl = v4l2_subdev_s_ctrl, .s_power = ov8830_s_power, .ioctl = ov8830_ioctl, .init = ov8830_init, }; /* REVISIT: Do we need pad operations? */ static const struct v4l2_subdev_pad_ops ov8830_pad_ops = { .enum_mbus_code = ov8830_enum_mbus_code, .enum_frame_size = ov8830_enum_frame_size, .get_fmt = ov8830_get_pad_format, .set_fmt = ov8830_set_pad_format, }; static const struct v4l2_subdev_ops ov8830_ops = { .core = &ov8830_core_ops, .video = &ov8830_video_ops, .pad = &ov8830_pad_ops, .sensor = &ov8830_sensor_ops, }; static int ov8830_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov8830_device *dev = to_ov8830_sensor(sd); if (dev->platform_data->platform_deinit) dev->platform_data->platform_deinit(); media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrl_handler); dev->platform_data->csi_cfg(sd, 0); v4l2_device_unregister_subdev(sd); kfree(dev); return 0; } static const struct v4l2_ctrl_ops ctrl_ops = { .s_ctrl = ov8830_s_ctrl, .g_volatile_ctrl = ov8830_g_ctrl, }; static const char * const ctrl_run_mode_menu[] = { NULL, "Video", "Still capture", "Continuous capture", "Preview", }; static const struct v4l2_ctrl_config ctrl_run_mode = { .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, }; static const struct v4l2_ctrl_config ctrls[] = { { .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE_ABSOLUTE, .name = "Absolute exposure", .type = V4L2_CTRL_TYPE_MENU, .max = 0xffff, .qmenu = ctrl_run_mode_menu, }, { .ops = &ctrl_ops, .id = V4L2_CID_TEST_PATTERN, .name = "Test pattern", .type = V4L2_CTRL_TYPE_INTEGER, .step = 1, .max = 0xffff, }, { .ops = &ctrl_ops, .id = V4L2_CID_FOCUS_ABSOLUTE, .name = "Focus absolute", .type = V4L2_CTRL_TYPE_INTEGER, .step = 1, .max = DRV201_MAX_FOCUS_POS, }, { /* This one is junk: see the spec for proper use of this CID. */ .ops = &ctrl_ops, .id = V4L2_CID_FOCUS_STATUS, .name = "Focus status", .type = V4L2_CTRL_TYPE_INTEGER, .step = 1, .max = 100, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, }, { /* This is crap. For compatibility use only. */ .ops = &ctrl_ops, .id = V4L2_CID_FOCAL_ABSOLUTE, .name = "Focal lenght", .type = V4L2_CTRL_TYPE_INTEGER, .min = (OV8830_FOCAL_LENGTH_NUM << 16) | OV8830_FOCAL_LENGTH_DEM, .max = (OV8830_FOCAL_LENGTH_NUM << 16) | OV8830_FOCAL_LENGTH_DEM, .step = 1, .def = (OV8830_FOCAL_LENGTH_NUM << 16) | OV8830_FOCAL_LENGTH_DEM, .flags = V4L2_CTRL_FLAG_READ_ONLY, }, { /* This one is crap, too. For compatibility use only. */ .ops = &ctrl_ops, .id = V4L2_CID_FNUMBER_ABSOLUTE, .name = "F-number", .type = V4L2_CTRL_TYPE_INTEGER, .min = (OV8830_F_NUMBER_DEFAULT_NUM << 16) | OV8830_F_NUMBER_DEM, .max = (OV8830_F_NUMBER_DEFAULT_NUM << 16) | OV8830_F_NUMBER_DEM, .step = 1, .def = (OV8830_F_NUMBER_DEFAULT_NUM << 16) | OV8830_F_NUMBER_DEM, .flags = V4L2_CTRL_FLAG_READ_ONLY, }, { /* * The most utter crap. _Never_ use this, even for * compatibility reasons! */ .ops = &ctrl_ops, .id = V4L2_CID_FNUMBER_RANGE, .name = "F-number range", .type = V4L2_CTRL_TYPE_INTEGER, .min = (OV8830_F_NUMBER_DEFAULT_NUM << 24) | (OV8830_F_NUMBER_DEM << 16) | (OV8830_F_NUMBER_DEFAULT_NUM << 8) | OV8830_F_NUMBER_DEM, .max = (OV8830_F_NUMBER_DEFAULT_NUM << 24) | (OV8830_F_NUMBER_DEM << 16) | (OV8830_F_NUMBER_DEFAULT_NUM << 8) | OV8830_F_NUMBER_DEM, .step = 1, .def = (OV8830_F_NUMBER_DEFAULT_NUM << 24) | (OV8830_F_NUMBER_DEM << 16) | (OV8830_F_NUMBER_DEFAULT_NUM << 8) | OV8830_F_NUMBER_DEM, .flags = V4L2_CTRL_FLAG_READ_ONLY, }, { .ops = &ctrl_ops, .id = V4L2_CID_BIN_FACTOR_HORZ, .name = "Horizontal binning factor", .type = V4L2_CTRL_TYPE_INTEGER, .max = OV8830_BIN_FACTOR_MAX, .step = 1, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, }, { .ops = &ctrl_ops, .id = V4L2_CID_BIN_FACTOR_VERT, .name = "Vertical binning factor", .type = V4L2_CTRL_TYPE_INTEGER, .max = OV8830_BIN_FACTOR_MAX, .step = 1, .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, } }; static int ov8830_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ov8830_device *dev; unsigned int i; int ret; /* allocate sensor device & init sub device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { v4l2_err(client, "%s: out of memory\n", __func__); return -ENOMEM; } mutex_init(&dev->input_lock); dev->fmt_idx = 0; v4l2_i2c_subdev_init(&(dev->sd), client, &ov8830_ops); ret = drv201_init(&dev->sd); if (ret < 0) goto out_free; if (client->dev.platform_data) { ret = ov8830_s_config(&dev->sd, client->irq, 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.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; dev->format.code = V4L2_MBUS_FMT_SBGGR10_1X10; ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1); if (ret) { ov8830_remove(client); return ret; } dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrl_run_mode, NULL); for (i = 0; i < ARRAY_SIZE(ctrls); i++) v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); if (dev->ctrl_handler.error) { ov8830_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); ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0); if (ret) { ov8830_remove(client); return ret; } return 0; out_free: v4l2_device_unregister_subdev(&dev->sd); kfree(dev); return ret; } static const struct i2c_device_id ov8830_id[] = { {OV8830_NAME, 0}, {} }; MODULE_DEVICE_TABLE(i2c, ov8830_id); static struct i2c_driver ov8830_driver = { .driver = { .owner = THIS_MODULE, .name = OV8830_NAME, }, .probe = ov8830_probe, .remove = ov8830_remove, .id_table = ov8830_id, }; static __init int ov8830_init_mod(void) { return i2c_add_driver(&ov8830_driver); } static __exit void ov8830_exit_mod(void) { i2c_del_driver(&ov8830_driver); } module_init(ov8830_init_mod); module_exit(ov8830_exit_mod); MODULE_DESCRIPTION("A low-level driver for Omnivision OV8830 sensors"); MODULE_LICENSE("GPL");