brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · d1c5c9b Raw
245 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2015 Red Hat4 * Copyright (C) 2015 Sony Mobile Communications Inc.5 * Author: Werner Johansson <werner.johansson@sonymobile.com>6 *7 * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>8 */9 10#include <linux/delay.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/regulator/consumer.h>14 15#include <video/mipi_display.h>16 17#include <drm/drm_crtc.h>18#include <drm/drm_device.h>19#include <drm/drm_mipi_dsi.h>20#include <drm/drm_panel.h>21 22/*23 * When power is turned off to this panel a minimum off time of 500ms has to be24 * observed before powering back on as there's no external reset pin. Keep25 * track of earliest wakeup time and delay subsequent prepare call accordingly26 */27#define MIN_POFF_MS (500)28 29struct wuxga_nt_panel {30	struct drm_panel base;31	struct mipi_dsi_device *dsi;32 33	struct regulator *supply;34 35	ktime_t earliest_wake;36 37	const struct drm_display_mode *mode;38};39 40static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)41{42	return container_of(panel, struct wuxga_nt_panel, base);43}44 45static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)46{47	return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi);48}49 50static int wuxga_nt_panel_disable(struct drm_panel *panel)51{52	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);53 54	return mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);55}56 57static int wuxga_nt_panel_unprepare(struct drm_panel *panel)58{59	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);60 61	regulator_disable(wuxga_nt->supply);62	wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);63 64	return 0;65}66 67static int wuxga_nt_panel_prepare(struct drm_panel *panel)68{69	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);70	int ret;71	s64 enablewait;72 73	/*74	 * If the user re-enabled the panel before the required off-time then75	 * we need to wait the remaining period before re-enabling regulator76	 */77	enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());78 79	/* Sanity check, this should never happen */80	if (enablewait > MIN_POFF_MS)81		enablewait = MIN_POFF_MS;82 83	if (enablewait > 0)84		msleep(enablewait);85 86	ret = regulator_enable(wuxga_nt->supply);87	if (ret < 0)88		return ret;89 90	/*91	 * A minimum delay of 250ms is required after power-up until commands92	 * can be sent93	 */94	msleep(250);95 96	ret = wuxga_nt_panel_on(wuxga_nt);97	if (ret < 0) {98		dev_err(panel->dev, "failed to set panel on: %d\n", ret);99		goto poweroff;100	}101 102	return 0;103 104poweroff:105	regulator_disable(wuxga_nt->supply);106 107	return ret;108}109 110static const struct drm_display_mode default_mode = {111	.clock = 164402,112	.hdisplay = 1920,113	.hsync_start = 1920 + 152,114	.hsync_end = 1920 + 152 + 52,115	.htotal = 1920 + 152 + 52 + 20,116	.vdisplay = 1200,117	.vsync_start = 1200 + 24,118	.vsync_end = 1200 + 24 + 6,119	.vtotal = 1200 + 24 + 6 + 48,120};121 122static int wuxga_nt_panel_get_modes(struct drm_panel *panel,123				    struct drm_connector *connector)124{125	struct drm_display_mode *mode;126 127	mode = drm_mode_duplicate(connector->dev, &default_mode);128	if (!mode) {129		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",130			default_mode.hdisplay, default_mode.vdisplay,131			drm_mode_vrefresh(&default_mode));132		return -ENOMEM;133	}134 135	drm_mode_set_name(mode);136 137	drm_mode_probed_add(connector, mode);138 139	connector->display_info.width_mm = 217;140	connector->display_info.height_mm = 136;141 142	return 1;143}144 145static const struct drm_panel_funcs wuxga_nt_panel_funcs = {146	.disable = wuxga_nt_panel_disable,147	.unprepare = wuxga_nt_panel_unprepare,148	.prepare = wuxga_nt_panel_prepare,149	.get_modes = wuxga_nt_panel_get_modes,150};151 152static const struct of_device_id wuxga_nt_of_match[] = {153	{ .compatible = "panasonic,vvx10f034n00", },154	{ }155};156MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);157 158static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)159{160	struct device *dev = &wuxga_nt->dsi->dev;161	int ret;162 163	wuxga_nt->mode = &default_mode;164 165	wuxga_nt->supply = devm_regulator_get(dev, "power");166	if (IS_ERR(wuxga_nt->supply))167		return PTR_ERR(wuxga_nt->supply);168 169	drm_panel_init(&wuxga_nt->base, &wuxga_nt->dsi->dev,170		       &wuxga_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);171 172	ret = drm_panel_of_backlight(&wuxga_nt->base);173	if (ret)174		return ret;175 176	drm_panel_add(&wuxga_nt->base);177 178	return 0;179}180 181static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)182{183	if (wuxga_nt->base.dev)184		drm_panel_remove(&wuxga_nt->base);185}186 187static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)188{189	struct wuxga_nt_panel *wuxga_nt;190	int ret;191 192	dsi->lanes = 4;193	dsi->format = MIPI_DSI_FMT_RGB888;194	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |195			MIPI_DSI_MODE_VIDEO_HSE |196			MIPI_DSI_CLOCK_NON_CONTINUOUS |197			MIPI_DSI_MODE_LPM;198 199	wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);200	if (!wuxga_nt)201		return -ENOMEM;202 203	mipi_dsi_set_drvdata(dsi, wuxga_nt);204 205	wuxga_nt->dsi = dsi;206 207	ret = wuxga_nt_panel_add(wuxga_nt);208	if (ret < 0)209		return ret;210 211	ret = mipi_dsi_attach(dsi);212	if (ret < 0) {213		wuxga_nt_panel_del(wuxga_nt);214		return ret;215	}216 217	return 0;218}219 220static void wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)221{222	struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);223	int ret;224 225	ret = mipi_dsi_detach(dsi);226	if (ret < 0)227		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);228 229	wuxga_nt_panel_del(wuxga_nt);230}231 232static struct mipi_dsi_driver wuxga_nt_panel_driver = {233	.driver = {234		.name = "panel-panasonic-vvx10f034n00",235		.of_match_table = wuxga_nt_of_match,236	},237	.probe = wuxga_nt_panel_probe,238	.remove = wuxga_nt_panel_remove,239};240module_mipi_dsi_driver(wuxga_nt_panel_driver);241 242MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");243MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");244MODULE_LICENSE("GPL v2");245