aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-01-30 16:37:08 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-25 12:02:45 -0400
commite9d50e9e7051a67783d75cd57ce360818b07d37b (patch)
treea6c0770da707de18e94622e2dd7a874480908b90 /drivers/media/i2c
parentc72a53ce059394749b6db067ba78ad2a317fd7e6 (diff)
[media] adv7604: Support hot-plug detect control through a GPIO
Add support for optional GPIO-controlled HPD pins in addition to the ADV7604-specific hotplug notifier. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r--drivers/media/i2c/adv7604.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 9ebe44c861c9..b14dc7d4b7bb 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -28,6 +28,7 @@
28 */ 28 */
29 29
30#include <linux/delay.h> 30#include <linux/delay.h>
31#include <linux/gpio/consumer.h>
31#include <linux/i2c.h> 32#include <linux/i2c.h>
32#include <linux/kernel.h> 33#include <linux/kernel.h>
33#include <linux/module.h> 34#include <linux/module.h>
@@ -135,6 +136,8 @@ struct adv7604_state {
135 const struct adv7604_chip_info *info; 136 const struct adv7604_chip_info *info;
136 struct adv7604_platform_data pdata; 137 struct adv7604_platform_data pdata;
137 138
139 struct gpio_desc *hpd_gpio[4];
140
138 struct v4l2_subdev sd; 141 struct v4l2_subdev sd;
139 struct media_pad pads[ADV7604_PAD_MAX]; 142 struct media_pad pads[ADV7604_PAD_MAX];
140 unsigned int source_pad; 143 unsigned int source_pad;
@@ -598,6 +601,20 @@ static inline int edid_write_block(struct v4l2_subdev *sd,
598 return err; 601 return err;
599} 602}
600 603
604static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd)
605{
606 unsigned int i;
607
608 for (i = 0; i < state->info->num_dv_ports; ++i) {
609 if (IS_ERR(state->hpd_gpio[i]))
610 continue;
611
612 gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i));
613 }
614
615 v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd);
616}
617
601static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) 618static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
602{ 619{
603 struct delayed_work *dwork = to_delayed_work(work); 620 struct delayed_work *dwork = to_delayed_work(work);
@@ -607,7 +624,7 @@ static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
607 624
608 v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); 625 v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
609 626
610 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); 627 adv7604_set_hpd(state, state->edid.present);
611} 628}
612 629
613static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) 630static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
@@ -2047,7 +2064,6 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
2047 struct adv7604_state *state = to_state(sd); 2064 struct adv7604_state *state = to_state(sd);
2048 const struct adv7604_chip_info *info = state->info; 2065 const struct adv7604_chip_info *info = state->info;
2049 int spa_loc; 2066 int spa_loc;
2050 int tmp = 0;
2051 int err; 2067 int err;
2052 int i; 2068 int i;
2053 2069
@@ -2058,7 +2074,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
2058 if (edid->blocks == 0) { 2074 if (edid->blocks == 0) {
2059 /* Disable hotplug and I2C access to EDID RAM from DDC port */ 2075 /* Disable hotplug and I2C access to EDID RAM from DDC port */
2060 state->edid.present &= ~(1 << edid->pad); 2076 state->edid.present &= ~(1 << edid->pad);
2061 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); 2077 adv7604_set_hpd(state, state->edid.present);
2062 rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); 2078 rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present);
2063 2079
2064 /* Fall back to a 16:9 aspect ratio */ 2080 /* Fall back to a 16:9 aspect ratio */
@@ -2082,7 +2098,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
2082 2098
2083 /* Disable hotplug and I2C access to EDID RAM from DDC port */ 2099 /* Disable hotplug and I2C access to EDID RAM from DDC port */
2084 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 2100 cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
2085 v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); 2101 adv7604_set_hpd(state, 0);
2086 rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); 2102 rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00);
2087 2103
2088 spa_loc = get_edid_spa_location(edid->edid); 2104 spa_loc = get_edid_spa_location(edid->edid);
@@ -2678,6 +2694,19 @@ static int adv7604_probe(struct i2c_client *client,
2678 return -ENODEV; 2694 return -ENODEV;
2679 } 2695 }
2680 state->pdata = *pdata; 2696 state->pdata = *pdata;
2697
2698 /* Request GPIOs. */
2699 for (i = 0; i < state->info->num_dv_ports; ++i) {
2700 state->hpd_gpio[i] =
2701 devm_gpiod_get_index(&client->dev, "hpd", i);
2702 if (IS_ERR(state->hpd_gpio[i]))
2703 continue;
2704
2705 gpiod_set_value_cansleep(state->hpd_gpio[i], 0);
2706
2707 v4l_info(client, "Handling HPD %u GPIO\n", i);
2708 }
2709
2681 state->timings = cea640x480; 2710 state->timings = cea640x480;
2682 state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8); 2711 state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8);
2683 2712