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-sharp-ls043t1le01.c (7657B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2015 Red Hat
      4 * 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/gpio/consumer.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/regulator/consumer.h>
     15
     16#include <video/mipi_display.h>
     17
     18#include <drm/drm_crtc.h>
     19#include <drm/drm_device.h>
     20#include <drm/drm_mipi_dsi.h>
     21#include <drm/drm_panel.h>
     22
     23struct sharp_nt_panel {
     24	struct drm_panel base;
     25	struct mipi_dsi_device *dsi;
     26
     27	struct regulator *supply;
     28	struct gpio_desc *reset_gpio;
     29
     30	bool prepared;
     31	bool enabled;
     32
     33	const struct drm_display_mode *mode;
     34};
     35
     36static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
     37{
     38	return container_of(panel, struct sharp_nt_panel, base);
     39}
     40
     41static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
     42{
     43	struct mipi_dsi_device *dsi = sharp_nt->dsi;
     44	int ret;
     45
     46	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
     47
     48	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
     49	if (ret < 0)
     50		return ret;
     51
     52	msleep(120);
     53
     54	/* Novatek two-lane operation */
     55	ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
     56	if (ret < 0)
     57		return ret;
     58
     59	/* Set both MCU and RGB I/F to 24bpp */
     60	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
     61					(MIPI_DCS_PIXEL_FMT_24BIT << 4));
     62	if (ret < 0)
     63		return ret;
     64
     65	return 0;
     66}
     67
     68static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
     69{
     70	struct mipi_dsi_device *dsi = sharp_nt->dsi;
     71	int ret;
     72
     73	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
     74
     75	ret = mipi_dsi_dcs_set_display_on(dsi);
     76	if (ret < 0)
     77		return ret;
     78
     79	return 0;
     80}
     81
     82static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
     83{
     84	struct mipi_dsi_device *dsi = sharp_nt->dsi;
     85	int ret;
     86
     87	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
     88
     89	ret = mipi_dsi_dcs_set_display_off(dsi);
     90	if (ret < 0)
     91		return ret;
     92
     93	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
     94	if (ret < 0)
     95		return ret;
     96
     97	return 0;
     98}
     99
    100
    101static int sharp_nt_panel_disable(struct drm_panel *panel)
    102{
    103	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
    104
    105	if (!sharp_nt->enabled)
    106		return 0;
    107
    108	sharp_nt->enabled = false;
    109
    110	return 0;
    111}
    112
    113static int sharp_nt_panel_unprepare(struct drm_panel *panel)
    114{
    115	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
    116	int ret;
    117
    118	if (!sharp_nt->prepared)
    119		return 0;
    120
    121	ret = sharp_nt_panel_off(sharp_nt);
    122	if (ret < 0) {
    123		dev_err(panel->dev, "failed to set panel off: %d\n", ret);
    124		return ret;
    125	}
    126
    127	regulator_disable(sharp_nt->supply);
    128	if (sharp_nt->reset_gpio)
    129		gpiod_set_value(sharp_nt->reset_gpio, 0);
    130
    131	sharp_nt->prepared = false;
    132
    133	return 0;
    134}
    135
    136static int sharp_nt_panel_prepare(struct drm_panel *panel)
    137{
    138	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
    139	int ret;
    140
    141	if (sharp_nt->prepared)
    142		return 0;
    143
    144	ret = regulator_enable(sharp_nt->supply);
    145	if (ret < 0)
    146		return ret;
    147
    148	msleep(20);
    149
    150	if (sharp_nt->reset_gpio) {
    151		gpiod_set_value(sharp_nt->reset_gpio, 1);
    152		msleep(1);
    153		gpiod_set_value(sharp_nt->reset_gpio, 0);
    154		msleep(1);
    155		gpiod_set_value(sharp_nt->reset_gpio, 1);
    156		msleep(10);
    157	}
    158
    159	ret = sharp_nt_panel_init(sharp_nt);
    160	if (ret < 0) {
    161		dev_err(panel->dev, "failed to init panel: %d\n", ret);
    162		goto poweroff;
    163	}
    164
    165	ret = sharp_nt_panel_on(sharp_nt);
    166	if (ret < 0) {
    167		dev_err(panel->dev, "failed to set panel on: %d\n", ret);
    168		goto poweroff;
    169	}
    170
    171	sharp_nt->prepared = true;
    172
    173	return 0;
    174
    175poweroff:
    176	regulator_disable(sharp_nt->supply);
    177	if (sharp_nt->reset_gpio)
    178		gpiod_set_value(sharp_nt->reset_gpio, 0);
    179	return ret;
    180}
    181
    182static int sharp_nt_panel_enable(struct drm_panel *panel)
    183{
    184	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
    185
    186	if (sharp_nt->enabled)
    187		return 0;
    188
    189	sharp_nt->enabled = true;
    190
    191	return 0;
    192}
    193
    194static const struct drm_display_mode default_mode = {
    195	.clock = 41118,
    196	.hdisplay = 540,
    197	.hsync_start = 540 + 48,
    198	.hsync_end = 540 + 48 + 80,
    199	.htotal = 540 + 48 + 80 + 32,
    200	.vdisplay = 960,
    201	.vsync_start = 960 + 3,
    202	.vsync_end = 960 + 3 + 15,
    203	.vtotal = 960 + 3 + 15 + 1,
    204};
    205
    206static int sharp_nt_panel_get_modes(struct drm_panel *panel,
    207				    struct drm_connector *connector)
    208{
    209	struct drm_display_mode *mode;
    210
    211	mode = drm_mode_duplicate(connector->dev, &default_mode);
    212	if (!mode) {
    213		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
    214			default_mode.hdisplay, default_mode.vdisplay,
    215			drm_mode_vrefresh(&default_mode));
    216		return -ENOMEM;
    217	}
    218
    219	drm_mode_set_name(mode);
    220
    221	drm_mode_probed_add(connector, mode);
    222
    223	connector->display_info.width_mm = 54;
    224	connector->display_info.height_mm = 95;
    225
    226	return 1;
    227}
    228
    229static const struct drm_panel_funcs sharp_nt_panel_funcs = {
    230	.disable = sharp_nt_panel_disable,
    231	.unprepare = sharp_nt_panel_unprepare,
    232	.prepare = sharp_nt_panel_prepare,
    233	.enable = sharp_nt_panel_enable,
    234	.get_modes = sharp_nt_panel_get_modes,
    235};
    236
    237static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
    238{
    239	struct device *dev = &sharp_nt->dsi->dev;
    240	int ret;
    241
    242	sharp_nt->mode = &default_mode;
    243
    244	sharp_nt->supply = devm_regulator_get(dev, "avdd");
    245	if (IS_ERR(sharp_nt->supply))
    246		return PTR_ERR(sharp_nt->supply);
    247
    248	sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
    249	if (IS_ERR(sharp_nt->reset_gpio)) {
    250		dev_err(dev, "cannot get reset-gpios %ld\n",
    251			PTR_ERR(sharp_nt->reset_gpio));
    252		sharp_nt->reset_gpio = NULL;
    253	} else {
    254		gpiod_set_value(sharp_nt->reset_gpio, 0);
    255	}
    256
    257	drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
    258		       &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
    259
    260	ret = drm_panel_of_backlight(&sharp_nt->base);
    261	if (ret)
    262		return ret;
    263
    264	drm_panel_add(&sharp_nt->base);
    265
    266	return 0;
    267}
    268
    269static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
    270{
    271	if (sharp_nt->base.dev)
    272		drm_panel_remove(&sharp_nt->base);
    273}
    274
    275static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
    276{
    277	struct sharp_nt_panel *sharp_nt;
    278	int ret;
    279
    280	dsi->lanes = 2;
    281	dsi->format = MIPI_DSI_FMT_RGB888;
    282	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
    283			MIPI_DSI_MODE_VIDEO_HSE |
    284			MIPI_DSI_CLOCK_NON_CONTINUOUS |
    285			MIPI_DSI_MODE_NO_EOT_PACKET;
    286
    287	sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
    288	if (!sharp_nt)
    289		return -ENOMEM;
    290
    291	mipi_dsi_set_drvdata(dsi, sharp_nt);
    292
    293	sharp_nt->dsi = dsi;
    294
    295	ret = sharp_nt_panel_add(sharp_nt);
    296	if (ret < 0)
    297		return ret;
    298
    299	ret = mipi_dsi_attach(dsi);
    300	if (ret < 0) {
    301		sharp_nt_panel_del(sharp_nt);
    302		return ret;
    303	}
    304
    305	return 0;
    306}
    307
    308static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
    309{
    310	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
    311	int ret;
    312
    313	ret = drm_panel_disable(&sharp_nt->base);
    314	if (ret < 0)
    315		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
    316
    317	ret = mipi_dsi_detach(dsi);
    318	if (ret < 0)
    319		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
    320
    321	sharp_nt_panel_del(sharp_nt);
    322
    323	return 0;
    324}
    325
    326static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
    327{
    328	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
    329
    330	drm_panel_disable(&sharp_nt->base);
    331}
    332
    333static const struct of_device_id sharp_nt_of_match[] = {
    334	{ .compatible = "sharp,ls043t1le01-qhd", },
    335	{ }
    336};
    337MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
    338
    339static struct mipi_dsi_driver sharp_nt_panel_driver = {
    340	.driver = {
    341		.name = "panel-sharp-ls043t1le01-qhd",
    342		.of_match_table = sharp_nt_of_match,
    343	},
    344	.probe = sharp_nt_panel_probe,
    345	.remove = sharp_nt_panel_remove,
    346	.shutdown = sharp_nt_panel_shutdown,
    347};
    348module_mipi_dsi_driver(sharp_nt_panel_driver);
    349
    350MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
    351MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
    352MODULE_LICENSE("GPL v2");