Commit 4e66a52a authored by Dave Stevenson's avatar Dave Stevenson Committed by Mauro Carvalho Chehab

[media] tc358743: Add support for platforms without IRQ line

interrupts is listed as an optional property in the DT
binding, but in reality the driver didn't work without it.
The existing driver relied on having the interrupt line
connected to the SoC to trigger handling various events.

Add the option to poll the interrupt status register via
a timer if no interrupt source is defined.
Signed-off-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.org>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 2da2391c
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -62,6 +63,8 @@ MODULE_LICENSE("GPL"); ...@@ -62,6 +63,8 @@ MODULE_LICENSE("GPL");
#define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2) #define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2)
#define POLL_INTERVAL_MS 1000
static const struct v4l2_dv_timings_cap tc358743_timings_cap = { static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
.type = V4L2_DV_BT_656_1120, .type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */ /* keep this initialization for compatibility with GCC < 4.4.6 */
...@@ -92,6 +95,9 @@ struct tc358743_state { ...@@ -92,6 +95,9 @@ struct tc358743_state {
struct delayed_work delayed_work_enable_hotplug; struct delayed_work delayed_work_enable_hotplug;
struct timer_list timer;
struct work_struct work_i2c_poll;
/* edid */ /* edid */
u8 edid_blocks_written; u8 edid_blocks_written;
...@@ -1320,6 +1326,24 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) ...@@ -1320,6 +1326,24 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
return handled ? IRQ_HANDLED : IRQ_NONE; 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, static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub) struct v4l2_event_subscription *sub)
{ {
...@@ -1938,6 +1962,14 @@ static int tc358743_probe(struct i2c_client *client, ...@@ -1938,6 +1962,14 @@ static int tc358743_probe(struct i2c_client *client,
"tc358743", state); "tc358743", state);
if (err) if (err)
goto err_work_queues; 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)); tc358743_enable_interrupts(sd, tx_5v_power_present(sd));
...@@ -1953,6 +1985,8 @@ static int tc358743_probe(struct i2c_client *client, ...@@ -1953,6 +1985,8 @@ static int tc358743_probe(struct i2c_client *client,
return 0; return 0;
err_work_queues: err_work_queues:
if (!state->i2c_client->irq)
flush_work(&state->work_i2c_poll);
cancel_delayed_work(&state->delayed_work_enable_hotplug); cancel_delayed_work(&state->delayed_work_enable_hotplug);
mutex_destroy(&state->confctl_mutex); mutex_destroy(&state->confctl_mutex);
err_hdl: err_hdl:
...@@ -1966,6 +2000,10 @@ static int tc358743_remove(struct i2c_client *client) ...@@ -1966,6 +2000,10 @@ static int tc358743_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client); struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct tc358743_state *state = to_state(sd); 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); cancel_delayed_work(&state->delayed_work_enable_hotplug);
v4l2_async_unregister_subdev(sd); v4l2_async_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd); v4l2_device_unregister_subdev(sd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment