brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · 888d94e Raw
330 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * LCD panel driver for Sharp LS037V7DW014 *5 * Copyright (C) 2013 Texas Instruments6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>7 */8 9#include <linux/delay.h>10#include <linux/gpio/consumer.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/slab.h>15#include <linux/regulator/consumer.h>16#include <video/omapfb_dss.h>17 18struct panel_drv_data {19	struct omap_dss_device dssdev;20	struct omap_dss_device *in;21	struct regulator *vcc;22 23	int data_lines;24 25	struct omap_video_timings videomode;26 27	struct gpio_desc *resb_gpio;	/* low = reset active min 20 us */28	struct gpio_desc *ini_gpio;	/* high = power on */29	struct gpio_desc *mo_gpio;	/* low = 480x640, high = 240x320 */30	struct gpio_desc *lr_gpio;	/* high = conventional horizontal scanning */31	struct gpio_desc *ud_gpio;	/* high = conventional vertical scanning */32};33 34static const struct omap_video_timings sharp_ls_timings = {35	.x_res = 480,36	.y_res = 640,37 38	.pixelclock	= 19200000,39 40	.hsw		= 2,41	.hfp		= 1,42	.hbp		= 28,43 44	.vsw		= 1,45	.vfp		= 1,46	.vbp		= 1,47 48	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW,49	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW,50	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE,51	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH,52	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_FALLING_EDGE,53};54 55#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)56 57static int sharp_ls_connect(struct omap_dss_device *dssdev)58{59	struct panel_drv_data *ddata = to_panel_data(dssdev);60	struct omap_dss_device *in = ddata->in;61 62	if (omapdss_device_is_connected(dssdev))63		return 0;64 65	return in->ops.dpi->connect(in, dssdev);66}67 68static void sharp_ls_disconnect(struct omap_dss_device *dssdev)69{70	struct panel_drv_data *ddata = to_panel_data(dssdev);71	struct omap_dss_device *in = ddata->in;72 73	if (!omapdss_device_is_connected(dssdev))74		return;75 76	in->ops.dpi->disconnect(in, dssdev);77}78 79static int sharp_ls_enable(struct omap_dss_device *dssdev)80{81	struct panel_drv_data *ddata = to_panel_data(dssdev);82	struct omap_dss_device *in = ddata->in;83	int r;84 85	if (!omapdss_device_is_connected(dssdev))86		return -ENODEV;87 88	if (omapdss_device_is_enabled(dssdev))89		return 0;90 91	if (ddata->data_lines)92		in->ops.dpi->set_data_lines(in, ddata->data_lines);93	in->ops.dpi->set_timings(in, &ddata->videomode);94 95	if (ddata->vcc) {96		r = regulator_enable(ddata->vcc);97		if (r != 0)98			return r;99	}100 101	r = in->ops.dpi->enable(in);102	if (r) {103		regulator_disable(ddata->vcc);104		return r;105	}106 107	/* wait couple of vsyncs until enabling the LCD */108	msleep(50);109 110	if (ddata->resb_gpio)111		gpiod_set_value_cansleep(ddata->resb_gpio, 1);112 113	if (ddata->ini_gpio)114		gpiod_set_value_cansleep(ddata->ini_gpio, 1);115 116	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;117 118	return 0;119}120 121static void sharp_ls_disable(struct omap_dss_device *dssdev)122{123	struct panel_drv_data *ddata = to_panel_data(dssdev);124	struct omap_dss_device *in = ddata->in;125 126	if (!omapdss_device_is_enabled(dssdev))127		return;128 129	if (ddata->ini_gpio)130		gpiod_set_value_cansleep(ddata->ini_gpio, 0);131 132	if (ddata->resb_gpio)133		gpiod_set_value_cansleep(ddata->resb_gpio, 0);134 135	/* wait at least 5 vsyncs after disabling the LCD */136 137	msleep(100);138 139	in->ops.dpi->disable(in);140 141	if (ddata->vcc)142		regulator_disable(ddata->vcc);143 144	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;145}146 147static void sharp_ls_set_timings(struct omap_dss_device *dssdev,148		struct omap_video_timings *timings)149{150	struct panel_drv_data *ddata = to_panel_data(dssdev);151	struct omap_dss_device *in = ddata->in;152 153	ddata->videomode = *timings;154	dssdev->panel.timings = *timings;155 156	in->ops.dpi->set_timings(in, timings);157}158 159static void sharp_ls_get_timings(struct omap_dss_device *dssdev,160		struct omap_video_timings *timings)161{162	struct panel_drv_data *ddata = to_panel_data(dssdev);163 164	*timings = ddata->videomode;165}166 167static int sharp_ls_check_timings(struct omap_dss_device *dssdev,168		struct omap_video_timings *timings)169{170	struct panel_drv_data *ddata = to_panel_data(dssdev);171	struct omap_dss_device *in = ddata->in;172 173	return in->ops.dpi->check_timings(in, timings);174}175 176static struct omap_dss_driver sharp_ls_ops = {177	.connect	= sharp_ls_connect,178	.disconnect	= sharp_ls_disconnect,179 180	.enable		= sharp_ls_enable,181	.disable	= sharp_ls_disable,182 183	.set_timings	= sharp_ls_set_timings,184	.get_timings	= sharp_ls_get_timings,185	.check_timings	= sharp_ls_check_timings,186 187	.get_resolution	= omapdss_default_get_resolution,188};189 190static  int sharp_ls_get_gpio_of(struct device *dev, int index, int val,191	const char *desc, struct gpio_desc **gpiod)192{193	struct gpio_desc *gd;194 195	*gpiod = NULL;196 197	gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW);198	if (IS_ERR(gd))199		return PTR_ERR(gd);200 201	*gpiod = gd;202	return 0;203}204 205static int sharp_ls_probe_of(struct platform_device *pdev)206{207	struct panel_drv_data *ddata = platform_get_drvdata(pdev);208	struct device_node *node = pdev->dev.of_node;209	struct omap_dss_device *in;210	int r;211 212	ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");213	if (IS_ERR(ddata->vcc))214		return dev_err_probe(&pdev->dev, PTR_ERR(ddata->vcc),215				     "failed to get regulator\n");216 217	/* lcd INI */218	r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio);219	if (r)220		return r;221 222	/* lcd RESB */223	r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio);224	if (r)225		return r;226 227	/* lcd MO */228	r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio);229	if (r)230		return r;231 232	/* lcd LR */233	r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio);234	if (r)235		return r;236 237	/* lcd UD */238	r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio);239	if (r)240		return r;241 242	in = omapdss_of_find_source_for_first_ep(node);243	if (IS_ERR(in)) {244		dev_err(&pdev->dev, "failed to find video source\n");245		return PTR_ERR(in);246	}247 248	ddata->in = in;249 250	return 0;251}252 253static int sharp_ls_probe(struct platform_device *pdev)254{255	struct panel_drv_data *ddata;256	struct omap_dss_device *dssdev;257	int r;258 259	if (!pdev->dev.of_node)260		return -ENODEV;261 262	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);263	if (ddata == NULL)264		return -ENOMEM;265 266	platform_set_drvdata(pdev, ddata);267 268	r = sharp_ls_probe_of(pdev);269	if (r)270		return r;271 272	ddata->videomode = sharp_ls_timings;273 274	dssdev = &ddata->dssdev;275	dssdev->dev = &pdev->dev;276	dssdev->driver = &sharp_ls_ops;277	dssdev->type = OMAP_DISPLAY_TYPE_DPI;278	dssdev->owner = THIS_MODULE;279	dssdev->panel.timings = ddata->videomode;280	dssdev->phy.dpi.data_lines = ddata->data_lines;281 282	r = omapdss_register_display(dssdev);283	if (r) {284		dev_err(&pdev->dev, "Failed to register panel\n");285		goto err_reg;286	}287 288	return 0;289 290err_reg:291	omap_dss_put_device(ddata->in);292	return r;293}294 295static void sharp_ls_remove(struct platform_device *pdev)296{297	struct panel_drv_data *ddata = platform_get_drvdata(pdev);298	struct omap_dss_device *dssdev = &ddata->dssdev;299	struct omap_dss_device *in = ddata->in;300 301	omapdss_unregister_display(dssdev);302 303	sharp_ls_disable(dssdev);304	sharp_ls_disconnect(dssdev);305 306	omap_dss_put_device(in);307}308 309static const struct of_device_id sharp_ls_of_match[] = {310	{ .compatible = "omapdss,sharp,ls037v7dw01", },311	{},312};313 314MODULE_DEVICE_TABLE(of, sharp_ls_of_match);315 316static struct platform_driver sharp_ls_driver = {317	.probe = sharp_ls_probe,318	.remove = sharp_ls_remove,319	.driver = {320		.name = "panel-sharp-ls037v7dw01",321		.of_match_table = sharp_ls_of_match,322	},323};324 325module_platform_driver(sharp_ls_driver);326 327MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");328MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");329MODULE_LICENSE("GPL");330