191807efbSDongchun Zhu // SPDX-License-Identifier: GPL-2.0 291807efbSDongchun Zhu // Copyright (c) 2020 MediaTek Inc. 391807efbSDongchun Zhu 491807efbSDongchun Zhu #include <linux/clk.h> 591807efbSDongchun Zhu #include <linux/delay.h> 691807efbSDongchun Zhu #include <linux/device.h> 791807efbSDongchun Zhu #include <linux/gpio/consumer.h> 891807efbSDongchun Zhu #include <linux/i2c.h> 991807efbSDongchun Zhu #include <linux/module.h> 1091807efbSDongchun Zhu #include <linux/pm_runtime.h> 1191807efbSDongchun Zhu #include <linux/regulator/consumer.h> 1291807efbSDongchun Zhu #include <media/media-entity.h> 1391807efbSDongchun Zhu #include <media/v4l2-async.h> 1491807efbSDongchun Zhu #include <media/v4l2-ctrls.h> 1591807efbSDongchun Zhu #include <media/v4l2-fwnode.h> 1691807efbSDongchun Zhu #include <media/v4l2-subdev.h> 1791807efbSDongchun Zhu 1891807efbSDongchun Zhu #define OV02A10_ID 0x2509 1991807efbSDongchun Zhu #define OV02A10_ID_MASK GENMASK(15, 0) 2091807efbSDongchun Zhu 2191807efbSDongchun Zhu #define OV02A10_REG_CHIP_ID 0x02 2291807efbSDongchun Zhu 2391807efbSDongchun Zhu /* Bit[1] vertical upside down */ 2491807efbSDongchun Zhu /* Bit[0] horizontal mirror */ 2591807efbSDongchun Zhu #define REG_MIRROR_FLIP_CONTROL 0x3f 2691807efbSDongchun Zhu 2791807efbSDongchun Zhu /* Orientation */ 2891807efbSDongchun Zhu #define REG_MIRROR_FLIP_ENABLE 0x03 2991807efbSDongchun Zhu 3091807efbSDongchun Zhu /* Bit[2:0] MIPI transmission speed select */ 3191807efbSDongchun Zhu #define TX_SPEED_AREA_SEL 0xa1 3291807efbSDongchun Zhu #define OV02A10_MIPI_TX_SPEED_DEFAULT 0x04 3391807efbSDongchun Zhu 3491807efbSDongchun Zhu #define REG_PAGE_SWITCH 0xfd 3591807efbSDongchun Zhu #define REG_GLOBAL_EFFECTIVE 0x01 3691807efbSDongchun Zhu #define REG_ENABLE BIT(0) 3791807efbSDongchun Zhu 3891807efbSDongchun Zhu #define REG_SC_CTRL_MODE 0xac 3991807efbSDongchun Zhu #define SC_CTRL_MODE_STANDBY 0x00 4091807efbSDongchun Zhu #define SC_CTRL_MODE_STREAMING 0x01 4191807efbSDongchun Zhu 4291807efbSDongchun Zhu /* Exposure control */ 4391807efbSDongchun Zhu #define OV02A10_EXP_SHIFT 8 4491807efbSDongchun Zhu #define OV02A10_REG_EXPOSURE_H 0x03 4591807efbSDongchun Zhu #define OV02A10_REG_EXPOSURE_L 0x04 4691807efbSDongchun Zhu #define OV02A10_EXPOSURE_MIN 4 4791807efbSDongchun Zhu #define OV02A10_EXPOSURE_MAX_MARGIN 4 4891807efbSDongchun Zhu #define OV02A10_EXPOSURE_STEP 1 4991807efbSDongchun Zhu 5091807efbSDongchun Zhu /* Vblanking control */ 5191807efbSDongchun Zhu #define OV02A10_VTS_SHIFT 8 5291807efbSDongchun Zhu #define OV02A10_REG_VTS_H 0x05 5391807efbSDongchun Zhu #define OV02A10_REG_VTS_L 0x06 5491807efbSDongchun Zhu #define OV02A10_VTS_MAX 0x209f 5591807efbSDongchun Zhu #define OV02A10_BASE_LINES 1224 5691807efbSDongchun Zhu 5791807efbSDongchun Zhu /* Analog gain control */ 5891807efbSDongchun Zhu #define OV02A10_REG_GAIN 0x24 5991807efbSDongchun Zhu #define OV02A10_GAIN_MIN 0x10 6091807efbSDongchun Zhu #define OV02A10_GAIN_MAX 0xf8 6191807efbSDongchun Zhu #define OV02A10_GAIN_STEP 0x01 6291807efbSDongchun Zhu #define OV02A10_GAIN_DEFAULT 0x40 6391807efbSDongchun Zhu 6491807efbSDongchun Zhu /* Test pattern control */ 6591807efbSDongchun Zhu #define OV02A10_REG_TEST_PATTERN 0xb6 6691807efbSDongchun Zhu 6791807efbSDongchun Zhu #define HZ_PER_MHZ 1000000L 6891807efbSDongchun Zhu #define OV02A10_LINK_FREQ_390MHZ (390 * HZ_PER_MHZ) 6991807efbSDongchun Zhu #define OV02A10_ECLK_FREQ (24 * HZ_PER_MHZ) 7091807efbSDongchun Zhu 7191807efbSDongchun Zhu /* Number of lanes supported by this driver */ 7291807efbSDongchun Zhu #define OV02A10_DATA_LANES 1 7391807efbSDongchun Zhu 7491807efbSDongchun Zhu /* Bits per sample of sensor output */ 7591807efbSDongchun Zhu #define OV02A10_BITS_PER_SAMPLE 10 7691807efbSDongchun Zhu 7791807efbSDongchun Zhu static const char * const ov02a10_supply_names[] = { 7891807efbSDongchun Zhu "dovdd", /* Digital I/O power */ 7991807efbSDongchun Zhu "avdd", /* Analog power */ 8091807efbSDongchun Zhu "dvdd", /* Digital core power */ 8191807efbSDongchun Zhu }; 8291807efbSDongchun Zhu 8391807efbSDongchun Zhu struct ov02a10_reg { 8491807efbSDongchun Zhu u8 addr; 8591807efbSDongchun Zhu u8 val; 8691807efbSDongchun Zhu }; 8791807efbSDongchun Zhu 8891807efbSDongchun Zhu struct ov02a10_reg_list { 8991807efbSDongchun Zhu u32 num_of_regs; 9091807efbSDongchun Zhu const struct ov02a10_reg *regs; 9191807efbSDongchun Zhu }; 9291807efbSDongchun Zhu 9391807efbSDongchun Zhu struct ov02a10_mode { 9491807efbSDongchun Zhu u32 width; 9591807efbSDongchun Zhu u32 height; 9691807efbSDongchun Zhu u32 exp_def; 9791807efbSDongchun Zhu u32 hts_def; 9891807efbSDongchun Zhu u32 vts_def; 9991807efbSDongchun Zhu const struct ov02a10_reg_list reg_list; 10091807efbSDongchun Zhu }; 10191807efbSDongchun Zhu 10291807efbSDongchun Zhu struct ov02a10 { 10391807efbSDongchun Zhu u32 eclk_freq; 10491807efbSDongchun Zhu /* Indication of MIPI transmission speed select */ 10591807efbSDongchun Zhu u32 mipi_clock_voltage; 10691807efbSDongchun Zhu 10791807efbSDongchun Zhu struct clk *eclk; 10891807efbSDongchun Zhu struct gpio_desc *pd_gpio; 10991807efbSDongchun Zhu struct gpio_desc *rst_gpio; 11091807efbSDongchun Zhu struct regulator_bulk_data supplies[ARRAY_SIZE(ov02a10_supply_names)]; 11191807efbSDongchun Zhu 11291807efbSDongchun Zhu bool streaming; 11391807efbSDongchun Zhu bool upside_down; 11491807efbSDongchun Zhu 11591807efbSDongchun Zhu /* 11691807efbSDongchun Zhu * Serialize control access, get/set format, get selection 11791807efbSDongchun Zhu * and start streaming. 11891807efbSDongchun Zhu */ 11991807efbSDongchun Zhu struct mutex mutex; 12091807efbSDongchun Zhu struct v4l2_subdev subdev; 12191807efbSDongchun Zhu struct media_pad pad; 12291807efbSDongchun Zhu struct v4l2_mbus_framefmt fmt; 12391807efbSDongchun Zhu struct v4l2_ctrl_handler ctrl_handler; 12491807efbSDongchun Zhu struct v4l2_ctrl *exposure; 12591807efbSDongchun Zhu 12691807efbSDongchun Zhu const struct ov02a10_mode *cur_mode; 12791807efbSDongchun Zhu }; 12891807efbSDongchun Zhu 12991807efbSDongchun Zhu static inline struct ov02a10 *to_ov02a10(struct v4l2_subdev *sd) 13091807efbSDongchun Zhu { 13191807efbSDongchun Zhu return container_of(sd, struct ov02a10, subdev); 13291807efbSDongchun Zhu } 13391807efbSDongchun Zhu 13491807efbSDongchun Zhu /* 13591807efbSDongchun Zhu * eclk 24Mhz 13691807efbSDongchun Zhu * pclk 39Mhz 13791807efbSDongchun Zhu * linelength 934(0x3a6) 13891807efbSDongchun Zhu * framelength 1390(0x56E) 13991807efbSDongchun Zhu * grabwindow_width 1600 14091807efbSDongchun Zhu * grabwindow_height 1200 14191807efbSDongchun Zhu * max_framerate 30fps 14291807efbSDongchun Zhu * mipi_datarate per lane 780Mbps 14391807efbSDongchun Zhu */ 14491807efbSDongchun Zhu static const struct ov02a10_reg ov02a10_1600x1200_regs[] = { 14591807efbSDongchun Zhu {0xfd, 0x01}, 14691807efbSDongchun Zhu {0xac, 0x00}, 14791807efbSDongchun Zhu {0xfd, 0x00}, 14891807efbSDongchun Zhu {0x2f, 0x29}, 14991807efbSDongchun Zhu {0x34, 0x00}, 15091807efbSDongchun Zhu {0x35, 0x21}, 15191807efbSDongchun Zhu {0x30, 0x15}, 15291807efbSDongchun Zhu {0x33, 0x01}, 15391807efbSDongchun Zhu {0xfd, 0x01}, 15491807efbSDongchun Zhu {0x44, 0x00}, 15591807efbSDongchun Zhu {0x2a, 0x4c}, 15691807efbSDongchun Zhu {0x2b, 0x1e}, 15791807efbSDongchun Zhu {0x2c, 0x60}, 15891807efbSDongchun Zhu {0x25, 0x11}, 15991807efbSDongchun Zhu {0x03, 0x01}, 16091807efbSDongchun Zhu {0x04, 0xae}, 16191807efbSDongchun Zhu {0x09, 0x00}, 16291807efbSDongchun Zhu {0x0a, 0x02}, 16391807efbSDongchun Zhu {0x06, 0xa6}, 16491807efbSDongchun Zhu {0x31, 0x00}, 16591807efbSDongchun Zhu {0x24, 0x40}, 16691807efbSDongchun Zhu {0x01, 0x01}, 16791807efbSDongchun Zhu {0xfb, 0x73}, 16891807efbSDongchun Zhu {0xfd, 0x01}, 16991807efbSDongchun Zhu {0x16, 0x04}, 17091807efbSDongchun Zhu {0x1c, 0x09}, 17191807efbSDongchun Zhu {0x21, 0x42}, 17291807efbSDongchun Zhu {0x12, 0x04}, 17391807efbSDongchun Zhu {0x13, 0x10}, 17491807efbSDongchun Zhu {0x11, 0x40}, 17591807efbSDongchun Zhu {0x33, 0x81}, 17691807efbSDongchun Zhu {0xd0, 0x00}, 17791807efbSDongchun Zhu {0xd1, 0x01}, 17891807efbSDongchun Zhu {0xd2, 0x00}, 17991807efbSDongchun Zhu {0x50, 0x10}, 18091807efbSDongchun Zhu {0x51, 0x23}, 18191807efbSDongchun Zhu {0x52, 0x20}, 18291807efbSDongchun Zhu {0x53, 0x10}, 18391807efbSDongchun Zhu {0x54, 0x02}, 18491807efbSDongchun Zhu {0x55, 0x20}, 18591807efbSDongchun Zhu {0x56, 0x02}, 18691807efbSDongchun Zhu {0x58, 0x48}, 18791807efbSDongchun Zhu {0x5d, 0x15}, 18891807efbSDongchun Zhu {0x5e, 0x05}, 18991807efbSDongchun Zhu {0x66, 0x66}, 19091807efbSDongchun Zhu {0x68, 0x68}, 19191807efbSDongchun Zhu {0x6b, 0x00}, 19291807efbSDongchun Zhu {0x6c, 0x00}, 19391807efbSDongchun Zhu {0x6f, 0x40}, 19491807efbSDongchun Zhu {0x70, 0x40}, 19591807efbSDongchun Zhu {0x71, 0x0a}, 19691807efbSDongchun Zhu {0x72, 0xf0}, 19791807efbSDongchun Zhu {0x73, 0x10}, 19891807efbSDongchun Zhu {0x75, 0x80}, 19991807efbSDongchun Zhu {0x76, 0x10}, 20091807efbSDongchun Zhu {0x84, 0x00}, 20191807efbSDongchun Zhu {0x85, 0x10}, 20291807efbSDongchun Zhu {0x86, 0x10}, 20391807efbSDongchun Zhu {0x87, 0x00}, 20491807efbSDongchun Zhu {0x8a, 0x22}, 20591807efbSDongchun Zhu {0x8b, 0x22}, 20691807efbSDongchun Zhu {0x19, 0xf1}, 20791807efbSDongchun Zhu {0x29, 0x01}, 20891807efbSDongchun Zhu {0xfd, 0x01}, 20991807efbSDongchun Zhu {0x9d, 0x16}, 21091807efbSDongchun Zhu {0xa0, 0x29}, 21191807efbSDongchun Zhu {0xa1, 0x04}, 21291807efbSDongchun Zhu {0xad, 0x62}, 21391807efbSDongchun Zhu {0xae, 0x00}, 21491807efbSDongchun Zhu {0xaf, 0x85}, 21591807efbSDongchun Zhu {0xb1, 0x01}, 21691807efbSDongchun Zhu {0x8e, 0x06}, 21791807efbSDongchun Zhu {0x8f, 0x40}, 21891807efbSDongchun Zhu {0x90, 0x04}, 21991807efbSDongchun Zhu {0x91, 0xb0}, 22091807efbSDongchun Zhu {0x45, 0x01}, 22191807efbSDongchun Zhu {0x46, 0x00}, 22291807efbSDongchun Zhu {0x47, 0x6c}, 22391807efbSDongchun Zhu {0x48, 0x03}, 22491807efbSDongchun Zhu {0x49, 0x8b}, 22591807efbSDongchun Zhu {0x4a, 0x00}, 22691807efbSDongchun Zhu {0x4b, 0x07}, 22791807efbSDongchun Zhu {0x4c, 0x04}, 22891807efbSDongchun Zhu {0x4d, 0xb7}, 22991807efbSDongchun Zhu {0xf0, 0x40}, 23091807efbSDongchun Zhu {0xf1, 0x40}, 23191807efbSDongchun Zhu {0xf2, 0x40}, 23291807efbSDongchun Zhu {0xf3, 0x40}, 23391807efbSDongchun Zhu {0x3f, 0x00}, 23491807efbSDongchun Zhu {0xfd, 0x01}, 23591807efbSDongchun Zhu {0x05, 0x00}, 23691807efbSDongchun Zhu {0x06, 0xa6}, 23791807efbSDongchun Zhu {0xfd, 0x01}, 23891807efbSDongchun Zhu }; 23991807efbSDongchun Zhu 24091807efbSDongchun Zhu static const char * const ov02a10_test_pattern_menu[] = { 24191807efbSDongchun Zhu "Disabled", 24291807efbSDongchun Zhu "Eight Vertical Colour Bars", 24391807efbSDongchun Zhu }; 24491807efbSDongchun Zhu 24591807efbSDongchun Zhu static const s64 link_freq_menu_items[] = { 24691807efbSDongchun Zhu OV02A10_LINK_FREQ_390MHZ, 24791807efbSDongchun Zhu }; 24891807efbSDongchun Zhu 24991807efbSDongchun Zhu static u64 to_pixel_rate(u32 f_index) 25091807efbSDongchun Zhu { 25191807efbSDongchun Zhu u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV02A10_DATA_LANES; 25291807efbSDongchun Zhu 25391807efbSDongchun Zhu do_div(pixel_rate, OV02A10_BITS_PER_SAMPLE); 25491807efbSDongchun Zhu 25591807efbSDongchun Zhu return pixel_rate; 25691807efbSDongchun Zhu } 25791807efbSDongchun Zhu 25891807efbSDongchun Zhu static const struct ov02a10_mode supported_modes[] = { 25991807efbSDongchun Zhu { 26091807efbSDongchun Zhu .width = 1600, 26191807efbSDongchun Zhu .height = 1200, 26291807efbSDongchun Zhu .exp_def = 0x01ae, 26391807efbSDongchun Zhu .hts_def = 0x03a6, 26491807efbSDongchun Zhu .vts_def = 0x056e, 26591807efbSDongchun Zhu .reg_list = { 26691807efbSDongchun Zhu .num_of_regs = ARRAY_SIZE(ov02a10_1600x1200_regs), 26791807efbSDongchun Zhu .regs = ov02a10_1600x1200_regs, 26891807efbSDongchun Zhu }, 26991807efbSDongchun Zhu }, 27091807efbSDongchun Zhu }; 27191807efbSDongchun Zhu 27291807efbSDongchun Zhu static int ov02a10_write_array(struct ov02a10 *ov02a10, 27391807efbSDongchun Zhu const struct ov02a10_reg_list *r_list) 27491807efbSDongchun Zhu { 27591807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 27691807efbSDongchun Zhu unsigned int i; 27791807efbSDongchun Zhu int ret; 27891807efbSDongchun Zhu 27991807efbSDongchun Zhu for (i = 0; i < r_list->num_of_regs; i++) { 28091807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, r_list->regs[i].addr, 28191807efbSDongchun Zhu r_list->regs[i].val); 28291807efbSDongchun Zhu if (ret < 0) 28391807efbSDongchun Zhu return ret; 28491807efbSDongchun Zhu } 28591807efbSDongchun Zhu 28691807efbSDongchun Zhu return 0; 28791807efbSDongchun Zhu } 28891807efbSDongchun Zhu 28991807efbSDongchun Zhu static void ov02a10_fill_fmt(const struct ov02a10_mode *mode, 29091807efbSDongchun Zhu struct v4l2_mbus_framefmt *fmt) 29191807efbSDongchun Zhu { 29291807efbSDongchun Zhu fmt->width = mode->width; 29391807efbSDongchun Zhu fmt->height = mode->height; 29491807efbSDongchun Zhu fmt->field = V4L2_FIELD_NONE; 29591807efbSDongchun Zhu } 29691807efbSDongchun Zhu 29791807efbSDongchun Zhu static int ov02a10_set_fmt(struct v4l2_subdev *sd, 29891807efbSDongchun Zhu struct v4l2_subdev_pad_config *cfg, 29991807efbSDongchun Zhu struct v4l2_subdev_format *fmt) 30091807efbSDongchun Zhu { 30191807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 30291807efbSDongchun Zhu struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; 30391807efbSDongchun Zhu struct v4l2_mbus_framefmt *frame_fmt; 30491807efbSDongchun Zhu int ret = 0; 30591807efbSDongchun Zhu 30691807efbSDongchun Zhu mutex_lock(&ov02a10->mutex); 30791807efbSDongchun Zhu 30891807efbSDongchun Zhu if (ov02a10->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 30991807efbSDongchun Zhu ret = -EBUSY; 31091807efbSDongchun Zhu goto out_unlock; 31191807efbSDongchun Zhu } 31291807efbSDongchun Zhu 31391807efbSDongchun Zhu /* Only one sensor mode supported */ 31491807efbSDongchun Zhu mbus_fmt->code = ov02a10->fmt.code; 31591807efbSDongchun Zhu ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); 31691807efbSDongchun Zhu 31791807efbSDongchun Zhu if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 31891807efbSDongchun Zhu frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); 31991807efbSDongchun Zhu else 32091807efbSDongchun Zhu frame_fmt = &ov02a10->fmt; 32191807efbSDongchun Zhu 32291807efbSDongchun Zhu *frame_fmt = *mbus_fmt; 32391807efbSDongchun Zhu 32491807efbSDongchun Zhu out_unlock: 32591807efbSDongchun Zhu mutex_unlock(&ov02a10->mutex); 32691807efbSDongchun Zhu return ret; 32791807efbSDongchun Zhu } 32891807efbSDongchun Zhu 32991807efbSDongchun Zhu static int ov02a10_get_fmt(struct v4l2_subdev *sd, 33091807efbSDongchun Zhu struct v4l2_subdev_pad_config *cfg, 33191807efbSDongchun Zhu struct v4l2_subdev_format *fmt) 33291807efbSDongchun Zhu { 33391807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 33491807efbSDongchun Zhu struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; 33591807efbSDongchun Zhu 33691807efbSDongchun Zhu mutex_lock(&ov02a10->mutex); 33791807efbSDongchun Zhu 33891807efbSDongchun Zhu if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 33991807efbSDongchun Zhu fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); 34091807efbSDongchun Zhu } else { 34191807efbSDongchun Zhu fmt->format = ov02a10->fmt; 34291807efbSDongchun Zhu mbus_fmt->code = ov02a10->fmt.code; 34391807efbSDongchun Zhu ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); 34491807efbSDongchun Zhu } 34591807efbSDongchun Zhu 34691807efbSDongchun Zhu mutex_unlock(&ov02a10->mutex); 34791807efbSDongchun Zhu 34891807efbSDongchun Zhu return 0; 34991807efbSDongchun Zhu } 35091807efbSDongchun Zhu 35191807efbSDongchun Zhu static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd, 35291807efbSDongchun Zhu struct v4l2_subdev_pad_config *cfg, 35391807efbSDongchun Zhu struct v4l2_subdev_mbus_code_enum *code) 35491807efbSDongchun Zhu { 35591807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 35691807efbSDongchun Zhu 35791807efbSDongchun Zhu if (code->index != 0) 35891807efbSDongchun Zhu return -EINVAL; 35991807efbSDongchun Zhu 36091807efbSDongchun Zhu code->code = ov02a10->fmt.code; 36191807efbSDongchun Zhu 36291807efbSDongchun Zhu return 0; 36391807efbSDongchun Zhu } 36491807efbSDongchun Zhu 36591807efbSDongchun Zhu static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd, 36691807efbSDongchun Zhu struct v4l2_subdev_pad_config *cfg, 36791807efbSDongchun Zhu struct v4l2_subdev_frame_size_enum *fse) 36891807efbSDongchun Zhu { 36991807efbSDongchun Zhu if (fse->index >= ARRAY_SIZE(supported_modes)) 37091807efbSDongchun Zhu return -EINVAL; 37191807efbSDongchun Zhu 37291807efbSDongchun Zhu fse->min_width = supported_modes[fse->index].width; 37391807efbSDongchun Zhu fse->max_width = supported_modes[fse->index].width; 37491807efbSDongchun Zhu fse->max_height = supported_modes[fse->index].height; 37591807efbSDongchun Zhu fse->min_height = supported_modes[fse->index].height; 37691807efbSDongchun Zhu 37791807efbSDongchun Zhu return 0; 37891807efbSDongchun Zhu } 37991807efbSDongchun Zhu 38091807efbSDongchun Zhu static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) 38191807efbSDongchun Zhu { 38291807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 38391807efbSDongchun Zhu u16 chip_id; 38491807efbSDongchun Zhu int ret; 38591807efbSDongchun Zhu 38691807efbSDongchun Zhu /* Validate the chip ID */ 38791807efbSDongchun Zhu ret = i2c_smbus_read_word_swapped(client, OV02A10_REG_CHIP_ID); 38891807efbSDongchun Zhu if (ret < 0) 38991807efbSDongchun Zhu return ret; 39091807efbSDongchun Zhu 39191807efbSDongchun Zhu chip_id = le16_to_cpu(ret); 39291807efbSDongchun Zhu 39391807efbSDongchun Zhu if ((chip_id & OV02A10_ID_MASK) != OV02A10_ID) { 39491807efbSDongchun Zhu dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", chip_id); 39591807efbSDongchun Zhu return -EINVAL; 39691807efbSDongchun Zhu } 39791807efbSDongchun Zhu 39891807efbSDongchun Zhu return 0; 39991807efbSDongchun Zhu } 40091807efbSDongchun Zhu 40191807efbSDongchun Zhu static int ov02a10_power_on(struct device *dev) 40291807efbSDongchun Zhu { 40391807efbSDongchun Zhu struct i2c_client *client = to_i2c_client(dev); 40491807efbSDongchun Zhu struct v4l2_subdev *sd = i2c_get_clientdata(client); 40591807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 40691807efbSDongchun Zhu int ret; 40791807efbSDongchun Zhu 40891807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); 40991807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); 41091807efbSDongchun Zhu 41191807efbSDongchun Zhu ret = clk_prepare_enable(ov02a10->eclk); 41291807efbSDongchun Zhu if (ret < 0) { 41391807efbSDongchun Zhu dev_err(dev, "failed to enable eclk\n"); 41491807efbSDongchun Zhu return ret; 41591807efbSDongchun Zhu } 41691807efbSDongchun Zhu 41791807efbSDongchun Zhu ret = regulator_bulk_enable(ARRAY_SIZE(ov02a10_supply_names), 41891807efbSDongchun Zhu ov02a10->supplies); 41991807efbSDongchun Zhu if (ret < 0) { 42091807efbSDongchun Zhu dev_err(dev, "failed to enable regulators\n"); 42191807efbSDongchun Zhu goto disable_clk; 42291807efbSDongchun Zhu } 42391807efbSDongchun Zhu usleep_range(5000, 6000); 42491807efbSDongchun Zhu 42591807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->pd_gpio, 0); 42691807efbSDongchun Zhu usleep_range(5000, 6000); 42791807efbSDongchun Zhu 42891807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->rst_gpio, 0); 42991807efbSDongchun Zhu usleep_range(5000, 6000); 43091807efbSDongchun Zhu 43191807efbSDongchun Zhu ret = ov02a10_check_sensor_id(ov02a10); 43291807efbSDongchun Zhu if (ret) 43391807efbSDongchun Zhu goto disable_regulator; 43491807efbSDongchun Zhu 43591807efbSDongchun Zhu return 0; 43691807efbSDongchun Zhu 43791807efbSDongchun Zhu disable_regulator: 43891807efbSDongchun Zhu regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), 43991807efbSDongchun Zhu ov02a10->supplies); 44091807efbSDongchun Zhu disable_clk: 44191807efbSDongchun Zhu clk_disable_unprepare(ov02a10->eclk); 44291807efbSDongchun Zhu 44391807efbSDongchun Zhu return ret; 44491807efbSDongchun Zhu } 44591807efbSDongchun Zhu 44691807efbSDongchun Zhu static int ov02a10_power_off(struct device *dev) 44791807efbSDongchun Zhu { 44891807efbSDongchun Zhu struct i2c_client *client = to_i2c_client(dev); 44991807efbSDongchun Zhu struct v4l2_subdev *sd = i2c_get_clientdata(client); 45091807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 45191807efbSDongchun Zhu 45291807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); 45391807efbSDongchun Zhu clk_disable_unprepare(ov02a10->eclk); 45491807efbSDongchun Zhu gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); 45591807efbSDongchun Zhu regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), 45691807efbSDongchun Zhu ov02a10->supplies); 45791807efbSDongchun Zhu 45891807efbSDongchun Zhu return 0; 45991807efbSDongchun Zhu } 46091807efbSDongchun Zhu 46191807efbSDongchun Zhu static int __ov02a10_start_stream(struct ov02a10 *ov02a10) 46291807efbSDongchun Zhu { 46391807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 46491807efbSDongchun Zhu const struct ov02a10_reg_list *reg_list; 46591807efbSDongchun Zhu int ret; 46691807efbSDongchun Zhu 46791807efbSDongchun Zhu /* Apply default values of current mode */ 46891807efbSDongchun Zhu reg_list = &ov02a10->cur_mode->reg_list; 46991807efbSDongchun Zhu ret = ov02a10_write_array(ov02a10, reg_list); 47091807efbSDongchun Zhu if (ret) 47191807efbSDongchun Zhu return ret; 47291807efbSDongchun Zhu 47391807efbSDongchun Zhu /* Apply customized values from user */ 47491807efbSDongchun Zhu ret = __v4l2_ctrl_handler_setup(ov02a10->subdev.ctrl_handler); 47591807efbSDongchun Zhu if (ret) 47691807efbSDongchun Zhu return ret; 47791807efbSDongchun Zhu 47891807efbSDongchun Zhu /* Set orientation to 180 degree */ 47991807efbSDongchun Zhu if (ov02a10->upside_down) { 48091807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, 48191807efbSDongchun Zhu REG_MIRROR_FLIP_ENABLE); 48291807efbSDongchun Zhu if (ret < 0) { 48391807efbSDongchun Zhu dev_err(&client->dev, "failed to set orientation\n"); 48491807efbSDongchun Zhu return ret; 48591807efbSDongchun Zhu } 48691807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, 48791807efbSDongchun Zhu REG_ENABLE); 48891807efbSDongchun Zhu if (ret < 0) 48991807efbSDongchun Zhu return ret; 49091807efbSDongchun Zhu } 49191807efbSDongchun Zhu 49291807efbSDongchun Zhu /* Set MIPI TX speed according to DT property */ 49391807efbSDongchun Zhu if (ov02a10->mipi_clock_voltage != OV02A10_MIPI_TX_SPEED_DEFAULT) { 49491807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, TX_SPEED_AREA_SEL, 49591807efbSDongchun Zhu ov02a10->mipi_clock_voltage); 49691807efbSDongchun Zhu if (ret < 0) 49791807efbSDongchun Zhu return ret; 49891807efbSDongchun Zhu } 49991807efbSDongchun Zhu 50091807efbSDongchun Zhu /* Set stream on register */ 50191807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, 50291807efbSDongchun Zhu SC_CTRL_MODE_STREAMING); 50391807efbSDongchun Zhu } 50491807efbSDongchun Zhu 50591807efbSDongchun Zhu static int __ov02a10_stop_stream(struct ov02a10 *ov02a10) 50691807efbSDongchun Zhu { 50791807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 50891807efbSDongchun Zhu 50991807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, 51091807efbSDongchun Zhu SC_CTRL_MODE_STANDBY); 51191807efbSDongchun Zhu } 51291807efbSDongchun Zhu 51391807efbSDongchun Zhu static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd, 51491807efbSDongchun Zhu struct v4l2_subdev_pad_config *cfg) 51591807efbSDongchun Zhu { 51691807efbSDongchun Zhu struct v4l2_subdev_format fmt = { 51791807efbSDongchun Zhu .which = V4L2_SUBDEV_FORMAT_TRY, 51891807efbSDongchun Zhu .format = { 51991807efbSDongchun Zhu .width = 1600, 52091807efbSDongchun Zhu .height = 1200, 52191807efbSDongchun Zhu } 52291807efbSDongchun Zhu }; 52391807efbSDongchun Zhu 52491807efbSDongchun Zhu ov02a10_set_fmt(sd, cfg, &fmt); 52591807efbSDongchun Zhu 52691807efbSDongchun Zhu return 0; 52791807efbSDongchun Zhu } 52891807efbSDongchun Zhu 52991807efbSDongchun Zhu static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) 53091807efbSDongchun Zhu { 53191807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 53291807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 53391807efbSDongchun Zhu int ret; 53491807efbSDongchun Zhu 53591807efbSDongchun Zhu mutex_lock(&ov02a10->mutex); 53691807efbSDongchun Zhu 537*cc17afa2SArnd Bergmann if (ov02a10->streaming == on) { 538*cc17afa2SArnd Bergmann ret = 0; 53991807efbSDongchun Zhu goto unlock_and_return; 540*cc17afa2SArnd Bergmann } 54191807efbSDongchun Zhu 54291807efbSDongchun Zhu if (on) { 54391807efbSDongchun Zhu ret = pm_runtime_get_sync(&client->dev); 54491807efbSDongchun Zhu if (ret < 0) { 54591807efbSDongchun Zhu pm_runtime_put_noidle(&client->dev); 54691807efbSDongchun Zhu goto unlock_and_return; 54791807efbSDongchun Zhu } 54891807efbSDongchun Zhu 54991807efbSDongchun Zhu ret = __ov02a10_start_stream(ov02a10); 55091807efbSDongchun Zhu if (ret) { 55191807efbSDongchun Zhu __ov02a10_stop_stream(ov02a10); 55291807efbSDongchun Zhu ov02a10->streaming = !on; 55391807efbSDongchun Zhu goto err_rpm_put; 55491807efbSDongchun Zhu } 55591807efbSDongchun Zhu } else { 55691807efbSDongchun Zhu __ov02a10_stop_stream(ov02a10); 55791807efbSDongchun Zhu pm_runtime_put(&client->dev); 55891807efbSDongchun Zhu } 55991807efbSDongchun Zhu 56091807efbSDongchun Zhu ov02a10->streaming = on; 56191807efbSDongchun Zhu mutex_unlock(&ov02a10->mutex); 56291807efbSDongchun Zhu 56391807efbSDongchun Zhu return 0; 56491807efbSDongchun Zhu 56591807efbSDongchun Zhu err_rpm_put: 56691807efbSDongchun Zhu pm_runtime_put(&client->dev); 56791807efbSDongchun Zhu unlock_and_return: 56891807efbSDongchun Zhu mutex_unlock(&ov02a10->mutex); 56991807efbSDongchun Zhu 57091807efbSDongchun Zhu return ret; 57191807efbSDongchun Zhu } 57291807efbSDongchun Zhu 57391807efbSDongchun Zhu static const struct dev_pm_ops ov02a10_pm_ops = { 57491807efbSDongchun Zhu SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 57591807efbSDongchun Zhu pm_runtime_force_resume) 57691807efbSDongchun Zhu SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) 57791807efbSDongchun Zhu }; 57891807efbSDongchun Zhu 57991807efbSDongchun Zhu static int ov02a10_set_exposure(struct ov02a10 *ov02a10, int val) 58091807efbSDongchun Zhu { 58191807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 58291807efbSDongchun Zhu int ret; 58391807efbSDongchun Zhu 58491807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); 58591807efbSDongchun Zhu if (ret < 0) 58691807efbSDongchun Zhu return ret; 58791807efbSDongchun Zhu 58891807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_H, 58991807efbSDongchun Zhu val >> OV02A10_EXP_SHIFT); 59091807efbSDongchun Zhu if (ret < 0) 59191807efbSDongchun Zhu return ret; 59291807efbSDongchun Zhu 59391807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_L, val); 59491807efbSDongchun Zhu if (ret < 0) 59591807efbSDongchun Zhu return ret; 59691807efbSDongchun Zhu 59791807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, 59891807efbSDongchun Zhu REG_ENABLE); 59991807efbSDongchun Zhu } 60091807efbSDongchun Zhu 60191807efbSDongchun Zhu static int ov02a10_set_gain(struct ov02a10 *ov02a10, int val) 60291807efbSDongchun Zhu { 60391807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 60491807efbSDongchun Zhu int ret; 60591807efbSDongchun Zhu 60691807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); 60791807efbSDongchun Zhu if (ret < 0) 60891807efbSDongchun Zhu return ret; 60991807efbSDongchun Zhu 61091807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_GAIN, val); 61191807efbSDongchun Zhu if (ret < 0) 61291807efbSDongchun Zhu return ret; 61391807efbSDongchun Zhu 61491807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, 61591807efbSDongchun Zhu REG_ENABLE); 61691807efbSDongchun Zhu } 61791807efbSDongchun Zhu 61891807efbSDongchun Zhu static int ov02a10_set_vblank(struct ov02a10 *ov02a10, int val) 61991807efbSDongchun Zhu { 62091807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 62191807efbSDongchun Zhu u32 vts = val + ov02a10->cur_mode->height - OV02A10_BASE_LINES; 62291807efbSDongchun Zhu int ret; 62391807efbSDongchun Zhu 62491807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); 62591807efbSDongchun Zhu if (ret < 0) 62691807efbSDongchun Zhu return ret; 62791807efbSDongchun Zhu 62891807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_H, 62991807efbSDongchun Zhu vts >> OV02A10_VTS_SHIFT); 63091807efbSDongchun Zhu if (ret < 0) 63191807efbSDongchun Zhu return ret; 63291807efbSDongchun Zhu 63391807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_L, vts); 63491807efbSDongchun Zhu if (ret < 0) 63591807efbSDongchun Zhu return ret; 63691807efbSDongchun Zhu 63791807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, 63891807efbSDongchun Zhu REG_ENABLE); 63991807efbSDongchun Zhu } 64091807efbSDongchun Zhu 64191807efbSDongchun Zhu static int ov02a10_set_test_pattern(struct ov02a10 *ov02a10, int pattern) 64291807efbSDongchun Zhu { 64391807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 64491807efbSDongchun Zhu int ret; 64591807efbSDongchun Zhu 64691807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); 64791807efbSDongchun Zhu if (ret < 0) 64891807efbSDongchun Zhu return ret; 64991807efbSDongchun Zhu 65091807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, OV02A10_REG_TEST_PATTERN, 65191807efbSDongchun Zhu pattern); 65291807efbSDongchun Zhu if (ret < 0) 65391807efbSDongchun Zhu return ret; 65491807efbSDongchun Zhu 65591807efbSDongchun Zhu ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, 65691807efbSDongchun Zhu REG_ENABLE); 65791807efbSDongchun Zhu if (ret < 0) 65891807efbSDongchun Zhu return ret; 65991807efbSDongchun Zhu 66091807efbSDongchun Zhu return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, 66191807efbSDongchun Zhu SC_CTRL_MODE_STREAMING); 66291807efbSDongchun Zhu } 66391807efbSDongchun Zhu 66491807efbSDongchun Zhu static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) 66591807efbSDongchun Zhu { 66691807efbSDongchun Zhu struct ov02a10 *ov02a10 = container_of(ctrl->handler, 66791807efbSDongchun Zhu struct ov02a10, ctrl_handler); 66891807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 66991807efbSDongchun Zhu s64 max_expo; 67091807efbSDongchun Zhu int ret; 67191807efbSDongchun Zhu 67291807efbSDongchun Zhu /* Propagate change of current control to all related controls */ 67391807efbSDongchun Zhu if (ctrl->id == V4L2_CID_VBLANK) { 67491807efbSDongchun Zhu /* Update max exposure while meeting expected vblanking */ 67591807efbSDongchun Zhu max_expo = ov02a10->cur_mode->height + ctrl->val - 67691807efbSDongchun Zhu OV02A10_EXPOSURE_MAX_MARGIN; 67791807efbSDongchun Zhu __v4l2_ctrl_modify_range(ov02a10->exposure, 67891807efbSDongchun Zhu ov02a10->exposure->minimum, max_expo, 67991807efbSDongchun Zhu ov02a10->exposure->step, 68091807efbSDongchun Zhu ov02a10->exposure->default_value); 68191807efbSDongchun Zhu } 68291807efbSDongchun Zhu 68391807efbSDongchun Zhu /* V4L2 controls values will be applied only when power is already up */ 68491807efbSDongchun Zhu if (!pm_runtime_get_if_in_use(&client->dev)) 68591807efbSDongchun Zhu return 0; 68691807efbSDongchun Zhu 68791807efbSDongchun Zhu switch (ctrl->id) { 68891807efbSDongchun Zhu case V4L2_CID_EXPOSURE: 68991807efbSDongchun Zhu ret = ov02a10_set_exposure(ov02a10, ctrl->val); 69091807efbSDongchun Zhu break; 69191807efbSDongchun Zhu case V4L2_CID_ANALOGUE_GAIN: 69291807efbSDongchun Zhu ret = ov02a10_set_gain(ov02a10, ctrl->val); 69391807efbSDongchun Zhu break; 69491807efbSDongchun Zhu case V4L2_CID_VBLANK: 69591807efbSDongchun Zhu ret = ov02a10_set_vblank(ov02a10, ctrl->val); 69691807efbSDongchun Zhu break; 69791807efbSDongchun Zhu case V4L2_CID_TEST_PATTERN: 69891807efbSDongchun Zhu ret = ov02a10_set_test_pattern(ov02a10, ctrl->val); 69991807efbSDongchun Zhu break; 70091807efbSDongchun Zhu default: 70191807efbSDongchun Zhu ret = -EINVAL; 70291807efbSDongchun Zhu break; 70391807efbSDongchun Zhu }; 70491807efbSDongchun Zhu 70591807efbSDongchun Zhu pm_runtime_put(&client->dev); 70691807efbSDongchun Zhu 70791807efbSDongchun Zhu return ret; 70891807efbSDongchun Zhu } 70991807efbSDongchun Zhu 71091807efbSDongchun Zhu static const struct v4l2_subdev_video_ops ov02a10_video_ops = { 71191807efbSDongchun Zhu .s_stream = ov02a10_s_stream, 71291807efbSDongchun Zhu }; 71391807efbSDongchun Zhu 71491807efbSDongchun Zhu static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = { 71591807efbSDongchun Zhu .init_cfg = ov02a10_entity_init_cfg, 71691807efbSDongchun Zhu .enum_mbus_code = ov02a10_enum_mbus_code, 71791807efbSDongchun Zhu .enum_frame_size = ov02a10_enum_frame_sizes, 71891807efbSDongchun Zhu .get_fmt = ov02a10_get_fmt, 71991807efbSDongchun Zhu .set_fmt = ov02a10_set_fmt, 72091807efbSDongchun Zhu }; 72191807efbSDongchun Zhu 72291807efbSDongchun Zhu static const struct v4l2_subdev_ops ov02a10_subdev_ops = { 72391807efbSDongchun Zhu .video = &ov02a10_video_ops, 72491807efbSDongchun Zhu .pad = &ov02a10_pad_ops, 72591807efbSDongchun Zhu }; 72691807efbSDongchun Zhu 72791807efbSDongchun Zhu static const struct media_entity_operations ov02a10_subdev_entity_ops = { 72891807efbSDongchun Zhu .link_validate = v4l2_subdev_link_validate, 72991807efbSDongchun Zhu }; 73091807efbSDongchun Zhu 73191807efbSDongchun Zhu static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { 73291807efbSDongchun Zhu .s_ctrl = ov02a10_set_ctrl, 73391807efbSDongchun Zhu }; 73491807efbSDongchun Zhu 73591807efbSDongchun Zhu static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) 73691807efbSDongchun Zhu { 73791807efbSDongchun Zhu struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); 73891807efbSDongchun Zhu const struct ov02a10_mode *mode; 73991807efbSDongchun Zhu struct v4l2_ctrl_handler *handler; 74091807efbSDongchun Zhu struct v4l2_ctrl *ctrl; 74191807efbSDongchun Zhu s64 exposure_max; 74291807efbSDongchun Zhu s64 vblank_def; 74391807efbSDongchun Zhu s64 pixel_rate; 74491807efbSDongchun Zhu s64 h_blank; 74591807efbSDongchun Zhu int ret; 74691807efbSDongchun Zhu 74791807efbSDongchun Zhu handler = &ov02a10->ctrl_handler; 74891807efbSDongchun Zhu mode = ov02a10->cur_mode; 74991807efbSDongchun Zhu ret = v4l2_ctrl_handler_init(handler, 7); 75091807efbSDongchun Zhu if (ret) 75191807efbSDongchun Zhu return ret; 75291807efbSDongchun Zhu 75391807efbSDongchun Zhu handler->lock = &ov02a10->mutex; 75491807efbSDongchun Zhu 75591807efbSDongchun Zhu ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, 75691807efbSDongchun Zhu link_freq_menu_items); 75791807efbSDongchun Zhu if (ctrl) 75891807efbSDongchun Zhu ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 75991807efbSDongchun Zhu 76091807efbSDongchun Zhu pixel_rate = to_pixel_rate(0); 76191807efbSDongchun Zhu v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, 76291807efbSDongchun Zhu pixel_rate); 76391807efbSDongchun Zhu 76491807efbSDongchun Zhu h_blank = mode->hts_def - mode->width; 76591807efbSDongchun Zhu v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, 76691807efbSDongchun Zhu h_blank); 76791807efbSDongchun Zhu 76891807efbSDongchun Zhu vblank_def = mode->vts_def - mode->height; 76991807efbSDongchun Zhu v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, V4L2_CID_VBLANK, 77091807efbSDongchun Zhu vblank_def, OV02A10_VTS_MAX - mode->height, 1, 77191807efbSDongchun Zhu vblank_def); 77291807efbSDongchun Zhu 77391807efbSDongchun Zhu exposure_max = mode->vts_def - 4; 77491807efbSDongchun Zhu ov02a10->exposure = v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, 77591807efbSDongchun Zhu V4L2_CID_EXPOSURE, 77691807efbSDongchun Zhu OV02A10_EXPOSURE_MIN, 77791807efbSDongchun Zhu exposure_max, 77891807efbSDongchun Zhu OV02A10_EXPOSURE_STEP, 77991807efbSDongchun Zhu mode->exp_def); 78091807efbSDongchun Zhu 78191807efbSDongchun Zhu v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, 78291807efbSDongchun Zhu V4L2_CID_ANALOGUE_GAIN, OV02A10_GAIN_MIN, 78391807efbSDongchun Zhu OV02A10_GAIN_MAX, OV02A10_GAIN_STEP, 78491807efbSDongchun Zhu OV02A10_GAIN_DEFAULT); 78591807efbSDongchun Zhu 78691807efbSDongchun Zhu v4l2_ctrl_new_std_menu_items(handler, &ov02a10_ctrl_ops, 78791807efbSDongchun Zhu V4L2_CID_TEST_PATTERN, 78891807efbSDongchun Zhu ARRAY_SIZE(ov02a10_test_pattern_menu) - 1, 78991807efbSDongchun Zhu 0, 0, ov02a10_test_pattern_menu); 79091807efbSDongchun Zhu 79191807efbSDongchun Zhu if (handler->error) { 79291807efbSDongchun Zhu ret = handler->error; 79391807efbSDongchun Zhu dev_err(&client->dev, "failed to init controls(%d)\n", ret); 79491807efbSDongchun Zhu goto err_free_handler; 79591807efbSDongchun Zhu } 79691807efbSDongchun Zhu 79791807efbSDongchun Zhu ov02a10->subdev.ctrl_handler = handler; 79891807efbSDongchun Zhu 79991807efbSDongchun Zhu return 0; 80091807efbSDongchun Zhu 80191807efbSDongchun Zhu err_free_handler: 80291807efbSDongchun Zhu v4l2_ctrl_handler_free(handler); 80391807efbSDongchun Zhu 80491807efbSDongchun Zhu return ret; 80591807efbSDongchun Zhu } 80691807efbSDongchun Zhu 80791807efbSDongchun Zhu static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) 80891807efbSDongchun Zhu { 80991807efbSDongchun Zhu struct fwnode_handle *ep; 81091807efbSDongchun Zhu struct fwnode_handle *fwnode = dev_fwnode(dev); 81191807efbSDongchun Zhu struct v4l2_fwnode_endpoint bus_cfg = { 81291807efbSDongchun Zhu .bus_type = V4L2_MBUS_CSI2_DPHY, 81391807efbSDongchun Zhu }; 81491807efbSDongchun Zhu unsigned int i, j; 81591807efbSDongchun Zhu u32 clk_volt; 81691807efbSDongchun Zhu int ret; 81791807efbSDongchun Zhu 81891807efbSDongchun Zhu if (!fwnode) 81991807efbSDongchun Zhu return -EINVAL; 82091807efbSDongchun Zhu 82191807efbSDongchun Zhu ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 82291807efbSDongchun Zhu if (!ep) 82391807efbSDongchun Zhu return -ENXIO; 82491807efbSDongchun Zhu 82591807efbSDongchun Zhu ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 82691807efbSDongchun Zhu fwnode_handle_put(ep); 82791807efbSDongchun Zhu if (ret) 82891807efbSDongchun Zhu return ret; 82991807efbSDongchun Zhu 83091807efbSDongchun Zhu /* Optional indication of MIPI clock voltage unit */ 83191807efbSDongchun Zhu ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", 83291807efbSDongchun Zhu &clk_volt); 83391807efbSDongchun Zhu 83491807efbSDongchun Zhu if (!ret) 83591807efbSDongchun Zhu ov02a10->mipi_clock_voltage = clk_volt; 83691807efbSDongchun Zhu 83791807efbSDongchun Zhu for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { 83891807efbSDongchun Zhu for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { 83991807efbSDongchun Zhu if (link_freq_menu_items[i] == 84091807efbSDongchun Zhu bus_cfg.link_frequencies[j]) 84191807efbSDongchun Zhu break; 84291807efbSDongchun Zhu } 84391807efbSDongchun Zhu 84491807efbSDongchun Zhu if (j == bus_cfg.nr_of_link_frequencies) { 84591807efbSDongchun Zhu dev_err(dev, "no link frequency %lld supported\n", 84691807efbSDongchun Zhu link_freq_menu_items[i]); 84791807efbSDongchun Zhu ret = -EINVAL; 84891807efbSDongchun Zhu break; 84991807efbSDongchun Zhu } 85091807efbSDongchun Zhu } 85191807efbSDongchun Zhu 85291807efbSDongchun Zhu v4l2_fwnode_endpoint_free(&bus_cfg); 85391807efbSDongchun Zhu 85491807efbSDongchun Zhu return ret; 85591807efbSDongchun Zhu } 85691807efbSDongchun Zhu 85791807efbSDongchun Zhu static int ov02a10_probe(struct i2c_client *client) 85891807efbSDongchun Zhu { 85991807efbSDongchun Zhu struct device *dev = &client->dev; 86091807efbSDongchun Zhu struct ov02a10 *ov02a10; 86191807efbSDongchun Zhu unsigned int i; 86291807efbSDongchun Zhu unsigned int rotation; 86391807efbSDongchun Zhu int ret; 86491807efbSDongchun Zhu 86591807efbSDongchun Zhu ov02a10 = devm_kzalloc(dev, sizeof(*ov02a10), GFP_KERNEL); 86691807efbSDongchun Zhu if (!ov02a10) 86791807efbSDongchun Zhu return -ENOMEM; 86891807efbSDongchun Zhu 86991807efbSDongchun Zhu ret = ov02a10_check_hwcfg(dev, ov02a10); 87091807efbSDongchun Zhu if (ret) 87191807efbSDongchun Zhu return dev_err_probe(dev, ret, 87291807efbSDongchun Zhu "failed to check HW configuration\n"); 87391807efbSDongchun Zhu 87491807efbSDongchun Zhu v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops); 87591807efbSDongchun Zhu 87691807efbSDongchun Zhu ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT; 87791807efbSDongchun Zhu ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; 87891807efbSDongchun Zhu 87991807efbSDongchun Zhu /* Optional indication of physical rotation of sensor */ 88091807efbSDongchun Zhu rotation = 0; 88191807efbSDongchun Zhu device_property_read_u32(dev, "rotation", &rotation); 88291807efbSDongchun Zhu if (rotation == 180) { 88391807efbSDongchun Zhu ov02a10->upside_down = true; 88491807efbSDongchun Zhu ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; 88591807efbSDongchun Zhu } 88691807efbSDongchun Zhu 88791807efbSDongchun Zhu ov02a10->eclk = devm_clk_get(dev, "eclk"); 88891807efbSDongchun Zhu if (IS_ERR(ov02a10->eclk)) 88991807efbSDongchun Zhu return dev_err_probe(dev, PTR_ERR(ov02a10->eclk), 89091807efbSDongchun Zhu "failed to get eclk\n"); 89191807efbSDongchun Zhu 89291807efbSDongchun Zhu ret = device_property_read_u32(dev, "clock-frequency", 89391807efbSDongchun Zhu &ov02a10->eclk_freq); 89491807efbSDongchun Zhu if (ret < 0) 89591807efbSDongchun Zhu return dev_err_probe(dev, ret, 89691807efbSDongchun Zhu "failed to get eclk frequency\n"); 89791807efbSDongchun Zhu 89891807efbSDongchun Zhu ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); 89991807efbSDongchun Zhu if (ret < 0) 90091807efbSDongchun Zhu return dev_err_probe(dev, ret, 90191807efbSDongchun Zhu "failed to set eclk frequency (24MHz)\n"); 90291807efbSDongchun Zhu 90391807efbSDongchun Zhu if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) 90491807efbSDongchun Zhu dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); 90591807efbSDongchun Zhu 90691807efbSDongchun Zhu ov02a10->pd_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); 90791807efbSDongchun Zhu if (IS_ERR(ov02a10->pd_gpio)) 90891807efbSDongchun Zhu return dev_err_probe(dev, PTR_ERR(ov02a10->pd_gpio), 90991807efbSDongchun Zhu "failed to get powerdown-gpios\n"); 91091807efbSDongchun Zhu 91191807efbSDongchun Zhu ov02a10->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 91291807efbSDongchun Zhu if (IS_ERR(ov02a10->rst_gpio)) 91391807efbSDongchun Zhu return dev_err_probe(dev, PTR_ERR(ov02a10->rst_gpio), 91491807efbSDongchun Zhu "failed to get reset-gpios\n"); 91591807efbSDongchun Zhu 91691807efbSDongchun Zhu for (i = 0; i < ARRAY_SIZE(ov02a10_supply_names); i++) 91791807efbSDongchun Zhu ov02a10->supplies[i].supply = ov02a10_supply_names[i]; 91891807efbSDongchun Zhu 91991807efbSDongchun Zhu ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov02a10_supply_names), 92091807efbSDongchun Zhu ov02a10->supplies); 92191807efbSDongchun Zhu if (ret) 92291807efbSDongchun Zhu return dev_err_probe(dev, ret, "failed to get regulators\n"); 92391807efbSDongchun Zhu 92491807efbSDongchun Zhu mutex_init(&ov02a10->mutex); 92591807efbSDongchun Zhu 92691807efbSDongchun Zhu /* Set default mode */ 92791807efbSDongchun Zhu ov02a10->cur_mode = &supported_modes[0]; 92891807efbSDongchun Zhu 92991807efbSDongchun Zhu ret = ov02a10_initialize_controls(ov02a10); 93091807efbSDongchun Zhu if (ret) { 93191807efbSDongchun Zhu dev_err_probe(dev, ret, "failed to initialize controls\n"); 93291807efbSDongchun Zhu goto err_destroy_mutex; 93391807efbSDongchun Zhu } 93491807efbSDongchun Zhu 93591807efbSDongchun Zhu /* Initialize subdev */ 93691807efbSDongchun Zhu ov02a10->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 93791807efbSDongchun Zhu ov02a10->subdev.entity.ops = &ov02a10_subdev_entity_ops; 93891807efbSDongchun Zhu ov02a10->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; 93991807efbSDongchun Zhu ov02a10->pad.flags = MEDIA_PAD_FL_SOURCE; 94091807efbSDongchun Zhu 94191807efbSDongchun Zhu ret = media_entity_pads_init(&ov02a10->subdev.entity, 1, &ov02a10->pad); 94291807efbSDongchun Zhu if (ret < 0) { 94391807efbSDongchun Zhu dev_err_probe(dev, ret, "failed to initialize entity pads\n"); 94491807efbSDongchun Zhu goto err_free_handler; 94591807efbSDongchun Zhu } 94691807efbSDongchun Zhu 94791807efbSDongchun Zhu pm_runtime_enable(dev); 94891807efbSDongchun Zhu if (!pm_runtime_enabled(dev)) { 94991807efbSDongchun Zhu ret = ov02a10_power_on(dev); 95091807efbSDongchun Zhu if (ret < 0) { 95191807efbSDongchun Zhu dev_err_probe(dev, ret, "failed to power on\n"); 95291807efbSDongchun Zhu goto err_clean_entity; 95391807efbSDongchun Zhu } 95491807efbSDongchun Zhu } 95591807efbSDongchun Zhu 95691807efbSDongchun Zhu ret = v4l2_async_register_subdev(&ov02a10->subdev); 95791807efbSDongchun Zhu if (ret) { 95891807efbSDongchun Zhu dev_err_probe(dev, ret, "failed to register V4L2 subdev\n"); 95991807efbSDongchun Zhu goto err_power_off; 96091807efbSDongchun Zhu } 96191807efbSDongchun Zhu 96291807efbSDongchun Zhu return 0; 96391807efbSDongchun Zhu 96491807efbSDongchun Zhu err_power_off: 96591807efbSDongchun Zhu if (pm_runtime_enabled(dev)) 96691807efbSDongchun Zhu pm_runtime_disable(dev); 96791807efbSDongchun Zhu else 96891807efbSDongchun Zhu ov02a10_power_off(dev); 96991807efbSDongchun Zhu err_clean_entity: 97091807efbSDongchun Zhu media_entity_cleanup(&ov02a10->subdev.entity); 97191807efbSDongchun Zhu err_free_handler: 97291807efbSDongchun Zhu v4l2_ctrl_handler_free(ov02a10->subdev.ctrl_handler); 97391807efbSDongchun Zhu err_destroy_mutex: 97491807efbSDongchun Zhu mutex_destroy(&ov02a10->mutex); 97591807efbSDongchun Zhu 97691807efbSDongchun Zhu return ret; 97791807efbSDongchun Zhu } 97891807efbSDongchun Zhu 97991807efbSDongchun Zhu static int ov02a10_remove(struct i2c_client *client) 98091807efbSDongchun Zhu { 98191807efbSDongchun Zhu struct v4l2_subdev *sd = i2c_get_clientdata(client); 98291807efbSDongchun Zhu struct ov02a10 *ov02a10 = to_ov02a10(sd); 98391807efbSDongchun Zhu 98491807efbSDongchun Zhu v4l2_async_unregister_subdev(sd); 98591807efbSDongchun Zhu media_entity_cleanup(&sd->entity); 98691807efbSDongchun Zhu v4l2_ctrl_handler_free(sd->ctrl_handler); 98791807efbSDongchun Zhu pm_runtime_disable(&client->dev); 98891807efbSDongchun Zhu if (!pm_runtime_status_suspended(&client->dev)) 98991807efbSDongchun Zhu ov02a10_power_off(&client->dev); 99091807efbSDongchun Zhu pm_runtime_set_suspended(&client->dev); 99191807efbSDongchun Zhu mutex_destroy(&ov02a10->mutex); 99291807efbSDongchun Zhu 99391807efbSDongchun Zhu return 0; 99491807efbSDongchun Zhu } 99591807efbSDongchun Zhu 99691807efbSDongchun Zhu static const struct of_device_id ov02a10_of_match[] = { 99791807efbSDongchun Zhu { .compatible = "ovti,ov02a10" }, 99891807efbSDongchun Zhu {} 99991807efbSDongchun Zhu }; 100091807efbSDongchun Zhu MODULE_DEVICE_TABLE(of, ov02a10_of_match); 100191807efbSDongchun Zhu 100291807efbSDongchun Zhu static struct i2c_driver ov02a10_i2c_driver = { 100391807efbSDongchun Zhu .driver = { 100491807efbSDongchun Zhu .name = "ov02a10", 100591807efbSDongchun Zhu .pm = &ov02a10_pm_ops, 100691807efbSDongchun Zhu .of_match_table = ov02a10_of_match, 100791807efbSDongchun Zhu }, 100891807efbSDongchun Zhu .probe_new = &ov02a10_probe, 100991807efbSDongchun Zhu .remove = &ov02a10_remove, 101091807efbSDongchun Zhu }; 101191807efbSDongchun Zhu module_i2c_driver(ov02a10_i2c_driver); 101291807efbSDongchun Zhu 101391807efbSDongchun Zhu MODULE_AUTHOR("Dongchun Zhu <dongchun.zhu@mediatek.com>"); 101491807efbSDongchun Zhu MODULE_DESCRIPTION("OmniVision OV02A10 sensor driver"); 101591807efbSDongchun Zhu MODULE_LICENSE("GPL v2"); 1016