1f5fbb83fSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2ad85094bSMauro Carvalho Chehab /*
3ad85094bSMauro Carvalho Chehab * Support for OmniVision OV5693 1080p HD camera sensor.
4ad85094bSMauro Carvalho Chehab *
5ad85094bSMauro Carvalho Chehab * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
6ad85094bSMauro Carvalho Chehab *
7ad85094bSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or
8ad85094bSMauro Carvalho Chehab * modify it under the terms of the GNU General Public License version
9ad85094bSMauro Carvalho Chehab * 2 as published by the Free Software Foundation.
10ad85094bSMauro Carvalho Chehab *
11ad85094bSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful,
12ad85094bSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of
13ad85094bSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14ad85094bSMauro Carvalho Chehab * GNU General Public License for more details.
15ad85094bSMauro Carvalho Chehab *
16ad85094bSMauro Carvalho Chehab *
17ad85094bSMauro Carvalho Chehab */
18ad85094bSMauro Carvalho Chehab
19ad85094bSMauro Carvalho Chehab #include <linux/module.h>
20ad85094bSMauro Carvalho Chehab #include <linux/types.h>
21ad85094bSMauro Carvalho Chehab #include <linux/kernel.h>
22ad85094bSMauro Carvalho Chehab #include <linux/mm.h>
23ad85094bSMauro Carvalho Chehab #include <linux/string.h>
24ad85094bSMauro Carvalho Chehab #include <linux/errno.h>
25ad85094bSMauro Carvalho Chehab #include <linux/init.h>
26ad85094bSMauro Carvalho Chehab #include <linux/kmod.h>
27ad85094bSMauro Carvalho Chehab #include <linux/device.h>
28ad85094bSMauro Carvalho Chehab #include <linux/delay.h>
29ad85094bSMauro Carvalho Chehab #include <linux/slab.h>
30ad85094bSMauro Carvalho Chehab #include <linux/i2c.h>
31ad85094bSMauro Carvalho Chehab #include <linux/moduleparam.h>
32ad85094bSMauro Carvalho Chehab #include <media/v4l2-device.h>
33ad85094bSMauro Carvalho Chehab #include <linux/io.h>
34ad85094bSMauro Carvalho Chehab #include <linux/acpi.h>
35ad85094bSMauro Carvalho Chehab #include "../../include/linux/atomisp_gmin_platform.h"
36ad85094bSMauro Carvalho Chehab
37ad85094bSMauro Carvalho Chehab #include "ov5693.h"
38ad85094bSMauro Carvalho Chehab #include "ad5823.h"
39ad85094bSMauro Carvalho Chehab
40ad85094bSMauro Carvalho Chehab #define __cci_delay(t) \
41ad85094bSMauro Carvalho Chehab do { \
42ad85094bSMauro Carvalho Chehab if ((t) < 10) { \
43ad85094bSMauro Carvalho Chehab usleep_range((t) * 1000, ((t) + 1) * 1000); \
44ad85094bSMauro Carvalho Chehab } else { \
45ad85094bSMauro Carvalho Chehab msleep((t)); \
46ad85094bSMauro Carvalho Chehab } \
47ad85094bSMauro Carvalho Chehab } while (0)
48ad85094bSMauro Carvalho Chehab
49ad85094bSMauro Carvalho Chehab /* Value 30ms reached through experimentation on byt ecs.
50ad85094bSMauro Carvalho Chehab * The DS specifies a much lower value but when using a smaller value
51ad85094bSMauro Carvalho Chehab * the I2C bus sometimes locks up permanently when starting the camera.
52ad85094bSMauro Carvalho Chehab * This issue could not be reproduced on cht, so we can reduce the
53ad85094bSMauro Carvalho Chehab * delay value to a lower value when insmod.
54ad85094bSMauro Carvalho Chehab */
55ad85094bSMauro Carvalho Chehab static uint up_delay = 30;
56ad85094bSMauro Carvalho Chehab module_param(up_delay, uint, 0644);
57eaa399ebSMauro Carvalho Chehab MODULE_PARM_DESC(up_delay,
58eaa399ebSMauro Carvalho Chehab "Delay prior to the first CCI transaction for ov5693");
59ad85094bSMauro Carvalho Chehab
vcm_ad_i2c_wr8(struct i2c_client * client,u8 reg,u8 val)60ad85094bSMauro Carvalho Chehab static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
61ad85094bSMauro Carvalho Chehab {
62ad85094bSMauro Carvalho Chehab int err;
63ad85094bSMauro Carvalho Chehab struct i2c_msg msg;
64ad85094bSMauro Carvalho Chehab u8 buf[2];
65ad85094bSMauro Carvalho Chehab
66ad85094bSMauro Carvalho Chehab buf[0] = reg;
67ad85094bSMauro Carvalho Chehab buf[1] = val;
68ad85094bSMauro Carvalho Chehab
69ad85094bSMauro Carvalho Chehab msg.addr = VCM_ADDR;
70ad85094bSMauro Carvalho Chehab msg.flags = 0;
71ad85094bSMauro Carvalho Chehab msg.len = 2;
72ad85094bSMauro Carvalho Chehab msg.buf = &buf[0];
73ad85094bSMauro Carvalho Chehab
74ad85094bSMauro Carvalho Chehab err = i2c_transfer(client->adapter, &msg, 1);
75ad85094bSMauro Carvalho Chehab if (err != 1) {
76ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n",
77ad85094bSMauro Carvalho Chehab __func__, err);
78ad85094bSMauro Carvalho Chehab return -EIO;
79ad85094bSMauro Carvalho Chehab }
80ad85094bSMauro Carvalho Chehab return 0;
81ad85094bSMauro Carvalho Chehab }
82ad85094bSMauro Carvalho Chehab
ad5823_i2c_write(struct i2c_client * client,u8 reg,u8 val)83ad85094bSMauro Carvalho Chehab static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
84ad85094bSMauro Carvalho Chehab {
85ad85094bSMauro Carvalho Chehab struct i2c_msg msg;
86ad85094bSMauro Carvalho Chehab u8 buf[2];
87ad85094bSMauro Carvalho Chehab
88ad85094bSMauro Carvalho Chehab buf[0] = reg;
89ad85094bSMauro Carvalho Chehab buf[1] = val;
90ad85094bSMauro Carvalho Chehab msg.addr = AD5823_VCM_ADDR;
91ad85094bSMauro Carvalho Chehab msg.flags = 0;
92ad85094bSMauro Carvalho Chehab msg.len = 0x02;
93ad85094bSMauro Carvalho Chehab msg.buf = &buf[0];
94ad85094bSMauro Carvalho Chehab
95ad85094bSMauro Carvalho Chehab if (i2c_transfer(client->adapter, &msg, 1) != 1)
96ad85094bSMauro Carvalho Chehab return -EIO;
97ad85094bSMauro Carvalho Chehab return 0;
98ad85094bSMauro Carvalho Chehab }
99ad85094bSMauro Carvalho Chehab
ad5823_i2c_read(struct i2c_client * client,u8 reg,u8 * val)100ad85094bSMauro Carvalho Chehab static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
101ad85094bSMauro Carvalho Chehab {
102ad85094bSMauro Carvalho Chehab struct i2c_msg msg[2];
103ad85094bSMauro Carvalho Chehab u8 buf[2];
104ad85094bSMauro Carvalho Chehab
105ad85094bSMauro Carvalho Chehab buf[0] = reg;
106ad85094bSMauro Carvalho Chehab buf[1] = 0;
107ad85094bSMauro Carvalho Chehab
108ad85094bSMauro Carvalho Chehab msg[0].addr = AD5823_VCM_ADDR;
109ad85094bSMauro Carvalho Chehab msg[0].flags = 0;
110ad85094bSMauro Carvalho Chehab msg[0].len = 0x01;
111ad85094bSMauro Carvalho Chehab msg[0].buf = &buf[0];
112ad85094bSMauro Carvalho Chehab
113ad85094bSMauro Carvalho Chehab msg[1].addr = 0x0c;
114ad85094bSMauro Carvalho Chehab msg[1].flags = I2C_M_RD;
115ad85094bSMauro Carvalho Chehab msg[1].len = 0x01;
116ad85094bSMauro Carvalho Chehab msg[1].buf = &buf[1];
117ad85094bSMauro Carvalho Chehab *val = 0;
118ad85094bSMauro Carvalho Chehab if (i2c_transfer(client->adapter, msg, 2) != 2)
119ad85094bSMauro Carvalho Chehab return -EIO;
120ad85094bSMauro Carvalho Chehab *val = buf[1];
121ad85094bSMauro Carvalho Chehab return 0;
122ad85094bSMauro Carvalho Chehab }
123ad85094bSMauro Carvalho Chehab
124bdfe0bebSMauro Carvalho Chehab static const u32 ov5693_embedded_effective_size = 28;
125ad85094bSMauro Carvalho Chehab
126ad85094bSMauro Carvalho Chehab /* i2c read/write stuff */
ov5693_read_reg(struct i2c_client * client,u16 data_length,u16 reg,u16 * val)127ad85094bSMauro Carvalho Chehab static int ov5693_read_reg(struct i2c_client *client,
128ad85094bSMauro Carvalho Chehab u16 data_length, u16 reg, u16 *val)
129ad85094bSMauro Carvalho Chehab {
130ad85094bSMauro Carvalho Chehab int err;
131ad85094bSMauro Carvalho Chehab struct i2c_msg msg[2];
132ad85094bSMauro Carvalho Chehab unsigned char data[6];
133ad85094bSMauro Carvalho Chehab
134ad85094bSMauro Carvalho Chehab if (!client->adapter) {
135ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s error, no client->adapter\n",
136ad85094bSMauro Carvalho Chehab __func__);
137ad85094bSMauro Carvalho Chehab return -ENODEV;
138ad85094bSMauro Carvalho Chehab }
139ad85094bSMauro Carvalho Chehab
140ad85094bSMauro Carvalho Chehab if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
141ad85094bSMauro Carvalho Chehab && data_length != OV5693_32BIT) {
142ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s error, invalid data length\n",
143ad85094bSMauro Carvalho Chehab __func__);
144ad85094bSMauro Carvalho Chehab return -EINVAL;
145ad85094bSMauro Carvalho Chehab }
146ad85094bSMauro Carvalho Chehab
147ad85094bSMauro Carvalho Chehab memset(msg, 0, sizeof(msg));
148ad85094bSMauro Carvalho Chehab
149ad85094bSMauro Carvalho Chehab msg[0].addr = client->addr;
150ad85094bSMauro Carvalho Chehab msg[0].flags = 0;
151ad85094bSMauro Carvalho Chehab msg[0].len = I2C_MSG_LENGTH;
152ad85094bSMauro Carvalho Chehab msg[0].buf = data;
153ad85094bSMauro Carvalho Chehab
154ad85094bSMauro Carvalho Chehab /* high byte goes out first */
155ad85094bSMauro Carvalho Chehab data[0] = (u8)(reg >> 8);
156ad85094bSMauro Carvalho Chehab data[1] = (u8)(reg & 0xff);
157ad85094bSMauro Carvalho Chehab
158ad85094bSMauro Carvalho Chehab msg[1].addr = client->addr;
159ad85094bSMauro Carvalho Chehab msg[1].len = data_length;
160ad85094bSMauro Carvalho Chehab msg[1].flags = I2C_M_RD;
161ad85094bSMauro Carvalho Chehab msg[1].buf = data;
162ad85094bSMauro Carvalho Chehab
163ad85094bSMauro Carvalho Chehab err = i2c_transfer(client->adapter, msg, 2);
164ad85094bSMauro Carvalho Chehab if (err != 2) {
165ad85094bSMauro Carvalho Chehab if (err >= 0)
166ad85094bSMauro Carvalho Chehab err = -EIO;
167ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
168ad85094bSMauro Carvalho Chehab "read from offset 0x%x error %d", reg, err);
169ad85094bSMauro Carvalho Chehab return err;
170ad85094bSMauro Carvalho Chehab }
171ad85094bSMauro Carvalho Chehab
172ad85094bSMauro Carvalho Chehab *val = 0;
173ad85094bSMauro Carvalho Chehab /* high byte comes first */
174ad85094bSMauro Carvalho Chehab if (data_length == OV5693_8BIT)
175ad85094bSMauro Carvalho Chehab *val = (u8)data[0];
176ad85094bSMauro Carvalho Chehab else if (data_length == OV5693_16BIT)
177ad85094bSMauro Carvalho Chehab *val = be16_to_cpu(*(__be16 *)&data[0]);
178ad85094bSMauro Carvalho Chehab else
179ad85094bSMauro Carvalho Chehab *val = be32_to_cpu(*(__be32 *)&data[0]);
180ad85094bSMauro Carvalho Chehab
181ad85094bSMauro Carvalho Chehab return 0;
182ad85094bSMauro Carvalho Chehab }
183ad85094bSMauro Carvalho Chehab
ov5693_i2c_write(struct i2c_client * client,u16 len,u8 * data)184ad85094bSMauro Carvalho Chehab static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
185ad85094bSMauro Carvalho Chehab {
186ad85094bSMauro Carvalho Chehab struct i2c_msg msg;
187ad85094bSMauro Carvalho Chehab const int num_msg = 1;
188ad85094bSMauro Carvalho Chehab int ret;
189ad85094bSMauro Carvalho Chehab
190ad85094bSMauro Carvalho Chehab msg.addr = client->addr;
191ad85094bSMauro Carvalho Chehab msg.flags = 0;
192ad85094bSMauro Carvalho Chehab msg.len = len;
193ad85094bSMauro Carvalho Chehab msg.buf = data;
194ad85094bSMauro Carvalho Chehab ret = i2c_transfer(client->adapter, &msg, 1);
195ad85094bSMauro Carvalho Chehab
196ad85094bSMauro Carvalho Chehab return ret == num_msg ? 0 : -EIO;
197ad85094bSMauro Carvalho Chehab }
198ad85094bSMauro Carvalho Chehab
vcm_dw_i2c_write(struct i2c_client * client,u16 data)199ad85094bSMauro Carvalho Chehab static int vcm_dw_i2c_write(struct i2c_client *client, u16 data)
200ad85094bSMauro Carvalho Chehab {
201ad85094bSMauro Carvalho Chehab struct i2c_msg msg;
202ad85094bSMauro Carvalho Chehab const int num_msg = 1;
203ad85094bSMauro Carvalho Chehab int ret;
204ad85094bSMauro Carvalho Chehab __be16 val;
205ad85094bSMauro Carvalho Chehab
206ad85094bSMauro Carvalho Chehab val = cpu_to_be16(data);
207ad85094bSMauro Carvalho Chehab msg.addr = VCM_ADDR;
208ad85094bSMauro Carvalho Chehab msg.flags = 0;
209ad85094bSMauro Carvalho Chehab msg.len = OV5693_16BIT;
210ad85094bSMauro Carvalho Chehab msg.buf = (void *)&val;
211ad85094bSMauro Carvalho Chehab
212ad85094bSMauro Carvalho Chehab ret = i2c_transfer(client->adapter, &msg, 1);
213ad85094bSMauro Carvalho Chehab
214ad85094bSMauro Carvalho Chehab return ret == num_msg ? 0 : -EIO;
215ad85094bSMauro Carvalho Chehab }
216ad85094bSMauro Carvalho Chehab
217ad85094bSMauro Carvalho Chehab /*
218ad85094bSMauro Carvalho Chehab * Theory: per datasheet, the two VCMs both allow for a 2-byte read.
219ad85094bSMauro Carvalho Chehab * The DW9714 doesn't actually specify what this does (it has a
220ad85094bSMauro Carvalho Chehab * two-byte write-only protocol, but specifies the read sequence as
221ad85094bSMauro Carvalho Chehab * legal), but it returns the same data (zeroes) always, after an
222ad85094bSMauro Carvalho Chehab * undocumented initial NAK. The AD5823 has a one-byte address
223ad85094bSMauro Carvalho Chehab * register to which all writes go, and subsequent reads will cycle
224ad85094bSMauro Carvalho Chehab * through the 8 bytes of registers. Notably, the default values (the
225ad85094bSMauro Carvalho Chehab * device is always power-cycled affirmatively, so we can rely on
226ad85094bSMauro Carvalho Chehab * these) in AD5823 are not pairwise repetitions of the same 16 bit
227ad85094bSMauro Carvalho Chehab * word. So all we have to do is sequentially read two bytes at a
228ad85094bSMauro Carvalho Chehab * time and see if we detect a difference in any of the first four
229ad85094bSMauro Carvalho Chehab * pairs.
230ad85094bSMauro Carvalho Chehab */
vcm_detect(struct i2c_client * client)231ad85094bSMauro Carvalho Chehab static int vcm_detect(struct i2c_client *client)
232ad85094bSMauro Carvalho Chehab {
233ad85094bSMauro Carvalho Chehab int i, ret;
234ad85094bSMauro Carvalho Chehab struct i2c_msg msg;
235ad85094bSMauro Carvalho Chehab u16 data0 = 0, data;
236ad85094bSMauro Carvalho Chehab
237ad85094bSMauro Carvalho Chehab for (i = 0; i < 4; i++) {
238ad85094bSMauro Carvalho Chehab msg.addr = VCM_ADDR;
239ad85094bSMauro Carvalho Chehab msg.flags = I2C_M_RD;
240ad85094bSMauro Carvalho Chehab msg.len = sizeof(data);
241ad85094bSMauro Carvalho Chehab msg.buf = (u8 *)&data;
242ad85094bSMauro Carvalho Chehab ret = i2c_transfer(client->adapter, &msg, 1);
243ad85094bSMauro Carvalho Chehab
244ad85094bSMauro Carvalho Chehab /*
245ad85094bSMauro Carvalho Chehab * DW9714 always fails the first read and returns
246ad85094bSMauro Carvalho Chehab * zeroes for subsequent ones
247ad85094bSMauro Carvalho Chehab */
248ad85094bSMauro Carvalho Chehab if (i == 0 && ret == -EREMOTEIO) {
249ad85094bSMauro Carvalho Chehab data0 = 0;
250ad85094bSMauro Carvalho Chehab continue;
251ad85094bSMauro Carvalho Chehab }
252ad85094bSMauro Carvalho Chehab
253ad85094bSMauro Carvalho Chehab if (i == 0)
254ad85094bSMauro Carvalho Chehab data0 = data;
255ad85094bSMauro Carvalho Chehab
256ad85094bSMauro Carvalho Chehab if (data != data0)
257ad85094bSMauro Carvalho Chehab return VCM_AD5823;
258ad85094bSMauro Carvalho Chehab }
259ad85094bSMauro Carvalho Chehab return ret == 1 ? VCM_DW9714 : ret;
260ad85094bSMauro Carvalho Chehab }
261ad85094bSMauro Carvalho Chehab
ov5693_write_reg(struct i2c_client * client,u16 data_length,u16 reg,u16 val)262ad85094bSMauro Carvalho Chehab static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
263ad85094bSMauro Carvalho Chehab u16 reg, u16 val)
264ad85094bSMauro Carvalho Chehab {
265ad85094bSMauro Carvalho Chehab int ret;
266ad85094bSMauro Carvalho Chehab unsigned char data[4] = {0};
267ad85094bSMauro Carvalho Chehab __be16 *wreg = (void *)data;
268ad85094bSMauro Carvalho Chehab const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
269ad85094bSMauro Carvalho Chehab
270ad85094bSMauro Carvalho Chehab if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
271ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
272ad85094bSMauro Carvalho Chehab "%s error, invalid data_length\n", __func__);
273ad85094bSMauro Carvalho Chehab return -EINVAL;
274ad85094bSMauro Carvalho Chehab }
275ad85094bSMauro Carvalho Chehab
276ad85094bSMauro Carvalho Chehab /* high byte goes out first */
277ad85094bSMauro Carvalho Chehab *wreg = cpu_to_be16(reg);
278ad85094bSMauro Carvalho Chehab
279ad85094bSMauro Carvalho Chehab if (data_length == OV5693_8BIT) {
280ad85094bSMauro Carvalho Chehab data[2] = (u8)(val);
281ad85094bSMauro Carvalho Chehab } else {
282ad85094bSMauro Carvalho Chehab /* OV5693_16BIT */
283ad85094bSMauro Carvalho Chehab __be16 *wdata = (void *)&data[2];
284ad85094bSMauro Carvalho Chehab
285ad85094bSMauro Carvalho Chehab *wdata = cpu_to_be16(val);
286ad85094bSMauro Carvalho Chehab }
287ad85094bSMauro Carvalho Chehab
288ad85094bSMauro Carvalho Chehab ret = ov5693_i2c_write(client, len, data);
289ad85094bSMauro Carvalho Chehab if (ret)
290ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
291ad85094bSMauro Carvalho Chehab "write error: wrote 0x%x to offset 0x%x error %d",
292ad85094bSMauro Carvalho Chehab val, reg, ret);
293ad85094bSMauro Carvalho Chehab
294ad85094bSMauro Carvalho Chehab return ret;
295ad85094bSMauro Carvalho Chehab }
296ad85094bSMauro Carvalho Chehab
297ad85094bSMauro Carvalho Chehab /*
298ad85094bSMauro Carvalho Chehab * ov5693_write_reg_array - Initializes a list of OV5693 registers
299ad85094bSMauro Carvalho Chehab * @client: i2c driver client structure
300ad85094bSMauro Carvalho Chehab * @reglist: list of registers to be written
301ad85094bSMauro Carvalho Chehab *
302ad85094bSMauro Carvalho Chehab * This function initializes a list of registers. When consecutive addresses
303ad85094bSMauro Carvalho Chehab * are found in a row on the list, this function creates a buffer and sends
304ad85094bSMauro Carvalho Chehab * consecutive data in a single i2c_transfer().
305ad85094bSMauro Carvalho Chehab *
306ad85094bSMauro Carvalho Chehab * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
307ad85094bSMauro Carvalho Chehab * __ov5693_write_reg_is_consecutive() are internal functions to
308ad85094bSMauro Carvalho Chehab * ov5693_write_reg_array_fast() and should be not used anywhere else.
309ad85094bSMauro Carvalho Chehab *
310ad85094bSMauro Carvalho Chehab */
311ad85094bSMauro Carvalho Chehab
__ov5693_flush_reg_array(struct i2c_client * client,struct ov5693_write_ctrl * ctrl)312ad85094bSMauro Carvalho Chehab static int __ov5693_flush_reg_array(struct i2c_client *client,
313ad85094bSMauro Carvalho Chehab struct ov5693_write_ctrl *ctrl)
314ad85094bSMauro Carvalho Chehab {
315ad85094bSMauro Carvalho Chehab u16 size;
316ad85094bSMauro Carvalho Chehab __be16 *reg = (void *)&ctrl->buffer.addr;
317ad85094bSMauro Carvalho Chehab
318ad85094bSMauro Carvalho Chehab if (ctrl->index == 0)
319ad85094bSMauro Carvalho Chehab return 0;
320ad85094bSMauro Carvalho Chehab
321ad85094bSMauro Carvalho Chehab size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
322ad85094bSMauro Carvalho Chehab
323ad85094bSMauro Carvalho Chehab *reg = cpu_to_be16(ctrl->buffer.addr);
324ad85094bSMauro Carvalho Chehab ctrl->index = 0;
325ad85094bSMauro Carvalho Chehab
326ad85094bSMauro Carvalho Chehab return ov5693_i2c_write(client, size, (u8 *)reg);
327ad85094bSMauro Carvalho Chehab }
328ad85094bSMauro Carvalho Chehab
__ov5693_buf_reg_array(struct i2c_client * client,struct ov5693_write_ctrl * ctrl,const struct ov5693_reg * next)329ad85094bSMauro Carvalho Chehab static int __ov5693_buf_reg_array(struct i2c_client *client,
330ad85094bSMauro Carvalho Chehab struct ov5693_write_ctrl *ctrl,
331ad85094bSMauro Carvalho Chehab const struct ov5693_reg *next)
332ad85094bSMauro Carvalho Chehab {
333ad85094bSMauro Carvalho Chehab int size;
334ad85094bSMauro Carvalho Chehab __be16 *data16;
335ad85094bSMauro Carvalho Chehab
336ad85094bSMauro Carvalho Chehab switch (next->type) {
337ad85094bSMauro Carvalho Chehab case OV5693_8BIT:
338ad85094bSMauro Carvalho Chehab size = 1;
339ad85094bSMauro Carvalho Chehab ctrl->buffer.data[ctrl->index] = (u8)next->val;
340ad85094bSMauro Carvalho Chehab break;
341ad85094bSMauro Carvalho Chehab case OV5693_16BIT:
342ad85094bSMauro Carvalho Chehab size = 2;
343ad85094bSMauro Carvalho Chehab
344ad85094bSMauro Carvalho Chehab data16 = (void *)&ctrl->buffer.data[ctrl->index];
345ad85094bSMauro Carvalho Chehab *data16 = cpu_to_be16((u16)next->val);
346ad85094bSMauro Carvalho Chehab break;
347ad85094bSMauro Carvalho Chehab default:
348ad85094bSMauro Carvalho Chehab return -EINVAL;
349ad85094bSMauro Carvalho Chehab }
350ad85094bSMauro Carvalho Chehab
351ad85094bSMauro Carvalho Chehab /* When first item is added, we need to store its starting address */
352ad85094bSMauro Carvalho Chehab if (ctrl->index == 0)
353ad85094bSMauro Carvalho Chehab ctrl->buffer.addr = next->reg;
354ad85094bSMauro Carvalho Chehab
355ad85094bSMauro Carvalho Chehab ctrl->index += size;
356ad85094bSMauro Carvalho Chehab
357ad85094bSMauro Carvalho Chehab /*
358ad85094bSMauro Carvalho Chehab * Buffer cannot guarantee free space for u32? Better flush it to avoid
359ad85094bSMauro Carvalho Chehab * possible lack of memory for next item.
360ad85094bSMauro Carvalho Chehab */
361ad85094bSMauro Carvalho Chehab if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
362ad85094bSMauro Carvalho Chehab return __ov5693_flush_reg_array(client, ctrl);
363ad85094bSMauro Carvalho Chehab
364ad85094bSMauro Carvalho Chehab return 0;
365ad85094bSMauro Carvalho Chehab }
366ad85094bSMauro Carvalho Chehab
__ov5693_write_reg_is_consecutive(struct i2c_client * client,struct ov5693_write_ctrl * ctrl,const struct ov5693_reg * next)367ad85094bSMauro Carvalho Chehab static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
368ad85094bSMauro Carvalho Chehab struct ov5693_write_ctrl *ctrl,
369ad85094bSMauro Carvalho Chehab const struct ov5693_reg *next)
370ad85094bSMauro Carvalho Chehab {
371ad85094bSMauro Carvalho Chehab if (ctrl->index == 0)
372ad85094bSMauro Carvalho Chehab return 1;
373ad85094bSMauro Carvalho Chehab
374ad85094bSMauro Carvalho Chehab return ctrl->buffer.addr + ctrl->index == next->reg;
375ad85094bSMauro Carvalho Chehab }
376ad85094bSMauro Carvalho Chehab
ov5693_write_reg_array(struct i2c_client * client,const struct ov5693_reg * reglist)377ad85094bSMauro Carvalho Chehab static int ov5693_write_reg_array(struct i2c_client *client,
378ad85094bSMauro Carvalho Chehab const struct ov5693_reg *reglist)
379ad85094bSMauro Carvalho Chehab {
380ad85094bSMauro Carvalho Chehab const struct ov5693_reg *next = reglist;
381ad85094bSMauro Carvalho Chehab struct ov5693_write_ctrl ctrl;
382ad85094bSMauro Carvalho Chehab int err;
383ad85094bSMauro Carvalho Chehab
384ad85094bSMauro Carvalho Chehab ctrl.index = 0;
385ad85094bSMauro Carvalho Chehab for (; next->type != OV5693_TOK_TERM; next++) {
386ad85094bSMauro Carvalho Chehab switch (next->type & OV5693_TOK_MASK) {
387ad85094bSMauro Carvalho Chehab case OV5693_TOK_DELAY:
388ad85094bSMauro Carvalho Chehab err = __ov5693_flush_reg_array(client, &ctrl);
389ad85094bSMauro Carvalho Chehab if (err)
390ad85094bSMauro Carvalho Chehab return err;
391ad85094bSMauro Carvalho Chehab msleep(next->val);
392ad85094bSMauro Carvalho Chehab break;
393ad85094bSMauro Carvalho Chehab default:
394ad85094bSMauro Carvalho Chehab /*
395ad85094bSMauro Carvalho Chehab * If next address is not consecutive, data needs to be
396ad85094bSMauro Carvalho Chehab * flushed before proceed.
397ad85094bSMauro Carvalho Chehab */
398ad85094bSMauro Carvalho Chehab if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
399ad85094bSMauro Carvalho Chehab next)) {
400ad85094bSMauro Carvalho Chehab err = __ov5693_flush_reg_array(client, &ctrl);
401ad85094bSMauro Carvalho Chehab if (err)
402ad85094bSMauro Carvalho Chehab return err;
403ad85094bSMauro Carvalho Chehab }
404ad85094bSMauro Carvalho Chehab err = __ov5693_buf_reg_array(client, &ctrl, next);
405ad85094bSMauro Carvalho Chehab if (err) {
406ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
407ad85094bSMauro Carvalho Chehab "%s: write error, aborted\n",
408ad85094bSMauro Carvalho Chehab __func__);
409ad85094bSMauro Carvalho Chehab return err;
410ad85094bSMauro Carvalho Chehab }
411ad85094bSMauro Carvalho Chehab break;
412ad85094bSMauro Carvalho Chehab }
413ad85094bSMauro Carvalho Chehab }
414ad85094bSMauro Carvalho Chehab
415ad85094bSMauro Carvalho Chehab return __ov5693_flush_reg_array(client, &ctrl);
416ad85094bSMauro Carvalho Chehab }
417bdfe0bebSMauro Carvalho Chehab
__ov5693_set_exposure(struct v4l2_subdev * sd,int coarse_itg,int gain,int digitgain)418ad85094bSMauro Carvalho Chehab static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
419ad85094bSMauro Carvalho Chehab int gain, int digitgain)
420ad85094bSMauro Carvalho Chehab
421ad85094bSMauro Carvalho Chehab {
422ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
423ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
424ad85094bSMauro Carvalho Chehab u16 vts, hts;
425ad85094bSMauro Carvalho Chehab int ret, exp_val;
426ad85094bSMauro Carvalho Chehab
427ad85094bSMauro Carvalho Chehab hts = ov5693_res[dev->fmt_idx].pixels_per_line;
428ad85094bSMauro Carvalho Chehab vts = ov5693_res[dev->fmt_idx].lines_per_frame;
429ad85094bSMauro Carvalho Chehab /*
430ad85094bSMauro Carvalho Chehab * If coarse_itg is larger than 1<<15, can not write to reg directly.
431ad85094bSMauro Carvalho Chehab * The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts
432ad85094bSMauro Carvalho Chehab * to the reg.
433ad85094bSMauro Carvalho Chehab */
434ad85094bSMauro Carvalho Chehab if (coarse_itg > (1 << 15)) {
435ad85094bSMauro Carvalho Chehab hts = hts * 2;
436ad85094bSMauro Carvalho Chehab coarse_itg = (int)coarse_itg / 2;
437ad85094bSMauro Carvalho Chehab }
438ad85094bSMauro Carvalho Chehab /* group hold */
439ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
440ad85094bSMauro Carvalho Chehab OV5693_GROUP_ACCESS, 0x00);
441ad85094bSMauro Carvalho Chehab if (ret) {
442ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
443ad85094bSMauro Carvalho Chehab __func__, OV5693_GROUP_ACCESS);
444ad85094bSMauro Carvalho Chehab return ret;
445ad85094bSMauro Carvalho Chehab }
446ad85094bSMauro Carvalho Chehab
447ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
448ad85094bSMauro Carvalho Chehab OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF);
449ad85094bSMauro Carvalho Chehab if (ret) {
450ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
451ad85094bSMauro Carvalho Chehab __func__, OV5693_TIMING_HTS_H);
452ad85094bSMauro Carvalho Chehab return ret;
453ad85094bSMauro Carvalho Chehab }
454ad85094bSMauro Carvalho Chehab
455ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
456ad85094bSMauro Carvalho Chehab OV5693_TIMING_HTS_L, hts & 0xFF);
457ad85094bSMauro Carvalho Chehab if (ret) {
458ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
459ad85094bSMauro Carvalho Chehab __func__, OV5693_TIMING_HTS_L);
460ad85094bSMauro Carvalho Chehab return ret;
461ad85094bSMauro Carvalho Chehab }
462ad85094bSMauro Carvalho Chehab /* Increase the VTS to match exposure + MARGIN */
463ad85094bSMauro Carvalho Chehab if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN)
464ad85094bSMauro Carvalho Chehab vts = (u16)coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
465ad85094bSMauro Carvalho Chehab
466ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
467ad85094bSMauro Carvalho Chehab OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF);
468ad85094bSMauro Carvalho Chehab if (ret) {
469ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
470ad85094bSMauro Carvalho Chehab __func__, OV5693_TIMING_VTS_H);
471ad85094bSMauro Carvalho Chehab return ret;
472ad85094bSMauro Carvalho Chehab }
473ad85094bSMauro Carvalho Chehab
474ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
475ad85094bSMauro Carvalho Chehab OV5693_TIMING_VTS_L, vts & 0xFF);
476ad85094bSMauro Carvalho Chehab if (ret) {
477ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
478ad85094bSMauro Carvalho Chehab __func__, OV5693_TIMING_VTS_L);
479ad85094bSMauro Carvalho Chehab return ret;
480ad85094bSMauro Carvalho Chehab }
481ad85094bSMauro Carvalho Chehab
482ad85094bSMauro Carvalho Chehab /* set exposure */
483ad85094bSMauro Carvalho Chehab
484ad85094bSMauro Carvalho Chehab /* Lower four bit should be 0*/
485ad85094bSMauro Carvalho Chehab exp_val = coarse_itg << 4;
486ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
487ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_L, exp_val & 0xFF);
488ad85094bSMauro Carvalho Chehab if (ret) {
489ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
490ad85094bSMauro Carvalho Chehab __func__, OV5693_EXPOSURE_L);
491ad85094bSMauro Carvalho Chehab return ret;
492ad85094bSMauro Carvalho Chehab }
493ad85094bSMauro Carvalho Chehab
494ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
495ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF);
496ad85094bSMauro Carvalho Chehab if (ret) {
497ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
498ad85094bSMauro Carvalho Chehab __func__, OV5693_EXPOSURE_M);
499ad85094bSMauro Carvalho Chehab return ret;
500ad85094bSMauro Carvalho Chehab }
501ad85094bSMauro Carvalho Chehab
502ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
503ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F);
504ad85094bSMauro Carvalho Chehab if (ret) {
505ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
506ad85094bSMauro Carvalho Chehab __func__, OV5693_EXPOSURE_H);
507ad85094bSMauro Carvalho Chehab return ret;
508ad85094bSMauro Carvalho Chehab }
509ad85094bSMauro Carvalho Chehab
510ad85094bSMauro Carvalho Chehab /* Analog gain */
511ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
512ad85094bSMauro Carvalho Chehab OV5693_AGC_L, gain & 0xff);
513ad85094bSMauro Carvalho Chehab if (ret) {
514ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
515ad85094bSMauro Carvalho Chehab __func__, OV5693_AGC_L);
516ad85094bSMauro Carvalho Chehab return ret;
517ad85094bSMauro Carvalho Chehab }
518ad85094bSMauro Carvalho Chehab
519ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
520ad85094bSMauro Carvalho Chehab OV5693_AGC_H, (gain >> 8) & 0xff);
521ad85094bSMauro Carvalho Chehab if (ret) {
522ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
523ad85094bSMauro Carvalho Chehab __func__, OV5693_AGC_H);
524ad85094bSMauro Carvalho Chehab return ret;
525ad85094bSMauro Carvalho Chehab }
526ad85094bSMauro Carvalho Chehab
527ad85094bSMauro Carvalho Chehab /* Digital gain */
528ad85094bSMauro Carvalho Chehab if (digitgain) {
529ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_16BIT,
530ad85094bSMauro Carvalho Chehab OV5693_MWB_RED_GAIN_H, digitgain);
531ad85094bSMauro Carvalho Chehab if (ret) {
532ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
533ad85094bSMauro Carvalho Chehab __func__, OV5693_MWB_RED_GAIN_H);
534ad85094bSMauro Carvalho Chehab return ret;
535ad85094bSMauro Carvalho Chehab }
536ad85094bSMauro Carvalho Chehab
537ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_16BIT,
538ad85094bSMauro Carvalho Chehab OV5693_MWB_GREEN_GAIN_H, digitgain);
539ad85094bSMauro Carvalho Chehab if (ret) {
540ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
541ad85094bSMauro Carvalho Chehab __func__, OV5693_MWB_RED_GAIN_H);
542ad85094bSMauro Carvalho Chehab return ret;
543ad85094bSMauro Carvalho Chehab }
544ad85094bSMauro Carvalho Chehab
545ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_16BIT,
546ad85094bSMauro Carvalho Chehab OV5693_MWB_BLUE_GAIN_H, digitgain);
547ad85094bSMauro Carvalho Chehab if (ret) {
548ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "%s: write %x error, aborted\n",
549ad85094bSMauro Carvalho Chehab __func__, OV5693_MWB_RED_GAIN_H);
550ad85094bSMauro Carvalho Chehab return ret;
551ad85094bSMauro Carvalho Chehab }
552ad85094bSMauro Carvalho Chehab }
553ad85094bSMauro Carvalho Chehab
554ad85094bSMauro Carvalho Chehab /* End group */
555ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
556ad85094bSMauro Carvalho Chehab OV5693_GROUP_ACCESS, 0x10);
557ad85094bSMauro Carvalho Chehab if (ret)
558ad85094bSMauro Carvalho Chehab return ret;
559ad85094bSMauro Carvalho Chehab
560ad85094bSMauro Carvalho Chehab /* Delay launch group */
561ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
562ad85094bSMauro Carvalho Chehab OV5693_GROUP_ACCESS, 0xa0);
563ad85094bSMauro Carvalho Chehab if (ret)
564ad85094bSMauro Carvalho Chehab return ret;
565ad85094bSMauro Carvalho Chehab return ret;
566ad85094bSMauro Carvalho Chehab }
567ad85094bSMauro Carvalho Chehab
ov5693_set_exposure(struct v4l2_subdev * sd,int exposure,int gain,int digitgain)568ad85094bSMauro Carvalho Chehab static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
569ad85094bSMauro Carvalho Chehab int gain, int digitgain)
570ad85094bSMauro Carvalho Chehab {
571ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
572ad85094bSMauro Carvalho Chehab int ret;
573ad85094bSMauro Carvalho Chehab
574ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
575ad85094bSMauro Carvalho Chehab ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
576ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
577ad85094bSMauro Carvalho Chehab
578ad85094bSMauro Carvalho Chehab return ret;
579ad85094bSMauro Carvalho Chehab }
580ad85094bSMauro Carvalho Chehab
ov5693_s_exposure(struct v4l2_subdev * sd,struct atomisp_exposure * exposure)581ad85094bSMauro Carvalho Chehab static long ov5693_s_exposure(struct v4l2_subdev *sd,
582ad85094bSMauro Carvalho Chehab struct atomisp_exposure *exposure)
583ad85094bSMauro Carvalho Chehab {
584ad85094bSMauro Carvalho Chehab u16 coarse_itg = exposure->integration_time[0];
585ad85094bSMauro Carvalho Chehab u16 analog_gain = exposure->gain[0];
586ad85094bSMauro Carvalho Chehab u16 digital_gain = exposure->gain[1];
587ad85094bSMauro Carvalho Chehab
588ad85094bSMauro Carvalho Chehab /* we should not accept the invalid value below */
589ad85094bSMauro Carvalho Chehab if (analog_gain == 0) {
590ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
591ad85094bSMauro Carvalho Chehab
592ad85094bSMauro Carvalho Chehab v4l2_err(client, "%s: invalid value\n", __func__);
593ad85094bSMauro Carvalho Chehab return -EINVAL;
594ad85094bSMauro Carvalho Chehab }
595ad85094bSMauro Carvalho Chehab return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
596ad85094bSMauro Carvalho Chehab }
597ad85094bSMauro Carvalho Chehab
ov5693_read_otp_reg_array(struct i2c_client * client,u16 size,u16 addr,u8 * buf)598ad85094bSMauro Carvalho Chehab static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size,
599ad85094bSMauro Carvalho Chehab u16 addr, u8 *buf)
600ad85094bSMauro Carvalho Chehab {
601ad85094bSMauro Carvalho Chehab u16 index;
602ad85094bSMauro Carvalho Chehab int ret;
603ad85094bSMauro Carvalho Chehab u16 *pVal = NULL;
604ad85094bSMauro Carvalho Chehab
605ad85094bSMauro Carvalho Chehab for (index = 0; index <= size; index++) {
606ad85094bSMauro Carvalho Chehab pVal = (u16 *)(buf + index);
607ad85094bSMauro Carvalho Chehab ret =
608ad85094bSMauro Carvalho Chehab ov5693_read_reg(client, OV5693_8BIT, addr + index,
609ad85094bSMauro Carvalho Chehab pVal);
610ad85094bSMauro Carvalho Chehab if (ret)
611ad85094bSMauro Carvalho Chehab return ret;
612ad85094bSMauro Carvalho Chehab }
613ad85094bSMauro Carvalho Chehab
614ad85094bSMauro Carvalho Chehab return 0;
615ad85094bSMauro Carvalho Chehab }
616ad85094bSMauro Carvalho Chehab
__ov5693_otp_read(struct v4l2_subdev * sd,u8 * buf)617ad85094bSMauro Carvalho Chehab static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
618ad85094bSMauro Carvalho Chehab {
619ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
620ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
621ad85094bSMauro Carvalho Chehab int ret;
622ad85094bSMauro Carvalho Chehab int i;
623ad85094bSMauro Carvalho Chehab u8 *b = buf;
624ad85094bSMauro Carvalho Chehab
625ad85094bSMauro Carvalho Chehab dev->otp_size = 0;
626ad85094bSMauro Carvalho Chehab for (i = 1; i < OV5693_OTP_BANK_MAX; i++) {
627ad85094bSMauro Carvalho Chehab /*set bank NO and OTP read mode. */
628eaa399ebSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG,
629eaa399ebSMauro Carvalho Chehab (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no
630ad85094bSMauro Carvalho Chehab if (ret) {
631ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "failed to prepare OTP page\n");
632ad85094bSMauro Carvalho Chehab return ret;
633ad85094bSMauro Carvalho Chehab }
634ad85094bSMauro Carvalho Chehab //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0));
635ad85094bSMauro Carvalho Chehab
636ad85094bSMauro Carvalho Chehab /*enable read */
637eaa399ebSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG,
638eaa399ebSMauro Carvalho Chehab OV5693_OTP_MODE_READ); // enable :1
639ad85094bSMauro Carvalho Chehab if (ret) {
640ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
641ad85094bSMauro Carvalho Chehab "failed to set OTP reading mode page");
642ad85094bSMauro Carvalho Chehab return ret;
643ad85094bSMauro Carvalho Chehab }
644ad85094bSMauro Carvalho Chehab //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ);
645ad85094bSMauro Carvalho Chehab
646ad85094bSMauro Carvalho Chehab /* Reading the OTP data array */
647ad85094bSMauro Carvalho Chehab ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE,
648ad85094bSMauro Carvalho Chehab OV5693_OTP_START_ADDR,
649ad85094bSMauro Carvalho Chehab b);
650ad85094bSMauro Carvalho Chehab if (ret) {
651ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "failed to read OTP data\n");
652ad85094bSMauro Carvalho Chehab return ret;
653ad85094bSMauro Carvalho Chehab }
654ad85094bSMauro Carvalho Chehab
655ad85094bSMauro Carvalho Chehab //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15));
656ad85094bSMauro Carvalho Chehab
657ad85094bSMauro Carvalho Chehab //Intel OTP map, try to read 320byts first.
658ad85094bSMauro Carvalho Chehab if (i == 21) {
659ad85094bSMauro Carvalho Chehab if ((*b) == 0) {
660ad85094bSMauro Carvalho Chehab dev->otp_size = 320;
661ad85094bSMauro Carvalho Chehab break;
662ad85094bSMauro Carvalho Chehab } else {
663ad85094bSMauro Carvalho Chehab b = buf;
664ad85094bSMauro Carvalho Chehab continue;
665ad85094bSMauro Carvalho Chehab }
666eaa399ebSMauro Carvalho Chehab } else if (i ==
667eaa399ebSMauro Carvalho Chehab 24) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data.
668ad85094bSMauro Carvalho Chehab if ((*b) == 0) {
669ad85094bSMauro Carvalho Chehab dev->otp_size = 32;
670ad85094bSMauro Carvalho Chehab break;
671ad85094bSMauro Carvalho Chehab } else {
672ad85094bSMauro Carvalho Chehab b = buf;
673ad85094bSMauro Carvalho Chehab continue;
674ad85094bSMauro Carvalho Chehab }
675eaa399ebSMauro Carvalho Chehab } else if (i ==
676eaa399ebSMauro Carvalho Chehab 27) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again.
677ad85094bSMauro Carvalho Chehab if ((*b) == 0) {
678ad85094bSMauro Carvalho Chehab dev->otp_size = 32;
679ad85094bSMauro Carvalho Chehab break;
680ad85094bSMauro Carvalho Chehab } else {
681ad85094bSMauro Carvalho Chehab dev->otp_size = 0; // no OTP data.
682ad85094bSMauro Carvalho Chehab break;
683ad85094bSMauro Carvalho Chehab }
684ad85094bSMauro Carvalho Chehab }
685ad85094bSMauro Carvalho Chehab
686ad85094bSMauro Carvalho Chehab b = b + OV5693_OTP_BANK_SIZE;
687ad85094bSMauro Carvalho Chehab }
688ad85094bSMauro Carvalho Chehab return 0;
689ad85094bSMauro Carvalho Chehab }
690ad85094bSMauro Carvalho Chehab
691ad85094bSMauro Carvalho Chehab /*
692ad85094bSMauro Carvalho Chehab * Read otp data and store it into a kmalloced buffer.
693ad85094bSMauro Carvalho Chehab * The caller must kfree the buffer when no more needed.
694ad85094bSMauro Carvalho Chehab * @size: set to the size of the returned otp data.
695ad85094bSMauro Carvalho Chehab */
ov5693_otp_read(struct v4l2_subdev * sd)696ad85094bSMauro Carvalho Chehab static void *ov5693_otp_read(struct v4l2_subdev *sd)
697ad85094bSMauro Carvalho Chehab {
698ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
699ad85094bSMauro Carvalho Chehab u8 *buf;
700ad85094bSMauro Carvalho Chehab int ret;
701ad85094bSMauro Carvalho Chehab
702ad85094bSMauro Carvalho Chehab buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL);
703ad85094bSMauro Carvalho Chehab if (!buf)
704ad85094bSMauro Carvalho Chehab return ERR_PTR(-ENOMEM);
705ad85094bSMauro Carvalho Chehab
706ad85094bSMauro Carvalho Chehab //otp valid after mipi on and sw stream on
707ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00);
708ad85094bSMauro Carvalho Chehab
709ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
710ad85094bSMauro Carvalho Chehab OV5693_SW_STREAM, OV5693_START_STREAMING);
711ad85094bSMauro Carvalho Chehab
712ad85094bSMauro Carvalho Chehab ret = __ov5693_otp_read(sd, buf);
713ad85094bSMauro Carvalho Chehab
714ad85094bSMauro Carvalho Chehab //mipi off and sw stream off after otp read
715ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f);
716ad85094bSMauro Carvalho Chehab
717ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
718ad85094bSMauro Carvalho Chehab OV5693_SW_STREAM, OV5693_STOP_STREAMING);
719ad85094bSMauro Carvalho Chehab
720ad85094bSMauro Carvalho Chehab /* Driver has failed to find valid data */
721ad85094bSMauro Carvalho Chehab if (ret) {
722ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "sensor found no valid OTP data\n");
723ad85094bSMauro Carvalho Chehab return ERR_PTR(ret);
724ad85094bSMauro Carvalho Chehab }
725ad85094bSMauro Carvalho Chehab
726ad85094bSMauro Carvalho Chehab return buf;
727ad85094bSMauro Carvalho Chehab }
728ad85094bSMauro Carvalho Chehab
ov5693_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)729ad85094bSMauro Carvalho Chehab static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
730ad85094bSMauro Carvalho Chehab {
731ad85094bSMauro Carvalho Chehab switch (cmd) {
732ad85094bSMauro Carvalho Chehab case ATOMISP_IOC_S_EXPOSURE:
733ad85094bSMauro Carvalho Chehab return ov5693_s_exposure(sd, arg);
734ad85094bSMauro Carvalho Chehab default:
735ad85094bSMauro Carvalho Chehab return -EINVAL;
736ad85094bSMauro Carvalho Chehab }
737ad85094bSMauro Carvalho Chehab return 0;
738ad85094bSMauro Carvalho Chehab }
739ad85094bSMauro Carvalho Chehab
740ad85094bSMauro Carvalho Chehab /*
741ad85094bSMauro Carvalho Chehab * This returns the exposure time being used. This should only be used
742ad85094bSMauro Carvalho Chehab * for filling in EXIF data, not for actual image processing.
743ad85094bSMauro Carvalho Chehab */
ov5693_q_exposure(struct v4l2_subdev * sd,s32 * value)744ad85094bSMauro Carvalho Chehab static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
745ad85094bSMauro Carvalho Chehab {
746ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
747ad85094bSMauro Carvalho Chehab u16 reg_v, reg_v2;
748ad85094bSMauro Carvalho Chehab int ret;
749ad85094bSMauro Carvalho Chehab
750ad85094bSMauro Carvalho Chehab /* get exposure */
751ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
752ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_L,
753ad85094bSMauro Carvalho Chehab ®_v);
754ad85094bSMauro Carvalho Chehab if (ret)
755ad85094bSMauro Carvalho Chehab goto err;
756ad85094bSMauro Carvalho Chehab
757ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
758ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_M,
759ad85094bSMauro Carvalho Chehab ®_v2);
760ad85094bSMauro Carvalho Chehab if (ret)
761ad85094bSMauro Carvalho Chehab goto err;
762ad85094bSMauro Carvalho Chehab
763ad85094bSMauro Carvalho Chehab reg_v += reg_v2 << 8;
764ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
765ad85094bSMauro Carvalho Chehab OV5693_EXPOSURE_H,
766ad85094bSMauro Carvalho Chehab ®_v2);
767ad85094bSMauro Carvalho Chehab if (ret)
768ad85094bSMauro Carvalho Chehab goto err;
769ad85094bSMauro Carvalho Chehab
770ad85094bSMauro Carvalho Chehab *value = reg_v + (((u32)reg_v2 << 16));
771ad85094bSMauro Carvalho Chehab err:
772ad85094bSMauro Carvalho Chehab return ret;
773ad85094bSMauro Carvalho Chehab }
774ad85094bSMauro Carvalho Chehab
ad5823_t_focus_vcm(struct v4l2_subdev * sd,u16 val)775ad85094bSMauro Carvalho Chehab static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
776ad85094bSMauro Carvalho Chehab {
777ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
778b6ef5c12SColin Ian King int ret;
779ad85094bSMauro Carvalho Chehab u8 vcm_code;
780ad85094bSMauro Carvalho Chehab
781ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
782ad85094bSMauro Carvalho Chehab if (ret)
783ad85094bSMauro Carvalho Chehab return ret;
784ad85094bSMauro Carvalho Chehab
785ad85094bSMauro Carvalho Chehab /* set reg VCM_CODE_MSB Bit[1:0] */
786ad85094bSMauro Carvalho Chehab vcm_code = (vcm_code & VCM_CODE_MSB_MASK) |
787ad85094bSMauro Carvalho Chehab ((val >> 8) & ~VCM_CODE_MSB_MASK);
788ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
789ad85094bSMauro Carvalho Chehab if (ret)
790ad85094bSMauro Carvalho Chehab return ret;
791ad85094bSMauro Carvalho Chehab
792ad85094bSMauro Carvalho Chehab /* set reg VCM_CODE_LSB Bit[7:0] */
793ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff));
794ad85094bSMauro Carvalho Chehab if (ret)
795ad85094bSMauro Carvalho Chehab return ret;
796ad85094bSMauro Carvalho Chehab
797ad85094bSMauro Carvalho Chehab /* set required vcm move time */
798ad85094bSMauro Carvalho Chehab vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
799ad85094bSMauro Carvalho Chehab - AD5823_HIGH_FREQ_RANGE;
800ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
801ad85094bSMauro Carvalho Chehab
802ad85094bSMauro Carvalho Chehab return ret;
803ad85094bSMauro Carvalho Chehab }
804ad85094bSMauro Carvalho Chehab
ad5823_t_focus_abs(struct v4l2_subdev * sd,s32 value)805ad85094bSMauro Carvalho Chehab static int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
806ad85094bSMauro Carvalho Chehab {
807ad85094bSMauro Carvalho Chehab value = min(value, AD5823_MAX_FOCUS_POS);
808ad85094bSMauro Carvalho Chehab return ad5823_t_focus_vcm(sd, value);
809ad85094bSMauro Carvalho Chehab }
810ad85094bSMauro Carvalho Chehab
ov5693_t_focus_abs(struct v4l2_subdev * sd,s32 value)811ad85094bSMauro Carvalho Chehab static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
812ad85094bSMauro Carvalho Chehab {
813ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
814ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
815ad85094bSMauro Carvalho Chehab int ret = 0;
816ad85094bSMauro Carvalho Chehab
817ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
818ad85094bSMauro Carvalho Chehab value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
819ad85094bSMauro Carvalho Chehab if (dev->vcm == VCM_DW9714) {
820ad85094bSMauro Carvalho Chehab if (dev->vcm_update) {
821ad85094bSMauro Carvalho Chehab ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
822ad85094bSMauro Carvalho Chehab if (ret)
823ad85094bSMauro Carvalho Chehab return ret;
824ad85094bSMauro Carvalho Chehab ret = vcm_dw_i2c_write(client, DIRECT_VCM);
825ad85094bSMauro Carvalho Chehab if (ret)
826ad85094bSMauro Carvalho Chehab return ret;
827ad85094bSMauro Carvalho Chehab ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
828ad85094bSMauro Carvalho Chehab if (ret)
829ad85094bSMauro Carvalho Chehab return ret;
830ad85094bSMauro Carvalho Chehab dev->vcm_update = false;
831ad85094bSMauro Carvalho Chehab }
832ad85094bSMauro Carvalho Chehab ret = vcm_dw_i2c_write(client,
833ad85094bSMauro Carvalho Chehab vcm_val(value, VCM_DEFAULT_S));
834ad85094bSMauro Carvalho Chehab } else if (dev->vcm == VCM_AD5823) {
835ad85094bSMauro Carvalho Chehab ad5823_t_focus_abs(sd, value);
836ad85094bSMauro Carvalho Chehab }
837ad85094bSMauro Carvalho Chehab if (ret == 0) {
838ad85094bSMauro Carvalho Chehab dev->number_of_steps = value - dev->focus;
839ad85094bSMauro Carvalho Chehab dev->focus = value;
840ad85094bSMauro Carvalho Chehab dev->timestamp_t_focus_abs = ktime_get();
841ad85094bSMauro Carvalho Chehab } else
842ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
843ad85094bSMauro Carvalho Chehab "%s: i2c failed. ret %d\n", __func__, ret);
844ad85094bSMauro Carvalho Chehab
845ad85094bSMauro Carvalho Chehab return ret;
846ad85094bSMauro Carvalho Chehab }
847ad85094bSMauro Carvalho Chehab
ov5693_t_focus_rel(struct v4l2_subdev * sd,s32 value)848ad85094bSMauro Carvalho Chehab static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
849ad85094bSMauro Carvalho Chehab {
850ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
851ad85094bSMauro Carvalho Chehab
852ad85094bSMauro Carvalho Chehab return ov5693_t_focus_abs(sd, dev->focus + value);
853ad85094bSMauro Carvalho Chehab }
854ad85094bSMauro Carvalho Chehab
855ad85094bSMauro Carvalho Chehab #define DELAY_PER_STEP_NS 1000000
856ad85094bSMauro Carvalho Chehab #define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
ov5693_q_focus_status(struct v4l2_subdev * sd,s32 * value)857ad85094bSMauro Carvalho Chehab static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
858ad85094bSMauro Carvalho Chehab {
859ad85094bSMauro Carvalho Chehab u32 status = 0;
860ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
861ad85094bSMauro Carvalho Chehab ktime_t temptime;
862ad85094bSMauro Carvalho Chehab ktime_t timedelay = ns_to_ktime(min_t(u32,
863ad85094bSMauro Carvalho Chehab abs(dev->number_of_steps) * DELAY_PER_STEP_NS,
864ad85094bSMauro Carvalho Chehab DELAY_MAX_PER_STEP_NS));
865ad85094bSMauro Carvalho Chehab
866ad85094bSMauro Carvalho Chehab temptime = ktime_sub(ktime_get(), (dev->timestamp_t_focus_abs));
867ad85094bSMauro Carvalho Chehab if (ktime_compare(temptime, timedelay) <= 0) {
868ad85094bSMauro Carvalho Chehab status |= ATOMISP_FOCUS_STATUS_MOVING;
869ad85094bSMauro Carvalho Chehab status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
870ad85094bSMauro Carvalho Chehab } else {
871ad85094bSMauro Carvalho Chehab status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
872ad85094bSMauro Carvalho Chehab status |= ATOMISP_FOCUS_HP_COMPLETE;
873ad85094bSMauro Carvalho Chehab }
874ad85094bSMauro Carvalho Chehab
875ad85094bSMauro Carvalho Chehab *value = status;
876ad85094bSMauro Carvalho Chehab
877ad85094bSMauro Carvalho Chehab return 0;
878ad85094bSMauro Carvalho Chehab }
879ad85094bSMauro Carvalho Chehab
ov5693_q_focus_abs(struct v4l2_subdev * sd,s32 * value)880ad85094bSMauro Carvalho Chehab static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
881ad85094bSMauro Carvalho Chehab {
882ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
883ad85094bSMauro Carvalho Chehab s32 val;
884ad85094bSMauro Carvalho Chehab
885ad85094bSMauro Carvalho Chehab ov5693_q_focus_status(sd, &val);
886ad85094bSMauro Carvalho Chehab
887ad85094bSMauro Carvalho Chehab if (val & ATOMISP_FOCUS_STATUS_MOVING)
888ad85094bSMauro Carvalho Chehab *value = dev->focus - dev->number_of_steps;
889ad85094bSMauro Carvalho Chehab else
890ad85094bSMauro Carvalho Chehab *value = dev->focus;
891ad85094bSMauro Carvalho Chehab
892ad85094bSMauro Carvalho Chehab return 0;
893ad85094bSMauro Carvalho Chehab }
894ad85094bSMauro Carvalho Chehab
ov5693_t_vcm_slew(struct v4l2_subdev * sd,s32 value)895ad85094bSMauro Carvalho Chehab static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
896ad85094bSMauro Carvalho Chehab {
897ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
898ad85094bSMauro Carvalho Chehab
899ad85094bSMauro Carvalho Chehab dev->number_of_steps = value;
900ad85094bSMauro Carvalho Chehab dev->vcm_update = true;
901ad85094bSMauro Carvalho Chehab return 0;
902ad85094bSMauro Carvalho Chehab }
903ad85094bSMauro Carvalho Chehab
ov5693_t_vcm_timing(struct v4l2_subdev * sd,s32 value)904ad85094bSMauro Carvalho Chehab static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
905ad85094bSMauro Carvalho Chehab {
906ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
907ad85094bSMauro Carvalho Chehab
908ad85094bSMauro Carvalho Chehab dev->number_of_steps = value;
909ad85094bSMauro Carvalho Chehab dev->vcm_update = true;
910ad85094bSMauro Carvalho Chehab return 0;
911ad85094bSMauro Carvalho Chehab }
912ad85094bSMauro Carvalho Chehab
ov5693_s_ctrl(struct v4l2_ctrl * ctrl)913ad85094bSMauro Carvalho Chehab static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
914ad85094bSMauro Carvalho Chehab {
915ad85094bSMauro Carvalho Chehab struct ov5693_device *dev =
916ad85094bSMauro Carvalho Chehab container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
917ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
918ad85094bSMauro Carvalho Chehab int ret = 0;
919ad85094bSMauro Carvalho Chehab
920ad85094bSMauro Carvalho Chehab switch (ctrl->id) {
921ad85094bSMauro Carvalho Chehab case V4L2_CID_FOCUS_ABSOLUTE:
922ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
923ad85094bSMauro Carvalho Chehab __func__, ctrl->val);
924ad85094bSMauro Carvalho Chehab ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
925ad85094bSMauro Carvalho Chehab break;
926ad85094bSMauro Carvalho Chehab case V4L2_CID_FOCUS_RELATIVE:
927ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
928ad85094bSMauro Carvalho Chehab __func__, ctrl->val);
929ad85094bSMauro Carvalho Chehab ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
930ad85094bSMauro Carvalho Chehab break;
931ad85094bSMauro Carvalho Chehab case V4L2_CID_VCM_SLEW:
932ad85094bSMauro Carvalho Chehab ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val);
933ad85094bSMauro Carvalho Chehab break;
934abbd669dSMauro Carvalho Chehab case V4L2_CID_VCM_TIMING:
935ad85094bSMauro Carvalho Chehab ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val);
936ad85094bSMauro Carvalho Chehab break;
937ad85094bSMauro Carvalho Chehab default:
938ad85094bSMauro Carvalho Chehab ret = -EINVAL;
939ad85094bSMauro Carvalho Chehab }
940ad85094bSMauro Carvalho Chehab return ret;
941ad85094bSMauro Carvalho Chehab }
942ad85094bSMauro Carvalho Chehab
ov5693_g_volatile_ctrl(struct v4l2_ctrl * ctrl)943ad85094bSMauro Carvalho Chehab static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
944ad85094bSMauro Carvalho Chehab {
945ad85094bSMauro Carvalho Chehab struct ov5693_device *dev =
946ad85094bSMauro Carvalho Chehab container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
947ad85094bSMauro Carvalho Chehab int ret = 0;
948ad85094bSMauro Carvalho Chehab
949ad85094bSMauro Carvalho Chehab switch (ctrl->id) {
950ad85094bSMauro Carvalho Chehab case V4L2_CID_EXPOSURE_ABSOLUTE:
951ad85094bSMauro Carvalho Chehab ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
952ad85094bSMauro Carvalho Chehab break;
953ad85094bSMauro Carvalho Chehab case V4L2_CID_FOCUS_ABSOLUTE:
954ad85094bSMauro Carvalho Chehab ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
955ad85094bSMauro Carvalho Chehab break;
956ad85094bSMauro Carvalho Chehab case V4L2_CID_FOCUS_STATUS:
957ad85094bSMauro Carvalho Chehab ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
958ad85094bSMauro Carvalho Chehab break;
959ad85094bSMauro Carvalho Chehab default:
960ad85094bSMauro Carvalho Chehab ret = -EINVAL;
961ad85094bSMauro Carvalho Chehab }
962ad85094bSMauro Carvalho Chehab
963ad85094bSMauro Carvalho Chehab return ret;
964ad85094bSMauro Carvalho Chehab }
965ad85094bSMauro Carvalho Chehab
966ad85094bSMauro Carvalho Chehab static const struct v4l2_ctrl_ops ctrl_ops = {
967ad85094bSMauro Carvalho Chehab .s_ctrl = ov5693_s_ctrl,
968ad85094bSMauro Carvalho Chehab .g_volatile_ctrl = ov5693_g_volatile_ctrl
969ad85094bSMauro Carvalho Chehab };
970ad85094bSMauro Carvalho Chehab
971ad85094bSMauro Carvalho Chehab static const struct v4l2_ctrl_config ov5693_controls[] = {
972ad85094bSMauro Carvalho Chehab {
973ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
974ad85094bSMauro Carvalho Chehab .id = V4L2_CID_EXPOSURE_ABSOLUTE,
975ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
976ad85094bSMauro Carvalho Chehab .name = "exposure",
977ad85094bSMauro Carvalho Chehab .min = 0x0,
978ad85094bSMauro Carvalho Chehab .max = 0xffff,
979ad85094bSMauro Carvalho Chehab .step = 0x01,
980ad85094bSMauro Carvalho Chehab .def = 0x00,
981ad85094bSMauro Carvalho Chehab .flags = 0,
982ad85094bSMauro Carvalho Chehab },
983ad85094bSMauro Carvalho Chehab {
984ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
985ad85094bSMauro Carvalho Chehab .id = V4L2_CID_FOCUS_ABSOLUTE,
986ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
987ad85094bSMauro Carvalho Chehab .name = "focus move absolute",
988ad85094bSMauro Carvalho Chehab .min = 0,
989ad85094bSMauro Carvalho Chehab .max = OV5693_VCM_MAX_FOCUS_POS,
990ad85094bSMauro Carvalho Chehab .step = 1,
991ad85094bSMauro Carvalho Chehab .def = 0,
992ad85094bSMauro Carvalho Chehab .flags = 0,
993ad85094bSMauro Carvalho Chehab },
994ad85094bSMauro Carvalho Chehab {
995ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
996ad85094bSMauro Carvalho Chehab .id = V4L2_CID_FOCUS_RELATIVE,
997ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
998ad85094bSMauro Carvalho Chehab .name = "focus move relative",
999ad85094bSMauro Carvalho Chehab .min = OV5693_VCM_MAX_FOCUS_NEG,
1000ad85094bSMauro Carvalho Chehab .max = OV5693_VCM_MAX_FOCUS_POS,
1001ad85094bSMauro Carvalho Chehab .step = 1,
1002ad85094bSMauro Carvalho Chehab .def = 0,
1003ad85094bSMauro Carvalho Chehab .flags = 0,
1004ad85094bSMauro Carvalho Chehab },
1005ad85094bSMauro Carvalho Chehab {
1006ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
1007ad85094bSMauro Carvalho Chehab .id = V4L2_CID_FOCUS_STATUS,
1008ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
1009ad85094bSMauro Carvalho Chehab .name = "focus status",
1010ad85094bSMauro Carvalho Chehab .min = 0,
1011ad85094bSMauro Carvalho Chehab .max = 100, /* allow enum to grow in the future */
1012ad85094bSMauro Carvalho Chehab .step = 1,
1013ad85094bSMauro Carvalho Chehab .def = 0,
1014ad85094bSMauro Carvalho Chehab .flags = 0,
1015ad85094bSMauro Carvalho Chehab },
1016ad85094bSMauro Carvalho Chehab {
1017ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
1018ad85094bSMauro Carvalho Chehab .id = V4L2_CID_VCM_SLEW,
1019ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
1020ad85094bSMauro Carvalho Chehab .name = "vcm slew",
1021ad85094bSMauro Carvalho Chehab .min = 0,
1022ad85094bSMauro Carvalho Chehab .max = OV5693_VCM_SLEW_STEP_MAX,
1023ad85094bSMauro Carvalho Chehab .step = 1,
1024ad85094bSMauro Carvalho Chehab .def = 0,
1025ad85094bSMauro Carvalho Chehab .flags = 0,
1026ad85094bSMauro Carvalho Chehab },
1027ad85094bSMauro Carvalho Chehab {
1028ad85094bSMauro Carvalho Chehab .ops = &ctrl_ops,
1029abbd669dSMauro Carvalho Chehab .id = V4L2_CID_VCM_TIMING,
1030ad85094bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER,
1031ad85094bSMauro Carvalho Chehab .name = "vcm step time",
1032ad85094bSMauro Carvalho Chehab .min = 0,
1033ad85094bSMauro Carvalho Chehab .max = OV5693_VCM_SLEW_TIME_MAX,
1034ad85094bSMauro Carvalho Chehab .step = 1,
1035ad85094bSMauro Carvalho Chehab .def = 0,
1036ad85094bSMauro Carvalho Chehab .flags = 0,
1037ad85094bSMauro Carvalho Chehab },
1038ad85094bSMauro Carvalho Chehab };
1039ad85094bSMauro Carvalho Chehab
ov5693_init(struct v4l2_subdev * sd)1040ad85094bSMauro Carvalho Chehab static int ov5693_init(struct v4l2_subdev *sd)
1041ad85094bSMauro Carvalho Chehab {
1042ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1043ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1044ad85094bSMauro Carvalho Chehab int ret;
1045ad85094bSMauro Carvalho Chehab
1046ad85094bSMauro Carvalho Chehab pr_info("%s\n", __func__);
1047ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
1048ad85094bSMauro Carvalho Chehab dev->vcm_update = false;
1049ad85094bSMauro Carvalho Chehab
1050ad85094bSMauro Carvalho Chehab if (dev->vcm == VCM_AD5823) {
1051ad85094bSMauro Carvalho Chehab ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
1052ad85094bSMauro Carvalho Chehab if (ret)
1053ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1054ad85094bSMauro Carvalho Chehab "vcm reset failed\n");
1055ad85094bSMauro Carvalho Chehab /*change the mode*/
1056ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
1057ad85094bSMauro Carvalho Chehab AD5823_RING_CTRL_ENABLE);
1058ad85094bSMauro Carvalho Chehab if (ret)
1059ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1060ad85094bSMauro Carvalho Chehab "vcm enable ringing failed\n");
1061ad85094bSMauro Carvalho Chehab ret = ad5823_i2c_write(client, AD5823_REG_MODE,
1062ad85094bSMauro Carvalho Chehab AD5823_ARC_RES1);
1063ad85094bSMauro Carvalho Chehab if (ret)
1064ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1065ad85094bSMauro Carvalho Chehab "vcm change mode failed\n");
1066ad85094bSMauro Carvalho Chehab }
1067ad85094bSMauro Carvalho Chehab
1068ad85094bSMauro Carvalho Chehab /*change initial focus value for ad5823*/
1069ad85094bSMauro Carvalho Chehab if (dev->vcm == VCM_AD5823) {
1070ad85094bSMauro Carvalho Chehab dev->focus = AD5823_INIT_FOCUS_POS;
1071ad85094bSMauro Carvalho Chehab ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
1072ad85094bSMauro Carvalho Chehab } else {
1073ad85094bSMauro Carvalho Chehab dev->focus = 0;
1074ad85094bSMauro Carvalho Chehab ov5693_t_focus_abs(sd, 0);
1075ad85094bSMauro Carvalho Chehab }
1076ad85094bSMauro Carvalho Chehab
1077ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1078ad85094bSMauro Carvalho Chehab
1079ad85094bSMauro Carvalho Chehab return 0;
1080ad85094bSMauro Carvalho Chehab }
1081ad85094bSMauro Carvalho Chehab
power_ctrl(struct v4l2_subdev * sd,bool flag)1082ad85094bSMauro Carvalho Chehab static int power_ctrl(struct v4l2_subdev *sd, bool flag)
1083ad85094bSMauro Carvalho Chehab {
1084ad85094bSMauro Carvalho Chehab int ret;
1085ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1086ad85094bSMauro Carvalho Chehab
1087ad85094bSMauro Carvalho Chehab if (!dev || !dev->platform_data)
1088ad85094bSMauro Carvalho Chehab return -ENODEV;
1089ad85094bSMauro Carvalho Chehab
1090ad85094bSMauro Carvalho Chehab /*
1091ad85094bSMauro Carvalho Chehab * This driver assumes "internal DVDD, PWDNB tied to DOVDD".
1092ad85094bSMauro Carvalho Chehab * In this set up only gpio0 (XSHUTDN) should be available
1093ad85094bSMauro Carvalho Chehab * but in some products (for example ECS) gpio1 (PWDNB) is
1094ad85094bSMauro Carvalho Chehab * also available. If gpio1 is available we emulate it being
1095ad85094bSMauro Carvalho Chehab * tied to DOVDD here.
1096ad85094bSMauro Carvalho Chehab */
1097ad85094bSMauro Carvalho Chehab if (flag) {
1098ad85094bSMauro Carvalho Chehab ret = dev->platform_data->v2p8_ctrl(sd, 1);
1099ad85094bSMauro Carvalho Chehab dev->platform_data->gpio1_ctrl(sd, 1);
1100ad85094bSMauro Carvalho Chehab if (ret == 0) {
1101ad85094bSMauro Carvalho Chehab ret = dev->platform_data->v1p8_ctrl(sd, 1);
1102ad85094bSMauro Carvalho Chehab if (ret) {
1103ad85094bSMauro Carvalho Chehab dev->platform_data->gpio1_ctrl(sd, 0);
1104ad85094bSMauro Carvalho Chehab ret = dev->platform_data->v2p8_ctrl(sd, 0);
1105ad85094bSMauro Carvalho Chehab }
1106ad85094bSMauro Carvalho Chehab }
1107ad85094bSMauro Carvalho Chehab } else {
1108ad85094bSMauro Carvalho Chehab dev->platform_data->gpio1_ctrl(sd, 0);
1109ad85094bSMauro Carvalho Chehab ret = dev->platform_data->v1p8_ctrl(sd, 0);
1110ad85094bSMauro Carvalho Chehab ret |= dev->platform_data->v2p8_ctrl(sd, 0);
1111ad85094bSMauro Carvalho Chehab }
1112ad85094bSMauro Carvalho Chehab
1113ad85094bSMauro Carvalho Chehab return ret;
1114ad85094bSMauro Carvalho Chehab }
1115ad85094bSMauro Carvalho Chehab
gpio_ctrl(struct v4l2_subdev * sd,bool flag)1116ad85094bSMauro Carvalho Chehab static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
1117ad85094bSMauro Carvalho Chehab {
1118ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1119ad85094bSMauro Carvalho Chehab
1120ad85094bSMauro Carvalho Chehab if (!dev || !dev->platform_data)
1121ad85094bSMauro Carvalho Chehab return -ENODEV;
1122ad85094bSMauro Carvalho Chehab
1123ad85094bSMauro Carvalho Chehab return dev->platform_data->gpio0_ctrl(sd, flag);
1124ad85094bSMauro Carvalho Chehab }
1125ad85094bSMauro Carvalho Chehab
__power_up(struct v4l2_subdev * sd)1126ad85094bSMauro Carvalho Chehab static int __power_up(struct v4l2_subdev *sd)
1127ad85094bSMauro Carvalho Chehab {
1128ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1129ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1130ad85094bSMauro Carvalho Chehab int ret;
1131ad85094bSMauro Carvalho Chehab
1132ad85094bSMauro Carvalho Chehab if (!dev->platform_data) {
1133ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1134ad85094bSMauro Carvalho Chehab "no camera_sensor_platform_data");
1135ad85094bSMauro Carvalho Chehab return -ENODEV;
1136ad85094bSMauro Carvalho Chehab }
1137ad85094bSMauro Carvalho Chehab
1138ad85094bSMauro Carvalho Chehab /* power control */
1139ad85094bSMauro Carvalho Chehab ret = power_ctrl(sd, 1);
1140ad85094bSMauro Carvalho Chehab if (ret)
1141ad85094bSMauro Carvalho Chehab goto fail_power;
1142ad85094bSMauro Carvalho Chehab
1143ad85094bSMauro Carvalho Chehab /* according to DS, at least 5ms is needed between DOVDD and PWDN */
1144ad85094bSMauro Carvalho Chehab /* add this delay time to 10~11ms*/
1145ad85094bSMauro Carvalho Chehab usleep_range(10000, 11000);
1146ad85094bSMauro Carvalho Chehab
1147ad85094bSMauro Carvalho Chehab /* gpio ctrl */
1148ad85094bSMauro Carvalho Chehab ret = gpio_ctrl(sd, 1);
1149ad85094bSMauro Carvalho Chehab if (ret) {
1150ad85094bSMauro Carvalho Chehab ret = gpio_ctrl(sd, 1);
1151ad85094bSMauro Carvalho Chehab if (ret)
1152ad85094bSMauro Carvalho Chehab goto fail_power;
1153ad85094bSMauro Carvalho Chehab }
1154ad85094bSMauro Carvalho Chehab
1155ad85094bSMauro Carvalho Chehab /* flis clock control */
1156ad85094bSMauro Carvalho Chehab ret = dev->platform_data->flisclk_ctrl(sd, 1);
1157ad85094bSMauro Carvalho Chehab if (ret)
1158ad85094bSMauro Carvalho Chehab goto fail_clk;
1159ad85094bSMauro Carvalho Chehab
1160ad85094bSMauro Carvalho Chehab __cci_delay(up_delay);
1161ad85094bSMauro Carvalho Chehab
1162ad85094bSMauro Carvalho Chehab return 0;
1163ad85094bSMauro Carvalho Chehab
1164ad85094bSMauro Carvalho Chehab fail_clk:
1165ad85094bSMauro Carvalho Chehab gpio_ctrl(sd, 0);
1166ad85094bSMauro Carvalho Chehab fail_power:
1167ad85094bSMauro Carvalho Chehab power_ctrl(sd, 0);
1168ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "sensor power-up failed\n");
1169ad85094bSMauro Carvalho Chehab
1170ad85094bSMauro Carvalho Chehab return ret;
1171ad85094bSMauro Carvalho Chehab }
1172ad85094bSMauro Carvalho Chehab
power_down(struct v4l2_subdev * sd)1173ad85094bSMauro Carvalho Chehab static int power_down(struct v4l2_subdev *sd)
1174ad85094bSMauro Carvalho Chehab {
1175ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1176ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1177ad85094bSMauro Carvalho Chehab int ret = 0;
1178ad85094bSMauro Carvalho Chehab
1179ad85094bSMauro Carvalho Chehab dev->focus = OV5693_INVALID_CONFIG;
1180ad85094bSMauro Carvalho Chehab if (!dev->platform_data) {
1181ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1182ad85094bSMauro Carvalho Chehab "no camera_sensor_platform_data");
1183ad85094bSMauro Carvalho Chehab return -ENODEV;
1184ad85094bSMauro Carvalho Chehab }
1185ad85094bSMauro Carvalho Chehab
1186ad85094bSMauro Carvalho Chehab ret = dev->platform_data->flisclk_ctrl(sd, 0);
1187ad85094bSMauro Carvalho Chehab if (ret)
1188ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "flisclk failed\n");
1189ad85094bSMauro Carvalho Chehab
1190ad85094bSMauro Carvalho Chehab /* gpio ctrl */
1191ad85094bSMauro Carvalho Chehab ret = gpio_ctrl(sd, 0);
1192ad85094bSMauro Carvalho Chehab if (ret) {
1193ad85094bSMauro Carvalho Chehab ret = gpio_ctrl(sd, 0);
1194ad85094bSMauro Carvalho Chehab if (ret)
1195ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "gpio failed 2\n");
1196ad85094bSMauro Carvalho Chehab }
1197ad85094bSMauro Carvalho Chehab
1198ad85094bSMauro Carvalho Chehab /* power control */
1199ad85094bSMauro Carvalho Chehab ret = power_ctrl(sd, 0);
1200ad85094bSMauro Carvalho Chehab if (ret)
1201ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "vprog failed.\n");
1202ad85094bSMauro Carvalho Chehab
1203ad85094bSMauro Carvalho Chehab return ret;
1204ad85094bSMauro Carvalho Chehab }
1205ad85094bSMauro Carvalho Chehab
power_up(struct v4l2_subdev * sd)1206ad85094bSMauro Carvalho Chehab static int power_up(struct v4l2_subdev *sd)
1207ad85094bSMauro Carvalho Chehab {
1208ad85094bSMauro Carvalho Chehab static const int retry_count = 4;
1209ad85094bSMauro Carvalho Chehab int i, ret;
1210ad85094bSMauro Carvalho Chehab
1211ad85094bSMauro Carvalho Chehab for (i = 0; i < retry_count; i++) {
1212ad85094bSMauro Carvalho Chehab ret = __power_up(sd);
1213ad85094bSMauro Carvalho Chehab if (!ret)
1214ad85094bSMauro Carvalho Chehab return 0;
1215ad85094bSMauro Carvalho Chehab
1216ad85094bSMauro Carvalho Chehab power_down(sd);
1217ad85094bSMauro Carvalho Chehab }
1218ad85094bSMauro Carvalho Chehab return ret;
1219ad85094bSMauro Carvalho Chehab }
1220ad85094bSMauro Carvalho Chehab
ov5693_s_power(struct v4l2_subdev * sd,int on)1221ad85094bSMauro Carvalho Chehab static int ov5693_s_power(struct v4l2_subdev *sd, int on)
1222ad85094bSMauro Carvalho Chehab {
1223ad85094bSMauro Carvalho Chehab int ret;
1224ad85094bSMauro Carvalho Chehab
1225ad85094bSMauro Carvalho Chehab pr_info("%s: on %d\n", __func__, on);
1226ad85094bSMauro Carvalho Chehab if (on == 0)
1227ad85094bSMauro Carvalho Chehab return power_down(sd);
1228ad85094bSMauro Carvalho Chehab else {
1229ad85094bSMauro Carvalho Chehab ret = power_up(sd);
1230ad85094bSMauro Carvalho Chehab if (!ret) {
1231ad85094bSMauro Carvalho Chehab ret = ov5693_init(sd);
1232ad85094bSMauro Carvalho Chehab /* restore settings */
1233ad85094bSMauro Carvalho Chehab ov5693_res = ov5693_res_preview;
1234ad85094bSMauro Carvalho Chehab N_RES = N_RES_PREVIEW;
1235ad85094bSMauro Carvalho Chehab }
1236ad85094bSMauro Carvalho Chehab }
1237ad85094bSMauro Carvalho Chehab return ret;
1238ad85094bSMauro Carvalho Chehab }
1239ad85094bSMauro Carvalho Chehab
1240ad85094bSMauro Carvalho Chehab /*
1241ad85094bSMauro Carvalho Chehab * distance - calculate the distance
1242ad85094bSMauro Carvalho Chehab * @res: resolution
1243ad85094bSMauro Carvalho Chehab * @w: width
1244ad85094bSMauro Carvalho Chehab * @h: height
1245ad85094bSMauro Carvalho Chehab *
1246ad85094bSMauro Carvalho Chehab * Get the gap between res_w/res_h and w/h.
1247ad85094bSMauro Carvalho Chehab * distance = (res_w/res_h - w/h) / (w/h) * 8192
1248ad85094bSMauro Carvalho Chehab * res->width/height smaller than w/h wouldn't be considered.
1249ad85094bSMauro Carvalho Chehab * The gap of ratio larger than 1/8 wouldn't be considered.
1250ad85094bSMauro Carvalho Chehab * Returns the value of gap or -1 if fail.
1251ad85094bSMauro Carvalho Chehab */
1252ad85094bSMauro Carvalho Chehab #define LARGEST_ALLOWED_RATIO_MISMATCH 1024
distance(struct ov5693_resolution * res,u32 w,u32 h)1253ad85094bSMauro Carvalho Chehab static int distance(struct ov5693_resolution *res, u32 w, u32 h)
1254ad85094bSMauro Carvalho Chehab {
1255ad85094bSMauro Carvalho Chehab int ratio;
1256ad85094bSMauro Carvalho Chehab int distance;
1257ad85094bSMauro Carvalho Chehab
1258ad85094bSMauro Carvalho Chehab if (w == 0 || h == 0 ||
1259ad85094bSMauro Carvalho Chehab res->width < w || res->height < h)
1260ad85094bSMauro Carvalho Chehab return -1;
1261ad85094bSMauro Carvalho Chehab
1262ad85094bSMauro Carvalho Chehab ratio = res->width << 13;
1263ad85094bSMauro Carvalho Chehab ratio /= w;
1264ad85094bSMauro Carvalho Chehab ratio *= h;
1265ad85094bSMauro Carvalho Chehab ratio /= res->height;
1266ad85094bSMauro Carvalho Chehab
1267ad85094bSMauro Carvalho Chehab distance = abs(ratio - 8192);
1268ad85094bSMauro Carvalho Chehab
1269ad85094bSMauro Carvalho Chehab if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
1270ad85094bSMauro Carvalho Chehab return -1;
1271ad85094bSMauro Carvalho Chehab
1272ad85094bSMauro Carvalho Chehab return distance;
1273ad85094bSMauro Carvalho Chehab }
1274ad85094bSMauro Carvalho Chehab
1275ad85094bSMauro Carvalho Chehab /* Return the nearest higher resolution index
1276ad85094bSMauro Carvalho Chehab * Firstly try to find the approximate aspect ratio resolution
1277ad85094bSMauro Carvalho Chehab * If we find multiple same AR resolutions, choose the
1278ad85094bSMauro Carvalho Chehab * minimal size.
1279ad85094bSMauro Carvalho Chehab */
nearest_resolution_index(int w,int h)1280ad85094bSMauro Carvalho Chehab static int nearest_resolution_index(int w, int h)
1281ad85094bSMauro Carvalho Chehab {
1282ad85094bSMauro Carvalho Chehab int i;
1283ad85094bSMauro Carvalho Chehab int idx = -1;
1284ad85094bSMauro Carvalho Chehab int dist;
1285ad85094bSMauro Carvalho Chehab int min_dist = INT_MAX;
1286ad85094bSMauro Carvalho Chehab int min_res_w = INT_MAX;
1287ad85094bSMauro Carvalho Chehab struct ov5693_resolution *tmp_res = NULL;
1288ad85094bSMauro Carvalho Chehab
1289ad85094bSMauro Carvalho Chehab for (i = 0; i < N_RES; i++) {
1290ad85094bSMauro Carvalho Chehab tmp_res = &ov5693_res[i];
1291ad85094bSMauro Carvalho Chehab dist = distance(tmp_res, w, h);
1292ad85094bSMauro Carvalho Chehab if (dist == -1)
1293ad85094bSMauro Carvalho Chehab continue;
1294ad85094bSMauro Carvalho Chehab if (dist < min_dist) {
1295ad85094bSMauro Carvalho Chehab min_dist = dist;
1296ad85094bSMauro Carvalho Chehab idx = i;
1297ad85094bSMauro Carvalho Chehab min_res_w = ov5693_res[i].width;
1298ad85094bSMauro Carvalho Chehab continue;
1299ad85094bSMauro Carvalho Chehab }
1300ad85094bSMauro Carvalho Chehab if (dist == min_dist && ov5693_res[i].width < min_res_w)
1301ad85094bSMauro Carvalho Chehab idx = i;
1302ad85094bSMauro Carvalho Chehab }
1303ad85094bSMauro Carvalho Chehab
1304ad85094bSMauro Carvalho Chehab return idx;
1305ad85094bSMauro Carvalho Chehab }
1306ad85094bSMauro Carvalho Chehab
get_resolution_index(int w,int h)1307ad85094bSMauro Carvalho Chehab static int get_resolution_index(int w, int h)
1308ad85094bSMauro Carvalho Chehab {
1309ad85094bSMauro Carvalho Chehab int i;
1310ad85094bSMauro Carvalho Chehab
1311ad85094bSMauro Carvalho Chehab for (i = 0; i < N_RES; i++) {
1312ad85094bSMauro Carvalho Chehab if (w != ov5693_res[i].width)
1313ad85094bSMauro Carvalho Chehab continue;
1314ad85094bSMauro Carvalho Chehab if (h != ov5693_res[i].height)
1315ad85094bSMauro Carvalho Chehab continue;
1316ad85094bSMauro Carvalho Chehab
1317ad85094bSMauro Carvalho Chehab return i;
1318ad85094bSMauro Carvalho Chehab }
1319ad85094bSMauro Carvalho Chehab
1320ad85094bSMauro Carvalho Chehab return -1;
1321ad85094bSMauro Carvalho Chehab }
1322ad85094bSMauro Carvalho Chehab
1323ad85094bSMauro Carvalho Chehab /* TODO: remove it. */
startup(struct v4l2_subdev * sd)1324ad85094bSMauro Carvalho Chehab static int startup(struct v4l2_subdev *sd)
1325ad85094bSMauro Carvalho Chehab {
1326ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1327ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1328ad85094bSMauro Carvalho Chehab int ret = 0;
1329ad85094bSMauro Carvalho Chehab
1330ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT,
1331ad85094bSMauro Carvalho Chehab OV5693_SW_RESET, 0x01);
1332ad85094bSMauro Carvalho Chehab if (ret) {
1333ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 reset err.\n");
1334ad85094bSMauro Carvalho Chehab return ret;
1335ad85094bSMauro Carvalho Chehab }
1336ad85094bSMauro Carvalho Chehab
1337ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg_array(client, ov5693_global_setting);
1338ad85094bSMauro Carvalho Chehab if (ret) {
1339ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 write register err.\n");
1340ad85094bSMauro Carvalho Chehab return ret;
1341ad85094bSMauro Carvalho Chehab }
1342ad85094bSMauro Carvalho Chehab
1343ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs);
1344ad85094bSMauro Carvalho Chehab if (ret) {
1345ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 write register err.\n");
1346ad85094bSMauro Carvalho Chehab return ret;
1347ad85094bSMauro Carvalho Chehab }
1348ad85094bSMauro Carvalho Chehab
1349ad85094bSMauro Carvalho Chehab return ret;
1350ad85094bSMauro Carvalho Chehab }
1351ad85094bSMauro Carvalho Chehab
ov5693_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1352ad85094bSMauro Carvalho Chehab static int ov5693_set_fmt(struct v4l2_subdev *sd,
13530d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1354ad85094bSMauro Carvalho Chehab struct v4l2_subdev_format *format)
1355ad85094bSMauro Carvalho Chehab {
1356ad85094bSMauro Carvalho Chehab struct v4l2_mbus_framefmt *fmt = &format->format;
1357ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1358ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1359ad85094bSMauro Carvalho Chehab struct camera_mipi_info *ov5693_info = NULL;
1360ad85094bSMauro Carvalho Chehab int ret = 0;
1361ad85094bSMauro Carvalho Chehab int idx;
1362ad85094bSMauro Carvalho Chehab
1363ad85094bSMauro Carvalho Chehab if (format->pad)
1364ad85094bSMauro Carvalho Chehab return -EINVAL;
1365ad85094bSMauro Carvalho Chehab if (!fmt)
1366ad85094bSMauro Carvalho Chehab return -EINVAL;
1367ad85094bSMauro Carvalho Chehab ov5693_info = v4l2_get_subdev_hostdata(sd);
1368bdfe0bebSMauro Carvalho Chehab if (!ov5693_info)
1369ad85094bSMauro Carvalho Chehab return -EINVAL;
1370ad85094bSMauro Carvalho Chehab
1371ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
1372ad85094bSMauro Carvalho Chehab idx = nearest_resolution_index(fmt->width, fmt->height);
1373ad85094bSMauro Carvalho Chehab if (idx == -1) {
1374ad85094bSMauro Carvalho Chehab /* return the largest resolution */
1375ad85094bSMauro Carvalho Chehab fmt->width = ov5693_res[N_RES - 1].width;
1376ad85094bSMauro Carvalho Chehab fmt->height = ov5693_res[N_RES - 1].height;
1377ad85094bSMauro Carvalho Chehab } else {
1378ad85094bSMauro Carvalho Chehab fmt->width = ov5693_res[idx].width;
1379ad85094bSMauro Carvalho Chehab fmt->height = ov5693_res[idx].height;
1380ad85094bSMauro Carvalho Chehab }
1381ad85094bSMauro Carvalho Chehab
1382ad85094bSMauro Carvalho Chehab fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
1383ad85094bSMauro Carvalho Chehab if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
13840d346d2aSTomi Valkeinen sd_state->pads->try_fmt = *fmt;
1385ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1386ad85094bSMauro Carvalho Chehab return 0;
1387ad85094bSMauro Carvalho Chehab }
1388ad85094bSMauro Carvalho Chehab
1389ad85094bSMauro Carvalho Chehab dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
1390ad85094bSMauro Carvalho Chehab if (dev->fmt_idx == -1) {
1391ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "get resolution fail\n");
1392ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1393ad85094bSMauro Carvalho Chehab return -EINVAL;
1394ad85094bSMauro Carvalho Chehab }
1395ad85094bSMauro Carvalho Chehab
1396ad85094bSMauro Carvalho Chehab ret = startup(sd);
1397ad85094bSMauro Carvalho Chehab if (ret) {
1398ad85094bSMauro Carvalho Chehab int i = 0;
1399ad85094bSMauro Carvalho Chehab
1400ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 startup err, retry to power up\n");
1401ad85094bSMauro Carvalho Chehab for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) {
1402ad85094bSMauro Carvalho Chehab dev_err(&client->dev,
1403ad85094bSMauro Carvalho Chehab "ov5693 retry to power up %d/%d times, result: ",
1404ad85094bSMauro Carvalho Chehab i + 1, OV5693_POWER_UP_RETRY_NUM);
1405ad85094bSMauro Carvalho Chehab power_down(sd);
1406ad85094bSMauro Carvalho Chehab ret = power_up(sd);
1407ad85094bSMauro Carvalho Chehab if (!ret) {
1408ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1409ad85094bSMauro Carvalho Chehab ov5693_init(sd);
1410ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
1411ad85094bSMauro Carvalho Chehab } else {
1412ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "power up failed, continue\n");
1413ad85094bSMauro Carvalho Chehab continue;
1414ad85094bSMauro Carvalho Chehab }
1415ad85094bSMauro Carvalho Chehab ret = startup(sd);
1416ad85094bSMauro Carvalho Chehab if (ret) {
1417ad85094bSMauro Carvalho Chehab dev_err(&client->dev, " startup FAILED!\n");
1418ad85094bSMauro Carvalho Chehab } else {
1419ad85094bSMauro Carvalho Chehab dev_err(&client->dev, " startup SUCCESS!\n");
1420ad85094bSMauro Carvalho Chehab break;
1421ad85094bSMauro Carvalho Chehab }
1422ad85094bSMauro Carvalho Chehab }
1423ad85094bSMauro Carvalho Chehab }
1424ad85094bSMauro Carvalho Chehab
1425ad85094bSMauro Carvalho Chehab /*
1426ad85094bSMauro Carvalho Chehab * After sensor settings are set to HW, sometimes stream is started.
1427ad85094bSMauro Carvalho Chehab * This would cause ISP timeout because ISP is not ready to receive
1428ad85094bSMauro Carvalho Chehab * data yet. So add stop streaming here.
1429ad85094bSMauro Carvalho Chehab */
1430ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
1431ad85094bSMauro Carvalho Chehab OV5693_STOP_STREAMING);
1432ad85094bSMauro Carvalho Chehab if (ret)
1433ad85094bSMauro Carvalho Chehab dev_warn(&client->dev, "ov5693 stream off err\n");
1434ad85094bSMauro Carvalho Chehab
1435ad85094bSMauro Carvalho Chehab ov5693_info->metadata_width = fmt->width * 10 / 8;
1436ad85094bSMauro Carvalho Chehab ov5693_info->metadata_height = 1;
1437ad85094bSMauro Carvalho Chehab ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size;
1438ad85094bSMauro Carvalho Chehab
1439ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1440ad85094bSMauro Carvalho Chehab return ret;
1441ad85094bSMauro Carvalho Chehab }
1442bdfe0bebSMauro Carvalho Chehab
ov5693_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1443ad85094bSMauro Carvalho Chehab static int ov5693_get_fmt(struct v4l2_subdev *sd,
14440d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1445ad85094bSMauro Carvalho Chehab struct v4l2_subdev_format *format)
1446ad85094bSMauro Carvalho Chehab {
1447ad85094bSMauro Carvalho Chehab struct v4l2_mbus_framefmt *fmt = &format->format;
1448ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1449ad85094bSMauro Carvalho Chehab
1450ad85094bSMauro Carvalho Chehab if (format->pad)
1451ad85094bSMauro Carvalho Chehab return -EINVAL;
1452ad85094bSMauro Carvalho Chehab
1453ad85094bSMauro Carvalho Chehab if (!fmt)
1454ad85094bSMauro Carvalho Chehab return -EINVAL;
1455ad85094bSMauro Carvalho Chehab
1456ad85094bSMauro Carvalho Chehab fmt->width = ov5693_res[dev->fmt_idx].width;
1457ad85094bSMauro Carvalho Chehab fmt->height = ov5693_res[dev->fmt_idx].height;
1458ad85094bSMauro Carvalho Chehab fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
1459ad85094bSMauro Carvalho Chehab
1460ad85094bSMauro Carvalho Chehab return 0;
1461ad85094bSMauro Carvalho Chehab }
1462ad85094bSMauro Carvalho Chehab
ov5693_detect(struct i2c_client * client)1463ad85094bSMauro Carvalho Chehab static int ov5693_detect(struct i2c_client *client)
1464ad85094bSMauro Carvalho Chehab {
1465ad85094bSMauro Carvalho Chehab struct i2c_adapter *adapter = client->adapter;
1466ad85094bSMauro Carvalho Chehab u16 high, low;
1467ad85094bSMauro Carvalho Chehab int ret;
1468ad85094bSMauro Carvalho Chehab u16 id;
1469ad85094bSMauro Carvalho Chehab u8 revision;
1470ad85094bSMauro Carvalho Chehab
1471ad85094bSMauro Carvalho Chehab if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
1472ad85094bSMauro Carvalho Chehab return -ENODEV;
1473ad85094bSMauro Carvalho Chehab
1474ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
1475ad85094bSMauro Carvalho Chehab OV5693_SC_CMMN_CHIP_ID_H, &high);
1476ad85094bSMauro Carvalho Chehab if (ret) {
1477ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
1478ad85094bSMauro Carvalho Chehab return -ENODEV;
1479ad85094bSMauro Carvalho Chehab }
1480ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
1481ad85094bSMauro Carvalho Chehab OV5693_SC_CMMN_CHIP_ID_L, &low);
14825ba9c067SYizhuo if (ret)
14835ba9c067SYizhuo return ret;
1484ad85094bSMauro Carvalho Chehab id = ((((u16)high) << 8) | (u16)low);
1485ad85094bSMauro Carvalho Chehab
1486ad85094bSMauro Carvalho Chehab if (id != OV5693_ID) {
1487ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "sensor ID error 0x%x\n", id);
1488ad85094bSMauro Carvalho Chehab return -ENODEV;
1489ad85094bSMauro Carvalho Chehab }
1490ad85094bSMauro Carvalho Chehab
1491ad85094bSMauro Carvalho Chehab ret = ov5693_read_reg(client, OV5693_8BIT,
1492ad85094bSMauro Carvalho Chehab OV5693_SC_CMMN_SUB_ID, &high);
1493ad85094bSMauro Carvalho Chehab revision = (u8)high & 0x0f;
1494ad85094bSMauro Carvalho Chehab
1495ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
1496ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "detect ov5693 success\n");
1497ad85094bSMauro Carvalho Chehab return 0;
1498ad85094bSMauro Carvalho Chehab }
1499ad85094bSMauro Carvalho Chehab
ov5693_s_stream(struct v4l2_subdev * sd,int enable)1500ad85094bSMauro Carvalho Chehab static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
1501ad85094bSMauro Carvalho Chehab {
1502ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1503ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1504ad85094bSMauro Carvalho Chehab int ret;
1505ad85094bSMauro Carvalho Chehab
1506ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
1507ad85094bSMauro Carvalho Chehab
1508ad85094bSMauro Carvalho Chehab ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
1509ad85094bSMauro Carvalho Chehab enable ? OV5693_START_STREAMING :
1510ad85094bSMauro Carvalho Chehab OV5693_STOP_STREAMING);
1511ad85094bSMauro Carvalho Chehab
1512ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1513ad85094bSMauro Carvalho Chehab
1514ad85094bSMauro Carvalho Chehab return ret;
1515ad85094bSMauro Carvalho Chehab }
1516ad85094bSMauro Carvalho Chehab
ov5693_s_config(struct v4l2_subdev * sd,int irq,void * platform_data)1517ad85094bSMauro Carvalho Chehab static int ov5693_s_config(struct v4l2_subdev *sd,
1518ad85094bSMauro Carvalho Chehab int irq, void *platform_data)
1519ad85094bSMauro Carvalho Chehab {
1520ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1521ad85094bSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd);
1522ad85094bSMauro Carvalho Chehab int ret = 0;
1523ad85094bSMauro Carvalho Chehab
1524bdfe0bebSMauro Carvalho Chehab if (!platform_data)
1525ad85094bSMauro Carvalho Chehab return -ENODEV;
1526ad85094bSMauro Carvalho Chehab
1527ad85094bSMauro Carvalho Chehab dev->platform_data =
1528ad85094bSMauro Carvalho Chehab (struct camera_sensor_platform_data *)platform_data;
1529ad85094bSMauro Carvalho Chehab
1530ad85094bSMauro Carvalho Chehab mutex_lock(&dev->input_lock);
1531ad85094bSMauro Carvalho Chehab /* power off the module, then power on it in future
1532ad85094bSMauro Carvalho Chehab * as first power on by board may not fulfill the
1533ad85094bSMauro Carvalho Chehab * power on sequqence needed by the module
1534ad85094bSMauro Carvalho Chehab */
1535ad85094bSMauro Carvalho Chehab ret = power_down(sd);
1536ad85094bSMauro Carvalho Chehab if (ret) {
1537ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 power-off err.\n");
1538ad85094bSMauro Carvalho Chehab goto fail_power_off;
1539ad85094bSMauro Carvalho Chehab }
1540ad85094bSMauro Carvalho Chehab
1541ad85094bSMauro Carvalho Chehab ret = power_up(sd);
1542ad85094bSMauro Carvalho Chehab if (ret) {
1543ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 power-up err.\n");
1544ad85094bSMauro Carvalho Chehab goto fail_power_on;
1545ad85094bSMauro Carvalho Chehab }
1546ad85094bSMauro Carvalho Chehab
1547ad85094bSMauro Carvalho Chehab if (!dev->vcm)
1548ad85094bSMauro Carvalho Chehab dev->vcm = vcm_detect(client);
1549ad85094bSMauro Carvalho Chehab
1550ad85094bSMauro Carvalho Chehab ret = dev->platform_data->csi_cfg(sd, 1);
1551ad85094bSMauro Carvalho Chehab if (ret)
1552ad85094bSMauro Carvalho Chehab goto fail_csi_cfg;
1553ad85094bSMauro Carvalho Chehab
1554ad85094bSMauro Carvalho Chehab /* config & detect sensor */
1555ad85094bSMauro Carvalho Chehab ret = ov5693_detect(client);
1556ad85094bSMauro Carvalho Chehab if (ret) {
1557ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693_detect err s_config.\n");
1558ad85094bSMauro Carvalho Chehab goto fail_csi_cfg;
1559ad85094bSMauro Carvalho Chehab }
1560ad85094bSMauro Carvalho Chehab
1561ad85094bSMauro Carvalho Chehab dev->otp_data = ov5693_otp_read(sd);
1562ad85094bSMauro Carvalho Chehab
1563ad85094bSMauro Carvalho Chehab /* turn off sensor, after probed */
1564ad85094bSMauro Carvalho Chehab ret = power_down(sd);
1565ad85094bSMauro Carvalho Chehab if (ret) {
1566ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "ov5693 power-off err.\n");
1567ad85094bSMauro Carvalho Chehab goto fail_csi_cfg;
1568ad85094bSMauro Carvalho Chehab }
1569ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1570ad85094bSMauro Carvalho Chehab
1571ad85094bSMauro Carvalho Chehab return ret;
1572ad85094bSMauro Carvalho Chehab
1573ad85094bSMauro Carvalho Chehab fail_csi_cfg:
1574ad85094bSMauro Carvalho Chehab dev->platform_data->csi_cfg(sd, 0);
1575ad85094bSMauro Carvalho Chehab fail_power_on:
1576ad85094bSMauro Carvalho Chehab power_down(sd);
1577ad85094bSMauro Carvalho Chehab dev_err(&client->dev, "sensor power-gating failed\n");
1578ad85094bSMauro Carvalho Chehab fail_power_off:
1579ad85094bSMauro Carvalho Chehab mutex_unlock(&dev->input_lock);
1580ad85094bSMauro Carvalho Chehab return ret;
1581ad85094bSMauro Carvalho Chehab }
1582ad85094bSMauro Carvalho Chehab
ov5693_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * interval)1583ad85094bSMauro Carvalho Chehab static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
1584ad85094bSMauro Carvalho Chehab struct v4l2_subdev_frame_interval *interval)
1585ad85094bSMauro Carvalho Chehab {
1586ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1587ad85094bSMauro Carvalho Chehab
1588ad85094bSMauro Carvalho Chehab interval->interval.numerator = 1;
1589ad85094bSMauro Carvalho Chehab interval->interval.denominator = ov5693_res[dev->fmt_idx].fps;
1590ad85094bSMauro Carvalho Chehab
1591ad85094bSMauro Carvalho Chehab return 0;
1592ad85094bSMauro Carvalho Chehab }
1593ad85094bSMauro Carvalho Chehab
ov5693_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1594ad85094bSMauro Carvalho Chehab static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
15950d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1596ad85094bSMauro Carvalho Chehab struct v4l2_subdev_mbus_code_enum *code)
1597ad85094bSMauro Carvalho Chehab {
1598ad85094bSMauro Carvalho Chehab if (code->index >= MAX_FMTS)
1599ad85094bSMauro Carvalho Chehab return -EINVAL;
1600ad85094bSMauro Carvalho Chehab
1601ad85094bSMauro Carvalho Chehab code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
1602ad85094bSMauro Carvalho Chehab return 0;
1603ad85094bSMauro Carvalho Chehab }
1604ad85094bSMauro Carvalho Chehab
ov5693_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1605ad85094bSMauro Carvalho Chehab static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
16060d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1607ad85094bSMauro Carvalho Chehab struct v4l2_subdev_frame_size_enum *fse)
1608ad85094bSMauro Carvalho Chehab {
1609ad85094bSMauro Carvalho Chehab int index = fse->index;
1610ad85094bSMauro Carvalho Chehab
1611ad85094bSMauro Carvalho Chehab if (index >= N_RES)
1612ad85094bSMauro Carvalho Chehab return -EINVAL;
1613ad85094bSMauro Carvalho Chehab
1614ad85094bSMauro Carvalho Chehab fse->min_width = ov5693_res[index].width;
1615ad85094bSMauro Carvalho Chehab fse->min_height = ov5693_res[index].height;
1616ad85094bSMauro Carvalho Chehab fse->max_width = ov5693_res[index].width;
1617ad85094bSMauro Carvalho Chehab fse->max_height = ov5693_res[index].height;
1618ad85094bSMauro Carvalho Chehab
1619ad85094bSMauro Carvalho Chehab return 0;
1620ad85094bSMauro Carvalho Chehab }
1621ad85094bSMauro Carvalho Chehab
1622ad85094bSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops ov5693_video_ops = {
1623ad85094bSMauro Carvalho Chehab .s_stream = ov5693_s_stream,
1624ad85094bSMauro Carvalho Chehab .g_frame_interval = ov5693_g_frame_interval,
1625ad85094bSMauro Carvalho Chehab };
1626ad85094bSMauro Carvalho Chehab
1627ad85094bSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops ov5693_core_ops = {
1628ad85094bSMauro Carvalho Chehab .s_power = ov5693_s_power,
1629ad85094bSMauro Carvalho Chehab .ioctl = ov5693_ioctl,
1630ad85094bSMauro Carvalho Chehab };
1631ad85094bSMauro Carvalho Chehab
1632ad85094bSMauro Carvalho Chehab static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
1633ad85094bSMauro Carvalho Chehab .enum_mbus_code = ov5693_enum_mbus_code,
1634ad85094bSMauro Carvalho Chehab .enum_frame_size = ov5693_enum_frame_size,
1635ad85094bSMauro Carvalho Chehab .get_fmt = ov5693_get_fmt,
1636ad85094bSMauro Carvalho Chehab .set_fmt = ov5693_set_fmt,
1637ad85094bSMauro Carvalho Chehab };
1638ad85094bSMauro Carvalho Chehab
1639ad85094bSMauro Carvalho Chehab static const struct v4l2_subdev_ops ov5693_ops = {
1640ad85094bSMauro Carvalho Chehab .core = &ov5693_core_ops,
1641ad85094bSMauro Carvalho Chehab .video = &ov5693_video_ops,
1642ad85094bSMauro Carvalho Chehab .pad = &ov5693_pad_ops,
1643ad85094bSMauro Carvalho Chehab };
1644ad85094bSMauro Carvalho Chehab
ov5693_remove(struct i2c_client * client)1645ed5c2f5fSUwe Kleine-König static void ov5693_remove(struct i2c_client *client)
1646ad85094bSMauro Carvalho Chehab {
1647ad85094bSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client);
1648ad85094bSMauro Carvalho Chehab struct ov5693_device *dev = to_ov5693_sensor(sd);
1649ad85094bSMauro Carvalho Chehab
1650ad85094bSMauro Carvalho Chehab dev_dbg(&client->dev, "ov5693_remove...\n");
1651ad85094bSMauro Carvalho Chehab
1652ad85094bSMauro Carvalho Chehab dev->platform_data->csi_cfg(sd, 0);
1653ad85094bSMauro Carvalho Chehab
1654ad85094bSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd);
1655ad85094bSMauro Carvalho Chehab
1656ad85094bSMauro Carvalho Chehab atomisp_gmin_remove_subdev(sd);
1657ad85094bSMauro Carvalho Chehab
1658ad85094bSMauro Carvalho Chehab media_entity_cleanup(&dev->sd.entity);
1659ad85094bSMauro Carvalho Chehab v4l2_ctrl_handler_free(&dev->ctrl_handler);
1660ad85094bSMauro Carvalho Chehab kfree(dev);
1661ad85094bSMauro Carvalho Chehab }
1662ad85094bSMauro Carvalho Chehab
ov5693_probe(struct i2c_client * client)1663ad85094bSMauro Carvalho Chehab static int ov5693_probe(struct i2c_client *client)
1664ad85094bSMauro Carvalho Chehab {
1665ad85094bSMauro Carvalho Chehab struct ov5693_device *dev;
1666ad85094bSMauro Carvalho Chehab int i2c;
1667ac828456SDan Carpenter int ret;
1668ad85094bSMauro Carvalho Chehab void *pdata;
1669ad85094bSMauro Carvalho Chehab unsigned int i;
1670ad85094bSMauro Carvalho Chehab
1671ad85094bSMauro Carvalho Chehab /*
1672ad85094bSMauro Carvalho Chehab * Firmware workaround: Some modules use a "secondary default"
1673ad85094bSMauro Carvalho Chehab * address of 0x10 which doesn't appear on schematics, and
1674ad85094bSMauro Carvalho Chehab * some BIOS versions haven't gotten the memo. Work around
1675ad85094bSMauro Carvalho Chehab * via config.
1676ad85094bSMauro Carvalho Chehab */
167785df8457SMauro Carvalho Chehab i2c = gmin_get_var_int(&client->dev, false, "I2CAddr", -1);
1678ad85094bSMauro Carvalho Chehab if (i2c != -1) {
1679ad85094bSMauro Carvalho Chehab dev_info(&client->dev,
1680ad85094bSMauro Carvalho Chehab "Overriding firmware-provided I2C address (0x%x) with 0x%x\n",
1681ad85094bSMauro Carvalho Chehab client->addr, i2c);
1682ad85094bSMauro Carvalho Chehab client->addr = i2c;
1683ad85094bSMauro Carvalho Chehab }
1684ad85094bSMauro Carvalho Chehab
1685ad85094bSMauro Carvalho Chehab dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1686ad85094bSMauro Carvalho Chehab if (!dev)
1687ad85094bSMauro Carvalho Chehab return -ENOMEM;
1688ad85094bSMauro Carvalho Chehab
1689ad85094bSMauro Carvalho Chehab mutex_init(&dev->input_lock);
1690ad85094bSMauro Carvalho Chehab
1691ad85094bSMauro Carvalho Chehab dev->fmt_idx = 0;
1692bdfe0bebSMauro Carvalho Chehab v4l2_i2c_subdev_init(&dev->sd, client, &ov5693_ops);
1693ad85094bSMauro Carvalho Chehab
1694ad85094bSMauro Carvalho Chehab pdata = gmin_camera_platform_data(&dev->sd,
1695ad85094bSMauro Carvalho Chehab ATOMISP_INPUT_FORMAT_RAW_10,
1696ad85094bSMauro Carvalho Chehab atomisp_bayer_order_bggr);
1697ac828456SDan Carpenter if (!pdata) {
1698ac828456SDan Carpenter ret = -EINVAL;
1699ad85094bSMauro Carvalho Chehab goto out_free;
1700ac828456SDan Carpenter }
1701ad85094bSMauro Carvalho Chehab
1702ad85094bSMauro Carvalho Chehab ret = ov5693_s_config(&dev->sd, client->irq, pdata);
1703ad85094bSMauro Carvalho Chehab if (ret)
1704ad85094bSMauro Carvalho Chehab goto out_free;
1705ad85094bSMauro Carvalho Chehab
1706ad85094bSMauro Carvalho Chehab ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
1707ad85094bSMauro Carvalho Chehab if (ret)
1708ad85094bSMauro Carvalho Chehab goto out_free;
1709ad85094bSMauro Carvalho Chehab
1710ad85094bSMauro Carvalho Chehab dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1711ad85094bSMauro Carvalho Chehab dev->pad.flags = MEDIA_PAD_FL_SOURCE;
1712ad85094bSMauro Carvalho Chehab dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
1713ad85094bSMauro Carvalho Chehab dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1714ad85094bSMauro Carvalho Chehab ret =
1715ad85094bSMauro Carvalho Chehab v4l2_ctrl_handler_init(&dev->ctrl_handler,
1716ad85094bSMauro Carvalho Chehab ARRAY_SIZE(ov5693_controls));
1717ad85094bSMauro Carvalho Chehab if (ret) {
1718ad85094bSMauro Carvalho Chehab ov5693_remove(client);
1719ad85094bSMauro Carvalho Chehab return ret;
1720ad85094bSMauro Carvalho Chehab }
1721ad85094bSMauro Carvalho Chehab
1722ad85094bSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++)
1723ad85094bSMauro Carvalho Chehab v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i],
1724ad85094bSMauro Carvalho Chehab NULL);
1725ad85094bSMauro Carvalho Chehab
1726ad85094bSMauro Carvalho Chehab if (dev->ctrl_handler.error) {
1727ad85094bSMauro Carvalho Chehab ov5693_remove(client);
1728ad85094bSMauro Carvalho Chehab return dev->ctrl_handler.error;
1729ad85094bSMauro Carvalho Chehab }
1730ad85094bSMauro Carvalho Chehab
1731ad85094bSMauro Carvalho Chehab /* Use same lock for controls as for everything else. */
1732ad85094bSMauro Carvalho Chehab dev->ctrl_handler.lock = &dev->input_lock;
1733ad85094bSMauro Carvalho Chehab dev->sd.ctrl_handler = &dev->ctrl_handler;
1734ad85094bSMauro Carvalho Chehab
1735ad85094bSMauro Carvalho Chehab ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
1736ad85094bSMauro Carvalho Chehab if (ret)
1737ad85094bSMauro Carvalho Chehab ov5693_remove(client);
1738ad85094bSMauro Carvalho Chehab
1739ad85094bSMauro Carvalho Chehab return ret;
1740ad85094bSMauro Carvalho Chehab out_free:
1741ad85094bSMauro Carvalho Chehab v4l2_device_unregister_subdev(&dev->sd);
1742ad85094bSMauro Carvalho Chehab kfree(dev);
1743ad85094bSMauro Carvalho Chehab return ret;
1744ad85094bSMauro Carvalho Chehab }
1745ad85094bSMauro Carvalho Chehab
1746ad85094bSMauro Carvalho Chehab static const struct acpi_device_id ov5693_acpi_match[] = {
1747ad85094bSMauro Carvalho Chehab {"INT33BE"},
1748ad85094bSMauro Carvalho Chehab {},
1749ad85094bSMauro Carvalho Chehab };
1750ad85094bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match);
1751ad85094bSMauro Carvalho Chehab
1752ad85094bSMauro Carvalho Chehab static struct i2c_driver ov5693_driver = {
1753ad85094bSMauro Carvalho Chehab .driver = {
1754ad85094bSMauro Carvalho Chehab .name = "ov5693",
1755ad85094bSMauro Carvalho Chehab .acpi_match_table = ov5693_acpi_match,
1756ad85094bSMauro Carvalho Chehab },
1757*625ac9afSUwe Kleine-König .probe = ov5693_probe,
1758ad85094bSMauro Carvalho Chehab .remove = ov5693_remove,
1759ad85094bSMauro Carvalho Chehab };
1760ad85094bSMauro Carvalho Chehab module_i2c_driver(ov5693_driver);
1761ad85094bSMauro Carvalho Chehab
1762ad85094bSMauro Carvalho Chehab MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
1763ad85094bSMauro Carvalho Chehab MODULE_LICENSE("GPL");
1764