xref: /openbmc/linux/drivers/media/i2c/imx208.c (revision 4106cd72)
1d953e3cbSShawn Tu // SPDX-License-Identifier: GPL-2.0
2d953e3cbSShawn Tu // Copyright (C) 2021 Intel Corporation
3d953e3cbSShawn Tu 
4d953e3cbSShawn Tu #include <linux/acpi.h>
5d953e3cbSShawn Tu #include <linux/delay.h>
6d953e3cbSShawn Tu #include <linux/i2c.h>
7d953e3cbSShawn Tu #include <linux/module.h>
8d953e3cbSShawn Tu #include <linux/pm_runtime.h>
9d953e3cbSShawn Tu #include <media/v4l2-ctrls.h>
10d953e3cbSShawn Tu #include <media/v4l2-device.h>
11d953e3cbSShawn Tu #include <asm/unaligned.h>
12d953e3cbSShawn Tu 
13d953e3cbSShawn Tu #define IMX208_REG_MODE_SELECT		0x0100
14d953e3cbSShawn Tu #define IMX208_MODE_STANDBY		0x00
15d953e3cbSShawn Tu #define IMX208_MODE_STREAMING		0x01
16d953e3cbSShawn Tu 
17d953e3cbSShawn Tu /* Chip ID */
18d953e3cbSShawn Tu #define IMX208_REG_CHIP_ID		0x0000
19d953e3cbSShawn Tu #define IMX208_CHIP_ID			0x0208
20d953e3cbSShawn Tu 
21d953e3cbSShawn Tu /* V_TIMING internal */
22d953e3cbSShawn Tu #define IMX208_REG_VTS			0x0340
23d953e3cbSShawn Tu #define IMX208_VTS_60FPS		0x0472
24d953e3cbSShawn Tu #define IMX208_VTS_BINNING		0x0239
25d953e3cbSShawn Tu #define IMX208_VTS_60FPS_MIN		0x0458
26d953e3cbSShawn Tu #define IMX208_VTS_BINNING_MIN		0x0230
27d953e3cbSShawn Tu #define IMX208_VTS_MAX			0xffff
28d953e3cbSShawn Tu 
29d953e3cbSShawn Tu /* HBLANK control - read only */
30d953e3cbSShawn Tu #define IMX208_PPL_384MHZ		2248
31d953e3cbSShawn Tu #define IMX208_PPL_96MHZ		2248
32d953e3cbSShawn Tu 
33d953e3cbSShawn Tu /* Exposure control */
34d953e3cbSShawn Tu #define IMX208_REG_EXPOSURE		0x0202
35d953e3cbSShawn Tu #define IMX208_EXPOSURE_MIN		4
36d953e3cbSShawn Tu #define IMX208_EXPOSURE_STEP		1
37d953e3cbSShawn Tu #define IMX208_EXPOSURE_DEFAULT		0x190
38d953e3cbSShawn Tu #define IMX208_EXPOSURE_MAX		65535
39d953e3cbSShawn Tu 
40d953e3cbSShawn Tu /* Analog gain control */
41d953e3cbSShawn Tu #define IMX208_REG_ANALOG_GAIN		0x0204
42d953e3cbSShawn Tu #define IMX208_ANA_GAIN_MIN		0
43d953e3cbSShawn Tu #define IMX208_ANA_GAIN_MAX		0x00e0
44d953e3cbSShawn Tu #define IMX208_ANA_GAIN_STEP		1
45d953e3cbSShawn Tu #define IMX208_ANA_GAIN_DEFAULT		0x0
46d953e3cbSShawn Tu 
47d953e3cbSShawn Tu /* Digital gain control */
48d953e3cbSShawn Tu #define IMX208_REG_GR_DIGITAL_GAIN	0x020e
49d953e3cbSShawn Tu #define IMX208_REG_R_DIGITAL_GAIN	0x0210
50d953e3cbSShawn Tu #define IMX208_REG_B_DIGITAL_GAIN	0x0212
51d953e3cbSShawn Tu #define IMX208_REG_GB_DIGITAL_GAIN	0x0214
52d953e3cbSShawn Tu #define IMX208_DIGITAL_GAIN_SHIFT	8
53d953e3cbSShawn Tu 
54d953e3cbSShawn Tu /* Orientation */
55d953e3cbSShawn Tu #define IMX208_REG_ORIENTATION_CONTROL	0x0101
56d953e3cbSShawn Tu 
57d953e3cbSShawn Tu /* Test Pattern Control */
58d953e3cbSShawn Tu #define IMX208_REG_TEST_PATTERN_MODE	0x0600
59d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_DISABLE	0x0
60d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_SOLID_COLOR	0x1
61d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_COLOR_BARS	0x2
62d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_GREY_COLOR	0x3
63d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_PN9		0x4
64d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_1	0x100
65d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_2	0x101
66d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_3	0x102
67d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_4	0x103
68d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_5	0x104
69d953e3cbSShawn Tu #define IMX208_TEST_PATTERN_FIX_6	0x105
70d953e3cbSShawn Tu 
71d953e3cbSShawn Tu /* OTP Access */
72d953e3cbSShawn Tu #define IMX208_OTP_BASE			0x3500
73d953e3cbSShawn Tu #define IMX208_OTP_SIZE			40
74d953e3cbSShawn Tu 
75d953e3cbSShawn Tu struct imx208_reg {
76d953e3cbSShawn Tu 	u16 address;
77d953e3cbSShawn Tu 	u8 val;
78d953e3cbSShawn Tu };
79d953e3cbSShawn Tu 
80d953e3cbSShawn Tu struct imx208_reg_list {
81d953e3cbSShawn Tu 	u32 num_of_regs;
82d953e3cbSShawn Tu 	const struct imx208_reg *regs;
83d953e3cbSShawn Tu };
84d953e3cbSShawn Tu 
85d953e3cbSShawn Tu /* Link frequency config */
86d953e3cbSShawn Tu struct imx208_link_freq_config {
87d953e3cbSShawn Tu 	u32 pixels_per_line;
88d953e3cbSShawn Tu 
89d953e3cbSShawn Tu 	/* PLL registers for this link frequency */
90d953e3cbSShawn Tu 	struct imx208_reg_list reg_list;
91d953e3cbSShawn Tu };
92d953e3cbSShawn Tu 
93d953e3cbSShawn Tu /* Mode : resolution and related config&values */
94d953e3cbSShawn Tu struct imx208_mode {
95d953e3cbSShawn Tu 	/* Frame width */
96d953e3cbSShawn Tu 	u32 width;
97d953e3cbSShawn Tu 	/* Frame height */
98d953e3cbSShawn Tu 	u32 height;
99d953e3cbSShawn Tu 
100d953e3cbSShawn Tu 	/* V-timing */
101d953e3cbSShawn Tu 	u32 vts_def;
102d953e3cbSShawn Tu 	u32 vts_min;
103d953e3cbSShawn Tu 
104d953e3cbSShawn Tu 	/* Index of Link frequency config to be used */
105d953e3cbSShawn Tu 	u32 link_freq_index;
106d953e3cbSShawn Tu 	/* Default register values */
107d953e3cbSShawn Tu 	struct imx208_reg_list reg_list;
108d953e3cbSShawn Tu };
109d953e3cbSShawn Tu 
110d953e3cbSShawn Tu static const struct imx208_reg pll_ctrl_reg[] = {
111d953e3cbSShawn Tu 	{0x0305, 0x02},
112d953e3cbSShawn Tu 	{0x0307, 0x50},
113d953e3cbSShawn Tu 	{0x303C, 0x3C},
114d953e3cbSShawn Tu };
115d953e3cbSShawn Tu 
116d953e3cbSShawn Tu static const struct imx208_reg mode_1936x1096_60fps_regs[] = {
117d953e3cbSShawn Tu 	{0x0340, 0x04},
118d953e3cbSShawn Tu 	{0x0341, 0x72},
119d953e3cbSShawn Tu 	{0x0342, 0x04},
120d953e3cbSShawn Tu 	{0x0343, 0x64},
121d953e3cbSShawn Tu 	{0x034C, 0x07},
122d953e3cbSShawn Tu 	{0x034D, 0x90},
123d953e3cbSShawn Tu 	{0x034E, 0x04},
124d953e3cbSShawn Tu 	{0x034F, 0x48},
125d953e3cbSShawn Tu 	{0x0381, 0x01},
126d953e3cbSShawn Tu 	{0x0383, 0x01},
127d953e3cbSShawn Tu 	{0x0385, 0x01},
128d953e3cbSShawn Tu 	{0x0387, 0x01},
129d953e3cbSShawn Tu 	{0x3048, 0x00},
130d953e3cbSShawn Tu 	{0x3050, 0x01},
131d953e3cbSShawn Tu 	{0x30D5, 0x00},
132d953e3cbSShawn Tu 	{0x3301, 0x00},
133d953e3cbSShawn Tu 	{0x3318, 0x62},
134d953e3cbSShawn Tu 	{0x0202, 0x01},
135d953e3cbSShawn Tu 	{0x0203, 0x90},
136d953e3cbSShawn Tu 	{0x0205, 0x00},
137d953e3cbSShawn Tu };
138d953e3cbSShawn Tu 
139d953e3cbSShawn Tu static const struct imx208_reg mode_968_548_60fps_regs[] = {
140d953e3cbSShawn Tu 	{0x0340, 0x02},
141d953e3cbSShawn Tu 	{0x0341, 0x39},
142d953e3cbSShawn Tu 	{0x0342, 0x08},
143d953e3cbSShawn Tu 	{0x0343, 0xC8},
144d953e3cbSShawn Tu 	{0x034C, 0x03},
145d953e3cbSShawn Tu 	{0x034D, 0xC8},
146d953e3cbSShawn Tu 	{0x034E, 0x02},
147d953e3cbSShawn Tu 	{0x034F, 0x24},
148d953e3cbSShawn Tu 	{0x0381, 0x01},
149d953e3cbSShawn Tu 	{0x0383, 0x03},
150d953e3cbSShawn Tu 	{0x0385, 0x01},
151d953e3cbSShawn Tu 	{0x0387, 0x03},
152d953e3cbSShawn Tu 	{0x3048, 0x01},
153d953e3cbSShawn Tu 	{0x3050, 0x02},
154d953e3cbSShawn Tu 	{0x30D5, 0x03},
155d953e3cbSShawn Tu 	{0x3301, 0x10},
156d953e3cbSShawn Tu 	{0x3318, 0x75},
157d953e3cbSShawn Tu 	{0x0202, 0x01},
158d953e3cbSShawn Tu 	{0x0203, 0x90},
159d953e3cbSShawn Tu 	{0x0205, 0x00},
160d953e3cbSShawn Tu };
161d953e3cbSShawn Tu 
162d953e3cbSShawn Tu static const s64 imx208_discrete_digital_gain[] = {
163d953e3cbSShawn Tu 	1, 2, 4, 8, 16,
164d953e3cbSShawn Tu };
165d953e3cbSShawn Tu 
166d953e3cbSShawn Tu static const char * const imx208_test_pattern_menu[] = {
167d953e3cbSShawn Tu 	"Disabled",
168d953e3cbSShawn Tu 	"Solid Color",
169d953e3cbSShawn Tu 	"100% Color Bar",
170d953e3cbSShawn Tu 	"Fade to Grey Color Bar",
171d953e3cbSShawn Tu 	"PN9",
172d953e3cbSShawn Tu 	"Fixed Pattern1",
173d953e3cbSShawn Tu 	"Fixed Pattern2",
174d953e3cbSShawn Tu 	"Fixed Pattern3",
175d953e3cbSShawn Tu 	"Fixed Pattern4",
176d953e3cbSShawn Tu 	"Fixed Pattern5",
177d953e3cbSShawn Tu 	"Fixed Pattern6"
178d953e3cbSShawn Tu };
179d953e3cbSShawn Tu 
180d953e3cbSShawn Tu static const int imx208_test_pattern_val[] = {
181d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_DISABLE,
182d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_SOLID_COLOR,
183d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_COLOR_BARS,
184d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_GREY_COLOR,
185d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_PN9,
186d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_1,
187d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_2,
188d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_3,
189d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_4,
190d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_5,
191d953e3cbSShawn Tu 	IMX208_TEST_PATTERN_FIX_6,
192d953e3cbSShawn Tu };
193d953e3cbSShawn Tu 
194d953e3cbSShawn Tu /* Configurations for supported link frequencies */
195d953e3cbSShawn Tu #define IMX208_MHZ			(1000 * 1000ULL)
196d953e3cbSShawn Tu #define IMX208_LINK_FREQ_384MHZ		(384ULL * IMX208_MHZ)
197d953e3cbSShawn Tu #define IMX208_LINK_FREQ_96MHZ		(96ULL * IMX208_MHZ)
198d953e3cbSShawn Tu 
199d953e3cbSShawn Tu #define IMX208_DATA_RATE_DOUBLE		2
200d953e3cbSShawn Tu #define IMX208_NUM_OF_LANES		2
201d953e3cbSShawn Tu #define IMX208_PIXEL_BITS		10
202d953e3cbSShawn Tu 
203d953e3cbSShawn Tu enum {
204d953e3cbSShawn Tu 	IMX208_LINK_FREQ_384MHZ_INDEX,
205d953e3cbSShawn Tu 	IMX208_LINK_FREQ_96MHZ_INDEX,
206d953e3cbSShawn Tu };
207d953e3cbSShawn Tu 
208d953e3cbSShawn Tu /*
209d953e3cbSShawn Tu  * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
210d953e3cbSShawn Tu  * data rate => double data rate; number of lanes => 2; bits per pixel => 10
211d953e3cbSShawn Tu  */
link_freq_to_pixel_rate(u64 f)212d953e3cbSShawn Tu static u64 link_freq_to_pixel_rate(u64 f)
213d953e3cbSShawn Tu {
214d953e3cbSShawn Tu 	f *= IMX208_DATA_RATE_DOUBLE * IMX208_NUM_OF_LANES;
215d953e3cbSShawn Tu 	do_div(f, IMX208_PIXEL_BITS);
216d953e3cbSShawn Tu 
217d953e3cbSShawn Tu 	return f;
218d953e3cbSShawn Tu }
219d953e3cbSShawn Tu 
220d953e3cbSShawn Tu /* Menu items for LINK_FREQ V4L2 control */
221d953e3cbSShawn Tu static const s64 link_freq_menu_items[] = {
222d953e3cbSShawn Tu 	[IMX208_LINK_FREQ_384MHZ_INDEX] = IMX208_LINK_FREQ_384MHZ,
223d953e3cbSShawn Tu 	[IMX208_LINK_FREQ_96MHZ_INDEX] = IMX208_LINK_FREQ_96MHZ,
224d953e3cbSShawn Tu };
225d953e3cbSShawn Tu 
226d953e3cbSShawn Tu /* Link frequency configs */
227d953e3cbSShawn Tu static const struct imx208_link_freq_config link_freq_configs[] = {
228d953e3cbSShawn Tu 	[IMX208_LINK_FREQ_384MHZ_INDEX] = {
229d953e3cbSShawn Tu 		.pixels_per_line = IMX208_PPL_384MHZ,
230d953e3cbSShawn Tu 		.reg_list = {
231d953e3cbSShawn Tu 			.num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
232d953e3cbSShawn Tu 			.regs = pll_ctrl_reg,
233d953e3cbSShawn Tu 		}
234d953e3cbSShawn Tu 	},
235d953e3cbSShawn Tu 	[IMX208_LINK_FREQ_96MHZ_INDEX] = {
236d953e3cbSShawn Tu 		.pixels_per_line = IMX208_PPL_96MHZ,
237d953e3cbSShawn Tu 		.reg_list = {
238d953e3cbSShawn Tu 			.num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
239d953e3cbSShawn Tu 			.regs = pll_ctrl_reg,
240d953e3cbSShawn Tu 		}
241d953e3cbSShawn Tu 	},
242d953e3cbSShawn Tu };
243d953e3cbSShawn Tu 
244d953e3cbSShawn Tu /* Mode configs */
245d953e3cbSShawn Tu static const struct imx208_mode supported_modes[] = {
246d953e3cbSShawn Tu 	{
247d953e3cbSShawn Tu 		.width = 1936,
248d953e3cbSShawn Tu 		.height = 1096,
249d953e3cbSShawn Tu 		.vts_def = IMX208_VTS_60FPS,
250d953e3cbSShawn Tu 		.vts_min = IMX208_VTS_60FPS_MIN,
251d953e3cbSShawn Tu 		.reg_list = {
252d953e3cbSShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_1936x1096_60fps_regs),
253d953e3cbSShawn Tu 			.regs = mode_1936x1096_60fps_regs,
254d953e3cbSShawn Tu 		},
255d953e3cbSShawn Tu 		.link_freq_index = IMX208_LINK_FREQ_384MHZ_INDEX,
256d953e3cbSShawn Tu 	},
257d953e3cbSShawn Tu 	{
258d953e3cbSShawn Tu 		.width = 968,
259d953e3cbSShawn Tu 		.height = 548,
260d953e3cbSShawn Tu 		.vts_def = IMX208_VTS_BINNING,
261d953e3cbSShawn Tu 		.vts_min = IMX208_VTS_BINNING_MIN,
262d953e3cbSShawn Tu 		.reg_list = {
263d953e3cbSShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_968_548_60fps_regs),
264d953e3cbSShawn Tu 			.regs = mode_968_548_60fps_regs,
265d953e3cbSShawn Tu 		},
266d953e3cbSShawn Tu 		.link_freq_index = IMX208_LINK_FREQ_96MHZ_INDEX,
267d953e3cbSShawn Tu 	},
268d953e3cbSShawn Tu };
269d953e3cbSShawn Tu 
270d953e3cbSShawn Tu struct imx208 {
271d953e3cbSShawn Tu 	struct v4l2_subdev sd;
272d953e3cbSShawn Tu 	struct media_pad pad;
273d953e3cbSShawn Tu 
274d953e3cbSShawn Tu 	struct v4l2_ctrl_handler ctrl_handler;
275d953e3cbSShawn Tu 	/* V4L2 Controls */
276d953e3cbSShawn Tu 	struct v4l2_ctrl *link_freq;
277d953e3cbSShawn Tu 	struct v4l2_ctrl *pixel_rate;
278d953e3cbSShawn Tu 	struct v4l2_ctrl *vblank;
279d953e3cbSShawn Tu 	struct v4l2_ctrl *hblank;
280d953e3cbSShawn Tu 	struct v4l2_ctrl *vflip;
281d953e3cbSShawn Tu 	struct v4l2_ctrl *hflip;
282d953e3cbSShawn Tu 
283d953e3cbSShawn Tu 	/* Current mode */
284d953e3cbSShawn Tu 	const struct imx208_mode *cur_mode;
285d953e3cbSShawn Tu 
286d953e3cbSShawn Tu 	/*
287d953e3cbSShawn Tu 	 * Mutex for serialized access:
288d953e3cbSShawn Tu 	 * Protect sensor set pad format and start/stop streaming safely.
289d953e3cbSShawn Tu 	 * Protect access to sensor v4l2 controls.
290d953e3cbSShawn Tu 	 */
291d953e3cbSShawn Tu 	struct mutex imx208_mx;
292d953e3cbSShawn Tu 
293d953e3cbSShawn Tu 	/* Streaming on/off */
294d953e3cbSShawn Tu 	bool streaming;
295d953e3cbSShawn Tu 
296d953e3cbSShawn Tu 	/* OTP data */
297d953e3cbSShawn Tu 	bool otp_read;
298d953e3cbSShawn Tu 	char otp_data[IMX208_OTP_SIZE];
29956ca3be8SBingbu Cao 
30056ca3be8SBingbu Cao 	/* True if the device has been identified */
30156ca3be8SBingbu Cao 	bool identified;
302d953e3cbSShawn Tu };
303d953e3cbSShawn Tu 
to_imx208(struct v4l2_subdev * _sd)304d953e3cbSShawn Tu static inline struct imx208 *to_imx208(struct v4l2_subdev *_sd)
305d953e3cbSShawn Tu {
306d953e3cbSShawn Tu 	return container_of(_sd, struct imx208, sd);
307d953e3cbSShawn Tu }
308d953e3cbSShawn Tu 
309d953e3cbSShawn Tu /* Get bayer order based on flip setting. */
imx208_get_format_code(struct imx208 * imx208)310d953e3cbSShawn Tu static u32 imx208_get_format_code(struct imx208 *imx208)
311d953e3cbSShawn Tu {
312d953e3cbSShawn Tu 	/*
313d953e3cbSShawn Tu 	 * Only one bayer order is supported.
314d953e3cbSShawn Tu 	 * It depends on the flip settings.
315d953e3cbSShawn Tu 	 */
316d953e3cbSShawn Tu 	static const u32 codes[2][2] = {
317d953e3cbSShawn Tu 		{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
318d953e3cbSShawn Tu 		{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
319d953e3cbSShawn Tu 	};
320d953e3cbSShawn Tu 
321d953e3cbSShawn Tu 	return codes[imx208->vflip->val][imx208->hflip->val];
322d953e3cbSShawn Tu }
323d953e3cbSShawn Tu 
324d953e3cbSShawn Tu /* Read registers up to 4 at a time */
imx208_read_reg(struct imx208 * imx208,u16 reg,u32 len,u32 * val)325d953e3cbSShawn Tu static int imx208_read_reg(struct imx208 *imx208, u16 reg, u32 len, u32 *val)
326d953e3cbSShawn Tu {
327d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
328d953e3cbSShawn Tu 	struct i2c_msg msgs[2];
329d953e3cbSShawn Tu 	u8 addr_buf[2] = { reg >> 8, reg & 0xff };
330d953e3cbSShawn Tu 	u8 data_buf[4] = { 0, };
331d953e3cbSShawn Tu 	int ret;
332d953e3cbSShawn Tu 
333d953e3cbSShawn Tu 	if (len > 4)
334d953e3cbSShawn Tu 		return -EINVAL;
335d953e3cbSShawn Tu 
336d953e3cbSShawn Tu 	/* Write register address */
337d953e3cbSShawn Tu 	msgs[0].addr = client->addr;
338d953e3cbSShawn Tu 	msgs[0].flags = 0;
339d953e3cbSShawn Tu 	msgs[0].len = ARRAY_SIZE(addr_buf);
340d953e3cbSShawn Tu 	msgs[0].buf = addr_buf;
341d953e3cbSShawn Tu 
342d953e3cbSShawn Tu 	/* Read data from register */
343d953e3cbSShawn Tu 	msgs[1].addr = client->addr;
344d953e3cbSShawn Tu 	msgs[1].flags = I2C_M_RD;
345d953e3cbSShawn Tu 	msgs[1].len = len;
346d953e3cbSShawn Tu 	msgs[1].buf = &data_buf[4 - len];
347d953e3cbSShawn Tu 
348d953e3cbSShawn Tu 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
349d953e3cbSShawn Tu 	if (ret != ARRAY_SIZE(msgs))
350d953e3cbSShawn Tu 		return -EIO;
351d953e3cbSShawn Tu 
352d953e3cbSShawn Tu 	*val = get_unaligned_be32(data_buf);
353d953e3cbSShawn Tu 
354d953e3cbSShawn Tu 	return 0;
355d953e3cbSShawn Tu }
356d953e3cbSShawn Tu 
357d953e3cbSShawn Tu /* Write registers up to 4 at a time */
imx208_write_reg(struct imx208 * imx208,u16 reg,u32 len,u32 val)358d953e3cbSShawn Tu static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val)
359d953e3cbSShawn Tu {
360d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
361d953e3cbSShawn Tu 	u8 buf[6];
362d953e3cbSShawn Tu 
363d953e3cbSShawn Tu 	if (len > 4)
364d953e3cbSShawn Tu 		return -EINVAL;
365d953e3cbSShawn Tu 
366d953e3cbSShawn Tu 	put_unaligned_be16(reg, buf);
367d953e3cbSShawn Tu 	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
368d953e3cbSShawn Tu 	if (i2c_master_send(client, buf, len + 2) != len + 2)
369d953e3cbSShawn Tu 		return -EIO;
370d953e3cbSShawn Tu 
371d953e3cbSShawn Tu 	return 0;
372d953e3cbSShawn Tu }
373d953e3cbSShawn Tu 
374d953e3cbSShawn Tu /* Write a list of registers */
imx208_write_regs(struct imx208 * imx208,const struct imx208_reg * regs,u32 len)375d953e3cbSShawn Tu static int imx208_write_regs(struct imx208 *imx208,
376d953e3cbSShawn Tu 			     const struct imx208_reg *regs, u32 len)
377d953e3cbSShawn Tu {
378d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
379d953e3cbSShawn Tu 	unsigned int i;
380d953e3cbSShawn Tu 	int ret;
381d953e3cbSShawn Tu 
382d953e3cbSShawn Tu 	for (i = 0; i < len; i++) {
383d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, regs[i].address, 1,
384d953e3cbSShawn Tu 				       regs[i].val);
385d953e3cbSShawn Tu 		if (ret) {
386d953e3cbSShawn Tu 			dev_err_ratelimited(&client->dev,
387d953e3cbSShawn Tu 					    "Failed to write reg 0x%4.4x. error = %d\n",
388d953e3cbSShawn Tu 					    regs[i].address, ret);
389d953e3cbSShawn Tu 
390d953e3cbSShawn Tu 			return ret;
391d953e3cbSShawn Tu 		}
392d953e3cbSShawn Tu 	}
393d953e3cbSShawn Tu 
394d953e3cbSShawn Tu 	return 0;
395d953e3cbSShawn Tu }
396d953e3cbSShawn Tu 
397d953e3cbSShawn Tu /* Open sub-device */
imx208_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)398d953e3cbSShawn Tu static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
399d953e3cbSShawn Tu {
400d953e3cbSShawn Tu 	struct v4l2_mbus_framefmt *try_fmt =
4010d346d2aSTomi Valkeinen 		v4l2_subdev_get_try_format(sd, fh->state, 0);
402d953e3cbSShawn Tu 
403d953e3cbSShawn Tu 	/* Initialize try_fmt */
404d953e3cbSShawn Tu 	try_fmt->width = supported_modes[0].width;
405d953e3cbSShawn Tu 	try_fmt->height = supported_modes[0].height;
406d953e3cbSShawn Tu 	try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
407d953e3cbSShawn Tu 	try_fmt->field = V4L2_FIELD_NONE;
408d953e3cbSShawn Tu 
409d953e3cbSShawn Tu 	return 0;
410d953e3cbSShawn Tu }
411d953e3cbSShawn Tu 
imx208_update_digital_gain(struct imx208 * imx208,u32 len,u32 val)412d953e3cbSShawn Tu static int imx208_update_digital_gain(struct imx208 *imx208, u32 len, u32 val)
413d953e3cbSShawn Tu {
414d953e3cbSShawn Tu 	int ret;
415d953e3cbSShawn Tu 
416d953e3cbSShawn Tu 	val = imx208_discrete_digital_gain[val] << IMX208_DIGITAL_GAIN_SHIFT;
417d953e3cbSShawn Tu 
418d953e3cbSShawn Tu 	ret = imx208_write_reg(imx208, IMX208_REG_GR_DIGITAL_GAIN, 2, val);
419d953e3cbSShawn Tu 	if (ret)
420d953e3cbSShawn Tu 		return ret;
421d953e3cbSShawn Tu 
422d953e3cbSShawn Tu 	ret = imx208_write_reg(imx208, IMX208_REG_GB_DIGITAL_GAIN, 2, val);
423d953e3cbSShawn Tu 	if (ret)
424d953e3cbSShawn Tu 		return ret;
425d953e3cbSShawn Tu 
426d953e3cbSShawn Tu 	ret = imx208_write_reg(imx208, IMX208_REG_R_DIGITAL_GAIN, 2, val);
427d953e3cbSShawn Tu 	if (ret)
428d953e3cbSShawn Tu 		return ret;
429d953e3cbSShawn Tu 
430d953e3cbSShawn Tu 	return imx208_write_reg(imx208, IMX208_REG_B_DIGITAL_GAIN, 2, val);
431d953e3cbSShawn Tu }
432d953e3cbSShawn Tu 
imx208_set_ctrl(struct v4l2_ctrl * ctrl)433d953e3cbSShawn Tu static int imx208_set_ctrl(struct v4l2_ctrl *ctrl)
434d953e3cbSShawn Tu {
435d953e3cbSShawn Tu 	struct imx208 *imx208 =
436d953e3cbSShawn Tu 		container_of(ctrl->handler, struct imx208, ctrl_handler);
437d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
438d953e3cbSShawn Tu 	int ret;
439d953e3cbSShawn Tu 
440d953e3cbSShawn Tu 	/*
441d953e3cbSShawn Tu 	 * Applying V4L2 control value only happens
442d953e3cbSShawn Tu 	 * when power is up for streaming
443d953e3cbSShawn Tu 	 */
444d953e3cbSShawn Tu 	if (!pm_runtime_get_if_in_use(&client->dev))
445d953e3cbSShawn Tu 		return 0;
446d953e3cbSShawn Tu 
447d953e3cbSShawn Tu 	switch (ctrl->id) {
448d953e3cbSShawn Tu 	case V4L2_CID_ANALOGUE_GAIN:
449d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, IMX208_REG_ANALOG_GAIN,
450d953e3cbSShawn Tu 				       2, ctrl->val);
451d953e3cbSShawn Tu 		break;
452d953e3cbSShawn Tu 	case V4L2_CID_EXPOSURE:
453d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, IMX208_REG_EXPOSURE,
454d953e3cbSShawn Tu 				       2, ctrl->val);
455d953e3cbSShawn Tu 		break;
456d953e3cbSShawn Tu 	case V4L2_CID_DIGITAL_GAIN:
457d953e3cbSShawn Tu 		ret = imx208_update_digital_gain(imx208, 2, ctrl->val);
458d953e3cbSShawn Tu 		break;
459d953e3cbSShawn Tu 	case V4L2_CID_VBLANK:
460d953e3cbSShawn Tu 		/* Update VTS that meets expected vertical blanking */
461d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, IMX208_REG_VTS, 2,
462d953e3cbSShawn Tu 				       imx208->cur_mode->height + ctrl->val);
463d953e3cbSShawn Tu 		break;
464d953e3cbSShawn Tu 	case V4L2_CID_TEST_PATTERN:
465d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, IMX208_REG_TEST_PATTERN_MODE,
466d953e3cbSShawn Tu 				       2, imx208_test_pattern_val[ctrl->val]);
467d953e3cbSShawn Tu 		break;
468d953e3cbSShawn Tu 	case V4L2_CID_HFLIP:
469d953e3cbSShawn Tu 	case V4L2_CID_VFLIP:
470d953e3cbSShawn Tu 		ret = imx208_write_reg(imx208, IMX208_REG_ORIENTATION_CONTROL,
471d953e3cbSShawn Tu 				       1,
472d953e3cbSShawn Tu 				       imx208->hflip->val |
473d953e3cbSShawn Tu 				       imx208->vflip->val << 1);
474d953e3cbSShawn Tu 		break;
475d953e3cbSShawn Tu 	default:
476d953e3cbSShawn Tu 		ret = -EINVAL;
477d953e3cbSShawn Tu 		dev_err(&client->dev,
478d953e3cbSShawn Tu 			"ctrl(id:0x%x,val:0x%x) is not handled\n",
479d953e3cbSShawn Tu 			ctrl->id, ctrl->val);
480d953e3cbSShawn Tu 		break;
481d953e3cbSShawn Tu 	}
482d953e3cbSShawn Tu 
483d953e3cbSShawn Tu 	pm_runtime_put(&client->dev);
484d953e3cbSShawn Tu 
485d953e3cbSShawn Tu 	return ret;
486d953e3cbSShawn Tu }
487d953e3cbSShawn Tu 
488d953e3cbSShawn Tu static const struct v4l2_ctrl_ops imx208_ctrl_ops = {
489d953e3cbSShawn Tu 	.s_ctrl = imx208_set_ctrl,
490d953e3cbSShawn Tu };
491d953e3cbSShawn Tu 
492d953e3cbSShawn Tu static const struct v4l2_ctrl_config imx208_digital_gain_control = {
493d953e3cbSShawn Tu 	.ops = &imx208_ctrl_ops,
494d953e3cbSShawn Tu 	.id = V4L2_CID_DIGITAL_GAIN,
495d953e3cbSShawn Tu 	.name = "Digital Gain",
496d953e3cbSShawn Tu 	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
497d953e3cbSShawn Tu 	.min = 0,
498d953e3cbSShawn Tu 	.max = ARRAY_SIZE(imx208_discrete_digital_gain) - 1,
499d953e3cbSShawn Tu 	.step = 0,
500d953e3cbSShawn Tu 	.def = 0,
501d953e3cbSShawn Tu 	.menu_skip_mask = 0,
502d953e3cbSShawn Tu 	.qmenu_int = imx208_discrete_digital_gain,
503d953e3cbSShawn Tu };
504d953e3cbSShawn Tu 
imx208_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)505d953e3cbSShawn Tu static int imx208_enum_mbus_code(struct v4l2_subdev *sd,
5060d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
507d953e3cbSShawn Tu 				 struct v4l2_subdev_mbus_code_enum *code)
508d953e3cbSShawn Tu {
509d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
510d953e3cbSShawn Tu 
511d953e3cbSShawn Tu 	if (code->index > 0)
512d953e3cbSShawn Tu 		return -EINVAL;
513d953e3cbSShawn Tu 
514d953e3cbSShawn Tu 	code->code = imx208_get_format_code(imx208);
515d953e3cbSShawn Tu 
516d953e3cbSShawn Tu 	return 0;
517d953e3cbSShawn Tu }
518d953e3cbSShawn Tu 
imx208_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)519d953e3cbSShawn Tu static int imx208_enum_frame_size(struct v4l2_subdev *sd,
5200d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
521d953e3cbSShawn Tu 				  struct v4l2_subdev_frame_size_enum *fse)
522d953e3cbSShawn Tu {
523d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
524d953e3cbSShawn Tu 
525d953e3cbSShawn Tu 	if (fse->index >= ARRAY_SIZE(supported_modes))
526d953e3cbSShawn Tu 		return -EINVAL;
527d953e3cbSShawn Tu 
528d953e3cbSShawn Tu 	if (fse->code != imx208_get_format_code(imx208))
529d953e3cbSShawn Tu 		return -EINVAL;
530d953e3cbSShawn Tu 
531d953e3cbSShawn Tu 	fse->min_width = supported_modes[fse->index].width;
532d953e3cbSShawn Tu 	fse->max_width = fse->min_width;
533d953e3cbSShawn Tu 	fse->min_height = supported_modes[fse->index].height;
534d953e3cbSShawn Tu 	fse->max_height = fse->min_height;
535d953e3cbSShawn Tu 
536d953e3cbSShawn Tu 	return 0;
537d953e3cbSShawn Tu }
538d953e3cbSShawn Tu 
imx208_mode_to_pad_format(struct imx208 * imx208,const struct imx208_mode * mode,struct v4l2_subdev_format * fmt)539d953e3cbSShawn Tu static void imx208_mode_to_pad_format(struct imx208 *imx208,
540d953e3cbSShawn Tu 				      const struct imx208_mode *mode,
541d953e3cbSShawn Tu 				      struct v4l2_subdev_format *fmt)
542d953e3cbSShawn Tu {
543d953e3cbSShawn Tu 	fmt->format.width = mode->width;
544d953e3cbSShawn Tu 	fmt->format.height = mode->height;
545d953e3cbSShawn Tu 	fmt->format.code = imx208_get_format_code(imx208);
546d953e3cbSShawn Tu 	fmt->format.field = V4L2_FIELD_NONE;
547d953e3cbSShawn Tu }
548d953e3cbSShawn Tu 
__imx208_get_pad_format(struct imx208 * imx208,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)549d953e3cbSShawn Tu static int __imx208_get_pad_format(struct imx208 *imx208,
5500d346d2aSTomi Valkeinen 				   struct v4l2_subdev_state *sd_state,
551d953e3cbSShawn Tu 				   struct v4l2_subdev_format *fmt)
552d953e3cbSShawn Tu {
553d953e3cbSShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
5540d346d2aSTomi Valkeinen 		fmt->format = *v4l2_subdev_get_try_format(&imx208->sd,
5550d346d2aSTomi Valkeinen 							  sd_state,
556d953e3cbSShawn Tu 							  fmt->pad);
557d953e3cbSShawn Tu 	else
558d953e3cbSShawn Tu 		imx208_mode_to_pad_format(imx208, imx208->cur_mode, fmt);
559d953e3cbSShawn Tu 
560d953e3cbSShawn Tu 	return 0;
561d953e3cbSShawn Tu }
562d953e3cbSShawn Tu 
imx208_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)563d953e3cbSShawn Tu static int imx208_get_pad_format(struct v4l2_subdev *sd,
5640d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
565d953e3cbSShawn Tu 				 struct v4l2_subdev_format *fmt)
566d953e3cbSShawn Tu {
567d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
568d953e3cbSShawn Tu 	int ret;
569d953e3cbSShawn Tu 
570d953e3cbSShawn Tu 	mutex_lock(&imx208->imx208_mx);
5710d346d2aSTomi Valkeinen 	ret = __imx208_get_pad_format(imx208, sd_state, fmt);
572d953e3cbSShawn Tu 	mutex_unlock(&imx208->imx208_mx);
573d953e3cbSShawn Tu 
574d953e3cbSShawn Tu 	return ret;
575d953e3cbSShawn Tu }
576d953e3cbSShawn Tu 
imx208_set_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)577d953e3cbSShawn Tu static int imx208_set_pad_format(struct v4l2_subdev *sd,
5780d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
579d953e3cbSShawn Tu 				 struct v4l2_subdev_format *fmt)
580d953e3cbSShawn Tu {
581d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
582d953e3cbSShawn Tu 	const struct imx208_mode *mode;
583d953e3cbSShawn Tu 	s32 vblank_def;
584d953e3cbSShawn Tu 	s32 vblank_min;
585d953e3cbSShawn Tu 	s64 h_blank;
586d953e3cbSShawn Tu 	s64 pixel_rate;
587d953e3cbSShawn Tu 	s64 link_freq;
588d953e3cbSShawn Tu 
589d953e3cbSShawn Tu 	mutex_lock(&imx208->imx208_mx);
590d953e3cbSShawn Tu 
591d953e3cbSShawn Tu 	fmt->format.code = imx208_get_format_code(imx208);
592d953e3cbSShawn Tu 	mode = v4l2_find_nearest_size(supported_modes,
593d953e3cbSShawn Tu 				      ARRAY_SIZE(supported_modes), width, height,
594d953e3cbSShawn Tu 				      fmt->format.width, fmt->format.height);
595d953e3cbSShawn Tu 	imx208_mode_to_pad_format(imx208, mode, fmt);
596d953e3cbSShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
5970d346d2aSTomi Valkeinen 		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
598d953e3cbSShawn Tu 	} else {
599d953e3cbSShawn Tu 		imx208->cur_mode = mode;
600d953e3cbSShawn Tu 		__v4l2_ctrl_s_ctrl(imx208->link_freq, mode->link_freq_index);
601d953e3cbSShawn Tu 		link_freq = link_freq_menu_items[mode->link_freq_index];
602d953e3cbSShawn Tu 		pixel_rate = link_freq_to_pixel_rate(link_freq);
603d953e3cbSShawn Tu 		__v4l2_ctrl_s_ctrl_int64(imx208->pixel_rate, pixel_rate);
604d953e3cbSShawn Tu 		/* Update limits and set FPS to default */
605d953e3cbSShawn Tu 		vblank_def = imx208->cur_mode->vts_def -
606d953e3cbSShawn Tu 			     imx208->cur_mode->height;
607d953e3cbSShawn Tu 		vblank_min = imx208->cur_mode->vts_min -
608d953e3cbSShawn Tu 			     imx208->cur_mode->height;
609d953e3cbSShawn Tu 		__v4l2_ctrl_modify_range(imx208->vblank, vblank_min,
610d953e3cbSShawn Tu 					 IMX208_VTS_MAX - imx208->cur_mode->height,
611d953e3cbSShawn Tu 					 1, vblank_def);
612d953e3cbSShawn Tu 		__v4l2_ctrl_s_ctrl(imx208->vblank, vblank_def);
613d953e3cbSShawn Tu 		h_blank =
614d953e3cbSShawn Tu 			link_freq_configs[mode->link_freq_index].pixels_per_line
615d953e3cbSShawn Tu 			 - imx208->cur_mode->width;
616d953e3cbSShawn Tu 		__v4l2_ctrl_modify_range(imx208->hblank, h_blank,
617d953e3cbSShawn Tu 					 h_blank, 1, h_blank);
618d953e3cbSShawn Tu 	}
619d953e3cbSShawn Tu 
620d953e3cbSShawn Tu 	mutex_unlock(&imx208->imx208_mx);
621d953e3cbSShawn Tu 
622d953e3cbSShawn Tu 	return 0;
623d953e3cbSShawn Tu }
624d953e3cbSShawn Tu 
imx208_identify_module(struct imx208 * imx208)62556ca3be8SBingbu Cao static int imx208_identify_module(struct imx208 *imx208)
62656ca3be8SBingbu Cao {
62756ca3be8SBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
62856ca3be8SBingbu Cao 	int ret;
62956ca3be8SBingbu Cao 	u32 val;
63056ca3be8SBingbu Cao 
63156ca3be8SBingbu Cao 	if (imx208->identified)
63256ca3be8SBingbu Cao 		return 0;
63356ca3be8SBingbu Cao 
63456ca3be8SBingbu Cao 	ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID,
63556ca3be8SBingbu Cao 			      2, &val);
63656ca3be8SBingbu Cao 	if (ret) {
63756ca3be8SBingbu Cao 		dev_err(&client->dev, "failed to read chip id %x\n",
63856ca3be8SBingbu Cao 			IMX208_CHIP_ID);
63956ca3be8SBingbu Cao 		return ret;
64056ca3be8SBingbu Cao 	}
64156ca3be8SBingbu Cao 
64256ca3be8SBingbu Cao 	if (val != IMX208_CHIP_ID) {
64356ca3be8SBingbu Cao 		dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
64456ca3be8SBingbu Cao 			IMX208_CHIP_ID, val);
64556ca3be8SBingbu Cao 		return -EIO;
64656ca3be8SBingbu Cao 	}
64756ca3be8SBingbu Cao 
64856ca3be8SBingbu Cao 	imx208->identified = true;
64956ca3be8SBingbu Cao 
65056ca3be8SBingbu Cao 	return 0;
65156ca3be8SBingbu Cao }
65256ca3be8SBingbu Cao 
653d953e3cbSShawn Tu /* Start streaming */
imx208_start_streaming(struct imx208 * imx208)654d953e3cbSShawn Tu static int imx208_start_streaming(struct imx208 *imx208)
655d953e3cbSShawn Tu {
656d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
657d953e3cbSShawn Tu 	const struct imx208_reg_list *reg_list;
658d953e3cbSShawn Tu 	int ret, link_freq_index;
659d953e3cbSShawn Tu 
66056ca3be8SBingbu Cao 	ret = imx208_identify_module(imx208);
66156ca3be8SBingbu Cao 	if (ret)
66256ca3be8SBingbu Cao 		return ret;
66356ca3be8SBingbu Cao 
664d953e3cbSShawn Tu 	/* Setup PLL */
665d953e3cbSShawn Tu 	link_freq_index = imx208->cur_mode->link_freq_index;
666d953e3cbSShawn Tu 	reg_list = &link_freq_configs[link_freq_index].reg_list;
667d953e3cbSShawn Tu 	ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
668d953e3cbSShawn Tu 	if (ret) {
669d953e3cbSShawn Tu 		dev_err(&client->dev, "%s failed to set plls\n", __func__);
670d953e3cbSShawn Tu 		return ret;
671d953e3cbSShawn Tu 	}
672d953e3cbSShawn Tu 
673d953e3cbSShawn Tu 	/* Apply default values of current mode */
674d953e3cbSShawn Tu 	reg_list = &imx208->cur_mode->reg_list;
675d953e3cbSShawn Tu 	ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
676d953e3cbSShawn Tu 	if (ret) {
677d953e3cbSShawn Tu 		dev_err(&client->dev, "%s failed to set mode\n", __func__);
678d953e3cbSShawn Tu 		return ret;
679d953e3cbSShawn Tu 	}
680d953e3cbSShawn Tu 
681d953e3cbSShawn Tu 	/* Apply customized values from user */
682d953e3cbSShawn Tu 	ret =  __v4l2_ctrl_handler_setup(imx208->sd.ctrl_handler);
683d953e3cbSShawn Tu 	if (ret)
684d953e3cbSShawn Tu 		return ret;
685d953e3cbSShawn Tu 
686d953e3cbSShawn Tu 	/* set stream on register */
687d953e3cbSShawn Tu 	return imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
688d953e3cbSShawn Tu 				1, IMX208_MODE_STREAMING);
689d953e3cbSShawn Tu }
690d953e3cbSShawn Tu 
691d953e3cbSShawn Tu /* Stop streaming */
imx208_stop_streaming(struct imx208 * imx208)692d953e3cbSShawn Tu static int imx208_stop_streaming(struct imx208 *imx208)
693d953e3cbSShawn Tu {
694d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
695d953e3cbSShawn Tu 	int ret;
696d953e3cbSShawn Tu 
697d953e3cbSShawn Tu 	/* set stream off register */
698d953e3cbSShawn Tu 	ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
699d953e3cbSShawn Tu 			       1, IMX208_MODE_STANDBY);
700d953e3cbSShawn Tu 	if (ret)
701d953e3cbSShawn Tu 		dev_err(&client->dev, "%s failed to set stream\n", __func__);
702d953e3cbSShawn Tu 
703d953e3cbSShawn Tu 	/*
704d953e3cbSShawn Tu 	 * Return success even if it was an error, as there is nothing the
705d953e3cbSShawn Tu 	 * caller can do about it.
706d953e3cbSShawn Tu 	 */
707d953e3cbSShawn Tu 	return 0;
708d953e3cbSShawn Tu }
709d953e3cbSShawn Tu 
imx208_set_stream(struct v4l2_subdev * sd,int enable)710d953e3cbSShawn Tu static int imx208_set_stream(struct v4l2_subdev *sd, int enable)
711d953e3cbSShawn Tu {
712d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
713d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(sd);
714d953e3cbSShawn Tu 	int ret = 0;
715d953e3cbSShawn Tu 
716d953e3cbSShawn Tu 	mutex_lock(&imx208->imx208_mx);
717d953e3cbSShawn Tu 	if (imx208->streaming == enable) {
718d953e3cbSShawn Tu 		mutex_unlock(&imx208->imx208_mx);
719d953e3cbSShawn Tu 		return 0;
720d953e3cbSShawn Tu 	}
721d953e3cbSShawn Tu 
722d953e3cbSShawn Tu 	if (enable) {
723d953e3cbSShawn Tu 		ret = pm_runtime_get_sync(&client->dev);
724d953e3cbSShawn Tu 		if (ret < 0)
725d953e3cbSShawn Tu 			goto err_rpm_put;
726d953e3cbSShawn Tu 
727d953e3cbSShawn Tu 		/*
728d953e3cbSShawn Tu 		 * Apply default & customized values
729d953e3cbSShawn Tu 		 * and then start streaming.
730d953e3cbSShawn Tu 		 */
731d953e3cbSShawn Tu 		ret = imx208_start_streaming(imx208);
732d953e3cbSShawn Tu 		if (ret)
733d953e3cbSShawn Tu 			goto err_rpm_put;
734d953e3cbSShawn Tu 	} else {
735d953e3cbSShawn Tu 		imx208_stop_streaming(imx208);
736d953e3cbSShawn Tu 		pm_runtime_put(&client->dev);
737d953e3cbSShawn Tu 	}
738d953e3cbSShawn Tu 
739d953e3cbSShawn Tu 	imx208->streaming = enable;
740d953e3cbSShawn Tu 	mutex_unlock(&imx208->imx208_mx);
741d953e3cbSShawn Tu 
742d953e3cbSShawn Tu 	/* vflip and hflip cannot change during streaming */
743d953e3cbSShawn Tu 	v4l2_ctrl_grab(imx208->vflip, enable);
744d953e3cbSShawn Tu 	v4l2_ctrl_grab(imx208->hflip, enable);
745d953e3cbSShawn Tu 
746d953e3cbSShawn Tu 	return ret;
747d953e3cbSShawn Tu 
748d953e3cbSShawn Tu err_rpm_put:
749d953e3cbSShawn Tu 	pm_runtime_put(&client->dev);
750d953e3cbSShawn Tu 	mutex_unlock(&imx208->imx208_mx);
751d953e3cbSShawn Tu 
752d953e3cbSShawn Tu 	return ret;
753d953e3cbSShawn Tu }
754d953e3cbSShawn Tu 
imx208_suspend(struct device * dev)755d953e3cbSShawn Tu static int __maybe_unused imx208_suspend(struct device *dev)
756d953e3cbSShawn Tu {
757d953e3cbSShawn Tu 	struct i2c_client *client = to_i2c_client(dev);
758d953e3cbSShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
759d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
760d953e3cbSShawn Tu 
761d953e3cbSShawn Tu 	if (imx208->streaming)
762d953e3cbSShawn Tu 		imx208_stop_streaming(imx208);
763d953e3cbSShawn Tu 
764d953e3cbSShawn Tu 	return 0;
765d953e3cbSShawn Tu }
766d953e3cbSShawn Tu 
imx208_resume(struct device * dev)767d953e3cbSShawn Tu static int __maybe_unused imx208_resume(struct device *dev)
768d953e3cbSShawn Tu {
769d953e3cbSShawn Tu 	struct i2c_client *client = to_i2c_client(dev);
770d953e3cbSShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
771d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
772d953e3cbSShawn Tu 	int ret;
773d953e3cbSShawn Tu 
774d953e3cbSShawn Tu 	if (imx208->streaming) {
775d953e3cbSShawn Tu 		ret = imx208_start_streaming(imx208);
776d953e3cbSShawn Tu 		if (ret)
777d953e3cbSShawn Tu 			goto error;
778d953e3cbSShawn Tu 	}
779d953e3cbSShawn Tu 
780d953e3cbSShawn Tu 	return 0;
781d953e3cbSShawn Tu 
782d953e3cbSShawn Tu error:
783d953e3cbSShawn Tu 	imx208_stop_streaming(imx208);
784d953e3cbSShawn Tu 	imx208->streaming = 0;
785d953e3cbSShawn Tu 
786d953e3cbSShawn Tu 	return ret;
787d953e3cbSShawn Tu }
788d953e3cbSShawn Tu 
789d953e3cbSShawn Tu /* Verify chip ID */
790d953e3cbSShawn Tu static const struct v4l2_subdev_video_ops imx208_video_ops = {
791d953e3cbSShawn Tu 	.s_stream = imx208_set_stream,
792d953e3cbSShawn Tu };
793d953e3cbSShawn Tu 
794d953e3cbSShawn Tu static const struct v4l2_subdev_pad_ops imx208_pad_ops = {
795d953e3cbSShawn Tu 	.enum_mbus_code = imx208_enum_mbus_code,
796d953e3cbSShawn Tu 	.get_fmt = imx208_get_pad_format,
797d953e3cbSShawn Tu 	.set_fmt = imx208_set_pad_format,
798d953e3cbSShawn Tu 	.enum_frame_size = imx208_enum_frame_size,
799d953e3cbSShawn Tu };
800d953e3cbSShawn Tu 
801d953e3cbSShawn Tu static const struct v4l2_subdev_ops imx208_subdev_ops = {
802d953e3cbSShawn Tu 	.video = &imx208_video_ops,
803d953e3cbSShawn Tu 	.pad = &imx208_pad_ops,
804d953e3cbSShawn Tu };
805d953e3cbSShawn Tu 
806d953e3cbSShawn Tu static const struct v4l2_subdev_internal_ops imx208_internal_ops = {
807d953e3cbSShawn Tu 	.open = imx208_open,
808d953e3cbSShawn Tu };
809d953e3cbSShawn Tu 
imx208_read_otp(struct imx208 * imx208)810d953e3cbSShawn Tu static int imx208_read_otp(struct imx208 *imx208)
811d953e3cbSShawn Tu {
812d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
813d953e3cbSShawn Tu 	struct i2c_msg msgs[2];
814d953e3cbSShawn Tu 	u8 addr_buf[2] = { IMX208_OTP_BASE >> 8, IMX208_OTP_BASE & 0xff };
815d953e3cbSShawn Tu 	int ret = 0;
816d953e3cbSShawn Tu 
817d953e3cbSShawn Tu 	mutex_lock(&imx208->imx208_mx);
818d953e3cbSShawn Tu 
819d953e3cbSShawn Tu 	if (imx208->otp_read)
820d953e3cbSShawn Tu 		goto out_unlock;
821d953e3cbSShawn Tu 
822d953e3cbSShawn Tu 	ret = pm_runtime_get_sync(&client->dev);
823d953e3cbSShawn Tu 	if (ret < 0) {
824d953e3cbSShawn Tu 		pm_runtime_put_noidle(&client->dev);
825d953e3cbSShawn Tu 		goto out_unlock;
826d953e3cbSShawn Tu 	}
827d953e3cbSShawn Tu 
82856ca3be8SBingbu Cao 	ret = imx208_identify_module(imx208);
82956ca3be8SBingbu Cao 	if (ret)
83056ca3be8SBingbu Cao 		goto out_pm_put;
83156ca3be8SBingbu Cao 
832d953e3cbSShawn Tu 	/* Write register address */
833d953e3cbSShawn Tu 	msgs[0].addr = client->addr;
834d953e3cbSShawn Tu 	msgs[0].flags = 0;
835d953e3cbSShawn Tu 	msgs[0].len = ARRAY_SIZE(addr_buf);
836d953e3cbSShawn Tu 	msgs[0].buf = addr_buf;
837d953e3cbSShawn Tu 
838d953e3cbSShawn Tu 	/* Read data from registers */
839d953e3cbSShawn Tu 	msgs[1].addr = client->addr;
840d953e3cbSShawn Tu 	msgs[1].flags = I2C_M_RD;
841d953e3cbSShawn Tu 	msgs[1].len = sizeof(imx208->otp_data);
842d953e3cbSShawn Tu 	msgs[1].buf = imx208->otp_data;
843d953e3cbSShawn Tu 
844d953e3cbSShawn Tu 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
845d953e3cbSShawn Tu 	if (ret == ARRAY_SIZE(msgs)) {
846d953e3cbSShawn Tu 		imx208->otp_read = true;
847d953e3cbSShawn Tu 		ret = 0;
848d953e3cbSShawn Tu 	}
849d953e3cbSShawn Tu 
85056ca3be8SBingbu Cao out_pm_put:
851d953e3cbSShawn Tu 	pm_runtime_put(&client->dev);
852d953e3cbSShawn Tu 
853d953e3cbSShawn Tu out_unlock:
854d953e3cbSShawn Tu 	mutex_unlock(&imx208->imx208_mx);
855d953e3cbSShawn Tu 
856d953e3cbSShawn Tu 	return ret;
857d953e3cbSShawn Tu }
858d953e3cbSShawn Tu 
otp_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)859d953e3cbSShawn Tu static ssize_t otp_read(struct file *filp, struct kobject *kobj,
860d953e3cbSShawn Tu 			struct bin_attribute *bin_attr,
861d953e3cbSShawn Tu 			char *buf, loff_t off, size_t count)
862d953e3cbSShawn Tu {
863d953e3cbSShawn Tu 	struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj));
864d953e3cbSShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
865d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
866d953e3cbSShawn Tu 	int ret;
867d953e3cbSShawn Tu 
868d953e3cbSShawn Tu 	ret = imx208_read_otp(imx208);
869d953e3cbSShawn Tu 	if (ret)
870d953e3cbSShawn Tu 		return ret;
871d953e3cbSShawn Tu 
872d953e3cbSShawn Tu 	memcpy(buf, &imx208->otp_data[off], count);
873d953e3cbSShawn Tu 	return count;
874d953e3cbSShawn Tu }
875d953e3cbSShawn Tu 
876d953e3cbSShawn Tu static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE);
877d953e3cbSShawn Tu 
878d953e3cbSShawn Tu /* Initialize control handlers */
imx208_init_controls(struct imx208 * imx208)879d953e3cbSShawn Tu static int imx208_init_controls(struct imx208 *imx208)
880d953e3cbSShawn Tu {
881d953e3cbSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
882d953e3cbSShawn Tu 	struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler;
883d953e3cbSShawn Tu 	s64 exposure_max;
884d953e3cbSShawn Tu 	s64 vblank_def;
885d953e3cbSShawn Tu 	s64 vblank_min;
886d953e3cbSShawn Tu 	s64 pixel_rate_min;
887d953e3cbSShawn Tu 	s64 pixel_rate_max;
888d953e3cbSShawn Tu 	int ret;
889d953e3cbSShawn Tu 
890d953e3cbSShawn Tu 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
891d953e3cbSShawn Tu 	if (ret)
892d953e3cbSShawn Tu 		return ret;
893d953e3cbSShawn Tu 
894d953e3cbSShawn Tu 	mutex_init(&imx208->imx208_mx);
895d953e3cbSShawn Tu 	ctrl_hdlr->lock = &imx208->imx208_mx;
896d953e3cbSShawn Tu 	imx208->link_freq =
897d953e3cbSShawn Tu 		v4l2_ctrl_new_int_menu(ctrl_hdlr,
898d953e3cbSShawn Tu 				       &imx208_ctrl_ops,
899d953e3cbSShawn Tu 				       V4L2_CID_LINK_FREQ,
900d953e3cbSShawn Tu 				       ARRAY_SIZE(link_freq_menu_items) - 1,
901d953e3cbSShawn Tu 				       0, link_freq_menu_items);
902d953e3cbSShawn Tu 
903d953e3cbSShawn Tu 	if (imx208->link_freq)
904d953e3cbSShawn Tu 		imx208->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
905d953e3cbSShawn Tu 
906d953e3cbSShawn Tu 	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
907d953e3cbSShawn Tu 	pixel_rate_min =
908d953e3cbSShawn Tu 		link_freq_to_pixel_rate(link_freq_menu_items[ARRAY_SIZE(link_freq_menu_items) - 1]);
909d953e3cbSShawn Tu 	/* By default, PIXEL_RATE is read only */
910d953e3cbSShawn Tu 	imx208->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
911d953e3cbSShawn Tu 					       V4L2_CID_PIXEL_RATE,
912d953e3cbSShawn Tu 					       pixel_rate_min, pixel_rate_max,
913d953e3cbSShawn Tu 					       1, pixel_rate_max);
914d953e3cbSShawn Tu 
915d953e3cbSShawn Tu 	vblank_def = imx208->cur_mode->vts_def - imx208->cur_mode->height;
916d953e3cbSShawn Tu 	vblank_min = imx208->cur_mode->vts_min - imx208->cur_mode->height;
917d953e3cbSShawn Tu 	imx208->vblank =
918d953e3cbSShawn Tu 		v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_VBLANK,
919d953e3cbSShawn Tu 				  vblank_min,
920d953e3cbSShawn Tu 				  IMX208_VTS_MAX - imx208->cur_mode->height, 1,
921d953e3cbSShawn Tu 				  vblank_def);
922d953e3cbSShawn Tu 
923d953e3cbSShawn Tu 	imx208->hblank =
924d953e3cbSShawn Tu 		v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_HBLANK,
925d953e3cbSShawn Tu 				  IMX208_PPL_384MHZ - imx208->cur_mode->width,
926d953e3cbSShawn Tu 				  IMX208_PPL_384MHZ - imx208->cur_mode->width,
927d953e3cbSShawn Tu 				  1,
928d953e3cbSShawn Tu 				  IMX208_PPL_384MHZ - imx208->cur_mode->width);
929d953e3cbSShawn Tu 
930d953e3cbSShawn Tu 	if (imx208->hblank)
931d953e3cbSShawn Tu 		imx208->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
932d953e3cbSShawn Tu 
933d953e3cbSShawn Tu 	exposure_max = imx208->cur_mode->vts_def - 8;
934d953e3cbSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_EXPOSURE,
935d953e3cbSShawn Tu 			  IMX208_EXPOSURE_MIN, exposure_max,
936d953e3cbSShawn Tu 			  IMX208_EXPOSURE_STEP, IMX208_EXPOSURE_DEFAULT);
937d953e3cbSShawn Tu 
938d953e3cbSShawn Tu 	imx208->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
939d953e3cbSShawn Tu 					  V4L2_CID_HFLIP, 0, 1, 1, 0);
940f19ba70fSDave Stevenson 	if (imx208->hflip)
941f19ba70fSDave Stevenson 		imx208->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
942d953e3cbSShawn Tu 	imx208->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
943d953e3cbSShawn Tu 					  V4L2_CID_VFLIP, 0, 1, 1, 0);
944f19ba70fSDave Stevenson 	if (imx208->vflip)
945f19ba70fSDave Stevenson 		imx208->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
946d953e3cbSShawn Tu 
947d953e3cbSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
948d953e3cbSShawn Tu 			  IMX208_ANA_GAIN_MIN, IMX208_ANA_GAIN_MAX,
949d953e3cbSShawn Tu 			  IMX208_ANA_GAIN_STEP, IMX208_ANA_GAIN_DEFAULT);
950d953e3cbSShawn Tu 
951d953e3cbSShawn Tu 	v4l2_ctrl_new_custom(ctrl_hdlr, &imx208_digital_gain_control, NULL);
952d953e3cbSShawn Tu 
953d953e3cbSShawn Tu 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx208_ctrl_ops,
954d953e3cbSShawn Tu 				     V4L2_CID_TEST_PATTERN,
955d953e3cbSShawn Tu 				     ARRAY_SIZE(imx208_test_pattern_menu) - 1,
956d953e3cbSShawn Tu 				     0, 0, imx208_test_pattern_menu);
957d953e3cbSShawn Tu 
958d953e3cbSShawn Tu 	if (ctrl_hdlr->error) {
959d953e3cbSShawn Tu 		ret = ctrl_hdlr->error;
960d953e3cbSShawn Tu 		dev_err(&client->dev, "%s control init failed (%d)\n",
961d953e3cbSShawn Tu 			__func__, ret);
962d953e3cbSShawn Tu 		goto error;
963d953e3cbSShawn Tu 	}
964d953e3cbSShawn Tu 
965d953e3cbSShawn Tu 	imx208->sd.ctrl_handler = ctrl_hdlr;
966d953e3cbSShawn Tu 
967d953e3cbSShawn Tu 	return 0;
968d953e3cbSShawn Tu 
969d953e3cbSShawn Tu error:
970d953e3cbSShawn Tu 	v4l2_ctrl_handler_free(ctrl_hdlr);
971d953e3cbSShawn Tu 	mutex_destroy(&imx208->imx208_mx);
972d953e3cbSShawn Tu 
973d953e3cbSShawn Tu 	return ret;
974d953e3cbSShawn Tu }
975d953e3cbSShawn Tu 
imx208_free_controls(struct imx208 * imx208)976d953e3cbSShawn Tu static void imx208_free_controls(struct imx208 *imx208)
977d953e3cbSShawn Tu {
978d953e3cbSShawn Tu 	v4l2_ctrl_handler_free(imx208->sd.ctrl_handler);
979d953e3cbSShawn Tu }
980d953e3cbSShawn Tu 
imx208_probe(struct i2c_client * client)981d953e3cbSShawn Tu static int imx208_probe(struct i2c_client *client)
982d953e3cbSShawn Tu {
983d953e3cbSShawn Tu 	struct imx208 *imx208;
984d953e3cbSShawn Tu 	int ret;
98556ca3be8SBingbu Cao 	bool full_power;
986d953e3cbSShawn Tu 	u32 val = 0;
987d953e3cbSShawn Tu 
988d953e3cbSShawn Tu 	device_property_read_u32(&client->dev, "clock-frequency", &val);
989d953e3cbSShawn Tu 	if (val != 19200000) {
990d953e3cbSShawn Tu 		dev_err(&client->dev,
991d953e3cbSShawn Tu 			"Unsupported clock-frequency %u. Expected 19200000.\n",
992d953e3cbSShawn Tu 			val);
993d953e3cbSShawn Tu 		return -EINVAL;
994d953e3cbSShawn Tu 	}
995d953e3cbSShawn Tu 
996d953e3cbSShawn Tu 	imx208 = devm_kzalloc(&client->dev, sizeof(*imx208), GFP_KERNEL);
997d953e3cbSShawn Tu 	if (!imx208)
998d953e3cbSShawn Tu 		return -ENOMEM;
999d953e3cbSShawn Tu 
1000d953e3cbSShawn Tu 	/* Initialize subdev */
1001d953e3cbSShawn Tu 	v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops);
1002d953e3cbSShawn Tu 
100356ca3be8SBingbu Cao 	full_power = acpi_dev_state_d0(&client->dev);
100456ca3be8SBingbu Cao 	if (full_power) {
1005d953e3cbSShawn Tu 		/* Check module identity */
1006d953e3cbSShawn Tu 		ret = imx208_identify_module(imx208);
1007d953e3cbSShawn Tu 		if (ret) {
1008d953e3cbSShawn Tu 			dev_err(&client->dev, "failed to find sensor: %d", ret);
1009d953e3cbSShawn Tu 			goto error_probe;
1010d953e3cbSShawn Tu 		}
101156ca3be8SBingbu Cao 	}
1012d953e3cbSShawn Tu 
1013d953e3cbSShawn Tu 	/* Set default mode to max resolution */
1014d953e3cbSShawn Tu 	imx208->cur_mode = &supported_modes[0];
1015d953e3cbSShawn Tu 
1016d953e3cbSShawn Tu 	ret = imx208_init_controls(imx208);
1017d953e3cbSShawn Tu 	if (ret) {
1018d953e3cbSShawn Tu 		dev_err(&client->dev, "failed to init controls: %d", ret);
1019d953e3cbSShawn Tu 		goto error_probe;
1020d953e3cbSShawn Tu 	}
1021d953e3cbSShawn Tu 
1022d953e3cbSShawn Tu 	/* Initialize subdev */
1023d953e3cbSShawn Tu 	imx208->sd.internal_ops = &imx208_internal_ops;
1024d953e3cbSShawn Tu 	imx208->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1025d953e3cbSShawn Tu 	imx208->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1026d953e3cbSShawn Tu 
1027d953e3cbSShawn Tu 	/* Initialize source pad */
1028d953e3cbSShawn Tu 	imx208->pad.flags = MEDIA_PAD_FL_SOURCE;
1029d953e3cbSShawn Tu 	ret = media_entity_pads_init(&imx208->sd.entity, 1, &imx208->pad);
1030d953e3cbSShawn Tu 	if (ret) {
1031d953e3cbSShawn Tu 		dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
1032d953e3cbSShawn Tu 		goto error_handler_free;
1033d953e3cbSShawn Tu 	}
1034d953e3cbSShawn Tu 
1035d953e3cbSShawn Tu 	ret = v4l2_async_register_subdev_sensor(&imx208->sd);
1036d953e3cbSShawn Tu 	if (ret < 0)
1037d953e3cbSShawn Tu 		goto error_media_entity;
1038d953e3cbSShawn Tu 
1039d953e3cbSShawn Tu 	ret = device_create_bin_file(&client->dev, &bin_attr_otp);
1040d953e3cbSShawn Tu 	if (ret) {
1041d953e3cbSShawn Tu 		dev_err(&client->dev, "sysfs otp creation failed\n");
1042d953e3cbSShawn Tu 		goto error_async_subdev;
1043d953e3cbSShawn Tu 	}
1044d953e3cbSShawn Tu 
104556ca3be8SBingbu Cao 	/* Set the device's state to active if it's in D0 state. */
104656ca3be8SBingbu Cao 	if (full_power)
1047d953e3cbSShawn Tu 		pm_runtime_set_active(&client->dev);
1048d953e3cbSShawn Tu 	pm_runtime_enable(&client->dev);
1049d953e3cbSShawn Tu 	pm_runtime_idle(&client->dev);
1050d953e3cbSShawn Tu 
1051d953e3cbSShawn Tu 	return 0;
1052d953e3cbSShawn Tu 
1053d953e3cbSShawn Tu error_async_subdev:
1054d953e3cbSShawn Tu 	v4l2_async_unregister_subdev(&imx208->sd);
1055d953e3cbSShawn Tu 
1056d953e3cbSShawn Tu error_media_entity:
1057d953e3cbSShawn Tu 	media_entity_cleanup(&imx208->sd.entity);
1058d953e3cbSShawn Tu 
1059d953e3cbSShawn Tu error_handler_free:
1060d953e3cbSShawn Tu 	imx208_free_controls(imx208);
1061d953e3cbSShawn Tu 
1062d953e3cbSShawn Tu error_probe:
1063d953e3cbSShawn Tu 	mutex_destroy(&imx208->imx208_mx);
1064d953e3cbSShawn Tu 
1065d953e3cbSShawn Tu 	return ret;
1066d953e3cbSShawn Tu }
1067d953e3cbSShawn Tu 
imx208_remove(struct i2c_client * client)1068ed5c2f5fSUwe Kleine-König static void imx208_remove(struct i2c_client *client)
1069d953e3cbSShawn Tu {
1070d953e3cbSShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1071d953e3cbSShawn Tu 	struct imx208 *imx208 = to_imx208(sd);
1072d953e3cbSShawn Tu 
1073d953e3cbSShawn Tu 	device_remove_bin_file(&client->dev, &bin_attr_otp);
1074d953e3cbSShawn Tu 	v4l2_async_unregister_subdev(sd);
1075d953e3cbSShawn Tu 	media_entity_cleanup(&sd->entity);
1076d953e3cbSShawn Tu 	imx208_free_controls(imx208);
1077d953e3cbSShawn Tu 
1078d953e3cbSShawn Tu 	pm_runtime_disable(&client->dev);
1079d953e3cbSShawn Tu 	pm_runtime_set_suspended(&client->dev);
1080d953e3cbSShawn Tu 
1081d953e3cbSShawn Tu 	mutex_destroy(&imx208->imx208_mx);
1082d953e3cbSShawn Tu }
1083d953e3cbSShawn Tu 
1084d953e3cbSShawn Tu static const struct dev_pm_ops imx208_pm_ops = {
1085d953e3cbSShawn Tu 	SET_SYSTEM_SLEEP_PM_OPS(imx208_suspend, imx208_resume)
1086d953e3cbSShawn Tu };
1087d953e3cbSShawn Tu 
1088d953e3cbSShawn Tu #ifdef CONFIG_ACPI
1089d953e3cbSShawn Tu static const struct acpi_device_id imx208_acpi_ids[] = {
1090d953e3cbSShawn Tu 	{ "INT3478" },
1091d953e3cbSShawn Tu 	{ /* sentinel */ }
1092d953e3cbSShawn Tu };
1093d953e3cbSShawn Tu 
1094d953e3cbSShawn Tu MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids);
1095d953e3cbSShawn Tu #endif
1096d953e3cbSShawn Tu 
1097d953e3cbSShawn Tu static struct i2c_driver imx208_i2c_driver = {
1098d953e3cbSShawn Tu 	.driver = {
1099d953e3cbSShawn Tu 		.name = "imx208",
1100d953e3cbSShawn Tu 		.pm = &imx208_pm_ops,
1101d953e3cbSShawn Tu 		.acpi_match_table = ACPI_PTR(imx208_acpi_ids),
1102d953e3cbSShawn Tu 	},
1103aaeb31c0SUwe Kleine-König 	.probe = imx208_probe,
1104d953e3cbSShawn Tu 	.remove = imx208_remove,
110556ca3be8SBingbu Cao 	.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
1106d953e3cbSShawn Tu };
1107d953e3cbSShawn Tu 
1108d953e3cbSShawn Tu module_i2c_driver(imx208_i2c_driver);
1109d953e3cbSShawn Tu 
1110d953e3cbSShawn Tu MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
1111d953e3cbSShawn Tu MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@intel.com>");
1112*4106cd72SSakari Ailus MODULE_AUTHOR("Shawn Tu");
1113d953e3cbSShawn Tu MODULE_DESCRIPTION("Sony IMX208 sensor driver");
1114d953e3cbSShawn Tu MODULE_LICENSE("GPL v2");
1115