| /* |
| * galileo1 - Nokia sensor |
| * |
| * It is a 41 MPix sensor present in the Nokia Lumia 808 |
| * |
| * Author : Eng-Hong SRON <eng-hong.sron@parrot.com> |
| * |
| * Date : Wed Jul 2 09:16:13 CEST 2014 |
| * |
| */ |
| #include <linux/delay.h> |
| #include <linux/errno.h> |
| #include <linux/gpio.h> |
| #include <linux/i2c.h> |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/videodev2.h> |
| #include <linux/delay.h> |
| |
| #include <media/v4l2-chip-ident.h> |
| #include <media/v4l2-device.h> |
| #include <media/v4l2-ctrls.h> |
| |
| #include <media/galileo1.h> |
| |
| #include "galileo1_reg.h" |
| |
| MODULE_AUTHOR("Eng-Hong SRON <eng-hong.sron@parrot.com>"); |
| MODULE_DESCRIPTION("Nokia Galileo1 driver"); |
| MODULE_LICENSE("GPL"); |
| |
| #define DRIVER_NAME "galileo1" |
| |
| #define SENSOR_WIDTH 7728 |
| #define SENSOR_HEIGHT 5368 |
| |
| #define MIN_VTCLK 20000000UL |
| #define MAX_VTCLK 256000000UL |
| |
| /* Here we take a MIPICLK slightly higher than the specification on purpose, |
| * because we are using the TC358746A bridge and it has its own limitation |
| * (PPICLK need to be between 66 and 125 MHz). |
| * In case of other bridge, we could go back to the specified value (80.0 MHz). |
| */ |
| #define MIN_MIPICLK 82500000UL |
| #define MAX_MIPICLK 1000000000UL |
| |
| #define MIN_REFCLK 6000000UL |
| #define MAX_REFCLK 27000000UL |
| |
| #define MIN_PLL_IN_CLK 3000000UL |
| #define MAX_PLL_IN_CLK 27000000UL |
| |
| #define MIN_PLL_OP_CLK 1000000000UL |
| #define MAX_PLL_OP_CLK 2080000000UL |
| |
| #define MIN_VT_SYS_CLK 83330000UL |
| #define MAX_VT_SYS_CLK 2080000000UL |
| |
| struct galileo1 { |
| struct v4l2_subdev sd; |
| struct media_pad pad; |
| struct galileo1_platform_data *pdata; |
| |
| struct v4l2_mbus_framefmt format; |
| struct v4l2_fract frame_interval; |
| |
| /* Internal states */ |
| bool streaming; |
| bool timings_uptodate; |
| |
| /* Dimensions */ |
| struct v4l2_rect crop; |
| struct v4l2_rect video_timing; |
| u32 x_binning; |
| u32 y_binning; |
| u32 bits_per_pixel; |
| |
| /* PLLs */ |
| struct { |
| u32 pre_pll_clk_div; |
| u32 pll_multiplier; |
| u32 vt_sys_clk_div; |
| u32 vt_pix_clk_div; |
| u32 op_sys_clk_div; |
| } pll1; |
| |
| struct { |
| u32 pre_pll_clk_div; |
| u32 pll_multiplier; |
| } pll0; |
| |
| /* Non-Volatile Memory */ |
| u8 *nvm; |
| union nvm_memaddr nvm_addr; |
| |
| |
| /* Clocks */ |
| unsigned long vtclk; |
| unsigned long mipiclk; |
| unsigned long line_duration_ns; |
| |
| u16 trdy_ctrl; |
| |
| /* i2c clients */ |
| struct i2c_client *i2c_sensor; |
| struct i2c_client *i2c_pmic; |
| |
| /* Controls */ |
| struct v4l2_ctrl_handler ctrl_handler; |
| struct v4l2_ctrl *hflip; |
| struct v4l2_ctrl *vflip; |
| struct v4l2_ctrl *exposure; |
| struct v4l2_ctrl *focus; |
| struct v4l2_ctrl *gain; |
| struct v4l2_ctrl *nd; |
| struct v4l2_ctrl *ms; |
| struct v4l2_ctrl *gs; |
| struct v4l2_ctrl *strobe_source; |
| struct v4l2_ctrl *strobe_width; |
| }; |
| |
| enum mech_shutter_state { |
| MS_STATE_SSTROBE, |
| MS_STATE_OPEN, |
| MS_STATE_CLOSE |
| }; |
| |
| static inline struct galileo1 *to_galileo1(struct v4l2_subdev *sd) |
| { |
| return container_of(sd, struct galileo1, sd); |
| } |
| |
| static inline struct galileo1 *ctrl_to_galileo1(struct v4l2_ctrl *ctrl) |
| { |
| return container_of(ctrl->handler, struct galileo1, ctrl_handler); |
| } |
| |
| static int galileo1_read8(struct i2c_client *client, u16 reg, u8 *val) |
| { |
| int ret; |
| struct i2c_msg msg[] = { |
| [0] = { |
| .addr = client->addr, |
| .flags = 0, |
| .len = 2, |
| .buf = (u8 *)®, |
| }, |
| [1] = { |
| .addr = client->addr, |
| .flags = I2C_M_RD, |
| .len = 1, |
| .buf = val, |
| }, |
| }; |
| |
| reg = swab16(reg); |
| |
| ret = i2c_transfer(client->adapter, msg, 2); |
| if (ret < 0) { |
| dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int galileo1_read16(struct i2c_client *client, u16 reg, u16 *val) |
| { |
| int ret; |
| struct i2c_msg msg[] = { |
| [0] = { |
| .addr = client->addr, |
| .flags = 0, |
| .len = 2, |
| .buf = (u8 *)®, |
| }, |
| [1] = { |
| .addr = client->addr, |
| .flags = I2C_M_RD, |
| .len = 2, |
| .buf = (u8 *)val, |
| }, |
| }; |
| |
| reg = swab16(reg); |
| |
| ret = i2c_transfer(client->adapter, msg, 2); |
| if (ret < 0) { |
| dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); |
| return ret; |
| } |
| |
| *val = swab16(*val); |
| |
| return 0; |
| } |
| |
| static int galileo1_write8(struct i2c_client *client, u16 reg, u8 val) |
| { |
| int ret; |
| struct i2c_msg msg; |
| struct { |
| u16 reg; |
| u8 val; |
| } __packed buf; |
| |
| reg = swab16(reg); |
| |
| buf.reg = reg; |
| buf.val = val; |
| |
| msg.addr = client->addr; |
| msg.flags = 0; |
| msg.len = 3; |
| msg.buf = (u8 *)&buf; |
| |
| ret = i2c_transfer(client->adapter, &msg, 1); |
| if (ret < 0) { |
| dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int galileo1_write16(struct i2c_client *client, u16 reg, u16 val) |
| { |
| int ret; |
| struct i2c_msg msg; |
| u16 buf[2]; |
| |
| buf[0] = swab16(reg); |
| buf[1] = swab16(val); |
| |
| msg.addr = client->addr; |
| msg.flags = 0; |
| msg.len = 4; |
| msg.buf = (u8 *)&buf; |
| |
| ret = i2c_transfer(client->adapter, &msg, 1); |
| |
| if (ret < 0) { |
| dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int galileo1_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, |
| struct v4l2_subdev_format *fmt) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct v4l2_mbus_framefmt *mf; |
| |
| if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| mf = v4l2_subdev_get_try_format(fh, 0); |
| fmt->format = *mf; |
| return 0; |
| } |
| |
| fmt->format = galileo1->format; |
| |
| return 0; |
| } |
| |
| static int galileo1_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, |
| struct v4l2_subdev_format *fmt) |
| { |
| struct v4l2_mbus_framefmt *mf = &fmt->format; |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| |
| if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| mf = v4l2_subdev_get_try_format(fh, fmt->pad); |
| fmt->format = *mf; |
| } else { |
| galileo1->format = fmt->format; |
| } |
| |
| galileo1->timings_uptodate = 0; |
| |
| return 0; |
| } |
| |
| static int galileo1_enum_mbus_code(struct v4l2_subdev *sd, |
| struct v4l2_subdev_fh *fh, |
| struct v4l2_subdev_mbus_code_enum *code) |
| { |
| /* For now we support only one code */ |
| if (code->index) |
| return -EINVAL; |
| |
| code->code = V4L2_MBUS_FMT_SGBRG10_1X10; |
| |
| return 0; |
| } |
| |
| static int galileo1_get_selection(struct v4l2_subdev *sd, |
| struct v4l2_subdev_fh *fh, |
| struct v4l2_subdev_selection *sel) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| |
| switch (sel->target) { |
| case V4L2_SEL_TGT_CROP_BOUNDS: |
| sel->r.left = 0; |
| sel->r.top = 0; |
| sel->r.width = SENSOR_WIDTH; |
| sel->r.height = SENSOR_HEIGHT; |
| break; |
| case V4L2_SEL_TGT_CROP: |
| sel->r = galileo1->crop; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| /* Compute VT timing and binning */ |
| static int galileo1_calc_vt(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_mbus_framefmt *fmt = &galileo1->format; |
| |
| /* We bin as much as possible before scaling */ |
| galileo1->x_binning = c->width / fmt->width; |
| galileo1->x_binning = min(galileo1->x_binning, 2U); |
| |
| galileo1->y_binning = c->height / fmt->height; |
| galileo1->y_binning = min(galileo1->y_binning, 8U); |
| |
| /* Video Timing is working on binned pixels |
| * min_vt_line_blanking_pck is 512 |
| * min_vt_frame_blanking_line is 38 |
| */ |
| vt->width = (c->width / galileo1->x_binning) + 512; |
| vt->height = (c->height / galileo1->y_binning) + 42; |
| |
| /* It seems there is a minimum VT width which differs from what the |
| * datasheet says (8240). It is an empiric value, I don't know if it is |
| * correct... */ |
| vt->width = max(vt->width, 1920); |
| |
| return 0; |
| } |
| |
| static int galileo1_set_selection(struct v4l2_subdev *sd, |
| struct v4l2_subdev_fh *fh, |
| struct v4l2_subdev_selection *sel) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_mbus_framefmt *fmt = &galileo1->format; |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| |
| switch (sel->target) { |
| case V4L2_SEL_TGT_CROP: |
| galileo1->crop = sel->r; |
| break; |
| default: |
| v4l2_err(sd, "selection target (%d) not supported yet\n", |
| sel->target); |
| return -EINVAL; |
| } |
| |
| galileo1->timings_uptodate = 0; |
| |
| if (!galileo1->streaming) |
| return 0; |
| |
| /* We bin as much as possible before scaling */ |
| galileo1->x_binning = c->width / fmt->width; |
| galileo1->x_binning = min(galileo1->x_binning, 2U); |
| |
| galileo1->y_binning = c->height / fmt->height; |
| galileo1->y_binning = min(galileo1->y_binning, 8U); |
| |
| galileo1_write16(i2c, GROUPED_PARAMETER_HOLD, 0x1); |
| |
| galileo1_write16(i2c, X_ADDR_START, c->left); |
| galileo1_write16(i2c, Y_ADDR_START, c->top); |
| galileo1_write16(i2c, X_ADDR_END, c->left + c->width - 1); |
| galileo1_write16(i2c, Y_ADDR_END, c->top + c->height - 1); |
| |
| galileo1_write16(i2c, DIGITAL_CROP_IMAGE_WIDTH, |
| c->width / galileo1->x_binning); |
| galileo1_write16(i2c, DIGITAL_CROP_IMAGE_HEIGHT, |
| c->height / galileo1->y_binning); |
| |
| galileo1_write8(i2c, BINNING_TYPE, galileo1->x_binning << 4 | |
| galileo1->y_binning); |
| |
| galileo1_write16(i2c, GROUPED_PARAMETER_HOLD, 0x0); |
| |
| return 0; |
| } |
| |
| static const struct v4l2_subdev_pad_ops galileo1_pad_ops = { |
| .get_fmt = galileo1_get_fmt, |
| .set_fmt = galileo1_set_fmt, |
| .enum_mbus_code = galileo1_enum_mbus_code, |
| .get_selection = galileo1_get_selection, |
| .set_selection = galileo1_set_selection, |
| }; |
| |
| #ifdef CONFIG_VIDEO_ADV_DEBUG |
| static int galileo1_get_register(struct v4l2_subdev *sd, |
| struct v4l2_dbg_register *reg) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| int ret; |
| u8 val; |
| |
| reg->size = 2; |
| |
| if (reg->reg & ~0xff) |
| return -EINVAL; |
| |
| ret = galileo1_read8(galileo1->i2c_sensor, reg->reg, &val); |
| if (ret) |
| return ret; |
| |
| reg->val = (__u64)val; |
| |
| return 0; |
| } |
| |
| static int galileo1_set_register(struct v4l2_subdev *sd, |
| struct v4l2_dbg_register *reg) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| |
| if (reg->reg & ~0xff || reg->val & ~0xff) |
| return -EINVAL; |
| |
| return galileo1_write8(galileo1->i2c_sensor, reg->reg, reg->val); |
| } |
| #endif |
| |
| static const struct v4l2_subdev_core_ops galileo1_core_ops = { |
| .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
| #ifdef CONFIG_VIDEO_ADV_DEBUG |
| .g_register = galileo1_get_register, |
| .s_register = galileo1_set_register, |
| #endif |
| }; |
| |
| /* Compute minimum clocks in order to reach the FPS */ |
| static int galileo1_calc_clocks(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| struct v4l2_fract *fi = &galileo1->frame_interval; |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_mbus_framefmt *fmt = &galileo1->format; |
| u64 mipiclk_numerator; |
| u64 mipiclk_denominator; |
| |
| galileo1->vtclk = div_u64((u64) vt->width * vt->height * fi->denominator, |
| fi->numerator); |
| |
| /* In case vtclk is too high, we need to adjust the frame interval */ |
| if (galileo1->vtclk > MAX_VTCLK) { |
| galileo1->vtclk = MAX_VTCLK; |
| |
| fi->denominator = galileo1->vtclk; |
| fi->numerator = vt->width * vt->height; |
| |
| /* In case vtclk is too low, we just increase the vertical blanking */ |
| } else if (galileo1->vtclk < MIN_VTCLK) { |
| galileo1->vtclk = MIN_VTCLK; |
| |
| vt->height = div_u64((u64) galileo1->vtclk * fi->numerator, |
| vt->width * fi->denominator); |
| |
| } |
| |
| /* Finally, mipiclk will have to transfer all the scaled pixels, but the |
| * vertical scaling need some line buffers, introducing some |
| * 'burstiness'. We can considered the transfered frame as only scaled |
| * horizontally. |
| */ |
| switch (fmt->code) { |
| case V4L2_MBUS_FMT_SBGGR10_1X10: |
| case V4L2_MBUS_FMT_SGBRG10_1X10: |
| case V4L2_MBUS_FMT_SGRBG10_1X10: |
| case V4L2_MBUS_FMT_SRGGB10_1X10: |
| galileo1->bits_per_pixel = 10; |
| break; |
| default: |
| v4l2_err(sd, "code not supported yet\n"); |
| galileo1->vtclk = 0; |
| galileo1->mipiclk = 0; |
| return -EINVAL; |
| } |
| |
| mipiclk_numerator = (u64) galileo1->vtclk * |
| galileo1->bits_per_pixel * |
| fmt->width * |
| galileo1->x_binning; |
| |
| mipiclk_denominator = c->width * pdata->lanes * 2; |
| |
| galileo1->mipiclk = div_u64(mipiclk_numerator, mipiclk_denominator); |
| |
| /* In case mipiclk is too low, we just strech vtclk and vertical |
| * blanking. |
| */ |
| if (galileo1->mipiclk < MIN_MIPICLK) { |
| vt->height = div_u64((u64) vt->height * MIN_MIPICLK, |
| galileo1->mipiclk); |
| |
| galileo1->vtclk = div_u64((u64) galileo1->vtclk * MIN_MIPICLK, |
| galileo1->mipiclk); |
| |
| galileo1->mipiclk = MIN_MIPICLK; |
| |
| } |
| |
| return 0; |
| } |
| |
| #define IS_BETWEEN(_f, _min, _max) ((_f >= _min) && (_f <= _max)) |
| |
| /* Try to reach vtclk and mipiclk from the same PLL. We give the 'priority' to |
| * vtclk, since it is the processing clock whereas mipiclk is 'just' the output |
| * clock. |
| * We are also trying to keep the targeted FPS (if specified so) |
| */ |
| static int galileo1_pll_brute_force(struct v4l2_subdev *sd, int keep_fps) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| struct v4l2_fract *fi = &galileo1->frame_interval; |
| |
| const u16 pre_pll_div[] = {1, 2, 4}; |
| const u16 vt_sys_div[] = {1, 2, 4, 6, 8, 10, 12}; |
| const u16 vt_pix_div[] = {4, 5, 6, 7, 8, 9, 10, 12}; |
| const u16 op_sys_div[] = {2, 4, 12, 16, 20, 24}; |
| long best_error = -1; |
| int ret = -EINVAL; |
| |
| /* PLL parameters */ |
| u32 p, best_p = 0; |
| u32 m, best_m = 0; |
| u32 vts, best_vts = 0; |
| u32 vtp, best_vtp = 0; |
| u32 op, best_op = 0; |
| |
| /* Brute force PLL */ |
| for (p = 0 ; p < ARRAY_SIZE(pre_pll_div) ; p++) { |
| unsigned long pll_in_clk = pdata->refclk / pre_pll_div[p]; |
| |
| if (!IS_BETWEEN(pll_in_clk, MIN_PLL_IN_CLK, MAX_PLL_IN_CLK)) |
| continue; |
| |
| for (m = 36 ; m <= 832 ; m++) { |
| unsigned long pll_op_clk = pll_in_clk * m; |
| |
| if (!IS_BETWEEN(pll_op_clk, MIN_PLL_OP_CLK, |
| MAX_PLL_OP_CLK)) |
| continue; |
| |
| for (vts = 0 ; vts < ARRAY_SIZE(vt_sys_div) ; vts++) { |
| unsigned long vt_sys_clk; |
| |
| vt_sys_clk = pll_op_clk / vt_sys_div[vts]; |
| if (!IS_BETWEEN(vt_sys_clk, MIN_VT_SYS_CLK, MAX_VT_SYS_CLK)) |
| continue; |
| |
| for (vtp = 0 ; vtp < ARRAY_SIZE(vt_pix_div) ; vtp++) { |
| unsigned long vtclk; |
| |
| vtclk = vt_sys_clk / vt_pix_div[vtp]; |
| |
| if (!IS_BETWEEN(vtclk, MIN_VTCLK, MAX_VTCLK)) |
| continue; |
| |
| for (op = 0 ; op < ARRAY_SIZE(op_sys_div) ; op++) { |
| unsigned long mipiclk; |
| long error; |
| long vt_error; |
| long mipi_error; |
| |
| mipiclk = pll_op_clk / op_sys_div[op] / 2; |
| |
| vt_error = vtclk - galileo1->vtclk; |
| mipi_error = mipiclk - galileo1->mipiclk; |
| |
| /* Don't go lower than the |
| * targeted frequencies, |
| * otherwise we won't be able to |
| * reach the FPS. |
| */ |
| if (keep_fps == 1) { |
| if (vt_error < 0) |
| continue; |
| |
| if (mipi_error < 0) |
| continue; |
| } else { |
| if (vt_error < 0) |
| vt_error = -vt_error; |
| |
| if (mipi_error < 0) |
| mipi_error = -mipi_error; |
| } |
| |
| /* Try to minimize both error */ |
| error = mipi_error + vt_error; |
| |
| if (error <= best_error || best_error < 0) { |
| ret = 0; |
| best_error = error; |
| best_p = pre_pll_div[p]; |
| best_m = m; |
| best_vts = vt_sys_div[vts]; |
| best_vtp = vt_pix_div[vtp]; |
| best_op = op_sys_div[op]; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (ret != 0) |
| return ret; |
| |
| /* Refresh clock frequencies */ |
| galileo1->vtclk = (pdata->refclk * best_m) / |
| (best_p * best_vts * best_vtp); |
| galileo1->mipiclk = (pdata->refclk * best_m) / |
| (best_p * best_op * 2); |
| |
| /* Refresh FPS */ |
| fi->denominator = galileo1->vtclk; |
| fi->numerator = vt->width * vt->height; |
| |
| /* Refresh line_duration */ |
| galileo1->line_duration_ns = div_u64((u64) vt->width * 1000000000, |
| galileo1->vtclk); |
| |
| galileo1->pll1.pre_pll_clk_div = best_p; |
| galileo1->pll1.pll_multiplier = best_m; |
| galileo1->pll1.vt_sys_clk_div = best_vts; |
| galileo1->pll1.vt_pix_clk_div = best_vtp; |
| galileo1->pll1.op_sys_clk_div = best_op; |
| |
| return 0; |
| } |
| |
| static int galileo1_calc_plls(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| |
| /* PLL0 parameters */ |
| const u16 pre_pll_div[] = {1, 2, 4}; |
| long best_error = -1; |
| u32 p, best_p = 0; |
| u32 m, best_m = 0; |
| |
| |
| /* Perform some sanity checks */ |
| if (!IS_BETWEEN(galileo1->mipiclk, MIN_MIPICLK, MAX_MIPICLK)) { |
| v4l2_err(sd, "mipiclk (%lu) is out of range [%lu - %lu]\n", |
| galileo1->mipiclk, MIN_MIPICLK, MAX_MIPICLK); |
| return -EINVAL; |
| } |
| |
| if (!IS_BETWEEN(galileo1->vtclk, MIN_VTCLK, MAX_VTCLK)) { |
| v4l2_err(sd, "vtclk (%lu) is out of range [%lu - %lu]\n", |
| galileo1->vtclk, MIN_VTCLK, MAX_VTCLK); |
| return -EINVAL; |
| } |
| |
| if (!IS_BETWEEN(pdata->refclk, MIN_REFCLK, MAX_REFCLK)) { |
| v4l2_err(sd, "refclk (%lu) is out of range [%lu - %lu]\n", |
| galileo1->mipiclk, MIN_REFCLK, MAX_REFCLK); |
| return -EINVAL; |
| } |
| |
| /* Try to reach the PLL frequencies while preserving the FPS, but in |
| * case it is not possible, we have to derate it. |
| */ |
| if (galileo1_pll_brute_force(sd, 1) < 0) { |
| if (galileo1_pll_brute_force(sd, 0) < 0) { |
| v4l2_err(sd, "Unable to find PLL config for:\n"); |
| v4l2_err(sd, " vtclk %lu", galileo1->vtclk); |
| v4l2_err(sd, " mipiclk %lu", galileo1->mipiclk); |
| return -EINVAL; |
| } |
| } |
| |
| /* TOSHIBA register setting |
| * I don't know what frequency is needed for the following BoostCK, |
| * ADC Clock, ck_st and hreg_clk... |
| * So I follow the given spreadsheet... |
| * I also assume the PLL0 constraints are the same as the PLL1. |
| */ |
| for (p = 0 ; p < ARRAY_SIZE(pre_pll_div) ; p++) { |
| unsigned long pll_in_clk = pdata->refclk / pre_pll_div[p]; |
| |
| if (!IS_BETWEEN(pll_in_clk, MIN_PLL_IN_CLK, MAX_PLL_IN_CLK)) |
| continue; |
| for (m = 36 ; m <= 832 ; m++) { |
| unsigned long pll_op_clk = pll_in_clk * m; |
| |
| /* Trying to reach 1GHz, again, it seems to work that |
| * way, but I don't know why... |
| */ |
| long error = 1000000000UL - pll_op_clk; |
| |
| if (error < 0) |
| error = -error; |
| |
| if (error < best_error || best_error < 0) { |
| best_error = error; |
| best_p = pre_pll_div[p] - 1; |
| best_m = m; |
| } |
| } |
| } |
| |
| galileo1->pll0.pre_pll_clk_div = best_p; |
| galileo1->pll0.pll_multiplier = best_m; |
| |
| return 0; |
| } |
| |
| #undef IS_BETWEEN |
| |
| static int galileo1_update_timings(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| int ret; |
| |
| /* From the crop and the output size, calculate the binning and the |
| * Video Timing. |
| */ |
| ret = galileo1_calc_vt(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate Video Timing\n"); |
| return ret; |
| } |
| |
| /* Calculate the the minimum theorical clock frequency in order to |
| * achieve the frame interval. |
| */ |
| ret = galileo1_calc_clocks(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate Clocks\n"); |
| return ret; |
| } |
| |
| /* Update clocks */ |
| ret = galileo1_calc_plls(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate plls\n"); |
| return ret; |
| } |
| |
| galileo1->timings_uptodate = 1; |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_plls(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c_sensor = galileo1->i2c_sensor; |
| |
| galileo1_write16(i2c_sensor, PRE_PLL_CLK_DIV, |
| galileo1->pll1.pre_pll_clk_div); |
| galileo1_write16(i2c_sensor, PLL_MULTIPLIER, |
| galileo1->pll1.pll_multiplier); |
| galileo1_write16(i2c_sensor, VT_SYS_CLK_DIV, |
| galileo1->pll1.vt_sys_clk_div); |
| galileo1_write16(i2c_sensor, VT_PIX_CLK_DIV, |
| galileo1->pll1.vt_pix_clk_div); |
| galileo1_write16(i2c_sensor, OP_SYS_CLK_DIV, |
| galileo1->pll1.op_sys_clk_div); |
| galileo1_write16(i2c_sensor, OP_PIX_CLK_DIV, |
| 0x0008); |
| |
| galileo1_write8(i2c_sensor, PRE_PLL_CNTL_ST, |
| galileo1->pll0.pre_pll_clk_div); |
| galileo1_write16(i2c_sensor, PLL_MULTI_ST, |
| galileo1->pll0.pll_multiplier); |
| |
| galileo1_write8(i2c_sensor, AD_CNTL, 0x02); |
| galileo1_write8(i2c_sensor, ST_CNTL, 0x07); |
| galileo1_write8(i2c_sensor, HREG_CNTL, 0x05); |
| galileo1_write8(i2c_sensor, PLL_HRG_CNTL, 0x01); |
| galileo1_write8(i2c_sensor, HREG_PLLSEL_SINGLE, 0x10); |
| galileo1_write8(i2c_sensor, OPCK_PLLSEL, 0x00); |
| |
| return 0; |
| } |
| |
| /* |
| * MODEPowerup_and_Initialize |
| * Following values are taken directly from Nokia INIT.txt file. |
| * I have no idea what it does... |
| */ |
| static int galileo1_init(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| struct i2c_client *i2c_sensor = galileo1->i2c_sensor; |
| struct i2c_client *i2c_pmic = galileo1->i2c_pmic; |
| u16 whole, fract; |
| union global_reset_mode_config1 glbrst_cfg1 = {{ |
| .vf_to_glbrst = 0, /* complete frame */ |
| .glbrst_to_vf = 0, |
| .readout_start = 0, /* Readout start by tRDOUT */ |
| .long_exposure_mode = 0, |
| .continous_global_reset_mode = 0, |
| .flash_strobe = 0, |
| .sstrobe_muxing = 1, |
| .sastrobe_muxing = 0, |
| }}; |
| |
| /* |
| * AD5814 settings |
| */ |
| galileo1_write8(i2c_pmic, CONTROL, 0x00); |
| /* DRIVE_CFG Slope 001(275ns) H Bridge,DIV2 */ |
| galileo1_write8(i2c_pmic, DRIVE_CFG, 0x39); |
| galileo1_write8(i2c_pmic, BUCK_CFG, 0x03); |
| /* TIMING 20ms */ |
| galileo1_write8(i2c_pmic, TIMING, 0x58); |
| /* CONFIG 2.5V */ |
| galileo1_write8(i2c_pmic, CONFIG, 0x10); |
| /* PERIOD 15.6us */ |
| galileo1_write8(i2c_pmic, PERIOD, 0x9C); |
| /* TAH 0.8us */ |
| galileo1_write8(i2c_pmic, TAH, 0x08); |
| /* TAL 14.8us */ |
| galileo1_write8(i2c_pmic, TAL, 0x94); |
| /* TBH 12.8us */ |
| galileo1_write8(i2c_pmic, TBH, 0x78); |
| /* TBL 1.7us */ |
| galileo1_write8(i2c_pmic, TBL, 0x11); |
| galileo1_write8(i2c_pmic, NR_CFG, 0x04); |
| galileo1_write8(i2c_pmic, NR_PERIOD, 0x02); |
| galileo1_write8(i2c_pmic, NR_TAH, 0x01); |
| galileo1_write8(i2c_pmic, NR_TAL, 0x01); |
| galileo1_write8(i2c_pmic, NR_TBH, 0x01); |
| galileo1_write8(i2c_pmic, NR_TBL, 0x01); |
| galileo1_write16(i2c_pmic, NR_PRE_PULSE, 0x0000); |
| galileo1_write16(i2c_pmic, NR_POST_PULSE, 0x0000); |
| galileo1_write8(i2c_pmic, NR_RISEFALL, 0x74); |
| /* NR_RF_PULSE NR 4 PLS */ |
| galileo1_write8(i2c_pmic, NR_RF_PULSE, 0x04); |
| /* CURRENT 10.5mA */ |
| galileo1_write8(i2c_pmic, CURRENT, 0x13); |
| /* IPOS_TEMPCOMP -0.10%/deg c */ |
| galileo1_write8(i2c_pmic, IPOS_TEMPCOMP, 0x02); |
| /*ADC_CONFIG 16Ave 200uA */ |
| galileo1_write8(i2c_pmic, ADC_CONFIG, 0x18); |
| galileo1_write8(i2c_pmic, ADC_ACT, 0x00); |
| galileo1_write8(i2c_pmic, ADC_RES, 0x00); |
| galileo1_write8(i2c_pmic, STATUS, 0x00); |
| |
| /* Sensor MSRs */ |
| galileo1_write8(i2c_sensor, POSBSTSEL, 0x1C); |
| galileo1_write8(i2c_sensor, READVDSEL, 0x06); |
| galileo1_write8(i2c_sensor, RSTVDSEL, 0x08); |
| galileo1_write8(i2c_sensor, BSVBPSEL, 0x18); |
| galileo1_write8(i2c_sensor, HREG_TEST, 0x04); |
| galileo1_write8(i2c_sensor, DRESET, 0xC8); |
| galileo1_write16(i2c_sensor, FRACEXP_TIME1, 0x08FF); |
| galileo1_write16(i2c_sensor, PORTGRESET_U, 0x026C); |
| galileo1_write8(i2c_sensor, PORTGRESET_W, 0x30); |
| galileo1_write8(i2c_sensor, ROREAD, 0xCE); |
| galileo1_write8(i2c_sensor, DRCUT, 0x01); |
| galileo1_write8(i2c_sensor, GDMOSCNT, 0x2F); |
| galileo1_write8(i2c_sensor, CDS_STOPBST, 0x01); |
| galileo1_write8(i2c_sensor, BSTCKLFIX_ADC, 0x89); |
| galileo1_write8(i2c_sensor, BSC_AGRNG2, 0x30); |
| galileo1_write8(i2c_sensor, BSC_AGRNG1, 0x18); |
| galileo1_write8(i2c_sensor, BSC_AGRNG0, 0x10); |
| galileo1_write8(i2c_sensor, KBIASCNT_RNG32, 0x98); |
| galileo1_write8(i2c_sensor, KBIASCNT_RNG10, 0x76); |
| galileo1_write8(i2c_sensor, GDMOSHEN, 0x01); |
| galileo1_write8(i2c_sensor, BSDIGITAL_MODE, 0x08); |
| galileo1_write8(i2c_sensor, PS_VZS_NML_COEF, 0xC7); |
| galileo1_write8(i2c_sensor, PS_VZS_NML_INTC, 0x7E); |
| galileo1_write8(i2c_sensor, ZSV_IN_LINES, 0x43); |
| galileo1_write8(i2c_sensor, FBC_IN_RANGE, 0x10); |
| galileo1_write8(i2c_sensor, OB_CLPTHRSH_NEAR, 0x28); |
| galileo1_write8(i2c_sensor, OB_CLPTHRSH_FAR, 0x28); |
| galileo1_write8(i2c_sensor, WKUP_WAIT_ON, 0xE9); |
| galileo1_write8(i2c_sensor, HALF_VTAP_MODE, 0x12); |
| galileo1_write8(i2c_sensor, CCP2BLKD, 0xB0); |
| |
| /* Sensor static register */ |
| whole = pdata->refclk / 1000000; |
| fract = ((pdata->refclk - (whole * 1000000)) * 0x100) / 1000000; |
| |
| galileo1_write8(i2c_sensor, EXTCLK_FRQ_MHZ, whole); |
| galileo1_write8(i2c_sensor, EXTCLK_FRQ_MHZ + 1, fract); |
| |
| galileo1_write8(i2c_sensor, GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| galileo1_write8(i2c_sensor, DPHY_CTRL, 0x01); |
| |
| /* Link MBPS seems to influence the bridge, I don't know why, so I let |
| * this value to zero. |
| */ |
| galileo1_write8(i2c_sensor, REQUESTED_LINK_BIT_RATE_MBPS_31_24, 0x0); |
| galileo1_write8(i2c_sensor, REQUESTED_LINK_BIT_RATE_MBPS_23_16, 0x0); |
| galileo1_write8(i2c_sensor, REQUESTED_LINK_BIT_RATE_MBPS_15_8, 0x0); |
| galileo1_write8(i2c_sensor, REQUESTED_LINK_BIT_RATE_MBPS_7_0, 0x0); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_hflip(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| union image_orientation reg; |
| |
| galileo1_read8(i2c, IMAGE_ORIENTATION, ®._register); |
| reg.h_mirror = galileo1->hflip->val; |
| galileo1_write8(i2c, IMAGE_ORIENTATION, reg._register); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_vflip(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| union image_orientation reg; |
| |
| galileo1_read8(i2c, IMAGE_ORIENTATION, ®._register); |
| reg.v_mirror = galileo1->vflip->val; |
| galileo1_write8(i2c, IMAGE_ORIENTATION, reg._register); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_nd(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_pmic; |
| |
| galileo1_write8(i2c, ACT_STATE_1, galileo1->nd->val); |
| galileo1_write8(i2c, OPERATION_MODE, 0x1); |
| |
| /* Drive the ND for 10 ms */ |
| galileo1_write8(i2c, MECH_SHUTTER_CONTROL, 0x01); |
| msleep(20); |
| galileo1_write8(i2c, MECH_SHUTTER_CONTROL, 0x00); |
| |
| return 0; |
| } |
| |
| static int galileo1_drive_shutter(struct v4l2_subdev *sd, u8 direction) { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_pmic; |
| |
| union operation_mode opmode = {{ |
| .sdirm_cfg = direction, |
| }}; |
| |
| /* Reset shutter usage */ |
| galileo1_write8(i2c, MECH_SHUTTER_CONTROL, 0x08); |
| galileo1_write8(i2c, OPERATION_MODE, opmode._register); |
| |
| /* Drive the shutter for 10 ms */ |
| galileo1_write8(i2c, MECH_SHUTTER_CONTROL, 0x01); |
| msleep(20); |
| galileo1_write8(i2c, MECH_SHUTTER_CONTROL, 0x00); |
| |
| return 0; |
| } |
| |
| static int galileo1_shutter_close(struct v4l2_subdev *sd) |
| { |
| return galileo1_drive_shutter(sd, 0); |
| } |
| |
| static int galileo1_shutter_open(struct v4l2_subdev *sd) |
| { |
| return galileo1_drive_shutter(sd, 1); |
| } |
| |
| static int galileo1_set_shutter(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| union global_reset_mode_config1 glbrst_cfg1; |
| struct i2c_client *i2c_sensor = galileo1->i2c_sensor; |
| |
| switch (galileo1->ms->val) { |
| case MS_STATE_OPEN: |
| return galileo1_shutter_open(sd); |
| case MS_STATE_CLOSE: |
| return galileo1_shutter_close(sd); |
| default: |
| break; |
| } |
| |
| galileo1_read8(i2c_sensor, GLOBAL_RESET_MODE_CONFIG1, |
| &glbrst_cfg1._register); |
| glbrst_cfg1.sastrobe_muxing = 0; |
| |
| if (galileo1->gs->val) { |
| struct i2c_client *i2c_pmic = galileo1->i2c_pmic; |
| |
| union operation_mode opmode = { |
| /* Shutter strobe & ND Strobe */ |
| /* Shutter */ |
| .smode = 1, /* Strobe mode */ |
| .sedge = 1, /* Edge mode |
| * rising edge = close |
| * falling edge = open |
| */ |
| .sdirm_cfg = 0, |
| .nmode = 1, /* Strobe mode */ |
| .nedge = 0, |
| .ndirm_cfg = 0, |
| }; |
| |
| /* Reset shutter usage */ |
| galileo1_write8(i2c_pmic, MECH_SHUTTER_CONTROL, 0x08); |
| galileo1_write8(i2c_pmic, OPERATION_MODE, opmode._register); |
| galileo1_write8(i2c_pmic, MECH_SHUTTER_CONTROL, 0x1); |
| |
| glbrst_cfg1.sastrobe_muxing = 1; |
| } |
| |
| galileo1_write8(i2c_sensor, GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_ms(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c_sensor = galileo1->i2c_sensor; |
| struct i2c_client *i2c_pmic = galileo1->i2c_pmic; |
| u32 *exposure_us = &galileo1->exposure->val; |
| u32 ms_state = galileo1->ms->val; |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| u8 *nvm = galileo1->nvm; |
| union nvm_memaddr *nvm_addr = &galileo1->nvm_addr; |
| u16 sdelay, sdelay_ctrl; |
| u16 trdout_ctrl; |
| u16 str_delay_ctrl; |
| u16 tgrst_interval_ctrl; |
| u32 half_line_duration; |
| |
| union global_reset_mode_config1 glbrst_cfg1 = { |
| .vf_to_glbrst = 0, |
| .glbrst_to_vf = 0, |
| .readout_start = 0, |
| .long_exposure_mode = 0, |
| .continous_global_reset_mode = 1, |
| .flash_strobe = 0, |
| .sstrobe_muxing = 1, |
| .sastrobe_muxing = 1, |
| }; |
| |
| if (ms_state != MS_STATE_SSTROBE) |
| glbrst_cfg1.sastrobe_muxing = 0; |
| |
| /* Deactivate GS mode if it was previously enabled */ |
| if (!galileo1->gs->val) { |
| glbrst_cfg1.sastrobe_muxing = 0; |
| glbrst_cfg1.continous_global_reset_mode = 0; |
| |
| galileo1_write8(i2c_sensor, GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| |
| galileo1_write8(galileo1->i2c_sensor, |
| GLOBAL_RESET_CTRL1, 0x0); |
| |
| if (ms_state != MS_STATE_CLOSE) |
| return galileo1_shutter_open(sd); |
| |
| return 0; |
| } |
| |
| galileo1->trdy_ctrl = 0x0034; |
| |
| /* This is used to round further timing computations instead of flooring */ |
| half_line_duration = galileo1->line_duration_ns / 2; |
| |
| /* Shutter should close after exposure time, but we need to take into |
| * account the shutter speed stored in the NVM */ |
| sdelay = swab16(*((u16 *)(nvm + nvm_addr->ms))); |
| sdelay_ctrl = ((u32)sdelay * 1000 + half_line_duration) / galileo1->line_duration_ns; |
| |
| /* Don't begin reading the pixels until we've waited for the exposure |
| * time */ |
| trdout_ctrl = ((u32)(*exposure_us) * 1000 + half_line_duration) / galileo1->line_duration_ns; |
| |
| if (sdelay_ctrl > galileo1->trdy_ctrl + trdout_ctrl) |
| galileo1->trdy_ctrl = sdelay_ctrl - trdout_ctrl; |
| |
| /* Leave the shutter open for some more time so that it closes when we |
| * start reading the pixels */ |
| str_delay_ctrl = galileo1->trdy_ctrl + trdout_ctrl - sdelay_ctrl; |
| |
| /* Configure timer */ |
| /* Set Global reset ready to its minimum */ |
| galileo1_write16(i2c_sensor, TRDY_CTRL, galileo1->trdy_ctrl); |
| |
| galileo1_write16(i2c_sensor, TSHUTTER_STROBE_DELAY_CTRL, |
| str_delay_ctrl); |
| |
| /* Start readout as soon as possible */ |
| galileo1_write16(i2c_sensor, TRDOUT_CTRL, trdout_ctrl); |
| |
| /* Close the shutter during the readout, thus it should last at least |
| * the number of active line. |
| */ |
| galileo1_write16(i2c_sensor, TSHUTTER_STROBE_WIDTH_CTRL, |
| c->height / galileo1->y_binning |
| + sdelay_ctrl); |
| |
| tgrst_interval_ctrl = vt->height + trdout_ctrl + galileo1->trdy_ctrl |
| + sdelay_ctrl + 512; |
| galileo1_write16(i2c_sensor, TGRST_INTERVAL_CTRL, tgrst_interval_ctrl); |
| |
| galileo1_write8(i2c_sensor, GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| |
| /* Mechanical shutter control */ |
| galileo1_write8(i2c_sensor, GLOBAL_RESET_CTRL1, 0x1); |
| galileo1_write8(i2c_pmic, MECH_SHUTTER_CONTROL, 0x1); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_exposure(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct v4l2_fract *fi = &galileo1->frame_interval; |
| u32 *exposure_us = &galileo1->exposure->val; |
| u16 coarse; |
| |
| /* Exposure is expressed in us */ |
| u32 exposure_max_us = div_u64((u64) fi->numerator * 1000000, |
| fi->denominator); |
| |
| if (*exposure_us > exposure_max_us) { |
| v4l2_warn(sd, "requested exposure (%d) is higher than exposure max (%d)\n", |
| *exposure_us, exposure_max_us); |
| |
| *exposure_us = exposure_max_us; |
| } |
| |
| coarse = (*exposure_us * 1000) / galileo1->line_duration_ns; |
| |
| galileo1_write16(galileo1->i2c_sensor, COARSE_INTEGRATION_TIME, coarse); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_gain(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| u32 gain = galileo1->gain->val; |
| |
| galileo1_write16(galileo1->i2c_sensor, ANALOG_GAIN_CODE_GLOBAL, gain); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_flash_strobe(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| enum v4l2_flash_strobe_source strobe_source; |
| union global_reset_mode_config1 glbrst_cfg1; |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| |
| strobe_source = galileo1->strobe_source->val; |
| |
| galileo1_read8(i2c, GLOBAL_RESET_MODE_CONFIG1, &glbrst_cfg1._register); |
| |
| if (strobe_source == V4L2_FLASH_STROBE_SOURCE_SOFTWARE) { |
| glbrst_cfg1.flash_strobe = 0; |
| galileo1_write8(i2c, |
| GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| galileo1_write8(i2c, FLASH_TRIGGER_RS, 0x0); |
| return 0; |
| } |
| |
| |
| /* Set the width to 100us, it is an arbitrary value, but the signal |
| * seems to take at least ~30us to go from 0 to 1 |
| */ |
| if (galileo1->gs->val) { |
| /* "Global" shutter mode (photo) */ |
| glbrst_cfg1.flash_strobe = 1; |
| |
| galileo1_write8(i2c, |
| GLOBAL_RESET_MODE_CONFIG1, |
| glbrst_cfg1._register); |
| |
| galileo1_write16(i2c, TFLASH_STROBE_WIDTH_HIGH_CTRL, (galileo1->strobe_width->val |
| * 1000) / 108); |
| |
| } else { |
| /* Rolling shutter mode (video) */ |
| galileo1_write16(i2c, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, (galileo1->strobe_width->val |
| * 1000) / 108); |
| galileo1_write8(i2c, FLASH_MODE_RS, 0x1); |
| galileo1_write8(i2c, FLASH_TRIGGER_RS, 0x1); |
| } |
| |
| |
| return 0; |
| } |
| |
| static int galileo1_get_lens_position(struct v4l2_subdev *sd, u16 *pos) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_pmic; |
| |
| union status status = { |
| .busy = 1, |
| }; |
| |
| union focus_change_control fcc = { |
| .measpos = 1, |
| }; |
| |
| galileo1_write8(i2c, FOCUS_CHANGE_CONTROL, fcc._register); |
| |
| while (status.busy) |
| galileo1_read8(i2c, STATUS, &status._register); |
| |
| galileo1_read16(i2c, POSITION, pos); |
| |
| return 0; |
| } |
| |
| static int galileo1_apply_focus(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_pmic; |
| u8 trial = 0; |
| u16 cur_pos; |
| u16 tgt_pos = galileo1->focus->val; |
| |
| galileo1_get_lens_position(sd, &cur_pos); |
| |
| /* We try to reach the tgt_pos with +/- 2 tolerance in 3 trials max */ |
| while ((cur_pos < tgt_pos - 2 || cur_pos > tgt_pos + 2) && trial < 3) { |
| union focus_change_control fcc = { ._register = 0 }; |
| union status status; |
| s16 step; |
| |
| fcc.enable = 1; |
| fcc.dir = (tgt_pos < cur_pos); |
| fcc.measpos = 1; |
| |
| step = 30 * (tgt_pos - cur_pos); |
| if (step < 0) |
| step = -step; |
| |
| galileo1_write16(i2c, FOCUS_CHANGE, step); |
| galileo1_write8(i2c, FOCUS_CHANGE_CONTROL, fcc._register); |
| |
| status.busy = 1; |
| while (status.busy) |
| galileo1_read8(i2c, STATUS, &status._register); |
| |
| galileo1_read16(i2c, POSITION, &cur_pos); |
| trial++; |
| |
| /* Avoid locking up the focus mechanics */ |
| udelay(750); |
| } |
| |
| galileo1->focus->val = cur_pos; |
| galileo1->focus->cur.val = cur_pos; |
| |
| return 0; |
| } |
| |
| /* Manually synchronize control values, I'm not sure if it is the right way to |
| * do it... |
| */ |
| static inline void galileo1_synchronize_ctrl(struct v4l2_ctrl *ctrl) |
| { |
| v4l2_ctrl_lock(ctrl); |
| ctrl->cur.val = ctrl->val; |
| v4l2_ctrl_unlock(ctrl); |
| } |
| |
| static int galileo1_configure(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_mbus_framefmt *fmt = &galileo1->format; |
| int ret; |
| |
| ret = galileo1_init(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "init failed\n"); |
| return ret; |
| } |
| |
| /* CSI2 mode */ |
| galileo1_write8(i2c, CSI_SIGNALING_MODE, 0x2); |
| |
| /* Pixel format */ |
| galileo1_write8(i2c, CSI_DATA_FORMAT, galileo1->bits_per_pixel << 8 | |
| galileo1->bits_per_pixel); |
| galileo1_write8(i2c, CSI_LANE_MODE, pdata->lanes - 1); |
| |
| /* Image Size */ |
| galileo1_write16(i2c, X_OUTPUT_SIZE, fmt->width); |
| galileo1_write16(i2c, Y_OUTPUT_SIZE, fmt->height); |
| |
| /* Image Scaling */ |
| /* Full scaling, Bayer sampling */ |
| galileo1_write16(i2c, SCALING_MODE, 0x0002); |
| galileo1_write16(i2c, SPATIAL_SAMPLING, 0x0000); |
| |
| /* Scaler */ |
| galileo1_write16(i2c, OUTPUT_IMAGE_WIDTH, fmt->width); |
| galileo1_write16(i2c, OUTPUT_IMAGE_HEIGHT, fmt->height); |
| galileo1_write16(i2c, SCALER_BLANKING_PCK, 0x26EC); |
| |
| /* Frame Timing */ |
| galileo1_write16(i2c, VT_LINE_LENGTH_PCK, vt->width); |
| galileo1_write16(i2c, VT_FRAME_LENGTH_LINES, vt->height); |
| |
| /* Image area */ |
| galileo1_write16(i2c, X_ADDR_START, c->left); |
| galileo1_write16(i2c, Y_ADDR_START, c->top); |
| galileo1_write16(i2c, X_ADDR_END, c->left + c->width - 1); |
| galileo1_write16(i2c, Y_ADDR_END, c->top + c->height - 1); |
| |
| /* Digital Crop: We do not crop before the scaler */ |
| galileo1_write16(i2c, DIGITAL_CROP_X_OFFSET, 0x0000); |
| galileo1_write16(i2c, DIGITAL_CROP_Y_OFFSET, 0x0000); |
| galileo1_write16(i2c, DIGITAL_CROP_IMAGE_WIDTH, |
| c->width / galileo1->x_binning); |
| galileo1_write16(i2c, DIGITAL_CROP_IMAGE_HEIGHT, |
| c->height / galileo1->y_binning); |
| |
| /* Binning */ |
| galileo1_write8(i2c, BINNING_MODE, 0x1); |
| galileo1_write8(i2c, BINNING_TYPE, galileo1->x_binning << 4 | |
| galileo1->y_binning); |
| |
| /* TOSHIBA register setting |
| * Scaler */ |
| galileo1_write8(i2c, GREEN_AVERAGED_BAYER, 0x00); |
| galileo1_write8(i2c, HORIZONTAL_DIGITAL_BINNING, 0x00); |
| galileo1_write8(i2c, VERTICAL_DIGITAL_BINNING, 0x00); |
| |
| /* Row Noise improve setting */ |
| galileo1_write8(i2c, BLC_SEL, 0x01); |
| galileo1_write16(i2c, CSI2_DELAY, 0x0000); |
| |
| /* DPC */ |
| galileo1_write8(i2c, SINGLE_DEFECT_CORRECT_ENABLE, 0x00); |
| galileo1_write8(i2c, COMBINED_COUPLET_SINGLE_DEFECT_CORRECT_ENABLE, |
| 0x01); |
| |
| /* Controls */ |
| galileo1_apply_exposure(sd); |
| galileo1_apply_gain(sd); |
| galileo1_apply_focus(sd); |
| |
| /* Synchronize control values */ |
| galileo1_synchronize_ctrl(galileo1->exposure); |
| galileo1_synchronize_ctrl(galileo1->focus); |
| |
| return 0; |
| } |
| |
| static int galileo1_s_stream(struct v4l2_subdev *sd, int enable) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| int ret; |
| |
| if (enable == 0) { |
| /* Nothing to do if we are already off */ |
| if (galileo1->streaming == 0) |
| return 0; |
| |
| galileo1->streaming = 0; |
| |
| if (galileo1->gs->val) { |
| galileo1_write8(galileo1->i2c_sensor, |
| GLOBAL_RESET_CTRL1, 0x0); |
| galileo1_write8(galileo1->i2c_pmic, |
| MECH_SHUTTER_CONTROL, 0); |
| } |
| |
| galileo1_write8(galileo1->i2c_sensor, MODE_SELECT, 0x00); |
| |
| if (pdata->set_power) |
| pdata->set_power(GALILEO1_POWER_OFF); |
| |
| return 0; |
| } |
| |
| if (!galileo1->timings_uptodate) { |
| ret = galileo1_update_timings(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate Video Timing\n"); |
| return ret; |
| } |
| } |
| |
| /* Now that all needed pre-calculations are done, we can power on the |
| * device and configure it. |
| */ |
| if (pdata->set_power) { |
| ret = pdata->set_power(GALILEO1_POWER_ON); |
| if (ret) { |
| v4l2_err(sd, "Power on failed\n"); |
| return ret; |
| } |
| } |
| |
| ret = galileo1_apply_plls(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to apply plls\n"); |
| goto power_off; |
| } |
| |
| ret = galileo1_configure(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to configure\n"); |
| goto power_off; |
| } |
| |
| /* Stream on */ |
| galileo1->streaming = 1; |
| galileo1_set_shutter(sd); |
| galileo1_apply_hflip(sd); |
| galileo1_apply_vflip(sd); |
| galileo1_apply_nd(sd); |
| galileo1_apply_ms(sd); |
| galileo1_apply_flash_strobe(sd); |
| galileo1_write8(galileo1->i2c_sensor, MODE_SELECT, 0x01); |
| |
| return 0; |
| |
| power_off: |
| if (pdata->set_power) |
| pdata->set_power(GALILEO1_POWER_OFF); |
| |
| return ret; |
| } |
| |
| static int galileo1_g_frame_interval(struct v4l2_subdev *sd, |
| struct v4l2_subdev_frame_interval *fi) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| |
| memset(fi, 0, sizeof(*fi)); |
| fi->interval = galileo1->frame_interval; |
| |
| return 0; |
| } |
| |
| static int galileo1_s_frame_interval(struct v4l2_subdev *sd, |
| struct v4l2_subdev_frame_interval *fi) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| struct v4l2_rect *vt = &galileo1->video_timing; |
| struct v4l2_rect *c = &galileo1->crop; |
| struct v4l2_fract *cur_fi = &galileo1->frame_interval; |
| u32 min_vt_height; |
| |
| *cur_fi = fi->interval; |
| |
| galileo1->timings_uptodate = 0; |
| |
| if (!galileo1->streaming) |
| return 0; |
| |
| /* We are already streaming, so we try to adjust the vertical blanking |
| * in order to match the frame rate. |
| */ |
| vt->height = div_u64((u64) galileo1->vtclk * cur_fi->numerator, |
| vt->width * cur_fi->denominator); |
| |
| /* In case min_vt_frame_blanking is not met, we adjust the frame rate */ |
| min_vt_height = c->height / galileo1->y_binning + 42; |
| |
| if (vt->height < min_vt_height) { |
| vt->height = min_vt_height; |
| /* Refresh FPS */ |
| cur_fi->denominator = galileo1->vtclk; |
| cur_fi->numerator = vt->width * vt->height; |
| } |
| |
| galileo1_write16(i2c, VT_FRAME_LENGTH_LINES, vt->height); |
| |
| return 0; |
| } |
| |
| static int galileo1_g_dv_timings(struct v4l2_subdev *sd, |
| struct v4l2_dv_timings *timings) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = galileo1->pdata; |
| struct v4l2_mbus_framefmt *fmt = &galileo1->format; |
| struct v4l2_bt_timings *bt = &timings->bt; |
| int ret; |
| |
| memset(timings, 0, sizeof(*timings)); |
| |
| /* We update the timing only when we are not streaming. Anyway, while |
| * streaming, it is forbidden to change the pixelcloclk. |
| */ |
| if (!galileo1->timings_uptodate && !galileo1->streaming) { |
| ret = galileo1_update_timings(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate Video Timing\n"); |
| return ret; |
| } |
| } |
| |
| bt->width = fmt->width; |
| bt->height = fmt->height; |
| bt->pixelclock = (galileo1->mipiclk * pdata->lanes * 2) / |
| galileo1->bits_per_pixel; |
| |
| /* Consider HSYNC and VSYNC as HACTIVE and VACTIVE*/ |
| bt->polarities = 0; |
| |
| /* Because we are in HACTIVE/VACTIVE mode, the blanking size does not |
| * matter for the capture device. |
| */ |
| |
| return 0; |
| } |
| |
| static const struct v4l2_subdev_video_ops galileo1_video_ops = { |
| .s_stream = galileo1_s_stream, |
| .g_frame_interval = galileo1_g_frame_interval, |
| .s_frame_interval = galileo1_s_frame_interval, |
| .g_dv_timings = galileo1_g_dv_timings, |
| }; |
| |
| static const struct v4l2_subdev_ops galileo1_ops = { |
| .core = &galileo1_core_ops, |
| .video = &galileo1_video_ops, |
| .pad = &galileo1_pad_ops, |
| }; |
| |
| static int galileo1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| { |
| struct galileo1 *galileo1 = ctrl_to_galileo1(ctrl); |
| |
| /* If not streaming, just default value */ |
| if (!galileo1->streaming) { |
| ctrl->val = ctrl->default_value; |
| return 0; |
| } |
| |
| switch (ctrl->id) { |
| case V4L2_CID_FOCUS_ABSOLUTE: |
| galileo1_get_lens_position(&galileo1->sd, (u16 *)&ctrl->val); |
| break; |
| } |
| |
| return 0; |
| } |
| |
| /* Custom ctrls */ |
| #define V4L2_CID_GALILEO1_ND (V4L2_CID_CAMERA_CLASS_BASE + 0x100) |
| #define V4L2_CID_GALILEO1_GS (V4L2_CID_CAMERA_CLASS_BASE + 0x101) |
| #define V4L2_CID_GALILEO1_STROBE_WIDTH (V4L2_CID_CAMERA_CLASS_BASE + 0x102) |
| #define V4L2_CID_GALILEO1_MS (V4L2_CID_CAMERA_CLASS_BASE + 0x103) |
| |
| static int galileo1_s_ctrl(struct v4l2_ctrl *ctrl) |
| { |
| struct galileo1 *galileo1 = ctrl_to_galileo1(ctrl); |
| |
| /* If not streaming, just keep interval structures up-to-date */ |
| if (!galileo1->streaming) |
| return 0; |
| |
| switch (ctrl->id) { |
| case V4L2_CID_HFLIP: |
| return galileo1_apply_hflip(&galileo1->sd); |
| case V4L2_CID_VFLIP: |
| return galileo1_apply_vflip(&galileo1->sd); |
| case V4L2_CID_EXPOSURE_ABSOLUTE: |
| return galileo1_apply_exposure(&galileo1->sd); |
| case V4L2_CID_FOCUS_ABSOLUTE: |
| return galileo1_apply_focus(&galileo1->sd); |
| case V4L2_CID_GALILEO1_ND: |
| return galileo1_apply_nd(&galileo1->sd); |
| case V4L2_CID_FLASH_STROBE_SOURCE: |
| case V4L2_CID_GALILEO1_STROBE_WIDTH: |
| return galileo1_apply_flash_strobe(&galileo1->sd); |
| case V4L2_CID_ANALOGUE_GAIN: |
| return galileo1_apply_gain(&galileo1->sd); |
| case V4L2_CID_GALILEO1_GS: |
| return galileo1_apply_ms(&galileo1->sd); |
| case V4L2_CID_GALILEO1_MS: |
| return galileo1_set_shutter(&galileo1->sd); |
| } |
| |
| return 0; |
| } |
| |
| static const struct v4l2_ctrl_ops galileo1_ctrl_ops = { |
| .g_volatile_ctrl = galileo1_g_volatile_ctrl, |
| .s_ctrl = galileo1_s_ctrl, |
| }; |
| |
| static const struct v4l2_ctrl_config galileo1_ctrl_nd = { |
| .ops = &galileo1_ctrl_ops, |
| .id = V4L2_CID_GALILEO1_ND, |
| .name = "Neutral Density Filter", |
| .type = V4L2_CTRL_TYPE_BOOLEAN, |
| .min = false, |
| .max = true, |
| .step = 1, |
| .def = false, |
| }; |
| |
| static const struct v4l2_ctrl_config galileo1_ctrl_gs = { |
| .ops = &galileo1_ctrl_ops, |
| .id = V4L2_CID_GALILEO1_GS, |
| .name = "Global Shutter", |
| .type = V4L2_CTRL_TYPE_BOOLEAN, |
| .min = false, |
| .max = true, |
| .step = 1, |
| .def = false, |
| }; |
| |
| static const struct v4l2_ctrl_config galileo1_ctrl_ms = { |
| .ops = &galileo1_ctrl_ops, |
| .id = V4L2_CID_GALILEO1_MS, |
| .name = "Mechanical Shutter", |
| .type = V4L2_CTRL_TYPE_INTEGER, |
| .min = 0, |
| .max = 2, |
| .step = 1, |
| .def = 0, |
| }; |
| |
| static const struct v4l2_ctrl_config galileo1_ctrl_sw = { |
| .ops = &galileo1_ctrl_ops, |
| .id = V4L2_CID_GALILEO1_STROBE_WIDTH, |
| .name = "Flash strobe width, in us", |
| .type = V4L2_CTRL_TYPE_INTEGER, |
| .min = 1, |
| .max = 50000, |
| .step = 1, |
| .def = 100, |
| }; |
| |
| static int galileo1_initialize_controls(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct v4l2_ctrl_handler *hdl = &galileo1->ctrl_handler; |
| u8 *nvm = galileo1->nvm; |
| union nvm_memaddr *nvm_addr = &galileo1->nvm_addr; |
| union nvm_af nvm_af; |
| int ret; |
| |
| ret = v4l2_ctrl_handler_init(hdl, 16); |
| if (ret < 0) { |
| v4l2_err(sd, "failed to init ctrl handler\n"); |
| goto einit; |
| } |
| |
| /* Flips */ |
| galileo1->hflip = v4l2_ctrl_new_std(hdl, |
| &galileo1_ctrl_ops, |
| V4L2_CID_HFLIP, |
| 0, 1, 1, 0); |
| |
| galileo1->vflip = v4l2_ctrl_new_std(hdl, |
| &galileo1_ctrl_ops, |
| V4L2_CID_VFLIP, |
| 0, 1, 1, 0); |
| |
| /* Exposure in us */ |
| galileo1->exposure = v4l2_ctrl_new_std(hdl, |
| &galileo1_ctrl_ops, |
| V4L2_CID_EXPOSURE_ABSOLUTE, |
| 0, 1000000, 1, 20000); |
| |
| /* Focus */ |
| nvm_af._registers = |
| swab64(*((u64 *)(nvm + nvm_addr->af + NVM_AF_FAR_END))); |
| |
| /* Format the Auto Focus registers */ |
| nvm_af.infinity += nvm_af.far_end; |
| nvm_af.macro += nvm_af.infinity; |
| nvm_af.near_end += nvm_af.macro; |
| |
| galileo1->focus = v4l2_ctrl_new_std(hdl, &galileo1_ctrl_ops, |
| V4L2_CID_FOCUS_ABSOLUTE, |
| nvm_af.far_end, |
| nvm_af.near_end, |
| 1, |
| nvm_af.infinity); |
| |
| /* Since the lens can move even if no command has been sent, flag the |
| * control as volatile. |
| */ |
| galileo1->focus->flags |= V4L2_CTRL_FLAG_VOLATILE; |
| |
| /* Neutral Density Filter */ |
| galileo1->nd = v4l2_ctrl_new_custom(hdl, &galileo1_ctrl_nd, NULL); |
| |
| /* Global Shutter */ |
| galileo1->gs = v4l2_ctrl_new_custom(hdl, &galileo1_ctrl_gs, NULL); |
| |
| /* Mechanical shutter control */ |
| galileo1->ms = v4l2_ctrl_new_custom(hdl, &galileo1_ctrl_ms, NULL); |
| |
| /* Flash strobe width */ |
| galileo1->strobe_width = v4l2_ctrl_new_custom(hdl, &galileo1_ctrl_sw, NULL); |
| |
| /* Flash Strobe */ |
| galileo1->strobe_source = |
| v4l2_ctrl_new_std_menu(hdl, |
| &galileo1_ctrl_ops, |
| V4L2_CID_FLASH_STROBE_SOURCE, |
| V4L2_FLASH_STROBE_SOURCE_EXTERNAL, |
| ~0x3, |
| V4L2_FLASH_STROBE_SOURCE_SOFTWARE); |
| |
| /* Analog Gain |
| * AGx1.0 = 0x003F |
| * AGx2.0 = 0x007E |
| * AGx8.0 = 0x01F8 |
| * AGx12.0 = 0x02F4, this is the max gain code |
| */ |
| galileo1->gain = v4l2_ctrl_new_std(hdl, |
| &galileo1_ctrl_ops, |
| V4L2_CID_ANALOGUE_GAIN, |
| 0, 0x2F4, 1, 5 * 0x3F); |
| |
| if (hdl->error) { |
| v4l2_err(sd, "failed to add new ctrls\n"); |
| ret = hdl->error; |
| goto ectrl; |
| } |
| |
| sd->ctrl_handler = hdl; |
| |
| return 0; |
| |
| ectrl: |
| v4l2_ctrl_handler_free(hdl); |
| einit: |
| return ret; |
| } |
| |
| static void galileo1_free_controls(struct v4l2_subdev *sd) |
| { |
| v4l2_ctrl_handler_free(sd->ctrl_handler); |
| } |
| |
| static int galileo1_detect_chip(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| u16 chip_id; |
| |
| galileo1_read16(galileo1->i2c_sensor, SENSOR_MODEL_ID, &chip_id); |
| |
| if (chip_id != GALILEO1_CHIPID) { |
| v4l2_err(sd, "Error Chipd ID = 0x%04x instead of 0x%04x\n", |
| chip_id, GALILEO1_CHIPID); |
| return -ENODEV; |
| } |
| |
| galileo1_read16(galileo1->i2c_pmic, IC_INFO, &chip_id); |
| |
| if (chip_id != PMIC_CHIPID) { |
| v4l2_err(sd, "Error Chipd ID = 0x%04x instead of 0x%04x\n", |
| chip_id, PMIC_CHIPID); |
| return -ENODEV; |
| } |
| |
| v4l2_info(sd, "Found " DRIVER_NAME " chip\n"); |
| |
| return 0; |
| } |
| |
| static int galileo1_read_nvm(struct v4l2_subdev *sd) |
| { |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct i2c_client *i2c = galileo1->i2c_sensor; |
| u8 *nvm = galileo1->nvm; |
| u8 page = 0; |
| int ret = 0; |
| |
| /* Enable Read */ |
| galileo1_write8(i2c, DATA_TRANSFER_IF_1_CTRL, 0x1); |
| |
| for (page = 0 ; page < NVM_PAGE_NB ; page++) { |
| unsigned int i; |
| |
| union data_transfer_if_1_status status = { |
| .read_if_ready = 0, |
| }; |
| |
| /* Select page */ |
| galileo1_write8(i2c, DATA_TRANSFER_IF_1_PAGE_SELECT, page); |
| |
| /* Check Status */ |
| while (!status.read_if_ready) { |
| galileo1_read8(i2c, DATA_TRANSFER_IF_1_STATUS, |
| &status._register); |
| |
| if (status.improper_if_usage || status.data_corrupted) { |
| v4l2_err(sd, "NVM Data transfer IF is bad\n"); |
| ret = -EINVAL; |
| goto out; |
| } |
| } |
| |
| /* Read the entire page (64 bytes) |
| * If it is taking too long, it can be optimized into reading |
| * the entire page in one i2c xfer. |
| */ |
| for (i = 0 ; i < NVM_PAGE_SZ ; i++) |
| galileo1_read8(i2c, DATA_TRANSFER_IF_1_DATA + i, |
| nvm + NVM_PAGE_SZ * page + i); |
| } |
| |
| out: |
| galileo1_write8(i2c, DATA_TRANSFER_IF_1_CTRL, 0x0); |
| |
| /* Check Version */ |
| if (*nvm != NVM_VERSION) { |
| v4l2_err(sd, "NVM Version (0x%02x) is not correct\n", *nvm); |
| v4l2_err(sd, "Expecting 0x%02x\n", NVM_VERSION); |
| ret = -ENODEV; |
| } |
| |
| return ret; |
| } |
| |
| static ssize_t galileo1_nvm_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| |
| memcpy(buf, galileo1->nvm, NVM_SIZE); |
| |
| return NVM_SIZE; |
| } |
| |
| DEVICE_ATTR(nvm, S_IRUGO, galileo1_nvm_show, NULL); |
| |
| static int galileo1_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| struct galileo1 *galileo1; |
| struct galileo1_platform_data *pdata = client->dev.platform_data; |
| struct v4l2_subdev *sd; |
| int ret = 0; |
| |
| if (pdata == NULL) { |
| dev_err(&client->dev, "platform data not specified\n"); |
| return -EINVAL; |
| } |
| |
| if (pdata->refclk == 0) { |
| dev_err(&client->dev, "refclk frequency is not specified\n"); |
| return -EINVAL; |
| } |
| |
| if (!i2c_check_functionality(client->adapter, |
| I2C_FUNC_SMBUS_BYTE_DATA)) { |
| dev_err(&client->dev, "i2c not available\n"); |
| return -ENODEV; |
| } |
| |
| galileo1 = kzalloc(sizeof(*galileo1), GFP_KERNEL); |
| if (!galileo1) { |
| dev_err(&client->dev, "alloc failed for data structure\n"); |
| return -ENOMEM; |
| } |
| |
| galileo1->pdata = pdata; |
| |
| sd = &galileo1->sd; |
| v4l2_i2c_subdev_init(sd, client, &galileo1_ops); |
| |
| sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
| |
| galileo1->pad.flags = MEDIA_PAD_FL_SOURCE; |
| sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; |
| ret = media_entity_init(&sd->entity, 1, &galileo1->pad, 0); |
| |
| if (ret < 0) { |
| v4l2_err(sd, "failed to init media entity\n"); |
| goto emedia; |
| } |
| |
| galileo1->i2c_sensor = client; |
| galileo1->i2c_pmic = i2c_new_dummy(client->adapter, |
| GALILEO1_PMIC_I2C_ADDR); |
| if (galileo1->i2c_pmic == NULL) { |
| v4l2_err(sd, "failed to register pmic i2c client\n"); |
| ret = -ENODEV; |
| goto epmic; |
| } |
| |
| /* Set default configuration: |
| * Max sensor crop into 720p30 |
| */ |
| galileo1->format.width = 1280; |
| galileo1->format.height = 720; |
| galileo1->format.code = V4L2_MBUS_FMT_SGBRG10_1X10; |
| |
| /* Center the crop */ |
| galileo1->crop.width = 7680; |
| galileo1->crop.height = 4320; |
| galileo1->crop.left = 24; |
| galileo1->crop.top = 524; |
| |
| /* 30 FPS */ |
| galileo1->frame_interval.numerator = 1; |
| galileo1->frame_interval.denominator = 30; |
| |
| /* Make sure all clocks info are up-to-date */ |
| ret = galileo1_update_timings(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Unable to calculate Video Timing\n"); |
| goto eupdate; |
| } |
| |
| if (pdata->set_power) { |
| ret = pdata->set_power(GALILEO1_POWER_ON); |
| if (ret) { |
| v4l2_err(sd, "Power on failed\n"); |
| return ret; |
| } |
| } |
| |
| /* Check if the chip is preset */ |
| ret = galileo1_detect_chip(sd); |
| if (ret < 0) |
| goto edetect; |
| |
| /* Make sure the shutter is closed */ |
| galileo1_shutter_close(sd); |
| |
| /* Non-Volatile Memory */ |
| ret = device_create_file(&client->dev, &dev_attr_nvm); |
| if (ret < 0) { |
| v4l2_err(sd, "Sysfs nvm entry creation failed\n"); |
| goto esysfs; |
| } |
| |
| galileo1->nvm = kzalloc(NVM_SIZE, GFP_KERNEL); |
| if (!galileo1->nvm) { |
| v4l2_err(sd, "alloc failed for NVM structure\n"); |
| ret = -ENOMEM; |
| goto enomem; |
| } |
| |
| ret = galileo1_read_nvm(sd); |
| if (ret < 0) { |
| v4l2_err(sd, "Failed to read NVM\n"); |
| goto envm; |
| } |
| |
| /* Extract NVM Memory map */ |
| galileo1->nvm_addr._registers = |
| swab64(*(u64 *)(galileo1->nvm + NVM_MEMORY_ADDRESS)); |
| |
| if (pdata->set_power) |
| pdata->set_power(GALILEO1_POWER_OFF); |
| |
| /* Initialize Control */ |
| ret = galileo1_initialize_controls(sd); |
| if (ret < 0) |
| goto einitctrl; |
| |
| return 0; |
| |
| einitctrl: |
| envm: |
| kfree(galileo1->nvm); |
| enomem: |
| device_remove_file(&client->dev, &dev_attr_nvm); |
| esysfs: |
| edetect: |
| if (pdata->set_power) |
| pdata->set_power(GALILEO1_POWER_OFF); |
| eupdate: |
| i2c_unregister_device(galileo1->i2c_pmic); |
| epmic: |
| emedia: |
| media_entity_cleanup(&sd->entity); |
| v4l2_device_unregister_subdev(sd); |
| kfree(galileo1); |
| |
| return ret; |
| } |
| |
| static int galileo1_remove(struct i2c_client *client) |
| { |
| struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| struct galileo1 *galileo1 = to_galileo1(sd); |
| struct galileo1_platform_data *pdata = client->dev.platform_data; |
| |
| if (!pdata) |
| return -EINVAL; |
| |
| if (pdata->set_power) |
| pdata->set_power(GALILEO1_POWER_OFF); |
| |
| if (galileo1->i2c_pmic) |
| i2c_unregister_device(galileo1->i2c_pmic); |
| |
| device_remove_file(&client->dev, &dev_attr_nvm); |
| galileo1_free_controls(sd); |
| media_entity_cleanup(&sd->entity); |
| v4l2_device_unregister_subdev(sd); |
| kfree(galileo1->nvm); |
| kfree(galileo1); |
| |
| return 0; |
| } |
| |
| static const struct i2c_device_id galileo1_id[] = { |
| {DRIVER_NAME, 0}, |
| { } |
| }; |
| |
| MODULE_DEVICE_TABLE(i2c, galileo1_id); |
| |
| static struct i2c_driver galileo1_driver = { |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = DRIVER_NAME, |
| }, |
| .probe = galileo1_probe, |
| .remove = galileo1_remove, |
| .id_table = galileo1_id, |
| }; |
| |
| module_i2c_driver(galileo1_driver); |