diff options
author | HeungJun Kim <riverful.kim@samsung.com> | 2011-12-02 19:53:20 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-12-30 11:34:27 -0500 |
commit | ce808a478ae5b79e52ea170b35c459829296330f (patch) | |
tree | cd281cacb0756ea8b216a05cdefe10750afd85a3 | |
parent | 575d6252a715c599964ec6ec06428e6362c0633e (diff) |
[media] m5mols: Improve the interrupt handling routines
The work struct based interrupt handling is not flexible enough
as the M-5MOLS control sequence involves I2C access sequences
before and after an interrupt is generated. A single waitqueue is
enough for the job so remove the work struct based code.
Signed-off-by: HeungJun Kim <riverful.kim@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/m5mols/m5mols.h | 9 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_capture.c | 34 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_core.c | 56 |
3 files changed, 25 insertions, 74 deletions
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index f33171672c31..2829d4a95f6a 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h | |||
@@ -163,7 +163,6 @@ struct m5mols_version { | |||
163 | * @ffmt: current fmt according to resolution type | 163 | * @ffmt: current fmt according to resolution type |
164 | * @res_type: current resolution type | 164 | * @res_type: current resolution type |
165 | * @irq_waitq: waitqueue for the capture | 165 | * @irq_waitq: waitqueue for the capture |
166 | * @work_irq: workqueue for the IRQ | ||
167 | * @flags: state variable for the interrupt handler | 166 | * @flags: state variable for the interrupt handler |
168 | * @handle: control handler | 167 | * @handle: control handler |
169 | * @autoexposure: Auto Exposure control | 168 | * @autoexposure: Auto Exposure control |
@@ -180,7 +179,6 @@ struct m5mols_version { | |||
180 | * @lock_ae: true means the Auto Exposure is locked | 179 | * @lock_ae: true means the Auto Exposure is locked |
181 | * @lock_awb: true means the Aut WhiteBalance is locked | 180 | * @lock_awb: true means the Aut WhiteBalance is locked |
182 | * @resolution: register value for current resolution | 181 | * @resolution: register value for current resolution |
183 | * @interrupt: register value for current interrupt status | ||
184 | * @mode: register value for current operation mode | 182 | * @mode: register value for current operation mode |
185 | * @mode_save: register value for current operation mode for saving | 183 | * @mode_save: register value for current operation mode for saving |
186 | * @set_power: optional power callback to the board code | 184 | * @set_power: optional power callback to the board code |
@@ -192,8 +190,7 @@ struct m5mols_info { | |||
192 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | 190 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; |
193 | int res_type; | 191 | int res_type; |
194 | wait_queue_head_t irq_waitq; | 192 | wait_queue_head_t irq_waitq; |
195 | struct work_struct work_irq; | 193 | atomic_t irq_done; |
196 | unsigned long flags; | ||
197 | 194 | ||
198 | struct v4l2_ctrl_handler handle; | 195 | struct v4l2_ctrl_handler handle; |
199 | /* Autoexposure/exposure control cluster */ | 196 | /* Autoexposure/exposure control cluster */ |
@@ -213,14 +210,11 @@ struct m5mols_info { | |||
213 | bool lock_ae; | 210 | bool lock_ae; |
214 | bool lock_awb; | 211 | bool lock_awb; |
215 | u8 resolution; | 212 | u8 resolution; |
216 | u8 interrupt; | ||
217 | u8 mode; | 213 | u8 mode; |
218 | u8 mode_save; | 214 | u8 mode_save; |
219 | int (*set_power)(struct device *dev, int on); | 215 | int (*set_power)(struct device *dev, int on); |
220 | }; | 216 | }; |
221 | 217 | ||
222 | #define ST_CAPT_IRQ 0 | ||
223 | |||
224 | #define is_powered(__info) (__info->power) | 218 | #define is_powered(__info) (__info->power) |
225 | #define is_ctrl_synced(__info) (__info->ctrl_sync) | 219 | #define is_ctrl_synced(__info) (__info->ctrl_sync) |
226 | #define is_available_af(__info) (__info->ver.af) | 220 | #define is_available_af(__info) (__info->ver.af) |
@@ -290,6 +284,7 @@ int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | |||
290 | int m5mols_mode(struct m5mols_info *info, u8 mode); | 284 | int m5mols_mode(struct m5mols_info *info, u8 mode); |
291 | 285 | ||
292 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); | 286 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); |
287 | int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); | ||
293 | int m5mols_sync_controls(struct m5mols_info *info); | 288 | int m5mols_sync_controls(struct m5mols_info *info); |
294 | int m5mols_start_capture(struct m5mols_info *info); | 289 | int m5mols_start_capture(struct m5mols_info *info); |
295 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); | 290 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); |
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index 3248ac805711..090e50afbc9f 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c | |||
@@ -29,22 +29,6 @@ | |||
29 | #include "m5mols.h" | 29 | #include "m5mols.h" |
30 | #include "m5mols_reg.h" | 30 | #include "m5mols_reg.h" |
31 | 31 | ||
32 | static int m5mols_capture_error_handler(struct m5mols_info *info, | ||
33 | int timeout) | ||
34 | { | ||
35 | int ret; | ||
36 | |||
37 | /* Disable all interrupts and clear relevant interrupt staus bits */ | ||
38 | ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, | ||
39 | info->interrupt & ~(REG_INT_CAPTURE)); | ||
40 | if (ret) | ||
41 | return ret; | ||
42 | |||
43 | if (timeout == 0) | ||
44 | return -ETIMEDOUT; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | /** | 32 | /** |
49 | * m5mols_read_rational - I2C read of a rational number | 33 | * m5mols_read_rational - I2C read of a rational number |
50 | * | 34 | * |
@@ -121,7 +105,6 @@ int m5mols_start_capture(struct m5mols_info *info) | |||
121 | { | 105 | { |
122 | struct v4l2_subdev *sd = &info->sd; | 106 | struct v4l2_subdev *sd = &info->sd; |
123 | u8 resolution = info->resolution; | 107 | u8 resolution = info->resolution; |
124 | int timeout; | ||
125 | int ret; | 108 | int ret; |
126 | 109 | ||
127 | /* | 110 | /* |
@@ -142,14 +125,9 @@ int m5mols_start_capture(struct m5mols_info *info) | |||
142 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | 125 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); |
143 | if (!ret) | 126 | if (!ret) |
144 | ret = m5mols_mode(info, REG_CAPTURE); | 127 | ret = m5mols_mode(info, REG_CAPTURE); |
145 | if (!ret) { | 128 | if (!ret) |
146 | /* Wait for capture interrupt, after changing capture mode */ | 129 | /* Wait for capture interrupt, after changing capture mode */ |
147 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | 130 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); |
148 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
149 | msecs_to_jiffies(2000)); | ||
150 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) | ||
151 | ret = m5mols_capture_error_handler(info, timeout); | ||
152 | } | ||
153 | if (!ret) | 131 | if (!ret) |
154 | ret = m5mols_lock_3a(info, false); | 132 | ret = m5mols_lock_3a(info, false); |
155 | if (ret) | 133 | if (ret) |
@@ -175,15 +153,13 @@ int m5mols_start_capture(struct m5mols_info *info) | |||
175 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | 153 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); |
176 | if (!ret) { | 154 | if (!ret) { |
177 | /* Wait for the capture completion interrupt */ | 155 | /* Wait for the capture completion interrupt */ |
178 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | 156 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); |
179 | test_bit(ST_CAPT_IRQ, &info->flags), | 157 | if (!ret) { |
180 | msecs_to_jiffies(2000)); | ||
181 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { | ||
182 | ret = m5mols_capture_info(info); | 158 | ret = m5mols_capture_info(info); |
183 | if (!ret) | 159 | if (!ret) |
184 | v4l2_subdev_notify(sd, 0, &info->cap.total); | 160 | v4l2_subdev_notify(sd, 0, &info->cap.total); |
185 | } | 161 | } |
186 | } | 162 | } |
187 | 163 | ||
188 | return m5mols_capture_error_handler(info, timeout); | 164 | return ret; |
189 | } | 165 | } |
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 5005127bb11c..68f117a413af 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
@@ -323,6 +323,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) | |||
323 | return ret; | 323 | return ret; |
324 | } | 324 | } |
325 | 325 | ||
326 | int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) | ||
327 | { | ||
328 | struct m5mols_info *info = to_m5mols(sd); | ||
329 | |||
330 | int ret = wait_event_interruptible_timeout(info->irq_waitq, | ||
331 | atomic_add_unless(&info->irq_done, -1, 0), | ||
332 | msecs_to_jiffies(timeout)); | ||
333 | if (ret <= 0) | ||
334 | return ret ? ret : -ETIMEDOUT; | ||
335 | |||
336 | return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, | ||
337 | M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); | ||
338 | } | ||
339 | |||
326 | /** | 340 | /** |
327 | * m5mols_reg_mode - Write the mode and check busy status | 341 | * m5mols_reg_mode - Write the mode and check busy status |
328 | * | 342 | * |
@@ -889,46 +903,12 @@ static const struct v4l2_subdev_ops m5mols_ops = { | |||
889 | .video = &m5mols_video_ops, | 903 | .video = &m5mols_video_ops, |
890 | }; | 904 | }; |
891 | 905 | ||
892 | static void m5mols_irq_work(struct work_struct *work) | ||
893 | { | ||
894 | struct m5mols_info *info = | ||
895 | container_of(work, struct m5mols_info, work_irq); | ||
896 | struct v4l2_subdev *sd = &info->sd; | ||
897 | u8 reg; | ||
898 | int ret; | ||
899 | |||
900 | if (!is_powered(info) || | ||
901 | m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) | ||
902 | return; | ||
903 | |||
904 | switch (info->interrupt & REG_INT_MASK) { | ||
905 | case REG_INT_AF: | ||
906 | if (!is_available_af(info)) | ||
907 | break; | ||
908 | ret = m5mols_read_u8(sd, AF_STATUS, ®); | ||
909 | v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", | ||
910 | reg == REG_AF_FAIL ? "Failed" : | ||
911 | reg == REG_AF_SUCCESS ? "Success" : | ||
912 | reg == REG_AF_IDLE ? "Idle" : "Busy"); | ||
913 | break; | ||
914 | case REG_INT_CAPTURE: | ||
915 | if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) | ||
916 | wake_up_interruptible(&info->irq_waitq); | ||
917 | |||
918 | v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); | ||
919 | break; | ||
920 | default: | ||
921 | v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); | ||
922 | break; | ||
923 | }; | ||
924 | } | ||
925 | |||
926 | static irqreturn_t m5mols_irq_handler(int irq, void *data) | 906 | static irqreturn_t m5mols_irq_handler(int irq, void *data) |
927 | { | 907 | { |
928 | struct v4l2_subdev *sd = data; | 908 | struct m5mols_info *info = to_m5mols(data); |
929 | struct m5mols_info *info = to_m5mols(sd); | ||
930 | 909 | ||
931 | schedule_work(&info->work_irq); | 910 | atomic_set(&info->irq_done, 1); |
911 | wake_up_interruptible(&info->irq_waitq); | ||
932 | 912 | ||
933 | return IRQ_HANDLED; | 913 | return IRQ_HANDLED; |
934 | } | 914 | } |
@@ -987,7 +967,6 @@ static int __devinit m5mols_probe(struct i2c_client *client, | |||
987 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | 967 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; |
988 | 968 | ||
989 | init_waitqueue_head(&info->irq_waitq); | 969 | init_waitqueue_head(&info->irq_waitq); |
990 | INIT_WORK(&info->work_irq, m5mols_irq_work); | ||
991 | ret = request_irq(client->irq, m5mols_irq_handler, | 970 | ret = request_irq(client->irq, m5mols_irq_handler, |
992 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); | 971 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); |
993 | if (ret) { | 972 | if (ret) { |
@@ -995,6 +974,7 @@ static int __devinit m5mols_probe(struct i2c_client *client, | |||
995 | goto out_me; | 974 | goto out_me; |
996 | } | 975 | } |
997 | info->res_type = M5MOLS_RESTYPE_MONITOR; | 976 | info->res_type = M5MOLS_RESTYPE_MONITOR; |
977 | |||
998 | return 0; | 978 | return 0; |
999 | out_me: | 979 | out_me: |
1000 | media_entity_cleanup(&sd->entity); | 980 | media_entity_cleanup(&sd->entity); |