diff options
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/cpia2/cpia2_v4l.c | 4 | ||||
-rw-r--r-- | drivers/media/video/gspca/kinect.c | 2 | ||||
-rw-r--r-- | drivers/media/video/m5mols/Kconfig | 5 | ||||
-rw-r--r-- | drivers/media/video/m5mols/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols.h | 296 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_capture.c | 191 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_controls.c | 299 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_core.c | 1004 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_reg.h | 399 | ||||
-rw-r--r-- | drivers/media/video/uvc/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 66 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_entity.c | 118 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 20 |
15 files changed, 2405 insertions, 12 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 3be180b3ba27..bb53de7fe408 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -687,7 +687,7 @@ config VIDEO_HEXIUM_GEMINI | |||
687 | 687 | ||
688 | config VIDEO_TIMBERDALE | 688 | config VIDEO_TIMBERDALE |
689 | tristate "Support for timberdale Video In/LogiWIN" | 689 | tristate "Support for timberdale Video In/LogiWIN" |
690 | depends on VIDEO_V4L2 && I2C | 690 | depends on VIDEO_V4L2 && I2C && DMADEVICES |
691 | select DMA_ENGINE | 691 | select DMA_ENGINE |
692 | select TIMB_DMA | 692 | select TIMB_DMA |
693 | select VIDEO_ADV7180 | 693 | select VIDEO_ADV7180 |
@@ -757,6 +757,8 @@ config VIDEO_NOON010PC30 | |||
757 | ---help--- | 757 | ---help--- |
758 | This driver supports NOON010PC30 CIF camera from Siliconfile | 758 | This driver supports NOON010PC30 CIF camera from Siliconfile |
759 | 759 | ||
760 | source "drivers/media/video/m5mols/Kconfig" | ||
761 | |||
760 | config VIDEO_OMAP3 | 762 | config VIDEO_OMAP3 |
761 | tristate "OMAP 3 Camera support (EXPERIMENTAL)" | 763 | tristate "OMAP 3 Camera support (EXPERIMENTAL)" |
762 | select OMAP_IOMMU | 764 | select OMAP_IOMMU |
@@ -952,7 +954,7 @@ config VIDEO_SAMSUNG_S5P_FIMC | |||
952 | 954 | ||
953 | config VIDEO_S5P_MIPI_CSIS | 955 | config VIDEO_S5P_MIPI_CSIS |
954 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" | 956 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" |
955 | depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API | 957 | depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API |
956 | ---help--- | 958 | ---help--- |
957 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. | 959 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. |
958 | 960 | ||
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9519160c2e01..f0fecd6f6a33 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | |||
69 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o | 69 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o |
70 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | 70 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o |
71 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 71 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
72 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | ||
72 | 73 | ||
73 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o | 74 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o |
74 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | 75 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o |
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 0073a8c55336..40eb6326e48a 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c | |||
@@ -438,7 +438,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v | |||
438 | strcat(vc->card, " (676/"); | 438 | strcat(vc->card, " (676/"); |
439 | break; | 439 | break; |
440 | default: | 440 | default: |
441 | strcat(vc->card, " (???/"); | 441 | strcat(vc->card, " (XXX/"); |
442 | break; | 442 | break; |
443 | } | 443 | } |
444 | switch (cam->params.version.sensor_flags) { | 444 | switch (cam->params.version.sensor_flags) { |
@@ -458,7 +458,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v | |||
458 | strcat(vc->card, "500)"); | 458 | strcat(vc->card, "500)"); |
459 | break; | 459 | break; |
460 | default: | 460 | default: |
461 | strcat(vc->card, "???)"); | 461 | strcat(vc->card, "XXX)"); |
462 | break; | 462 | break; |
463 | } | 463 | } |
464 | 464 | ||
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index 66671a4092e4..26fc206f095e 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c | |||
@@ -34,7 +34,7 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | |||
34 | MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); | 34 | MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); |
35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
36 | 36 | ||
37 | #ifdef DEBUG | 37 | #ifdef GSPCA_DEBUG |
38 | int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | | 38 | int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | |
39 | D_USBI | D_USBO | D_V4L2; | 39 | D_USBI | D_USBO | D_V4L2; |
40 | #endif | 40 | #endif |
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig new file mode 100644 index 000000000000..302dc3d70193 --- /dev/null +++ b/drivers/media/video/m5mols/Kconfig | |||
@@ -0,0 +1,5 @@ | |||
1 | config VIDEO_M5MOLS | ||
2 | tristate "Fujitsu M-5MOLS 8MP sensor support" | ||
3 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
4 | ---help--- | ||
5 | This driver supports Fujitsu M-5MOLS camera sensor with ISP | ||
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile new file mode 100644 index 000000000000..0a44e028edc7 --- /dev/null +++ b/drivers/media/video/m5mols/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o | ||
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h new file mode 100644 index 000000000000..10b55c854487 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols.h | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Header for M-5MOLS 8M Pixel camera sensor with ISP | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #ifndef M5MOLS_H | ||
17 | #define M5MOLS_H | ||
18 | |||
19 | #include <media/v4l2-subdev.h> | ||
20 | #include "m5mols_reg.h" | ||
21 | |||
22 | extern int m5mols_debug; | ||
23 | |||
24 | #define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd) | ||
25 | |||
26 | #define to_sd(__ctrl) \ | ||
27 | (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd) | ||
28 | |||
29 | enum m5mols_restype { | ||
30 | M5MOLS_RESTYPE_MONITOR, | ||
31 | M5MOLS_RESTYPE_CAPTURE, | ||
32 | M5MOLS_RESTYPE_MAX, | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * struct m5mols_resolution - structure for the resolution | ||
37 | * @type: resolution type according to the pixel code | ||
38 | * @width: width of the resolution | ||
39 | * @height: height of the resolution | ||
40 | * @reg: resolution preset register value | ||
41 | */ | ||
42 | struct m5mols_resolution { | ||
43 | u8 reg; | ||
44 | enum m5mols_restype type; | ||
45 | u16 width; | ||
46 | u16 height; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * struct m5mols_exif - structure for the EXIF information of M-5MOLS | ||
51 | * @exposure_time: exposure time register value | ||
52 | * @shutter_speed: speed of the shutter register value | ||
53 | * @aperture: aperture register value | ||
54 | * @exposure_bias: it calls also EV bias | ||
55 | * @iso_speed: ISO register value | ||
56 | * @flash: status register value of the flash | ||
57 | * @sdr: status register value of the Subject Distance Range | ||
58 | * @qval: not written exact meaning in document | ||
59 | */ | ||
60 | struct m5mols_exif { | ||
61 | u32 exposure_time; | ||
62 | u32 shutter_speed; | ||
63 | u32 aperture; | ||
64 | u32 brightness; | ||
65 | u32 exposure_bias; | ||
66 | u16 iso_speed; | ||
67 | u16 flash; | ||
68 | u16 sdr; | ||
69 | u16 qval; | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * struct m5mols_capture - Structure for the capture capability | ||
74 | * @exif: EXIF information | ||
75 | * @main: size in bytes of the main image | ||
76 | * @thumb: size in bytes of the thumb image, if it was accompanied | ||
77 | * @total: total size in bytes of the produced image | ||
78 | */ | ||
79 | struct m5mols_capture { | ||
80 | struct m5mols_exif exif; | ||
81 | u32 main; | ||
82 | u32 thumb; | ||
83 | u32 total; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct m5mols_scenemode - structure for the scenemode capability | ||
88 | * @metering: metering light register value | ||
89 | * @ev_bias: EV bias register value | ||
90 | * @wb_mode: mode which means the WhiteBalance is Auto or Manual | ||
91 | * @wb_preset: whitebalance preset register value in the Manual mode | ||
92 | * @chroma_en: register value whether the Chroma capability is enabled or not | ||
93 | * @chroma_lvl: chroma's level register value | ||
94 | * @edge_en: register value Whether the Edge capability is enabled or not | ||
95 | * @edge_lvl: edge's level register value | ||
96 | * @af_range: Auto Focus's range | ||
97 | * @fd_mode: Face Detection mode | ||
98 | * @mcc: Multi-axis Color Conversion which means emotion color | ||
99 | * @light: status of the Light | ||
100 | * @flash: status of the Flash | ||
101 | * @tone: Tone color which means Contrast | ||
102 | * @iso: ISO register value | ||
103 | * @capt_mode: Mode of the Image Stabilization while the camera capturing | ||
104 | * @wdr: Wide Dynamic Range register value | ||
105 | * | ||
106 | * The each value according to each scenemode is recommended in the documents. | ||
107 | */ | ||
108 | struct m5mols_scenemode { | ||
109 | u32 metering; | ||
110 | u32 ev_bias; | ||
111 | u32 wb_mode; | ||
112 | u32 wb_preset; | ||
113 | u32 chroma_en; | ||
114 | u32 chroma_lvl; | ||
115 | u32 edge_en; | ||
116 | u32 edge_lvl; | ||
117 | u32 af_range; | ||
118 | u32 fd_mode; | ||
119 | u32 mcc; | ||
120 | u32 light; | ||
121 | u32 flash; | ||
122 | u32 tone; | ||
123 | u32 iso; | ||
124 | u32 capt_mode; | ||
125 | u32 wdr; | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * struct m5mols_version - firmware version information | ||
130 | * @customer: customer information | ||
131 | * @project: version of project information according to customer | ||
132 | * @fw: firmware revision | ||
133 | * @hw: hardware revision | ||
134 | * @param: version of the parameter | ||
135 | * @awb: Auto WhiteBalance algorithm version | ||
136 | * @str: information about manufacturer and packaging vendor | ||
137 | * @af: Auto Focus version | ||
138 | * | ||
139 | * The register offset starts the customer version at 0x0, and it ends | ||
140 | * the awb version at 0x09. The customer, project information occupies 1 bytes | ||
141 | * each. And also the fw, hw, param, awb each requires 2 bytes. The str is | ||
142 | * unique string associated with firmware's version. It includes information | ||
143 | * about manufacturer and the vendor of the sensor's packaging. The least | ||
144 | * significant 2 bytes of the string indicate packaging manufacturer. | ||
145 | */ | ||
146 | #define VERSION_STRING_SIZE 22 | ||
147 | struct m5mols_version { | ||
148 | u8 customer; | ||
149 | u8 project; | ||
150 | u16 fw; | ||
151 | u16 hw; | ||
152 | u16 param; | ||
153 | u16 awb; | ||
154 | u8 str[VERSION_STRING_SIZE]; | ||
155 | u8 af; | ||
156 | }; | ||
157 | #define VERSION_SIZE sizeof(struct m5mols_version) | ||
158 | |||
159 | /** | ||
160 | * struct m5mols_info - M-5MOLS driver data structure | ||
161 | * @pdata: platform data | ||
162 | * @sd: v4l-subdev instance | ||
163 | * @pad: media pad | ||
164 | * @ffmt: current fmt according to resolution type | ||
165 | * @res_type: current resolution type | ||
166 | * @code: current code | ||
167 | * @irq_waitq: waitqueue for the capture | ||
168 | * @work_irq: workqueue for the IRQ | ||
169 | * @flags: state variable for the interrupt handler | ||
170 | * @handle: control handler | ||
171 | * @autoexposure: Auto Exposure control | ||
172 | * @exposure: Exposure control | ||
173 | * @autowb: Auto White Balance control | ||
174 | * @colorfx: Color effect control | ||
175 | * @saturation: Saturation control | ||
176 | * @zoom: Zoom control | ||
177 | * @ver: information of the version | ||
178 | * @cap: the capture mode attributes | ||
179 | * @power: current sensor's power status | ||
180 | * @ctrl_sync: true means all controls of the sensor are initialized | ||
181 | * @int_capture: true means the capture interrupt is issued once | ||
182 | * @lock_ae: true means the Auto Exposure is locked | ||
183 | * @lock_awb: true means the Aut WhiteBalance is locked | ||
184 | * @resolution: register value for current resolution | ||
185 | * @interrupt: register value for current interrupt status | ||
186 | * @mode: register value for current operation mode | ||
187 | * @mode_save: register value for current operation mode for saving | ||
188 | * @set_power: optional power callback to the board code | ||
189 | */ | ||
190 | struct m5mols_info { | ||
191 | const struct m5mols_platform_data *pdata; | ||
192 | struct v4l2_subdev sd; | ||
193 | struct media_pad pad; | ||
194 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | ||
195 | int res_type; | ||
196 | enum v4l2_mbus_pixelcode code; | ||
197 | wait_queue_head_t irq_waitq; | ||
198 | struct work_struct work_irq; | ||
199 | unsigned long flags; | ||
200 | |||
201 | struct v4l2_ctrl_handler handle; | ||
202 | /* Autoexposure/exposure control cluster */ | ||
203 | struct { | ||
204 | struct v4l2_ctrl *autoexposure; | ||
205 | struct v4l2_ctrl *exposure; | ||
206 | }; | ||
207 | struct v4l2_ctrl *autowb; | ||
208 | struct v4l2_ctrl *colorfx; | ||
209 | struct v4l2_ctrl *saturation; | ||
210 | struct v4l2_ctrl *zoom; | ||
211 | |||
212 | struct m5mols_version ver; | ||
213 | struct m5mols_capture cap; | ||
214 | bool power; | ||
215 | bool ctrl_sync; | ||
216 | bool lock_ae; | ||
217 | bool lock_awb; | ||
218 | u8 resolution; | ||
219 | u32 interrupt; | ||
220 | u32 mode; | ||
221 | u32 mode_save; | ||
222 | int (*set_power)(struct device *dev, int on); | ||
223 | }; | ||
224 | |||
225 | #define ST_CAPT_IRQ 0 | ||
226 | |||
227 | #define is_powered(__info) (__info->power) | ||
228 | #define is_ctrl_synced(__info) (__info->ctrl_sync) | ||
229 | #define is_available_af(__info) (__info->ver.af) | ||
230 | #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) | ||
231 | #define is_manufacturer(__info, __manufacturer) \ | ||
232 | (__info->ver.str[0] == __manufacturer[0] && \ | ||
233 | __info->ver.str[1] == __manufacturer[1]) | ||
234 | /* | ||
235 | * I2C operation of the M-5MOLS | ||
236 | * | ||
237 | * The I2C read operation of the M-5MOLS requires 2 messages. The first | ||
238 | * message sends the information about the command, command category, and total | ||
239 | * message size. The second message is used to retrieve the data specifed in | ||
240 | * the first message | ||
241 | * | ||
242 | * 1st message 2nd message | ||
243 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
244 | * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | | ||
245 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
246 | * - size1: message data size(5 in this case) | ||
247 | * - size2: desired buffer size of the 2nd message | ||
248 | * - d[0..3]: according to size2 | ||
249 | * | ||
250 | * The I2C write operation needs just one message. The message includes | ||
251 | * category, command, total size, and desired data. | ||
252 | * | ||
253 | * 1st message | ||
254 | * +-------+---+----------+-----+------+------+------+------+ | ||
255 | * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | | ||
256 | * +-------+---+----------+-----+------+------+------+------+ | ||
257 | * - d[0..3]: according to size1 | ||
258 | */ | ||
259 | int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); | ||
260 | int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); | ||
261 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); | ||
262 | |||
263 | /* | ||
264 | * Mode operation of the M-5MOLS | ||
265 | * | ||
266 | * Changing the mode of the M-5MOLS is needed right executing order. | ||
267 | * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed | ||
268 | * by user. There are various categories associated with each mode. | ||
269 | * | ||
270 | * +============================================================+ | ||
271 | * | mode | category | | ||
272 | * +============================================================+ | ||
273 | * | FLASH | FLASH(only after Stand-by or Power-on) | | ||
274 | * | SYSTEM | SYSTEM(only after sensor arm-booting) | | ||
275 | * | PARAMETER | PARAMETER | | ||
276 | * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | | ||
277 | * | CAPTURE | Single CAPTURE, Preview(recording) | | ||
278 | * +============================================================+ | ||
279 | * | ||
280 | * The available executing order between each modes are as follows: | ||
281 | * PARAMETER <---> MONITOR <---> CAPTURE | ||
282 | */ | ||
283 | int m5mols_mode(struct m5mols_info *info, u32 mode); | ||
284 | |||
285 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg); | ||
286 | int m5mols_sync_controls(struct m5mols_info *info); | ||
287 | int m5mols_start_capture(struct m5mols_info *info); | ||
288 | int m5mols_do_scenemode(struct m5mols_info *info, u32 mode); | ||
289 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); | ||
290 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | ||
291 | |||
292 | /* The firmware function */ | ||
293 | int m5mols_update_fw(struct v4l2_subdev *sd, | ||
294 | int (*set_power)(struct m5mols_info *, bool)); | ||
295 | |||
296 | #endif /* M5MOLS_H */ | ||
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c new file mode 100644 index 000000000000..d71a3903b60f --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_capture.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * The Capture code for Fujitsu M-5MOLS ISP | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <media/v4l2-ctrls.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-subdev.h> | ||
29 | #include <media/m5mols.h> | ||
30 | |||
31 | #include "m5mols.h" | ||
32 | #include "m5mols_reg.h" | ||
33 | |||
34 | static int m5mols_capture_error_handler(struct m5mols_info *info, | ||
35 | int timeout) | ||
36 | { | ||
37 | int ret; | ||
38 | |||
39 | /* Disable all interrupts and clear relevant interrupt staus bits */ | ||
40 | ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, | ||
41 | info->interrupt & ~(REG_INT_CAPTURE)); | ||
42 | if (ret) | ||
43 | return ret; | ||
44 | |||
45 | if (timeout == 0) | ||
46 | return -ETIMEDOUT; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | /** | ||
51 | * m5mols_read_rational - I2C read of a rational number | ||
52 | * | ||
53 | * Read numerator and denominator from registers @addr_num and @addr_den | ||
54 | * respectively and return the division result in @val. | ||
55 | */ | ||
56 | static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, | ||
57 | u32 addr_den, u32 *val) | ||
58 | { | ||
59 | u32 num, den; | ||
60 | |||
61 | int ret = m5mols_read(sd, addr_num, &num); | ||
62 | if (!ret) | ||
63 | ret = m5mols_read(sd, addr_den, &den); | ||
64 | if (ret) | ||
65 | return ret; | ||
66 | *val = den == 0 ? 0 : num / den; | ||
67 | return ret; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * m5mols_capture_info - Gather captured image information | ||
72 | * | ||
73 | * For now it gathers only EXIF information and file size. | ||
74 | */ | ||
75 | static int m5mols_capture_info(struct m5mols_info *info) | ||
76 | { | ||
77 | struct m5mols_exif *exif = &info->cap.exif; | ||
78 | struct v4l2_subdev *sd = &info->sd; | ||
79 | int ret; | ||
80 | |||
81 | ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, | ||
82 | EXIF_INFO_EXPTIME_DE, &exif->exposure_time); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, | ||
86 | &exif->shutter_speed); | ||
87 | if (ret) | ||
88 | return ret; | ||
89 | ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, | ||
90 | &exif->aperture); | ||
91 | if (ret) | ||
92 | return ret; | ||
93 | ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, | ||
94 | &exif->brightness); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, | ||
98 | &exif->exposure_bias); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed); | ||
103 | if (!ret) | ||
104 | ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); | ||
105 | if (!ret) | ||
106 | ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); | ||
107 | if (!ret) | ||
108 | ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | |||
112 | if (!ret) | ||
113 | ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main); | ||
114 | if (!ret) | ||
115 | ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb); | ||
116 | if (!ret) | ||
117 | info->cap.total = info->cap.main + info->cap.thumb; | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | int m5mols_start_capture(struct m5mols_info *info) | ||
123 | { | ||
124 | struct v4l2_subdev *sd = &info->sd; | ||
125 | u32 resolution = info->resolution; | ||
126 | int timeout; | ||
127 | int ret; | ||
128 | |||
129 | /* | ||
130 | * Preparing capture. Setting control & interrupt before entering | ||
131 | * capture mode | ||
132 | * | ||
133 | * 1) change to MONITOR mode for operating control & interrupt | ||
134 | * 2) set controls (considering v4l2_control value & lock 3A) | ||
135 | * 3) set interrupt | ||
136 | * 4) change to CAPTURE mode | ||
137 | */ | ||
138 | ret = m5mols_mode(info, REG_MONITOR); | ||
139 | if (!ret) | ||
140 | ret = m5mols_sync_controls(info); | ||
141 | if (!ret) | ||
142 | ret = m5mols_lock_3a(info, true); | ||
143 | if (!ret) | ||
144 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
145 | if (!ret) | ||
146 | ret = m5mols_mode(info, REG_CAPTURE); | ||
147 | if (!ret) { | ||
148 | /* Wait for capture interrupt, after changing capture mode */ | ||
149 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
150 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
151 | msecs_to_jiffies(2000)); | ||
152 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) | ||
153 | ret = m5mols_capture_error_handler(info, timeout); | ||
154 | } | ||
155 | if (!ret) | ||
156 | ret = m5mols_lock_3a(info, false); | ||
157 | if (ret) | ||
158 | return ret; | ||
159 | /* | ||
160 | * Starting capture. Setting capture frame count and resolution and | ||
161 | * the format(available format: JPEG, Bayer RAW, YUV). | ||
162 | * | ||
163 | * 1) select single or multi(enable to 25), format, size | ||
164 | * 2) set interrupt | ||
165 | * 3) start capture(for main image, now) | ||
166 | * 4) get information | ||
167 | * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) | ||
168 | */ | ||
169 | ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); | ||
170 | if (!ret) | ||
171 | ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); | ||
172 | if (!ret) | ||
173 | ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); | ||
174 | if (!ret) | ||
175 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
176 | if (!ret) | ||
177 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | ||
178 | if (!ret) { | ||
179 | /* Wait for the capture completion interrupt */ | ||
180 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
181 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
182 | msecs_to_jiffies(2000)); | ||
183 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { | ||
184 | ret = m5mols_capture_info(info); | ||
185 | if (!ret) | ||
186 | v4l2_subdev_notify(sd, 0, &info->cap.total); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | return m5mols_capture_error_handler(info, timeout); | ||
191 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c new file mode 100644 index 000000000000..817c16fec368 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_controls.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Controls for M-5MOLS 8M Pixel camera sensor with ISP | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/videodev2.h> | ||
19 | #include <media/v4l2-ctrls.h> | ||
20 | |||
21 | #include "m5mols.h" | ||
22 | #include "m5mols_reg.h" | ||
23 | |||
24 | static struct m5mols_scenemode m5mols_default_scenemode[] = { | ||
25 | [REG_SCENE_NORMAL] = { | ||
26 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
27 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
28 | REG_AF_NORMAL, REG_FD_OFF, | ||
29 | REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
30 | 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
31 | }, | ||
32 | [REG_SCENE_PORTRAIT] = { | ||
33 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
34 | REG_CHROMA_ON, 3, REG_EDGE_ON, 4, | ||
35 | REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, | ||
36 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
37 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
38 | }, | ||
39 | [REG_SCENE_LANDSCAPE] = { | ||
40 | REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
41 | REG_CHROMA_ON, 4, REG_EDGE_ON, 6, | ||
42 | REG_AF_NORMAL, REG_FD_OFF, | ||
43 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
44 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
45 | }, | ||
46 | [REG_SCENE_SPORTS] = { | ||
47 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
48 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
49 | REG_AF_NORMAL, REG_FD_OFF, | ||
50 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
51 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
52 | }, | ||
53 | [REG_SCENE_PARTY_INDOOR] = { | ||
54 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
55 | REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | ||
56 | REG_AF_NORMAL, REG_FD_OFF, | ||
57 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
58 | 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, | ||
59 | }, | ||
60 | [REG_SCENE_BEACH_SNOW] = { | ||
61 | REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, | ||
62 | REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | ||
63 | REG_AF_NORMAL, REG_FD_OFF, | ||
64 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
65 | 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | ||
66 | }, | ||
67 | [REG_SCENE_SUNSET] = { | ||
68 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | ||
69 | REG_AWB_DAYLIGHT, | ||
70 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
71 | REG_AF_NORMAL, REG_FD_OFF, | ||
72 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
73 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
74 | }, | ||
75 | [REG_SCENE_DAWN_DUSK] = { | ||
76 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | ||
77 | REG_AWB_FLUORESCENT_1, | ||
78 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
79 | REG_AF_NORMAL, REG_FD_OFF, | ||
80 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
81 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
82 | }, | ||
83 | [REG_SCENE_FALL] = { | ||
84 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
85 | REG_CHROMA_ON, 5, REG_EDGE_ON, 5, | ||
86 | REG_AF_NORMAL, REG_FD_OFF, | ||
87 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
88 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
89 | }, | ||
90 | [REG_SCENE_NIGHT] = { | ||
91 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
92 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
93 | REG_AF_NORMAL, REG_FD_OFF, | ||
94 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
95 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
96 | }, | ||
97 | [REG_SCENE_AGAINST_LIGHT] = { | ||
98 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
99 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
100 | REG_AF_NORMAL, REG_FD_OFF, | ||
101 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
102 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
103 | }, | ||
104 | [REG_SCENE_FIRE] = { | ||
105 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
106 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
107 | REG_AF_NORMAL, REG_FD_OFF, | ||
108 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
109 | 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | ||
110 | }, | ||
111 | [REG_SCENE_TEXT] = { | ||
112 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
113 | REG_CHROMA_ON, 3, REG_EDGE_ON, 7, | ||
114 | REG_AF_MACRO, REG_FD_OFF, | ||
115 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
116 | 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, | ||
117 | }, | ||
118 | [REG_SCENE_CANDLE] = { | ||
119 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
120 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
121 | REG_AF_NORMAL, REG_FD_OFF, | ||
122 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
123 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
124 | }, | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * m5mols_do_scenemode() - Change current scenemode | ||
129 | * @mode: Desired mode of the scenemode | ||
130 | * | ||
131 | * WARNING: The execution order is important. Do not change the order. | ||
132 | */ | ||
133 | int m5mols_do_scenemode(struct m5mols_info *info, u32 mode) | ||
134 | { | ||
135 | struct v4l2_subdev *sd = &info->sd; | ||
136 | struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; | ||
137 | int ret; | ||
138 | |||
139 | if (mode > REG_SCENE_CANDLE) | ||
140 | return -EINVAL; | ||
141 | |||
142 | ret = m5mols_lock_3a(info, false); | ||
143 | if (!ret) | ||
144 | ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); | ||
145 | if (!ret) | ||
146 | ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); | ||
147 | if (!ret) | ||
148 | ret = m5mols_write(sd, AE_MODE, scenemode.metering); | ||
149 | if (!ret) | ||
150 | ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); | ||
151 | if (!ret) | ||
152 | ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); | ||
153 | if (!ret) | ||
154 | ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); | ||
155 | if (!ret) | ||
156 | ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); | ||
157 | if (!ret) | ||
158 | ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); | ||
159 | if (!ret) | ||
160 | ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); | ||
161 | if (!ret) | ||
162 | ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); | ||
163 | if (!ret && is_available_af(info)) | ||
164 | ret = m5mols_write(sd, AF_MODE, scenemode.af_range); | ||
165 | if (!ret && is_available_af(info)) | ||
166 | ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); | ||
167 | if (!ret) | ||
168 | ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); | ||
169 | if (!ret) | ||
170 | ret = m5mols_write(sd, AE_ISO, scenemode.iso); | ||
171 | if (!ret) | ||
172 | ret = m5mols_mode(info, REG_CAPTURE); | ||
173 | if (!ret) | ||
174 | ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); | ||
175 | if (!ret) | ||
176 | ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); | ||
177 | if (!ret) | ||
178 | ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); | ||
179 | if (!ret) | ||
180 | ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); | ||
181 | if (!ret) | ||
182 | ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); | ||
183 | if (!ret) | ||
184 | ret = m5mols_mode(info, REG_MONITOR); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int m5mols_lock_ae(struct m5mols_info *info, bool lock) | ||
190 | { | ||
191 | int ret = 0; | ||
192 | |||
193 | if (info->lock_ae != lock) | ||
194 | ret = m5mols_write(&info->sd, AE_LOCK, | ||
195 | lock ? REG_AE_LOCK : REG_AE_UNLOCK); | ||
196 | if (!ret) | ||
197 | info->lock_ae = lock; | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int m5mols_lock_awb(struct m5mols_info *info, bool lock) | ||
203 | { | ||
204 | int ret = 0; | ||
205 | |||
206 | if (info->lock_awb != lock) | ||
207 | ret = m5mols_write(&info->sd, AWB_LOCK, | ||
208 | lock ? REG_AWB_LOCK : REG_AWB_UNLOCK); | ||
209 | if (!ret) | ||
210 | info->lock_awb = lock; | ||
211 | |||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | /* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */ | ||
216 | int m5mols_lock_3a(struct m5mols_info *info, bool lock) | ||
217 | { | ||
218 | int ret; | ||
219 | |||
220 | ret = m5mols_lock_ae(info, lock); | ||
221 | if (!ret) | ||
222 | ret = m5mols_lock_awb(info, lock); | ||
223 | /* Don't need to handle unlocking AF */ | ||
224 | if (!ret && is_available_af(info) && lock) | ||
225 | ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ | ||
231 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) | ||
232 | { | ||
233 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
234 | struct m5mols_info *info = to_m5mols(sd); | ||
235 | int ret; | ||
236 | |||
237 | switch (ctrl->id) { | ||
238 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
239 | return m5mols_write(sd, MON_ZOOM, ctrl->val); | ||
240 | |||
241 | case V4L2_CID_EXPOSURE_AUTO: | ||
242 | ret = m5mols_lock_ae(info, | ||
243 | ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); | ||
244 | if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) | ||
245 | ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); | ||
246 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
247 | int val = info->exposure->val; | ||
248 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
249 | if (!ret) | ||
250 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); | ||
251 | if (!ret) | ||
252 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); | ||
253 | } | ||
254 | return ret; | ||
255 | |||
256 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
257 | ret = m5mols_lock_awb(info, ctrl->val ? false : true); | ||
258 | if (!ret) | ||
259 | ret = m5mols_write(sd, AWB_MODE, ctrl->val ? | ||
260 | REG_AWB_AUTO : REG_AWB_PRESET); | ||
261 | return ret; | ||
262 | |||
263 | case V4L2_CID_SATURATION: | ||
264 | ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); | ||
265 | if (!ret) | ||
266 | ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
267 | return ret; | ||
268 | |||
269 | case V4L2_CID_COLORFX: | ||
270 | /* | ||
271 | * This control uses two kinds of registers: normal & color. | ||
272 | * The normal effect belongs to category 1, while the color | ||
273 | * one belongs to category 2. | ||
274 | * | ||
275 | * The normal effect uses one register: CAT1_EFFECT. | ||
276 | * The color effect uses three registers: | ||
277 | * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. | ||
278 | */ | ||
279 | ret = m5mols_write(sd, PARM_EFFECT, | ||
280 | ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : | ||
281 | ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : | ||
282 | REG_EFFECT_OFF); | ||
283 | if (!ret) | ||
284 | ret = m5mols_write(sd, MON_EFFECT, | ||
285 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
286 | REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); | ||
287 | if (!ret) | ||
288 | ret = m5mols_write(sd, MON_CFIXR, | ||
289 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
290 | REG_CFIXR_SEPIA : 0); | ||
291 | if (!ret) | ||
292 | ret = m5mols_write(sd, MON_CFIXB, | ||
293 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
294 | REG_CFIXB_SEPIA : 0); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | return -EINVAL; | ||
299 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c new file mode 100644 index 000000000000..76eac26e84ae --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
@@ -0,0 +1,1004 @@ | |||
1 | /* | ||
2 | * Driver for M-5MOLS 8M Pixel camera sensor with ISP | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <media/v4l2-ctrls.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-subdev.h> | ||
28 | #include <media/m5mols.h> | ||
29 | |||
30 | #include "m5mols.h" | ||
31 | #include "m5mols_reg.h" | ||
32 | |||
33 | int m5mols_debug; | ||
34 | module_param(m5mols_debug, int, 0644); | ||
35 | |||
36 | #define MODULE_NAME "M5MOLS" | ||
37 | #define M5MOLS_I2C_CHECK_RETRY 500 | ||
38 | |||
39 | /* The regulator consumer names for external voltage regulators */ | ||
40 | static struct regulator_bulk_data supplies[] = { | ||
41 | { | ||
42 | .supply = "core", /* ARM core power, 1.2V */ | ||
43 | }, { | ||
44 | .supply = "dig_18", /* digital power 1, 1.8V */ | ||
45 | }, { | ||
46 | .supply = "d_sensor", /* sensor power 1, 1.8V */ | ||
47 | }, { | ||
48 | .supply = "dig_28", /* digital power 2, 2.8V */ | ||
49 | }, { | ||
50 | .supply = "a_sensor", /* analog power */ | ||
51 | }, { | ||
52 | .supply = "dig_12", /* digital power 3, 1.2V */ | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { | ||
57 | [M5MOLS_RESTYPE_MONITOR] = { | ||
58 | .width = 1920, | ||
59 | .height = 1080, | ||
60 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
61 | .field = V4L2_FIELD_NONE, | ||
62 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
63 | }, | ||
64 | [M5MOLS_RESTYPE_CAPTURE] = { | ||
65 | .width = 1920, | ||
66 | .height = 1080, | ||
67 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
68 | .field = V4L2_FIELD_NONE, | ||
69 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
70 | }, | ||
71 | }; | ||
72 | #define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) | ||
73 | |||
74 | static const struct m5mols_resolution m5mols_reg_res[] = { | ||
75 | { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ | ||
76 | { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ | ||
77 | { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ | ||
78 | { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, | ||
79 | { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ | ||
80 | { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ | ||
81 | { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ | ||
82 | { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ | ||
83 | { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ | ||
84 | { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, | ||
85 | { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ | ||
86 | { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ | ||
87 | { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, | ||
88 | { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ | ||
89 | { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ | ||
90 | { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ | ||
91 | { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ | ||
92 | { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ | ||
93 | { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ | ||
94 | |||
95 | { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ | ||
96 | { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ | ||
97 | { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, | ||
98 | { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ | ||
99 | { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ | ||
100 | { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ | ||
101 | { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ | ||
102 | { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ | ||
103 | { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ | ||
104 | { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ | ||
105 | { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ | ||
106 | { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, | ||
107 | { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ | ||
108 | { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, | ||
109 | { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ | ||
110 | { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ | ||
111 | { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, | ||
112 | { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * m5mols_swap_byte - an byte array to integer conversion function | ||
117 | * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet | ||
118 | * | ||
119 | * Convert I2C data byte array with performing any required byte | ||
120 | * reordering to assure proper values for each data type, regardless | ||
121 | * of the architecture endianness. | ||
122 | */ | ||
123 | static u32 m5mols_swap_byte(u8 *data, u8 length) | ||
124 | { | ||
125 | if (length == 1) | ||
126 | return *data; | ||
127 | else if (length == 2) | ||
128 | return be16_to_cpu(*((u16 *)data)); | ||
129 | else | ||
130 | return be32_to_cpu(*((u32 *)data)); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * m5mols_read - I2C read function | ||
135 | * @reg: combination of size, category and command for the I2C packet | ||
136 | * @val: read value | ||
137 | */ | ||
138 | int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) | ||
139 | { | ||
140 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
141 | u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; | ||
142 | u8 size = I2C_SIZE(reg); | ||
143 | u8 category = I2C_CATEGORY(reg); | ||
144 | u8 cmd = I2C_COMMAND(reg); | ||
145 | struct i2c_msg msg[2]; | ||
146 | u8 wbuf[5]; | ||
147 | int ret; | ||
148 | |||
149 | if (!client->adapter) | ||
150 | return -ENODEV; | ||
151 | |||
152 | if (size != 1 && size != 2 && size != 4) { | ||
153 | v4l2_err(sd, "Wrong data size\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | msg[0].addr = client->addr; | ||
158 | msg[0].flags = 0; | ||
159 | msg[0].len = 5; | ||
160 | msg[0].buf = wbuf; | ||
161 | wbuf[0] = 5; | ||
162 | wbuf[1] = M5MOLS_BYTE_READ; | ||
163 | wbuf[2] = category; | ||
164 | wbuf[3] = cmd; | ||
165 | wbuf[4] = size; | ||
166 | |||
167 | msg[1].addr = client->addr; | ||
168 | msg[1].flags = I2C_M_RD; | ||
169 | msg[1].len = size + 1; | ||
170 | msg[1].buf = rbuf; | ||
171 | |||
172 | /* minimum stabilization time */ | ||
173 | usleep_range(200, 200); | ||
174 | |||
175 | ret = i2c_transfer(client->adapter, msg, 2); | ||
176 | if (ret < 0) { | ||
177 | v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
178 | size, category, cmd, ret); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | *val = m5mols_swap_byte(&rbuf[1], size); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * m5mols_write - I2C command write function | ||
189 | * @reg: combination of size, category and command for the I2C packet | ||
190 | * @val: value to write | ||
191 | */ | ||
192 | int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) | ||
193 | { | ||
194 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
195 | u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; | ||
196 | u8 category = I2C_CATEGORY(reg); | ||
197 | u8 cmd = I2C_COMMAND(reg); | ||
198 | u8 size = I2C_SIZE(reg); | ||
199 | u32 *buf = (u32 *)&wbuf[4]; | ||
200 | struct i2c_msg msg[1]; | ||
201 | int ret; | ||
202 | |||
203 | if (!client->adapter) | ||
204 | return -ENODEV; | ||
205 | |||
206 | if (size != 1 && size != 2 && size != 4) { | ||
207 | v4l2_err(sd, "Wrong data size\n"); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | msg->addr = client->addr; | ||
212 | msg->flags = 0; | ||
213 | msg->len = (u16)size + 4; | ||
214 | msg->buf = wbuf; | ||
215 | wbuf[0] = size + 4; | ||
216 | wbuf[1] = M5MOLS_BYTE_WRITE; | ||
217 | wbuf[2] = category; | ||
218 | wbuf[3] = cmd; | ||
219 | |||
220 | *buf = m5mols_swap_byte((u8 *)&val, size); | ||
221 | |||
222 | usleep_range(200, 200); | ||
223 | |||
224 | ret = i2c_transfer(client->adapter, msg, 1); | ||
225 | if (ret < 0) { | ||
226 | v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
227 | size, category, cmd, ret); | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) | ||
235 | { | ||
236 | u32 busy, i; | ||
237 | int ret; | ||
238 | |||
239 | for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { | ||
240 | ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy); | ||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | if ((busy & mask) == mask) | ||
244 | return 0; | ||
245 | } | ||
246 | return -EBUSY; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts | ||
251 | * | ||
252 | * Before writing desired interrupt value the INT_FACTOR register should | ||
253 | * be read to clear pending interrupts. | ||
254 | */ | ||
255 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) | ||
256 | { | ||
257 | struct m5mols_info *info = to_m5mols(sd); | ||
258 | u32 mask = is_available_af(info) ? REG_INT_AF : 0; | ||
259 | u32 dummy; | ||
260 | int ret; | ||
261 | |||
262 | ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); | ||
263 | if (!ret) | ||
264 | ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * m5mols_reg_mode - Write the mode and check busy status | ||
270 | * | ||
271 | * It always accompanies a little delay changing the M-5MOLS mode, so it is | ||
272 | * needed checking current busy status to guarantee right mode. | ||
273 | */ | ||
274 | static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) | ||
275 | { | ||
276 | int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); | ||
277 | |||
278 | return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * m5mols_mode - manage the M-5MOLS's mode | ||
283 | * @mode: the required operation mode | ||
284 | * | ||
285 | * The commands of M-5MOLS are grouped into specific modes. Each functionality | ||
286 | * can be guaranteed only when the sensor is operating in mode which which | ||
287 | * a command belongs to. | ||
288 | */ | ||
289 | int m5mols_mode(struct m5mols_info *info, u32 mode) | ||
290 | { | ||
291 | struct v4l2_subdev *sd = &info->sd; | ||
292 | int ret = -EINVAL; | ||
293 | u32 reg; | ||
294 | |||
295 | if (mode < REG_PARAMETER && mode > REG_CAPTURE) | ||
296 | return ret; | ||
297 | |||
298 | ret = m5mols_read(sd, SYSTEM_SYSMODE, ®); | ||
299 | if ((!ret && reg == mode) || ret) | ||
300 | return ret; | ||
301 | |||
302 | switch (reg) { | ||
303 | case REG_PARAMETER: | ||
304 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
305 | if (!ret && mode == REG_MONITOR) | ||
306 | break; | ||
307 | if (!ret) | ||
308 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
309 | break; | ||
310 | |||
311 | case REG_MONITOR: | ||
312 | if (mode == REG_PARAMETER) { | ||
313 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
318 | break; | ||
319 | |||
320 | case REG_CAPTURE: | ||
321 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
322 | if (!ret && mode == REG_MONITOR) | ||
323 | break; | ||
324 | if (!ret) | ||
325 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
326 | break; | ||
327 | |||
328 | default: | ||
329 | v4l2_warn(sd, "Wrong mode: %d\n", mode); | ||
330 | } | ||
331 | |||
332 | if (!ret) | ||
333 | info->mode = mode; | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * m5mols_get_version - retrieve full revisions information of M-5MOLS | ||
340 | * | ||
341 | * The version information includes revisions of hardware and firmware, | ||
342 | * AutoFocus alghorithm version and the version string. | ||
343 | */ | ||
344 | static int m5mols_get_version(struct v4l2_subdev *sd) | ||
345 | { | ||
346 | struct m5mols_info *info = to_m5mols(sd); | ||
347 | union { | ||
348 | struct m5mols_version ver; | ||
349 | u8 bytes[VERSION_SIZE]; | ||
350 | } version; | ||
351 | u32 *value; | ||
352 | u8 cmd = CAT0_VER_CUSTOMER; | ||
353 | int ret; | ||
354 | |||
355 | do { | ||
356 | value = (u32 *)&version.bytes[cmd]; | ||
357 | ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); | ||
358 | if (ret) | ||
359 | return ret; | ||
360 | } while (cmd++ != CAT0_VER_AWB); | ||
361 | |||
362 | do { | ||
363 | value = (u32 *)&version.bytes[cmd]; | ||
364 | ret = m5mols_read(sd, SYSTEM_VER_STRING, value); | ||
365 | if (ret) | ||
366 | return ret; | ||
367 | if (cmd >= VERSION_SIZE - 1) | ||
368 | return -EINVAL; | ||
369 | } while (version.bytes[cmd++]); | ||
370 | |||
371 | value = (u32 *)&version.bytes[cmd]; | ||
372 | ret = m5mols_read(sd, AF_VERSION, value); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | |||
376 | /* store version information swapped for being readable */ | ||
377 | info->ver = version.ver; | ||
378 | info->ver.fw = be16_to_cpu(info->ver.fw); | ||
379 | info->ver.hw = be16_to_cpu(info->ver.hw); | ||
380 | info->ver.param = be16_to_cpu(info->ver.param); | ||
381 | info->ver.awb = be16_to_cpu(info->ver.awb); | ||
382 | |||
383 | v4l2_info(sd, "Manufacturer\t[%s]\n", | ||
384 | is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? | ||
385 | "Samsung Electro-Machanics" : | ||
386 | is_manufacturer(info, REG_SAMSUNG_OPTICS) ? | ||
387 | "Samsung Fiber-Optics" : | ||
388 | is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? | ||
389 | "Samsung Techwin" : "None"); | ||
390 | v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", | ||
391 | info->ver.customer, info->ver.project); | ||
392 | |||
393 | if (!is_available_af(info)) | ||
394 | v4l2_info(sd, "No support Auto Focus on this firmware\n"); | ||
395 | |||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * __find_restype - Lookup M-5MOLS resolution type according to pixel code | ||
401 | * @code: pixel code | ||
402 | */ | ||
403 | static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) | ||
404 | { | ||
405 | enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; | ||
406 | |||
407 | do { | ||
408 | if (code == m5mols_default_ffmt[type].code) | ||
409 | return type; | ||
410 | } while (type++ != SIZE_DEFAULT_FFMT); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * __find_resolution - Lookup preset and type of M-5MOLS's resolution | ||
417 | * @mf: pixel format to find/negotiate the resolution preset for | ||
418 | * @type: M-5MOLS resolution type | ||
419 | * @resolution: M-5MOLS resolution preset register value | ||
420 | * | ||
421 | * Find nearest resolution matching resolution preset and adjust mf | ||
422 | * to supported values. | ||
423 | */ | ||
424 | static int __find_resolution(struct v4l2_subdev *sd, | ||
425 | struct v4l2_mbus_framefmt *mf, | ||
426 | enum m5mols_restype *type, | ||
427 | u32 *resolution) | ||
428 | { | ||
429 | const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; | ||
430 | const struct m5mols_resolution *match = NULL; | ||
431 | enum m5mols_restype stype = __find_restype(mf->code); | ||
432 | int i = ARRAY_SIZE(m5mols_reg_res); | ||
433 | unsigned int min_err = ~0; | ||
434 | |||
435 | while (i--) { | ||
436 | int err; | ||
437 | if (stype == fsize->type) { | ||
438 | err = abs(fsize->width - mf->width) | ||
439 | + abs(fsize->height - mf->height); | ||
440 | |||
441 | if (err < min_err) { | ||
442 | min_err = err; | ||
443 | match = fsize; | ||
444 | } | ||
445 | } | ||
446 | fsize++; | ||
447 | } | ||
448 | if (match) { | ||
449 | mf->width = match->width; | ||
450 | mf->height = match->height; | ||
451 | *resolution = match->reg; | ||
452 | *type = stype; | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, | ||
460 | struct v4l2_subdev_fh *fh, | ||
461 | enum v4l2_subdev_format_whence which, | ||
462 | enum m5mols_restype type) | ||
463 | { | ||
464 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
465 | return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; | ||
466 | |||
467 | return &info->ffmt[type]; | ||
468 | } | ||
469 | |||
470 | static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
471 | struct v4l2_subdev_format *fmt) | ||
472 | { | ||
473 | struct m5mols_info *info = to_m5mols(sd); | ||
474 | struct v4l2_mbus_framefmt *format; | ||
475 | |||
476 | if (fmt->pad != 0) | ||
477 | return -EINVAL; | ||
478 | |||
479 | format = __find_format(info, fh, fmt->which, info->res_type); | ||
480 | if (!format) | ||
481 | return -EINVAL; | ||
482 | |||
483 | fmt->format = *format; | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
488 | struct v4l2_subdev_format *fmt) | ||
489 | { | ||
490 | struct m5mols_info *info = to_m5mols(sd); | ||
491 | struct v4l2_mbus_framefmt *format = &fmt->format; | ||
492 | struct v4l2_mbus_framefmt *sfmt; | ||
493 | enum m5mols_restype type; | ||
494 | u32 resolution = 0; | ||
495 | int ret; | ||
496 | |||
497 | if (fmt->pad != 0) | ||
498 | return -EINVAL; | ||
499 | |||
500 | ret = __find_resolution(sd, format, &type, &resolution); | ||
501 | if (ret < 0) | ||
502 | return ret; | ||
503 | |||
504 | sfmt = __find_format(info, fh, fmt->which, type); | ||
505 | if (!sfmt) | ||
506 | return 0; | ||
507 | |||
508 | *sfmt = m5mols_default_ffmt[type]; | ||
509 | sfmt->width = format->width; | ||
510 | sfmt->height = format->height; | ||
511 | |||
512 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
513 | info->resolution = resolution; | ||
514 | info->code = format->code; | ||
515 | info->res_type = type; | ||
516 | } | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, | ||
522 | struct v4l2_subdev_fh *fh, | ||
523 | struct v4l2_subdev_mbus_code_enum *code) | ||
524 | { | ||
525 | if (!code || code->index >= SIZE_DEFAULT_FFMT) | ||
526 | return -EINVAL; | ||
527 | |||
528 | code->code = m5mols_default_ffmt[code->index].code; | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static struct v4l2_subdev_pad_ops m5mols_pad_ops = { | ||
534 | .enum_mbus_code = m5mols_enum_mbus_code, | ||
535 | .get_fmt = m5mols_get_fmt, | ||
536 | .set_fmt = m5mols_set_fmt, | ||
537 | }; | ||
538 | |||
539 | /** | ||
540 | * m5mols_sync_controls - Apply default scene mode and the current controls | ||
541 | * | ||
542 | * This is used only streaming for syncing between v4l2_ctrl framework and | ||
543 | * m5mols's controls. First, do the scenemode to the sensor, then call | ||
544 | * v4l2_ctrl_handler_setup. It can be same between some commands and | ||
545 | * the scenemode's in the default v4l2_ctrls. But, such commands of control | ||
546 | * should be prior to the scenemode's one. | ||
547 | */ | ||
548 | int m5mols_sync_controls(struct m5mols_info *info) | ||
549 | { | ||
550 | int ret = -EINVAL; | ||
551 | |||
552 | if (!is_ctrl_synced(info)) { | ||
553 | ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); | ||
554 | if (ret) | ||
555 | return ret; | ||
556 | |||
557 | v4l2_ctrl_handler_setup(&info->handle); | ||
558 | info->ctrl_sync = true; | ||
559 | } | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * m5mols_start_monitor - Start the monitor mode | ||
566 | * | ||
567 | * Before applying the controls setup the resolution and frame rate | ||
568 | * in PARAMETER mode, and then switch over to MONITOR mode. | ||
569 | */ | ||
570 | static int m5mols_start_monitor(struct m5mols_info *info) | ||
571 | { | ||
572 | struct v4l2_subdev *sd = &info->sd; | ||
573 | int ret; | ||
574 | |||
575 | ret = m5mols_mode(info, REG_PARAMETER); | ||
576 | if (!ret) | ||
577 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | ||
578 | if (!ret) | ||
579 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | ||
580 | if (!ret) | ||
581 | ret = m5mols_mode(info, REG_MONITOR); | ||
582 | if (!ret) | ||
583 | ret = m5mols_sync_controls(info); | ||
584 | |||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | ||
589 | { | ||
590 | struct m5mols_info *info = to_m5mols(sd); | ||
591 | |||
592 | if (enable) { | ||
593 | int ret = -EINVAL; | ||
594 | |||
595 | if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) | ||
596 | ret = m5mols_start_monitor(info); | ||
597 | if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) | ||
598 | ret = m5mols_start_capture(info); | ||
599 | |||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | return m5mols_mode(info, REG_PARAMETER); | ||
604 | } | ||
605 | |||
606 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { | ||
607 | .s_stream = m5mols_s_stream, | ||
608 | }; | ||
609 | |||
610 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
611 | { | ||
612 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
613 | struct m5mols_info *info = to_m5mols(sd); | ||
614 | int ret; | ||
615 | |||
616 | info->mode_save = info->mode; | ||
617 | |||
618 | ret = m5mols_mode(info, REG_PARAMETER); | ||
619 | if (!ret) | ||
620 | ret = m5mols_set_ctrl(ctrl); | ||
621 | if (!ret) | ||
622 | ret = m5mols_mode(info, info->mode_save); | ||
623 | |||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | ||
628 | .s_ctrl = m5mols_s_ctrl, | ||
629 | }; | ||
630 | |||
631 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | ||
632 | { | ||
633 | struct v4l2_subdev *sd = &info->sd; | ||
634 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
635 | const struct m5mols_platform_data *pdata = info->pdata; | ||
636 | int ret; | ||
637 | |||
638 | if (enable) { | ||
639 | if (is_powered(info)) | ||
640 | return 0; | ||
641 | |||
642 | if (info->set_power) { | ||
643 | ret = info->set_power(&client->dev, 1); | ||
644 | if (ret) | ||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
649 | if (ret) { | ||
650 | info->set_power(&client->dev, 0); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); | ||
655 | usleep_range(1000, 1000); | ||
656 | info->power = true; | ||
657 | |||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | if (!is_powered(info)) | ||
662 | return 0; | ||
663 | |||
664 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
665 | if (ret) | ||
666 | return ret; | ||
667 | |||
668 | if (info->set_power) | ||
669 | info->set_power(&client->dev, 0); | ||
670 | |||
671 | gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); | ||
672 | usleep_range(1000, 1000); | ||
673 | info->power = false; | ||
674 | |||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | /* m5mols_update_fw - optional firmware update routine */ | ||
679 | int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, | ||
680 | int (*set_power)(struct m5mols_info *, bool)) | ||
681 | { | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. | ||
687 | * | ||
688 | * Booting internal ARM core makes the M-5MOLS is ready for getting commands | ||
689 | * with I2C. It's the first thing to be done after it powered up. It must wait | ||
690 | * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. | ||
691 | */ | ||
692 | static int m5mols_sensor_armboot(struct v4l2_subdev *sd) | ||
693 | { | ||
694 | int ret; | ||
695 | |||
696 | ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); | ||
697 | if (ret < 0) | ||
698 | return ret; | ||
699 | |||
700 | msleep(520); | ||
701 | |||
702 | ret = m5mols_get_version(sd); | ||
703 | if (!ret) | ||
704 | ret = m5mols_update_fw(sd, m5mols_sensor_power); | ||
705 | if (ret) | ||
706 | return ret; | ||
707 | |||
708 | v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); | ||
709 | |||
710 | ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); | ||
711 | if (!ret) | ||
712 | ret = m5mols_enable_interrupt(sd, REG_INT_AF); | ||
713 | |||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static int m5mols_init_controls(struct m5mols_info *info) | ||
718 | { | ||
719 | struct v4l2_subdev *sd = &info->sd; | ||
720 | u16 max_exposure; | ||
721 | u16 step_zoom; | ||
722 | int ret; | ||
723 | |||
724 | /* Determine value's range & step of controls for various FW version */ | ||
725 | ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure); | ||
726 | if (!ret) | ||
727 | step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
728 | if (ret) | ||
729 | return ret; | ||
730 | |||
731 | v4l2_ctrl_handler_init(&info->handle, 6); | ||
732 | info->autowb = v4l2_ctrl_new_std(&info->handle, | ||
733 | &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
734 | 0, 1, 1, 0); | ||
735 | info->saturation = v4l2_ctrl_new_std(&info->handle, | ||
736 | &m5mols_ctrl_ops, V4L2_CID_SATURATION, | ||
737 | 1, 5, 1, 3); | ||
738 | info->zoom = v4l2_ctrl_new_std(&info->handle, | ||
739 | &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, | ||
740 | 1, 70, step_zoom, 1); | ||
741 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
742 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
743 | 0, max_exposure, 1, (int)max_exposure/2); | ||
744 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, | ||
745 | &m5mols_ctrl_ops, V4L2_CID_COLORFX, | ||
746 | 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); | ||
747 | info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
748 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
749 | 1, 0, V4L2_EXPOSURE_MANUAL); | ||
750 | |||
751 | sd->ctrl_handler = &info->handle; | ||
752 | if (info->handle.error) { | ||
753 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
754 | v4l2_ctrl_handler_free(&info->handle); | ||
755 | return info->handle.error; | ||
756 | } | ||
757 | |||
758 | v4l2_ctrl_cluster(2, &info->autoexposure); | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | /** | ||
764 | * m5mols_s_power - Main sensor power control function | ||
765 | * | ||
766 | * To prevent breaking the lens when the sensor is powered off the Soft-Landing | ||
767 | * algorithm is called where available. The Soft-Landing algorithm availability | ||
768 | * dependends on the firmware provider. | ||
769 | */ | ||
770 | static int m5mols_s_power(struct v4l2_subdev *sd, int on) | ||
771 | { | ||
772 | struct m5mols_info *info = to_m5mols(sd); | ||
773 | int ret; | ||
774 | |||
775 | if (on) { | ||
776 | ret = m5mols_sensor_power(info, true); | ||
777 | if (!ret) | ||
778 | ret = m5mols_sensor_armboot(sd); | ||
779 | if (!ret) | ||
780 | ret = m5mols_init_controls(info); | ||
781 | if (ret) | ||
782 | return ret; | ||
783 | |||
784 | info->ffmt[M5MOLS_RESTYPE_MONITOR] = | ||
785 | m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; | ||
786 | info->ffmt[M5MOLS_RESTYPE_CAPTURE] = | ||
787 | m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | ||
792 | ret = m5mols_mode(info, REG_MONITOR); | ||
793 | if (!ret) | ||
794 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); | ||
795 | if (!ret) | ||
796 | ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); | ||
797 | if (!ret) | ||
798 | ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, | ||
799 | REG_AF_IDLE); | ||
800 | if (!ret) | ||
801 | v4l2_info(sd, "Success soft-landing lens\n"); | ||
802 | } | ||
803 | |||
804 | ret = m5mols_sensor_power(info, false); | ||
805 | if (!ret) { | ||
806 | v4l2_ctrl_handler_free(&info->handle); | ||
807 | info->ctrl_sync = false; | ||
808 | } | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | static int m5mols_log_status(struct v4l2_subdev *sd) | ||
814 | { | ||
815 | struct m5mols_info *info = to_m5mols(sd); | ||
816 | |||
817 | v4l2_ctrl_handler_log_status(&info->handle, sd->name); | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static const struct v4l2_subdev_core_ops m5mols_core_ops = { | ||
823 | .s_power = m5mols_s_power, | ||
824 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
825 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
826 | .queryctrl = v4l2_subdev_queryctrl, | ||
827 | .querymenu = v4l2_subdev_querymenu, | ||
828 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
829 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
830 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
831 | .log_status = m5mols_log_status, | ||
832 | }; | ||
833 | |||
834 | static const struct v4l2_subdev_ops m5mols_ops = { | ||
835 | .core = &m5mols_core_ops, | ||
836 | .pad = &m5mols_pad_ops, | ||
837 | .video = &m5mols_video_ops, | ||
838 | }; | ||
839 | |||
840 | static void m5mols_irq_work(struct work_struct *work) | ||
841 | { | ||
842 | struct m5mols_info *info = | ||
843 | container_of(work, struct m5mols_info, work_irq); | ||
844 | struct v4l2_subdev *sd = &info->sd; | ||
845 | u32 reg; | ||
846 | int ret; | ||
847 | |||
848 | if (!is_powered(info) || | ||
849 | m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) | ||
850 | return; | ||
851 | |||
852 | switch (info->interrupt & REG_INT_MASK) { | ||
853 | case REG_INT_AF: | ||
854 | if (!is_available_af(info)) | ||
855 | break; | ||
856 | ret = m5mols_read(sd, AF_STATUS, ®); | ||
857 | v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", | ||
858 | reg == REG_AF_FAIL ? "Failed" : | ||
859 | reg == REG_AF_SUCCESS ? "Success" : | ||
860 | reg == REG_AF_IDLE ? "Idle" : "Busy"); | ||
861 | break; | ||
862 | case REG_INT_CAPTURE: | ||
863 | if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) | ||
864 | wake_up_interruptible(&info->irq_waitq); | ||
865 | |||
866 | v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); | ||
867 | break; | ||
868 | default: | ||
869 | v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); | ||
870 | break; | ||
871 | }; | ||
872 | } | ||
873 | |||
874 | static irqreturn_t m5mols_irq_handler(int irq, void *data) | ||
875 | { | ||
876 | struct v4l2_subdev *sd = data; | ||
877 | struct m5mols_info *info = to_m5mols(sd); | ||
878 | |||
879 | schedule_work(&info->work_irq); | ||
880 | |||
881 | return IRQ_HANDLED; | ||
882 | } | ||
883 | |||
884 | static int __devinit m5mols_probe(struct i2c_client *client, | ||
885 | const struct i2c_device_id *id) | ||
886 | { | ||
887 | const struct m5mols_platform_data *pdata = client->dev.platform_data; | ||
888 | struct m5mols_info *info; | ||
889 | struct v4l2_subdev *sd; | ||
890 | int ret; | ||
891 | |||
892 | if (pdata == NULL) { | ||
893 | dev_err(&client->dev, "No platform data\n"); | ||
894 | return -EINVAL; | ||
895 | } | ||
896 | |||
897 | if (!gpio_is_valid(pdata->gpio_reset)) { | ||
898 | dev_err(&client->dev, "No valid RESET GPIO specified\n"); | ||
899 | return -EINVAL; | ||
900 | } | ||
901 | |||
902 | if (!pdata->irq) { | ||
903 | dev_err(&client->dev, "Interrupt not assigned\n"); | ||
904 | return -EINVAL; | ||
905 | } | ||
906 | |||
907 | info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); | ||
908 | if (!info) | ||
909 | return -ENOMEM; | ||
910 | |||
911 | info->pdata = pdata; | ||
912 | info->set_power = pdata->set_power; | ||
913 | |||
914 | ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); | ||
915 | if (ret) { | ||
916 | dev_err(&client->dev, "Failed to request gpio: %d\n", ret); | ||
917 | goto out_free; | ||
918 | } | ||
919 | gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); | ||
920 | |||
921 | ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); | ||
922 | if (ret) { | ||
923 | dev_err(&client->dev, "Failed to get regulators: %d\n", ret); | ||
924 | goto out_gpio; | ||
925 | } | ||
926 | |||
927 | sd = &info->sd; | ||
928 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
929 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | ||
930 | |||
931 | info->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
932 | ret = media_entity_init(&sd->entity, 1, &info->pad, 0); | ||
933 | if (ret < 0) | ||
934 | goto out_reg; | ||
935 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
936 | |||
937 | init_waitqueue_head(&info->irq_waitq); | ||
938 | INIT_WORK(&info->work_irq, m5mols_irq_work); | ||
939 | ret = request_irq(pdata->irq, m5mols_irq_handler, | ||
940 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); | ||
941 | if (ret) { | ||
942 | dev_err(&client->dev, "Interrupt request failed: %d\n", ret); | ||
943 | goto out_me; | ||
944 | } | ||
945 | info->res_type = M5MOLS_RESTYPE_MONITOR; | ||
946 | return 0; | ||
947 | out_me: | ||
948 | media_entity_cleanup(&sd->entity); | ||
949 | out_reg: | ||
950 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
951 | out_gpio: | ||
952 | gpio_free(pdata->gpio_reset); | ||
953 | out_free: | ||
954 | kfree(info); | ||
955 | return ret; | ||
956 | } | ||
957 | |||
958 | static int __devexit m5mols_remove(struct i2c_client *client) | ||
959 | { | ||
960 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
961 | struct m5mols_info *info = to_m5mols(sd); | ||
962 | |||
963 | v4l2_device_unregister_subdev(sd); | ||
964 | free_irq(info->pdata->irq, sd); | ||
965 | |||
966 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
967 | gpio_free(info->pdata->gpio_reset); | ||
968 | media_entity_cleanup(&sd->entity); | ||
969 | kfree(info); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static const struct i2c_device_id m5mols_id[] = { | ||
974 | { MODULE_NAME, 0 }, | ||
975 | { }, | ||
976 | }; | ||
977 | MODULE_DEVICE_TABLE(i2c, m5mols_id); | ||
978 | |||
979 | static struct i2c_driver m5mols_i2c_driver = { | ||
980 | .driver = { | ||
981 | .name = MODULE_NAME, | ||
982 | }, | ||
983 | .probe = m5mols_probe, | ||
984 | .remove = __devexit_p(m5mols_remove), | ||
985 | .id_table = m5mols_id, | ||
986 | }; | ||
987 | |||
988 | static int __init m5mols_mod_init(void) | ||
989 | { | ||
990 | return i2c_add_driver(&m5mols_i2c_driver); | ||
991 | } | ||
992 | |||
993 | static void __exit m5mols_mod_exit(void) | ||
994 | { | ||
995 | i2c_del_driver(&m5mols_i2c_driver); | ||
996 | } | ||
997 | |||
998 | module_init(m5mols_mod_init); | ||
999 | module_exit(m5mols_mod_exit); | ||
1000 | |||
1001 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | ||
1002 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | ||
1003 | MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); | ||
1004 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h new file mode 100644 index 000000000000..b83e36fc6ac6 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_reg.h | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * Register map for M-5MOLS 8M Pixel camera sensor with ISP | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
6 | * | ||
7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #ifndef M5MOLS_REG_H | ||
17 | #define M5MOLS_REG_H | ||
18 | |||
19 | #define M5MOLS_I2C_MAX_SIZE 4 | ||
20 | #define M5MOLS_BYTE_READ 0x01 | ||
21 | #define M5MOLS_BYTE_WRITE 0x02 | ||
22 | |||
23 | #define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) | ||
24 | #define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) | ||
25 | #define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) | ||
26 | #define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) | ||
27 | |||
28 | /* | ||
29 | * Category section register | ||
30 | * | ||
31 | * The category means set including relevant command of M-5MOLS. | ||
32 | */ | ||
33 | #define CAT_SYSTEM 0x00 | ||
34 | #define CAT_PARAM 0x01 | ||
35 | #define CAT_MONITOR 0x02 | ||
36 | #define CAT_AE 0x03 | ||
37 | #define CAT_WB 0x06 | ||
38 | #define CAT_EXIF 0x07 | ||
39 | #define CAT_FD 0x09 | ||
40 | #define CAT_LENS 0x0a | ||
41 | #define CAT_CAPT_PARM 0x0b | ||
42 | #define CAT_CAPT_CTRL 0x0c | ||
43 | #define CAT_FLASH 0x0f /* related to FW, revisions, booting */ | ||
44 | |||
45 | /* | ||
46 | * Category 0 - SYSTEM mode | ||
47 | * | ||
48 | * The SYSTEM mode in the M-5MOLS means area available to handle with the whole | ||
49 | * & all-round system of sensor. It deals with version/interrupt/setting mode & | ||
50 | * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by | ||
51 | * packaging & manufacturer, even the customer and project code. And the | ||
52 | * function details may vary among them. The version information helps to | ||
53 | * determine what methods shall be used in the driver. | ||
54 | * | ||
55 | * There is many registers between customer version address and awb one. For | ||
56 | * more specific contents, see definition if file m5mols.h. | ||
57 | */ | ||
58 | #define CAT0_VER_CUSTOMER 0x00 /* customer version */ | ||
59 | #define CAT0_VER_AWB 0x09 /* Auto WB version */ | ||
60 | #define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ | ||
61 | #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ | ||
62 | #define CAT0_STATUS 0x0c /* SYSTEM mode status register */ | ||
63 | #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ | ||
64 | #define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ | ||
65 | |||
66 | #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) | ||
67 | #define REG_SYSINIT 0x00 /* SYSTEM mode */ | ||
68 | #define REG_PARAMETER 0x01 /* PARAMETER mode */ | ||
69 | #define REG_MONITOR 0x02 /* MONITOR mode */ | ||
70 | #define REG_CAPTURE 0x03 /* CAPTURE mode */ | ||
71 | |||
72 | #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) | ||
73 | #define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) | ||
74 | #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ | ||
75 | #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ | ||
76 | #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ | ||
77 | |||
78 | #define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) | ||
79 | #define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) | ||
80 | #define REG_INT_MODE (1 << 0) | ||
81 | #define REG_INT_AF (1 << 1) | ||
82 | #define REG_INT_ZOOM (1 << 2) | ||
83 | #define REG_INT_CAPTURE (1 << 3) | ||
84 | #define REG_INT_FRAMESYNC (1 << 4) | ||
85 | #define REG_INT_FD (1 << 5) | ||
86 | #define REG_INT_LENS_INIT (1 << 6) | ||
87 | #define REG_INT_SOUND (1 << 7) | ||
88 | #define REG_INT_MASK 0x0f | ||
89 | |||
90 | /* | ||
91 | * category 1 - PARAMETER mode | ||
92 | * | ||
93 | * This category supports function of camera features of M-5MOLS. It means we | ||
94 | * can handle with preview(MONITOR) resolution size/frame per second/interface | ||
95 | * between the sensor and the Application Processor/even the image effect. | ||
96 | */ | ||
97 | #define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ | ||
98 | #define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ | ||
99 | #define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ | ||
100 | #define CAT1_EFFECT 0x0b /* image effects */ | ||
101 | |||
102 | #define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) | ||
103 | |||
104 | #define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) | ||
105 | #define REG_FPS_30 0x02 | ||
106 | |||
107 | #define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) | ||
108 | #define REG_INTERFACE_MIPI 0x02 | ||
109 | |||
110 | #define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) | ||
111 | #define REG_EFFECT_OFF 0x00 | ||
112 | #define REG_EFFECT_NEGA 0x01 | ||
113 | #define REG_EFFECT_EMBOSS 0x06 | ||
114 | #define REG_EFFECT_OUTLINE 0x07 | ||
115 | #define REG_EFFECT_WATERCOLOR 0x08 | ||
116 | |||
117 | /* | ||
118 | * Category 2 - MONITOR mode | ||
119 | * | ||
120 | * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another | ||
121 | * mode named "Preview", but this preview mode is used at the case specific | ||
122 | * vider-recording mode. This mmode supports only YUYV format. On the other | ||
123 | * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are | ||
124 | * another options like zoom/color effect(different with effect in PARAMETER | ||
125 | * mode)/anti hand shaking algorithm. | ||
126 | */ | ||
127 | #define CAT2_ZOOM 0x01 /* set the zoom position & execute */ | ||
128 | #define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ | ||
129 | #define CAT2_CFIXB 0x09 /* CB value for color effect */ | ||
130 | #define CAT2_CFIXR 0x0a /* CR value for color effect */ | ||
131 | #define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ | ||
132 | #define CAT2_CHROMA_LVL 0x0f /* set chroma level */ | ||
133 | #define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ | ||
134 | #define CAT2_EDGE_LVL 0x11 /* set sharpness level */ | ||
135 | #define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ | ||
136 | #define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ | ||
137 | |||
138 | #define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) | ||
139 | |||
140 | #define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) | ||
141 | #define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) | ||
142 | #define REG_CFIXB_SEPIA 0xd8 | ||
143 | #define REG_CFIXR_SEPIA 0x18 | ||
144 | |||
145 | #define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) | ||
146 | #define REG_COLOR_EFFECT_OFF 0x00 | ||
147 | #define REG_COLOR_EFFECT_ON 0x01 | ||
148 | |||
149 | #define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) | ||
150 | #define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) | ||
151 | #define REG_CHROMA_OFF 0x00 | ||
152 | #define REG_CHROMA_ON 0x01 | ||
153 | |||
154 | #define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) | ||
155 | #define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) | ||
156 | #define REG_EDGE_OFF 0x00 | ||
157 | #define REG_EDGE_ON 0x01 | ||
158 | |||
159 | #define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) | ||
160 | |||
161 | /* | ||
162 | * Category 3 - Auto Exposure | ||
163 | * | ||
164 | * The M-5MOLS exposure capbility is detailed as which is similar to digital | ||
165 | * camera. This category supports AE locking/various AE mode(range of exposure) | ||
166 | * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the | ||
167 | * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be | ||
168 | * different. So, this category also provide getting the max/min values. And, | ||
169 | * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. | ||
170 | */ | ||
171 | #define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ | ||
172 | #define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ | ||
173 | #define CAT3_ISO 0x05 /* set ISO */ | ||
174 | #define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ | ||
175 | #define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ | ||
176 | #define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ | ||
177 | #define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ | ||
178 | #define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ | ||
179 | #define CAT3_AE_INDEX 0x38 /* AE index */ | ||
180 | |||
181 | #define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) | ||
182 | #define REG_AE_UNLOCK 0x00 | ||
183 | #define REG_AE_LOCK 0x01 | ||
184 | |||
185 | #define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) | ||
186 | #define REG_AE_OFF 0x00 /* AE off */ | ||
187 | #define REG_AE_ALL 0x01 /* calc AE in all block integral */ | ||
188 | #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ | ||
189 | #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ | ||
190 | |||
191 | #define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) | ||
192 | #define REG_ISO_AUTO 0x00 | ||
193 | #define REG_ISO_50 0x01 | ||
194 | #define REG_ISO_100 0x02 | ||
195 | #define REG_ISO_200 0x03 | ||
196 | #define REG_ISO_400 0x04 | ||
197 | #define REG_ISO_800 0x05 | ||
198 | |||
199 | #define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) | ||
200 | #define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) | ||
201 | #define REG_SCENE_NORMAL 0x00 | ||
202 | #define REG_SCENE_PORTRAIT 0x01 | ||
203 | #define REG_SCENE_LANDSCAPE 0x02 | ||
204 | #define REG_SCENE_SPORTS 0x03 | ||
205 | #define REG_SCENE_PARTY_INDOOR 0x04 | ||
206 | #define REG_SCENE_BEACH_SNOW 0x05 | ||
207 | #define REG_SCENE_SUNSET 0x06 | ||
208 | #define REG_SCENE_DAWN_DUSK 0x07 | ||
209 | #define REG_SCENE_FALL 0x08 | ||
210 | #define REG_SCENE_NIGHT 0x09 | ||
211 | #define REG_SCENE_AGAINST_LIGHT 0x0a | ||
212 | #define REG_SCENE_FIRE 0x0b | ||
213 | #define REG_SCENE_TEXT 0x0c | ||
214 | #define REG_SCENE_CANDLE 0x0d | ||
215 | |||
216 | #define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) | ||
217 | #define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) | ||
218 | #define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) | ||
219 | |||
220 | #define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) | ||
221 | #define REG_AE_INDEX_20_NEG 0x00 | ||
222 | #define REG_AE_INDEX_15_NEG 0x01 | ||
223 | #define REG_AE_INDEX_10_NEG 0x02 | ||
224 | #define REG_AE_INDEX_05_NEG 0x03 | ||
225 | #define REG_AE_INDEX_00 0x04 | ||
226 | #define REG_AE_INDEX_05_POS 0x05 | ||
227 | #define REG_AE_INDEX_10_POS 0x06 | ||
228 | #define REG_AE_INDEX_15_POS 0x07 | ||
229 | #define REG_AE_INDEX_20_POS 0x08 | ||
230 | |||
231 | /* | ||
232 | * Category 6 - White Balance | ||
233 | * | ||
234 | * This category provide AWB locking/mode/preset/speed/gain bias, etc. | ||
235 | */ | ||
236 | #define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ | ||
237 | #define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ | ||
238 | #define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ | ||
239 | |||
240 | #define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) | ||
241 | #define REG_AWB_UNLOCK 0x00 | ||
242 | #define REG_AWB_LOCK 0x01 | ||
243 | |||
244 | #define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) | ||
245 | #define REG_AWB_AUTO 0x01 /* AWB off */ | ||
246 | #define REG_AWB_PRESET 0x02 /* AWB preset */ | ||
247 | |||
248 | #define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) | ||
249 | #define REG_AWB_INCANDESCENT 0x01 | ||
250 | #define REG_AWB_FLUORESCENT_1 0x02 | ||
251 | #define REG_AWB_FLUORESCENT_2 0x03 | ||
252 | #define REG_AWB_DAYLIGHT 0x04 | ||
253 | #define REG_AWB_CLOUDY 0x05 | ||
254 | #define REG_AWB_SHADE 0x06 | ||
255 | #define REG_AWB_HORIZON 0x07 | ||
256 | #define REG_AWB_LEDLIGHT 0x09 | ||
257 | |||
258 | /* | ||
259 | * Category 7 - EXIF information | ||
260 | */ | ||
261 | #define CAT7_INFO_EXPTIME_NU 0x00 | ||
262 | #define CAT7_INFO_EXPTIME_DE 0x04 | ||
263 | #define CAT7_INFO_TV_NU 0x08 | ||
264 | #define CAT7_INFO_TV_DE 0x0c | ||
265 | #define CAT7_INFO_AV_NU 0x10 | ||
266 | #define CAT7_INFO_AV_DE 0x14 | ||
267 | #define CAT7_INFO_BV_NU 0x18 | ||
268 | #define CAT7_INFO_BV_DE 0x1c | ||
269 | #define CAT7_INFO_EBV_NU 0x20 | ||
270 | #define CAT7_INFO_EBV_DE 0x24 | ||
271 | #define CAT7_INFO_ISO 0x28 | ||
272 | #define CAT7_INFO_FLASH 0x2a | ||
273 | #define CAT7_INFO_SDR 0x2c | ||
274 | #define CAT7_INFO_QVAL 0x2e | ||
275 | |||
276 | #define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) | ||
277 | #define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) | ||
278 | #define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) | ||
279 | #define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) | ||
280 | #define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) | ||
281 | #define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) | ||
282 | #define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) | ||
283 | #define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) | ||
284 | #define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) | ||
285 | #define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) | ||
286 | #define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) | ||
287 | #define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) | ||
288 | #define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) | ||
289 | #define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) | ||
290 | |||
291 | /* | ||
292 | * Category 9 - Face Detection | ||
293 | */ | ||
294 | #define CAT9_FD_CTL 0x00 | ||
295 | |||
296 | #define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) | ||
297 | #define BIT_FD_EN 0 | ||
298 | #define BIT_FD_DRAW_FACE_FRAME 4 | ||
299 | #define BIT_FD_DRAW_SMILE_LVL 6 | ||
300 | #define REG_FD(shift) (1 << shift) | ||
301 | #define REG_FD_OFF 0x0 | ||
302 | |||
303 | /* | ||
304 | * Category A - Lens Parameter | ||
305 | */ | ||
306 | #define CATA_AF_MODE 0x01 | ||
307 | #define CATA_AF_EXECUTE 0x02 | ||
308 | #define CATA_AF_STATUS 0x03 | ||
309 | #define CATA_AF_VERSION 0x0a | ||
310 | |||
311 | #define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) | ||
312 | #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ | ||
313 | #define REG_AF_MACRO 0x01 /* Macro AF, one time */ | ||
314 | #define REG_AF_POWEROFF 0x07 | ||
315 | |||
316 | #define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) | ||
317 | #define REG_AF_STOP 0x00 | ||
318 | #define REG_AF_EXE_AUTO 0x01 | ||
319 | #define REG_AF_EXE_CAF 0x02 | ||
320 | |||
321 | #define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) | ||
322 | #define REG_AF_FAIL 0x00 | ||
323 | #define REG_AF_SUCCESS 0x02 | ||
324 | #define REG_AF_IDLE 0x04 | ||
325 | #define REG_AF_BUSY 0x05 | ||
326 | |||
327 | #define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) | ||
328 | |||
329 | /* | ||
330 | * Category B - CAPTURE Parameter | ||
331 | */ | ||
332 | #define CATB_YUVOUT_MAIN 0x00 | ||
333 | #define CATB_MAIN_IMAGE_SIZE 0x01 | ||
334 | #define CATB_MCC_MODE 0x1d | ||
335 | #define CATB_WDR_EN 0x2c | ||
336 | #define CATB_LIGHT_CTRL 0x40 | ||
337 | #define CATB_FLASH_CTRL 0x41 | ||
338 | |||
339 | #define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) | ||
340 | #define REG_YUV422 0x00 | ||
341 | #define REG_BAYER10 0x05 | ||
342 | #define REG_BAYER8 0x06 | ||
343 | #define REG_JPEG 0x10 | ||
344 | |||
345 | #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) | ||
346 | |||
347 | #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) | ||
348 | #define REG_MCC_OFF 0x00 | ||
349 | #define REG_MCC_NORMAL 0x01 | ||
350 | |||
351 | #define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) | ||
352 | #define REG_WDR_OFF 0x00 | ||
353 | #define REG_WDR_ON 0x01 | ||
354 | #define REG_WDR_AUTO 0x02 | ||
355 | |||
356 | #define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) | ||
357 | #define REG_LIGHT_OFF 0x00 | ||
358 | #define REG_LIGHT_ON 0x01 | ||
359 | #define REG_LIGHT_AUTO 0x02 | ||
360 | |||
361 | #define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) | ||
362 | #define REG_FLASH_OFF 0x00 | ||
363 | #define REG_FLASH_ON 0x01 | ||
364 | #define REG_FLASH_AUTO 0x02 | ||
365 | |||
366 | /* | ||
367 | * Category C - CAPTURE Control | ||
368 | */ | ||
369 | #define CATC_CAP_MODE 0x00 | ||
370 | #define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ | ||
371 | #define CATC_CAP_START 0x09 | ||
372 | #define CATC_CAP_IMAGE_SIZE 0x0d | ||
373 | #define CATC_CAP_THUMB_SIZE 0x11 | ||
374 | |||
375 | #define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) | ||
376 | #define REG_CAP_NONE 0x00 | ||
377 | #define REG_CAP_ANTI_SHAKE 0x02 | ||
378 | |||
379 | #define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) | ||
380 | |||
381 | #define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) | ||
382 | #define REG_CAP_START_MAIN 0x01 | ||
383 | #define REG_CAP_START_THUMB 0x03 | ||
384 | |||
385 | #define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1) | ||
386 | #define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1) | ||
387 | |||
388 | /* | ||
389 | * Category F - Flash | ||
390 | * | ||
391 | * This mode provides functions about internal flash stuff and system startup. | ||
392 | */ | ||
393 | #define CATF_CAM_START 0x12 /* It starts internal ARM core booting | ||
394 | * after power-up */ | ||
395 | |||
396 | #define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) | ||
397 | #define REG_START_ARM_BOOT 0x01 | ||
398 | |||
399 | #endif /* M5MOLS_REG_H */ | ||
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile index 968c1994eda0..2071ca8a2f03 100644 --- a/drivers/media/video/uvc/Makefile +++ b/drivers/media/video/uvc/Makefile | |||
@@ -1,3 +1,6 @@ | |||
1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ | 1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ |
2 | uvc_status.o uvc_isight.o | 2 | uvc_status.o uvc_isight.o |
3 | ifeq ($(CONFIG_MEDIA_CONTROLLER),y) | ||
4 | uvcvideo-objs += uvc_entity.o | ||
5 | endif | ||
3 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o | 6 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o |
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 823f4b389745..b6eae48d7fb8 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -248,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) | |||
248 | * Terminal and unit management | 248 | * Terminal and unit management |
249 | */ | 249 | */ |
250 | 250 | ||
251 | static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) | 251 | struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) |
252 | { | 252 | { |
253 | struct uvc_entity *entity; | 253 | struct uvc_entity *entity; |
254 | 254 | ||
@@ -795,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
795 | struct uvc_entity *entity; | 795 | struct uvc_entity *entity; |
796 | unsigned int num_inputs; | 796 | unsigned int num_inputs; |
797 | unsigned int size; | 797 | unsigned int size; |
798 | unsigned int i; | ||
798 | 799 | ||
800 | extra_size = ALIGN(extra_size, sizeof(*entity->pads)); | ||
799 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; | 801 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; |
800 | size = sizeof(*entity) + extra_size + num_inputs; | 802 | size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads |
803 | + num_inputs; | ||
801 | entity = kzalloc(size, GFP_KERNEL); | 804 | entity = kzalloc(size, GFP_KERNEL); |
802 | if (entity == NULL) | 805 | if (entity == NULL) |
803 | return NULL; | 806 | return NULL; |
@@ -805,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
805 | entity->id = id; | 808 | entity->id = id; |
806 | entity->type = type; | 809 | entity->type = type; |
807 | 810 | ||
811 | entity->num_links = 0; | ||
812 | entity->num_pads = num_pads; | ||
813 | entity->pads = ((void *)(entity + 1)) + extra_size; | ||
814 | |||
815 | for (i = 0; i < num_inputs; ++i) | ||
816 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; | ||
817 | if (!UVC_ENTITY_IS_OTERM(entity)) | ||
818 | entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; | ||
819 | |||
808 | entity->bNrInPins = num_inputs; | 820 | entity->bNrInPins = num_inputs; |
809 | entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; | 821 | entity->baSourceID = (__u8 *)(&entity->pads[num_pads]); |
810 | 822 | ||
811 | return entity; | 823 | return entity; |
812 | } | 824 | } |
@@ -1585,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
1585 | uvc_status_cleanup(dev); | 1597 | uvc_status_cleanup(dev); |
1586 | uvc_ctrl_cleanup_device(dev); | 1598 | uvc_ctrl_cleanup_device(dev); |
1587 | 1599 | ||
1600 | if (dev->vdev.dev) | ||
1601 | v4l2_device_unregister(&dev->vdev); | ||
1602 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1603 | if (media_devnode_is_registered(&dev->mdev.devnode)) | ||
1604 | media_device_unregister(&dev->mdev); | ||
1605 | #endif | ||
1606 | |||
1588 | list_for_each_safe(p, n, &dev->chains) { | 1607 | list_for_each_safe(p, n, &dev->chains) { |
1589 | struct uvc_video_chain *chain; | 1608 | struct uvc_video_chain *chain; |
1590 | chain = list_entry(p, struct uvc_video_chain, list); | 1609 | chain = list_entry(p, struct uvc_video_chain, list); |
@@ -1594,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
1594 | list_for_each_safe(p, n, &dev->entities) { | 1613 | list_for_each_safe(p, n, &dev->entities) { |
1595 | struct uvc_entity *entity; | 1614 | struct uvc_entity *entity; |
1596 | entity = list_entry(p, struct uvc_entity, list); | 1615 | entity = list_entry(p, struct uvc_entity, list); |
1616 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1617 | uvc_mc_cleanup_entity(entity); | ||
1618 | #endif | ||
1619 | if (entity->vdev) { | ||
1620 | video_device_release(entity->vdev); | ||
1621 | entity->vdev = NULL; | ||
1622 | } | ||
1597 | kfree(entity); | 1623 | kfree(entity); |
1598 | } | 1624 | } |
1599 | 1625 | ||
@@ -1616,8 +1642,6 @@ static void uvc_release(struct video_device *vdev) | |||
1616 | struct uvc_streaming *stream = video_get_drvdata(vdev); | 1642 | struct uvc_streaming *stream = video_get_drvdata(vdev); |
1617 | struct uvc_device *dev = stream->dev; | 1643 | struct uvc_device *dev = stream->dev; |
1618 | 1644 | ||
1619 | video_device_release(vdev); | ||
1620 | |||
1621 | /* Decrement the registered streams count and delete the device when it | 1645 | /* Decrement the registered streams count and delete the device when it |
1622 | * reaches zero. | 1646 | * reaches zero. |
1623 | */ | 1647 | */ |
@@ -1682,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1682 | * unregistered before the reference is released, so we don't need to | 1706 | * unregistered before the reference is released, so we don't need to |
1683 | * get another one. | 1707 | * get another one. |
1684 | */ | 1708 | */ |
1685 | vdev->parent = &dev->intf->dev; | 1709 | vdev->v4l2_dev = &dev->vdev; |
1686 | vdev->fops = &uvc_fops; | 1710 | vdev->fops = &uvc_fops; |
1687 | vdev->release = uvc_release; | 1711 | vdev->release = uvc_release; |
1688 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | 1712 | strlcpy(vdev->name, dev->name, sizeof vdev->name); |
@@ -1731,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev, | |||
1731 | ret = uvc_register_video(dev, stream); | 1755 | ret = uvc_register_video(dev, stream); |
1732 | if (ret < 0) | 1756 | if (ret < 0) |
1733 | return ret; | 1757 | return ret; |
1758 | |||
1759 | term->vdev = stream->vdev; | ||
1734 | } | 1760 | } |
1735 | 1761 | ||
1736 | return 0; | 1762 | return 0; |
@@ -1745,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
1745 | ret = uvc_register_terms(dev, chain); | 1771 | ret = uvc_register_terms(dev, chain); |
1746 | if (ret < 0) | 1772 | if (ret < 0) |
1747 | return ret; | 1773 | return ret; |
1774 | |||
1775 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1776 | ret = uvc_mc_register_entities(chain); | ||
1777 | if (ret < 0) { | ||
1778 | uvc_printk(KERN_INFO, "Failed to register entites " | ||
1779 | "(%d).\n", ret); | ||
1780 | } | ||
1781 | #endif | ||
1748 | } | 1782 | } |
1749 | 1783 | ||
1750 | return 0; | 1784 | return 0; |
@@ -1814,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf, | |||
1814 | "linux-uvc-devel mailing list.\n"); | 1848 | "linux-uvc-devel mailing list.\n"); |
1815 | } | 1849 | } |
1816 | 1850 | ||
1851 | /* Register the media and V4L2 devices. */ | ||
1852 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
1853 | dev->mdev.dev = &intf->dev; | ||
1854 | strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); | ||
1855 | if (udev->serial) | ||
1856 | strlcpy(dev->mdev.serial, udev->serial, | ||
1857 | sizeof(dev->mdev.serial)); | ||
1858 | strcpy(dev->mdev.bus_info, udev->devpath); | ||
1859 | dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); | ||
1860 | dev->mdev.driver_version = DRIVER_VERSION_NUMBER; | ||
1861 | if (media_device_register(&dev->mdev) < 0) | ||
1862 | goto error; | ||
1863 | |||
1864 | dev->vdev.mdev = &dev->mdev; | ||
1865 | #endif | ||
1866 | if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) | ||
1867 | goto error; | ||
1868 | |||
1817 | /* Initialize controls. */ | 1869 | /* Initialize controls. */ |
1818 | if (uvc_ctrl_init_device(dev) < 0) | 1870 | if (uvc_ctrl_init_device(dev) < 0) |
1819 | goto error; | 1871 | goto error; |
@@ -1822,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
1822 | if (uvc_scan_device(dev) < 0) | 1874 | if (uvc_scan_device(dev) < 0) |
1823 | goto error; | 1875 | goto error; |
1824 | 1876 | ||
1825 | /* Register video devices. */ | 1877 | /* Register video device nodes. */ |
1826 | if (uvc_register_chains(dev) < 0) | 1878 | if (uvc_register_chains(dev) < 0) |
1827 | goto error; | 1879 | goto error; |
1828 | 1880 | ||
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c new file mode 100644 index 000000000000..ede7852bb1df --- /dev/null +++ b/drivers/media/video/uvc/uvc_entity.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * uvc_entity.c -- USB Video Class driver | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 | ||
5 | * Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
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 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | |||
18 | #include <media/v4l2-common.h> | ||
19 | |||
20 | #include "uvcvideo.h" | ||
21 | |||
22 | /* ------------------------------------------------------------------------ | ||
23 | * Video subdevices registration and unregistration | ||
24 | */ | ||
25 | |||
26 | static int uvc_mc_register_entity(struct uvc_video_chain *chain, | ||
27 | struct uvc_entity *entity) | ||
28 | { | ||
29 | const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; | ||
30 | struct uvc_entity *remote; | ||
31 | unsigned int i; | ||
32 | u8 remote_pad; | ||
33 | int ret; | ||
34 | |||
35 | for (i = 0; i < entity->num_pads; ++i) { | ||
36 | struct media_entity *source; | ||
37 | struct media_entity *sink; | ||
38 | |||
39 | if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) | ||
40 | continue; | ||
41 | |||
42 | remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); | ||
43 | if (remote == NULL) | ||
44 | return -EINVAL; | ||
45 | |||
46 | source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) | ||
47 | ? &remote->vdev->entity : &remote->subdev.entity; | ||
48 | sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) | ||
49 | ? &entity->vdev->entity : &entity->subdev.entity; | ||
50 | |||
51 | remote_pad = remote->num_pads - 1; | ||
52 | ret = media_entity_create_link(source, remote_pad, | ||
53 | sink, i, flags); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) | ||
59 | ret = v4l2_device_register_subdev(&chain->dev->vdev, | ||
60 | &entity->subdev); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static struct v4l2_subdev_ops uvc_subdev_ops = { | ||
66 | }; | ||
67 | |||
68 | void uvc_mc_cleanup_entity(struct uvc_entity *entity) | ||
69 | { | ||
70 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) | ||
71 | media_entity_cleanup(&entity->subdev.entity); | ||
72 | else if (entity->vdev != NULL) | ||
73 | media_entity_cleanup(&entity->vdev->entity); | ||
74 | } | ||
75 | |||
76 | static int uvc_mc_init_entity(struct uvc_entity *entity) | ||
77 | { | ||
78 | int ret; | ||
79 | |||
80 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) { | ||
81 | v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops); | ||
82 | strlcpy(entity->subdev.name, entity->name, | ||
83 | sizeof(entity->subdev.name)); | ||
84 | |||
85 | ret = media_entity_init(&entity->subdev.entity, | ||
86 | entity->num_pads, entity->pads, 0); | ||
87 | } else | ||
88 | ret = media_entity_init(&entity->vdev->entity, | ||
89 | entity->num_pads, entity->pads, 0); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | int uvc_mc_register_entities(struct uvc_video_chain *chain) | ||
95 | { | ||
96 | struct uvc_entity *entity; | ||
97 | int ret; | ||
98 | |||
99 | list_for_each_entry(entity, &chain->entities, chain) { | ||
100 | ret = uvc_mc_init_entity(entity); | ||
101 | if (ret < 0) { | ||
102 | uvc_printk(KERN_INFO, "Failed to initialize entity for " | ||
103 | "entity %u\n", entity->id); | ||
104 | return ret; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | list_for_each_entry(entity, &chain->entities, chain) { | ||
109 | ret = uvc_mc_register_entity(chain, entity); | ||
110 | if (ret < 0) { | ||
111 | uvc_printk(KERN_INFO, "Failed to register entity for " | ||
112 | "entity %u\n", entity->id); | ||
113 | return ret; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 7cf224bae2e5..20107fd3574d 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -98,8 +98,11 @@ struct uvc_xu_control { | |||
98 | #ifdef __KERNEL__ | 98 | #ifdef __KERNEL__ |
99 | 99 | ||
100 | #include <linux/poll.h> | 100 | #include <linux/poll.h> |
101 | #include <linux/usb.h> | ||
101 | #include <linux/usb/video.h> | 102 | #include <linux/usb/video.h> |
102 | #include <linux/uvcvideo.h> | 103 | #include <linux/uvcvideo.h> |
104 | #include <media/media-device.h> | ||
105 | #include <media/v4l2-device.h> | ||
103 | 106 | ||
104 | /* -------------------------------------------------------------------------- | 107 | /* -------------------------------------------------------------------------- |
105 | * UVC constants | 108 | * UVC constants |
@@ -301,6 +304,13 @@ struct uvc_entity { | |||
301 | __u16 type; | 304 | __u16 type; |
302 | char name[64]; | 305 | char name[64]; |
303 | 306 | ||
307 | /* Media controller-related fields. */ | ||
308 | struct video_device *vdev; | ||
309 | struct v4l2_subdev subdev; | ||
310 | unsigned int num_pads; | ||
311 | unsigned int num_links; | ||
312 | struct media_pad *pads; | ||
313 | |||
304 | union { | 314 | union { |
305 | struct { | 315 | struct { |
306 | __u16 wObjectiveFocalLengthMin; | 316 | __u16 wObjectiveFocalLengthMin; |
@@ -504,6 +514,10 @@ struct uvc_device { | |||
504 | atomic_t nmappings; | 514 | atomic_t nmappings; |
505 | 515 | ||
506 | /* Video control interface */ | 516 | /* Video control interface */ |
517 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
518 | struct media_device mdev; | ||
519 | #endif | ||
520 | struct v4l2_device vdev; | ||
507 | __u16 uvc_version; | 521 | __u16 uvc_version; |
508 | __u32 clock_frequency; | 522 | __u32 clock_frequency; |
509 | 523 | ||
@@ -583,6 +597,8 @@ extern unsigned int uvc_timeout_param; | |||
583 | /* Core driver */ | 597 | /* Core driver */ |
584 | extern struct uvc_driver uvc_driver; | 598 | extern struct uvc_driver uvc_driver; |
585 | 599 | ||
600 | extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); | ||
601 | |||
586 | /* Video buffers queue management. */ | 602 | /* Video buffers queue management. */ |
587 | extern void uvc_queue_init(struct uvc_video_queue *queue, | 603 | extern void uvc_queue_init(struct uvc_video_queue *queue, |
588 | enum v4l2_buf_type type, int drop_corrupted); | 604 | enum v4l2_buf_type type, int drop_corrupted); |
@@ -616,6 +632,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) | |||
616 | /* V4L2 interface */ | 632 | /* V4L2 interface */ |
617 | extern const struct v4l2_file_operations uvc_fops; | 633 | extern const struct v4l2_file_operations uvc_fops; |
618 | 634 | ||
635 | /* Media controller */ | ||
636 | extern int uvc_mc_register_entities(struct uvc_video_chain *chain); | ||
637 | extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); | ||
638 | |||
619 | /* Video */ | 639 | /* Video */ |
620 | extern int uvc_video_init(struct uvc_streaming *stream); | 640 | extern int uvc_video_init(struct uvc_streaming *stream); |
621 | extern int uvc_video_suspend(struct uvc_streaming *stream); | 641 | extern int uvc_video_suspend(struct uvc_streaming *stream); |