diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2014-01-30 16:37:08 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-05-25 12:02:45 -0400 |
commit | e9d50e9e7051a67783d75cd57ce360818b07d37b (patch) | |
tree | a6c0770da707de18e94622e2dd7a874480908b90 /drivers/media/i2c | |
parent | c72a53ce059394749b6db067ba78ad2a317fd7e6 (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.c | 37 |
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 | ||
604 | static 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 | |||
601 | static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) | 618 | static 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 | ||
613 | static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) | 630 | static 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 | ||