brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · e85d63a Raw
284 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2022 Joel Selvaraj <jo@jsfamily.in>4 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:5 * Copyright (c) 2013, The Linux Foundation. All rights reserved.6 */7 8#include <linux/delay.h>9#include <linux/gpio/consumer.h>10#include <linux/regulator/consumer.h>11#include <linux/module.h>12#include <linux/of.h>13 14#include <video/mipi_display.h>15 16#include <drm/drm_mipi_dsi.h>17#include <drm/drm_modes.h>18#include <drm/drm_panel.h>19 20static const char * const regulator_names[] = {21	"vddio",22	"vddpos",23	"vddneg",24};25 26static const unsigned long regulator_enable_loads[] = {27	62000,28	100000,29	10000030};31 32struct ebbg_ft8719 {33	struct drm_panel panel;34	struct mipi_dsi_device *dsi;35 36	struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];37 38	struct gpio_desc *reset_gpio;39};40 41static inline42struct ebbg_ft8719 *to_ebbg_ft8719(struct drm_panel *panel)43{44	return container_of(panel, struct ebbg_ft8719, panel);45}46 47static void ebbg_ft8719_reset(struct ebbg_ft8719 *ctx)48{49	gpiod_set_value_cansleep(ctx->reset_gpio, 0);50	usleep_range(4000, 5000);51	gpiod_set_value_cansleep(ctx->reset_gpio, 1);52	usleep_range(1000, 2000);53	gpiod_set_value_cansleep(ctx->reset_gpio, 0);54	usleep_range(15000, 16000);55}56 57static int ebbg_ft8719_on(struct ebbg_ft8719 *ctx)58{59	struct mipi_dsi_device *dsi = ctx->dsi;60	struct device *dev = &dsi->dev;61	int ret;62 63	dsi->mode_flags |= MIPI_DSI_MODE_LPM;64 65	ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff);66	if (ret < 0) {67		dev_err(dev, "Failed to set display brightness: %d\n", ret);68		return ret;69	}70 71	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);72	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);73 74	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);75	if (ret < 0) {76		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);77		return ret;78	}79	msleep(90);80 81	ret = mipi_dsi_dcs_set_display_on(dsi);82	if (ret < 0) {83		dev_err(dev, "Failed to set display on: %d\n", ret);84		return ret;85	}86 87	return 0;88}89 90static int ebbg_ft8719_off(struct ebbg_ft8719 *ctx)91{92	struct mipi_dsi_device *dsi = ctx->dsi;93	struct device *dev = &dsi->dev;94	int ret;95 96	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;97 98	ret = mipi_dsi_dcs_set_display_off(dsi);99	if (ret < 0) {100		dev_err(dev, "Failed to set display off: %d\n", ret);101		return ret;102	}103	usleep_range(10000, 11000);104 105	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);106	if (ret < 0) {107		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);108		return ret;109	}110	msleep(90);111 112	return 0;113}114 115static int ebbg_ft8719_prepare(struct drm_panel *panel)116{117	struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);118	struct device *dev = &ctx->dsi->dev;119	int ret;120 121	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);122	if (ret < 0)123		return ret;124 125	ebbg_ft8719_reset(ctx);126 127	ret = ebbg_ft8719_on(ctx);128	if (ret < 0) {129		dev_err(dev, "Failed to initialize panel: %d\n", ret);130		gpiod_set_value_cansleep(ctx->reset_gpio, 1);131		return ret;132	}133 134	return 0;135}136 137static int ebbg_ft8719_unprepare(struct drm_panel *panel)138{139	struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);140	struct device *dev = &ctx->dsi->dev;141	int ret;142 143	ret = ebbg_ft8719_off(ctx);144	if (ret < 0)145		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);146 147	gpiod_set_value_cansleep(ctx->reset_gpio, 1);148 149	ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);150	if (ret)151		dev_err(panel->dev, "Failed to disable regulators: %d\n", ret);152 153	return 0;154}155 156static const struct drm_display_mode ebbg_ft8719_mode = {157	.clock = (1080 + 28 + 4 + 16) * (2246 + 120 + 4 + 12) * 60 / 1000,158	.hdisplay = 1080,159	.hsync_start = 1080 + 28,160	.hsync_end = 1080 + 28 + 4,161	.htotal = 1080 + 28 + 4 + 16,162	.vdisplay = 2246,163	.vsync_start = 2246 + 120,164	.vsync_end = 2246 + 120 + 4,165	.vtotal = 2246 + 120 + 4 + 12,166	.width_mm = 68,167	.height_mm = 141,168};169 170static int ebbg_ft8719_get_modes(struct drm_panel *panel,171				     struct drm_connector *connector)172{173	struct drm_display_mode *mode;174 175	mode = drm_mode_duplicate(connector->dev, &ebbg_ft8719_mode);176	if (!mode)177		return -ENOMEM;178 179	drm_mode_set_name(mode);180 181	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;182	connector->display_info.width_mm = mode->width_mm;183	connector->display_info.height_mm = mode->height_mm;184	drm_mode_probed_add(connector, mode);185 186	return 1;187}188 189static const struct drm_panel_funcs ebbg_ft8719_panel_funcs = {190	.prepare = ebbg_ft8719_prepare,191	.unprepare = ebbg_ft8719_unprepare,192	.get_modes = ebbg_ft8719_get_modes,193};194 195static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi)196{197	struct device *dev = &dsi->dev;198	struct ebbg_ft8719 *ctx;199	int i, ret;200 201	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);202	if (!ctx)203		return -ENOMEM;204 205	for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)206		ctx->supplies[i].supply = regulator_names[i];207 208	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),209				      ctx->supplies);210	if (ret < 0)211		return dev_err_probe(dev, ret, "Failed to get regulators\n");212 213	for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {214		ret = regulator_set_load(ctx->supplies[i].consumer,215						regulator_enable_loads[i]);216		if (ret)217			return dev_err_probe(dev, ret,218						 "Failed to set regulator load\n");219	}220 221	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);222	if (IS_ERR(ctx->reset_gpio))223		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),224				     "Failed to get reset-gpios\n");225 226	ctx->dsi = dsi;227	mipi_dsi_set_drvdata(dsi, ctx);228 229	dsi->lanes = 4;230	dsi->format = MIPI_DSI_FMT_RGB888;231	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |232			  MIPI_DSI_CLOCK_NON_CONTINUOUS;233 234	drm_panel_init(&ctx->panel, dev, &ebbg_ft8719_panel_funcs,235		       DRM_MODE_CONNECTOR_DSI);236 237	ret = drm_panel_of_backlight(&ctx->panel);238	if (ret)239		return dev_err_probe(dev, ret, "Failed to get backlight\n");240 241	drm_panel_add(&ctx->panel);242 243	ret = mipi_dsi_attach(dsi);244	if (ret < 0) {245		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);246		drm_panel_remove(&ctx->panel);247		return ret;248	}249 250	return 0;251}252 253static void ebbg_ft8719_remove(struct mipi_dsi_device *dsi)254{255	struct ebbg_ft8719 *ctx = mipi_dsi_get_drvdata(dsi);256	int ret;257 258	ret = mipi_dsi_detach(dsi);259	if (ret < 0)260		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);261 262	drm_panel_remove(&ctx->panel);263}264 265static const struct of_device_id ebbg_ft8719_of_match[] = {266	{ .compatible = "ebbg,ft8719" },267	{ /* sentinel */ }268};269MODULE_DEVICE_TABLE(of, ebbg_ft8719_of_match);270 271static struct mipi_dsi_driver ebbg_ft8719_driver = {272	.probe = ebbg_ft8719_probe,273	.remove = ebbg_ft8719_remove,274	.driver = {275		.name = "panel-ebbg-ft8719",276		.of_match_table = ebbg_ft8719_of_match,277	},278};279module_mipi_dsi_driver(ebbg_ft8719_driver);280 281MODULE_AUTHOR("Joel Selvaraj <jo@jsfamily.in>");282MODULE_DESCRIPTION("DRM driver for EBBG FT8719 video dsi panel");283MODULE_LICENSE("GPL v2");284