Skip to content

Commit 4e66a52

Browse files
6by9mchehab
authored andcommitted
[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: Dave Stevenson <dave.stevenson@raspberrypi.org> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
1 parent 2da2391 commit 4e66a52

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

drivers/media/i2c/tc358743.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/delay.h>
3434
#include <linux/gpio/consumer.h>
3535
#include <linux/interrupt.h>
36+
#include <linux/timer.h>
3637
#include <linux/of_graph.h>
3738
#include <linux/videodev2.h>
3839
#include <linux/workqueue.h>
@@ -62,6 +63,8 @@ MODULE_LICENSE("GPL");
6263

6364
#define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2)
6465

66+
#define POLL_INTERVAL_MS 1000
67+
6568
static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
6669
.type = V4L2_DV_BT_656_1120,
6770
/* keep this initialization for compatibility with GCC < 4.4.6 */
@@ -92,6 +95,9 @@ struct tc358743_state {
9295

9396
struct delayed_work delayed_work_enable_hotplug;
9497

98+
struct timer_list timer;
99+
struct work_struct work_i2c_poll;
100+
95101
/* edid */
96102
u8 edid_blocks_written;
97103

@@ -1320,6 +1326,24 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
13201326
return handled ? IRQ_HANDLED : IRQ_NONE;
13211327
}
13221328

1329+
static void tc358743_irq_poll_timer(unsigned long arg)
1330+
{
1331+
struct tc358743_state *state = (struct tc358743_state *)arg;
1332+
1333+
schedule_work(&state->work_i2c_poll);
1334+
1335+
mod_timer(&state->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
1336+
}
1337+
1338+
static void tc358743_work_i2c_poll(struct work_struct *work)
1339+
{
1340+
struct tc358743_state *state = container_of(work,
1341+
struct tc358743_state, work_i2c_poll);
1342+
bool handled;
1343+
1344+
tc358743_isr(&state->sd, 0, &handled);
1345+
}
1346+
13231347
static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
13241348
struct v4l2_event_subscription *sub)
13251349
{
@@ -1938,6 +1962,14 @@ static int tc358743_probe(struct i2c_client *client,
19381962
"tc358743", state);
19391963
if (err)
19401964
goto err_work_queues;
1965+
} else {
1966+
INIT_WORK(&state->work_i2c_poll,
1967+
tc358743_work_i2c_poll);
1968+
state->timer.data = (unsigned long)state;
1969+
state->timer.function = tc358743_irq_poll_timer;
1970+
state->timer.expires = jiffies +
1971+
msecs_to_jiffies(POLL_INTERVAL_MS);
1972+
add_timer(&state->timer);
19411973
}
19421974

19431975
tc358743_enable_interrupts(sd, tx_5v_power_present(sd));
@@ -1953,6 +1985,8 @@ static int tc358743_probe(struct i2c_client *client,
19531985
return 0;
19541986

19551987
err_work_queues:
1988+
if (!state->i2c_client->irq)
1989+
flush_work(&state->work_i2c_poll);
19561990
cancel_delayed_work(&state->delayed_work_enable_hotplug);
19571991
mutex_destroy(&state->confctl_mutex);
19581992
err_hdl:
@@ -1966,6 +2000,10 @@ static int tc358743_remove(struct i2c_client *client)
19662000
struct v4l2_subdev *sd = i2c_get_clientdata(client);
19672001
struct tc358743_state *state = to_state(sd);
19682002

2003+
if (!state->i2c_client->irq) {
2004+
del_timer_sync(&state->timer);
2005+
flush_work(&state->work_i2c_poll);
2006+
}
19692007
cancel_delayed_work(&state->delayed_work_enable_hotplug);
19702008
v4l2_async_unregister_subdev(sd);
19712009
v4l2_device_unregister_subdev(sd);

0 commit comments

Comments
 (0)