|
@@ -33,6 +33,7 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/gpio/consumer.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
+#include <linux/timer.h>
|
|
|
#include <linux/of_graph.h>
|
|
|
#include <linux/videodev2.h>
|
|
|
#include <linux/workqueue.h>
|
|
@@ -62,6 +63,8 @@ MODULE_LICENSE("GPL");
|
|
|
|
|
|
#define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2)
|
|
|
|
|
|
+#define POLL_INTERVAL_MS 1000
|
|
|
+
|
|
|
static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
|
|
|
.type = V4L2_DV_BT_656_1120,
|
|
|
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
|
@@ -92,6 +95,9 @@ struct tc358743_state {
|
|
|
|
|
|
struct delayed_work delayed_work_enable_hotplug;
|
|
|
|
|
|
+ struct timer_list timer;
|
|
|
+ struct work_struct work_i2c_poll;
|
|
|
+
|
|
|
/* edid */
|
|
|
u8 edid_blocks_written;
|
|
|
|
|
@@ -1320,6 +1326,24 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
|
|
|
return handled ? IRQ_HANDLED : IRQ_NONE;
|
|
|
}
|
|
|
|
|
|
+static void tc358743_irq_poll_timer(unsigned long arg)
|
|
|
+{
|
|
|
+ struct tc358743_state *state = (struct tc358743_state *)arg;
|
|
|
+
|
|
|
+ schedule_work(&state->work_i2c_poll);
|
|
|
+
|
|
|
+ mod_timer(&state->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
|
|
|
+}
|
|
|
+
|
|
|
+static void tc358743_work_i2c_poll(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct tc358743_state *state = container_of(work,
|
|
|
+ struct tc358743_state, work_i2c_poll);
|
|
|
+ bool handled;
|
|
|
+
|
|
|
+ tc358743_isr(&state->sd, 0, &handled);
|
|
|
+}
|
|
|
+
|
|
|
static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
|
|
|
struct v4l2_event_subscription *sub)
|
|
|
{
|
|
@@ -1938,6 +1962,14 @@ static int tc358743_probe(struct i2c_client *client,
|
|
|
"tc358743", state);
|
|
|
if (err)
|
|
|
goto err_work_queues;
|
|
|
+ } else {
|
|
|
+ INIT_WORK(&state->work_i2c_poll,
|
|
|
+ tc358743_work_i2c_poll);
|
|
|
+ state->timer.data = (unsigned long)state;
|
|
|
+ state->timer.function = tc358743_irq_poll_timer;
|
|
|
+ state->timer.expires = jiffies +
|
|
|
+ msecs_to_jiffies(POLL_INTERVAL_MS);
|
|
|
+ add_timer(&state->timer);
|
|
|
}
|
|
|
|
|
|
tc358743_enable_interrupts(sd, tx_5v_power_present(sd));
|
|
@@ -1953,6 +1985,8 @@ static int tc358743_probe(struct i2c_client *client,
|
|
|
return 0;
|
|
|
|
|
|
err_work_queues:
|
|
|
+ if (!state->i2c_client->irq)
|
|
|
+ flush_work(&state->work_i2c_poll);
|
|
|
cancel_delayed_work(&state->delayed_work_enable_hotplug);
|
|
|
mutex_destroy(&state->confctl_mutex);
|
|
|
err_hdl:
|
|
@@ -1966,6 +2000,10 @@ static int tc358743_remove(struct i2c_client *client)
|
|
|
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
|
|
struct tc358743_state *state = to_state(sd);
|
|
|
|
|
|
+ if (!state->i2c_client->irq) {
|
|
|
+ del_timer_sync(&state->timer);
|
|
|
+ flush_work(&state->work_i2c_poll);
|
|
|
+ }
|
|
|
cancel_delayed_work(&state->delayed_work_enable_hotplug);
|
|
|
v4l2_async_unregister_subdev(sd);
|
|
|
v4l2_device_unregister_subdev(sd);
|