diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-07 04:49:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-07 04:49:05 -0400 |
commit | 0b8e74c6f44094189dbe78baf4101acc7570c6af (patch) | |
tree | 6440561d09fb71ba5928664604ec92f29940be6b /drivers/media/platform/soc_camera | |
parent | 7f60ba388f5b9dd8b0da463b394412dace3ab814 (diff) | |
parent | bd0d10498826ed150da5e4c45baf8b9c7088fb71 (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"The first part of the media updates for Kernel 3.7.
This series contain:
- A major tree renaming patch series: now, drivers are organized
internally by their used bus, instead of by V4L2 and/or DVB API,
providing a cleaner driver location for hybrid drivers that
implement both APIs, and allowing to cleanup the Kconfig items and
make them more intuitive for the end user;
- Media Kernel developers are typically very lazy with their duties
of keeping the MAINTAINERS entries for their drivers updated. As
now the tree is more organized, we're doing an effort to add/update
those entries for the drivers that aren't currently orphan;
- Several DVB USB drivers got moved to a new DVB USB v2 core; the new
core fixes several bugs (as the existing one that got bitroted).
Now, suspend/resume finally started to work fine (at least with
some devices - we should expect more work with regards to it);
- added multistream support for DVB-T2, and unified the API for
DVB-S2 and ISDB-S. Backward binary support is preserved;
- as usual, a few new drivers, some V4L2 core improvements and lots
of drivers improvements and fixes.
There are some points to notice on this series:
1) you should expect a trivial merge conflict on your tree, with the
removal of Documentation/feature-removal-schedule.txt: this series
would be adding two additional entries there. I opted to not
rebase it due to this recent change;
2) With regards to the PCTV 520e udev-related breakage, I opted to
fix it in a way that the patches can be backported to 3.5 even
without your firmware fix patch. This way, Greg doesn't need to
rush backporting your patch (as there are still the firmware cache
and firmware path customization issues to be addressed there).
I'll send later a patch (likely after the end of the merge window)
reverting the rest of the DRX-K async firmware request, fully
restoring its original behaviour to allow media drivers to
initialize everything serialized as before for 3.7 and upper.
3) I'm planning to work on this weekend to test the DMABUF patches
for V4L2. The patches are on my queue for several Kernel cycles,
but, up to now, there is/was no way to test the series locally.
I have some concerns about this particular changeset with regards
to security issues, and with regards to the replacement of the old
VIDIOC_OVERLAY ioctl's that is broken on modern systems, due to
GPU drivers change. The Overlay API allows direct PCI2PCI
transfers from a media capture card into the GPU framebuffer, but
its API is crappy. Also, the only existing X11 driver that
implements it requires a XV extension that is not available
anymore on modern drivers. The DMABUF can do the same thing, but
with it is promising to be a properly-designed API. If I can
successfully test this series and be happy with it, I should be
asking you to pull them next week."
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (717 commits)
em28xx: regression fix: use DRX-K sync firmware requests on em28xx
drxk: allow loading firmware synchrousnously
em28xx: Make all em28xx extensions to be initialized asynchronously
[media] tda18271: properly report read errors in tda18271_get_id
[media] tda18271: delay IR & RF calibration until init() if delay_cal is set
[media] MAINTAINERS: add Michael Krufky as tda827x maintainer
[media] MAINTAINERS: add Michael Krufky as tda8290 maintainer
[media] MAINTAINERS: add Michael Krufky as cxusb maintainer
[media] MAINTAINERS: add Michael Krufky as lg2160 maintainer
[media] MAINTAINERS: add Michael Krufky as lgdt3305 maintainer
[media] MAINTAINERS: add Michael Krufky as mxl111sf maintainer
[media] MAINTAINERS: add Michael Krufky as mxl5007t maintainer
[media] MAINTAINERS: add Michael Krufky as tda18271 maintainer
[media] s5p-tv: Report only multi-plane capabilities in vidioc_querycap
[media] s5p-mfc: Fix misplaced return statement in s5p_mfc_suspend()
[media] exynos-gsc: Add missing static storage class specifiers
[media] exynos-gsc: Remove <linux/version.h> header file inclusion
[media] s5p-fimc: Fix incorrect condition in fimc_lite_reqbufs()
[media] s5p-tv: Fix potential NULL pointer dereference error
[media] s5k6aa: Fix possible NULL pointer dereference
...
Diffstat (limited to 'drivers/media/platform/soc_camera')
-rw-r--r-- | drivers/media/platform/soc_camera/Kconfig | 87 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/Makefile | 14 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/atmel-isi.c | 1099 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/mx1_camera.c | 889 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/mx2_camera.c | 1863 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/mx3_camera.c | 1290 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/omap1_camera.c | 1723 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/pxa_camera.c | 1852 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 2331 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/sh_mobile_csi2.c | 398 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/soc_camera.c | 1605 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/soc_camera_platform.c | 206 | ||||
-rw-r--r-- | drivers/media/platform/soc_camera/soc_mediabus.c | 493 |
13 files changed, 13850 insertions, 0 deletions
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig new file mode 100644 index 000000000000..9afe1e7bde74 --- /dev/null +++ b/drivers/media/platform/soc_camera/Kconfig | |||
@@ -0,0 +1,87 @@ | |||
1 | config SOC_CAMERA | ||
2 | tristate "SoC camera support" | ||
3 | depends on VIDEO_V4L2 && HAS_DMA && I2C | ||
4 | select VIDEOBUF_GEN | ||
5 | select VIDEOBUF2_CORE | ||
6 | help | ||
7 | SoC Camera is a common API to several cameras, not connecting | ||
8 | over a bus like PCI or USB. For example some i2c camera connected | ||
9 | directly to the data bus of an SoC. | ||
10 | |||
11 | config SOC_CAMERA_PLATFORM | ||
12 | tristate "platform camera support" | ||
13 | depends on SOC_CAMERA | ||
14 | help | ||
15 | This is a generic SoC camera platform driver, useful for testing | ||
16 | |||
17 | config MX1_VIDEO | ||
18 | bool | ||
19 | |||
20 | config VIDEO_MX1 | ||
21 | tristate "i.MX1/i.MXL CMOS Sensor Interface driver" | ||
22 | depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA | ||
23 | select FIQ | ||
24 | select VIDEOBUF_DMA_CONTIG | ||
25 | select MX1_VIDEO | ||
26 | ---help--- | ||
27 | This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface | ||
28 | |||
29 | config MX3_VIDEO | ||
30 | bool | ||
31 | |||
32 | config VIDEO_MX3 | ||
33 | tristate "i.MX3x Camera Sensor Interface driver" | ||
34 | depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA | ||
35 | select VIDEOBUF2_DMA_CONTIG | ||
36 | select MX3_VIDEO | ||
37 | ---help--- | ||
38 | This is a v4l2 driver for the i.MX3x Camera Sensor Interface | ||
39 | |||
40 | config VIDEO_PXA27x | ||
41 | tristate "PXA27x Quick Capture Interface driver" | ||
42 | depends on VIDEO_DEV && PXA27x && SOC_CAMERA | ||
43 | select VIDEOBUF_DMA_SG | ||
44 | ---help--- | ||
45 | This is a v4l2 driver for the PXA27x Quick Capture Interface | ||
46 | |||
47 | config VIDEO_SH_MOBILE_CSI2 | ||
48 | tristate "SuperH Mobile MIPI CSI-2 Interface driver" | ||
49 | depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK | ||
50 | ---help--- | ||
51 | This is a v4l2 driver for the SuperH MIPI CSI-2 Interface | ||
52 | |||
53 | config VIDEO_SH_MOBILE_CEU | ||
54 | tristate "SuperH Mobile CEU Interface driver" | ||
55 | depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK | ||
56 | select VIDEOBUF2_DMA_CONTIG | ||
57 | ---help--- | ||
58 | This is a v4l2 driver for the SuperH Mobile CEU Interface | ||
59 | |||
60 | config VIDEO_OMAP1 | ||
61 | tristate "OMAP1 Camera Interface driver" | ||
62 | depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA | ||
63 | select VIDEOBUF_DMA_CONTIG | ||
64 | select VIDEOBUF_DMA_SG | ||
65 | ---help--- | ||
66 | This is a v4l2 driver for the TI OMAP1 camera interface | ||
67 | |||
68 | config VIDEO_MX2_HOSTSUPPORT | ||
69 | bool | ||
70 | |||
71 | config VIDEO_MX2 | ||
72 | tristate "i.MX27/i.MX25 Camera Sensor Interface driver" | ||
73 | depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || (ARCH_MX25 && BROKEN)) | ||
74 | select VIDEOBUF2_DMA_CONTIG | ||
75 | select VIDEO_MX2_HOSTSUPPORT | ||
76 | ---help--- | ||
77 | This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor | ||
78 | Interface | ||
79 | |||
80 | config VIDEO_ATMEL_ISI | ||
81 | tristate "ATMEL Image Sensor Interface (ISI) support" | ||
82 | depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91 | ||
83 | select VIDEOBUF2_DMA_CONTIG | ||
84 | ---help--- | ||
85 | This module makes the ATMEL Image Sensor Interface available | ||
86 | as a v4l2 device. | ||
87 | |||
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile new file mode 100644 index 000000000000..136b7f8ff10d --- /dev/null +++ b/drivers/media/platform/soc_camera/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o | ||
2 | obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o | ||
3 | |||
4 | # soc-camera host drivers have to be linked after camera drivers | ||
5 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | ||
6 | obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o | ||
7 | obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o | ||
8 | obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o | ||
9 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o | ||
10 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | ||
11 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | ||
12 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o | ||
13 | |||
14 | ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera | ||
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c new file mode 100644 index 000000000000..6274a91c25c7 --- /dev/null +++ b/drivers/media/platform/soc_camera/atmel-isi.c | |||
@@ -0,0 +1,1099 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Atmel Corporation | ||
3 | * Josh Wu, <josh.wu@atmel.com> | ||
4 | * | ||
5 | * Based on previous work by Lars Haring, <lars.haring@atmel.com> | ||
6 | * and Sedji Gaouaou | ||
7 | * Based on the bttv driver for Bt848 with respective copyright holders | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <media/atmel-isi.h> | ||
26 | #include <media/soc_camera.h> | ||
27 | #include <media/soc_mediabus.h> | ||
28 | #include <media/videobuf2-dma-contig.h> | ||
29 | |||
30 | #define MAX_BUFFER_NUM 32 | ||
31 | #define MAX_SUPPORT_WIDTH 2048 | ||
32 | #define MAX_SUPPORT_HEIGHT 2048 | ||
33 | #define VID_LIMIT_BYTES (16 * 1024 * 1024) | ||
34 | #define MIN_FRAME_RATE 15 | ||
35 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) | ||
36 | |||
37 | /* ISI states */ | ||
38 | enum { | ||
39 | ISI_STATE_IDLE = 0, | ||
40 | ISI_STATE_READY, | ||
41 | ISI_STATE_WAIT_SOF, | ||
42 | }; | ||
43 | |||
44 | /* Frame buffer descriptor */ | ||
45 | struct fbd { | ||
46 | /* Physical address of the frame buffer */ | ||
47 | u32 fb_address; | ||
48 | /* DMA Control Register(only in HISI2) */ | ||
49 | u32 dma_ctrl; | ||
50 | /* Physical address of the next fbd */ | ||
51 | u32 next_fbd_address; | ||
52 | }; | ||
53 | |||
54 | static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) | ||
55 | { | ||
56 | fb_desc->dma_ctrl = ctrl; | ||
57 | } | ||
58 | |||
59 | struct isi_dma_desc { | ||
60 | struct list_head list; | ||
61 | struct fbd *p_fbd; | ||
62 | u32 fbd_phys; | ||
63 | }; | ||
64 | |||
65 | /* Frame buffer data */ | ||
66 | struct frame_buffer { | ||
67 | struct vb2_buffer vb; | ||
68 | struct isi_dma_desc *p_dma_desc; | ||
69 | struct list_head list; | ||
70 | }; | ||
71 | |||
72 | struct atmel_isi { | ||
73 | /* Protects the access of variables shared with the ISR */ | ||
74 | spinlock_t lock; | ||
75 | void __iomem *regs; | ||
76 | |||
77 | int sequence; | ||
78 | /* State of the ISI module in capturing mode */ | ||
79 | int state; | ||
80 | |||
81 | /* Wait queue for waiting for SOF */ | ||
82 | wait_queue_head_t vsync_wq; | ||
83 | |||
84 | struct vb2_alloc_ctx *alloc_ctx; | ||
85 | |||
86 | /* Allocate descriptors for dma buffer use */ | ||
87 | struct fbd *p_fb_descriptors; | ||
88 | u32 fb_descriptors_phys; | ||
89 | struct list_head dma_desc_head; | ||
90 | struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; | ||
91 | |||
92 | struct completion complete; | ||
93 | /* ISI peripherial clock */ | ||
94 | struct clk *pclk; | ||
95 | /* ISI_MCK, feed to camera sensor to generate pixel clock */ | ||
96 | struct clk *mck; | ||
97 | unsigned int irq; | ||
98 | |||
99 | struct isi_platform_data *pdata; | ||
100 | u16 width_flags; /* max 12 bits */ | ||
101 | |||
102 | struct list_head video_buffer_list; | ||
103 | struct frame_buffer *active; | ||
104 | |||
105 | struct soc_camera_device *icd; | ||
106 | struct soc_camera_host soc_host; | ||
107 | }; | ||
108 | |||
109 | static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) | ||
110 | { | ||
111 | writel(val, isi->regs + reg); | ||
112 | } | ||
113 | static u32 isi_readl(struct atmel_isi *isi, u32 reg) | ||
114 | { | ||
115 | return readl(isi->regs + reg); | ||
116 | } | ||
117 | |||
118 | static int configure_geometry(struct atmel_isi *isi, u32 width, | ||
119 | u32 height, enum v4l2_mbus_pixelcode code) | ||
120 | { | ||
121 | u32 cfg2, cr; | ||
122 | |||
123 | switch (code) { | ||
124 | /* YUV, including grey */ | ||
125 | case V4L2_MBUS_FMT_Y8_1X8: | ||
126 | cr = ISI_CFG2_GRAYSCALE; | ||
127 | break; | ||
128 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
129 | cr = ISI_CFG2_YCC_SWAP_MODE_3; | ||
130 | break; | ||
131 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
132 | cr = ISI_CFG2_YCC_SWAP_MODE_2; | ||
133 | break; | ||
134 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
135 | cr = ISI_CFG2_YCC_SWAP_MODE_1; | ||
136 | break; | ||
137 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
138 | cr = ISI_CFG2_YCC_SWAP_DEFAULT; | ||
139 | break; | ||
140 | /* RGB, TODO */ | ||
141 | default: | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
146 | |||
147 | cfg2 = isi_readl(isi, ISI_CFG2); | ||
148 | cfg2 |= cr; | ||
149 | /* Set width */ | ||
150 | cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); | ||
151 | cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & | ||
152 | ISI_CFG2_IM_HSIZE_MASK; | ||
153 | /* Set height */ | ||
154 | cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK); | ||
155 | cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) | ||
156 | & ISI_CFG2_IM_VSIZE_MASK; | ||
157 | isi_writel(isi, ISI_CFG2, cfg2); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) | ||
163 | { | ||
164 | if (isi->active) { | ||
165 | struct vb2_buffer *vb = &isi->active->vb; | ||
166 | struct frame_buffer *buf = isi->active; | ||
167 | |||
168 | list_del_init(&buf->list); | ||
169 | do_gettimeofday(&vb->v4l2_buf.timestamp); | ||
170 | vb->v4l2_buf.sequence = isi->sequence++; | ||
171 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
172 | } | ||
173 | |||
174 | if (list_empty(&isi->video_buffer_list)) { | ||
175 | isi->active = NULL; | ||
176 | } else { | ||
177 | /* start next dma frame. */ | ||
178 | isi->active = list_entry(isi->video_buffer_list.next, | ||
179 | struct frame_buffer, list); | ||
180 | isi_writel(isi, ISI_DMA_C_DSCR, | ||
181 | isi->active->p_dma_desc->fbd_phys); | ||
182 | isi_writel(isi, ISI_DMA_C_CTRL, | ||
183 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
184 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
185 | } | ||
186 | return IRQ_HANDLED; | ||
187 | } | ||
188 | |||
189 | /* ISI interrupt service routine */ | ||
190 | static irqreturn_t isi_interrupt(int irq, void *dev_id) | ||
191 | { | ||
192 | struct atmel_isi *isi = dev_id; | ||
193 | u32 status, mask, pending; | ||
194 | irqreturn_t ret = IRQ_NONE; | ||
195 | |||
196 | spin_lock(&isi->lock); | ||
197 | |||
198 | status = isi_readl(isi, ISI_STATUS); | ||
199 | mask = isi_readl(isi, ISI_INTMASK); | ||
200 | pending = status & mask; | ||
201 | |||
202 | if (pending & ISI_CTRL_SRST) { | ||
203 | complete(&isi->complete); | ||
204 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST); | ||
205 | ret = IRQ_HANDLED; | ||
206 | } else if (pending & ISI_CTRL_DIS) { | ||
207 | complete(&isi->complete); | ||
208 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); | ||
209 | ret = IRQ_HANDLED; | ||
210 | } else { | ||
211 | if ((pending & ISI_SR_VSYNC) && | ||
212 | (isi->state == ISI_STATE_IDLE)) { | ||
213 | isi->state = ISI_STATE_READY; | ||
214 | wake_up_interruptible(&isi->vsync_wq); | ||
215 | ret = IRQ_HANDLED; | ||
216 | } | ||
217 | if (likely(pending & ISI_SR_CXFR_DONE)) | ||
218 | ret = atmel_isi_handle_streaming(isi); | ||
219 | } | ||
220 | |||
221 | spin_unlock(&isi->lock); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | #define WAIT_ISI_RESET 1 | ||
226 | #define WAIT_ISI_DISABLE 0 | ||
227 | static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) | ||
228 | { | ||
229 | unsigned long timeout; | ||
230 | /* | ||
231 | * The reset or disable will only succeed if we have a | ||
232 | * pixel clock from the camera. | ||
233 | */ | ||
234 | init_completion(&isi->complete); | ||
235 | |||
236 | if (wait_reset) { | ||
237 | isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); | ||
238 | isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); | ||
239 | } else { | ||
240 | isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); | ||
241 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
242 | } | ||
243 | |||
244 | timeout = wait_for_completion_timeout(&isi->complete, | ||
245 | msecs_to_jiffies(100)); | ||
246 | if (timeout == 0) | ||
247 | return -ETIMEDOUT; | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /* ------------------------------------------------------------------ | ||
253 | Videobuf operations | ||
254 | ------------------------------------------------------------------*/ | ||
255 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | ||
256 | unsigned int *nbuffers, unsigned int *nplanes, | ||
257 | unsigned int sizes[], void *alloc_ctxs[]) | ||
258 | { | ||
259 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
260 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
261 | struct atmel_isi *isi = ici->priv; | ||
262 | unsigned long size; | ||
263 | int ret; | ||
264 | |||
265 | /* Reset ISI */ | ||
266 | ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); | ||
267 | if (ret < 0) { | ||
268 | dev_err(icd->parent, "Reset ISI timed out\n"); | ||
269 | return ret; | ||
270 | } | ||
271 | /* Disable all interrupts */ | ||
272 | isi_writel(isi, ISI_INTDIS, ~0UL); | ||
273 | |||
274 | size = icd->sizeimage; | ||
275 | |||
276 | if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM) | ||
277 | *nbuffers = MAX_BUFFER_NUM; | ||
278 | |||
279 | if (size * *nbuffers > VID_LIMIT_BYTES) | ||
280 | *nbuffers = VID_LIMIT_BYTES / size; | ||
281 | |||
282 | *nplanes = 1; | ||
283 | sizes[0] = size; | ||
284 | alloc_ctxs[0] = isi->alloc_ctx; | ||
285 | |||
286 | isi->sequence = 0; | ||
287 | isi->active = NULL; | ||
288 | |||
289 | dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__, | ||
290 | *nbuffers, size); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int buffer_init(struct vb2_buffer *vb) | ||
296 | { | ||
297 | struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); | ||
298 | |||
299 | buf->p_dma_desc = NULL; | ||
300 | INIT_LIST_HEAD(&buf->list); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int buffer_prepare(struct vb2_buffer *vb) | ||
306 | { | ||
307 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
308 | struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); | ||
309 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
310 | struct atmel_isi *isi = ici->priv; | ||
311 | unsigned long size; | ||
312 | struct isi_dma_desc *desc; | ||
313 | |||
314 | size = icd->sizeimage; | ||
315 | |||
316 | if (vb2_plane_size(vb, 0) < size) { | ||
317 | dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n", | ||
318 | __func__, vb2_plane_size(vb, 0), size); | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | |||
322 | vb2_set_plane_payload(&buf->vb, 0, size); | ||
323 | |||
324 | if (!buf->p_dma_desc) { | ||
325 | if (list_empty(&isi->dma_desc_head)) { | ||
326 | dev_err(icd->parent, "Not enough dma descriptors.\n"); | ||
327 | return -EINVAL; | ||
328 | } else { | ||
329 | /* Get an available descriptor */ | ||
330 | desc = list_entry(isi->dma_desc_head.next, | ||
331 | struct isi_dma_desc, list); | ||
332 | /* Delete the descriptor since now it is used */ | ||
333 | list_del_init(&desc->list); | ||
334 | |||
335 | /* Initialize the dma descriptor */ | ||
336 | desc->p_fbd->fb_address = | ||
337 | vb2_dma_contig_plane_dma_addr(vb, 0); | ||
338 | desc->p_fbd->next_fbd_address = 0; | ||
339 | set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); | ||
340 | |||
341 | buf->p_dma_desc = desc; | ||
342 | } | ||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void buffer_cleanup(struct vb2_buffer *vb) | ||
348 | { | ||
349 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
350 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
351 | struct atmel_isi *isi = ici->priv; | ||
352 | struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); | ||
353 | |||
354 | /* This descriptor is available now and we add to head list */ | ||
355 | if (buf->p_dma_desc) | ||
356 | list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); | ||
357 | } | ||
358 | |||
359 | static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) | ||
360 | { | ||
361 | u32 ctrl, cfg1; | ||
362 | |||
363 | cfg1 = isi_readl(isi, ISI_CFG1); | ||
364 | /* Enable irq: cxfr for the codec path, pxfr for the preview path */ | ||
365 | isi_writel(isi, ISI_INTEN, | ||
366 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
367 | |||
368 | /* Check if already in a frame */ | ||
369 | if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { | ||
370 | dev_err(isi->icd->parent, "Already in frame handling.\n"); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys); | ||
375 | isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
376 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
377 | |||
378 | /* Enable linked list */ | ||
379 | cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; | ||
380 | |||
381 | /* Enable codec path and ISI */ | ||
382 | ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; | ||
383 | isi_writel(isi, ISI_CTRL, ctrl); | ||
384 | isi_writel(isi, ISI_CFG1, cfg1); | ||
385 | } | ||
386 | |||
387 | static void buffer_queue(struct vb2_buffer *vb) | ||
388 | { | ||
389 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
390 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
391 | struct atmel_isi *isi = ici->priv; | ||
392 | struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb); | ||
393 | unsigned long flags = 0; | ||
394 | |||
395 | spin_lock_irqsave(&isi->lock, flags); | ||
396 | list_add_tail(&buf->list, &isi->video_buffer_list); | ||
397 | |||
398 | if (isi->active == NULL) { | ||
399 | isi->active = buf; | ||
400 | if (vb2_is_streaming(vb->vb2_queue)) | ||
401 | start_dma(isi, buf); | ||
402 | } | ||
403 | spin_unlock_irqrestore(&isi->lock, flags); | ||
404 | } | ||
405 | |||
406 | static int start_streaming(struct vb2_queue *vq, unsigned int count) | ||
407 | { | ||
408 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
409 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
410 | struct atmel_isi *isi = ici->priv; | ||
411 | |||
412 | u32 sr = 0; | ||
413 | int ret; | ||
414 | |||
415 | spin_lock_irq(&isi->lock); | ||
416 | isi->state = ISI_STATE_IDLE; | ||
417 | /* Clear any pending SOF interrupt */ | ||
418 | sr = isi_readl(isi, ISI_STATUS); | ||
419 | /* Enable VSYNC interrupt for SOF */ | ||
420 | isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC); | ||
421 | isi_writel(isi, ISI_CTRL, ISI_CTRL_EN); | ||
422 | spin_unlock_irq(&isi->lock); | ||
423 | |||
424 | dev_dbg(icd->parent, "Waiting for SOF\n"); | ||
425 | ret = wait_event_interruptible(isi->vsync_wq, | ||
426 | isi->state != ISI_STATE_IDLE); | ||
427 | if (ret) | ||
428 | goto err; | ||
429 | |||
430 | if (isi->state != ISI_STATE_READY) { | ||
431 | ret = -EIO; | ||
432 | goto err; | ||
433 | } | ||
434 | |||
435 | spin_lock_irq(&isi->lock); | ||
436 | isi->state = ISI_STATE_WAIT_SOF; | ||
437 | isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); | ||
438 | if (count) | ||
439 | start_dma(isi, isi->active); | ||
440 | spin_unlock_irq(&isi->lock); | ||
441 | |||
442 | return 0; | ||
443 | err: | ||
444 | isi->active = NULL; | ||
445 | isi->sequence = 0; | ||
446 | INIT_LIST_HEAD(&isi->video_buffer_list); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | /* abort streaming and wait for last buffer */ | ||
451 | static int stop_streaming(struct vb2_queue *vq) | ||
452 | { | ||
453 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
454 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
455 | struct atmel_isi *isi = ici->priv; | ||
456 | struct frame_buffer *buf, *node; | ||
457 | int ret = 0; | ||
458 | unsigned long timeout; | ||
459 | |||
460 | spin_lock_irq(&isi->lock); | ||
461 | isi->active = NULL; | ||
462 | /* Release all active buffers */ | ||
463 | list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { | ||
464 | list_del_init(&buf->list); | ||
465 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
466 | } | ||
467 | spin_unlock_irq(&isi->lock); | ||
468 | |||
469 | timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; | ||
470 | /* Wait until the end of the current frame. */ | ||
471 | while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && | ||
472 | time_before(jiffies, timeout)) | ||
473 | msleep(1); | ||
474 | |||
475 | if (time_after(jiffies, timeout)) { | ||
476 | dev_err(icd->parent, | ||
477 | "Timeout waiting for finishing codec request\n"); | ||
478 | return -ETIMEDOUT; | ||
479 | } | ||
480 | |||
481 | /* Disable interrupts */ | ||
482 | isi_writel(isi, ISI_INTDIS, | ||
483 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
484 | |||
485 | /* Disable ISI and wait for it is done */ | ||
486 | ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); | ||
487 | if (ret < 0) | ||
488 | dev_err(icd->parent, "Disable ISI timed out\n"); | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | static struct vb2_ops isi_video_qops = { | ||
494 | .queue_setup = queue_setup, | ||
495 | .buf_init = buffer_init, | ||
496 | .buf_prepare = buffer_prepare, | ||
497 | .buf_cleanup = buffer_cleanup, | ||
498 | .buf_queue = buffer_queue, | ||
499 | .start_streaming = start_streaming, | ||
500 | .stop_streaming = stop_streaming, | ||
501 | .wait_prepare = soc_camera_unlock, | ||
502 | .wait_finish = soc_camera_lock, | ||
503 | }; | ||
504 | |||
505 | /* ------------------------------------------------------------------ | ||
506 | SOC camera operations for the device | ||
507 | ------------------------------------------------------------------*/ | ||
508 | static int isi_camera_init_videobuf(struct vb2_queue *q, | ||
509 | struct soc_camera_device *icd) | ||
510 | { | ||
511 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
512 | q->io_modes = VB2_MMAP; | ||
513 | q->drv_priv = icd; | ||
514 | q->buf_struct_size = sizeof(struct frame_buffer); | ||
515 | q->ops = &isi_video_qops; | ||
516 | q->mem_ops = &vb2_dma_contig_memops; | ||
517 | |||
518 | return vb2_queue_init(q); | ||
519 | } | ||
520 | |||
521 | static int isi_camera_set_fmt(struct soc_camera_device *icd, | ||
522 | struct v4l2_format *f) | ||
523 | { | ||
524 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
525 | struct atmel_isi *isi = ici->priv; | ||
526 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
527 | const struct soc_camera_format_xlate *xlate; | ||
528 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
529 | struct v4l2_mbus_framefmt mf; | ||
530 | int ret; | ||
531 | |||
532 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
533 | if (!xlate) { | ||
534 | dev_warn(icd->parent, "Format %x not found\n", | ||
535 | pix->pixelformat); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | dev_dbg(icd->parent, "Plan to set format %dx%d\n", | ||
540 | pix->width, pix->height); | ||
541 | |||
542 | mf.width = pix->width; | ||
543 | mf.height = pix->height; | ||
544 | mf.field = pix->field; | ||
545 | mf.colorspace = pix->colorspace; | ||
546 | mf.code = xlate->code; | ||
547 | |||
548 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
549 | if (ret < 0) | ||
550 | return ret; | ||
551 | |||
552 | if (mf.code != xlate->code) | ||
553 | return -EINVAL; | ||
554 | |||
555 | ret = configure_geometry(isi, pix->width, pix->height, xlate->code); | ||
556 | if (ret < 0) | ||
557 | return ret; | ||
558 | |||
559 | pix->width = mf.width; | ||
560 | pix->height = mf.height; | ||
561 | pix->field = mf.field; | ||
562 | pix->colorspace = mf.colorspace; | ||
563 | icd->current_fmt = xlate; | ||
564 | |||
565 | dev_dbg(icd->parent, "Finally set format %dx%d\n", | ||
566 | pix->width, pix->height); | ||
567 | |||
568 | return ret; | ||
569 | } | ||
570 | |||
571 | static int isi_camera_try_fmt(struct soc_camera_device *icd, | ||
572 | struct v4l2_format *f) | ||
573 | { | ||
574 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
575 | const struct soc_camera_format_xlate *xlate; | ||
576 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
577 | struct v4l2_mbus_framefmt mf; | ||
578 | u32 pixfmt = pix->pixelformat; | ||
579 | int ret; | ||
580 | |||
581 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
582 | if (pixfmt && !xlate) { | ||
583 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
584 | return -EINVAL; | ||
585 | } | ||
586 | |||
587 | /* limit to Atmel ISI hardware capabilities */ | ||
588 | if (pix->height > MAX_SUPPORT_HEIGHT) | ||
589 | pix->height = MAX_SUPPORT_HEIGHT; | ||
590 | if (pix->width > MAX_SUPPORT_WIDTH) | ||
591 | pix->width = MAX_SUPPORT_WIDTH; | ||
592 | |||
593 | /* limit to sensor capabilities */ | ||
594 | mf.width = pix->width; | ||
595 | mf.height = pix->height; | ||
596 | mf.field = pix->field; | ||
597 | mf.colorspace = pix->colorspace; | ||
598 | mf.code = xlate->code; | ||
599 | |||
600 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
601 | if (ret < 0) | ||
602 | return ret; | ||
603 | |||
604 | pix->width = mf.width; | ||
605 | pix->height = mf.height; | ||
606 | pix->colorspace = mf.colorspace; | ||
607 | |||
608 | switch (mf.field) { | ||
609 | case V4L2_FIELD_ANY: | ||
610 | pix->field = V4L2_FIELD_NONE; | ||
611 | break; | ||
612 | case V4L2_FIELD_NONE: | ||
613 | break; | ||
614 | default: | ||
615 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
616 | mf.field); | ||
617 | ret = -EINVAL; | ||
618 | } | ||
619 | |||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | static const struct soc_mbus_pixelfmt isi_camera_formats[] = { | ||
624 | { | ||
625 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
626 | .name = "Packed YUV422 16 bit", | ||
627 | .bits_per_sample = 8, | ||
628 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
629 | .order = SOC_MBUS_ORDER_LE, | ||
630 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
631 | }, | ||
632 | }; | ||
633 | |||
634 | /* This will be corrected as we get more formats */ | ||
635 | static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
636 | { | ||
637 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
638 | (fmt->bits_per_sample == 8 && | ||
639 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
640 | (fmt->bits_per_sample > 8 && | ||
641 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
642 | } | ||
643 | |||
644 | #define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \ | ||
645 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
646 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
647 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
648 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
649 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
650 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
651 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
652 | |||
653 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, | ||
654 | unsigned char buswidth) | ||
655 | { | ||
656 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
657 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
658 | struct atmel_isi *isi = ici->priv; | ||
659 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
660 | unsigned long common_flags; | ||
661 | int ret; | ||
662 | |||
663 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
664 | if (!ret) { | ||
665 | common_flags = soc_mbus_config_compatible(&cfg, | ||
666 | ISI_BUS_PARAM); | ||
667 | if (!common_flags) { | ||
668 | dev_warn(icd->parent, | ||
669 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
670 | cfg.flags, ISI_BUS_PARAM); | ||
671 | return -EINVAL; | ||
672 | } | ||
673 | } else if (ret != -ENOIOCTLCMD) { | ||
674 | return ret; | ||
675 | } | ||
676 | |||
677 | if ((1 << (buswidth - 1)) & isi->width_flags) | ||
678 | return 0; | ||
679 | return -EINVAL; | ||
680 | } | ||
681 | |||
682 | |||
683 | static int isi_camera_get_formats(struct soc_camera_device *icd, | ||
684 | unsigned int idx, | ||
685 | struct soc_camera_format_xlate *xlate) | ||
686 | { | ||
687 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
688 | int formats = 0, ret; | ||
689 | /* sensor format */ | ||
690 | enum v4l2_mbus_pixelcode code; | ||
691 | /* soc camera host format */ | ||
692 | const struct soc_mbus_pixelfmt *fmt; | ||
693 | |||
694 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
695 | if (ret < 0) | ||
696 | /* No more formats */ | ||
697 | return 0; | ||
698 | |||
699 | fmt = soc_mbus_get_fmtdesc(code); | ||
700 | if (!fmt) { | ||
701 | dev_err(icd->parent, | ||
702 | "Invalid format code #%u: %d\n", idx, code); | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | /* This also checks support for the requested bits-per-sample */ | ||
707 | ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
708 | if (ret < 0) { | ||
709 | dev_err(icd->parent, | ||
710 | "Fail to try the bus parameters.\n"); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | switch (code) { | ||
715 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
716 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
717 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
718 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
719 | formats++; | ||
720 | if (xlate) { | ||
721 | xlate->host_fmt = &isi_camera_formats[0]; | ||
722 | xlate->code = code; | ||
723 | xlate++; | ||
724 | dev_dbg(icd->parent, "Providing format %s using code %d\n", | ||
725 | isi_camera_formats[0].name, code); | ||
726 | } | ||
727 | break; | ||
728 | default: | ||
729 | if (!isi_camera_packing_supported(fmt)) | ||
730 | return 0; | ||
731 | if (xlate) | ||
732 | dev_dbg(icd->parent, | ||
733 | "Providing format %s in pass-through mode\n", | ||
734 | fmt->name); | ||
735 | } | ||
736 | |||
737 | /* Generic pass-through */ | ||
738 | formats++; | ||
739 | if (xlate) { | ||
740 | xlate->host_fmt = fmt; | ||
741 | xlate->code = code; | ||
742 | xlate++; | ||
743 | } | ||
744 | |||
745 | return formats; | ||
746 | } | ||
747 | |||
748 | /* Called with .video_lock held */ | ||
749 | static int isi_camera_add_device(struct soc_camera_device *icd) | ||
750 | { | ||
751 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
752 | struct atmel_isi *isi = ici->priv; | ||
753 | int ret; | ||
754 | |||
755 | if (isi->icd) | ||
756 | return -EBUSY; | ||
757 | |||
758 | ret = clk_enable(isi->pclk); | ||
759 | if (ret) | ||
760 | return ret; | ||
761 | |||
762 | ret = clk_enable(isi->mck); | ||
763 | if (ret) { | ||
764 | clk_disable(isi->pclk); | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | isi->icd = icd; | ||
769 | dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", | ||
770 | icd->devnum); | ||
771 | return 0; | ||
772 | } | ||
773 | /* Called with .video_lock held */ | ||
774 | static void isi_camera_remove_device(struct soc_camera_device *icd) | ||
775 | { | ||
776 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
777 | struct atmel_isi *isi = ici->priv; | ||
778 | |||
779 | BUG_ON(icd != isi->icd); | ||
780 | |||
781 | clk_disable(isi->mck); | ||
782 | clk_disable(isi->pclk); | ||
783 | isi->icd = NULL; | ||
784 | |||
785 | dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n", | ||
786 | icd->devnum); | ||
787 | } | ||
788 | |||
789 | static unsigned int isi_camera_poll(struct file *file, poll_table *pt) | ||
790 | { | ||
791 | struct soc_camera_device *icd = file->private_data; | ||
792 | |||
793 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
794 | } | ||
795 | |||
796 | static int isi_camera_querycap(struct soc_camera_host *ici, | ||
797 | struct v4l2_capability *cap) | ||
798 | { | ||
799 | strcpy(cap->driver, "atmel-isi"); | ||
800 | strcpy(cap->card, "Atmel Image Sensor Interface"); | ||
801 | cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | | ||
802 | V4L2_CAP_STREAMING); | ||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int isi_camera_set_bus_param(struct soc_camera_device *icd) | ||
807 | { | ||
808 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
809 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
810 | struct atmel_isi *isi = ici->priv; | ||
811 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
812 | unsigned long common_flags; | ||
813 | int ret; | ||
814 | u32 cfg1 = 0; | ||
815 | |||
816 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
817 | if (!ret) { | ||
818 | common_flags = soc_mbus_config_compatible(&cfg, | ||
819 | ISI_BUS_PARAM); | ||
820 | if (!common_flags) { | ||
821 | dev_warn(icd->parent, | ||
822 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
823 | cfg.flags, ISI_BUS_PARAM); | ||
824 | return -EINVAL; | ||
825 | } | ||
826 | } else if (ret != -ENOIOCTLCMD) { | ||
827 | return ret; | ||
828 | } else { | ||
829 | common_flags = ISI_BUS_PARAM; | ||
830 | } | ||
831 | dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n", | ||
832 | cfg.flags, ISI_BUS_PARAM, common_flags); | ||
833 | |||
834 | /* Make choises, based on platform preferences */ | ||
835 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
836 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
837 | if (isi->pdata->hsync_act_low) | ||
838 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
839 | else | ||
840 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
841 | } | ||
842 | |||
843 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
844 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
845 | if (isi->pdata->vsync_act_low) | ||
846 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
847 | else | ||
848 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
849 | } | ||
850 | |||
851 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
852 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
853 | if (isi->pdata->pclk_act_falling) | ||
854 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
855 | else | ||
856 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
857 | } | ||
858 | |||
859 | cfg.flags = common_flags; | ||
860 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
861 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
862 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
863 | common_flags, ret); | ||
864 | return ret; | ||
865 | } | ||
866 | |||
867 | /* set bus param for ISI */ | ||
868 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
869 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; | ||
870 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
871 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; | ||
872 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
873 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; | ||
874 | |||
875 | if (isi->pdata->has_emb_sync) | ||
876 | cfg1 |= ISI_CFG1_EMB_SYNC; | ||
877 | if (isi->pdata->full_mode) | ||
878 | cfg1 |= ISI_CFG1_FULL_MODE; | ||
879 | |||
880 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
881 | isi_writel(isi, ISI_CFG1, cfg1); | ||
882 | |||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | static struct soc_camera_host_ops isi_soc_camera_host_ops = { | ||
887 | .owner = THIS_MODULE, | ||
888 | .add = isi_camera_add_device, | ||
889 | .remove = isi_camera_remove_device, | ||
890 | .set_fmt = isi_camera_set_fmt, | ||
891 | .try_fmt = isi_camera_try_fmt, | ||
892 | .get_formats = isi_camera_get_formats, | ||
893 | .init_videobuf2 = isi_camera_init_videobuf, | ||
894 | .poll = isi_camera_poll, | ||
895 | .querycap = isi_camera_querycap, | ||
896 | .set_bus_param = isi_camera_set_bus_param, | ||
897 | }; | ||
898 | |||
899 | /* -----------------------------------------------------------------------*/ | ||
900 | static int __devexit atmel_isi_remove(struct platform_device *pdev) | ||
901 | { | ||
902 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
903 | struct atmel_isi *isi = container_of(soc_host, | ||
904 | struct atmel_isi, soc_host); | ||
905 | |||
906 | free_irq(isi->irq, isi); | ||
907 | soc_camera_host_unregister(soc_host); | ||
908 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); | ||
909 | dma_free_coherent(&pdev->dev, | ||
910 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
911 | isi->p_fb_descriptors, | ||
912 | isi->fb_descriptors_phys); | ||
913 | |||
914 | iounmap(isi->regs); | ||
915 | clk_unprepare(isi->mck); | ||
916 | clk_put(isi->mck); | ||
917 | clk_unprepare(isi->pclk); | ||
918 | clk_put(isi->pclk); | ||
919 | kfree(isi); | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static int __devinit atmel_isi_probe(struct platform_device *pdev) | ||
925 | { | ||
926 | unsigned int irq; | ||
927 | struct atmel_isi *isi; | ||
928 | struct clk *pclk; | ||
929 | struct resource *regs; | ||
930 | int ret, i; | ||
931 | struct device *dev = &pdev->dev; | ||
932 | struct soc_camera_host *soc_host; | ||
933 | struct isi_platform_data *pdata; | ||
934 | |||
935 | pdata = dev->platform_data; | ||
936 | if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { | ||
937 | dev_err(&pdev->dev, | ||
938 | "No config available for Atmel ISI\n"); | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | |||
942 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
943 | if (!regs) | ||
944 | return -ENXIO; | ||
945 | |||
946 | pclk = clk_get(&pdev->dev, "isi_clk"); | ||
947 | if (IS_ERR(pclk)) | ||
948 | return PTR_ERR(pclk); | ||
949 | |||
950 | ret = clk_prepare(pclk); | ||
951 | if (ret) | ||
952 | goto err_clk_prepare_pclk; | ||
953 | |||
954 | isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); | ||
955 | if (!isi) { | ||
956 | ret = -ENOMEM; | ||
957 | dev_err(&pdev->dev, "Can't allocate interface!\n"); | ||
958 | goto err_alloc_isi; | ||
959 | } | ||
960 | |||
961 | isi->pclk = pclk; | ||
962 | isi->pdata = pdata; | ||
963 | isi->active = NULL; | ||
964 | spin_lock_init(&isi->lock); | ||
965 | init_waitqueue_head(&isi->vsync_wq); | ||
966 | INIT_LIST_HEAD(&isi->video_buffer_list); | ||
967 | INIT_LIST_HEAD(&isi->dma_desc_head); | ||
968 | |||
969 | /* Get ISI_MCK, provided by programmable clock or external clock */ | ||
970 | isi->mck = clk_get(dev, "isi_mck"); | ||
971 | if (IS_ERR(isi->mck)) { | ||
972 | dev_err(dev, "Failed to get isi_mck\n"); | ||
973 | ret = PTR_ERR(isi->mck); | ||
974 | goto err_clk_get; | ||
975 | } | ||
976 | |||
977 | ret = clk_prepare(isi->mck); | ||
978 | if (ret) | ||
979 | goto err_clk_prepare_mck; | ||
980 | |||
981 | /* Set ISI_MCK's frequency, it should be faster than pixel clock */ | ||
982 | ret = clk_set_rate(isi->mck, pdata->mck_hz); | ||
983 | if (ret < 0) | ||
984 | goto err_set_mck_rate; | ||
985 | |||
986 | isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, | ||
987 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
988 | &isi->fb_descriptors_phys, | ||
989 | GFP_KERNEL); | ||
990 | if (!isi->p_fb_descriptors) { | ||
991 | ret = -ENOMEM; | ||
992 | dev_err(&pdev->dev, "Can't allocate descriptors!\n"); | ||
993 | goto err_alloc_descriptors; | ||
994 | } | ||
995 | |||
996 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | ||
997 | isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; | ||
998 | isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + | ||
999 | i * sizeof(struct fbd); | ||
1000 | list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); | ||
1001 | } | ||
1002 | |||
1003 | isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1004 | if (IS_ERR(isi->alloc_ctx)) { | ||
1005 | ret = PTR_ERR(isi->alloc_ctx); | ||
1006 | goto err_alloc_ctx; | ||
1007 | } | ||
1008 | |||
1009 | isi->regs = ioremap(regs->start, resource_size(regs)); | ||
1010 | if (!isi->regs) { | ||
1011 | ret = -ENOMEM; | ||
1012 | goto err_ioremap; | ||
1013 | } | ||
1014 | |||
1015 | if (pdata->data_width_flags & ISI_DATAWIDTH_8) | ||
1016 | isi->width_flags = 1 << 7; | ||
1017 | if (pdata->data_width_flags & ISI_DATAWIDTH_10) | ||
1018 | isi->width_flags |= 1 << 9; | ||
1019 | |||
1020 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
1021 | |||
1022 | irq = platform_get_irq(pdev, 0); | ||
1023 | if (irq < 0) { | ||
1024 | ret = irq; | ||
1025 | goto err_req_irq; | ||
1026 | } | ||
1027 | |||
1028 | ret = request_irq(irq, isi_interrupt, 0, "isi", isi); | ||
1029 | if (ret) { | ||
1030 | dev_err(&pdev->dev, "Unable to request irq %d\n", irq); | ||
1031 | goto err_req_irq; | ||
1032 | } | ||
1033 | isi->irq = irq; | ||
1034 | |||
1035 | soc_host = &isi->soc_host; | ||
1036 | soc_host->drv_name = "isi-camera"; | ||
1037 | soc_host->ops = &isi_soc_camera_host_ops; | ||
1038 | soc_host->priv = isi; | ||
1039 | soc_host->v4l2_dev.dev = &pdev->dev; | ||
1040 | soc_host->nr = pdev->id; | ||
1041 | |||
1042 | ret = soc_camera_host_register(soc_host); | ||
1043 | if (ret) { | ||
1044 | dev_err(&pdev->dev, "Unable to register soc camera host\n"); | ||
1045 | goto err_register_soc_camera_host; | ||
1046 | } | ||
1047 | return 0; | ||
1048 | |||
1049 | err_register_soc_camera_host: | ||
1050 | free_irq(isi->irq, isi); | ||
1051 | err_req_irq: | ||
1052 | iounmap(isi->regs); | ||
1053 | err_ioremap: | ||
1054 | vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); | ||
1055 | err_alloc_ctx: | ||
1056 | dma_free_coherent(&pdev->dev, | ||
1057 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
1058 | isi->p_fb_descriptors, | ||
1059 | isi->fb_descriptors_phys); | ||
1060 | err_alloc_descriptors: | ||
1061 | err_set_mck_rate: | ||
1062 | clk_unprepare(isi->mck); | ||
1063 | err_clk_prepare_mck: | ||
1064 | clk_put(isi->mck); | ||
1065 | err_clk_get: | ||
1066 | kfree(isi); | ||
1067 | err_alloc_isi: | ||
1068 | clk_unprepare(pclk); | ||
1069 | err_clk_prepare_pclk: | ||
1070 | clk_put(pclk); | ||
1071 | |||
1072 | return ret; | ||
1073 | } | ||
1074 | |||
1075 | static struct platform_driver atmel_isi_driver = { | ||
1076 | .probe = atmel_isi_probe, | ||
1077 | .remove = __devexit_p(atmel_isi_remove), | ||
1078 | .driver = { | ||
1079 | .name = "atmel_isi", | ||
1080 | .owner = THIS_MODULE, | ||
1081 | }, | ||
1082 | }; | ||
1083 | |||
1084 | static int __init atmel_isi_init_module(void) | ||
1085 | { | ||
1086 | return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe); | ||
1087 | } | ||
1088 | |||
1089 | static void __exit atmel_isi_exit(void) | ||
1090 | { | ||
1091 | platform_driver_unregister(&atmel_isi_driver); | ||
1092 | } | ||
1093 | module_init(atmel_isi_init_module); | ||
1094 | module_exit(atmel_isi_exit); | ||
1095 | |||
1096 | MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>"); | ||
1097 | MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); | ||
1098 | MODULE_LICENSE("GPL"); | ||
1099 | MODULE_SUPPORTED_DEVICE("video"); | ||
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c new file mode 100644 index 000000000000..bbe70991d30b --- /dev/null +++ b/drivers/media/platform/soc_camera/mx1_camera.c | |||
@@ -0,0 +1,889 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for i.MXL/i.MXL camera (CSI) host | ||
3 | * | ||
4 | * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
5 | * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com> | ||
6 | * | ||
7 | * Based on PXA SoC camera driver | ||
8 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | ||
9 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/time.h> | ||
34 | #include <linux/videodev2.h> | ||
35 | |||
36 | #include <media/soc_camera.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | #include <media/v4l2-dev.h> | ||
39 | #include <media/videobuf-dma-contig.h> | ||
40 | #include <media/soc_mediabus.h> | ||
41 | |||
42 | #include <asm/dma.h> | ||
43 | #include <asm/fiq.h> | ||
44 | #include <mach/dma-mx1-mx2.h> | ||
45 | #include <mach/hardware.h> | ||
46 | #include <mach/irqs.h> | ||
47 | #include <linux/platform_data/camera-mx1.h> | ||
48 | |||
49 | /* | ||
50 | * CSI registers | ||
51 | */ | ||
52 | #define CSICR1 0x00 /* CSI Control Register 1 */ | ||
53 | #define CSISR 0x08 /* CSI Status Register */ | ||
54 | #define CSIRXR 0x10 /* CSI RxFIFO Register */ | ||
55 | |||
56 | #define CSICR1_RXFF_LEVEL(x) (((x) & 0x3) << 19) | ||
57 | #define CSICR1_SOF_POL (1 << 17) | ||
58 | #define CSICR1_SOF_INTEN (1 << 16) | ||
59 | #define CSICR1_MCLKDIV(x) (((x) & 0xf) << 12) | ||
60 | #define CSICR1_MCLKEN (1 << 9) | ||
61 | #define CSICR1_FCC (1 << 8) | ||
62 | #define CSICR1_BIG_ENDIAN (1 << 7) | ||
63 | #define CSICR1_CLR_RXFIFO (1 << 5) | ||
64 | #define CSICR1_GCLK_MODE (1 << 4) | ||
65 | #define CSICR1_DATA_POL (1 << 2) | ||
66 | #define CSICR1_REDGE (1 << 1) | ||
67 | #define CSICR1_EN (1 << 0) | ||
68 | |||
69 | #define CSISR_SFF_OR_INT (1 << 25) | ||
70 | #define CSISR_RFF_OR_INT (1 << 24) | ||
71 | #define CSISR_STATFF_INT (1 << 21) | ||
72 | #define CSISR_RXFF_INT (1 << 18) | ||
73 | #define CSISR_SOF_INT (1 << 16) | ||
74 | #define CSISR_DRDY (1 << 0) | ||
75 | |||
76 | #define DRIVER_VERSION "0.0.2" | ||
77 | #define DRIVER_NAME "mx1-camera" | ||
78 | |||
79 | #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ | ||
80 | CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) | ||
81 | |||
82 | #define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
83 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
84 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
85 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW) | ||
86 | |||
87 | #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ | ||
88 | |||
89 | /* | ||
90 | * Structures | ||
91 | */ | ||
92 | |||
93 | /* buffer for one video frame */ | ||
94 | struct mx1_buffer { | ||
95 | /* common v4l buffer stuff -- must be first */ | ||
96 | struct videobuf_buffer vb; | ||
97 | enum v4l2_mbus_pixelcode code; | ||
98 | int inwork; | ||
99 | }; | ||
100 | |||
101 | /* | ||
102 | * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor | ||
103 | * Interface. If anyone ever builds hardware to enable more than | ||
104 | * one camera, they will have to modify this driver too | ||
105 | */ | ||
106 | struct mx1_camera_dev { | ||
107 | struct soc_camera_host soc_host; | ||
108 | struct soc_camera_device *icd; | ||
109 | struct mx1_camera_pdata *pdata; | ||
110 | struct mx1_buffer *active; | ||
111 | struct resource *res; | ||
112 | struct clk *clk; | ||
113 | struct list_head capture; | ||
114 | |||
115 | void __iomem *base; | ||
116 | int dma_chan; | ||
117 | unsigned int irq; | ||
118 | unsigned long mclk; | ||
119 | |||
120 | spinlock_t lock; | ||
121 | }; | ||
122 | |||
123 | /* | ||
124 | * Videobuf operations | ||
125 | */ | ||
126 | static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | ||
127 | unsigned int *size) | ||
128 | { | ||
129 | struct soc_camera_device *icd = vq->priv_data; | ||
130 | |||
131 | *size = icd->sizeimage; | ||
132 | |||
133 | if (!*count) | ||
134 | *count = 32; | ||
135 | |||
136 | if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) | ||
137 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; | ||
138 | |||
139 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) | ||
145 | { | ||
146 | struct soc_camera_device *icd = vq->priv_data; | ||
147 | struct videobuf_buffer *vb = &buf->vb; | ||
148 | |||
149 | BUG_ON(in_interrupt()); | ||
150 | |||
151 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
152 | vb, vb->baddr, vb->bsize); | ||
153 | |||
154 | /* | ||
155 | * This waits until this buffer is out of danger, i.e., until it is no | ||
156 | * longer in STATE_QUEUED or STATE_ACTIVE | ||
157 | */ | ||
158 | videobuf_waiton(vq, vb, 0, 0); | ||
159 | videobuf_dma_contig_free(vq, vb); | ||
160 | |||
161 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
162 | } | ||
163 | |||
164 | static int mx1_videobuf_prepare(struct videobuf_queue *vq, | ||
165 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
166 | { | ||
167 | struct soc_camera_device *icd = vq->priv_data; | ||
168 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | ||
169 | int ret; | ||
170 | |||
171 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
172 | vb, vb->baddr, vb->bsize); | ||
173 | |||
174 | /* Added list head initialization on alloc */ | ||
175 | WARN_ON(!list_empty(&vb->queue)); | ||
176 | |||
177 | BUG_ON(NULL == icd->current_fmt); | ||
178 | |||
179 | /* | ||
180 | * I think, in buf_prepare you only have to protect global data, | ||
181 | * the actual buffer is yours | ||
182 | */ | ||
183 | buf->inwork = 1; | ||
184 | |||
185 | if (buf->code != icd->current_fmt->code || | ||
186 | vb->width != icd->user_width || | ||
187 | vb->height != icd->user_height || | ||
188 | vb->field != field) { | ||
189 | buf->code = icd->current_fmt->code; | ||
190 | vb->width = icd->user_width; | ||
191 | vb->height = icd->user_height; | ||
192 | vb->field = field; | ||
193 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
194 | } | ||
195 | |||
196 | vb->size = icd->sizeimage; | ||
197 | if (0 != vb->baddr && vb->bsize < vb->size) { | ||
198 | ret = -EINVAL; | ||
199 | goto out; | ||
200 | } | ||
201 | |||
202 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
203 | ret = videobuf_iolock(vq, vb, NULL); | ||
204 | if (ret) | ||
205 | goto fail; | ||
206 | |||
207 | vb->state = VIDEOBUF_PREPARED; | ||
208 | } | ||
209 | |||
210 | buf->inwork = 0; | ||
211 | |||
212 | return 0; | ||
213 | |||
214 | fail: | ||
215 | free_buffer(vq, buf); | ||
216 | out: | ||
217 | buf->inwork = 0; | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) | ||
222 | { | ||
223 | struct videobuf_buffer *vbuf = &pcdev->active->vb; | ||
224 | struct device *dev = pcdev->icd->parent; | ||
225 | int ret; | ||
226 | |||
227 | if (unlikely(!pcdev->active)) { | ||
228 | dev_err(dev, "DMA End IRQ with no active buffer\n"); | ||
229 | return -EFAULT; | ||
230 | } | ||
231 | |||
232 | /* setup sg list for future DMA */ | ||
233 | ret = imx_dma_setup_single(pcdev->dma_chan, | ||
234 | videobuf_to_dma_contig(vbuf), | ||
235 | vbuf->size, pcdev->res->start + | ||
236 | CSIRXR, DMA_MODE_READ); | ||
237 | if (unlikely(ret)) | ||
238 | dev_err(dev, "Failed to setup DMA sg list\n"); | ||
239 | |||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | /* Called under spinlock_irqsave(&pcdev->lock, ...) */ | ||
244 | static void mx1_videobuf_queue(struct videobuf_queue *vq, | ||
245 | struct videobuf_buffer *vb) | ||
246 | { | ||
247 | struct soc_camera_device *icd = vq->priv_data; | ||
248 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
249 | struct mx1_camera_dev *pcdev = ici->priv; | ||
250 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | ||
251 | |||
252 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
253 | vb, vb->baddr, vb->bsize); | ||
254 | |||
255 | list_add_tail(&vb->queue, &pcdev->capture); | ||
256 | |||
257 | vb->state = VIDEOBUF_ACTIVE; | ||
258 | |||
259 | if (!pcdev->active) { | ||
260 | pcdev->active = buf; | ||
261 | |||
262 | /* setup sg list for future DMA */ | ||
263 | if (!mx1_camera_setup_dma(pcdev)) { | ||
264 | unsigned int temp; | ||
265 | /* enable SOF irq */ | ||
266 | temp = __raw_readl(pcdev->base + CSICR1) | | ||
267 | CSICR1_SOF_INTEN; | ||
268 | __raw_writel(temp, pcdev->base + CSICR1); | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | static void mx1_videobuf_release(struct videobuf_queue *vq, | ||
274 | struct videobuf_buffer *vb) | ||
275 | { | ||
276 | struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); | ||
277 | #ifdef DEBUG | ||
278 | struct soc_camera_device *icd = vq->priv_data; | ||
279 | struct device *dev = icd->parent; | ||
280 | |||
281 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
282 | vb, vb->baddr, vb->bsize); | ||
283 | |||
284 | switch (vb->state) { | ||
285 | case VIDEOBUF_ACTIVE: | ||
286 | dev_dbg(dev, "%s (active)\n", __func__); | ||
287 | break; | ||
288 | case VIDEOBUF_QUEUED: | ||
289 | dev_dbg(dev, "%s (queued)\n", __func__); | ||
290 | break; | ||
291 | case VIDEOBUF_PREPARED: | ||
292 | dev_dbg(dev, "%s (prepared)\n", __func__); | ||
293 | break; | ||
294 | default: | ||
295 | dev_dbg(dev, "%s (unknown)\n", __func__); | ||
296 | break; | ||
297 | } | ||
298 | #endif | ||
299 | |||
300 | free_buffer(vq, buf); | ||
301 | } | ||
302 | |||
303 | static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev, | ||
304 | struct videobuf_buffer *vb, | ||
305 | struct mx1_buffer *buf) | ||
306 | { | ||
307 | /* _init is used to debug races, see comment in mx1_camera_reqbufs() */ | ||
308 | list_del_init(&vb->queue); | ||
309 | vb->state = VIDEOBUF_DONE; | ||
310 | do_gettimeofday(&vb->ts); | ||
311 | vb->field_count++; | ||
312 | wake_up(&vb->done); | ||
313 | |||
314 | if (list_empty(&pcdev->capture)) { | ||
315 | pcdev->active = NULL; | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | pcdev->active = list_entry(pcdev->capture.next, | ||
320 | struct mx1_buffer, vb.queue); | ||
321 | |||
322 | /* setup sg list for future DMA */ | ||
323 | if (likely(!mx1_camera_setup_dma(pcdev))) { | ||
324 | unsigned int temp; | ||
325 | |||
326 | /* enable SOF irq */ | ||
327 | temp = __raw_readl(pcdev->base + CSICR1) | CSICR1_SOF_INTEN; | ||
328 | __raw_writel(temp, pcdev->base + CSICR1); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static void mx1_camera_dma_irq(int channel, void *data) | ||
333 | { | ||
334 | struct mx1_camera_dev *pcdev = data; | ||
335 | struct device *dev = pcdev->icd->parent; | ||
336 | struct mx1_buffer *buf; | ||
337 | struct videobuf_buffer *vb; | ||
338 | unsigned long flags; | ||
339 | |||
340 | spin_lock_irqsave(&pcdev->lock, flags); | ||
341 | |||
342 | imx_dma_disable(channel); | ||
343 | |||
344 | if (unlikely(!pcdev->active)) { | ||
345 | dev_err(dev, "DMA End IRQ with no active buffer\n"); | ||
346 | goto out; | ||
347 | } | ||
348 | |||
349 | vb = &pcdev->active->vb; | ||
350 | buf = container_of(vb, struct mx1_buffer, vb); | ||
351 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | ||
352 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
353 | vb, vb->baddr, vb->bsize); | ||
354 | |||
355 | mx1_camera_wakeup(pcdev, vb, buf); | ||
356 | out: | ||
357 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
358 | } | ||
359 | |||
360 | static struct videobuf_queue_ops mx1_videobuf_ops = { | ||
361 | .buf_setup = mx1_videobuf_setup, | ||
362 | .buf_prepare = mx1_videobuf_prepare, | ||
363 | .buf_queue = mx1_videobuf_queue, | ||
364 | .buf_release = mx1_videobuf_release, | ||
365 | }; | ||
366 | |||
367 | static void mx1_camera_init_videobuf(struct videobuf_queue *q, | ||
368 | struct soc_camera_device *icd) | ||
369 | { | ||
370 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
371 | struct mx1_camera_dev *pcdev = ici->priv; | ||
372 | |||
373 | videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent, | ||
374 | &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
375 | V4L2_FIELD_NONE, | ||
376 | sizeof(struct mx1_buffer), icd, &icd->video_lock); | ||
377 | } | ||
378 | |||
379 | static int mclk_get_divisor(struct mx1_camera_dev *pcdev) | ||
380 | { | ||
381 | unsigned int mclk = pcdev->mclk; | ||
382 | unsigned long div; | ||
383 | unsigned long lcdclk; | ||
384 | |||
385 | lcdclk = clk_get_rate(pcdev->clk); | ||
386 | |||
387 | /* | ||
388 | * We verify platform_mclk_10khz != 0, so if anyone breaks it, here | ||
389 | * they get a nice Oops | ||
390 | */ | ||
391 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; | ||
392 | |||
393 | dev_dbg(pcdev->icd->parent, | ||
394 | "System clock %lukHz, target freq %dkHz, divisor %lu\n", | ||
395 | lcdclk / 1000, mclk / 1000, div); | ||
396 | |||
397 | return div; | ||
398 | } | ||
399 | |||
400 | static void mx1_camera_activate(struct mx1_camera_dev *pcdev) | ||
401 | { | ||
402 | unsigned int csicr1 = CSICR1_EN; | ||
403 | |||
404 | dev_dbg(pcdev->icd->parent, "Activate device\n"); | ||
405 | |||
406 | clk_prepare_enable(pcdev->clk); | ||
407 | |||
408 | /* enable CSI before doing anything else */ | ||
409 | __raw_writel(csicr1, pcdev->base + CSICR1); | ||
410 | |||
411 | csicr1 |= CSICR1_MCLKEN | CSICR1_FCC | CSICR1_GCLK_MODE; | ||
412 | csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev)); | ||
413 | csicr1 |= CSICR1_RXFF_LEVEL(2); /* 16 words */ | ||
414 | |||
415 | __raw_writel(csicr1, pcdev->base + CSICR1); | ||
416 | } | ||
417 | |||
418 | static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) | ||
419 | { | ||
420 | dev_dbg(pcdev->icd->parent, "Deactivate device\n"); | ||
421 | |||
422 | /* Disable all CSI interface */ | ||
423 | __raw_writel(0x00, pcdev->base + CSICR1); | ||
424 | |||
425 | clk_disable_unprepare(pcdev->clk); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * The following two functions absolutely depend on the fact, that | ||
430 | * there can be only one camera on i.MX1/i.MXL camera sensor interface | ||
431 | */ | ||
432 | static int mx1_camera_add_device(struct soc_camera_device *icd) | ||
433 | { | ||
434 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
435 | struct mx1_camera_dev *pcdev = ici->priv; | ||
436 | |||
437 | if (pcdev->icd) | ||
438 | return -EBUSY; | ||
439 | |||
440 | dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n", | ||
441 | icd->devnum); | ||
442 | |||
443 | mx1_camera_activate(pcdev); | ||
444 | |||
445 | pcdev->icd = icd; | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static void mx1_camera_remove_device(struct soc_camera_device *icd) | ||
451 | { | ||
452 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
453 | struct mx1_camera_dev *pcdev = ici->priv; | ||
454 | unsigned int csicr1; | ||
455 | |||
456 | BUG_ON(icd != pcdev->icd); | ||
457 | |||
458 | /* disable interrupts */ | ||
459 | csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK; | ||
460 | __raw_writel(csicr1, pcdev->base + CSICR1); | ||
461 | |||
462 | /* Stop DMA engine */ | ||
463 | imx_dma_disable(pcdev->dma_chan); | ||
464 | |||
465 | dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n", | ||
466 | icd->devnum); | ||
467 | |||
468 | mx1_camera_deactivate(pcdev); | ||
469 | |||
470 | pcdev->icd = NULL; | ||
471 | } | ||
472 | |||
473 | static int mx1_camera_set_crop(struct soc_camera_device *icd, | ||
474 | struct v4l2_crop *a) | ||
475 | { | ||
476 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
477 | |||
478 | return v4l2_subdev_call(sd, video, s_crop, a); | ||
479 | } | ||
480 | |||
481 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd) | ||
482 | { | ||
483 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
484 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
485 | struct mx1_camera_dev *pcdev = ici->priv; | ||
486 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
487 | unsigned long common_flags; | ||
488 | unsigned int csicr1; | ||
489 | int ret; | ||
490 | |||
491 | /* MX1 supports only 8bit buswidth */ | ||
492 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
493 | if (!ret) { | ||
494 | common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS); | ||
495 | if (!common_flags) { | ||
496 | dev_warn(icd->parent, | ||
497 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
498 | cfg.flags, CSI_BUS_FLAGS); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | } else if (ret != -ENOIOCTLCMD) { | ||
502 | return ret; | ||
503 | } else { | ||
504 | common_flags = CSI_BUS_FLAGS; | ||
505 | } | ||
506 | |||
507 | /* Make choises, based on platform choice */ | ||
508 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
509 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
510 | if (!pcdev->pdata || | ||
511 | pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) | ||
512 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
513 | else | ||
514 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
515 | } | ||
516 | |||
517 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
518 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
519 | if (!pcdev->pdata || | ||
520 | pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) | ||
521 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
522 | else | ||
523 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
524 | } | ||
525 | |||
526 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && | ||
527 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { | ||
528 | if (!pcdev->pdata || | ||
529 | pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) | ||
530 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; | ||
531 | else | ||
532 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
533 | } | ||
534 | |||
535 | cfg.flags = common_flags; | ||
536 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
537 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
538 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
539 | common_flags, ret); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | csicr1 = __raw_readl(pcdev->base + CSICR1); | ||
544 | |||
545 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
546 | csicr1 |= CSICR1_REDGE; | ||
547 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
548 | csicr1 |= CSICR1_SOF_POL; | ||
549 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) | ||
550 | csicr1 |= CSICR1_DATA_POL; | ||
551 | |||
552 | __raw_writel(csicr1, pcdev->base + CSICR1); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int mx1_camera_set_fmt(struct soc_camera_device *icd, | ||
558 | struct v4l2_format *f) | ||
559 | { | ||
560 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
561 | const struct soc_camera_format_xlate *xlate; | ||
562 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
563 | struct v4l2_mbus_framefmt mf; | ||
564 | int ret, buswidth; | ||
565 | |||
566 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
567 | if (!xlate) { | ||
568 | dev_warn(icd->parent, "Format %x not found\n", | ||
569 | pix->pixelformat); | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | buswidth = xlate->host_fmt->bits_per_sample; | ||
574 | if (buswidth > 8) { | ||
575 | dev_warn(icd->parent, | ||
576 | "bits-per-sample %d for format %x unsupported\n", | ||
577 | buswidth, pix->pixelformat); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | mf.width = pix->width; | ||
582 | mf.height = pix->height; | ||
583 | mf.field = pix->field; | ||
584 | mf.colorspace = pix->colorspace; | ||
585 | mf.code = xlate->code; | ||
586 | |||
587 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
588 | if (ret < 0) | ||
589 | return ret; | ||
590 | |||
591 | if (mf.code != xlate->code) | ||
592 | return -EINVAL; | ||
593 | |||
594 | pix->width = mf.width; | ||
595 | pix->height = mf.height; | ||
596 | pix->field = mf.field; | ||
597 | pix->colorspace = mf.colorspace; | ||
598 | icd->current_fmt = xlate; | ||
599 | |||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | static int mx1_camera_try_fmt(struct soc_camera_device *icd, | ||
604 | struct v4l2_format *f) | ||
605 | { | ||
606 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
607 | const struct soc_camera_format_xlate *xlate; | ||
608 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
609 | struct v4l2_mbus_framefmt mf; | ||
610 | int ret; | ||
611 | /* TODO: limit to mx1 hardware capabilities */ | ||
612 | |||
613 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
614 | if (!xlate) { | ||
615 | dev_warn(icd->parent, "Format %x not found\n", | ||
616 | pix->pixelformat); | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | |||
620 | mf.width = pix->width; | ||
621 | mf.height = pix->height; | ||
622 | mf.field = pix->field; | ||
623 | mf.colorspace = pix->colorspace; | ||
624 | mf.code = xlate->code; | ||
625 | |||
626 | /* limit to sensor capabilities */ | ||
627 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
628 | if (ret < 0) | ||
629 | return ret; | ||
630 | |||
631 | pix->width = mf.width; | ||
632 | pix->height = mf.height; | ||
633 | pix->field = mf.field; | ||
634 | pix->colorspace = mf.colorspace; | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int mx1_camera_reqbufs(struct soc_camera_device *icd, | ||
640 | struct v4l2_requestbuffers *p) | ||
641 | { | ||
642 | int i; | ||
643 | |||
644 | /* | ||
645 | * This is for locking debugging only. I removed spinlocks and now I | ||
646 | * check whether .prepare is ever called on a linked buffer, or whether | ||
647 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | ||
648 | * it hadn't triggered | ||
649 | */ | ||
650 | for (i = 0; i < p->count; i++) { | ||
651 | struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i], | ||
652 | struct mx1_buffer, vb); | ||
653 | buf->inwork = 0; | ||
654 | INIT_LIST_HEAD(&buf->vb.queue); | ||
655 | } | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static unsigned int mx1_camera_poll(struct file *file, poll_table *pt) | ||
661 | { | ||
662 | struct soc_camera_device *icd = file->private_data; | ||
663 | struct mx1_buffer *buf; | ||
664 | |||
665 | buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer, | ||
666 | vb.stream); | ||
667 | |||
668 | poll_wait(file, &buf->vb.done, pt); | ||
669 | |||
670 | if (buf->vb.state == VIDEOBUF_DONE || | ||
671 | buf->vb.state == VIDEOBUF_ERROR) | ||
672 | return POLLIN | POLLRDNORM; | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static int mx1_camera_querycap(struct soc_camera_host *ici, | ||
678 | struct v4l2_capability *cap) | ||
679 | { | ||
680 | /* cap->name is set by the friendly caller:-> */ | ||
681 | strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card)); | ||
682 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static struct soc_camera_host_ops mx1_soc_camera_host_ops = { | ||
688 | .owner = THIS_MODULE, | ||
689 | .add = mx1_camera_add_device, | ||
690 | .remove = mx1_camera_remove_device, | ||
691 | .set_bus_param = mx1_camera_set_bus_param, | ||
692 | .set_crop = mx1_camera_set_crop, | ||
693 | .set_fmt = mx1_camera_set_fmt, | ||
694 | .try_fmt = mx1_camera_try_fmt, | ||
695 | .init_videobuf = mx1_camera_init_videobuf, | ||
696 | .reqbufs = mx1_camera_reqbufs, | ||
697 | .poll = mx1_camera_poll, | ||
698 | .querycap = mx1_camera_querycap, | ||
699 | }; | ||
700 | |||
701 | static struct fiq_handler fh = { | ||
702 | .name = "csi_sof" | ||
703 | }; | ||
704 | |||
705 | static int __init mx1_camera_probe(struct platform_device *pdev) | ||
706 | { | ||
707 | struct mx1_camera_dev *pcdev; | ||
708 | struct resource *res; | ||
709 | struct pt_regs regs; | ||
710 | struct clk *clk; | ||
711 | void __iomem *base; | ||
712 | unsigned int irq; | ||
713 | int err = 0; | ||
714 | |||
715 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
716 | irq = platform_get_irq(pdev, 0); | ||
717 | if (!res || (int)irq <= 0) { | ||
718 | err = -ENODEV; | ||
719 | goto exit; | ||
720 | } | ||
721 | |||
722 | clk = clk_get(&pdev->dev, "csi_clk"); | ||
723 | if (IS_ERR(clk)) { | ||
724 | err = PTR_ERR(clk); | ||
725 | goto exit; | ||
726 | } | ||
727 | |||
728 | pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); | ||
729 | if (!pcdev) { | ||
730 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
731 | err = -ENOMEM; | ||
732 | goto exit_put_clk; | ||
733 | } | ||
734 | |||
735 | pcdev->res = res; | ||
736 | pcdev->clk = clk; | ||
737 | |||
738 | pcdev->pdata = pdev->dev.platform_data; | ||
739 | |||
740 | if (pcdev->pdata) | ||
741 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | ||
742 | |||
743 | if (!pcdev->mclk) { | ||
744 | dev_warn(&pdev->dev, | ||
745 | "mclk_10khz == 0! Please, fix your platform data. " | ||
746 | "Using default 20MHz\n"); | ||
747 | pcdev->mclk = 20000000; | ||
748 | } | ||
749 | |||
750 | INIT_LIST_HEAD(&pcdev->capture); | ||
751 | spin_lock_init(&pcdev->lock); | ||
752 | |||
753 | /* | ||
754 | * Request the regions. | ||
755 | */ | ||
756 | if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { | ||
757 | err = -EBUSY; | ||
758 | goto exit_kfree; | ||
759 | } | ||
760 | |||
761 | base = ioremap(res->start, resource_size(res)); | ||
762 | if (!base) { | ||
763 | err = -ENOMEM; | ||
764 | goto exit_release; | ||
765 | } | ||
766 | pcdev->irq = irq; | ||
767 | pcdev->base = base; | ||
768 | |||
769 | /* request dma */ | ||
770 | pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH); | ||
771 | if (pcdev->dma_chan < 0) { | ||
772 | dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n"); | ||
773 | err = -EBUSY; | ||
774 | goto exit_iounmap; | ||
775 | } | ||
776 | dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan); | ||
777 | |||
778 | imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL, | ||
779 | pcdev); | ||
780 | |||
781 | imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO, | ||
782 | IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0); | ||
783 | /* burst length : 16 words = 64 bytes */ | ||
784 | imx_dma_config_burstlen(pcdev->dma_chan, 0); | ||
785 | |||
786 | /* request irq */ | ||
787 | err = claim_fiq(&fh); | ||
788 | if (err) { | ||
789 | dev_err(&pdev->dev, "Camera interrupt register failed \n"); | ||
790 | goto exit_free_dma; | ||
791 | } | ||
792 | |||
793 | set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end - | ||
794 | &mx1_camera_sof_fiq_start); | ||
795 | |||
796 | regs.ARM_r8 = (long)MX1_DMA_DIMR; | ||
797 | regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan); | ||
798 | regs.ARM_r10 = (long)pcdev->base + CSICR1; | ||
799 | regs.ARM_fp = (long)pcdev->base + CSISR; | ||
800 | regs.ARM_sp = 1 << pcdev->dma_chan; | ||
801 | set_fiq_regs(®s); | ||
802 | |||
803 | mxc_set_irq_fiq(irq, 1); | ||
804 | enable_fiq(irq); | ||
805 | |||
806 | pcdev->soc_host.drv_name = DRIVER_NAME; | ||
807 | pcdev->soc_host.ops = &mx1_soc_camera_host_ops; | ||
808 | pcdev->soc_host.priv = pcdev; | ||
809 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
810 | pcdev->soc_host.nr = pdev->id; | ||
811 | err = soc_camera_host_register(&pcdev->soc_host); | ||
812 | if (err) | ||
813 | goto exit_free_irq; | ||
814 | |||
815 | dev_info(&pdev->dev, "MX1 Camera driver loaded\n"); | ||
816 | |||
817 | return 0; | ||
818 | |||
819 | exit_free_irq: | ||
820 | disable_fiq(irq); | ||
821 | mxc_set_irq_fiq(irq, 0); | ||
822 | release_fiq(&fh); | ||
823 | exit_free_dma: | ||
824 | imx_dma_free(pcdev->dma_chan); | ||
825 | exit_iounmap: | ||
826 | iounmap(base); | ||
827 | exit_release: | ||
828 | release_mem_region(res->start, resource_size(res)); | ||
829 | exit_kfree: | ||
830 | kfree(pcdev); | ||
831 | exit_put_clk: | ||
832 | clk_put(clk); | ||
833 | exit: | ||
834 | return err; | ||
835 | } | ||
836 | |||
837 | static int __exit mx1_camera_remove(struct platform_device *pdev) | ||
838 | { | ||
839 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
840 | struct mx1_camera_dev *pcdev = container_of(soc_host, | ||
841 | struct mx1_camera_dev, soc_host); | ||
842 | struct resource *res; | ||
843 | |||
844 | imx_dma_free(pcdev->dma_chan); | ||
845 | disable_fiq(pcdev->irq); | ||
846 | mxc_set_irq_fiq(pcdev->irq, 0); | ||
847 | release_fiq(&fh); | ||
848 | |||
849 | clk_put(pcdev->clk); | ||
850 | |||
851 | soc_camera_host_unregister(soc_host); | ||
852 | |||
853 | iounmap(pcdev->base); | ||
854 | |||
855 | res = pcdev->res; | ||
856 | release_mem_region(res->start, resource_size(res)); | ||
857 | |||
858 | kfree(pcdev); | ||
859 | |||
860 | dev_info(&pdev->dev, "MX1 Camera driver unloaded\n"); | ||
861 | |||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | static struct platform_driver mx1_camera_driver = { | ||
866 | .driver = { | ||
867 | .name = DRIVER_NAME, | ||
868 | }, | ||
869 | .remove = __exit_p(mx1_camera_remove), | ||
870 | }; | ||
871 | |||
872 | static int __init mx1_camera_init(void) | ||
873 | { | ||
874 | return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe); | ||
875 | } | ||
876 | |||
877 | static void __exit mx1_camera_exit(void) | ||
878 | { | ||
879 | return platform_driver_unregister(&mx1_camera_driver); | ||
880 | } | ||
881 | |||
882 | module_init(mx1_camera_init); | ||
883 | module_exit(mx1_camera_exit); | ||
884 | |||
885 | MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver"); | ||
886 | MODULE_AUTHOR("Paulius Zaleckas <paulius.zaleckas@teltonika.lt>"); | ||
887 | MODULE_LICENSE("GPL v2"); | ||
888 | MODULE_VERSION(DRIVER_VERSION); | ||
889 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c new file mode 100644 index 000000000000..403d7f17bfab --- /dev/null +++ b/drivers/media/platform/soc_camera/mx2_camera.c | |||
@@ -0,0 +1,1863 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for i.MX27/i.MX25 camera host | ||
3 | * | ||
4 | * Copyright (C) 2008, Sascha Hauer, Pengutronix | ||
5 | * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography | ||
6 | * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/gcd.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/math64.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/clk.h> | ||
33 | |||
34 | #include <media/v4l2-common.h> | ||
35 | #include <media/v4l2-dev.h> | ||
36 | #include <media/videobuf2-core.h> | ||
37 | #include <media/videobuf2-dma-contig.h> | ||
38 | #include <media/soc_camera.h> | ||
39 | #include <media/soc_mediabus.h> | ||
40 | |||
41 | #include <linux/videodev2.h> | ||
42 | |||
43 | #include <linux/platform_data/camera-mx2.h> | ||
44 | #include <mach/hardware.h> | ||
45 | |||
46 | #include <asm/dma.h> | ||
47 | |||
48 | #define MX2_CAM_DRV_NAME "mx2-camera" | ||
49 | #define MX2_CAM_VERSION "0.0.6" | ||
50 | #define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" | ||
51 | |||
52 | /* reset values */ | ||
53 | #define CSICR1_RESET_VAL 0x40000800 | ||
54 | #define CSICR2_RESET_VAL 0x0 | ||
55 | #define CSICR3_RESET_VAL 0x0 | ||
56 | |||
57 | /* csi control reg 1 */ | ||
58 | #define CSICR1_SWAP16_EN (1 << 31) | ||
59 | #define CSICR1_EXT_VSYNC (1 << 30) | ||
60 | #define CSICR1_EOF_INTEN (1 << 29) | ||
61 | #define CSICR1_PRP_IF_EN (1 << 28) | ||
62 | #define CSICR1_CCIR_MODE (1 << 27) | ||
63 | #define CSICR1_COF_INTEN (1 << 26) | ||
64 | #define CSICR1_SF_OR_INTEN (1 << 25) | ||
65 | #define CSICR1_RF_OR_INTEN (1 << 24) | ||
66 | #define CSICR1_STATFF_LEVEL (3 << 22) | ||
67 | #define CSICR1_STATFF_INTEN (1 << 21) | ||
68 | #define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */ | ||
69 | #define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */ | ||
70 | #define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */ | ||
71 | #define CSICR1_RXFF_INTEN (1 << 18) | ||
72 | #define CSICR1_SOF_POL (1 << 17) | ||
73 | #define CSICR1_SOF_INTEN (1 << 16) | ||
74 | #define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) | ||
75 | #define CSICR1_HSYNC_POL (1 << 11) | ||
76 | #define CSICR1_CCIR_EN (1 << 10) | ||
77 | #define CSICR1_MCLKEN (1 << 9) | ||
78 | #define CSICR1_FCC (1 << 8) | ||
79 | #define CSICR1_PACK_DIR (1 << 7) | ||
80 | #define CSICR1_CLR_STATFIFO (1 << 6) | ||
81 | #define CSICR1_CLR_RXFIFO (1 << 5) | ||
82 | #define CSICR1_GCLK_MODE (1 << 4) | ||
83 | #define CSICR1_INV_DATA (1 << 3) | ||
84 | #define CSICR1_INV_PCLK (1 << 2) | ||
85 | #define CSICR1_REDGE (1 << 1) | ||
86 | #define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN) | ||
87 | |||
88 | #define SHIFT_STATFF_LEVEL 22 | ||
89 | #define SHIFT_RXFF_LEVEL 19 | ||
90 | #define SHIFT_MCLKDIV 12 | ||
91 | |||
92 | /* control reg 3 */ | ||
93 | #define CSICR3_FRMCNT (0xFFFF << 16) | ||
94 | #define CSICR3_FRMCNT_RST (1 << 15) | ||
95 | #define CSICR3_DMA_REFLASH_RFF (1 << 14) | ||
96 | #define CSICR3_DMA_REFLASH_SFF (1 << 13) | ||
97 | #define CSICR3_DMA_REQ_EN_RFF (1 << 12) | ||
98 | #define CSICR3_DMA_REQ_EN_SFF (1 << 11) | ||
99 | #define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */ | ||
100 | #define CSICR3_CSI_SUP (1 << 3) | ||
101 | #define CSICR3_ZERO_PACK_EN (1 << 2) | ||
102 | #define CSICR3_ECC_INT_EN (1 << 1) | ||
103 | #define CSICR3_ECC_AUTO_EN (1 << 0) | ||
104 | |||
105 | #define SHIFT_FRMCNT 16 | ||
106 | |||
107 | /* csi status reg */ | ||
108 | #define CSISR_SFF_OR_INT (1 << 25) | ||
109 | #define CSISR_RFF_OR_INT (1 << 24) | ||
110 | #define CSISR_STATFF_INT (1 << 21) | ||
111 | #define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */ | ||
112 | #define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */ | ||
113 | #define CSISR_RXFF_INT (1 << 18) | ||
114 | #define CSISR_EOF_INT (1 << 17) | ||
115 | #define CSISR_SOF_INT (1 << 16) | ||
116 | #define CSISR_F2_INT (1 << 15) | ||
117 | #define CSISR_F1_INT (1 << 14) | ||
118 | #define CSISR_COF_INT (1 << 13) | ||
119 | #define CSISR_ECC_INT (1 << 1) | ||
120 | #define CSISR_DRDY (1 << 0) | ||
121 | |||
122 | #define CSICR1 0x00 | ||
123 | #define CSICR2 0x04 | ||
124 | #define CSISR (cpu_is_mx27() ? 0x08 : 0x18) | ||
125 | #define CSISTATFIFO 0x0c | ||
126 | #define CSIRFIFO 0x10 | ||
127 | #define CSIRXCNT 0x14 | ||
128 | #define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) | ||
129 | #define CSIDMASA_STATFIFO 0x20 | ||
130 | #define CSIDMATA_STATFIFO 0x24 | ||
131 | #define CSIDMASA_FB1 0x28 | ||
132 | #define CSIDMASA_FB2 0x2c | ||
133 | #define CSIFBUF_PARA 0x30 | ||
134 | #define CSIIMAG_PARA 0x34 | ||
135 | |||
136 | /* EMMA PrP */ | ||
137 | #define PRP_CNTL 0x00 | ||
138 | #define PRP_INTR_CNTL 0x04 | ||
139 | #define PRP_INTRSTATUS 0x08 | ||
140 | #define PRP_SOURCE_Y_PTR 0x0c | ||
141 | #define PRP_SOURCE_CB_PTR 0x10 | ||
142 | #define PRP_SOURCE_CR_PTR 0x14 | ||
143 | #define PRP_DEST_RGB1_PTR 0x18 | ||
144 | #define PRP_DEST_RGB2_PTR 0x1c | ||
145 | #define PRP_DEST_Y_PTR 0x20 | ||
146 | #define PRP_DEST_CB_PTR 0x24 | ||
147 | #define PRP_DEST_CR_PTR 0x28 | ||
148 | #define PRP_SRC_FRAME_SIZE 0x2c | ||
149 | #define PRP_DEST_CH1_LINE_STRIDE 0x30 | ||
150 | #define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 | ||
151 | #define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 | ||
152 | #define PRP_CH1_OUT_IMAGE_SIZE 0x3c | ||
153 | #define PRP_CH2_OUT_IMAGE_SIZE 0x40 | ||
154 | #define PRP_SRC_LINE_STRIDE 0x44 | ||
155 | #define PRP_CSC_COEF_012 0x48 | ||
156 | #define PRP_CSC_COEF_345 0x4c | ||
157 | #define PRP_CSC_COEF_678 0x50 | ||
158 | #define PRP_CH1_RZ_HORI_COEF1 0x54 | ||
159 | #define PRP_CH1_RZ_HORI_COEF2 0x58 | ||
160 | #define PRP_CH1_RZ_HORI_VALID 0x5c | ||
161 | #define PRP_CH1_RZ_VERT_COEF1 0x60 | ||
162 | #define PRP_CH1_RZ_VERT_COEF2 0x64 | ||
163 | #define PRP_CH1_RZ_VERT_VALID 0x68 | ||
164 | #define PRP_CH2_RZ_HORI_COEF1 0x6c | ||
165 | #define PRP_CH2_RZ_HORI_COEF2 0x70 | ||
166 | #define PRP_CH2_RZ_HORI_VALID 0x74 | ||
167 | #define PRP_CH2_RZ_VERT_COEF1 0x78 | ||
168 | #define PRP_CH2_RZ_VERT_COEF2 0x7c | ||
169 | #define PRP_CH2_RZ_VERT_VALID 0x80 | ||
170 | |||
171 | #define PRP_CNTL_CH1EN (1 << 0) | ||
172 | #define PRP_CNTL_CH2EN (1 << 1) | ||
173 | #define PRP_CNTL_CSIEN (1 << 2) | ||
174 | #define PRP_CNTL_DATA_IN_YUV420 (0 << 3) | ||
175 | #define PRP_CNTL_DATA_IN_YUV422 (1 << 3) | ||
176 | #define PRP_CNTL_DATA_IN_RGB16 (2 << 3) | ||
177 | #define PRP_CNTL_DATA_IN_RGB32 (3 << 3) | ||
178 | #define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) | ||
179 | #define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) | ||
180 | #define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) | ||
181 | #define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) | ||
182 | #define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) | ||
183 | #define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) | ||
184 | #define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) | ||
185 | #define PRP_CNTL_CH1_LEN (1 << 9) | ||
186 | #define PRP_CNTL_CH2_LEN (1 << 10) | ||
187 | #define PRP_CNTL_SKIP_FRAME (1 << 11) | ||
188 | #define PRP_CNTL_SWRST (1 << 12) | ||
189 | #define PRP_CNTL_CLKEN (1 << 13) | ||
190 | #define PRP_CNTL_WEN (1 << 14) | ||
191 | #define PRP_CNTL_CH1BYP (1 << 15) | ||
192 | #define PRP_CNTL_IN_TSKIP(x) ((x) << 16) | ||
193 | #define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) | ||
194 | #define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) | ||
195 | #define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) | ||
196 | #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) | ||
197 | #define PRP_CNTL_CH2B1EN (1 << 29) | ||
198 | #define PRP_CNTL_CH2B2EN (1 << 30) | ||
199 | #define PRP_CNTL_CH2FEN (1 << 31) | ||
200 | |||
201 | /* IRQ Enable and status register */ | ||
202 | #define PRP_INTR_RDERR (1 << 0) | ||
203 | #define PRP_INTR_CH1WERR (1 << 1) | ||
204 | #define PRP_INTR_CH2WERR (1 << 2) | ||
205 | #define PRP_INTR_CH1FC (1 << 3) | ||
206 | #define PRP_INTR_CH2FC (1 << 5) | ||
207 | #define PRP_INTR_LBOVF (1 << 7) | ||
208 | #define PRP_INTR_CH2OVF (1 << 8) | ||
209 | |||
210 | /* Resizing registers */ | ||
211 | #define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) | ||
212 | #define PRP_RZ_VALID_BILINEAR (1 << 31) | ||
213 | |||
214 | #define MAX_VIDEO_MEM 16 | ||
215 | |||
216 | #define RESIZE_NUM_MIN 1 | ||
217 | #define RESIZE_NUM_MAX 20 | ||
218 | #define BC_COEF 3 | ||
219 | #define SZ_COEF (1 << BC_COEF) | ||
220 | |||
221 | #define RESIZE_DIR_H 0 | ||
222 | #define RESIZE_DIR_V 1 | ||
223 | |||
224 | #define RESIZE_ALGO_BILINEAR 0 | ||
225 | #define RESIZE_ALGO_AVERAGING 1 | ||
226 | |||
227 | struct mx2_prp_cfg { | ||
228 | int channel; | ||
229 | u32 in_fmt; | ||
230 | u32 out_fmt; | ||
231 | u32 src_pixel; | ||
232 | u32 ch1_pixel; | ||
233 | u32 irq_flags; | ||
234 | u32 csicr1; | ||
235 | }; | ||
236 | |||
237 | /* prp resizing parameters */ | ||
238 | struct emma_prp_resize { | ||
239 | int algo; /* type of algorithm used */ | ||
240 | int len; /* number of coefficients */ | ||
241 | unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ | ||
242 | }; | ||
243 | |||
244 | /* prp configuration for a client-host fmt pair */ | ||
245 | struct mx2_fmt_cfg { | ||
246 | enum v4l2_mbus_pixelcode in_fmt; | ||
247 | u32 out_fmt; | ||
248 | struct mx2_prp_cfg cfg; | ||
249 | }; | ||
250 | |||
251 | enum mx2_buffer_state { | ||
252 | MX2_STATE_QUEUED, | ||
253 | MX2_STATE_ACTIVE, | ||
254 | MX2_STATE_DONE, | ||
255 | }; | ||
256 | |||
257 | struct mx2_buf_internal { | ||
258 | struct list_head queue; | ||
259 | int bufnum; | ||
260 | bool discard; | ||
261 | }; | ||
262 | |||
263 | /* buffer for one video frame */ | ||
264 | struct mx2_buffer { | ||
265 | /* common v4l buffer stuff -- must be first */ | ||
266 | struct vb2_buffer vb; | ||
267 | enum mx2_buffer_state state; | ||
268 | struct mx2_buf_internal internal; | ||
269 | }; | ||
270 | |||
271 | struct mx2_camera_dev { | ||
272 | struct device *dev; | ||
273 | struct soc_camera_host soc_host; | ||
274 | struct soc_camera_device *icd; | ||
275 | struct clk *clk_csi, *clk_emma_ahb, *clk_emma_ipg; | ||
276 | |||
277 | void __iomem *base_csi, *base_emma; | ||
278 | |||
279 | struct mx2_camera_platform_data *pdata; | ||
280 | unsigned long platform_flags; | ||
281 | |||
282 | struct list_head capture; | ||
283 | struct list_head active_bufs; | ||
284 | struct list_head discard; | ||
285 | |||
286 | spinlock_t lock; | ||
287 | |||
288 | int dma; | ||
289 | struct mx2_buffer *active; | ||
290 | struct mx2_buffer *fb1_active; | ||
291 | struct mx2_buffer *fb2_active; | ||
292 | |||
293 | u32 csicr1; | ||
294 | |||
295 | struct mx2_buf_internal buf_discard[2]; | ||
296 | void *discard_buffer; | ||
297 | dma_addr_t discard_buffer_dma; | ||
298 | size_t discard_size; | ||
299 | struct mx2_fmt_cfg *emma_prp; | ||
300 | struct emma_prp_resize resizing[2]; | ||
301 | unsigned int s_width, s_height; | ||
302 | u32 frame_count; | ||
303 | struct vb2_alloc_ctx *alloc_ctx; | ||
304 | }; | ||
305 | |||
306 | static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) | ||
307 | { | ||
308 | return container_of(int_buf, struct mx2_buffer, internal); | ||
309 | } | ||
310 | |||
311 | static struct mx2_fmt_cfg mx27_emma_prp_table[] = { | ||
312 | /* | ||
313 | * This is a generic configuration which is valid for most | ||
314 | * prp input-output format combinations. | ||
315 | * We set the incomming and outgoing pixelformat to a | ||
316 | * 16 Bit wide format and adjust the bytesperline | ||
317 | * accordingly. With this configuration the inputdata | ||
318 | * will not be changed by the emma and could be any type | ||
319 | * of 16 Bit Pixelformat. | ||
320 | */ | ||
321 | { | ||
322 | .in_fmt = 0, | ||
323 | .out_fmt = 0, | ||
324 | .cfg = { | ||
325 | .channel = 1, | ||
326 | .in_fmt = PRP_CNTL_DATA_IN_RGB16, | ||
327 | .out_fmt = PRP_CNTL_CH1_OUT_RGB16, | ||
328 | .src_pixel = 0x2ca00565, /* RGB565 */ | ||
329 | .ch1_pixel = 0x2ca00565, /* RGB565 */ | ||
330 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
331 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
332 | .csicr1 = 0, | ||
333 | } | ||
334 | }, | ||
335 | { | ||
336 | .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, | ||
337 | .out_fmt = V4L2_PIX_FMT_YUYV, | ||
338 | .cfg = { | ||
339 | .channel = 1, | ||
340 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
341 | .out_fmt = PRP_CNTL_CH1_OUT_YUV422, | ||
342 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
343 | .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ | ||
344 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
345 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
346 | .csicr1 = CSICR1_SWAP16_EN, | ||
347 | } | ||
348 | }, | ||
349 | { | ||
350 | .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8, | ||
351 | .out_fmt = V4L2_PIX_FMT_YUYV, | ||
352 | .cfg = { | ||
353 | .channel = 1, | ||
354 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
355 | .out_fmt = PRP_CNTL_CH1_OUT_YUV422, | ||
356 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
357 | .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ | ||
358 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
359 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
360 | .csicr1 = CSICR1_PACK_DIR, | ||
361 | } | ||
362 | }, | ||
363 | { | ||
364 | .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8, | ||
365 | .out_fmt = V4L2_PIX_FMT_YUV420, | ||
366 | .cfg = { | ||
367 | .channel = 2, | ||
368 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
369 | .out_fmt = PRP_CNTL_CH2_OUT_YUV420, | ||
370 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
371 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | | ||
372 | PRP_INTR_CH2FC | PRP_INTR_LBOVF | | ||
373 | PRP_INTR_CH2OVF, | ||
374 | .csicr1 = CSICR1_PACK_DIR, | ||
375 | } | ||
376 | }, | ||
377 | { | ||
378 | .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, | ||
379 | .out_fmt = V4L2_PIX_FMT_YUV420, | ||
380 | .cfg = { | ||
381 | .channel = 2, | ||
382 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
383 | .out_fmt = PRP_CNTL_CH2_OUT_YUV420, | ||
384 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
385 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | | ||
386 | PRP_INTR_CH2FC | PRP_INTR_LBOVF | | ||
387 | PRP_INTR_CH2OVF, | ||
388 | .csicr1 = CSICR1_SWAP16_EN, | ||
389 | } | ||
390 | }, | ||
391 | }; | ||
392 | |||
393 | static struct mx2_fmt_cfg *mx27_emma_prp_get_format( | ||
394 | enum v4l2_mbus_pixelcode in_fmt, | ||
395 | u32 out_fmt) | ||
396 | { | ||
397 | int i; | ||
398 | |||
399 | for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++) | ||
400 | if ((mx27_emma_prp_table[i].in_fmt == in_fmt) && | ||
401 | (mx27_emma_prp_table[i].out_fmt == out_fmt)) { | ||
402 | return &mx27_emma_prp_table[i]; | ||
403 | } | ||
404 | /* If no match return the most generic configuration */ | ||
405 | return &mx27_emma_prp_table[0]; | ||
406 | }; | ||
407 | |||
408 | static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, | ||
409 | unsigned long phys, int bufnum) | ||
410 | { | ||
411 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
412 | |||
413 | if (prp->cfg.channel == 1) { | ||
414 | writel(phys, pcdev->base_emma + | ||
415 | PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
416 | } else { | ||
417 | writel(phys, pcdev->base_emma + | ||
418 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
419 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
420 | u32 imgsize = pcdev->icd->user_height * | ||
421 | pcdev->icd->user_width; | ||
422 | |||
423 | writel(phys + imgsize, pcdev->base_emma + | ||
424 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
425 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
426 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) | ||
432 | { | ||
433 | unsigned long flags; | ||
434 | |||
435 | clk_disable_unprepare(pcdev->clk_csi); | ||
436 | writel(0, pcdev->base_csi + CSICR1); | ||
437 | if (cpu_is_mx27()) { | ||
438 | writel(0, pcdev->base_emma + PRP_CNTL); | ||
439 | } else if (cpu_is_mx25()) { | ||
440 | spin_lock_irqsave(&pcdev->lock, flags); | ||
441 | pcdev->fb1_active = NULL; | ||
442 | pcdev->fb2_active = NULL; | ||
443 | writel(0, pcdev->base_csi + CSIDMASA_FB1); | ||
444 | writel(0, pcdev->base_csi + CSIDMASA_FB2); | ||
445 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * The following two functions absolutely depend on the fact, that | ||
451 | * there can be only one camera on mx2 camera sensor interface | ||
452 | */ | ||
453 | static int mx2_camera_add_device(struct soc_camera_device *icd) | ||
454 | { | ||
455 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
456 | struct mx2_camera_dev *pcdev = ici->priv; | ||
457 | int ret; | ||
458 | u32 csicr1; | ||
459 | |||
460 | if (pcdev->icd) | ||
461 | return -EBUSY; | ||
462 | |||
463 | ret = clk_prepare_enable(pcdev->clk_csi); | ||
464 | if (ret < 0) | ||
465 | return ret; | ||
466 | |||
467 | csicr1 = CSICR1_MCLKEN; | ||
468 | |||
469 | if (cpu_is_mx27()) | ||
470 | csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | | ||
471 | CSICR1_RXFF_LEVEL(0); | ||
472 | |||
473 | pcdev->csicr1 = csicr1; | ||
474 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
475 | |||
476 | pcdev->icd = icd; | ||
477 | pcdev->frame_count = 0; | ||
478 | |||
479 | dev_info(icd->parent, "Camera driver attached to camera %d\n", | ||
480 | icd->devnum); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static void mx2_camera_remove_device(struct soc_camera_device *icd) | ||
486 | { | ||
487 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
488 | struct mx2_camera_dev *pcdev = ici->priv; | ||
489 | |||
490 | BUG_ON(icd != pcdev->icd); | ||
491 | |||
492 | dev_info(icd->parent, "Camera driver detached from camera %d\n", | ||
493 | icd->devnum); | ||
494 | |||
495 | mx2_camera_deactivate(pcdev); | ||
496 | |||
497 | pcdev->icd = NULL; | ||
498 | } | ||
499 | |||
500 | static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, | ||
501 | int state) | ||
502 | { | ||
503 | struct vb2_buffer *vb; | ||
504 | struct mx2_buffer *buf; | ||
505 | struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : | ||
506 | &pcdev->fb2_active; | ||
507 | u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2; | ||
508 | unsigned long flags; | ||
509 | |||
510 | spin_lock_irqsave(&pcdev->lock, flags); | ||
511 | |||
512 | if (*fb_active == NULL) | ||
513 | goto out; | ||
514 | |||
515 | vb = &(*fb_active)->vb; | ||
516 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
517 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
518 | |||
519 | do_gettimeofday(&vb->v4l2_buf.timestamp); | ||
520 | vb->v4l2_buf.sequence++; | ||
521 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
522 | |||
523 | if (list_empty(&pcdev->capture)) { | ||
524 | buf = NULL; | ||
525 | writel(0, pcdev->base_csi + fb_reg); | ||
526 | } else { | ||
527 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
528 | internal.queue); | ||
529 | vb = &buf->vb; | ||
530 | list_del(&buf->internal.queue); | ||
531 | buf->state = MX2_STATE_ACTIVE; | ||
532 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), | ||
533 | pcdev->base_csi + fb_reg); | ||
534 | } | ||
535 | |||
536 | *fb_active = buf; | ||
537 | |||
538 | out: | ||
539 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
540 | } | ||
541 | |||
542 | static irqreturn_t mx25_camera_irq(int irq_csi, void *data) | ||
543 | { | ||
544 | struct mx2_camera_dev *pcdev = data; | ||
545 | u32 status = readl(pcdev->base_csi + CSISR); | ||
546 | |||
547 | if (status & CSISR_DMA_TSF_FB1_INT) | ||
548 | mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); | ||
549 | else if (status & CSISR_DMA_TSF_FB2_INT) | ||
550 | mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE); | ||
551 | |||
552 | /* FIXME: handle CSISR_RFF_OR_INT */ | ||
553 | |||
554 | writel(status, pcdev->base_csi + CSISR); | ||
555 | |||
556 | return IRQ_HANDLED; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * Videobuf operations | ||
561 | */ | ||
562 | static int mx2_videobuf_setup(struct vb2_queue *vq, | ||
563 | const struct v4l2_format *fmt, | ||
564 | unsigned int *count, unsigned int *num_planes, | ||
565 | unsigned int sizes[], void *alloc_ctxs[]) | ||
566 | { | ||
567 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
568 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
569 | struct mx2_camera_dev *pcdev = ici->priv; | ||
570 | |||
571 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); | ||
572 | |||
573 | /* TODO: support for VIDIOC_CREATE_BUFS not ready */ | ||
574 | if (fmt != NULL) | ||
575 | return -ENOTTY; | ||
576 | |||
577 | alloc_ctxs[0] = pcdev->alloc_ctx; | ||
578 | |||
579 | sizes[0] = icd->sizeimage; | ||
580 | |||
581 | if (0 == *count) | ||
582 | *count = 32; | ||
583 | if (!*num_planes && | ||
584 | sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) | ||
585 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; | ||
586 | |||
587 | *num_planes = 1; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int mx2_videobuf_prepare(struct vb2_buffer *vb) | ||
593 | { | ||
594 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
595 | int ret = 0; | ||
596 | |||
597 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
598 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
599 | |||
600 | #ifdef DEBUG | ||
601 | /* | ||
602 | * This can be useful if you want to see if we actually fill | ||
603 | * the buffer with something | ||
604 | */ | ||
605 | memset((void *)vb2_plane_vaddr(vb, 0), | ||
606 | 0xaa, vb2_get_plane_payload(vb, 0)); | ||
607 | #endif | ||
608 | |||
609 | vb2_set_plane_payload(vb, 0, icd->sizeimage); | ||
610 | if (vb2_plane_vaddr(vb, 0) && | ||
611 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { | ||
612 | ret = -EINVAL; | ||
613 | goto out; | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | |||
618 | out: | ||
619 | return ret; | ||
620 | } | ||
621 | |||
622 | static void mx2_videobuf_queue(struct vb2_buffer *vb) | ||
623 | { | ||
624 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
625 | struct soc_camera_host *ici = | ||
626 | to_soc_camera_host(icd->parent); | ||
627 | struct mx2_camera_dev *pcdev = ici->priv; | ||
628 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); | ||
629 | unsigned long flags; | ||
630 | |||
631 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
632 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
633 | |||
634 | spin_lock_irqsave(&pcdev->lock, flags); | ||
635 | |||
636 | buf->state = MX2_STATE_QUEUED; | ||
637 | list_add_tail(&buf->internal.queue, &pcdev->capture); | ||
638 | |||
639 | if (cpu_is_mx25()) { | ||
640 | u32 csicr3, dma_inten = 0; | ||
641 | |||
642 | if (pcdev->fb1_active == NULL) { | ||
643 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), | ||
644 | pcdev->base_csi + CSIDMASA_FB1); | ||
645 | pcdev->fb1_active = buf; | ||
646 | dma_inten = CSICR1_FB1_DMA_INTEN; | ||
647 | } else if (pcdev->fb2_active == NULL) { | ||
648 | writel(vb2_dma_contig_plane_dma_addr(vb, 0), | ||
649 | pcdev->base_csi + CSIDMASA_FB2); | ||
650 | pcdev->fb2_active = buf; | ||
651 | dma_inten = CSICR1_FB2_DMA_INTEN; | ||
652 | } | ||
653 | |||
654 | if (dma_inten) { | ||
655 | list_del(&buf->internal.queue); | ||
656 | buf->state = MX2_STATE_ACTIVE; | ||
657 | |||
658 | csicr3 = readl(pcdev->base_csi + CSICR3); | ||
659 | |||
660 | /* Reflash DMA */ | ||
661 | writel(csicr3 | CSICR3_DMA_REFLASH_RFF, | ||
662 | pcdev->base_csi + CSICR3); | ||
663 | |||
664 | /* clear & enable interrupts */ | ||
665 | writel(dma_inten, pcdev->base_csi + CSISR); | ||
666 | pcdev->csicr1 |= dma_inten; | ||
667 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
668 | |||
669 | /* enable DMA */ | ||
670 | csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); | ||
671 | writel(csicr3, pcdev->base_csi + CSICR3); | ||
672 | } | ||
673 | } | ||
674 | |||
675 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
676 | } | ||
677 | |||
678 | static void mx2_videobuf_release(struct vb2_buffer *vb) | ||
679 | { | ||
680 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
681 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
682 | struct mx2_camera_dev *pcdev = ici->priv; | ||
683 | struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); | ||
684 | unsigned long flags; | ||
685 | |||
686 | #ifdef DEBUG | ||
687 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
688 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
689 | |||
690 | switch (buf->state) { | ||
691 | case MX2_STATE_ACTIVE: | ||
692 | dev_info(icd->parent, "%s (active)\n", __func__); | ||
693 | break; | ||
694 | case MX2_STATE_QUEUED: | ||
695 | dev_info(icd->parent, "%s (queued)\n", __func__); | ||
696 | break; | ||
697 | default: | ||
698 | dev_info(icd->parent, "%s (unknown) %d\n", __func__, | ||
699 | buf->state); | ||
700 | break; | ||
701 | } | ||
702 | #endif | ||
703 | |||
704 | /* | ||
705 | * Terminate only queued but inactive buffers. Active buffers are | ||
706 | * released when they become inactive after videobuf_waiton(). | ||
707 | * | ||
708 | * FIXME: implement forced termination of active buffers for mx27 and | ||
709 | * mx27 eMMA, so that the user won't get stuck in an uninterruptible | ||
710 | * state. This requires a specific handling for each of the these DMA | ||
711 | * types. | ||
712 | */ | ||
713 | |||
714 | spin_lock_irqsave(&pcdev->lock, flags); | ||
715 | if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { | ||
716 | if (pcdev->fb1_active == buf) { | ||
717 | pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; | ||
718 | writel(0, pcdev->base_csi + CSIDMASA_FB1); | ||
719 | pcdev->fb1_active = NULL; | ||
720 | } else if (pcdev->fb2_active == buf) { | ||
721 | pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN; | ||
722 | writel(0, pcdev->base_csi + CSIDMASA_FB2); | ||
723 | pcdev->fb2_active = NULL; | ||
724 | } | ||
725 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
726 | } | ||
727 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
728 | } | ||
729 | |||
730 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | ||
731 | int bytesperline) | ||
732 | { | ||
733 | struct soc_camera_host *ici = | ||
734 | to_soc_camera_host(icd->parent); | ||
735 | struct mx2_camera_dev *pcdev = ici->priv; | ||
736 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
737 | |||
738 | writel((pcdev->s_width << 16) | pcdev->s_height, | ||
739 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
740 | writel(prp->cfg.src_pixel, | ||
741 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | ||
742 | if (prp->cfg.channel == 1) { | ||
743 | writel((icd->user_width << 16) | icd->user_height, | ||
744 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | ||
745 | writel(bytesperline, | ||
746 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | ||
747 | writel(prp->cfg.ch1_pixel, | ||
748 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | ||
749 | } else { /* channel 2 */ | ||
750 | writel((icd->user_width << 16) | icd->user_height, | ||
751 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
752 | } | ||
753 | |||
754 | /* Enable interrupts */ | ||
755 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); | ||
756 | } | ||
757 | |||
758 | static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) | ||
759 | { | ||
760 | int dir; | ||
761 | |||
762 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { | ||
763 | unsigned char *s = pcdev->resizing[dir].s; | ||
764 | int len = pcdev->resizing[dir].len; | ||
765 | unsigned int coeff[2] = {0, 0}; | ||
766 | unsigned int valid = 0; | ||
767 | int i; | ||
768 | |||
769 | if (len == 0) | ||
770 | continue; | ||
771 | |||
772 | for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { | ||
773 | int j; | ||
774 | |||
775 | j = i > 9 ? 1 : 0; | ||
776 | coeff[j] = (coeff[j] << BC_COEF) | | ||
777 | (s[i] & (SZ_COEF - 1)); | ||
778 | |||
779 | if (i == 5 || i == 15) | ||
780 | coeff[j] <<= 1; | ||
781 | |||
782 | valid = (valid << 1) | (s[i] >> BC_COEF); | ||
783 | } | ||
784 | |||
785 | valid |= PRP_RZ_VALID_TBL_LEN(len); | ||
786 | |||
787 | if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) | ||
788 | valid |= PRP_RZ_VALID_BILINEAR; | ||
789 | |||
790 | if (pcdev->emma_prp->cfg.channel == 1) { | ||
791 | if (dir == RESIZE_DIR_H) { | ||
792 | writel(coeff[0], pcdev->base_emma + | ||
793 | PRP_CH1_RZ_HORI_COEF1); | ||
794 | writel(coeff[1], pcdev->base_emma + | ||
795 | PRP_CH1_RZ_HORI_COEF2); | ||
796 | writel(valid, pcdev->base_emma + | ||
797 | PRP_CH1_RZ_HORI_VALID); | ||
798 | } else { | ||
799 | writel(coeff[0], pcdev->base_emma + | ||
800 | PRP_CH1_RZ_VERT_COEF1); | ||
801 | writel(coeff[1], pcdev->base_emma + | ||
802 | PRP_CH1_RZ_VERT_COEF2); | ||
803 | writel(valid, pcdev->base_emma + | ||
804 | PRP_CH1_RZ_VERT_VALID); | ||
805 | } | ||
806 | } else { | ||
807 | if (dir == RESIZE_DIR_H) { | ||
808 | writel(coeff[0], pcdev->base_emma + | ||
809 | PRP_CH2_RZ_HORI_COEF1); | ||
810 | writel(coeff[1], pcdev->base_emma + | ||
811 | PRP_CH2_RZ_HORI_COEF2); | ||
812 | writel(valid, pcdev->base_emma + | ||
813 | PRP_CH2_RZ_HORI_VALID); | ||
814 | } else { | ||
815 | writel(coeff[0], pcdev->base_emma + | ||
816 | PRP_CH2_RZ_VERT_COEF1); | ||
817 | writel(coeff[1], pcdev->base_emma + | ||
818 | PRP_CH2_RZ_VERT_COEF2); | ||
819 | writel(valid, pcdev->base_emma + | ||
820 | PRP_CH2_RZ_VERT_VALID); | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | } | ||
825 | |||
826 | static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | ||
827 | { | ||
828 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
829 | struct soc_camera_host *ici = | ||
830 | to_soc_camera_host(icd->parent); | ||
831 | struct mx2_camera_dev *pcdev = ici->priv; | ||
832 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
833 | struct vb2_buffer *vb; | ||
834 | struct mx2_buffer *buf; | ||
835 | unsigned long phys; | ||
836 | int bytesperline; | ||
837 | |||
838 | if (cpu_is_mx27()) { | ||
839 | unsigned long flags; | ||
840 | if (count < 2) | ||
841 | return -EINVAL; | ||
842 | |||
843 | spin_lock_irqsave(&pcdev->lock, flags); | ||
844 | |||
845 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
846 | internal.queue); | ||
847 | buf->internal.bufnum = 0; | ||
848 | vb = &buf->vb; | ||
849 | buf->state = MX2_STATE_ACTIVE; | ||
850 | |||
851 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
852 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
853 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
854 | |||
855 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
856 | internal.queue); | ||
857 | buf->internal.bufnum = 1; | ||
858 | vb = &buf->vb; | ||
859 | buf->state = MX2_STATE_ACTIVE; | ||
860 | |||
861 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
862 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
863 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
864 | |||
865 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
866 | icd->current_fmt->host_fmt); | ||
867 | if (bytesperline < 0) | ||
868 | return bytesperline; | ||
869 | |||
870 | /* | ||
871 | * I didn't manage to properly enable/disable the prp | ||
872 | * on a per frame basis during running transfers, | ||
873 | * thus we allocate a buffer here and use it to | ||
874 | * discard frames when no buffer is available. | ||
875 | * Feel free to work on this ;) | ||
876 | */ | ||
877 | pcdev->discard_size = icd->user_height * bytesperline; | ||
878 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
879 | pcdev->discard_size, &pcdev->discard_buffer_dma, | ||
880 | GFP_KERNEL); | ||
881 | if (!pcdev->discard_buffer) | ||
882 | return -ENOMEM; | ||
883 | |||
884 | pcdev->buf_discard[0].discard = true; | ||
885 | list_add_tail(&pcdev->buf_discard[0].queue, | ||
886 | &pcdev->discard); | ||
887 | |||
888 | pcdev->buf_discard[1].discard = true; | ||
889 | list_add_tail(&pcdev->buf_discard[1].queue, | ||
890 | &pcdev->discard); | ||
891 | |||
892 | mx2_prp_resize_commit(pcdev); | ||
893 | |||
894 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
895 | |||
896 | if (prp->cfg.channel == 1) { | ||
897 | writel(PRP_CNTL_CH1EN | | ||
898 | PRP_CNTL_CSIEN | | ||
899 | prp->cfg.in_fmt | | ||
900 | prp->cfg.out_fmt | | ||
901 | PRP_CNTL_CH1_LEN | | ||
902 | PRP_CNTL_CH1BYP | | ||
903 | PRP_CNTL_CH1_TSKIP(0) | | ||
904 | PRP_CNTL_IN_TSKIP(0), | ||
905 | pcdev->base_emma + PRP_CNTL); | ||
906 | } else { | ||
907 | writel(PRP_CNTL_CH2EN | | ||
908 | PRP_CNTL_CSIEN | | ||
909 | prp->cfg.in_fmt | | ||
910 | prp->cfg.out_fmt | | ||
911 | PRP_CNTL_CH2_LEN | | ||
912 | PRP_CNTL_CH2_TSKIP(0) | | ||
913 | PRP_CNTL_IN_TSKIP(0), | ||
914 | pcdev->base_emma + PRP_CNTL); | ||
915 | } | ||
916 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
917 | } | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int mx2_stop_streaming(struct vb2_queue *q) | ||
923 | { | ||
924 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
925 | struct soc_camera_host *ici = | ||
926 | to_soc_camera_host(icd->parent); | ||
927 | struct mx2_camera_dev *pcdev = ici->priv; | ||
928 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
929 | unsigned long flags; | ||
930 | void *b; | ||
931 | u32 cntl; | ||
932 | |||
933 | if (cpu_is_mx27()) { | ||
934 | spin_lock_irqsave(&pcdev->lock, flags); | ||
935 | |||
936 | cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
937 | if (prp->cfg.channel == 1) { | ||
938 | writel(cntl & ~PRP_CNTL_CH1EN, | ||
939 | pcdev->base_emma + PRP_CNTL); | ||
940 | } else { | ||
941 | writel(cntl & ~PRP_CNTL_CH2EN, | ||
942 | pcdev->base_emma + PRP_CNTL); | ||
943 | } | ||
944 | INIT_LIST_HEAD(&pcdev->capture); | ||
945 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
946 | INIT_LIST_HEAD(&pcdev->discard); | ||
947 | |||
948 | b = pcdev->discard_buffer; | ||
949 | pcdev->discard_buffer = NULL; | ||
950 | |||
951 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
952 | |||
953 | dma_free_coherent(ici->v4l2_dev.dev, | ||
954 | pcdev->discard_size, b, pcdev->discard_buffer_dma); | ||
955 | } | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static struct vb2_ops mx2_videobuf_ops = { | ||
961 | .queue_setup = mx2_videobuf_setup, | ||
962 | .buf_prepare = mx2_videobuf_prepare, | ||
963 | .buf_queue = mx2_videobuf_queue, | ||
964 | .buf_cleanup = mx2_videobuf_release, | ||
965 | .start_streaming = mx2_start_streaming, | ||
966 | .stop_streaming = mx2_stop_streaming, | ||
967 | }; | ||
968 | |||
969 | static int mx2_camera_init_videobuf(struct vb2_queue *q, | ||
970 | struct soc_camera_device *icd) | ||
971 | { | ||
972 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
973 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
974 | q->drv_priv = icd; | ||
975 | q->ops = &mx2_videobuf_ops; | ||
976 | q->mem_ops = &vb2_dma_contig_memops; | ||
977 | q->buf_struct_size = sizeof(struct mx2_buffer); | ||
978 | |||
979 | return vb2_queue_init(q); | ||
980 | } | ||
981 | |||
982 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
983 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
984 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
985 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
986 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
987 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
988 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
989 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ | ||
990 | V4L2_MBUS_DATA_ACTIVE_LOW) | ||
991 | |||
992 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | ||
993 | { | ||
994 | u32 cntl; | ||
995 | int count = 0; | ||
996 | |||
997 | cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
998 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); | ||
999 | while (count++ < 100) { | ||
1000 | if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) | ||
1001 | return 0; | ||
1002 | barrier(); | ||
1003 | udelay(1); | ||
1004 | } | ||
1005 | |||
1006 | return -ETIMEDOUT; | ||
1007 | } | ||
1008 | |||
1009 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | ||
1010 | { | ||
1011 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1012 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1013 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1014 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
1015 | unsigned long common_flags; | ||
1016 | int ret; | ||
1017 | int bytesperline; | ||
1018 | u32 csicr1 = pcdev->csicr1; | ||
1019 | |||
1020 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1021 | if (!ret) { | ||
1022 | common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); | ||
1023 | if (!common_flags) { | ||
1024 | dev_warn(icd->parent, | ||
1025 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
1026 | cfg.flags, MX2_BUS_FLAGS); | ||
1027 | return -EINVAL; | ||
1028 | } | ||
1029 | } else if (ret != -ENOIOCTLCMD) { | ||
1030 | return ret; | ||
1031 | } else { | ||
1032 | common_flags = MX2_BUS_FLAGS; | ||
1033 | } | ||
1034 | |||
1035 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
1036 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
1037 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) | ||
1038 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
1039 | else | ||
1040 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
1041 | } | ||
1042 | |||
1043 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1044 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1045 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) | ||
1046 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1047 | else | ||
1048 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1049 | } | ||
1050 | |||
1051 | cfg.flags = common_flags; | ||
1052 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1053 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1054 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1055 | common_flags, ret); | ||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
1059 | csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1; | ||
1060 | |||
1061 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
1062 | csicr1 |= CSICR1_REDGE; | ||
1063 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
1064 | csicr1 |= CSICR1_SOF_POL; | ||
1065 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) | ||
1066 | csicr1 |= CSICR1_HSYNC_POL; | ||
1067 | if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) | ||
1068 | csicr1 |= CSICR1_EXT_VSYNC; | ||
1069 | if (pcdev->platform_flags & MX2_CAMERA_CCIR) | ||
1070 | csicr1 |= CSICR1_CCIR_EN; | ||
1071 | if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) | ||
1072 | csicr1 |= CSICR1_CCIR_MODE; | ||
1073 | if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) | ||
1074 | csicr1 |= CSICR1_GCLK_MODE; | ||
1075 | if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) | ||
1076 | csicr1 |= CSICR1_INV_DATA; | ||
1077 | |||
1078 | pcdev->csicr1 = csicr1; | ||
1079 | |||
1080 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
1081 | icd->current_fmt->host_fmt); | ||
1082 | if (bytesperline < 0) | ||
1083 | return bytesperline; | ||
1084 | |||
1085 | if (cpu_is_mx27()) { | ||
1086 | ret = mx27_camera_emma_prp_reset(pcdev); | ||
1087 | if (ret) | ||
1088 | return ret; | ||
1089 | } else if (cpu_is_mx25()) { | ||
1090 | writel((bytesperline * icd->user_height) >> 2, | ||
1091 | pcdev->base_csi + CSIRXCNT); | ||
1092 | writel((bytesperline << 16) | icd->user_height, | ||
1093 | pcdev->base_csi + CSIIMAG_PARA); | ||
1094 | } | ||
1095 | |||
1096 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | static int mx2_camera_set_crop(struct soc_camera_device *icd, | ||
1102 | struct v4l2_crop *a) | ||
1103 | { | ||
1104 | struct v4l2_rect *rect = &a->c; | ||
1105 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1106 | struct v4l2_mbus_framefmt mf; | ||
1107 | int ret; | ||
1108 | |||
1109 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); | ||
1110 | soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); | ||
1111 | |||
1112 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
1113 | if (ret < 0) | ||
1114 | return ret; | ||
1115 | |||
1116 | /* The capture device might have changed its output */ | ||
1117 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
1118 | if (ret < 0) | ||
1119 | return ret; | ||
1120 | |||
1121 | dev_dbg(icd->parent, "Sensor cropped %dx%d\n", | ||
1122 | mf.width, mf.height); | ||
1123 | |||
1124 | icd->user_width = mf.width; | ||
1125 | icd->user_height = mf.height; | ||
1126 | |||
1127 | return ret; | ||
1128 | } | ||
1129 | |||
1130 | static int mx2_camera_get_formats(struct soc_camera_device *icd, | ||
1131 | unsigned int idx, | ||
1132 | struct soc_camera_format_xlate *xlate) | ||
1133 | { | ||
1134 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1135 | const struct soc_mbus_pixelfmt *fmt; | ||
1136 | struct device *dev = icd->parent; | ||
1137 | enum v4l2_mbus_pixelcode code; | ||
1138 | int ret, formats = 0; | ||
1139 | |||
1140 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
1141 | if (ret < 0) | ||
1142 | /* no more formats */ | ||
1143 | return 0; | ||
1144 | |||
1145 | fmt = soc_mbus_get_fmtdesc(code); | ||
1146 | if (!fmt) { | ||
1147 | dev_err(dev, "Invalid format code #%u: %d\n", idx, code); | ||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | if (code == V4L2_MBUS_FMT_YUYV8_2X8 || | ||
1152 | code == V4L2_MBUS_FMT_UYVY8_2X8) { | ||
1153 | formats++; | ||
1154 | if (xlate) { | ||
1155 | /* | ||
1156 | * CH2 can output YUV420 which is a standard format in | ||
1157 | * soc_mediabus.c | ||
1158 | */ | ||
1159 | xlate->host_fmt = | ||
1160 | soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8); | ||
1161 | xlate->code = code; | ||
1162 | dev_dbg(dev, "Providing host format %s for sensor code %d\n", | ||
1163 | xlate->host_fmt->name, code); | ||
1164 | xlate++; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | if (code == V4L2_MBUS_FMT_UYVY8_2X8) { | ||
1169 | formats++; | ||
1170 | if (xlate) { | ||
1171 | xlate->host_fmt = | ||
1172 | soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8); | ||
1173 | xlate->code = code; | ||
1174 | dev_dbg(dev, "Providing host format %s for sensor code %d\n", | ||
1175 | xlate->host_fmt->name, code); | ||
1176 | xlate++; | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | /* Generic pass-trough */ | ||
1181 | formats++; | ||
1182 | if (xlate) { | ||
1183 | xlate->host_fmt = fmt; | ||
1184 | xlate->code = code; | ||
1185 | xlate++; | ||
1186 | } | ||
1187 | return formats; | ||
1188 | } | ||
1189 | |||
1190 | static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, | ||
1191 | struct v4l2_mbus_framefmt *mf_in, | ||
1192 | struct v4l2_pix_format *pix_out, bool apply) | ||
1193 | { | ||
1194 | int num, den; | ||
1195 | unsigned long m; | ||
1196 | int i, dir; | ||
1197 | |||
1198 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { | ||
1199 | struct emma_prp_resize tmprsz; | ||
1200 | unsigned char *s = tmprsz.s; | ||
1201 | int len = 0; | ||
1202 | int in, out; | ||
1203 | |||
1204 | if (dir == RESIZE_DIR_H) { | ||
1205 | in = mf_in->width; | ||
1206 | out = pix_out->width; | ||
1207 | } else { | ||
1208 | in = mf_in->height; | ||
1209 | out = pix_out->height; | ||
1210 | } | ||
1211 | |||
1212 | if (in < out) | ||
1213 | return -EINVAL; | ||
1214 | else if (in == out) | ||
1215 | continue; | ||
1216 | |||
1217 | /* Calculate ratio */ | ||
1218 | m = gcd(in, out); | ||
1219 | num = in / m; | ||
1220 | den = out / m; | ||
1221 | if (num > RESIZE_NUM_MAX) | ||
1222 | return -EINVAL; | ||
1223 | |||
1224 | if ((num >= 2 * den) && (den == 1) && | ||
1225 | (num < 9) && (!(num & 0x01))) { | ||
1226 | int sum = 0; | ||
1227 | int j; | ||
1228 | |||
1229 | /* Average scaling for >= 2:1 ratios */ | ||
1230 | /* Support can be added for num >=9 and odd values */ | ||
1231 | |||
1232 | tmprsz.algo = RESIZE_ALGO_AVERAGING; | ||
1233 | len = num; | ||
1234 | |||
1235 | for (i = 0; i < (len / 2); i++) | ||
1236 | s[i] = 8; | ||
1237 | |||
1238 | do { | ||
1239 | for (i = 0; i < (len / 2); i++) { | ||
1240 | s[i] = s[i] >> 1; | ||
1241 | sum = 0; | ||
1242 | for (j = 0; j < (len / 2); j++) | ||
1243 | sum += s[j]; | ||
1244 | if (sum == 4) | ||
1245 | break; | ||
1246 | } | ||
1247 | } while (sum != 4); | ||
1248 | |||
1249 | for (i = (len / 2); i < len; i++) | ||
1250 | s[i] = s[len - i - 1]; | ||
1251 | |||
1252 | s[len - 1] |= SZ_COEF; | ||
1253 | } else { | ||
1254 | /* bilinear scaling for < 2:1 ratios */ | ||
1255 | int v; /* overflow counter */ | ||
1256 | int coeff, nxt; /* table output */ | ||
1257 | int in_pos_inc = 2 * den; | ||
1258 | int out_pos = num; | ||
1259 | int out_pos_inc = 2 * num; | ||
1260 | int init_carry = num - den; | ||
1261 | int carry = init_carry; | ||
1262 | |||
1263 | tmprsz.algo = RESIZE_ALGO_BILINEAR; | ||
1264 | v = den + in_pos_inc; | ||
1265 | do { | ||
1266 | coeff = v - out_pos; | ||
1267 | out_pos += out_pos_inc; | ||
1268 | carry += out_pos_inc; | ||
1269 | for (nxt = 0; v < out_pos; nxt++) { | ||
1270 | v += in_pos_inc; | ||
1271 | carry -= in_pos_inc; | ||
1272 | } | ||
1273 | |||
1274 | if (len > RESIZE_NUM_MAX) | ||
1275 | return -EINVAL; | ||
1276 | |||
1277 | coeff = ((coeff << BC_COEF) + | ||
1278 | (in_pos_inc >> 1)) / in_pos_inc; | ||
1279 | |||
1280 | if (coeff >= (SZ_COEF - 1)) | ||
1281 | coeff--; | ||
1282 | |||
1283 | coeff |= SZ_COEF; | ||
1284 | s[len] = (unsigned char)coeff; | ||
1285 | len++; | ||
1286 | |||
1287 | for (i = 1; i < nxt; i++) { | ||
1288 | if (len >= RESIZE_NUM_MAX) | ||
1289 | return -EINVAL; | ||
1290 | s[len] = 0; | ||
1291 | len++; | ||
1292 | } | ||
1293 | } while (carry != init_carry); | ||
1294 | } | ||
1295 | tmprsz.len = len; | ||
1296 | if (dir == RESIZE_DIR_H) | ||
1297 | mf_in->width = pix_out->width; | ||
1298 | else | ||
1299 | mf_in->height = pix_out->height; | ||
1300 | |||
1301 | if (apply) | ||
1302 | memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); | ||
1303 | } | ||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | static int mx2_camera_set_fmt(struct soc_camera_device *icd, | ||
1308 | struct v4l2_format *f) | ||
1309 | { | ||
1310 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1311 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1312 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1313 | const struct soc_camera_format_xlate *xlate; | ||
1314 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1315 | struct v4l2_mbus_framefmt mf; | ||
1316 | int ret; | ||
1317 | |||
1318 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1319 | __func__, pix->width, pix->height); | ||
1320 | |||
1321 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1322 | if (!xlate) { | ||
1323 | dev_warn(icd->parent, "Format %x not found\n", | ||
1324 | pix->pixelformat); | ||
1325 | return -EINVAL; | ||
1326 | } | ||
1327 | |||
1328 | mf.width = pix->width; | ||
1329 | mf.height = pix->height; | ||
1330 | mf.field = pix->field; | ||
1331 | mf.colorspace = pix->colorspace; | ||
1332 | mf.code = xlate->code; | ||
1333 | |||
1334 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
1335 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
1336 | return ret; | ||
1337 | |||
1338 | /* Store width and height returned by the sensor for resizing */ | ||
1339 | pcdev->s_width = mf.width; | ||
1340 | pcdev->s_height = mf.height; | ||
1341 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1342 | __func__, pcdev->s_width, pcdev->s_height); | ||
1343 | |||
1344 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1345 | xlate->host_fmt->fourcc); | ||
1346 | |||
1347 | memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); | ||
1348 | if ((mf.width != pix->width || mf.height != pix->height) && | ||
1349 | pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1350 | if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) | ||
1351 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1352 | } | ||
1353 | |||
1354 | if (mf.code != xlate->code) | ||
1355 | return -EINVAL; | ||
1356 | |||
1357 | pix->width = mf.width; | ||
1358 | pix->height = mf.height; | ||
1359 | pix->field = mf.field; | ||
1360 | pix->colorspace = mf.colorspace; | ||
1361 | icd->current_fmt = xlate; | ||
1362 | |||
1363 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", | ||
1364 | __func__, pix->width, pix->height); | ||
1365 | |||
1366 | return 0; | ||
1367 | } | ||
1368 | |||
1369 | static int mx2_camera_try_fmt(struct soc_camera_device *icd, | ||
1370 | struct v4l2_format *f) | ||
1371 | { | ||
1372 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1373 | const struct soc_camera_format_xlate *xlate; | ||
1374 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1375 | struct v4l2_mbus_framefmt mf; | ||
1376 | __u32 pixfmt = pix->pixelformat; | ||
1377 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1378 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1379 | unsigned int width_limit; | ||
1380 | int ret; | ||
1381 | |||
1382 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1383 | __func__, pix->width, pix->height); | ||
1384 | |||
1385 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1386 | if (pixfmt && !xlate) { | ||
1387 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
1388 | return -EINVAL; | ||
1389 | } | ||
1390 | |||
1391 | /* FIXME: implement MX27 limits */ | ||
1392 | |||
1393 | /* limit to MX25 hardware capabilities */ | ||
1394 | if (cpu_is_mx25()) { | ||
1395 | if (xlate->host_fmt->bits_per_sample <= 8) | ||
1396 | width_limit = 0xffff * 4; | ||
1397 | else | ||
1398 | width_limit = 0xffff * 2; | ||
1399 | /* CSIIMAG_PARA limit */ | ||
1400 | if (pix->width > width_limit) | ||
1401 | pix->width = width_limit; | ||
1402 | if (pix->height > 0xffff) | ||
1403 | pix->height = 0xffff; | ||
1404 | |||
1405 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, | ||
1406 | xlate->host_fmt); | ||
1407 | if (pix->bytesperline < 0) | ||
1408 | return pix->bytesperline; | ||
1409 | pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, | ||
1410 | pix->bytesperline, pix->height); | ||
1411 | /* Check against the CSIRXCNT limit */ | ||
1412 | if (pix->sizeimage > 4 * 0x3ffff) { | ||
1413 | /* Adjust geometry, preserve aspect ratio */ | ||
1414 | unsigned int new_height = int_sqrt(div_u64(0x3ffffULL * | ||
1415 | 4 * pix->height, pix->bytesperline)); | ||
1416 | pix->width = new_height * pix->width / pix->height; | ||
1417 | pix->height = new_height; | ||
1418 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, | ||
1419 | xlate->host_fmt); | ||
1420 | BUG_ON(pix->bytesperline < 0); | ||
1421 | pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, | ||
1422 | pix->bytesperline, pix->height); | ||
1423 | } | ||
1424 | } | ||
1425 | |||
1426 | /* limit to sensor capabilities */ | ||
1427 | mf.width = pix->width; | ||
1428 | mf.height = pix->height; | ||
1429 | mf.field = pix->field; | ||
1430 | mf.colorspace = pix->colorspace; | ||
1431 | mf.code = xlate->code; | ||
1432 | |||
1433 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1434 | if (ret < 0) | ||
1435 | return ret; | ||
1436 | |||
1437 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1438 | __func__, pcdev->s_width, pcdev->s_height); | ||
1439 | |||
1440 | /* If the sensor does not support image size try PrP resizing */ | ||
1441 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1442 | xlate->host_fmt->fourcc); | ||
1443 | |||
1444 | memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); | ||
1445 | if ((mf.width != pix->width || mf.height != pix->height) && | ||
1446 | pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1447 | if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) | ||
1448 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1449 | } | ||
1450 | |||
1451 | if (mf.field == V4L2_FIELD_ANY) | ||
1452 | mf.field = V4L2_FIELD_NONE; | ||
1453 | /* | ||
1454 | * Driver supports interlaced images provided they have | ||
1455 | * both fields so that they can be processed as if they | ||
1456 | * were progressive. | ||
1457 | */ | ||
1458 | if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) { | ||
1459 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
1460 | mf.field); | ||
1461 | return -EINVAL; | ||
1462 | } | ||
1463 | |||
1464 | pix->width = mf.width; | ||
1465 | pix->height = mf.height; | ||
1466 | pix->field = mf.field; | ||
1467 | pix->colorspace = mf.colorspace; | ||
1468 | |||
1469 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", | ||
1470 | __func__, pix->width, pix->height); | ||
1471 | |||
1472 | return 0; | ||
1473 | } | ||
1474 | |||
1475 | static int mx2_camera_querycap(struct soc_camera_host *ici, | ||
1476 | struct v4l2_capability *cap) | ||
1477 | { | ||
1478 | /* cap->name is set by the friendly caller:-> */ | ||
1479 | strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); | ||
1480 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1481 | |||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) | ||
1486 | { | ||
1487 | struct soc_camera_device *icd = file->private_data; | ||
1488 | |||
1489 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
1490 | } | ||
1491 | |||
1492 | static struct soc_camera_host_ops mx2_soc_camera_host_ops = { | ||
1493 | .owner = THIS_MODULE, | ||
1494 | .add = mx2_camera_add_device, | ||
1495 | .remove = mx2_camera_remove_device, | ||
1496 | .set_fmt = mx2_camera_set_fmt, | ||
1497 | .set_crop = mx2_camera_set_crop, | ||
1498 | .get_formats = mx2_camera_get_formats, | ||
1499 | .try_fmt = mx2_camera_try_fmt, | ||
1500 | .init_videobuf2 = mx2_camera_init_videobuf, | ||
1501 | .poll = mx2_camera_poll, | ||
1502 | .querycap = mx2_camera_querycap, | ||
1503 | .set_bus_param = mx2_camera_set_bus_param, | ||
1504 | }; | ||
1505 | |||
1506 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | ||
1507 | int bufnum, bool err) | ||
1508 | { | ||
1509 | #ifdef DEBUG | ||
1510 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
1511 | #endif | ||
1512 | struct mx2_buf_internal *ibuf; | ||
1513 | struct mx2_buffer *buf; | ||
1514 | struct vb2_buffer *vb; | ||
1515 | unsigned long phys; | ||
1516 | |||
1517 | ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, | ||
1518 | queue); | ||
1519 | |||
1520 | BUG_ON(ibuf->bufnum != bufnum); | ||
1521 | |||
1522 | if (ibuf->discard) { | ||
1523 | /* | ||
1524 | * Discard buffer must not be returned to user space. | ||
1525 | * Just return it to the discard queue. | ||
1526 | */ | ||
1527 | list_move_tail(pcdev->active_bufs.next, &pcdev->discard); | ||
1528 | } else { | ||
1529 | buf = mx2_ibuf_to_buf(ibuf); | ||
1530 | |||
1531 | vb = &buf->vb; | ||
1532 | #ifdef DEBUG | ||
1533 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1534 | if (prp->cfg.channel == 1) { | ||
1535 | if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + | ||
1536 | 4 * bufnum) != phys) { | ||
1537 | dev_err(pcdev->dev, "%lx != %x\n", phys, | ||
1538 | readl(pcdev->base_emma + | ||
1539 | PRP_DEST_RGB1_PTR + 4 * bufnum)); | ||
1540 | } | ||
1541 | } else { | ||
1542 | if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - | ||
1543 | 0x14 * bufnum) != phys) { | ||
1544 | dev_err(pcdev->dev, "%lx != %x\n", phys, | ||
1545 | readl(pcdev->base_emma + | ||
1546 | PRP_DEST_Y_PTR - 0x14 * bufnum)); | ||
1547 | } | ||
1548 | } | ||
1549 | #endif | ||
1550 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, | ||
1551 | vb2_plane_vaddr(vb, 0), | ||
1552 | vb2_get_plane_payload(vb, 0)); | ||
1553 | |||
1554 | list_del_init(&buf->internal.queue); | ||
1555 | do_gettimeofday(&vb->v4l2_buf.timestamp); | ||
1556 | vb->v4l2_buf.sequence = pcdev->frame_count; | ||
1557 | if (err) | ||
1558 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
1559 | else | ||
1560 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
1561 | } | ||
1562 | |||
1563 | pcdev->frame_count++; | ||
1564 | |||
1565 | if (list_empty(&pcdev->capture)) { | ||
1566 | if (list_empty(&pcdev->discard)) { | ||
1567 | dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", | ||
1568 | __func__); | ||
1569 | return; | ||
1570 | } | ||
1571 | |||
1572 | ibuf = list_first_entry(&pcdev->discard, | ||
1573 | struct mx2_buf_internal, queue); | ||
1574 | ibuf->bufnum = bufnum; | ||
1575 | |||
1576 | list_move_tail(pcdev->discard.next, &pcdev->active_bufs); | ||
1577 | mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); | ||
1578 | return; | ||
1579 | } | ||
1580 | |||
1581 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
1582 | internal.queue); | ||
1583 | |||
1584 | buf->internal.bufnum = bufnum; | ||
1585 | |||
1586 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
1587 | |||
1588 | vb = &buf->vb; | ||
1589 | buf->state = MX2_STATE_ACTIVE; | ||
1590 | |||
1591 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1592 | mx27_update_emma_buf(pcdev, phys, bufnum); | ||
1593 | } | ||
1594 | |||
1595 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | ||
1596 | { | ||
1597 | struct mx2_camera_dev *pcdev = data; | ||
1598 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); | ||
1599 | struct mx2_buf_internal *ibuf; | ||
1600 | |||
1601 | spin_lock(&pcdev->lock); | ||
1602 | |||
1603 | if (list_empty(&pcdev->active_bufs)) { | ||
1604 | dev_warn(pcdev->dev, "%s: called while active list is empty\n", | ||
1605 | __func__); | ||
1606 | |||
1607 | if (!status) { | ||
1608 | spin_unlock(&pcdev->lock); | ||
1609 | return IRQ_NONE; | ||
1610 | } | ||
1611 | } | ||
1612 | |||
1613 | if (status & (1 << 7)) { /* overflow */ | ||
1614 | u32 cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
1615 | writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), | ||
1616 | pcdev->base_emma + PRP_CNTL); | ||
1617 | writel(cntl, pcdev->base_emma + PRP_CNTL); | ||
1618 | |||
1619 | ibuf = list_first_entry(&pcdev->active_bufs, | ||
1620 | struct mx2_buf_internal, queue); | ||
1621 | mx27_camera_frame_done_emma(pcdev, | ||
1622 | ibuf->bufnum, true); | ||
1623 | |||
1624 | status &= ~(1 << 7); | ||
1625 | } else if (((status & (3 << 5)) == (3 << 5)) || | ||
1626 | ((status & (3 << 3)) == (3 << 3))) { | ||
1627 | /* | ||
1628 | * Both buffers have triggered, process the one we're expecting | ||
1629 | * to first | ||
1630 | */ | ||
1631 | ibuf = list_first_entry(&pcdev->active_bufs, | ||
1632 | struct mx2_buf_internal, queue); | ||
1633 | mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); | ||
1634 | status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ | ||
1635 | } else if ((status & (1 << 6)) || (status & (1 << 4))) { | ||
1636 | mx27_camera_frame_done_emma(pcdev, 0, false); | ||
1637 | } else if ((status & (1 << 5)) || (status & (1 << 3))) { | ||
1638 | mx27_camera_frame_done_emma(pcdev, 1, false); | ||
1639 | } | ||
1640 | |||
1641 | spin_unlock(&pcdev->lock); | ||
1642 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); | ||
1643 | |||
1644 | return IRQ_HANDLED; | ||
1645 | } | ||
1646 | |||
1647 | static int __devinit mx27_camera_emma_init(struct platform_device *pdev) | ||
1648 | { | ||
1649 | struct mx2_camera_dev *pcdev = platform_get_drvdata(pdev); | ||
1650 | struct resource *res_emma; | ||
1651 | int irq_emma; | ||
1652 | int err = 0; | ||
1653 | |||
1654 | res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1655 | irq_emma = platform_get_irq(pdev, 1); | ||
1656 | if (!res_emma || !irq_emma) { | ||
1657 | dev_err(pcdev->dev, "no EMMA resources\n"); | ||
1658 | goto out; | ||
1659 | } | ||
1660 | |||
1661 | pcdev->base_emma = devm_request_and_ioremap(pcdev->dev, res_emma); | ||
1662 | if (!pcdev->base_emma) { | ||
1663 | err = -EADDRNOTAVAIL; | ||
1664 | goto out; | ||
1665 | } | ||
1666 | |||
1667 | err = devm_request_irq(pcdev->dev, irq_emma, mx27_camera_emma_irq, 0, | ||
1668 | MX2_CAM_DRV_NAME, pcdev); | ||
1669 | if (err) { | ||
1670 | dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n"); | ||
1671 | goto out; | ||
1672 | } | ||
1673 | |||
1674 | pcdev->clk_emma_ipg = devm_clk_get(pcdev->dev, "emma-ipg"); | ||
1675 | if (IS_ERR(pcdev->clk_emma_ipg)) { | ||
1676 | err = PTR_ERR(pcdev->clk_emma_ipg); | ||
1677 | goto out; | ||
1678 | } | ||
1679 | |||
1680 | clk_prepare_enable(pcdev->clk_emma_ipg); | ||
1681 | |||
1682 | pcdev->clk_emma_ahb = devm_clk_get(pcdev->dev, "emma-ahb"); | ||
1683 | if (IS_ERR(pcdev->clk_emma_ahb)) { | ||
1684 | err = PTR_ERR(pcdev->clk_emma_ahb); | ||
1685 | goto exit_clk_emma_ipg; | ||
1686 | } | ||
1687 | |||
1688 | clk_prepare_enable(pcdev->clk_emma_ahb); | ||
1689 | |||
1690 | err = mx27_camera_emma_prp_reset(pcdev); | ||
1691 | if (err) | ||
1692 | goto exit_clk_emma_ahb; | ||
1693 | |||
1694 | return err; | ||
1695 | |||
1696 | exit_clk_emma_ahb: | ||
1697 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1698 | exit_clk_emma_ipg: | ||
1699 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1700 | out: | ||
1701 | return err; | ||
1702 | } | ||
1703 | |||
1704 | static int __devinit mx2_camera_probe(struct platform_device *pdev) | ||
1705 | { | ||
1706 | struct mx2_camera_dev *pcdev; | ||
1707 | struct resource *res_csi; | ||
1708 | int irq_csi; | ||
1709 | int err = 0; | ||
1710 | |||
1711 | dev_dbg(&pdev->dev, "initialising\n"); | ||
1712 | |||
1713 | res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1714 | irq_csi = platform_get_irq(pdev, 0); | ||
1715 | if (res_csi == NULL || irq_csi < 0) { | ||
1716 | dev_err(&pdev->dev, "Missing platform resources data\n"); | ||
1717 | err = -ENODEV; | ||
1718 | goto exit; | ||
1719 | } | ||
1720 | |||
1721 | pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); | ||
1722 | if (!pcdev) { | ||
1723 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
1724 | err = -ENOMEM; | ||
1725 | goto exit; | ||
1726 | } | ||
1727 | |||
1728 | pcdev->clk_csi = devm_clk_get(&pdev->dev, "ahb"); | ||
1729 | if (IS_ERR(pcdev->clk_csi)) { | ||
1730 | dev_err(&pdev->dev, "Could not get csi clock\n"); | ||
1731 | err = PTR_ERR(pcdev->clk_csi); | ||
1732 | goto exit; | ||
1733 | } | ||
1734 | |||
1735 | pcdev->pdata = pdev->dev.platform_data; | ||
1736 | if (pcdev->pdata) { | ||
1737 | long rate; | ||
1738 | |||
1739 | pcdev->platform_flags = pcdev->pdata->flags; | ||
1740 | |||
1741 | rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2); | ||
1742 | if (rate <= 0) { | ||
1743 | err = -ENODEV; | ||
1744 | goto exit; | ||
1745 | } | ||
1746 | err = clk_set_rate(pcdev->clk_csi, rate); | ||
1747 | if (err < 0) | ||
1748 | goto exit; | ||
1749 | } | ||
1750 | |||
1751 | INIT_LIST_HEAD(&pcdev->capture); | ||
1752 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
1753 | INIT_LIST_HEAD(&pcdev->discard); | ||
1754 | spin_lock_init(&pcdev->lock); | ||
1755 | |||
1756 | pcdev->base_csi = devm_request_and_ioremap(&pdev->dev, res_csi); | ||
1757 | if (!pcdev->base_csi) { | ||
1758 | err = -EADDRNOTAVAIL; | ||
1759 | goto exit; | ||
1760 | } | ||
1761 | |||
1762 | pcdev->dev = &pdev->dev; | ||
1763 | platform_set_drvdata(pdev, pcdev); | ||
1764 | |||
1765 | if (cpu_is_mx25()) { | ||
1766 | err = devm_request_irq(&pdev->dev, irq_csi, mx25_camera_irq, 0, | ||
1767 | MX2_CAM_DRV_NAME, pcdev); | ||
1768 | if (err) { | ||
1769 | dev_err(pcdev->dev, "Camera interrupt register failed \n"); | ||
1770 | goto exit; | ||
1771 | } | ||
1772 | } | ||
1773 | |||
1774 | if (cpu_is_mx27()) { | ||
1775 | err = mx27_camera_emma_init(pdev); | ||
1776 | if (err) | ||
1777 | goto exit; | ||
1778 | } | ||
1779 | |||
1780 | /* | ||
1781 | * We're done with drvdata here. Clear the pointer so that | ||
1782 | * v4l2 core can start using drvdata on its purpose. | ||
1783 | */ | ||
1784 | platform_set_drvdata(pdev, NULL); | ||
1785 | |||
1786 | pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, | ||
1787 | pcdev->soc_host.ops = &mx2_soc_camera_host_ops, | ||
1788 | pcdev->soc_host.priv = pcdev; | ||
1789 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1790 | pcdev->soc_host.nr = pdev->id; | ||
1791 | if (cpu_is_mx25()) | ||
1792 | pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE; | ||
1793 | |||
1794 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1795 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
1796 | err = PTR_ERR(pcdev->alloc_ctx); | ||
1797 | goto eallocctx; | ||
1798 | } | ||
1799 | err = soc_camera_host_register(&pcdev->soc_host); | ||
1800 | if (err) | ||
1801 | goto exit_free_emma; | ||
1802 | |||
1803 | dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n", | ||
1804 | clk_get_rate(pcdev->clk_csi)); | ||
1805 | |||
1806 | return 0; | ||
1807 | |||
1808 | exit_free_emma: | ||
1809 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
1810 | eallocctx: | ||
1811 | if (cpu_is_mx27()) { | ||
1812 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1813 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1814 | } | ||
1815 | exit: | ||
1816 | return err; | ||
1817 | } | ||
1818 | |||
1819 | static int __devexit mx2_camera_remove(struct platform_device *pdev) | ||
1820 | { | ||
1821 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1822 | struct mx2_camera_dev *pcdev = container_of(soc_host, | ||
1823 | struct mx2_camera_dev, soc_host); | ||
1824 | |||
1825 | soc_camera_host_unregister(&pcdev->soc_host); | ||
1826 | |||
1827 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
1828 | |||
1829 | if (cpu_is_mx27()) { | ||
1830 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1831 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1832 | } | ||
1833 | |||
1834 | dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); | ||
1835 | |||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | static struct platform_driver mx2_camera_driver = { | ||
1840 | .driver = { | ||
1841 | .name = MX2_CAM_DRV_NAME, | ||
1842 | }, | ||
1843 | .remove = __devexit_p(mx2_camera_remove), | ||
1844 | }; | ||
1845 | |||
1846 | |||
1847 | static int __init mx2_camera_init(void) | ||
1848 | { | ||
1849 | return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe); | ||
1850 | } | ||
1851 | |||
1852 | static void __exit mx2_camera_exit(void) | ||
1853 | { | ||
1854 | return platform_driver_unregister(&mx2_camera_driver); | ||
1855 | } | ||
1856 | |||
1857 | module_init(mx2_camera_init); | ||
1858 | module_exit(mx2_camera_exit); | ||
1859 | |||
1860 | MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver"); | ||
1861 | MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>"); | ||
1862 | MODULE_LICENSE("GPL"); | ||
1863 | MODULE_VERSION(MX2_CAM_VERSION); | ||
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c new file mode 100644 index 000000000000..3557ac97e430 --- /dev/null +++ b/drivers/media/platform/soc_camera/mx3_camera.c | |||
@@ -0,0 +1,1290 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for i.MX3x camera host | ||
3 | * | ||
4 | * Copyright (C) 2008 | ||
5 | * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/videodev2.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/vmalloc.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/sched.h> | ||
20 | |||
21 | #include <media/v4l2-common.h> | ||
22 | #include <media/v4l2-dev.h> | ||
23 | #include <media/videobuf2-dma-contig.h> | ||
24 | #include <media/soc_camera.h> | ||
25 | #include <media/soc_mediabus.h> | ||
26 | |||
27 | #include <mach/ipu.h> | ||
28 | #include <linux/platform_data/camera-mx3.h> | ||
29 | #include <linux/platform_data/dma-imx.h> | ||
30 | |||
31 | #define MX3_CAM_DRV_NAME "mx3-camera" | ||
32 | |||
33 | /* CMOS Sensor Interface Registers */ | ||
34 | #define CSI_REG_START 0x60 | ||
35 | |||
36 | #define CSI_SENS_CONF (0x60 - CSI_REG_START) | ||
37 | #define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) | ||
38 | #define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) | ||
39 | #define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) | ||
40 | #define CSI_TST_CTRL (0x70 - CSI_REG_START) | ||
41 | #define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) | ||
42 | #define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) | ||
43 | #define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) | ||
44 | #define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) | ||
45 | #define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) | ||
46 | |||
47 | #define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 | ||
48 | #define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 | ||
49 | #define CSI_SENS_CONF_DATA_POL_SHIFT 2 | ||
50 | #define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 | ||
51 | #define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 | ||
52 | #define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 | ||
53 | #define CSI_SENS_CONF_DATA_FMT_SHIFT 8 | ||
54 | #define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 | ||
55 | #define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 | ||
56 | #define CSI_SENS_CONF_DIVRATIO_SHIFT 16 | ||
57 | |||
58 | #define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
59 | #define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
60 | #define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
61 | |||
62 | #define MAX_VIDEO_MEM 16 | ||
63 | |||
64 | struct mx3_camera_buffer { | ||
65 | /* common v4l buffer stuff -- must be first */ | ||
66 | struct vb2_buffer vb; | ||
67 | struct list_head queue; | ||
68 | |||
69 | /* One descriptot per scatterlist (per frame) */ | ||
70 | struct dma_async_tx_descriptor *txd; | ||
71 | |||
72 | /* We have to "build" a scatterlist ourselves - one element per frame */ | ||
73 | struct scatterlist sg; | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * struct mx3_camera_dev - i.MX3x camera (CSI) object | ||
78 | * @dev: camera device, to which the coherent buffer is attached | ||
79 | * @icd: currently attached camera sensor | ||
80 | * @clk: pointer to clock | ||
81 | * @base: remapped register base address | ||
82 | * @pdata: platform data | ||
83 | * @platform_flags: platform flags | ||
84 | * @mclk: master clock frequency in Hz | ||
85 | * @capture: list of capture videobuffers | ||
86 | * @lock: protects video buffer lists | ||
87 | * @active: active video buffer | ||
88 | * @idmac_channel: array of pointers to IPU DMAC DMA channels | ||
89 | * @soc_host: embedded soc_host object | ||
90 | */ | ||
91 | struct mx3_camera_dev { | ||
92 | /* | ||
93 | * i.MX3x is only supposed to handle one camera on its Camera Sensor | ||
94 | * Interface. If anyone ever builds hardware to enable more than one | ||
95 | * camera _simultaneously_, they will have to modify this driver too | ||
96 | */ | ||
97 | struct soc_camera_device *icd; | ||
98 | struct clk *clk; | ||
99 | |||
100 | void __iomem *base; | ||
101 | |||
102 | struct mx3_camera_pdata *pdata; | ||
103 | |||
104 | unsigned long platform_flags; | ||
105 | unsigned long mclk; | ||
106 | u16 width_flags; /* max 15 bits */ | ||
107 | |||
108 | struct list_head capture; | ||
109 | spinlock_t lock; /* Protects video buffer lists */ | ||
110 | struct mx3_camera_buffer *active; | ||
111 | size_t buf_total; | ||
112 | struct vb2_alloc_ctx *alloc_ctx; | ||
113 | enum v4l2_field field; | ||
114 | int sequence; | ||
115 | |||
116 | /* IDMAC / dmaengine interface */ | ||
117 | struct idmac_channel *idmac_channel[1]; /* We need one channel */ | ||
118 | |||
119 | struct soc_camera_host soc_host; | ||
120 | }; | ||
121 | |||
122 | struct dma_chan_request { | ||
123 | struct mx3_camera_dev *mx3_cam; | ||
124 | enum ipu_channel id; | ||
125 | }; | ||
126 | |||
127 | static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) | ||
128 | { | ||
129 | return __raw_readl(mx3->base + reg); | ||
130 | } | ||
131 | |||
132 | static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) | ||
133 | { | ||
134 | __raw_writel(value, mx3->base + reg); | ||
135 | } | ||
136 | |||
137 | static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb) | ||
138 | { | ||
139 | return container_of(vb, struct mx3_camera_buffer, vb); | ||
140 | } | ||
141 | |||
142 | /* Called from the IPU IDMAC ISR */ | ||
143 | static void mx3_cam_dma_done(void *arg) | ||
144 | { | ||
145 | struct idmac_tx_desc *desc = to_tx_desc(arg); | ||
146 | struct dma_chan *chan = desc->txd.chan; | ||
147 | struct idmac_channel *ichannel = to_idmac_chan(chan); | ||
148 | struct mx3_camera_dev *mx3_cam = ichannel->client; | ||
149 | |||
150 | dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", | ||
151 | desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); | ||
152 | |||
153 | spin_lock(&mx3_cam->lock); | ||
154 | if (mx3_cam->active) { | ||
155 | struct vb2_buffer *vb = &mx3_cam->active->vb; | ||
156 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | ||
157 | |||
158 | list_del_init(&buf->queue); | ||
159 | do_gettimeofday(&vb->v4l2_buf.timestamp); | ||
160 | vb->v4l2_buf.field = mx3_cam->field; | ||
161 | vb->v4l2_buf.sequence = mx3_cam->sequence++; | ||
162 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
163 | } | ||
164 | |||
165 | if (list_empty(&mx3_cam->capture)) { | ||
166 | mx3_cam->active = NULL; | ||
167 | spin_unlock(&mx3_cam->lock); | ||
168 | |||
169 | /* | ||
170 | * stop capture - without further buffers IPU_CHA_BUF0_RDY will | ||
171 | * not get updated | ||
172 | */ | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | mx3_cam->active = list_entry(mx3_cam->capture.next, | ||
177 | struct mx3_camera_buffer, queue); | ||
178 | spin_unlock(&mx3_cam->lock); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Videobuf operations | ||
183 | */ | ||
184 | |||
185 | /* | ||
186 | * Calculate the __buffer__ (not data) size and number of buffers. | ||
187 | */ | ||
188 | static int mx3_videobuf_setup(struct vb2_queue *vq, | ||
189 | const struct v4l2_format *fmt, | ||
190 | unsigned int *count, unsigned int *num_planes, | ||
191 | unsigned int sizes[], void *alloc_ctxs[]) | ||
192 | { | ||
193 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
194 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
195 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
196 | |||
197 | if (!mx3_cam->idmac_channel[0]) | ||
198 | return -EINVAL; | ||
199 | |||
200 | if (fmt) { | ||
201 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | ||
202 | fmt->fmt.pix.pixelformat); | ||
203 | unsigned int bytes_per_line; | ||
204 | int ret; | ||
205 | |||
206 | if (!xlate) | ||
207 | return -EINVAL; | ||
208 | |||
209 | ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | ||
210 | xlate->host_fmt); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | |||
214 | bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret); | ||
215 | |||
216 | ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line, | ||
217 | fmt->fmt.pix.height); | ||
218 | if (ret < 0) | ||
219 | return ret; | ||
220 | |||
221 | sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret); | ||
222 | } else { | ||
223 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
224 | sizes[0] = icd->sizeimage; | ||
225 | } | ||
226 | |||
227 | alloc_ctxs[0] = mx3_cam->alloc_ctx; | ||
228 | |||
229 | if (!vq->num_buffers) | ||
230 | mx3_cam->sequence = 0; | ||
231 | |||
232 | if (!*count) | ||
233 | *count = 2; | ||
234 | |||
235 | /* If *num_planes != 0, we have already verified *count. */ | ||
236 | if (!*num_planes && | ||
237 | sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) | ||
238 | *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / | ||
239 | sizes[0]; | ||
240 | |||
241 | *num_planes = 1; | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) | ||
247 | { | ||
248 | /* Add more formats as need arises and test possibilities appear... */ | ||
249 | switch (fourcc) { | ||
250 | case V4L2_PIX_FMT_RGB24: | ||
251 | return IPU_PIX_FMT_RGB24; | ||
252 | case V4L2_PIX_FMT_UYVY: | ||
253 | case V4L2_PIX_FMT_RGB565: | ||
254 | default: | ||
255 | return IPU_PIX_FMT_GENERIC; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static void mx3_videobuf_queue(struct vb2_buffer *vb) | ||
260 | { | ||
261 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
262 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
263 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
264 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | ||
265 | struct scatterlist *sg = &buf->sg; | ||
266 | struct dma_async_tx_descriptor *txd; | ||
267 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
268 | struct idmac_video_param *video = &ichan->params.video; | ||
269 | const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; | ||
270 | unsigned long flags; | ||
271 | dma_cookie_t cookie; | ||
272 | size_t new_size; | ||
273 | |||
274 | new_size = icd->sizeimage; | ||
275 | |||
276 | if (vb2_plane_size(vb, 0) < new_size) { | ||
277 | dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", | ||
278 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size); | ||
279 | goto error; | ||
280 | } | ||
281 | |||
282 | if (!buf->txd) { | ||
283 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
284 | sg_dma_len(sg) = new_size; | ||
285 | |||
286 | txd = dmaengine_prep_slave_sg( | ||
287 | &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM, | ||
288 | DMA_PREP_INTERRUPT); | ||
289 | if (!txd) | ||
290 | goto error; | ||
291 | |||
292 | txd->callback_param = txd; | ||
293 | txd->callback = mx3_cam_dma_done; | ||
294 | |||
295 | buf->txd = txd; | ||
296 | } else { | ||
297 | txd = buf->txd; | ||
298 | } | ||
299 | |||
300 | vb2_set_plane_payload(vb, 0, new_size); | ||
301 | |||
302 | /* This is the configuration of one sg-element */ | ||
303 | video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); | ||
304 | |||
305 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { | ||
306 | /* | ||
307 | * If the IPU DMA channel is configured to transfer generic | ||
308 | * 8-bit data, we have to set up the geometry parameters | ||
309 | * correctly, according to the current pixel format. The DMA | ||
310 | * horizontal parameters in this case are expressed in bytes, | ||
311 | * not in pixels. | ||
312 | */ | ||
313 | video->out_width = icd->bytesperline; | ||
314 | video->out_height = icd->user_height; | ||
315 | video->out_stride = icd->bytesperline; | ||
316 | } else { | ||
317 | /* | ||
318 | * For IPU known formats the pixel unit will be managed | ||
319 | * successfully by the IPU code | ||
320 | */ | ||
321 | video->out_width = icd->user_width; | ||
322 | video->out_height = icd->user_height; | ||
323 | video->out_stride = icd->user_width; | ||
324 | } | ||
325 | |||
326 | #ifdef DEBUG | ||
327 | /* helps to see what DMA actually has written */ | ||
328 | if (vb2_plane_vaddr(vb, 0)) | ||
329 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | ||
330 | #endif | ||
331 | |||
332 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
333 | list_add_tail(&buf->queue, &mx3_cam->capture); | ||
334 | |||
335 | if (!mx3_cam->active) | ||
336 | mx3_cam->active = buf; | ||
337 | |||
338 | spin_unlock_irq(&mx3_cam->lock); | ||
339 | |||
340 | cookie = txd->tx_submit(txd); | ||
341 | dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n", | ||
342 | cookie, sg_dma_address(&buf->sg)); | ||
343 | |||
344 | if (cookie >= 0) | ||
345 | return; | ||
346 | |||
347 | spin_lock_irq(&mx3_cam->lock); | ||
348 | |||
349 | /* Submit error */ | ||
350 | list_del_init(&buf->queue); | ||
351 | |||
352 | if (mx3_cam->active == buf) | ||
353 | mx3_cam->active = NULL; | ||
354 | |||
355 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
356 | error: | ||
357 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
358 | } | ||
359 | |||
360 | static void mx3_videobuf_release(struct vb2_buffer *vb) | ||
361 | { | ||
362 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
363 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
364 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
365 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | ||
366 | struct dma_async_tx_descriptor *txd = buf->txd; | ||
367 | unsigned long flags; | ||
368 | |||
369 | dev_dbg(icd->parent, | ||
370 | "Release%s DMA 0x%08x, queue %sempty\n", | ||
371 | mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), | ||
372 | list_empty(&buf->queue) ? "" : "not "); | ||
373 | |||
374 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
375 | |||
376 | if (mx3_cam->active == buf) | ||
377 | mx3_cam->active = NULL; | ||
378 | |||
379 | /* Doesn't hurt also if the list is empty */ | ||
380 | list_del_init(&buf->queue); | ||
381 | |||
382 | if (txd) { | ||
383 | buf->txd = NULL; | ||
384 | if (mx3_cam->idmac_channel[0]) | ||
385 | async_tx_ack(txd); | ||
386 | } | ||
387 | |||
388 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
389 | |||
390 | mx3_cam->buf_total -= vb2_plane_size(vb, 0); | ||
391 | } | ||
392 | |||
393 | static int mx3_videobuf_init(struct vb2_buffer *vb) | ||
394 | { | ||
395 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
396 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
397 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
398 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | ||
399 | |||
400 | if (!buf->txd) { | ||
401 | /* This is for locking debugging only */ | ||
402 | INIT_LIST_HEAD(&buf->queue); | ||
403 | sg_init_table(&buf->sg, 1); | ||
404 | |||
405 | mx3_cam->buf_total += vb2_plane_size(vb, 0); | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int mx3_stop_streaming(struct vb2_queue *q) | ||
412 | { | ||
413 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
414 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
415 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
416 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
417 | struct mx3_camera_buffer *buf, *tmp; | ||
418 | unsigned long flags; | ||
419 | |||
420 | if (ichan) { | ||
421 | struct dma_chan *chan = &ichan->dma_chan; | ||
422 | chan->device->device_control(chan, DMA_PAUSE, 0); | ||
423 | } | ||
424 | |||
425 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
426 | |||
427 | mx3_cam->active = NULL; | ||
428 | |||
429 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { | ||
430 | list_del_init(&buf->queue); | ||
431 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
432 | } | ||
433 | |||
434 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct vb2_ops mx3_videobuf_ops = { | ||
440 | .queue_setup = mx3_videobuf_setup, | ||
441 | .buf_queue = mx3_videobuf_queue, | ||
442 | .buf_cleanup = mx3_videobuf_release, | ||
443 | .buf_init = mx3_videobuf_init, | ||
444 | .wait_prepare = soc_camera_unlock, | ||
445 | .wait_finish = soc_camera_lock, | ||
446 | .stop_streaming = mx3_stop_streaming, | ||
447 | }; | ||
448 | |||
449 | static int mx3_camera_init_videobuf(struct vb2_queue *q, | ||
450 | struct soc_camera_device *icd) | ||
451 | { | ||
452 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
453 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
454 | q->drv_priv = icd; | ||
455 | q->ops = &mx3_videobuf_ops; | ||
456 | q->mem_ops = &vb2_dma_contig_memops; | ||
457 | q->buf_struct_size = sizeof(struct mx3_camera_buffer); | ||
458 | |||
459 | return vb2_queue_init(q); | ||
460 | } | ||
461 | |||
462 | /* First part of ipu_csi_init_interface() */ | ||
463 | static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, | ||
464 | struct soc_camera_device *icd) | ||
465 | { | ||
466 | u32 conf; | ||
467 | long rate; | ||
468 | |||
469 | /* Set default size: ipu_csi_set_window_size() */ | ||
470 | csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); | ||
471 | /* ...and position to 0:0: ipu_csi_set_window_pos() */ | ||
472 | conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; | ||
473 | csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); | ||
474 | |||
475 | /* We use only gated clock synchronisation mode so far */ | ||
476 | conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; | ||
477 | |||
478 | /* Set generic data, platform-biggest bus-width */ | ||
479 | conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | ||
480 | |||
481 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
482 | conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
483 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
484 | conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
485 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
486 | conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
487 | else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ | ||
488 | conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
489 | |||
490 | if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) | ||
491 | conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; | ||
492 | if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) | ||
493 | conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; | ||
494 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | ||
495 | conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | ||
496 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | ||
497 | conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | ||
498 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | ||
499 | conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | ||
500 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | ||
501 | conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | ||
502 | |||
503 | /* ipu_csi_init_interface() */ | ||
504 | csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); | ||
505 | |||
506 | clk_prepare_enable(mx3_cam->clk); | ||
507 | rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); | ||
508 | dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); | ||
509 | if (rate) | ||
510 | clk_set_rate(mx3_cam->clk, rate); | ||
511 | } | ||
512 | |||
513 | /* Called with .video_lock held */ | ||
514 | static int mx3_camera_add_device(struct soc_camera_device *icd) | ||
515 | { | ||
516 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
517 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
518 | |||
519 | if (mx3_cam->icd) | ||
520 | return -EBUSY; | ||
521 | |||
522 | mx3_camera_activate(mx3_cam, icd); | ||
523 | |||
524 | mx3_cam->buf_total = 0; | ||
525 | mx3_cam->icd = icd; | ||
526 | |||
527 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", | ||
528 | icd->devnum); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /* Called with .video_lock held */ | ||
534 | static void mx3_camera_remove_device(struct soc_camera_device *icd) | ||
535 | { | ||
536 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
537 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
538 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
539 | |||
540 | BUG_ON(icd != mx3_cam->icd); | ||
541 | |||
542 | if (*ichan) { | ||
543 | dma_release_channel(&(*ichan)->dma_chan); | ||
544 | *ichan = NULL; | ||
545 | } | ||
546 | |||
547 | clk_disable_unprepare(mx3_cam->clk); | ||
548 | |||
549 | mx3_cam->icd = NULL; | ||
550 | |||
551 | dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n", | ||
552 | icd->devnum); | ||
553 | } | ||
554 | |||
555 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | ||
556 | unsigned char buswidth, unsigned long *flags) | ||
557 | { | ||
558 | /* | ||
559 | * If requested data width is supported by the platform, use it or any | ||
560 | * possible lower value - i.MX31 is smart enough to shift bits | ||
561 | */ | ||
562 | if (buswidth > fls(mx3_cam->width_flags)) | ||
563 | return -EINVAL; | ||
564 | |||
565 | /* | ||
566 | * Platform specified synchronization and pixel clock polarities are | ||
567 | * only a recommendation and are only used during probing. MX3x | ||
568 | * camera interface only works in master mode, i.e., uses HSYNC and | ||
569 | * VSYNC signals from the sensor | ||
570 | */ | ||
571 | *flags = V4L2_MBUS_MASTER | | ||
572 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
573 | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
574 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
575 | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
576 | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
577 | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
578 | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
579 | V4L2_MBUS_DATA_ACTIVE_LOW; | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | ||
585 | const unsigned int depth) | ||
586 | { | ||
587 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
588 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
589 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
590 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
591 | unsigned long bus_flags, common_flags; | ||
592 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | ||
593 | |||
594 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); | ||
595 | |||
596 | if (ret < 0) | ||
597 | return ret; | ||
598 | |||
599 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
600 | if (!ret) { | ||
601 | common_flags = soc_mbus_config_compatible(&cfg, | ||
602 | bus_flags); | ||
603 | if (!common_flags) { | ||
604 | dev_warn(icd->parent, | ||
605 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
606 | cfg.flags, bus_flags); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | } else if (ret != -ENOIOCTLCMD) { | ||
610 | return ret; | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static bool chan_filter(struct dma_chan *chan, void *arg) | ||
617 | { | ||
618 | struct dma_chan_request *rq = arg; | ||
619 | struct mx3_camera_pdata *pdata; | ||
620 | |||
621 | if (!imx_dma_is_ipu(chan)) | ||
622 | return false; | ||
623 | |||
624 | if (!rq) | ||
625 | return false; | ||
626 | |||
627 | pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; | ||
628 | |||
629 | return rq->id == chan->chan_id && | ||
630 | pdata->dma_dev == chan->device->dev; | ||
631 | } | ||
632 | |||
633 | static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { | ||
634 | { | ||
635 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
636 | .name = "Bayer BGGR (sRGB) 8 bit", | ||
637 | .bits_per_sample = 8, | ||
638 | .packing = SOC_MBUS_PACKING_NONE, | ||
639 | .order = SOC_MBUS_ORDER_LE, | ||
640 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
641 | }, { | ||
642 | .fourcc = V4L2_PIX_FMT_GREY, | ||
643 | .name = "Monochrome 8 bit", | ||
644 | .bits_per_sample = 8, | ||
645 | .packing = SOC_MBUS_PACKING_NONE, | ||
646 | .order = SOC_MBUS_ORDER_LE, | ||
647 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
648 | }, | ||
649 | }; | ||
650 | |||
651 | /* This will be corrected as we get more formats */ | ||
652 | static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
653 | { | ||
654 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
655 | (fmt->bits_per_sample == 8 && | ||
656 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
657 | (fmt->bits_per_sample > 8 && | ||
658 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
659 | } | ||
660 | |||
661 | static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, | ||
662 | struct soc_camera_format_xlate *xlate) | ||
663 | { | ||
664 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
665 | struct device *dev = icd->parent; | ||
666 | int formats = 0, ret; | ||
667 | enum v4l2_mbus_pixelcode code; | ||
668 | const struct soc_mbus_pixelfmt *fmt; | ||
669 | |||
670 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
671 | if (ret < 0) | ||
672 | /* No more formats */ | ||
673 | return 0; | ||
674 | |||
675 | fmt = soc_mbus_get_fmtdesc(code); | ||
676 | if (!fmt) { | ||
677 | dev_warn(icd->parent, | ||
678 | "Unsupported format code #%u: %d\n", idx, code); | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | /* This also checks support for the requested bits-per-sample */ | ||
683 | ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
684 | if (ret < 0) | ||
685 | return 0; | ||
686 | |||
687 | switch (code) { | ||
688 | case V4L2_MBUS_FMT_SBGGR10_1X10: | ||
689 | formats++; | ||
690 | if (xlate) { | ||
691 | xlate->host_fmt = &mx3_camera_formats[0]; | ||
692 | xlate->code = code; | ||
693 | xlate++; | ||
694 | dev_dbg(dev, "Providing format %s using code %d\n", | ||
695 | mx3_camera_formats[0].name, code); | ||
696 | } | ||
697 | break; | ||
698 | case V4L2_MBUS_FMT_Y10_1X10: | ||
699 | formats++; | ||
700 | if (xlate) { | ||
701 | xlate->host_fmt = &mx3_camera_formats[1]; | ||
702 | xlate->code = code; | ||
703 | xlate++; | ||
704 | dev_dbg(dev, "Providing format %s using code %d\n", | ||
705 | mx3_camera_formats[1].name, code); | ||
706 | } | ||
707 | break; | ||
708 | default: | ||
709 | if (!mx3_camera_packing_supported(fmt)) | ||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | /* Generic pass-through */ | ||
714 | formats++; | ||
715 | if (xlate) { | ||
716 | xlate->host_fmt = fmt; | ||
717 | xlate->code = code; | ||
718 | dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", | ||
719 | (fmt->fourcc >> (0*8)) & 0xFF, | ||
720 | (fmt->fourcc >> (1*8)) & 0xFF, | ||
721 | (fmt->fourcc >> (2*8)) & 0xFF, | ||
722 | (fmt->fourcc >> (3*8)) & 0xFF); | ||
723 | xlate++; | ||
724 | } | ||
725 | |||
726 | return formats; | ||
727 | } | ||
728 | |||
729 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, | ||
730 | unsigned int width, unsigned int height, | ||
731 | const struct soc_mbus_pixelfmt *fmt) | ||
732 | { | ||
733 | u32 ctrl, width_field, height_field; | ||
734 | |||
735 | if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { | ||
736 | /* | ||
737 | * As the CSI will be configured to output BAYER, here | ||
738 | * the width parameter count the number of samples to | ||
739 | * capture to complete the whole image width. | ||
740 | */ | ||
741 | unsigned int num, den; | ||
742 | int ret = soc_mbus_samples_per_pixel(fmt, &num, &den); | ||
743 | BUG_ON(ret < 0); | ||
744 | width = width * num / den; | ||
745 | } | ||
746 | |||
747 | /* Setup frame size - this cannot be changed on-the-fly... */ | ||
748 | width_field = width - 1; | ||
749 | height_field = height - 1; | ||
750 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); | ||
751 | |||
752 | csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); | ||
753 | csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); | ||
754 | |||
755 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); | ||
756 | |||
757 | /* ...and position */ | ||
758 | ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; | ||
759 | /* Sensor does the cropping */ | ||
760 | csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); | ||
761 | } | ||
762 | |||
763 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | ||
764 | { | ||
765 | dma_cap_mask_t mask; | ||
766 | struct dma_chan *chan; | ||
767 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
768 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
769 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
770 | .id = IDMAC_IC_7}; | ||
771 | |||
772 | dma_cap_zero(mask); | ||
773 | dma_cap_set(DMA_SLAVE, mask); | ||
774 | dma_cap_set(DMA_PRIVATE, mask); | ||
775 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
776 | if (!chan) | ||
777 | return -EBUSY; | ||
778 | |||
779 | *ichan = to_idmac_chan(chan); | ||
780 | (*ichan)->client = mx3_cam; | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | /* | ||
786 | * FIXME: learn to use stride != width, then we can keep stride properly aligned | ||
787 | * and support arbitrary (even) widths. | ||
788 | */ | ||
789 | static inline void stride_align(__u32 *width) | ||
790 | { | ||
791 | if (ALIGN(*width, 8) < 4096) | ||
792 | *width = ALIGN(*width, 8); | ||
793 | else | ||
794 | *width = *width & ~7; | ||
795 | } | ||
796 | |||
797 | /* | ||
798 | * As long as we don't implement host-side cropping and scaling, we can use | ||
799 | * default g_crop and cropcap from soc_camera.c | ||
800 | */ | ||
801 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | ||
802 | struct v4l2_crop *a) | ||
803 | { | ||
804 | struct v4l2_rect *rect = &a->c; | ||
805 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
806 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
807 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
808 | struct v4l2_mbus_framefmt mf; | ||
809 | int ret; | ||
810 | |||
811 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); | ||
812 | soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); | ||
813 | |||
814 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
815 | if (ret < 0) | ||
816 | return ret; | ||
817 | |||
818 | /* The capture device might have changed its output sizes */ | ||
819 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
820 | if (ret < 0) | ||
821 | return ret; | ||
822 | |||
823 | if (mf.code != icd->current_fmt->code) | ||
824 | return -EINVAL; | ||
825 | |||
826 | if (mf.width & 7) { | ||
827 | /* Ouch! We can only handle 8-byte aligned width... */ | ||
828 | stride_align(&mf.width); | ||
829 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
830 | if (ret < 0) | ||
831 | return ret; | ||
832 | } | ||
833 | |||
834 | if (mf.width != icd->user_width || mf.height != icd->user_height) | ||
835 | configure_geometry(mx3_cam, mf.width, mf.height, | ||
836 | icd->current_fmt->host_fmt); | ||
837 | |||
838 | dev_dbg(icd->parent, "Sensor cropped %dx%d\n", | ||
839 | mf.width, mf.height); | ||
840 | |||
841 | icd->user_width = mf.width; | ||
842 | icd->user_height = mf.height; | ||
843 | |||
844 | return ret; | ||
845 | } | ||
846 | |||
847 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | ||
848 | struct v4l2_format *f) | ||
849 | { | ||
850 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
851 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
852 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
853 | const struct soc_camera_format_xlate *xlate; | ||
854 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
855 | struct v4l2_mbus_framefmt mf; | ||
856 | int ret; | ||
857 | |||
858 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
859 | if (!xlate) { | ||
860 | dev_warn(icd->parent, "Format %x not found\n", | ||
861 | pix->pixelformat); | ||
862 | return -EINVAL; | ||
863 | } | ||
864 | |||
865 | stride_align(&pix->width); | ||
866 | dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height); | ||
867 | |||
868 | /* | ||
869 | * Might have to perform a complete interface initialisation like in | ||
870 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
871 | * mxc_v4l2_s_fmt() | ||
872 | */ | ||
873 | |||
874 | configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); | ||
875 | |||
876 | mf.width = pix->width; | ||
877 | mf.height = pix->height; | ||
878 | mf.field = pix->field; | ||
879 | mf.colorspace = pix->colorspace; | ||
880 | mf.code = xlate->code; | ||
881 | |||
882 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
883 | if (ret < 0) | ||
884 | return ret; | ||
885 | |||
886 | if (mf.code != xlate->code) | ||
887 | return -EINVAL; | ||
888 | |||
889 | if (!mx3_cam->idmac_channel[0]) { | ||
890 | ret = acquire_dma_channel(mx3_cam); | ||
891 | if (ret < 0) | ||
892 | return ret; | ||
893 | } | ||
894 | |||
895 | pix->width = mf.width; | ||
896 | pix->height = mf.height; | ||
897 | pix->field = mf.field; | ||
898 | mx3_cam->field = mf.field; | ||
899 | pix->colorspace = mf.colorspace; | ||
900 | icd->current_fmt = xlate; | ||
901 | |||
902 | dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); | ||
903 | |||
904 | return ret; | ||
905 | } | ||
906 | |||
907 | static int mx3_camera_try_fmt(struct soc_camera_device *icd, | ||
908 | struct v4l2_format *f) | ||
909 | { | ||
910 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
911 | const struct soc_camera_format_xlate *xlate; | ||
912 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
913 | struct v4l2_mbus_framefmt mf; | ||
914 | __u32 pixfmt = pix->pixelformat; | ||
915 | int ret; | ||
916 | |||
917 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
918 | if (pixfmt && !xlate) { | ||
919 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
920 | return -EINVAL; | ||
921 | } | ||
922 | |||
923 | /* limit to MX3 hardware capabilities */ | ||
924 | if (pix->height > 4096) | ||
925 | pix->height = 4096; | ||
926 | if (pix->width > 4096) | ||
927 | pix->width = 4096; | ||
928 | |||
929 | /* limit to sensor capabilities */ | ||
930 | mf.width = pix->width; | ||
931 | mf.height = pix->height; | ||
932 | mf.field = pix->field; | ||
933 | mf.colorspace = pix->colorspace; | ||
934 | mf.code = xlate->code; | ||
935 | |||
936 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
937 | if (ret < 0) | ||
938 | return ret; | ||
939 | |||
940 | pix->width = mf.width; | ||
941 | pix->height = mf.height; | ||
942 | pix->colorspace = mf.colorspace; | ||
943 | |||
944 | switch (mf.field) { | ||
945 | case V4L2_FIELD_ANY: | ||
946 | pix->field = V4L2_FIELD_NONE; | ||
947 | break; | ||
948 | case V4L2_FIELD_NONE: | ||
949 | break; | ||
950 | default: | ||
951 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
952 | mf.field); | ||
953 | ret = -EINVAL; | ||
954 | } | ||
955 | |||
956 | return ret; | ||
957 | } | ||
958 | |||
959 | static int mx3_camera_reqbufs(struct soc_camera_device *icd, | ||
960 | struct v4l2_requestbuffers *p) | ||
961 | { | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) | ||
966 | { | ||
967 | struct soc_camera_device *icd = file->private_data; | ||
968 | |||
969 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
970 | } | ||
971 | |||
972 | static int mx3_camera_querycap(struct soc_camera_host *ici, | ||
973 | struct v4l2_capability *cap) | ||
974 | { | ||
975 | /* cap->name is set by the firendly caller:-> */ | ||
976 | strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); | ||
977 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd) | ||
983 | { | ||
984 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
985 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
986 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
987 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
988 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | ||
989 | unsigned long bus_flags, common_flags; | ||
990 | u32 dw, sens_conf; | ||
991 | const struct soc_mbus_pixelfmt *fmt; | ||
992 | int buswidth; | ||
993 | int ret; | ||
994 | const struct soc_camera_format_xlate *xlate; | ||
995 | struct device *dev = icd->parent; | ||
996 | |||
997 | fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); | ||
998 | if (!fmt) | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1002 | if (!xlate) { | ||
1003 | dev_warn(dev, "Format %x not found\n", pixfmt); | ||
1004 | return -EINVAL; | ||
1005 | } | ||
1006 | |||
1007 | buswidth = fmt->bits_per_sample; | ||
1008 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
1009 | |||
1010 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); | ||
1011 | |||
1012 | if (ret < 0) | ||
1013 | return ret; | ||
1014 | |||
1015 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1016 | if (!ret) { | ||
1017 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1018 | bus_flags); | ||
1019 | if (!common_flags) { | ||
1020 | dev_warn(icd->parent, | ||
1021 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1022 | cfg.flags, bus_flags); | ||
1023 | return -EINVAL; | ||
1024 | } | ||
1025 | } else if (ret != -ENOIOCTLCMD) { | ||
1026 | return ret; | ||
1027 | } else { | ||
1028 | common_flags = bus_flags; | ||
1029 | } | ||
1030 | |||
1031 | dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", | ||
1032 | cfg.flags, bus_flags, common_flags); | ||
1033 | |||
1034 | /* Make choices, based on platform preferences */ | ||
1035 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
1036 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
1037 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | ||
1038 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
1039 | else | ||
1040 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
1041 | } | ||
1042 | |||
1043 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
1044 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
1045 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | ||
1046 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
1047 | else | ||
1048 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
1049 | } | ||
1050 | |||
1051 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && | ||
1052 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { | ||
1053 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | ||
1054 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
1055 | else | ||
1056 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; | ||
1057 | } | ||
1058 | |||
1059 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1060 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1061 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | ||
1062 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1063 | else | ||
1064 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1065 | } | ||
1066 | |||
1067 | cfg.flags = common_flags; | ||
1068 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1069 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1070 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1071 | common_flags, ret); | ||
1072 | return ret; | ||
1073 | } | ||
1074 | |||
1075 | /* | ||
1076 | * So far only gated clock mode is supported. Add a line | ||
1077 | * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | | ||
1078 | * below and select the required mode when supporting other | ||
1079 | * synchronisation protocols. | ||
1080 | */ | ||
1081 | sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & | ||
1082 | ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | | ||
1083 | (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | | ||
1084 | (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | | ||
1085 | (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | | ||
1086 | (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | | ||
1087 | (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); | ||
1088 | |||
1089 | /* TODO: Support RGB and YUV formats */ | ||
1090 | |||
1091 | /* This has been set in mx3_camera_activate(), but we clear it above */ | ||
1092 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | ||
1093 | |||
1094 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
1095 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | ||
1096 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1097 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | ||
1098 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1099 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | ||
1100 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) | ||
1101 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | ||
1102 | |||
1103 | /* Just do what we're asked to do */ | ||
1104 | switch (xlate->host_fmt->bits_per_sample) { | ||
1105 | case 4: | ||
1106 | dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1107 | break; | ||
1108 | case 8: | ||
1109 | dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1110 | break; | ||
1111 | case 10: | ||
1112 | dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1113 | break; | ||
1114 | default: | ||
1115 | /* | ||
1116 | * Actually it can only be 15 now, default is just to silence | ||
1117 | * compiler warnings | ||
1118 | */ | ||
1119 | case 15: | ||
1120 | dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1121 | } | ||
1122 | |||
1123 | csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); | ||
1124 | |||
1125 | dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | static struct soc_camera_host_ops mx3_soc_camera_host_ops = { | ||
1131 | .owner = THIS_MODULE, | ||
1132 | .add = mx3_camera_add_device, | ||
1133 | .remove = mx3_camera_remove_device, | ||
1134 | .set_crop = mx3_camera_set_crop, | ||
1135 | .set_fmt = mx3_camera_set_fmt, | ||
1136 | .try_fmt = mx3_camera_try_fmt, | ||
1137 | .get_formats = mx3_camera_get_formats, | ||
1138 | .init_videobuf2 = mx3_camera_init_videobuf, | ||
1139 | .reqbufs = mx3_camera_reqbufs, | ||
1140 | .poll = mx3_camera_poll, | ||
1141 | .querycap = mx3_camera_querycap, | ||
1142 | .set_bus_param = mx3_camera_set_bus_param, | ||
1143 | }; | ||
1144 | |||
1145 | static int __devinit mx3_camera_probe(struct platform_device *pdev) | ||
1146 | { | ||
1147 | struct mx3_camera_dev *mx3_cam; | ||
1148 | struct resource *res; | ||
1149 | void __iomem *base; | ||
1150 | int err = 0; | ||
1151 | struct soc_camera_host *soc_host; | ||
1152 | |||
1153 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1154 | if (!res) { | ||
1155 | err = -ENODEV; | ||
1156 | goto egetres; | ||
1157 | } | ||
1158 | |||
1159 | mx3_cam = vzalloc(sizeof(*mx3_cam)); | ||
1160 | if (!mx3_cam) { | ||
1161 | dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); | ||
1162 | err = -ENOMEM; | ||
1163 | goto ealloc; | ||
1164 | } | ||
1165 | |||
1166 | mx3_cam->clk = clk_get(&pdev->dev, NULL); | ||
1167 | if (IS_ERR(mx3_cam->clk)) { | ||
1168 | err = PTR_ERR(mx3_cam->clk); | ||
1169 | goto eclkget; | ||
1170 | } | ||
1171 | |||
1172 | mx3_cam->pdata = pdev->dev.platform_data; | ||
1173 | mx3_cam->platform_flags = mx3_cam->pdata->flags; | ||
1174 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) { | ||
1175 | /* | ||
1176 | * Platform hasn't set available data widths. This is bad. | ||
1177 | * Warn and use a default. | ||
1178 | */ | ||
1179 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | ||
1180 | "data widths, using default 8 bit\n"); | ||
1181 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | ||
1182 | } | ||
1183 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
1184 | mx3_cam->width_flags = 1 << 3; | ||
1185 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
1186 | mx3_cam->width_flags |= 1 << 7; | ||
1187 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
1188 | mx3_cam->width_flags |= 1 << 9; | ||
1189 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
1190 | mx3_cam->width_flags |= 1 << 14; | ||
1191 | |||
1192 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; | ||
1193 | if (!mx3_cam->mclk) { | ||
1194 | dev_warn(&pdev->dev, | ||
1195 | "mclk_10khz == 0! Please, fix your platform data. " | ||
1196 | "Using default 20MHz\n"); | ||
1197 | mx3_cam->mclk = 20000000; | ||
1198 | } | ||
1199 | |||
1200 | /* list of video-buffers */ | ||
1201 | INIT_LIST_HEAD(&mx3_cam->capture); | ||
1202 | spin_lock_init(&mx3_cam->lock); | ||
1203 | |||
1204 | base = ioremap(res->start, resource_size(res)); | ||
1205 | if (!base) { | ||
1206 | pr_err("Couldn't map %x@%x\n", resource_size(res), res->start); | ||
1207 | err = -ENOMEM; | ||
1208 | goto eioremap; | ||
1209 | } | ||
1210 | |||
1211 | mx3_cam->base = base; | ||
1212 | |||
1213 | soc_host = &mx3_cam->soc_host; | ||
1214 | soc_host->drv_name = MX3_CAM_DRV_NAME; | ||
1215 | soc_host->ops = &mx3_soc_camera_host_ops; | ||
1216 | soc_host->priv = mx3_cam; | ||
1217 | soc_host->v4l2_dev.dev = &pdev->dev; | ||
1218 | soc_host->nr = pdev->id; | ||
1219 | |||
1220 | mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1221 | if (IS_ERR(mx3_cam->alloc_ctx)) { | ||
1222 | err = PTR_ERR(mx3_cam->alloc_ctx); | ||
1223 | goto eallocctx; | ||
1224 | } | ||
1225 | |||
1226 | err = soc_camera_host_register(soc_host); | ||
1227 | if (err) | ||
1228 | goto ecamhostreg; | ||
1229 | |||
1230 | /* IDMAC interface */ | ||
1231 | dmaengine_get(); | ||
1232 | |||
1233 | return 0; | ||
1234 | |||
1235 | ecamhostreg: | ||
1236 | vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); | ||
1237 | eallocctx: | ||
1238 | iounmap(base); | ||
1239 | eioremap: | ||
1240 | clk_put(mx3_cam->clk); | ||
1241 | eclkget: | ||
1242 | vfree(mx3_cam); | ||
1243 | ealloc: | ||
1244 | egetres: | ||
1245 | return err; | ||
1246 | } | ||
1247 | |||
1248 | static int __devexit mx3_camera_remove(struct platform_device *pdev) | ||
1249 | { | ||
1250 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1251 | struct mx3_camera_dev *mx3_cam = container_of(soc_host, | ||
1252 | struct mx3_camera_dev, soc_host); | ||
1253 | |||
1254 | clk_put(mx3_cam->clk); | ||
1255 | |||
1256 | soc_camera_host_unregister(soc_host); | ||
1257 | |||
1258 | iounmap(mx3_cam->base); | ||
1259 | |||
1260 | /* | ||
1261 | * The channel has either not been allocated, | ||
1262 | * or should have been released | ||
1263 | */ | ||
1264 | if (WARN_ON(mx3_cam->idmac_channel[0])) | ||
1265 | dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); | ||
1266 | |||
1267 | vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); | ||
1268 | |||
1269 | vfree(mx3_cam); | ||
1270 | |||
1271 | dmaengine_put(); | ||
1272 | |||
1273 | return 0; | ||
1274 | } | ||
1275 | |||
1276 | static struct platform_driver mx3_camera_driver = { | ||
1277 | .driver = { | ||
1278 | .name = MX3_CAM_DRV_NAME, | ||
1279 | }, | ||
1280 | .probe = mx3_camera_probe, | ||
1281 | .remove = __devexit_p(mx3_camera_remove), | ||
1282 | }; | ||
1283 | |||
1284 | module_platform_driver(mx3_camera_driver); | ||
1285 | |||
1286 | MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); | ||
1287 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); | ||
1288 | MODULE_LICENSE("GPL v2"); | ||
1289 | MODULE_VERSION("0.2.3"); | ||
1290 | MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); | ||
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c new file mode 100644 index 000000000000..fa08c7695ccb --- /dev/null +++ b/drivers/media/platform/soc_camera/omap1_camera.c | |||
@@ -0,0 +1,1723 @@ | |||
1 | /* | ||
2 | * V4L2 SoC Camera driver for OMAP1 Camera Interface | ||
3 | * | ||
4 | * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> | ||
5 | * | ||
6 | * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host | ||
7 | * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
8 | * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com> | ||
9 | * | ||
10 | * Based on PXA SoC camera driver | ||
11 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | ||
12 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
13 | * | ||
14 | * Hardware specific bits initialy based on former work by Matt Callow | ||
15 | * drivers/media/platform/omap/omap1510cam.c | ||
16 | * Copyright (C) 2006 Matt Callow | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License version 2 as | ||
20 | * published by the Free Software Foundation. | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/clk.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <media/omap1_camera.h> | ||
32 | #include <media/soc_camera.h> | ||
33 | #include <media/soc_mediabus.h> | ||
34 | #include <media/videobuf-dma-contig.h> | ||
35 | #include <media/videobuf-dma-sg.h> | ||
36 | |||
37 | #include <plat/dma.h> | ||
38 | |||
39 | |||
40 | #define DRIVER_NAME "omap1-camera" | ||
41 | #define DRIVER_VERSION "0.0.2" | ||
42 | |||
43 | |||
44 | /* | ||
45 | * --------------------------------------------------------------------------- | ||
46 | * OMAP1 Camera Interface registers | ||
47 | * --------------------------------------------------------------------------- | ||
48 | */ | ||
49 | |||
50 | #define REG_CTRLCLOCK 0x00 | ||
51 | #define REG_IT_STATUS 0x04 | ||
52 | #define REG_MODE 0x08 | ||
53 | #define REG_STATUS 0x0C | ||
54 | #define REG_CAMDATA 0x10 | ||
55 | #define REG_GPIO 0x14 | ||
56 | #define REG_PEAK_COUNTER 0x18 | ||
57 | |||
58 | /* CTRLCLOCK bit shifts */ | ||
59 | #define LCLK_EN BIT(7) | ||
60 | #define DPLL_EN BIT(6) | ||
61 | #define MCLK_EN BIT(5) | ||
62 | #define CAMEXCLK_EN BIT(4) | ||
63 | #define POLCLK BIT(3) | ||
64 | #define FOSCMOD_SHIFT 0 | ||
65 | #define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT) | ||
66 | #define FOSCMOD_12MHz 0x0 | ||
67 | #define FOSCMOD_6MHz 0x2 | ||
68 | #define FOSCMOD_9_6MHz 0x4 | ||
69 | #define FOSCMOD_24MHz 0x5 | ||
70 | #define FOSCMOD_8MHz 0x6 | ||
71 | |||
72 | /* IT_STATUS bit shifts */ | ||
73 | #define DATA_TRANSFER BIT(5) | ||
74 | #define FIFO_FULL BIT(4) | ||
75 | #define H_DOWN BIT(3) | ||
76 | #define H_UP BIT(2) | ||
77 | #define V_DOWN BIT(1) | ||
78 | #define V_UP BIT(0) | ||
79 | |||
80 | /* MODE bit shifts */ | ||
81 | #define RAZ_FIFO BIT(18) | ||
82 | #define EN_FIFO_FULL BIT(17) | ||
83 | #define EN_NIRQ BIT(16) | ||
84 | #define THRESHOLD_SHIFT 9 | ||
85 | #define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT) | ||
86 | #define DMA BIT(8) | ||
87 | #define EN_H_DOWN BIT(7) | ||
88 | #define EN_H_UP BIT(6) | ||
89 | #define EN_V_DOWN BIT(5) | ||
90 | #define EN_V_UP BIT(4) | ||
91 | #define ORDERCAMD BIT(3) | ||
92 | |||
93 | #define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \ | ||
94 | EN_NIRQ | EN_FIFO_FULL) | ||
95 | |||
96 | /* STATUS bit shifts */ | ||
97 | #define HSTATUS BIT(1) | ||
98 | #define VSTATUS BIT(0) | ||
99 | |||
100 | /* GPIO bit shifts */ | ||
101 | #define CAM_RST BIT(0) | ||
102 | |||
103 | /* end of OMAP1 Camera Interface registers */ | ||
104 | |||
105 | |||
106 | #define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
107 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
108 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
109 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
110 | |||
111 | |||
112 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) | ||
113 | #define FIFO_SHIFT __fls(FIFO_SIZE) | ||
114 | |||
115 | #define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4) | ||
116 | #define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT) | ||
117 | |||
118 | #define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32 | ||
119 | #define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT) | ||
120 | |||
121 | #define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1) | ||
122 | #define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT | ||
123 | |||
124 | #define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \ | ||
125 | DMA_FRAME_SHIFT_CONTIG : \ | ||
126 | DMA_FRAME_SHIFT_SG) | ||
127 | #define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x)) | ||
128 | #define DMA_SYNC OMAP_DMA_SYNC_FRAME | ||
129 | #define THRESHOLD_LEVEL DMA_FRAME_SIZE | ||
130 | |||
131 | |||
132 | #define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */ | ||
133 | |||
134 | |||
135 | /* | ||
136 | * Structures | ||
137 | */ | ||
138 | |||
139 | /* buffer for one video frame */ | ||
140 | struct omap1_cam_buf { | ||
141 | struct videobuf_buffer vb; | ||
142 | enum v4l2_mbus_pixelcode code; | ||
143 | int inwork; | ||
144 | struct scatterlist *sgbuf; | ||
145 | int sgcount; | ||
146 | int bytes_left; | ||
147 | enum videobuf_state result; | ||
148 | }; | ||
149 | |||
150 | struct omap1_cam_dev { | ||
151 | struct soc_camera_host soc_host; | ||
152 | struct soc_camera_device *icd; | ||
153 | struct clk *clk; | ||
154 | |||
155 | unsigned int irq; | ||
156 | void __iomem *base; | ||
157 | |||
158 | int dma_ch; | ||
159 | |||
160 | struct omap1_cam_platform_data *pdata; | ||
161 | struct resource *res; | ||
162 | unsigned long pflags; | ||
163 | unsigned long camexclk; | ||
164 | |||
165 | struct list_head capture; | ||
166 | |||
167 | /* lock used to protect videobuf */ | ||
168 | spinlock_t lock; | ||
169 | |||
170 | /* Pointers to DMA buffers */ | ||
171 | struct omap1_cam_buf *active; | ||
172 | struct omap1_cam_buf *ready; | ||
173 | |||
174 | enum omap1_cam_vb_mode vb_mode; | ||
175 | int (*mmap_mapper)(struct videobuf_queue *q, | ||
176 | struct videobuf_buffer *buf, | ||
177 | struct vm_area_struct *vma); | ||
178 | |||
179 | u32 reg_cache[0]; | ||
180 | }; | ||
181 | |||
182 | |||
183 | static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val) | ||
184 | { | ||
185 | pcdev->reg_cache[reg / sizeof(u32)] = val; | ||
186 | __raw_writel(val, pcdev->base + reg); | ||
187 | } | ||
188 | |||
189 | static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache) | ||
190 | { | ||
191 | return !from_cache ? __raw_readl(pcdev->base + reg) : | ||
192 | pcdev->reg_cache[reg / sizeof(u32)]; | ||
193 | } | ||
194 | |||
195 | #define CAM_READ(pcdev, reg) \ | ||
196 | cam_read(pcdev, REG_##reg, false) | ||
197 | #define CAM_WRITE(pcdev, reg, val) \ | ||
198 | cam_write(pcdev, REG_##reg, val) | ||
199 | #define CAM_READ_CACHE(pcdev, reg) \ | ||
200 | cam_read(pcdev, REG_##reg, true) | ||
201 | |||
202 | /* | ||
203 | * Videobuf operations | ||
204 | */ | ||
205 | static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | ||
206 | unsigned int *size) | ||
207 | { | ||
208 | struct soc_camera_device *icd = vq->priv_data; | ||
209 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
210 | struct omap1_cam_dev *pcdev = ici->priv; | ||
211 | |||
212 | *size = icd->sizeimage; | ||
213 | |||
214 | if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode)) | ||
215 | *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode); | ||
216 | |||
217 | if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) | ||
218 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; | ||
219 | |||
220 | dev_dbg(icd->parent, | ||
221 | "%s: count=%d, size=%d\n", __func__, *count, *size); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf, | ||
227 | enum omap1_cam_vb_mode vb_mode) | ||
228 | { | ||
229 | struct videobuf_buffer *vb = &buf->vb; | ||
230 | |||
231 | BUG_ON(in_interrupt()); | ||
232 | |||
233 | videobuf_waiton(vq, vb, 0, 0); | ||
234 | |||
235 | if (vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
236 | videobuf_dma_contig_free(vq, vb); | ||
237 | } else { | ||
238 | struct soc_camera_device *icd = vq->priv_data; | ||
239 | struct device *dev = icd->parent; | ||
240 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
241 | |||
242 | videobuf_dma_unmap(dev, dma); | ||
243 | videobuf_dma_free(dma); | ||
244 | } | ||
245 | |||
246 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
247 | } | ||
248 | |||
249 | static int omap1_videobuf_prepare(struct videobuf_queue *vq, | ||
250 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
251 | { | ||
252 | struct soc_camera_device *icd = vq->priv_data; | ||
253 | struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb); | ||
254 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
255 | struct omap1_cam_dev *pcdev = ici->priv; | ||
256 | int ret; | ||
257 | |||
258 | WARN_ON(!list_empty(&vb->queue)); | ||
259 | |||
260 | BUG_ON(NULL == icd->current_fmt); | ||
261 | |||
262 | buf->inwork = 1; | ||
263 | |||
264 | if (buf->code != icd->current_fmt->code || vb->field != field || | ||
265 | vb->width != icd->user_width || | ||
266 | vb->height != icd->user_height) { | ||
267 | buf->code = icd->current_fmt->code; | ||
268 | vb->width = icd->user_width; | ||
269 | vb->height = icd->user_height; | ||
270 | vb->field = field; | ||
271 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
272 | } | ||
273 | |||
274 | vb->size = icd->sizeimage; | ||
275 | |||
276 | if (vb->baddr && vb->bsize < vb->size) { | ||
277 | ret = -EINVAL; | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
282 | ret = videobuf_iolock(vq, vb, NULL); | ||
283 | if (ret) | ||
284 | goto fail; | ||
285 | |||
286 | vb->state = VIDEOBUF_PREPARED; | ||
287 | } | ||
288 | buf->inwork = 0; | ||
289 | |||
290 | return 0; | ||
291 | fail: | ||
292 | free_buffer(vq, buf, pcdev->vb_mode); | ||
293 | out: | ||
294 | buf->inwork = 0; | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf, | ||
299 | enum omap1_cam_vb_mode vb_mode) | ||
300 | { | ||
301 | dma_addr_t dma_addr; | ||
302 | unsigned int block_size; | ||
303 | |||
304 | if (vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
305 | dma_addr = videobuf_to_dma_contig(&buf->vb); | ||
306 | block_size = buf->vb.size; | ||
307 | } else { | ||
308 | if (WARN_ON(!buf->sgbuf)) { | ||
309 | buf->result = VIDEOBUF_ERROR; | ||
310 | return; | ||
311 | } | ||
312 | dma_addr = sg_dma_address(buf->sgbuf); | ||
313 | if (WARN_ON(!dma_addr)) { | ||
314 | buf->sgbuf = NULL; | ||
315 | buf->result = VIDEOBUF_ERROR; | ||
316 | return; | ||
317 | } | ||
318 | block_size = sg_dma_len(buf->sgbuf); | ||
319 | if (WARN_ON(!block_size)) { | ||
320 | buf->sgbuf = NULL; | ||
321 | buf->result = VIDEOBUF_ERROR; | ||
322 | return; | ||
323 | } | ||
324 | if (unlikely(buf->bytes_left < block_size)) | ||
325 | block_size = buf->bytes_left; | ||
326 | if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) * | ||
327 | DMA_ELEMENT_SIZE - 1))) { | ||
328 | dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) * | ||
329 | DMA_ELEMENT_SIZE); | ||
330 | block_size &= ~(DMA_FRAME_SIZE(vb_mode) * | ||
331 | DMA_ELEMENT_SIZE - 1); | ||
332 | } | ||
333 | buf->bytes_left -= block_size; | ||
334 | buf->sgcount++; | ||
335 | } | ||
336 | |||
337 | omap_set_dma_dest_params(dma_ch, | ||
338 | OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); | ||
339 | omap_set_dma_transfer_params(dma_ch, | ||
340 | OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode), | ||
341 | block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT), | ||
342 | DMA_SYNC, 0, 0); | ||
343 | } | ||
344 | |||
345 | static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev) | ||
346 | { | ||
347 | struct omap1_cam_buf *buf; | ||
348 | |||
349 | /* | ||
350 | * If there is already a buffer pointed out by the pcdev->ready, | ||
351 | * (re)use it, otherwise try to fetch and configure a new one. | ||
352 | */ | ||
353 | buf = pcdev->ready; | ||
354 | if (!buf) { | ||
355 | if (list_empty(&pcdev->capture)) | ||
356 | return buf; | ||
357 | buf = list_entry(pcdev->capture.next, | ||
358 | struct omap1_cam_buf, vb.queue); | ||
359 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
360 | pcdev->ready = buf; | ||
361 | list_del_init(&buf->vb.queue); | ||
362 | } | ||
363 | |||
364 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
365 | /* | ||
366 | * In CONTIG mode, we can safely enter next buffer parameters | ||
367 | * into the DMA programming register set after the DMA | ||
368 | * has already been activated on the previous buffer | ||
369 | */ | ||
370 | set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode); | ||
371 | } else { | ||
372 | /* | ||
373 | * In SG mode, the above is not safe since there are probably | ||
374 | * a bunch of sgbufs from previous sglist still pending. | ||
375 | * Instead, mark the sglist fresh for the upcoming | ||
376 | * try_next_sgbuf(). | ||
377 | */ | ||
378 | buf->sgbuf = NULL; | ||
379 | } | ||
380 | |||
381 | return buf; | ||
382 | } | ||
383 | |||
384 | static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf) | ||
385 | { | ||
386 | struct scatterlist *sgbuf; | ||
387 | |||
388 | if (likely(buf->sgbuf)) { | ||
389 | /* current sglist is active */ | ||
390 | if (unlikely(!buf->bytes_left)) { | ||
391 | /* indicate sglist complete */ | ||
392 | sgbuf = NULL; | ||
393 | } else { | ||
394 | /* process next sgbuf */ | ||
395 | sgbuf = sg_next(buf->sgbuf); | ||
396 | if (WARN_ON(!sgbuf)) { | ||
397 | buf->result = VIDEOBUF_ERROR; | ||
398 | } else if (WARN_ON(!sg_dma_len(sgbuf))) { | ||
399 | sgbuf = NULL; | ||
400 | buf->result = VIDEOBUF_ERROR; | ||
401 | } | ||
402 | } | ||
403 | buf->sgbuf = sgbuf; | ||
404 | } else { | ||
405 | /* sglist is fresh, initialize it before using */ | ||
406 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
407 | |||
408 | sgbuf = dma->sglist; | ||
409 | if (!(WARN_ON(!sgbuf))) { | ||
410 | buf->sgbuf = sgbuf; | ||
411 | buf->sgcount = 0; | ||
412 | buf->bytes_left = buf->vb.size; | ||
413 | buf->result = VIDEOBUF_DONE; | ||
414 | } | ||
415 | } | ||
416 | if (sgbuf) | ||
417 | /* | ||
418 | * Put our next sgbuf parameters (address, size) | ||
419 | * into the DMA programming register set. | ||
420 | */ | ||
421 | set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG); | ||
422 | |||
423 | return sgbuf; | ||
424 | } | ||
425 | |||
426 | static void start_capture(struct omap1_cam_dev *pcdev) | ||
427 | { | ||
428 | struct omap1_cam_buf *buf = pcdev->active; | ||
429 | u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
430 | u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN; | ||
431 | |||
432 | if (WARN_ON(!buf)) | ||
433 | return; | ||
434 | |||
435 | /* | ||
436 | * Enable start of frame interrupt, which we will use for activating | ||
437 | * our end of frame watchdog when capture actually starts. | ||
438 | */ | ||
439 | mode |= EN_V_UP; | ||
440 | |||
441 | if (unlikely(ctrlclock & LCLK_EN)) | ||
442 | /* stop pixel clock before FIFO reset */ | ||
443 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
444 | /* reset FIFO */ | ||
445 | CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO); | ||
446 | |||
447 | omap_start_dma(pcdev->dma_ch); | ||
448 | |||
449 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
450 | /* | ||
451 | * In SG mode, it's a good moment for fetching next sgbuf | ||
452 | * from the current sglist and, if available, already putting | ||
453 | * its parameters into the DMA programming register set. | ||
454 | */ | ||
455 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
456 | } | ||
457 | |||
458 | /* (re)enable pixel clock */ | ||
459 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN); | ||
460 | /* release FIFO reset */ | ||
461 | CAM_WRITE(pcdev, MODE, mode); | ||
462 | } | ||
463 | |||
464 | static void suspend_capture(struct omap1_cam_dev *pcdev) | ||
465 | { | ||
466 | u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
467 | |||
468 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
469 | omap_stop_dma(pcdev->dma_ch); | ||
470 | } | ||
471 | |||
472 | static void disable_capture(struct omap1_cam_dev *pcdev) | ||
473 | { | ||
474 | u32 mode = CAM_READ_CACHE(pcdev, MODE); | ||
475 | |||
476 | CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA)); | ||
477 | } | ||
478 | |||
479 | static void omap1_videobuf_queue(struct videobuf_queue *vq, | ||
480 | struct videobuf_buffer *vb) | ||
481 | { | ||
482 | struct soc_camera_device *icd = vq->priv_data; | ||
483 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
484 | struct omap1_cam_dev *pcdev = ici->priv; | ||
485 | struct omap1_cam_buf *buf; | ||
486 | u32 mode; | ||
487 | |||
488 | list_add_tail(&vb->queue, &pcdev->capture); | ||
489 | vb->state = VIDEOBUF_QUEUED; | ||
490 | |||
491 | if (pcdev->active) { | ||
492 | /* | ||
493 | * Capture in progress, so don't touch pcdev->ready even if | ||
494 | * empty. Since the transfer of the DMA programming register set | ||
495 | * content to the DMA working register set is done automatically | ||
496 | * by the DMA hardware, this can pretty well happen while we | ||
497 | * are keeping the lock here. Leave fetching it from the queue | ||
498 | * to be done when a next DMA interrupt occures instead. | ||
499 | */ | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | WARN_ON(pcdev->ready); | ||
504 | |||
505 | buf = prepare_next_vb(pcdev); | ||
506 | if (WARN_ON(!buf)) | ||
507 | return; | ||
508 | |||
509 | pcdev->active = buf; | ||
510 | pcdev->ready = NULL; | ||
511 | |||
512 | dev_dbg(icd->parent, | ||
513 | "%s: capture not active, setup FIFO, start DMA\n", __func__); | ||
514 | mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK; | ||
515 | mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT; | ||
516 | CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA); | ||
517 | |||
518 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
519 | /* | ||
520 | * In SG mode, the above prepare_next_vb() didn't actually | ||
521 | * put anything into the DMA programming register set, | ||
522 | * so we have to do it now, before activating DMA. | ||
523 | */ | ||
524 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
525 | } | ||
526 | |||
527 | start_capture(pcdev); | ||
528 | } | ||
529 | |||
530 | static void omap1_videobuf_release(struct videobuf_queue *vq, | ||
531 | struct videobuf_buffer *vb) | ||
532 | { | ||
533 | struct omap1_cam_buf *buf = | ||
534 | container_of(vb, struct omap1_cam_buf, vb); | ||
535 | struct soc_camera_device *icd = vq->priv_data; | ||
536 | struct device *dev = icd->parent; | ||
537 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
538 | struct omap1_cam_dev *pcdev = ici->priv; | ||
539 | |||
540 | switch (vb->state) { | ||
541 | case VIDEOBUF_DONE: | ||
542 | dev_dbg(dev, "%s (done)\n", __func__); | ||
543 | break; | ||
544 | case VIDEOBUF_ACTIVE: | ||
545 | dev_dbg(dev, "%s (active)\n", __func__); | ||
546 | break; | ||
547 | case VIDEOBUF_QUEUED: | ||
548 | dev_dbg(dev, "%s (queued)\n", __func__); | ||
549 | break; | ||
550 | case VIDEOBUF_PREPARED: | ||
551 | dev_dbg(dev, "%s (prepared)\n", __func__); | ||
552 | break; | ||
553 | default: | ||
554 | dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state); | ||
555 | break; | ||
556 | } | ||
557 | |||
558 | free_buffer(vq, buf, pcdev->vb_mode); | ||
559 | } | ||
560 | |||
561 | static void videobuf_done(struct omap1_cam_dev *pcdev, | ||
562 | enum videobuf_state result) | ||
563 | { | ||
564 | struct omap1_cam_buf *buf = pcdev->active; | ||
565 | struct videobuf_buffer *vb; | ||
566 | struct device *dev = pcdev->icd->parent; | ||
567 | |||
568 | if (WARN_ON(!buf)) { | ||
569 | suspend_capture(pcdev); | ||
570 | disable_capture(pcdev); | ||
571 | return; | ||
572 | } | ||
573 | |||
574 | if (result == VIDEOBUF_ERROR) | ||
575 | suspend_capture(pcdev); | ||
576 | |||
577 | vb = &buf->vb; | ||
578 | if (waitqueue_active(&vb->done)) { | ||
579 | if (!pcdev->ready && result != VIDEOBUF_ERROR) { | ||
580 | /* | ||
581 | * No next buffer has been entered into the DMA | ||
582 | * programming register set on time (could be done only | ||
583 | * while the previous DMA interurpt was processed, not | ||
584 | * later), so the last DMA block, be it a whole buffer | ||
585 | * if in CONTIG or its last sgbuf if in SG mode, is | ||
586 | * about to be reused by the just autoreinitialized DMA | ||
587 | * engine, and overwritten with next frame data. Best we | ||
588 | * can do is stopping the capture as soon as possible, | ||
589 | * hopefully before the next frame start. | ||
590 | */ | ||
591 | suspend_capture(pcdev); | ||
592 | } | ||
593 | vb->state = result; | ||
594 | do_gettimeofday(&vb->ts); | ||
595 | if (result != VIDEOBUF_ERROR) | ||
596 | vb->field_count++; | ||
597 | wake_up(&vb->done); | ||
598 | |||
599 | /* shift in next buffer */ | ||
600 | buf = pcdev->ready; | ||
601 | pcdev->active = buf; | ||
602 | pcdev->ready = NULL; | ||
603 | |||
604 | if (!buf) { | ||
605 | /* | ||
606 | * No next buffer was ready on time (see above), so | ||
607 | * indicate error condition to force capture restart or | ||
608 | * stop, depending on next buffer already queued or not. | ||
609 | */ | ||
610 | result = VIDEOBUF_ERROR; | ||
611 | prepare_next_vb(pcdev); | ||
612 | |||
613 | buf = pcdev->ready; | ||
614 | pcdev->active = buf; | ||
615 | pcdev->ready = NULL; | ||
616 | } | ||
617 | } else if (pcdev->ready) { | ||
618 | /* | ||
619 | * In both CONTIG and SG mode, the DMA engine has possibly | ||
620 | * been already autoreinitialized with the preprogrammed | ||
621 | * pcdev->ready buffer. We can either accept this fact | ||
622 | * and just swap the buffers, or provoke an error condition | ||
623 | * and restart capture. The former seems less intrusive. | ||
624 | */ | ||
625 | dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n", | ||
626 | __func__); | ||
627 | pcdev->active = pcdev->ready; | ||
628 | |||
629 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
630 | /* | ||
631 | * In SG mode, we have to make sure that the buffer we | ||
632 | * are putting back into the pcdev->ready is marked | ||
633 | * fresh. | ||
634 | */ | ||
635 | buf->sgbuf = NULL; | ||
636 | } | ||
637 | pcdev->ready = buf; | ||
638 | |||
639 | buf = pcdev->active; | ||
640 | } else { | ||
641 | /* | ||
642 | * No next buffer has been entered into | ||
643 | * the DMA programming register set on time. | ||
644 | */ | ||
645 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
646 | /* | ||
647 | * In CONTIG mode, the DMA engine has already been | ||
648 | * reinitialized with the current buffer. Best we can do | ||
649 | * is not touching it. | ||
650 | */ | ||
651 | dev_dbg(dev, | ||
652 | "%s: nobody waiting on videobuf, reuse it\n", | ||
653 | __func__); | ||
654 | } else { | ||
655 | /* | ||
656 | * In SG mode, the DMA engine has just been | ||
657 | * autoreinitialized with the last sgbuf from the | ||
658 | * current list. Restart capture in order to transfer | ||
659 | * next frame start into the first sgbuf, not the last | ||
660 | * one. | ||
661 | */ | ||
662 | if (result != VIDEOBUF_ERROR) { | ||
663 | suspend_capture(pcdev); | ||
664 | result = VIDEOBUF_ERROR; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (!buf) { | ||
670 | dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__); | ||
671 | disable_capture(pcdev); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
676 | /* | ||
677 | * In CONTIG mode, the current buffer parameters had already | ||
678 | * been entered into the DMA programming register set while the | ||
679 | * buffer was fetched with prepare_next_vb(), they may have also | ||
680 | * been transferred into the runtime set and already active if | ||
681 | * the DMA still running. | ||
682 | */ | ||
683 | } else { | ||
684 | /* In SG mode, extra steps are required */ | ||
685 | if (result == VIDEOBUF_ERROR) | ||
686 | /* make sure we (re)use sglist from start on error */ | ||
687 | buf->sgbuf = NULL; | ||
688 | |||
689 | /* | ||
690 | * In any case, enter the next sgbuf parameters into the DMA | ||
691 | * programming register set. They will be used either during | ||
692 | * nearest DMA autoreinitialization or, in case of an error, | ||
693 | * on DMA startup below. | ||
694 | */ | ||
695 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
696 | } | ||
697 | |||
698 | if (result == VIDEOBUF_ERROR) { | ||
699 | dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n", | ||
700 | __func__); | ||
701 | start_capture(pcdev); | ||
702 | /* | ||
703 | * In SG mode, the above also resulted in the next sgbuf | ||
704 | * parameters being entered into the DMA programming register | ||
705 | * set, making them ready for next DMA autoreinitialization. | ||
706 | */ | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Finally, try fetching next buffer. | ||
711 | * In CONTIG mode, it will also enter it into the DMA programming | ||
712 | * register set, making it ready for next DMA autoreinitialization. | ||
713 | */ | ||
714 | prepare_next_vb(pcdev); | ||
715 | } | ||
716 | |||
717 | static void dma_isr(int channel, unsigned short status, void *data) | ||
718 | { | ||
719 | struct omap1_cam_dev *pcdev = data; | ||
720 | struct omap1_cam_buf *buf = pcdev->active; | ||
721 | unsigned long flags; | ||
722 | |||
723 | spin_lock_irqsave(&pcdev->lock, flags); | ||
724 | |||
725 | if (WARN_ON(!buf)) { | ||
726 | suspend_capture(pcdev); | ||
727 | disable_capture(pcdev); | ||
728 | goto out; | ||
729 | } | ||
730 | |||
731 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
732 | /* | ||
733 | * In CONTIG mode, assume we have just managed to collect the | ||
734 | * whole frame, hopefully before our end of frame watchdog is | ||
735 | * triggered. Then, all we have to do is disabling the watchdog | ||
736 | * for this frame, and calling videobuf_done() with success | ||
737 | * indicated. | ||
738 | */ | ||
739 | CAM_WRITE(pcdev, MODE, | ||
740 | CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN); | ||
741 | videobuf_done(pcdev, VIDEOBUF_DONE); | ||
742 | } else { | ||
743 | /* | ||
744 | * In SG mode, we have to process every sgbuf from the current | ||
745 | * sglist, one after another. | ||
746 | */ | ||
747 | if (buf->sgbuf) { | ||
748 | /* | ||
749 | * Current sglist not completed yet, try fetching next | ||
750 | * sgbuf, hopefully putting it into the DMA programming | ||
751 | * register set, making it ready for next DMA | ||
752 | * autoreinitialization. | ||
753 | */ | ||
754 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
755 | if (buf->sgbuf) | ||
756 | goto out; | ||
757 | |||
758 | /* | ||
759 | * No more sgbufs left in the current sglist. This | ||
760 | * doesn't mean that the whole videobuffer is already | ||
761 | * complete, but only that the last sgbuf from the | ||
762 | * current sglist is about to be filled. It will be | ||
763 | * ready on next DMA interrupt, signalled with the | ||
764 | * buf->sgbuf set back to NULL. | ||
765 | */ | ||
766 | if (buf->result != VIDEOBUF_ERROR) { | ||
767 | /* | ||
768 | * Video frame collected without errors so far, | ||
769 | * we can prepare for collecting a next one | ||
770 | * as soon as DMA gets autoreinitialized | ||
771 | * after the current (last) sgbuf is completed. | ||
772 | */ | ||
773 | buf = prepare_next_vb(pcdev); | ||
774 | if (!buf) | ||
775 | goto out; | ||
776 | |||
777 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
778 | goto out; | ||
779 | } | ||
780 | } | ||
781 | /* end of videobuf */ | ||
782 | videobuf_done(pcdev, buf->result); | ||
783 | } | ||
784 | |||
785 | out: | ||
786 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
787 | } | ||
788 | |||
789 | static irqreturn_t cam_isr(int irq, void *data) | ||
790 | { | ||
791 | struct omap1_cam_dev *pcdev = data; | ||
792 | struct device *dev = pcdev->icd->parent; | ||
793 | struct omap1_cam_buf *buf = pcdev->active; | ||
794 | u32 it_status; | ||
795 | unsigned long flags; | ||
796 | |||
797 | it_status = CAM_READ(pcdev, IT_STATUS); | ||
798 | if (!it_status) | ||
799 | return IRQ_NONE; | ||
800 | |||
801 | spin_lock_irqsave(&pcdev->lock, flags); | ||
802 | |||
803 | if (WARN_ON(!buf)) { | ||
804 | dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", | ||
805 | __func__, it_status); | ||
806 | suspend_capture(pcdev); | ||
807 | disable_capture(pcdev); | ||
808 | goto out; | ||
809 | } | ||
810 | |||
811 | if (unlikely(it_status & FIFO_FULL)) { | ||
812 | dev_warn(dev, "%s: FIFO overflow\n", __func__); | ||
813 | |||
814 | } else if (it_status & V_DOWN) { | ||
815 | /* end of video frame watchdog */ | ||
816 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
817 | /* | ||
818 | * In CONTIG mode, the watchdog is disabled with | ||
819 | * successful DMA end of block interrupt, and reenabled | ||
820 | * on next frame start. If we get here, there is nothing | ||
821 | * to check, we must be out of sync. | ||
822 | */ | ||
823 | } else { | ||
824 | if (buf->sgcount == 2) { | ||
825 | /* | ||
826 | * If exactly 2 sgbufs from the next sglist have | ||
827 | * been programmed into the DMA engine (the | ||
828 | * first one already transferred into the DMA | ||
829 | * runtime register set, the second one still | ||
830 | * in the programming set), then we are in sync. | ||
831 | */ | ||
832 | goto out; | ||
833 | } | ||
834 | } | ||
835 | dev_notice(dev, "%s: unexpected end of video frame\n", | ||
836 | __func__); | ||
837 | |||
838 | } else if (it_status & V_UP) { | ||
839 | u32 mode; | ||
840 | |||
841 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
842 | /* | ||
843 | * In CONTIG mode, we need this interrupt every frame | ||
844 | * in oredr to reenable our end of frame watchdog. | ||
845 | */ | ||
846 | mode = CAM_READ_CACHE(pcdev, MODE); | ||
847 | } else { | ||
848 | /* | ||
849 | * In SG mode, the below enabled end of frame watchdog | ||
850 | * is kept on permanently, so we can turn this one shot | ||
851 | * setup off. | ||
852 | */ | ||
853 | mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP; | ||
854 | } | ||
855 | |||
856 | if (!(mode & EN_V_DOWN)) { | ||
857 | /* (re)enable end of frame watchdog interrupt */ | ||
858 | mode |= EN_V_DOWN; | ||
859 | } | ||
860 | CAM_WRITE(pcdev, MODE, mode); | ||
861 | goto out; | ||
862 | |||
863 | } else { | ||
864 | dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", | ||
865 | __func__, it_status); | ||
866 | goto out; | ||
867 | } | ||
868 | |||
869 | videobuf_done(pcdev, VIDEOBUF_ERROR); | ||
870 | out: | ||
871 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
872 | return IRQ_HANDLED; | ||
873 | } | ||
874 | |||
875 | static struct videobuf_queue_ops omap1_videobuf_ops = { | ||
876 | .buf_setup = omap1_videobuf_setup, | ||
877 | .buf_prepare = omap1_videobuf_prepare, | ||
878 | .buf_queue = omap1_videobuf_queue, | ||
879 | .buf_release = omap1_videobuf_release, | ||
880 | }; | ||
881 | |||
882 | |||
883 | /* | ||
884 | * SOC Camera host operations | ||
885 | */ | ||
886 | |||
887 | static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset) | ||
888 | { | ||
889 | /* apply/release camera sensor reset if requested by platform data */ | ||
890 | if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH) | ||
891 | CAM_WRITE(pcdev, GPIO, reset); | ||
892 | else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW) | ||
893 | CAM_WRITE(pcdev, GPIO, !reset); | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * The following two functions absolutely depend on the fact, that | ||
898 | * there can be only one camera on OMAP1 camera sensor interface | ||
899 | */ | ||
900 | static int omap1_cam_add_device(struct soc_camera_device *icd) | ||
901 | { | ||
902 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
903 | struct omap1_cam_dev *pcdev = ici->priv; | ||
904 | u32 ctrlclock; | ||
905 | |||
906 | if (pcdev->icd) | ||
907 | return -EBUSY; | ||
908 | |||
909 | clk_enable(pcdev->clk); | ||
910 | |||
911 | /* setup sensor clock */ | ||
912 | ctrlclock = CAM_READ(pcdev, CTRLCLOCK); | ||
913 | ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN); | ||
914 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
915 | |||
916 | ctrlclock &= ~FOSCMOD_MASK; | ||
917 | switch (pcdev->camexclk) { | ||
918 | case 6000000: | ||
919 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz; | ||
920 | break; | ||
921 | case 8000000: | ||
922 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN; | ||
923 | break; | ||
924 | case 9600000: | ||
925 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN; | ||
926 | break; | ||
927 | case 12000000: | ||
928 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz; | ||
929 | break; | ||
930 | case 24000000: | ||
931 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN; | ||
932 | default: | ||
933 | break; | ||
934 | } | ||
935 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN); | ||
936 | |||
937 | /* enable internal clock */ | ||
938 | ctrlclock |= MCLK_EN; | ||
939 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
940 | |||
941 | sensor_reset(pcdev, false); | ||
942 | |||
943 | pcdev->icd = icd; | ||
944 | |||
945 | dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n", | ||
946 | icd->devnum); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static void omap1_cam_remove_device(struct soc_camera_device *icd) | ||
951 | { | ||
952 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
953 | struct omap1_cam_dev *pcdev = ici->priv; | ||
954 | u32 ctrlclock; | ||
955 | |||
956 | BUG_ON(icd != pcdev->icd); | ||
957 | |||
958 | suspend_capture(pcdev); | ||
959 | disable_capture(pcdev); | ||
960 | |||
961 | sensor_reset(pcdev, true); | ||
962 | |||
963 | /* disable and release system clocks */ | ||
964 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
965 | ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN); | ||
966 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
967 | |||
968 | ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz; | ||
969 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
970 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN); | ||
971 | |||
972 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN); | ||
973 | |||
974 | clk_disable(pcdev->clk); | ||
975 | |||
976 | pcdev->icd = NULL; | ||
977 | |||
978 | dev_dbg(icd->parent, | ||
979 | "OMAP1 Camera driver detached from camera %d\n", icd->devnum); | ||
980 | } | ||
981 | |||
982 | /* Duplicate standard formats based on host capability of byte swapping */ | ||
983 | static const struct soc_mbus_lookup omap1_cam_formats[] = { | ||
984 | { | ||
985 | .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
986 | .fmt = { | ||
987 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
988 | .name = "YUYV", | ||
989 | .bits_per_sample = 8, | ||
990 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
991 | .order = SOC_MBUS_ORDER_BE, | ||
992 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
993 | }, | ||
994 | }, { | ||
995 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
996 | .fmt = { | ||
997 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
998 | .name = "YVYU", | ||
999 | .bits_per_sample = 8, | ||
1000 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1001 | .order = SOC_MBUS_ORDER_BE, | ||
1002 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1003 | }, | ||
1004 | }, { | ||
1005 | .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
1006 | .fmt = { | ||
1007 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
1008 | .name = "UYVY", | ||
1009 | .bits_per_sample = 8, | ||
1010 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1011 | .order = SOC_MBUS_ORDER_BE, | ||
1012 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1013 | }, | ||
1014 | }, { | ||
1015 | .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
1016 | .fmt = { | ||
1017 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
1018 | .name = "VYUY", | ||
1019 | .bits_per_sample = 8, | ||
1020 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1021 | .order = SOC_MBUS_ORDER_BE, | ||
1022 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1023 | }, | ||
1024 | }, { | ||
1025 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, | ||
1026 | .fmt = { | ||
1027 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
1028 | .name = "RGB555", | ||
1029 | .bits_per_sample = 8, | ||
1030 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1031 | .order = SOC_MBUS_ORDER_BE, | ||
1032 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1033 | }, | ||
1034 | }, { | ||
1035 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
1036 | .fmt = { | ||
1037 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
1038 | .name = "RGB555X", | ||
1039 | .bits_per_sample = 8, | ||
1040 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1041 | .order = SOC_MBUS_ORDER_BE, | ||
1042 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1043 | }, | ||
1044 | }, { | ||
1045 | .code = V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
1046 | .fmt = { | ||
1047 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
1048 | .name = "RGB565", | ||
1049 | .bits_per_sample = 8, | ||
1050 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1051 | .order = SOC_MBUS_ORDER_BE, | ||
1052 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1053 | }, | ||
1054 | }, { | ||
1055 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
1056 | .fmt = { | ||
1057 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
1058 | .name = "RGB565X", | ||
1059 | .bits_per_sample = 8, | ||
1060 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1061 | .order = SOC_MBUS_ORDER_BE, | ||
1062 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1063 | }, | ||
1064 | }, | ||
1065 | }; | ||
1066 | |||
1067 | static int omap1_cam_get_formats(struct soc_camera_device *icd, | ||
1068 | unsigned int idx, struct soc_camera_format_xlate *xlate) | ||
1069 | { | ||
1070 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1071 | struct device *dev = icd->parent; | ||
1072 | int formats = 0, ret; | ||
1073 | enum v4l2_mbus_pixelcode code; | ||
1074 | const struct soc_mbus_pixelfmt *fmt; | ||
1075 | |||
1076 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
1077 | if (ret < 0) | ||
1078 | /* No more formats */ | ||
1079 | return 0; | ||
1080 | |||
1081 | fmt = soc_mbus_get_fmtdesc(code); | ||
1082 | if (!fmt) { | ||
1083 | dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, | ||
1084 | idx, code); | ||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | /* Check support for the requested bits-per-sample */ | ||
1089 | if (fmt->bits_per_sample != 8) | ||
1090 | return 0; | ||
1091 | |||
1092 | switch (code) { | ||
1093 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
1094 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
1095 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
1096 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
1097 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: | ||
1098 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: | ||
1099 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
1100 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
1101 | formats++; | ||
1102 | if (xlate) { | ||
1103 | xlate->host_fmt = soc_mbus_find_fmtdesc(code, | ||
1104 | omap1_cam_formats, | ||
1105 | ARRAY_SIZE(omap1_cam_formats)); | ||
1106 | xlate->code = code; | ||
1107 | xlate++; | ||
1108 | dev_dbg(dev, | ||
1109 | "%s: providing format %s as byte swapped code #%d\n", | ||
1110 | __func__, xlate->host_fmt->name, code); | ||
1111 | } | ||
1112 | default: | ||
1113 | if (xlate) | ||
1114 | dev_dbg(dev, | ||
1115 | "%s: providing format %s in pass-through mode\n", | ||
1116 | __func__, fmt->name); | ||
1117 | } | ||
1118 | formats++; | ||
1119 | if (xlate) { | ||
1120 | xlate->host_fmt = fmt; | ||
1121 | xlate->code = code; | ||
1122 | xlate++; | ||
1123 | } | ||
1124 | |||
1125 | return formats; | ||
1126 | } | ||
1127 | |||
1128 | static bool is_dma_aligned(s32 bytes_per_line, unsigned int height, | ||
1129 | enum omap1_cam_vb_mode vb_mode) | ||
1130 | { | ||
1131 | int size = bytes_per_line * height; | ||
1132 | |||
1133 | return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) && | ||
1134 | IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE); | ||
1135 | } | ||
1136 | |||
1137 | static int dma_align(int *width, int *height, | ||
1138 | const struct soc_mbus_pixelfmt *fmt, | ||
1139 | enum omap1_cam_vb_mode vb_mode, bool enlarge) | ||
1140 | { | ||
1141 | s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt); | ||
1142 | |||
1143 | if (bytes_per_line < 0) | ||
1144 | return bytes_per_line; | ||
1145 | |||
1146 | if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) { | ||
1147 | unsigned int pxalign = __fls(bytes_per_line / *width); | ||
1148 | unsigned int salign = DMA_FRAME_SHIFT(vb_mode) + | ||
1149 | DMA_ELEMENT_SHIFT - pxalign; | ||
1150 | unsigned int incr = enlarge << salign; | ||
1151 | |||
1152 | v4l_bound_align_image(width, 1, *width + incr, 0, | ||
1153 | height, 1, *height + incr, 0, salign); | ||
1154 | return 0; | ||
1155 | } | ||
1156 | return 1; | ||
1157 | } | ||
1158 | |||
1159 | #define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ | ||
1160 | ({ \ | ||
1161 | struct soc_camera_sense sense = { \ | ||
1162 | .master_clock = pcdev->camexclk, \ | ||
1163 | .pixel_clock_max = 0, \ | ||
1164 | }; \ | ||
1165 | int __ret; \ | ||
1166 | \ | ||
1167 | if (pcdev->pdata) \ | ||
1168 | sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ | ||
1169 | icd->sense = &sense; \ | ||
1170 | __ret = v4l2_subdev_call(sd, video, function, ##args); \ | ||
1171 | icd->sense = NULL; \ | ||
1172 | \ | ||
1173 | if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ | ||
1174 | if (sense.pixel_clock > sense.pixel_clock_max) { \ | ||
1175 | dev_err(dev, \ | ||
1176 | "%s: pixel clock %lu set by the camera too high!\n", \ | ||
1177 | __func__, sense.pixel_clock); \ | ||
1178 | __ret = -EINVAL; \ | ||
1179 | } \ | ||
1180 | } \ | ||
1181 | __ret; \ | ||
1182 | }) | ||
1183 | |||
1184 | static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, | ||
1185 | struct soc_camera_device *icd, struct v4l2_subdev *sd, | ||
1186 | struct v4l2_mbus_framefmt *mf, | ||
1187 | const struct soc_camera_format_xlate *xlate) | ||
1188 | { | ||
1189 | s32 bytes_per_line; | ||
1190 | int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf); | ||
1191 | |||
1192 | if (ret < 0) { | ||
1193 | dev_err(dev, "%s: s_mbus_fmt failed\n", __func__); | ||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | if (mf->code != xlate->code) { | ||
1198 | dev_err(dev, "%s: unexpected pixel code change\n", __func__); | ||
1199 | return -EINVAL; | ||
1200 | } | ||
1201 | |||
1202 | bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt); | ||
1203 | if (bytes_per_line < 0) { | ||
1204 | dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n", | ||
1205 | __func__); | ||
1206 | return bytes_per_line; | ||
1207 | } | ||
1208 | |||
1209 | if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) { | ||
1210 | dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n", | ||
1211 | __func__, mf->width, mf->height); | ||
1212 | return -EINVAL; | ||
1213 | } | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static int omap1_cam_set_crop(struct soc_camera_device *icd, | ||
1218 | struct v4l2_crop *crop) | ||
1219 | { | ||
1220 | struct v4l2_rect *rect = &crop->c; | ||
1221 | const struct soc_camera_format_xlate *xlate = icd->current_fmt; | ||
1222 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1223 | struct device *dev = icd->parent; | ||
1224 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1225 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1226 | struct v4l2_mbus_framefmt mf; | ||
1227 | int ret; | ||
1228 | |||
1229 | ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop); | ||
1230 | if (ret < 0) { | ||
1231 | dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, | ||
1232 | rect->width, rect->height, rect->left, rect->top); | ||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
1237 | if (ret < 0) { | ||
1238 | dev_warn(dev, "%s: failed to fetch current format\n", __func__); | ||
1239 | return ret; | ||
1240 | } | ||
1241 | |||
1242 | ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, | ||
1243 | false); | ||
1244 | if (ret < 0) { | ||
1245 | dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", | ||
1246 | __func__, mf.width, mf.height, | ||
1247 | xlate->host_fmt->name); | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | if (!ret) { | ||
1252 | /* sensor returned geometry not DMA aligned, trying to fix */ | ||
1253 | ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); | ||
1254 | if (ret < 0) { | ||
1255 | dev_err(dev, "%s: failed to set format\n", __func__); | ||
1256 | return ret; | ||
1257 | } | ||
1258 | } | ||
1259 | |||
1260 | icd->user_width = mf.width; | ||
1261 | icd->user_height = mf.height; | ||
1262 | |||
1263 | return 0; | ||
1264 | } | ||
1265 | |||
1266 | static int omap1_cam_set_fmt(struct soc_camera_device *icd, | ||
1267 | struct v4l2_format *f) | ||
1268 | { | ||
1269 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1270 | const struct soc_camera_format_xlate *xlate; | ||
1271 | struct device *dev = icd->parent; | ||
1272 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1273 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1274 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1275 | struct v4l2_mbus_framefmt mf; | ||
1276 | int ret; | ||
1277 | |||
1278 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1279 | if (!xlate) { | ||
1280 | dev_warn(dev, "%s: format %#x not found\n", __func__, | ||
1281 | pix->pixelformat); | ||
1282 | return -EINVAL; | ||
1283 | } | ||
1284 | |||
1285 | mf.width = pix->width; | ||
1286 | mf.height = pix->height; | ||
1287 | mf.field = pix->field; | ||
1288 | mf.colorspace = pix->colorspace; | ||
1289 | mf.code = xlate->code; | ||
1290 | |||
1291 | ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, | ||
1292 | true); | ||
1293 | if (ret < 0) { | ||
1294 | dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", | ||
1295 | __func__, pix->width, pix->height, | ||
1296 | xlate->host_fmt->name); | ||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); | ||
1301 | if (ret < 0) { | ||
1302 | dev_err(dev, "%s: failed to set format\n", __func__); | ||
1303 | return ret; | ||
1304 | } | ||
1305 | |||
1306 | pix->width = mf.width; | ||
1307 | pix->height = mf.height; | ||
1308 | pix->field = mf.field; | ||
1309 | pix->colorspace = mf.colorspace; | ||
1310 | icd->current_fmt = xlate; | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | static int omap1_cam_try_fmt(struct soc_camera_device *icd, | ||
1316 | struct v4l2_format *f) | ||
1317 | { | ||
1318 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1319 | const struct soc_camera_format_xlate *xlate; | ||
1320 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1321 | struct v4l2_mbus_framefmt mf; | ||
1322 | int ret; | ||
1323 | /* TODO: limit to mx1 hardware capabilities */ | ||
1324 | |||
1325 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1326 | if (!xlate) { | ||
1327 | dev_warn(icd->parent, "Format %#x not found\n", | ||
1328 | pix->pixelformat); | ||
1329 | return -EINVAL; | ||
1330 | } | ||
1331 | |||
1332 | mf.width = pix->width; | ||
1333 | mf.height = pix->height; | ||
1334 | mf.field = pix->field; | ||
1335 | mf.colorspace = pix->colorspace; | ||
1336 | mf.code = xlate->code; | ||
1337 | |||
1338 | /* limit to sensor capabilities */ | ||
1339 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1340 | if (ret < 0) | ||
1341 | return ret; | ||
1342 | |||
1343 | pix->width = mf.width; | ||
1344 | pix->height = mf.height; | ||
1345 | pix->field = mf.field; | ||
1346 | pix->colorspace = mf.colorspace; | ||
1347 | |||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static bool sg_mode; | ||
1352 | |||
1353 | /* | ||
1354 | * Local mmap_mapper wrapper, | ||
1355 | * used for detecting videobuf-dma-contig buffer allocation failures | ||
1356 | * and switching to videobuf-dma-sg automatically for future attempts. | ||
1357 | */ | ||
1358 | static int omap1_cam_mmap_mapper(struct videobuf_queue *q, | ||
1359 | struct videobuf_buffer *buf, | ||
1360 | struct vm_area_struct *vma) | ||
1361 | { | ||
1362 | struct soc_camera_device *icd = q->priv_data; | ||
1363 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1364 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1365 | int ret; | ||
1366 | |||
1367 | ret = pcdev->mmap_mapper(q, buf, vma); | ||
1368 | |||
1369 | if (ret == -ENOMEM) | ||
1370 | sg_mode = true; | ||
1371 | |||
1372 | return ret; | ||
1373 | } | ||
1374 | |||
1375 | static void omap1_cam_init_videobuf(struct videobuf_queue *q, | ||
1376 | struct soc_camera_device *icd) | ||
1377 | { | ||
1378 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1379 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1380 | |||
1381 | if (!sg_mode) | ||
1382 | videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops, | ||
1383 | icd->parent, &pcdev->lock, | ||
1384 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
1385 | sizeof(struct omap1_cam_buf), icd, &icd->video_lock); | ||
1386 | else | ||
1387 | videobuf_queue_sg_init(q, &omap1_videobuf_ops, | ||
1388 | icd->parent, &pcdev->lock, | ||
1389 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
1390 | sizeof(struct omap1_cam_buf), icd, &icd->video_lock); | ||
1391 | |||
1392 | /* use videobuf mode (auto)selected with the module parameter */ | ||
1393 | pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG; | ||
1394 | |||
1395 | /* | ||
1396 | * Ensure we substitute the videobuf-dma-contig version of the | ||
1397 | * mmap_mapper() callback with our own wrapper, used for switching | ||
1398 | * automatically to videobuf-dma-sg on buffer allocation failure. | ||
1399 | */ | ||
1400 | if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) { | ||
1401 | pcdev->mmap_mapper = q->int_ops->mmap_mapper; | ||
1402 | q->int_ops->mmap_mapper = omap1_cam_mmap_mapper; | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | static int omap1_cam_reqbufs(struct soc_camera_device *icd, | ||
1407 | struct v4l2_requestbuffers *p) | ||
1408 | { | ||
1409 | int i; | ||
1410 | |||
1411 | /* | ||
1412 | * This is for locking debugging only. I removed spinlocks and now I | ||
1413 | * check whether .prepare is ever called on a linked buffer, or whether | ||
1414 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | ||
1415 | * it hadn't triggered | ||
1416 | */ | ||
1417 | for (i = 0; i < p->count; i++) { | ||
1418 | struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i], | ||
1419 | struct omap1_cam_buf, vb); | ||
1420 | buf->inwork = 0; | ||
1421 | INIT_LIST_HEAD(&buf->vb.queue); | ||
1422 | } | ||
1423 | |||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static int omap1_cam_querycap(struct soc_camera_host *ici, | ||
1428 | struct v4l2_capability *cap) | ||
1429 | { | ||
1430 | /* cap->name is set by the friendly caller:-> */ | ||
1431 | strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card)); | ||
1432 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1433 | |||
1434 | return 0; | ||
1435 | } | ||
1436 | |||
1437 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd) | ||
1438 | { | ||
1439 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1440 | struct device *dev = icd->parent; | ||
1441 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1442 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1443 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | ||
1444 | const struct soc_camera_format_xlate *xlate; | ||
1445 | const struct soc_mbus_pixelfmt *fmt; | ||
1446 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
1447 | unsigned long common_flags; | ||
1448 | u32 ctrlclock, mode; | ||
1449 | int ret; | ||
1450 | |||
1451 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1452 | if (!ret) { | ||
1453 | common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); | ||
1454 | if (!common_flags) { | ||
1455 | dev_warn(dev, | ||
1456 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
1457 | cfg.flags, SOCAM_BUS_FLAGS); | ||
1458 | return -EINVAL; | ||
1459 | } | ||
1460 | } else if (ret != -ENOIOCTLCMD) { | ||
1461 | return ret; | ||
1462 | } else { | ||
1463 | common_flags = SOCAM_BUS_FLAGS; | ||
1464 | } | ||
1465 | |||
1466 | /* Make choices, possibly based on platform configuration */ | ||
1467 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1468 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1469 | if (!pcdev->pdata || | ||
1470 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) | ||
1471 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1472 | else | ||
1473 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1474 | } | ||
1475 | |||
1476 | cfg.flags = common_flags; | ||
1477 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1478 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1479 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1480 | common_flags, ret); | ||
1481 | return ret; | ||
1482 | } | ||
1483 | |||
1484 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
1485 | if (ctrlclock & LCLK_EN) | ||
1486 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
1487 | |||
1488 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { | ||
1489 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); | ||
1490 | ctrlclock |= POLCLK; | ||
1491 | } else { | ||
1492 | dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n"); | ||
1493 | ctrlclock &= ~POLCLK; | ||
1494 | } | ||
1495 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
1496 | |||
1497 | if (ctrlclock & LCLK_EN) | ||
1498 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
1499 | |||
1500 | /* select bus endianess */ | ||
1501 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1502 | fmt = xlate->host_fmt; | ||
1503 | |||
1504 | mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA); | ||
1505 | if (fmt->order == SOC_MBUS_ORDER_LE) { | ||
1506 | dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n"); | ||
1507 | CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD); | ||
1508 | } else { | ||
1509 | dev_dbg(dev, "MODE_REG |= ORDERCAMD\n"); | ||
1510 | CAM_WRITE(pcdev, MODE, mode | ORDERCAMD); | ||
1511 | } | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | static unsigned int omap1_cam_poll(struct file *file, poll_table *pt) | ||
1517 | { | ||
1518 | struct soc_camera_device *icd = file->private_data; | ||
1519 | struct omap1_cam_buf *buf; | ||
1520 | |||
1521 | buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf, | ||
1522 | vb.stream); | ||
1523 | |||
1524 | poll_wait(file, &buf->vb.done, pt); | ||
1525 | |||
1526 | if (buf->vb.state == VIDEOBUF_DONE || | ||
1527 | buf->vb.state == VIDEOBUF_ERROR) | ||
1528 | return POLLIN | POLLRDNORM; | ||
1529 | |||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | static struct soc_camera_host_ops omap1_host_ops = { | ||
1534 | .owner = THIS_MODULE, | ||
1535 | .add = omap1_cam_add_device, | ||
1536 | .remove = omap1_cam_remove_device, | ||
1537 | .get_formats = omap1_cam_get_formats, | ||
1538 | .set_crop = omap1_cam_set_crop, | ||
1539 | .set_fmt = omap1_cam_set_fmt, | ||
1540 | .try_fmt = omap1_cam_try_fmt, | ||
1541 | .init_videobuf = omap1_cam_init_videobuf, | ||
1542 | .reqbufs = omap1_cam_reqbufs, | ||
1543 | .querycap = omap1_cam_querycap, | ||
1544 | .set_bus_param = omap1_cam_set_bus_param, | ||
1545 | .poll = omap1_cam_poll, | ||
1546 | }; | ||
1547 | |||
1548 | static int __init omap1_cam_probe(struct platform_device *pdev) | ||
1549 | { | ||
1550 | struct omap1_cam_dev *pcdev; | ||
1551 | struct resource *res; | ||
1552 | struct clk *clk; | ||
1553 | void __iomem *base; | ||
1554 | unsigned int irq; | ||
1555 | int err = 0; | ||
1556 | |||
1557 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1558 | irq = platform_get_irq(pdev, 0); | ||
1559 | if (!res || (int)irq <= 0) { | ||
1560 | err = -ENODEV; | ||
1561 | goto exit; | ||
1562 | } | ||
1563 | |||
1564 | clk = clk_get(&pdev->dev, "armper_ck"); | ||
1565 | if (IS_ERR(clk)) { | ||
1566 | err = PTR_ERR(clk); | ||
1567 | goto exit; | ||
1568 | } | ||
1569 | |||
1570 | pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL); | ||
1571 | if (!pcdev) { | ||
1572 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
1573 | err = -ENOMEM; | ||
1574 | goto exit_put_clk; | ||
1575 | } | ||
1576 | |||
1577 | pcdev->res = res; | ||
1578 | pcdev->clk = clk; | ||
1579 | |||
1580 | pcdev->pdata = pdev->dev.platform_data; | ||
1581 | if (pcdev->pdata) { | ||
1582 | pcdev->pflags = pcdev->pdata->flags; | ||
1583 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; | ||
1584 | } | ||
1585 | |||
1586 | switch (pcdev->camexclk) { | ||
1587 | case 6000000: | ||
1588 | case 8000000: | ||
1589 | case 9600000: | ||
1590 | case 12000000: | ||
1591 | case 24000000: | ||
1592 | break; | ||
1593 | default: | ||
1594 | /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ | ||
1595 | dev_warn(&pdev->dev, | ||
1596 | "Incorrect sensor clock frequency %ld kHz, " | ||
1597 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " | ||
1598 | "please correct your platform data\n", | ||
1599 | pcdev->pdata->camexclk_khz); | ||
1600 | pcdev->camexclk = 0; | ||
1601 | case 0: | ||
1602 | dev_info(&pdev->dev, "Not providing sensor clock\n"); | ||
1603 | } | ||
1604 | |||
1605 | INIT_LIST_HEAD(&pcdev->capture); | ||
1606 | spin_lock_init(&pcdev->lock); | ||
1607 | |||
1608 | /* | ||
1609 | * Request the region. | ||
1610 | */ | ||
1611 | if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { | ||
1612 | err = -EBUSY; | ||
1613 | goto exit_kfree; | ||
1614 | } | ||
1615 | |||
1616 | base = ioremap(res->start, resource_size(res)); | ||
1617 | if (!base) { | ||
1618 | err = -ENOMEM; | ||
1619 | goto exit_release; | ||
1620 | } | ||
1621 | pcdev->irq = irq; | ||
1622 | pcdev->base = base; | ||
1623 | |||
1624 | sensor_reset(pcdev, true); | ||
1625 | |||
1626 | err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME, | ||
1627 | dma_isr, (void *)pcdev, &pcdev->dma_ch); | ||
1628 | if (err < 0) { | ||
1629 | dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n"); | ||
1630 | err = -EBUSY; | ||
1631 | goto exit_iounmap; | ||
1632 | } | ||
1633 | dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch); | ||
1634 | |||
1635 | /* preconfigure DMA */ | ||
1636 | omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB, | ||
1637 | OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA, | ||
1638 | 0, 0); | ||
1639 | omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4); | ||
1640 | /* setup DMA autoinitialization */ | ||
1641 | omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch); | ||
1642 | |||
1643 | err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev); | ||
1644 | if (err) { | ||
1645 | dev_err(&pdev->dev, "Camera interrupt register failed\n"); | ||
1646 | goto exit_free_dma; | ||
1647 | } | ||
1648 | |||
1649 | pcdev->soc_host.drv_name = DRIVER_NAME; | ||
1650 | pcdev->soc_host.ops = &omap1_host_ops; | ||
1651 | pcdev->soc_host.priv = pcdev; | ||
1652 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1653 | pcdev->soc_host.nr = pdev->id; | ||
1654 | |||
1655 | err = soc_camera_host_register(&pcdev->soc_host); | ||
1656 | if (err) | ||
1657 | goto exit_free_irq; | ||
1658 | |||
1659 | dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n"); | ||
1660 | |||
1661 | return 0; | ||
1662 | |||
1663 | exit_free_irq: | ||
1664 | free_irq(pcdev->irq, pcdev); | ||
1665 | exit_free_dma: | ||
1666 | omap_free_dma(pcdev->dma_ch); | ||
1667 | exit_iounmap: | ||
1668 | iounmap(base); | ||
1669 | exit_release: | ||
1670 | release_mem_region(res->start, resource_size(res)); | ||
1671 | exit_kfree: | ||
1672 | kfree(pcdev); | ||
1673 | exit_put_clk: | ||
1674 | clk_put(clk); | ||
1675 | exit: | ||
1676 | return err; | ||
1677 | } | ||
1678 | |||
1679 | static int __exit omap1_cam_remove(struct platform_device *pdev) | ||
1680 | { | ||
1681 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1682 | struct omap1_cam_dev *pcdev = container_of(soc_host, | ||
1683 | struct omap1_cam_dev, soc_host); | ||
1684 | struct resource *res; | ||
1685 | |||
1686 | free_irq(pcdev->irq, pcdev); | ||
1687 | |||
1688 | omap_free_dma(pcdev->dma_ch); | ||
1689 | |||
1690 | soc_camera_host_unregister(soc_host); | ||
1691 | |||
1692 | iounmap(pcdev->base); | ||
1693 | |||
1694 | res = pcdev->res; | ||
1695 | release_mem_region(res->start, resource_size(res)); | ||
1696 | |||
1697 | clk_put(pcdev->clk); | ||
1698 | |||
1699 | kfree(pcdev); | ||
1700 | |||
1701 | dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n"); | ||
1702 | |||
1703 | return 0; | ||
1704 | } | ||
1705 | |||
1706 | static struct platform_driver omap1_cam_driver = { | ||
1707 | .driver = { | ||
1708 | .name = DRIVER_NAME, | ||
1709 | }, | ||
1710 | .probe = omap1_cam_probe, | ||
1711 | .remove = __exit_p(omap1_cam_remove), | ||
1712 | }; | ||
1713 | |||
1714 | module_platform_driver(omap1_cam_driver); | ||
1715 | |||
1716 | module_param(sg_mode, bool, 0644); | ||
1717 | MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); | ||
1718 | |||
1719 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); | ||
1720 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); | ||
1721 | MODULE_LICENSE("GPL v2"); | ||
1722 | MODULE_VERSION(DRIVER_VERSION); | ||
1723 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c new file mode 100644 index 000000000000..1e3776d08dac --- /dev/null +++ b/drivers/media/platform/soc_camera/pxa_camera.c | |||
@@ -0,0 +1,1852 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for PXA camera host | ||
3 | * | ||
4 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | ||
5 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <media/v4l2-common.h> | ||
32 | #include <media/v4l2-dev.h> | ||
33 | #include <media/videobuf-dma-sg.h> | ||
34 | #include <media/soc_camera.h> | ||
35 | #include <media/soc_mediabus.h> | ||
36 | |||
37 | #include <linux/videodev2.h> | ||
38 | |||
39 | #include <mach/dma.h> | ||
40 | #include <linux/platform_data/camera-pxa.h> | ||
41 | |||
42 | #define PXA_CAM_VERSION "0.0.6" | ||
43 | #define PXA_CAM_DRV_NAME "pxa27x-camera" | ||
44 | |||
45 | /* Camera Interface */ | ||
46 | #define CICR0 0x0000 | ||
47 | #define CICR1 0x0004 | ||
48 | #define CICR2 0x0008 | ||
49 | #define CICR3 0x000C | ||
50 | #define CICR4 0x0010 | ||
51 | #define CISR 0x0014 | ||
52 | #define CIFR 0x0018 | ||
53 | #define CITOR 0x001C | ||
54 | #define CIBR0 0x0028 | ||
55 | #define CIBR1 0x0030 | ||
56 | #define CIBR2 0x0038 | ||
57 | |||
58 | #define CICR0_DMAEN (1 << 31) /* DMA request enable */ | ||
59 | #define CICR0_PAR_EN (1 << 30) /* Parity enable */ | ||
60 | #define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */ | ||
61 | #define CICR0_ENB (1 << 28) /* Camera interface enable */ | ||
62 | #define CICR0_DIS (1 << 27) /* Camera interface disable */ | ||
63 | #define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */ | ||
64 | #define CICR0_TOM (1 << 9) /* Time-out mask */ | ||
65 | #define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */ | ||
66 | #define CICR0_FEM (1 << 7) /* FIFO-empty mask */ | ||
67 | #define CICR0_EOLM (1 << 6) /* End-of-line mask */ | ||
68 | #define CICR0_PERRM (1 << 5) /* Parity-error mask */ | ||
69 | #define CICR0_QDM (1 << 4) /* Quick-disable mask */ | ||
70 | #define CICR0_CDM (1 << 3) /* Disable-done mask */ | ||
71 | #define CICR0_SOFM (1 << 2) /* Start-of-frame mask */ | ||
72 | #define CICR0_EOFM (1 << 1) /* End-of-frame mask */ | ||
73 | #define CICR0_FOM (1 << 0) /* FIFO-overrun mask */ | ||
74 | |||
75 | #define CICR1_TBIT (1 << 31) /* Transparency bit */ | ||
76 | #define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */ | ||
77 | #define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */ | ||
78 | #define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */ | ||
79 | #define CICR1_RGB_F (1 << 11) /* RGB format */ | ||
80 | #define CICR1_YCBCR_F (1 << 10) /* YCbCr format */ | ||
81 | #define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */ | ||
82 | #define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */ | ||
83 | #define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */ | ||
84 | #define CICR1_DW (0x7 << 0) /* Data width mask */ | ||
85 | |||
86 | #define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock | ||
87 | wait count mask */ | ||
88 | #define CICR2_ELW (0xff << 16) /* End-of-line pixel clock | ||
89 | wait count mask */ | ||
90 | #define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */ | ||
91 | #define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock | ||
92 | wait count mask */ | ||
93 | #define CICR2_FSW (0x7 << 0) /* Frame stabilization | ||
94 | wait count mask */ | ||
95 | |||
96 | #define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock | ||
97 | wait count mask */ | ||
98 | #define CICR3_EFW (0xff << 16) /* End-of-frame line clock | ||
99 | wait count mask */ | ||
100 | #define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */ | ||
101 | #define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock | ||
102 | wait count mask */ | ||
103 | #define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */ | ||
104 | |||
105 | #define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */ | ||
106 | #define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */ | ||
107 | #define CICR4_PCP (1 << 22) /* Pixel clock polarity */ | ||
108 | #define CICR4_HSP (1 << 21) /* Horizontal sync polarity */ | ||
109 | #define CICR4_VSP (1 << 20) /* Vertical sync polarity */ | ||
110 | #define CICR4_MCLK_EN (1 << 19) /* MCLK enable */ | ||
111 | #define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */ | ||
112 | #define CICR4_DIV (0xff << 0) /* Clock divisor mask */ | ||
113 | |||
114 | #define CISR_FTO (1 << 15) /* FIFO time-out */ | ||
115 | #define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */ | ||
116 | #define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */ | ||
117 | #define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */ | ||
118 | #define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */ | ||
119 | #define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */ | ||
120 | #define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */ | ||
121 | #define CISR_EOL (1 << 8) /* End of line */ | ||
122 | #define CISR_PAR_ERR (1 << 7) /* Parity error */ | ||
123 | #define CISR_CQD (1 << 6) /* Camera interface quick disable */ | ||
124 | #define CISR_CDD (1 << 5) /* Camera interface disable done */ | ||
125 | #define CISR_SOF (1 << 4) /* Start of frame */ | ||
126 | #define CISR_EOF (1 << 3) /* End of frame */ | ||
127 | #define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */ | ||
128 | #define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */ | ||
129 | #define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */ | ||
130 | |||
131 | #define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */ | ||
132 | #define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */ | ||
133 | #define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */ | ||
134 | #define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */ | ||
135 | #define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */ | ||
136 | #define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */ | ||
137 | #define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */ | ||
138 | #define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */ | ||
139 | |||
140 | #define CICR0_SIM_MP (0 << 24) | ||
141 | #define CICR0_SIM_SP (1 << 24) | ||
142 | #define CICR0_SIM_MS (2 << 24) | ||
143 | #define CICR0_SIM_EP (3 << 24) | ||
144 | #define CICR0_SIM_ES (4 << 24) | ||
145 | |||
146 | #define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */ | ||
147 | #define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */ | ||
148 | #define CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */ | ||
149 | #define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */ | ||
150 | #define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */ | ||
151 | |||
152 | #define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */ | ||
153 | #define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */ | ||
154 | #define CICR2_HSW_VAL(x) (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */ | ||
155 | #define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */ | ||
156 | #define CICR2_FSW_VAL(x) (((x) << 0) & CICR2_FSW) /* Frame stabilization wait count */ | ||
157 | |||
158 | #define CICR3_BFW_VAL(x) (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count */ | ||
159 | #define CICR3_EFW_VAL(x) (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */ | ||
160 | #define CICR3_VSW_VAL(x) (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */ | ||
161 | #define CICR3_LPF_VAL(x) (((x) << 0) & CICR3_LPF) /* Lines per frame */ | ||
162 | |||
163 | #define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \ | ||
164 | CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ | ||
165 | CICR0_EOFM | CICR0_FOM) | ||
166 | |||
167 | /* | ||
168 | * Structures | ||
169 | */ | ||
170 | enum pxa_camera_active_dma { | ||
171 | DMA_Y = 0x1, | ||
172 | DMA_U = 0x2, | ||
173 | DMA_V = 0x4, | ||
174 | }; | ||
175 | |||
176 | /* descriptor needed for the PXA DMA engine */ | ||
177 | struct pxa_cam_dma { | ||
178 | dma_addr_t sg_dma; | ||
179 | struct pxa_dma_desc *sg_cpu; | ||
180 | size_t sg_size; | ||
181 | int sglen; | ||
182 | }; | ||
183 | |||
184 | /* buffer for one video frame */ | ||
185 | struct pxa_buffer { | ||
186 | /* common v4l buffer stuff -- must be first */ | ||
187 | struct videobuf_buffer vb; | ||
188 | enum v4l2_mbus_pixelcode code; | ||
189 | /* our descriptor lists for Y, U and V channels */ | ||
190 | struct pxa_cam_dma dmas[3]; | ||
191 | int inwork; | ||
192 | enum pxa_camera_active_dma active_dma; | ||
193 | }; | ||
194 | |||
195 | struct pxa_camera_dev { | ||
196 | struct soc_camera_host soc_host; | ||
197 | /* | ||
198 | * PXA27x is only supposed to handle one camera on its Quick Capture | ||
199 | * interface. If anyone ever builds hardware to enable more than | ||
200 | * one camera, they will have to modify this driver too | ||
201 | */ | ||
202 | struct soc_camera_device *icd; | ||
203 | struct clk *clk; | ||
204 | |||
205 | unsigned int irq; | ||
206 | void __iomem *base; | ||
207 | |||
208 | int channels; | ||
209 | unsigned int dma_chans[3]; | ||
210 | |||
211 | struct pxacamera_platform_data *pdata; | ||
212 | struct resource *res; | ||
213 | unsigned long platform_flags; | ||
214 | unsigned long ciclk; | ||
215 | unsigned long mclk; | ||
216 | u32 mclk_divisor; | ||
217 | u16 width_flags; /* max 10 bits */ | ||
218 | |||
219 | struct list_head capture; | ||
220 | |||
221 | spinlock_t lock; | ||
222 | |||
223 | struct pxa_buffer *active; | ||
224 | struct pxa_dma_desc *sg_tail[3]; | ||
225 | |||
226 | u32 save_cicr[5]; | ||
227 | }; | ||
228 | |||
229 | struct pxa_cam { | ||
230 | unsigned long flags; | ||
231 | }; | ||
232 | |||
233 | static const char *pxa_cam_driver_description = "PXA_Camera"; | ||
234 | |||
235 | static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ | ||
236 | |||
237 | /* | ||
238 | * Videobuf operations | ||
239 | */ | ||
240 | static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | ||
241 | unsigned int *size) | ||
242 | { | ||
243 | struct soc_camera_device *icd = vq->priv_data; | ||
244 | |||
245 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); | ||
246 | |||
247 | *size = icd->sizeimage; | ||
248 | |||
249 | if (0 == *count) | ||
250 | *count = 32; | ||
251 | if (*size * *count > vid_limit * 1024 * 1024) | ||
252 | *count = (vid_limit * 1024 * 1024) / *size; | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | ||
258 | { | ||
259 | struct soc_camera_device *icd = vq->priv_data; | ||
260 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
261 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
262 | int i; | ||
263 | |||
264 | BUG_ON(in_interrupt()); | ||
265 | |||
266 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
267 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | ||
268 | |||
269 | /* | ||
270 | * This waits until this buffer is out of danger, i.e., until it is no | ||
271 | * longer in STATE_QUEUED or STATE_ACTIVE | ||
272 | */ | ||
273 | videobuf_waiton(vq, &buf->vb, 0, 0); | ||
274 | videobuf_dma_unmap(vq->dev, dma); | ||
275 | videobuf_dma_free(dma); | ||
276 | |||
277 | for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { | ||
278 | if (buf->dmas[i].sg_cpu) | ||
279 | dma_free_coherent(ici->v4l2_dev.dev, | ||
280 | buf->dmas[i].sg_size, | ||
281 | buf->dmas[i].sg_cpu, | ||
282 | buf->dmas[i].sg_dma); | ||
283 | buf->dmas[i].sg_cpu = NULL; | ||
284 | } | ||
285 | |||
286 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
287 | } | ||
288 | |||
289 | static int calculate_dma_sglen(struct scatterlist *sglist, int sglen, | ||
290 | int sg_first_ofs, int size) | ||
291 | { | ||
292 | int i, offset, dma_len, xfer_len; | ||
293 | struct scatterlist *sg; | ||
294 | |||
295 | offset = sg_first_ofs; | ||
296 | for_each_sg(sglist, sg, sglen, i) { | ||
297 | dma_len = sg_dma_len(sg); | ||
298 | |||
299 | /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ | ||
300 | xfer_len = roundup(min(dma_len - offset, size), 8); | ||
301 | |||
302 | size = max(0, size - xfer_len); | ||
303 | offset = 0; | ||
304 | if (size == 0) | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | BUG_ON(size != 0); | ||
309 | return i + 1; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * pxa_init_dma_channel - init dma descriptors | ||
314 | * @pcdev: pxa camera device | ||
315 | * @buf: pxa buffer to find pxa dma channel | ||
316 | * @dma: dma video buffer | ||
317 | * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V') | ||
318 | * @cibr: camera Receive Buffer Register | ||
319 | * @size: bytes to transfer | ||
320 | * @sg_first: first element of sg_list | ||
321 | * @sg_first_ofs: offset in first element of sg_list | ||
322 | * | ||
323 | * Prepares the pxa dma descriptors to transfer one camera channel. | ||
324 | * Beware sg_first and sg_first_ofs are both input and output parameters. | ||
325 | * | ||
326 | * Returns 0 or -ENOMEM if no coherent memory is available | ||
327 | */ | ||
328 | static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | ||
329 | struct pxa_buffer *buf, | ||
330 | struct videobuf_dmabuf *dma, int channel, | ||
331 | int cibr, int size, | ||
332 | struct scatterlist **sg_first, int *sg_first_ofs) | ||
333 | { | ||
334 | struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; | ||
335 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
336 | struct scatterlist *sg; | ||
337 | int i, offset, sglen; | ||
338 | int dma_len = 0, xfer_len = 0; | ||
339 | |||
340 | if (pxa_dma->sg_cpu) | ||
341 | dma_free_coherent(dev, pxa_dma->sg_size, | ||
342 | pxa_dma->sg_cpu, pxa_dma->sg_dma); | ||
343 | |||
344 | sglen = calculate_dma_sglen(*sg_first, dma->sglen, | ||
345 | *sg_first_ofs, size); | ||
346 | |||
347 | pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); | ||
348 | pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size, | ||
349 | &pxa_dma->sg_dma, GFP_KERNEL); | ||
350 | if (!pxa_dma->sg_cpu) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | pxa_dma->sglen = sglen; | ||
354 | offset = *sg_first_ofs; | ||
355 | |||
356 | dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", | ||
357 | *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); | ||
358 | |||
359 | |||
360 | for_each_sg(*sg_first, sg, sglen, i) { | ||
361 | dma_len = sg_dma_len(sg); | ||
362 | |||
363 | /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ | ||
364 | xfer_len = roundup(min(dma_len - offset, size), 8); | ||
365 | |||
366 | size = max(0, size - xfer_len); | ||
367 | |||
368 | pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr; | ||
369 | pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset; | ||
370 | pxa_dma->sg_cpu[i].dcmd = | ||
371 | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; | ||
372 | #ifdef DEBUG | ||
373 | if (!i) | ||
374 | pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN; | ||
375 | #endif | ||
376 | pxa_dma->sg_cpu[i].ddadr = | ||
377 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); | ||
378 | |||
379 | dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", | ||
380 | pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), | ||
381 | sg_dma_address(sg) + offset, xfer_len); | ||
382 | offset = 0; | ||
383 | |||
384 | if (size == 0) | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP; | ||
389 | pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN; | ||
390 | |||
391 | /* | ||
392 | * Handle 1 special case : | ||
393 | * - in 3 planes (YUV422P format), we might finish with xfer_len equal | ||
394 | * to dma_len (end on PAGE boundary). In this case, the sg element | ||
395 | * for next plane should be the next after the last used to store the | ||
396 | * last scatter gather RAM page | ||
397 | */ | ||
398 | if (xfer_len >= dma_len) { | ||
399 | *sg_first_ofs = xfer_len - dma_len; | ||
400 | *sg_first = sg_next(sg); | ||
401 | } else { | ||
402 | *sg_first_ofs = xfer_len; | ||
403 | *sg_first = sg; | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev, | ||
410 | struct pxa_buffer *buf) | ||
411 | { | ||
412 | buf->active_dma = DMA_Y; | ||
413 | if (pcdev->channels == 3) | ||
414 | buf->active_dma |= DMA_U | DMA_V; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Please check the DMA prepared buffer structure in : | ||
419 | * Documentation/video4linux/pxa_camera.txt | ||
420 | * Please check also in pxa_camera_check_link_miss() to understand why DMA chain | ||
421 | * modification while DMA chain is running will work anyway. | ||
422 | */ | ||
423 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, | ||
424 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
425 | { | ||
426 | struct soc_camera_device *icd = vq->priv_data; | ||
427 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
428 | struct pxa_camera_dev *pcdev = ici->priv; | ||
429 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
430 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
431 | int ret; | ||
432 | int size_y, size_u = 0, size_v = 0; | ||
433 | |||
434 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
435 | vb, vb->baddr, vb->bsize); | ||
436 | |||
437 | /* Added list head initialization on alloc */ | ||
438 | WARN_ON(!list_empty(&vb->queue)); | ||
439 | |||
440 | #ifdef DEBUG | ||
441 | /* | ||
442 | * This can be useful if you want to see if we actually fill | ||
443 | * the buffer with something | ||
444 | */ | ||
445 | memset((void *)vb->baddr, 0xaa, vb->bsize); | ||
446 | #endif | ||
447 | |||
448 | BUG_ON(NULL == icd->current_fmt); | ||
449 | |||
450 | /* | ||
451 | * I think, in buf_prepare you only have to protect global data, | ||
452 | * the actual buffer is yours | ||
453 | */ | ||
454 | buf->inwork = 1; | ||
455 | |||
456 | if (buf->code != icd->current_fmt->code || | ||
457 | vb->width != icd->user_width || | ||
458 | vb->height != icd->user_height || | ||
459 | vb->field != field) { | ||
460 | buf->code = icd->current_fmt->code; | ||
461 | vb->width = icd->user_width; | ||
462 | vb->height = icd->user_height; | ||
463 | vb->field = field; | ||
464 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
465 | } | ||
466 | |||
467 | vb->size = icd->sizeimage; | ||
468 | if (0 != vb->baddr && vb->bsize < vb->size) { | ||
469 | ret = -EINVAL; | ||
470 | goto out; | ||
471 | } | ||
472 | |||
473 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
474 | int size = vb->size; | ||
475 | int next_ofs = 0; | ||
476 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
477 | struct scatterlist *sg; | ||
478 | |||
479 | ret = videobuf_iolock(vq, vb, NULL); | ||
480 | if (ret) | ||
481 | goto fail; | ||
482 | |||
483 | if (pcdev->channels == 3) { | ||
484 | size_y = size / 2; | ||
485 | size_u = size_v = size / 4; | ||
486 | } else { | ||
487 | size_y = size; | ||
488 | } | ||
489 | |||
490 | sg = dma->sglist; | ||
491 | |||
492 | /* init DMA for Y channel */ | ||
493 | ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, | ||
494 | &sg, &next_ofs); | ||
495 | if (ret) { | ||
496 | dev_err(dev, "DMA initialization for Y/RGB failed\n"); | ||
497 | goto fail; | ||
498 | } | ||
499 | |||
500 | /* init DMA for U channel */ | ||
501 | if (size_u) | ||
502 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, | ||
503 | size_u, &sg, &next_ofs); | ||
504 | if (ret) { | ||
505 | dev_err(dev, "DMA initialization for U failed\n"); | ||
506 | goto fail_u; | ||
507 | } | ||
508 | |||
509 | /* init DMA for V channel */ | ||
510 | if (size_v) | ||
511 | ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, | ||
512 | size_v, &sg, &next_ofs); | ||
513 | if (ret) { | ||
514 | dev_err(dev, "DMA initialization for V failed\n"); | ||
515 | goto fail_v; | ||
516 | } | ||
517 | |||
518 | vb->state = VIDEOBUF_PREPARED; | ||
519 | } | ||
520 | |||
521 | buf->inwork = 0; | ||
522 | pxa_videobuf_set_actdma(pcdev, buf); | ||
523 | |||
524 | return 0; | ||
525 | |||
526 | fail_v: | ||
527 | dma_free_coherent(dev, buf->dmas[1].sg_size, | ||
528 | buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); | ||
529 | fail_u: | ||
530 | dma_free_coherent(dev, buf->dmas[0].sg_size, | ||
531 | buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); | ||
532 | fail: | ||
533 | free_buffer(vq, buf); | ||
534 | out: | ||
535 | buf->inwork = 0; | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * pxa_dma_start_channels - start DMA channel for active buffer | ||
541 | * @pcdev: pxa camera device | ||
542 | * | ||
543 | * Initialize DMA channels to the beginning of the active video buffer, and | ||
544 | * start these channels. | ||
545 | */ | ||
546 | static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) | ||
547 | { | ||
548 | int i; | ||
549 | struct pxa_buffer *active; | ||
550 | |||
551 | active = pcdev->active; | ||
552 | |||
553 | for (i = 0; i < pcdev->channels; i++) { | ||
554 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | ||
555 | "%s (channel=%d) ddadr=%08x\n", __func__, | ||
556 | i, active->dmas[i].sg_dma); | ||
557 | DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; | ||
558 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
559 | } | ||
560 | } | ||
561 | |||
562 | static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) | ||
563 | { | ||
564 | int i; | ||
565 | |||
566 | for (i = 0; i < pcdev->channels; i++) { | ||
567 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | ||
568 | "%s (channel=%d)\n", __func__, i); | ||
569 | DCSR(pcdev->dma_chans[i]) = 0; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev, | ||
574 | struct pxa_buffer *buf) | ||
575 | { | ||
576 | int i; | ||
577 | struct pxa_dma_desc *buf_last_desc; | ||
578 | |||
579 | for (i = 0; i < pcdev->channels; i++) { | ||
580 | buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen; | ||
581 | buf_last_desc->ddadr = DDADR_STOP; | ||
582 | |||
583 | if (pcdev->sg_tail[i]) | ||
584 | /* Link the new buffer to the old tail */ | ||
585 | pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma; | ||
586 | |||
587 | /* Update the channel tail */ | ||
588 | pcdev->sg_tail[i] = buf_last_desc; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | /** | ||
593 | * pxa_camera_start_capture - start video capturing | ||
594 | * @pcdev: camera device | ||
595 | * | ||
596 | * Launch capturing. DMA channels should not be active yet. They should get | ||
597 | * activated at the end of frame interrupt, to capture only whole frames, and | ||
598 | * never begin the capture of a partial frame. | ||
599 | */ | ||
600 | static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) | ||
601 | { | ||
602 | unsigned long cicr0; | ||
603 | |||
604 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); | ||
605 | /* Enable End-Of-Frame Interrupt */ | ||
606 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; | ||
607 | cicr0 &= ~CICR0_EOFM; | ||
608 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
609 | } | ||
610 | |||
611 | static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) | ||
612 | { | ||
613 | unsigned long cicr0; | ||
614 | |||
615 | pxa_dma_stop_channels(pcdev); | ||
616 | |||
617 | cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; | ||
618 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
619 | |||
620 | pcdev->active = NULL; | ||
621 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); | ||
622 | } | ||
623 | |||
624 | /* Called under spinlock_irqsave(&pcdev->lock, ...) */ | ||
625 | static void pxa_videobuf_queue(struct videobuf_queue *vq, | ||
626 | struct videobuf_buffer *vb) | ||
627 | { | ||
628 | struct soc_camera_device *icd = vq->priv_data; | ||
629 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
630 | struct pxa_camera_dev *pcdev = ici->priv; | ||
631 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
632 | |||
633 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n", | ||
634 | __func__, vb, vb->baddr, vb->bsize, pcdev->active); | ||
635 | |||
636 | list_add_tail(&vb->queue, &pcdev->capture); | ||
637 | |||
638 | vb->state = VIDEOBUF_ACTIVE; | ||
639 | pxa_dma_add_tail_buf(pcdev, buf); | ||
640 | |||
641 | if (!pcdev->active) | ||
642 | pxa_camera_start_capture(pcdev); | ||
643 | } | ||
644 | |||
645 | static void pxa_videobuf_release(struct videobuf_queue *vq, | ||
646 | struct videobuf_buffer *vb) | ||
647 | { | ||
648 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
649 | #ifdef DEBUG | ||
650 | struct soc_camera_device *icd = vq->priv_data; | ||
651 | struct device *dev = icd->parent; | ||
652 | |||
653 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
654 | vb, vb->baddr, vb->bsize); | ||
655 | |||
656 | switch (vb->state) { | ||
657 | case VIDEOBUF_ACTIVE: | ||
658 | dev_dbg(dev, "%s (active)\n", __func__); | ||
659 | break; | ||
660 | case VIDEOBUF_QUEUED: | ||
661 | dev_dbg(dev, "%s (queued)\n", __func__); | ||
662 | break; | ||
663 | case VIDEOBUF_PREPARED: | ||
664 | dev_dbg(dev, "%s (prepared)\n", __func__); | ||
665 | break; | ||
666 | default: | ||
667 | dev_dbg(dev, "%s (unknown)\n", __func__); | ||
668 | break; | ||
669 | } | ||
670 | #endif | ||
671 | |||
672 | free_buffer(vq, buf); | ||
673 | } | ||
674 | |||
675 | static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | ||
676 | struct videobuf_buffer *vb, | ||
677 | struct pxa_buffer *buf) | ||
678 | { | ||
679 | int i; | ||
680 | |||
681 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | ||
682 | list_del_init(&vb->queue); | ||
683 | vb->state = VIDEOBUF_DONE; | ||
684 | do_gettimeofday(&vb->ts); | ||
685 | vb->field_count++; | ||
686 | wake_up(&vb->done); | ||
687 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n", | ||
688 | __func__, vb); | ||
689 | |||
690 | if (list_empty(&pcdev->capture)) { | ||
691 | pxa_camera_stop_capture(pcdev); | ||
692 | for (i = 0; i < pcdev->channels; i++) | ||
693 | pcdev->sg_tail[i] = NULL; | ||
694 | return; | ||
695 | } | ||
696 | |||
697 | pcdev->active = list_entry(pcdev->capture.next, | ||
698 | struct pxa_buffer, vb.queue); | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * pxa_camera_check_link_miss - check missed DMA linking | ||
703 | * @pcdev: camera device | ||
704 | * | ||
705 | * The DMA chaining is done with DMA running. This means a tiny temporal window | ||
706 | * remains, where a buffer is queued on the chain, while the chain is already | ||
707 | * stopped. This means the tailed buffer would never be transferred by DMA. | ||
708 | * This function restarts the capture for this corner case, where : | ||
709 | * - DADR() == DADDR_STOP | ||
710 | * - a videobuffer is queued on the pcdev->capture list | ||
711 | * | ||
712 | * Please check the "DMA hot chaining timeslice issue" in | ||
713 | * Documentation/video4linux/pxa_camera.txt | ||
714 | * | ||
715 | * Context: should only be called within the dma irq handler | ||
716 | */ | ||
717 | static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) | ||
718 | { | ||
719 | int i, is_dma_stopped = 1; | ||
720 | |||
721 | for (i = 0; i < pcdev->channels; i++) | ||
722 | if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) | ||
723 | is_dma_stopped = 0; | ||
724 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | ||
725 | "%s : top queued buffer=%p, dma_stopped=%d\n", | ||
726 | __func__, pcdev->active, is_dma_stopped); | ||
727 | if (pcdev->active && is_dma_stopped) | ||
728 | pxa_camera_start_capture(pcdev); | ||
729 | } | ||
730 | |||
731 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | ||
732 | enum pxa_camera_active_dma act_dma) | ||
733 | { | ||
734 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
735 | struct pxa_buffer *buf; | ||
736 | unsigned long flags; | ||
737 | u32 status, camera_status, overrun; | ||
738 | struct videobuf_buffer *vb; | ||
739 | |||
740 | spin_lock_irqsave(&pcdev->lock, flags); | ||
741 | |||
742 | status = DCSR(channel); | ||
743 | DCSR(channel) = status; | ||
744 | |||
745 | camera_status = __raw_readl(pcdev->base + CISR); | ||
746 | overrun = CISR_IFO_0; | ||
747 | if (pcdev->channels == 3) | ||
748 | overrun |= CISR_IFO_1 | CISR_IFO_2; | ||
749 | |||
750 | if (status & DCSR_BUSERR) { | ||
751 | dev_err(dev, "DMA Bus Error IRQ!\n"); | ||
752 | goto out; | ||
753 | } | ||
754 | |||
755 | if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { | ||
756 | dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n", | ||
757 | status); | ||
758 | goto out; | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * pcdev->active should not be NULL in DMA irq handler. | ||
763 | * | ||
764 | * But there is one corner case : if capture was stopped due to an | ||
765 | * overrun of channel 1, and at that same channel 2 was completed. | ||
766 | * | ||
767 | * When handling the overrun in DMA irq for channel 1, we'll stop the | ||
768 | * capture and restart it (and thus set pcdev->active to NULL). But the | ||
769 | * DMA irq handler will already be pending for channel 2. So on entering | ||
770 | * the DMA irq handler for channel 2 there will be no active buffer, yet | ||
771 | * that is normal. | ||
772 | */ | ||
773 | if (!pcdev->active) | ||
774 | goto out; | ||
775 | |||
776 | vb = &pcdev->active->vb; | ||
777 | buf = container_of(vb, struct pxa_buffer, vb); | ||
778 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | ||
779 | |||
780 | dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", | ||
781 | __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", | ||
782 | status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); | ||
783 | |||
784 | if (status & DCSR_ENDINTR) { | ||
785 | /* | ||
786 | * It's normal if the last frame creates an overrun, as there | ||
787 | * are no more DMA descriptors to fetch from QCI fifos | ||
788 | */ | ||
789 | if (camera_status & overrun && | ||
790 | !list_is_last(pcdev->capture.next, &pcdev->capture)) { | ||
791 | dev_dbg(dev, "FIFO overrun! CISR: %x\n", | ||
792 | camera_status); | ||
793 | pxa_camera_stop_capture(pcdev); | ||
794 | pxa_camera_start_capture(pcdev); | ||
795 | goto out; | ||
796 | } | ||
797 | buf->active_dma &= ~act_dma; | ||
798 | if (!buf->active_dma) { | ||
799 | pxa_camera_wakeup(pcdev, vb, buf); | ||
800 | pxa_camera_check_link_miss(pcdev); | ||
801 | } | ||
802 | } | ||
803 | |||
804 | out: | ||
805 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
806 | } | ||
807 | |||
808 | static void pxa_camera_dma_irq_y(int channel, void *data) | ||
809 | { | ||
810 | struct pxa_camera_dev *pcdev = data; | ||
811 | pxa_camera_dma_irq(channel, pcdev, DMA_Y); | ||
812 | } | ||
813 | |||
814 | static void pxa_camera_dma_irq_u(int channel, void *data) | ||
815 | { | ||
816 | struct pxa_camera_dev *pcdev = data; | ||
817 | pxa_camera_dma_irq(channel, pcdev, DMA_U); | ||
818 | } | ||
819 | |||
820 | static void pxa_camera_dma_irq_v(int channel, void *data) | ||
821 | { | ||
822 | struct pxa_camera_dev *pcdev = data; | ||
823 | pxa_camera_dma_irq(channel, pcdev, DMA_V); | ||
824 | } | ||
825 | |||
826 | static struct videobuf_queue_ops pxa_videobuf_ops = { | ||
827 | .buf_setup = pxa_videobuf_setup, | ||
828 | .buf_prepare = pxa_videobuf_prepare, | ||
829 | .buf_queue = pxa_videobuf_queue, | ||
830 | .buf_release = pxa_videobuf_release, | ||
831 | }; | ||
832 | |||
833 | static void pxa_camera_init_videobuf(struct videobuf_queue *q, | ||
834 | struct soc_camera_device *icd) | ||
835 | { | ||
836 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
837 | struct pxa_camera_dev *pcdev = ici->priv; | ||
838 | |||
839 | /* | ||
840 | * We must pass NULL as dev pointer, then all pci_* dma operations | ||
841 | * transform to normal dma_* ones. | ||
842 | */ | ||
843 | videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, | ||
844 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
845 | sizeof(struct pxa_buffer), icd, &icd->video_lock); | ||
846 | } | ||
847 | |||
848 | static u32 mclk_get_divisor(struct platform_device *pdev, | ||
849 | struct pxa_camera_dev *pcdev) | ||
850 | { | ||
851 | unsigned long mclk = pcdev->mclk; | ||
852 | struct device *dev = &pdev->dev; | ||
853 | u32 div; | ||
854 | unsigned long lcdclk; | ||
855 | |||
856 | lcdclk = clk_get_rate(pcdev->clk); | ||
857 | pcdev->ciclk = lcdclk; | ||
858 | |||
859 | /* mclk <= ciclk / 4 (27.4.2) */ | ||
860 | if (mclk > lcdclk / 4) { | ||
861 | mclk = lcdclk / 4; | ||
862 | dev_warn(dev, "Limiting master clock to %lu\n", mclk); | ||
863 | } | ||
864 | |||
865 | /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ | ||
866 | div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; | ||
867 | |||
868 | /* If we're not supplying MCLK, leave it at 0 */ | ||
869 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | ||
870 | pcdev->mclk = lcdclk / (2 * (div + 1)); | ||
871 | |||
872 | dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n", | ||
873 | lcdclk, mclk, div); | ||
874 | |||
875 | return div; | ||
876 | } | ||
877 | |||
878 | static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev, | ||
879 | unsigned long pclk) | ||
880 | { | ||
881 | /* We want a timeout > 1 pixel time, not ">=" */ | ||
882 | u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1; | ||
883 | |||
884 | __raw_writel(ciclk_per_pixel, pcdev->base + CITOR); | ||
885 | } | ||
886 | |||
887 | static void pxa_camera_activate(struct pxa_camera_dev *pcdev) | ||
888 | { | ||
889 | u32 cicr4 = 0; | ||
890 | |||
891 | /* disable all interrupts */ | ||
892 | __raw_writel(0x3ff, pcdev->base + CICR0); | ||
893 | |||
894 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
895 | cicr4 |= CICR4_PCLK_EN; | ||
896 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | ||
897 | cicr4 |= CICR4_MCLK_EN; | ||
898 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | ||
899 | cicr4 |= CICR4_PCP; | ||
900 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | ||
901 | cicr4 |= CICR4_HSP; | ||
902 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | ||
903 | cicr4 |= CICR4_VSP; | ||
904 | |||
905 | __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4); | ||
906 | |||
907 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | ||
908 | /* Initialise the timeout under the assumption pclk = mclk */ | ||
909 | recalculate_fifo_timeout(pcdev, pcdev->mclk); | ||
910 | else | ||
911 | /* "Safe default" - 13MHz */ | ||
912 | recalculate_fifo_timeout(pcdev, 13000000); | ||
913 | |||
914 | clk_prepare_enable(pcdev->clk); | ||
915 | } | ||
916 | |||
917 | static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) | ||
918 | { | ||
919 | clk_disable_unprepare(pcdev->clk); | ||
920 | } | ||
921 | |||
922 | static irqreturn_t pxa_camera_irq(int irq, void *data) | ||
923 | { | ||
924 | struct pxa_camera_dev *pcdev = data; | ||
925 | unsigned long status, cifr, cicr0; | ||
926 | struct pxa_buffer *buf; | ||
927 | struct videobuf_buffer *vb; | ||
928 | |||
929 | status = __raw_readl(pcdev->base + CISR); | ||
930 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | ||
931 | "Camera interrupt status 0x%lx\n", status); | ||
932 | |||
933 | if (!status) | ||
934 | return IRQ_NONE; | ||
935 | |||
936 | __raw_writel(status, pcdev->base + CISR); | ||
937 | |||
938 | if (status & CISR_EOF) { | ||
939 | /* Reset the FIFOs */ | ||
940 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | ||
941 | __raw_writel(cifr, pcdev->base + CIFR); | ||
942 | |||
943 | pcdev->active = list_first_entry(&pcdev->capture, | ||
944 | struct pxa_buffer, vb.queue); | ||
945 | vb = &pcdev->active->vb; | ||
946 | buf = container_of(vb, struct pxa_buffer, vb); | ||
947 | pxa_videobuf_set_actdma(pcdev, buf); | ||
948 | |||
949 | pxa_dma_start_channels(pcdev); | ||
950 | |||
951 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; | ||
952 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
953 | } | ||
954 | |||
955 | return IRQ_HANDLED; | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * The following two functions absolutely depend on the fact, that | ||
960 | * there can be only one camera on PXA quick capture interface | ||
961 | * Called with .video_lock held | ||
962 | */ | ||
963 | static int pxa_camera_add_device(struct soc_camera_device *icd) | ||
964 | { | ||
965 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
966 | struct pxa_camera_dev *pcdev = ici->priv; | ||
967 | |||
968 | if (pcdev->icd) | ||
969 | return -EBUSY; | ||
970 | |||
971 | pxa_camera_activate(pcdev); | ||
972 | |||
973 | pcdev->icd = icd; | ||
974 | |||
975 | dev_info(icd->parent, "PXA Camera driver attached to camera %d\n", | ||
976 | icd->devnum); | ||
977 | |||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | /* Called with .video_lock held */ | ||
982 | static void pxa_camera_remove_device(struct soc_camera_device *icd) | ||
983 | { | ||
984 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
985 | struct pxa_camera_dev *pcdev = ici->priv; | ||
986 | |||
987 | BUG_ON(icd != pcdev->icd); | ||
988 | |||
989 | dev_info(icd->parent, "PXA Camera driver detached from camera %d\n", | ||
990 | icd->devnum); | ||
991 | |||
992 | /* disable capture, disable interrupts */ | ||
993 | __raw_writel(0x3ff, pcdev->base + CICR0); | ||
994 | |||
995 | /* Stop DMA engine */ | ||
996 | DCSR(pcdev->dma_chans[0]) = 0; | ||
997 | DCSR(pcdev->dma_chans[1]) = 0; | ||
998 | DCSR(pcdev->dma_chans[2]) = 0; | ||
999 | |||
1000 | pxa_camera_deactivate(pcdev); | ||
1001 | |||
1002 | pcdev->icd = NULL; | ||
1003 | } | ||
1004 | |||
1005 | static int test_platform_param(struct pxa_camera_dev *pcdev, | ||
1006 | unsigned char buswidth, unsigned long *flags) | ||
1007 | { | ||
1008 | /* | ||
1009 | * Platform specified synchronization and pixel clock polarities are | ||
1010 | * only a recommendation and are only used during probing. The PXA270 | ||
1011 | * quick capture interface supports both. | ||
1012 | */ | ||
1013 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? | ||
1014 | V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | | ||
1015 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
1016 | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
1017 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
1018 | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
1019 | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
1020 | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
1021 | V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1022 | |||
1023 | /* If requested data width is supported by the platform, use it */ | ||
1024 | if ((1 << (buswidth - 1)) & pcdev->width_flags) | ||
1025 | return 0; | ||
1026 | |||
1027 | return -EINVAL; | ||
1028 | } | ||
1029 | |||
1030 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | ||
1031 | unsigned long flags, __u32 pixfmt) | ||
1032 | { | ||
1033 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1034 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1035 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1036 | unsigned long dw, bpp; | ||
1037 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; | ||
1038 | int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top); | ||
1039 | |||
1040 | if (ret < 0) | ||
1041 | y_skip_top = 0; | ||
1042 | |||
1043 | /* | ||
1044 | * Datawidth is now guaranteed to be equal to one of the three values. | ||
1045 | * We fix bit-per-pixel equal to data-width... | ||
1046 | */ | ||
1047 | switch (icd->current_fmt->host_fmt->bits_per_sample) { | ||
1048 | case 10: | ||
1049 | dw = 4; | ||
1050 | bpp = 0x40; | ||
1051 | break; | ||
1052 | case 9: | ||
1053 | dw = 3; | ||
1054 | bpp = 0x20; | ||
1055 | break; | ||
1056 | default: | ||
1057 | /* | ||
1058 | * Actually it can only be 8 now, | ||
1059 | * default is just to silence compiler warnings | ||
1060 | */ | ||
1061 | case 8: | ||
1062 | dw = 2; | ||
1063 | bpp = 0; | ||
1064 | } | ||
1065 | |||
1066 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
1067 | cicr4 |= CICR4_PCLK_EN; | ||
1068 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | ||
1069 | cicr4 |= CICR4_MCLK_EN; | ||
1070 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
1071 | cicr4 |= CICR4_PCP; | ||
1072 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1073 | cicr4 |= CICR4_HSP; | ||
1074 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1075 | cicr4 |= CICR4_VSP; | ||
1076 | |||
1077 | cicr0 = __raw_readl(pcdev->base + CICR0); | ||
1078 | if (cicr0 & CICR0_ENB) | ||
1079 | __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); | ||
1080 | |||
1081 | cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw; | ||
1082 | |||
1083 | switch (pixfmt) { | ||
1084 | case V4L2_PIX_FMT_YUV422P: | ||
1085 | pcdev->channels = 3; | ||
1086 | cicr1 |= CICR1_YCBCR_F; | ||
1087 | /* | ||
1088 | * Normally, pxa bus wants as input UYVY format. We allow all | ||
1089 | * reorderings of the YUV422 format, as no processing is done, | ||
1090 | * and the YUV stream is just passed through without any | ||
1091 | * transformation. Note that UYVY is the only format that | ||
1092 | * should be used if pxa framebuffer Overlay2 is used. | ||
1093 | */ | ||
1094 | case V4L2_PIX_FMT_UYVY: | ||
1095 | case V4L2_PIX_FMT_VYUY: | ||
1096 | case V4L2_PIX_FMT_YUYV: | ||
1097 | case V4L2_PIX_FMT_YVYU: | ||
1098 | cicr1 |= CICR1_COLOR_SP_VAL(2); | ||
1099 | break; | ||
1100 | case V4L2_PIX_FMT_RGB555: | ||
1101 | cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) | | ||
1102 | CICR1_TBIT | CICR1_COLOR_SP_VAL(1); | ||
1103 | break; | ||
1104 | case V4L2_PIX_FMT_RGB565: | ||
1105 | cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2); | ||
1106 | break; | ||
1107 | } | ||
1108 | |||
1109 | cicr2 = 0; | ||
1110 | cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | | ||
1111 | CICR3_BFW_VAL(min((u32)255, y_skip_top)); | ||
1112 | cicr4 |= pcdev->mclk_divisor; | ||
1113 | |||
1114 | __raw_writel(cicr1, pcdev->base + CICR1); | ||
1115 | __raw_writel(cicr2, pcdev->base + CICR2); | ||
1116 | __raw_writel(cicr3, pcdev->base + CICR3); | ||
1117 | __raw_writel(cicr4, pcdev->base + CICR4); | ||
1118 | |||
1119 | /* CIF interrupts are not used, only DMA */ | ||
1120 | cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ? | ||
1121 | CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); | ||
1122 | cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; | ||
1123 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
1124 | } | ||
1125 | |||
1126 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd) | ||
1127 | { | ||
1128 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1129 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1130 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1131 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
1132 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | ||
1133 | unsigned long bus_flags, common_flags; | ||
1134 | int ret; | ||
1135 | struct pxa_cam *cam = icd->host_priv; | ||
1136 | |||
1137 | ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample, | ||
1138 | &bus_flags); | ||
1139 | if (ret < 0) | ||
1140 | return ret; | ||
1141 | |||
1142 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1143 | if (!ret) { | ||
1144 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1145 | bus_flags); | ||
1146 | if (!common_flags) { | ||
1147 | dev_warn(icd->parent, | ||
1148 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1149 | cfg.flags, bus_flags); | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | } else if (ret != -ENOIOCTLCMD) { | ||
1153 | return ret; | ||
1154 | } else { | ||
1155 | common_flags = bus_flags; | ||
1156 | } | ||
1157 | |||
1158 | pcdev->channels = 1; | ||
1159 | |||
1160 | /* Make choises, based on platform preferences */ | ||
1161 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
1162 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
1163 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | ||
1164 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
1165 | else | ||
1166 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
1167 | } | ||
1168 | |||
1169 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
1170 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
1171 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | ||
1172 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
1173 | else | ||
1174 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
1175 | } | ||
1176 | |||
1177 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1178 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1179 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | ||
1180 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1181 | else | ||
1182 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1183 | } | ||
1184 | |||
1185 | cfg.flags = common_flags; | ||
1186 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1187 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1188 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1189 | common_flags, ret); | ||
1190 | return ret; | ||
1191 | } | ||
1192 | |||
1193 | cam->flags = common_flags; | ||
1194 | |||
1195 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | ||
1196 | |||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | ||
1201 | unsigned char buswidth) | ||
1202 | { | ||
1203 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1204 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1205 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1206 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
1207 | unsigned long bus_flags, common_flags; | ||
1208 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); | ||
1209 | |||
1210 | if (ret < 0) | ||
1211 | return ret; | ||
1212 | |||
1213 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1214 | if (!ret) { | ||
1215 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1216 | bus_flags); | ||
1217 | if (!common_flags) { | ||
1218 | dev_warn(icd->parent, | ||
1219 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1220 | cfg.flags, bus_flags); | ||
1221 | return -EINVAL; | ||
1222 | } | ||
1223 | } else if (ret == -ENOIOCTLCMD) { | ||
1224 | ret = 0; | ||
1225 | } | ||
1226 | |||
1227 | return ret; | ||
1228 | } | ||
1229 | |||
1230 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { | ||
1231 | { | ||
1232 | .fourcc = V4L2_PIX_FMT_YUV422P, | ||
1233 | .name = "Planar YUV422 16 bit", | ||
1234 | .bits_per_sample = 8, | ||
1235 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1236 | .order = SOC_MBUS_ORDER_LE, | ||
1237 | .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_U_V, | ||
1238 | }, | ||
1239 | }; | ||
1240 | |||
1241 | /* This will be corrected as we get more formats */ | ||
1242 | static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
1243 | { | ||
1244 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
1245 | (fmt->bits_per_sample == 8 && | ||
1246 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
1247 | (fmt->bits_per_sample > 8 && | ||
1248 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
1249 | } | ||
1250 | |||
1251 | static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, | ||
1252 | struct soc_camera_format_xlate *xlate) | ||
1253 | { | ||
1254 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1255 | struct device *dev = icd->parent; | ||
1256 | int formats = 0, ret; | ||
1257 | struct pxa_cam *cam; | ||
1258 | enum v4l2_mbus_pixelcode code; | ||
1259 | const struct soc_mbus_pixelfmt *fmt; | ||
1260 | |||
1261 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
1262 | if (ret < 0) | ||
1263 | /* No more formats */ | ||
1264 | return 0; | ||
1265 | |||
1266 | fmt = soc_mbus_get_fmtdesc(code); | ||
1267 | if (!fmt) { | ||
1268 | dev_err(dev, "Invalid format code #%u: %d\n", idx, code); | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | /* This also checks support for the requested bits-per-sample */ | ||
1273 | ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
1274 | if (ret < 0) | ||
1275 | return 0; | ||
1276 | |||
1277 | if (!icd->host_priv) { | ||
1278 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1279 | if (!cam) | ||
1280 | return -ENOMEM; | ||
1281 | |||
1282 | icd->host_priv = cam; | ||
1283 | } else { | ||
1284 | cam = icd->host_priv; | ||
1285 | } | ||
1286 | |||
1287 | switch (code) { | ||
1288 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
1289 | formats++; | ||
1290 | if (xlate) { | ||
1291 | xlate->host_fmt = &pxa_camera_formats[0]; | ||
1292 | xlate->code = code; | ||
1293 | xlate++; | ||
1294 | dev_dbg(dev, "Providing format %s using code %d\n", | ||
1295 | pxa_camera_formats[0].name, code); | ||
1296 | } | ||
1297 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
1298 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
1299 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
1300 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
1301 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: | ||
1302 | if (xlate) | ||
1303 | dev_dbg(dev, "Providing format %s packed\n", | ||
1304 | fmt->name); | ||
1305 | break; | ||
1306 | default: | ||
1307 | if (!pxa_camera_packing_supported(fmt)) | ||
1308 | return 0; | ||
1309 | if (xlate) | ||
1310 | dev_dbg(dev, | ||
1311 | "Providing format %s in pass-through mode\n", | ||
1312 | fmt->name); | ||
1313 | } | ||
1314 | |||
1315 | /* Generic pass-through */ | ||
1316 | formats++; | ||
1317 | if (xlate) { | ||
1318 | xlate->host_fmt = fmt; | ||
1319 | xlate->code = code; | ||
1320 | xlate++; | ||
1321 | } | ||
1322 | |||
1323 | return formats; | ||
1324 | } | ||
1325 | |||
1326 | static void pxa_camera_put_formats(struct soc_camera_device *icd) | ||
1327 | { | ||
1328 | kfree(icd->host_priv); | ||
1329 | icd->host_priv = NULL; | ||
1330 | } | ||
1331 | |||
1332 | static int pxa_camera_check_frame(u32 width, u32 height) | ||
1333 | { | ||
1334 | /* limit to pxa hardware capabilities */ | ||
1335 | return height < 32 || height > 2048 || width < 48 || width > 2048 || | ||
1336 | (width & 0x01); | ||
1337 | } | ||
1338 | |||
1339 | static int pxa_camera_set_crop(struct soc_camera_device *icd, | ||
1340 | struct v4l2_crop *a) | ||
1341 | { | ||
1342 | struct v4l2_rect *rect = &a->c; | ||
1343 | struct device *dev = icd->parent; | ||
1344 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1345 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1346 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1347 | struct soc_camera_sense sense = { | ||
1348 | .master_clock = pcdev->mclk, | ||
1349 | .pixel_clock_max = pcdev->ciclk / 4, | ||
1350 | }; | ||
1351 | struct v4l2_mbus_framefmt mf; | ||
1352 | struct pxa_cam *cam = icd->host_priv; | ||
1353 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | ||
1354 | int ret; | ||
1355 | |||
1356 | /* If PCLK is used to latch data from the sensor, check sense */ | ||
1357 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
1358 | icd->sense = &sense; | ||
1359 | |||
1360 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
1361 | |||
1362 | icd->sense = NULL; | ||
1363 | |||
1364 | if (ret < 0) { | ||
1365 | dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", | ||
1366 | rect->width, rect->height, rect->left, rect->top); | ||
1367 | return ret; | ||
1368 | } | ||
1369 | |||
1370 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
1371 | if (ret < 0) | ||
1372 | return ret; | ||
1373 | |||
1374 | if (pxa_camera_check_frame(mf.width, mf.height)) { | ||
1375 | /* | ||
1376 | * Camera cropping produced a frame beyond our capabilities. | ||
1377 | * FIXME: just extract a subframe, that we can process. | ||
1378 | */ | ||
1379 | v4l_bound_align_image(&mf.width, 48, 2048, 1, | ||
1380 | &mf.height, 32, 2048, 0, | ||
1381 | fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); | ||
1382 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
1383 | if (ret < 0) | ||
1384 | return ret; | ||
1385 | |||
1386 | if (pxa_camera_check_frame(mf.width, mf.height)) { | ||
1387 | dev_warn(icd->parent, | ||
1388 | "Inconsistent state. Use S_FMT to repair\n"); | ||
1389 | return -EINVAL; | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1394 | if (sense.pixel_clock > sense.pixel_clock_max) { | ||
1395 | dev_err(dev, | ||
1396 | "pixel clock %lu set by the camera too high!", | ||
1397 | sense.pixel_clock); | ||
1398 | return -EIO; | ||
1399 | } | ||
1400 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | ||
1401 | } | ||
1402 | |||
1403 | icd->user_width = mf.width; | ||
1404 | icd->user_height = mf.height; | ||
1405 | |||
1406 | pxa_camera_setup_cicr(icd, cam->flags, fourcc); | ||
1407 | |||
1408 | return ret; | ||
1409 | } | ||
1410 | |||
1411 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, | ||
1412 | struct v4l2_format *f) | ||
1413 | { | ||
1414 | struct device *dev = icd->parent; | ||
1415 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1416 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1417 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1418 | const struct soc_camera_format_xlate *xlate = NULL; | ||
1419 | struct soc_camera_sense sense = { | ||
1420 | .master_clock = pcdev->mclk, | ||
1421 | .pixel_clock_max = pcdev->ciclk / 4, | ||
1422 | }; | ||
1423 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1424 | struct v4l2_mbus_framefmt mf; | ||
1425 | int ret; | ||
1426 | |||
1427 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1428 | if (!xlate) { | ||
1429 | dev_warn(dev, "Format %x not found\n", pix->pixelformat); | ||
1430 | return -EINVAL; | ||
1431 | } | ||
1432 | |||
1433 | /* If PCLK is used to latch data from the sensor, check sense */ | ||
1434 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
1435 | /* The caller holds a mutex. */ | ||
1436 | icd->sense = &sense; | ||
1437 | |||
1438 | mf.width = pix->width; | ||
1439 | mf.height = pix->height; | ||
1440 | mf.field = pix->field; | ||
1441 | mf.colorspace = pix->colorspace; | ||
1442 | mf.code = xlate->code; | ||
1443 | |||
1444 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); | ||
1445 | |||
1446 | if (mf.code != xlate->code) | ||
1447 | return -EINVAL; | ||
1448 | |||
1449 | icd->sense = NULL; | ||
1450 | |||
1451 | if (ret < 0) { | ||
1452 | dev_warn(dev, "Failed to configure for format %x\n", | ||
1453 | pix->pixelformat); | ||
1454 | } else if (pxa_camera_check_frame(mf.width, mf.height)) { | ||
1455 | dev_warn(dev, | ||
1456 | "Camera driver produced an unsupported frame %dx%d\n", | ||
1457 | mf.width, mf.height); | ||
1458 | ret = -EINVAL; | ||
1459 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1460 | if (sense.pixel_clock > sense.pixel_clock_max) { | ||
1461 | dev_err(dev, | ||
1462 | "pixel clock %lu set by the camera too high!", | ||
1463 | sense.pixel_clock); | ||
1464 | return -EIO; | ||
1465 | } | ||
1466 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | ||
1467 | } | ||
1468 | |||
1469 | if (ret < 0) | ||
1470 | return ret; | ||
1471 | |||
1472 | pix->width = mf.width; | ||
1473 | pix->height = mf.height; | ||
1474 | pix->field = mf.field; | ||
1475 | pix->colorspace = mf.colorspace; | ||
1476 | icd->current_fmt = xlate; | ||
1477 | |||
1478 | return ret; | ||
1479 | } | ||
1480 | |||
1481 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, | ||
1482 | struct v4l2_format *f) | ||
1483 | { | ||
1484 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1485 | const struct soc_camera_format_xlate *xlate; | ||
1486 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1487 | struct v4l2_mbus_framefmt mf; | ||
1488 | __u32 pixfmt = pix->pixelformat; | ||
1489 | int ret; | ||
1490 | |||
1491 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1492 | if (!xlate) { | ||
1493 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
1494 | return -EINVAL; | ||
1495 | } | ||
1496 | |||
1497 | /* | ||
1498 | * Limit to pxa hardware capabilities. YUV422P planar format requires | ||
1499 | * images size to be a multiple of 16 bytes. If not, zeros will be | ||
1500 | * inserted between Y and U planes, and U and V planes, which violates | ||
1501 | * the YUV422P standard. | ||
1502 | */ | ||
1503 | v4l_bound_align_image(&pix->width, 48, 2048, 1, | ||
1504 | &pix->height, 32, 2048, 0, | ||
1505 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); | ||
1506 | |||
1507 | /* limit to sensor capabilities */ | ||
1508 | mf.width = pix->width; | ||
1509 | mf.height = pix->height; | ||
1510 | /* Only progressive video supported so far */ | ||
1511 | mf.field = V4L2_FIELD_NONE; | ||
1512 | mf.colorspace = pix->colorspace; | ||
1513 | mf.code = xlate->code; | ||
1514 | |||
1515 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1516 | if (ret < 0) | ||
1517 | return ret; | ||
1518 | |||
1519 | pix->width = mf.width; | ||
1520 | pix->height = mf.height; | ||
1521 | pix->colorspace = mf.colorspace; | ||
1522 | |||
1523 | switch (mf.field) { | ||
1524 | case V4L2_FIELD_ANY: | ||
1525 | case V4L2_FIELD_NONE: | ||
1526 | pix->field = V4L2_FIELD_NONE; | ||
1527 | break; | ||
1528 | default: | ||
1529 | /* TODO: support interlaced at least in pass-through mode */ | ||
1530 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
1531 | mf.field); | ||
1532 | return -EINVAL; | ||
1533 | } | ||
1534 | |||
1535 | return ret; | ||
1536 | } | ||
1537 | |||
1538 | static int pxa_camera_reqbufs(struct soc_camera_device *icd, | ||
1539 | struct v4l2_requestbuffers *p) | ||
1540 | { | ||
1541 | int i; | ||
1542 | |||
1543 | /* | ||
1544 | * This is for locking debugging only. I removed spinlocks and now I | ||
1545 | * check whether .prepare is ever called on a linked buffer, or whether | ||
1546 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | ||
1547 | * it hadn't triggered | ||
1548 | */ | ||
1549 | for (i = 0; i < p->count; i++) { | ||
1550 | struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i], | ||
1551 | struct pxa_buffer, vb); | ||
1552 | buf->inwork = 0; | ||
1553 | INIT_LIST_HEAD(&buf->vb.queue); | ||
1554 | } | ||
1555 | |||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | static unsigned int pxa_camera_poll(struct file *file, poll_table *pt) | ||
1560 | { | ||
1561 | struct soc_camera_device *icd = file->private_data; | ||
1562 | struct pxa_buffer *buf; | ||
1563 | |||
1564 | buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer, | ||
1565 | vb.stream); | ||
1566 | |||
1567 | poll_wait(file, &buf->vb.done, pt); | ||
1568 | |||
1569 | if (buf->vb.state == VIDEOBUF_DONE || | ||
1570 | buf->vb.state == VIDEOBUF_ERROR) | ||
1571 | return POLLIN|POLLRDNORM; | ||
1572 | |||
1573 | return 0; | ||
1574 | } | ||
1575 | |||
1576 | static int pxa_camera_querycap(struct soc_camera_host *ici, | ||
1577 | struct v4l2_capability *cap) | ||
1578 | { | ||
1579 | /* cap->name is set by the firendly caller:-> */ | ||
1580 | strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); | ||
1581 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1582 | |||
1583 | return 0; | ||
1584 | } | ||
1585 | |||
1586 | static int pxa_camera_suspend(struct device *dev) | ||
1587 | { | ||
1588 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1589 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1590 | int i = 0, ret = 0; | ||
1591 | |||
1592 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); | ||
1593 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1); | ||
1594 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2); | ||
1595 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); | ||
1596 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); | ||
1597 | |||
1598 | if (pcdev->icd) { | ||
1599 | struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd); | ||
1600 | ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
1601 | if (ret == -ENOIOCTLCMD) | ||
1602 | ret = 0; | ||
1603 | } | ||
1604 | |||
1605 | return ret; | ||
1606 | } | ||
1607 | |||
1608 | static int pxa_camera_resume(struct device *dev) | ||
1609 | { | ||
1610 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1611 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1612 | int i = 0, ret = 0; | ||
1613 | |||
1614 | DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; | ||
1615 | DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; | ||
1616 | DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; | ||
1617 | |||
1618 | __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); | ||
1619 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1); | ||
1620 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2); | ||
1621 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); | ||
1622 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); | ||
1623 | |||
1624 | if (pcdev->icd) { | ||
1625 | struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd); | ||
1626 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
1627 | if (ret == -ENOIOCTLCMD) | ||
1628 | ret = 0; | ||
1629 | } | ||
1630 | |||
1631 | /* Restart frame capture if active buffer exists */ | ||
1632 | if (!ret && pcdev->active) | ||
1633 | pxa_camera_start_capture(pcdev); | ||
1634 | |||
1635 | return ret; | ||
1636 | } | ||
1637 | |||
1638 | static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | ||
1639 | .owner = THIS_MODULE, | ||
1640 | .add = pxa_camera_add_device, | ||
1641 | .remove = pxa_camera_remove_device, | ||
1642 | .set_crop = pxa_camera_set_crop, | ||
1643 | .get_formats = pxa_camera_get_formats, | ||
1644 | .put_formats = pxa_camera_put_formats, | ||
1645 | .set_fmt = pxa_camera_set_fmt, | ||
1646 | .try_fmt = pxa_camera_try_fmt, | ||
1647 | .init_videobuf = pxa_camera_init_videobuf, | ||
1648 | .reqbufs = pxa_camera_reqbufs, | ||
1649 | .poll = pxa_camera_poll, | ||
1650 | .querycap = pxa_camera_querycap, | ||
1651 | .set_bus_param = pxa_camera_set_bus_param, | ||
1652 | }; | ||
1653 | |||
1654 | static int __devinit pxa_camera_probe(struct platform_device *pdev) | ||
1655 | { | ||
1656 | struct pxa_camera_dev *pcdev; | ||
1657 | struct resource *res; | ||
1658 | void __iomem *base; | ||
1659 | int irq; | ||
1660 | int err = 0; | ||
1661 | |||
1662 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1663 | irq = platform_get_irq(pdev, 0); | ||
1664 | if (!res || irq < 0) { | ||
1665 | err = -ENODEV; | ||
1666 | goto exit; | ||
1667 | } | ||
1668 | |||
1669 | pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); | ||
1670 | if (!pcdev) { | ||
1671 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
1672 | err = -ENOMEM; | ||
1673 | goto exit; | ||
1674 | } | ||
1675 | |||
1676 | pcdev->clk = clk_get(&pdev->dev, NULL); | ||
1677 | if (IS_ERR(pcdev->clk)) { | ||
1678 | err = PTR_ERR(pcdev->clk); | ||
1679 | goto exit_kfree; | ||
1680 | } | ||
1681 | |||
1682 | pcdev->res = res; | ||
1683 | |||
1684 | pcdev->pdata = pdev->dev.platform_data; | ||
1685 | pcdev->platform_flags = pcdev->pdata->flags; | ||
1686 | if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | | ||
1687 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { | ||
1688 | /* | ||
1689 | * Platform hasn't set available data widths. This is bad. | ||
1690 | * Warn and use a default. | ||
1691 | */ | ||
1692 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | ||
1693 | "data widths, using default 10 bit\n"); | ||
1694 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; | ||
1695 | } | ||
1696 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) | ||
1697 | pcdev->width_flags = 1 << 7; | ||
1698 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) | ||
1699 | pcdev->width_flags |= 1 << 8; | ||
1700 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) | ||
1701 | pcdev->width_flags |= 1 << 9; | ||
1702 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | ||
1703 | if (!pcdev->mclk) { | ||
1704 | dev_warn(&pdev->dev, | ||
1705 | "mclk == 0! Please, fix your platform data. " | ||
1706 | "Using default 20MHz\n"); | ||
1707 | pcdev->mclk = 20000000; | ||
1708 | } | ||
1709 | |||
1710 | pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev); | ||
1711 | |||
1712 | INIT_LIST_HEAD(&pcdev->capture); | ||
1713 | spin_lock_init(&pcdev->lock); | ||
1714 | |||
1715 | /* | ||
1716 | * Request the regions. | ||
1717 | */ | ||
1718 | if (!request_mem_region(res->start, resource_size(res), | ||
1719 | PXA_CAM_DRV_NAME)) { | ||
1720 | err = -EBUSY; | ||
1721 | goto exit_clk; | ||
1722 | } | ||
1723 | |||
1724 | base = ioremap(res->start, resource_size(res)); | ||
1725 | if (!base) { | ||
1726 | err = -ENOMEM; | ||
1727 | goto exit_release; | ||
1728 | } | ||
1729 | pcdev->irq = irq; | ||
1730 | pcdev->base = base; | ||
1731 | |||
1732 | /* request dma */ | ||
1733 | err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, | ||
1734 | pxa_camera_dma_irq_y, pcdev); | ||
1735 | if (err < 0) { | ||
1736 | dev_err(&pdev->dev, "Can't request DMA for Y\n"); | ||
1737 | goto exit_iounmap; | ||
1738 | } | ||
1739 | pcdev->dma_chans[0] = err; | ||
1740 | dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); | ||
1741 | |||
1742 | err = pxa_request_dma("CI_U", DMA_PRIO_HIGH, | ||
1743 | pxa_camera_dma_irq_u, pcdev); | ||
1744 | if (err < 0) { | ||
1745 | dev_err(&pdev->dev, "Can't request DMA for U\n"); | ||
1746 | goto exit_free_dma_y; | ||
1747 | } | ||
1748 | pcdev->dma_chans[1] = err; | ||
1749 | dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); | ||
1750 | |||
1751 | err = pxa_request_dma("CI_V", DMA_PRIO_HIGH, | ||
1752 | pxa_camera_dma_irq_v, pcdev); | ||
1753 | if (err < 0) { | ||
1754 | dev_err(&pdev->dev, "Can't request DMA for V\n"); | ||
1755 | goto exit_free_dma_u; | ||
1756 | } | ||
1757 | pcdev->dma_chans[2] = err; | ||
1758 | dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); | ||
1759 | |||
1760 | DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; | ||
1761 | DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; | ||
1762 | DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; | ||
1763 | |||
1764 | /* request irq */ | ||
1765 | err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, | ||
1766 | pcdev); | ||
1767 | if (err) { | ||
1768 | dev_err(&pdev->dev, "Camera interrupt register failed \n"); | ||
1769 | goto exit_free_dma; | ||
1770 | } | ||
1771 | |||
1772 | pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; | ||
1773 | pcdev->soc_host.ops = &pxa_soc_camera_host_ops; | ||
1774 | pcdev->soc_host.priv = pcdev; | ||
1775 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1776 | pcdev->soc_host.nr = pdev->id; | ||
1777 | |||
1778 | err = soc_camera_host_register(&pcdev->soc_host); | ||
1779 | if (err) | ||
1780 | goto exit_free_irq; | ||
1781 | |||
1782 | return 0; | ||
1783 | |||
1784 | exit_free_irq: | ||
1785 | free_irq(pcdev->irq, pcdev); | ||
1786 | exit_free_dma: | ||
1787 | pxa_free_dma(pcdev->dma_chans[2]); | ||
1788 | exit_free_dma_u: | ||
1789 | pxa_free_dma(pcdev->dma_chans[1]); | ||
1790 | exit_free_dma_y: | ||
1791 | pxa_free_dma(pcdev->dma_chans[0]); | ||
1792 | exit_iounmap: | ||
1793 | iounmap(base); | ||
1794 | exit_release: | ||
1795 | release_mem_region(res->start, resource_size(res)); | ||
1796 | exit_clk: | ||
1797 | clk_put(pcdev->clk); | ||
1798 | exit_kfree: | ||
1799 | kfree(pcdev); | ||
1800 | exit: | ||
1801 | return err; | ||
1802 | } | ||
1803 | |||
1804 | static int __devexit pxa_camera_remove(struct platform_device *pdev) | ||
1805 | { | ||
1806 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1807 | struct pxa_camera_dev *pcdev = container_of(soc_host, | ||
1808 | struct pxa_camera_dev, soc_host); | ||
1809 | struct resource *res; | ||
1810 | |||
1811 | clk_put(pcdev->clk); | ||
1812 | |||
1813 | pxa_free_dma(pcdev->dma_chans[0]); | ||
1814 | pxa_free_dma(pcdev->dma_chans[1]); | ||
1815 | pxa_free_dma(pcdev->dma_chans[2]); | ||
1816 | free_irq(pcdev->irq, pcdev); | ||
1817 | |||
1818 | soc_camera_host_unregister(soc_host); | ||
1819 | |||
1820 | iounmap(pcdev->base); | ||
1821 | |||
1822 | res = pcdev->res; | ||
1823 | release_mem_region(res->start, resource_size(res)); | ||
1824 | |||
1825 | kfree(pcdev); | ||
1826 | |||
1827 | dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); | ||
1828 | |||
1829 | return 0; | ||
1830 | } | ||
1831 | |||
1832 | static struct dev_pm_ops pxa_camera_pm = { | ||
1833 | .suspend = pxa_camera_suspend, | ||
1834 | .resume = pxa_camera_resume, | ||
1835 | }; | ||
1836 | |||
1837 | static struct platform_driver pxa_camera_driver = { | ||
1838 | .driver = { | ||
1839 | .name = PXA_CAM_DRV_NAME, | ||
1840 | .pm = &pxa_camera_pm, | ||
1841 | }, | ||
1842 | .probe = pxa_camera_probe, | ||
1843 | .remove = __devexit_p(pxa_camera_remove), | ||
1844 | }; | ||
1845 | |||
1846 | module_platform_driver(pxa_camera_driver); | ||
1847 | |||
1848 | MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); | ||
1849 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | ||
1850 | MODULE_LICENSE("GPL"); | ||
1851 | MODULE_VERSION(PXA_CAM_VERSION); | ||
1852 | MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME); | ||
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c new file mode 100644 index 000000000000..0a24253dcda2 --- /dev/null +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | |||
@@ -0,0 +1,2331 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for SuperH Mobile CEU interface | ||
3 | * | ||
4 | * Copyright (C) 2008 Magnus Damm | ||
5 | * | ||
6 | * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", | ||
7 | * | ||
8 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | ||
9 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/dma-mapping.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/videodev2.h> | ||
34 | #include <linux/pm_runtime.h> | ||
35 | #include <linux/sched.h> | ||
36 | |||
37 | #include <media/v4l2-common.h> | ||
38 | #include <media/v4l2-dev.h> | ||
39 | #include <media/soc_camera.h> | ||
40 | #include <media/sh_mobile_ceu.h> | ||
41 | #include <media/sh_mobile_csi2.h> | ||
42 | #include <media/videobuf2-dma-contig.h> | ||
43 | #include <media/v4l2-mediabus.h> | ||
44 | #include <media/soc_mediabus.h> | ||
45 | |||
46 | /* register offsets for sh7722 / sh7723 */ | ||
47 | |||
48 | #define CAPSR 0x00 /* Capture start register */ | ||
49 | #define CAPCR 0x04 /* Capture control register */ | ||
50 | #define CAMCR 0x08 /* Capture interface control register */ | ||
51 | #define CMCYR 0x0c /* Capture interface cycle register */ | ||
52 | #define CAMOR 0x10 /* Capture interface offset register */ | ||
53 | #define CAPWR 0x14 /* Capture interface width register */ | ||
54 | #define CAIFR 0x18 /* Capture interface input format register */ | ||
55 | #define CSTCR 0x20 /* Camera strobe control register (<= sh7722) */ | ||
56 | #define CSECR 0x24 /* Camera strobe emission count register (<= sh7722) */ | ||
57 | #define CRCNTR 0x28 /* CEU register control register */ | ||
58 | #define CRCMPR 0x2c /* CEU register forcible control register */ | ||
59 | #define CFLCR 0x30 /* Capture filter control register */ | ||
60 | #define CFSZR 0x34 /* Capture filter size clip register */ | ||
61 | #define CDWDR 0x38 /* Capture destination width register */ | ||
62 | #define CDAYR 0x3c /* Capture data address Y register */ | ||
63 | #define CDACR 0x40 /* Capture data address C register */ | ||
64 | #define CDBYR 0x44 /* Capture data bottom-field address Y register */ | ||
65 | #define CDBCR 0x48 /* Capture data bottom-field address C register */ | ||
66 | #define CBDSR 0x4c /* Capture bundle destination size register */ | ||
67 | #define CFWCR 0x5c /* Firewall operation control register */ | ||
68 | #define CLFCR 0x60 /* Capture low-pass filter control register */ | ||
69 | #define CDOCR 0x64 /* Capture data output control register */ | ||
70 | #define CDDCR 0x68 /* Capture data complexity level register */ | ||
71 | #define CDDAR 0x6c /* Capture data complexity level address register */ | ||
72 | #define CEIER 0x70 /* Capture event interrupt enable register */ | ||
73 | #define CETCR 0x74 /* Capture event flag clear register */ | ||
74 | #define CSTSR 0x7c /* Capture status register */ | ||
75 | #define CSRTR 0x80 /* Capture software reset register */ | ||
76 | #define CDSSR 0x84 /* Capture data size register */ | ||
77 | #define CDAYR2 0x90 /* Capture data address Y register 2 */ | ||
78 | #define CDACR2 0x94 /* Capture data address C register 2 */ | ||
79 | #define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ | ||
80 | #define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ | ||
81 | |||
82 | #undef DEBUG_GEOMETRY | ||
83 | #ifdef DEBUG_GEOMETRY | ||
84 | #define dev_geo dev_info | ||
85 | #else | ||
86 | #define dev_geo dev_dbg | ||
87 | #endif | ||
88 | |||
89 | /* per video frame buffer */ | ||
90 | struct sh_mobile_ceu_buffer { | ||
91 | struct vb2_buffer vb; /* v4l buffer must be first */ | ||
92 | struct list_head queue; | ||
93 | }; | ||
94 | |||
95 | struct sh_mobile_ceu_dev { | ||
96 | struct soc_camera_host ici; | ||
97 | struct soc_camera_device *icd; | ||
98 | struct platform_device *csi2_pdev; | ||
99 | |||
100 | unsigned int irq; | ||
101 | void __iomem *base; | ||
102 | size_t video_limit; | ||
103 | size_t buf_total; | ||
104 | |||
105 | spinlock_t lock; /* Protects video buffer lists */ | ||
106 | struct list_head capture; | ||
107 | struct vb2_buffer *active; | ||
108 | struct vb2_alloc_ctx *alloc_ctx; | ||
109 | |||
110 | struct sh_mobile_ceu_info *pdata; | ||
111 | struct completion complete; | ||
112 | |||
113 | u32 cflcr; | ||
114 | |||
115 | /* static max sizes either from platform data or default */ | ||
116 | int max_width; | ||
117 | int max_height; | ||
118 | |||
119 | enum v4l2_field field; | ||
120 | int sequence; | ||
121 | |||
122 | unsigned int image_mode:1; | ||
123 | unsigned int is_16bit:1; | ||
124 | unsigned int frozen:1; | ||
125 | }; | ||
126 | |||
127 | struct sh_mobile_ceu_cam { | ||
128 | /* CEU offsets within the camera output, before the CEU scaler */ | ||
129 | unsigned int ceu_left; | ||
130 | unsigned int ceu_top; | ||
131 | /* Client output, as seen by the CEU */ | ||
132 | unsigned int width; | ||
133 | unsigned int height; | ||
134 | /* | ||
135 | * User window from S_CROP / G_CROP, produced by client cropping and | ||
136 | * scaling, CEU scaling and CEU cropping, mapped back onto the client | ||
137 | * input window | ||
138 | */ | ||
139 | struct v4l2_rect subrect; | ||
140 | /* Camera cropping rectangle */ | ||
141 | struct v4l2_rect rect; | ||
142 | const struct soc_mbus_pixelfmt *extra_fmt; | ||
143 | enum v4l2_mbus_pixelcode code; | ||
144 | }; | ||
145 | |||
146 | static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) | ||
147 | { | ||
148 | return container_of(vb, struct sh_mobile_ceu_buffer, vb); | ||
149 | } | ||
150 | |||
151 | static void ceu_write(struct sh_mobile_ceu_dev *priv, | ||
152 | unsigned long reg_offs, u32 data) | ||
153 | { | ||
154 | iowrite32(data, priv->base + reg_offs); | ||
155 | } | ||
156 | |||
157 | static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs) | ||
158 | { | ||
159 | return ioread32(priv->base + reg_offs); | ||
160 | } | ||
161 | |||
162 | static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) | ||
163 | { | ||
164 | int i, success = 0; | ||
165 | struct soc_camera_device *icd = pcdev->icd; | ||
166 | |||
167 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ | ||
168 | |||
169 | /* wait CSTSR.CPTON bit */ | ||
170 | for (i = 0; i < 1000; i++) { | ||
171 | if (!(ceu_read(pcdev, CSTSR) & 1)) { | ||
172 | success++; | ||
173 | break; | ||
174 | } | ||
175 | udelay(1); | ||
176 | } | ||
177 | |||
178 | /* wait CAPSR.CPKIL bit */ | ||
179 | for (i = 0; i < 1000; i++) { | ||
180 | if (!(ceu_read(pcdev, CAPSR) & (1 << 16))) { | ||
181 | success++; | ||
182 | break; | ||
183 | } | ||
184 | udelay(1); | ||
185 | } | ||
186 | |||
187 | |||
188 | if (2 != success) { | ||
189 | dev_warn(icd->pdev, "soft reset time out\n"); | ||
190 | return -EIO; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Videobuf operations | ||
198 | */ | ||
199 | |||
200 | /* | ||
201 | * .queue_setup() is called to check, whether the driver can accept the | ||
202 | * requested number of buffers and to fill in plane sizes | ||
203 | * for the current frame format if required | ||
204 | */ | ||
205 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, | ||
206 | const struct v4l2_format *fmt, | ||
207 | unsigned int *count, unsigned int *num_planes, | ||
208 | unsigned int sizes[], void *alloc_ctxs[]) | ||
209 | { | ||
210 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); | ||
211 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
212 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
213 | |||
214 | if (fmt) { | ||
215 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | ||
216 | fmt->fmt.pix.pixelformat); | ||
217 | unsigned int bytes_per_line; | ||
218 | int ret; | ||
219 | |||
220 | if (!xlate) | ||
221 | return -EINVAL; | ||
222 | |||
223 | ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | ||
224 | xlate->host_fmt); | ||
225 | if (ret < 0) | ||
226 | return ret; | ||
227 | |||
228 | bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret); | ||
229 | |||
230 | ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line, | ||
231 | fmt->fmt.pix.height); | ||
232 | if (ret < 0) | ||
233 | return ret; | ||
234 | |||
235 | sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret); | ||
236 | } else { | ||
237 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
238 | sizes[0] = icd->sizeimage; | ||
239 | } | ||
240 | |||
241 | alloc_ctxs[0] = pcdev->alloc_ctx; | ||
242 | |||
243 | if (!vq->num_buffers) | ||
244 | pcdev->sequence = 0; | ||
245 | |||
246 | if (!*count) | ||
247 | *count = 2; | ||
248 | |||
249 | /* If *num_planes != 0, we have already verified *count. */ | ||
250 | if (pcdev->video_limit && !*num_planes) { | ||
251 | size_t size = PAGE_ALIGN(sizes[0]) * *count; | ||
252 | |||
253 | if (size + pcdev->buf_total > pcdev->video_limit) | ||
254 | *count = (pcdev->video_limit - pcdev->buf_total) / | ||
255 | PAGE_ALIGN(sizes[0]); | ||
256 | } | ||
257 | |||
258 | *num_planes = 1; | ||
259 | |||
260 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | #define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ | ||
266 | #define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ | ||
267 | #define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ | ||
268 | #define CEU_CEIER_VBP (1 << 20) /* vbp error */ | ||
269 | #define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */ | ||
270 | #define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP) | ||
271 | |||
272 | |||
273 | /* | ||
274 | * return value doesn't reflex the success/failure to queue the new buffer, | ||
275 | * but rather the status of the previous buffer. | ||
276 | */ | ||
277 | static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | ||
278 | { | ||
279 | struct soc_camera_device *icd = pcdev->icd; | ||
280 | dma_addr_t phys_addr_top, phys_addr_bottom; | ||
281 | unsigned long top1, top2; | ||
282 | unsigned long bottom1, bottom2; | ||
283 | u32 status; | ||
284 | bool planar; | ||
285 | int ret = 0; | ||
286 | |||
287 | /* | ||
288 | * The hardware is _very_ picky about this sequence. Especially | ||
289 | * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge | ||
290 | * several not-so-well documented interrupt sources in CETCR. | ||
291 | */ | ||
292 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK); | ||
293 | status = ceu_read(pcdev, CETCR); | ||
294 | ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC); | ||
295 | if (!pcdev->frozen) | ||
296 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK); | ||
297 | ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); | ||
298 | ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); | ||
299 | |||
300 | /* | ||
301 | * When a VBP interrupt occurs, a capture end interrupt does not occur | ||
302 | * and the image of that frame is not captured correctly. So, soft reset | ||
303 | * is needed here. | ||
304 | */ | ||
305 | if (status & CEU_CEIER_VBP) { | ||
306 | sh_mobile_ceu_soft_reset(pcdev); | ||
307 | ret = -EIO; | ||
308 | } | ||
309 | |||
310 | if (pcdev->frozen) { | ||
311 | complete(&pcdev->complete); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | if (!pcdev->active) | ||
316 | return ret; | ||
317 | |||
318 | if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { | ||
319 | top1 = CDBYR; | ||
320 | top2 = CDBCR; | ||
321 | bottom1 = CDAYR; | ||
322 | bottom2 = CDACR; | ||
323 | } else { | ||
324 | top1 = CDAYR; | ||
325 | top2 = CDACR; | ||
326 | bottom1 = CDBYR; | ||
327 | bottom2 = CDBCR; | ||
328 | } | ||
329 | |||
330 | phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); | ||
331 | |||
332 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
333 | case V4L2_PIX_FMT_NV12: | ||
334 | case V4L2_PIX_FMT_NV21: | ||
335 | case V4L2_PIX_FMT_NV16: | ||
336 | case V4L2_PIX_FMT_NV61: | ||
337 | planar = true; | ||
338 | break; | ||
339 | default: | ||
340 | planar = false; | ||
341 | } | ||
342 | |||
343 | ceu_write(pcdev, top1, phys_addr_top); | ||
344 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
345 | phys_addr_bottom = phys_addr_top + icd->bytesperline; | ||
346 | ceu_write(pcdev, bottom1, phys_addr_bottom); | ||
347 | } | ||
348 | |||
349 | if (planar) { | ||
350 | phys_addr_top += icd->bytesperline * icd->user_height; | ||
351 | ceu_write(pcdev, top2, phys_addr_top); | ||
352 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
353 | phys_addr_bottom = phys_addr_top + icd->bytesperline; | ||
354 | ceu_write(pcdev, bottom2, phys_addr_bottom); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | ceu_write(pcdev, CAPSR, 0x1); /* start capture */ | ||
359 | |||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | ||
364 | { | ||
365 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
366 | |||
367 | /* Added list head initialization on alloc */ | ||
368 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
374 | { | ||
375 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
376 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
377 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
378 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
379 | unsigned long size; | ||
380 | |||
381 | size = icd->sizeimage; | ||
382 | |||
383 | if (vb2_plane_size(vb, 0) < size) { | ||
384 | dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", | ||
385 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); | ||
386 | goto error; | ||
387 | } | ||
388 | |||
389 | vb2_set_plane_payload(vb, 0, size); | ||
390 | |||
391 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
392 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
393 | |||
394 | #ifdef DEBUG | ||
395 | /* | ||
396 | * This can be useful if you want to see if we actually fill | ||
397 | * the buffer with something | ||
398 | */ | ||
399 | if (vb2_plane_vaddr(vb, 0)) | ||
400 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | ||
401 | #endif | ||
402 | |||
403 | spin_lock_irq(&pcdev->lock); | ||
404 | list_add_tail(&buf->queue, &pcdev->capture); | ||
405 | |||
406 | if (!pcdev->active) { | ||
407 | /* | ||
408 | * Because there were no active buffer at this moment, | ||
409 | * we are not interested in the return value of | ||
410 | * sh_mobile_ceu_capture here. | ||
411 | */ | ||
412 | pcdev->active = vb; | ||
413 | sh_mobile_ceu_capture(pcdev); | ||
414 | } | ||
415 | spin_unlock_irq(&pcdev->lock); | ||
416 | |||
417 | return; | ||
418 | |||
419 | error: | ||
420 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
421 | } | ||
422 | |||
423 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | ||
424 | { | ||
425 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
426 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
427 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
428 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
429 | |||
430 | spin_lock_irq(&pcdev->lock); | ||
431 | |||
432 | if (pcdev->active == vb) { | ||
433 | /* disable capture (release DMA buffer), reset */ | ||
434 | ceu_write(pcdev, CAPSR, 1 << 16); | ||
435 | pcdev->active = NULL; | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * Doesn't hurt also if the list is empty, but it hurts, if queuing the | ||
440 | * buffer failed, and .buf_init() hasn't been called | ||
441 | */ | ||
442 | if (buf->queue.next) | ||
443 | list_del_init(&buf->queue); | ||
444 | |||
445 | pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
446 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
447 | pcdev->buf_total); | ||
448 | |||
449 | spin_unlock_irq(&pcdev->lock); | ||
450 | } | ||
451 | |||
452 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | ||
453 | { | ||
454 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
455 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
456 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
457 | |||
458 | pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
459 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
460 | pcdev->buf_total); | ||
461 | |||
462 | /* This is for locking debugging only */ | ||
463 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q) | ||
468 | { | ||
469 | struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq); | ||
470 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
471 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
472 | struct list_head *buf_head, *tmp; | ||
473 | |||
474 | spin_lock_irq(&pcdev->lock); | ||
475 | |||
476 | pcdev->active = NULL; | ||
477 | |||
478 | list_for_each_safe(buf_head, tmp, &pcdev->capture) | ||
479 | list_del_init(buf_head); | ||
480 | |||
481 | spin_unlock_irq(&pcdev->lock); | ||
482 | |||
483 | return sh_mobile_ceu_soft_reset(pcdev); | ||
484 | } | ||
485 | |||
486 | static struct vb2_ops sh_mobile_ceu_videobuf_ops = { | ||
487 | .queue_setup = sh_mobile_ceu_videobuf_setup, | ||
488 | .buf_prepare = sh_mobile_ceu_videobuf_prepare, | ||
489 | .buf_queue = sh_mobile_ceu_videobuf_queue, | ||
490 | .buf_cleanup = sh_mobile_ceu_videobuf_release, | ||
491 | .buf_init = sh_mobile_ceu_videobuf_init, | ||
492 | .wait_prepare = soc_camera_unlock, | ||
493 | .wait_finish = soc_camera_lock, | ||
494 | .stop_streaming = sh_mobile_ceu_stop_streaming, | ||
495 | }; | ||
496 | |||
497 | static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) | ||
498 | { | ||
499 | struct sh_mobile_ceu_dev *pcdev = data; | ||
500 | struct vb2_buffer *vb; | ||
501 | int ret; | ||
502 | |||
503 | spin_lock(&pcdev->lock); | ||
504 | |||
505 | vb = pcdev->active; | ||
506 | if (!vb) | ||
507 | /* Stale interrupt from a released buffer */ | ||
508 | goto out; | ||
509 | |||
510 | list_del_init(&to_ceu_vb(vb)->queue); | ||
511 | |||
512 | if (!list_empty(&pcdev->capture)) | ||
513 | pcdev->active = &list_entry(pcdev->capture.next, | ||
514 | struct sh_mobile_ceu_buffer, queue)->vb; | ||
515 | else | ||
516 | pcdev->active = NULL; | ||
517 | |||
518 | ret = sh_mobile_ceu_capture(pcdev); | ||
519 | do_gettimeofday(&vb->v4l2_buf.timestamp); | ||
520 | if (!ret) { | ||
521 | vb->v4l2_buf.field = pcdev->field; | ||
522 | vb->v4l2_buf.sequence = pcdev->sequence++; | ||
523 | } | ||
524 | vb2_buffer_done(vb, ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); | ||
525 | |||
526 | out: | ||
527 | spin_unlock(&pcdev->lock); | ||
528 | |||
529 | return IRQ_HANDLED; | ||
530 | } | ||
531 | |||
532 | static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev) | ||
533 | { | ||
534 | struct v4l2_subdev *sd; | ||
535 | |||
536 | if (!pcdev->csi2_pdev) | ||
537 | return NULL; | ||
538 | |||
539 | v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) | ||
540 | if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd)) | ||
541 | return sd; | ||
542 | |||
543 | return NULL; | ||
544 | } | ||
545 | |||
546 | /* Called with .video_lock held */ | ||
547 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | ||
548 | { | ||
549 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
550 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
551 | struct v4l2_subdev *csi2_sd; | ||
552 | int ret; | ||
553 | |||
554 | if (pcdev->icd) | ||
555 | return -EBUSY; | ||
556 | |||
557 | dev_info(icd->parent, | ||
558 | "SuperH Mobile CEU driver attached to camera %d\n", | ||
559 | icd->devnum); | ||
560 | |||
561 | pm_runtime_get_sync(ici->v4l2_dev.dev); | ||
562 | |||
563 | pcdev->buf_total = 0; | ||
564 | |||
565 | ret = sh_mobile_ceu_soft_reset(pcdev); | ||
566 | |||
567 | csi2_sd = find_csi2(pcdev); | ||
568 | if (csi2_sd) { | ||
569 | csi2_sd->grp_id = soc_camera_grp_id(icd); | ||
570 | v4l2_set_subdev_hostdata(csi2_sd, icd); | ||
571 | } | ||
572 | |||
573 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); | ||
574 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { | ||
575 | pm_runtime_put_sync(ici->v4l2_dev.dev); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver | ||
581 | * has not found this soc-camera device among its clients | ||
582 | */ | ||
583 | if (ret == -ENODEV && csi2_sd) | ||
584 | csi2_sd->grp_id = 0; | ||
585 | pcdev->icd = icd; | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /* Called with .video_lock held */ | ||
591 | static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | ||
592 | { | ||
593 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
594 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
595 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
596 | |||
597 | BUG_ON(icd != pcdev->icd); | ||
598 | |||
599 | v4l2_subdev_call(csi2_sd, core, s_power, 0); | ||
600 | if (csi2_sd) | ||
601 | csi2_sd->grp_id = 0; | ||
602 | /* disable capture, disable interrupts */ | ||
603 | ceu_write(pcdev, CEIER, 0); | ||
604 | sh_mobile_ceu_soft_reset(pcdev); | ||
605 | |||
606 | /* make sure active buffer is canceled */ | ||
607 | spin_lock_irq(&pcdev->lock); | ||
608 | if (pcdev->active) { | ||
609 | list_del_init(&to_ceu_vb(pcdev->active)->queue); | ||
610 | vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); | ||
611 | pcdev->active = NULL; | ||
612 | } | ||
613 | spin_unlock_irq(&pcdev->lock); | ||
614 | |||
615 | pm_runtime_put_sync(ici->v4l2_dev.dev); | ||
616 | |||
617 | dev_info(icd->parent, | ||
618 | "SuperH Mobile CEU driver detached from camera %d\n", | ||
619 | icd->devnum); | ||
620 | |||
621 | pcdev->icd = NULL; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)" | ||
626 | * in SH7722 Hardware Manual | ||
627 | */ | ||
628 | static unsigned int size_dst(unsigned int src, unsigned int scale) | ||
629 | { | ||
630 | unsigned int mant_pre = scale >> 12; | ||
631 | if (!src || !scale) | ||
632 | return src; | ||
633 | return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) * | ||
634 | mant_pre * 4096 / scale + 1; | ||
635 | } | ||
636 | |||
637 | static u16 calc_scale(unsigned int src, unsigned int *dst) | ||
638 | { | ||
639 | u16 scale; | ||
640 | |||
641 | if (src == *dst) | ||
642 | return 0; | ||
643 | |||
644 | scale = (src * 4096 / *dst) & ~7; | ||
645 | |||
646 | while (scale > 4096 && size_dst(src, scale) < *dst) | ||
647 | scale -= 8; | ||
648 | |||
649 | *dst = size_dst(src, scale); | ||
650 | |||
651 | return scale; | ||
652 | } | ||
653 | |||
654 | /* rect is guaranteed to not exceed the scaled camera rectangle */ | ||
655 | static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | ||
656 | { | ||
657 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
658 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
659 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
660 | unsigned int height, width, cdwdr_width, in_width, in_height; | ||
661 | unsigned int left_offset, top_offset; | ||
662 | u32 camor; | ||
663 | |||
664 | dev_geo(icd->parent, "Crop %ux%u@%u:%u\n", | ||
665 | icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top); | ||
666 | |||
667 | left_offset = cam->ceu_left; | ||
668 | top_offset = cam->ceu_top; | ||
669 | |||
670 | WARN_ON(icd->user_width & 3 || icd->user_height & 3); | ||
671 | |||
672 | width = icd->user_width; | ||
673 | |||
674 | if (pcdev->image_mode) { | ||
675 | in_width = cam->width; | ||
676 | if (!pcdev->is_16bit) { | ||
677 | in_width *= 2; | ||
678 | left_offset *= 2; | ||
679 | } | ||
680 | } else { | ||
681 | unsigned int w_factor; | ||
682 | |||
683 | switch (icd->current_fmt->host_fmt->packing) { | ||
684 | case SOC_MBUS_PACKING_2X8_PADHI: | ||
685 | w_factor = 2; | ||
686 | break; | ||
687 | default: | ||
688 | w_factor = 1; | ||
689 | } | ||
690 | |||
691 | in_width = cam->width * w_factor; | ||
692 | left_offset *= w_factor; | ||
693 | } | ||
694 | |||
695 | cdwdr_width = icd->bytesperline; | ||
696 | |||
697 | height = icd->user_height; | ||
698 | in_height = cam->height; | ||
699 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
700 | height = (height / 2) & ~3; | ||
701 | in_height /= 2; | ||
702 | top_offset /= 2; | ||
703 | cdwdr_width *= 2; | ||
704 | } | ||
705 | |||
706 | /* CSI2 special configuration */ | ||
707 | if (pcdev->pdata->csi2) { | ||
708 | in_width = ((in_width - 2) * 2); | ||
709 | left_offset *= 2; | ||
710 | } | ||
711 | |||
712 | /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ | ||
713 | camor = left_offset | (top_offset << 16); | ||
714 | |||
715 | dev_geo(icd->parent, | ||
716 | "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor, | ||
717 | (in_height << 16) | in_width, (height << 16) | width, | ||
718 | cdwdr_width); | ||
719 | |||
720 | ceu_write(pcdev, CAMOR, camor); | ||
721 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); | ||
722 | /* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */ | ||
723 | ceu_write(pcdev, CFSZR, (height << 16) | width); | ||
724 | ceu_write(pcdev, CDWDR, cdwdr_width); | ||
725 | } | ||
726 | |||
727 | static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev) | ||
728 | { | ||
729 | u32 capsr = ceu_read(pcdev, CAPSR); | ||
730 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */ | ||
731 | return capsr; | ||
732 | } | ||
733 | |||
734 | static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | ||
735 | { | ||
736 | unsigned long timeout = jiffies + 10 * HZ; | ||
737 | |||
738 | /* | ||
739 | * Wait until the end of the current frame. It can take a long time, | ||
740 | * but if it has been aborted by a CAPSR reset, it shoule exit sooner. | ||
741 | */ | ||
742 | while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout)) | ||
743 | msleep(1); | ||
744 | |||
745 | if (time_after(jiffies, timeout)) { | ||
746 | dev_err(pcdev->ici.v4l2_dev.dev, | ||
747 | "Timeout waiting for frame end! Interface problem?\n"); | ||
748 | return; | ||
749 | } | ||
750 | |||
751 | /* Wait until reset clears, this shall not hang... */ | ||
752 | while (ceu_read(pcdev, CAPSR) & (1 << 16)) | ||
753 | udelay(10); | ||
754 | |||
755 | /* Anything to restore? */ | ||
756 | if (capsr & ~(1 << 16)) | ||
757 | ceu_write(pcdev, CAPSR, capsr); | ||
758 | } | ||
759 | |||
760 | /* Find the bus subdevice driver, e.g., CSI2 */ | ||
761 | static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, | ||
762 | struct soc_camera_device *icd) | ||
763 | { | ||
764 | if (pcdev->csi2_pdev) { | ||
765 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
766 | if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd)) | ||
767 | return csi2_sd; | ||
768 | } | ||
769 | |||
770 | return soc_camera_to_subdev(icd); | ||
771 | } | ||
772 | |||
773 | #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
774 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
775 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
776 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
777 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
778 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
779 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
780 | |||
781 | /* Capture is not running, no interrupts, no locking needed */ | ||
782 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) | ||
783 | { | ||
784 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
785 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
786 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); | ||
787 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
788 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
789 | unsigned long value, common_flags = CEU_BUS_FLAGS; | ||
790 | u32 capsr = capture_save_reset(pcdev); | ||
791 | unsigned int yuv_lineskip; | ||
792 | int ret; | ||
793 | |||
794 | /* | ||
795 | * If the client doesn't implement g_mbus_config, we just use our | ||
796 | * platform data | ||
797 | */ | ||
798 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
799 | if (!ret) { | ||
800 | common_flags = soc_mbus_config_compatible(&cfg, | ||
801 | common_flags); | ||
802 | if (!common_flags) | ||
803 | return -EINVAL; | ||
804 | } else if (ret != -ENOIOCTLCMD) { | ||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | /* Make choises, based on platform preferences */ | ||
809 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
810 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
811 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) | ||
812 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
813 | else | ||
814 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
815 | } | ||
816 | |||
817 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
818 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
819 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) | ||
820 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
821 | else | ||
822 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
823 | } | ||
824 | |||
825 | cfg.flags = common_flags; | ||
826 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
827 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
828 | return ret; | ||
829 | |||
830 | if (icd->current_fmt->host_fmt->bits_per_sample > 8) | ||
831 | pcdev->is_16bit = 1; | ||
832 | else | ||
833 | pcdev->is_16bit = 0; | ||
834 | |||
835 | ceu_write(pcdev, CRCNTR, 0); | ||
836 | ceu_write(pcdev, CRCMPR, 0); | ||
837 | |||
838 | value = 0x00000010; /* data fetch by default */ | ||
839 | yuv_lineskip = 0x10; | ||
840 | |||
841 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
842 | case V4L2_PIX_FMT_NV12: | ||
843 | case V4L2_PIX_FMT_NV21: | ||
844 | /* convert 4:2:2 -> 4:2:0 */ | ||
845 | yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */ | ||
846 | /* fall-through */ | ||
847 | case V4L2_PIX_FMT_NV16: | ||
848 | case V4L2_PIX_FMT_NV61: | ||
849 | switch (cam->code) { | ||
850 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
851 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ | ||
852 | break; | ||
853 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
854 | value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ | ||
855 | break; | ||
856 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
857 | value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ | ||
858 | break; | ||
859 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
860 | value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ | ||
861 | break; | ||
862 | default: | ||
863 | BUG(); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || | ||
868 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) | ||
869 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ | ||
870 | |||
871 | value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | ||
872 | value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | ||
873 | |||
874 | if (pcdev->pdata->csi2) /* CSI2 mode */ | ||
875 | value |= 3 << 12; | ||
876 | else if (pcdev->is_16bit) | ||
877 | value |= 1 << 12; | ||
878 | else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT) | ||
879 | value |= 2 << 12; | ||
880 | |||
881 | ceu_write(pcdev, CAMCR, value); | ||
882 | |||
883 | ceu_write(pcdev, CAPCR, 0x00300000); | ||
884 | |||
885 | switch (pcdev->field) { | ||
886 | case V4L2_FIELD_INTERLACED_TB: | ||
887 | value = 0x101; | ||
888 | break; | ||
889 | case V4L2_FIELD_INTERLACED_BT: | ||
890 | value = 0x102; | ||
891 | break; | ||
892 | default: | ||
893 | value = 0; | ||
894 | break; | ||
895 | } | ||
896 | ceu_write(pcdev, CAIFR, value); | ||
897 | |||
898 | sh_mobile_ceu_set_rect(icd); | ||
899 | mdelay(1); | ||
900 | |||
901 | dev_geo(icd->parent, "CFLCR 0x%x\n", pcdev->cflcr); | ||
902 | ceu_write(pcdev, CFLCR, pcdev->cflcr); | ||
903 | |||
904 | /* | ||
905 | * A few words about byte order (observed in Big Endian mode) | ||
906 | * | ||
907 | * In data fetch mode bytes are received in chunks of 8 bytes. | ||
908 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) | ||
909 | * | ||
910 | * The data is however by default written to memory in reverse order: | ||
911 | * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) | ||
912 | * | ||
913 | * The lowest three bits of CDOCR allows us to do swapping, | ||
914 | * using 7 we swap the data bytes to match the incoming order: | ||
915 | * D0, D1, D2, D3, D4, D5, D6, D7 | ||
916 | */ | ||
917 | value = 0x00000007 | yuv_lineskip; | ||
918 | |||
919 | ceu_write(pcdev, CDOCR, value); | ||
920 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ | ||
921 | |||
922 | capture_restore(pcdev, capsr); | ||
923 | |||
924 | /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ | ||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, | ||
929 | unsigned char buswidth) | ||
930 | { | ||
931 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
932 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
933 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); | ||
934 | unsigned long common_flags = CEU_BUS_FLAGS; | ||
935 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
936 | int ret; | ||
937 | |||
938 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
939 | if (!ret) | ||
940 | common_flags = soc_mbus_config_compatible(&cfg, | ||
941 | common_flags); | ||
942 | else if (ret != -ENOIOCTLCMD) | ||
943 | return ret; | ||
944 | |||
945 | if (!common_flags || buswidth > 16) | ||
946 | return -EINVAL; | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { | ||
952 | { | ||
953 | .fourcc = V4L2_PIX_FMT_NV12, | ||
954 | .name = "NV12", | ||
955 | .bits_per_sample = 8, | ||
956 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
957 | .order = SOC_MBUS_ORDER_LE, | ||
958 | .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C, | ||
959 | }, { | ||
960 | .fourcc = V4L2_PIX_FMT_NV21, | ||
961 | .name = "NV21", | ||
962 | .bits_per_sample = 8, | ||
963 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
964 | .order = SOC_MBUS_ORDER_LE, | ||
965 | .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C, | ||
966 | }, { | ||
967 | .fourcc = V4L2_PIX_FMT_NV16, | ||
968 | .name = "NV16", | ||
969 | .bits_per_sample = 8, | ||
970 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
971 | .order = SOC_MBUS_ORDER_LE, | ||
972 | .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C, | ||
973 | }, { | ||
974 | .fourcc = V4L2_PIX_FMT_NV61, | ||
975 | .name = "NV61", | ||
976 | .bits_per_sample = 8, | ||
977 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
978 | .order = SOC_MBUS_ORDER_LE, | ||
979 | .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C, | ||
980 | }, | ||
981 | }; | ||
982 | |||
983 | /* This will be corrected as we get more formats */ | ||
984 | static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
985 | { | ||
986 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
987 | (fmt->bits_per_sample == 8 && | ||
988 | fmt->packing == SOC_MBUS_PACKING_1_5X8) || | ||
989 | (fmt->bits_per_sample == 8 && | ||
990 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
991 | (fmt->bits_per_sample > 8 && | ||
992 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
993 | } | ||
994 | |||
995 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); | ||
996 | |||
997 | static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) | ||
998 | { | ||
999 | return container_of(ctrl->handler, struct soc_camera_device, | ||
1000 | ctrl_handler); | ||
1001 | } | ||
1002 | |||
1003 | static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1004 | { | ||
1005 | struct soc_camera_device *icd = ctrl_to_icd(ctrl); | ||
1006 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1007 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1008 | |||
1009 | switch (ctrl->id) { | ||
1010 | case V4L2_CID_SHARPNESS: | ||
1011 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
1012 | case V4L2_PIX_FMT_NV12: | ||
1013 | case V4L2_PIX_FMT_NV21: | ||
1014 | case V4L2_PIX_FMT_NV16: | ||
1015 | case V4L2_PIX_FMT_NV61: | ||
1016 | ceu_write(pcdev, CLFCR, !ctrl->val); | ||
1017 | return 0; | ||
1018 | } | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | |||
1025 | static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { | ||
1026 | .s_ctrl = sh_mobile_ceu_s_ctrl, | ||
1027 | }; | ||
1028 | |||
1029 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, | ||
1030 | struct soc_camera_format_xlate *xlate) | ||
1031 | { | ||
1032 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1033 | struct device *dev = icd->parent; | ||
1034 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1035 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1036 | int ret, k, n; | ||
1037 | int formats = 0; | ||
1038 | struct sh_mobile_ceu_cam *cam; | ||
1039 | enum v4l2_mbus_pixelcode code; | ||
1040 | const struct soc_mbus_pixelfmt *fmt; | ||
1041 | |||
1042 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); | ||
1043 | if (ret < 0) | ||
1044 | /* No more formats */ | ||
1045 | return 0; | ||
1046 | |||
1047 | fmt = soc_mbus_get_fmtdesc(code); | ||
1048 | if (!fmt) { | ||
1049 | dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); | ||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | if (!pcdev->pdata->csi2) { | ||
1054 | /* Are there any restrictions in the CSI-2 case? */ | ||
1055 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | ||
1056 | if (ret < 0) | ||
1057 | return 0; | ||
1058 | } | ||
1059 | |||
1060 | if (!icd->host_priv) { | ||
1061 | struct v4l2_mbus_framefmt mf; | ||
1062 | struct v4l2_rect rect; | ||
1063 | int shift = 0; | ||
1064 | |||
1065 | /* Add our control */ | ||
1066 | v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, | ||
1067 | V4L2_CID_SHARPNESS, 0, 1, 1, 0); | ||
1068 | if (icd->ctrl_handler.error) | ||
1069 | return icd->ctrl_handler.error; | ||
1070 | |||
1071 | /* FIXME: subwindow is lost between close / open */ | ||
1072 | |||
1073 | /* Cache current client geometry */ | ||
1074 | ret = client_g_rect(sd, &rect); | ||
1075 | if (ret < 0) | ||
1076 | return ret; | ||
1077 | |||
1078 | /* First time */ | ||
1079 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
1080 | if (ret < 0) | ||
1081 | return ret; | ||
1082 | |||
1083 | /* | ||
1084 | * All currently existing CEU implementations support 2560x1920 | ||
1085 | * or larger frames. If the sensor is proposing too big a frame, | ||
1086 | * don't bother with possibly supportred by the CEU larger | ||
1087 | * sizes, just try VGA multiples. If needed, this can be | ||
1088 | * adjusted in the future. | ||
1089 | */ | ||
1090 | while ((mf.width > pcdev->max_width || | ||
1091 | mf.height > pcdev->max_height) && shift < 4) { | ||
1092 | /* Try 2560x1920, 1280x960, 640x480, 320x240 */ | ||
1093 | mf.width = 2560 >> shift; | ||
1094 | mf.height = 1920 >> shift; | ||
1095 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1096 | soc_camera_grp_id(icd), video, | ||
1097 | s_mbus_fmt, &mf); | ||
1098 | if (ret < 0) | ||
1099 | return ret; | ||
1100 | shift++; | ||
1101 | } | ||
1102 | |||
1103 | if (shift == 4) { | ||
1104 | dev_err(dev, "Failed to configure the client below %ux%x\n", | ||
1105 | mf.width, mf.height); | ||
1106 | return -EIO; | ||
1107 | } | ||
1108 | |||
1109 | dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); | ||
1110 | |||
1111 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1112 | if (!cam) | ||
1113 | return -ENOMEM; | ||
1114 | |||
1115 | /* We are called with current camera crop, initialise subrect with it */ | ||
1116 | cam->rect = rect; | ||
1117 | cam->subrect = rect; | ||
1118 | |||
1119 | cam->width = mf.width; | ||
1120 | cam->height = mf.height; | ||
1121 | |||
1122 | icd->host_priv = cam; | ||
1123 | } else { | ||
1124 | cam = icd->host_priv; | ||
1125 | } | ||
1126 | |||
1127 | /* Beginning of a pass */ | ||
1128 | if (!idx) | ||
1129 | cam->extra_fmt = NULL; | ||
1130 | |||
1131 | switch (code) { | ||
1132 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
1133 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
1134 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
1135 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
1136 | if (cam->extra_fmt) | ||
1137 | break; | ||
1138 | |||
1139 | /* | ||
1140 | * Our case is simple so far: for any of the above four camera | ||
1141 | * formats we add all our four synthesized NV* formats, so, | ||
1142 | * just marking the device with a single flag suffices. If | ||
1143 | * the format generation rules are more complex, you would have | ||
1144 | * to actually hang your already added / counted formats onto | ||
1145 | * the host_priv pointer and check whether the format you're | ||
1146 | * going to add now is already there. | ||
1147 | */ | ||
1148 | cam->extra_fmt = sh_mobile_ceu_formats; | ||
1149 | |||
1150 | n = ARRAY_SIZE(sh_mobile_ceu_formats); | ||
1151 | formats += n; | ||
1152 | for (k = 0; xlate && k < n; k++) { | ||
1153 | xlate->host_fmt = &sh_mobile_ceu_formats[k]; | ||
1154 | xlate->code = code; | ||
1155 | xlate++; | ||
1156 | dev_dbg(dev, "Providing format %s using code %d\n", | ||
1157 | sh_mobile_ceu_formats[k].name, code); | ||
1158 | } | ||
1159 | break; | ||
1160 | default: | ||
1161 | if (!sh_mobile_ceu_packing_supported(fmt)) | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | /* Generic pass-through */ | ||
1166 | formats++; | ||
1167 | if (xlate) { | ||
1168 | xlate->host_fmt = fmt; | ||
1169 | xlate->code = code; | ||
1170 | xlate++; | ||
1171 | dev_dbg(dev, "Providing format %s in pass-through mode\n", | ||
1172 | fmt->name); | ||
1173 | } | ||
1174 | |||
1175 | return formats; | ||
1176 | } | ||
1177 | |||
1178 | static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) | ||
1179 | { | ||
1180 | kfree(icd->host_priv); | ||
1181 | icd->host_priv = NULL; | ||
1182 | } | ||
1183 | |||
1184 | /* Check if any dimension of r1 is smaller than respective one of r2 */ | ||
1185 | static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) | ||
1186 | { | ||
1187 | return r1->width < r2->width || r1->height < r2->height; | ||
1188 | } | ||
1189 | |||
1190 | /* Check if r1 fails to cover r2 */ | ||
1191 | static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2) | ||
1192 | { | ||
1193 | return r1->left > r2->left || r1->top > r2->top || | ||
1194 | r1->left + r1->width < r2->left + r2->width || | ||
1195 | r1->top + r1->height < r2->top + r2->height; | ||
1196 | } | ||
1197 | |||
1198 | static unsigned int scale_down(unsigned int size, unsigned int scale) | ||
1199 | { | ||
1200 | return (size * 4096 + scale / 2) / scale; | ||
1201 | } | ||
1202 | |||
1203 | static unsigned int calc_generic_scale(unsigned int input, unsigned int output) | ||
1204 | { | ||
1205 | return (input * 4096 + output / 2) / output; | ||
1206 | } | ||
1207 | |||
1208 | /* Get and store current client crop */ | ||
1209 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) | ||
1210 | { | ||
1211 | struct v4l2_crop crop; | ||
1212 | struct v4l2_cropcap cap; | ||
1213 | int ret; | ||
1214 | |||
1215 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1216 | |||
1217 | ret = v4l2_subdev_call(sd, video, g_crop, &crop); | ||
1218 | if (!ret) { | ||
1219 | *rect = crop.c; | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | /* Camera driver doesn't support .g_crop(), assume default rectangle */ | ||
1224 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1225 | |||
1226 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
1227 | if (!ret) | ||
1228 | *rect = cap.defrect; | ||
1229 | |||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | /* Client crop has changed, update our sub-rectangle to remain within the area */ | ||
1234 | static void update_subrect(struct sh_mobile_ceu_cam *cam) | ||
1235 | { | ||
1236 | struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect; | ||
1237 | |||
1238 | if (rect->width < subrect->width) | ||
1239 | subrect->width = rect->width; | ||
1240 | |||
1241 | if (rect->height < subrect->height) | ||
1242 | subrect->height = rect->height; | ||
1243 | |||
1244 | if (rect->left > subrect->left) | ||
1245 | subrect->left = rect->left; | ||
1246 | else if (rect->left + rect->width > | ||
1247 | subrect->left + subrect->width) | ||
1248 | subrect->left = rect->left + rect->width - | ||
1249 | subrect->width; | ||
1250 | |||
1251 | if (rect->top > subrect->top) | ||
1252 | subrect->top = rect->top; | ||
1253 | else if (rect->top + rect->height > | ||
1254 | subrect->top + subrect->height) | ||
1255 | subrect->top = rect->top + rect->height - | ||
1256 | subrect->height; | ||
1257 | } | ||
1258 | |||
1259 | /* | ||
1260 | * The common for both scaling and cropping iterative approach is: | ||
1261 | * 1. try if the client can produce exactly what requested by the user | ||
1262 | * 2. if (1) failed, try to double the client image until we get one big enough | ||
1263 | * 3. if (2) failed, try to request the maximum image | ||
1264 | */ | ||
1265 | static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, | ||
1266 | const struct v4l2_crop *cam_crop) | ||
1267 | { | ||
1268 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1269 | struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; | ||
1270 | struct device *dev = sd->v4l2_dev->dev; | ||
1271 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1272 | struct v4l2_cropcap cap; | ||
1273 | int ret; | ||
1274 | unsigned int width, height; | ||
1275 | |||
1276 | v4l2_subdev_call(sd, video, s_crop, crop); | ||
1277 | ret = client_g_rect(sd, cam_rect); | ||
1278 | if (ret < 0) | ||
1279 | return ret; | ||
1280 | |||
1281 | /* | ||
1282 | * Now cam_crop contains the current camera input rectangle, and it must | ||
1283 | * be within camera cropcap bounds | ||
1284 | */ | ||
1285 | if (!memcmp(rect, cam_rect, sizeof(*rect))) { | ||
1286 | /* Even if camera S_CROP failed, but camera rectangle matches */ | ||
1287 | dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n", | ||
1288 | rect->width, rect->height, rect->left, rect->top); | ||
1289 | cam->rect = *cam_rect; | ||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | /* Try to fix cropping, that camera hasn't managed to set */ | ||
1294 | dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n", | ||
1295 | cam_rect->width, cam_rect->height, | ||
1296 | cam_rect->left, cam_rect->top, | ||
1297 | rect->width, rect->height, rect->left, rect->top); | ||
1298 | |||
1299 | /* We need sensor maximum rectangle */ | ||
1300 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
1301 | if (ret < 0) | ||
1302 | return ret; | ||
1303 | |||
1304 | /* Put user requested rectangle within sensor bounds */ | ||
1305 | soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2, | ||
1306 | cap.bounds.width); | ||
1307 | soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4, | ||
1308 | cap.bounds.height); | ||
1309 | |||
1310 | /* | ||
1311 | * Popular special case - some cameras can only handle fixed sizes like | ||
1312 | * QVGA, VGA,... Take care to avoid infinite loop. | ||
1313 | */ | ||
1314 | width = max(cam_rect->width, 2); | ||
1315 | height = max(cam_rect->height, 2); | ||
1316 | |||
1317 | /* | ||
1318 | * Loop as long as sensor is not covering the requested rectangle and | ||
1319 | * is still within its bounds | ||
1320 | */ | ||
1321 | while (!ret && (is_smaller(cam_rect, rect) || | ||
1322 | is_inside(cam_rect, rect)) && | ||
1323 | (cap.bounds.width > width || cap.bounds.height > height)) { | ||
1324 | |||
1325 | width *= 2; | ||
1326 | height *= 2; | ||
1327 | |||
1328 | cam_rect->width = width; | ||
1329 | cam_rect->height = height; | ||
1330 | |||
1331 | /* | ||
1332 | * We do not know what capabilities the camera has to set up | ||
1333 | * left and top borders. We could try to be smarter in iterating | ||
1334 | * them, e.g., if camera current left is to the right of the | ||
1335 | * target left, set it to the middle point between the current | ||
1336 | * left and minimum left. But that would add too much | ||
1337 | * complexity: we would have to iterate each border separately. | ||
1338 | * Instead we just drop to the left and top bounds. | ||
1339 | */ | ||
1340 | if (cam_rect->left > rect->left) | ||
1341 | cam_rect->left = cap.bounds.left; | ||
1342 | |||
1343 | if (cam_rect->left + cam_rect->width < rect->left + rect->width) | ||
1344 | cam_rect->width = rect->left + rect->width - | ||
1345 | cam_rect->left; | ||
1346 | |||
1347 | if (cam_rect->top > rect->top) | ||
1348 | cam_rect->top = cap.bounds.top; | ||
1349 | |||
1350 | if (cam_rect->top + cam_rect->height < rect->top + rect->height) | ||
1351 | cam_rect->height = rect->top + rect->height - | ||
1352 | cam_rect->top; | ||
1353 | |||
1354 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | ||
1355 | ret = client_g_rect(sd, cam_rect); | ||
1356 | dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret, | ||
1357 | cam_rect->width, cam_rect->height, | ||
1358 | cam_rect->left, cam_rect->top); | ||
1359 | } | ||
1360 | |||
1361 | /* S_CROP must not modify the rectangle */ | ||
1362 | if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { | ||
1363 | /* | ||
1364 | * The camera failed to configure a suitable cropping, | ||
1365 | * we cannot use the current rectangle, set to max | ||
1366 | */ | ||
1367 | *cam_rect = cap.bounds; | ||
1368 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | ||
1369 | ret = client_g_rect(sd, cam_rect); | ||
1370 | dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret, | ||
1371 | cam_rect->width, cam_rect->height, | ||
1372 | cam_rect->left, cam_rect->top); | ||
1373 | } | ||
1374 | |||
1375 | if (!ret) { | ||
1376 | cam->rect = *cam_rect; | ||
1377 | update_subrect(cam); | ||
1378 | } | ||
1379 | |||
1380 | return ret; | ||
1381 | } | ||
1382 | |||
1383 | /* Iterative s_mbus_fmt, also updates cached client crop on success */ | ||
1384 | static int client_s_fmt(struct soc_camera_device *icd, | ||
1385 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) | ||
1386 | { | ||
1387 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1388 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1389 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1390 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1391 | struct device *dev = icd->parent; | ||
1392 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; | ||
1393 | unsigned int max_width, max_height; | ||
1394 | struct v4l2_cropcap cap; | ||
1395 | bool ceu_1to1; | ||
1396 | int ret; | ||
1397 | |||
1398 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1399 | soc_camera_grp_id(icd), video, | ||
1400 | s_mbus_fmt, mf); | ||
1401 | if (ret < 0) | ||
1402 | return ret; | ||
1403 | |||
1404 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); | ||
1405 | |||
1406 | if (width == mf->width && height == mf->height) { | ||
1407 | /* Perfect! The client has done it all. */ | ||
1408 | ceu_1to1 = true; | ||
1409 | goto update_cache; | ||
1410 | } | ||
1411 | |||
1412 | ceu_1to1 = false; | ||
1413 | if (!ceu_can_scale) | ||
1414 | goto update_cache; | ||
1415 | |||
1416 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1417 | |||
1418 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
1419 | if (ret < 0) | ||
1420 | return ret; | ||
1421 | |||
1422 | max_width = min(cap.bounds.width, pcdev->max_width); | ||
1423 | max_height = min(cap.bounds.height, pcdev->max_height); | ||
1424 | |||
1425 | /* Camera set a format, but geometry is not precise, try to improve */ | ||
1426 | tmp_w = mf->width; | ||
1427 | tmp_h = mf->height; | ||
1428 | |||
1429 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ | ||
1430 | while ((width > tmp_w || height > tmp_h) && | ||
1431 | tmp_w < max_width && tmp_h < max_height) { | ||
1432 | tmp_w = min(2 * tmp_w, max_width); | ||
1433 | tmp_h = min(2 * tmp_h, max_height); | ||
1434 | mf->width = tmp_w; | ||
1435 | mf->height = tmp_h; | ||
1436 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1437 | soc_camera_grp_id(icd), video, | ||
1438 | s_mbus_fmt, mf); | ||
1439 | dev_geo(dev, "Camera scaled to %ux%u\n", | ||
1440 | mf->width, mf->height); | ||
1441 | if (ret < 0) { | ||
1442 | /* This shouldn't happen */ | ||
1443 | dev_err(dev, "Client failed to set format: %d\n", ret); | ||
1444 | return ret; | ||
1445 | } | ||
1446 | } | ||
1447 | |||
1448 | update_cache: | ||
1449 | /* Update cache */ | ||
1450 | ret = client_g_rect(sd, &cam->rect); | ||
1451 | if (ret < 0) | ||
1452 | return ret; | ||
1453 | |||
1454 | if (ceu_1to1) | ||
1455 | cam->subrect = cam->rect; | ||
1456 | else | ||
1457 | update_subrect(cam); | ||
1458 | |||
1459 | return 0; | ||
1460 | } | ||
1461 | |||
1462 | /** | ||
1463 | * @width - on output: user width, mapped back to input | ||
1464 | * @height - on output: user height, mapped back to input | ||
1465 | * @mf - in- / output camera output window | ||
1466 | */ | ||
1467 | static int client_scale(struct soc_camera_device *icd, | ||
1468 | struct v4l2_mbus_framefmt *mf, | ||
1469 | unsigned int *width, unsigned int *height, | ||
1470 | bool ceu_can_scale) | ||
1471 | { | ||
1472 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1473 | struct device *dev = icd->parent; | ||
1474 | struct v4l2_mbus_framefmt mf_tmp = *mf; | ||
1475 | unsigned int scale_h, scale_v; | ||
1476 | int ret; | ||
1477 | |||
1478 | /* | ||
1479 | * 5. Apply iterative camera S_FMT for camera user window (also updates | ||
1480 | * client crop cache and the imaginary sub-rectangle). | ||
1481 | */ | ||
1482 | ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); | ||
1483 | if (ret < 0) | ||
1484 | return ret; | ||
1485 | |||
1486 | dev_geo(dev, "5: camera scaled to %ux%u\n", | ||
1487 | mf_tmp.width, mf_tmp.height); | ||
1488 | |||
1489 | /* 6. Retrieve camera output window (g_fmt) */ | ||
1490 | |||
1491 | /* unneeded - it is already in "mf_tmp" */ | ||
1492 | |||
1493 | /* 7. Calculate new client scales. */ | ||
1494 | scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width); | ||
1495 | scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height); | ||
1496 | |||
1497 | mf->width = mf_tmp.width; | ||
1498 | mf->height = mf_tmp.height; | ||
1499 | mf->colorspace = mf_tmp.colorspace; | ||
1500 | |||
1501 | /* | ||
1502 | * 8. Calculate new CEU crop - apply camera scales to previously | ||
1503 | * updated "effective" crop. | ||
1504 | */ | ||
1505 | *width = scale_down(cam->subrect.width, scale_h); | ||
1506 | *height = scale_down(cam->subrect.height, scale_v); | ||
1507 | |||
1508 | dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height); | ||
1509 | |||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1513 | /* | ||
1514 | * CEU can scale and crop, but we don't want to waste bandwidth and kill the | ||
1515 | * framerate by always requesting the maximum image from the client. See | ||
1516 | * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of | ||
1517 | * scaling and cropping algorithms and for the meaning of referenced here steps. | ||
1518 | */ | ||
1519 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | ||
1520 | const struct v4l2_crop *a) | ||
1521 | { | ||
1522 | struct v4l2_rect *rect = &a->c; | ||
1523 | struct device *dev = icd->parent; | ||
1524 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1525 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1526 | struct v4l2_crop cam_crop; | ||
1527 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1528 | struct v4l2_rect *cam_rect = &cam_crop.c; | ||
1529 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1530 | struct v4l2_mbus_framefmt mf; | ||
1531 | unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, | ||
1532 | out_width, out_height; | ||
1533 | int interm_width, interm_height; | ||
1534 | u32 capsr, cflcr; | ||
1535 | int ret; | ||
1536 | |||
1537 | dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height, | ||
1538 | rect->left, rect->top); | ||
1539 | |||
1540 | /* During camera cropping its output window can change too, stop CEU */ | ||
1541 | capsr = capture_save_reset(pcdev); | ||
1542 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | ||
1543 | |||
1544 | /* | ||
1545 | * 1. - 2. Apply iterative camera S_CROP for new input window, read back | ||
1546 | * actual camera rectangle. | ||
1547 | */ | ||
1548 | ret = client_s_crop(icd, a, &cam_crop); | ||
1549 | if (ret < 0) | ||
1550 | return ret; | ||
1551 | |||
1552 | dev_geo(dev, "1-2: camera cropped to %ux%u@%u:%u\n", | ||
1553 | cam_rect->width, cam_rect->height, | ||
1554 | cam_rect->left, cam_rect->top); | ||
1555 | |||
1556 | /* On success cam_crop contains current camera crop */ | ||
1557 | |||
1558 | /* 3. Retrieve camera output window */ | ||
1559 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | ||
1560 | if (ret < 0) | ||
1561 | return ret; | ||
1562 | |||
1563 | if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) | ||
1564 | return -EINVAL; | ||
1565 | |||
1566 | /* 4. Calculate camera scales */ | ||
1567 | scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); | ||
1568 | scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); | ||
1569 | |||
1570 | /* Calculate intermediate window */ | ||
1571 | interm_width = scale_down(rect->width, scale_cam_h); | ||
1572 | interm_height = scale_down(rect->height, scale_cam_v); | ||
1573 | |||
1574 | if (interm_width < icd->user_width) { | ||
1575 | u32 new_scale_h; | ||
1576 | |||
1577 | new_scale_h = calc_generic_scale(rect->width, icd->user_width); | ||
1578 | |||
1579 | mf.width = scale_down(cam_rect->width, new_scale_h); | ||
1580 | } | ||
1581 | |||
1582 | if (interm_height < icd->user_height) { | ||
1583 | u32 new_scale_v; | ||
1584 | |||
1585 | new_scale_v = calc_generic_scale(rect->height, icd->user_height); | ||
1586 | |||
1587 | mf.height = scale_down(cam_rect->height, new_scale_v); | ||
1588 | } | ||
1589 | |||
1590 | if (interm_width < icd->user_width || interm_height < icd->user_height) { | ||
1591 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1592 | soc_camera_grp_id(icd), video, | ||
1593 | s_mbus_fmt, &mf); | ||
1594 | if (ret < 0) | ||
1595 | return ret; | ||
1596 | |||
1597 | dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height); | ||
1598 | scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); | ||
1599 | scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); | ||
1600 | interm_width = scale_down(rect->width, scale_cam_h); | ||
1601 | interm_height = scale_down(rect->height, scale_cam_v); | ||
1602 | } | ||
1603 | |||
1604 | /* Cache camera output window */ | ||
1605 | cam->width = mf.width; | ||
1606 | cam->height = mf.height; | ||
1607 | |||
1608 | if (pcdev->image_mode) { | ||
1609 | out_width = min(interm_width, icd->user_width); | ||
1610 | out_height = min(interm_height, icd->user_height); | ||
1611 | } else { | ||
1612 | out_width = interm_width; | ||
1613 | out_height = interm_height; | ||
1614 | } | ||
1615 | |||
1616 | /* | ||
1617 | * 5. Calculate CEU scales from camera scales from results of (5) and | ||
1618 | * the user window | ||
1619 | */ | ||
1620 | scale_ceu_h = calc_scale(interm_width, &out_width); | ||
1621 | scale_ceu_v = calc_scale(interm_height, &out_height); | ||
1622 | |||
1623 | dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v); | ||
1624 | |||
1625 | /* Apply CEU scales. */ | ||
1626 | cflcr = scale_ceu_h | (scale_ceu_v << 16); | ||
1627 | if (cflcr != pcdev->cflcr) { | ||
1628 | pcdev->cflcr = cflcr; | ||
1629 | ceu_write(pcdev, CFLCR, cflcr); | ||
1630 | } | ||
1631 | |||
1632 | icd->user_width = out_width & ~3; | ||
1633 | icd->user_height = out_height & ~3; | ||
1634 | /* Offsets are applied at the CEU scaling filter input */ | ||
1635 | cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; | ||
1636 | cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; | ||
1637 | |||
1638 | /* 6. Use CEU cropping to crop to the new window. */ | ||
1639 | sh_mobile_ceu_set_rect(icd); | ||
1640 | |||
1641 | cam->subrect = *rect; | ||
1642 | |||
1643 | dev_geo(dev, "6: CEU cropped to %ux%u@%u:%u\n", | ||
1644 | icd->user_width, icd->user_height, | ||
1645 | cam->ceu_left, cam->ceu_top); | ||
1646 | |||
1647 | /* Restore capture. The CE bit can be cleared by the hardware */ | ||
1648 | if (pcdev->active) | ||
1649 | capsr |= 1; | ||
1650 | capture_restore(pcdev, capsr); | ||
1651 | |||
1652 | /* Even if only camera cropping succeeded */ | ||
1653 | return ret; | ||
1654 | } | ||
1655 | |||
1656 | static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, | ||
1657 | struct v4l2_crop *a) | ||
1658 | { | ||
1659 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1660 | |||
1661 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1662 | a->c = cam->subrect; | ||
1663 | |||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | /* | ||
1668 | * Calculate real client output window by applying new scales to the current | ||
1669 | * client crop. New scales are calculated from the requested output format and | ||
1670 | * CEU crop, mapped backed onto the client input (subrect). | ||
1671 | */ | ||
1672 | static void calculate_client_output(struct soc_camera_device *icd, | ||
1673 | const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) | ||
1674 | { | ||
1675 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1676 | struct device *dev = icd->parent; | ||
1677 | struct v4l2_rect *cam_subrect = &cam->subrect; | ||
1678 | unsigned int scale_v, scale_h; | ||
1679 | |||
1680 | if (cam_subrect->width == cam->rect.width && | ||
1681 | cam_subrect->height == cam->rect.height) { | ||
1682 | /* No sub-cropping */ | ||
1683 | mf->width = pix->width; | ||
1684 | mf->height = pix->height; | ||
1685 | return; | ||
1686 | } | ||
1687 | |||
1688 | /* 1.-2. Current camera scales and subwin - cached. */ | ||
1689 | |||
1690 | dev_geo(dev, "2: subwin %ux%u@%u:%u\n", | ||
1691 | cam_subrect->width, cam_subrect->height, | ||
1692 | cam_subrect->left, cam_subrect->top); | ||
1693 | |||
1694 | /* | ||
1695 | * 3. Calculate new combined scales from input sub-window to requested | ||
1696 | * user window. | ||
1697 | */ | ||
1698 | |||
1699 | /* | ||
1700 | * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF | ||
1701 | * (128x96) or larger than VGA | ||
1702 | */ | ||
1703 | scale_h = calc_generic_scale(cam_subrect->width, pix->width); | ||
1704 | scale_v = calc_generic_scale(cam_subrect->height, pix->height); | ||
1705 | |||
1706 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); | ||
1707 | |||
1708 | /* | ||
1709 | * 4. Calculate desired client output window by applying combined scales | ||
1710 | * to client (real) input window. | ||
1711 | */ | ||
1712 | mf->width = scale_down(cam->rect.width, scale_h); | ||
1713 | mf->height = scale_down(cam->rect.height, scale_v); | ||
1714 | } | ||
1715 | |||
1716 | /* Similar to set_crop multistage iterative algorithm */ | ||
1717 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | ||
1718 | struct v4l2_format *f) | ||
1719 | { | ||
1720 | struct device *dev = icd->parent; | ||
1721 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1722 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1723 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
1724 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1725 | struct v4l2_mbus_framefmt mf; | ||
1726 | __u32 pixfmt = pix->pixelformat; | ||
1727 | const struct soc_camera_format_xlate *xlate; | ||
1728 | /* Keep Compiler Happy */ | ||
1729 | unsigned int ceu_sub_width = 0, ceu_sub_height = 0; | ||
1730 | u16 scale_v, scale_h; | ||
1731 | int ret; | ||
1732 | bool image_mode; | ||
1733 | enum v4l2_field field; | ||
1734 | |||
1735 | switch (pix->field) { | ||
1736 | default: | ||
1737 | pix->field = V4L2_FIELD_NONE; | ||
1738 | /* fall-through */ | ||
1739 | case V4L2_FIELD_INTERLACED_TB: | ||
1740 | case V4L2_FIELD_INTERLACED_BT: | ||
1741 | case V4L2_FIELD_NONE: | ||
1742 | field = pix->field; | ||
1743 | break; | ||
1744 | case V4L2_FIELD_INTERLACED: | ||
1745 | field = V4L2_FIELD_INTERLACED_TB; | ||
1746 | break; | ||
1747 | } | ||
1748 | |||
1749 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1750 | if (!xlate) { | ||
1751 | dev_warn(dev, "Format %x not found\n", pixfmt); | ||
1752 | return -EINVAL; | ||
1753 | } | ||
1754 | |||
1755 | /* 1.-4. Calculate desired client output geometry */ | ||
1756 | calculate_client_output(icd, pix, &mf); | ||
1757 | mf.field = pix->field; | ||
1758 | mf.colorspace = pix->colorspace; | ||
1759 | mf.code = xlate->code; | ||
1760 | |||
1761 | switch (pixfmt) { | ||
1762 | case V4L2_PIX_FMT_NV12: | ||
1763 | case V4L2_PIX_FMT_NV21: | ||
1764 | case V4L2_PIX_FMT_NV16: | ||
1765 | case V4L2_PIX_FMT_NV61: | ||
1766 | image_mode = true; | ||
1767 | break; | ||
1768 | default: | ||
1769 | image_mode = false; | ||
1770 | } | ||
1771 | |||
1772 | dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, | ||
1773 | pix->width, pix->height); | ||
1774 | |||
1775 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); | ||
1776 | |||
1777 | /* 5. - 9. */ | ||
1778 | ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height, | ||
1779 | image_mode && V4L2_FIELD_NONE == field); | ||
1780 | |||
1781 | dev_geo(dev, "5-9: client scale return %d\n", ret); | ||
1782 | |||
1783 | /* Done with the camera. Now see if we can improve the result */ | ||
1784 | |||
1785 | dev_geo(dev, "fmt %ux%u, requested %ux%u\n", | ||
1786 | mf.width, mf.height, pix->width, pix->height); | ||
1787 | if (ret < 0) | ||
1788 | return ret; | ||
1789 | |||
1790 | if (mf.code != xlate->code) | ||
1791 | return -EINVAL; | ||
1792 | |||
1793 | /* 9. Prepare CEU crop */ | ||
1794 | cam->width = mf.width; | ||
1795 | cam->height = mf.height; | ||
1796 | |||
1797 | /* 10. Use CEU scaling to scale to the requested user window. */ | ||
1798 | |||
1799 | /* We cannot scale up */ | ||
1800 | if (pix->width > ceu_sub_width) | ||
1801 | ceu_sub_width = pix->width; | ||
1802 | |||
1803 | if (pix->height > ceu_sub_height) | ||
1804 | ceu_sub_height = pix->height; | ||
1805 | |||
1806 | pix->colorspace = mf.colorspace; | ||
1807 | |||
1808 | if (image_mode) { | ||
1809 | /* Scale pix->{width x height} down to width x height */ | ||
1810 | scale_h = calc_scale(ceu_sub_width, &pix->width); | ||
1811 | scale_v = calc_scale(ceu_sub_height, &pix->height); | ||
1812 | } else { | ||
1813 | pix->width = ceu_sub_width; | ||
1814 | pix->height = ceu_sub_height; | ||
1815 | scale_h = 0; | ||
1816 | scale_v = 0; | ||
1817 | } | ||
1818 | |||
1819 | pcdev->cflcr = scale_h | (scale_v << 16); | ||
1820 | |||
1821 | /* | ||
1822 | * We have calculated CFLCR, the actual configuration will be performed | ||
1823 | * in sh_mobile_ceu_set_bus_param() | ||
1824 | */ | ||
1825 | |||
1826 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", | ||
1827 | ceu_sub_width, scale_h, pix->width, | ||
1828 | ceu_sub_height, scale_v, pix->height); | ||
1829 | |||
1830 | cam->code = xlate->code; | ||
1831 | icd->current_fmt = xlate; | ||
1832 | |||
1833 | pcdev->field = field; | ||
1834 | pcdev->image_mode = image_mode; | ||
1835 | |||
1836 | /* CFSZR requirement */ | ||
1837 | pix->width &= ~3; | ||
1838 | pix->height &= ~3; | ||
1839 | |||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | #define CEU_CHDW_MAX 8188U /* Maximum line stride */ | ||
1844 | |||
1845 | static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | ||
1846 | struct v4l2_format *f) | ||
1847 | { | ||
1848 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1849 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1850 | const struct soc_camera_format_xlate *xlate; | ||
1851 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1852 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1853 | struct v4l2_mbus_framefmt mf; | ||
1854 | __u32 pixfmt = pix->pixelformat; | ||
1855 | int width, height; | ||
1856 | int ret; | ||
1857 | |||
1858 | dev_geo(icd->parent, "TRY_FMT(pix=0x%x, %ux%u)\n", | ||
1859 | pixfmt, pix->width, pix->height); | ||
1860 | |||
1861 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1862 | if (!xlate) { | ||
1863 | xlate = icd->current_fmt; | ||
1864 | dev_dbg(icd->parent, "Format %x not found, keeping %x\n", | ||
1865 | pixfmt, xlate->host_fmt->fourcc); | ||
1866 | pixfmt = xlate->host_fmt->fourcc; | ||
1867 | pix->pixelformat = pixfmt; | ||
1868 | pix->colorspace = icd->colorspace; | ||
1869 | } | ||
1870 | |||
1871 | /* FIXME: calculate using depth and bus width */ | ||
1872 | |||
1873 | /* CFSZR requires height and width to be 4-pixel aligned */ | ||
1874 | v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2, | ||
1875 | &pix->height, 4, pcdev->max_height, 2, 0); | ||
1876 | |||
1877 | width = pix->width; | ||
1878 | height = pix->height; | ||
1879 | |||
1880 | /* limit to sensor capabilities */ | ||
1881 | mf.width = pix->width; | ||
1882 | mf.height = pix->height; | ||
1883 | mf.field = pix->field; | ||
1884 | mf.code = xlate->code; | ||
1885 | mf.colorspace = pix->colorspace; | ||
1886 | |||
1887 | ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), | ||
1888 | video, try_mbus_fmt, &mf); | ||
1889 | if (ret < 0) | ||
1890 | return ret; | ||
1891 | |||
1892 | pix->width = mf.width; | ||
1893 | pix->height = mf.height; | ||
1894 | pix->field = mf.field; | ||
1895 | pix->colorspace = mf.colorspace; | ||
1896 | |||
1897 | switch (pixfmt) { | ||
1898 | case V4L2_PIX_FMT_NV12: | ||
1899 | case V4L2_PIX_FMT_NV21: | ||
1900 | case V4L2_PIX_FMT_NV16: | ||
1901 | case V4L2_PIX_FMT_NV61: | ||
1902 | /* FIXME: check against rect_max after converting soc-camera */ | ||
1903 | /* We can scale precisely, need a bigger image from camera */ | ||
1904 | if (pix->width < width || pix->height < height) { | ||
1905 | /* | ||
1906 | * We presume, the sensor behaves sanely, i.e., if | ||
1907 | * requested a bigger rectangle, it will not return a | ||
1908 | * smaller one. | ||
1909 | */ | ||
1910 | mf.width = pcdev->max_width; | ||
1911 | mf.height = pcdev->max_height; | ||
1912 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1913 | soc_camera_grp_id(icd), video, | ||
1914 | try_mbus_fmt, &mf); | ||
1915 | if (ret < 0) { | ||
1916 | /* Shouldn't actually happen... */ | ||
1917 | dev_err(icd->parent, | ||
1918 | "FIXME: client try_fmt() = %d\n", ret); | ||
1919 | return ret; | ||
1920 | } | ||
1921 | } | ||
1922 | /* We will scale exactly */ | ||
1923 | if (mf.width > width) | ||
1924 | pix->width = width; | ||
1925 | if (mf.height > height) | ||
1926 | pix->height = height; | ||
1927 | |||
1928 | pix->bytesperline = max(pix->bytesperline, pix->width); | ||
1929 | pix->bytesperline = min(pix->bytesperline, CEU_CHDW_MAX); | ||
1930 | pix->bytesperline &= ~3; | ||
1931 | break; | ||
1932 | |||
1933 | default: | ||
1934 | /* Configurable stride isn't supported in pass-through mode. */ | ||
1935 | pix->bytesperline = 0; | ||
1936 | } | ||
1937 | |||
1938 | pix->width &= ~3; | ||
1939 | pix->height &= ~3; | ||
1940 | pix->sizeimage = 0; | ||
1941 | |||
1942 | dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", | ||
1943 | __func__, ret, pix->pixelformat, pix->width, pix->height); | ||
1944 | |||
1945 | return ret; | ||
1946 | } | ||
1947 | |||
1948 | static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | ||
1949 | struct v4l2_crop *a) | ||
1950 | { | ||
1951 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1952 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1953 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1954 | u32 out_width = icd->user_width, out_height = icd->user_height; | ||
1955 | int ret; | ||
1956 | |||
1957 | /* Freeze queue */ | ||
1958 | pcdev->frozen = 1; | ||
1959 | /* Wait for frame */ | ||
1960 | ret = wait_for_completion_interruptible(&pcdev->complete); | ||
1961 | /* Stop the client */ | ||
1962 | ret = v4l2_subdev_call(sd, video, s_stream, 0); | ||
1963 | if (ret < 0) | ||
1964 | dev_warn(icd->parent, | ||
1965 | "Client failed to stop the stream: %d\n", ret); | ||
1966 | else | ||
1967 | /* Do the crop, if it fails, there's nothing more we can do */ | ||
1968 | sh_mobile_ceu_set_crop(icd, a); | ||
1969 | |||
1970 | dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height); | ||
1971 | |||
1972 | if (icd->user_width != out_width || icd->user_height != out_height) { | ||
1973 | struct v4l2_format f = { | ||
1974 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1975 | .fmt.pix = { | ||
1976 | .width = out_width, | ||
1977 | .height = out_height, | ||
1978 | .pixelformat = icd->current_fmt->host_fmt->fourcc, | ||
1979 | .field = pcdev->field, | ||
1980 | .colorspace = icd->colorspace, | ||
1981 | }, | ||
1982 | }; | ||
1983 | ret = sh_mobile_ceu_set_fmt(icd, &f); | ||
1984 | if (!ret && (out_width != f.fmt.pix.width || | ||
1985 | out_height != f.fmt.pix.height)) | ||
1986 | ret = -EINVAL; | ||
1987 | if (!ret) { | ||
1988 | icd->user_width = out_width & ~3; | ||
1989 | icd->user_height = out_height & ~3; | ||
1990 | ret = sh_mobile_ceu_set_bus_param(icd); | ||
1991 | } | ||
1992 | } | ||
1993 | |||
1994 | /* Thaw the queue */ | ||
1995 | pcdev->frozen = 0; | ||
1996 | spin_lock_irq(&pcdev->lock); | ||
1997 | sh_mobile_ceu_capture(pcdev); | ||
1998 | spin_unlock_irq(&pcdev->lock); | ||
1999 | /* Start the client */ | ||
2000 | ret = v4l2_subdev_call(sd, video, s_stream, 1); | ||
2001 | return ret; | ||
2002 | } | ||
2003 | |||
2004 | static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) | ||
2005 | { | ||
2006 | struct soc_camera_device *icd = file->private_data; | ||
2007 | |||
2008 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
2009 | } | ||
2010 | |||
2011 | static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, | ||
2012 | struct v4l2_capability *cap) | ||
2013 | { | ||
2014 | strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card)); | ||
2015 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
2016 | return 0; | ||
2017 | } | ||
2018 | |||
2019 | static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, | ||
2020 | struct soc_camera_device *icd) | ||
2021 | { | ||
2022 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2023 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
2024 | q->drv_priv = icd; | ||
2025 | q->ops = &sh_mobile_ceu_videobuf_ops; | ||
2026 | q->mem_ops = &vb2_dma_contig_memops; | ||
2027 | q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); | ||
2028 | |||
2029 | return vb2_queue_init(q); | ||
2030 | } | ||
2031 | |||
2032 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | ||
2033 | .owner = THIS_MODULE, | ||
2034 | .add = sh_mobile_ceu_add_device, | ||
2035 | .remove = sh_mobile_ceu_remove_device, | ||
2036 | .get_formats = sh_mobile_ceu_get_formats, | ||
2037 | .put_formats = sh_mobile_ceu_put_formats, | ||
2038 | .get_crop = sh_mobile_ceu_get_crop, | ||
2039 | .set_crop = sh_mobile_ceu_set_crop, | ||
2040 | .set_livecrop = sh_mobile_ceu_set_livecrop, | ||
2041 | .set_fmt = sh_mobile_ceu_set_fmt, | ||
2042 | .try_fmt = sh_mobile_ceu_try_fmt, | ||
2043 | .poll = sh_mobile_ceu_poll, | ||
2044 | .querycap = sh_mobile_ceu_querycap, | ||
2045 | .set_bus_param = sh_mobile_ceu_set_bus_param, | ||
2046 | .init_videobuf2 = sh_mobile_ceu_init_videobuf, | ||
2047 | }; | ||
2048 | |||
2049 | struct bus_wait { | ||
2050 | struct notifier_block notifier; | ||
2051 | struct completion completion; | ||
2052 | struct device *dev; | ||
2053 | }; | ||
2054 | |||
2055 | static int bus_notify(struct notifier_block *nb, | ||
2056 | unsigned long action, void *data) | ||
2057 | { | ||
2058 | struct device *dev = data; | ||
2059 | struct bus_wait *wait = container_of(nb, struct bus_wait, notifier); | ||
2060 | |||
2061 | if (wait->dev != dev) | ||
2062 | return NOTIFY_DONE; | ||
2063 | |||
2064 | switch (action) { | ||
2065 | case BUS_NOTIFY_UNBOUND_DRIVER: | ||
2066 | /* Protect from module unloading */ | ||
2067 | wait_for_completion(&wait->completion); | ||
2068 | return NOTIFY_OK; | ||
2069 | } | ||
2070 | return NOTIFY_DONE; | ||
2071 | } | ||
2072 | |||
2073 | static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | ||
2074 | { | ||
2075 | struct sh_mobile_ceu_dev *pcdev; | ||
2076 | struct resource *res; | ||
2077 | void __iomem *base; | ||
2078 | unsigned int irq; | ||
2079 | int err = 0; | ||
2080 | struct bus_wait wait = { | ||
2081 | .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), | ||
2082 | .notifier.notifier_call = bus_notify, | ||
2083 | }; | ||
2084 | struct sh_mobile_ceu_companion *csi2; | ||
2085 | |||
2086 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
2087 | irq = platform_get_irq(pdev, 0); | ||
2088 | if (!res || (int)irq <= 0) { | ||
2089 | dev_err(&pdev->dev, "Not enough CEU platform resources.\n"); | ||
2090 | err = -ENODEV; | ||
2091 | goto exit; | ||
2092 | } | ||
2093 | |||
2094 | pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); | ||
2095 | if (!pcdev) { | ||
2096 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
2097 | err = -ENOMEM; | ||
2098 | goto exit; | ||
2099 | } | ||
2100 | |||
2101 | INIT_LIST_HEAD(&pcdev->capture); | ||
2102 | spin_lock_init(&pcdev->lock); | ||
2103 | init_completion(&pcdev->complete); | ||
2104 | |||
2105 | pcdev->pdata = pdev->dev.platform_data; | ||
2106 | if (!pcdev->pdata) { | ||
2107 | err = -EINVAL; | ||
2108 | dev_err(&pdev->dev, "CEU platform data not set.\n"); | ||
2109 | goto exit_kfree; | ||
2110 | } | ||
2111 | |||
2112 | pcdev->max_width = pcdev->pdata->max_width ? : 2560; | ||
2113 | pcdev->max_height = pcdev->pdata->max_height ? : 1920; | ||
2114 | |||
2115 | base = ioremap_nocache(res->start, resource_size(res)); | ||
2116 | if (!base) { | ||
2117 | err = -ENXIO; | ||
2118 | dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); | ||
2119 | goto exit_kfree; | ||
2120 | } | ||
2121 | |||
2122 | pcdev->irq = irq; | ||
2123 | pcdev->base = base; | ||
2124 | pcdev->video_limit = 0; /* only enabled if second resource exists */ | ||
2125 | |||
2126 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
2127 | if (res) { | ||
2128 | err = dma_declare_coherent_memory(&pdev->dev, res->start, | ||
2129 | res->start, | ||
2130 | resource_size(res), | ||
2131 | DMA_MEMORY_MAP | | ||
2132 | DMA_MEMORY_EXCLUSIVE); | ||
2133 | if (!err) { | ||
2134 | dev_err(&pdev->dev, "Unable to declare CEU memory.\n"); | ||
2135 | err = -ENXIO; | ||
2136 | goto exit_iounmap; | ||
2137 | } | ||
2138 | |||
2139 | pcdev->video_limit = resource_size(res); | ||
2140 | } | ||
2141 | |||
2142 | /* request irq */ | ||
2143 | err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED, | ||
2144 | dev_name(&pdev->dev), pcdev); | ||
2145 | if (err) { | ||
2146 | dev_err(&pdev->dev, "Unable to register CEU interrupt.\n"); | ||
2147 | goto exit_release_mem; | ||
2148 | } | ||
2149 | |||
2150 | pm_suspend_ignore_children(&pdev->dev, true); | ||
2151 | pm_runtime_enable(&pdev->dev); | ||
2152 | pm_runtime_resume(&pdev->dev); | ||
2153 | |||
2154 | pcdev->ici.priv = pcdev; | ||
2155 | pcdev->ici.v4l2_dev.dev = &pdev->dev; | ||
2156 | pcdev->ici.nr = pdev->id; | ||
2157 | pcdev->ici.drv_name = dev_name(&pdev->dev); | ||
2158 | pcdev->ici.ops = &sh_mobile_ceu_host_ops; | ||
2159 | pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE; | ||
2160 | |||
2161 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
2162 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
2163 | err = PTR_ERR(pcdev->alloc_ctx); | ||
2164 | goto exit_free_clk; | ||
2165 | } | ||
2166 | |||
2167 | err = soc_camera_host_register(&pcdev->ici); | ||
2168 | if (err) | ||
2169 | goto exit_free_ctx; | ||
2170 | |||
2171 | /* CSI2 interfacing */ | ||
2172 | csi2 = pcdev->pdata->csi2; | ||
2173 | if (csi2) { | ||
2174 | struct platform_device *csi2_pdev = | ||
2175 | platform_device_alloc("sh-mobile-csi2", csi2->id); | ||
2176 | struct sh_csi2_pdata *csi2_pdata = csi2->platform_data; | ||
2177 | |||
2178 | if (!csi2_pdev) { | ||
2179 | err = -ENOMEM; | ||
2180 | goto exit_host_unregister; | ||
2181 | } | ||
2182 | |||
2183 | pcdev->csi2_pdev = csi2_pdev; | ||
2184 | |||
2185 | err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata)); | ||
2186 | if (err < 0) | ||
2187 | goto exit_pdev_put; | ||
2188 | |||
2189 | csi2_pdata = csi2_pdev->dev.platform_data; | ||
2190 | csi2_pdata->v4l2_dev = &pcdev->ici.v4l2_dev; | ||
2191 | |||
2192 | csi2_pdev->resource = csi2->resource; | ||
2193 | csi2_pdev->num_resources = csi2->num_resources; | ||
2194 | |||
2195 | err = platform_device_add(csi2_pdev); | ||
2196 | if (err < 0) | ||
2197 | goto exit_pdev_put; | ||
2198 | |||
2199 | wait.dev = &csi2_pdev->dev; | ||
2200 | |||
2201 | err = bus_register_notifier(&platform_bus_type, &wait.notifier); | ||
2202 | if (err < 0) | ||
2203 | goto exit_pdev_unregister; | ||
2204 | |||
2205 | /* | ||
2206 | * From this point the driver module will not unload, until | ||
2207 | * we complete the completion. | ||
2208 | */ | ||
2209 | |||
2210 | if (!csi2_pdev->dev.driver) { | ||
2211 | complete(&wait.completion); | ||
2212 | /* Either too late, or probing failed */ | ||
2213 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | ||
2214 | err = -ENXIO; | ||
2215 | goto exit_pdev_unregister; | ||
2216 | } | ||
2217 | |||
2218 | /* | ||
2219 | * The module is still loaded, in the worst case it is hanging | ||
2220 | * in device release on our completion. So, _now_ dereferencing | ||
2221 | * the "owner" is safe! | ||
2222 | */ | ||
2223 | |||
2224 | err = try_module_get(csi2_pdev->dev.driver->owner); | ||
2225 | |||
2226 | /* Let notifier complete, if it has been locked */ | ||
2227 | complete(&wait.completion); | ||
2228 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | ||
2229 | if (!err) { | ||
2230 | err = -ENODEV; | ||
2231 | goto exit_pdev_unregister; | ||
2232 | } | ||
2233 | } | ||
2234 | |||
2235 | return 0; | ||
2236 | |||
2237 | exit_pdev_unregister: | ||
2238 | platform_device_del(pcdev->csi2_pdev); | ||
2239 | exit_pdev_put: | ||
2240 | pcdev->csi2_pdev->resource = NULL; | ||
2241 | platform_device_put(pcdev->csi2_pdev); | ||
2242 | exit_host_unregister: | ||
2243 | soc_camera_host_unregister(&pcdev->ici); | ||
2244 | exit_free_ctx: | ||
2245 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
2246 | exit_free_clk: | ||
2247 | pm_runtime_disable(&pdev->dev); | ||
2248 | free_irq(pcdev->irq, pcdev); | ||
2249 | exit_release_mem: | ||
2250 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) | ||
2251 | dma_release_declared_memory(&pdev->dev); | ||
2252 | exit_iounmap: | ||
2253 | iounmap(base); | ||
2254 | exit_kfree: | ||
2255 | kfree(pcdev); | ||
2256 | exit: | ||
2257 | return err; | ||
2258 | } | ||
2259 | |||
2260 | static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) | ||
2261 | { | ||
2262 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
2263 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, | ||
2264 | struct sh_mobile_ceu_dev, ici); | ||
2265 | struct platform_device *csi2_pdev = pcdev->csi2_pdev; | ||
2266 | |||
2267 | soc_camera_host_unregister(soc_host); | ||
2268 | pm_runtime_disable(&pdev->dev); | ||
2269 | free_irq(pcdev->irq, pcdev); | ||
2270 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) | ||
2271 | dma_release_declared_memory(&pdev->dev); | ||
2272 | iounmap(pcdev->base); | ||
2273 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
2274 | if (csi2_pdev && csi2_pdev->dev.driver) { | ||
2275 | struct module *csi2_drv = csi2_pdev->dev.driver->owner; | ||
2276 | platform_device_del(csi2_pdev); | ||
2277 | csi2_pdev->resource = NULL; | ||
2278 | platform_device_put(csi2_pdev); | ||
2279 | module_put(csi2_drv); | ||
2280 | } | ||
2281 | kfree(pcdev); | ||
2282 | |||
2283 | return 0; | ||
2284 | } | ||
2285 | |||
2286 | static int sh_mobile_ceu_runtime_nop(struct device *dev) | ||
2287 | { | ||
2288 | /* Runtime PM callback shared between ->runtime_suspend() | ||
2289 | * and ->runtime_resume(). Simply returns success. | ||
2290 | * | ||
2291 | * This driver re-initializes all registers after | ||
2292 | * pm_runtime_get_sync() anyway so there is no need | ||
2293 | * to save and restore registers here. | ||
2294 | */ | ||
2295 | return 0; | ||
2296 | } | ||
2297 | |||
2298 | static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { | ||
2299 | .runtime_suspend = sh_mobile_ceu_runtime_nop, | ||
2300 | .runtime_resume = sh_mobile_ceu_runtime_nop, | ||
2301 | }; | ||
2302 | |||
2303 | static struct platform_driver sh_mobile_ceu_driver = { | ||
2304 | .driver = { | ||
2305 | .name = "sh_mobile_ceu", | ||
2306 | .pm = &sh_mobile_ceu_dev_pm_ops, | ||
2307 | }, | ||
2308 | .probe = sh_mobile_ceu_probe, | ||
2309 | .remove = __devexit_p(sh_mobile_ceu_remove), | ||
2310 | }; | ||
2311 | |||
2312 | static int __init sh_mobile_ceu_init(void) | ||
2313 | { | ||
2314 | /* Whatever return code */ | ||
2315 | request_module("sh_mobile_csi2"); | ||
2316 | return platform_driver_register(&sh_mobile_ceu_driver); | ||
2317 | } | ||
2318 | |||
2319 | static void __exit sh_mobile_ceu_exit(void) | ||
2320 | { | ||
2321 | platform_driver_unregister(&sh_mobile_ceu_driver); | ||
2322 | } | ||
2323 | |||
2324 | module_init(sh_mobile_ceu_init); | ||
2325 | module_exit(sh_mobile_ceu_exit); | ||
2326 | |||
2327 | MODULE_DESCRIPTION("SuperH Mobile CEU driver"); | ||
2328 | MODULE_AUTHOR("Magnus Damm"); | ||
2329 | MODULE_LICENSE("GPL"); | ||
2330 | MODULE_VERSION("0.0.6"); | ||
2331 | MODULE_ALIAS("platform:sh_mobile_ceu"); | ||
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c new file mode 100644 index 000000000000..05286500b4d4 --- /dev/null +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * Driver for the SH-Mobile MIPI CSI-2 unit | ||
3 | * | ||
4 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/pm_runtime.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/videodev2.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | #include <media/sh_mobile_ceu.h> | ||
21 | #include <media/sh_mobile_csi2.h> | ||
22 | #include <media/soc_camera.h> | ||
23 | #include <media/soc_mediabus.h> | ||
24 | #include <media/v4l2-common.h> | ||
25 | #include <media/v4l2-dev.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-mediabus.h> | ||
28 | #include <media/v4l2-subdev.h> | ||
29 | |||
30 | #define SH_CSI2_TREF 0x00 | ||
31 | #define SH_CSI2_SRST 0x04 | ||
32 | #define SH_CSI2_PHYCNT 0x08 | ||
33 | #define SH_CSI2_CHKSUM 0x0C | ||
34 | #define SH_CSI2_VCDT 0x10 | ||
35 | |||
36 | struct sh_csi2 { | ||
37 | struct v4l2_subdev subdev; | ||
38 | struct list_head list; | ||
39 | unsigned int irq; | ||
40 | unsigned long mipi_flags; | ||
41 | void __iomem *base; | ||
42 | struct platform_device *pdev; | ||
43 | struct sh_csi2_client_config *client; | ||
44 | }; | ||
45 | |||
46 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, | ||
47 | struct v4l2_mbus_framefmt *mf) | ||
48 | { | ||
49 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
50 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
51 | |||
52 | if (mf->width > 8188) | ||
53 | mf->width = 8188; | ||
54 | else if (mf->width & 1) | ||
55 | mf->width &= ~1; | ||
56 | |||
57 | switch (pdata->type) { | ||
58 | case SH_CSI2C: | ||
59 | switch (mf->code) { | ||
60 | case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */ | ||
61 | case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */ | ||
62 | case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ | ||
63 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
64 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
65 | break; | ||
66 | default: | ||
67 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
68 | mf->code = V4L2_MBUS_FMT_YUYV8_2X8; | ||
69 | } | ||
70 | break; | ||
71 | case SH_CSI2I: | ||
72 | switch (mf->code) { | ||
73 | case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ | ||
74 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
75 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
76 | case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */ | ||
77 | case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */ | ||
78 | break; | ||
79 | default: | ||
80 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
81 | mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; | ||
82 | } | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * We have done our best in try_fmt to try and tell the sensor, which formats | ||
91 | * we support. If now the configuration is unsuitable for us we can only | ||
92 | * error out. | ||
93 | */ | ||
94 | static int sh_csi2_s_fmt(struct v4l2_subdev *sd, | ||
95 | struct v4l2_mbus_framefmt *mf) | ||
96 | { | ||
97 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
98 | u32 tmp = (priv->client->channel & 3) << 8; | ||
99 | |||
100 | dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); | ||
101 | if (mf->width > 8188 || mf->width & 1) | ||
102 | return -EINVAL; | ||
103 | |||
104 | switch (mf->code) { | ||
105 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
106 | tmp |= 0x1e; /* YUV422 8 bit */ | ||
107 | break; | ||
108 | case V4L2_MBUS_FMT_YUYV8_1_5X8: | ||
109 | tmp |= 0x18; /* YUV420 8 bit */ | ||
110 | break; | ||
111 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: | ||
112 | tmp |= 0x21; /* RGB555 */ | ||
113 | break; | ||
114 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
115 | tmp |= 0x22; /* RGB565 */ | ||
116 | break; | ||
117 | case V4L2_MBUS_FMT_Y8_1X8: | ||
118 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
119 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
120 | tmp |= 0x2a; /* RAW8 */ | ||
121 | break; | ||
122 | default: | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | iowrite32(tmp, priv->base + SH_CSI2_VCDT); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, | ||
132 | struct v4l2_mbus_config *cfg) | ||
133 | { | ||
134 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
135 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
136 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
137 | cfg->type = V4L2_MBUS_PARALLEL; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, | ||
143 | const struct v4l2_mbus_config *cfg) | ||
144 | { | ||
145 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
146 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); | ||
147 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
148 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, | ||
149 | .flags = priv->mipi_flags}; | ||
150 | |||
151 | return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); | ||
152 | } | ||
153 | |||
154 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | ||
155 | .s_mbus_fmt = sh_csi2_s_fmt, | ||
156 | .try_mbus_fmt = sh_csi2_try_fmt, | ||
157 | .g_mbus_config = sh_csi2_g_mbus_config, | ||
158 | .s_mbus_config = sh_csi2_s_mbus_config, | ||
159 | }; | ||
160 | |||
161 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | ||
162 | { | ||
163 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
164 | __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */ | ||
165 | |||
166 | /* Reflect registers immediately */ | ||
167 | iowrite32(0x00000001, priv->base + SH_CSI2_TREF); | ||
168 | /* reset CSI2 harware */ | ||
169 | iowrite32(0x00000001, priv->base + SH_CSI2_SRST); | ||
170 | udelay(5); | ||
171 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); | ||
172 | |||
173 | switch (pdata->type) { | ||
174 | case SH_CSI2C: | ||
175 | if (priv->client->lanes == 1) | ||
176 | tmp |= 1; | ||
177 | else | ||
178 | /* Default - both lanes */ | ||
179 | tmp |= 3; | ||
180 | break; | ||
181 | case SH_CSI2I: | ||
182 | if (!priv->client->lanes || priv->client->lanes > 4) | ||
183 | /* Default - all 4 lanes */ | ||
184 | tmp |= 0xf; | ||
185 | else | ||
186 | tmp |= (1 << priv->client->lanes) - 1; | ||
187 | } | ||
188 | |||
189 | if (priv->client->phy == SH_CSI2_PHY_MAIN) | ||
190 | tmp |= 0x8000; | ||
191 | |||
192 | iowrite32(tmp, priv->base + SH_CSI2_PHYCNT); | ||
193 | |||
194 | tmp = 0; | ||
195 | if (pdata->flags & SH_CSI2_ECC) | ||
196 | tmp |= 2; | ||
197 | if (pdata->flags & SH_CSI2_CRC) | ||
198 | tmp |= 1; | ||
199 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); | ||
200 | } | ||
201 | |||
202 | static int sh_csi2_client_connect(struct sh_csi2 *priv) | ||
203 | { | ||
204 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
205 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev); | ||
206 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
207 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | ||
208 | struct v4l2_mbus_config cfg; | ||
209 | unsigned long common_flags, csi2_flags; | ||
210 | int i, ret; | ||
211 | |||
212 | if (priv->client) | ||
213 | return -EBUSY; | ||
214 | |||
215 | for (i = 0; i < pdata->num_clients; i++) | ||
216 | if (&pdata->clients[i].pdev->dev == icd->pdev) | ||
217 | break; | ||
218 | |||
219 | dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i); | ||
220 | |||
221 | if (i == pdata->num_clients) | ||
222 | return -ENODEV; | ||
223 | |||
224 | /* Check if we can support this camera */ | ||
225 | csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE; | ||
226 | |||
227 | switch (pdata->type) { | ||
228 | case SH_CSI2C: | ||
229 | if (pdata->clients[i].lanes != 1) | ||
230 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
231 | break; | ||
232 | case SH_CSI2I: | ||
233 | switch (pdata->clients[i].lanes) { | ||
234 | default: | ||
235 | csi2_flags |= V4L2_MBUS_CSI2_4_LANE; | ||
236 | case 3: | ||
237 | csi2_flags |= V4L2_MBUS_CSI2_3_LANE; | ||
238 | case 2: | ||
239 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | cfg.type = V4L2_MBUS_CSI2; | ||
244 | ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); | ||
245 | if (ret == -ENOIOCTLCMD) | ||
246 | common_flags = csi2_flags; | ||
247 | else if (!ret) | ||
248 | common_flags = soc_mbus_config_compatible(&cfg, | ||
249 | csi2_flags); | ||
250 | else | ||
251 | common_flags = 0; | ||
252 | |||
253 | if (!common_flags) | ||
254 | return -EINVAL; | ||
255 | |||
256 | /* All good: camera MIPI configuration supported */ | ||
257 | priv->mipi_flags = common_flags; | ||
258 | priv->client = pdata->clients + i; | ||
259 | |||
260 | pm_runtime_get_sync(dev); | ||
261 | |||
262 | sh_csi2_hwinit(priv); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) | ||
268 | { | ||
269 | if (!priv->client) | ||
270 | return; | ||
271 | |||
272 | priv->client = NULL; | ||
273 | |||
274 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | ||
275 | } | ||
276 | |||
277 | static int sh_csi2_s_power(struct v4l2_subdev *sd, int on) | ||
278 | { | ||
279 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
280 | |||
281 | if (on) | ||
282 | return sh_csi2_client_connect(priv); | ||
283 | |||
284 | sh_csi2_client_disconnect(priv); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { | ||
289 | .s_power = sh_csi2_s_power, | ||
290 | }; | ||
291 | |||
292 | static struct v4l2_subdev_ops sh_csi2_subdev_ops = { | ||
293 | .core = &sh_csi2_subdev_core_ops, | ||
294 | .video = &sh_csi2_subdev_video_ops, | ||
295 | }; | ||
296 | |||
297 | static __devinit int sh_csi2_probe(struct platform_device *pdev) | ||
298 | { | ||
299 | struct resource *res; | ||
300 | unsigned int irq; | ||
301 | int ret; | ||
302 | struct sh_csi2 *priv; | ||
303 | /* Platform data specify the PHY, lanes, ECC, CRC */ | ||
304 | struct sh_csi2_pdata *pdata = pdev->dev.platform_data; | ||
305 | |||
306 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
307 | /* Interrupt unused so far */ | ||
308 | irq = platform_get_irq(pdev, 0); | ||
309 | |||
310 | if (!res || (int)irq <= 0 || !pdata) { | ||
311 | dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n"); | ||
312 | return -ENODEV; | ||
313 | } | ||
314 | |||
315 | /* TODO: Add support for CSI2I. Careful: different register layout! */ | ||
316 | if (pdata->type != SH_CSI2C) { | ||
317 | dev_err(&pdev->dev, "Only CSI2C supported ATM.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL); | ||
322 | if (!priv) | ||
323 | return -ENOMEM; | ||
324 | |||
325 | priv->irq = irq; | ||
326 | |||
327 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
328 | dev_err(&pdev->dev, "CSI2 register region already claimed\n"); | ||
329 | ret = -EBUSY; | ||
330 | goto ereqreg; | ||
331 | } | ||
332 | |||
333 | priv->base = ioremap(res->start, resource_size(res)); | ||
334 | if (!priv->base) { | ||
335 | ret = -ENXIO; | ||
336 | dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n"); | ||
337 | goto eremap; | ||
338 | } | ||
339 | |||
340 | priv->pdev = pdev; | ||
341 | platform_set_drvdata(pdev, priv); | ||
342 | |||
343 | v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); | ||
344 | v4l2_set_subdevdata(&priv->subdev, &pdev->dev); | ||
345 | |||
346 | snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi", | ||
347 | dev_name(pdata->v4l2_dev->dev)); | ||
348 | ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev); | ||
349 | dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); | ||
350 | if (ret < 0) | ||
351 | goto esdreg; | ||
352 | |||
353 | pm_runtime_enable(&pdev->dev); | ||
354 | |||
355 | dev_dbg(&pdev->dev, "CSI2 probed.\n"); | ||
356 | |||
357 | return 0; | ||
358 | |||
359 | esdreg: | ||
360 | iounmap(priv->base); | ||
361 | eremap: | ||
362 | release_mem_region(res->start, resource_size(res)); | ||
363 | ereqreg: | ||
364 | kfree(priv); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | static __devexit int sh_csi2_remove(struct platform_device *pdev) | ||
370 | { | ||
371 | struct sh_csi2 *priv = platform_get_drvdata(pdev); | ||
372 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
373 | |||
374 | v4l2_device_unregister_subdev(&priv->subdev); | ||
375 | pm_runtime_disable(&pdev->dev); | ||
376 | iounmap(priv->base); | ||
377 | release_mem_region(res->start, resource_size(res)); | ||
378 | platform_set_drvdata(pdev, NULL); | ||
379 | kfree(priv); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static struct platform_driver __refdata sh_csi2_pdrv = { | ||
385 | .remove = __devexit_p(sh_csi2_remove), | ||
386 | .probe = sh_csi2_probe, | ||
387 | .driver = { | ||
388 | .name = "sh-mobile-csi2", | ||
389 | .owner = THIS_MODULE, | ||
390 | }, | ||
391 | }; | ||
392 | |||
393 | module_platform_driver(sh_csi2_pdrv); | ||
394 | |||
395 | MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); | ||
396 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
397 | MODULE_LICENSE("GPL v2"); | ||
398 | MODULE_ALIAS("platform:sh-mobile-csi2"); | ||
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c new file mode 100644 index 000000000000..3be92944f8e7 --- /dev/null +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
@@ -0,0 +1,1605 @@ | |||
1 | /* | ||
2 | * camera image capture (abstract) bus driver | ||
3 | * | ||
4 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
5 | * | ||
6 | * This driver provides an interface between platform-specific camera | ||
7 | * busses and camera devices. It should be used if the camera is | ||
8 | * connected not over a "proper" bus like PCI or USB, but over a | ||
9 | * special bus, like, for example, the Quick Capture interface on PXA270 | ||
10 | * SoCs. Later it should also be used for i.MX31 SoCs from Freescale. | ||
11 | * It can handle multiple cameras and / or multiple busses, which can | ||
12 | * be used, e.g., in stereo-vision applications. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | */ | ||
18 | |||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/mutex.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/regulator/consumer.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | #include <linux/vmalloc.h> | ||
31 | |||
32 | #include <media/soc_camera.h> | ||
33 | #include <media/v4l2-common.h> | ||
34 | #include <media/v4l2-ioctl.h> | ||
35 | #include <media/v4l2-dev.h> | ||
36 | #include <media/videobuf-core.h> | ||
37 | #include <media/videobuf2-core.h> | ||
38 | #include <media/soc_mediabus.h> | ||
39 | |||
40 | /* Default to VGA resolution */ | ||
41 | #define DEFAULT_WIDTH 640 | ||
42 | #define DEFAULT_HEIGHT 480 | ||
43 | |||
44 | #define is_streaming(ici, icd) \ | ||
45 | (((ici)->ops->init_videobuf) ? \ | ||
46 | (icd)->vb_vidq.streaming : \ | ||
47 | vb2_is_streaming(&(icd)->vb2_vidq)) | ||
48 | |||
49 | static LIST_HEAD(hosts); | ||
50 | static LIST_HEAD(devices); | ||
51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | ||
52 | |||
53 | int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl) | ||
54 | { | ||
55 | int ret = regulator_bulk_enable(icl->num_regulators, | ||
56 | icl->regulators); | ||
57 | if (ret < 0) { | ||
58 | dev_err(dev, "Cannot enable regulators\n"); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | if (icl->power) { | ||
63 | ret = icl->power(dev, 1); | ||
64 | if (ret < 0) { | ||
65 | dev_err(dev, | ||
66 | "Platform failed to power-on the camera.\n"); | ||
67 | regulator_bulk_disable(icl->num_regulators, | ||
68 | icl->regulators); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | EXPORT_SYMBOL(soc_camera_power_on); | ||
75 | |||
76 | int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl) | ||
77 | { | ||
78 | int ret = 0; | ||
79 | int err; | ||
80 | |||
81 | if (icl->power) { | ||
82 | err = icl->power(dev, 0); | ||
83 | if (err < 0) { | ||
84 | dev_err(dev, | ||
85 | "Platform failed to power-off the camera.\n"); | ||
86 | ret = err; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | err = regulator_bulk_disable(icl->num_regulators, | ||
91 | icl->regulators); | ||
92 | if (err < 0) { | ||
93 | dev_err(dev, "Cannot disable regulators\n"); | ||
94 | ret = ret ? : err; | ||
95 | } | ||
96 | |||
97 | return ret; | ||
98 | } | ||
99 | EXPORT_SYMBOL(soc_camera_power_off); | ||
100 | |||
101 | static int __soc_camera_power_on(struct soc_camera_device *icd) | ||
102 | { | ||
103 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
104 | int ret; | ||
105 | |||
106 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
107 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
108 | return ret; | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int __soc_camera_power_off(struct soc_camera_device *icd) | ||
114 | { | ||
115 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
116 | int ret; | ||
117 | |||
118 | ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
119 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
120 | return ret; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | ||
126 | struct soc_camera_device *icd, unsigned int fourcc) | ||
127 | { | ||
128 | unsigned int i; | ||
129 | |||
130 | for (i = 0; i < icd->num_user_formats; i++) | ||
131 | if (icd->user_formats[i].host_fmt->fourcc == fourcc) | ||
132 | return icd->user_formats + i; | ||
133 | return NULL; | ||
134 | } | ||
135 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | ||
136 | |||
137 | /** | ||
138 | * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags | ||
139 | * @icl: camera platform parameters | ||
140 | * @cfg: media bus configuration | ||
141 | * @return: resulting flags | ||
142 | */ | ||
143 | unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, | ||
144 | const struct v4l2_mbus_config *cfg) | ||
145 | { | ||
146 | unsigned long f, flags = cfg->flags; | ||
147 | |||
148 | /* If only one of the two polarities is supported, switch to the opposite */ | ||
149 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { | ||
150 | f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
151 | if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
152 | flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
153 | } | ||
154 | |||
155 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { | ||
156 | f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
157 | if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
158 | flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
159 | } | ||
160 | |||
161 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { | ||
162 | f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
163 | if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
164 | flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
165 | } | ||
166 | |||
167 | return flags; | ||
168 | } | ||
169 | EXPORT_SYMBOL(soc_camera_apply_board_flags); | ||
170 | |||
171 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | ||
172 | ((x) >> 24) & 0xff | ||
173 | |||
174 | static int soc_camera_try_fmt(struct soc_camera_device *icd, | ||
175 | struct v4l2_format *f) | ||
176 | { | ||
177 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
178 | const struct soc_camera_format_xlate *xlate; | ||
179 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
180 | int ret; | ||
181 | |||
182 | dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n", | ||
183 | pixfmtstr(pix->pixelformat), pix->width, pix->height); | ||
184 | |||
185 | if (pix->pixelformat != V4L2_PIX_FMT_JPEG && | ||
186 | !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) { | ||
187 | pix->bytesperline = 0; | ||
188 | pix->sizeimage = 0; | ||
189 | } | ||
190 | |||
191 | ret = ici->ops->try_fmt(icd, f); | ||
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
196 | if (!xlate) | ||
197 | return -EINVAL; | ||
198 | |||
199 | ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt); | ||
200 | if (ret < 0) | ||
201 | return ret; | ||
202 | |||
203 | pix->bytesperline = max_t(u32, pix->bytesperline, ret); | ||
204 | |||
205 | ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline, | ||
206 | pix->height); | ||
207 | if (ret < 0) | ||
208 | return ret; | ||
209 | |||
210 | pix->sizeimage = max_t(u32, pix->sizeimage, ret); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, | ||
216 | struct v4l2_format *f) | ||
217 | { | ||
218 | struct soc_camera_device *icd = file->private_data; | ||
219 | |||
220 | WARN_ON(priv != file->private_data); | ||
221 | |||
222 | /* Only single-plane capture is supported so far */ | ||
223 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
224 | return -EINVAL; | ||
225 | |||
226 | /* limit format to hardware capabilities */ | ||
227 | return soc_camera_try_fmt(icd, f); | ||
228 | } | ||
229 | |||
230 | static int soc_camera_enum_input(struct file *file, void *priv, | ||
231 | struct v4l2_input *inp) | ||
232 | { | ||
233 | if (inp->index != 0) | ||
234 | return -EINVAL; | ||
235 | |||
236 | /* default is camera */ | ||
237 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
238 | inp->std = V4L2_STD_UNKNOWN; | ||
239 | strcpy(inp->name, "Camera"); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) | ||
245 | { | ||
246 | *i = 0; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) | ||
252 | { | ||
253 | if (i > 0) | ||
254 | return -EINVAL; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | ||
260 | { | ||
261 | struct soc_camera_device *icd = file->private_data; | ||
262 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
263 | |||
264 | return v4l2_subdev_call(sd, core, s_std, *a); | ||
265 | } | ||
266 | |||
267 | static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) | ||
268 | { | ||
269 | struct soc_camera_device *icd = file->private_data; | ||
270 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
271 | |||
272 | return v4l2_subdev_call(sd, core, g_std, a); | ||
273 | } | ||
274 | |||
275 | static int soc_camera_enum_framesizes(struct file *file, void *fh, | ||
276 | struct v4l2_frmsizeenum *fsize) | ||
277 | { | ||
278 | struct soc_camera_device *icd = file->private_data; | ||
279 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
280 | |||
281 | return ici->ops->enum_framesizes(icd, fsize); | ||
282 | } | ||
283 | |||
284 | static int soc_camera_reqbufs(struct file *file, void *priv, | ||
285 | struct v4l2_requestbuffers *p) | ||
286 | { | ||
287 | int ret; | ||
288 | struct soc_camera_device *icd = file->private_data; | ||
289 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
290 | |||
291 | WARN_ON(priv != file->private_data); | ||
292 | |||
293 | if (icd->streamer && icd->streamer != file) | ||
294 | return -EBUSY; | ||
295 | |||
296 | if (ici->ops->init_videobuf) { | ||
297 | ret = videobuf_reqbufs(&icd->vb_vidq, p); | ||
298 | if (ret < 0) | ||
299 | return ret; | ||
300 | |||
301 | ret = ici->ops->reqbufs(icd, p); | ||
302 | } else { | ||
303 | ret = vb2_reqbufs(&icd->vb2_vidq, p); | ||
304 | } | ||
305 | |||
306 | if (!ret && !icd->streamer) | ||
307 | icd->streamer = file; | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | static int soc_camera_querybuf(struct file *file, void *priv, | ||
313 | struct v4l2_buffer *p) | ||
314 | { | ||
315 | struct soc_camera_device *icd = file->private_data; | ||
316 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
317 | |||
318 | WARN_ON(priv != file->private_data); | ||
319 | |||
320 | if (ici->ops->init_videobuf) | ||
321 | return videobuf_querybuf(&icd->vb_vidq, p); | ||
322 | else | ||
323 | return vb2_querybuf(&icd->vb2_vidq, p); | ||
324 | } | ||
325 | |||
326 | static int soc_camera_qbuf(struct file *file, void *priv, | ||
327 | struct v4l2_buffer *p) | ||
328 | { | ||
329 | struct soc_camera_device *icd = file->private_data; | ||
330 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
331 | |||
332 | WARN_ON(priv != file->private_data); | ||
333 | |||
334 | if (icd->streamer != file) | ||
335 | return -EBUSY; | ||
336 | |||
337 | if (ici->ops->init_videobuf) | ||
338 | return videobuf_qbuf(&icd->vb_vidq, p); | ||
339 | else | ||
340 | return vb2_qbuf(&icd->vb2_vidq, p); | ||
341 | } | ||
342 | |||
343 | static int soc_camera_dqbuf(struct file *file, void *priv, | ||
344 | struct v4l2_buffer *p) | ||
345 | { | ||
346 | struct soc_camera_device *icd = file->private_data; | ||
347 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
348 | |||
349 | WARN_ON(priv != file->private_data); | ||
350 | |||
351 | if (icd->streamer != file) | ||
352 | return -EBUSY; | ||
353 | |||
354 | if (ici->ops->init_videobuf) | ||
355 | return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK); | ||
356 | else | ||
357 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); | ||
358 | } | ||
359 | |||
360 | static int soc_camera_create_bufs(struct file *file, void *priv, | ||
361 | struct v4l2_create_buffers *create) | ||
362 | { | ||
363 | struct soc_camera_device *icd = file->private_data; | ||
364 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
365 | |||
366 | /* videobuf2 only */ | ||
367 | if (ici->ops->init_videobuf) | ||
368 | return -EINVAL; | ||
369 | else | ||
370 | return vb2_create_bufs(&icd->vb2_vidq, create); | ||
371 | } | ||
372 | |||
373 | static int soc_camera_prepare_buf(struct file *file, void *priv, | ||
374 | struct v4l2_buffer *b) | ||
375 | { | ||
376 | struct soc_camera_device *icd = file->private_data; | ||
377 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
378 | |||
379 | /* videobuf2 only */ | ||
380 | if (ici->ops->init_videobuf) | ||
381 | return -EINVAL; | ||
382 | else | ||
383 | return vb2_prepare_buf(&icd->vb2_vidq, b); | ||
384 | } | ||
385 | |||
386 | /* Always entered with .video_lock held */ | ||
387 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | ||
388 | { | ||
389 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
390 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
391 | unsigned int i, fmts = 0, raw_fmts = 0; | ||
392 | int ret; | ||
393 | enum v4l2_mbus_pixelcode code; | ||
394 | |||
395 | while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) | ||
396 | raw_fmts++; | ||
397 | |||
398 | if (!ici->ops->get_formats) | ||
399 | /* | ||
400 | * Fallback mode - the host will have to serve all | ||
401 | * sensor-provided formats one-to-one to the user | ||
402 | */ | ||
403 | fmts = raw_fmts; | ||
404 | else | ||
405 | /* | ||
406 | * First pass - only count formats this host-sensor | ||
407 | * configuration can provide | ||
408 | */ | ||
409 | for (i = 0; i < raw_fmts; i++) { | ||
410 | ret = ici->ops->get_formats(icd, i, NULL); | ||
411 | if (ret < 0) | ||
412 | return ret; | ||
413 | fmts += ret; | ||
414 | } | ||
415 | |||
416 | if (!fmts) | ||
417 | return -ENXIO; | ||
418 | |||
419 | icd->user_formats = | ||
420 | vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); | ||
421 | if (!icd->user_formats) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts); | ||
425 | |||
426 | /* Second pass - actually fill data formats */ | ||
427 | fmts = 0; | ||
428 | for (i = 0; i < raw_fmts; i++) | ||
429 | if (!ici->ops->get_formats) { | ||
430 | v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); | ||
431 | icd->user_formats[fmts].host_fmt = | ||
432 | soc_mbus_get_fmtdesc(code); | ||
433 | if (icd->user_formats[fmts].host_fmt) | ||
434 | icd->user_formats[fmts++].code = code; | ||
435 | } else { | ||
436 | ret = ici->ops->get_formats(icd, i, | ||
437 | &icd->user_formats[fmts]); | ||
438 | if (ret < 0) | ||
439 | goto egfmt; | ||
440 | fmts += ret; | ||
441 | } | ||
442 | |||
443 | icd->num_user_formats = fmts; | ||
444 | icd->current_fmt = &icd->user_formats[0]; | ||
445 | |||
446 | return 0; | ||
447 | |||
448 | egfmt: | ||
449 | vfree(icd->user_formats); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | /* Always entered with .video_lock held */ | ||
454 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | ||
455 | { | ||
456 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
457 | |||
458 | if (ici->ops->put_formats) | ||
459 | ici->ops->put_formats(icd); | ||
460 | icd->current_fmt = NULL; | ||
461 | icd->num_user_formats = 0; | ||
462 | vfree(icd->user_formats); | ||
463 | icd->user_formats = NULL; | ||
464 | } | ||
465 | |||
466 | /* Called with .vb_lock held, or from the first open(2), see comment there */ | ||
467 | static int soc_camera_set_fmt(struct soc_camera_device *icd, | ||
468 | struct v4l2_format *f) | ||
469 | { | ||
470 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
471 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
472 | int ret; | ||
473 | |||
474 | dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n", | ||
475 | pixfmtstr(pix->pixelformat), pix->width, pix->height); | ||
476 | |||
477 | /* We always call try_fmt() before set_fmt() or set_crop() */ | ||
478 | ret = soc_camera_try_fmt(icd, f); | ||
479 | if (ret < 0) | ||
480 | return ret; | ||
481 | |||
482 | ret = ici->ops->set_fmt(icd, f); | ||
483 | if (ret < 0) { | ||
484 | return ret; | ||
485 | } else if (!icd->current_fmt || | ||
486 | icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { | ||
487 | dev_err(icd->pdev, | ||
488 | "Host driver hasn't set up current format correctly!\n"); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | |||
492 | icd->user_width = pix->width; | ||
493 | icd->user_height = pix->height; | ||
494 | icd->bytesperline = pix->bytesperline; | ||
495 | icd->sizeimage = pix->sizeimage; | ||
496 | icd->colorspace = pix->colorspace; | ||
497 | icd->field = pix->field; | ||
498 | if (ici->ops->init_videobuf) | ||
499 | icd->vb_vidq.field = pix->field; | ||
500 | |||
501 | dev_dbg(icd->pdev, "set width: %d height: %d\n", | ||
502 | icd->user_width, icd->user_height); | ||
503 | |||
504 | /* set physical bus parameters */ | ||
505 | return ici->ops->set_bus_param(icd); | ||
506 | } | ||
507 | |||
508 | static int soc_camera_open(struct file *file) | ||
509 | { | ||
510 | struct video_device *vdev = video_devdata(file); | ||
511 | struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); | ||
512 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
513 | struct soc_camera_host *ici; | ||
514 | int ret; | ||
515 | |||
516 | if (!to_soc_camera_control(icd)) | ||
517 | /* No device driver attached */ | ||
518 | return -ENODEV; | ||
519 | |||
520 | ici = to_soc_camera_host(icd->parent); | ||
521 | |||
522 | if (mutex_lock_interruptible(&icd->video_lock)) | ||
523 | return -ERESTARTSYS; | ||
524 | if (!try_module_get(ici->ops->owner)) { | ||
525 | dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); | ||
526 | ret = -EINVAL; | ||
527 | goto emodule; | ||
528 | } | ||
529 | |||
530 | icd->use_count++; | ||
531 | |||
532 | /* Now we really have to activate the camera */ | ||
533 | if (icd->use_count == 1) { | ||
534 | /* Restore parameters before the last close() per V4L2 API */ | ||
535 | struct v4l2_format f = { | ||
536 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
537 | .fmt.pix = { | ||
538 | .width = icd->user_width, | ||
539 | .height = icd->user_height, | ||
540 | .field = icd->field, | ||
541 | .colorspace = icd->colorspace, | ||
542 | .pixelformat = | ||
543 | icd->current_fmt->host_fmt->fourcc, | ||
544 | }, | ||
545 | }; | ||
546 | |||
547 | /* The camera could have been already on, try to reset */ | ||
548 | if (icl->reset) | ||
549 | icl->reset(icd->pdev); | ||
550 | |||
551 | /* Don't mess with the host during probe */ | ||
552 | mutex_lock(&ici->host_lock); | ||
553 | ret = ici->ops->add(icd); | ||
554 | mutex_unlock(&ici->host_lock); | ||
555 | if (ret < 0) { | ||
556 | dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); | ||
557 | goto eiciadd; | ||
558 | } | ||
559 | |||
560 | ret = __soc_camera_power_on(icd); | ||
561 | if (ret < 0) | ||
562 | goto epower; | ||
563 | |||
564 | pm_runtime_enable(&icd->vdev->dev); | ||
565 | ret = pm_runtime_resume(&icd->vdev->dev); | ||
566 | if (ret < 0 && ret != -ENOSYS) | ||
567 | goto eresume; | ||
568 | |||
569 | /* | ||
570 | * Try to configure with default parameters. Notice: this is the | ||
571 | * very first open, so, we cannot race against other calls, | ||
572 | * apart from someone else calling open() simultaneously, but | ||
573 | * .video_lock is protecting us against it. | ||
574 | */ | ||
575 | ret = soc_camera_set_fmt(icd, &f); | ||
576 | if (ret < 0) | ||
577 | goto esfmt; | ||
578 | |||
579 | if (ici->ops->init_videobuf) { | ||
580 | ici->ops->init_videobuf(&icd->vb_vidq, icd); | ||
581 | } else { | ||
582 | ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); | ||
583 | if (ret < 0) | ||
584 | goto einitvb; | ||
585 | } | ||
586 | v4l2_ctrl_handler_setup(&icd->ctrl_handler); | ||
587 | } | ||
588 | mutex_unlock(&icd->video_lock); | ||
589 | |||
590 | file->private_data = icd; | ||
591 | dev_dbg(icd->pdev, "camera device open\n"); | ||
592 | |||
593 | return 0; | ||
594 | |||
595 | /* | ||
596 | * First four errors are entered with the .video_lock held | ||
597 | * and use_count == 1 | ||
598 | */ | ||
599 | einitvb: | ||
600 | esfmt: | ||
601 | pm_runtime_disable(&icd->vdev->dev); | ||
602 | eresume: | ||
603 | __soc_camera_power_off(icd); | ||
604 | epower: | ||
605 | ici->ops->remove(icd); | ||
606 | eiciadd: | ||
607 | icd->use_count--; | ||
608 | module_put(ici->ops->owner); | ||
609 | emodule: | ||
610 | mutex_unlock(&icd->video_lock); | ||
611 | |||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | static int soc_camera_close(struct file *file) | ||
616 | { | ||
617 | struct soc_camera_device *icd = file->private_data; | ||
618 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
619 | |||
620 | mutex_lock(&icd->video_lock); | ||
621 | icd->use_count--; | ||
622 | if (!icd->use_count) { | ||
623 | pm_runtime_suspend(&icd->vdev->dev); | ||
624 | pm_runtime_disable(&icd->vdev->dev); | ||
625 | |||
626 | if (ici->ops->init_videobuf2) | ||
627 | vb2_queue_release(&icd->vb2_vidq); | ||
628 | ici->ops->remove(icd); | ||
629 | |||
630 | __soc_camera_power_off(icd); | ||
631 | } | ||
632 | |||
633 | if (icd->streamer == file) | ||
634 | icd->streamer = NULL; | ||
635 | mutex_unlock(&icd->video_lock); | ||
636 | |||
637 | module_put(ici->ops->owner); | ||
638 | |||
639 | dev_dbg(icd->pdev, "camera device close\n"); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static ssize_t soc_camera_read(struct file *file, char __user *buf, | ||
645 | size_t count, loff_t *ppos) | ||
646 | { | ||
647 | struct soc_camera_device *icd = file->private_data; | ||
648 | int err = -EINVAL; | ||
649 | |||
650 | dev_err(icd->pdev, "camera device read not implemented\n"); | ||
651 | |||
652 | return err; | ||
653 | } | ||
654 | |||
655 | static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) | ||
656 | { | ||
657 | struct soc_camera_device *icd = file->private_data; | ||
658 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
659 | int err; | ||
660 | |||
661 | dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | ||
662 | |||
663 | if (icd->streamer != file) | ||
664 | return -EBUSY; | ||
665 | |||
666 | if (mutex_lock_interruptible(&icd->video_lock)) | ||
667 | return -ERESTARTSYS; | ||
668 | if (ici->ops->init_videobuf) | ||
669 | err = videobuf_mmap_mapper(&icd->vb_vidq, vma); | ||
670 | else | ||
671 | err = vb2_mmap(&icd->vb2_vidq, vma); | ||
672 | mutex_unlock(&icd->video_lock); | ||
673 | |||
674 | dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n", | ||
675 | (unsigned long)vma->vm_start, | ||
676 | (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, | ||
677 | err); | ||
678 | |||
679 | return err; | ||
680 | } | ||
681 | |||
682 | static unsigned int soc_camera_poll(struct file *file, poll_table *pt) | ||
683 | { | ||
684 | struct soc_camera_device *icd = file->private_data; | ||
685 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
686 | unsigned res = POLLERR; | ||
687 | |||
688 | if (icd->streamer != file) | ||
689 | return POLLERR; | ||
690 | |||
691 | mutex_lock(&icd->video_lock); | ||
692 | if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) | ||
693 | dev_err(icd->pdev, "Trying to poll with no queued buffers!\n"); | ||
694 | else | ||
695 | res = ici->ops->poll(file, pt); | ||
696 | mutex_unlock(&icd->video_lock); | ||
697 | return res; | ||
698 | } | ||
699 | |||
700 | void soc_camera_lock(struct vb2_queue *vq) | ||
701 | { | ||
702 | struct soc_camera_device *icd = vb2_get_drv_priv(vq); | ||
703 | mutex_lock(&icd->video_lock); | ||
704 | } | ||
705 | EXPORT_SYMBOL(soc_camera_lock); | ||
706 | |||
707 | void soc_camera_unlock(struct vb2_queue *vq) | ||
708 | { | ||
709 | struct soc_camera_device *icd = vb2_get_drv_priv(vq); | ||
710 | mutex_unlock(&icd->video_lock); | ||
711 | } | ||
712 | EXPORT_SYMBOL(soc_camera_unlock); | ||
713 | |||
714 | static struct v4l2_file_operations soc_camera_fops = { | ||
715 | .owner = THIS_MODULE, | ||
716 | .open = soc_camera_open, | ||
717 | .release = soc_camera_close, | ||
718 | .unlocked_ioctl = video_ioctl2, | ||
719 | .read = soc_camera_read, | ||
720 | .mmap = soc_camera_mmap, | ||
721 | .poll = soc_camera_poll, | ||
722 | }; | ||
723 | |||
724 | static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | ||
725 | struct v4l2_format *f) | ||
726 | { | ||
727 | struct soc_camera_device *icd = file->private_data; | ||
728 | int ret; | ||
729 | |||
730 | WARN_ON(priv != file->private_data); | ||
731 | |||
732 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
733 | dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type); | ||
734 | return -EINVAL; | ||
735 | } | ||
736 | |||
737 | if (icd->streamer && icd->streamer != file) | ||
738 | return -EBUSY; | ||
739 | |||
740 | if (is_streaming(to_soc_camera_host(icd->parent), icd)) { | ||
741 | dev_err(icd->pdev, "S_FMT denied: queue initialised\n"); | ||
742 | return -EBUSY; | ||
743 | } | ||
744 | |||
745 | ret = soc_camera_set_fmt(icd, f); | ||
746 | |||
747 | if (!ret && !icd->streamer) | ||
748 | icd->streamer = file; | ||
749 | |||
750 | return ret; | ||
751 | } | ||
752 | |||
753 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | ||
754 | struct v4l2_fmtdesc *f) | ||
755 | { | ||
756 | struct soc_camera_device *icd = file->private_data; | ||
757 | const struct soc_mbus_pixelfmt *format; | ||
758 | |||
759 | WARN_ON(priv != file->private_data); | ||
760 | |||
761 | if (f->index >= icd->num_user_formats) | ||
762 | return -EINVAL; | ||
763 | |||
764 | format = icd->user_formats[f->index].host_fmt; | ||
765 | |||
766 | if (format->name) | ||
767 | strlcpy(f->description, format->name, sizeof(f->description)); | ||
768 | f->pixelformat = format->fourcc; | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, | ||
773 | struct v4l2_format *f) | ||
774 | { | ||
775 | struct soc_camera_device *icd = file->private_data; | ||
776 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
777 | |||
778 | WARN_ON(priv != file->private_data); | ||
779 | |||
780 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
781 | return -EINVAL; | ||
782 | |||
783 | pix->width = icd->user_width; | ||
784 | pix->height = icd->user_height; | ||
785 | pix->bytesperline = icd->bytesperline; | ||
786 | pix->sizeimage = icd->sizeimage; | ||
787 | pix->field = icd->field; | ||
788 | pix->pixelformat = icd->current_fmt->host_fmt->fourcc; | ||
789 | pix->colorspace = icd->colorspace; | ||
790 | dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n", | ||
791 | icd->current_fmt->host_fmt->fourcc); | ||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static int soc_camera_querycap(struct file *file, void *priv, | ||
796 | struct v4l2_capability *cap) | ||
797 | { | ||
798 | struct soc_camera_device *icd = file->private_data; | ||
799 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
800 | |||
801 | WARN_ON(priv != file->private_data); | ||
802 | |||
803 | strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver)); | ||
804 | return ici->ops->querycap(ici, cap); | ||
805 | } | ||
806 | |||
807 | static int soc_camera_streamon(struct file *file, void *priv, | ||
808 | enum v4l2_buf_type i) | ||
809 | { | ||
810 | struct soc_camera_device *icd = file->private_data; | ||
811 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
812 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
813 | int ret; | ||
814 | |||
815 | WARN_ON(priv != file->private_data); | ||
816 | |||
817 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
818 | return -EINVAL; | ||
819 | |||
820 | if (icd->streamer != file) | ||
821 | return -EBUSY; | ||
822 | |||
823 | /* This calls buf_queue from host driver's videobuf_queue_ops */ | ||
824 | if (ici->ops->init_videobuf) | ||
825 | ret = videobuf_streamon(&icd->vb_vidq); | ||
826 | else | ||
827 | ret = vb2_streamon(&icd->vb2_vidq, i); | ||
828 | |||
829 | if (!ret) | ||
830 | v4l2_subdev_call(sd, video, s_stream, 1); | ||
831 | |||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | static int soc_camera_streamoff(struct file *file, void *priv, | ||
836 | enum v4l2_buf_type i) | ||
837 | { | ||
838 | struct soc_camera_device *icd = file->private_data; | ||
839 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
840 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
841 | |||
842 | WARN_ON(priv != file->private_data); | ||
843 | |||
844 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
845 | return -EINVAL; | ||
846 | |||
847 | if (icd->streamer != file) | ||
848 | return -EBUSY; | ||
849 | |||
850 | /* | ||
851 | * This calls buf_release from host driver's videobuf_queue_ops for all | ||
852 | * remaining buffers. When the last buffer is freed, stop capture | ||
853 | */ | ||
854 | if (ici->ops->init_videobuf) | ||
855 | videobuf_streamoff(&icd->vb_vidq); | ||
856 | else | ||
857 | vb2_streamoff(&icd->vb2_vidq, i); | ||
858 | |||
859 | v4l2_subdev_call(sd, video, s_stream, 0); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int soc_camera_cropcap(struct file *file, void *fh, | ||
865 | struct v4l2_cropcap *a) | ||
866 | { | ||
867 | struct soc_camera_device *icd = file->private_data; | ||
868 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
869 | |||
870 | return ici->ops->cropcap(icd, a); | ||
871 | } | ||
872 | |||
873 | static int soc_camera_g_crop(struct file *file, void *fh, | ||
874 | struct v4l2_crop *a) | ||
875 | { | ||
876 | struct soc_camera_device *icd = file->private_data; | ||
877 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
878 | int ret; | ||
879 | |||
880 | ret = ici->ops->get_crop(icd, a); | ||
881 | |||
882 | return ret; | ||
883 | } | ||
884 | |||
885 | /* | ||
886 | * According to the V4L2 API, drivers shall not update the struct v4l2_crop | ||
887 | * argument with the actual geometry, instead, the user shall use G_CROP to | ||
888 | * retrieve it. | ||
889 | */ | ||
890 | static int soc_camera_s_crop(struct file *file, void *fh, | ||
891 | const struct v4l2_crop *a) | ||
892 | { | ||
893 | struct soc_camera_device *icd = file->private_data; | ||
894 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
895 | const struct v4l2_rect *rect = &a->c; | ||
896 | struct v4l2_crop current_crop; | ||
897 | int ret; | ||
898 | |||
899 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
900 | return -EINVAL; | ||
901 | |||
902 | dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n", | ||
903 | rect->width, rect->height, rect->left, rect->top); | ||
904 | |||
905 | /* If get_crop fails, we'll let host and / or client drivers decide */ | ||
906 | ret = ici->ops->get_crop(icd, ¤t_crop); | ||
907 | |||
908 | /* Prohibit window size change with initialised buffers */ | ||
909 | if (ret < 0) { | ||
910 | dev_err(icd->pdev, | ||
911 | "S_CROP denied: getting current crop failed\n"); | ||
912 | } else if ((a->c.width == current_crop.c.width && | ||
913 | a->c.height == current_crop.c.height) || | ||
914 | !is_streaming(ici, icd)) { | ||
915 | /* same size or not streaming - use .set_crop() */ | ||
916 | ret = ici->ops->set_crop(icd, a); | ||
917 | } else if (ici->ops->set_livecrop) { | ||
918 | ret = ici->ops->set_livecrop(icd, a); | ||
919 | } else { | ||
920 | dev_err(icd->pdev, | ||
921 | "S_CROP denied: queue initialised and sizes differ\n"); | ||
922 | ret = -EBUSY; | ||
923 | } | ||
924 | |||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | static int soc_camera_g_selection(struct file *file, void *fh, | ||
929 | struct v4l2_selection *s) | ||
930 | { | ||
931 | struct soc_camera_device *icd = file->private_data; | ||
932 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
933 | |||
934 | /* With a wrong type no need to try to fall back to cropping */ | ||
935 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
936 | return -EINVAL; | ||
937 | |||
938 | if (!ici->ops->get_selection) | ||
939 | return -ENOTTY; | ||
940 | |||
941 | return ici->ops->get_selection(icd, s); | ||
942 | } | ||
943 | |||
944 | static int soc_camera_s_selection(struct file *file, void *fh, | ||
945 | struct v4l2_selection *s) | ||
946 | { | ||
947 | struct soc_camera_device *icd = file->private_data; | ||
948 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
949 | int ret; | ||
950 | |||
951 | /* In all these cases cropping emulation will not help */ | ||
952 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
953 | (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE && | ||
954 | s->target != V4L2_SEL_TGT_CROP_ACTIVE)) | ||
955 | return -EINVAL; | ||
956 | |||
957 | if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { | ||
958 | /* No output size change during a running capture! */ | ||
959 | if (is_streaming(ici, icd) && | ||
960 | (icd->user_width != s->r.width || | ||
961 | icd->user_height != s->r.height)) | ||
962 | return -EBUSY; | ||
963 | |||
964 | /* | ||
965 | * Only one user is allowed to change the output format, touch | ||
966 | * buffers, start / stop streaming, poll for data | ||
967 | */ | ||
968 | if (icd->streamer && icd->streamer != file) | ||
969 | return -EBUSY; | ||
970 | } | ||
971 | |||
972 | if (!ici->ops->set_selection) | ||
973 | return -ENOTTY; | ||
974 | |||
975 | ret = ici->ops->set_selection(icd, s); | ||
976 | if (!ret && | ||
977 | s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { | ||
978 | icd->user_width = s->r.width; | ||
979 | icd->user_height = s->r.height; | ||
980 | if (!icd->streamer) | ||
981 | icd->streamer = file; | ||
982 | } | ||
983 | |||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | static int soc_camera_g_parm(struct file *file, void *fh, | ||
988 | struct v4l2_streamparm *a) | ||
989 | { | ||
990 | struct soc_camera_device *icd = file->private_data; | ||
991 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
992 | |||
993 | if (ici->ops->get_parm) | ||
994 | return ici->ops->get_parm(icd, a); | ||
995 | |||
996 | return -ENOIOCTLCMD; | ||
997 | } | ||
998 | |||
999 | static int soc_camera_s_parm(struct file *file, void *fh, | ||
1000 | struct v4l2_streamparm *a) | ||
1001 | { | ||
1002 | struct soc_camera_device *icd = file->private_data; | ||
1003 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1004 | |||
1005 | if (ici->ops->set_parm) | ||
1006 | return ici->ops->set_parm(icd, a); | ||
1007 | |||
1008 | return -ENOIOCTLCMD; | ||
1009 | } | ||
1010 | |||
1011 | static int soc_camera_g_chip_ident(struct file *file, void *fh, | ||
1012 | struct v4l2_dbg_chip_ident *id) | ||
1013 | { | ||
1014 | struct soc_camera_device *icd = file->private_data; | ||
1015 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1016 | |||
1017 | return v4l2_subdev_call(sd, core, g_chip_ident, id); | ||
1018 | } | ||
1019 | |||
1020 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1021 | static int soc_camera_g_register(struct file *file, void *fh, | ||
1022 | struct v4l2_dbg_register *reg) | ||
1023 | { | ||
1024 | struct soc_camera_device *icd = file->private_data; | ||
1025 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1026 | |||
1027 | return v4l2_subdev_call(sd, core, g_register, reg); | ||
1028 | } | ||
1029 | |||
1030 | static int soc_camera_s_register(struct file *file, void *fh, | ||
1031 | struct v4l2_dbg_register *reg) | ||
1032 | { | ||
1033 | struct soc_camera_device *icd = file->private_data; | ||
1034 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1035 | |||
1036 | return v4l2_subdev_call(sd, core, s_register, reg); | ||
1037 | } | ||
1038 | #endif | ||
1039 | |||
1040 | static int soc_camera_probe(struct soc_camera_device *icd); | ||
1041 | |||
1042 | /* So far this function cannot fail */ | ||
1043 | static void scan_add_host(struct soc_camera_host *ici) | ||
1044 | { | ||
1045 | struct soc_camera_device *icd; | ||
1046 | |||
1047 | mutex_lock(&ici->host_lock); | ||
1048 | |||
1049 | list_for_each_entry(icd, &devices, list) { | ||
1050 | if (icd->iface == ici->nr) { | ||
1051 | int ret; | ||
1052 | |||
1053 | icd->parent = ici->v4l2_dev.dev; | ||
1054 | ret = soc_camera_probe(icd); | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | mutex_unlock(&ici->host_lock); | ||
1059 | } | ||
1060 | |||
1061 | #ifdef CONFIG_I2C_BOARDINFO | ||
1062 | static int soc_camera_init_i2c(struct soc_camera_device *icd, | ||
1063 | struct soc_camera_link *icl) | ||
1064 | { | ||
1065 | struct i2c_client *client; | ||
1066 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1067 | struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id); | ||
1068 | struct v4l2_subdev *subdev; | ||
1069 | |||
1070 | if (!adap) { | ||
1071 | dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n", | ||
1072 | icl->i2c_adapter_id); | ||
1073 | goto ei2cga; | ||
1074 | } | ||
1075 | |||
1076 | icl->board_info->platform_data = icl; | ||
1077 | |||
1078 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, | ||
1079 | icl->board_info, NULL); | ||
1080 | if (!subdev) | ||
1081 | goto ei2cnd; | ||
1082 | |||
1083 | client = v4l2_get_subdevdata(subdev); | ||
1084 | |||
1085 | /* Use to_i2c_client(dev) to recover the i2c client */ | ||
1086 | icd->control = &client->dev; | ||
1087 | |||
1088 | return 0; | ||
1089 | ei2cnd: | ||
1090 | i2c_put_adapter(adap); | ||
1091 | ei2cga: | ||
1092 | return -ENODEV; | ||
1093 | } | ||
1094 | |||
1095 | static void soc_camera_free_i2c(struct soc_camera_device *icd) | ||
1096 | { | ||
1097 | struct i2c_client *client = | ||
1098 | to_i2c_client(to_soc_camera_control(icd)); | ||
1099 | struct i2c_adapter *adap = client->adapter; | ||
1100 | |||
1101 | icd->control = NULL; | ||
1102 | v4l2_device_unregister_subdev(i2c_get_clientdata(client)); | ||
1103 | i2c_unregister_device(client); | ||
1104 | i2c_put_adapter(adap); | ||
1105 | } | ||
1106 | #else | ||
1107 | #define soc_camera_init_i2c(icd, icl) (-ENODEV) | ||
1108 | #define soc_camera_free_i2c(icd) do {} while (0) | ||
1109 | #endif | ||
1110 | |||
1111 | static int soc_camera_video_start(struct soc_camera_device *icd); | ||
1112 | static int video_dev_create(struct soc_camera_device *icd); | ||
1113 | /* Called during host-driver probe */ | ||
1114 | static int soc_camera_probe(struct soc_camera_device *icd) | ||
1115 | { | ||
1116 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1117 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
1118 | struct device *control = NULL; | ||
1119 | struct v4l2_subdev *sd; | ||
1120 | struct v4l2_mbus_framefmt mf; | ||
1121 | int ret; | ||
1122 | |||
1123 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); | ||
1124 | |||
1125 | /* | ||
1126 | * Currently the subdev with the largest number of controls (13) is | ||
1127 | * ov6550. So let's pick 16 as a hint for the control handler. Note | ||
1128 | * that this is a hint only: too large and you waste some memory, too | ||
1129 | * small and there is a (very) small performance hit when looking up | ||
1130 | * controls in the internal hash. | ||
1131 | */ | ||
1132 | ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); | ||
1133 | if (ret < 0) | ||
1134 | return ret; | ||
1135 | |||
1136 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, | ||
1137 | icl->regulators); | ||
1138 | if (ret < 0) | ||
1139 | goto ereg; | ||
1140 | |||
1141 | /* The camera could have been already on, try to reset */ | ||
1142 | if (icl->reset) | ||
1143 | icl->reset(icd->pdev); | ||
1144 | |||
1145 | ret = ici->ops->add(icd); | ||
1146 | if (ret < 0) | ||
1147 | goto eadd; | ||
1148 | |||
1149 | /* Must have icd->vdev before registering the device */ | ||
1150 | ret = video_dev_create(icd); | ||
1151 | if (ret < 0) | ||
1152 | goto evdc; | ||
1153 | |||
1154 | /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ | ||
1155 | if (icl->board_info) { | ||
1156 | ret = soc_camera_init_i2c(icd, icl); | ||
1157 | if (ret < 0) | ||
1158 | goto eadddev; | ||
1159 | } else if (!icl->add_device || !icl->del_device) { | ||
1160 | ret = -EINVAL; | ||
1161 | goto eadddev; | ||
1162 | } else { | ||
1163 | if (icl->module_name) | ||
1164 | ret = request_module(icl->module_name); | ||
1165 | |||
1166 | ret = icl->add_device(icd); | ||
1167 | if (ret < 0) | ||
1168 | goto eadddev; | ||
1169 | |||
1170 | /* | ||
1171 | * FIXME: this is racy, have to use driver-binding notification, | ||
1172 | * when it is available | ||
1173 | */ | ||
1174 | control = to_soc_camera_control(icd); | ||
1175 | if (!control || !control->driver || !dev_get_drvdata(control) || | ||
1176 | !try_module_get(control->driver->owner)) { | ||
1177 | icl->del_device(icd); | ||
1178 | ret = -ENODEV; | ||
1179 | goto enodrv; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | sd = soc_camera_to_subdev(icd); | ||
1184 | sd->grp_id = soc_camera_grp_id(icd); | ||
1185 | v4l2_set_subdev_hostdata(sd, icd); | ||
1186 | |||
1187 | if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL)) | ||
1188 | goto ectrl; | ||
1189 | |||
1190 | /* At this point client .probe() should have run already */ | ||
1191 | ret = soc_camera_init_user_formats(icd); | ||
1192 | if (ret < 0) | ||
1193 | goto eiufmt; | ||
1194 | |||
1195 | icd->field = V4L2_FIELD_ANY; | ||
1196 | |||
1197 | /* | ||
1198 | * ..._video_start() will create a device node, video_register_device() | ||
1199 | * itself is protected against concurrent open() calls, but we also have | ||
1200 | * to protect our data. | ||
1201 | */ | ||
1202 | mutex_lock(&icd->video_lock); | ||
1203 | |||
1204 | ret = soc_camera_video_start(icd); | ||
1205 | if (ret < 0) | ||
1206 | goto evidstart; | ||
1207 | |||
1208 | /* Try to improve our guess of a reasonable window format */ | ||
1209 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { | ||
1210 | icd->user_width = mf.width; | ||
1211 | icd->user_height = mf.height; | ||
1212 | icd->colorspace = mf.colorspace; | ||
1213 | icd->field = mf.field; | ||
1214 | } | ||
1215 | |||
1216 | ici->ops->remove(icd); | ||
1217 | |||
1218 | mutex_unlock(&icd->video_lock); | ||
1219 | |||
1220 | return 0; | ||
1221 | |||
1222 | evidstart: | ||
1223 | mutex_unlock(&icd->video_lock); | ||
1224 | soc_camera_free_user_formats(icd); | ||
1225 | eiufmt: | ||
1226 | ectrl: | ||
1227 | if (icl->board_info) { | ||
1228 | soc_camera_free_i2c(icd); | ||
1229 | } else { | ||
1230 | icl->del_device(icd); | ||
1231 | module_put(control->driver->owner); | ||
1232 | } | ||
1233 | enodrv: | ||
1234 | eadddev: | ||
1235 | video_device_release(icd->vdev); | ||
1236 | icd->vdev = NULL; | ||
1237 | evdc: | ||
1238 | ici->ops->remove(icd); | ||
1239 | eadd: | ||
1240 | regulator_bulk_free(icl->num_regulators, icl->regulators); | ||
1241 | ereg: | ||
1242 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
1243 | return ret; | ||
1244 | } | ||
1245 | |||
1246 | /* | ||
1247 | * This is called on device_unregister, which only means we have to disconnect | ||
1248 | * from the host, but not remove ourselves from the device list | ||
1249 | */ | ||
1250 | static int soc_camera_remove(struct soc_camera_device *icd) | ||
1251 | { | ||
1252 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
1253 | struct video_device *vdev = icd->vdev; | ||
1254 | |||
1255 | BUG_ON(!icd->parent); | ||
1256 | |||
1257 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
1258 | if (vdev) { | ||
1259 | video_unregister_device(vdev); | ||
1260 | icd->vdev = NULL; | ||
1261 | } | ||
1262 | |||
1263 | if (icl->board_info) { | ||
1264 | soc_camera_free_i2c(icd); | ||
1265 | } else { | ||
1266 | struct device_driver *drv = to_soc_camera_control(icd)->driver; | ||
1267 | if (drv) { | ||
1268 | icl->del_device(icd); | ||
1269 | module_put(drv->owner); | ||
1270 | } | ||
1271 | } | ||
1272 | soc_camera_free_user_formats(icd); | ||
1273 | |||
1274 | regulator_bulk_free(icl->num_regulators, icl->regulators); | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | static int default_cropcap(struct soc_camera_device *icd, | ||
1280 | struct v4l2_cropcap *a) | ||
1281 | { | ||
1282 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1283 | return v4l2_subdev_call(sd, video, cropcap, a); | ||
1284 | } | ||
1285 | |||
1286 | static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a) | ||
1287 | { | ||
1288 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1289 | return v4l2_subdev_call(sd, video, g_crop, a); | ||
1290 | } | ||
1291 | |||
1292 | static int default_s_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) | ||
1293 | { | ||
1294 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1295 | return v4l2_subdev_call(sd, video, s_crop, a); | ||
1296 | } | ||
1297 | |||
1298 | static int default_g_parm(struct soc_camera_device *icd, | ||
1299 | struct v4l2_streamparm *parm) | ||
1300 | { | ||
1301 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1302 | return v4l2_subdev_call(sd, video, g_parm, parm); | ||
1303 | } | ||
1304 | |||
1305 | static int default_s_parm(struct soc_camera_device *icd, | ||
1306 | struct v4l2_streamparm *parm) | ||
1307 | { | ||
1308 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1309 | return v4l2_subdev_call(sd, video, s_parm, parm); | ||
1310 | } | ||
1311 | |||
1312 | static int default_enum_framesizes(struct soc_camera_device *icd, | ||
1313 | struct v4l2_frmsizeenum *fsize) | ||
1314 | { | ||
1315 | int ret; | ||
1316 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1317 | const struct soc_camera_format_xlate *xlate; | ||
1318 | __u32 pixfmt = fsize->pixel_format; | ||
1319 | struct v4l2_frmsizeenum fsize_mbus = *fsize; | ||
1320 | |||
1321 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1322 | if (!xlate) | ||
1323 | return -EINVAL; | ||
1324 | /* map xlate-code to pixel_format, sensor only handle xlate-code*/ | ||
1325 | fsize_mbus.pixel_format = xlate->code; | ||
1326 | |||
1327 | ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus); | ||
1328 | if (ret < 0) | ||
1329 | return ret; | ||
1330 | |||
1331 | *fsize = fsize_mbus; | ||
1332 | fsize->pixel_format = pixfmt; | ||
1333 | |||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | int soc_camera_host_register(struct soc_camera_host *ici) | ||
1338 | { | ||
1339 | struct soc_camera_host *ix; | ||
1340 | int ret; | ||
1341 | |||
1342 | if (!ici || !ici->ops || | ||
1343 | !ici->ops->try_fmt || | ||
1344 | !ici->ops->set_fmt || | ||
1345 | !ici->ops->set_bus_param || | ||
1346 | !ici->ops->querycap || | ||
1347 | ((!ici->ops->init_videobuf || | ||
1348 | !ici->ops->reqbufs) && | ||
1349 | !ici->ops->init_videobuf2) || | ||
1350 | !ici->ops->add || | ||
1351 | !ici->ops->remove || | ||
1352 | !ici->ops->poll || | ||
1353 | !ici->v4l2_dev.dev) | ||
1354 | return -EINVAL; | ||
1355 | |||
1356 | if (!ici->ops->set_crop) | ||
1357 | ici->ops->set_crop = default_s_crop; | ||
1358 | if (!ici->ops->get_crop) | ||
1359 | ici->ops->get_crop = default_g_crop; | ||
1360 | if (!ici->ops->cropcap) | ||
1361 | ici->ops->cropcap = default_cropcap; | ||
1362 | if (!ici->ops->set_parm) | ||
1363 | ici->ops->set_parm = default_s_parm; | ||
1364 | if (!ici->ops->get_parm) | ||
1365 | ici->ops->get_parm = default_g_parm; | ||
1366 | if (!ici->ops->enum_framesizes) | ||
1367 | ici->ops->enum_framesizes = default_enum_framesizes; | ||
1368 | |||
1369 | mutex_lock(&list_lock); | ||
1370 | list_for_each_entry(ix, &hosts, list) { | ||
1371 | if (ix->nr == ici->nr) { | ||
1372 | ret = -EBUSY; | ||
1373 | goto edevreg; | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev); | ||
1378 | if (ret < 0) | ||
1379 | goto edevreg; | ||
1380 | |||
1381 | list_add_tail(&ici->list, &hosts); | ||
1382 | mutex_unlock(&list_lock); | ||
1383 | |||
1384 | mutex_init(&ici->host_lock); | ||
1385 | scan_add_host(ici); | ||
1386 | |||
1387 | return 0; | ||
1388 | |||
1389 | edevreg: | ||
1390 | mutex_unlock(&list_lock); | ||
1391 | return ret; | ||
1392 | } | ||
1393 | EXPORT_SYMBOL(soc_camera_host_register); | ||
1394 | |||
1395 | /* Unregister all clients! */ | ||
1396 | void soc_camera_host_unregister(struct soc_camera_host *ici) | ||
1397 | { | ||
1398 | struct soc_camera_device *icd; | ||
1399 | |||
1400 | mutex_lock(&list_lock); | ||
1401 | |||
1402 | list_del(&ici->list); | ||
1403 | list_for_each_entry(icd, &devices, list) | ||
1404 | if (icd->iface == ici->nr && to_soc_camera_control(icd)) | ||
1405 | soc_camera_remove(icd); | ||
1406 | |||
1407 | mutex_unlock(&list_lock); | ||
1408 | |||
1409 | v4l2_device_unregister(&ici->v4l2_dev); | ||
1410 | } | ||
1411 | EXPORT_SYMBOL(soc_camera_host_unregister); | ||
1412 | |||
1413 | /* Image capture device */ | ||
1414 | static int soc_camera_device_register(struct soc_camera_device *icd) | ||
1415 | { | ||
1416 | struct soc_camera_device *ix; | ||
1417 | int num = -1, i; | ||
1418 | |||
1419 | for (i = 0; i < 256 && num < 0; i++) { | ||
1420 | num = i; | ||
1421 | /* Check if this index is available on this interface */ | ||
1422 | list_for_each_entry(ix, &devices, list) { | ||
1423 | if (ix->iface == icd->iface && ix->devnum == i) { | ||
1424 | num = -1; | ||
1425 | break; | ||
1426 | } | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | if (num < 0) | ||
1431 | /* | ||
1432 | * ok, we have 256 cameras on this host... | ||
1433 | * man, stay reasonable... | ||
1434 | */ | ||
1435 | return -ENOMEM; | ||
1436 | |||
1437 | icd->devnum = num; | ||
1438 | icd->use_count = 0; | ||
1439 | icd->host_priv = NULL; | ||
1440 | mutex_init(&icd->video_lock); | ||
1441 | |||
1442 | list_add_tail(&icd->list, &devices); | ||
1443 | |||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1447 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | ||
1448 | .vidioc_querycap = soc_camera_querycap, | ||
1449 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | ||
1450 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, | ||
1451 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, | ||
1452 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | ||
1453 | .vidioc_enum_input = soc_camera_enum_input, | ||
1454 | .vidioc_g_input = soc_camera_g_input, | ||
1455 | .vidioc_s_input = soc_camera_s_input, | ||
1456 | .vidioc_s_std = soc_camera_s_std, | ||
1457 | .vidioc_g_std = soc_camera_g_std, | ||
1458 | .vidioc_enum_framesizes = soc_camera_enum_framesizes, | ||
1459 | .vidioc_reqbufs = soc_camera_reqbufs, | ||
1460 | .vidioc_querybuf = soc_camera_querybuf, | ||
1461 | .vidioc_qbuf = soc_camera_qbuf, | ||
1462 | .vidioc_dqbuf = soc_camera_dqbuf, | ||
1463 | .vidioc_create_bufs = soc_camera_create_bufs, | ||
1464 | .vidioc_prepare_buf = soc_camera_prepare_buf, | ||
1465 | .vidioc_streamon = soc_camera_streamon, | ||
1466 | .vidioc_streamoff = soc_camera_streamoff, | ||
1467 | .vidioc_cropcap = soc_camera_cropcap, | ||
1468 | .vidioc_g_crop = soc_camera_g_crop, | ||
1469 | .vidioc_s_crop = soc_camera_s_crop, | ||
1470 | .vidioc_g_selection = soc_camera_g_selection, | ||
1471 | .vidioc_s_selection = soc_camera_s_selection, | ||
1472 | .vidioc_g_parm = soc_camera_g_parm, | ||
1473 | .vidioc_s_parm = soc_camera_s_parm, | ||
1474 | .vidioc_g_chip_ident = soc_camera_g_chip_ident, | ||
1475 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1476 | .vidioc_g_register = soc_camera_g_register, | ||
1477 | .vidioc_s_register = soc_camera_s_register, | ||
1478 | #endif | ||
1479 | }; | ||
1480 | |||
1481 | static int video_dev_create(struct soc_camera_device *icd) | ||
1482 | { | ||
1483 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1484 | struct video_device *vdev = video_device_alloc(); | ||
1485 | |||
1486 | if (!vdev) | ||
1487 | return -ENOMEM; | ||
1488 | |||
1489 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | ||
1490 | |||
1491 | vdev->parent = icd->pdev; | ||
1492 | vdev->current_norm = V4L2_STD_UNKNOWN; | ||
1493 | vdev->fops = &soc_camera_fops; | ||
1494 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | ||
1495 | vdev->release = video_device_release; | ||
1496 | vdev->tvnorms = V4L2_STD_UNKNOWN; | ||
1497 | vdev->ctrl_handler = &icd->ctrl_handler; | ||
1498 | vdev->lock = &icd->video_lock; | ||
1499 | |||
1500 | icd->vdev = vdev; | ||
1501 | |||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | /* | ||
1506 | * Called from soc_camera_probe() above (with .video_lock held???) | ||
1507 | */ | ||
1508 | static int soc_camera_video_start(struct soc_camera_device *icd) | ||
1509 | { | ||
1510 | const struct device_type *type = icd->vdev->dev.type; | ||
1511 | int ret; | ||
1512 | |||
1513 | if (!icd->parent) | ||
1514 | return -ENODEV; | ||
1515 | |||
1516 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); | ||
1517 | if (ret < 0) { | ||
1518 | dev_err(icd->pdev, "video_register_device failed: %d\n", ret); | ||
1519 | return ret; | ||
1520 | } | ||
1521 | |||
1522 | /* Restore device type, possibly set by the subdevice driver */ | ||
1523 | icd->vdev->dev.type = type; | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) | ||
1529 | { | ||
1530 | struct soc_camera_link *icl = pdev->dev.platform_data; | ||
1531 | struct soc_camera_device *icd; | ||
1532 | int ret; | ||
1533 | |||
1534 | if (!icl) | ||
1535 | return -EINVAL; | ||
1536 | |||
1537 | icd = kzalloc(sizeof(*icd), GFP_KERNEL); | ||
1538 | if (!icd) | ||
1539 | return -ENOMEM; | ||
1540 | |||
1541 | icd->iface = icl->bus_id; | ||
1542 | icd->link = icl; | ||
1543 | icd->pdev = &pdev->dev; | ||
1544 | platform_set_drvdata(pdev, icd); | ||
1545 | |||
1546 | ret = soc_camera_device_register(icd); | ||
1547 | if (ret < 0) | ||
1548 | goto escdevreg; | ||
1549 | |||
1550 | icd->user_width = DEFAULT_WIDTH; | ||
1551 | icd->user_height = DEFAULT_HEIGHT; | ||
1552 | |||
1553 | return 0; | ||
1554 | |||
1555 | escdevreg: | ||
1556 | kfree(icd); | ||
1557 | |||
1558 | return ret; | ||
1559 | } | ||
1560 | |||
1561 | /* | ||
1562 | * Only called on rmmod for each platform device, since they are not | ||
1563 | * hot-pluggable. Now we know, that all our users - hosts and devices have | ||
1564 | * been unloaded already | ||
1565 | */ | ||
1566 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | ||
1567 | { | ||
1568 | struct soc_camera_device *icd = platform_get_drvdata(pdev); | ||
1569 | |||
1570 | if (!icd) | ||
1571 | return -EINVAL; | ||
1572 | |||
1573 | list_del(&icd->list); | ||
1574 | |||
1575 | kfree(icd); | ||
1576 | |||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | static struct platform_driver __refdata soc_camera_pdrv = { | ||
1581 | .probe = soc_camera_pdrv_probe, | ||
1582 | .remove = __devexit_p(soc_camera_pdrv_remove), | ||
1583 | .driver = { | ||
1584 | .name = "soc-camera-pdrv", | ||
1585 | .owner = THIS_MODULE, | ||
1586 | }, | ||
1587 | }; | ||
1588 | |||
1589 | static int __init soc_camera_init(void) | ||
1590 | { | ||
1591 | return platform_driver_register(&soc_camera_pdrv); | ||
1592 | } | ||
1593 | |||
1594 | static void __exit soc_camera_exit(void) | ||
1595 | { | ||
1596 | platform_driver_unregister(&soc_camera_pdrv); | ||
1597 | } | ||
1598 | |||
1599 | module_init(soc_camera_init); | ||
1600 | module_exit(soc_camera_exit); | ||
1601 | |||
1602 | MODULE_DESCRIPTION("Image capture bus driver"); | ||
1603 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | ||
1604 | MODULE_LICENSE("GPL"); | ||
1605 | MODULE_ALIAS("platform:soc-camera-pdrv"); | ||
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c new file mode 100644 index 000000000000..7cf7fd16481f --- /dev/null +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Generic Platform Camera Driver | ||
3 | * | ||
4 | * Copyright (C) 2008 Magnus Damm | ||
5 | * Based on mt9m001 driver, | ||
6 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/videodev2.h> | ||
19 | #include <media/v4l2-subdev.h> | ||
20 | #include <media/soc_camera.h> | ||
21 | #include <media/soc_camera_platform.h> | ||
22 | |||
23 | struct soc_camera_platform_priv { | ||
24 | struct v4l2_subdev subdev; | ||
25 | }; | ||
26 | |||
27 | static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) | ||
28 | { | ||
29 | struct v4l2_subdev *subdev = platform_get_drvdata(pdev); | ||
30 | return container_of(subdev, struct soc_camera_platform_priv, subdev); | ||
31 | } | ||
32 | |||
33 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) | ||
34 | { | ||
35 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
36 | return p->set_capture(p, enable); | ||
37 | } | ||
38 | |||
39 | static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, | ||
40 | struct v4l2_mbus_framefmt *mf) | ||
41 | { | ||
42 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
43 | |||
44 | mf->width = p->format.width; | ||
45 | mf->height = p->format.height; | ||
46 | mf->code = p->format.code; | ||
47 | mf->colorspace = p->format.colorspace; | ||
48 | mf->field = p->format.field; | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on) | ||
54 | { | ||
55 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
56 | |||
57 | return soc_camera_set_power(p->icd->control, p->icd->link, on); | ||
58 | } | ||
59 | |||
60 | static struct v4l2_subdev_core_ops platform_subdev_core_ops = { | ||
61 | .s_power = soc_camera_platform_s_power, | ||
62 | }; | ||
63 | |||
64 | static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | ||
65 | enum v4l2_mbus_pixelcode *code) | ||
66 | { | ||
67 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
68 | |||
69 | if (index) | ||
70 | return -EINVAL; | ||
71 | |||
72 | *code = p->format.code; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int soc_camera_platform_g_crop(struct v4l2_subdev *sd, | ||
77 | struct v4l2_crop *a) | ||
78 | { | ||
79 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
80 | |||
81 | a->c.left = 0; | ||
82 | a->c.top = 0; | ||
83 | a->c.width = p->format.width; | ||
84 | a->c.height = p->format.height; | ||
85 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, | ||
91 | struct v4l2_cropcap *a) | ||
92 | { | ||
93 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
94 | |||
95 | a->bounds.left = 0; | ||
96 | a->bounds.top = 0; | ||
97 | a->bounds.width = p->format.width; | ||
98 | a->bounds.height = p->format.height; | ||
99 | a->defrect = a->bounds; | ||
100 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
101 | a->pixelaspect.numerator = 1; | ||
102 | a->pixelaspect.denominator = 1; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, | ||
108 | struct v4l2_mbus_config *cfg) | ||
109 | { | ||
110 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
111 | |||
112 | cfg->flags = p->mbus_param; | ||
113 | cfg->type = p->mbus_type; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | ||
119 | .s_stream = soc_camera_platform_s_stream, | ||
120 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, | ||
121 | .cropcap = soc_camera_platform_cropcap, | ||
122 | .g_crop = soc_camera_platform_g_crop, | ||
123 | .try_mbus_fmt = soc_camera_platform_fill_fmt, | ||
124 | .g_mbus_fmt = soc_camera_platform_fill_fmt, | ||
125 | .s_mbus_fmt = soc_camera_platform_fill_fmt, | ||
126 | .g_mbus_config = soc_camera_platform_g_mbus_config, | ||
127 | }; | ||
128 | |||
129 | static struct v4l2_subdev_ops platform_subdev_ops = { | ||
130 | .core = &platform_subdev_core_ops, | ||
131 | .video = &platform_subdev_video_ops, | ||
132 | }; | ||
133 | |||
134 | static int soc_camera_platform_probe(struct platform_device *pdev) | ||
135 | { | ||
136 | struct soc_camera_host *ici; | ||
137 | struct soc_camera_platform_priv *priv; | ||
138 | struct soc_camera_platform_info *p = pdev->dev.platform_data; | ||
139 | struct soc_camera_device *icd; | ||
140 | int ret; | ||
141 | |||
142 | if (!p) | ||
143 | return -EINVAL; | ||
144 | |||
145 | if (!p->icd) { | ||
146 | dev_err(&pdev->dev, | ||
147 | "Platform has not set soc_camera_device pointer!\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
152 | if (!priv) | ||
153 | return -ENOMEM; | ||
154 | |||
155 | icd = p->icd; | ||
156 | |||
157 | /* soc-camera convention: control's drvdata points to the subdev */ | ||
158 | platform_set_drvdata(pdev, &priv->subdev); | ||
159 | /* Set the control device reference */ | ||
160 | icd->control = &pdev->dev; | ||
161 | |||
162 | ici = to_soc_camera_host(icd->parent); | ||
163 | |||
164 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); | ||
165 | v4l2_set_subdevdata(&priv->subdev, p); | ||
166 | strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); | ||
167 | |||
168 | ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev); | ||
169 | if (ret) | ||
170 | goto evdrs; | ||
171 | |||
172 | return ret; | ||
173 | |||
174 | evdrs: | ||
175 | platform_set_drvdata(pdev, NULL); | ||
176 | kfree(priv); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static int soc_camera_platform_remove(struct platform_device *pdev) | ||
181 | { | ||
182 | struct soc_camera_platform_priv *priv = get_priv(pdev); | ||
183 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); | ||
184 | |||
185 | p->icd->control = NULL; | ||
186 | v4l2_device_unregister_subdev(&priv->subdev); | ||
187 | platform_set_drvdata(pdev, NULL); | ||
188 | kfree(priv); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static struct platform_driver soc_camera_platform_driver = { | ||
193 | .driver = { | ||
194 | .name = "soc_camera_platform", | ||
195 | .owner = THIS_MODULE, | ||
196 | }, | ||
197 | .probe = soc_camera_platform_probe, | ||
198 | .remove = soc_camera_platform_remove, | ||
199 | }; | ||
200 | |||
201 | module_platform_driver(soc_camera_platform_driver); | ||
202 | |||
203 | MODULE_DESCRIPTION("SoC Camera Platform driver"); | ||
204 | MODULE_AUTHOR("Magnus Damm"); | ||
205 | MODULE_LICENSE("GPL v2"); | ||
206 | MODULE_ALIAS("platform:soc_camera_platform"); | ||
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c new file mode 100644 index 000000000000..a397812635d6 --- /dev/null +++ b/drivers/media/platform/soc_camera/soc_mediabus.c | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * soc-camera media bus helper routines | ||
3 | * | ||
4 | * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include <media/v4l2-device.h> | ||
15 | #include <media/v4l2-mediabus.h> | ||
16 | #include <media/soc_mediabus.h> | ||
17 | |||
18 | static const struct soc_mbus_lookup mbus_fmt[] = { | ||
19 | { | ||
20 | .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
21 | .fmt = { | ||
22 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
23 | .name = "YUYV", | ||
24 | .bits_per_sample = 8, | ||
25 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
26 | .order = SOC_MBUS_ORDER_LE, | ||
27 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
28 | }, | ||
29 | }, { | ||
30 | .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
31 | .fmt = { | ||
32 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
33 | .name = "YVYU", | ||
34 | .bits_per_sample = 8, | ||
35 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
36 | .order = SOC_MBUS_ORDER_LE, | ||
37 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
38 | }, | ||
39 | }, { | ||
40 | .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
41 | .fmt = { | ||
42 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
43 | .name = "UYVY", | ||
44 | .bits_per_sample = 8, | ||
45 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
46 | .order = SOC_MBUS_ORDER_LE, | ||
47 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
48 | }, | ||
49 | }, { | ||
50 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
51 | .fmt = { | ||
52 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
53 | .name = "VYUY", | ||
54 | .bits_per_sample = 8, | ||
55 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
56 | .order = SOC_MBUS_ORDER_LE, | ||
57 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
58 | }, | ||
59 | }, { | ||
60 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
61 | .fmt = { | ||
62 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
63 | .name = "RGB555", | ||
64 | .bits_per_sample = 8, | ||
65 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
66 | .order = SOC_MBUS_ORDER_LE, | ||
67 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
68 | }, | ||
69 | }, { | ||
70 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, | ||
71 | .fmt = { | ||
72 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
73 | .name = "RGB555X", | ||
74 | .bits_per_sample = 8, | ||
75 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
76 | .order = SOC_MBUS_ORDER_LE, | ||
77 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
78 | }, | ||
79 | }, { | ||
80 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
81 | .fmt = { | ||
82 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
83 | .name = "RGB565", | ||
84 | .bits_per_sample = 8, | ||
85 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
86 | .order = SOC_MBUS_ORDER_LE, | ||
87 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
88 | }, | ||
89 | }, { | ||
90 | .code = V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
91 | .fmt = { | ||
92 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
93 | .name = "RGB565X", | ||
94 | .bits_per_sample = 8, | ||
95 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
96 | .order = SOC_MBUS_ORDER_LE, | ||
97 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
98 | }, | ||
99 | }, { | ||
100 | .code = V4L2_MBUS_FMT_SBGGR8_1X8, | ||
101 | .fmt = { | ||
102 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
103 | .name = "Bayer 8 BGGR", | ||
104 | .bits_per_sample = 8, | ||
105 | .packing = SOC_MBUS_PACKING_NONE, | ||
106 | .order = SOC_MBUS_ORDER_LE, | ||
107 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
108 | }, | ||
109 | }, { | ||
110 | .code = V4L2_MBUS_FMT_SBGGR10_1X10, | ||
111 | .fmt = { | ||
112 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
113 | .name = "Bayer 10 BGGR", | ||
114 | .bits_per_sample = 10, | ||
115 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
116 | .order = SOC_MBUS_ORDER_LE, | ||
117 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
118 | }, | ||
119 | }, { | ||
120 | .code = V4L2_MBUS_FMT_Y8_1X8, | ||
121 | .fmt = { | ||
122 | .fourcc = V4L2_PIX_FMT_GREY, | ||
123 | .name = "Grey", | ||
124 | .bits_per_sample = 8, | ||
125 | .packing = SOC_MBUS_PACKING_NONE, | ||
126 | .order = SOC_MBUS_ORDER_LE, | ||
127 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
128 | }, | ||
129 | }, { | ||
130 | .code = V4L2_MBUS_FMT_Y10_1X10, | ||
131 | .fmt = { | ||
132 | .fourcc = V4L2_PIX_FMT_Y10, | ||
133 | .name = "Grey 10bit", | ||
134 | .bits_per_sample = 10, | ||
135 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
136 | .order = SOC_MBUS_ORDER_LE, | ||
137 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
138 | }, | ||
139 | }, { | ||
140 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, | ||
141 | .fmt = { | ||
142 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
143 | .name = "Bayer 10 BGGR", | ||
144 | .bits_per_sample = 8, | ||
145 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
146 | .order = SOC_MBUS_ORDER_LE, | ||
147 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
148 | }, | ||
149 | }, { | ||
150 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, | ||
151 | .fmt = { | ||
152 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
153 | .name = "Bayer 10 BGGR", | ||
154 | .bits_per_sample = 8, | ||
155 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | ||
156 | .order = SOC_MBUS_ORDER_LE, | ||
157 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
158 | }, | ||
159 | }, { | ||
160 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, | ||
161 | .fmt = { | ||
162 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
163 | .name = "Bayer 10 BGGR", | ||
164 | .bits_per_sample = 8, | ||
165 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
166 | .order = SOC_MBUS_ORDER_BE, | ||
167 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
168 | }, | ||
169 | }, { | ||
170 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, | ||
171 | .fmt = { | ||
172 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
173 | .name = "Bayer 10 BGGR", | ||
174 | .bits_per_sample = 8, | ||
175 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | ||
176 | .order = SOC_MBUS_ORDER_BE, | ||
177 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
178 | }, | ||
179 | }, { | ||
180 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
181 | .fmt = { | ||
182 | .fourcc = V4L2_PIX_FMT_JPEG, | ||
183 | .name = "JPEG", | ||
184 | .bits_per_sample = 8, | ||
185 | .packing = SOC_MBUS_PACKING_VARIABLE, | ||
186 | .order = SOC_MBUS_ORDER_LE, | ||
187 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
188 | }, | ||
189 | }, { | ||
190 | .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE, | ||
191 | .fmt = { | ||
192 | .fourcc = V4L2_PIX_FMT_RGB444, | ||
193 | .name = "RGB444", | ||
194 | .bits_per_sample = 8, | ||
195 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
196 | .order = SOC_MBUS_ORDER_BE, | ||
197 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
198 | }, | ||
199 | }, { | ||
200 | .code = V4L2_MBUS_FMT_YUYV8_1_5X8, | ||
201 | .fmt = { | ||
202 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
203 | .name = "YUYV 4:2:0", | ||
204 | .bits_per_sample = 8, | ||
205 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
206 | .order = SOC_MBUS_ORDER_LE, | ||
207 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
208 | }, | ||
209 | }, { | ||
210 | .code = V4L2_MBUS_FMT_YVYU8_1_5X8, | ||
211 | .fmt = { | ||
212 | .fourcc = V4L2_PIX_FMT_YVU420, | ||
213 | .name = "YVYU 4:2:0", | ||
214 | .bits_per_sample = 8, | ||
215 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
216 | .order = SOC_MBUS_ORDER_LE, | ||
217 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
218 | }, | ||
219 | }, { | ||
220 | .code = V4L2_MBUS_FMT_UYVY8_1X16, | ||
221 | .fmt = { | ||
222 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
223 | .name = "UYVY 16bit", | ||
224 | .bits_per_sample = 16, | ||
225 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
226 | .order = SOC_MBUS_ORDER_LE, | ||
227 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
228 | }, | ||
229 | }, { | ||
230 | .code = V4L2_MBUS_FMT_VYUY8_1X16, | ||
231 | .fmt = { | ||
232 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
233 | .name = "VYUY 16bit", | ||
234 | .bits_per_sample = 16, | ||
235 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
236 | .order = SOC_MBUS_ORDER_LE, | ||
237 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
238 | }, | ||
239 | }, { | ||
240 | .code = V4L2_MBUS_FMT_YUYV8_1X16, | ||
241 | .fmt = { | ||
242 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
243 | .name = "YUYV 16bit", | ||
244 | .bits_per_sample = 16, | ||
245 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
246 | .order = SOC_MBUS_ORDER_LE, | ||
247 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
248 | }, | ||
249 | }, { | ||
250 | .code = V4L2_MBUS_FMT_YVYU8_1X16, | ||
251 | .fmt = { | ||
252 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
253 | .name = "YVYU 16bit", | ||
254 | .bits_per_sample = 16, | ||
255 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
256 | .order = SOC_MBUS_ORDER_LE, | ||
257 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
258 | }, | ||
259 | }, { | ||
260 | .code = V4L2_MBUS_FMT_SGRBG8_1X8, | ||
261 | .fmt = { | ||
262 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
263 | .name = "Bayer 8 GRBG", | ||
264 | .bits_per_sample = 8, | ||
265 | .packing = SOC_MBUS_PACKING_NONE, | ||
266 | .order = SOC_MBUS_ORDER_LE, | ||
267 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
268 | }, | ||
269 | }, { | ||
270 | .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, | ||
271 | .fmt = { | ||
272 | .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
273 | .name = "Bayer 10 BGGR DPCM 8", | ||
274 | .bits_per_sample = 8, | ||
275 | .packing = SOC_MBUS_PACKING_NONE, | ||
276 | .order = SOC_MBUS_ORDER_LE, | ||
277 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
278 | }, | ||
279 | }, { | ||
280 | .code = V4L2_MBUS_FMT_SGBRG10_1X10, | ||
281 | .fmt = { | ||
282 | .fourcc = V4L2_PIX_FMT_SGBRG10, | ||
283 | .name = "Bayer 10 GBRG", | ||
284 | .bits_per_sample = 10, | ||
285 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
286 | .order = SOC_MBUS_ORDER_LE, | ||
287 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
288 | }, | ||
289 | }, { | ||
290 | .code = V4L2_MBUS_FMT_SGRBG10_1X10, | ||
291 | .fmt = { | ||
292 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
293 | .name = "Bayer 10 GRBG", | ||
294 | .bits_per_sample = 10, | ||
295 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
296 | .order = SOC_MBUS_ORDER_LE, | ||
297 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
298 | }, | ||
299 | }, { | ||
300 | .code = V4L2_MBUS_FMT_SRGGB10_1X10, | ||
301 | .fmt = { | ||
302 | .fourcc = V4L2_PIX_FMT_SRGGB10, | ||
303 | .name = "Bayer 10 RGGB", | ||
304 | .bits_per_sample = 10, | ||
305 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
306 | .order = SOC_MBUS_ORDER_LE, | ||
307 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
308 | }, | ||
309 | }, { | ||
310 | .code = V4L2_MBUS_FMT_SBGGR12_1X12, | ||
311 | .fmt = { | ||
312 | .fourcc = V4L2_PIX_FMT_SBGGR12, | ||
313 | .name = "Bayer 12 BGGR", | ||
314 | .bits_per_sample = 12, | ||
315 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
316 | .order = SOC_MBUS_ORDER_LE, | ||
317 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
318 | }, | ||
319 | }, { | ||
320 | .code = V4L2_MBUS_FMT_SGBRG12_1X12, | ||
321 | .fmt = { | ||
322 | .fourcc = V4L2_PIX_FMT_SGBRG12, | ||
323 | .name = "Bayer 12 GBRG", | ||
324 | .bits_per_sample = 12, | ||
325 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
326 | .order = SOC_MBUS_ORDER_LE, | ||
327 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
328 | }, | ||
329 | }, { | ||
330 | .code = V4L2_MBUS_FMT_SGRBG12_1X12, | ||
331 | .fmt = { | ||
332 | .fourcc = V4L2_PIX_FMT_SGRBG12, | ||
333 | .name = "Bayer 12 GRBG", | ||
334 | .bits_per_sample = 12, | ||
335 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
336 | .order = SOC_MBUS_ORDER_LE, | ||
337 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
338 | }, | ||
339 | }, { | ||
340 | .code = V4L2_MBUS_FMT_SRGGB12_1X12, | ||
341 | .fmt = { | ||
342 | .fourcc = V4L2_PIX_FMT_SRGGB12, | ||
343 | .name = "Bayer 12 RGGB", | ||
344 | .bits_per_sample = 12, | ||
345 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
346 | .order = SOC_MBUS_ORDER_LE, | ||
347 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
348 | }, | ||
349 | }, | ||
350 | }; | ||
351 | |||
352 | int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, | ||
353 | unsigned int *numerator, unsigned int *denominator) | ||
354 | { | ||
355 | switch (mf->packing) { | ||
356 | case SOC_MBUS_PACKING_NONE: | ||
357 | case SOC_MBUS_PACKING_EXTEND16: | ||
358 | *numerator = 1; | ||
359 | *denominator = 1; | ||
360 | return 0; | ||
361 | case SOC_MBUS_PACKING_2X8_PADHI: | ||
362 | case SOC_MBUS_PACKING_2X8_PADLO: | ||
363 | *numerator = 2; | ||
364 | *denominator = 1; | ||
365 | return 0; | ||
366 | case SOC_MBUS_PACKING_1_5X8: | ||
367 | *numerator = 3; | ||
368 | *denominator = 2; | ||
369 | return 0; | ||
370 | case SOC_MBUS_PACKING_VARIABLE: | ||
371 | *numerator = 0; | ||
372 | *denominator = 1; | ||
373 | return 0; | ||
374 | } | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | EXPORT_SYMBOL(soc_mbus_samples_per_pixel); | ||
378 | |||
379 | s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) | ||
380 | { | ||
381 | if (mf->fourcc == V4L2_PIX_FMT_JPEG) | ||
382 | return 0; | ||
383 | |||
384 | if (mf->layout != SOC_MBUS_LAYOUT_PACKED) | ||
385 | return width * mf->bits_per_sample / 8; | ||
386 | |||
387 | switch (mf->packing) { | ||
388 | case SOC_MBUS_PACKING_NONE: | ||
389 | return width * mf->bits_per_sample / 8; | ||
390 | case SOC_MBUS_PACKING_2X8_PADHI: | ||
391 | case SOC_MBUS_PACKING_2X8_PADLO: | ||
392 | case SOC_MBUS_PACKING_EXTEND16: | ||
393 | return width * 2; | ||
394 | case SOC_MBUS_PACKING_1_5X8: | ||
395 | return width * 3 / 2; | ||
396 | case SOC_MBUS_PACKING_VARIABLE: | ||
397 | return 0; | ||
398 | } | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | EXPORT_SYMBOL(soc_mbus_bytes_per_line); | ||
402 | |||
403 | s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf, | ||
404 | u32 bytes_per_line, u32 height) | ||
405 | { | ||
406 | if (mf->fourcc == V4L2_PIX_FMT_JPEG) | ||
407 | return 0; | ||
408 | |||
409 | if (mf->layout == SOC_MBUS_LAYOUT_PACKED) | ||
410 | return bytes_per_line * height; | ||
411 | |||
412 | switch (mf->packing) { | ||
413 | case SOC_MBUS_PACKING_2X8_PADHI: | ||
414 | case SOC_MBUS_PACKING_2X8_PADLO: | ||
415 | return bytes_per_line * height * 2; | ||
416 | case SOC_MBUS_PACKING_1_5X8: | ||
417 | return bytes_per_line * height * 3 / 2; | ||
418 | default: | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | } | ||
422 | EXPORT_SYMBOL(soc_mbus_image_size); | ||
423 | |||
424 | const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( | ||
425 | enum v4l2_mbus_pixelcode code, | ||
426 | const struct soc_mbus_lookup *lookup, | ||
427 | int n) | ||
428 | { | ||
429 | int i; | ||
430 | |||
431 | for (i = 0; i < n; i++) | ||
432 | if (lookup[i].code == code) | ||
433 | return &lookup[i].fmt; | ||
434 | |||
435 | return NULL; | ||
436 | } | ||
437 | EXPORT_SYMBOL(soc_mbus_find_fmtdesc); | ||
438 | |||
439 | const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | ||
440 | enum v4l2_mbus_pixelcode code) | ||
441 | { | ||
442 | return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); | ||
443 | } | ||
444 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); | ||
445 | |||
446 | unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, | ||
447 | unsigned int flags) | ||
448 | { | ||
449 | unsigned long common_flags; | ||
450 | bool hsync = true, vsync = true, pclk, data, mode; | ||
451 | bool mipi_lanes, mipi_clock; | ||
452 | |||
453 | common_flags = cfg->flags & flags; | ||
454 | |||
455 | switch (cfg->type) { | ||
456 | case V4L2_MBUS_PARALLEL: | ||
457 | hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
458 | V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
459 | vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
460 | V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
461 | case V4L2_MBUS_BT656: | ||
462 | pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
463 | V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
464 | data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
465 | V4L2_MBUS_DATA_ACTIVE_LOW); | ||
466 | mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); | ||
467 | return (!hsync || !vsync || !pclk || !data || !mode) ? | ||
468 | 0 : common_flags; | ||
469 | case V4L2_MBUS_CSI2: | ||
470 | mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; | ||
471 | mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | | ||
472 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); | ||
473 | return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; | ||
474 | } | ||
475 | return 0; | ||
476 | } | ||
477 | EXPORT_SYMBOL(soc_mbus_config_compatible); | ||
478 | |||
479 | static int __init soc_mbus_init(void) | ||
480 | { | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static void __exit soc_mbus_exit(void) | ||
485 | { | ||
486 | } | ||
487 | |||
488 | module_init(soc_mbus_init); | ||
489 | module_exit(soc_mbus_exit); | ||
490 | |||
491 | MODULE_DESCRIPTION("soc-camera media bus interface"); | ||
492 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
493 | MODULE_LICENSE("GPL v2"); | ||