brintos

brintos / linux-shallow public Read only

0
0
Text · 10.1 KiB · 1cbc257 Raw
406 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2020 BSH Hausgerate GmbH4 */5 6#include <linux/delay.h>7#include <linux/device.h>8#include <linux/err.h>9#include <linux/errno.h>10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/of.h>13 14#include <linux/gpio/consumer.h>15#include <linux/regulator/consumer.h>16 17#include <drm/drm_mipi_dsi.h>18#include <drm/drm_modes.h>19#include <drm/drm_panel.h>20 21#include <video/mipi_display.h>22 23#define ILI9805_EXTCMD_CMD_SET_ENABLE_REG	(0xff)24#define ILI9805_SETEXTC_PARAMETER1		(0xff)25#define ILI9805_SETEXTC_PARAMETER2		(0x98)26#define ILI9805_SETEXTC_PARAMETER3		(0x05)27 28#define ILI9805_INSTR(_delay, ...) { \29		.delay = (_delay), \30		.len = sizeof((u8[]) {__VA_ARGS__}), \31		.data = (u8[]){__VA_ARGS__} \32	}33 34struct ili9805_instr {35	size_t len;36	const u8 *data;37	u32 delay;38};39 40struct ili9805_desc {41	const char *name;42	const struct ili9805_instr *init;43	const size_t init_length;44	const struct drm_display_mode *mode;45	u32 width_mm;46	u32 height_mm;47};48 49struct ili9805 {50	struct drm_panel	panel;51	struct mipi_dsi_device	*dsi;52	const struct ili9805_desc	*desc;53 54	struct regulator	*dvdd;55	struct regulator	*avdd;56	struct gpio_desc	*reset_gpio;57};58 59static const struct ili9805_instr gpm1780a0_init[] = {60	ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,61		      ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),62	ILI9805_INSTR(100, 0xFD, 0x0F, 0x10, 0x44, 0x00),63	ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,64		      0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00),65	ILI9805_INSTR(0, 0xB8, 0x62),66	ILI9805_INSTR(0, 0xF1, 0x00),67	ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),68	ILI9805_INSTR(0, 0xF3, 0x60, 0x83, 0x04),69	ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),70	ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),71	ILI9805_INSTR(0, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,72		      0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),73	ILI9805_INSTR(0, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,74		      0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),75	ILI9805_INSTR(10, 0xc1, 0x13, 0x39, 0x19, 0x06),76	ILI9805_INSTR(10, 0xc7, 0xe5),77	ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),78	ILI9805_INSTR(10, 0xB4, 0x02),79	ILI9805_INSTR(0, 0xBB, 0x14, 0x55),80	ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x08),81	ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),82	ILI9805_INSTR(0, 0x20),83	ILI9805_INSTR(0, 0xB0, 0x01),84	ILI9805_INSTR(0, 0xB6, 0x31, 0x00, 0xef),85	ILI9805_INSTR(0, 0xDF, 0x23),86	ILI9805_INSTR(0, 0xB9, 0x02, 0x00),87};88 89static const struct ili9805_instr tm041xdhg01_init[] = {90	ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,91		      ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),92	ILI9805_INSTR(100, 0xFD, 0x0F, 0x13, 0x44, 0x00),93	ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,94		      0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01),95	ILI9805_INSTR(0, 0xB8, 0x74),96	ILI9805_INSTR(0, 0xF1, 0x00),97	ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),98	ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),99	ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),100	ILI9805_INSTR(0, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,101		      0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),102	ILI9805_INSTR(0, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,103		      0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),104	ILI9805_INSTR(10, 0xc1, 0x15, 0x03, 0x03, 0x31),105	ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),106	ILI9805_INSTR(10, 0xB4, 0x02),107	ILI9805_INSTR(0, 0xBB, 0x14, 0x55),108	ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x0a),109	ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),110	ILI9805_INSTR(0, 0x20),111	ILI9805_INSTR(0, 0xB0, 0x00),112	ILI9805_INSTR(0, 0xB6, 0x01),113	ILI9805_INSTR(0, 0xc2, 0x11),114	ILI9805_INSTR(0, 0x51, 0xFF),115	ILI9805_INSTR(0, 0x53, 0x24),116	ILI9805_INSTR(0, 0x55, 0x00),117};118 119static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)120{121	return container_of(panel, struct ili9805, panel);122}123 124static int ili9805_power_on(struct ili9805 *ctx)125{126	struct mipi_dsi_device *dsi = ctx->dsi;127	struct device *dev = &dsi->dev;128	int ret;129 130	ret = regulator_enable(ctx->avdd);131	if (ret) {132		dev_err(dev, "Failed to enable avdd regulator (%d)\n", ret);133		return ret;134	}135 136	ret = regulator_enable(ctx->dvdd);137	if (ret) {138		dev_err(dev, "Failed to enable dvdd regulator (%d)\n", ret);139		regulator_disable(ctx->avdd);140		return ret;141	}142 143	gpiod_set_value(ctx->reset_gpio, 0);144	usleep_range(5000, 10000);145	gpiod_set_value(ctx->reset_gpio, 1);146	msleep(120);147 148	return 0;149}150 151static int ili9805_power_off(struct ili9805 *ctx)152{153	gpiod_set_value(ctx->reset_gpio, 0);154	regulator_disable(ctx->dvdd);155	regulator_disable(ctx->avdd);156 157	return 0;158}159 160static int ili9805_activate(struct ili9805 *ctx)161{162	struct mipi_dsi_device *dsi = ctx->dsi;163	struct device *dev = &dsi->dev;164	int i, ret;165 166	for (i = 0; i < ctx->desc->init_length; i++) {167		const struct ili9805_instr *instr = &ctx->desc->init[i];168 169		ret = mipi_dsi_dcs_write_buffer(ctx->dsi, instr->data, instr->len);170		if (ret < 0)171			return ret;172 173		if (instr->delay > 0)174			msleep(instr->delay);175	}176 177	ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);178	if (ret) {179		dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);180		return ret;181	}182 183	usleep_range(5000, 6000);184 185	ret = mipi_dsi_dcs_set_display_on(ctx->dsi);186	if (ret) {187		dev_err(dev, "Failed to set display ON (%d)\n", ret);188		return ret;189	}190 191	return 0;192}193 194static int ili9805_prepare(struct drm_panel *panel)195{196	struct ili9805 *ctx = panel_to_ili9805(panel);197	int ret;198 199	ret = ili9805_power_on(ctx);200	if (ret)201		return ret;202 203	ret = ili9805_activate(ctx);204	if (ret) {205		ili9805_power_off(ctx);206		return ret;207	}208 209	return 0;210}211 212static int ili9805_deactivate(struct ili9805 *ctx)213{214	struct mipi_dsi_device *dsi = ctx->dsi;215	struct device *dev = &dsi->dev;216	int ret;217 218	ret = mipi_dsi_dcs_set_display_off(ctx->dsi);219	if (ret < 0) {220		dev_err(dev, "Failed to set display OFF (%d)\n", ret);221		return ret;222	}223 224	usleep_range(5000, 10000);225 226	ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);227	if (ret < 0) {228		dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);229		return ret;230	}231 232	return 0;233}234 235static int ili9805_unprepare(struct drm_panel *panel)236{237	struct ili9805 *ctx = panel_to_ili9805(panel);238 239	ili9805_deactivate(ctx);240	ili9805_power_off(ctx);241 242	return 0;243}244 245static const struct drm_display_mode gpm1780a0_timing = {246	.clock = 26227,247 248	.hdisplay = 480,249	.hsync_start = 480 + 10,250	.hsync_end = 480 + 10 + 2,251	.htotal = 480 + 10 + 2 + 36,252 253	.vdisplay = 480,254	.vsync_start = 480 + 2,255	.vsync_end = 480 + 10 + 4,256	.vtotal = 480 + 2 + 4 + 10,257};258 259static const struct drm_display_mode tm041xdhg01_timing = {260	.clock = 26227,261 262	.hdisplay = 480,263	.hsync_start = 480 + 10,264	.hsync_end = 480 + 10 + 2,265	.htotal = 480 + 10 + 2 + 36,266 267	.vdisplay = 768,268	.vsync_start = 768 + 2,269	.vsync_end = 768 + 10 + 4,270	.vtotal = 768 + 2 + 4 + 10,271};272 273static int ili9805_get_modes(struct drm_panel *panel,274			      struct drm_connector *connector)275{276	struct ili9805 *ctx = panel_to_ili9805(panel);277	struct drm_display_mode *mode;278 279	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);280	if (!mode) {281		dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",282			ctx->desc->mode->hdisplay,283			ctx->desc->mode->vdisplay,284			drm_mode_vrefresh(ctx->desc->mode));285		return -ENOMEM;286	}287 288	drm_mode_set_name(mode);289 290	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;291	drm_mode_probed_add(connector, mode);292 293	connector->display_info.width_mm = mode->width_mm;294	connector->display_info.height_mm = mode->height_mm;295 296	return 1;297}298 299static const struct drm_panel_funcs ili9805_funcs = {300	.prepare	= ili9805_prepare,301	.unprepare	= ili9805_unprepare,302	.get_modes	= ili9805_get_modes,303};304 305static int ili9805_dsi_probe(struct mipi_dsi_device *dsi)306{307	struct ili9805 *ctx;308	int ret;309 310	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);311	if (!ctx)312		return -ENOMEM;313	mipi_dsi_set_drvdata(dsi, ctx);314	ctx->dsi = dsi;315	ctx->desc = of_device_get_match_data(&dsi->dev);316 317	dsi->format = MIPI_DSI_FMT_RGB888;318	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |319		MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |320		MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET;321	dsi->lanes = 2;322 323	drm_panel_init(&ctx->panel, &dsi->dev, &ili9805_funcs,324		       DRM_MODE_CONNECTOR_DSI);325 326	ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");327	if (IS_ERR(ctx->dvdd))328		return PTR_ERR(ctx->dvdd);329	ctx->avdd = devm_regulator_get(&dsi->dev, "avdd");330	if (IS_ERR(ctx->avdd))331		return PTR_ERR(ctx->avdd);332 333	ctx->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);334	if (IS_ERR(ctx->reset_gpio)) {335		dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");336		return PTR_ERR(ctx->reset_gpio);337	}338 339	ctx->panel.prepare_prev_first = true;340	ret = drm_panel_of_backlight(&ctx->panel);341	if (ret)342		return ret;343 344	drm_panel_add(&ctx->panel);345 346	ret = mipi_dsi_attach(dsi);347	if (ret < 0) {348		dev_err(&dsi->dev, "mipi_dsi_attach failed: %d\n", ret);349		drm_panel_remove(&ctx->panel);350		return ret;351	}352 353	return 0;354}355 356static void ili9805_dsi_remove(struct mipi_dsi_device *dsi)357{358	struct ili9805 *ctx = mipi_dsi_get_drvdata(dsi);359	int ret;360 361	ret = mipi_dsi_detach(dsi);362	if (ret < 0)363		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",364			ret);365 366	drm_panel_remove(&ctx->panel);367}368 369static const struct ili9805_desc gpm1780a0_desc = {370	.init = gpm1780a0_init,371	.init_length = ARRAY_SIZE(gpm1780a0_init),372	.mode = &gpm1780a0_timing,373	.width_mm = 65,374	.height_mm = 65,375};376 377static const struct ili9805_desc tm041xdhg01_desc = {378	.init = tm041xdhg01_init,379	.init_length = ARRAY_SIZE(tm041xdhg01_init),380	.mode = &tm041xdhg01_timing,381	.width_mm = 42,382	.height_mm = 96,383};384 385static const struct of_device_id ili9805_of_match[] = {386	{ .compatible = "giantplus,gpm1790a0", .data = &gpm1780a0_desc },387	{ .compatible = "tianma,tm041xdhg01", .data = &tm041xdhg01_desc },388	{ }389};390MODULE_DEVICE_TABLE(of, ili9805_of_match);391 392static struct mipi_dsi_driver ili9805_dsi_driver = {393	.probe		= ili9805_dsi_probe,394	.remove		= ili9805_dsi_remove,395	.driver = {396		.name		= "ili9805-dsi",397		.of_match_table	= ili9805_of_match,398	},399};400module_mipi_dsi_driver(ili9805_dsi_driver);401 402MODULE_AUTHOR("Matthias Proske <Matthias.Proske@bshg.com>");403MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");404MODULE_DESCRIPTION("Ilitek ILI9805 Controller Driver");405MODULE_LICENSE("GPL");406