1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * OmniVision OV96xx Camera Driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Based on ov772x camera driver:
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Copyright (C) 2008 Renesas Solutions Corp.
10*4882a593Smuzhiyun * Kuninori Morimoto <morimoto.kuninori@renesas.com>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Based on ov7670 and soc_camera_platform driver,
13*4882a593Smuzhiyun * transition from soc_camera to pxa_camera based on mt9m111
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
16*4882a593Smuzhiyun * Copyright (C) 2008 Magnus Damm
17*4882a593Smuzhiyun * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/i2c.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/v4l2-mediabus.h>
26*4882a593Smuzhiyun #include <linux/videodev2.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <media/v4l2-async.h>
29*4882a593Smuzhiyun #include <media/v4l2-clk.h>
30*4882a593Smuzhiyun #include <media/v4l2-common.h>
31*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
32*4882a593Smuzhiyun #include <media/v4l2-device.h>
33*4882a593Smuzhiyun #include <media/v4l2-event.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include "ov9640.h"
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* default register setup */
42*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_dflt[] = {
43*4882a593Smuzhiyun { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
44*4882a593Smuzhiyun { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
45*4882a593Smuzhiyun OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
46*4882a593Smuzhiyun { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) },
47*4882a593Smuzhiyun { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
48*4882a593Smuzhiyun { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY },
49*4882a593Smuzhiyun { OV9640_COM16, OV9640_COM16_RB_AVG },
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Gamma curve P */
52*4882a593Smuzhiyun { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 },
53*4882a593Smuzhiyun { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 },
54*4882a593Smuzhiyun { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 },
55*4882a593Smuzhiyun { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 },
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* Gamma curve T */
58*4882a593Smuzhiyun { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 },
59*4882a593Smuzhiyun { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 },
60*4882a593Smuzhiyun { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e },
61*4882a593Smuzhiyun { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 },
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* Configurations
65*4882a593Smuzhiyun * NOTE: for YUV, alter the following registers:
66*4882a593Smuzhiyun * COM12 |= OV9640_COM12_YUV_AVG
67*4882a593Smuzhiyun *
68*4882a593Smuzhiyun * for RGB, alter the following registers:
69*4882a593Smuzhiyun * COM7 |= OV9640_COM7_RGB
70*4882a593Smuzhiyun * COM13 |= OV9640_COM13_RGB_AVG
71*4882a593Smuzhiyun * COM15 |= proper RGB color encoding mode
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_qqcif[] = {
74*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
75*4882a593Smuzhiyun { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
76*4882a593Smuzhiyun { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
77*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_QCIF },
78*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
79*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
80*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_qqvga[] = {
84*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
85*4882a593Smuzhiyun { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
86*4882a593Smuzhiyun { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
87*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_QVGA },
88*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
89*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
90*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_qcif[] = {
94*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
95*4882a593Smuzhiyun { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
96*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_QCIF },
97*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
98*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
99*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_qvga[] = {
103*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
104*4882a593Smuzhiyun { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
105*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_QVGA },
106*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
107*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
108*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_cif[] = {
112*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
113*4882a593Smuzhiyun { OV9640_COM3, OV9640_COM3_VP },
114*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_CIF },
115*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
116*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
117*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_vga[] = {
121*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
122*4882a593Smuzhiyun { OV9640_COM3, OV9640_COM3_VP },
123*4882a593Smuzhiyun { OV9640_COM7, OV9640_COM7_VGA },
124*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
125*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
126*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_sxga[] = {
130*4882a593Smuzhiyun { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
131*4882a593Smuzhiyun { OV9640_COM3, OV9640_COM3_VP },
132*4882a593Smuzhiyun { OV9640_COM7, 0 },
133*4882a593Smuzhiyun { OV9640_COM12, OV9640_COM12_RSVD },
134*4882a593Smuzhiyun { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
135*4882a593Smuzhiyun { OV9640_COM15, OV9640_COM15_OR_10F0 },
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_yuv[] = {
139*4882a593Smuzhiyun { OV9640_MTX1, 0x58 },
140*4882a593Smuzhiyun { OV9640_MTX2, 0x48 },
141*4882a593Smuzhiyun { OV9640_MTX3, 0x10 },
142*4882a593Smuzhiyun { OV9640_MTX4, 0x28 },
143*4882a593Smuzhiyun { OV9640_MTX5, 0x48 },
144*4882a593Smuzhiyun { OV9640_MTX6, 0x70 },
145*4882a593Smuzhiyun { OV9640_MTX7, 0x40 },
146*4882a593Smuzhiyun { OV9640_MTX8, 0x40 },
147*4882a593Smuzhiyun { OV9640_MTX9, 0x40 },
148*4882a593Smuzhiyun { OV9640_MTXS, 0x0f },
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun static const struct ov9640_reg ov9640_regs_rgb[] = {
152*4882a593Smuzhiyun { OV9640_MTX1, 0x71 },
153*4882a593Smuzhiyun { OV9640_MTX2, 0x3e },
154*4882a593Smuzhiyun { OV9640_MTX3, 0x0c },
155*4882a593Smuzhiyun { OV9640_MTX4, 0x33 },
156*4882a593Smuzhiyun { OV9640_MTX5, 0x72 },
157*4882a593Smuzhiyun { OV9640_MTX6, 0x00 },
158*4882a593Smuzhiyun { OV9640_MTX7, 0x2b },
159*4882a593Smuzhiyun { OV9640_MTX8, 0x66 },
160*4882a593Smuzhiyun { OV9640_MTX9, 0xd2 },
161*4882a593Smuzhiyun { OV9640_MTXS, 0x65 },
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun static const u32 ov9640_codes[] = {
165*4882a593Smuzhiyun MEDIA_BUS_FMT_UYVY8_2X8,
166*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
167*4882a593Smuzhiyun MEDIA_BUS_FMT_RGB565_2X8_LE,
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* read a register */
ov9640_reg_read(struct i2c_client * client,u8 reg,u8 * val)171*4882a593Smuzhiyun static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun int ret;
174*4882a593Smuzhiyun u8 data = reg;
175*4882a593Smuzhiyun struct i2c_msg msg = {
176*4882a593Smuzhiyun .addr = client->addr,
177*4882a593Smuzhiyun .flags = 0,
178*4882a593Smuzhiyun .len = 1,
179*4882a593Smuzhiyun .buf = &data,
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, &msg, 1);
183*4882a593Smuzhiyun if (ret < 0)
184*4882a593Smuzhiyun goto err;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun msg.flags = I2C_M_RD;
187*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, &msg, 1);
188*4882a593Smuzhiyun if (ret < 0)
189*4882a593Smuzhiyun goto err;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun *val = data;
192*4882a593Smuzhiyun return 0;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun err:
195*4882a593Smuzhiyun dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
196*4882a593Smuzhiyun return ret;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* write a register */
ov9640_reg_write(struct i2c_client * client,u8 reg,u8 val)200*4882a593Smuzhiyun static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int ret;
203*4882a593Smuzhiyun u8 _val;
204*4882a593Smuzhiyun unsigned char data[2] = { reg, val };
205*4882a593Smuzhiyun struct i2c_msg msg = {
206*4882a593Smuzhiyun .addr = client->addr,
207*4882a593Smuzhiyun .flags = 0,
208*4882a593Smuzhiyun .len = 2,
209*4882a593Smuzhiyun .buf = data,
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, &msg, 1);
213*4882a593Smuzhiyun if (ret < 0) {
214*4882a593Smuzhiyun dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
215*4882a593Smuzhiyun return ret;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* we have to read the register back ... no idea why, maybe HW bug */
219*4882a593Smuzhiyun ret = ov9640_reg_read(client, reg, &_val);
220*4882a593Smuzhiyun if (ret)
221*4882a593Smuzhiyun dev_err(&client->dev,
222*4882a593Smuzhiyun "Failed reading back register 0x%02x!\n", reg);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* Read a register, alter its bits, write it back */
ov9640_reg_rmw(struct i2c_client * client,u8 reg,u8 set,u8 unset)229*4882a593Smuzhiyun static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun u8 val;
232*4882a593Smuzhiyun int ret;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ret = ov9640_reg_read(client, reg, &val);
235*4882a593Smuzhiyun if (ret) {
236*4882a593Smuzhiyun dev_err(&client->dev,
237*4882a593Smuzhiyun "[Read]-Modify-Write of register %02x failed!\n", reg);
238*4882a593Smuzhiyun return ret;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun val |= set;
242*4882a593Smuzhiyun val &= ~unset;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun ret = ov9640_reg_write(client, reg, val);
245*4882a593Smuzhiyun if (ret)
246*4882a593Smuzhiyun dev_err(&client->dev,
247*4882a593Smuzhiyun "Read-Modify-[Write] of register %02x failed!\n", reg);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return ret;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* Soft reset the camera. This has nothing to do with the RESET pin! */
ov9640_reset(struct i2c_client * client)253*4882a593Smuzhiyun static int ov9640_reset(struct i2c_client *client)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun int ret;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
258*4882a593Smuzhiyun if (ret)
259*4882a593Smuzhiyun dev_err(&client->dev,
260*4882a593Smuzhiyun "An error occurred while entering soft reset!\n");
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun return ret;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /* Start/Stop streaming from the device */
ov9640_s_stream(struct v4l2_subdev * sd,int enable)266*4882a593Smuzhiyun static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun return 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Set status of additional camera capabilities */
ov9640_s_ctrl(struct v4l2_ctrl * ctrl)272*4882a593Smuzhiyun static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun struct ov9640_priv *priv = container_of(ctrl->handler,
275*4882a593Smuzhiyun struct ov9640_priv, hdl);
276*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun switch (ctrl->id) {
279*4882a593Smuzhiyun case V4L2_CID_VFLIP:
280*4882a593Smuzhiyun if (ctrl->val)
281*4882a593Smuzhiyun return ov9640_reg_rmw(client, OV9640_MVFP,
282*4882a593Smuzhiyun OV9640_MVFP_V, 0);
283*4882a593Smuzhiyun return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
284*4882a593Smuzhiyun case V4L2_CID_HFLIP:
285*4882a593Smuzhiyun if (ctrl->val)
286*4882a593Smuzhiyun return ov9640_reg_rmw(client, OV9640_MVFP,
287*4882a593Smuzhiyun OV9640_MVFP_H, 0);
288*4882a593Smuzhiyun return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun return -EINVAL;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
ov9640_get_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)295*4882a593Smuzhiyun static int ov9640_get_register(struct v4l2_subdev *sd,
296*4882a593Smuzhiyun struct v4l2_dbg_register *reg)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(sd);
299*4882a593Smuzhiyun int ret;
300*4882a593Smuzhiyun u8 val;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (reg->reg & ~0xff)
303*4882a593Smuzhiyun return -EINVAL;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun reg->size = 1;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun ret = ov9640_reg_read(client, reg->reg, &val);
308*4882a593Smuzhiyun if (ret)
309*4882a593Smuzhiyun return ret;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun reg->val = (__u64)val;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
ov9640_set_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)316*4882a593Smuzhiyun static int ov9640_set_register(struct v4l2_subdev *sd,
317*4882a593Smuzhiyun const struct v4l2_dbg_register *reg)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(sd);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (reg->reg & ~0xff || reg->val & ~0xff)
322*4882a593Smuzhiyun return -EINVAL;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return ov9640_reg_write(client, reg->reg, reg->val);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun #endif
327*4882a593Smuzhiyun
ov9640_s_power(struct v4l2_subdev * sd,int on)328*4882a593Smuzhiyun static int ov9640_s_power(struct v4l2_subdev *sd, int on)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun struct ov9640_priv *priv = to_ov9640_sensor(sd);
331*4882a593Smuzhiyun int ret = 0;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (on) {
334*4882a593Smuzhiyun gpiod_set_value(priv->gpio_power, 1);
335*4882a593Smuzhiyun usleep_range(1000, 2000);
336*4882a593Smuzhiyun ret = v4l2_clk_enable(priv->clk);
337*4882a593Smuzhiyun usleep_range(1000, 2000);
338*4882a593Smuzhiyun gpiod_set_value(priv->gpio_reset, 0);
339*4882a593Smuzhiyun } else {
340*4882a593Smuzhiyun gpiod_set_value(priv->gpio_reset, 1);
341*4882a593Smuzhiyun usleep_range(1000, 2000);
342*4882a593Smuzhiyun v4l2_clk_disable(priv->clk);
343*4882a593Smuzhiyun usleep_range(1000, 2000);
344*4882a593Smuzhiyun gpiod_set_value(priv->gpio_power, 0);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return ret;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* select nearest higher resolution for capture */
ov9640_res_roundup(u32 * width,u32 * height)351*4882a593Smuzhiyun static void ov9640_res_roundup(u32 *width, u32 *height)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun unsigned int i;
354*4882a593Smuzhiyun enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
355*4882a593Smuzhiyun static const u32 res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
356*4882a593Smuzhiyun static const u32 res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(res_x); i++) {
359*4882a593Smuzhiyun if (res_x[i] >= *width && res_y[i] >= *height) {
360*4882a593Smuzhiyun *width = res_x[i];
361*4882a593Smuzhiyun *height = res_y[i];
362*4882a593Smuzhiyun return;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun *width = res_x[SXGA];
367*4882a593Smuzhiyun *height = res_y[SXGA];
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /* Prepare necessary register changes depending on color encoding */
ov9640_alter_regs(u32 code,struct ov9640_reg_alt * alt)371*4882a593Smuzhiyun static void ov9640_alter_regs(u32 code,
372*4882a593Smuzhiyun struct ov9640_reg_alt *alt)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun switch (code) {
375*4882a593Smuzhiyun default:
376*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_2X8:
377*4882a593Smuzhiyun alt->com12 = OV9640_COM12_YUV_AVG;
378*4882a593Smuzhiyun alt->com13 = OV9640_COM13_Y_DELAY_EN |
379*4882a593Smuzhiyun OV9640_COM13_YUV_DLY(0x01);
380*4882a593Smuzhiyun break;
381*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
382*4882a593Smuzhiyun alt->com7 = OV9640_COM7_RGB;
383*4882a593Smuzhiyun alt->com13 = OV9640_COM13_RGB_AVG;
384*4882a593Smuzhiyun alt->com15 = OV9640_COM15_RGB_555;
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB565_2X8_LE:
387*4882a593Smuzhiyun alt->com7 = OV9640_COM7_RGB;
388*4882a593Smuzhiyun alt->com13 = OV9640_COM13_RGB_AVG;
389*4882a593Smuzhiyun alt->com15 = OV9640_COM15_RGB_565;
390*4882a593Smuzhiyun break;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /* Setup registers according to resolution and color encoding */
ov9640_write_regs(struct i2c_client * client,u32 width,u32 code,struct ov9640_reg_alt * alts)395*4882a593Smuzhiyun static int ov9640_write_regs(struct i2c_client *client, u32 width,
396*4882a593Smuzhiyun u32 code, struct ov9640_reg_alt *alts)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun const struct ov9640_reg *ov9640_regs, *matrix_regs;
399*4882a593Smuzhiyun unsigned int ov9640_regs_len, matrix_regs_len;
400*4882a593Smuzhiyun unsigned int i;
401*4882a593Smuzhiyun int ret;
402*4882a593Smuzhiyun u8 val;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun /* select register configuration for given resolution */
405*4882a593Smuzhiyun switch (width) {
406*4882a593Smuzhiyun case W_QQCIF:
407*4882a593Smuzhiyun ov9640_regs = ov9640_regs_qqcif;
408*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif);
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun case W_QQVGA:
411*4882a593Smuzhiyun ov9640_regs = ov9640_regs_qqvga;
412*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga);
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun case W_QCIF:
415*4882a593Smuzhiyun ov9640_regs = ov9640_regs_qcif;
416*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif);
417*4882a593Smuzhiyun break;
418*4882a593Smuzhiyun case W_QVGA:
419*4882a593Smuzhiyun ov9640_regs = ov9640_regs_qvga;
420*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga);
421*4882a593Smuzhiyun break;
422*4882a593Smuzhiyun case W_CIF:
423*4882a593Smuzhiyun ov9640_regs = ov9640_regs_cif;
424*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif);
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun case W_VGA:
427*4882a593Smuzhiyun ov9640_regs = ov9640_regs_vga;
428*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga);
429*4882a593Smuzhiyun break;
430*4882a593Smuzhiyun case W_SXGA:
431*4882a593Smuzhiyun ov9640_regs = ov9640_regs_sxga;
432*4882a593Smuzhiyun ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga);
433*4882a593Smuzhiyun break;
434*4882a593Smuzhiyun default:
435*4882a593Smuzhiyun dev_err(&client->dev, "Failed to select resolution!\n");
436*4882a593Smuzhiyun return -EINVAL;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /* select color matrix configuration for given color encoding */
440*4882a593Smuzhiyun if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
441*4882a593Smuzhiyun matrix_regs = ov9640_regs_yuv;
442*4882a593Smuzhiyun matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
443*4882a593Smuzhiyun } else {
444*4882a593Smuzhiyun matrix_regs = ov9640_regs_rgb;
445*4882a593Smuzhiyun matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* write register settings into the module */
449*4882a593Smuzhiyun for (i = 0; i < ov9640_regs_len; i++) {
450*4882a593Smuzhiyun val = ov9640_regs[i].val;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun switch (ov9640_regs[i].reg) {
453*4882a593Smuzhiyun case OV9640_COM7:
454*4882a593Smuzhiyun val |= alts->com7;
455*4882a593Smuzhiyun break;
456*4882a593Smuzhiyun case OV9640_COM12:
457*4882a593Smuzhiyun val |= alts->com12;
458*4882a593Smuzhiyun break;
459*4882a593Smuzhiyun case OV9640_COM13:
460*4882a593Smuzhiyun val |= alts->com13;
461*4882a593Smuzhiyun break;
462*4882a593Smuzhiyun case OV9640_COM15:
463*4882a593Smuzhiyun val |= alts->com15;
464*4882a593Smuzhiyun break;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
468*4882a593Smuzhiyun if (ret)
469*4882a593Smuzhiyun return ret;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /* write color matrix configuration into the module */
473*4882a593Smuzhiyun for (i = 0; i < matrix_regs_len; i++) {
474*4882a593Smuzhiyun ret = ov9640_reg_write(client, matrix_regs[i].reg,
475*4882a593Smuzhiyun matrix_regs[i].val);
476*4882a593Smuzhiyun if (ret)
477*4882a593Smuzhiyun return ret;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun /* program default register values */
ov9640_prog_dflt(struct i2c_client * client)484*4882a593Smuzhiyun static int ov9640_prog_dflt(struct i2c_client *client)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun unsigned int i;
487*4882a593Smuzhiyun int ret;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
490*4882a593Smuzhiyun ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
491*4882a593Smuzhiyun ov9640_regs_dflt[i].val);
492*4882a593Smuzhiyun if (ret)
493*4882a593Smuzhiyun return ret;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /* wait for the changes to actually happen, 140ms are not enough yet */
497*4882a593Smuzhiyun msleep(150);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* set the format we will capture in */
ov9640_s_fmt(struct v4l2_subdev * sd,struct v4l2_mbus_framefmt * mf)503*4882a593Smuzhiyun static int ov9640_s_fmt(struct v4l2_subdev *sd,
504*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mf)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun struct i2c_client *client = v4l2_get_subdevdata(sd);
507*4882a593Smuzhiyun struct ov9640_reg_alt alts = {0};
508*4882a593Smuzhiyun int ret;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun ov9640_alter_regs(mf->code, &alts);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun ov9640_reset(client);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun ret = ov9640_prog_dflt(client);
515*4882a593Smuzhiyun if (ret)
516*4882a593Smuzhiyun return ret;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun return ov9640_write_regs(client, mf->width, mf->code, &alts);
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
ov9640_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)521*4882a593Smuzhiyun static int ov9640_set_fmt(struct v4l2_subdev *sd,
522*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
523*4882a593Smuzhiyun struct v4l2_subdev_format *format)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mf = &format->format;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (format->pad)
528*4882a593Smuzhiyun return -EINVAL;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun ov9640_res_roundup(&mf->width, &mf->height);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun mf->field = V4L2_FIELD_NONE;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun switch (mf->code) {
535*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
536*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB565_2X8_LE:
537*4882a593Smuzhiyun mf->colorspace = V4L2_COLORSPACE_SRGB;
538*4882a593Smuzhiyun break;
539*4882a593Smuzhiyun default:
540*4882a593Smuzhiyun mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
541*4882a593Smuzhiyun fallthrough;
542*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_2X8:
543*4882a593Smuzhiyun mf->colorspace = V4L2_COLORSPACE_JPEG;
544*4882a593Smuzhiyun break;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
548*4882a593Smuzhiyun return ov9640_s_fmt(sd, mf);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun cfg->try_fmt = *mf;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
ov9640_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)555*4882a593Smuzhiyun static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
556*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
557*4882a593Smuzhiyun struct v4l2_subdev_mbus_code_enum *code)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes))
560*4882a593Smuzhiyun return -EINVAL;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun code->code = ov9640_codes[code->index];
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun return 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
ov9640_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)567*4882a593Smuzhiyun static int ov9640_get_selection(struct v4l2_subdev *sd,
568*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
569*4882a593Smuzhiyun struct v4l2_subdev_selection *sel)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
572*4882a593Smuzhiyun return -EINVAL;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun sel->r.left = 0;
575*4882a593Smuzhiyun sel->r.top = 0;
576*4882a593Smuzhiyun switch (sel->target) {
577*4882a593Smuzhiyun case V4L2_SEL_TGT_CROP_BOUNDS:
578*4882a593Smuzhiyun case V4L2_SEL_TGT_CROP:
579*4882a593Smuzhiyun sel->r.width = W_SXGA;
580*4882a593Smuzhiyun sel->r.height = H_SXGA;
581*4882a593Smuzhiyun return 0;
582*4882a593Smuzhiyun default:
583*4882a593Smuzhiyun return -EINVAL;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
ov9640_video_probe(struct i2c_client * client)587*4882a593Smuzhiyun static int ov9640_video_probe(struct i2c_client *client)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun struct v4l2_subdev *sd = i2c_get_clientdata(client);
590*4882a593Smuzhiyun struct ov9640_priv *priv = to_ov9640_sensor(sd);
591*4882a593Smuzhiyun u8 pid, ver, midh, midl;
592*4882a593Smuzhiyun const char *devname;
593*4882a593Smuzhiyun int ret;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun ret = ov9640_s_power(&priv->subdev, 1);
596*4882a593Smuzhiyun if (ret < 0)
597*4882a593Smuzhiyun return ret;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /*
600*4882a593Smuzhiyun * check and show product ID and manufacturer ID
601*4882a593Smuzhiyun */
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun ret = ov9640_reg_read(client, OV9640_PID, &pid);
604*4882a593Smuzhiyun if (!ret)
605*4882a593Smuzhiyun ret = ov9640_reg_read(client, OV9640_VER, &ver);
606*4882a593Smuzhiyun if (!ret)
607*4882a593Smuzhiyun ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
608*4882a593Smuzhiyun if (!ret)
609*4882a593Smuzhiyun ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
610*4882a593Smuzhiyun if (ret)
611*4882a593Smuzhiyun goto done;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun switch (VERSION(pid, ver)) {
614*4882a593Smuzhiyun case OV9640_V2:
615*4882a593Smuzhiyun devname = "ov9640";
616*4882a593Smuzhiyun priv->revision = 2;
617*4882a593Smuzhiyun break;
618*4882a593Smuzhiyun case OV9640_V3:
619*4882a593Smuzhiyun devname = "ov9640";
620*4882a593Smuzhiyun priv->revision = 3;
621*4882a593Smuzhiyun break;
622*4882a593Smuzhiyun default:
623*4882a593Smuzhiyun dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
624*4882a593Smuzhiyun ret = -ENODEV;
625*4882a593Smuzhiyun goto done;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
629*4882a593Smuzhiyun devname, pid, ver, midh, midl);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun ret = v4l2_ctrl_handler_setup(&priv->hdl);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun done:
634*4882a593Smuzhiyun ov9640_s_power(&priv->subdev, 0);
635*4882a593Smuzhiyun return ret;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
639*4882a593Smuzhiyun .s_ctrl = ov9640_s_ctrl,
640*4882a593Smuzhiyun };
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops ov9640_core_ops = {
643*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
644*4882a593Smuzhiyun .g_register = ov9640_get_register,
645*4882a593Smuzhiyun .s_register = ov9640_set_register,
646*4882a593Smuzhiyun #endif
647*4882a593Smuzhiyun .s_power = ov9640_s_power,
648*4882a593Smuzhiyun };
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun /* Request bus settings on camera side */
ov9640_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)651*4882a593Smuzhiyun static int ov9640_get_mbus_config(struct v4l2_subdev *sd,
652*4882a593Smuzhiyun unsigned int pad,
653*4882a593Smuzhiyun struct v4l2_mbus_config *cfg)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
656*4882a593Smuzhiyun V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
657*4882a593Smuzhiyun V4L2_MBUS_DATA_ACTIVE_HIGH;
658*4882a593Smuzhiyun cfg->type = V4L2_MBUS_PARALLEL;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops ov9640_video_ops = {
664*4882a593Smuzhiyun .s_stream = ov9640_s_stream,
665*4882a593Smuzhiyun };
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops ov9640_pad_ops = {
668*4882a593Smuzhiyun .enum_mbus_code = ov9640_enum_mbus_code,
669*4882a593Smuzhiyun .get_selection = ov9640_get_selection,
670*4882a593Smuzhiyun .set_fmt = ov9640_set_fmt,
671*4882a593Smuzhiyun .get_mbus_config = ov9640_get_mbus_config,
672*4882a593Smuzhiyun };
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun static const struct v4l2_subdev_ops ov9640_subdev_ops = {
675*4882a593Smuzhiyun .core = &ov9640_core_ops,
676*4882a593Smuzhiyun .video = &ov9640_video_ops,
677*4882a593Smuzhiyun .pad = &ov9640_pad_ops,
678*4882a593Smuzhiyun };
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun /*
681*4882a593Smuzhiyun * i2c_driver function
682*4882a593Smuzhiyun */
ov9640_probe(struct i2c_client * client,const struct i2c_device_id * did)683*4882a593Smuzhiyun static int ov9640_probe(struct i2c_client *client,
684*4882a593Smuzhiyun const struct i2c_device_id *did)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun struct ov9640_priv *priv;
687*4882a593Smuzhiyun int ret;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
690*4882a593Smuzhiyun if (!priv)
691*4882a593Smuzhiyun return -ENOMEM;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power",
694*4882a593Smuzhiyun GPIOD_OUT_LOW);
695*4882a593Smuzhiyun if (IS_ERR(priv->gpio_power)) {
696*4882a593Smuzhiyun ret = PTR_ERR(priv->gpio_power);
697*4882a593Smuzhiyun return ret;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset",
701*4882a593Smuzhiyun GPIOD_OUT_HIGH);
702*4882a593Smuzhiyun if (IS_ERR(priv->gpio_reset)) {
703*4882a593Smuzhiyun ret = PTR_ERR(priv->gpio_reset);
704*4882a593Smuzhiyun return ret;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun v4l2_ctrl_handler_init(&priv->hdl, 2);
710*4882a593Smuzhiyun v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
711*4882a593Smuzhiyun V4L2_CID_VFLIP, 0, 1, 1, 0);
712*4882a593Smuzhiyun v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
713*4882a593Smuzhiyun V4L2_CID_HFLIP, 0, 1, 1, 0);
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun if (priv->hdl.error) {
716*4882a593Smuzhiyun ret = priv->hdl.error;
717*4882a593Smuzhiyun goto ectrlinit;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun priv->subdev.ctrl_handler = &priv->hdl;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun priv->clk = v4l2_clk_get(&client->dev, "mclk");
723*4882a593Smuzhiyun if (IS_ERR(priv->clk)) {
724*4882a593Smuzhiyun ret = PTR_ERR(priv->clk);
725*4882a593Smuzhiyun goto ectrlinit;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun ret = ov9640_video_probe(client);
729*4882a593Smuzhiyun if (ret)
730*4882a593Smuzhiyun goto eprobe;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun priv->subdev.dev = &client->dev;
733*4882a593Smuzhiyun ret = v4l2_async_register_subdev(&priv->subdev);
734*4882a593Smuzhiyun if (ret)
735*4882a593Smuzhiyun goto eprobe;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun return 0;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun eprobe:
740*4882a593Smuzhiyun v4l2_clk_put(priv->clk);
741*4882a593Smuzhiyun ectrlinit:
742*4882a593Smuzhiyun v4l2_ctrl_handler_free(&priv->hdl);
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun return ret;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
ov9640_remove(struct i2c_client * client)747*4882a593Smuzhiyun static int ov9640_remove(struct i2c_client *client)
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun struct v4l2_subdev *sd = i2c_get_clientdata(client);
750*4882a593Smuzhiyun struct ov9640_priv *priv = to_ov9640_sensor(sd);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun v4l2_clk_put(priv->clk);
753*4882a593Smuzhiyun v4l2_async_unregister_subdev(&priv->subdev);
754*4882a593Smuzhiyun v4l2_ctrl_handler_free(&priv->hdl);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun static const struct i2c_device_id ov9640_id[] = {
760*4882a593Smuzhiyun { "ov9640", 0 },
761*4882a593Smuzhiyun { }
762*4882a593Smuzhiyun };
763*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, ov9640_id);
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun static struct i2c_driver ov9640_i2c_driver = {
766*4882a593Smuzhiyun .driver = {
767*4882a593Smuzhiyun .name = "ov9640",
768*4882a593Smuzhiyun },
769*4882a593Smuzhiyun .probe = ov9640_probe,
770*4882a593Smuzhiyun .remove = ov9640_remove,
771*4882a593Smuzhiyun .id_table = ov9640_id,
772*4882a593Smuzhiyun };
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun module_i2c_driver(ov9640_i2c_driver);
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun MODULE_DESCRIPTION("OmniVision OV96xx CMOS Image Sensor driver");
777*4882a593Smuzhiyun MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
778*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
779