[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>
This commit is contained in:
parent
575d6252a7
commit
ce808a478a
@ -163,7 +163,6 @@ struct m5mols_version {
|
|||||||
* @ffmt: current fmt according to resolution type
|
* @ffmt: current fmt according to resolution type
|
||||||
* @res_type: current resolution type
|
* @res_type: current resolution type
|
||||||
* @irq_waitq: waitqueue for the capture
|
* @irq_waitq: waitqueue for the capture
|
||||||
* @work_irq: workqueue for the IRQ
|
|
||||||
* @flags: state variable for the interrupt handler
|
* @flags: state variable for the interrupt handler
|
||||||
* @handle: control handler
|
* @handle: control handler
|
||||||
* @autoexposure: Auto Exposure control
|
* @autoexposure: Auto Exposure control
|
||||||
@ -180,7 +179,6 @@ struct m5mols_version {
|
|||||||
* @lock_ae: true means the Auto Exposure is locked
|
* @lock_ae: true means the Auto Exposure is locked
|
||||||
* @lock_awb: true means the Aut WhiteBalance is locked
|
* @lock_awb: true means the Aut WhiteBalance is locked
|
||||||
* @resolution: register value for current resolution
|
* @resolution: register value for current resolution
|
||||||
* @interrupt: register value for current interrupt status
|
|
||||||
* @mode: register value for current operation mode
|
* @mode: register value for current operation mode
|
||||||
* @mode_save: register value for current operation mode for saving
|
* @mode_save: register value for current operation mode for saving
|
||||||
* @set_power: optional power callback to the board code
|
* @set_power: optional power callback to the board code
|
||||||
@ -192,8 +190,7 @@ struct m5mols_info {
|
|||||||
struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
|
struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
|
||||||
int res_type;
|
int res_type;
|
||||||
wait_queue_head_t irq_waitq;
|
wait_queue_head_t irq_waitq;
|
||||||
struct work_struct work_irq;
|
atomic_t irq_done;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
struct v4l2_ctrl_handler handle;
|
struct v4l2_ctrl_handler handle;
|
||||||
/* Autoexposure/exposure control cluster */
|
/* Autoexposure/exposure control cluster */
|
||||||
@ -213,14 +210,11 @@ struct m5mols_info {
|
|||||||
bool lock_ae;
|
bool lock_ae;
|
||||||
bool lock_awb;
|
bool lock_awb;
|
||||||
u8 resolution;
|
u8 resolution;
|
||||||
u8 interrupt;
|
|
||||||
u8 mode;
|
u8 mode;
|
||||||
u8 mode_save;
|
u8 mode_save;
|
||||||
int (*set_power)(struct device *dev, int on);
|
int (*set_power)(struct device *dev, int on);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ST_CAPT_IRQ 0
|
|
||||||
|
|
||||||
#define is_powered(__info) (__info->power)
|
#define is_powered(__info) (__info->power)
|
||||||
#define is_ctrl_synced(__info) (__info->ctrl_sync)
|
#define is_ctrl_synced(__info) (__info->ctrl_sync)
|
||||||
#define is_available_af(__info) (__info->ver.af)
|
#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,
|
|||||||
int m5mols_mode(struct m5mols_info *info, u8 mode);
|
int m5mols_mode(struct m5mols_info *info, u8 mode);
|
||||||
|
|
||||||
int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
|
int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
|
||||||
|
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
|
||||||
int m5mols_sync_controls(struct m5mols_info *info);
|
int m5mols_sync_controls(struct m5mols_info *info);
|
||||||
int m5mols_start_capture(struct m5mols_info *info);
|
int m5mols_start_capture(struct m5mols_info *info);
|
||||||
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
|
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
|
||||||
|
@ -29,22 +29,6 @@
|
|||||||
#include "m5mols.h"
|
#include "m5mols.h"
|
||||||
#include "m5mols_reg.h"
|
#include "m5mols_reg.h"
|
||||||
|
|
||||||
static int m5mols_capture_error_handler(struct m5mols_info *info,
|
|
||||||
int timeout)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Disable all interrupts and clear relevant interrupt staus bits */
|
|
||||||
ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
|
|
||||||
info->interrupt & ~(REG_INT_CAPTURE));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (timeout == 0)
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* m5mols_read_rational - I2C read of a rational number
|
* m5mols_read_rational - I2C read of a rational number
|
||||||
*
|
*
|
||||||
@ -121,7 +105,6 @@ int m5mols_start_capture(struct m5mols_info *info)
|
|||||||
{
|
{
|
||||||
struct v4l2_subdev *sd = &info->sd;
|
struct v4l2_subdev *sd = &info->sd;
|
||||||
u8 resolution = info->resolution;
|
u8 resolution = info->resolution;
|
||||||
int timeout;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -142,14 +125,9 @@ int m5mols_start_capture(struct m5mols_info *info)
|
|||||||
ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
|
ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = m5mols_mode(info, REG_CAPTURE);
|
ret = m5mols_mode(info, REG_CAPTURE);
|
||||||
if (!ret) {
|
if (!ret)
|
||||||
/* Wait for capture interrupt, after changing capture mode */
|
/* Wait for capture interrupt, after changing capture mode */
|
||||||
timeout = wait_event_interruptible_timeout(info->irq_waitq,
|
ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
|
||||||
test_bit(ST_CAPT_IRQ, &info->flags),
|
|
||||||
msecs_to_jiffies(2000));
|
|
||||||
if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
|
|
||||||
ret = m5mols_capture_error_handler(info, timeout);
|
|
||||||
}
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = m5mols_lock_3a(info, false);
|
ret = m5mols_lock_3a(info, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -175,15 +153,13 @@ int m5mols_start_capture(struct m5mols_info *info)
|
|||||||
ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
|
ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
/* Wait for the capture completion interrupt */
|
/* Wait for the capture completion interrupt */
|
||||||
timeout = wait_event_interruptible_timeout(info->irq_waitq,
|
ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
|
||||||
test_bit(ST_CAPT_IRQ, &info->flags),
|
if (!ret) {
|
||||||
msecs_to_jiffies(2000));
|
|
||||||
if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
|
|
||||||
ret = m5mols_capture_info(info);
|
ret = m5mols_capture_info(info);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
v4l2_subdev_notify(sd, 0, &info->cap.total);
|
v4l2_subdev_notify(sd, 0, &info->cap.total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m5mols_capture_error_handler(info, timeout);
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -323,6 +323,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
|
||||||
|
{
|
||||||
|
struct m5mols_info *info = to_m5mols(sd);
|
||||||
|
|
||||||
|
int ret = wait_event_interruptible_timeout(info->irq_waitq,
|
||||||
|
atomic_add_unless(&info->irq_done, -1, 0),
|
||||||
|
msecs_to_jiffies(timeout));
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret ? ret : -ETIMEDOUT;
|
||||||
|
|
||||||
|
return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
|
||||||
|
M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* m5mols_reg_mode - Write the mode and check busy status
|
* m5mols_reg_mode - Write the mode and check busy status
|
||||||
*
|
*
|
||||||
@ -889,46 +903,12 @@ static const struct v4l2_subdev_ops m5mols_ops = {
|
|||||||
.video = &m5mols_video_ops,
|
.video = &m5mols_video_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void m5mols_irq_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct m5mols_info *info =
|
|
||||||
container_of(work, struct m5mols_info, work_irq);
|
|
||||||
struct v4l2_subdev *sd = &info->sd;
|
|
||||||
u8 reg;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!is_powered(info) ||
|
|
||||||
m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (info->interrupt & REG_INT_MASK) {
|
|
||||||
case REG_INT_AF:
|
|
||||||
if (!is_available_af(info))
|
|
||||||
break;
|
|
||||||
ret = m5mols_read_u8(sd, AF_STATUS, ®);
|
|
||||||
v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
|
|
||||||
reg == REG_AF_FAIL ? "Failed" :
|
|
||||||
reg == REG_AF_SUCCESS ? "Success" :
|
|
||||||
reg == REG_AF_IDLE ? "Idle" : "Busy");
|
|
||||||
break;
|
|
||||||
case REG_INT_CAPTURE:
|
|
||||||
if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
|
|
||||||
wake_up_interruptible(&info->irq_waitq);
|
|
||||||
|
|
||||||
v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t m5mols_irq_handler(int irq, void *data)
|
static irqreturn_t m5mols_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct v4l2_subdev *sd = data;
|
struct m5mols_info *info = to_m5mols(data);
|
||||||
struct m5mols_info *info = to_m5mols(sd);
|
|
||||||
|
|
||||||
schedule_work(&info->work_irq);
|
atomic_set(&info->irq_done, 1);
|
||||||
|
wake_up_interruptible(&info->irq_waitq);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -987,7 +967,6 @@ static int __devinit m5mols_probe(struct i2c_client *client,
|
|||||||
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
|
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
|
||||||
|
|
||||||
init_waitqueue_head(&info->irq_waitq);
|
init_waitqueue_head(&info->irq_waitq);
|
||||||
INIT_WORK(&info->work_irq, m5mols_irq_work);
|
|
||||||
ret = request_irq(client->irq, m5mols_irq_handler,
|
ret = request_irq(client->irq, m5mols_irq_handler,
|
||||||
IRQF_TRIGGER_RISING, MODULE_NAME, sd);
|
IRQF_TRIGGER_RISING, MODULE_NAME, sd);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -995,6 +974,7 @@ static int __devinit m5mols_probe(struct i2c_client *client,
|
|||||||
goto out_me;
|
goto out_me;
|
||||||
}
|
}
|
||||||
info->res_type = M5MOLS_RESTYPE_MONITOR;
|
info->res_type = M5MOLS_RESTYPE_MONITOR;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_me:
|
out_me:
|
||||||
media_entity_cleanup(&sd->entity);
|
media_entity_cleanup(&sd->entity);
|
||||||
|
Loading…
Reference in New Issue
Block a user