cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-dpi.c (7391B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Generic MIPI DPI Panel Driver
      4 *
      5 * Copyright (C) 2013 Texas Instruments
      6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      7 */
      8
      9#include <linux/gpio.h>
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/slab.h>
     13#include <linux/of.h>
     14#include <linux/of_gpio.h>
     15
     16#include <video/omapfb_dss.h>
     17#include <video/omap-panel-data.h>
     18#include <video/of_display_timing.h>
     19
     20struct panel_drv_data {
     21	struct omap_dss_device dssdev;
     22	struct omap_dss_device *in;
     23
     24	int data_lines;
     25
     26	struct omap_video_timings videomode;
     27
     28	/* used for non-DT boot, to be removed */
     29	int backlight_gpio;
     30
     31	struct gpio_desc *enable_gpio;
     32};
     33
     34#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
     35
     36static int panel_dpi_connect(struct omap_dss_device *dssdev)
     37{
     38	struct panel_drv_data *ddata = to_panel_data(dssdev);
     39	struct omap_dss_device *in = ddata->in;
     40
     41	if (omapdss_device_is_connected(dssdev))
     42		return 0;
     43
     44	return in->ops.dpi->connect(in, dssdev);
     45}
     46
     47static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
     48{
     49	struct panel_drv_data *ddata = to_panel_data(dssdev);
     50	struct omap_dss_device *in = ddata->in;
     51
     52	if (!omapdss_device_is_connected(dssdev))
     53		return;
     54
     55	in->ops.dpi->disconnect(in, dssdev);
     56}
     57
     58static int panel_dpi_enable(struct omap_dss_device *dssdev)
     59{
     60	struct panel_drv_data *ddata = to_panel_data(dssdev);
     61	struct omap_dss_device *in = ddata->in;
     62	int r;
     63
     64	if (!omapdss_device_is_connected(dssdev))
     65		return -ENODEV;
     66
     67	if (omapdss_device_is_enabled(dssdev))
     68		return 0;
     69
     70	if (ddata->data_lines)
     71		in->ops.dpi->set_data_lines(in, ddata->data_lines);
     72	in->ops.dpi->set_timings(in, &ddata->videomode);
     73
     74	r = in->ops.dpi->enable(in);
     75	if (r)
     76		return r;
     77
     78	gpiod_set_value_cansleep(ddata->enable_gpio, 1);
     79
     80	if (gpio_is_valid(ddata->backlight_gpio))
     81		gpio_set_value_cansleep(ddata->backlight_gpio, 1);
     82
     83	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
     84
     85	return 0;
     86}
     87
     88static void panel_dpi_disable(struct omap_dss_device *dssdev)
     89{
     90	struct panel_drv_data *ddata = to_panel_data(dssdev);
     91	struct omap_dss_device *in = ddata->in;
     92
     93	if (!omapdss_device_is_enabled(dssdev))
     94		return;
     95
     96	if (gpio_is_valid(ddata->backlight_gpio))
     97		gpio_set_value_cansleep(ddata->backlight_gpio, 0);
     98
     99	gpiod_set_value_cansleep(ddata->enable_gpio, 0);
    100
    101	in->ops.dpi->disable(in);
    102
    103	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
    104}
    105
    106static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
    107		struct omap_video_timings *timings)
    108{
    109	struct panel_drv_data *ddata = to_panel_data(dssdev);
    110	struct omap_dss_device *in = ddata->in;
    111
    112	ddata->videomode = *timings;
    113	dssdev->panel.timings = *timings;
    114
    115	in->ops.dpi->set_timings(in, timings);
    116}
    117
    118static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
    119		struct omap_video_timings *timings)
    120{
    121	struct panel_drv_data *ddata = to_panel_data(dssdev);
    122
    123	*timings = ddata->videomode;
    124}
    125
    126static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
    127		struct omap_video_timings *timings)
    128{
    129	struct panel_drv_data *ddata = to_panel_data(dssdev);
    130	struct omap_dss_device *in = ddata->in;
    131
    132	return in->ops.dpi->check_timings(in, timings);
    133}
    134
    135static struct omap_dss_driver panel_dpi_ops = {
    136	.connect	= panel_dpi_connect,
    137	.disconnect	= panel_dpi_disconnect,
    138
    139	.enable		= panel_dpi_enable,
    140	.disable	= panel_dpi_disable,
    141
    142	.set_timings	= panel_dpi_set_timings,
    143	.get_timings	= panel_dpi_get_timings,
    144	.check_timings	= panel_dpi_check_timings,
    145
    146	.get_resolution	= omapdss_default_get_resolution,
    147};
    148
    149static int panel_dpi_probe_pdata(struct platform_device *pdev)
    150{
    151	const struct panel_dpi_platform_data *pdata;
    152	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
    153	struct omap_dss_device *dssdev, *in;
    154	struct videomode vm;
    155	int r;
    156
    157	pdata = dev_get_platdata(&pdev->dev);
    158
    159	in = omap_dss_find_output(pdata->source);
    160	if (in == NULL) {
    161		dev_err(&pdev->dev, "failed to find video source '%s'\n",
    162				pdata->source);
    163		return -EPROBE_DEFER;
    164	}
    165
    166	ddata->in = in;
    167
    168	ddata->data_lines = pdata->data_lines;
    169
    170	videomode_from_timing(pdata->display_timing, &vm);
    171	videomode_to_omap_video_timings(&vm, &ddata->videomode);
    172
    173	dssdev = &ddata->dssdev;
    174	dssdev->name = pdata->name;
    175
    176	r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
    177					GPIOF_OUT_INIT_LOW, "panel enable");
    178	if (r)
    179		goto err_gpio;
    180
    181	ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
    182
    183	ddata->backlight_gpio = pdata->backlight_gpio;
    184
    185	return 0;
    186
    187err_gpio:
    188	omap_dss_put_device(ddata->in);
    189	return r;
    190}
    191
    192static int panel_dpi_probe_of(struct platform_device *pdev)
    193{
    194	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
    195	struct device_node *node = pdev->dev.of_node;
    196	struct omap_dss_device *in;
    197	int r;
    198	struct display_timing timing;
    199	struct videomode vm;
    200	struct gpio_desc *gpio;
    201
    202	gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
    203	if (IS_ERR(gpio))
    204		return PTR_ERR(gpio);
    205
    206	ddata->enable_gpio = gpio;
    207
    208	ddata->backlight_gpio = -ENOENT;
    209
    210	r = of_get_display_timing(node, "panel-timing", &timing);
    211	if (r) {
    212		dev_err(&pdev->dev, "failed to get video timing\n");
    213		return r;
    214	}
    215
    216	videomode_from_timing(&timing, &vm);
    217	videomode_to_omap_video_timings(&vm, &ddata->videomode);
    218
    219	in = omapdss_of_find_source_for_first_ep(node);
    220	if (IS_ERR(in)) {
    221		dev_err(&pdev->dev, "failed to find video source\n");
    222		return PTR_ERR(in);
    223	}
    224
    225	ddata->in = in;
    226
    227	return 0;
    228}
    229
    230static int panel_dpi_probe(struct platform_device *pdev)
    231{
    232	struct panel_drv_data *ddata;
    233	struct omap_dss_device *dssdev;
    234	int r;
    235
    236	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
    237	if (ddata == NULL)
    238		return -ENOMEM;
    239
    240	platform_set_drvdata(pdev, ddata);
    241
    242	if (dev_get_platdata(&pdev->dev)) {
    243		r = panel_dpi_probe_pdata(pdev);
    244		if (r)
    245			return r;
    246	} else if (pdev->dev.of_node) {
    247		r = panel_dpi_probe_of(pdev);
    248		if (r)
    249			return r;
    250	} else {
    251		return -ENODEV;
    252	}
    253
    254	if (gpio_is_valid(ddata->backlight_gpio)) {
    255		r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
    256				GPIOF_OUT_INIT_LOW, "panel backlight");
    257		if (r)
    258			goto err_gpio;
    259	}
    260
    261	dssdev = &ddata->dssdev;
    262	dssdev->dev = &pdev->dev;
    263	dssdev->driver = &panel_dpi_ops;
    264	dssdev->type = OMAP_DISPLAY_TYPE_DPI;
    265	dssdev->owner = THIS_MODULE;
    266	dssdev->panel.timings = ddata->videomode;
    267	dssdev->phy.dpi.data_lines = ddata->data_lines;
    268
    269	r = omapdss_register_display(dssdev);
    270	if (r) {
    271		dev_err(&pdev->dev, "Failed to register panel\n");
    272		goto err_reg;
    273	}
    274
    275	return 0;
    276
    277err_reg:
    278err_gpio:
    279	omap_dss_put_device(ddata->in);
    280	return r;
    281}
    282
    283static int __exit panel_dpi_remove(struct platform_device *pdev)
    284{
    285	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
    286	struct omap_dss_device *dssdev = &ddata->dssdev;
    287	struct omap_dss_device *in = ddata->in;
    288
    289	omapdss_unregister_display(dssdev);
    290
    291	panel_dpi_disable(dssdev);
    292	panel_dpi_disconnect(dssdev);
    293
    294	omap_dss_put_device(in);
    295
    296	return 0;
    297}
    298
    299static const struct of_device_id panel_dpi_of_match[] = {
    300	{ .compatible = "omapdss,panel-dpi", },
    301	{},
    302};
    303
    304MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
    305
    306static struct platform_driver panel_dpi_driver = {
    307	.probe = panel_dpi_probe,
    308	.remove = __exit_p(panel_dpi_remove),
    309	.driver = {
    310		.name = "panel-dpi",
    311		.of_match_table = panel_dpi_of_match,
    312		.suppress_bind_attrs = true,
    313	},
    314};
    315
    316module_platform_driver(panel_dpi_driver);
    317
    318MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
    319MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
    320MODULE_LICENSE("GPL");