aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeungJun Kim <riverful.kim@samsung.com>2011-12-02 19:53:20 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-12-30 11:34:27 -0500
commitce808a478ae5b79e52ea170b35c459829296330f (patch)
treecd281cacb0756ea8b216a05cdefe10750afd85a3
parent575d6252a715c599964ec6ec06428e6362c0633e (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.h9
-rw-r--r--drivers/media/video/m5mols/m5mols_capture.c34
-rw-r--r--drivers/media/video/m5mols/m5mols_core.c56
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,
290int m5mols_mode(struct m5mols_info *info, u8 mode); 284int m5mols_mode(struct m5mols_info *info, u8 mode);
291 285
292int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); 286int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
287int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
293int m5mols_sync_controls(struct m5mols_info *info); 288int m5mols_sync_controls(struct m5mols_info *info);
294int m5mols_start_capture(struct m5mols_info *info); 289int m5mols_start_capture(struct m5mols_info *info);
295int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); 290int 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
32static 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
326int 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
892static 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, &reg);
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
926static irqreturn_t m5mols_irq_handler(int irq, void *data) 906static 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;
999out_me: 979out_me:
1000 media_entity_cleanup(&sd->entity); 980 media_entity_cleanup(&sd->entity);