diff options
Diffstat (limited to 'drivers/video/sh_mobile_hdmi.c')
-rw-r--r-- | drivers/video/sh_mobile_hdmi.c | 321 |
1 files changed, 212 insertions, 109 deletions
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index fcda0e97011..2b9e56a6bde 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/workqueue.h> +#include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -209,7 +210,11 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; /* hot-plug status */ - bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ + u8 preprogrammed_vic; /* use a pre-programmed VIC or + the external mode */ + u8 edid_block_addr; + u8 edid_segment_nr; + u8 edid_blocks; struct clk *hdmi_clk; struct device *dev; struct fb_info *info; @@ -217,6 +222,7 @@ struct sh_hdmi { struct delayed_work edid_work; struct fb_var_screeninfo var; struct fb_monspecs monspec; + struct notifier_block notifier; }; static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) @@ -342,7 +348,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ - if (!hdmi->preprogrammed_mode) + if (!hdmi->preprogrammed_vic) hdmi_write(hdmi, sync | 1 | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } @@ -466,7 +472,18 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - if (hdmi->var.yres > 480) { + if (hdmi->var.pixclock < 10000) { + /* for 1080p8bit 148MHz */ + hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } else if (hdmi->var.pixclock < 30000) { /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ /* * [1:0] Speed_A @@ -565,13 +582,11 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); /* - * VIC = 1280 x 720p: ignored if external config is used - * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode + * VIC should be ignored if external config is used, so, we could just use 0, + * but play safe and use a valid value in any case just in case */ - if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) - vic = 16; - else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) - vic = 2; + if (hdmi->preprogrammed_vic) + vic = hdmi->preprogrammed_vic; else vic = 4; hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); @@ -685,11 +700,21 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) } static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, - const struct fb_videomode *mode) + const struct fb_videomode *mode, + unsigned long *hdmi_rate, unsigned long *parent_rate) { - long target = PICOS2KHZ(mode->pixclock) * 1000, - rate = clk_round_rate(hdmi->hdmi_clk, target); - unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; + unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error; + struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + + *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target); + if ((long)*hdmi_rate < 0) + *hdmi_rate = clk_get_rate(hdmi->hdmi_clk); + + rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX; + if (rate_error && pdata->clk_optimize_parent) + rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate); + else if (clk_get_parent(hdmi->hdmi_clk)) + *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk)); dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", mode->left_margin, mode->xres, @@ -697,14 +722,15 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, mode->upper_margin, mode->yres, mode->lower_margin, mode->vsync_len); - dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, - rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, - mode->refresh); + dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target, + rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, + mode->refresh, *parent_rate); return rate_error; } -static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) +static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, + unsigned long *parent_rate) { struct fb_var_screeninfo tmpvar; struct fb_var_screeninfo *var = &tmpvar; @@ -713,7 +739,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) struct fb_modelist *modelist = NULL; unsigned int f_width = 0, f_height = 0, f_refresh = 0; unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ - bool exact_match = false; + bool scanning = false, preferred_bad = false; u8 edid[128]; char *forced; int i; @@ -735,7 +761,38 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) printk(KERN_CONT "\n"); #endif - fb_edid_to_monspecs(edid, &hdmi->monspec); + if (!hdmi->edid_blocks) { + fb_edid_to_monspecs(edid, &hdmi->monspec); + hdmi->edid_blocks = edid[126] + 1; + + dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n", + hdmi->monspec.modedb_len, hdmi->edid_blocks - 1); + } else { + dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n", + edid[0], edid[2]); + fb_edid_add_monspecs(edid, &hdmi->monspec); + } + + if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 + + (hdmi->edid_block_addr >> 7) + 1) { + /* More blocks to read */ + if (hdmi->edid_block_addr) { + hdmi->edid_block_addr = 0; + hdmi->edid_segment_nr++; + } else { + hdmi->edid_block_addr = 0x80; + } + /* Set EDID word address */ + hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); + /* Enable EDID interrupt */ + hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); + /* Set EDID segment pointer - starts reading EDID */ + hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); + return -EAGAIN; + } + + /* All E-EDID blocks ready */ + dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len); fb_get_options("sh_mobile_lcdc", &forced); if (forced && *forced) { @@ -745,6 +802,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (i < 2) { f_width = 0; f_height = 0; + } else { + /* The user wants us to use the EDID data */ + scanning = true; } dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", f_width, f_height, f_refresh); @@ -752,34 +812,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) /* Walk monitor modes to find the best or the exact match */ for (i = 0, mode = hdmi->monspec.modedb; - f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; + i < hdmi->monspec.modedb_len && scanning; i++, mode++) { - unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); + unsigned long rate_error; - /* No interest in unmatching modes */ - if (f_width != mode->xres || f_height != mode->yres) - continue; - if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) - /* - * Exact match if either the refresh rate matches or it - * hasn't been specified and we've found a mode, for - * which we can configure the clock precisely - */ - exact_match = true; - else if (found && found_rate_error <= rate_error) + if (!f_width && !f_height) { /* - * We otherwise search for the closest matching clock - * rate - either if no refresh rate has been specified - * or we cannot find an exactly matching one + * A parameter string "video=sh_mobile_lcdc:0x0" means + * use the preferred EDID mode. If it is rejected by + * .fb_check_var(), keep looking, until an acceptable + * one is found. */ + if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad) + scanning = false; + else + continue; + } else if (f_width != mode->xres || f_height != mode->yres) { + /* No interest in unmatching modes */ continue; + } + + rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); + + if (scanning) { + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) + /* + * Exact match if either the refresh rate + * matches or it hasn't been specified and we've + * found a mode, for which we can configure the + * clock precisely + */ + scanning = false; + else if (found && found_rate_error <= rate_error) + /* + * We otherwise search for the closest matching + * clock rate - either if no refresh rate has + * been specified or we cannot find an exactly + * matching one + */ + continue; + } /* Check if supported: sufficient fb memory, supported clock-rate */ fb_videomode_to_var(var, mode); + var->bits_per_pixel = info->var.bits_per_pixel; + if (info && info->fbops->fb_check_var && info->fbops->fb_check_var(var, info)) { - exact_match = false; + scanning = true; + preferred_bad = true; continue; } @@ -797,15 +879,15 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) * driver, and passing ->info with HDMI platform data. */ if (info && !found) { - modelist = hdmi->info->modelist.next && - !list_empty(&hdmi->info->modelist) ? - list_entry(hdmi->info->modelist.next, + modelist = info->modelist.next && + !list_empty(&info->modelist) ? + list_entry(info->modelist.next, struct fb_modelist, list) : NULL; if (modelist) { found = &modelist->mode; - found_rate_error = sh_hdmi_rate_error(hdmi, found); + found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate); } } @@ -813,16 +895,27 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (!found) return -ENXIO; - dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", - modelist ? "default" : "EDID", found->xres, found->yres, - found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); - - if ((found->xres == 720 && found->yres == 480) || - (found->xres == 1280 && found->yres == 720) || - (found->xres == 1920 && found->yres == 1080)) - hdmi->preprogrammed_mode = true; + if (found->xres == 640 && found->yres == 480 && found->refresh == 60) + hdmi->preprogrammed_vic = 1; + else if (found->xres == 720 && found->yres == 480 && found->refresh == 60) + hdmi->preprogrammed_vic = 2; + else if (found->xres == 720 && found->yres == 576 && found->refresh == 50) + hdmi->preprogrammed_vic = 17; + else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60) + hdmi->preprogrammed_vic = 4; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24) + hdmi->preprogrammed_vic = 32; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50) + hdmi->preprogrammed_vic = 31; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60) + hdmi->preprogrammed_vic = 16; else - hdmi->preprogrammed_mode = false; + hdmi->preprogrammed_vic = 0; + + dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", + modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", + found->xres, found->yres, found->refresh, + PICOS2KHZ(found->pixclock) * 1000, found_rate_error); fb_videomode_to_var(&hdmi->var, found); sh_hdmi_external_video_param(hdmi); @@ -871,32 +964,34 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ + hdmi->edid_segment_nr = 0; + hdmi->edid_block_addr = 0; + hdmi->edid_blocks = 0; hdmi->hp_state = HDMI_HOTPLUG_CONNECTED; /* Set EDID word address */ hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); - /* Set EDID segment pointer */ - hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); /* Enable EDID interrupt */ hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); + /* Set EDID segment pointer - starts reading EDID */ + hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); } else if (!(status1 & 0x80)) { /* Display unplug, beware multiple interrupts */ - if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) + if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) { + hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; schedule_delayed_work(&hdmi->edid_work, 0); - - hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; + } /* display_off will switch back to mode_a */ } } else if (status1 & 2) { /* EDID error interrupt: retry */ /* Set EDID word address */ - hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); + hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); /* Set EDID segment pointer */ - hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); + hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); } else if (status1 & 4) { /* Disable EDID interrupt */ hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1); - hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10)); } @@ -979,39 +1074,37 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) /** * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock - * @hdmi: driver context - * @pixclock: pixel clock period in picoseconds - * return: configured positive rate if successful - * 0 if couldn't set the rate, but managed to enable the clock - * negative error, if couldn't enable the clock + * @hdmi: driver context + * @hdmi_rate: HDMI clock frequency in Hz + * @parent_rate: if != 0 - set parent clock rate for optimal precision + * return: configured positive rate if successful + * 0 if couldn't set the rate, but managed to enable the + * clock, negative error, if couldn't enable the clock */ -static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) +static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, + unsigned long parent_rate) { - long rate; int ret; - rate = PICOS2KHZ(pixclock) * 1000; - rate = clk_round_rate(hdmi->hdmi_clk, rate); - if (rate > 0) { - ret = clk_set_rate(hdmi->hdmi_clk, rate); + if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { + ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate); if (ret < 0) { - dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); - rate = 0; + dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret); + hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate); } else { - dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); + dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate); } - } else { - rate = 0; - dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); } - ret = clk_enable(hdmi->hdmi_clk); + ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate); if (ret < 0) { - dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); - return ret; + dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret); + hdmi_rate = 0; + } else { + dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate); } - return rate; + return hdmi_rate; } /* Hotplug interrupt occurred, read EDID */ @@ -1030,17 +1123,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); - if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { + if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { + struct fb_info *info = hdmi->info; + unsigned long parent_rate = 0, hdmi_rate; + /* A device has been plugged in */ pm_runtime_get_sync(hdmi->dev); - ret = sh_hdmi_read_edid(hdmi); + ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); if (ret < 0) goto out; + hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; + /* Reconfigure the clock */ - clk_disable(hdmi->hdmi_clk); - ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); + ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); if (ret < 0) goto out; @@ -1049,22 +1146,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) /* Switched to another (d) power-save mode */ msleep(10); - if (!hdmi->info) + if (!info) goto out; - ch = hdmi->info->par; + ch = info->par; - acquire_console_sem(); + console_lock(); /* HDMI plug in */ if (!sh_hdmi_must_reconfigure(hdmi) && - hdmi->info->state == FBINFO_STATE_RUNNING) { + info->state == FBINFO_STATE_RUNNING) { /* * First activation with the default monitor - just turn * on, if we run a resume here, the logo disappears */ - if (lock_fb_info(hdmi->info)) { - struct fb_info *info = hdmi->info; + if (lock_fb_info(info)) { info->var.width = hdmi->var.width; info->var.height = hdmi->var.height; sh_hdmi_display_on(hdmi, info); @@ -1072,10 +1168,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) } } else { /* New monitor or have to wake up */ - fb_set_suspend(hdmi->info, 0); + fb_set_suspend(info, 0); } - release_console_sem(); + console_unlock(); } else { ret = 0; if (!hdmi->info) @@ -1085,17 +1181,17 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) fb_destroy_modedb(hdmi->monspec.modedb); hdmi->monspec.modedb = NULL; - acquire_console_sem(); + console_lock(); /* HDMI disconnect */ fb_set_suspend(hdmi->info, 1); - release_console_sem(); + console_unlock(); pm_runtime_put(hdmi->dev); } out: - if (ret < 0) + if (ret < 0 && ret != -EAGAIN) hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; mutex_unlock(&hdmi->mutex); @@ -1103,13 +1199,6 @@ out: } static int sh_hdmi_notify(struct notifier_block *nb, - unsigned long action, void *data); - -static struct notifier_block sh_hdmi_notifier = { - .notifier_call = sh_hdmi_notify, -}; - -static int sh_hdmi_notify(struct notifier_block *nb, unsigned long action, void *data) { struct fb_event *event = data; @@ -1118,7 +1207,7 @@ static int sh_hdmi_notify(struct notifier_block *nb, struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; struct sh_hdmi *hdmi = board_cfg->board_data; - if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) + if (!hdmi || nb != &hdmi->notifier || hdmi->info != info) return NOTIFY_DONE; switch(action) { @@ -1137,11 +1226,11 @@ static int sh_hdmi_notify(struct notifier_block *nb, * temporarily, synchronise with the work queue and re-acquire * the info->lock. */ - unlock_fb_info(hdmi->info); + unlock_fb_info(info); mutex_lock(&hdmi->mutex); hdmi->info = NULL; mutex_unlock(&hdmi->mutex); - lock_fb_info(hdmi->info); + lock_fb_info(info); return NOTIFY_OK; } return NOTIFY_DONE; @@ -1176,13 +1265,22 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } - /* Some arbitrary relaxed pixclock just to get things started */ - rate = sh_hdmi_clk_configure(hdmi, 37037); + /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ + rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); + if (rate > 0) + rate = sh_hdmi_clk_configure(hdmi, rate, 0); + if (rate < 0) { ret = rate; goto erate; } + ret = clk_enable(hdmi->hdmi_clk); + if (ret < 0) { + dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); + goto erate; + } + dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { @@ -1200,10 +1298,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); - /* Product and revision IDs are 0 in sh-mobile version */ - dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", - hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); - /* Set up LCDC callbacks */ board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; @@ -1216,6 +1310,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); + /* Product and revision IDs are 0 in sh-mobile version */ + dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", + hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); + ret = request_irq(irq, sh_hdmi_hotplug, 0, dev_name(&pdev->dev), hdmi); if (ret < 0) { @@ -1230,6 +1328,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto ecodec; } + hdmi->notifier.notifier_call = sh_hdmi_notify; + fb_register_client(&hdmi->notifier); + return 0; ecodec: @@ -1260,6 +1361,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) snd_soc_unregister_codec(&pdev->dev); + fb_unregister_client(&hdmi->notifier); + board_cfg->display_on = NULL; board_cfg->display_off = NULL; board_cfg->board_data = NULL; |