diff options
Diffstat (limited to 'drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c')
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 77 |
1 files changed, 65 insertions, 12 deletions
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 9af81f18f163..6847a478b459 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/gpio.h> | ||
31 | 32 | ||
32 | #include "ti_hdmi_4xxx_ip.h" | 33 | #include "ti_hdmi_4xxx_ip.h" |
33 | #include "dss.h" | 34 | #include "dss.h" |
@@ -223,6 +224,49 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) | |||
223 | hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); | 224 | hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); |
224 | } | 225 | } |
225 | 226 | ||
227 | static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) | ||
228 | { | ||
229 | unsigned long flags; | ||
230 | bool hpd; | ||
231 | int r; | ||
232 | /* this should be in ti_hdmi_4xxx_ip private data */ | ||
233 | static DEFINE_SPINLOCK(phy_tx_lock); | ||
234 | |||
235 | spin_lock_irqsave(&phy_tx_lock, flags); | ||
236 | |||
237 | hpd = gpio_get_value(ip_data->hpd_gpio); | ||
238 | |||
239 | if (hpd == ip_data->phy_tx_enabled) { | ||
240 | spin_unlock_irqrestore(&phy_tx_lock, flags); | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | if (hpd) | ||
245 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); | ||
246 | else | ||
247 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | ||
248 | |||
249 | if (r) { | ||
250 | DSSERR("Failed to %s PHY TX power\n", | ||
251 | hpd ? "enable" : "disable"); | ||
252 | goto err; | ||
253 | } | ||
254 | |||
255 | ip_data->phy_tx_enabled = hpd; | ||
256 | err: | ||
257 | spin_unlock_irqrestore(&phy_tx_lock, flags); | ||
258 | return r; | ||
259 | } | ||
260 | |||
261 | static irqreturn_t hpd_irq_handler(int irq, void *data) | ||
262 | { | ||
263 | struct hdmi_ip_data *ip_data = data; | ||
264 | |||
265 | hdmi_check_hpd_state(ip_data); | ||
266 | |||
267 | return IRQ_HANDLED; | ||
268 | } | ||
269 | |||
226 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | 270 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) |
227 | { | 271 | { |
228 | u16 r = 0; | 272 | u16 r = 0; |
@@ -232,10 +276,6 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | |||
232 | if (r) | 276 | if (r) |
233 | return r; | 277 | return r; |
234 | 278 | ||
235 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); | ||
236 | if (r) | ||
237 | return r; | ||
238 | |||
239 | /* | 279 | /* |
240 | * Read address 0 in order to get the SCP reset done completed | 280 | * Read address 0 in order to get the SCP reset done completed |
241 | * Dummy access performed to make sure reset is done | 281 | * Dummy access performed to make sure reset is done |
@@ -257,12 +297,32 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | |||
257 | /* Write to phy address 3 to change the polarity control */ | 297 | /* Write to phy address 3 to change the polarity control */ |
258 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | 298 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); |
259 | 299 | ||
300 | r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), | ||
301 | NULL, hpd_irq_handler, | ||
302 | IRQF_DISABLED | IRQF_TRIGGER_RISING | | ||
303 | IRQF_TRIGGER_FALLING, "hpd", ip_data); | ||
304 | if (r) { | ||
305 | DSSERR("HPD IRQ request failed\n"); | ||
306 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
307 | return r; | ||
308 | } | ||
309 | |||
310 | r = hdmi_check_hpd_state(ip_data); | ||
311 | if (r) { | ||
312 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | ||
313 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
314 | return r; | ||
315 | } | ||
316 | |||
260 | return 0; | 317 | return 0; |
261 | } | 318 | } |
262 | 319 | ||
263 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) | 320 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) |
264 | { | 321 | { |
322 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | ||
323 | |||
265 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | 324 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); |
325 | ip_data->phy_tx_enabled = false; | ||
266 | } | 326 | } |
267 | 327 | ||
268 | static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) | 328 | static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) |
@@ -419,14 +479,7 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, | |||
419 | 479 | ||
420 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) | 480 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) |
421 | { | 481 | { |
422 | int r; | 482 | return gpio_get_value(ip_data->hpd_gpio); |
423 | |||
424 | void __iomem *base = hdmi_core_sys_base(ip_data); | ||
425 | |||
426 | /* HPD */ | ||
427 | r = REG_GET(base, HDMI_CORE_SYS_SYS_STAT, 1, 1); | ||
428 | |||
429 | return r == 1; | ||
430 | } | 483 | } |
431 | 484 | ||
432 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, | 485 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, |