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-ronbo-rb070d30.c (6090B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2018-2019, Bridge Systems BV
      4 * Copyright (C) 2018-2019, Bootlin
      5 * Copyright (C) 2017, Free Electrons
      6 *
      7 * This file based on panel-ilitek-ili9881c.c
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/device.h>
     12#include <linux/err.h>
     13#include <linux/errno.h>
     14#include <linux/fb.h>
     15#include <linux/kernel.h>
     16#include <linux/media-bus-format.h>
     17#include <linux/module.h>
     18
     19#include <linux/gpio/consumer.h>
     20#include <linux/regulator/consumer.h>
     21
     22#include <drm/drm_connector.h>
     23#include <drm/drm_mipi_dsi.h>
     24#include <drm/drm_modes.h>
     25#include <drm/drm_panel.h>
     26
     27struct rb070d30_panel {
     28	struct drm_panel panel;
     29	struct mipi_dsi_device *dsi;
     30	struct regulator *supply;
     31
     32	struct {
     33		struct gpio_desc *power;
     34		struct gpio_desc *reset;
     35		struct gpio_desc *updn;
     36		struct gpio_desc *shlr;
     37	} gpios;
     38};
     39
     40static inline struct rb070d30_panel *panel_to_rb070d30_panel(struct drm_panel *panel)
     41{
     42	return container_of(panel, struct rb070d30_panel, panel);
     43}
     44
     45static int rb070d30_panel_prepare(struct drm_panel *panel)
     46{
     47	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
     48	int ret;
     49
     50	ret = regulator_enable(ctx->supply);
     51	if (ret < 0) {
     52		dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);
     53		return ret;
     54	}
     55
     56	msleep(20);
     57	gpiod_set_value(ctx->gpios.power, 1);
     58	msleep(20);
     59	gpiod_set_value(ctx->gpios.reset, 1);
     60	msleep(20);
     61	return 0;
     62}
     63
     64static int rb070d30_panel_unprepare(struct drm_panel *panel)
     65{
     66	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
     67
     68	gpiod_set_value(ctx->gpios.reset, 0);
     69	gpiod_set_value(ctx->gpios.power, 0);
     70	regulator_disable(ctx->supply);
     71
     72	return 0;
     73}
     74
     75static int rb070d30_panel_enable(struct drm_panel *panel)
     76{
     77	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
     78
     79	return mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
     80}
     81
     82static int rb070d30_panel_disable(struct drm_panel *panel)
     83{
     84	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
     85
     86	return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
     87}
     88
     89/* Default timings */
     90static const struct drm_display_mode default_mode = {
     91	.clock		= 51206,
     92	.hdisplay	= 1024,
     93	.hsync_start	= 1024 + 160,
     94	.hsync_end	= 1024 + 160 + 80,
     95	.htotal		= 1024 + 160 + 80 + 80,
     96	.vdisplay	= 600,
     97	.vsync_start	= 600 + 12,
     98	.vsync_end	= 600 + 12 + 10,
     99	.vtotal		= 600 + 12 + 10 + 13,
    100
    101	.width_mm	= 154,
    102	.height_mm	= 85,
    103};
    104
    105static int rb070d30_panel_get_modes(struct drm_panel *panel,
    106				    struct drm_connector *connector)
    107{
    108	struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
    109	struct drm_display_mode *mode;
    110	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
    111
    112	mode = drm_mode_duplicate(connector->dev, &default_mode);
    113	if (!mode) {
    114		dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n",
    115			DRM_MODE_ARG(&default_mode));
    116		return -EINVAL;
    117	}
    118
    119	drm_mode_set_name(mode);
    120
    121	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    122	drm_mode_probed_add(connector, mode);
    123
    124	connector->display_info.bpc = 8;
    125	connector->display_info.width_mm = mode->width_mm;
    126	connector->display_info.height_mm = mode->height_mm;
    127	drm_display_info_set_bus_formats(&connector->display_info,
    128					 &bus_format, 1);
    129
    130	return 1;
    131}
    132
    133static const struct drm_panel_funcs rb070d30_panel_funcs = {
    134	.get_modes	= rb070d30_panel_get_modes,
    135	.prepare	= rb070d30_panel_prepare,
    136	.enable		= rb070d30_panel_enable,
    137	.disable	= rb070d30_panel_disable,
    138	.unprepare	= rb070d30_panel_unprepare,
    139};
    140
    141static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
    142{
    143	struct rb070d30_panel *ctx;
    144	int ret;
    145
    146	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
    147	if (!ctx)
    148		return -ENOMEM;
    149
    150	ctx->supply = devm_regulator_get(&dsi->dev, "vcc-lcd");
    151	if (IS_ERR(ctx->supply))
    152		return PTR_ERR(ctx->supply);
    153
    154	mipi_dsi_set_drvdata(dsi, ctx);
    155	ctx->dsi = dsi;
    156
    157	drm_panel_init(&ctx->panel, &dsi->dev, &rb070d30_panel_funcs,
    158		       DRM_MODE_CONNECTOR_DSI);
    159
    160	ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
    161	if (IS_ERR(ctx->gpios.reset)) {
    162		dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
    163		return PTR_ERR(ctx->gpios.reset);
    164	}
    165
    166	ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
    167	if (IS_ERR(ctx->gpios.power)) {
    168		dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
    169		return PTR_ERR(ctx->gpios.power);
    170	}
    171
    172	/*
    173	 * We don't change the state of that GPIO later on but we need
    174	 * to force it into a low state.
    175	 */
    176	ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);
    177	if (IS_ERR(ctx->gpios.updn)) {
    178		dev_err(&dsi->dev, "Couldn't get our updn GPIO\n");
    179		return PTR_ERR(ctx->gpios.updn);
    180	}
    181
    182	/*
    183	 * We don't change the state of that GPIO later on but we need
    184	 * to force it into a low state.
    185	 */
    186	ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW);
    187	if (IS_ERR(ctx->gpios.shlr)) {
    188		dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n");
    189		return PTR_ERR(ctx->gpios.shlr);
    190	}
    191
    192	ret = drm_panel_of_backlight(&ctx->panel);
    193	if (ret)
    194		return ret;
    195
    196	drm_panel_add(&ctx->panel);
    197
    198	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
    199	dsi->format = MIPI_DSI_FMT_RGB888;
    200	dsi->lanes = 4;
    201
    202	ret = mipi_dsi_attach(dsi);
    203	if (ret < 0) {
    204		drm_panel_remove(&ctx->panel);
    205		return ret;
    206	}
    207
    208	return 0;
    209}
    210
    211static int rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi)
    212{
    213	struct rb070d30_panel *ctx = mipi_dsi_get_drvdata(dsi);
    214
    215	mipi_dsi_detach(dsi);
    216	drm_panel_remove(&ctx->panel);
    217
    218	return 0;
    219}
    220
    221static const struct of_device_id rb070d30_panel_of_match[] = {
    222	{ .compatible = "ronbo,rb070d30" },
    223	{ /* sentinel */ },
    224};
    225MODULE_DEVICE_TABLE(of, rb070d30_panel_of_match);
    226
    227static struct mipi_dsi_driver rb070d30_panel_driver = {
    228	.probe = rb070d30_panel_dsi_probe,
    229	.remove = rb070d30_panel_dsi_remove,
    230	.driver = {
    231		.name = "panel-ronbo-rb070d30",
    232		.of_match_table	= rb070d30_panel_of_match,
    233	},
    234};
    235module_mipi_dsi_driver(rb070d30_panel_driver);
    236
    237MODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
    238MODULE_AUTHOR("Konstantin Sudakov <k.sudakov@integrasources.com>");
    239MODULE_DESCRIPTION("Ronbo RB070D30 Panel Driver");
    240MODULE_LICENSE("GPL");