cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-tdo-tl070wsh30.c (6177B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020 BayLibre, SAS
      4 * Author: Neil Armstrong <narmstrong@baylibre.com>
      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
     13#include <video/mipi_display.h>
     14
     15#include <drm/drm_crtc.h>
     16#include <drm/drm_device.h>
     17#include <drm/drm_mipi_dsi.h>
     18#include <drm/drm_modes.h>
     19#include <drm/drm_panel.h>
     20
     21struct tdo_tl070wsh30_panel {
     22	struct drm_panel base;
     23	struct mipi_dsi_device *link;
     24
     25	struct regulator *supply;
     26	struct gpio_desc *reset_gpio;
     27
     28	bool prepared;
     29};
     30
     31static inline
     32struct tdo_tl070wsh30_panel *to_tdo_tl070wsh30_panel(struct drm_panel *panel)
     33{
     34	return container_of(panel, struct tdo_tl070wsh30_panel, base);
     35}
     36
     37static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
     38{
     39	struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
     40	int err;
     41
     42	if (tdo_tl070wsh30->prepared)
     43		return 0;
     44
     45	err = regulator_enable(tdo_tl070wsh30->supply);
     46	if (err < 0)
     47		return err;
     48
     49	usleep_range(10000, 11000);
     50
     51	gpiod_set_value_cansleep(tdo_tl070wsh30->reset_gpio, 1);
     52
     53	usleep_range(10000, 11000);
     54
     55	gpiod_set_value_cansleep(tdo_tl070wsh30->reset_gpio, 0);
     56
     57	msleep(200);
     58
     59	err = mipi_dsi_dcs_exit_sleep_mode(tdo_tl070wsh30->link);
     60	if (err < 0) {
     61		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
     62		regulator_disable(tdo_tl070wsh30->supply);
     63		return err;
     64	}
     65
     66	msleep(200);
     67
     68	err = mipi_dsi_dcs_set_display_on(tdo_tl070wsh30->link);
     69	if (err < 0) {
     70		dev_err(panel->dev, "failed to set display on: %d\n", err);
     71		regulator_disable(tdo_tl070wsh30->supply);
     72		return err;
     73	}
     74
     75	msleep(20);
     76
     77	tdo_tl070wsh30->prepared = true;
     78
     79	return 0;
     80}
     81
     82static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)
     83{
     84	struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
     85	int err;
     86
     87	if (!tdo_tl070wsh30->prepared)
     88		return 0;
     89
     90	err = mipi_dsi_dcs_set_display_off(tdo_tl070wsh30->link);
     91	if (err < 0)
     92		dev_err(panel->dev, "failed to set display off: %d\n", err);
     93
     94	usleep_range(10000, 11000);
     95
     96	err = mipi_dsi_dcs_enter_sleep_mode(tdo_tl070wsh30->link);
     97	if (err < 0) {
     98		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
     99		return err;
    100	}
    101
    102	usleep_range(10000, 11000);
    103
    104	regulator_disable(tdo_tl070wsh30->supply);
    105
    106	tdo_tl070wsh30->prepared = false;
    107
    108	return 0;
    109}
    110
    111static const struct drm_display_mode default_mode = {
    112	.clock = 47250,
    113	.hdisplay = 1024,
    114	.hsync_start = 1024 + 46,
    115	.hsync_end = 1024 + 46 + 80,
    116	.htotal = 1024 + 46 + 80 + 100,
    117	.vdisplay = 600,
    118	.vsync_start = 600 + 5,
    119	.vsync_end = 600 + 5 + 5,
    120	.vtotal = 600 + 5 + 5 + 20,
    121	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
    122};
    123
    124static int tdo_tl070wsh30_panel_get_modes(struct drm_panel *panel,
    125				       struct drm_connector *connector)
    126{
    127	struct drm_display_mode *mode;
    128
    129	mode = drm_mode_duplicate(connector->dev, &default_mode);
    130	if (!mode) {
    131		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
    132			default_mode.hdisplay, default_mode.vdisplay,
    133			drm_mode_vrefresh(&default_mode));
    134		return -ENOMEM;
    135	}
    136
    137	drm_mode_set_name(mode);
    138
    139	drm_mode_probed_add(connector, mode);
    140
    141	connector->display_info.width_mm = 154;
    142	connector->display_info.height_mm = 85;
    143	connector->display_info.bpc = 8;
    144
    145	return 1;
    146}
    147
    148static const struct drm_panel_funcs tdo_tl070wsh30_panel_funcs = {
    149	.unprepare = tdo_tl070wsh30_panel_unprepare,
    150	.prepare = tdo_tl070wsh30_panel_prepare,
    151	.get_modes = tdo_tl070wsh30_panel_get_modes,
    152};
    153
    154static const struct of_device_id tdo_tl070wsh30_of_match[] = {
    155	{ .compatible = "tdo,tl070wsh30", },
    156	{ /* sentinel */ }
    157};
    158MODULE_DEVICE_TABLE(of, tdo_tl070wsh30_of_match);
    159
    160static int tdo_tl070wsh30_panel_add(struct tdo_tl070wsh30_panel *tdo_tl070wsh30)
    161{
    162	struct device *dev = &tdo_tl070wsh30->link->dev;
    163	int err;
    164
    165	tdo_tl070wsh30->supply = devm_regulator_get(dev, "power");
    166	if (IS_ERR(tdo_tl070wsh30->supply))
    167		return PTR_ERR(tdo_tl070wsh30->supply);
    168
    169	tdo_tl070wsh30->reset_gpio = devm_gpiod_get(dev, "reset",
    170						    GPIOD_OUT_LOW);
    171	if (IS_ERR(tdo_tl070wsh30->reset_gpio)) {
    172		err = PTR_ERR(tdo_tl070wsh30->reset_gpio);
    173		dev_dbg(dev, "failed to get reset gpio: %d\n", err);
    174		return err;
    175	}
    176
    177	drm_panel_init(&tdo_tl070wsh30->base, &tdo_tl070wsh30->link->dev,
    178		       &tdo_tl070wsh30_panel_funcs, DRM_MODE_CONNECTOR_DSI);
    179
    180	err = drm_panel_of_backlight(&tdo_tl070wsh30->base);
    181	if (err)
    182		return err;
    183
    184	drm_panel_add(&tdo_tl070wsh30->base);
    185
    186	return 0;
    187}
    188
    189static int tdo_tl070wsh30_panel_probe(struct mipi_dsi_device *dsi)
    190{
    191	struct tdo_tl070wsh30_panel *tdo_tl070wsh30;
    192	int err;
    193
    194	dsi->lanes = 4;
    195	dsi->format = MIPI_DSI_FMT_RGB888;
    196	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
    197
    198	tdo_tl070wsh30 = devm_kzalloc(&dsi->dev, sizeof(*tdo_tl070wsh30),
    199				    GFP_KERNEL);
    200	if (!tdo_tl070wsh30)
    201		return -ENOMEM;
    202
    203	mipi_dsi_set_drvdata(dsi, tdo_tl070wsh30);
    204	tdo_tl070wsh30->link = dsi;
    205
    206	err = tdo_tl070wsh30_panel_add(tdo_tl070wsh30);
    207	if (err < 0)
    208		return err;
    209
    210	return mipi_dsi_attach(dsi);
    211}
    212
    213static int tdo_tl070wsh30_panel_remove(struct mipi_dsi_device *dsi)
    214{
    215	struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = mipi_dsi_get_drvdata(dsi);
    216	int err;
    217
    218	err = mipi_dsi_detach(dsi);
    219	if (err < 0)
    220		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
    221
    222	drm_panel_remove(&tdo_tl070wsh30->base);
    223	drm_panel_disable(&tdo_tl070wsh30->base);
    224	drm_panel_unprepare(&tdo_tl070wsh30->base);
    225
    226	return 0;
    227}
    228
    229static void tdo_tl070wsh30_panel_shutdown(struct mipi_dsi_device *dsi)
    230{
    231	struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = mipi_dsi_get_drvdata(dsi);
    232
    233	drm_panel_disable(&tdo_tl070wsh30->base);
    234	drm_panel_unprepare(&tdo_tl070wsh30->base);
    235}
    236
    237static struct mipi_dsi_driver tdo_tl070wsh30_panel_driver = {
    238	.driver = {
    239		.name = "panel-tdo-tl070wsh30",
    240		.of_match_table = tdo_tl070wsh30_of_match,
    241	},
    242	.probe = tdo_tl070wsh30_panel_probe,
    243	.remove = tdo_tl070wsh30_panel_remove,
    244	.shutdown = tdo_tl070wsh30_panel_shutdown,
    245};
    246module_mipi_dsi_driver(tdo_tl070wsh30_panel_driver);
    247
    248MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    249MODULE_DESCRIPTION("TDO TL070WSH30 panel driver");
    250MODULE_LICENSE("GPL v2");