brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 04ce925 Raw
324 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2020 Caleb Connolly <caleb@connolly.tech>3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:4 * Copyright (c) 2020, The Linux Foundation. All rights reserved.5 */6 7#include <linux/delay.h>8#include <linux/gpio/consumer.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/regulator/consumer.h>12#include <linux/backlight.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 20struct sofef00_panel {21	struct drm_panel panel;22	struct mipi_dsi_device *dsi;23	struct regulator *supply;24	struct gpio_desc *reset_gpio;25	const struct drm_display_mode *mode;26};27 28static inline29struct sofef00_panel *to_sofef00_panel(struct drm_panel *panel)30{31	return container_of(panel, struct sofef00_panel, panel);32}33 34static void sofef00_panel_reset(struct sofef00_panel *ctx)35{36	gpiod_set_value_cansleep(ctx->reset_gpio, 0);37	usleep_range(5000, 6000);38	gpiod_set_value_cansleep(ctx->reset_gpio, 1);39	usleep_range(2000, 3000);40	gpiod_set_value_cansleep(ctx->reset_gpio, 0);41	usleep_range(12000, 13000);42}43 44static int sofef00_panel_on(struct sofef00_panel *ctx)45{46	struct mipi_dsi_device *dsi = ctx->dsi;47	struct device *dev = &dsi->dev;48	int ret;49 50	dsi->mode_flags |= MIPI_DSI_MODE_LPM;51 52	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);53	if (ret < 0) {54		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);55		return ret;56	}57	usleep_range(10000, 11000);58 59	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);60 61	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);62	if (ret < 0) {63		dev_err(dev, "Failed to set tear on: %d\n", ret);64		return ret;65	}66 67	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);68	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);69	mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x07);70	mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x12);71	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);72	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);73	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);74 75	ret = mipi_dsi_dcs_set_display_on(dsi);76	if (ret < 0) {77		dev_err(dev, "Failed to set display on: %d\n", ret);78		return ret;79	}80 81	return 0;82}83 84static int sofef00_panel_off(struct sofef00_panel *ctx)85{86	struct mipi_dsi_device *dsi = ctx->dsi;87	struct device *dev = &dsi->dev;88	int ret;89 90	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;91 92	ret = mipi_dsi_dcs_set_display_off(dsi);93	if (ret < 0) {94		dev_err(dev, "Failed to set display off: %d\n", ret);95		return ret;96	}97	msleep(40);98 99	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);100	if (ret < 0) {101		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);102		return ret;103	}104	msleep(160);105 106	return 0;107}108 109static int sofef00_panel_prepare(struct drm_panel *panel)110{111	struct sofef00_panel *ctx = to_sofef00_panel(panel);112	struct device *dev = &ctx->dsi->dev;113	int ret;114 115	ret = regulator_enable(ctx->supply);116	if (ret < 0) {117		dev_err(dev, "Failed to enable regulator: %d\n", ret);118		return ret;119	}120 121	sofef00_panel_reset(ctx);122 123	ret = sofef00_panel_on(ctx);124	if (ret < 0) {125		dev_err(dev, "Failed to initialize panel: %d\n", ret);126		gpiod_set_value_cansleep(ctx->reset_gpio, 1);127		return ret;128	}129 130	return 0;131}132 133static int sofef00_panel_unprepare(struct drm_panel *panel)134{135	struct sofef00_panel *ctx = to_sofef00_panel(panel);136	struct device *dev = &ctx->dsi->dev;137	int ret;138 139	ret = sofef00_panel_off(ctx);140	if (ret < 0)141		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);142 143	regulator_disable(ctx->supply);144 145	return 0;146}147 148static const struct drm_display_mode enchilada_panel_mode = {149	.clock = (1080 + 112 + 16 + 36) * (2280 + 36 + 8 + 12) * 60 / 1000,150	.hdisplay = 1080,151	.hsync_start = 1080 + 112,152	.hsync_end = 1080 + 112 + 16,153	.htotal = 1080 + 112 + 16 + 36,154	.vdisplay = 2280,155	.vsync_start = 2280 + 36,156	.vsync_end = 2280 + 36 + 8,157	.vtotal = 2280 + 36 + 8 + 12,158	.width_mm = 68,159	.height_mm = 145,160};161 162static const struct drm_display_mode fajita_panel_mode = {163	.clock = (1080 + 72 + 16 + 36) * (2340 + 32 + 4 + 18) * 60 / 1000,164	.hdisplay = 1080,165	.hsync_start = 1080 + 72,166	.hsync_end = 1080 + 72 + 16,167	.htotal = 1080 + 72 + 16 + 36,168	.vdisplay = 2340,169	.vsync_start = 2340 + 32,170	.vsync_end = 2340 + 32 + 4,171	.vtotal = 2340 + 32 + 4 + 18,172	.width_mm = 68,173	.height_mm = 145,174};175 176static int sofef00_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector)177{178	struct drm_display_mode *mode;179	struct sofef00_panel *ctx = to_sofef00_panel(panel);180 181	mode = drm_mode_duplicate(connector->dev, ctx->mode);182	if (!mode)183		return -ENOMEM;184 185	drm_mode_set_name(mode);186 187	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;188	connector->display_info.width_mm = mode->width_mm;189	connector->display_info.height_mm = mode->height_mm;190	drm_mode_probed_add(connector, mode);191 192	return 1;193}194 195static const struct drm_panel_funcs sofef00_panel_panel_funcs = {196	.prepare = sofef00_panel_prepare,197	.unprepare = sofef00_panel_unprepare,198	.get_modes = sofef00_panel_get_modes,199};200 201static int sofef00_panel_bl_update_status(struct backlight_device *bl)202{203	struct mipi_dsi_device *dsi = bl_get_data(bl);204	int err;205	u16 brightness = (u16)backlight_get_brightness(bl);206 207	err = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);208	if (err < 0)209		return err;210 211	return 0;212}213 214static const struct backlight_ops sofef00_panel_bl_ops = {215	.update_status = sofef00_panel_bl_update_status,216};217 218static struct backlight_device *219sofef00_create_backlight(struct mipi_dsi_device *dsi)220{221	struct device *dev = &dsi->dev;222	const struct backlight_properties props = {223		.type = BACKLIGHT_PLATFORM,224		.brightness = 1023,225		.max_brightness = 1023,226	};227 228	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,229					      &sofef00_panel_bl_ops, &props);230}231 232static int sofef00_panel_probe(struct mipi_dsi_device *dsi)233{234	struct device *dev = &dsi->dev;235	struct sofef00_panel *ctx;236	int ret;237 238	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);239	if (!ctx)240		return -ENOMEM;241 242	ctx->mode = of_device_get_match_data(dev);243 244	if (!ctx->mode) {245		dev_err(dev, "Missing device mode\n");246		return -ENODEV;247	}248 249	ctx->supply = devm_regulator_get(dev, "vddio");250	if (IS_ERR(ctx->supply))251		return dev_err_probe(dev, PTR_ERR(ctx->supply),252				     "Failed to get vddio regulator\n");253 254	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);255	if (IS_ERR(ctx->reset_gpio))256		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),257				     "Failed to get reset-gpios\n");258 259	ctx->dsi = dsi;260	mipi_dsi_set_drvdata(dsi, ctx);261 262	dsi->lanes = 4;263	dsi->format = MIPI_DSI_FMT_RGB888;264 265	drm_panel_init(&ctx->panel, dev, &sofef00_panel_panel_funcs,266		       DRM_MODE_CONNECTOR_DSI);267 268	ctx->panel.backlight = sofef00_create_backlight(dsi);269	if (IS_ERR(ctx->panel.backlight))270		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),271				     "Failed to create backlight\n");272 273	drm_panel_add(&ctx->panel);274 275	ret = mipi_dsi_attach(dsi);276	if (ret < 0) {277		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);278		drm_panel_remove(&ctx->panel);279		return ret;280	}281 282	return 0;283}284 285static void sofef00_panel_remove(struct mipi_dsi_device *dsi)286{287	struct sofef00_panel *ctx = mipi_dsi_get_drvdata(dsi);288	int ret;289 290	ret = mipi_dsi_detach(dsi);291	if (ret < 0)292		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);293 294	drm_panel_remove(&ctx->panel);295}296 297static const struct of_device_id sofef00_panel_of_match[] = {298	{ // OnePlus 6 / enchilada299		.compatible = "samsung,sofef00",300		.data = &enchilada_panel_mode,301	},302	{ // OnePlus 6T / fajita303		.compatible = "samsung,s6e3fc2x01",304		.data = &fajita_panel_mode,305	},306	{ /* sentinel */ }307};308MODULE_DEVICE_TABLE(of, sofef00_panel_of_match);309 310static struct mipi_dsi_driver sofef00_panel_driver = {311	.probe = sofef00_panel_probe,312	.remove = sofef00_panel_remove,313	.driver = {314		.name = "panel-oneplus6",315		.of_match_table = sofef00_panel_of_match,316	},317};318 319module_mipi_dsi_driver(sofef00_panel_driver);320 321MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");322MODULE_DESCRIPTION("DRM driver for Samsung AMOLED DSI panels found in OnePlus 6/6T phones");323MODULE_LICENSE("GPL v2");324