diff options
Diffstat (limited to 'drivers/media/video/marvell-ccic/cafe-driver.c')
-rw-r--r-- | drivers/media/video/marvell-ccic/cafe-driver.c | 654 |
1 files changed, 0 insertions, 654 deletions
diff --git a/drivers/media/video/marvell-ccic/cafe-driver.c b/drivers/media/video/marvell-ccic/cafe-driver.c deleted file mode 100644 index d030f9beae88..000000000000 --- a/drivers/media/video/marvell-ccic/cafe-driver.c +++ /dev/null | |||
@@ -1,654 +0,0 @@ | |||
1 | /* | ||
2 | * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" | ||
3 | * multifunction chip. Currently works with the Omnivision OV7670 | ||
4 | * sensor. | ||
5 | * | ||
6 | * The data sheet for this device can be found at: | ||
7 | * http://www.marvell.com/products/pc_connectivity/88alp01/ | ||
8 | * | ||
9 | * Copyright 2006-11 One Laptop Per Child Association, Inc. | ||
10 | * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net> | ||
11 | * | ||
12 | * Written by Jonathan Corbet, corbet@lwn.net. | ||
13 | * | ||
14 | * v4l2_device/v4l2_subdev conversion by: | ||
15 | * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl> | ||
16 | * | ||
17 | * This file may be distributed under the terms of the GNU General | ||
18 | * Public License, version 2. | ||
19 | */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/videodev2.h> | ||
29 | #include <media/v4l2-device.h> | ||
30 | #include <media/v4l2-chip-ident.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/io.h> | ||
35 | |||
36 | #include "mcam-core.h" | ||
37 | |||
38 | #define CAFE_VERSION 0x000002 | ||
39 | |||
40 | |||
41 | /* | ||
42 | * Parameters. | ||
43 | */ | ||
44 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | ||
45 | MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | MODULE_SUPPORTED_DEVICE("Video"); | ||
48 | |||
49 | |||
50 | |||
51 | |||
52 | struct cafe_camera { | ||
53 | int registered; /* Fully initialized? */ | ||
54 | struct mcam_camera mcam; | ||
55 | struct pci_dev *pdev; | ||
56 | wait_queue_head_t smbus_wait; /* Waiting on i2c events */ | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * Most of the camera controller registers are defined in mcam-core.h, | ||
61 | * but the Cafe platform has some additional registers of its own; | ||
62 | * they are described here. | ||
63 | */ | ||
64 | |||
65 | /* | ||
66 | * "General purpose register" has a couple of GPIOs used for sensor | ||
67 | * power and reset on OLPC XO 1.0 systems. | ||
68 | */ | ||
69 | #define REG_GPR 0xb4 | ||
70 | #define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ | ||
71 | #define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ | ||
72 | #define GPR_C1 0x00000002 /* Control 1 value */ | ||
73 | /* | ||
74 | * Control 0 is wired to reset on OLPC machines. For ov7x sensors, | ||
75 | * it is active low. | ||
76 | */ | ||
77 | #define GPR_C0 0x00000001 /* Control 0 value */ | ||
78 | |||
79 | /* | ||
80 | * These registers control the SMBUS module for communicating | ||
81 | * with the sensor. | ||
82 | */ | ||
83 | #define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ | ||
84 | #define TWSIC0_EN 0x00000001 /* TWSI enable */ | ||
85 | #define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ | ||
86 | #define TWSIC0_SID 0x000003fc /* Slave ID */ | ||
87 | /* | ||
88 | * Subtle trickery: the slave ID field starts with bit 2. But the | ||
89 | * Linux i2c stack wants to treat the bottommost bit as a separate | ||
90 | * read/write bit, which is why slave ID's are usually presented | ||
91 | * >>1. For consistency with that behavior, we shift over three | ||
92 | * bits instead of two. | ||
93 | */ | ||
94 | #define TWSIC0_SID_SHIFT 3 | ||
95 | #define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ | ||
96 | #define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ | ||
97 | #define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ | ||
98 | |||
99 | #define REG_TWSIC1 0xbc /* TWSI control 1 */ | ||
100 | #define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ | ||
101 | #define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ | ||
102 | #define TWSIC1_ADDR_SHIFT 16 | ||
103 | #define TWSIC1_READ 0x01000000 /* Set for read op */ | ||
104 | #define TWSIC1_WSTAT 0x02000000 /* Write status */ | ||
105 | #define TWSIC1_RVALID 0x04000000 /* Read data valid */ | ||
106 | #define TWSIC1_ERROR 0x08000000 /* Something screwed up */ | ||
107 | |||
108 | /* | ||
109 | * Here's the weird global control registers | ||
110 | */ | ||
111 | #define REG_GL_CSR 0x3004 /* Control/status register */ | ||
112 | #define GCSR_SRS 0x00000001 /* SW Reset set */ | ||
113 | #define GCSR_SRC 0x00000002 /* SW Reset clear */ | ||
114 | #define GCSR_MRS 0x00000004 /* Master reset set */ | ||
115 | #define GCSR_MRC 0x00000008 /* HW Reset clear */ | ||
116 | #define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ | ||
117 | #define REG_GL_IMASK 0x300c /* Interrupt mask register */ | ||
118 | #define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ | ||
119 | |||
120 | #define REG_GL_FCR 0x3038 /* GPIO functional control register */ | ||
121 | #define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ | ||
122 | #define REG_GL_GPIOR 0x315c /* GPIO register */ | ||
123 | #define GGPIO_OUT 0x80000 /* GPIO output */ | ||
124 | #define GGPIO_VAL 0x00008 /* Output pin value */ | ||
125 | |||
126 | #define REG_LEN (REG_GL_IMASK + 4) | ||
127 | |||
128 | |||
129 | /* | ||
130 | * Debugging and related. | ||
131 | */ | ||
132 | #define cam_err(cam, fmt, arg...) \ | ||
133 | dev_err(&(cam)->pdev->dev, fmt, ##arg); | ||
134 | #define cam_warn(cam, fmt, arg...) \ | ||
135 | dev_warn(&(cam)->pdev->dev, fmt, ##arg); | ||
136 | |||
137 | /* -------------------------------------------------------------------- */ | ||
138 | /* | ||
139 | * The I2C/SMBUS interface to the camera itself starts here. The | ||
140 | * controller handles SMBUS itself, presenting a relatively simple register | ||
141 | * interface; all we have to do is to tell it where to route the data. | ||
142 | */ | ||
143 | #define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ | ||
144 | |||
145 | static inline struct cafe_camera *to_cam(struct v4l2_device *dev) | ||
146 | { | ||
147 | struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev); | ||
148 | return container_of(m, struct cafe_camera, mcam); | ||
149 | } | ||
150 | |||
151 | |||
152 | static int cafe_smbus_write_done(struct mcam_camera *mcam) | ||
153 | { | ||
154 | unsigned long flags; | ||
155 | int c1; | ||
156 | |||
157 | /* | ||
158 | * We must delay after the interrupt, or the controller gets confused | ||
159 | * and never does give us good status. Fortunately, we don't do this | ||
160 | * often. | ||
161 | */ | ||
162 | udelay(20); | ||
163 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
164 | c1 = mcam_reg_read(mcam, REG_TWSIC1); | ||
165 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
166 | return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; | ||
167 | } | ||
168 | |||
169 | static int cafe_smbus_write_data(struct cafe_camera *cam, | ||
170 | u16 addr, u8 command, u8 value) | ||
171 | { | ||
172 | unsigned int rval; | ||
173 | unsigned long flags; | ||
174 | struct mcam_camera *mcam = &cam->mcam; | ||
175 | |||
176 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
177 | rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); | ||
178 | rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ | ||
179 | /* | ||
180 | * Marvell sez set clkdiv to all 1's for now. | ||
181 | */ | ||
182 | rval |= TWSIC0_CLKDIV; | ||
183 | mcam_reg_write(mcam, REG_TWSIC0, rval); | ||
184 | (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ | ||
185 | rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); | ||
186 | mcam_reg_write(mcam, REG_TWSIC1, rval); | ||
187 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
188 | |||
189 | /* Unfortunately, reading TWSIC1 too soon after sending a command | ||
190 | * causes the device to die. | ||
191 | * Use a busy-wait because we often send a large quantity of small | ||
192 | * commands at-once; using msleep() would cause a lot of context | ||
193 | * switches which take longer than 2ms, resulting in a noticeable | ||
194 | * boot-time and capture-start delays. | ||
195 | */ | ||
196 | mdelay(2); | ||
197 | |||
198 | /* | ||
199 | * Another sad fact is that sometimes, commands silently complete but | ||
200 | * cafe_smbus_write_done() never becomes aware of this. | ||
201 | * This happens at random and appears to possible occur with any | ||
202 | * command. | ||
203 | * We don't understand why this is. We work around this issue | ||
204 | * with the timeout in the wait below, assuming that all commands | ||
205 | * complete within the timeout. | ||
206 | */ | ||
207 | wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam), | ||
208 | CAFE_SMBUS_TIMEOUT); | ||
209 | |||
210 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
211 | rval = mcam_reg_read(mcam, REG_TWSIC1); | ||
212 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
213 | |||
214 | if (rval & TWSIC1_WSTAT) { | ||
215 | cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, | ||
216 | command, value); | ||
217 | return -EIO; | ||
218 | } | ||
219 | if (rval & TWSIC1_ERROR) { | ||
220 | cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, | ||
221 | command, value); | ||
222 | return -EIO; | ||
223 | } | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | |||
228 | |||
229 | static int cafe_smbus_read_done(struct mcam_camera *mcam) | ||
230 | { | ||
231 | unsigned long flags; | ||
232 | int c1; | ||
233 | |||
234 | /* | ||
235 | * We must delay after the interrupt, or the controller gets confused | ||
236 | * and never does give us good status. Fortunately, we don't do this | ||
237 | * often. | ||
238 | */ | ||
239 | udelay(20); | ||
240 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
241 | c1 = mcam_reg_read(mcam, REG_TWSIC1); | ||
242 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
243 | return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); | ||
244 | } | ||
245 | |||
246 | |||
247 | |||
248 | static int cafe_smbus_read_data(struct cafe_camera *cam, | ||
249 | u16 addr, u8 command, u8 *value) | ||
250 | { | ||
251 | unsigned int rval; | ||
252 | unsigned long flags; | ||
253 | struct mcam_camera *mcam = &cam->mcam; | ||
254 | |||
255 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
256 | rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); | ||
257 | rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ | ||
258 | /* | ||
259 | * Marvel sez set clkdiv to all 1's for now. | ||
260 | */ | ||
261 | rval |= TWSIC0_CLKDIV; | ||
262 | mcam_reg_write(mcam, REG_TWSIC0, rval); | ||
263 | (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ | ||
264 | rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); | ||
265 | mcam_reg_write(mcam, REG_TWSIC1, rval); | ||
266 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
267 | |||
268 | wait_event_timeout(cam->smbus_wait, | ||
269 | cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT); | ||
270 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
271 | rval = mcam_reg_read(mcam, REG_TWSIC1); | ||
272 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
273 | |||
274 | if (rval & TWSIC1_ERROR) { | ||
275 | cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); | ||
276 | return -EIO; | ||
277 | } | ||
278 | if (!(rval & TWSIC1_RVALID)) { | ||
279 | cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, | ||
280 | command); | ||
281 | return -EIO; | ||
282 | } | ||
283 | *value = rval & 0xff; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Perform a transfer over SMBUS. This thing is called under | ||
289 | * the i2c bus lock, so we shouldn't race with ourselves... | ||
290 | */ | ||
291 | static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | ||
292 | unsigned short flags, char rw, u8 command, | ||
293 | int size, union i2c_smbus_data *data) | ||
294 | { | ||
295 | struct cafe_camera *cam = i2c_get_adapdata(adapter); | ||
296 | int ret = -EINVAL; | ||
297 | |||
298 | /* | ||
299 | * This interface would appear to only do byte data ops. OK | ||
300 | * it can do word too, but the cam chip has no use for that. | ||
301 | */ | ||
302 | if (size != I2C_SMBUS_BYTE_DATA) { | ||
303 | cam_err(cam, "funky xfer size %d\n", size); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | if (rw == I2C_SMBUS_WRITE) | ||
308 | ret = cafe_smbus_write_data(cam, addr, command, data->byte); | ||
309 | else if (rw == I2C_SMBUS_READ) | ||
310 | ret = cafe_smbus_read_data(cam, addr, command, &data->byte); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | |||
315 | static void cafe_smbus_enable_irq(struct cafe_camera *cam) | ||
316 | { | ||
317 | unsigned long flags; | ||
318 | |||
319 | spin_lock_irqsave(&cam->mcam.dev_lock, flags); | ||
320 | mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS); | ||
321 | spin_unlock_irqrestore(&cam->mcam.dev_lock, flags); | ||
322 | } | ||
323 | |||
324 | static u32 cafe_smbus_func(struct i2c_adapter *adapter) | ||
325 | { | ||
326 | return I2C_FUNC_SMBUS_READ_BYTE_DATA | | ||
327 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | ||
328 | } | ||
329 | |||
330 | static struct i2c_algorithm cafe_smbus_algo = { | ||
331 | .smbus_xfer = cafe_smbus_xfer, | ||
332 | .functionality = cafe_smbus_func | ||
333 | }; | ||
334 | |||
335 | static int cafe_smbus_setup(struct cafe_camera *cam) | ||
336 | { | ||
337 | struct i2c_adapter *adap; | ||
338 | int ret; | ||
339 | |||
340 | adap = kzalloc(sizeof(*adap), GFP_KERNEL); | ||
341 | if (adap == NULL) | ||
342 | return -ENOMEM; | ||
343 | cam->mcam.i2c_adapter = adap; | ||
344 | cafe_smbus_enable_irq(cam); | ||
345 | adap->owner = THIS_MODULE; | ||
346 | adap->algo = &cafe_smbus_algo; | ||
347 | strcpy(adap->name, "cafe_ccic"); | ||
348 | adap->dev.parent = &cam->pdev->dev; | ||
349 | i2c_set_adapdata(adap, cam); | ||
350 | ret = i2c_add_adapter(adap); | ||
351 | if (ret) | ||
352 | printk(KERN_ERR "Unable to register cafe i2c adapter\n"); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | static void cafe_smbus_shutdown(struct cafe_camera *cam) | ||
357 | { | ||
358 | i2c_del_adapter(cam->mcam.i2c_adapter); | ||
359 | kfree(cam->mcam.i2c_adapter); | ||
360 | } | ||
361 | |||
362 | |||
363 | /* | ||
364 | * Controller-level stuff | ||
365 | */ | ||
366 | |||
367 | static void cafe_ctlr_init(struct mcam_camera *mcam) | ||
368 | { | ||
369 | unsigned long flags; | ||
370 | |||
371 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
372 | /* | ||
373 | * Added magic to bring up the hardware on the B-Test board | ||
374 | */ | ||
375 | mcam_reg_write(mcam, 0x3038, 0x8); | ||
376 | mcam_reg_write(mcam, 0x315c, 0x80008); | ||
377 | /* | ||
378 | * Go through the dance needed to wake the device up. | ||
379 | * Note that these registers are global and shared | ||
380 | * with the NAND and SD devices. Interaction between the | ||
381 | * three still needs to be examined. | ||
382 | */ | ||
383 | mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ | ||
384 | mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); | ||
385 | mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); | ||
386 | /* | ||
387 | * Here we must wait a bit for the controller to come around. | ||
388 | */ | ||
389 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
390 | msleep(5); | ||
391 | spin_lock_irqsave(&mcam->dev_lock, flags); | ||
392 | |||
393 | mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); | ||
394 | mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN); | ||
395 | /* | ||
396 | * Mask all interrupts. | ||
397 | */ | ||
398 | mcam_reg_write(mcam, REG_IRQMASK, 0); | ||
399 | spin_unlock_irqrestore(&mcam->dev_lock, flags); | ||
400 | } | ||
401 | |||
402 | |||
403 | static void cafe_ctlr_power_up(struct mcam_camera *mcam) | ||
404 | { | ||
405 | /* | ||
406 | * Part one of the sensor dance: turn the global | ||
407 | * GPIO signal on. | ||
408 | */ | ||
409 | mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); | ||
410 | mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); | ||
411 | /* | ||
412 | * Put the sensor into operational mode (assumes OLPC-style | ||
413 | * wiring). Control 0 is reset - set to 1 to operate. | ||
414 | * Control 1 is power down, set to 0 to operate. | ||
415 | */ | ||
416 | mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ | ||
417 | mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); | ||
418 | } | ||
419 | |||
420 | static void cafe_ctlr_power_down(struct mcam_camera *mcam) | ||
421 | { | ||
422 | mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); | ||
423 | mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); | ||
424 | mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT); | ||
425 | } | ||
426 | |||
427 | |||
428 | |||
429 | /* | ||
430 | * The platform interrupt handler. | ||
431 | */ | ||
432 | static irqreturn_t cafe_irq(int irq, void *data) | ||
433 | { | ||
434 | struct cafe_camera *cam = data; | ||
435 | struct mcam_camera *mcam = &cam->mcam; | ||
436 | unsigned int irqs, handled; | ||
437 | |||
438 | spin_lock(&mcam->dev_lock); | ||
439 | irqs = mcam_reg_read(mcam, REG_IRQSTAT); | ||
440 | handled = cam->registered && mccic_irq(mcam, irqs); | ||
441 | if (irqs & TWSIIRQS) { | ||
442 | mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS); | ||
443 | wake_up(&cam->smbus_wait); | ||
444 | handled = 1; | ||
445 | } | ||
446 | spin_unlock(&mcam->dev_lock); | ||
447 | return IRQ_RETVAL(handled); | ||
448 | } | ||
449 | |||
450 | |||
451 | /* -------------------------------------------------------------------------- */ | ||
452 | /* | ||
453 | * PCI interface stuff. | ||
454 | */ | ||
455 | |||
456 | static int cafe_pci_probe(struct pci_dev *pdev, | ||
457 | const struct pci_device_id *id) | ||
458 | { | ||
459 | int ret; | ||
460 | struct cafe_camera *cam; | ||
461 | struct mcam_camera *mcam; | ||
462 | |||
463 | /* | ||
464 | * Start putting together one of our big camera structures. | ||
465 | */ | ||
466 | ret = -ENOMEM; | ||
467 | cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); | ||
468 | if (cam == NULL) | ||
469 | goto out; | ||
470 | cam->pdev = pdev; | ||
471 | mcam = &cam->mcam; | ||
472 | mcam->chip_id = V4L2_IDENT_CAFE; | ||
473 | spin_lock_init(&mcam->dev_lock); | ||
474 | init_waitqueue_head(&cam->smbus_wait); | ||
475 | mcam->plat_power_up = cafe_ctlr_power_up; | ||
476 | mcam->plat_power_down = cafe_ctlr_power_down; | ||
477 | mcam->dev = &pdev->dev; | ||
478 | /* | ||
479 | * Set the clock speed for the XO 1; I don't believe this | ||
480 | * driver has ever run anywhere else. | ||
481 | */ | ||
482 | mcam->clock_speed = 45; | ||
483 | mcam->use_smbus = 1; | ||
484 | /* | ||
485 | * Vmalloc mode for buffers is traditional with this driver. | ||
486 | * We *might* be able to run DMA_contig, especially on a system | ||
487 | * with CMA in it. | ||
488 | */ | ||
489 | mcam->buffer_mode = B_vmalloc; | ||
490 | /* | ||
491 | * Get set up on the PCI bus. | ||
492 | */ | ||
493 | ret = pci_enable_device(pdev); | ||
494 | if (ret) | ||
495 | goto out_free; | ||
496 | pci_set_master(pdev); | ||
497 | |||
498 | ret = -EIO; | ||
499 | mcam->regs = pci_iomap(pdev, 0, 0); | ||
500 | if (!mcam->regs) { | ||
501 | printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); | ||
502 | goto out_disable; | ||
503 | } | ||
504 | ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); | ||
505 | if (ret) | ||
506 | goto out_iounmap; | ||
507 | |||
508 | /* | ||
509 | * Initialize the controller and leave it powered up. It will | ||
510 | * stay that way until the sensor driver shows up. | ||
511 | */ | ||
512 | cafe_ctlr_init(mcam); | ||
513 | cafe_ctlr_power_up(mcam); | ||
514 | /* | ||
515 | * Set up I2C/SMBUS communications. We have to drop the mutex here | ||
516 | * because the sensor could attach in this call chain, leading to | ||
517 | * unsightly deadlocks. | ||
518 | */ | ||
519 | ret = cafe_smbus_setup(cam); | ||
520 | if (ret) | ||
521 | goto out_pdown; | ||
522 | |||
523 | ret = mccic_register(mcam); | ||
524 | if (ret == 0) { | ||
525 | cam->registered = 1; | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | cafe_smbus_shutdown(cam); | ||
530 | out_pdown: | ||
531 | cafe_ctlr_power_down(mcam); | ||
532 | free_irq(pdev->irq, cam); | ||
533 | out_iounmap: | ||
534 | pci_iounmap(pdev, mcam->regs); | ||
535 | out_disable: | ||
536 | pci_disable_device(pdev); | ||
537 | out_free: | ||
538 | kfree(cam); | ||
539 | out: | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | |||
544 | /* | ||
545 | * Shut down an initialized device | ||
546 | */ | ||
547 | static void cafe_shutdown(struct cafe_camera *cam) | ||
548 | { | ||
549 | mccic_shutdown(&cam->mcam); | ||
550 | cafe_smbus_shutdown(cam); | ||
551 | free_irq(cam->pdev->irq, cam); | ||
552 | pci_iounmap(cam->pdev, cam->mcam.regs); | ||
553 | } | ||
554 | |||
555 | |||
556 | static void cafe_pci_remove(struct pci_dev *pdev) | ||
557 | { | ||
558 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | ||
559 | struct cafe_camera *cam = to_cam(v4l2_dev); | ||
560 | |||
561 | if (cam == NULL) { | ||
562 | printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); | ||
563 | return; | ||
564 | } | ||
565 | cafe_shutdown(cam); | ||
566 | kfree(cam); | ||
567 | } | ||
568 | |||
569 | |||
570 | #ifdef CONFIG_PM | ||
571 | /* | ||
572 | * Basic power management. | ||
573 | */ | ||
574 | static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
575 | { | ||
576 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | ||
577 | struct cafe_camera *cam = to_cam(v4l2_dev); | ||
578 | int ret; | ||
579 | |||
580 | ret = pci_save_state(pdev); | ||
581 | if (ret) | ||
582 | return ret; | ||
583 | mccic_suspend(&cam->mcam); | ||
584 | pci_disable_device(pdev); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | |||
589 | static int cafe_pci_resume(struct pci_dev *pdev) | ||
590 | { | ||
591 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | ||
592 | struct cafe_camera *cam = to_cam(v4l2_dev); | ||
593 | int ret = 0; | ||
594 | |||
595 | pci_restore_state(pdev); | ||
596 | ret = pci_enable_device(pdev); | ||
597 | |||
598 | if (ret) { | ||
599 | cam_warn(cam, "Unable to re-enable device on resume!\n"); | ||
600 | return ret; | ||
601 | } | ||
602 | cafe_ctlr_init(&cam->mcam); | ||
603 | return mccic_resume(&cam->mcam); | ||
604 | } | ||
605 | |||
606 | #endif /* CONFIG_PM */ | ||
607 | |||
608 | static struct pci_device_id cafe_ids[] = { | ||
609 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, | ||
610 | PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, | ||
611 | { 0, } | ||
612 | }; | ||
613 | |||
614 | MODULE_DEVICE_TABLE(pci, cafe_ids); | ||
615 | |||
616 | static struct pci_driver cafe_pci_driver = { | ||
617 | .name = "cafe1000-ccic", | ||
618 | .id_table = cafe_ids, | ||
619 | .probe = cafe_pci_probe, | ||
620 | .remove = cafe_pci_remove, | ||
621 | #ifdef CONFIG_PM | ||
622 | .suspend = cafe_pci_suspend, | ||
623 | .resume = cafe_pci_resume, | ||
624 | #endif | ||
625 | }; | ||
626 | |||
627 | |||
628 | |||
629 | |||
630 | static int __init cafe_init(void) | ||
631 | { | ||
632 | int ret; | ||
633 | |||
634 | printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", | ||
635 | CAFE_VERSION); | ||
636 | ret = pci_register_driver(&cafe_pci_driver); | ||
637 | if (ret) { | ||
638 | printk(KERN_ERR "Unable to register cafe_ccic driver\n"); | ||
639 | goto out; | ||
640 | } | ||
641 | ret = 0; | ||
642 | |||
643 | out: | ||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | |||
648 | static void __exit cafe_exit(void) | ||
649 | { | ||
650 | pci_unregister_driver(&cafe_pci_driver); | ||
651 | } | ||
652 | |||
653 | module_init(cafe_init); | ||
654 | module_exit(cafe_exit); | ||