diff options
39 files changed, 3604 insertions, 574 deletions
diff --git a/Documentation/devicetree/bindings/video/hdmi-connector.txt b/Documentation/devicetree/bindings/video/hdmi-connector.txt index ccccc19e2573..acd5668b1ce1 100644 --- a/Documentation/devicetree/bindings/video/hdmi-connector.txt +++ b/Documentation/devicetree/bindings/video/hdmi-connector.txt @@ -7,6 +7,7 @@ Required properties: Optional properties: - label: a symbolic name for the connector +- hpd-gpios: HPD GPIO number Required nodes: - Video port for HDMI input diff --git a/Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt b/Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt new file mode 100644 index 000000000000..1a1e653e5407 --- /dev/null +++ b/Documentation/devicetree/bindings/video/lgphilips,lb035q02.txt @@ -0,0 +1,33 @@ +LG.Philips LB035Q02 Panel +========================= + +Required properties: +- compatible: "lgphilips,lb035q02" +- enable-gpios: panel enable gpio + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: panel@0 { + compatible = "lgphilips,lb035q02"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + + enable-gpios = <&gpio7 7 0>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/panel-dpi.txt b/Documentation/devicetree/bindings/video/panel-dpi.txt new file mode 100644 index 000000000000..a40180b05bab --- /dev/null +++ b/Documentation/devicetree/bindings/video/panel-dpi.txt @@ -0,0 +1,45 @@ +Generic MIPI DPI Panel +====================== + +Required properties: +- compatible: "panel-dpi" + +Optional properties: +- label: a symbolic name for the panel +- enable-gpios: panel enable gpio + +Required nodes: +- "panel-timing" containing video timings + (Documentation/devicetree/bindings/video/display-timing.txt) +- Video port for DPI input + +Example +------- + +lcd0: display@0 { + compatible = "samsung,lte430wq-f0c", "panel-dpi"; + label = "lcd"; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + panel-timing { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; +}; diff --git a/Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt b/Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt new file mode 100644 index 000000000000..0cc8981e9d49 --- /dev/null +++ b/Documentation/devicetree/bindings/video/sharp,ls037v7dw01.txt @@ -0,0 +1,43 @@ +SHARP LS037V7DW01 TFT-LCD panel +=================================== + +Required properties: +- compatible: "sharp,ls037v7dw01" + +Optional properties: +- label: a symbolic name for the panel +- enable-gpios: a GPIO spec for the optional enable pin. + This pin is the INI pin as specified in the LS037V7DW01.pdf file. +- reset-gpios: a GPIO spec for the optional reset pin. + This pin is the RESB pin as specified in the LS037V7DW01.pdf file. +- mode-gpios: a GPIO + ordered MO, LR, and UD as specified in the LS037V7DW01.pdf file. + +Required nodes: +- Video port for DPI input + +This panel can have zero to five GPIOs to configure to change configuration +between QVGA and VGA mode and the scan direction. As these pins can be also +configured with external pulls, all the GPIOs are considered optional with holes +in the array. + +Example +------- + +Example when connected to a omap2+ based device: + +lcd0: display { + compatible = "sharp,ls037v7dw01"; + power-supply = <&lcd_3v3>; + enable-gpios = <&gpio5 24 GPIO_ACTIVE_HIGH>; /* gpio152, lcd INI */ + reset-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd RESB */ + mode-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH /* gpio154, lcd MO */ + &gpio1 2 GPIO_ACTIVE_HIGH /* gpio2, lcd LR */ + &gpio1 3 GPIO_ACTIVE_HIGH>; /* gpio3, lcd UD */ + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/ti,omap4-dss.txt b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt index f85d6fcfa705..b8c29fbd1fbb 100644 --- a/Documentation/devicetree/bindings/video/ti,omap4-dss.txt +++ b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt @@ -109,3 +109,7 @@ Required properties: Optional nodes: - Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/Documentation/devicetree/bindings/video/ti,omap5-dss.txt b/Documentation/devicetree/bindings/video/ti,omap5-dss.txt new file mode 100644 index 000000000000..38ffc8fcd816 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,omap5-dss.txt @@ -0,0 +1,96 @@ +Texas Instruments OMAP5 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap5-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: RFBI, DSI, HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap5-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + + +RFBI +---- + +Required properties: +- compatible: "ti,omap5-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + +Optional nodes: +- Video port for RFBI output +- RFBI controlled peripherals + + +DSI +--- + +Required properties: +- compatible: "ti,omap5-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" or "dss_dsi2" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for DSI output +- DSI controlled peripherals + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... + + +HDMI +---- + +Required properties: +- compatible: "ti,omap5-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt b/Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt new file mode 100644 index 000000000000..7175dc3740ac --- /dev/null +++ b/Documentation/devicetree/bindings/video/toppoly,td028ttec1.txt @@ -0,0 +1,30 @@ +Toppoly TD028TTEC1 Panel +======================== + +Required properties: +- compatible: "toppoly,td028ttec1" + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: td028ttec1@0 { + compatible = "toppoly,td028ttec1"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; + diff --git a/Documentation/devicetree/bindings/video/tpo,td043mtea1.txt b/Documentation/devicetree/bindings/video/tpo,td043mtea1.txt new file mode 100644 index 000000000000..ec6d62975162 --- /dev/null +++ b/Documentation/devicetree/bindings/video/tpo,td043mtea1.txt @@ -0,0 +1,33 @@ +TPO TD043MTEA1 Panel +==================== + +Required properties: +- compatible: "tpo,td043mtea1" +- reset-gpios: panel reset gpio + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: panel@0 { + compatible = "tpo,td043mtea1"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + + reset-gpios = <&gpio7 7 0>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 16d33d831287..bf852d7ae951 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -279,6 +279,8 @@ static enum omapdss_version __init omap_display_get_version(void) return OMAPDSS_VER_OMAP4; else if (soc_is_omap54xx()) return OMAPDSS_VER_OMAP5; + else if (soc_is_am43xx()) + return OMAPDSS_VER_AM43xx; else return OMAPDSS_VER_UNKNOWN; } @@ -555,65 +557,9 @@ int omap_dss_reset(struct omap_hwmod *oh) return r; } -/* list of 'compatible' nodes to convert to omapdss specific */ -static const char * const dss_compat_conv_list[] __initconst = { - "composite-connector", - "dvi-connector", - "hdmi-connector", - "panel-dpi", - "panel-dsi-cm", - "sony,acx565akm", - "svideo-connector", - "ti,tfp410", - "ti,tpd12s015", -}; - -/* prepend compatible string with "omapdss," */ -static __init void omapdss_omapify_node(struct device_node *node, - const char *compat) -{ - char *new_compat; - struct property *prop; - - new_compat = kasprintf(GFP_KERNEL, "omapdss,%s", compat); - - prop = kzalloc(sizeof(*prop), GFP_KERNEL); - - if (!prop) { - pr_err("omapdss_omapify_node: kzalloc failed\n"); - return; - } - - prop->name = "compatible"; - prop->value = new_compat; - prop->length = strlen(new_compat) + 1; - - of_update_property(node, prop); -} - -/* - * As omapdss panel drivers are omapdss specific, but we want to define the - * DT-data in generic manner, we convert the compatible strings of the panel - * nodes from "panel-foo" to "omapdss,panel-foo". This way we can have both - * correct DT data and omapdss specific drivers. - * - * When we get generic panel drivers to the kernel, this will be removed. - */ void __init omapdss_early_init_of(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(dss_compat_conv_list); ++i) { - const char *compat = dss_compat_conv_list[i]; - struct device_node *node = NULL; - - while ((node = of_find_compatible_node(node, NULL, compat))) { - if (!of_device_is_available(node)) - continue; - omapdss_omapify_node(node, compat); - } - } } struct device_node * __init omapdss_find_dss_of_node(void) @@ -632,6 +578,10 @@ struct device_node * __init omapdss_find_dss_of_node(void) if (node) return node; + node = of_find_compatible_node(NULL, NULL, "ti,omap5-dss"); + if (node) + return node; + return NULL; } diff --git a/drivers/video/fbdev/omap2/Makefile b/drivers/video/fbdev/omap2/Makefile index bf8127df8c71..f8745ec369cc 100644 --- a/drivers/video/fbdev/omap2/Makefile +++ b/drivers/video/fbdev/omap2/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o -obj-$(CONFIG_OMAP2_DSS) += dss/ +obj-y += dss/ obj-y += displays-new/ obj-$(CONFIG_FB_OMAP2) += omapfb/ diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c index 29ed21b9dce5..4420ccb69aa9 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> +#include <linux/of_gpio.h> #include <drm/drm_edid.h> @@ -43,6 +44,8 @@ struct panel_drv_data { struct device *dev; struct omap_video_timings timings; + + int hpd_gpio; }; #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) @@ -161,7 +164,10 @@ static bool hdmic_detect(struct omap_dss_device *dssdev) struct panel_drv_data *ddata = to_panel_data(dssdev); struct omap_dss_device *in = ddata->in; - return in->ops.hdmi->detect(in); + if (gpio_is_valid(ddata->hpd_gpio)) + return gpio_get_value_cansleep(ddata->hpd_gpio); + else + return in->ops.hdmi->detect(in); } static int hdmic_audio_enable(struct omap_dss_device *dssdev) @@ -288,6 +294,8 @@ static int hdmic_probe_pdata(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); + ddata->hpd_gpio = -ENODEV; + in = omap_dss_find_output(pdata->source); if (in == NULL) { dev_err(&pdev->dev, "Failed to find video source\n"); @@ -307,6 +315,14 @@ static int hdmic_probe_of(struct platform_device *pdev) struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; struct omap_dss_device *in; + int gpio; + + /* HPD GPIO */ + gpio = of_get_named_gpio(node, "hpd-gpios", 0); + if (gpio_is_valid(gpio)) + ddata->hpd_gpio = gpio; + else + ddata->hpd_gpio = -ENODEV; in = omapdss_of_find_source_for_first_ep(node); if (IS_ERR(in)) { @@ -344,6 +360,13 @@ static int hdmic_probe(struct platform_device *pdev) return -ENODEV; } + if (gpio_is_valid(ddata->hpd_gpio)) { + r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, + GPIOF_DIR_IN, "hdmi_hpd"); + if (r) + goto err_reg; + } + ddata->timings = hdmic_default_timings; dssdev = &ddata->dssdev; diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c index 5f8f7e7c81ef..3636b61dc9b4 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c @@ -13,9 +13,12 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> +#include <video/of_display_timing.h> struct panel_drv_data { struct omap_dss_device dssdev; @@ -25,8 +28,10 @@ struct panel_drv_data { struct omap_video_timings videomode; + /* used for non-DT boot, to be removed */ int backlight_gpio; - int enable_gpio; + + struct gpio_desc *enable_gpio; }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) @@ -70,15 +75,16 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev) if (omapdss_device_is_enabled(dssdev)) return 0; - in->ops.dpi->set_data_lines(in, ddata->data_lines); + if (ddata->data_lines) + 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 (ddata->enable_gpio) + gpiod_set_value_cansleep(ddata->enable_gpio, 1); if (gpio_is_valid(ddata->backlight_gpio)) gpio_set_value_cansleep(ddata->backlight_gpio, 1); @@ -96,8 +102,8 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev) if (!omapdss_device_is_enabled(dssdev)) return; - if (gpio_is_valid(ddata->enable_gpio)) - gpio_set_value_cansleep(ddata->enable_gpio, 0); + if (ddata->enable_gpio) + gpiod_set_value_cansleep(ddata->enable_gpio, 0); if (gpio_is_valid(ddata->backlight_gpio)) gpio_set_value_cansleep(ddata->backlight_gpio, 0); @@ -156,6 +162,7 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev) struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev, *in; struct videomode vm; + int r; pdata = dev_get_platdata(&pdev->dev); @@ -176,10 +183,65 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev) dssdev = &ddata->dssdev; dssdev->name = pdata->name; - ddata->enable_gpio = pdata->enable_gpio; + r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio, + GPIOF_OUT_INIT_LOW, "panel enable"); + if (r) + goto err_gpio; + + ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio); + ddata->backlight_gpio = pdata->backlight_gpio; return 0; + +err_gpio: + omap_dss_put_device(ddata->in); + return r; +} + +static int panel_dpi_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int r; + struct display_timing timing; + struct videomode vm; + struct gpio_desc *gpio; + + gpio = devm_gpiod_get(&pdev->dev, "enable"); + + if (IS_ERR(gpio)) { + if (PTR_ERR(gpio) != -ENOENT) + return PTR_ERR(gpio); + else + gpio = NULL; + } else { + gpiod_direction_output(gpio, 0); + } + + ddata->enable_gpio = gpio; + + ddata->backlight_gpio = -ENOENT; + + r = of_get_display_timing(node, "panel-timing", &timing); + if (r) { + dev_err(&pdev->dev, "failed to get video timing\n"); + return r; + } + + videomode_from_timing(&timing, &vm); + videomode_to_omap_video_timings(&vm, &ddata->videomode); + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; } static int panel_dpi_probe(struct platform_device *pdev) @@ -198,17 +260,14 @@ static int panel_dpi_probe(struct platform_device *pdev) r = panel_dpi_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = panel_dpi_probe_of(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"); @@ -254,12 +313,20 @@ static int __exit panel_dpi_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id panel_dpi_of_match[] = { + { .compatible = "omapdss,panel-dpi", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, panel_dpi_of_match); + static struct platform_driver panel_dpi_driver = { .probe = panel_dpi_probe, .remove = __exit_p(panel_dpi_remove), .driver = { .name = "panel-dpi", .owner = THIS_MODULE, + .of_match_table = panel_dpi_of_match, }, }; diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c index 2e6b513222d9..cc5b5124e0b4 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c @@ -50,9 +50,10 @@ struct panel_drv_data { struct omap_video_timings videomode; - int reset_gpio; + /* used for non-DT boot, to be removed */ int backlight_gpio; - int enable_gpio; + + struct gpio_desc *enable_gpio; }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) @@ -158,15 +159,16 @@ static int lb035q02_enable(struct omap_dss_device *dssdev) if (omapdss_device_is_enabled(dssdev)) return 0; - in->ops.dpi->set_data_lines(in, ddata->data_lines); + if (ddata->data_lines) + 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 (ddata->enable_gpio) + gpiod_set_value_cansleep(ddata->enable_gpio, 1); if (gpio_is_valid(ddata->backlight_gpio)) gpio_set_value_cansleep(ddata->backlight_gpio, 1); @@ -184,8 +186,8 @@ static void lb035q02_disable(struct omap_dss_device *dssdev) if (!omapdss_device_is_enabled(dssdev)) return; - if (gpio_is_valid(ddata->enable_gpio)) - gpio_set_value_cansleep(ddata->enable_gpio, 0); + if (ddata->enable_gpio) + gpiod_set_value_cansleep(ddata->enable_gpio, 0); if (gpio_is_valid(ddata->backlight_gpio)) gpio_set_value_cansleep(ddata->backlight_gpio, 0); @@ -243,6 +245,7 @@ static int lb035q02_probe_pdata(struct spi_device *spi) const struct panel_lb035q02_platform_data *pdata; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev, *in; + int r; pdata = dev_get_platdata(&spi->dev); @@ -260,10 +263,48 @@ static int lb035q02_probe_pdata(struct spi_device *spi) dssdev = &ddata->dssdev; dssdev->name = pdata->name; - ddata->enable_gpio = pdata->enable_gpio; + r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio, + GPIOF_OUT_INIT_LOW, "panel enable"); + if (r) + goto err_gpio; + + ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio); + ddata->backlight_gpio = pdata->backlight_gpio; return 0; +err_gpio: + omap_dss_put_device(ddata->in); + return r; +} + +static int lb035q02_probe_of(struct spi_device *spi) +{ + struct device_node *node = spi->dev.of_node; + struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); + struct omap_dss_device *in; + struct gpio_desc *gpio; + + gpio = devm_gpiod_get(&spi->dev, "enable"); + if (IS_ERR(gpio)) { + dev_err(&spi->dev, "failed to parse enable gpio\n"); + return PTR_ERR(gpio); + } else { + gpiod_direction_output(gpio, 0); + ddata->enable_gpio = gpio; + } + + ddata->backlight_gpio = -ENOENT; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&spi->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; } static int lb035q02_panel_spi_probe(struct spi_device *spi) @@ -284,17 +325,14 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) r = lb035q02_probe_pdata(spi); if (r) return r; + } else if (spi->dev.of_node) { + r = lb035q02_probe_of(spi); + if (r) + return r; } else { return -ENODEV; } - if (gpio_is_valid(ddata->enable_gpio)) { - r = devm_gpio_request_one(&spi->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(&spi->dev, ddata->backlight_gpio, GPIOF_OUT_INIT_LOW, "panel backlight"); @@ -342,17 +380,26 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi) return 0; } +static const struct of_device_id lb035q02_of_match[] = { + { .compatible = "omapdss,lgphilips,lb035q02", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, lb035q02_of_match); + static struct spi_driver lb035q02_sp |