xref: /openbmc/linux/drivers/media/i2c/imx296.c (revision 7c7e33b7)
1cb33db2bSLaurent Pinchart // SPDX-License-Identifier: GPL-2.0
2cb33db2bSLaurent Pinchart /*
3cb33db2bSLaurent Pinchart  * Driver for IMX296 CMOS Image Sensor from Sony
4cb33db2bSLaurent Pinchart  *
5cb33db2bSLaurent Pinchart  * Copyright 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
6cb33db2bSLaurent Pinchart  */
7cb33db2bSLaurent Pinchart 
8cb33db2bSLaurent Pinchart #include <linux/clk.h>
9cb33db2bSLaurent Pinchart #include <linux/gpio/consumer.h>
10cb33db2bSLaurent Pinchart #include <linux/i2c.h>
11cb33db2bSLaurent Pinchart #include <linux/module.h>
12*7c7e33b7SRob Herring #include <linux/of.h>
13cb33db2bSLaurent Pinchart #include <linux/pm_runtime.h>
14cb33db2bSLaurent Pinchart #include <linux/regmap.h>
15cb33db2bSLaurent Pinchart #include <linux/regulator/consumer.h>
16cb33db2bSLaurent Pinchart #include <linux/slab.h>
17cb33db2bSLaurent Pinchart #include <linux/videodev2.h>
18cb33db2bSLaurent Pinchart 
19cb33db2bSLaurent Pinchart #include <media/v4l2-ctrls.h>
20cb33db2bSLaurent Pinchart #include <media/v4l2-fwnode.h>
21cb33db2bSLaurent Pinchart #include <media/v4l2-subdev.h>
22cb33db2bSLaurent Pinchart 
23cb33db2bSLaurent Pinchart #define IMX296_PIXEL_ARRAY_WIDTH			1456
24cb33db2bSLaurent Pinchart #define IMX296_PIXEL_ARRAY_HEIGHT			1088
25cb33db2bSLaurent Pinchart 
26cb33db2bSLaurent Pinchart #define IMX296_REG_8BIT(n)				((1 << 16) | (n))
27cb33db2bSLaurent Pinchart #define IMX296_REG_16BIT(n)				((2 << 16) | (n))
28cb33db2bSLaurent Pinchart #define IMX296_REG_24BIT(n)				((3 << 16) | (n))
29cb33db2bSLaurent Pinchart #define IMX296_REG_SIZE_SHIFT				16
30cb33db2bSLaurent Pinchart #define IMX296_REG_ADDR_MASK				0xffff
31cb33db2bSLaurent Pinchart 
32cb33db2bSLaurent Pinchart #define IMX296_CTRL00					IMX296_REG_8BIT(0x3000)
33cb33db2bSLaurent Pinchart #define IMX296_CTRL00_STANDBY				BIT(0)
34cb33db2bSLaurent Pinchart #define IMX296_CTRL08					IMX296_REG_8BIT(0x3008)
35cb33db2bSLaurent Pinchart #define IMX296_CTRL08_REGHOLD				BIT(0)
36cb33db2bSLaurent Pinchart #define IMX296_CTRL0A					IMX296_REG_8BIT(0x300a)
37cb33db2bSLaurent Pinchart #define IMX296_CTRL0A_XMSTA				BIT(0)
38cb33db2bSLaurent Pinchart #define IMX296_CTRL0B					IMX296_REG_8BIT(0x300b)
39cb33db2bSLaurent Pinchart #define IMX296_CTRL0B_TRIGEN				BIT(0)
40cb33db2bSLaurent Pinchart #define IMX296_CTRL0D					IMX296_REG_8BIT(0x300d)
41cb33db2bSLaurent Pinchart #define IMX296_CTRL0D_WINMODE_ALL			(0 << 0)
42cb33db2bSLaurent Pinchart #define IMX296_CTRL0D_WINMODE_FD_BINNING		(2 << 0)
43cb33db2bSLaurent Pinchart #define IMX296_CTRL0D_HADD_ON_BINNING			BIT(5)
44cb33db2bSLaurent Pinchart #define IMX296_CTRL0D_SAT_CNT				BIT(6)
45cb33db2bSLaurent Pinchart #define IMX296_CTRL0E					IMX296_REG_8BIT(0x300e)
46cb33db2bSLaurent Pinchart #define IMX296_CTRL0E_VREVERSE				BIT(0)
47cb33db2bSLaurent Pinchart #define IMX296_CTRL0E_HREVERSE				BIT(1)
48cb33db2bSLaurent Pinchart #define IMX296_VMAX					IMX296_REG_24BIT(0x3010)
49cb33db2bSLaurent Pinchart #define IMX296_HMAX					IMX296_REG_16BIT(0x3014)
50cb33db2bSLaurent Pinchart #define IMX296_TMDCTRL					IMX296_REG_8BIT(0x301d)
51cb33db2bSLaurent Pinchart #define IMX296_TMDCTRL_LATCH				BIT(0)
52cb33db2bSLaurent Pinchart #define IMX296_TMDOUT					IMX296_REG_16BIT(0x301e)
53cb33db2bSLaurent Pinchart #define IMX296_TMDOUT_MASK				0x3ff
54cb33db2bSLaurent Pinchart #define IMX296_WDSEL					IMX296_REG_8BIT(0x3021)
55cb33db2bSLaurent Pinchart #define IMX296_WDSEL_NORMAL				(0 << 0)
56cb33db2bSLaurent Pinchart #define IMX296_WDSEL_MULTI_2				(1 << 0)
57cb33db2bSLaurent Pinchart #define IMX296_WDSEL_MULTI_4				(3 << 0)
58cb33db2bSLaurent Pinchart #define IMX296_BLKLEVELAUTO				IMX296_REG_8BIT(0x3022)
59cb33db2bSLaurent Pinchart #define IMX296_BLKLEVELAUTO_ON				0x01
60cb33db2bSLaurent Pinchart #define IMX296_BLKLEVELAUTO_OFF				0xf0
61cb33db2bSLaurent Pinchart #define IMX296_SST					IMX296_REG_8BIT(0x3024)
62cb33db2bSLaurent Pinchart #define IMX296_SST_EN					BIT(0)
63cb33db2bSLaurent Pinchart #define IMX296_CTRLTOUT					IMX296_REG_8BIT(0x3026)
64cb33db2bSLaurent Pinchart #define IMX296_CTRLTOUT_TOUT1SEL_LOW			(0 << 0)
65cb33db2bSLaurent Pinchart #define IMX296_CTRLTOUT_TOUT1SEL_PULSE			(3 << 0)
66cb33db2bSLaurent Pinchart #define IMX296_CTRLTOUT_TOUT2SEL_LOW			(0 << 2)
67cb33db2bSLaurent Pinchart #define IMX296_CTRLTOUT_TOUT2SEL_PULSE			(3 << 2)
68cb33db2bSLaurent Pinchart #define IMX296_CTRLTRIG					IMX296_REG_8BIT(0x3029)
69cb33db2bSLaurent Pinchart #define IMX296_CTRLTRIG_TOUT1_SEL_LOW			(0 << 0)
70cb33db2bSLaurent Pinchart #define IMX296_CTRLTRIG_TOUT1_SEL_PULSE1		(1 << 0)
71cb33db2bSLaurent Pinchart #define IMX296_CTRLTRIG_TOUT2_SEL_LOW			(0 << 4)
72cb33db2bSLaurent Pinchart #define IMX296_CTRLTRIG_TOUT2_SEL_PULSE2		(2 << 4)
73cb33db2bSLaurent Pinchart #define IMX296_SYNCSEL					IMX296_REG_8BIT(0x3036)
74cb33db2bSLaurent Pinchart #define IMX296_SYNCSEL_NORMAL				0xc0
75cb33db2bSLaurent Pinchart #define IMX296_SYNCSEL_HIZ				0xf0
76cb33db2bSLaurent Pinchart #define IMX296_PULSE1					IMX296_REG_8BIT(0x306d)
77cb33db2bSLaurent Pinchart #define IMX296_PULSE1_EN_NOR				BIT(0)
78cb33db2bSLaurent Pinchart #define IMX296_PULSE1_EN_TRIG				BIT(1)
79cb33db2bSLaurent Pinchart #define IMX296_PULSE1_POL_HIGH				(0 << 2)
80cb33db2bSLaurent Pinchart #define IMX296_PULSE1_POL_LOW				(1 << 2)
81cb33db2bSLaurent Pinchart #define IMX296_PULSE1_UP				IMX296_REG_24BIT(0x3070)
82cb33db2bSLaurent Pinchart #define IMX296_PULSE1_DN				IMX296_REG_24BIT(0x3074)
83cb33db2bSLaurent Pinchart #define IMX296_PULSE2					IMX296_REG_8BIT(0x3079)
84cb33db2bSLaurent Pinchart #define IMX296_PULSE2_EN_NOR				BIT(0)
85cb33db2bSLaurent Pinchart #define IMX296_PULSE2_EN_TRIG				BIT(1)
86cb33db2bSLaurent Pinchart #define IMX296_PULSE2_POL_HIGH				(0 << 2)
87cb33db2bSLaurent Pinchart #define IMX296_PULSE2_POL_LOW				(1 << 2)
88cb33db2bSLaurent Pinchart #define IMX296_PULSE2_UP				IMX296_REG_24BIT(0x307c)
89cb33db2bSLaurent Pinchart #define IMX296_PULSE2_DN				IMX296_REG_24BIT(0x3080)
90cb33db2bSLaurent Pinchart #define IMX296_INCKSEL(n)				IMX296_REG_8BIT(0x3089 + (n))
91cb33db2bSLaurent Pinchart #define IMX296_SHS1					IMX296_REG_24BIT(0x308d)
92cb33db2bSLaurent Pinchart #define IMX296_SHS2					IMX296_REG_24BIT(0x3090)
93cb33db2bSLaurent Pinchart #define IMX296_SHS3					IMX296_REG_24BIT(0x3094)
94cb33db2bSLaurent Pinchart #define IMX296_SHS4					IMX296_REG_24BIT(0x3098)
95cb33db2bSLaurent Pinchart #define IMX296_VBLANKLP					IMX296_REG_8BIT(0x309c)
96cb33db2bSLaurent Pinchart #define IMX296_VBLANKLP_NORMAL				0x04
97cb33db2bSLaurent Pinchart #define IMX296_VBLANKLP_LOW_POWER			0x2c
98cb33db2bSLaurent Pinchart #define IMX296_EXP_CNT					IMX296_REG_8BIT(0x30a3)
99cb33db2bSLaurent Pinchart #define IMX296_EXP_CNT_RESET				BIT(0)
100cb33db2bSLaurent Pinchart #define IMX296_EXP_MAX					IMX296_REG_16BIT(0x30a6)
101cb33db2bSLaurent Pinchart #define IMX296_VINT					IMX296_REG_8BIT(0x30aa)
102cb33db2bSLaurent Pinchart #define IMX296_VINT_EN					BIT(0)
103cb33db2bSLaurent Pinchart #define IMX296_LOWLAGTRG				IMX296_REG_8BIT(0x30ae)
104cb33db2bSLaurent Pinchart #define IMX296_LOWLAGTRG_FAST				BIT(0)
105cb33db2bSLaurent Pinchart #define IMX296_I2CCTRL					IMX296_REG_8BIT(0x30ef)
106cb33db2bSLaurent Pinchart #define IMX296_I2CCTRL_I2CACKEN				BIT(0)
107cb33db2bSLaurent Pinchart 
108cb33db2bSLaurent Pinchart #define IMX296_SENSOR_INFO				IMX296_REG_16BIT(0x3148)
109cb33db2bSLaurent Pinchart #define IMX296_SENSOR_INFO_MONO				BIT(15)
110cb33db2bSLaurent Pinchart #define IMX296_SENSOR_INFO_IMX296LQ			0x4a00
111cb33db2bSLaurent Pinchart #define IMX296_SENSOR_INFO_IMX296LL			0xca00
112cb33db2bSLaurent Pinchart #define IMX296_S_SHSA					IMX296_REG_16BIT(0x31ca)
113cb33db2bSLaurent Pinchart #define IMX296_S_SHSB					IMX296_REG_16BIT(0x31d2)
114cb33db2bSLaurent Pinchart /*
115cb33db2bSLaurent Pinchart  * Registers 0x31c8 to 0x31cd, 0x31d0 to 0x31d5, 0x31e2, 0x31e3, 0x31ea and
116cb33db2bSLaurent Pinchart  * 0x31eb are related to exposure mode but otherwise not documented.
117cb33db2bSLaurent Pinchart  */
118cb33db2bSLaurent Pinchart 
119cb33db2bSLaurent Pinchart #define IMX296_GAINCTRL					IMX296_REG_8BIT(0x3200)
120cb33db2bSLaurent Pinchart #define IMX296_GAINCTRL_WD_GAIN_MODE_NORMAL		0x01
121cb33db2bSLaurent Pinchart #define IMX296_GAINCTRL_WD_GAIN_MODE_MULTI		0x41
122cb33db2bSLaurent Pinchart #define IMX296_GAIN					IMX296_REG_16BIT(0x3204)
123cb33db2bSLaurent Pinchart #define IMX296_GAIN_MIN					0
124cb33db2bSLaurent Pinchart #define IMX296_GAIN_MAX					480
125cb33db2bSLaurent Pinchart #define IMX296_GAIN1					IMX296_REG_16BIT(0x3208)
126cb33db2bSLaurent Pinchart #define IMX296_GAIN2					IMX296_REG_16BIT(0x320c)
127cb33db2bSLaurent Pinchart #define IMX296_GAIN3					IMX296_REG_16BIT(0x3210)
128cb33db2bSLaurent Pinchart #define IMX296_GAINDLY					IMX296_REG_8BIT(0x3212)
129cb33db2bSLaurent Pinchart #define IMX296_GAINDLY_NONE				0x08
130cb33db2bSLaurent Pinchart #define IMX296_GAINDLY_1FRAME				0x09
131cb33db2bSLaurent Pinchart #define IMX296_PGCTRL					IMX296_REG_8BIT(0x3238)
132cb33db2bSLaurent Pinchart #define IMX296_PGCTRL_REGEN				BIT(0)
133cb33db2bSLaurent Pinchart #define IMX296_PGCTRL_THRU				BIT(1)
134cb33db2bSLaurent Pinchart #define IMX296_PGCTRL_CLKEN				BIT(2)
135cb33db2bSLaurent Pinchart #define IMX296_PGCTRL_MODE(n)				((n) << 3)
136cb33db2bSLaurent Pinchart #define IMX296_PGHPOS					IMX296_REG_16BIT(0x3239)
137cb33db2bSLaurent Pinchart #define IMX296_PGVPOS					IMX296_REG_16BIT(0x323c)
138cb33db2bSLaurent Pinchart #define IMX296_PGHPSTEP					IMX296_REG_8BIT(0x323e)
139cb33db2bSLaurent Pinchart #define IMX296_PGVPSTEP					IMX296_REG_8BIT(0x323f)
140cb33db2bSLaurent Pinchart #define IMX296_PGHPNUM					IMX296_REG_8BIT(0x3240)
141cb33db2bSLaurent Pinchart #define IMX296_PGVPNUM					IMX296_REG_8BIT(0x3241)
142cb33db2bSLaurent Pinchart #define IMX296_PGDATA1					IMX296_REG_16BIT(0x3244)
143cb33db2bSLaurent Pinchart #define IMX296_PGDATA2					IMX296_REG_16BIT(0x3246)
144cb33db2bSLaurent Pinchart #define IMX296_PGHGSTEP					IMX296_REG_8BIT(0x3249)
145cb33db2bSLaurent Pinchart #define IMX296_BLKLEVEL					IMX296_REG_16BIT(0x3254)
146cb33db2bSLaurent Pinchart 
147cb33db2bSLaurent Pinchart #define IMX296_FID0_ROI					IMX296_REG_8BIT(0x3300)
148cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIH1ON				BIT(0)
149cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIV1ON				BIT(1)
150cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIPH1				IMX296_REG_16BIT(0x3310)
151cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIPV1				IMX296_REG_16BIT(0x3312)
152cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIWH1				IMX296_REG_16BIT(0x3314)
153cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIWH1_MIN				80
154cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIWV1				IMX296_REG_16BIT(0x3316)
155cb33db2bSLaurent Pinchart #define IMX296_FID0_ROIWV1_MIN				4
156cb33db2bSLaurent Pinchart 
157cb33db2bSLaurent Pinchart #define IMX296_CM_HSST_STARTTMG				IMX296_REG_16BIT(0x4018)
158cb33db2bSLaurent Pinchart #define IMX296_CM_HSST_ENDTMG				IMX296_REG_16BIT(0x401a)
159cb33db2bSLaurent Pinchart #define IMX296_DA_HSST_STARTTMG				IMX296_REG_16BIT(0x404d)
160cb33db2bSLaurent Pinchart #define IMX296_DA_HSST_ENDTMG				IMX296_REG_16BIT(0x4050)
161cb33db2bSLaurent Pinchart #define IMX296_LM_HSST_STARTTMG				IMX296_REG_16BIT(0x4094)
162cb33db2bSLaurent Pinchart #define IMX296_LM_HSST_ENDTMG				IMX296_REG_16BIT(0x4096)
163cb33db2bSLaurent Pinchart #define IMX296_SST_SIEASTA1_SET				IMX296_REG_8BIT(0x40c9)
164cb33db2bSLaurent Pinchart #define IMX296_SST_SIEASTA1PRE_1U			IMX296_REG_16BIT(0x40cc)
165cb33db2bSLaurent Pinchart #define IMX296_SST_SIEASTA1PRE_1D			IMX296_REG_16BIT(0x40ce)
166cb33db2bSLaurent Pinchart #define IMX296_SST_SIEASTA1PRE_2U			IMX296_REG_16BIT(0x40d0)
167cb33db2bSLaurent Pinchart #define IMX296_SST_SIEASTA1PRE_2D			IMX296_REG_16BIT(0x40d2)
168cb33db2bSLaurent Pinchart #define IMX296_HSST					IMX296_REG_8BIT(0x40dc)
169cb33db2bSLaurent Pinchart #define IMX296_HSST_EN					BIT(2)
170cb33db2bSLaurent Pinchart 
171cb33db2bSLaurent Pinchart #define IMX296_CKREQSEL					IMX296_REG_8BIT(0x4101)
172cb33db2bSLaurent Pinchart #define IMX296_CKREQSEL_HS				BIT(2)
173cb33db2bSLaurent Pinchart #define IMX296_GTTABLENUM				IMX296_REG_8BIT(0x4114)
174cb33db2bSLaurent Pinchart #define IMX296_CTRL418C					IMX296_REG_8BIT(0x418c)
175cb33db2bSLaurent Pinchart 
176cb33db2bSLaurent Pinchart struct imx296_clk_params {
177cb33db2bSLaurent Pinchart 	unsigned int freq;
178cb33db2bSLaurent Pinchart 	u8 incksel[4];
179cb33db2bSLaurent Pinchart 	u8 ctrl418c;
180cb33db2bSLaurent Pinchart };
181cb33db2bSLaurent Pinchart 
182cb33db2bSLaurent Pinchart static const struct imx296_clk_params imx296_clk_params[] = {
183cb33db2bSLaurent Pinchart 	{ 37125000, { 0x80, 0x0b, 0x80, 0x08 }, 116 },
184cb33db2bSLaurent Pinchart 	{ 54000000, { 0xb0, 0x0f, 0xb0, 0x0c }, 168 },
185cb33db2bSLaurent Pinchart 	{ 74250000, { 0x80, 0x0f, 0x80, 0x0c }, 232 },
186cb33db2bSLaurent Pinchart };
187cb33db2bSLaurent Pinchart 
188cb33db2bSLaurent Pinchart static const char * const imx296_supply_names[] = {
189cb33db2bSLaurent Pinchart 	"dvdd",
190cb33db2bSLaurent Pinchart 	"ovdd",
191cb33db2bSLaurent Pinchart 	"avdd",
192cb33db2bSLaurent Pinchart };
193cb33db2bSLaurent Pinchart 
194cb33db2bSLaurent Pinchart struct imx296 {
195cb33db2bSLaurent Pinchart 	struct device *dev;
196cb33db2bSLaurent Pinchart 	struct clk *clk;
197cb33db2bSLaurent Pinchart 	struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)];
198cb33db2bSLaurent Pinchart 	struct gpio_desc *reset;
199cb33db2bSLaurent Pinchart 	struct regmap *regmap;
200cb33db2bSLaurent Pinchart 
201cb33db2bSLaurent Pinchart 	const struct imx296_clk_params *clk_params;
202cb33db2bSLaurent Pinchart 	bool mono;
203cb33db2bSLaurent Pinchart 
204cb33db2bSLaurent Pinchart 	bool streaming;
205cb33db2bSLaurent Pinchart 
206cb33db2bSLaurent Pinchart 	struct v4l2_subdev subdev;
207cb33db2bSLaurent Pinchart 	struct media_pad pad;
208cb33db2bSLaurent Pinchart 
209cb33db2bSLaurent Pinchart 	struct v4l2_ctrl_handler ctrls;
210cb33db2bSLaurent Pinchart 	struct v4l2_ctrl *hblank;
211cb33db2bSLaurent Pinchart 	struct v4l2_ctrl *vblank;
212cb33db2bSLaurent Pinchart };
213cb33db2bSLaurent Pinchart 
to_imx296(struct v4l2_subdev * sd)214cb33db2bSLaurent Pinchart static inline struct imx296 *to_imx296(struct v4l2_subdev *sd)
215cb33db2bSLaurent Pinchart {
216cb33db2bSLaurent Pinchart 	return container_of(sd, struct imx296, subdev);
217cb33db2bSLaurent Pinchart }
218cb33db2bSLaurent Pinchart 
imx296_read(struct imx296 * sensor,u32 addr)219cb33db2bSLaurent Pinchart static int imx296_read(struct imx296 *sensor, u32 addr)
220cb33db2bSLaurent Pinchart {
221cb33db2bSLaurent Pinchart 	u8 data[3] = { 0, 0, 0 };
222cb33db2bSLaurent Pinchart 	int ret;
223cb33db2bSLaurent Pinchart 
224cb33db2bSLaurent Pinchart 	ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data,
225cb33db2bSLaurent Pinchart 			      (addr >> IMX296_REG_SIZE_SHIFT) & 3);
226cb33db2bSLaurent Pinchart 	if (ret < 0)
227cb33db2bSLaurent Pinchart 		return ret;
228cb33db2bSLaurent Pinchart 
229cb33db2bSLaurent Pinchart 	return (data[2] << 16) | (data[1] << 8) | data[0];
230cb33db2bSLaurent Pinchart }
231cb33db2bSLaurent Pinchart 
imx296_write(struct imx296 * sensor,u32 addr,u32 value,int * err)232cb33db2bSLaurent Pinchart static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err)
233cb33db2bSLaurent Pinchart {
234cb33db2bSLaurent Pinchart 	u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
235cb33db2bSLaurent Pinchart 	int ret;
236cb33db2bSLaurent Pinchart 
237cb33db2bSLaurent Pinchart 	if (err && *err)
238cb33db2bSLaurent Pinchart 		return *err;
239cb33db2bSLaurent Pinchart 
240cb33db2bSLaurent Pinchart 	ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK,
241cb33db2bSLaurent Pinchart 			       data, (addr >> IMX296_REG_SIZE_SHIFT) & 3);
242cb33db2bSLaurent Pinchart 	if (ret < 0) {
243cb33db2bSLaurent Pinchart 		dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n",
244cb33db2bSLaurent Pinchart 			((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8,
245cb33db2bSLaurent Pinchart 			addr & IMX296_REG_ADDR_MASK, ret);
246cb33db2bSLaurent Pinchart 		if (err)
247cb33db2bSLaurent Pinchart 			*err = ret;
248cb33db2bSLaurent Pinchart 	}
249cb33db2bSLaurent Pinchart 
250cb33db2bSLaurent Pinchart 	return ret;
251cb33db2bSLaurent Pinchart }
252cb33db2bSLaurent Pinchart 
imx296_power_on(struct imx296 * sensor)253cb33db2bSLaurent Pinchart static int imx296_power_on(struct imx296 *sensor)
254cb33db2bSLaurent Pinchart {
255cb33db2bSLaurent Pinchart 	int ret;
256cb33db2bSLaurent Pinchart 
257cb33db2bSLaurent Pinchart 	ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
258cb33db2bSLaurent Pinchart 				    sensor->supplies);
259cb33db2bSLaurent Pinchart 	if (ret < 0)
260cb33db2bSLaurent Pinchart 		return ret;
261cb33db2bSLaurent Pinchart 
262cb33db2bSLaurent Pinchart 	udelay(1);
263cb33db2bSLaurent Pinchart 
264cb33db2bSLaurent Pinchart 	ret = gpiod_direction_output(sensor->reset, 0);
265cb33db2bSLaurent Pinchart 	if (ret < 0)
266cb33db2bSLaurent Pinchart 		goto err_supply;
267cb33db2bSLaurent Pinchart 
268cb33db2bSLaurent Pinchart 	udelay(1);
269cb33db2bSLaurent Pinchart 
270cb33db2bSLaurent Pinchart 	ret = clk_prepare_enable(sensor->clk);
271cb33db2bSLaurent Pinchart 	if (ret < 0)
272cb33db2bSLaurent Pinchart 		goto err_reset;
273cb33db2bSLaurent Pinchart 
274cb33db2bSLaurent Pinchart 	/*
275cb33db2bSLaurent Pinchart 	 * The documentation doesn't explicitly say how much time is required
276cb33db2bSLaurent Pinchart 	 * after providing a clock and before starting I2C communication. It
277cb33db2bSLaurent Pinchart 	 * mentions a delay of 20µs in 4-wire mode, but tests showed that a
278cb33db2bSLaurent Pinchart 	 * delay of 100µs resulted in I2C communication failures, while 500µs
279cb33db2bSLaurent Pinchart 	 * seems to be enough. Be conservative.
280cb33db2bSLaurent Pinchart 	 */
281cb33db2bSLaurent Pinchart 	usleep_range(1000, 2000);
282cb33db2bSLaurent Pinchart 
283cb33db2bSLaurent Pinchart 	return 0;
284cb33db2bSLaurent Pinchart 
285cb33db2bSLaurent Pinchart err_reset:
286cb33db2bSLaurent Pinchart 	gpiod_direction_output(sensor->reset, 1);
287cb33db2bSLaurent Pinchart err_supply:
288cb33db2bSLaurent Pinchart 	regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
289cb33db2bSLaurent Pinchart 	return ret;
290cb33db2bSLaurent Pinchart }
291cb33db2bSLaurent Pinchart 
imx296_power_off(struct imx296 * sensor)292cb33db2bSLaurent Pinchart static void imx296_power_off(struct imx296 *sensor)
293cb33db2bSLaurent Pinchart {
294cb33db2bSLaurent Pinchart 	clk_disable_unprepare(sensor->clk);
295cb33db2bSLaurent Pinchart 	gpiod_direction_output(sensor->reset, 1);
296cb33db2bSLaurent Pinchart 	regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
297cb33db2bSLaurent Pinchart }
298cb33db2bSLaurent Pinchart 
299cb33db2bSLaurent Pinchart /* -----------------------------------------------------------------------------
300cb33db2bSLaurent Pinchart  * Controls
301cb33db2bSLaurent Pinchart  */
302cb33db2bSLaurent Pinchart 
303cb33db2bSLaurent Pinchart static const char * const imx296_test_pattern_menu[] = {
304cb33db2bSLaurent Pinchart 	"Disabled",
305cb33db2bSLaurent Pinchart 	"Multiple Pixels",
306cb33db2bSLaurent Pinchart 	"Sequence 1",
307cb33db2bSLaurent Pinchart 	"Sequence 2",
308cb33db2bSLaurent Pinchart 	"Gradient",
309cb33db2bSLaurent Pinchart 	"Row",
310cb33db2bSLaurent Pinchart 	"Column",
311cb33db2bSLaurent Pinchart 	"Cross",
312cb33db2bSLaurent Pinchart 	"Stripe",
313cb33db2bSLaurent Pinchart 	"Checks",
314cb33db2bSLaurent Pinchart };
315cb33db2bSLaurent Pinchart 
imx296_s_ctrl(struct v4l2_ctrl * ctrl)316cb33db2bSLaurent Pinchart static int imx296_s_ctrl(struct v4l2_ctrl *ctrl)
317cb33db2bSLaurent Pinchart {
318cb33db2bSLaurent Pinchart 	struct imx296 *sensor = container_of(ctrl->handler, struct imx296, ctrls);
319cb33db2bSLaurent Pinchart 	const struct v4l2_mbus_framefmt *format;
320cb33db2bSLaurent Pinchart 	struct v4l2_subdev_state *state;
321cb33db2bSLaurent Pinchart 	unsigned int vmax;
322cb33db2bSLaurent Pinchart 	int ret = 0;
323cb33db2bSLaurent Pinchart 
324cb33db2bSLaurent Pinchart 	if (!sensor->streaming)
325cb33db2bSLaurent Pinchart 		return 0;
326cb33db2bSLaurent Pinchart 
327cb33db2bSLaurent Pinchart 	state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
328cb33db2bSLaurent Pinchart 	format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
329cb33db2bSLaurent Pinchart 
330cb33db2bSLaurent Pinchart 	switch (ctrl->id) {
331cb33db2bSLaurent Pinchart 	case V4L2_CID_EXPOSURE:
332cb33db2bSLaurent Pinchart 		/* Clamp the exposure value to VMAX. */
333cb33db2bSLaurent Pinchart 		vmax = format->height + sensor->vblank->cur.val;
334cb33db2bSLaurent Pinchart 		ctrl->val = min_t(int, ctrl->val, vmax);
335cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_SHS1, vmax - ctrl->val, &ret);
336cb33db2bSLaurent Pinchart 		break;
337cb33db2bSLaurent Pinchart 
338cb33db2bSLaurent Pinchart 	case V4L2_CID_ANALOGUE_GAIN:
339cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_GAIN, ctrl->val, &ret);
340cb33db2bSLaurent Pinchart 		break;
341cb33db2bSLaurent Pinchart 
342cb33db2bSLaurent Pinchart 	case V4L2_CID_VBLANK:
343cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_VMAX, format->height + ctrl->val,
344cb33db2bSLaurent Pinchart 			     &ret);
345cb33db2bSLaurent Pinchart 		break;
346cb33db2bSLaurent Pinchart 
347cb33db2bSLaurent Pinchart 	case V4L2_CID_TEST_PATTERN:
348cb33db2bSLaurent Pinchart 		if (ctrl->val) {
349cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGHPOS, 8, &ret);
350cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGVPOS, 8, &ret);
351cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGHPSTEP, 8, &ret);
352cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGVPSTEP, 8, &ret);
353cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGHPNUM, 100, &ret);
354cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGVPNUM, 100, &ret);
355cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGDATA1, 0x300, &ret);
356cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGDATA2, 0x100, &ret);
357cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGHGSTEP, 0, &ret);
358cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_BLKLEVEL, 0, &ret);
359cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_BLKLEVELAUTO,
360cb33db2bSLaurent Pinchart 				     IMX296_BLKLEVELAUTO_OFF, &ret);
361cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGCTRL,
362cb33db2bSLaurent Pinchart 				     IMX296_PGCTRL_REGEN |
363cb33db2bSLaurent Pinchart 				     IMX296_PGCTRL_CLKEN |
364cb33db2bSLaurent Pinchart 				     IMX296_PGCTRL_MODE(ctrl->val - 1), &ret);
365cb33db2bSLaurent Pinchart 		} else {
366cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_PGCTRL,
367cb33db2bSLaurent Pinchart 				     IMX296_PGCTRL_CLKEN, &ret);
368cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_BLKLEVEL, 0x3c, &ret);
369cb33db2bSLaurent Pinchart 			imx296_write(sensor, IMX296_BLKLEVELAUTO,
370cb33db2bSLaurent Pinchart 				     IMX296_BLKLEVELAUTO_ON, &ret);
371cb33db2bSLaurent Pinchart 		}
372cb33db2bSLaurent Pinchart 		break;
373cb33db2bSLaurent Pinchart 
374cb33db2bSLaurent Pinchart 	default:
375cb33db2bSLaurent Pinchart 		ret = -EINVAL;
376cb33db2bSLaurent Pinchart 		break;
377cb33db2bSLaurent Pinchart 	}
378cb33db2bSLaurent Pinchart 
379cb33db2bSLaurent Pinchart 	return ret;
380cb33db2bSLaurent Pinchart }
381cb33db2bSLaurent Pinchart 
382cb33db2bSLaurent Pinchart static const struct v4l2_ctrl_ops imx296_ctrl_ops = {
383cb33db2bSLaurent Pinchart 	.s_ctrl = imx296_s_ctrl,
384cb33db2bSLaurent Pinchart };
385cb33db2bSLaurent Pinchart 
imx296_ctrls_init(struct imx296 * sensor)386cb33db2bSLaurent Pinchart static int imx296_ctrls_init(struct imx296 *sensor)
387cb33db2bSLaurent Pinchart {
388cb33db2bSLaurent Pinchart 	struct v4l2_fwnode_device_properties props;
389cb33db2bSLaurent Pinchart 	unsigned int hblank;
390cb33db2bSLaurent Pinchart 	int ret;
391cb33db2bSLaurent Pinchart 
392cb33db2bSLaurent Pinchart 	ret = v4l2_fwnode_device_parse(sensor->dev, &props);
393cb33db2bSLaurent Pinchart 	if (ret < 0)
394cb33db2bSLaurent Pinchart 		return ret;
395cb33db2bSLaurent Pinchart 
396cb33db2bSLaurent Pinchart 	v4l2_ctrl_handler_init(&sensor->ctrls, 9);
397cb33db2bSLaurent Pinchart 
398cb33db2bSLaurent Pinchart 	v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
399cb33db2bSLaurent Pinchart 			  V4L2_CID_EXPOSURE, 1, 1048575, 1, 1104);
400cb33db2bSLaurent Pinchart 	v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
401cb33db2bSLaurent Pinchart 			  V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
402cb33db2bSLaurent Pinchart 			  IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
403cb33db2bSLaurent Pinchart 
404cb33db2bSLaurent Pinchart 	/*
405cb33db2bSLaurent Pinchart 	 * Horizontal blanking is controlled through the HMAX register, which
406cb33db2bSLaurent Pinchart 	 * contains a line length in INCK clock units. The INCK frequency is
407cb33db2bSLaurent Pinchart 	 * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100,
408cb33db2bSLaurent Pinchart 	 * convert it to a number of pixels based on the nominal pixel rate.
409cb33db2bSLaurent Pinchart 	 */
410cb33db2bSLaurent Pinchart 	hblank = 1100 * 1188000000ULL / 10 / 74250000
411cb33db2bSLaurent Pinchart 	       - IMX296_PIXEL_ARRAY_WIDTH;
412cb33db2bSLaurent Pinchart 	sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
413cb33db2bSLaurent Pinchart 					   V4L2_CID_HBLANK, hblank, hblank, 1,
414cb33db2bSLaurent Pinchart 					   hblank);
415cb33db2bSLaurent Pinchart 	if (sensor->hblank)
416cb33db2bSLaurent Pinchart 		sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
417cb33db2bSLaurent Pinchart 
418cb33db2bSLaurent Pinchart 	sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
419cb33db2bSLaurent Pinchart 					   V4L2_CID_VBLANK, 30,
420cb33db2bSLaurent Pinchart 					   1048575 - IMX296_PIXEL_ARRAY_HEIGHT,
421cb33db2bSLaurent Pinchart 					   1, 30);
422cb33db2bSLaurent Pinchart 	/*
423cb33db2bSLaurent Pinchart 	 * The sensor calculates the MIPI timings internally to achieve a bit
424cb33db2bSLaurent Pinchart 	 * rate between 1122 and 1198 Mbps. The exact value is unfortunately not
425cb33db2bSLaurent Pinchart 	 * reported, at least according to the documentation. Report a nominal
426cb33db2bSLaurent Pinchart 	 * rate of 1188 Mbps as that is used by the datasheet in multiple
427cb33db2bSLaurent Pinchart 	 * examples.
428cb33db2bSLaurent Pinchart 	 */
429cb33db2bSLaurent Pinchart 	v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE,
430cb33db2bSLaurent Pinchart 			  1122000000 / 10, 1198000000 / 10, 1, 1188000000 / 10);
431cb33db2bSLaurent Pinchart 	v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx296_ctrl_ops,
432cb33db2bSLaurent Pinchart 				     V4L2_CID_TEST_PATTERN,
433cb33db2bSLaurent Pinchart 				     ARRAY_SIZE(imx296_test_pattern_menu) - 1,
434cb33db2bSLaurent Pinchart 				     0, 0, imx296_test_pattern_menu);
435cb33db2bSLaurent Pinchart 
436cb33db2bSLaurent Pinchart 	v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx296_ctrl_ops,
437cb33db2bSLaurent Pinchart 					&props);
438cb33db2bSLaurent Pinchart 
439cb33db2bSLaurent Pinchart 	if (sensor->ctrls.error) {
440cb33db2bSLaurent Pinchart 		dev_err(sensor->dev, "failed to add controls (%d)\n",
441cb33db2bSLaurent Pinchart 			sensor->ctrls.error);
442cb33db2bSLaurent Pinchart 		v4l2_ctrl_handler_free(&sensor->ctrls);
443cb33db2bSLaurent Pinchart 		return sensor->ctrls.error;
444cb33db2bSLaurent Pinchart 	}
445cb33db2bSLaurent Pinchart 
446cb33db2bSLaurent Pinchart 	sensor->subdev.ctrl_handler = &sensor->ctrls;
447cb33db2bSLaurent Pinchart 
448cb33db2bSLaurent Pinchart 	return 0;
449cb33db2bSLaurent Pinchart }
450cb33db2bSLaurent Pinchart 
451cb33db2bSLaurent Pinchart /* -----------------------------------------------------------------------------
452cb33db2bSLaurent Pinchart  * V4L2 Subdev Operations
453cb33db2bSLaurent Pinchart  */
454cb33db2bSLaurent Pinchart 
455cb33db2bSLaurent Pinchart /*
456cb33db2bSLaurent Pinchart  * This table is extracted from vendor data that is entirely undocumented. The
457cb33db2bSLaurent Pinchart  * first register write is required to activate the CSI-2 output. The other
458cb33db2bSLaurent Pinchart  * entries may or may not be optional?
459cb33db2bSLaurent Pinchart  */
460cb33db2bSLaurent Pinchart static const struct {
461cb33db2bSLaurent Pinchart 	unsigned int reg;
462cb33db2bSLaurent Pinchart 	unsigned int value;
463cb33db2bSLaurent Pinchart } imx296_init_table[] = {
464cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3005), 0xf0 },
465cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x309e), 0x04 },
466cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30a0), 0x04 },
467cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30a1), 0x3c },
468cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30a4), 0x5f },
469cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30a8), 0x91 },
470cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30ac), 0x28 },
471cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30af), 0x09 },
472cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x30df), 0x00 },
473cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3165), 0x00 },
474cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3169), 0x10 },
475cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x316a), 0x02 },
476cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x31c8), 0xf3 },	/* Exposure-related */
477cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x31d0), 0xf4 },	/* Exposure-related */
478cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x321a), 0x00 },
479cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3226), 0x02 },
480cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3256), 0x01 },
481cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3541), 0x72 },
482cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3516), 0x77 },
483cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x350b), 0x7f },
484cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3758), 0xa3 },
485cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3759), 0x00 },
486cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x375a), 0x85 },
487cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x375b), 0x00 },
488cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3832), 0xf5 },
489cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3833), 0x00 },
490cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x38a2), 0xf6 },
491cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x38a3), 0x00 },
492cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3a00), 0x80 },
493cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3d48), 0xa3 },
494cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3d49), 0x00 },
495cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3d4a), 0x85 },
496cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x3d4b), 0x00 },
497cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x400e), 0x58 },
498cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x4014), 0x1c },
499cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x4041), 0x2a },
500cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x40a2), 0x06 },
501cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x40c1), 0xf6 },
502cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x40c7), 0x0f },
503cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x40c8), 0x00 },
504cb33db2bSLaurent Pinchart 	{ IMX296_REG_8BIT(0x4174), 0x00 },
505cb33db2bSLaurent Pinchart };
506cb33db2bSLaurent Pinchart 
imx296_setup(struct imx296 * sensor,struct v4l2_subdev_state * state)507cb33db2bSLaurent Pinchart static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state)
508cb33db2bSLaurent Pinchart {
509cb33db2bSLaurent Pinchart 	const struct v4l2_mbus_framefmt *format;
510cb33db2bSLaurent Pinchart 	const struct v4l2_rect *crop;
511cb33db2bSLaurent Pinchart 	unsigned int i;
512cb33db2bSLaurent Pinchart 	int ret = 0;
513cb33db2bSLaurent Pinchart 
514cb33db2bSLaurent Pinchart 	format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
515cb33db2bSLaurent Pinchart 	crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0);
516cb33db2bSLaurent Pinchart 
517cb33db2bSLaurent Pinchart 	for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i)
518cb33db2bSLaurent Pinchart 		imx296_write(sensor, imx296_init_table[i].reg,
519cb33db2bSLaurent Pinchart 			     imx296_init_table[i].value, &ret);
520cb33db2bSLaurent Pinchart 
521cb33db2bSLaurent Pinchart 	if (crop->width != IMX296_PIXEL_ARRAY_WIDTH ||
522cb33db2bSLaurent Pinchart 	    crop->height != IMX296_PIXEL_ARRAY_HEIGHT) {
523cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROI,
524cb33db2bSLaurent Pinchart 			     IMX296_FID0_ROIH1ON | IMX296_FID0_ROIV1ON, &ret);
525cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROIPH1, crop->left, &ret);
526cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret);
527cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret);
528cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret);
529cb33db2bSLaurent Pinchart 	} else {
530cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_FID0_ROI, 0, &ret);
531cb33db2bSLaurent Pinchart 	}
532cb33db2bSLaurent Pinchart 
533cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL0D,
534cb33db2bSLaurent Pinchart 		     (crop->width != format->width ?
535cb33db2bSLaurent Pinchart 		      IMX296_CTRL0D_HADD_ON_BINNING : 0) |
536cb33db2bSLaurent Pinchart 		     (crop->height != format->height ?
537cb33db2bSLaurent Pinchart 		      IMX296_CTRL0D_WINMODE_FD_BINNING : 0),
538cb33db2bSLaurent Pinchart 		     &ret);
539cb33db2bSLaurent Pinchart 
540cb33db2bSLaurent Pinchart 	/*
541cb33db2bSLaurent Pinchart 	 * HMAX and VMAX configure horizontal and vertical blanking by
542cb33db2bSLaurent Pinchart 	 * specifying the total line time and frame time respectively. The line
543cb33db2bSLaurent Pinchart 	 * time is specified in operational clock units (which appears to be the
544cb33db2bSLaurent Pinchart 	 * output of an internal PLL, fixed at 74.25 MHz regardless of the
545cb33db2bSLaurent Pinchart 	 * exernal clock frequency), while the frame time is specified as a
546cb33db2bSLaurent Pinchart 	 * number of lines.
547cb33db2bSLaurent Pinchart 	 *
548cb33db2bSLaurent Pinchart 	 * In the vertical direction the sensor outputs the following:
549cb33db2bSLaurent Pinchart 	 *
550cb33db2bSLaurent Pinchart 	 * - one line for the FS packet
551cb33db2bSLaurent Pinchart 	 * - two lines of embedded data (DT 0x12)
552cb33db2bSLaurent Pinchart 	 * - six null lines (DT 0x10)
553cb33db2bSLaurent Pinchart 	 * - four lines of vertical effective optical black (DT 0x37)
554cb33db2bSLaurent Pinchart 	 * - 8 to 1088 lines of active image data (RAW10, DT 0x2b)
555cb33db2bSLaurent Pinchart 	 * - one line for the FE packet
556cb33db2bSLaurent Pinchart 	 * - 16 or more lines of vertical blanking
557cb33db2bSLaurent Pinchart 	 */
558cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_HMAX, 1100, &ret);
559cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_VMAX,
560cb33db2bSLaurent Pinchart 		     format->height + sensor->vblank->cur.val, &ret);
561cb33db2bSLaurent Pinchart 
562cb33db2bSLaurent Pinchart 	for (i = 0; i < ARRAY_SIZE(sensor->clk_params->incksel); ++i)
563cb33db2bSLaurent Pinchart 		imx296_write(sensor, IMX296_INCKSEL(i),
564cb33db2bSLaurent Pinchart 			     sensor->clk_params->incksel[i], &ret);
565cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_GTTABLENUM, 0xc5, &ret);
566cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c,
567cb33db2bSLaurent Pinchart 		     &ret);
568cb33db2bSLaurent Pinchart 
569cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret);
570cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret);
571cb33db2bSLaurent Pinchart 
572cb33db2bSLaurent Pinchart 	return ret;
573cb33db2bSLaurent Pinchart }
574cb33db2bSLaurent Pinchart 
imx296_stream_on(struct imx296 * sensor)575cb33db2bSLaurent Pinchart static int imx296_stream_on(struct imx296 *sensor)
576cb33db2bSLaurent Pinchart {
577cb33db2bSLaurent Pinchart 	int ret = 0;
578cb33db2bSLaurent Pinchart 
579cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL00, 0, &ret);
580cb33db2bSLaurent Pinchart 	usleep_range(2000, 5000);
581cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
582cb33db2bSLaurent Pinchart 
583cb33db2bSLaurent Pinchart 	return ret;
584cb33db2bSLaurent Pinchart }
585cb33db2bSLaurent Pinchart 
imx296_stream_off(struct imx296 * sensor)586cb33db2bSLaurent Pinchart static int imx296_stream_off(struct imx296 *sensor)
587cb33db2bSLaurent Pinchart {
588cb33db2bSLaurent Pinchart 	int ret = 0;
589cb33db2bSLaurent Pinchart 
590cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret);
591cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret);
592cb33db2bSLaurent Pinchart 
593cb33db2bSLaurent Pinchart 	return ret;
594cb33db2bSLaurent Pinchart }
595cb33db2bSLaurent Pinchart 
imx296_s_stream(struct v4l2_subdev * sd,int enable)596cb33db2bSLaurent Pinchart static int imx296_s_stream(struct v4l2_subdev *sd, int enable)
597cb33db2bSLaurent Pinchart {
598cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(sd);
599cb33db2bSLaurent Pinchart 	struct v4l2_subdev_state *state;
600cb33db2bSLaurent Pinchart 	int ret;
601cb33db2bSLaurent Pinchart 
602cb33db2bSLaurent Pinchart 	state = v4l2_subdev_lock_and_get_active_state(sd);
603cb33db2bSLaurent Pinchart 
604cb33db2bSLaurent Pinchart 	if (!enable) {
605cb33db2bSLaurent Pinchart 		ret = imx296_stream_off(sensor);
606cb33db2bSLaurent Pinchart 
607cb33db2bSLaurent Pinchart 		pm_runtime_mark_last_busy(sensor->dev);
608cb33db2bSLaurent Pinchart 		pm_runtime_put_autosuspend(sensor->dev);
609cb33db2bSLaurent Pinchart 
610cb33db2bSLaurent Pinchart 		sensor->streaming = false;
611cb33db2bSLaurent Pinchart 
612cb33db2bSLaurent Pinchart 		goto unlock;
613cb33db2bSLaurent Pinchart 	}
614cb33db2bSLaurent Pinchart 
615cb33db2bSLaurent Pinchart 	ret = pm_runtime_resume_and_get(sensor->dev);
616cb33db2bSLaurent Pinchart 	if (ret < 0)
617cb33db2bSLaurent Pinchart 		goto unlock;
618cb33db2bSLaurent Pinchart 
619cb33db2bSLaurent Pinchart 	ret = imx296_setup(sensor, state);
620cb33db2bSLaurent Pinchart 	if (ret < 0)
621cb33db2bSLaurent Pinchart 		goto err_pm;
622cb33db2bSLaurent Pinchart 
623cb33db2bSLaurent Pinchart 	/*
624cb33db2bSLaurent Pinchart 	 * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set
625cb33db2bSLaurent Pinchart 	 * the controls. The flag is reset to false further down if an error
626cb33db2bSLaurent Pinchart 	 * occurs.
627cb33db2bSLaurent Pinchart 	 */
628cb33db2bSLaurent Pinchart 	sensor->streaming = true;
629cb33db2bSLaurent Pinchart 
630cb33db2bSLaurent Pinchart 	ret = __v4l2_ctrl_handler_setup(&sensor->ctrls);
631cb33db2bSLaurent Pinchart 	if (ret < 0)
632cb33db2bSLaurent Pinchart 		goto err_pm;
633cb33db2bSLaurent Pinchart 
634cb33db2bSLaurent Pinchart 	ret = imx296_stream_on(sensor);
635cb33db2bSLaurent Pinchart 	if (ret)
636cb33db2bSLaurent Pinchart 		goto err_pm;
637cb33db2bSLaurent Pinchart 
638cb33db2bSLaurent Pinchart unlock:
639cb33db2bSLaurent Pinchart 	v4l2_subdev_unlock_state(state);
640cb33db2bSLaurent Pinchart 
641cb33db2bSLaurent Pinchart 	return ret;
642cb33db2bSLaurent Pinchart 
643cb33db2bSLaurent Pinchart err_pm:
644cb33db2bSLaurent Pinchart 	/*
645cb33db2bSLaurent Pinchart 	 * In case of error, turn the power off synchronously as the device
646cb33db2bSLaurent Pinchart 	 * likely has no other chance to recover.
647cb33db2bSLaurent Pinchart 	 */
648cb33db2bSLaurent Pinchart 	pm_runtime_put_sync(sensor->dev);
649cb33db2bSLaurent Pinchart 	sensor->streaming = false;
650cb33db2bSLaurent Pinchart 
651cb33db2bSLaurent Pinchart 	goto unlock;
652cb33db2bSLaurent Pinchart }
653cb33db2bSLaurent Pinchart 
imx296_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_mbus_code_enum * code)654cb33db2bSLaurent Pinchart static int imx296_enum_mbus_code(struct v4l2_subdev *sd,
655cb33db2bSLaurent Pinchart 				 struct v4l2_subdev_state *state,
656cb33db2bSLaurent Pinchart 				 struct v4l2_subdev_mbus_code_enum *code)
657cb33db2bSLaurent Pinchart {
658cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(sd);
659cb33db2bSLaurent Pinchart 
660cb33db2bSLaurent Pinchart 	if (code->index != 0)
661cb33db2bSLaurent Pinchart 		return -EINVAL;
662cb33db2bSLaurent Pinchart 
663cb33db2bSLaurent Pinchart 	code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
664cb33db2bSLaurent Pinchart 		   : MEDIA_BUS_FMT_SBGGR10_1X10;
665cb33db2bSLaurent Pinchart 
666cb33db2bSLaurent Pinchart 	return 0;
667cb33db2bSLaurent Pinchart }
668cb33db2bSLaurent Pinchart 
imx296_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_frame_size_enum * fse)669cb33db2bSLaurent Pinchart static int imx296_enum_frame_size(struct v4l2_subdev *sd,
670cb33db2bSLaurent Pinchart 				  struct v4l2_subdev_state *state,
671cb33db2bSLaurent Pinchart 				  struct v4l2_subdev_frame_size_enum *fse)
672cb33db2bSLaurent Pinchart {
673cb33db2bSLaurent Pinchart 	const struct v4l2_mbus_framefmt *format;
674cb33db2bSLaurent Pinchart 
675cb33db2bSLaurent Pinchart 	format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
676cb33db2bSLaurent Pinchart 
677cb33db2bSLaurent Pinchart 	if (fse->index >= 2 || fse->code != format->code)
678cb33db2bSLaurent Pinchart 		return -EINVAL;
679cb33db2bSLaurent Pinchart 
680cb33db2bSLaurent Pinchart 	fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1);
681cb33db2bSLaurent Pinchart 	fse->max_width = fse->min_width;
682cb33db2bSLaurent Pinchart 	fse->min_height = IMX296_PIXEL_ARRAY_HEIGHT / (fse->index + 1);
683cb33db2bSLaurent Pinchart 	fse->max_height = fse->min_height;
684cb33db2bSLaurent Pinchart 
685cb33db2bSLaurent Pinchart 	return 0;
686cb33db2bSLaurent Pinchart }
687cb33db2bSLaurent Pinchart 
imx296_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_format * fmt)688cb33db2bSLaurent Pinchart static int imx296_set_format(struct v4l2_subdev *sd,
689cb33db2bSLaurent Pinchart 			     struct v4l2_subdev_state *state,
690cb33db2bSLaurent Pinchart 			     struct v4l2_subdev_format *fmt)
691cb33db2bSLaurent Pinchart {
692cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(sd);
693cb33db2bSLaurent Pinchart 	struct v4l2_mbus_framefmt *format;
694cb33db2bSLaurent Pinchart 	struct v4l2_rect *crop;
695cb33db2bSLaurent Pinchart 
696cb33db2bSLaurent Pinchart 	crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad);
697cb33db2bSLaurent Pinchart 	format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
698cb33db2bSLaurent Pinchart 
699cb33db2bSLaurent Pinchart 	/*
700cb33db2bSLaurent Pinchart 	 * Binning is only allowed when cropping is disabled according to the
701cb33db2bSLaurent Pinchart 	 * documentation. This should be double-checked.
702cb33db2bSLaurent Pinchart 	 */
703cb33db2bSLaurent Pinchart 	if (crop->width == IMX296_PIXEL_ARRAY_WIDTH &&
704cb33db2bSLaurent Pinchart 	    crop->height == IMX296_PIXEL_ARRAY_HEIGHT) {
705cb33db2bSLaurent Pinchart 		unsigned int width;
706cb33db2bSLaurent Pinchart 		unsigned int height;
707cb33db2bSLaurent Pinchart 		unsigned int hratio;
708cb33db2bSLaurent Pinchart 		unsigned int vratio;
709cb33db2bSLaurent Pinchart 
710cb33db2bSLaurent Pinchart 		/* Clamp the width and height to avoid dividing by zero. */
711cb33db2bSLaurent Pinchart 		width = clamp_t(unsigned int, fmt->format.width,
712cb33db2bSLaurent Pinchart 				crop->width / 2, crop->width);
713cb33db2bSLaurent Pinchart 		height = clamp_t(unsigned int, fmt->format.height,
714cb33db2bSLaurent Pinchart 				 crop->height / 2, crop->height);
715cb33db2bSLaurent Pinchart 
716cb33db2bSLaurent Pinchart 		hratio = DIV_ROUND_CLOSEST(crop->width, width);
717cb33db2bSLaurent Pinchart 		vratio = DIV_ROUND_CLOSEST(crop->height, height);
718cb33db2bSLaurent Pinchart 
719cb33db2bSLaurent Pinchart 		format->width = crop->width / hratio;
720cb33db2bSLaurent Pinchart 		format->height = crop->height / vratio;
721cb33db2bSLaurent Pinchart 	} else {
722cb33db2bSLaurent Pinchart 		format->width = crop->width;
723cb33db2bSLaurent Pinchart 		format->height = crop->height;
724cb33db2bSLaurent Pinchart 	}
725cb33db2bSLaurent Pinchart 
726cb33db2bSLaurent Pinchart 	format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
727cb33db2bSLaurent Pinchart 		     : MEDIA_BUS_FMT_SBGGR10_1X10;
728cb33db2bSLaurent Pinchart 	format->field = V4L2_FIELD_NONE;
729cb33db2bSLaurent Pinchart 	format->colorspace = V4L2_COLORSPACE_RAW;
730cb33db2bSLaurent Pinchart 	format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
731cb33db2bSLaurent Pinchart 	format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
732cb33db2bSLaurent Pinchart 	format->xfer_func = V4L2_XFER_FUNC_NONE;
733cb33db2bSLaurent Pinchart 
734cb33db2bSLaurent Pinchart 	fmt->format = *format;
735cb33db2bSLaurent Pinchart 
736cb33db2bSLaurent Pinchart 	return 0;
737cb33db2bSLaurent Pinchart }
738cb33db2bSLaurent Pinchart 
imx296_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_selection * sel)739cb33db2bSLaurent Pinchart static int imx296_get_selection(struct v4l2_subdev *sd,
740cb33db2bSLaurent Pinchart 				struct v4l2_subdev_state *state,
741cb33db2bSLaurent Pinchart 				struct v4l2_subdev_selection *sel)
742cb33db2bSLaurent Pinchart {
743cb33db2bSLaurent Pinchart 	switch (sel->target) {
744cb33db2bSLaurent Pinchart 	case V4L2_SEL_TGT_CROP:
745cb33db2bSLaurent Pinchart 		sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad);
746cb33db2bSLaurent Pinchart 		break;
747cb33db2bSLaurent Pinchart 
748cb33db2bSLaurent Pinchart 	case V4L2_SEL_TGT_CROP_DEFAULT:
749cb33db2bSLaurent Pinchart 	case V4L2_SEL_TGT_CROP_BOUNDS:
750cb33db2bSLaurent Pinchart 	case V4L2_SEL_TGT_NATIVE_SIZE:
751cb33db2bSLaurent Pinchart 		sel->r.left = 0;
752cb33db2bSLaurent Pinchart 		sel->r.top = 0;
753cb33db2bSLaurent Pinchart 		sel->r.width = IMX296_PIXEL_ARRAY_WIDTH;
754cb33db2bSLaurent Pinchart 		sel->r.height = IMX296_PIXEL_ARRAY_HEIGHT;
755cb33db2bSLaurent Pinchart 		break;
756cb33db2bSLaurent Pinchart 
757cb33db2bSLaurent Pinchart 	default:
758cb33db2bSLaurent Pinchart 		return -EINVAL;
759cb33db2bSLaurent Pinchart 	}
760cb33db2bSLaurent Pinchart 
761cb33db2bSLaurent Pinchart 	return 0;
762cb33db2bSLaurent Pinchart }
763cb33db2bSLaurent Pinchart 
imx296_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_selection * sel)764cb33db2bSLaurent Pinchart static int imx296_set_selection(struct v4l2_subdev *sd,
765cb33db2bSLaurent Pinchart 				struct v4l2_subdev_state *state,
766cb33db2bSLaurent Pinchart 				struct v4l2_subdev_selection *sel)
767cb33db2bSLaurent Pinchart {
768cb33db2bSLaurent Pinchart 	struct v4l2_mbus_framefmt *format;
769cb33db2bSLaurent Pinchart 	struct v4l2_rect *crop;
770cb33db2bSLaurent Pinchart 	struct v4l2_rect rect;
771cb33db2bSLaurent Pinchart 
772cb33db2bSLaurent Pinchart 	if (sel->target != V4L2_SEL_TGT_CROP)
773cb33db2bSLaurent Pinchart 		return -EINVAL;
774cb33db2bSLaurent Pinchart 
775cb33db2bSLaurent Pinchart 	/*
776cb33db2bSLaurent Pinchart 	 * Clamp the crop rectangle boundaries and align them to a multiple of 4
777cb33db2bSLaurent Pinchart 	 * pixels to satisfy hardware requirements.
778cb33db2bSLaurent Pinchart 	 */
779cb33db2bSLaurent Pinchart 	rect.left = clamp(ALIGN(sel->r.left, 4), 0,
780cb33db2bSLaurent Pinchart 			  IMX296_PIXEL_ARRAY_WIDTH - IMX296_FID0_ROIWH1_MIN);
781cb33db2bSLaurent Pinchart 	rect.top = clamp(ALIGN(sel->r.top, 4), 0,
782cb33db2bSLaurent Pinchart 			 IMX296_PIXEL_ARRAY_HEIGHT - IMX296_FID0_ROIWV1_MIN);
783cb33db2bSLaurent Pinchart 	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4),
784cb33db2bSLaurent Pinchart 			     IMX296_FID0_ROIWH1_MIN, IMX296_PIXEL_ARRAY_WIDTH);
785cb33db2bSLaurent Pinchart 	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 4),
786cb33db2bSLaurent Pinchart 			      IMX296_FID0_ROIWV1_MIN, IMX296_PIXEL_ARRAY_HEIGHT);
787cb33db2bSLaurent Pinchart 
788cb33db2bSLaurent Pinchart 	rect.width = min_t(unsigned int, rect.width,
789cb33db2bSLaurent Pinchart 			   IMX296_PIXEL_ARRAY_WIDTH - rect.left);
790cb33db2bSLaurent Pinchart 	rect.height = min_t(unsigned int, rect.height,
791cb33db2bSLaurent Pinchart 			    IMX296_PIXEL_ARRAY_HEIGHT - rect.top);
792cb33db2bSLaurent Pinchart 
793cb33db2bSLaurent Pinchart 	crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad);
794cb33db2bSLaurent Pinchart 
795cb33db2bSLaurent Pinchart 	if (rect.width != crop->width || rect.height != crop->height) {
796cb33db2bSLaurent Pinchart 		/*
797cb33db2bSLaurent Pinchart 		 * Reset the output image size if the crop rectangle size has
798cb33db2bSLaurent Pinchart 		 * been modified.
799cb33db2bSLaurent Pinchart 		 */
800cb33db2bSLaurent Pinchart 		format = v4l2_subdev_get_pad_format(sd, state, sel->pad);
801cb33db2bSLaurent Pinchart 		format->width = rect.width;
802cb33db2bSLaurent Pinchart 		format->height = rect.height;
803cb33db2bSLaurent Pinchart 	}
804cb33db2bSLaurent Pinchart 
805cb33db2bSLaurent Pinchart 	*crop = rect;
806cb33db2bSLaurent Pinchart 	sel->r = rect;
807cb33db2bSLaurent Pinchart 
808cb33db2bSLaurent Pinchart 	return 0;
809cb33db2bSLaurent Pinchart }
810cb33db2bSLaurent Pinchart 
imx296_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * state)811cb33db2bSLaurent Pinchart static int imx296_init_cfg(struct v4l2_subdev *sd,
812cb33db2bSLaurent Pinchart 			   struct v4l2_subdev_state *state)
813cb33db2bSLaurent Pinchart {
814cb33db2bSLaurent Pinchart 	struct v4l2_subdev_selection sel = {
815cb33db2bSLaurent Pinchart 		.target = V4L2_SEL_TGT_CROP,
816cb33db2bSLaurent Pinchart 		.r.width = IMX296_PIXEL_ARRAY_WIDTH,
817cb33db2bSLaurent Pinchart 		.r.height = IMX296_PIXEL_ARRAY_HEIGHT,
818cb33db2bSLaurent Pinchart 	};
819cb33db2bSLaurent Pinchart 	struct v4l2_subdev_format format = {
820cb33db2bSLaurent Pinchart 		.format = {
821cb33db2bSLaurent Pinchart 			.width = IMX296_PIXEL_ARRAY_WIDTH,
822cb33db2bSLaurent Pinchart 			.height = IMX296_PIXEL_ARRAY_HEIGHT,
823cb33db2bSLaurent Pinchart 		},
824cb33db2bSLaurent Pinchart 	};
825cb33db2bSLaurent Pinchart 
826cb33db2bSLaurent Pinchart 	imx296_set_selection(sd, state, &sel);
827cb33db2bSLaurent Pinchart 	imx296_set_format(sd, state, &format);
828cb33db2bSLaurent Pinchart 
829cb33db2bSLaurent Pinchart 	return 0;
830cb33db2bSLaurent Pinchart }
831cb33db2bSLaurent Pinchart 
832cb33db2bSLaurent Pinchart static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = {
833cb33db2bSLaurent Pinchart 	.s_stream = imx296_s_stream,
834cb33db2bSLaurent Pinchart };
835cb33db2bSLaurent Pinchart 
836cb33db2bSLaurent Pinchart static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = {
837cb33db2bSLaurent Pinchart 	.enum_mbus_code = imx296_enum_mbus_code,
838cb33db2bSLaurent Pinchart 	.enum_frame_size = imx296_enum_frame_size,
839ef586f26SLaurent Pinchart 	.get_fmt = v4l2_subdev_get_fmt,
840cb33db2bSLaurent Pinchart 	.set_fmt = imx296_set_format,
841cb33db2bSLaurent Pinchart 	.get_selection = imx296_get_selection,
842cb33db2bSLaurent Pinchart 	.set_selection = imx296_set_selection,
843cb33db2bSLaurent Pinchart 	.init_cfg = imx296_init_cfg,
844cb33db2bSLaurent Pinchart };
845cb33db2bSLaurent Pinchart 
846cb33db2bSLaurent Pinchart static const struct v4l2_subdev_ops imx296_subdev_ops = {
847cb33db2bSLaurent Pinchart 	.video = &imx296_subdev_video_ops,
848cb33db2bSLaurent Pinchart 	.pad = &imx296_subdev_pad_ops,
849cb33db2bSLaurent Pinchart };
850cb33db2bSLaurent Pinchart 
imx296_subdev_init(struct imx296 * sensor)851cb33db2bSLaurent Pinchart static int imx296_subdev_init(struct imx296 *sensor)
852cb33db2bSLaurent Pinchart {
853cb33db2bSLaurent Pinchart 	struct i2c_client *client = to_i2c_client(sensor->dev);
854cb33db2bSLaurent Pinchart 	int ret;
855cb33db2bSLaurent Pinchart 
856cb33db2bSLaurent Pinchart 	v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops);
857cb33db2bSLaurent Pinchart 
858cb33db2bSLaurent Pinchart 	ret = imx296_ctrls_init(sensor);
859cb33db2bSLaurent Pinchart 	if (ret < 0)
860cb33db2bSLaurent Pinchart 		return ret;
861cb33db2bSLaurent Pinchart 
862cb33db2bSLaurent Pinchart 	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
863cb33db2bSLaurent Pinchart 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
864cb33db2bSLaurent Pinchart 	sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
865cb33db2bSLaurent Pinchart 	ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
866cb33db2bSLaurent Pinchart 	if (ret < 0) {
867cb33db2bSLaurent Pinchart 		v4l2_ctrl_handler_free(&sensor->ctrls);
868cb33db2bSLaurent Pinchart 		return ret;
869cb33db2bSLaurent Pinchart 	}
870cb33db2bSLaurent Pinchart 
871cb33db2bSLaurent Pinchart 	sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock;
872cb33db2bSLaurent Pinchart 
873cb33db2bSLaurent Pinchart 	v4l2_subdev_init_finalize(&sensor->subdev);
874cb33db2bSLaurent Pinchart 
875cb33db2bSLaurent Pinchart 	return ret;
876cb33db2bSLaurent Pinchart }
877cb33db2bSLaurent Pinchart 
imx296_subdev_cleanup(struct imx296 * sensor)878cb33db2bSLaurent Pinchart static void imx296_subdev_cleanup(struct imx296 *sensor)
879cb33db2bSLaurent Pinchart {
880cb33db2bSLaurent Pinchart 	media_entity_cleanup(&sensor->subdev.entity);
881cb33db2bSLaurent Pinchart 	v4l2_ctrl_handler_free(&sensor->ctrls);
882cb33db2bSLaurent Pinchart }
883cb33db2bSLaurent Pinchart 
884cb33db2bSLaurent Pinchart /* -----------------------------------------------------------------------------
885cb33db2bSLaurent Pinchart  * Power management
886cb33db2bSLaurent Pinchart  */
887cb33db2bSLaurent Pinchart 
imx296_runtime_resume(struct device * dev)888cb33db2bSLaurent Pinchart static int __maybe_unused imx296_runtime_resume(struct device *dev)
889cb33db2bSLaurent Pinchart {
890cb33db2bSLaurent Pinchart 	struct i2c_client *client = to_i2c_client(dev);
891cb33db2bSLaurent Pinchart 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
892cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(subdev);
893cb33db2bSLaurent Pinchart 
894cb33db2bSLaurent Pinchart 	return imx296_power_on(sensor);
895cb33db2bSLaurent Pinchart }
896cb33db2bSLaurent Pinchart 
imx296_runtime_suspend(struct device * dev)897cb33db2bSLaurent Pinchart static int __maybe_unused imx296_runtime_suspend(struct device *dev)
898cb33db2bSLaurent Pinchart {
899cb33db2bSLaurent Pinchart 	struct i2c_client *client = to_i2c_client(dev);
900cb33db2bSLaurent Pinchart 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
901cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(subdev);
902cb33db2bSLaurent Pinchart 
903cb33db2bSLaurent Pinchart 	imx296_power_off(sensor);
904cb33db2bSLaurent Pinchart 
905cb33db2bSLaurent Pinchart 	return 0;
906cb33db2bSLaurent Pinchart }
907cb33db2bSLaurent Pinchart 
908cb33db2bSLaurent Pinchart static const struct dev_pm_ops imx296_pm_ops = {
909cb33db2bSLaurent Pinchart 	SET_RUNTIME_PM_OPS(imx296_runtime_suspend, imx296_runtime_resume, NULL)
910cb33db2bSLaurent Pinchart };
911cb33db2bSLaurent Pinchart 
912cb33db2bSLaurent Pinchart /* -----------------------------------------------------------------------------
913cb33db2bSLaurent Pinchart  * Probe & Remove
914cb33db2bSLaurent Pinchart  */
915cb33db2bSLaurent Pinchart 
imx296_read_temperature(struct imx296 * sensor,int * temp)916cb33db2bSLaurent Pinchart static int imx296_read_temperature(struct imx296 *sensor, int *temp)
917cb33db2bSLaurent Pinchart {
918cb33db2bSLaurent Pinchart 	int tmdout;
919cb33db2bSLaurent Pinchart 	int ret;
920cb33db2bSLaurent Pinchart 
921cb33db2bSLaurent Pinchart 	ret = imx296_write(sensor, IMX296_TMDCTRL, IMX296_TMDCTRL_LATCH, NULL);
922cb33db2bSLaurent Pinchart 	if (ret < 0)
923cb33db2bSLaurent Pinchart 		return ret;
924cb33db2bSLaurent Pinchart 
9251b3565dbSDan Carpenter 	tmdout = imx296_read(sensor, IMX296_TMDOUT);
926cb33db2bSLaurent Pinchart 	if (tmdout < 0)
927cb33db2bSLaurent Pinchart 		return tmdout;
928cb33db2bSLaurent Pinchart 
9291b3565dbSDan Carpenter 	tmdout &= IMX296_TMDOUT_MASK;
9301b3565dbSDan Carpenter 
931cb33db2bSLaurent Pinchart 	/* T(°C) = 246.312 - 0.304 * TMDOUT */;
932cb33db2bSLaurent Pinchart 	*temp = 246312 - 304 * tmdout;
933cb33db2bSLaurent Pinchart 
934cb33db2bSLaurent Pinchart 	return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL);
935cb33db2bSLaurent Pinchart }
936cb33db2bSLaurent Pinchart 
imx296_identify_model(struct imx296 * sensor)937cb33db2bSLaurent Pinchart static int imx296_identify_model(struct imx296 *sensor)
938cb33db2bSLaurent Pinchart {
939cb33db2bSLaurent Pinchart 	unsigned int model;
940cb33db2bSLaurent Pinchart 	int temp = 0;
941cb33db2bSLaurent Pinchart 	int ret;
942cb33db2bSLaurent Pinchart 
943cb33db2bSLaurent Pinchart 	model = (uintptr_t)of_device_get_match_data(sensor->dev);
944cb33db2bSLaurent Pinchart 	if (model) {
945cb33db2bSLaurent Pinchart 		dev_dbg(sensor->dev,
946cb33db2bSLaurent Pinchart 			"sensor model auto-detection disabled, forcing 0x%04x\n",
947cb33db2bSLaurent Pinchart 			model);
948cb33db2bSLaurent Pinchart 		sensor->mono = model & IMX296_SENSOR_INFO_MONO;
949cb33db2bSLaurent Pinchart 		return 0;
950cb33db2bSLaurent Pinchart 	}
951cb33db2bSLaurent Pinchart 
952cb33db2bSLaurent Pinchart 	/*
953cb33db2bSLaurent Pinchart 	 * While most registers can be read when the sensor is in standby, this
954cb33db2bSLaurent Pinchart 	 * is not the case of the sensor info register :-(
955cb33db2bSLaurent Pinchart 	 */
956cb33db2bSLaurent Pinchart 	ret = imx296_write(sensor, IMX296_CTRL00, 0, NULL);
957cb33db2bSLaurent Pinchart 	if (ret < 0) {
958cb33db2bSLaurent Pinchart 		dev_err(sensor->dev,
959cb33db2bSLaurent Pinchart 			"failed to get sensor out of standby (%d)\n", ret);
960cb33db2bSLaurent Pinchart 		return ret;
961cb33db2bSLaurent Pinchart 	}
962cb33db2bSLaurent Pinchart 
963cb33db2bSLaurent Pinchart 	ret = imx296_read(sensor, IMX296_SENSOR_INFO);
964cb33db2bSLaurent Pinchart 	if (ret < 0) {
965cb33db2bSLaurent Pinchart 		dev_err(sensor->dev, "failed to read sensor information (%d)\n",
966cb33db2bSLaurent Pinchart 			ret);
967cb33db2bSLaurent Pinchart 		goto done;
968cb33db2bSLaurent Pinchart 	}
969cb33db2bSLaurent Pinchart 
970cb33db2bSLaurent Pinchart 	model = (ret >> 6) & 0x1ff;
971cb33db2bSLaurent Pinchart 
972cb33db2bSLaurent Pinchart 	switch (model) {
973cb33db2bSLaurent Pinchart 	case 296:
974cb33db2bSLaurent Pinchart 		sensor->mono = ret & IMX296_SENSOR_INFO_MONO;
975cb33db2bSLaurent Pinchart 		break;
976cb33db2bSLaurent Pinchart 	/*
977cb33db2bSLaurent Pinchart 	 * The IMX297 seems to share features with the IMX296, it may be
978cb33db2bSLaurent Pinchart 	 * possible to support it in the same driver.
979cb33db2bSLaurent Pinchart 	 */
980cb33db2bSLaurent Pinchart 	case 297:
981cb33db2bSLaurent Pinchart 	default:
982cb33db2bSLaurent Pinchart 		dev_err(sensor->dev, "invalid device model 0x%04x\n", ret);
983cb33db2bSLaurent Pinchart 		ret = -ENODEV;
984cb33db2bSLaurent Pinchart 		goto done;
985cb33db2bSLaurent Pinchart 	}
986cb33db2bSLaurent Pinchart 
987cb33db2bSLaurent Pinchart 	ret = imx296_read_temperature(sensor, &temp);
988cb33db2bSLaurent Pinchart 	if (ret < 0)
989cb33db2bSLaurent Pinchart 		goto done;
990cb33db2bSLaurent Pinchart 
991cb33db2bSLaurent Pinchart 	dev_info(sensor->dev, "found IMX%u%s (%u.%uC)\n", model,
992cb33db2bSLaurent Pinchart 		 sensor->mono ? "LL" : "LQ", temp / 1000, (temp / 100) % 10);
993cb33db2bSLaurent Pinchart 
994cb33db2bSLaurent Pinchart done:
995cb33db2bSLaurent Pinchart 	imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, NULL);
996cb33db2bSLaurent Pinchart 	return ret;
997cb33db2bSLaurent Pinchart }
998cb33db2bSLaurent Pinchart 
999cb33db2bSLaurent Pinchart static const struct regmap_config imx296_regmap_config = {
1000cb33db2bSLaurent Pinchart 	.reg_bits = 16,
1001cb33db2bSLaurent Pinchart 	.val_bits = 8,
1002cb33db2bSLaurent Pinchart 
1003cb33db2bSLaurent Pinchart 	.wr_table = &(const struct regmap_access_table) {
1004cb33db2bSLaurent Pinchart 		.no_ranges = (const struct regmap_range[]) {
1005cb33db2bSLaurent Pinchart 			{
1006cb33db2bSLaurent Pinchart 				.range_min = IMX296_SENSOR_INFO & 0xffff,
1007cb33db2bSLaurent Pinchart 				.range_max = (IMX296_SENSOR_INFO & 0xffff) + 1,
1008cb33db2bSLaurent Pinchart 			},
1009cb33db2bSLaurent Pinchart 		},
1010cb33db2bSLaurent Pinchart 		.n_no_ranges = 1,
1011cb33db2bSLaurent Pinchart 	},
1012cb33db2bSLaurent Pinchart };
1013cb33db2bSLaurent Pinchart 
imx296_probe(struct i2c_client * client)1014cb33db2bSLaurent Pinchart static int imx296_probe(struct i2c_client *client)
1015cb33db2bSLaurent Pinchart {
1016cb33db2bSLaurent Pinchart 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1017cb33db2bSLaurent Pinchart 	unsigned long clk_rate;
1018cb33db2bSLaurent Pinchart 	struct imx296 *sensor;
1019cb33db2bSLaurent Pinchart 	unsigned int i;
1020cb33db2bSLaurent Pinchart 	int ret;
1021cb33db2bSLaurent Pinchart 
1022cb33db2bSLaurent Pinchart 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1023cb33db2bSLaurent Pinchart 		dev_warn(&adapter->dev,
1024cb33db2bSLaurent Pinchart 			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
1025cb33db2bSLaurent Pinchart 		return -EIO;
1026cb33db2bSLaurent Pinchart 	}
1027cb33db2bSLaurent Pinchart 
1028cb33db2bSLaurent Pinchart 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
1029cb33db2bSLaurent Pinchart 	if (!sensor)
1030cb33db2bSLaurent Pinchart 		return -ENOMEM;
1031cb33db2bSLaurent Pinchart 
1032cb33db2bSLaurent Pinchart 	sensor->dev = &client->dev;
1033cb33db2bSLaurent Pinchart 
1034cb33db2bSLaurent Pinchart 	/* Acquire resources. */
1035cb33db2bSLaurent Pinchart 	for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i)
1036cb33db2bSLaurent Pinchart 		sensor->supplies[i].supply = imx296_supply_names[i];
1037cb33db2bSLaurent Pinchart 
1038cb33db2bSLaurent Pinchart 	ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies),
1039cb33db2bSLaurent Pinchart 				      sensor->supplies);
1040cb33db2bSLaurent Pinchart 	if (ret) {
1041cb33db2bSLaurent Pinchart 		dev_err_probe(sensor->dev, ret, "failed to get supplies\n");
1042cb33db2bSLaurent Pinchart 		return ret;
1043cb33db2bSLaurent Pinchart 	}
1044cb33db2bSLaurent Pinchart 
1045cb33db2bSLaurent Pinchart 	sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset",
1046cb33db2bSLaurent Pinchart 						GPIOD_OUT_HIGH);
1047cb33db2bSLaurent Pinchart 	if (IS_ERR(sensor->reset))
1048cb33db2bSLaurent Pinchart 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
1049cb33db2bSLaurent Pinchart 				     "failed to get reset GPIO\n");
1050cb33db2bSLaurent Pinchart 
1051cb33db2bSLaurent Pinchart 	sensor->clk = devm_clk_get(sensor->dev, "inck");
1052cb33db2bSLaurent Pinchart 	if (IS_ERR(sensor->clk))
1053cb33db2bSLaurent Pinchart 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
1054cb33db2bSLaurent Pinchart 				     "failed to get clock\n");
1055cb33db2bSLaurent Pinchart 
1056cb33db2bSLaurent Pinchart 	clk_rate = clk_get_rate(sensor->clk);
1057cb33db2bSLaurent Pinchart 	for (i = 0; i < ARRAY_SIZE(imx296_clk_params); ++i) {
1058cb33db2bSLaurent Pinchart 		if (clk_rate == imx296_clk_params[i].freq) {
1059cb33db2bSLaurent Pinchart 			sensor->clk_params = &imx296_clk_params[i];
1060cb33db2bSLaurent Pinchart 			break;
1061cb33db2bSLaurent Pinchart 		}
1062cb33db2bSLaurent Pinchart 	}
1063cb33db2bSLaurent Pinchart 
1064cb33db2bSLaurent Pinchart 	if (!sensor->clk_params) {
1065cb33db2bSLaurent Pinchart 		dev_err(sensor->dev, "unsupported clock rate %lu\n", clk_rate);
1066cb33db2bSLaurent Pinchart 		return -EINVAL;
1067cb33db2bSLaurent Pinchart 	}
1068cb33db2bSLaurent Pinchart 
1069cb33db2bSLaurent Pinchart 	sensor->regmap = devm_regmap_init_i2c(client, &imx296_regmap_config);
1070cb33db2bSLaurent Pinchart 	if (IS_ERR(sensor->regmap))
1071cb33db2bSLaurent Pinchart 		return PTR_ERR(sensor->regmap);
1072cb33db2bSLaurent Pinchart 
1073cb33db2bSLaurent Pinchart 	/*
1074cb33db2bSLaurent Pinchart 	 * Enable power management. The driver supports runtime PM, but needs to
1075cb33db2bSLaurent Pinchart 	 * work when runtime PM is disabled in the kernel. To that end, power
1076cb33db2bSLaurent Pinchart 	 * the sensor on manually here, identify it, and fully initialize it.
1077cb33db2bSLaurent Pinchart 	 */
1078cb33db2bSLaurent Pinchart 	ret = imx296_power_on(sensor);
1079cb33db2bSLaurent Pinchart 	if (ret < 0)
1080cb33db2bSLaurent Pinchart 		return ret;
1081cb33db2bSLaurent Pinchart 
1082cb33db2bSLaurent Pinchart 	ret = imx296_identify_model(sensor);
1083cb33db2bSLaurent Pinchart 	if (ret < 0)
1084cb33db2bSLaurent Pinchart 		goto err_power;
1085cb33db2bSLaurent Pinchart 
1086cb33db2bSLaurent Pinchart 	/* Initialize the V4L2 subdev. */
1087cb33db2bSLaurent Pinchart 	ret = imx296_subdev_init(sensor);
1088cb33db2bSLaurent Pinchart 	if (ret < 0)
1089cb33db2bSLaurent Pinchart 		goto err_power;
1090cb33db2bSLaurent Pinchart 
1091cb33db2bSLaurent Pinchart 	/*
1092cb33db2bSLaurent Pinchart 	 * Enable runtime PM. As the device has been powered manually, mark it
1093cb33db2bSLaurent Pinchart 	 * as active, and increase the usage count without resuming the device.
1094cb33db2bSLaurent Pinchart 	 */
1095cb33db2bSLaurent Pinchart 	pm_runtime_set_active(sensor->dev);
1096cb33db2bSLaurent Pinchart 	pm_runtime_get_noresume(sensor->dev);
1097cb33db2bSLaurent Pinchart 	pm_runtime_enable(sensor->dev);
1098cb33db2bSLaurent Pinchart 
1099cb33db2bSLaurent Pinchart 	/* Register the V4L2 subdev. */
1100cb33db2bSLaurent Pinchart 	ret = v4l2_async_register_subdev(&sensor->subdev);
1101cb33db2bSLaurent Pinchart 	if (ret < 0)
1102cb33db2bSLaurent Pinchart 		goto err_pm;
1103cb33db2bSLaurent Pinchart 
1104cb33db2bSLaurent Pinchart 	/*
1105cb33db2bSLaurent Pinchart 	 * Finally, enable autosuspend and decrease the usage count. The device
1106cb33db2bSLaurent Pinchart 	 * will get suspended after the autosuspend delay, turning the power
1107cb33db2bSLaurent Pinchart 	 * off.
1108cb33db2bSLaurent Pinchart 	 */
1109cb33db2bSLaurent Pinchart 	pm_runtime_set_autosuspend_delay(sensor->dev, 1000);
1110cb33db2bSLaurent Pinchart 	pm_runtime_use_autosuspend(sensor->dev);
1111cb33db2bSLaurent Pinchart 	pm_runtime_put_autosuspend(sensor->dev);
1112cb33db2bSLaurent Pinchart 
1113cb33db2bSLaurent Pinchart 	return 0;
1114cb33db2bSLaurent Pinchart 
1115cb33db2bSLaurent Pinchart err_pm:
1116cb33db2bSLaurent Pinchart 	pm_runtime_disable(sensor->dev);
1117cb33db2bSLaurent Pinchart 	pm_runtime_put_noidle(sensor->dev);
1118cb33db2bSLaurent Pinchart 	imx296_subdev_cleanup(sensor);
1119cb33db2bSLaurent Pinchart err_power:
1120cb33db2bSLaurent Pinchart 	imx296_power_off(sensor);
1121cb33db2bSLaurent Pinchart 	return ret;
1122cb33db2bSLaurent Pinchart }
1123cb33db2bSLaurent Pinchart 
imx296_remove(struct i2c_client * client)1124cb33db2bSLaurent Pinchart static void imx296_remove(struct i2c_client *client)
1125cb33db2bSLaurent Pinchart {
1126cb33db2bSLaurent Pinchart 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
1127cb33db2bSLaurent Pinchart 	struct imx296 *sensor = to_imx296(subdev);
1128cb33db2bSLaurent Pinchart 
1129cb33db2bSLaurent Pinchart 	v4l2_async_unregister_subdev(subdev);
1130cb33db2bSLaurent Pinchart 
1131cb33db2bSLaurent Pinchart 	imx296_subdev_cleanup(sensor);
1132cb33db2bSLaurent Pinchart 
1133cb33db2bSLaurent Pinchart 	/*
1134cb33db2bSLaurent Pinchart 	 * Disable runtime PM. In case runtime PM is disabled in the kernel,
1135cb33db2bSLaurent Pinchart 	 * make sure to turn power off manually.
1136cb33db2bSLaurent Pinchart 	 */
1137cb33db2bSLaurent Pinchart 	pm_runtime_disable(sensor->dev);
1138cb33db2bSLaurent Pinchart 	if (!pm_runtime_status_suspended(sensor->dev))
1139cb33db2bSLaurent Pinchart 		imx296_power_off(sensor);
1140cb33db2bSLaurent Pinchart 	pm_runtime_set_suspended(sensor->dev);
1141cb33db2bSLaurent Pinchart }
1142cb33db2bSLaurent Pinchart 
1143cb33db2bSLaurent Pinchart static const struct of_device_id imx296_of_match[] = {
1144cb33db2bSLaurent Pinchart 	{ .compatible = "sony,imx296", .data = NULL },
1145cb33db2bSLaurent Pinchart 	{ .compatible = "sony,imx296ll", .data = (void *)IMX296_SENSOR_INFO_IMX296LL },
1146cb33db2bSLaurent Pinchart 	{ .compatible = "sony,imx296lq", .data = (void *)IMX296_SENSOR_INFO_IMX296LQ },
1147cb33db2bSLaurent Pinchart 	{ /* sentinel */ },
1148cb33db2bSLaurent Pinchart };
1149cb33db2bSLaurent Pinchart MODULE_DEVICE_TABLE(of, imx296_of_match);
1150cb33db2bSLaurent Pinchart 
1151cb33db2bSLaurent Pinchart static struct i2c_driver imx296_i2c_driver = {
1152cb33db2bSLaurent Pinchart 	.driver = {
1153cb33db2bSLaurent Pinchart 		.of_match_table = imx296_of_match,
1154cb33db2bSLaurent Pinchart 		.name = "imx296",
1155cb33db2bSLaurent Pinchart 		.pm = &imx296_pm_ops
1156cb33db2bSLaurent Pinchart 	},
1157aaeb31c0SUwe Kleine-König 	.probe = imx296_probe,
1158cb33db2bSLaurent Pinchart 	.remove = imx296_remove,
1159cb33db2bSLaurent Pinchart };
1160cb33db2bSLaurent Pinchart 
1161cb33db2bSLaurent Pinchart module_i2c_driver(imx296_i2c_driver);
1162cb33db2bSLaurent Pinchart 
1163cb33db2bSLaurent Pinchart MODULE_DESCRIPTION("Sony IMX296 Camera driver");
1164cb33db2bSLaurent Pinchart MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
1165cb33db2bSLaurent Pinchart MODULE_LICENSE("GPL");
1166