aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tegra/ov9726.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/ov9726.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/video/tegra/ov9726.c')
-rw-r--r--drivers/media/video/tegra/ov9726.c845
1 files changed, 845 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/ov9726.c b/drivers/media/video/tegra/ov9726.c
new file mode 100644
index 00000000000..655d07c736a
--- /dev/null
+++ b/drivers/media/video/tegra/ov9726.c
@@ -0,0 +1,845 @@
1/*
2 * ov9726.c - ov9726 sensor driver
3 *
4 * Copyright (c) 2011, NVIDIA, All Rights Reserved.
5 *
6 * Contributors:
7 * Charlie Huang <chahuang@nvidia.com>
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
14#include <linux/kernel.h>
15#include <linux/delay.h>
16#include <linux/fs.h>
17#include <linux/i2c.h>
18#include <linux/miscdevice.h>
19#include <linux/slab.h>
20#include <linux/io.h>
21#include <linux/uaccess.h>
22#include <mach/iomap.h>
23#include <linux/atomic.h>
24#include <mach/gpio.h>
25#include <linux/regulator/consumer.h>
26
27#include <media/ov9726.h>
28
29struct ov9726_power_rail {
30 struct regulator *sen_1v8_reg;
31 struct regulator *sen_2v8_reg;
32};
33
34struct ov9726_devinfo {
35 struct miscdevice miscdev_info;
36 struct i2c_client *i2c_client;
37 struct ov9726_platform_data *pdata;
38 struct ov9726_power_rail power_rail;
39 atomic_t in_use;
40 __u32 mode;
41};
42
43static struct ov9726_reg mode_1280x720[] = {
44 /*
45 (1) clock setting
46 clock formula: (Ref_clk / pre_pll_clk_div) * pll_multiplier /
47 vt_sys_clk_div / vt_pix_clk_div / divmip
48 input clk at 24Mhz
49 pre_pll_clk_div 0305[3:0] => 4
50 pll_multiplier 0307[6:0] => 100
51 vt_sys_clk_div 0303[3:0] => 1
52 vt_pix_clk_div 0301[3:0] => 10
53 divmip 3010[2:0] => 1
54
55 Overall timing:
56 line length: 1664 (reg 0x342/0x343)
57 frame length: 840 (reg 0x340/0x341)
58 coarse integration time: 835 lines (reg 0x202/0x203) => change to 836
59
60 visible pixels: (0,40) - (1280, 720+40) with size 1280x720
61 Output pixels (1280x720)
62
63 Frame rate if MCLK=24MHz:
64 24Mhz/4 *100/1/10/1 = 60 Mhz
65 60Mhz/1664/840 = 42.9 fps
66 */
67
68 {0x0103, 0x01},
69
70 {OV9726_TABLE_WAIT_MS, 10},
71
72 {0x3026, 0x00},
73 {0x3027, 0x00},
74 {0x3705, 0x45},
75 {0x3603, 0xaa},
76 {0x3632, 0x2f},
77 {0x3620, 0x66},
78 {0x3621, 0xc0},
79 {0x0202, 0x03},
80 {0x0203, 0x13},
81 {0x3833, 0x04},
82 {0x3835, 0x02},
83 {0x4702, 0x04},
84 {0x4704, 0x00},
85 {0x4706, 0x08},
86 {0x5052, 0x01},
87 {0x3819, 0x6c},
88 {0x3817, 0x94},
89 {0x404e, 0x7e},
90 {0x3601, 0x40},
91 {0x3610, 0xa0},
92 {0x0344, 0x00},
93 {0x0345, 0x00},
94 {0x0346, 0x00},
95 {0x0347, 0x28},
96
97 {0x034c, 0x05},
98 {0x034d, 0x00},
99 {0x034e, 0x02},
100 {0x034f, 0xd8},
101 {0x3002, 0x00},
102 {0x3004, 0x00},
103 {0x3005, 0x00},
104 {0x4800, 0x44},
105 {0x4801, 0x0f},
106 {0x4803, 0x05},
107 {0x4601, 0x16},
108 {0x3014, 0x05},
109 {0x0101, 0x01},
110 {0x3707, 0x14},
111 {0x3622, 0x9f},
112 {0x4002, 0x45},
113 {0x5001, 0x00},
114 {0x3406, 0x01},
115 {0x3503, 0x17},
116 {0x0205, 0x3f},
117 {0x0100, 0x01},
118 {0x0112, 0x0a},
119 {0x0113, 0x0a},
120 {0x3013, 0x20},
121 {0x4837, 0x2f},
122 {0x3615, 0xf0},
123 {0x0340, 0x03},
124 {0x0341, 0x48},
125 {0x0342, 0x06},
126 {0x0343, 0x80},
127 {0x3702, 0x1e},
128 {0x3703, 0x3c},
129 {0x3704, 0x0e},
130
131 {0x3104, 0x20},
132 {0x0305, 0x04},
133 {0x0307, 0x46},
134 {0x0303, 0x01},
135 {0x0301, 0x0a},
136 {0x3010, 0x01},
137 {0x460e, 0x00},
138
139 {0x5000, 0x00},
140 {0x5002, 0x00},
141 {0x3017, 0xd2},
142 {0x3018, 0x69},
143 {0x3019, 0x96},
144 {0x5047, 0x61},
145 {0x3604, 0x1c},
146 {0x3602, 0x10},
147 {0x3612, 0x21},
148 {0x3630, 0x0a},
149 {0x3631, 0x53},
150 {0x3633, 0x70},
151 {0x4005, 0x1a},
152 {0x4009, 0x10},
153
154 {OV9726_TABLE_END, 0x0000}
155};
156
157static struct ov9726_reg mode_1280x800[] = {
158 {0x0103, 0x01},
159
160 {OV9726_TABLE_WAIT_MS, 10},
161
162 {0x3026, 0x00},
163 {0x3027, 0x00},
164 {0x3705, 0x45},
165 {0x3603, 0xaa},
166 {0x3632, 0x2f},
167 {0x3620, 0x66},
168 {0x3621, 0xc0},
169 {0x0202, 0x03},
170 {0x0203, 0x13},
171 {0x3833, 0x04},
172 {0x3835, 0x02},
173 {0x4702, 0x04},
174 {0x4704, 0x00},
175 {0x4706, 0x08},
176 {0x5052, 0x01},
177 {0x3819, 0x6c},
178 {0x3817, 0x94},
179 {0x404e, 0x7e},
180 {0x3601, 0x40},
181 {0x3610, 0xa0},
182
183 {0x0344, 0x00},
184 {0x0345, 0x00},
185 {0x0346, 0x00},
186 {0x0347, 0x00},
187 {0x034c, 0x05},
188 {0x034d, 0x10},
189 {0x034e, 0x03},
190 {0x034f, 0x28},
191
192 {0x3002, 0x00},
193 {0x3004, 0x00},
194 {0x3005, 0x00},
195 {0x4800, 0x44},
196 {0x4801, 0x0f},
197 {0x4803, 0x05},
198 {0x4601, 0x16},
199 {0x3014, 0x05},
200 {0x0101, 0x01},
201 {0x3707, 0x14},
202 {0x3622, 0x9f},
203 {0x4002, 0x45},
204 {0x5001, 0x00},
205 {0x3406, 0x01},
206 {0x3503, 0x17},
207 {0x0205, 0x3f},
208 {0x0100, 0x01},
209 {0x0112, 0x0a},
210 {0x0113, 0x0a},
211 {0x3013, 0x20},
212 {0x4837, 0x2f},
213 {0x3615, 0xf0},
214 {0x0340, 0x03},
215 {0x0341, 0x48},
216 {0x0342, 0x06},
217 {0x0343, 0x80},
218 {0x3702, 0x1e},
219 {0x3703, 0x3c},
220 {0x3704, 0x0e},
221
222 {0x3104, 0x20},
223 {0x0305, 0x04},
224 {0x0307, 0x46},
225 {0x0303, 0x01},
226 {0x0301, 0x0a},
227 {0x3010, 0x01},
228 {0x460e, 0x00},
229
230 {0x5000, 0x00},
231 {0x5002, 0x00},
232 {0x3017, 0xd2},
233 {0x3018, 0x69},
234 {0x3019, 0x96},
235 {0x5047, 0x61},
236 {0x3604, 0x1c},
237 {0x3602, 0x10},
238 {0x3612, 0x21},
239 {0x3630, 0x0a},
240 {0x3631, 0x53},
241 {0x3633, 0x70},
242 {0x4005, 0x1a},
243 {0x4009, 0x10},
244
245 {OV9726_TABLE_END, 0x0000}
246};
247
248enum {
249 OV9726_MODE_1280x720,
250 OV9726_MODE_1280x800,
251};
252
253static struct ov9726_reg *mode_table[] = {
254 [OV9726_MODE_1280x720] = mode_1280x720,
255 [OV9726_MODE_1280x800] = mode_1280x800,
256};
257
258static inline void
259msleep_range(unsigned int delay_base)
260{
261 usleep_range(delay_base*1000, delay_base*1000 + 500);
262}
263
264static inline int
265ov9726_power_init(struct ov9726_devinfo *dev)
266{
267 struct i2c_client *i2c_client = dev->i2c_client;
268 int err = 0;
269
270 dev->power_rail.sen_1v8_reg = regulator_get(&i2c_client->dev, "dovdd");
271 if (IS_ERR_OR_NULL(dev->power_rail.sen_1v8_reg)) {
272 dev_err(&i2c_client->dev, "%s: failed to get vdd\n",
273 __func__);
274 err = PTR_ERR(dev->power_rail.sen_1v8_reg);
275 goto ov9726_power_init_end;
276 }
277
278 dev->power_rail.sen_2v8_reg = regulator_get(&i2c_client->dev, "avdd");
279 if (IS_ERR_OR_NULL(dev->power_rail.sen_2v8_reg)) {
280 dev_err(&i2c_client->dev, "%s: failed to get vaa\n",
281 __func__);
282 err = PTR_ERR(dev->power_rail.sen_2v8_reg);
283
284 regulator_put(dev->power_rail.sen_1v8_reg);
285 dev->power_rail.sen_1v8_reg = NULL;
286 }
287
288ov9726_power_init_end:
289 return err;
290}
291
292static inline void
293ov9726_power_release(struct ov9726_devinfo *dev)
294{
295 regulator_put(dev->power_rail.sen_1v8_reg);
296 regulator_put(dev->power_rail.sen_2v8_reg);
297}
298
299static int
300ov9726_power(struct ov9726_devinfo *dev, bool pwr_on)
301{
302 struct i2c_client *i2c_client = dev->i2c_client;
303 int rst_active_state = dev->pdata->rst_low_active ? 0 : 1;
304 int pwdn_active_state = dev->pdata->pwdn_low_active ? 0 : 1;
305 int ret = 0;
306
307 dev_info(&i2c_client->dev, "%s %s\n", __func__, pwr_on ? "on" : "off");
308
309 if (pwr_on) {
310 /* pull low the RST pin of ov9726 first */
311 gpio_set_value(dev->pdata->gpio_rst, rst_active_state);
312 msleep_range(1);
313 /* Plug 1.8V and 2.8V power to sensor */
314 ret = regulator_enable(dev->power_rail.sen_1v8_reg);
315 if (ret) {
316 dev_err(&i2c_client->dev, "%s: failed to enable vdd\n",
317 __func__);
318 goto fail_regulator_1v8_reg;
319 }
320
321 msleep_range(20);
322
323 ret = regulator_enable(dev->power_rail.sen_2v8_reg);
324 if (ret) {
325 dev_err(&i2c_client->dev, "%s: failed to enable vaa\n",
326 __func__);
327 goto fail_regulator_2v8_reg;
328 }
329 msleep_range(1);
330 /* turn on ov9726 */
331 gpio_set_value(dev->pdata->gpio_pwdn, !pwdn_active_state);
332
333 msleep_range(5);
334 /* release RST pin */
335 gpio_set_value(dev->pdata->gpio_rst, !rst_active_state);
336 msleep_range(20);
337
338 /* Board specific power-on sequence */
339 dev->pdata->power_on();
340 } else {
341 /* pull low the RST pin of ov9726 */
342 gpio_set_value(dev->pdata->gpio_rst, rst_active_state);
343 msleep_range(1);
344 /* turn off ov9726 */
345 gpio_set_value(dev->pdata->gpio_pwdn, pwdn_active_state);
346 msleep_range(1);
347
348 /* Unplug 1.8V and 2.8V power from sensor */
349 regulator_disable(dev->power_rail.sen_2v8_reg);
350 regulator_disable(dev->power_rail.sen_1v8_reg);
351
352 /* Board specific power-down sequence */
353 dev->pdata->power_off();
354 }
355
356 return 0;
357
358fail_regulator_2v8_reg:
359 regulator_put(dev->power_rail.sen_2v8_reg);
360 dev->power_rail.sen_2v8_reg = NULL;
361 regulator_disable(dev->power_rail.sen_1v8_reg);
362fail_regulator_1v8_reg:
363 regulator_put(dev->power_rail.sen_1v8_reg);
364 dev->power_rail.sen_1v8_reg = NULL;
365 return ret;
366}
367
368static inline void
369ov9726_get_frame_length_regs(struct ov9726_reg *regs, u32 frame_length)
370{
371 regs->addr = OV9726_REG_FRAME_LENGTH_HI;
372 regs->val = (frame_length >> 8) & 0xff;
373 regs++;
374 regs->addr = OV9726_REG_FRAME_LENGTH_LO;
375 regs->val = frame_length & 0xff;
376}
377
378static inline void
379ov9726_get_coarse_time_regs(struct ov9726_reg *regs, u32 coarse_time)
380{
381 regs->addr = OV9726_REG_COARSE_TIME_HI;
382 regs->val = (coarse_time >> 8) & 0xff;
383 regs++;
384 regs->addr = OV9726_REG_COARSE_TIME_LO;
385 regs->val = coarse_time & 0xff;
386}
387
388static inline void
389ov9726_get_gain_reg(struct ov9726_reg *regs, u16 gain)
390{
391 regs->addr = OV9726_REG_GAIN_HI;
392 regs->val = (gain >> 8) & 0xff;
393 regs++;
394 regs->addr = OV9726_REG_GAIN_LO;
395 regs->val = gain & 0xff;
396}
397
398static int
399ov9726_read_reg8(struct i2c_client *client, u16 addr, u8 *val)
400{
401 int err;
402 struct i2c_msg msg[2];
403 unsigned char data[3];
404
405 if (!client->adapter)
406 return -ENODEV;
407
408 msg[0].addr = client->addr;
409 msg[0].flags = 0;
410 msg[0].len = 2;
411 msg[0].buf = data;
412
413 /* high byte goes out first */
414 data[0] = (u8)(addr >> 8);
415 data[1] = (u8)(addr & 0xff);
416
417 msg[1].addr = client->addr;
418 msg[1].flags = I2C_M_RD;
419 msg[1].len = 1;
420 msg[1].buf = data + 2;
421
422 err = i2c_transfer(client->adapter, msg, 2);
423
424 if (err != 2)
425 err = -EINVAL;
426 else {
427 *val = data[2];
428 err = 0;
429 }
430
431 return err;
432}
433
434static int
435ov9726_write_reg8(struct i2c_client *client, u16 addr, u8 val)
436{
437 int err;
438 struct i2c_msg msg;
439 unsigned char data[3];
440 int retry = 0;
441
442 if (!client->adapter)
443 return -ENODEV;
444
445 data[0] = (u8)(addr >> 8);
446 data[1] = (u8)(addr & 0xff);
447 data[2] = (u8)(val & 0xff);
448
449 msg.addr = client->addr;
450 msg.flags = 0;
451 msg.len = 3;
452 msg.buf = data;
453
454 do {
455 err = i2c_transfer(client->adapter, &msg, 1);
456 if (err == 1)
457 break;
458
459 retry++;
460 dev_err(&client->dev,
461 "ov9726: i2c transfer failed, retrying %x %x\n",
462 addr, val);
463 msleep_range(3);
464 } while (retry <= OV9726_MAX_RETRIES);
465
466 return (err != 1);
467}
468
469static int
470ov9726_write_reg16(struct i2c_client *client, u16 addr, u16 val)
471{
472 int count;
473 struct i2c_msg msg;
474 unsigned char data[4];
475 int retry = 0;
476
477 if (!client->adapter)
478 return -ENODEV;
479
480 data[0] = (u8)(addr >> 8);
481 data[1] = (u8)(addr & 0xff);
482 data[2] = (u8)(val >> 8);
483 data[3] = (u8)(val & 0xff);
484
485 msg.addr = client->addr;
486 msg.flags = 0;
487 msg.len = 4;
488 msg.buf = data;
489
490 do {
491 count = i2c_transfer(client->adapter, &msg, 1);
492 if (count == 1)
493 return 0;
494
495 retry++;
496 dev_err(&client->dev,
497 "ov9726: i2c transfer failed, retrying %x %x %x\n",
498 addr, val, count);
499 msleep_range(3);
500 } while (retry <= OV9726_MAX_RETRIES);
501
502 return -EIO;
503}
504
505static int
506ov9726_write_table(
507 struct i2c_client *client,
508 struct ov9726_reg table[],
509 struct ov9726_reg override_list[],
510 int num_override_regs)
511{
512 const struct ov9726_reg *next;
513 int err = 0;
514 int i;
515 u16 val;
516
517 dev_info(&client->dev, "ov9726_write_table\n");
518
519 for (next = table; next->addr != OV9726_TABLE_END; next++) {
520
521 if (next->addr == OV9726_TABLE_WAIT_MS) {
522 msleep_range(next->val);
523 continue;
524 }
525
526 val = next->val;
527
528 /* When an override list is passed in, replace the reg */
529 /* value to write if the reg is in the list */
530 if (override_list) {
531 for (i = 0; i < num_override_regs; i++) {
532 if (next->addr == override_list[i].addr) {
533 val = override_list[i].val;
534 break;
535 }
536 }
537 }
538
539 err = ov9726_write_reg8(client, next->addr, val);
540 if (err)
541 break;
542 }
543
544 return err;
545}
546
547static int
548ov9726_set_frame_length(struct i2c_client *i2c_client, u32 frame_length)
549{
550 int ret;
551
552 dev_info(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, frame_length);
553 /* hold register value */
554 ret = ov9726_write_reg8(i2c_client, 0x104, 0x01);
555 if (ret)
556 return ret;
557
558 ret = ov9726_write_reg16(i2c_client,
559 OV9726_REG_FRAME_LENGTH_HI,
560 frame_length);
561
562 /* release hold, update register value */
563 ret |= ov9726_write_reg8(i2c_client, 0x104, 0x00);
564
565 return ret;
566}
567
568static int
569ov9726_set_coarse_time(struct i2c_client *i2c_client, u32 coarse_time)
570{
571 int ret;
572
573 dev_info(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, coarse_time);
574 /* hold register value */
575 ret = ov9726_write_reg8(i2c_client, 0x104, 0x01);
576 if (ret)
577 return ret;
578
579 ret = ov9726_write_reg16(i2c_client,
580 OV9726_REG_COARSE_TIME_HI,
581 coarse_time);
582
583 /* release hold, update register value */
584 ret |= ov9726_write_reg8(i2c_client, 0x104, 0x00);
585
586 return ret;
587}
588
589static int ov9726_set_gain(struct i2c_client *i2c_client, u16 gain)
590{
591 int ret;
592
593 /* hold register value */
594 ret = ov9726_write_reg8(i2c_client, 0x104, 0x01);
595 if (ret)
596 return ret;
597
598 ret = ov9726_write_reg16(i2c_client, OV9726_REG_GAIN_HI, gain);
599
600 /* release hold, update register value */
601 ret |= ov9726_write_reg8(i2c_client, 0x104, 0x00);
602
603 return ret;
604}
605
606static int ov9726_get_status(struct i2c_client *i2c_client, u8 *status)
607{
608 int err;
609
610 err = ov9726_read_reg8(i2c_client, 0x003, status);
611 *status = 0;
612 return err;
613}
614
615static int
616ov9726_set_mode(
617 struct ov9726_devinfo *dev,
618 struct ov9726_mode *mode)
619{
620 struct i2c_client *i2c_client = dev->i2c_client;
621 struct ov9726_reg reg_override[6];
622 int err = 0;
623 int sensor_mode;
624
625 dev_info(&i2c_client->dev, "%s.\n", __func__);
626
627 if (mode->xres == 1280 && mode->yres == 800)
628 sensor_mode = OV9726_MODE_1280x800;
629 else if (mode->xres == 1280 && mode->yres == 720)
630 sensor_mode = OV9726_MODE_1280x720;
631 else {
632 dev_err(&i2c_client->dev,
633 "%s: invalid resolution supplied to set mode %d %d\n",
634 __func__, mode->xres, mode->yres);
635 return -EINVAL;
636 }
637
638 ov9726_get_frame_length_regs(reg_override, mode->frame_length);
639 ov9726_get_coarse_time_regs(reg_override + 2, mode->coarse_time);
640 ov9726_get_gain_reg(reg_override + 4, mode->gain);
641
642 if (dev->mode != mode->mode_id) {
643 dev_info(&i2c_client->dev,
644 "%s: xres %u yres %u framelen %u coarse %u gain %u\n",
645 __func__, mode->xres, mode->yres, mode->frame_length,
646 mode->coarse_time, mode->gain);
647
648 err = ov9726_write_table(i2c_client,
649 mode_table[sensor_mode], reg_override,
650 sizeof(reg_override) / sizeof(reg_override[0]));
651 if (err)
652 goto ov9726_set_mode_exit;
653
654 dev->mode = mode->mode_id;
655 }
656
657ov9726_set_mode_exit:
658 return err;
659}
660
661static long
662ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
663{
664 struct ov9726_devinfo *dev = file->private_data;
665 struct i2c_client *i2c_client = dev->i2c_client;
666 int err = 0;
667
668 switch (cmd) {
669 case OV9726_IOCTL_SET_MODE:
670 {
671 struct ov9726_mode mode;
672
673 if (copy_from_user(&mode,
674 (const void __user *)arg,
675 sizeof(struct ov9726_mode))) {
676 err = -EFAULT;
677 break;
678 }
679
680 err = ov9726_set_mode(dev, &mode);
681
682 break;
683 }
684
685 case OV9726_IOCTL_SET_FRAME_LENGTH:
686 err = ov9726_set_frame_length(i2c_client, (u32)arg);
687 break;
688
689 case OV9726_IOCTL_SET_COARSE_TIME:
690 err = ov9726_set_coarse_time(i2c_client, (u32)arg);
691 break;
692
693 case OV9726_IOCTL_SET_GAIN:
694 err = ov9726_set_gain(i2c_client, (u16)arg);
695 break;
696
697 case OV9726_IOCTL_GET_STATUS:
698 {
699 u8 status;
700
701 err = ov9726_get_status(i2c_client, &status);
702 if (!err) {
703 if (copy_to_user((void __user *)arg,
704 &status, sizeof(status)))
705 err = -EFAULT;
706 }
707 break;
708 }
709
710 default:
711 err = -EINVAL;
712 break;
713 }
714
715 return err;
716}
717
718static int ov9726_open(struct inode *inode, struct file *file)
719{
720 struct miscdevice *miscdev = file->private_data;
721 struct ov9726_devinfo *dev;
722
723 dev = container_of(miscdev, struct ov9726_devinfo, miscdev_info);
724 /* check if device is in use */
725 if (atomic_xchg(&dev->in_use, 1))
726 return -EBUSY;
727 dev->mode = (__u32)-1;
728 file->private_data = dev;
729
730 ov9726_power(dev, true);
731
732 return 0;
733}
734
735int ov9726_release(struct inode *inode, struct file *file)
736{
737 struct ov9726_devinfo *dev;
738
739 dev = file->private_data;
740 file->private_data = NULL;
741
742 ov9726_power(dev, false);
743
744 /* warn if device already released */
745 WARN_ON(!atomic_xchg(&dev->in_use, 0));
746 return 0;
747}
748
749static const struct file_operations ov9726_fileops = {
750 .owner = THIS_MODULE,
751 .open = ov9726_open,
752 .unlocked_ioctl = ov9726_ioctl,
753 .release = ov9726_release,
754};
755
756static struct miscdevice ov9726_device = {
757 .name = "ov9726",
758 .minor = MISC_DYNAMIC_MINOR,
759 .fops = &ov9726_fileops,
760};
761
762static int
763ov9726_probe(struct i2c_client *client, const struct i2c_device_id *id)
764{
765 struct ov9726_devinfo *dev;
766 int err = 0;
767
768 dev_info(&client->dev, "ov9726: probing sensor.\n");
769
770 dev = kzalloc(sizeof(struct ov9726_devinfo), GFP_KERNEL);
771 if (!dev) {
772 dev_err(&client->dev, "ov9726: Unable to allocate memory!\n");
773 err = -ENOMEM;
774 goto probe_end;
775 }
776
777 memcpy(&(dev->miscdev_info),
778 &ov9726_device,
779 sizeof(struct miscdevice));
780
781 err = misc_register(&(dev->miscdev_info));
782 if (err) {
783 dev_err(&client->dev, "ov9726: Unable to register misc device!\n");
784 goto probe_end;
785 }
786
787 dev->pdata = client->dev.platform_data;
788 dev->i2c_client = client;
789 atomic_set(&dev->in_use, 0);
790 i2c_set_clientdata(client, dev);
791
792 err = ov9726_power_init(dev);
793
794probe_end:
795 if (err) {
796 kfree(dev);
797 dev_err(&client->dev, "failed.\n");
798 }
799
800 return err;
801}
802
803static int ov9726_remove(struct i2c_client *client)
804{
805 struct ov9726_devinfo *dev;
806
807 dev = i2c_get_clientdata(client);
808 i2c_set_clientdata(client, NULL);
809 misc_deregister(&ov9726_device);
810 ov9726_power_release(dev);
811 kfree(dev);
812
813 return 0;
814}
815
816static const struct i2c_device_id ov9726_id[] = {
817 {"ov9726", 0},
818 {},
819};
820
821MODULE_DEVICE_TABLE(i2c, ov9726_id);
822
823static struct i2c_driver ov9726_i2c_driver = {
824 .driver = {
825 .name = "ov9726",
826 .owner = THIS_MODULE,
827 },
828 .probe = ov9726_probe,
829 .remove = ov9726_remove,
830 .id_table = ov9726_id,
831};
832
833static int __init ov9726_init(void)
834{
835 pr_info("ov9726 sensor driver loading\n");
836 return i2c_add_driver(&ov9726_i2c_driver);
837}
838
839static void __exit ov9726_exit(void)
840{
841 i2c_del_driver(&ov9726_i2c_driver);
842}
843
844module_init(ov9726_init);
845module_exit(ov9726_exit);