aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tegra/soc380.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/tegra/soc380.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/video/tegra/soc380.c')
-rw-r--r--drivers/media/video/tegra/soc380.c473
1 files changed, 473 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/soc380.c b/drivers/media/video/tegra/soc380.c
new file mode 100644
index 00000000000..7f2c1361466
--- /dev/null
+++ b/drivers/media/video/tegra/soc380.c
@@ -0,0 +1,473 @@
1/*
2 * soc380.c - soc380 sensor driver
3 *
4 * Copyright (c) 2011, NVIDIA, All Rights Reserved.
5 *
6 * Contributors:
7 * Abhinav Sinha <absinha@nvidia.com>
8 *
9 * Leverage OV2710.c
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2. This program is licensed "as is" without any warranty of any
13 * kind, whether express or implied.
14 */
15
16/**
17 * SetMode Sequence for 640x480. Phase 0. Sensor Dependent.
18 * This sequence should put sensor in streaming mode for 640x480
19 * This is usually given by the FAE or the sensor vendor.
20 */
21
22#include <linux/delay.h>
23#include <linux/fs.h>
24#include <linux/i2c.h>
25#include <linux/miscdevice.h>
26#include <linux/slab.h>
27#include <linux/uaccess.h>
28#include <media/soc380.h>
29
30struct soc380_reg {
31 u16 addr;
32 u16 val;
33};
34
35struct soc380_info {
36 int mode;
37 struct i2c_client *i2c_client;
38 struct soc380_platform_data *pdata;
39};
40
41#define SOC380_TABLE_WAIT_MS 0
42#define SOC380_TABLE_END 1
43#define SOC380_MAX_RETRIES 3
44
45static struct soc380_reg mode_640x480[] = {
46 {0x001A, 0x0011},
47
48 {SOC380_TABLE_WAIT_MS, 1},
49
50 {0x001A, 0x0010},
51
52 {SOC380_TABLE_WAIT_MS, 1},
53
54 {0x0018, 0x4028},
55 {0x001A, 0x0210},
56 {0x0010, 0x021c},
57 {0x0012, 0x0000},
58 {0x0014, 0x244B},
59
60 {SOC380_TABLE_WAIT_MS, 10},
61
62 {0x0014, 0x304B},
63
64 {SOC380_TABLE_WAIT_MS, 50},
65
66 {0x0014, 0xB04A},
67
68 {0x098C, 0x2703},
69 {0x0990, 0x0280},
70 {0x098C, 0x2705},
71 {0x0990, 0x01E0},
72 {0x098C, 0x2707},
73 {0x0990, 0x0280},
74 {0x098C, 0x2709},
75 {0x0990, 0x01E0},
76 {0x098C, 0x270D},
77 {0x0990, 0x0000},
78 {0x098C, 0x270F},
79 {0x0990, 0x0000},
80 {0x098C, 0x2711},
81 {0x0990, 0x01E7},
82 {0x098C, 0x2713},
83 {0x0990, 0x0287},
84 {0x098C, 0x2715},
85 {0x0990, 0x0001},
86 {0x098C, 0x2717},
87 {0x0990, 0x0026},
88 {0x098C, 0x2719},
89 {0x0990, 0x001A},
90 {0x098C, 0x271B},
91 {0x0990, 0x006B},
92 {0x098C, 0x271D},
93 {0x0990, 0x006B},
94 {0x098C, 0x271F},
95 {0x0990, 0x022A},
96 {0x098C, 0x2721},
97 {0x0990, 0x034A},
98 {0x098C, 0x2723},
99 {0x0990, 0x0000},
100 {0x098C, 0x2725},
101 {0x0990, 0x0000},
102 {0x098C, 0x2727},
103 {0x0990, 0x01E7},
104 {0x098C, 0x2729},
105 {0x0990, 0x0287},
106 {0x098C, 0x272B},
107 {0x0990, 0x0001},
108 {0x098C, 0x272D},
109 {0x0990, 0x0026},
110 {0x098C, 0x272F},
111 {0x0990, 0x001A},
112 {0x098C, 0x2731},
113 {0x0990, 0x006B},
114 {0x098C, 0x2733},
115 {0x0990, 0x006B},
116 {0x098C, 0x2735},
117 {0x0990, 0x022A},
118 {0x098C, 0x2737},
119 {0x0990, 0x034A},
120 {0x098C, 0x2739},
121 {0x0990, 0x0000},
122 {0x098C, 0x273B},
123 {0x0990, 0x027F},
124 {0x098C, 0x273D},
125 {0x0990, 0x0000},
126 {0x098C, 0x273F},
127 {0x0990, 0x01DF},
128 {0x098C, 0x2747},
129 {0x0990, 0x0000},
130 {0x098C, 0x2749},
131 {0x0990, 0x027F},
132 {0x098C, 0x274B},
133 {0x0990, 0x0000},
134 {0x098C, 0x274D},
135 {0x0990, 0x01DF},
136 {0x098C, 0x222D},
137 {0x0990, 0x008B},
138 {0x098C, 0xA408},
139 {0x0990, 0x0021},
140 {0x098C, 0xA409},
141 {0x0990, 0x0023},
142 {0x098C, 0xA40A},
143 {0x0990, 0x0028},
144 {0x098C, 0xA40B},
145 {0x0990, 0x002A},
146 {0x098C, 0x2411},
147 {0x0990, 0x008B},
148 {0x098C, 0x2413},
149 {0x0990, 0x00A6},
150 {0x098C, 0x2415},
151 {0x0990, 0x008B},
152 {0x098C, 0x2417},
153 {0x0990, 0x00A6},
154 {0x098C, 0xA404},
155 {0x0990, 0x0010},
156 {0x098C, 0xA40D},
157 {0x0990, 0x0002},
158 {0x098C, 0xA40E},
159 {0x0990, 0x0003},
160 {0x098C, 0xA410},
161 {0x0990, 0x000A},
162 {0x098C, 0xA215},
163 {0x0990, 0x0003},
164 {0x098C, 0xA20C},
165 {0x0990, 0x0003},
166
167 {0x098C, 0xA103},
168 {0x0990, 0x0006},
169 {SOC380_TABLE_WAIT_MS, 100},
170
171 {0x098C, 0xA103},
172 {0x0990, 0x0005},
173 {SOC380_TABLE_WAIT_MS, 50},
174
175 {SOC380_TABLE_END, 0x0000}
176};
177
178enum {
179 SOC380_MODE_680x480,
180};
181
182static struct soc380_reg *mode_table[] = {
183 [SOC380_MODE_680x480] = mode_640x480,
184};
185
186static int soc380_read_reg(struct i2c_client *client, u16 addr, u16 *val)
187{
188 int err;
189 struct i2c_msg msg[2];
190 unsigned char data[4];
191
192 if (!client->adapter)
193 return -ENODEV;
194
195 msg[0].addr = client->addr;
196 msg[0].flags = 0;
197 msg[0].len = 2;
198 msg[0].buf = data;
199
200 /* high byte goes out first */
201 data[0] = (u8) (addr >> 8);
202 data[1] = (u8) (addr & 0xff);
203
204 msg[1].addr = client->addr;
205 msg[1].flags = I2C_M_RD;
206 msg[1].len = 2;
207 msg[1].buf = data + 2;
208
209 err = i2c_transfer(client->adapter, msg, 2);
210
211 if (err != 2)
212 return -EINVAL;
213
214 *val = data[2] << 8 | data[3];
215
216 return 0;
217}
218
219static int soc380_write_reg(struct i2c_client *client, u16 addr, u16 val)
220{
221 int err;
222 struct i2c_msg msg;
223 unsigned char data[4];
224 int retry = 0;
225
226 if (!client->adapter)
227 return -ENODEV;
228
229 data[0] = (u8) (addr >> 8);
230 data[1] = (u8) (addr & 0xff);
231 data[2] = (u8) (val >> 8);
232 data[3] = (u8) (val & 0xff);
233
234 msg.addr = client->addr;
235 msg.flags = 0;
236 msg.len = 4;
237 msg.buf = data;
238
239 do {
240 err = i2c_transfer(client->adapter, &msg, 1);
241 if (err == 1)
242 return 0;
243 retry++;
244 pr_err("soc380: i2c transfer failed, retrying %x %x\n",
245 addr, val);
246 msleep(3);
247 } while (retry <= SOC380_MAX_RETRIES);
248
249 return err;
250}
251
252static int soc380_write_table(struct i2c_client *client,
253 const struct soc380_reg table[],
254 const struct soc380_reg override_list[],
255 int num_override_regs)
256{
257 int err;
258 const struct soc380_reg *next;
259 int i;
260 u16 val;
261
262 for (next = table; next->addr != SOC380_TABLE_END; next++) {
263 if (next->addr == SOC380_TABLE_WAIT_MS) {
264 msleep(next->val);
265 continue;
266 }
267
268 val = next->val;
269
270 /* When an override list is passed in, replace the reg */
271 /* value to write if the reg is in the list */
272 if (override_list) {
273 for (i = 0; i < num_override_regs; i++) {
274 if (next->addr == override_list[i].addr) {
275 val = override_list[i].val;
276 break;
277 }
278 }
279 }
280
281 err = soc380_write_reg(client, next->addr, val);
282 if (err)
283 return err;
284 }
285 return 0;
286}
287
288static int soc380_set_mode(struct soc380_info *info, struct soc380_mode *mode)
289{
290 int sensor_mode;
291 int err;
292
293 pr_info("%s: xres %u yres %u\n", __func__, mode->xres, mode->yres);
294 if (mode->xres == 640 && mode->yres == 480)
295 sensor_mode = SOC380_MODE_680x480;
296 else {
297 pr_err("%s: invalid resolution supplied to set mode %d %d\n",
298 __func__, mode->xres, mode->yres);
299 return -EINVAL;
300 }
301
302 err = soc380_write_table(info->i2c_client, mode_table[sensor_mode],
303 NULL, 0);
304 if (err)
305 return err;
306
307 info->mode = sensor_mode;
308 return 0;
309}
310
311static int soc380_get_status(struct soc380_info *info,
312 struct soc380_status *dev_status)
313{
314 int err;
315
316 err = soc380_write_reg(info->i2c_client, 0x98C, dev_status->data);
317 if (err)
318 return err;
319
320 err = soc380_read_reg(info->i2c_client, 0x0990,
321 (u16 *) &dev_status->status);
322 if (err)
323 return err;
324
325 return err;
326}
327
328static long soc380_ioctl(struct file *file,
329 unsigned int cmd, unsigned long arg)
330{
331 int err;
332 struct soc380_info *info = file->private_data;
333
334 switch (cmd) {
335 case SOC380_IOCTL_SET_MODE:
336 {
337 struct soc380_mode mode;
338 if (copy_from_user(&mode,
339 (const void __user *)arg,
340 sizeof(struct soc380_mode))) {
341 return -EFAULT;
342 }
343
344 return soc380_set_mode(info, &mode);
345 }
346 case SOC380_IOCTL_GET_STATUS:
347 {
348 struct soc380_status dev_status;
349 if (copy_from_user(&dev_status,
350 (const void __user *)arg,
351 sizeof(struct soc380_status))) {
352 return -EFAULT;
353 }
354
355 err = soc380_get_status(info, &dev_status);
356 if (err)
357 return err;
358 if (copy_to_user((void __user *)arg, &dev_status,
359 sizeof(struct soc380_status))) {
360 return -EFAULT;
361 }
362 return 0;
363 }
364 default:
365 return -EINVAL;
366 }
367 return 0;
368}
369
370static struct soc380_info *info;
371
372static int soc380_open(struct inode *inode, struct file *file)
373{
374 struct soc380_status dev_status;
375 int err;
376
377 file->private_data = info;
378 if (info->pdata && info->pdata->power_on)
379 info->pdata->power_on();
380
381 dev_status.data = 0;
382 dev_status.status = 0;
383 err = soc380_get_status(info, &dev_status);
384 return err;
385}
386
387int soc380_release(struct inode *inode, struct file *file)
388{
389 if (info->pdata && info->pdata->power_off)
390 info->pdata->power_off();
391 file->private_data = NULL;
392 return 0;
393}
394
395static const struct file_operations soc380_fileops = {
396 .owner = THIS_MODULE,
397 .open = soc380_open,
398 .unlocked_ioctl = soc380_ioctl,
399 .release = soc380_release,
400};
401
402static struct miscdevice soc380_device = {
403 .minor = MISC_DYNAMIC_MINOR,
404 .name = "soc380",
405 .fops = &soc380_fileops,
406};
407
408static int soc380_probe(struct i2c_client *client,
409 const struct i2c_device_id *id)
410{
411 int err;
412
413 pr_info("soc380: probing sensor.\n");
414
415 info = kzalloc(sizeof(struct soc380_info), GFP_KERNEL);
416 if (!info) {
417 pr_err("soc380: Unable to allocate memory!\n");
418 return -ENOMEM;
419 }
420
421 err = misc_register(&soc380_device);
422 if (err) {
423 pr_err("soc380: Unable to register misc device!\n");
424 kfree(info);
425 return err;
426 }
427
428 info->pdata = client->dev.platform_data;
429 info->i2c_client = client;
430
431 i2c_set_clientdata(client, info);
432 return 0;
433}
434
435static int soc380_remove(struct i2c_client *client)
436{
437 struct soc380_info *info;
438 info = i2c_get_clientdata(client);
439 misc_deregister(&soc380_device);
440 kfree(info);
441 return 0;
442}
443
444static const struct i2c_device_id soc380_id[] = {
445 { "soc380", 0 },
446 { },
447};
448
449MODULE_DEVICE_TABLE(i2c, soc380_id);
450
451static struct i2c_driver soc380_i2c_driver = {
452 .driver = {
453 .name = "soc380",
454 .owner = THIS_MODULE,
455 },
456 .probe = soc380_probe,
457 .remove = soc380_remove,
458 .id_table = soc380_id,
459};
460
461static int __init soc380_init(void)
462{
463 pr_info("soc380 sensor driver loading\n");
464 return i2c_add_driver(&soc380_i2c_driver);
465}
466
467static void __exit soc380_exit(void)
468{
469 i2c_del_driver(&soc380_i2c_driver);
470}
471
472module_init(soc380_init);
473module_exit(soc380_exit);