brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 458e657 Raw
260 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TFP410 DPI-to-DVI encoder driver4 *5 * Copyright (C) 2013 Texas Instruments6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>7 */8 9#include <linux/err.h>10#include <linux/gpio/consumer.h>11#include <linux/module.h>12#include <linux/mod_devicetable.h>13#include <linux/platform_device.h>14#include <linux/slab.h>15 16#include <video/omapfb_dss.h>17 18struct panel_drv_data {19	struct omap_dss_device dssdev;20	struct omap_dss_device *in;21 22	struct gpio_desc *pd_gpio;23 24	int data_lines;25 26	struct omap_video_timings timings;27};28 29#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)30 31static int tfp410_connect(struct omap_dss_device *dssdev,32		struct omap_dss_device *dst)33{34	struct panel_drv_data *ddata = to_panel_data(dssdev);35	struct omap_dss_device *in = ddata->in;36	int r;37 38	if (omapdss_device_is_connected(dssdev))39		return -EBUSY;40 41	r = in->ops.dpi->connect(in, dssdev);42	if (r)43		return r;44 45	dst->src = dssdev;46	dssdev->dst = dst;47 48	return 0;49}50 51static void tfp410_disconnect(struct omap_dss_device *dssdev,52		struct omap_dss_device *dst)53{54	struct panel_drv_data *ddata = to_panel_data(dssdev);55	struct omap_dss_device *in = ddata->in;56 57	WARN_ON(!omapdss_device_is_connected(dssdev));58	if (!omapdss_device_is_connected(dssdev))59		return;60 61	WARN_ON(dst != dssdev->dst);62	if (dst != dssdev->dst)63		return;64 65	dst->src = NULL;66	dssdev->dst = NULL;67 68	in->ops.dpi->disconnect(in, &ddata->dssdev);69}70 71static int tfp410_enable(struct omap_dss_device *dssdev)72{73	struct panel_drv_data *ddata = to_panel_data(dssdev);74	struct omap_dss_device *in = ddata->in;75	int r;76 77	if (!omapdss_device_is_connected(dssdev))78		return -ENODEV;79 80	if (omapdss_device_is_enabled(dssdev))81		return 0;82 83	in->ops.dpi->set_timings(in, &ddata->timings);84	if (ddata->data_lines)85		in->ops.dpi->set_data_lines(in, ddata->data_lines);86 87	r = in->ops.dpi->enable(in);88	if (r)89		return r;90 91	if (ddata->pd_gpio)92		gpiod_set_value_cansleep(ddata->pd_gpio, 0);93 94	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;95 96	return 0;97}98 99static void tfp410_disable(struct omap_dss_device *dssdev)100{101	struct panel_drv_data *ddata = to_panel_data(dssdev);102	struct omap_dss_device *in = ddata->in;103 104	if (!omapdss_device_is_enabled(dssdev))105		return;106 107	if (ddata->pd_gpio)108		gpiod_set_value_cansleep(ddata->pd_gpio, 1);109 110	in->ops.dpi->disable(in);111 112	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;113}114 115static void tfp410_fix_timings(struct omap_video_timings *timings)116{117	timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;118	timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;119	timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;120}121 122static void tfp410_set_timings(struct omap_dss_device *dssdev,123		struct omap_video_timings *timings)124{125	struct panel_drv_data *ddata = to_panel_data(dssdev);126	struct omap_dss_device *in = ddata->in;127 128	tfp410_fix_timings(timings);129 130	ddata->timings = *timings;131	dssdev->panel.timings = *timings;132 133	in->ops.dpi->set_timings(in, timings);134}135 136static void tfp410_get_timings(struct omap_dss_device *dssdev,137		struct omap_video_timings *timings)138{139	struct panel_drv_data *ddata = to_panel_data(dssdev);140 141	*timings = ddata->timings;142}143 144static int tfp410_check_timings(struct omap_dss_device *dssdev,145		struct omap_video_timings *timings)146{147	struct panel_drv_data *ddata = to_panel_data(dssdev);148	struct omap_dss_device *in = ddata->in;149 150	tfp410_fix_timings(timings);151 152	return in->ops.dpi->check_timings(in, timings);153}154 155static const struct omapdss_dvi_ops tfp410_dvi_ops = {156	.connect	= tfp410_connect,157	.disconnect	= tfp410_disconnect,158 159	.enable		= tfp410_enable,160	.disable	= tfp410_disable,161 162	.check_timings	= tfp410_check_timings,163	.set_timings	= tfp410_set_timings,164	.get_timings	= tfp410_get_timings,165};166 167static int tfp410_probe(struct platform_device *pdev)168{169	struct panel_drv_data *ddata;170	struct omap_dss_device *dssdev;171	int r;172 173	if (!pdev->dev.of_node)174		return -ENODEV;175 176	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);177	if (!ddata)178		return -ENOMEM;179 180	platform_set_drvdata(pdev, ddata);181 182	ddata->pd_gpio = devm_gpiod_get_optional(&pdev->dev, "powerdown",183						 GPIOD_OUT_HIGH);184	r = PTR_ERR_OR_ZERO(ddata->pd_gpio);185	if (r) {186		dev_err(&pdev->dev, "Failed to request PD GPIO: %d\n", r);187		return r;188	}189 190	gpiod_set_consumer_name(ddata->pd_gpio, "tfp410 PD");191 192	ddata->in = omapdss_of_find_source_for_first_ep(pdev->dev.of_node);193	r = PTR_ERR_OR_ZERO(ddata->in);194	if (r) {195		dev_err(&pdev->dev, "failed to find video source: %d\n", r);196		return r;197	}198 199	dssdev = &ddata->dssdev;200	dssdev->ops.dvi = &tfp410_dvi_ops;201	dssdev->dev = &pdev->dev;202	dssdev->type = OMAP_DISPLAY_TYPE_DPI;203	dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;204	dssdev->owner = THIS_MODULE;205	dssdev->phy.dpi.data_lines = ddata->data_lines;206	dssdev->port_num = 1;207 208	r = omapdss_register_output(dssdev);209	if (r) {210		dev_err(&pdev->dev, "Failed to register output\n");211		goto err_reg;212	}213 214	return 0;215err_reg:216	omap_dss_put_device(ddata->in);217	return r;218}219 220static void tfp410_remove(struct platform_device *pdev)221{222	struct panel_drv_data *ddata = platform_get_drvdata(pdev);223	struct omap_dss_device *dssdev = &ddata->dssdev;224	struct omap_dss_device *in = ddata->in;225 226	omapdss_unregister_output(&ddata->dssdev);227 228	WARN_ON(omapdss_device_is_enabled(dssdev));229	if (omapdss_device_is_enabled(dssdev))230		tfp410_disable(dssdev);231 232	WARN_ON(omapdss_device_is_connected(dssdev));233	if (omapdss_device_is_connected(dssdev))234		tfp410_disconnect(dssdev, dssdev->dst);235 236	omap_dss_put_device(in);237}238 239static const struct of_device_id tfp410_of_match[] = {240	{ .compatible = "omapdss,ti,tfp410", },241	{},242};243 244MODULE_DEVICE_TABLE(of, tfp410_of_match);245 246static struct platform_driver tfp410_driver = {247	.probe	= tfp410_probe,248	.remove	= tfp410_remove,249	.driver	= {250		.name	= "tfp410",251		.of_match_table = tfp410_of_match,252	},253};254 255module_platform_driver(tfp410_driver);256 257MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");258MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");259MODULE_LICENSE("GPL");260