114ea315bSMartina Krasteva // SPDX-License-Identifier: GPL-2.0-only 214ea315bSMartina Krasteva /* 314ea315bSMartina Krasteva * OmniVision ov9282 Camera Sensor Driver 414ea315bSMartina Krasteva * 514ea315bSMartina Krasteva * Copyright (C) 2021 Intel Corporation 614ea315bSMartina Krasteva */ 714ea315bSMartina Krasteva #include <asm/unaligned.h> 814ea315bSMartina Krasteva 914ea315bSMartina Krasteva #include <linux/clk.h> 1014ea315bSMartina Krasteva #include <linux/delay.h> 1114ea315bSMartina Krasteva #include <linux/i2c.h> 1214ea315bSMartina Krasteva #include <linux/module.h> 1314ea315bSMartina Krasteva #include <linux/pm_runtime.h> 1414ea315bSMartina Krasteva 1514ea315bSMartina Krasteva #include <media/v4l2-ctrls.h> 1614ea315bSMartina Krasteva #include <media/v4l2-fwnode.h> 1714ea315bSMartina Krasteva #include <media/v4l2-subdev.h> 1814ea315bSMartina Krasteva 1914ea315bSMartina Krasteva /* Streaming Mode */ 2014ea315bSMartina Krasteva #define OV9282_REG_MODE_SELECT 0x0100 2114ea315bSMartina Krasteva #define OV9282_MODE_STANDBY 0x00 2214ea315bSMartina Krasteva #define OV9282_MODE_STREAMING 0x01 2314ea315bSMartina Krasteva 2414ea315bSMartina Krasteva /* Lines per frame */ 2514ea315bSMartina Krasteva #define OV9282_REG_LPFR 0x380e 2614ea315bSMartina Krasteva 2714ea315bSMartina Krasteva /* Chip ID */ 2814ea315bSMartina Krasteva #define OV9282_REG_ID 0x300a 2914ea315bSMartina Krasteva #define OV9282_ID 0x9281 3014ea315bSMartina Krasteva 3114ea315bSMartina Krasteva /* Exposure control */ 3214ea315bSMartina Krasteva #define OV9282_REG_EXPOSURE 0x3500 3314ea315bSMartina Krasteva #define OV9282_EXPOSURE_MIN 1 3414ea315bSMartina Krasteva #define OV9282_EXPOSURE_OFFSET 12 3514ea315bSMartina Krasteva #define OV9282_EXPOSURE_STEP 1 3614ea315bSMartina Krasteva #define OV9282_EXPOSURE_DEFAULT 0x0282 3714ea315bSMartina Krasteva 3814ea315bSMartina Krasteva /* Analog gain control */ 3914ea315bSMartina Krasteva #define OV9282_REG_AGAIN 0x3509 4014ea315bSMartina Krasteva #define OV9282_AGAIN_MIN 0x10 4114ea315bSMartina Krasteva #define OV9282_AGAIN_MAX 0xff 4214ea315bSMartina Krasteva #define OV9282_AGAIN_STEP 1 4314ea315bSMartina Krasteva #define OV9282_AGAIN_DEFAULT 0x10 4414ea315bSMartina Krasteva 4514ea315bSMartina Krasteva /* Group hold register */ 4614ea315bSMartina Krasteva #define OV9282_REG_HOLD 0x3308 4714ea315bSMartina Krasteva 4814ea315bSMartina Krasteva /* Input clock rate */ 4914ea315bSMartina Krasteva #define OV9282_INCLK_RATE 24000000 5014ea315bSMartina Krasteva 5114ea315bSMartina Krasteva /* CSI2 HW configuration */ 5214ea315bSMartina Krasteva #define OV9282_LINK_FREQ 400000000 5314ea315bSMartina Krasteva #define OV9282_NUM_DATA_LANES 2 5414ea315bSMartina Krasteva 55f15b0612SDave Stevenson /* Pixel rate */ 56f15b0612SDave Stevenson #define OV9282_PIXEL_RATE (OV9282_LINK_FREQ * 2 * \ 57f15b0612SDave Stevenson OV9282_NUM_DATA_LANES / 10) 58f15b0612SDave Stevenson 5914ea315bSMartina Krasteva #define OV9282_REG_MIN 0x00 6014ea315bSMartina Krasteva #define OV9282_REG_MAX 0xfffff 6114ea315bSMartina Krasteva 6214ea315bSMartina Krasteva /** 6314ea315bSMartina Krasteva * struct ov9282_reg - ov9282 sensor register 6414ea315bSMartina Krasteva * @address: Register address 6514ea315bSMartina Krasteva * @val: Register value 6614ea315bSMartina Krasteva */ 6714ea315bSMartina Krasteva struct ov9282_reg { 6814ea315bSMartina Krasteva u16 address; 6914ea315bSMartina Krasteva u8 val; 7014ea315bSMartina Krasteva }; 7114ea315bSMartina Krasteva 7214ea315bSMartina Krasteva /** 7314ea315bSMartina Krasteva * struct ov9282_reg_list - ov9282 sensor register list 7414ea315bSMartina Krasteva * @num_of_regs: Number of registers in the list 7514ea315bSMartina Krasteva * @regs: Pointer to register list 7614ea315bSMartina Krasteva */ 7714ea315bSMartina Krasteva struct ov9282_reg_list { 7814ea315bSMartina Krasteva u32 num_of_regs; 7914ea315bSMartina Krasteva const struct ov9282_reg *regs; 8014ea315bSMartina Krasteva }; 8114ea315bSMartina Krasteva 8214ea315bSMartina Krasteva /** 8314ea315bSMartina Krasteva * struct ov9282_mode - ov9282 sensor mode structure 8414ea315bSMartina Krasteva * @width: Frame width 8514ea315bSMartina Krasteva * @height: Frame height 8614ea315bSMartina Krasteva * @hblank: Horizontal blanking in lines 8714ea315bSMartina Krasteva * @vblank: Vertical blanking in lines 8814ea315bSMartina Krasteva * @vblank_min: Minimum vertical blanking in lines 8914ea315bSMartina Krasteva * @vblank_max: Maximum vertical blanking in lines 9014ea315bSMartina Krasteva * @link_freq_idx: Link frequency index 9114ea315bSMartina Krasteva * @reg_list: Register list for sensor mode 9214ea315bSMartina Krasteva */ 9314ea315bSMartina Krasteva struct ov9282_mode { 9414ea315bSMartina Krasteva u32 width; 9514ea315bSMartina Krasteva u32 height; 9614ea315bSMartina Krasteva u32 hblank; 9714ea315bSMartina Krasteva u32 vblank; 9814ea315bSMartina Krasteva u32 vblank_min; 9914ea315bSMartina Krasteva u32 vblank_max; 10014ea315bSMartina Krasteva u32 link_freq_idx; 10114ea315bSMartina Krasteva struct ov9282_reg_list reg_list; 10214ea315bSMartina Krasteva }; 10314ea315bSMartina Krasteva 10414ea315bSMartina Krasteva /** 10514ea315bSMartina Krasteva * struct ov9282 - ov9282 sensor device structure 10614ea315bSMartina Krasteva * @dev: Pointer to generic device 10714ea315bSMartina Krasteva * @client: Pointer to i2c client 10814ea315bSMartina Krasteva * @sd: V4L2 sub-device 10914ea315bSMartina Krasteva * @pad: Media pad. Only one pad supported 11014ea315bSMartina Krasteva * @reset_gpio: Sensor reset gpio 11114ea315bSMartina Krasteva * @inclk: Sensor input clock 11214ea315bSMartina Krasteva * @ctrl_handler: V4L2 control handler 11314ea315bSMartina Krasteva * @link_freq_ctrl: Pointer to link frequency control 11414ea315bSMartina Krasteva * @hblank_ctrl: Pointer to horizontal blanking control 11514ea315bSMartina Krasteva * @vblank_ctrl: Pointer to vertical blanking control 11614ea315bSMartina Krasteva * @exp_ctrl: Pointer to exposure control 11714ea315bSMartina Krasteva * @again_ctrl: Pointer to analog gain control 11814ea315bSMartina Krasteva * @vblank: Vertical blanking in lines 11914ea315bSMartina Krasteva * @cur_mode: Pointer to current selected sensor mode 12014ea315bSMartina Krasteva * @mutex: Mutex for serializing sensor controls 12114ea315bSMartina Krasteva * @streaming: Flag indicating streaming state 12214ea315bSMartina Krasteva */ 12314ea315bSMartina Krasteva struct ov9282 { 12414ea315bSMartina Krasteva struct device *dev; 12514ea315bSMartina Krasteva struct i2c_client *client; 12614ea315bSMartina Krasteva struct v4l2_subdev sd; 12714ea315bSMartina Krasteva struct media_pad pad; 12814ea315bSMartina Krasteva struct gpio_desc *reset_gpio; 12914ea315bSMartina Krasteva struct clk *inclk; 13014ea315bSMartina Krasteva struct v4l2_ctrl_handler ctrl_handler; 13114ea315bSMartina Krasteva struct v4l2_ctrl *link_freq_ctrl; 13214ea315bSMartina Krasteva struct v4l2_ctrl *hblank_ctrl; 13314ea315bSMartina Krasteva struct v4l2_ctrl *vblank_ctrl; 13414ea315bSMartina Krasteva struct { 13514ea315bSMartina Krasteva struct v4l2_ctrl *exp_ctrl; 13614ea315bSMartina Krasteva struct v4l2_ctrl *again_ctrl; 13714ea315bSMartina Krasteva }; 13814ea315bSMartina Krasteva u32 vblank; 13914ea315bSMartina Krasteva const struct ov9282_mode *cur_mode; 14014ea315bSMartina Krasteva struct mutex mutex; 14114ea315bSMartina Krasteva bool streaming; 14214ea315bSMartina Krasteva }; 14314ea315bSMartina Krasteva 14414ea315bSMartina Krasteva static const s64 link_freq[] = { 14514ea315bSMartina Krasteva OV9282_LINK_FREQ, 14614ea315bSMartina Krasteva }; 14714ea315bSMartina Krasteva 1487195aabfSDave Stevenson /* Common registers */ 1497195aabfSDave Stevenson static const struct ov9282_reg common_regs[] = { 15014ea315bSMartina Krasteva {0x0302, 0x32}, 15114ea315bSMartina Krasteva {0x030d, 0x50}, 15214ea315bSMartina Krasteva {0x030e, 0x02}, 15314ea315bSMartina Krasteva {0x3001, 0x00}, 15414ea315bSMartina Krasteva {0x3004, 0x00}, 15514ea315bSMartina Krasteva {0x3005, 0x00}, 15614ea315bSMartina Krasteva {0x3006, 0x04}, 15714ea315bSMartina Krasteva {0x3011, 0x0a}, 15814ea315bSMartina Krasteva {0x3013, 0x18}, 15914ea315bSMartina Krasteva {0x301c, 0xf0}, 16014ea315bSMartina Krasteva {0x3022, 0x01}, 16114ea315bSMartina Krasteva {0x3030, 0x10}, 16214ea315bSMartina Krasteva {0x3039, 0x32}, 16314ea315bSMartina Krasteva {0x303a, 0x00}, 16414ea315bSMartina Krasteva {0x3503, 0x08}, 16514ea315bSMartina Krasteva {0x3505, 0x8c}, 16614ea315bSMartina Krasteva {0x3507, 0x03}, 16714ea315bSMartina Krasteva {0x3508, 0x00}, 16814ea315bSMartina Krasteva {0x3610, 0x80}, 16914ea315bSMartina Krasteva {0x3611, 0xa0}, 17014ea315bSMartina Krasteva {0x3620, 0x6e}, 17114ea315bSMartina Krasteva {0x3632, 0x56}, 17214ea315bSMartina Krasteva {0x3633, 0x78}, 17314ea315bSMartina Krasteva {0x3666, 0x00}, 17414ea315bSMartina Krasteva {0x366f, 0x5a}, 17514ea315bSMartina Krasteva {0x3680, 0x84}, 17614ea315bSMartina Krasteva {0x3712, 0x80}, 17714ea315bSMartina Krasteva {0x372d, 0x22}, 17814ea315bSMartina Krasteva {0x3731, 0x80}, 17914ea315bSMartina Krasteva {0x3732, 0x30}, 18014ea315bSMartina Krasteva {0x377d, 0x22}, 18114ea315bSMartina Krasteva {0x3788, 0x02}, 18214ea315bSMartina Krasteva {0x3789, 0xa4}, 18314ea315bSMartina Krasteva {0x378a, 0x00}, 18414ea315bSMartina Krasteva {0x378b, 0x4a}, 18514ea315bSMartina Krasteva {0x3799, 0x20}, 1867195aabfSDave Stevenson {0x3881, 0x42}, 1877195aabfSDave Stevenson {0x38a8, 0x02}, 1887195aabfSDave Stevenson {0x38a9, 0x80}, 1897195aabfSDave Stevenson {0x38b1, 0x00}, 1907195aabfSDave Stevenson {0x38c4, 0x00}, 1917195aabfSDave Stevenson {0x38c5, 0xc0}, 1927195aabfSDave Stevenson {0x38c6, 0x04}, 1937195aabfSDave Stevenson {0x38c7, 0x80}, 1947195aabfSDave Stevenson {0x3920, 0xff}, 1957195aabfSDave Stevenson {0x4010, 0x40}, 1967195aabfSDave Stevenson {0x4043, 0x40}, 1977195aabfSDave Stevenson {0x4307, 0x30}, 1987195aabfSDave Stevenson {0x4317, 0x00}, 1997195aabfSDave Stevenson {0x4501, 0x00}, 2007195aabfSDave Stevenson {0x450a, 0x08}, 2017195aabfSDave Stevenson {0x4601, 0x04}, 2027195aabfSDave Stevenson {0x470f, 0x00}, 2037195aabfSDave Stevenson {0x4f07, 0x00}, 2047195aabfSDave Stevenson {0x4800, 0x20}, 2057195aabfSDave Stevenson {0x5000, 0x9f}, 2067195aabfSDave Stevenson {0x5001, 0x00}, 2077195aabfSDave Stevenson {0x5e00, 0x00}, 2087195aabfSDave Stevenson {0x5d00, 0x07}, 2097195aabfSDave Stevenson {0x5d01, 0x00}, 2107195aabfSDave Stevenson {0x0101, 0x01}, 2117195aabfSDave Stevenson {0x1000, 0x03}, 2127195aabfSDave Stevenson {0x5a08, 0x84}, 2137195aabfSDave Stevenson }; 2147195aabfSDave Stevenson 2157195aabfSDave Stevenson struct ov9282_reg_list common_regs_list = { 2167195aabfSDave Stevenson .num_of_regs = ARRAY_SIZE(common_regs), 2177195aabfSDave Stevenson .regs = common_regs, 2187195aabfSDave Stevenson }; 2197195aabfSDave Stevenson 220*995809ceSDave Stevenson #define MODE_1280_720 0 221*995809ceSDave Stevenson 222*995809ceSDave Stevenson #define DEFAULT_MODE MODE_1280_720 223*995809ceSDave Stevenson 2247195aabfSDave Stevenson /* Sensor mode registers */ 2257195aabfSDave Stevenson static const struct ov9282_reg mode_1280x720_regs[] = { 2267195aabfSDave Stevenson {0x3778, 0x00}, 22714ea315bSMartina Krasteva {0x3800, 0x00}, 22814ea315bSMartina Krasteva {0x3801, 0x00}, 22914ea315bSMartina Krasteva {0x3802, 0x00}, 23014ea315bSMartina Krasteva {0x3803, 0x00}, 23114ea315bSMartina Krasteva {0x3804, 0x05}, 23214ea315bSMartina Krasteva {0x3805, 0x0f}, 23314ea315bSMartina Krasteva {0x3806, 0x02}, 23414ea315bSMartina Krasteva {0x3807, 0xdf}, 23514ea315bSMartina Krasteva {0x3808, 0x05}, 23614ea315bSMartina Krasteva {0x3809, 0x00}, 23714ea315bSMartina Krasteva {0x380a, 0x02}, 23814ea315bSMartina Krasteva {0x380b, 0xd0}, 23914ea315bSMartina Krasteva {0x380c, 0x05}, 24014ea315bSMartina Krasteva {0x380d, 0xfa}, 24114ea315bSMartina Krasteva {0x3810, 0x00}, 24214ea315bSMartina Krasteva {0x3811, 0x08}, 24314ea315bSMartina Krasteva {0x3812, 0x00}, 24414ea315bSMartina Krasteva {0x3813, 0x08}, 24514ea315bSMartina Krasteva {0x3814, 0x11}, 24614ea315bSMartina Krasteva {0x3815, 0x11}, 24714ea315bSMartina Krasteva {0x3820, 0x3c}, 24814ea315bSMartina Krasteva {0x3821, 0x84}, 24914ea315bSMartina Krasteva {0x4003, 0x40}, 25014ea315bSMartina Krasteva {0x4008, 0x02}, 25114ea315bSMartina Krasteva {0x4009, 0x05}, 25214ea315bSMartina Krasteva {0x400c, 0x00}, 25314ea315bSMartina Krasteva {0x400d, 0x03}, 25414ea315bSMartina Krasteva {0x4507, 0x00}, 25514ea315bSMartina Krasteva {0x4509, 0x80}, 25614ea315bSMartina Krasteva }; 25714ea315bSMartina Krasteva 25814ea315bSMartina Krasteva /* Supported sensor mode configurations */ 259*995809ceSDave Stevenson static const struct ov9282_mode supported_modes[] = { 260*995809ceSDave Stevenson [MODE_1280_720] = { 26114ea315bSMartina Krasteva .width = 1280, 26214ea315bSMartina Krasteva .height = 720, 26314ea315bSMartina Krasteva .hblank = 250, 26414ea315bSMartina Krasteva .vblank = 1022, 26514ea315bSMartina Krasteva .vblank_min = 151, 26614ea315bSMartina Krasteva .vblank_max = 51540, 26714ea315bSMartina Krasteva .link_freq_idx = 0, 26814ea315bSMartina Krasteva .reg_list = { 26914ea315bSMartina Krasteva .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), 27014ea315bSMartina Krasteva .regs = mode_1280x720_regs, 27114ea315bSMartina Krasteva }, 272*995809ceSDave Stevenson }, 27314ea315bSMartina Krasteva }; 27414ea315bSMartina Krasteva 27514ea315bSMartina Krasteva /** 27614ea315bSMartina Krasteva * to_ov9282() - ov9282 V4L2 sub-device to ov9282 device. 27714ea315bSMartina Krasteva * @subdev: pointer to ov9282 V4L2 sub-device 27814ea315bSMartina Krasteva * 27914ea315bSMartina Krasteva * Return: pointer to ov9282 device 28014ea315bSMartina Krasteva */ 28114ea315bSMartina Krasteva static inline struct ov9282 *to_ov9282(struct v4l2_subdev *subdev) 28214ea315bSMartina Krasteva { 28314ea315bSMartina Krasteva return container_of(subdev, struct ov9282, sd); 28414ea315bSMartina Krasteva } 28514ea315bSMartina Krasteva 28614ea315bSMartina Krasteva /** 28714ea315bSMartina Krasteva * ov9282_read_reg() - Read registers. 28814ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 28914ea315bSMartina Krasteva * @reg: register address 29014ea315bSMartina Krasteva * @len: length of bytes to read. Max supported bytes is 4 29114ea315bSMartina Krasteva * @val: pointer to register value to be filled. 29214ea315bSMartina Krasteva * 29314ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 29414ea315bSMartina Krasteva */ 29514ea315bSMartina Krasteva static int ov9282_read_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 *val) 29614ea315bSMartina Krasteva { 29714ea315bSMartina Krasteva struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); 29814ea315bSMartina Krasteva struct i2c_msg msgs[2] = {0}; 29914ea315bSMartina Krasteva u8 addr_buf[2] = {0}; 30014ea315bSMartina Krasteva u8 data_buf[4] = {0}; 30114ea315bSMartina Krasteva int ret; 30214ea315bSMartina Krasteva 30314ea315bSMartina Krasteva if (WARN_ON(len > 4)) 30414ea315bSMartina Krasteva return -EINVAL; 30514ea315bSMartina Krasteva 30614ea315bSMartina Krasteva put_unaligned_be16(reg, addr_buf); 30714ea315bSMartina Krasteva 30814ea315bSMartina Krasteva /* Write register address */ 30914ea315bSMartina Krasteva msgs[0].addr = client->addr; 31014ea315bSMartina Krasteva msgs[0].flags = 0; 31114ea315bSMartina Krasteva msgs[0].len = ARRAY_SIZE(addr_buf); 31214ea315bSMartina Krasteva msgs[0].buf = addr_buf; 31314ea315bSMartina Krasteva 31414ea315bSMartina Krasteva /* Read data from register */ 31514ea315bSMartina Krasteva msgs[1].addr = client->addr; 31614ea315bSMartina Krasteva msgs[1].flags = I2C_M_RD; 31714ea315bSMartina Krasteva msgs[1].len = len; 31814ea315bSMartina Krasteva msgs[1].buf = &data_buf[4 - len]; 31914ea315bSMartina Krasteva 32014ea315bSMartina Krasteva ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 32114ea315bSMartina Krasteva if (ret != ARRAY_SIZE(msgs)) 32214ea315bSMartina Krasteva return -EIO; 32314ea315bSMartina Krasteva 32414ea315bSMartina Krasteva *val = get_unaligned_be32(data_buf); 32514ea315bSMartina Krasteva 32614ea315bSMartina Krasteva return 0; 32714ea315bSMartina Krasteva } 32814ea315bSMartina Krasteva 32914ea315bSMartina Krasteva /** 33014ea315bSMartina Krasteva * ov9282_write_reg() - Write register 33114ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 33214ea315bSMartina Krasteva * @reg: register address 33314ea315bSMartina Krasteva * @len: length of bytes. Max supported bytes is 4 33414ea315bSMartina Krasteva * @val: register value 33514ea315bSMartina Krasteva * 33614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 33714ea315bSMartina Krasteva */ 33814ea315bSMartina Krasteva static int ov9282_write_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 val) 33914ea315bSMartina Krasteva { 34014ea315bSMartina Krasteva struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); 34114ea315bSMartina Krasteva u8 buf[6] = {0}; 34214ea315bSMartina Krasteva 34314ea315bSMartina Krasteva if (WARN_ON(len > 4)) 34414ea315bSMartina Krasteva return -EINVAL; 34514ea315bSMartina Krasteva 34614ea315bSMartina Krasteva put_unaligned_be16(reg, buf); 34714ea315bSMartina Krasteva put_unaligned_be32(val << (8 * (4 - len)), buf + 2); 34814ea315bSMartina Krasteva if (i2c_master_send(client, buf, len + 2) != len + 2) 34914ea315bSMartina Krasteva return -EIO; 35014ea315bSMartina Krasteva 35114ea315bSMartina Krasteva return 0; 35214ea315bSMartina Krasteva } 35314ea315bSMartina Krasteva 35414ea315bSMartina Krasteva /** 35514ea315bSMartina Krasteva * ov9282_write_regs() - Write a list of registers 35614ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 35714ea315bSMartina Krasteva * @regs: list of registers to be written 35814ea315bSMartina Krasteva * @len: length of registers array 35914ea315bSMartina Krasteva * 36014ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 36114ea315bSMartina Krasteva */ 36214ea315bSMartina Krasteva static int ov9282_write_regs(struct ov9282 *ov9282, 36314ea315bSMartina Krasteva const struct ov9282_reg *regs, u32 len) 36414ea315bSMartina Krasteva { 36514ea315bSMartina Krasteva unsigned int i; 36614ea315bSMartina Krasteva int ret; 36714ea315bSMartina Krasteva 36814ea315bSMartina Krasteva for (i = 0; i < len; i++) { 36914ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, regs[i].address, 1, regs[i].val); 37014ea315bSMartina Krasteva if (ret) 37114ea315bSMartina Krasteva return ret; 37214ea315bSMartina Krasteva } 37314ea315bSMartina Krasteva 37414ea315bSMartina Krasteva return 0; 37514ea315bSMartina Krasteva } 37614ea315bSMartina Krasteva 37714ea315bSMartina Krasteva /** 37814ea315bSMartina Krasteva * ov9282_update_controls() - Update control ranges based on streaming mode 37914ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 38014ea315bSMartina Krasteva * @mode: pointer to ov9282_mode sensor mode 38114ea315bSMartina Krasteva * 38214ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 38314ea315bSMartina Krasteva */ 38414ea315bSMartina Krasteva static int ov9282_update_controls(struct ov9282 *ov9282, 38514ea315bSMartina Krasteva const struct ov9282_mode *mode) 38614ea315bSMartina Krasteva { 38714ea315bSMartina Krasteva int ret; 38814ea315bSMartina Krasteva 38914ea315bSMartina Krasteva ret = __v4l2_ctrl_s_ctrl(ov9282->link_freq_ctrl, mode->link_freq_idx); 39014ea315bSMartina Krasteva if (ret) 39114ea315bSMartina Krasteva return ret; 39214ea315bSMartina Krasteva 39314ea315bSMartina Krasteva ret = __v4l2_ctrl_s_ctrl(ov9282->hblank_ctrl, mode->hblank); 39414ea315bSMartina Krasteva if (ret) 39514ea315bSMartina Krasteva return ret; 39614ea315bSMartina Krasteva 39714ea315bSMartina Krasteva return __v4l2_ctrl_modify_range(ov9282->vblank_ctrl, mode->vblank_min, 39814ea315bSMartina Krasteva mode->vblank_max, 1, mode->vblank); 39914ea315bSMartina Krasteva } 40014ea315bSMartina Krasteva 40114ea315bSMartina Krasteva /** 40214ea315bSMartina Krasteva * ov9282_update_exp_gain() - Set updated exposure and gain 40314ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 40414ea315bSMartina Krasteva * @exposure: updated exposure value 40514ea315bSMartina Krasteva * @gain: updated analog gain value 40614ea315bSMartina Krasteva * 40714ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 40814ea315bSMartina Krasteva */ 40914ea315bSMartina Krasteva static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain) 41014ea315bSMartina Krasteva { 41114ea315bSMartina Krasteva u32 lpfr; 41214ea315bSMartina Krasteva int ret; 41314ea315bSMartina Krasteva 41414ea315bSMartina Krasteva lpfr = ov9282->vblank + ov9282->cur_mode->height; 41514ea315bSMartina Krasteva 41614ea315bSMartina Krasteva dev_dbg(ov9282->dev, "Set exp %u, analog gain %u, lpfr %u", 41714ea315bSMartina Krasteva exposure, gain, lpfr); 41814ea315bSMartina Krasteva 41914ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1); 42014ea315bSMartina Krasteva if (ret) 42114ea315bSMartina Krasteva return ret; 42214ea315bSMartina Krasteva 42314ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr); 42414ea315bSMartina Krasteva if (ret) 42514ea315bSMartina Krasteva goto error_release_group_hold; 42614ea315bSMartina Krasteva 42714ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, OV9282_REG_EXPOSURE, 3, exposure << 4); 42814ea315bSMartina Krasteva if (ret) 42914ea315bSMartina Krasteva goto error_release_group_hold; 43014ea315bSMartina Krasteva 43114ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, OV9282_REG_AGAIN, 1, gain); 43214ea315bSMartina Krasteva 43314ea315bSMartina Krasteva error_release_group_hold: 43414ea315bSMartina Krasteva ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 0); 43514ea315bSMartina Krasteva 43614ea315bSMartina Krasteva return ret; 43714ea315bSMartina Krasteva } 43814ea315bSMartina Krasteva 43914ea315bSMartina Krasteva /** 44014ea315bSMartina Krasteva * ov9282_set_ctrl() - Set subdevice control 44114ea315bSMartina Krasteva * @ctrl: pointer to v4l2_ctrl structure 44214ea315bSMartina Krasteva * 44314ea315bSMartina Krasteva * Supported controls: 44414ea315bSMartina Krasteva * - V4L2_CID_VBLANK 44514ea315bSMartina Krasteva * - cluster controls: 44614ea315bSMartina Krasteva * - V4L2_CID_ANALOGUE_GAIN 44714ea315bSMartina Krasteva * - V4L2_CID_EXPOSURE 44814ea315bSMartina Krasteva * 44914ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 45014ea315bSMartina Krasteva */ 45114ea315bSMartina Krasteva static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) 45214ea315bSMartina Krasteva { 45314ea315bSMartina Krasteva struct ov9282 *ov9282 = 45414ea315bSMartina Krasteva container_of(ctrl->handler, struct ov9282, ctrl_handler); 45514ea315bSMartina Krasteva u32 analog_gain; 45614ea315bSMartina Krasteva u32 exposure; 45714ea315bSMartina Krasteva int ret; 45814ea315bSMartina Krasteva 45914ea315bSMartina Krasteva switch (ctrl->id) { 46014ea315bSMartina Krasteva case V4L2_CID_VBLANK: 46114ea315bSMartina Krasteva ov9282->vblank = ov9282->vblank_ctrl->val; 46214ea315bSMartina Krasteva 46314ea315bSMartina Krasteva dev_dbg(ov9282->dev, "Received vblank %u, new lpfr %u", 46414ea315bSMartina Krasteva ov9282->vblank, 46514ea315bSMartina Krasteva ov9282->vblank + ov9282->cur_mode->height); 46614ea315bSMartina Krasteva 46714ea315bSMartina Krasteva ret = __v4l2_ctrl_modify_range(ov9282->exp_ctrl, 46814ea315bSMartina Krasteva OV9282_EXPOSURE_MIN, 46914ea315bSMartina Krasteva ov9282->vblank + 47014ea315bSMartina Krasteva ov9282->cur_mode->height - 47114ea315bSMartina Krasteva OV9282_EXPOSURE_OFFSET, 47214ea315bSMartina Krasteva 1, OV9282_EXPOSURE_DEFAULT); 47314ea315bSMartina Krasteva break; 47414ea315bSMartina Krasteva case V4L2_CID_EXPOSURE: 47514ea315bSMartina Krasteva /* Set controls only if sensor is in power on state */ 47614ea315bSMartina Krasteva if (!pm_runtime_get_if_in_use(ov9282->dev)) 47714ea315bSMartina Krasteva return 0; 47814ea315bSMartina Krasteva 47914ea315bSMartina Krasteva exposure = ctrl->val; 48014ea315bSMartina Krasteva analog_gain = ov9282->again_ctrl->val; 48114ea315bSMartina Krasteva 48214ea315bSMartina Krasteva dev_dbg(ov9282->dev, "Received exp %u, analog gain %u", 48314ea315bSMartina Krasteva exposure, analog_gain); 48414ea315bSMartina Krasteva 48514ea315bSMartina Krasteva ret = ov9282_update_exp_gain(ov9282, exposure, analog_gain); 48614ea315bSMartina Krasteva 48714ea315bSMartina Krasteva pm_runtime_put(ov9282->dev); 48814ea315bSMartina Krasteva 48914ea315bSMartina Krasteva break; 49014ea315bSMartina Krasteva default: 49114ea315bSMartina Krasteva dev_err(ov9282->dev, "Invalid control %d", ctrl->id); 49214ea315bSMartina Krasteva ret = -EINVAL; 49314ea315bSMartina Krasteva } 49414ea315bSMartina Krasteva 49514ea315bSMartina Krasteva return ret; 49614ea315bSMartina Krasteva } 49714ea315bSMartina Krasteva 49814ea315bSMartina Krasteva /* V4l2 subdevice control ops*/ 49914ea315bSMartina Krasteva static const struct v4l2_ctrl_ops ov9282_ctrl_ops = { 50014ea315bSMartina Krasteva .s_ctrl = ov9282_set_ctrl, 50114ea315bSMartina Krasteva }; 50214ea315bSMartina Krasteva 50314ea315bSMartina Krasteva /** 50414ea315bSMartina Krasteva * ov9282_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes 50514ea315bSMartina Krasteva * @sd: pointer to ov9282 V4L2 sub-device structure 50614ea315bSMartina Krasteva * @sd_state: V4L2 sub-device configuration 50714ea315bSMartina Krasteva * @code: V4L2 sub-device code enumeration need to be filled 50814ea315bSMartina Krasteva * 50914ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 51014ea315bSMartina Krasteva */ 51114ea315bSMartina Krasteva static int ov9282_enum_mbus_code(struct v4l2_subdev *sd, 51214ea315bSMartina Krasteva struct v4l2_subdev_state *sd_state, 51314ea315bSMartina Krasteva struct v4l2_subdev_mbus_code_enum *code) 51414ea315bSMartina Krasteva { 51514ea315bSMartina Krasteva if (code->index > 0) 51614ea315bSMartina Krasteva return -EINVAL; 51714ea315bSMartina Krasteva 518bf3c4a5bSDave Stevenson code->code = MEDIA_BUS_FMT_Y10_1X10; 51914ea315bSMartina Krasteva 52014ea315bSMartina Krasteva return 0; 52114ea315bSMartina Krasteva } 52214ea315bSMartina Krasteva 52314ea315bSMartina Krasteva /** 52414ea315bSMartina Krasteva * ov9282_enum_frame_size() - Enumerate V4L2 sub-device frame sizes 52514ea315bSMartina Krasteva * @sd: pointer to ov9282 V4L2 sub-device structure 52614ea315bSMartina Krasteva * @sd_state: V4L2 sub-device configuration 52714ea315bSMartina Krasteva * @fsize: V4L2 sub-device size enumeration need to be filled 52814ea315bSMartina Krasteva * 52914ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 53014ea315bSMartina Krasteva */ 53114ea315bSMartina Krasteva static int ov9282_enum_frame_size(struct v4l2_subdev *sd, 53214ea315bSMartina Krasteva struct v4l2_subdev_state *sd_state, 53314ea315bSMartina Krasteva struct v4l2_subdev_frame_size_enum *fsize) 53414ea315bSMartina Krasteva { 535*995809ceSDave Stevenson if (fsize->index >= ARRAY_SIZE(supported_modes)) 53614ea315bSMartina Krasteva return -EINVAL; 53714ea315bSMartina Krasteva 538bf3c4a5bSDave Stevenson if (fsize->code != MEDIA_BUS_FMT_Y10_1X10) 53914ea315bSMartina Krasteva return -EINVAL; 54014ea315bSMartina Krasteva 541*995809ceSDave Stevenson fsize->min_width = supported_modes[fsize->index].width; 54214ea315bSMartina Krasteva fsize->max_width = fsize->min_width; 543*995809ceSDave Stevenson fsize->min_height = supported_modes[fsize->index].height; 54414ea315bSMartina Krasteva fsize->max_height = fsize->min_height; 54514ea315bSMartina Krasteva 54614ea315bSMartina Krasteva return 0; 54714ea315bSMartina Krasteva } 54814ea315bSMartina Krasteva 54914ea315bSMartina Krasteva /** 55014ea315bSMartina Krasteva * ov9282_fill_pad_format() - Fill subdevice pad format 55114ea315bSMartina Krasteva * from selected sensor mode 55214ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 55314ea315bSMartina Krasteva * @mode: pointer to ov9282_mode sensor mode 55414ea315bSMartina Krasteva * @fmt: V4L2 sub-device format need to be filled 55514ea315bSMartina Krasteva */ 55614ea315bSMartina Krasteva static void ov9282_fill_pad_format(struct ov9282 *ov9282, 55714ea315bSMartina Krasteva const struct ov9282_mode *mode, 55814ea315bSMartina Krasteva struct v4l2_subdev_format *fmt) 55914ea315bSMartina Krasteva { 56014ea315bSMartina Krasteva fmt->format.width = mode->width; 56114ea315bSMartina Krasteva fmt->format.height = mode->height; 562bf3c4a5bSDave Stevenson fmt->format.code = MEDIA_BUS_FMT_Y10_1X10; 56314ea315bSMartina Krasteva fmt->format.field = V4L2_FIELD_NONE; 56414ea315bSMartina Krasteva fmt->format.colorspace = V4L2_COLORSPACE_RAW; 56514ea315bSMartina Krasteva fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 56614ea315bSMartina Krasteva fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; 56714ea315bSMartina Krasteva fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; 56814ea315bSMartina Krasteva } 56914ea315bSMartina Krasteva 57014ea315bSMartina Krasteva /** 57114ea315bSMartina Krasteva * ov9282_get_pad_format() - Get subdevice pad format 57214ea315bSMartina Krasteva * @sd: pointer to ov9282 V4L2 sub-device structure 57314ea315bSMartina Krasteva * @sd_state: V4L2 sub-device configuration 57414ea315bSMartina Krasteva * @fmt: V4L2 sub-device format need to be set 57514ea315bSMartina Krasteva * 57614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 57714ea315bSMartina Krasteva */ 57814ea315bSMartina Krasteva static int ov9282_get_pad_format(struct v4l2_subdev *sd, 57914ea315bSMartina Krasteva struct v4l2_subdev_state *sd_state, 58014ea315bSMartina Krasteva struct v4l2_subdev_format *fmt) 58114ea315bSMartina Krasteva { 58214ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 58314ea315bSMartina Krasteva 58414ea315bSMartina Krasteva mutex_lock(&ov9282->mutex); 58514ea315bSMartina Krasteva 58614ea315bSMartina Krasteva if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 58714ea315bSMartina Krasteva struct v4l2_mbus_framefmt *framefmt; 58814ea315bSMartina Krasteva 58914ea315bSMartina Krasteva framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 59014ea315bSMartina Krasteva fmt->format = *framefmt; 59114ea315bSMartina Krasteva } else { 59214ea315bSMartina Krasteva ov9282_fill_pad_format(ov9282, ov9282->cur_mode, fmt); 59314ea315bSMartina Krasteva } 59414ea315bSMartina Krasteva 59514ea315bSMartina Krasteva mutex_unlock(&ov9282->mutex); 59614ea315bSMartina Krasteva 59714ea315bSMartina Krasteva return 0; 59814ea315bSMartina Krasteva } 59914ea315bSMartina Krasteva 60014ea315bSMartina Krasteva /** 60114ea315bSMartina Krasteva * ov9282_set_pad_format() - Set subdevice pad format 60214ea315bSMartina Krasteva * @sd: pointer to ov9282 V4L2 sub-device structure 60314ea315bSMartina Krasteva * @sd_state: V4L2 sub-device configuration 60414ea315bSMartina Krasteva * @fmt: V4L2 sub-device format need to be set 60514ea315bSMartina Krasteva * 60614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 60714ea315bSMartina Krasteva */ 60814ea315bSMartina Krasteva static int ov9282_set_pad_format(struct v4l2_subdev *sd, 60914ea315bSMartina Krasteva struct v4l2_subdev_state *sd_state, 61014ea315bSMartina Krasteva struct v4l2_subdev_format *fmt) 61114ea315bSMartina Krasteva { 61214ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 61314ea315bSMartina Krasteva const struct ov9282_mode *mode; 61414ea315bSMartina Krasteva int ret = 0; 61514ea315bSMartina Krasteva 61614ea315bSMartina Krasteva mutex_lock(&ov9282->mutex); 61714ea315bSMartina Krasteva 618*995809ceSDave Stevenson mode = v4l2_find_nearest_size(supported_modes, 619*995809ceSDave Stevenson ARRAY_SIZE(supported_modes), 620*995809ceSDave Stevenson width, height, 621*995809ceSDave Stevenson fmt->format.width, 622*995809ceSDave Stevenson fmt->format.height); 62314ea315bSMartina Krasteva ov9282_fill_pad_format(ov9282, mode, fmt); 62414ea315bSMartina Krasteva 62514ea315bSMartina Krasteva if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 62614ea315bSMartina Krasteva struct v4l2_mbus_framefmt *framefmt; 62714ea315bSMartina Krasteva 62814ea315bSMartina Krasteva framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 62914ea315bSMartina Krasteva *framefmt = fmt->format; 63014ea315bSMartina Krasteva } else { 63114ea315bSMartina Krasteva ret = ov9282_update_controls(ov9282, mode); 63214ea315bSMartina Krasteva if (!ret) 63314ea315bSMartina Krasteva ov9282->cur_mode = mode; 63414ea315bSMartina Krasteva } 63514ea315bSMartina Krasteva 63614ea315bSMartina Krasteva mutex_unlock(&ov9282->mutex); 63714ea315bSMartina Krasteva 63814ea315bSMartina Krasteva return ret; 63914ea315bSMartina Krasteva } 64014ea315bSMartina Krasteva 64114ea315bSMartina Krasteva /** 64214ea315bSMartina Krasteva * ov9282_init_pad_cfg() - Initialize sub-device pad configuration 64314ea315bSMartina Krasteva * @sd: pointer to ov9282 V4L2 sub-device structure 64414ea315bSMartina Krasteva * @sd_state: V4L2 sub-device configuration 64514ea315bSMartina Krasteva * 64614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 64714ea315bSMartina Krasteva */ 64814ea315bSMartina Krasteva static int ov9282_init_pad_cfg(struct v4l2_subdev *sd, 64914ea315bSMartina Krasteva struct v4l2_subdev_state *sd_state) 65014ea315bSMartina Krasteva { 65114ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 65214ea315bSMartina Krasteva struct v4l2_subdev_format fmt = { 0 }; 65314ea315bSMartina Krasteva 65414ea315bSMartina Krasteva fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 655*995809ceSDave Stevenson ov9282_fill_pad_format(ov9282, &supported_modes[DEFAULT_MODE], &fmt); 65614ea315bSMartina Krasteva 65714ea315bSMartina Krasteva return ov9282_set_pad_format(sd, sd_state, &fmt); 65814ea315bSMartina Krasteva } 65914ea315bSMartina Krasteva 66014ea315bSMartina Krasteva /** 66114ea315bSMartina Krasteva * ov9282_start_streaming() - Start sensor stream 66214ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 66314ea315bSMartina Krasteva * 66414ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 66514ea315bSMartina Krasteva */ 66614ea315bSMartina Krasteva static int ov9282_start_streaming(struct ov9282 *ov9282) 66714ea315bSMartina Krasteva { 66814ea315bSMartina Krasteva const struct ov9282_reg_list *reg_list; 66914ea315bSMartina Krasteva int ret; 67014ea315bSMartina Krasteva 6717195aabfSDave Stevenson /* Write common registers */ 6727195aabfSDave Stevenson ret = ov9282_write_regs(ov9282, common_regs_list.regs, 6737195aabfSDave Stevenson common_regs_list.num_of_regs); 6747195aabfSDave Stevenson if (ret) { 6757195aabfSDave Stevenson dev_err(ov9282->dev, "fail to write common registers"); 6767195aabfSDave Stevenson return ret; 6777195aabfSDave Stevenson } 6787195aabfSDave Stevenson 67914ea315bSMartina Krasteva /* Write sensor mode registers */ 68014ea315bSMartina Krasteva reg_list = &ov9282->cur_mode->reg_list; 68114ea315bSMartina Krasteva ret = ov9282_write_regs(ov9282, reg_list->regs, reg_list->num_of_regs); 68214ea315bSMartina Krasteva if (ret) { 68314ea315bSMartina Krasteva dev_err(ov9282->dev, "fail to write initial registers"); 68414ea315bSMartina Krasteva return ret; 68514ea315bSMartina Krasteva } 68614ea315bSMartina Krasteva 68714ea315bSMartina Krasteva /* Setup handler will write actual exposure and gain */ 68814ea315bSMartina Krasteva ret = __v4l2_ctrl_handler_setup(ov9282->sd.ctrl_handler); 68914ea315bSMartina Krasteva if (ret) { 69014ea315bSMartina Krasteva dev_err(ov9282->dev, "fail to setup handler"); 69114ea315bSMartina Krasteva return ret; 69214ea315bSMartina Krasteva } 69314ea315bSMartina Krasteva 69414ea315bSMartina Krasteva /* Start streaming */ 69514ea315bSMartina Krasteva ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, 69614ea315bSMartina Krasteva 1, OV9282_MODE_STREAMING); 69714ea315bSMartina Krasteva if (ret) { 69814ea315bSMartina Krasteva dev_err(ov9282->dev, "fail to start streaming"); 69914ea315bSMartina Krasteva return ret; 70014ea315bSMartina Krasteva } 70114ea315bSMartina Krasteva 70214ea315bSMartina Krasteva return 0; 70314ea315bSMartina Krasteva } 70414ea315bSMartina Krasteva 70514ea315bSMartina Krasteva /** 70614ea315bSMartina Krasteva * ov9282_stop_streaming() - Stop sensor stream 70714ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 70814ea315bSMartina Krasteva * 70914ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 71014ea315bSMartina Krasteva */ 71114ea315bSMartina Krasteva static int ov9282_stop_streaming(struct ov9282 *ov9282) 71214ea315bSMartina Krasteva { 71314ea315bSMartina Krasteva return ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, 71414ea315bSMartina Krasteva 1, OV9282_MODE_STANDBY); 71514ea315bSMartina Krasteva } 71614ea315bSMartina Krasteva 71714ea315bSMartina Krasteva /** 71814ea315bSMartina Krasteva * ov9282_set_stream() - Enable sensor streaming 71914ea315bSMartina Krasteva * @sd: pointer to ov9282 subdevice 72014ea315bSMartina Krasteva * @enable: set to enable sensor streaming 72114ea315bSMartina Krasteva * 72214ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 72314ea315bSMartina Krasteva */ 72414ea315bSMartina Krasteva static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) 72514ea315bSMartina Krasteva { 72614ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 72714ea315bSMartina Krasteva int ret; 72814ea315bSMartina Krasteva 72914ea315bSMartina Krasteva mutex_lock(&ov9282->mutex); 73014ea315bSMartina Krasteva 73114ea315bSMartina Krasteva if (ov9282->streaming == enable) { 73214ea315bSMartina Krasteva mutex_unlock(&ov9282->mutex); 73314ea315bSMartina Krasteva return 0; 73414ea315bSMartina Krasteva } 73514ea315bSMartina Krasteva 73614ea315bSMartina Krasteva if (enable) { 73714ea315bSMartina Krasteva ret = pm_runtime_resume_and_get(ov9282->dev); 73814ea315bSMartina Krasteva if (ret) 73914ea315bSMartina Krasteva goto error_unlock; 74014ea315bSMartina Krasteva 74114ea315bSMartina Krasteva ret = ov9282_start_streaming(ov9282); 74214ea315bSMartina Krasteva if (ret) 74314ea315bSMartina Krasteva goto error_power_off; 74414ea315bSMartina Krasteva } else { 74514ea315bSMartina Krasteva ov9282_stop_streaming(ov9282); 74614ea315bSMartina Krasteva pm_runtime_put(ov9282->dev); 74714ea315bSMartina Krasteva } 74814ea315bSMartina Krasteva 74914ea315bSMartina Krasteva ov9282->streaming = enable; 75014ea315bSMartina Krasteva 75114ea315bSMartina Krasteva mutex_unlock(&ov9282->mutex); 75214ea315bSMartina Krasteva 75314ea315bSMartina Krasteva return 0; 75414ea315bSMartina Krasteva 75514ea315bSMartina Krasteva error_power_off: 75614ea315bSMartina Krasteva pm_runtime_put(ov9282->dev); 75714ea315bSMartina Krasteva error_unlock: 75814ea315bSMartina Krasteva mutex_unlock(&ov9282->mutex); 75914ea315bSMartina Krasteva 76014ea315bSMartina Krasteva return ret; 76114ea315bSMartina Krasteva } 76214ea315bSMartina Krasteva 76314ea315bSMartina Krasteva /** 76414ea315bSMartina Krasteva * ov9282_detect() - Detect ov9282 sensor 76514ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 76614ea315bSMartina Krasteva * 76714ea315bSMartina Krasteva * Return: 0 if successful, -EIO if sensor id does not match 76814ea315bSMartina Krasteva */ 76914ea315bSMartina Krasteva static int ov9282_detect(struct ov9282 *ov9282) 77014ea315bSMartina Krasteva { 77114ea315bSMartina Krasteva int ret; 77214ea315bSMartina Krasteva u32 val; 77314ea315bSMartina Krasteva 77414ea315bSMartina Krasteva ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 2, &val); 77514ea315bSMartina Krasteva if (ret) 77614ea315bSMartina Krasteva return ret; 77714ea315bSMartina Krasteva 77814ea315bSMartina Krasteva if (val != OV9282_ID) { 77914ea315bSMartina Krasteva dev_err(ov9282->dev, "chip id mismatch: %x!=%x", 78014ea315bSMartina Krasteva OV9282_ID, val); 78114ea315bSMartina Krasteva return -ENXIO; 78214ea315bSMartina Krasteva } 78314ea315bSMartina Krasteva 78414ea315bSMartina Krasteva return 0; 78514ea315bSMartina Krasteva } 78614ea315bSMartina Krasteva 78714ea315bSMartina Krasteva /** 78814ea315bSMartina Krasteva * ov9282_parse_hw_config() - Parse HW configuration and check if supported 78914ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 79014ea315bSMartina Krasteva * 79114ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 79214ea315bSMartina Krasteva */ 79314ea315bSMartina Krasteva static int ov9282_parse_hw_config(struct ov9282 *ov9282) 79414ea315bSMartina Krasteva { 79514ea315bSMartina Krasteva struct fwnode_handle *fwnode = dev_fwnode(ov9282->dev); 79614ea315bSMartina Krasteva struct v4l2_fwnode_endpoint bus_cfg = { 79714ea315bSMartina Krasteva .bus_type = V4L2_MBUS_CSI2_DPHY 79814ea315bSMartina Krasteva }; 79914ea315bSMartina Krasteva struct fwnode_handle *ep; 80014ea315bSMartina Krasteva unsigned long rate; 80114ea315bSMartina Krasteva unsigned int i; 80214ea315bSMartina Krasteva int ret; 80314ea315bSMartina Krasteva 80414ea315bSMartina Krasteva if (!fwnode) 80514ea315bSMartina Krasteva return -ENXIO; 80614ea315bSMartina Krasteva 80714ea315bSMartina Krasteva /* Request optional reset pin */ 80814ea315bSMartina Krasteva ov9282->reset_gpio = devm_gpiod_get_optional(ov9282->dev, "reset", 80914ea315bSMartina Krasteva GPIOD_OUT_LOW); 81014ea315bSMartina Krasteva if (IS_ERR(ov9282->reset_gpio)) { 81114ea315bSMartina Krasteva dev_err(ov9282->dev, "failed to get reset gpio %ld", 81214ea315bSMartina Krasteva PTR_ERR(ov9282->reset_gpio)); 81314ea315bSMartina Krasteva return PTR_ERR(ov9282->reset_gpio); 81414ea315bSMartina Krasteva } 81514ea315bSMartina Krasteva 81614ea315bSMartina Krasteva /* Get sensor input clock */ 81714ea315bSMartina Krasteva ov9282->inclk = devm_clk_get(ov9282->dev, NULL); 81814ea315bSMartina Krasteva if (IS_ERR(ov9282->inclk)) { 81914ea315bSMartina Krasteva dev_err(ov9282->dev, "could not get inclk"); 82014ea315bSMartina Krasteva return PTR_ERR(ov9282->inclk); 82114ea315bSMartina Krasteva } 82214ea315bSMartina Krasteva 82314ea315bSMartina Krasteva rate = clk_get_rate(ov9282->inclk); 82414ea315bSMartina Krasteva if (rate != OV9282_INCLK_RATE) { 82514ea315bSMartina Krasteva dev_err(ov9282->dev, "inclk frequency mismatch"); 82614ea315bSMartina Krasteva return -EINVAL; 82714ea315bSMartina Krasteva } 82814ea315bSMartina Krasteva 82914ea315bSMartina Krasteva ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 83014ea315bSMartina Krasteva if (!ep) 83114ea315bSMartina Krasteva return -ENXIO; 83214ea315bSMartina Krasteva 83314ea315bSMartina Krasteva ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 83414ea315bSMartina Krasteva fwnode_handle_put(ep); 83514ea315bSMartina Krasteva if (ret) 83614ea315bSMartina Krasteva return ret; 83714ea315bSMartina Krasteva 83814ea315bSMartina Krasteva if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV9282_NUM_DATA_LANES) { 83914ea315bSMartina Krasteva dev_err(ov9282->dev, 84014ea315bSMartina Krasteva "number of CSI2 data lanes %d is not supported", 84114ea315bSMartina Krasteva bus_cfg.bus.mipi_csi2.num_data_lanes); 84214ea315bSMartina Krasteva ret = -EINVAL; 84314ea315bSMartina Krasteva goto done_endpoint_free; 84414ea315bSMartina Krasteva } 84514ea315bSMartina Krasteva 84614ea315bSMartina Krasteva if (!bus_cfg.nr_of_link_frequencies) { 84714ea315bSMartina Krasteva dev_err(ov9282->dev, "no link frequencies defined"); 84814ea315bSMartina Krasteva ret = -EINVAL; 84914ea315bSMartina Krasteva goto done_endpoint_free; 85014ea315bSMartina Krasteva } 85114ea315bSMartina Krasteva 85214ea315bSMartina Krasteva for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) 85314ea315bSMartina Krasteva if (bus_cfg.link_frequencies[i] == OV9282_LINK_FREQ) 85414ea315bSMartina Krasteva goto done_endpoint_free; 85514ea315bSMartina Krasteva 85614ea315bSMartina Krasteva ret = -EINVAL; 85714ea315bSMartina Krasteva 85814ea315bSMartina Krasteva done_endpoint_free: 85914ea315bSMartina Krasteva v4l2_fwnode_endpoint_free(&bus_cfg); 86014ea315bSMartina Krasteva 86114ea315bSMartina Krasteva return ret; 86214ea315bSMartina Krasteva } 86314ea315bSMartina Krasteva 86414ea315bSMartina Krasteva /* V4l2 subdevice ops */ 86514ea315bSMartina Krasteva static const struct v4l2_subdev_video_ops ov9282_video_ops = { 86614ea315bSMartina Krasteva .s_stream = ov9282_set_stream, 86714ea315bSMartina Krasteva }; 86814ea315bSMartina Krasteva 86914ea315bSMartina Krasteva static const struct v4l2_subdev_pad_ops ov9282_pad_ops = { 87014ea315bSMartina Krasteva .init_cfg = ov9282_init_pad_cfg, 87114ea315bSMartina Krasteva .enum_mbus_code = ov9282_enum_mbus_code, 87214ea315bSMartina Krasteva .enum_frame_size = ov9282_enum_frame_size, 87314ea315bSMartina Krasteva .get_fmt = ov9282_get_pad_format, 87414ea315bSMartina Krasteva .set_fmt = ov9282_set_pad_format, 87514ea315bSMartina Krasteva }; 87614ea315bSMartina Krasteva 87714ea315bSMartina Krasteva static const struct v4l2_subdev_ops ov9282_subdev_ops = { 87814ea315bSMartina Krasteva .video = &ov9282_video_ops, 87914ea315bSMartina Krasteva .pad = &ov9282_pad_ops, 88014ea315bSMartina Krasteva }; 88114ea315bSMartina Krasteva 88214ea315bSMartina Krasteva /** 88314ea315bSMartina Krasteva * ov9282_power_on() - Sensor power on sequence 88414ea315bSMartina Krasteva * @dev: pointer to i2c device 88514ea315bSMartina Krasteva * 88614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 88714ea315bSMartina Krasteva */ 88814ea315bSMartina Krasteva static int ov9282_power_on(struct device *dev) 88914ea315bSMartina Krasteva { 89014ea315bSMartina Krasteva struct v4l2_subdev *sd = dev_get_drvdata(dev); 89114ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 89214ea315bSMartina Krasteva int ret; 89314ea315bSMartina Krasteva 89414ea315bSMartina Krasteva usleep_range(400, 600); 89514ea315bSMartina Krasteva 89614ea315bSMartina Krasteva gpiod_set_value_cansleep(ov9282->reset_gpio, 1); 89714ea315bSMartina Krasteva 89814ea315bSMartina Krasteva ret = clk_prepare_enable(ov9282->inclk); 89914ea315bSMartina Krasteva if (ret) { 90014ea315bSMartina Krasteva dev_err(ov9282->dev, "fail to enable inclk"); 90114ea315bSMartina Krasteva goto error_reset; 90214ea315bSMartina Krasteva } 90314ea315bSMartina Krasteva 90414ea315bSMartina Krasteva usleep_range(400, 600); 90514ea315bSMartina Krasteva 90614ea315bSMartina Krasteva return 0; 90714ea315bSMartina Krasteva 90814ea315bSMartina Krasteva error_reset: 90914ea315bSMartina Krasteva gpiod_set_value_cansleep(ov9282->reset_gpio, 0); 91014ea315bSMartina Krasteva 91114ea315bSMartina Krasteva return ret; 91214ea315bSMartina Krasteva } 91314ea315bSMartina Krasteva 91414ea315bSMartina Krasteva /** 91514ea315bSMartina Krasteva * ov9282_power_off() - Sensor power off sequence 91614ea315bSMartina Krasteva * @dev: pointer to i2c device 91714ea315bSMartina Krasteva * 91814ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 91914ea315bSMartina Krasteva */ 92014ea315bSMartina Krasteva static int ov9282_power_off(struct device *dev) 92114ea315bSMartina Krasteva { 92214ea315bSMartina Krasteva struct v4l2_subdev *sd = dev_get_drvdata(dev); 92314ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 92414ea315bSMartina Krasteva 92514ea315bSMartina Krasteva gpiod_set_value_cansleep(ov9282->reset_gpio, 0); 92614ea315bSMartina Krasteva 92714ea315bSMartina Krasteva clk_disable_unprepare(ov9282->inclk); 92814ea315bSMartina Krasteva 92914ea315bSMartina Krasteva return 0; 93014ea315bSMartina Krasteva } 93114ea315bSMartina Krasteva 93214ea315bSMartina Krasteva /** 93314ea315bSMartina Krasteva * ov9282_init_controls() - Initialize sensor subdevice controls 93414ea315bSMartina Krasteva * @ov9282: pointer to ov9282 device 93514ea315bSMartina Krasteva * 93614ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 93714ea315bSMartina Krasteva */ 93814ea315bSMartina Krasteva static int ov9282_init_controls(struct ov9282 *ov9282) 93914ea315bSMartina Krasteva { 94014ea315bSMartina Krasteva struct v4l2_ctrl_handler *ctrl_hdlr = &ov9282->ctrl_handler; 94114ea315bSMartina Krasteva const struct ov9282_mode *mode = ov9282->cur_mode; 94214ea315bSMartina Krasteva u32 lpfr; 94314ea315bSMartina Krasteva int ret; 94414ea315bSMartina Krasteva 94514ea315bSMartina Krasteva ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); 94614ea315bSMartina Krasteva if (ret) 94714ea315bSMartina Krasteva return ret; 94814ea315bSMartina Krasteva 94914ea315bSMartina Krasteva /* Serialize controls with sensor device */ 95014ea315bSMartina Krasteva ctrl_hdlr->lock = &ov9282->mutex; 95114ea315bSMartina Krasteva 95214ea315bSMartina Krasteva /* Initialize exposure and gain */ 95314ea315bSMartina Krasteva lpfr = mode->vblank + mode->height; 95414ea315bSMartina Krasteva ov9282->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, 95514ea315bSMartina Krasteva &ov9282_ctrl_ops, 95614ea315bSMartina Krasteva V4L2_CID_EXPOSURE, 95714ea315bSMartina Krasteva OV9282_EXPOSURE_MIN, 95814ea315bSMartina Krasteva lpfr - OV9282_EXPOSURE_OFFSET, 95914ea315bSMartina Krasteva OV9282_EXPOSURE_STEP, 96014ea315bSMartina Krasteva OV9282_EXPOSURE_DEFAULT); 96114ea315bSMartina Krasteva 96214ea315bSMartina Krasteva ov9282->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, 96314ea315bSMartina Krasteva &ov9282_ctrl_ops, 96414ea315bSMartina Krasteva V4L2_CID_ANALOGUE_GAIN, 96514ea315bSMartina Krasteva OV9282_AGAIN_MIN, 96614ea315bSMartina Krasteva OV9282_AGAIN_MAX, 96714ea315bSMartina Krasteva OV9282_AGAIN_STEP, 96814ea315bSMartina Krasteva OV9282_AGAIN_DEFAULT); 96914ea315bSMartina Krasteva 97014ea315bSMartina Krasteva v4l2_ctrl_cluster(2, &ov9282->exp_ctrl); 97114ea315bSMartina Krasteva 97214ea315bSMartina Krasteva ov9282->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, 97314ea315bSMartina Krasteva &ov9282_ctrl_ops, 97414ea315bSMartina Krasteva V4L2_CID_VBLANK, 97514ea315bSMartina Krasteva mode->vblank_min, 97614ea315bSMartina Krasteva mode->vblank_max, 97714ea315bSMartina Krasteva 1, mode->vblank); 97814ea315bSMartina Krasteva 97914ea315bSMartina Krasteva /* Read only controls */ 980f15b0612SDave Stevenson v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops, V4L2_CID_PIXEL_RATE, 981f15b0612SDave Stevenson OV9282_PIXEL_RATE, OV9282_PIXEL_RATE, 1, 982f15b0612SDave Stevenson OV9282_PIXEL_RATE); 98314ea315bSMartina Krasteva 98414ea315bSMartina Krasteva ov9282->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, 98514ea315bSMartina Krasteva &ov9282_ctrl_ops, 98614ea315bSMartina Krasteva V4L2_CID_LINK_FREQ, 98714ea315bSMartina Krasteva ARRAY_SIZE(link_freq) - 98814ea315bSMartina Krasteva 1, 98914ea315bSMartina Krasteva mode->link_freq_idx, 99014ea315bSMartina Krasteva link_freq); 99114ea315bSMartina Krasteva if (ov9282->link_freq_ctrl) 99214ea315bSMartina Krasteva ov9282->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 99314ea315bSMartina Krasteva 99414ea315bSMartina Krasteva ov9282->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, 99514ea315bSMartina Krasteva &ov9282_ctrl_ops, 99614ea315bSMartina Krasteva V4L2_CID_HBLANK, 99714ea315bSMartina Krasteva OV9282_REG_MIN, 99814ea315bSMartina Krasteva OV9282_REG_MAX, 99914ea315bSMartina Krasteva 1, mode->hblank); 100014ea315bSMartina Krasteva if (ov9282->hblank_ctrl) 100114ea315bSMartina Krasteva ov9282->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 100214ea315bSMartina Krasteva 100314ea315bSMartina Krasteva if (ctrl_hdlr->error) { 100414ea315bSMartina Krasteva dev_err(ov9282->dev, "control init failed: %d", 100514ea315bSMartina Krasteva ctrl_hdlr->error); 100614ea315bSMartina Krasteva v4l2_ctrl_handler_free(ctrl_hdlr); 100714ea315bSMartina Krasteva return ctrl_hdlr->error; 100814ea315bSMartina Krasteva } 100914ea315bSMartina Krasteva 101014ea315bSMartina Krasteva ov9282->sd.ctrl_handler = ctrl_hdlr; 101114ea315bSMartina Krasteva 101214ea315bSMartina Krasteva return 0; 101314ea315bSMartina Krasteva } 101414ea315bSMartina Krasteva 101514ea315bSMartina Krasteva /** 101614ea315bSMartina Krasteva * ov9282_probe() - I2C client device binding 101714ea315bSMartina Krasteva * @client: pointer to i2c client device 101814ea315bSMartina Krasteva * 101914ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 102014ea315bSMartina Krasteva */ 102114ea315bSMartina Krasteva static int ov9282_probe(struct i2c_client *client) 102214ea315bSMartina Krasteva { 102314ea315bSMartina Krasteva struct ov9282 *ov9282; 102414ea315bSMartina Krasteva int ret; 102514ea315bSMartina Krasteva 102614ea315bSMartina Krasteva ov9282 = devm_kzalloc(&client->dev, sizeof(*ov9282), GFP_KERNEL); 102714ea315bSMartina Krasteva if (!ov9282) 102814ea315bSMartina Krasteva return -ENOMEM; 102914ea315bSMartina Krasteva 103014ea315bSMartina Krasteva ov9282->dev = &client->dev; 103114ea315bSMartina Krasteva 103214ea315bSMartina Krasteva /* Initialize subdev */ 103314ea315bSMartina Krasteva v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops); 103414ea315bSMartina Krasteva 103514ea315bSMartina Krasteva ret = ov9282_parse_hw_config(ov9282); 103614ea315bSMartina Krasteva if (ret) { 103714ea315bSMartina Krasteva dev_err(ov9282->dev, "HW configuration is not supported"); 103814ea315bSMartina Krasteva return ret; 103914ea315bSMartina Krasteva } 104014ea315bSMartina Krasteva 104114ea315bSMartina Krasteva mutex_init(&ov9282->mutex); 104214ea315bSMartina Krasteva 104314ea315bSMartina Krasteva ret = ov9282_power_on(ov9282->dev); 104414ea315bSMartina Krasteva if (ret) { 104514ea315bSMartina Krasteva dev_err(ov9282->dev, "failed to power-on the sensor"); 104614ea315bSMartina Krasteva goto error_mutex_destroy; 104714ea315bSMartina Krasteva } 104814ea315bSMartina Krasteva 104914ea315bSMartina Krasteva /* Check module identity */ 105014ea315bSMartina Krasteva ret = ov9282_detect(ov9282); 105114ea315bSMartina Krasteva if (ret) { 105214ea315bSMartina Krasteva dev_err(ov9282->dev, "failed to find sensor: %d", ret); 105314ea315bSMartina Krasteva goto error_power_off; 105414ea315bSMartina Krasteva } 105514ea315bSMartina Krasteva 1056*995809ceSDave Stevenson /* Set default mode to first mode */ 1057*995809ceSDave Stevenson ov9282->cur_mode = &supported_modes[DEFAULT_MODE]; 105814ea315bSMartina Krasteva ov9282->vblank = ov9282->cur_mode->vblank; 105914ea315bSMartina Krasteva 106014ea315bSMartina Krasteva ret = ov9282_init_controls(ov9282); 106114ea315bSMartina Krasteva if (ret) { 106214ea315bSMartina Krasteva dev_err(ov9282->dev, "failed to init controls: %d", ret); 106314ea315bSMartina Krasteva goto error_power_off; 106414ea315bSMartina Krasteva } 106514ea315bSMartina Krasteva 106614ea315bSMartina Krasteva /* Initialize subdev */ 106714ea315bSMartina Krasteva ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 106814ea315bSMartina Krasteva ov9282->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 106914ea315bSMartina Krasteva 107014ea315bSMartina Krasteva /* Initialize source pad */ 107114ea315bSMartina Krasteva ov9282->pad.flags = MEDIA_PAD_FL_SOURCE; 107214ea315bSMartina Krasteva ret = media_entity_pads_init(&ov9282->sd.entity, 1, &ov9282->pad); 107314ea315bSMartina Krasteva if (ret) { 107414ea315bSMartina Krasteva dev_err(ov9282->dev, "failed to init entity pads: %d", ret); 107514ea315bSMartina Krasteva goto error_handler_free; 107614ea315bSMartina Krasteva } 107714ea315bSMartina Krasteva 107814ea315bSMartina Krasteva ret = v4l2_async_register_subdev_sensor(&ov9282->sd); 107914ea315bSMartina Krasteva if (ret < 0) { 108014ea315bSMartina Krasteva dev_err(ov9282->dev, 108114ea315bSMartina Krasteva "failed to register async subdev: %d", ret); 108214ea315bSMartina Krasteva goto error_media_entity; 108314ea315bSMartina Krasteva } 108414ea315bSMartina Krasteva 108514ea315bSMartina Krasteva pm_runtime_set_active(ov9282->dev); 108614ea315bSMartina Krasteva pm_runtime_enable(ov9282->dev); 108714ea315bSMartina Krasteva pm_runtime_idle(ov9282->dev); 108814ea315bSMartina Krasteva 108914ea315bSMartina Krasteva return 0; 109014ea315bSMartina Krasteva 109114ea315bSMartina Krasteva error_media_entity: 109214ea315bSMartina Krasteva media_entity_cleanup(&ov9282->sd.entity); 109314ea315bSMartina Krasteva error_handler_free: 109414ea315bSMartina Krasteva v4l2_ctrl_handler_free(ov9282->sd.ctrl_handler); 109514ea315bSMartina Krasteva error_power_off: 109614ea315bSMartina Krasteva ov9282_power_off(ov9282->dev); 109714ea315bSMartina Krasteva error_mutex_destroy: 109814ea315bSMartina Krasteva mutex_destroy(&ov9282->mutex); 109914ea315bSMartina Krasteva 110014ea315bSMartina Krasteva return ret; 110114ea315bSMartina Krasteva } 110214ea315bSMartina Krasteva 110314ea315bSMartina Krasteva /** 110414ea315bSMartina Krasteva * ov9282_remove() - I2C client device unbinding 110514ea315bSMartina Krasteva * @client: pointer to I2C client device 110614ea315bSMartina Krasteva * 110714ea315bSMartina Krasteva * Return: 0 if successful, error code otherwise. 110814ea315bSMartina Krasteva */ 1109ed5c2f5fSUwe Kleine-König static void ov9282_remove(struct i2c_client *client) 111014ea315bSMartina Krasteva { 111114ea315bSMartina Krasteva struct v4l2_subdev *sd = i2c_get_clientdata(client); 111214ea315bSMartina Krasteva struct ov9282 *ov9282 = to_ov9282(sd); 111314ea315bSMartina Krasteva 111414ea315bSMartina Krasteva v4l2_async_unregister_subdev(sd); 111514ea315bSMartina Krasteva media_entity_cleanup(&sd->entity); 111614ea315bSMartina Krasteva v4l2_ctrl_handler_free(sd->ctrl_handler); 111714ea315bSMartina Krasteva 111814ea315bSMartina Krasteva pm_runtime_disable(&client->dev); 111914ea315bSMartina Krasteva if (!pm_runtime_status_suspended(&client->dev)) 112014ea315bSMartina Krasteva ov9282_power_off(&client->dev); 112114ea315bSMartina Krasteva pm_runtime_set_suspended(&client->dev); 112214ea315bSMartina Krasteva 112314ea315bSMartina Krasteva mutex_destroy(&ov9282->mutex); 112414ea315bSMartina Krasteva } 112514ea315bSMartina Krasteva 112614ea315bSMartina Krasteva static const struct dev_pm_ops ov9282_pm_ops = { 112714ea315bSMartina Krasteva SET_RUNTIME_PM_OPS(ov9282_power_off, ov9282_power_on, NULL) 112814ea315bSMartina Krasteva }; 112914ea315bSMartina Krasteva 113014ea315bSMartina Krasteva static const struct of_device_id ov9282_of_match[] = { 113114ea315bSMartina Krasteva { .compatible = "ovti,ov9282" }, 113214ea315bSMartina Krasteva { } 113314ea315bSMartina Krasteva }; 113414ea315bSMartina Krasteva 113514ea315bSMartina Krasteva MODULE_DEVICE_TABLE(of, ov9282_of_match); 113614ea315bSMartina Krasteva 113714ea315bSMartina Krasteva static struct i2c_driver ov9282_driver = { 113814ea315bSMartina Krasteva .probe_new = ov9282_probe, 113914ea315bSMartina Krasteva .remove = ov9282_remove, 114014ea315bSMartina Krasteva .driver = { 114114ea315bSMartina Krasteva .name = "ov9282", 114214ea315bSMartina Krasteva .pm = &ov9282_pm_ops, 114314ea315bSMartina Krasteva .of_match_table = ov9282_of_match, 114414ea315bSMartina Krasteva }, 114514ea315bSMartina Krasteva }; 114614ea315bSMartina Krasteva 114714ea315bSMartina Krasteva module_i2c_driver(ov9282_driver); 114814ea315bSMartina Krasteva 114914ea315bSMartina Krasteva MODULE_DESCRIPTION("OmniVision ov9282 sensor driver"); 115014ea315bSMartina Krasteva MODULE_LICENSE("GPL"); 1151