diff options
Diffstat (limited to 'drivers/media/video/tegra/tegra_camera.c')
-rw-r--r-- | drivers/media/video/tegra/tegra_camera.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/tegra_camera.c b/drivers/media/video/tegra/tegra_camera.c new file mode 100644 index 00000000000..e90b130bcd6 --- /dev/null +++ b/drivers/media/video/tegra/tegra_camera.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * drivers/media/video/tegra/tegra_camera.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Copyright (C) 2012 Nvidia Corp | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/miscdevice.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/ioctl.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <mach/iomap.h> | ||
29 | #include <mach/clk.h> | ||
30 | #include <mach/powergate.h> | ||
31 | |||
32 | #include <media/tegra_camera.h> | ||
33 | |||
34 | /* Eventually this should handle all clock and reset calls for the isp, vi, | ||
35 | * vi_sensor, and csi modules, replacing nvrm and nvos completely for camera | ||
36 | */ | ||
37 | #define TEGRA_CAMERA_NAME "tegra_camera" | ||
38 | |||
39 | struct tegra_camera_dev { | ||
40 | struct device *dev; | ||
41 | struct miscdevice misc_dev; | ||
42 | struct clk *isp_clk; | ||
43 | struct clk *vi_clk; | ||
44 | struct clk *vi_sensor_clk; | ||
45 | struct clk *csus_clk; | ||
46 | struct clk *csi_clk; | ||
47 | struct clk *emc_clk; | ||
48 | struct regulator *reg; | ||
49 | struct tegra_camera_clk_info info; | ||
50 | struct mutex tegra_camera_lock; | ||
51 | int power_refcnt; | ||
52 | }; | ||
53 | |||
54 | struct tegra_camera_block { | ||
55 | int (*enable) (struct tegra_camera_dev *dev); | ||
56 | int (*disable) (struct tegra_camera_dev *dev); | ||
57 | bool is_enabled; | ||
58 | }; | ||
59 | |||
60 | static int tegra_camera_enable_isp(struct tegra_camera_dev *dev) | ||
61 | { | ||
62 | return clk_enable(dev->isp_clk); | ||
63 | } | ||
64 | |||
65 | static int tegra_camera_disable_isp(struct tegra_camera_dev *dev) | ||
66 | { | ||
67 | clk_disable(dev->isp_clk); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int tegra_camera_enable_vi(struct tegra_camera_dev *dev) | ||
72 | { | ||
73 | int ret = 0; | ||
74 | |||
75 | ret |= clk_enable(dev->vi_clk); | ||
76 | ret |= clk_enable(dev->vi_sensor_clk); | ||
77 | ret |= clk_enable(dev->csus_clk); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static int tegra_camera_disable_vi(struct tegra_camera_dev *dev) | ||
82 | { | ||
83 | clk_disable(dev->vi_clk); | ||
84 | clk_disable(dev->vi_sensor_clk); | ||
85 | clk_disable(dev->csus_clk); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int tegra_camera_enable_csi(struct tegra_camera_dev *dev) | ||
90 | { | ||
91 | return clk_enable(dev->csi_clk); | ||
92 | } | ||
93 | |||
94 | static int tegra_camera_disable_csi(struct tegra_camera_dev *dev) | ||
95 | { | ||
96 | clk_disable(dev->csi_clk); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int tegra_camera_enable_emc(struct tegra_camera_dev *dev) | ||
101 | { | ||
102 | /* tegra_camera wasn't added as a user of emc_clk until 3x. | ||
103 | set to 150 MHz, will likely need to be increased as we support | ||
104 | sensors with higher framerates and resolutions. */ | ||
105 | clk_enable(dev->emc_clk); | ||
106 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
107 | clk_set_rate(dev->emc_clk, 300000000); | ||
108 | #else | ||
109 | clk_set_rate(dev->emc_clk, 150000000); | ||
110 | #endif | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int tegra_camera_disable_emc(struct tegra_camera_dev *dev) | ||
115 | { | ||
116 | clk_disable(dev->emc_clk); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | struct tegra_camera_block tegra_camera_block[] = { | ||
121 | [TEGRA_CAMERA_MODULE_ISP] = {tegra_camera_enable_isp, | ||
122 | tegra_camera_disable_isp, false}, | ||
123 | [TEGRA_CAMERA_MODULE_VI] = {tegra_camera_enable_vi, | ||
124 | tegra_camera_disable_vi, false}, | ||
125 | [TEGRA_CAMERA_MODULE_CSI] = {tegra_camera_enable_csi, | ||
126 | tegra_camera_disable_csi, false}, | ||
127 | }; | ||
128 | |||
129 | #define TEGRA_CAMERA_VI_CLK_SEL_INTERNAL 0 | ||
130 | #define TEGRA_CAMERA_VI_CLK_SEL_EXTERNAL (1<<24) | ||
131 | #define TEGRA_CAMERA_PD2VI_CLK_SEL_VI_SENSOR_CLK (1<<25) | ||
132 | #define TEGRA_CAMERA_PD2VI_CLK_SEL_PD2VI_CLK 0 | ||
133 | |||
134 | static bool tegra_camera_enabled(struct tegra_camera_dev *dev) | ||
135 | { | ||
136 | bool ret = false; | ||
137 | |||
138 | mutex_lock(&dev->tegra_camera_lock); | ||
139 | ret = tegra_camera_block[TEGRA_CAMERA_MODULE_ISP].is_enabled == true || | ||
140 | tegra_camera_block[TEGRA_CAMERA_MODULE_VI].is_enabled == true || | ||
141 | tegra_camera_block[TEGRA_CAMERA_MODULE_CSI].is_enabled == true; | ||
142 | mutex_unlock(&dev->tegra_camera_lock); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev) | ||
147 | { | ||
148 | struct clk *clk, *clk_parent; | ||
149 | struct tegra_camera_clk_info *info = &dev->info; | ||
150 | unsigned long parent_rate, parent_div_rate, parent_div_rate_pre; | ||
151 | |||
152 | if (!info) { | ||
153 | dev_err(dev->dev, | ||
154 | "%s: no clock info %d\n", | ||
155 | __func__, info->id); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | if (info->id != TEGRA_CAMERA_MODULE_VI) { | ||
160 | dev_err(dev->dev, | ||
161 | "%s: set rate only aplies to vi module %d\n", | ||
162 | __func__, info->id); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | switch (info->clk_id) { | ||
167 | case TEGRA_CAMERA_VI_CLK: | ||
168 | clk = dev->vi_clk; | ||
169 | break; | ||
170 | case TEGRA_CAMERA_VI_SENSOR_CLK: | ||
171 | clk = dev->vi_sensor_clk; | ||
172 | break; | ||
173 | default: | ||
174 | dev_err(dev->dev, | ||
175 | "%s: invalid clk id for set rate %d\n", | ||
176 | __func__, info->clk_id); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | clk_parent = clk_get_parent(clk); | ||
181 | parent_rate = clk_get_rate(clk_parent); | ||
182 | dev_dbg(dev->dev, "%s: clk_id=%d, parent_rate=%lu, clk_rate=%lu\n", | ||
183 | __func__, info->clk_id, parent_rate, info->rate); | ||
184 | parent_div_rate = parent_rate; | ||
185 | parent_div_rate_pre = parent_rate; | ||
186 | |||
187 | /* | ||
188 | * The requested clock rate from user space should be respected. | ||
189 | * This loop is to search the clock rate that is higher than requested | ||
190 | * clock. | ||
191 | */ | ||
192 | while (parent_div_rate >= info->rate) { | ||
193 | parent_div_rate_pre = parent_div_rate; | ||
194 | parent_div_rate = clk_round_rate(clk, parent_div_rate-1); | ||
195 | } | ||
196 | |||
197 | dev_dbg(dev->dev, "%s: set_rate=%lu", | ||
198 | __func__, parent_div_rate_pre); | ||
199 | |||
200 | clk_set_rate(clk, parent_div_rate_pre); | ||
201 | |||
202 | if (info->clk_id == TEGRA_CAMERA_VI_CLK) { | ||
203 | /* | ||
204 | * bit 25: 0 = pd2vi_Clk, 1 = vi_sensor_clk | ||
205 | * bit 24: 0 = internal clock, 1 = external clock(pd2vi_clk) | ||
206 | */ | ||
207 | if (info->flag == TEGRA_CAMERA_ENABLE_PD2VI_CLK) | ||
208 | tegra_clk_cfg_ex(clk, TEGRA_CLK_VI_INP_SEL, 2); | ||
209 | |||
210 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
211 | u32 val; | ||
212 | void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE); | ||
213 | val = readl(apb_misc + 0x42c); | ||
214 | writel(val | 0x1, apb_misc + 0x42c); | ||
215 | #endif | ||
216 | } | ||
217 | |||
218 | info->rate = clk_get_rate(clk); | ||
219 | dev_dbg(dev->dev, "%s: get_rate=%lu", | ||
220 | __func__, info->rate); | ||
221 | return 0; | ||
222 | |||
223 | } | ||
224 | static int tegra_camera_reset(struct tegra_camera_dev *dev, uint id) | ||
225 | { | ||
226 | struct clk *clk; | ||
227 | |||
228 | switch (id) { | ||
229 | case TEGRA_CAMERA_MODULE_VI: | ||
230 | clk = dev->vi_clk; | ||
231 | break; | ||
232 | case TEGRA_CAMERA_MODULE_ISP: | ||
233 | clk = dev->isp_clk; | ||
234 | break; | ||
235 | case TEGRA_CAMERA_MODULE_CSI: | ||
236 | clk = dev->csi_clk; | ||
237 | break; | ||
238 | default: | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | tegra_periph_reset_assert(clk); | ||
242 | udelay(10); | ||
243 | tegra_periph_reset_deassert(clk); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int tegra_camera_power_on(struct tegra_camera_dev *dev) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | |||
252 | if (dev->power_refcnt++ == 0) { | ||
253 | /* Enable external power */ | ||
254 | if (dev->reg) { | ||
255 | ret = regulator_enable(dev->reg); | ||
256 | if (ret) { | ||
257 | dev_err(dev->dev, | ||
258 | "%s: enable csi regulator failed.\n", | ||
259 | __func__); | ||
260 | return ret; | ||
261 | } | ||
262 | } | ||
263 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
264 | /* Unpowergate VE */ | ||
265 | ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC); | ||
266 | if (ret) | ||
267 | dev_err(dev->dev, | ||
268 | "%s: unpowergate failed.\n", | ||
269 | __func__); | ||
270 | #endif | ||
271 | } | ||
272 | |||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | static int tegra_camera_power_off(struct tegra_camera_dev *dev) | ||
277 | { | ||
278 | int ret = 0; | ||
279 | |||
280 | if (--dev->power_refcnt == 0) { | ||
281 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
282 | /* Powergate VE */ | ||
283 | ret = tegra_powergate_partition(TEGRA_POWERGATE_VENC); | ||
284 | if (ret) | ||
285 | dev_err(dev->dev, | ||
286 | "%s: powergate failed.\n", | ||
287 | __func__); | ||
288 | #endif | ||
289 | /* Disable external power */ | ||
290 | if (dev->reg) { | ||
291 | ret = regulator_disable(dev->reg); | ||
292 | if (ret) { | ||
293 | dev_err(dev->dev, | ||
294 | "%s: disable csi regulator failed.\n", | ||
295 | __func__); | ||
296 | return ret; | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static long tegra_camera_ioctl(struct file *file, | ||
304 | unsigned int cmd, unsigned long arg) | ||
305 | { | ||
306 | uint id; | ||
307 | struct tegra_camera_dev *dev = file->private_data; | ||
308 | |||
309 | /* first element of arg must be u32 with id of module to talk to */ | ||
310 | if (copy_from_user(&id, (const void __user *)arg, sizeof(uint))) { | ||
311 | dev_err(dev->dev, | ||
312 | "%s: Failed to copy arg from user", __func__); | ||
313 | return -EFAULT; | ||
314 | } | ||
315 | |||
316 | if (id >= ARRAY_SIZE(tegra_camera_block)) { | ||
317 | dev_err(dev->dev, | ||
318 | "%s: Invalid id to tegra isp ioctl%d\n", | ||
319 | __func__, id); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | switch (cmd) { | ||
324 | case TEGRA_CAMERA_IOCTL_ENABLE: | ||
325 | { | ||
326 | int ret = 0; | ||
327 | |||
328 | mutex_lock(&dev->tegra_camera_lock); | ||
329 | /* Unpowergate camera blocks (vi, csi and isp) | ||
330 | before enabling clocks */ | ||
331 | ret = tegra_camera_power_on(dev); | ||
332 | if (ret) { | ||
333 | dev->power_refcnt = 0; | ||
334 | mutex_unlock(&dev->tegra_camera_lock); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | if (!tegra_camera_block[id].is_enabled) { | ||
339 | ret = tegra_camera_block[id].enable(dev); | ||
340 | tegra_camera_block[id].is_enabled = true; | ||
341 | } | ||
342 | mutex_unlock(&dev->tegra_camera_lock); | ||
343 | return ret; | ||
344 | } | ||
345 | case TEGRA_CAMERA_IOCTL_DISABLE: | ||
346 | { | ||
347 | int ret = 0; | ||
348 | |||
349 | mutex_lock(&dev->tegra_camera_lock); | ||
350 | if (tegra_camera_block[id].is_enabled) { | ||
351 | ret = tegra_camera_block[id].disable(dev); | ||
352 | tegra_camera_block[id].is_enabled = false; | ||
353 | } | ||
354 | /* Powergate camera blocks (vi, csi and isp) | ||
355 | after disabling all the clocks */ | ||
356 | if (!ret) { | ||
357 | ret = tegra_camera_power_off(dev); | ||
358 | } | ||
359 | mutex_unlock(&dev->tegra_camera_lock); | ||
360 | return ret; | ||
361 | } | ||
362 | case TEGRA_CAMERA_IOCTL_CLK_SET_RATE: | ||
363 | { | ||
364 | int ret; | ||
365 | |||
366 | if (copy_from_user(&dev->info, (const void __user *)arg, | ||
367 | sizeof(struct tegra_camera_clk_info))) { | ||
368 | dev_err(dev->dev, | ||
369 | "%s: Failed to copy arg from user\n", __func__); | ||
370 | return -EFAULT; | ||
371 | } | ||
372 | ret = tegra_camera_clk_set_rate(dev); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | if (copy_to_user((void __user *)arg, &dev->info, | ||
376 | sizeof(struct tegra_camera_clk_info))) { | ||
377 | dev_err(dev->dev, | ||
378 | "%s: Failed to copy arg to user\n", __func__); | ||
379 | return -EFAULT; | ||
380 | } | ||
381 | return 0; | ||
382 | } | ||
383 | case TEGRA_CAMERA_IOCTL_RESET: | ||
384 | return tegra_camera_reset(dev, id); | ||
385 | default: | ||
386 | dev_err(dev->dev, | ||
387 | "%s: Unknown tegra_camera ioctl.\n", __func__); | ||
388 | return -EINVAL; | ||
389 | } | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int tegra_camera_open(struct inode *inode, struct file *file) | ||
394 | { | ||
395 | struct miscdevice *miscdev = file->private_data; | ||
396 | struct tegra_camera_dev *dev = container_of(miscdev, | ||
397 | struct tegra_camera_dev, | ||
398 | misc_dev); | ||
399 | dev_info(dev->dev, "%s\n", __func__); | ||
400 | file->private_data = dev; | ||
401 | |||
402 | tegra_camera_enable_emc(dev); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int tegra_camera_release(struct inode *inode, struct file *file) | ||
408 | { | ||
409 | int i, err; | ||
410 | struct tegra_camera_dev *dev = file->private_data; | ||
411 | |||
412 | dev_info(dev->dev, "%s\n", __func__); | ||
413 | for (i = 0; i < ARRAY_SIZE(tegra_camera_block); i++) | ||
414 | if (tegra_camera_block[i].is_enabled) { | ||
415 | tegra_camera_block[i].disable(dev); | ||
416 | tegra_camera_block[i].is_enabled = false; | ||
417 | } | ||
418 | |||
419 | /* If camera blocks are not powergated yet, do it now */ | ||
420 | if (dev->power_refcnt > 0) { | ||
421 | mutex_lock(&dev->tegra_camera_lock); | ||
422 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
423 | err = tegra_powergate_partition(TEGRA_POWERGATE_VENC); | ||
424 | if (err) | ||
425 | dev_err(dev->dev, "%s: powergate failed.\n", __func__); | ||
426 | #endif | ||
427 | dev->power_refcnt = 0; | ||
428 | mutex_unlock(&dev->tegra_camera_lock); | ||
429 | } | ||
430 | |||
431 | tegra_camera_disable_emc(dev); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static const struct file_operations tegra_camera_fops = { | ||
437 | .owner = THIS_MODULE, | ||
438 | .open = tegra_camera_open, | ||
439 | .unlocked_ioctl = tegra_camera_ioctl, | ||
440 | .release = tegra_camera_release, | ||
441 | }; | ||
442 | |||
443 | static int tegra_camera_clk_get(struct platform_device *pdev, const char *name, | ||
444 | struct clk **clk) | ||
445 | { | ||
446 | *clk = clk_get(&pdev->dev, name); | ||
447 | if (IS_ERR_OR_NULL(*clk)) { | ||
448 | dev_err(&pdev->dev, "%s: unable to get clock for %s\n", | ||
449 | __func__, name); | ||
450 | *clk = NULL; | ||
451 | return PTR_ERR(*clk); | ||
452 | } | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int tegra_camera_probe(struct platform_device *pdev) | ||
457 | { | ||
458 | int err; | ||
459 | struct tegra_camera_dev *dev; | ||
460 | |||
461 | dev_info(&pdev->dev, "%s\n", __func__); | ||
462 | dev = devm_kzalloc(&pdev->dev, sizeof(struct tegra_camera_dev), | ||
463 | GFP_KERNEL); | ||
464 | if (!dev) { | ||
465 | err = -ENOMEM; | ||
466 | dev_err(&pdev->dev, "%s: unable to allocate memory\n", | ||
467 | __func__); | ||
468 | goto alloc_err; | ||
469 | } | ||
470 | |||
471 | mutex_init(&dev->tegra_camera_lock); | ||
472 | |||
473 | /* Powergate VE when boot */ | ||
474 | mutex_lock(&dev->tegra_camera_lock); | ||
475 | dev->power_refcnt = 0; | ||
476 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
477 | err = tegra_powergate_partition(TEGRA_POWERGATE_VENC); | ||
478 | if (err) | ||
479 | dev_err(&pdev->dev, "%s: powergate failed.\n", __func__); | ||
480 | #endif | ||
481 | mutex_unlock(&dev->tegra_camera_lock); | ||
482 | |||
483 | dev->dev = &pdev->dev; | ||
484 | |||
485 | /* Get regulator pointer */ | ||
486 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
487 | dev->reg = regulator_get(&pdev->dev, "vcsi"); | ||
488 | #else | ||
489 | dev->reg = regulator_get(&pdev->dev, "avdd_dsi_csi"); | ||
490 | #endif | ||
491 | if (IS_ERR_OR_NULL(dev->reg)) { | ||
492 | if (dev->reg == ERR_PTR(-ENODEV)) { | ||
493 | dev->reg = NULL; | ||
494 | dev_info(&pdev->dev, "%s: no regulator device, overriding\n", | ||
495 | __func__); | ||
496 | } else { | ||
497 | dev_err(&pdev->dev, "%s: couldn't get regulator\n", | ||
498 | __func__); | ||
499 | return PTR_ERR(dev->reg); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | dev->misc_dev.minor = MISC_DYNAMIC_MINOR; | ||
504 | dev->misc_dev.name = TEGRA_CAMERA_NAME; | ||
505 | dev->misc_dev.fops = &tegra_camera_fops; | ||
506 | dev->misc_dev.parent = &pdev->dev; | ||
507 | |||
508 | err = misc_register(&dev->misc_dev); | ||
509 | if (err) { | ||
510 | dev_err(&pdev->dev, "%s: Unable to register misc device!\n", | ||
511 | TEGRA_CAMERA_NAME); | ||
512 | goto misc_register_err; | ||
513 | } | ||
514 | |||
515 | err = tegra_camera_clk_get(pdev, "isp", &dev->isp_clk); | ||
516 | if (err) | ||
517 | goto misc_register_err; | ||
518 | err = tegra_camera_clk_get(pdev, "vi", &dev->vi_clk); | ||
519 | if (err) | ||
520 | goto vi_clk_get_err; | ||
521 | err = tegra_camera_clk_get(pdev, "vi_sensor", &dev->vi_sensor_clk); | ||
522 | if (err) | ||
523 | goto vi_sensor_clk_get_err; | ||
524 | err = tegra_camera_clk_get(pdev, "csus", &dev->csus_clk); | ||
525 | if (err) | ||
526 | goto csus_clk_get_err; | ||
527 | err = tegra_camera_clk_get(pdev, "csi", &dev->csi_clk); | ||
528 | if (err) | ||
529 | goto csi_clk_get_err; | ||
530 | err = tegra_camera_clk_get(pdev, "emc", &dev->emc_clk); | ||
531 | if (err) | ||
532 | goto emc_clk_get_err; | ||
533 | |||
534 | /* dev is set in order to restore in _remove */ | ||
535 | platform_set_drvdata(pdev, dev); | ||
536 | |||
537 | return 0; | ||
538 | |||
539 | emc_clk_get_err: | ||
540 | clk_put(dev->emc_clk); | ||
541 | csi_clk_get_err: | ||
542 | clk_put(dev->csus_clk); | ||
543 | csus_clk_get_err: | ||
544 | clk_put(dev->vi_sensor_clk); | ||
545 | vi_sensor_clk_get_err: | ||
546 | clk_put(dev->vi_clk); | ||
547 | vi_clk_get_err: | ||
548 | clk_put(dev->isp_clk); | ||
549 | misc_register_err: | ||
550 | regulator_put(dev->reg); | ||
551 | alloc_err: | ||
552 | return err; | ||
553 | } | ||
554 | |||
555 | static int tegra_camera_remove(struct platform_device *pdev) | ||
556 | { | ||
557 | struct tegra_camera_dev *dev = platform_get_drvdata(pdev); | ||
558 | |||
559 | clk_put(dev->isp_clk); | ||
560 | clk_put(dev->vi_clk); | ||
561 | clk_put(dev->vi_sensor_clk); | ||
562 | clk_put(dev->csus_clk); | ||
563 | clk_put(dev->csi_clk); | ||
564 | |||
565 | misc_deregister(&dev->misc_dev); | ||
566 | regulator_put(dev->reg); | ||
567 | mutex_destroy(&dev->tegra_camera_lock); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int tegra_camera_suspend(struct platform_device *pdev, pm_message_t state) | ||
573 | { | ||
574 | struct tegra_camera_dev *dev = platform_get_drvdata(pdev); | ||
575 | int ret = 0; | ||
576 | |||
577 | if (tegra_camera_enabled(dev)) { | ||
578 | ret = -EBUSY; | ||
579 | dev_err(&pdev->dev, | ||
580 | "tegra_camera cannot suspend, " | ||
581 | "application is holding on to camera. \n"); | ||
582 | } | ||
583 | |||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | static int tegra_camera_resume(struct platform_device *pdev) | ||
588 | { | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static struct platform_driver tegra_camera_driver = { | ||
593 | .probe = tegra_camera_probe, | ||
594 | .remove = tegra_camera_remove, | ||
595 | .suspend = tegra_camera_suspend, | ||
596 | .resume = tegra_camera_resume, | ||
597 | .driver = { .name = TEGRA_CAMERA_NAME } | ||
598 | }; | ||
599 | |||
600 | static int __init tegra_camera_init(void) | ||
601 | { | ||
602 | return platform_driver_register(&tegra_camera_driver); | ||
603 | } | ||
604 | |||
605 | static void __exit tegra_camera_exit(void) | ||
606 | { | ||
607 | platform_driver_unregister(&tegra_camera_driver); | ||
608 | } | ||
609 | |||
610 | module_init(tegra_camera_init); | ||
611 | module_exit(tegra_camera_exit); | ||
612 | |||