diff options
author | Per Persson <per.xb.persson@stericsson.com> | 2011-04-26 16:14:14 +0200 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-04-27 16:28:17 +0200 |
commit | 6044b9da5b3702c9f236def93210db4e8894d5eb (patch) | |
tree | c2783b9367eb9a1231e50751c429afb53f091ed1 /drivers | |
parent | 5473eb520328523576d47c896a0010a781ec280f (diff) |
video: mcde_hdmi: Support for HDMI user space service
Add changes needed by HDMI service in user space.
HDMI service is a user space service that provide
functionality for applications using HDMI.
ST-Ericsson ID: 335747
ST-Ericsson Linux next: Not tested, ER 282779
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I7c2ffd5ae61310f9a152ca984c4f62152fc1e2e0
Signed-off-by: Per Persson <per.xb.persson@stericsson.com>
Change-Id: Ie04b52ce91b33961ed36201e1019d92fb696487e
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/20950
Reviewed-by: Marcel TUNNISSEN <marcel.tuennissen@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/dispdev/dispdev.c | 30 | ||||
-rw-r--r-- | drivers/video/av8100/av8100.c | 21 | ||||
-rw-r--r-- | drivers/video/av8100/hdmi.c | 84 | ||||
-rw-r--r-- | drivers/video/mcde/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/mcde/display-av8100.c | 309 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_fb.c | 24 |
6 files changed, 454 insertions, 23 deletions
diff --git a/drivers/misc/dispdev/dispdev.c b/drivers/misc/dispdev/dispdev.c index dc6266d241b..af854841d95 100644 --- a/drivers/misc/dispdev/dispdev.c +++ b/drivers/misc/dispdev/dispdev.c @@ -162,9 +162,8 @@ static void get_ovly_info(struct dispdev_config *cfg, static int dispdev_set_config(struct dispdev *dd, struct dispdev_config *cfg) { - int ret, i; + int ret; struct mcde_overlay_info info; - u8 reuse_buffers = false; if (memcmp(&dd->config, cfg, sizeof(struct dispdev_config)) == 0) return 0; @@ -455,7 +454,30 @@ out: return ret; } -static void dispdev_destroy(void) +void dispdev_destroy(struct mcde_display_device *ddev) +{ + struct dispdev *dd; + struct dispdev *tmp; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(dd, tmp, &dev_list, list) { + if (dd->ddev == ddev) { + list_del(&dd->list); + misc_deregister(&dd->mdev); + mcde_dss_destroy_overlay(dd->ovly); + /* + * TODO: Uncomment when DSS has reference + * counting of enable/disable + */ + /* mcde_dss_disable_display(dd->ddev); */ + kfree(dd); + break; + } + } + mutex_unlock(&dev_list_lock); +} + +static void dispdev_destroy_all(void) { struct dispdev *dd; struct dispdev *tmp; @@ -489,7 +511,7 @@ module_init(dispdev_init); static void __exit dispdev_exit(void) { - dispdev_destroy(); + dispdev_destroy_all(); pr_info("%s\n", __func__); } module_exit(dispdev_exit); diff --git a/drivers/video/av8100/av8100.c b/drivers/video/av8100/av8100.c index 29c553d0522..b2920f277ac 100644 --- a/drivers/video/av8100/av8100.c +++ b/drivers/video/av8100/av8100.c @@ -1059,10 +1059,7 @@ static void av8100_set_state(enum av8100_operating_mode state) { g_av8100_status.av8100_state = state; - if (state == AV8100_OPMODE_UNDEFINED) - g_av8100_status.hdmi_on = false; - - if (state == AV8100_OPMODE_STANDBY) { + if (state <= AV8100_OPMODE_STANDBY) { clr_plug_status(AV8100_HDMI_PLUGIN); clr_plug_status(AV8100_CVBS_PLUGIN); g_av8100_status.hdmi_on = false; @@ -1929,15 +1926,23 @@ static int av8100_powerup2(void) int av8100_powerup(void) { + int ret = 0; + if (av8100_status_get().av8100_state == AV8100_OPMODE_UNDEFINED) return -EINVAL; - if (av8100_powerup1()) { - dev_err(av8100dev, "av8100_powerup1 fail\n"); - return -EFAULT; + if (av8100_status_get().av8100_state < AV8100_OPMODE_STANDBY) { + ret = av8100_powerup1(); + if (ret) { + dev_err(av8100dev, "av8100_powerup1 fail\n"); + return -EFAULT; + } } - return av8100_powerup2(); + if (av8100_status_get().av8100_state < AV8100_OPMODE_SCAN) + ret = av8100_powerup2(); + + return ret; } EXPORT_SYMBOL(av8100_powerup); diff --git a/drivers/video/av8100/hdmi.c b/drivers/video/av8100/hdmi.c index 3459bac69fd..be267188018 100644 --- a/drivers/video/av8100/hdmi.c +++ b/drivers/video/av8100/hdmi.c @@ -82,6 +82,10 @@ static ssize_t show_plugstatus(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t store_poweronoff(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_poweronoff(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_evwakeup(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); static DEVICE_ATTR(storeastext, S_IWUSR, NULL, store_storeastext); static DEVICE_ATTR(plugdeten, S_IWUSR, NULL, store_plugdeten); @@ -103,7 +107,9 @@ static DEVICE_ATTR(evread, S_IRUGO, show_evread, NULL); static DEVICE_ATTR(evclr, S_IWUSR, NULL, store_evclr); static DEVICE_ATTR(audiocfg, S_IWUSR, NULL, store_audiocfg); static DEVICE_ATTR(plugstatus, S_IRUGO, show_plugstatus, NULL); -static DEVICE_ATTR(poweronoff, S_IWUSR, NULL, store_poweronoff); +static DEVICE_ATTR(poweronoff, S_IRUGO | S_IWUSR, show_poweronoff, + store_poweronoff); +static DEVICE_ATTR(evwakeup, S_IWUSR, NULL, store_evwakeup); /* Hex to int conversion */ static unsigned int htoi(const char *ptr) @@ -608,6 +614,24 @@ static int events_clear(u8 ev) return 0; } +static int event_wakeup(void) +{ + struct kobject *kobj = &hdmidev->kobj; + + dev_dbg(hdmidev, "%s", __func__); + + LOCK_HDMI_EVENTS; + events |= HDMI_EVENT_WAKEUP; + events_received = true; + UNLOCK_HDMI_EVENTS; + + /* Wake up application waiting for event via call to poll() */ + sysfs_notify(kobj, NULL, SYSFS_EVENT_FILENAME); + wake_up_interruptible(&hdmi_event_wq); + + return 0; +} + static int audiocfg(struct audio_cfg *cfg) { union av8100_configuration config; @@ -1614,6 +1638,44 @@ static ssize_t store_poweronoff(struct device *dev, return count; } +static ssize_t show_poweronoff(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_driver_data *hdmi_driver_data; + int index = 0; + struct av8100_status status; + u8 power_state; + + dev_dbg(hdmidev, "%s\n", __func__); + + hdmi_driver_data = dev_get_drvdata(dev); + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_SCAN) + power_state = 0; + else + power_state = 1; + + if (hdmi_driver_data->store_as_hextext) { + snprintf(buf + index, 3, "%02x", power_state); + index += 3; + } else { + *(buf + index++) = power_state; + } + + return index; +} + +static ssize_t store_evwakeup(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + dev_dbg(hdmidev, "%s\n", __func__); + + event_wakeup(); + + return count; +} + static int hdmi_open(struct inode *inode, struct file *filp) { if (device_open) @@ -1915,6 +1977,21 @@ ioc_hdcploadaes_err: } break; + case IOC_EVENT_WAKEUP: + /* Trigger event */ + event_wakeup(); + break; + + case IOC_POWERSTATE: + status = av8100_status_get(); + value = status.av8100_state >= AV8100_OPMODE_SCAN; + + if (copy_to_user((void *)arg, (void *)&value, + sizeof(u8))) { + return -EINVAL; + } + break; + /* Internal */ case IOC_HDMI_ENABLE_INTERRUPTS: av8100_disable_interrupt(); @@ -2074,10 +2151,12 @@ void hdmi_event(enum av8100_hdmi_event ev) /* Set event */ switch (ev) { case AV8100_HDMI_EVENT_HDMI_PLUGIN: + events &= ~HDMI_EVENT_HDMI_PLUGOUT; events |= events_mask & HDMI_EVENT_HDMI_PLUGIN; break; case AV8100_HDMI_EVENT_HDMI_PLUGOUT: + events &= ~HDMI_EVENT_HDMI_PLUGIN; events |= events_mask & HDMI_EVENT_HDMI_PLUGOUT; break; @@ -2177,6 +2256,8 @@ int __init hdmi_init(void) dev_info(hdmidev, "Unable to create plugstatus attribute\n"); if (device_create_file(hdmidev, &dev_attr_poweronoff)) dev_info(hdmidev, "Unable to create poweronoff attribute\n"); + if (device_create_file(hdmidev, &dev_attr_evwakeup)) + dev_info(hdmidev, "Unable to create evwakeup attribute\n"); /* Register event callback */ av8100_hdmi_event_cb_set(hdmi_event); @@ -2211,6 +2292,7 @@ void hdmi_exit(void) device_remove_file(hdmidev, &dev_attr_audiocfg); device_remove_file(hdmidev, &dev_attr_plugstatus); device_remove_file(hdmidev, &dev_attr_poweronoff); + device_remove_file(hdmidev, &dev_attr_evwakeup); hdmi_driver_data = dev_get_drvdata(hdmidev); kfree(hdmi_driver_data); diff --git a/drivers/video/mcde/Kconfig b/drivers/video/mcde/Kconfig index c97387a97ed..a1310332cf9 100644 --- a/drivers/video/mcde/Kconfig +++ b/drivers/video/mcde/Kconfig @@ -44,6 +44,15 @@ config MCDE_DISPLAY_AV8100 depends on FB_MCDE select AV8100 +config MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + bool "HDMI_FB_AUTO_CREATE" + default y + depends on MCDE_DISPLAY_AV8100 + ---help--- + Say Y if you want the HDMI frame buffer to be created on start + Say N if you want the HDMI frame buffer to be created when HDMI + cable is plugged (needs user space HDMIservice) + config MCDE_DISPLAY_AB8500_DENC tristate "AB8500 CVBS display driver" depends on FB_MCDE diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c index 84818a558fc..5d400a9958e 100644 --- a/drivers/video/mcde/display-av8100.c +++ b/drivers/video/mcde/display-av8100.c @@ -24,10 +24,10 @@ #define SWITCH_HELPSTR ", 0=HDMI, 1=SDTV, 2=DVI\n" -struct display_driver_data { - struct regulator *cvbs_regulator; - bool cvbs_regulator_enabled; - bool update_port_pixel_format; +struct cea_vesa_video_mode { + u32 cea; + u32 vesa_cea_nr; + struct mcde_video_mode *video_mode; }; static int hdmi_try_video_mode( @@ -36,6 +36,8 @@ static int hdmi_set_video_mode( struct mcde_display_device *ddev, struct mcde_video_mode *video_mode); static int hdmi_set_pixel_format( struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format); +static struct mcde_video_mode *video_mode_get(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr); static ssize_t show_hdmisdtvswitch(struct device *dev, struct device_attribute *attr, char *buf); @@ -45,6 +47,23 @@ static ssize_t show_input_pixel_format(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t store_input_pixel_format(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_disponoff(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_disponoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_vesacea(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_timing(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_timing(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_stayalive(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static DEVICE_ATTR(disponoff, S_IRUGO | S_IWUSR, show_disponoff, + store_disponoff); +static DEVICE_ATTR(vesacea, S_IRUGO, show_vesacea, NULL); +static DEVICE_ATTR(timing, S_IRUGO | S_IWUSR, show_timing, store_timing); +static DEVICE_ATTR(stayalive, S_IWUSR, NULL, store_stayalive); static DEVICE_ATTR(hdmisdtvswitch, S_IRUGO | S_IWUSR, show_hdmisdtvswitch, store_hdmisdtvswitch); @@ -137,6 +156,134 @@ static ssize_t store_input_pixel_format(struct device *dev, return count; } +static ssize_t show_disponoff(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(dev, "%s\n", __func__); + + if (ddev->fbi && driver_data->fbdevname) { + dev_dbg(dev, "name:%s\n", driver_data->fbdevname); + strcpy(buf, driver_data->fbdevname); + return strlen(driver_data->fbdevname) + 1; + } + return 0; +} + +static ssize_t store_disponoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *mdev = to_mcde_display_device(dev); + bool enable = false; + u8 cea = 0; + u8 vesa_cea_nr = 0; + + dev_dbg(dev, "%s\n", __func__); + + if ((count != DISPONOFF_SIZE) && (count != DISPONOFF_SIZE + 1)) + return -EINVAL; + + if ((*buf == '0') && (*(buf + 1) == '1')) + enable = true; + cea = (hex_to_bin(buf[2]) << 4) + hex_to_bin(buf[3]); + vesa_cea_nr = (hex_to_bin(buf[4]) << 4) + hex_to_bin(buf[5]); + dev_dbg(dev, "enable:%d cea:%d nr:%d\n", enable, cea, vesa_cea_nr); + + hdmi_fb_onoff(mdev, enable, cea, vesa_cea_nr); + + return count; +} + +static ssize_t show_timing(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + struct mcde_video_mode *video_mode; + int index; + + dev_dbg(dev, "%s\n", __func__); + + index = 0; + if (driver_data->video_mode) { + video_mode = driver_data->video_mode; + memcpy(buf + index, &video_mode->xres, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->yres, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->pixclock, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->hbp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->hfp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->vbp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->vfp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->interlaced, sizeof(u32)); + index += sizeof(u32); + } + return index; +} + +static ssize_t store_timing(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(dev, "%s\n", __func__); + + if (count != TIMING_SIZE) + return -EINVAL; + + driver_data->video_mode = video_mode_get(ddev, *buf, *(buf + 1)); + + return count; +} + +static ssize_t store_stayalive(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + + if (count != STAYALIVE_SIZE) + return -EINVAL; + + if ((*buf == 1) || (*buf == '1')) + ddev->stay_alive = true; + else + ddev->stay_alive = false; + + dev_dbg(dev, "%s %d\n", __func__, ddev->stay_alive); + + return count; +} + +static int ceanr_convert(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr, int buffering, + u16 *w, u16 *h, u16 *vw, u16 *vh) +{ + struct mcde_video_mode *video_mode; + + dev_dbg(&ddev->dev, "%s\n", __func__); + video_mode = video_mode_get(ddev, cea, vesa_cea_nr); + if (video_mode) { + *w = video_mode->xres; + *h = video_mode->yres; + *vw = video_mode->xres; + *vh = video_mode->yres * buffering; + dev_dbg(&ddev->dev, "cea:%d nr:%d found\n", + cea, vesa_cea_nr); + return 0; + } + + return -EINVAL; +} + /* Supported HDMI modes */ static struct mcde_video_mode video_modes_supp_hdmi[] = { /* 640_480_60_P */ @@ -249,6 +396,124 @@ static struct mcde_video_mode video_modes_supp_sdtv[] = { }, }; +static struct cea_vesa_video_mode cea_vesa_video_mode[] = { + /* 640_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 1, + .video_mode = &video_modes_supp_hdmi[0], + }, + /* 720_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 2, + .video_mode = &video_modes_supp_hdmi[1], + }, + /* 720_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 3, + .video_mode = &video_modes_supp_hdmi[1], + }, + /* 720_576_50_P */ + { + .cea = 1, .vesa_cea_nr = 17, + .video_mode = &video_modes_supp_hdmi[2], + }, + /* 720_576_50_P */ + { + .cea = 1, .vesa_cea_nr = 18, + .video_mode = &video_modes_supp_hdmi[2], + }, + /* 1280_720_60_P */ + { + .cea = 1, .vesa_cea_nr = 4, + .video_mode = &video_modes_supp_hdmi[3], + }, + /* 1280_720_50_P */ + { + .cea = 1, .vesa_cea_nr = 19, + .video_mode = &video_modes_supp_hdmi[4], + }, + /* 1920_1080_30_P */ + { + .cea = 1, .vesa_cea_nr = 34, + .video_mode = &video_modes_supp_hdmi[5], + }, + /* 1920_1080_24_P */ + { + .cea = 1, .vesa_cea_nr = 32, + .video_mode = &video_modes_supp_hdmi[6], + }, + /* 1920_1080_25_P */ + { + .cea = 1, .vesa_cea_nr = 33, + .video_mode = &video_modes_supp_hdmi[7], + }, + /* 720_480_60_I) */ + { + .cea = 1, .vesa_cea_nr = 6, + .video_mode = &video_modes_supp_hdmi[8], + }, + /* 720_480_60_I) */ + { + .cea = 1, .vesa_cea_nr = 7, + .video_mode = &video_modes_supp_hdmi[8], + }, + /* 720_576_50_I) */ + { + .cea = 1, .vesa_cea_nr = 21, + .video_mode = &video_modes_supp_hdmi[9], + }, + /* 720_576_50_I) */ + { + .cea = 1, .vesa_cea_nr = 22, + .video_mode = &video_modes_supp_hdmi[9], + }, + /* 1920_1080_50_I) */ + { + .cea = 1, .vesa_cea_nr = 20, + .video_mode = &video_modes_supp_hdmi[10], + }, + /* 1920_1080_60_I) */ + { + .cea = 1, .vesa_cea_nr = 5, + .video_mode = &video_modes_supp_hdmi[11], + }, +}; + +static ssize_t show_vesacea(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int findex; + + dev_dbg(dev, "%s\n", __func__); + + for (findex = 0; findex < ARRAY_SIZE(cea_vesa_video_mode); findex++) { + *(buf + findex * 2) = cea_vesa_video_mode[findex].cea; + *(buf + findex * 2 + 1) = + cea_vesa_video_mode[findex].vesa_cea_nr; + } + *(buf + findex * 2) = '\0'; + + return findex * 2 + 1; +} + +static struct mcde_video_mode *video_mode_get(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr) +{ + int findex; + + dev_dbg(&ddev->dev, "%s\n", __func__); + + for (findex = 0; findex < ARRAY_SIZE(cea_vesa_video_mode); findex++) + if ((cea == cea_vesa_video_mode[findex].cea) && + (vesa_cea_nr == + cea_vesa_video_mode[findex].vesa_cea_nr)) { + dev_dbg(&ddev->dev, "cea:%d nr:%d\n", cea, vesa_cea_nr); + return cea_vesa_video_mode[findex].video_mode; + } + + return NULL; +} + #define AV8100_MAX_LEVEL 255 static int hdmi_try_video_mode( @@ -445,17 +710,20 @@ static int hdmi_set_video_mode( dev_err(&dev->dev, "av8100_powerup failed\n"); return ret; } + } + if (status.av8100_state < AV8100_OPMODE_IDLE) { ret = av8100_download_firmware(NULL, 0, I2C_INTERFACE); if (ret) { dev_err(&dev->dev, "av8100_download_firmware failed\n"); av8100_powerdown(); return ret; } - } else if (av8100_disable_interrupt()) { - return -EFAULT; } + if (av8100_disable_interrupt()) + return -EFAULT; + /* * Don't look at dev->port->hdmi_sdtv_switch; it states only which * one should be started, not which one is currently working @@ -817,6 +1085,14 @@ static int hdmi_set_power_mode(struct mcde_display_device *ddev, if (ret) return ret; } + + ret = av8100_powerup(); + if (ret) { + dev_err(&ddev->dev, "av8100_powerup failed\n"); + return ret; + } + av8100_enable_interrupt(); + /* * the regulator for analog TV out is only enabled here, * this means that one needs to switch to the OFF state @@ -907,14 +1183,27 @@ static int __devinit hdmi_probe(struct mcde_display_device *dev) dev->apply_config = hdmi_apply_config; dev->set_pixel_format = hdmi_set_pixel_format; dev->set_power_mode = hdmi_set_power_mode; + dev->ceanr_convert = ceanr_convert; - /* Create sysfs file for switching between hdmi and sdtv */ + /* Create sysfs files */ if (device_create_file(&dev->dev, &dev_attr_hdmisdtvswitch)) dev_info(&dev->dev, "Unable to create hdmisdtvswitch attr\n"); if (device_create_file(&dev->dev, &dev_attr_input_pixel_format)) dev_info(&dev->dev, "Unable to create input_pixel_format attr\n"); + if (device_create_file(&dev->dev, &dev_attr_disponoff)) + dev_info(&dev->dev, + "Unable to create disponoff attr\n"); + if (device_create_file(&dev->dev, &dev_attr_vesacea)) + dev_info(&dev->dev, + "Unable to create ceavesa attr\n"); + if (device_create_file(&dev->dev, &dev_attr_timing)) + dev_info(&dev->dev, + "Unable to create timing attr\n"); + if (device_create_file(&dev->dev, &dev_attr_stayalive)) + dev_info(&dev->dev, + "Unable to create stayalive attr\n"); if (pdata->cvbs_regulator_id) { driver_data->cvbs_regulator = regulator_get(&dev->dev, @@ -944,9 +1233,13 @@ static int __devexit hdmi_remove(struct mcde_display_device *dev) struct mcde_display_hdmi_platform_data *pdata = dev->dev.platform_data; - /* Remove sysfs file */ + /* Remove sysfs files */ device_remove_file(&dev->dev, &dev_attr_input_pixel_format); device_remove_file(&dev->dev, &dev_attr_hdmisdtvswitch); + device_remove_file(&dev->dev, &dev_attr_disponoff); + device_remove_file(&dev->dev, &dev_attr_vesacea); + device_remove_file(&dev->dev, &dev_attr_timing); + device_remove_file(&dev->dev, &dev_attr_stayalive); dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c index 8b1cca47339..49924e4fe5d 100644 --- a/drivers/video/mcde/mcde_fb.c +++ b/drivers/video/mcde/mcde_fb.c @@ -209,6 +209,7 @@ static int init_var_fmt(struct fb_var_screeninfo *var, var->yoffset = 0; var->activate = FB_ACTIVATE_NOW; var->rotate = rotate; + return 0; }; @@ -692,6 +693,8 @@ struct fb_info *mcde_fb_create(struct mcde_display_device *ddev, if (ret) goto fb_register_failed; + ddev->fbi = fbi; + #ifdef CONFIG_HAS_EARLYSUSPEND mfb->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; @@ -726,9 +729,26 @@ int mcde_fb_attach_overlay(struct fb_info *fb_info, struct mcde_overlay *ovl) return -EINVAL; } -void mcde_fb_destroy(struct fb_info *fb_info) +void mcde_fb_destroy(struct mcde_display_device *dev) { - /* TODO: clean up */ + struct mcde_fb *mfb; + int i; + + dev_vdbg(&dev->dev, "%s\n", __func__); + + mcde_dss_disable_display(dev); + mcde_dss_close_channel(dev); + + mfb = to_mcde_fb(dev->fbi); + for (i = 0; i < mfb->num_ovlys; i++) { + if (mfb->ovlys[i]) + mcde_dss_destroy_overlay(mfb->ovlys[i]); + } + + unregister_framebuffer(dev->fbi); + free_fb_mem(dev->fbi); + framebuffer_release(dev->fbi); + dev->fbi = NULL; } /* Overlay fbs' platform device */ |