diff options
Diffstat (limited to 'drivers/staging/media/atomisp/i2c/atomisp-ov2680.c')
-rw-r--r-- | drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 1280 |
1 files changed, 392 insertions, 888 deletions
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index fa1de45b7a2d..aeb38599fe13 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -15,30 +15,22 @@ * */ -#include <asm/unaligned.h> - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/kmod.h> +#include <linux/acpi.h> #include <linux/device.h> -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/i2c.h> -#include <linux/moduleparam.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/types.h> + +#include <media/ov_16bit_addr_reg_helpers.h> #include <media/v4l2-device.h> -#include <linux/io.h> -#include <linux/acpi.h> + #include "../include/linux/atomisp_gmin_platform.h" #include "ov2680.h" -static int h_flag; -static int v_flag; static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_bggr, atomisp_bayer_order_grbg, @@ -46,64 +38,6 @@ static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_rggb, }; -/* i2c read/write stuff */ -static int ov2680_read_reg(struct i2c_client *client, - int len, u16 reg, u32 *val) -{ - struct i2c_msg msgs[2]; - u8 addr_buf[2] = { reg >> 8, reg & 0xff }; - u8 data_buf[4] = { 0, }; - int ret; - - if (len > 4) - return -EINVAL; - - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) { - dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret); - return -EIO; - } - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -static int ov2680_write_reg(struct i2c_client *client, unsigned int len, - u16 reg, u16 val) -{ - u8 buf[6]; - int ret; - - if (len == 2) - put_unaligned_be16(val, buf + 2); - else if (len == 1) - buf[2] = val; - else - return -EINVAL; - - put_unaligned_be16(reg, buf); - - ret = i2c_master_send(client, buf, len + 2); - if (ret != len + 2) { - dev_err(&client->dev, "write error %d reg 0x%04x, val 0x%02x: buf sent: %*ph\n", - ret, reg, val, len + 2, &buf); - return -EIO; - } - - return 0; -} - static int ov2680_write_reg_array(struct i2c_client *client, const struct ov2680_reg *reglist) { @@ -111,7 +45,7 @@ static int ov2680_write_reg_array(struct i2c_client *client, int ret; for (; next->reg != 0; next++) { - ret = ov2680_write_reg(client, 1, next->reg, next->val); + ret = ov_write_reg8(client, next->reg, next->val); if (ret) return ret; } @@ -119,518 +53,127 @@ static int ov2680_write_reg_array(struct i2c_client *client, return 0; } -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) +static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt) { - /* const f number for ov2680 */ - - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; - return 0; -} + static const int ov2680_hv_flip_bayer_order[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + }; + struct camera_mipi_info *ov2680_info; + int hv_flip = 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; -} + if (sensor->ctrls.vflip->val) + hv_flip += 1; -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); + if (sensor->ctrls.hflip->val) + hv_flip += 2; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); - *val = dev->res->bin_factor_x; + fmt->code = ov2680_hv_flip_bayer_order[hv_flip]; - return 0; + /* TODO atomisp specific custom API, should be removed */ + ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd); + if (ov2680_info) + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip]; } -static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - *val = dev->res->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 atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u32 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; - - 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, 2, - OV2680_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; + if (sensor->is_streaming) + return -EBUSY; - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT1, BIT(2), val ? BIT(2) : 0); + if (ret < 0) return ret; - buf->output_width = reg_val; - ret = ov2680_read_reg(client, 2, - 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; + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); return 0; } -static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - +static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts; - int ret, exp_val; - - dev_dbg(&client->dev, - "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n", - coarse_itg, gain, digitgain); - - vts = dev->res->lines_per_frame; - - /* group hold */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: 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, 2, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: 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, 1, - OV2680_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_L); - return ret; - } - - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_M); - return ret; - } - - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov2680_write_reg(client, 2, OV2680_AGC_H, gain); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_AGC_H); - return ret; - } - /* Digital gain */ - if (digitgain) { - ret = ov2680_write_reg(client, 2, - OV2680_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, 2, - OV2680_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, 2, - OV2680_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - } + int ret; - /* End group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x10); - if (ret) - return ret; + if (sensor->is_streaming) + return -EBUSY; - /* Delay launch group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0xa0); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT2, BIT(2), val ? BIT(2) : 0); + if (ret < 0) 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 = 0; - - mutex_lock(&dev->input_lock); - - dev->exposure = exposure; - dev->gain = gain; - dev->digitgain = digitgain; - if (dev->power_on) - ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); - - mutex_unlock(&dev->input_lock); - - return ret; + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; } -static long ov2680_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) +static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp) { - 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 ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); + return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4); } -static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain) { - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2680_s_exposure(sd, arg); - - default: - return -EINVAL; - } - return 0; + return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain); } -/* - * 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) +static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 reg_val; int ret; - /* get exposure */ - ret = ov2680_read_reg(client, 3, OV2680_EXPOSURE_H, ®_val); - if (ret) - return ret; - - /* Lower four bits are not part of the exposure val (always 0) */ - *value = reg_val >> 4; - return 0; -} + if (!value) + return ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), 0); -static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) -{ - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u32 val; - u8 index; - - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, 0x03, value - 1); + if (ret < 0) return ret; - if (value) - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - else - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov2680_write_reg(client, 1, - OV2680_FLIP_REG, val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), BIT(7)); + if (ret < 0) 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]; - } - return ret; + + return 0; } -static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) +static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) { - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct ov2680_device *sensor = to_ov2680_sensor(sd); int ret; - u32 val; - u8 index; - - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - - ret = ov2680_read_reg(client, 1, 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, 1, - 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]; + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) { + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; } - 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); + ret = ov2680_set_vflip(sensor, 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); + ret = ov2680_set_hflip(sensor, 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); + case V4L2_CID_EXPOSURE: + ret = ov2680_exposure_set(sensor, ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); + case V4L2_CID_GAIN: + ret = ov2680_gain_set(sensor, ctrl->val); break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); + case V4L2_CID_TEST_PATTERN: + ret = ov2680_test_pattern_set(sensor, ctrl->val); break; default: ret = -EINVAL; } + pm_runtime_put(sensor->sd.dev); return ret; } -static const struct v4l2_ctrl_ops ctrl_ops = { +static const struct v4l2_ctrl_ops ov2680_ctrl_ops = { .s_ctrl = ov2680_s_ctrl, - .g_volatile_ctrl = ov2680_g_volatile_ctrl -}; - -static const 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) @@ -638,288 +181,191 @@ static int ov2680_init_registers(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - ret = ov2680_write_reg(client, 1, OV2680_SW_RESET, 0x01); + ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01); ret |= ov2680_write_reg_array(client, ov2680_global_setting); return ret; } -static int power_ctrl(struct v4l2_subdev *sd, bool flag) +static struct v4l2_mbus_framefmt * +__ov2680_get_pad_format(struct ov2680_device *sensor, + struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) { - int ret = 0; - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - dev_dbg(&client->dev, "%s: %s", __func__, flag ? "on" : "off"); - - if (flag) { - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&sensor->sd, state, pad); - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; + return &sensor->mode.fmt; } -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +static void ov2680_fill_format(struct ov2680_device *sensor, + struct v4l2_mbus_framefmt *fmt, + unsigned int width, unsigned int height) { - int ret; - struct ov2680_device *dev = to_ov2680_sensor(sd); + memset(fmt, 0, sizeof(*fmt)); + fmt->width = width; + fmt->height = height; + fmt->field = V4L2_FIELD_NONE; + ov2680_set_bayer_order(sensor, fmt); +} - if (!dev || !dev->platform_data) - return -ENODEV; +static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height) +{ + int orig_width = width; + int orig_height = height; - /* - * 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); + if (width <= (OV2680_NATIVE_WIDTH / 2) && + height <= (OV2680_NATIVE_HEIGHT / 2)) { + sensor->mode.binning = true; + width *= 2; + height *= 2; } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->gpio0_ctrl(sd, 0); + sensor->mode.binning = false; } - return ret; + + sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1; + sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1; + sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1, + OV2680_NATIVE_WIDTH - 1); + sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1, + OV2680_NATIVE_HEIGHT - 1); + sensor->mode.h_output_size = orig_width; + sensor->mode.v_output_size = orig_height; + sensor->mode.hts = OV2680_PIXELS_PER_LINE; + sensor->mode.vts = OV2680_LINES_PER_FRAME; } -static int power_up(struct v4l2_subdev *sd) +static int ov2680_set_mode(struct ov2680_device *sensor) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_client *client = sensor->client; + u8 pll_div, unknown, inc, fmt1, fmt2; int ret; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; + if (sensor->mode.binning) { + pll_div = 1; + unknown = 0x23; + inc = 0x31; + fmt1 = 0xc2; + fmt2 = 0x01; + } else { + pll_div = 0; + unknown = 0x21; + inc = 0x11; + fmt1 = 0xc0; + fmt2 = 0x00; } - if (dev->power_on) - return 0; /* Already on */ - - /* power control */ - ret = power_ctrl(sd, 1); + ret = ov_write_reg8(client, 0x3086, pll_div); 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; - } + return ret; - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); + ret = ov_write_reg8(client, 0x370a, unknown); if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); + return ret; - ret = ov2680_init_registers(sd); + ret = ov_write_reg16(client, OV2680_HORIZONTAL_START_H, sensor->mode.h_start); if (ret) - goto fail_init_registers; + return ret; - ret = __ov2680_set_exposure(sd, dev->exposure, dev->gain, dev->digitgain); + ret = ov_write_reg16(client, OV2680_VERTICAL_START_H, sensor->mode.v_start); if (ret) - goto fail_init_registers; + return ret; - dev->power_on = true; - return 0; + ret = ov_write_reg16(client, OV2680_HORIZONTAL_END_H, sensor->mode.h_end); + if (ret) + return ret; -fail_init_registers: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); + ret = ov_write_reg16(client, OV2680_VERTICAL_END_H, sensor->mode.v_end); + if (ret) + return ret; - return ret; -} + ret = ov_write_reg16(client, OV2680_HORIZONTAL_OUTPUT_SIZE_H, + sensor->mode.h_output_size); + if (ret) + 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; + ret = ov_write_reg16(client, OV2680_VERTICAL_OUTPUT_SIZE_H, + sensor->mode.v_output_size); + if (ret) + return ret; - h_flag = 0; - v_flag = 0; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } + ret = ov_write_reg16(client, OV2680_HTS, sensor->mode.hts); + if (ret) + return ret; - if (!dev->power_on) - return 0; /* Already off */ + ret = ov_write_reg16(client, OV2680_VTS, sensor->mode.vts); + if (ret) + return ret; - ret = dev->platform_data->flisclk_ctrl(sd, 0); + ret = ov_write_reg16(client, OV2680_ISP_X_WIN, 0); if (ret) - dev_err(&client->dev, "flisclk failed\n"); + return ret; - /* 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 = ov_write_reg16(client, OV2680_ISP_Y_WIN, 0); + if (ret) + return ret; - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) { - dev_err(&client->dev, "vprog failed.\n"); + ret = ov_write_reg8(client, OV2680_X_INC, inc); + if (ret) return ret; - } - dev->power_on = false; - return 0; -} + ret = ov_write_reg8(client, OV2680_Y_INC, inc); + if (ret) + return ret; -static int ov2680_s_power(struct v4l2_subdev *sd, int on) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret; + ret = ov_write_reg16(client, OV2680_X_WIN, sensor->mode.h_output_size); + if (ret) + return ret; - mutex_lock(&dev->input_lock); + ret = ov_write_reg16(client, OV2680_Y_WIN, sensor->mode.v_output_size); + if (ret) + return ret; - if (on == 0) { - ret = power_down(sd); - } else { - ret = power_up(sd); - } + ret = ov_write_reg8(client, OV2680_REG_FORMAT1, fmt1); + if (ret) + return ret; - mutex_unlock(&dev->input_lock); + ret = ov_write_reg8(client, OV2680_REG_FORMAT2, fmt2); + if (ret) + return ret; - return ret; + return 0; } static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, 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; - struct ov2680_resolution *res; - int vts, ret = 0; - - dev_dbg(&client->dev, "%s: %s: pad: %d, fmt: %p\n", - __func__, - (format->which == V4L2_SUBDEV_FORMAT_TRY) ? "try" : "set", - format->pad, fmt); - - if (format->pad) - return -EINVAL; + struct ov2680_device *sensor = to_ov2680_sensor(sd); + struct v4l2_mbus_framefmt *fmt; + unsigned int width, height; - if (!fmt) - return -EINVAL; + width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH); + height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (!ov2680_info) - return -EINVAL; + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); + ov2680_fill_format(sensor, fmt, width, height); - res = v4l2_find_nearest_size(ov2680_res_preview, - ARRAY_SIZE(ov2680_res_preview), width, - height, fmt->width, fmt->height); - if (!res) - res = &ov2680_res_preview[N_RES_PREVIEW - 1]; + format->format = *fmt; - fmt->width = res->width; - fmt->height = res->height; - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - } - - dev_dbg(&client->dev, "%s: %dx%d\n", - __func__, fmt->width, fmt->height); - mutex_lock(&dev->input_lock); - - /* s_power has not been called yet for std v4l2 clients (camorama) */ - power_up(sd); - ret = ov2680_write_reg_array(client, dev->res->regs); - if (ret) { - dev_err(&client->dev, - "ov2680 write resolution register err: %d\n", ret); - goto err; - } - - vts = dev->res->lines_per_frame; - - /* If necessary increase the VTS to match exposure + MARGIN */ - if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); - goto err; - } - - ret = ov2680_get_intg_factor(client, ov2680_info, res); - 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); - - dev->res = res; -err: - mutex_unlock(&dev->input_lock); - return ret; + mutex_lock(&sensor->input_lock); + ov2680_calc_mode(sensor, fmt->width, fmt->height); + mutex_unlock(&sensor->input_lock); + return 0; } static int ov2680_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, 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 = dev->res->width; - fmt->height = dev->res->height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + struct ov2680_device *sensor = to_ov2680_sensor(sd); + struct v4l2_mbus_framefmt *fmt; + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); + format->format = *fmt; return 0; } @@ -934,14 +380,12 @@ static int ov2680_detect(struct i2c_client *client) if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_CHIP_ID_H, &high); + ret = ov_read_reg8(client, 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, 1, - OV2680_SC_CMMN_CHIP_ID_L, &low); + ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low); id = ((((u16)high) << 8) | (u16)low); if (id != OV2680_ID) { @@ -949,8 +393,7 @@ static int ov2680_detect(struct i2c_client *client) return -ENODEV; } - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_SUB_ID, &high); + ret = ov_read_reg8(client, OV2680_SC_CMMN_SUB_ID, &high); revision = (u8)high & 0x0f; dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n", @@ -961,88 +404,79 @@ static int ov2680_detect(struct i2c_client *client) static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; + int ret = 0; + + mutex_lock(&sensor->input_lock); + + if (sensor->is_streaming == enable) { + dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped"); + goto error_unlock; + } + + if (enable) { + ret = pm_runtime_get_sync(sensor->sd.dev); + if (ret < 0) + goto error_unlock; + + ret = ov2680_set_mode(sensor); + if (ret) + goto error_power_down; - 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"); + /* Restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) + goto error_power_down; - ret = ov2680_write_reg(client, 1, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : - OV2680_STOP_STREAMING); + ret = ov_write_reg8(client, OV2680_SW_STREAM, OV2680_START_STREAMING); + if (ret) + goto error_power_down; + } else { + ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING); + pm_runtime_put(sensor->sd.dev); + } - //otp valid at stream on state - //if(!dev->otp_data) - // dev->otp_data = ov2680_otp_read(sd); + sensor->is_streaming = enable; + v4l2_ctrl_activate(sensor->ctrls.vflip, !enable); + v4l2_ctrl_activate(sensor->ctrls.hflip, !enable); - mutex_unlock(&dev->input_lock); + mutex_unlock(&sensor->input_lock); + return 0; +error_power_down: + pm_runtime_put(sensor->sd.dev); +error_unlock: + mutex_unlock(&sensor->input_lock); return ret; } -static int ov2680_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) +static int ov2680_s_config(struct v4l2_subdev *sd) { - 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); + int ret; - ret = power_up(sd); - if (ret) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { 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) { + 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"); - mutex_unlock(&dev->input_lock); + pm_runtime_put(&client->dev); return ret; } 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 = dev->res->fps; - + interval->interval.denominator = OV2680_FPS; return 0; } @@ -1050,7 +484,8 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index >= MAX_FMTS) + /* We support only a single format */ + if (code->index) return -EINVAL; code->code = MEDIA_BUS_FMT_SBGGR10_1X10; @@ -1061,15 +496,25 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { + static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = { + { 1616, 1216 }, + { 1616, 1096 }, + { 1616, 916 }, + { 1456, 1096 }, + { 1296, 976 }, + { 1296, 736 }, + { 784, 592 }, + { 656, 496 }, + }; int index = fse->index; - if (index >= N_RES_PREVIEW) + if (index >= ARRAY_SIZE(ov2680_frame_sizes)) return -EINVAL; - fse->min_width = ov2680_res_preview[index].width; - fse->min_height = ov2680_res_preview[index].height; - fse->max_width = ov2680_res_preview[index].width; - fse->max_height = ov2680_res_preview[index].height; + fse->min_width = ov2680_frame_sizes[index].width; + fse->min_height = ov2680_frame_sizes[index].height; + fse->max_width = ov2680_frame_sizes[index].width; + fse->max_height = ov2680_frame_sizes[index].height; return 0; } @@ -1078,30 +523,18 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { - struct v4l2_fract fract; - - if (fie->index >= N_RES_PREVIEW || - fie->width > ov2680_res_preview[0].width || - fie->height > ov2680_res_preview[0].height || - fie->which > V4L2_SUBDEV_FORMAT_ACTIVE) + /* Only 1 framerate */ + if (fie->index) return -EINVAL; - fract.denominator = ov2680_res_preview[fie->index].fps; - fract.numerator = 1; - - fie->interval = fract; - + fie->interval.numerator = 1; + fie->interval.denominator = OV2680_FPS; 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 = dev->res->skip_frames; - mutex_unlock(&dev->input_lock); - + *frames = OV2680_SKIP_FRAMES; return 0; } @@ -1114,11 +547,6 @@ 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, @@ -1128,98 +556,173 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { }; 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_init_controls(struct ov2680_device *sensor) +{ + static const char * const test_pattern_menu[] = { + "Disabled", + "Color Bars", + "Random Data", + "Square", + "Black Image", + }; + const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; + struct ov2680_ctrls *ctrls = &sensor->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN; + + v4l2_ctrl_handler_init(hdl, 4); + + hdl->lock = &sensor->input_lock; + + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, exp_max, 1, exp_max); + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250); + ctrls->test_pattern = + v4l2_ctrl_new_std_menu_items(hdl, + &ov2680_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); + + ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + if (hdl->error) + return hdl->error; + + sensor->sd.ctrl_handler = hdl; + return 0; +} + static void ov2680_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); dev_dbg(&client->dev, "ov2680_remove...\n"); - dev->platform_data->csi_cfg(sd, 0); - + atomisp_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); + pm_runtime_disable(&client->dev); } +/* + * Unlike other sensors which have both a rest and powerdown input pins, + * the OV2680 only has a powerdown input. But some ACPI tables still list + * 2 GPIOs for the OV2680 and it is unclear which to use. So try to get + * up to 2 GPIOs (1 mandatory, 1 optional) and control them in sync. + */ +static const struct acpi_gpio_params ov2680_first_gpio = { 0, 0, true }; +static const struct acpi_gpio_params ov2680_second_gpio = { 1, 0, true }; + +static const struct acpi_gpio_mapping ov2680_gpio_mapping[] = { + { "powerdown-gpios", &ov2680_first_gpio, 1 }, + { "powerdown-alt-gpios", &ov2680_second_gpio, 1 }, + { }, +}; + static int ov2680_probe(struct i2c_client *client) { - struct ov2680_device *dev; + struct device *dev = &client->dev; + struct ov2680_device *sensor; int ret; - void *pdata; - unsigned int i; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) return -ENOMEM; - mutex_init(&dev->input_lock); + mutex_init(&sensor->input_lock); - dev->res = &ov2680_res_preview[0]; - dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; - dev->gain = 250; /* 0-2047 */ - v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops); + sensor->client = client; + v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops); - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = ov2680_s_config(&dev->sd, client->irq, pdata); + ret = devm_acpi_dev_add_driver_gpios(&client->dev, ov2680_gpio_mapping); if (ret) - goto out_free; + return ret; + + sensor->powerdown = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n"); + + sensor->powerdown_alt = devm_gpiod_get_optional(dev, "powerdown-alt", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown_alt)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown_alt), "getting powerdown-alt GPIO\n"); - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = ov2680_s_config(&sensor->sd); 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; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov2680_controls)); + return ret; + + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = ov2680_init_controls(sensor); 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) { + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) { ov2680_remove(client); - return dev->ctrl_handler.error; + return ret; } - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; + ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); if (ret) { ov2680_remove(client); - dev_dbg(&client->dev, "+++ remove ov2680\n"); + return ret; } - return ret; -out_free: - dev_dbg(&client->dev, "+++ out free\n"); - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; + + return 0; } +static int ov2680_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); + + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->powerdown_alt, 1); + return 0; +} + +static int ov2680_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); + + /* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */ + usleep_range(5000, 6000); + + gpiod_set_value_cansleep(sensor->powerdown, 0); + gpiod_set_value_cansleep(sensor->powerdown_alt, 0); + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + ov2680_init_registers(sd); + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL); + static const struct acpi_device_id ov2680_acpi_match[] = { {"XXOV2680"}, {"OVTI2680"}, @@ -1230,6 +733,7 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); static struct i2c_driver ov2680_driver = { .driver = { .name = "ov2680", + .pm = pm_sleep_ptr(&ov2680_pm_ops), .acpi_match_table = ov2680_acpi_match, }, .probe_new = ov2680_probe, |