Skip to content

Commit

Permalink
OMAPDSS: Add new simple DPI panel driver
Browse files Browse the repository at this point in the history
Add simple DPI Panel driver which uses the new DSS device model and DSS
ops. A "simple" panel means one that does not require any special setup.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
  • Loading branch information
Tomi Valkeinen committed Jun 17, 2013
1 parent 61a7f24 commit 04f0ff0
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 0 deletions.
5 changes: 5 additions & 0 deletions drivers/video/omap2/displays-new/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@ config DISPLAY_CONNECTOR_ANALOG_TV
help
Driver for a generic analog TV connector.

config DISPLAY_PANEL_DPI
tristate "Generic DPI panel"
help
Driver for generic DPI panels.

endmenu
1 change: 1 addition & 0 deletions drivers/video/omap2/displays-new/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o
270 changes: 270 additions & 0 deletions drivers/video/omap2/displays-new/panel-dpi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Generic MIPI DPI Panel Driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/

#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include <video/omapdss.h>
#include <video/omap-panel-data.h>

struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;

int data_lines;

struct omap_video_timings videomode;

int backlight_gpio;
int enable_gpio;
};

#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)

static int panel_dpi_connect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;

if (omapdss_device_is_connected(dssdev))
return 0;

r = in->ops.dpi->connect(in, dssdev);
if (r)
return r;

return 0;
}

static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;

if (!omapdss_device_is_connected(dssdev))
return;

in->ops.dpi->disconnect(in, dssdev);
}

static int panel_dpi_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;

if (!omapdss_device_is_connected(dssdev))
return -ENODEV;

if (omapdss_device_is_enabled(dssdev))
return 0;

in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);

r = in->ops.dpi->enable(in);
if (r)
return r;

if (gpio_is_valid(ddata->enable_gpio))
gpio_set_value_cansleep(ddata->enable_gpio, 1);

if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 1);

dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;

return 0;
}

static void panel_dpi_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;

if (!omapdss_device_is_enabled(dssdev))
return;

if (gpio_is_valid(ddata->enable_gpio))
gpio_set_value_cansleep(ddata->enable_gpio, 0);

if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 0);

in->ops.dpi->disable(in);

dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}

static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;

ddata->videomode = *timings;
dssdev->panel.timings = *timings;

in->ops.dpi->set_timings(in, timings);
}

static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);

*timings = ddata->videomode;
}

static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;

return in->ops.dpi->check_timings(in, timings);
}

static struct omap_dss_driver panel_dpi_ops = {
.connect = panel_dpi_connect,
.disconnect = panel_dpi_disconnect,

.enable = panel_dpi_enable,
.disable = panel_dpi_disable,

.set_timings = panel_dpi_set_timings,
.get_timings = panel_dpi_get_timings,
.check_timings = panel_dpi_check_timings,

.get_resolution = omapdss_default_get_resolution,
};

static int panel_dpi_probe_pdata(struct platform_device *pdev)
{
const struct panel_dpi_platform_data *pdata;
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev, *in;
struct videomode vm;

pdata = dev_get_platdata(&pdev->dev);

in = omap_dss_find_output(pdata->source);
if (in == NULL) {
dev_err(&pdev->dev, "failed to find video source '%s'\n",
pdata->source);
return -EPROBE_DEFER;
}

ddata->in = in;

ddata->data_lines = pdata->data_lines;

videomode_from_timing(pdata->display_timing, &vm);
videomode_to_omap_video_timings(&vm, &ddata->videomode);

dssdev = &ddata->dssdev;
dssdev->name = pdata->name;

ddata->enable_gpio = pdata->enable_gpio;
ddata->backlight_gpio = pdata->backlight_gpio;

return 0;
}

static int panel_dpi_probe(struct platform_device *pdev)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
int r;

ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (ddata == NULL)
return -ENOMEM;

platform_set_drvdata(pdev, ddata);

if (dev_get_platdata(&pdev->dev)) {
r = panel_dpi_probe_pdata(pdev);
if (r)
return r;
} else {
return -ENODEV;
}

if (gpio_is_valid(ddata->enable_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio,
GPIOF_OUT_INIT_LOW, "panel enable");
if (r)
goto err_gpio;
}

if (gpio_is_valid(ddata->backlight_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
GPIOF_OUT_INIT_LOW, "panel backlight");
if (r)
goto err_gpio;
}

dssdev = &ddata->dssdev;
dssdev->dev = &pdev->dev;
dssdev->driver = &panel_dpi_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.timings = ddata->videomode;
dssdev->phy.dpi.data_lines = ddata->data_lines;

r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
goto err_reg;
}

return 0;

err_reg:
err_gpio:
omap_dss_put_device(ddata->in);
return r;
}

static int __exit panel_dpi_remove(struct platform_device *pdev)
{
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
struct omap_dss_device *in = ddata->in;

omapdss_unregister_display(dssdev);

panel_dpi_disable(dssdev);
panel_dpi_disconnect(dssdev);

omap_dss_put_device(in);

return 0;
}

static struct platform_driver panel_dpi_driver = {
.probe = panel_dpi_probe,
.remove = __exit_p(panel_dpi_remove),
.driver = {
.name = "panel-dpi",
.owner = THIS_MODULE,
},
};

module_platform_driver(panel_dpi_driver);

MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
MODULE_LICENSE("GPL");
23 changes: 23 additions & 0 deletions include/video/omap-panel-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#ifndef __OMAP_PANEL_DATA_H
#define __OMAP_PANEL_DATA_H

#include <video/display_timing.h>

struct omap_dss_device;

/**
Expand Down Expand Up @@ -213,4 +215,25 @@ struct connector_atv_platform_data {
bool invert_polarity;
};

/**
* panel_dpi platform data
* @name: name for this display entity
* @source: name of the display entity used as a video source
* @data_lines: number of DPI datalines
* @display_timing: timings for this panel
* @backlight_gpio: gpio to enable/disable the backlight (or -1)
* @enable_gpio: gpio to enable/disable the panel (or -1)
*/
struct panel_dpi_platform_data {
const char *name;
const char *source;

int data_lines;

const struct display_timing *display_timing;

int backlight_gpio;
int enable_gpio;
};

#endif /* __OMAP_PANEL_DATA_H */

0 comments on commit 04f0ff0

Please sign in to comment.