brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 48e3aca Raw
263 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2018 Amarula Solutions4 * Author: Jagan Teki <jagan@amarulasolutions.com>5 */6 7#include <drm/drm_mipi_dsi.h>8#include <drm/drm_modes.h>9#include <drm/drm_panel.h>10 11#include <linux/gpio/consumer.h>12#include <linux/delay.h>13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/regulator/consumer.h>16 17#define FEIYANG_INIT_CMD_LEN	218 19struct feiyang {20	struct drm_panel	panel;21	struct mipi_dsi_device	*dsi;22 23	struct regulator	*dvdd;24	struct regulator	*avdd;25	struct gpio_desc	*reset;26};27 28static inline struct feiyang *panel_to_feiyang(struct drm_panel *panel)29{30	return container_of(panel, struct feiyang, panel);31}32 33struct feiyang_init_cmd {34	u8 data[FEIYANG_INIT_CMD_LEN];35};36 37static const struct feiyang_init_cmd feiyang_init_cmds[] = {38	{ .data = { 0x80, 0x58 } },39	{ .data = { 0x81, 0x47 } },40	{ .data = { 0x82, 0xD4 } },41	{ .data = { 0x83, 0x88 } },42	{ .data = { 0x84, 0xA9 } },43	{ .data = { 0x85, 0xC3 } },44	{ .data = { 0x86, 0x82 } },45};46 47static int feiyang_prepare(struct drm_panel *panel)48{49	struct feiyang *ctx = panel_to_feiyang(panel);50	struct mipi_dsi_device *dsi = ctx->dsi;51	unsigned int i;52	int ret;53 54	ret = regulator_enable(ctx->dvdd);55	if (ret)56		return ret;57 58	/* T1 (dvdd start + dvdd rise) 0 < T1 <= 10ms */59	msleep(10);60 61	ret = regulator_enable(ctx->avdd);62	if (ret)63		return ret;64 65	/* T3 (dvdd rise + avdd start + avdd rise) T3 >= 20ms */66	msleep(20);67 68	gpiod_set_value(ctx->reset, 0);69 70	/*71	 * T5 + T6 (avdd rise + video & logic signal rise)72	 * T5 >= 10ms, 0 < T6 <= 10ms73	 */74	msleep(20);75 76	gpiod_set_value(ctx->reset, 1);77 78	/* T12 (video & logic signal rise + backlight rise) T12 >= 200ms */79	msleep(200);80 81	for (i = 0; i < ARRAY_SIZE(feiyang_init_cmds); i++) {82		const struct feiyang_init_cmd *cmd =83						&feiyang_init_cmds[i];84 85		ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data,86						FEIYANG_INIT_CMD_LEN);87		if (ret < 0)88			return ret;89	}90 91	return 0;92}93 94static int feiyang_enable(struct drm_panel *panel)95{96	struct feiyang *ctx = panel_to_feiyang(panel);97 98	/* T12 (video & logic signal rise + backlight rise) T12 >= 200ms */99	msleep(200);100 101	mipi_dsi_dcs_set_display_on(ctx->dsi);102 103	return 0;104}105 106static int feiyang_disable(struct drm_panel *panel)107{108	struct feiyang *ctx = panel_to_feiyang(panel);109 110	return mipi_dsi_dcs_set_display_off(ctx->dsi);111}112 113static int feiyang_unprepare(struct drm_panel *panel)114{115	struct feiyang *ctx = panel_to_feiyang(panel);116	int ret;117 118	ret = mipi_dsi_dcs_set_display_off(ctx->dsi);119	if (ret < 0)120		dev_err(panel->dev, "failed to set display off: %d\n", ret);121 122	ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);123	if (ret < 0)124		dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret);125 126	/* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */127	msleep(200);128 129	gpiod_set_value(ctx->reset, 0);130 131	regulator_disable(ctx->avdd);132 133	/* T11 (dvdd rise to fall) 0 < T11 <= 10ms  */134	msleep(10);135 136	regulator_disable(ctx->dvdd);137 138	return 0;139}140 141static const struct drm_display_mode feiyang_default_mode = {142	.clock		= 55000,143 144	.hdisplay	= 1024,145	.hsync_start	= 1024 + 310,146	.hsync_end	= 1024 + 310 + 20,147	.htotal		= 1024 + 310 + 20 + 90,148 149	.vdisplay	= 600,150	.vsync_start	= 600 + 12,151	.vsync_end	= 600 + 12 + 2,152	.vtotal		= 600 + 12 + 2 + 21,153 154	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,155};156 157static int feiyang_get_modes(struct drm_panel *panel,158			     struct drm_connector *connector)159{160	struct feiyang *ctx = panel_to_feiyang(panel);161	struct drm_display_mode *mode;162 163	mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode);164	if (!mode) {165		dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n",166			feiyang_default_mode.hdisplay,167			feiyang_default_mode.vdisplay,168			drm_mode_vrefresh(&feiyang_default_mode));169		return -ENOMEM;170	}171 172	drm_mode_set_name(mode);173 174	drm_mode_probed_add(connector, mode);175 176	return 1;177}178 179static const struct drm_panel_funcs feiyang_funcs = {180	.disable = feiyang_disable,181	.unprepare = feiyang_unprepare,182	.prepare = feiyang_prepare,183	.enable = feiyang_enable,184	.get_modes = feiyang_get_modes,185};186 187static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)188{189	struct feiyang *ctx;190	int ret;191 192	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);193	if (!ctx)194		return -ENOMEM;195 196	mipi_dsi_set_drvdata(dsi, ctx);197	ctx->dsi = dsi;198 199	drm_panel_init(&ctx->panel, &dsi->dev, &feiyang_funcs,200		       DRM_MODE_CONNECTOR_DSI);201 202	ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");203	if (IS_ERR(ctx->dvdd))204		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->dvdd),205				     "Couldn't get dvdd regulator\n");206 207	ctx->avdd = devm_regulator_get(&dsi->dev, "avdd");208	if (IS_ERR(ctx->avdd))209		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->avdd),210				     "Couldn't get avdd regulator\n");211 212	ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);213	if (IS_ERR(ctx->reset))214		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),215				     "Couldn't get our reset GPIO\n");216 217	ret = drm_panel_of_backlight(&ctx->panel);218	if (ret)219		return ret;220 221	drm_panel_add(&ctx->panel);222 223	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;224	dsi->format = MIPI_DSI_FMT_RGB888;225	dsi->lanes = 4;226 227	ret = mipi_dsi_attach(dsi);228	if (ret < 0) {229		drm_panel_remove(&ctx->panel);230		return ret;231	}232 233	return 0;234}235 236static void feiyang_dsi_remove(struct mipi_dsi_device *dsi)237{238	struct feiyang *ctx = mipi_dsi_get_drvdata(dsi);239 240	mipi_dsi_detach(dsi);241	drm_panel_remove(&ctx->panel);242}243 244static const struct of_device_id feiyang_of_match[] = {245	{ .compatible = "feiyang,fy07024di26a30d", },246	{ /* sentinel */ }247};248MODULE_DEVICE_TABLE(of, feiyang_of_match);249 250static struct mipi_dsi_driver feiyang_driver = {251	.probe = feiyang_dsi_probe,252	.remove = feiyang_dsi_remove,253	.driver = {254		.name = "feiyang-fy07024di26a30d",255		.of_match_table = feiyang_of_match,256	},257};258module_mipi_dsi_driver(feiyang_driver);259 260MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");261MODULE_DESCRIPTION("Feiyang FY07024DI26A30-D MIPI-DSI LCD panel");262MODULE_LICENSE("GPL");263