Commit a44e552a authored by Sebastian Reichel's avatar Sebastian Reichel Committed by Tomi Valkeinen

drm/omap: panel-dsi-cm: add external backlight support

Droid 4 has a command mode DSI panel, which does not have/use
DSI based backlight support. This adds proper support for this
using a backlight phandle property, which follows the common
panel binding.

If no backlight phandle is found, it is assumed, that the
native backlight should be used instead. This is used by
the Nokia N950.
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.co.uk>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
parent d95c5a0e
...@@ -51,6 +51,7 @@ struct panel_drv_data { ...@@ -51,6 +51,7 @@ struct panel_drv_data {
struct mutex lock; struct mutex lock;
struct backlight_device *bldev; struct backlight_device *bldev;
struct backlight_device *extbldev;
unsigned long hw_guard_end; /* next value of jiffies when we can unsigned long hw_guard_end; /* next value of jiffies when we can
* issue the next sleep in/out command * issue the next sleep in/out command
...@@ -100,6 +101,30 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata); ...@@ -100,6 +101,30 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata);
static void dsicm_ulps_work(struct work_struct *work); static void dsicm_ulps_work(struct work_struct *work);
static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable)
{
struct backlight_device *backlight;
if (ddata->bldev)
backlight = ddata->bldev;
else if (ddata->extbldev)
backlight = ddata->extbldev;
else
return;
if (enable) {
backlight->props.fb_blank = FB_BLANK_UNBLANK;
backlight->props.state = ~(BL_CORE_FBBLANK | BL_CORE_SUSPENDED);
backlight->props.power = FB_BLANK_UNBLANK;
} else {
backlight->props.fb_blank = FB_BLANK_NORMAL;
backlight->props.power = FB_BLANK_POWERDOWN;
backlight->props.state |= BL_CORE_FBBLANK | BL_CORE_SUSPENDED;
}
backlight_update_status(backlight);
}
static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec) static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
{ {
ddata->hw_guard_wait = msecs_to_jiffies(guard_msec); ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
...@@ -343,7 +368,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev) ...@@ -343,7 +368,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev)
{ {
struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
struct omap_dss_device *in = ddata->in; struct omap_dss_device *in = ddata->in;
int r; int r = 0;
int level; int level;
if (dev->props.fb_blank == FB_BLANK_UNBLANK && if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
...@@ -364,8 +389,6 @@ static int dsicm_bl_update_status(struct backlight_device *dev) ...@@ -364,8 +389,6 @@ static int dsicm_bl_update_status(struct backlight_device *dev)
r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level); r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
in->ops.dsi->bus_unlock(in); in->ops.dsi->bus_unlock(in);
} else {
r = 0;
} }
mutex_unlock(&ddata->lock); mutex_unlock(&ddata->lock);
...@@ -819,6 +842,8 @@ static int dsicm_enable(struct omap_dss_device *dssdev) ...@@ -819,6 +842,8 @@ static int dsicm_enable(struct omap_dss_device *dssdev)
mutex_unlock(&ddata->lock); mutex_unlock(&ddata->lock);
dsicm_bl_power(ddata, true);
return 0; return 0;
err: err:
dev_dbg(&ddata->pdev->dev, "enable failed\n"); dev_dbg(&ddata->pdev->dev, "enable failed\n");
...@@ -834,6 +859,8 @@ static void dsicm_disable(struct omap_dss_device *dssdev) ...@@ -834,6 +859,8 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
dev_dbg(&ddata->pdev->dev, "disable\n"); dev_dbg(&ddata->pdev->dev, "disable\n");
dsicm_bl_power(ddata, false);
mutex_lock(&ddata->lock); mutex_lock(&ddata->lock);
dsicm_cancel_ulps_work(ddata); dsicm_cancel_ulps_work(ddata);
...@@ -1198,6 +1225,7 @@ static struct omap_dss_driver dsicm_ops = { ...@@ -1198,6 +1225,7 @@ static struct omap_dss_driver dsicm_ops = {
static int dsicm_probe_of(struct platform_device *pdev) static int dsicm_probe_of(struct platform_device *pdev)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct device_node *backlight;
struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *in; struct omap_dss_device *in;
struct display_timing timing; struct display_timing timing;
...@@ -1259,14 +1287,25 @@ static int dsicm_probe_of(struct platform_device *pdev) ...@@ -1259,14 +1287,25 @@ static int dsicm_probe_of(struct platform_device *pdev)
ddata->in = in; ddata->in = in;
/* TODO: ulps, backlight */ backlight = of_parse_phandle(node, "backlight", 0);
if (backlight) {
ddata->extbldev = of_find_backlight_by_node(backlight);
of_node_put(backlight);
if (!ddata->extbldev)
return -EPROBE_DEFER;
} else {
/* assume native backlight support */
ddata->use_dsi_backlight = true;
}
/* TODO: ulps */
return 0; return 0;
} }
static int dsicm_probe(struct platform_device *pdev) static int dsicm_probe(struct platform_device *pdev)
{ {
struct backlight_properties props;
struct panel_drv_data *ddata; struct panel_drv_data *ddata;
struct backlight_device *bldev = NULL; struct backlight_device *bldev = NULL;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -1319,7 +1358,7 @@ static int dsicm_probe(struct platform_device *pdev) ...@@ -1319,7 +1358,7 @@ static int dsicm_probe(struct platform_device *pdev)
GPIOF_OUT_INIT_LOW, "taal rst"); GPIOF_OUT_INIT_LOW, "taal rst");
if (r) { if (r) {
dev_err(dev, "failed to request reset gpio\n"); dev_err(dev, "failed to request reset gpio\n");
return r; goto err_reg;
} }
} }
...@@ -1328,7 +1367,7 @@ static int dsicm_probe(struct platform_device *pdev) ...@@ -1328,7 +1367,7 @@ static int dsicm_probe(struct platform_device *pdev)
GPIOF_IN, "taal irq"); GPIOF_IN, "taal irq");
if (r) { if (r) {
dev_err(dev, "GPIO request failed\n"); dev_err(dev, "GPIO request failed\n");
return r; goto err_reg;
} }
r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio), r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio),
...@@ -1338,7 +1377,7 @@ static int dsicm_probe(struct platform_device *pdev) ...@@ -1338,7 +1377,7 @@ static int dsicm_probe(struct platform_device *pdev)
if (r) { if (r) {
dev_err(dev, "IRQ request failed\n"); dev_err(dev, "IRQ request failed\n");
return r; goto err_reg;
} }
INIT_DEFERRABLE_WORK(&ddata->te_timeout_work, INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,
...@@ -1348,48 +1387,43 @@ static int dsicm_probe(struct platform_device *pdev) ...@@ -1348,48 +1387,43 @@ static int dsicm_probe(struct platform_device *pdev)
} }
ddata->workqueue = create_singlethread_workqueue("dsicm_wq"); ddata->workqueue = create_singlethread_workqueue("dsicm_wq");
if (ddata->workqueue == NULL) { if (!ddata->workqueue) {
dev_err(dev, "can't create workqueue\n"); r = -ENOMEM;
return -ENOMEM; goto err_reg;
} }
INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work); INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);
dsicm_hw_reset(ddata); dsicm_hw_reset(ddata);
if (ddata->use_dsi_backlight) { if (ddata->use_dsi_backlight) {
memset(&props, 0, sizeof(props)); struct backlight_properties props = { 0 };
props.max_brightness = 255; props.max_brightness = 255;
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
bldev = backlight_device_register(dev_name(dev),
dev, ddata, &dsicm_bl_ops, &props); bldev = devm_backlight_device_register(dev, dev_name(dev),
dev, ddata, &dsicm_bl_ops, &props);
if (IS_ERR(bldev)) { if (IS_ERR(bldev)) {
r = PTR_ERR(bldev); r = PTR_ERR(bldev);
goto err_bl; goto err_bl;
} }
ddata->bldev = bldev; ddata->bldev = bldev;
bldev->props.fb_blank = FB_BLANK_UNBLANK;
bldev->props.power = FB_BLANK_UNBLANK;
bldev->props.brightness = 255;
dsicm_bl_update_status(bldev);
} }
r = sysfs_create_group(&dev->kobj, &dsicm_attr_group); r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
if (r) { if (r) {
dev_err(dev, "failed to create sysfs files\n"); dev_err(dev, "failed to create sysfs files\n");
goto err_sysfs_create; goto err_bl;
} }
return 0; return 0;
err_sysfs_create:
backlight_device_unregister(bldev);
err_bl: err_bl:
destroy_workqueue(ddata->workqueue); destroy_workqueue(ddata->workqueue);
err_reg: err_reg:
if (ddata->extbldev)
put_device(&ddata->extbldev->dev);
return r; return r;
} }
...@@ -1397,7 +1431,6 @@ static int __exit dsicm_remove(struct platform_device *pdev) ...@@ -1397,7 +1431,6 @@ static int __exit dsicm_remove(struct platform_device *pdev)
{ {
struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev; struct omap_dss_device *dssdev = &ddata->dssdev;
struct backlight_device *bldev;
dev_dbg(&pdev->dev, "remove\n"); dev_dbg(&pdev->dev, "remove\n");
...@@ -1408,12 +1441,8 @@ static int __exit dsicm_remove(struct platform_device *pdev) ...@@ -1408,12 +1441,8 @@ static int __exit dsicm_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group); sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
bldev = ddata->bldev; if (ddata->extbldev)
if (bldev != NULL) { put_device(&ddata->extbldev->dev);
bldev->props.power = FB_BLANK_POWERDOWN;
dsicm_bl_update_status(bldev);
backlight_device_unregister(bldev);
}
omap_dss_put_device(ddata->in); omap_dss_put_device(ddata->in);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment