// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 Radxa Limited
* Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd.
*
* Author:
* - Jagan Teki <jagan@amarulasolutions.com>
* - Stephen Chen <stephen@radxa.com>
*/
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
struct jadard;
struct jadard_panel_desc {
const struct drm_display_mode mode;
unsigned int lanes;
enum mipi_dsi_pixel_format format;
int (*init)(struct jadard *jadard);
bool lp11_before_reset;
bool reset_before_power_off_vcioo;
unsigned int vcioo_to_lp11_delay_ms;
unsigned int lp11_to_reset_delay_ms;
unsigned int backlight_off_to_display_off_delay_ms;
unsigned int display_off_to_enter_sleep_delay_ms;
unsigned int enter_sleep_to_reset_down_delay_ms;
};
struct jadard {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
const struct jadard_panel_desc *desc;
enum drm_panel_orientation orientation;
struct regulator *vdd;
struct regulator *vccio;
struct gpio_desc *reset;
};
#define JD9365DA_DCS_SWITCH_PAGE 0xe0
#define jd9365da_switch_page(dsi_ctx, page) \
mipi_dsi_dcs_write_seq_multi(dsi_ctx, JD9365DA_DCS_SWITCH_PAGE, (page))
static void jadard_enable_standard_cmds(struct mipi_dsi_multi_context *dsi_ctx)
{
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x93);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x65);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe3, 0xf8);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x80, 0x03);
}
static inline struct jadard *panel_to_jadard(struct drm_panel *panel)
{
return container_of(panel, struct jadard, panel);
}
static int jadard_disable(struct drm_panel *panel)
{
struct jadard *jadard = panel_to_jadard(panel);
struct mipi_dsi_multi_context dsi_ctx = { .dsi = jadard->dsi };
if (jadard->desc->backlight_off_to_display_off_delay_ms)
mipi_dsi_msleep(&dsi_ctx, jadard->desc->backlight_off_to_display_off_delay_ms);
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
if (jadard->desc->display_off_to_enter_sleep_delay_ms)
mipi_dsi_msleep(&dsi_ctx, jadard->desc->display_off_to_enter_sleep_delay_ms);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
if (jadard->desc->enter_sleep_to_reset_down_delay_ms)
mipi_dsi_msleep(&dsi_ctx, jadard->desc->enter_sleep_to_reset_down_delay_ms);
return dsi_ctx.accum_err;
}
static int jadard_prepare(struct drm_panel *panel)
{
struct jadard *jadard = panel_to_jadard(panel);
int ret;
ret = regulator_enable(jadard->vccio);
if (ret)
return ret;
ret = regulator_enable(jadard->vdd);
if (ret)
return ret;
if (jadard->desc->vcioo_to_lp11_delay_ms)
msleep(jadard->desc->vcioo_to_lp11_delay_ms);
if (jadard->desc->lp11_before_reset) {
ret = mipi_dsi_dcs_nop(jadard->dsi);
if (ret)
return ret;
}
if (jadard->desc->lp11_to_reset_delay_ms)
msleep(jadard->desc->lp11_to_reset_delay_ms);
gpiod_set_value(jadard->reset, 1);
msleep(5);
gpiod_set_value(jadard->reset, 0);
msleep(10);
gpiod_set_value(jadard->reset, 1);
msleep(130);
ret = jadard->desc->init(