diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2020-03-23 15:38:27 +0800 |
---|---|---|
committer | Bryan O'Donoghue <bryan.odonoghue@linaro.org> | 2022-11-15 10:24:42 +0000 |
commit | 4fe1836e6772382d464c1f9b5b7db992c711f30d (patch) | |
tree | d3de731e745f4897a5ace0fb371cacb484666904 | |
parent | 8f912cc47fef2f85793345b7dc16b69f1c121498 (diff) |
drm/panel: Add driver for Truly panel with R65530 IC
It adds a drm panel driver for Truly panel with R65530 driver IC. It
supports not only Truly panel but also panel from AUO that is integrated
with a R65530 driver IC, although the driver is named after Truly.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-truly-r63350.c | 697 |
3 files changed, 706 insertions, 0 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index a582ddd583c2..efe7da25bb33 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -690,6 +690,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel +config DRM_PANEL_TRULY_R65530 + tristate "Truly panel with R65530 driver IC" + depends on OF + depends on DRM_MIPI_DSI + help + Say Y here if you want to enable support for Truly DSI panel with + R65530 driver IC. + config DRM_PANEL_VISIONOX_RM69299 tristate "Visionox RM69299" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 34e717382dbb..3801c756338f 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_TRULY_R65530) += panel-truly-r63350.o obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o diff --git a/drivers/gpu/drm/panel/panel-truly-r63350.c b/drivers/gpu/drm/panel/panel-truly-r63350.c new file mode 100644 index 000000000000..926fd72f7667 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-truly-r63350.c @@ -0,0 +1,697 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/pinctrl/consumer.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +static const char * const regulator_names[] = { + "iovcc", + "avdd", + "avee", +}; + +struct cmd_set { + const u8 *payload; + size_t size; + int wait_ms; +}; + +struct truly_data { + const struct cmd_set *panel_oncmds; + unsigned int num_oncmds; + const struct cmd_set *panel_offcmds; + unsigned int num_offcmds; +}; + +struct truly_panel { + struct drm_panel panel; + struct device *dev; + struct mipi_dsi_device *dsi; + const struct truly_data *data; + + struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)]; + struct gpio_desc *reset_gpio; + + bool prepared; + bool enabled; +}; + +static inline struct truly_panel *panel_to_truly(struct drm_panel *panel) +{ + return container_of(panel, struct truly_panel, panel); +} + +static int truly_r63350_power_off(struct truly_panel *truly) +{ + gpiod_set_value(truly->reset_gpio, 1); + return regulator_bulk_disable(ARRAY_SIZE(truly->supplies), + truly->supplies); +} + +static int truly_r63350_power_on(struct truly_panel *truly) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(truly->supplies), + truly->supplies); + if (ret) + return ret; + + /* Reset panel */ + gpiod_set_value(truly->reset_gpio, 0); + usleep_range(20000, 30000); + + gpiod_set_value(truly->reset_gpio, 1); + usleep_range(10000, 20000); + + gpiod_set_value(truly->reset_gpio, 0); + usleep_range(20000, 30000); + + return 0; +} + +static int truly_r63350_unprepare(struct drm_panel *panel) +{ + struct truly_panel *truly = panel_to_truly(panel); + const struct truly_data *data = truly->data; + const struct cmd_set *cmds = data->panel_offcmds; + unsigned int num_cmds = data->num_offcmds; + struct mipi_dsi_device *dsi = truly->dsi; + struct device *dev = truly->dev; + int ret; + int i; + + if (!truly->prepared) + return 0; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "set_display_off cmd failed: %d\n", ret); + return ret; + } + + /* 120ms delay required here as per DCS spec */ + msleep(120); + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "enter_sleep cmd failed: %d\n", ret); + return ret; + } + + /* Panel-off magic commands */ + for (i = 0; i < num_cmds; i++) { + ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload, + cmds[i].size); + if (ret < 0) { + DRM_DEV_ERROR(dev, "off cmd tx%d failed: %d\n", i, ret); + return ret; + } + + if (cmds[i].wait_ms) + msleep(cmds[i].wait_ms); + else + usleep_range(80, 100); + } + + ret = truly_r63350_power_off(truly); + if (ret < 0) { + DRM_DEV_ERROR(dev, "power_off failed: %d\n", ret); + return ret; + } + + truly->prepared = false; + + return 0; +} + +static int truly_r63350_prepare(struct drm_panel *panel) +{ + struct truly_panel *truly = panel_to_truly(panel); + const struct truly_data *data = truly->data; + const struct cmd_set *cmds = data->panel_oncmds; + unsigned int num_cmds = data->num_oncmds; + struct mipi_dsi_device *dsi = truly->dsi; + struct device *dev = truly->dev; + int ret; + int i; + + if (truly->prepared) + return 0; + + ret = truly_r63350_power_on(truly); + if (ret < 0) { + DRM_DEV_ERROR(dev, "failed to power on: %d\n", ret); + return ret; + } + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_soft_reset(dsi); + if (ret < 0) + return ret; + + usleep_range(10000, 20000); + + /* Panel-on magic commands */ + for (i = 0; i < num_cmds; i++) { + ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload, + cmds[i].size); + if (ret < 0) { + DRM_DEV_ERROR(dev, "on cmd tx%d failed: %d\n", i, ret); + goto power_off; + } + + if (cmds[i].wait_ms) + msleep(cmds[i].wait_ms); + else + usleep_range(80, 100); + } + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "exit_sleep_mode cmd failed: %d\n", ret); + goto power_off; + } + + /* Per DSI spec wait 120ms after sending exit sleep DCS command */ + msleep(120); + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "set_display_on cmd failed: %d\n", ret); + goto power_off; + } + + /* Per DSI spec wait 120ms after sending set_display_on DCS command */ + msleep(120); + + truly->prepared = true; + + return 0; + +power_off: + truly_r63350_power_off(truly); + return ret; +} + +static const struct drm_display_mode truly_fhd_mode = { + .clock = 144981, + .hdisplay = 1080, + .hsync_start = 1080 + 92, + .hsync_end = 1080 + 92 + 20, + .htotal = 1080 + 92 + 20 + 60, + .vdisplay = 1920, + .vsync_start = 1920 + 4, + .vsync_end = 1920 + 4 + 1, + .vtotal = 1920 + 4 + 1 + 5, + .vrefresh = 60, + .flags = 0, +}; + +static int truly_r63350_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct truly_panel *truly = panel_to_truly(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &truly_fhd_mode); + if (!mode) { + DRM_DEV_ERROR(truly->dev, + "failed to add display mode\n"); + return -ENOMEM; + } + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = 68; + connector->display_info.height_mm = 121; + + return 1; +} + +static const struct drm_panel_funcs truly_r63350_drm_funcs = { + .prepare = truly_r63350_prepare, + .unprepare = truly_r63350_unprepare, + .get_modes = truly_r63350_get_modes, +}; + +static int truly_r63350_panel_add(struct truly_panel *truly) +{ + struct device *dev = truly->dev; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(truly->supplies); i++) + truly->supplies[i].supply = regulator_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(truly->supplies), + truly->supplies); + if (ret) { + dev_err(dev, "failed to get regulator: %d\n", ret); + return ret; + } + + truly->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(truly->reset_gpio)) { + DRM_DEV_ERROR(dev, "failed to get reset gpio %ld\n", + PTR_ERR(truly->reset_gpio)); + return PTR_ERR(truly->reset_gpio); + } + + drm_panel_init(&truly->panel, dev, &truly_r63350_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&truly->panel); + if (ret) { + DRM_DEV_ERROR(dev, "failed to find backlight: %d\n", ret); + return ret; + } + + ret = drm_panel_add(&truly->panel); + if (ret) { + DRM_DEV_ERROR(dev, "failed to add panel: %d\n", ret); + return ret; + } + + return 0; +} + +static const u8 truly_oncmd0[] = { + 0xb0, 0x00, +}; + +static const u8 truly_oncmd1[] = { + 0xd6, 0x01, +}; + +static const u8 truly_oncmd2[] = { + 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd3[] = { + 0xb4, 0x0c, 0x00, +}; + +static const u8 truly_oncmd4[] = { + 0xb6, 0x4b, 0xdb, 0x16, +}; + +static const u8 truly_oncmd5[] = { + 0xbe, 0x00, 0x04, +}; + +static const u8 truly_oncmd6[] = { + 0xc0, 0x66, +}; + +static const u8 truly_oncmd7[] = { + 0xc1, 0x04, 0x60, 0x00, 0x20, 0xa9, 0x30, 0x20, + 0x63, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5, + 0xff, 0xff, 0x87, 0x8c, 0x41, 0x22, 0x54, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x33, 0x03, + 0x22, 0x00, 0xff, +}; + +static const u8 truly_oncmd8[] = { + 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00, + 0x08, +}; + +static const u8 truly_oncmd9[] = { + 0xc3, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd10[] = { + 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x00, 0x02, +}; + +static const u8 truly_oncmd11[] = { + 0xc5, 0x00, +}; + +static const u8 truly_oncmd12[] = { + 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8, +}; + +static const u8 truly_oncmd13[] = { + 0xc7, 0x03, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e, + 0x5b, 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x72, + 0x01, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e, 0x5b, + 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x78, +}; + +static const u8 truly_oncmd14[] = { + 0xcb, 0xff, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xe1, 0x87, 0xff, 0xe8, 0x00, 0x00, +}; + +static const u8 truly_oncmd15[] = { + 0xcc, 0x34, +}; + +static const u8 truly_oncmd16[] = { + 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd5, 0x40, 0x19, + 0x19, 0x09, 0x00, +}; + +static const u8 truly_oncmd17[] = { + 0xd1, 0x00, 0x48, 0x16, 0x0f, +}; + +static const u8 truly_oncmd18[] = { + 0xd2, 0x5c, 0x00, 0x00, +}; + +static const u8 truly_oncmd19[] = { + 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 truly_oncmd20[] = { + 0xd5, 0x06, 0x00, 0x00, 0x01, 0x39, 0x01, 0x39, +}; + +static const u8 truly_oncmd21[] = { + 0xd8, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd22[] = { + 0xd9, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd23[] = { + 0xfd, 0x00, 0x00, 0x00, 0x30, +}; + +static const u8 truly_oncmd24[] = { + 0x35, 0x00, +}; + +static const u8 truly_oncmd25[] = { + 0x29, +}; + +static const u8 truly_oncmd26[] = { + 0x11, +}; + +static const struct cmd_set truly_oncmds[] = { + { truly_oncmd0, ARRAY_SIZE(truly_oncmd0), }, + { truly_oncmd1, ARRAY_SIZE(truly_oncmd1), }, + { truly_oncmd2, ARRAY_SIZE(truly_oncmd2), }, + { truly_oncmd3, ARRAY_SIZE(truly_oncmd3), }, + { truly_oncmd4, ARRAY_SIZE(truly_oncmd4), }, + { truly_oncmd5, ARRAY_SIZE(truly_oncmd5), }, + { truly_oncmd6, ARRAY_SIZE(truly_oncmd6), }, + { truly_oncmd7, ARRAY_SIZE(truly_oncmd7), }, + { truly_oncmd8, ARRAY_SIZE(truly_oncmd8), }, + { truly_oncmd9, ARRAY_SIZE(truly_oncmd9), }, + { truly_oncmd10, ARRAY_SIZE(truly_oncmd10), }, + { truly_oncmd11, ARRAY_SIZE(truly_oncmd11), }, + { truly_oncmd12, ARRAY_SIZE(truly_oncmd12), }, + { truly_oncmd13, ARRAY_SIZE(truly_oncmd13), }, + { truly_oncmd14, ARRAY_SIZE(truly_oncmd14), }, + { truly_oncmd15, ARRAY_SIZE(truly_oncmd15), }, + { truly_oncmd16, ARRAY_SIZE(truly_oncmd16), }, + { truly_oncmd17, ARRAY_SIZE(truly_oncmd17), }, + { truly_oncmd18, ARRAY_SIZE(truly_oncmd18), }, + { truly_oncmd19, ARRAY_SIZE(truly_oncmd19), }, + { truly_oncmd20, ARRAY_SIZE(truly_oncmd20), }, + { truly_oncmd21, ARRAY_SIZE(truly_oncmd21), }, + { truly_oncmd22, ARRAY_SIZE(truly_oncmd22), }, + { truly_oncmd23, ARRAY_SIZE(truly_oncmd23), }, + { truly_oncmd24, ARRAY_SIZE(truly_oncmd24), }, + { truly_oncmd25, ARRAY_SIZE(truly_oncmd25), 50, }, + { truly_oncmd26, ARRAY_SIZE(truly_oncmd26), 120, }, +}; + +static const u8 truly_offcmd0[] = { + 0x28, +}; + +static const u8 truly_offcmd1[] = { + 0xb0, 0x04, +}; + +static const u8 truly_offcmd2[] = { + 0xd3, 0x13, 0x33, 0xbb, 0xb3, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 truly_offcmd3[] = { + 0x10, +}; + +static const u8 truly_offcmd4[] = { + 0xb0, 0x00, +}; + +static const u8 truly_offcmd5[] = { + 0xb1, 0x01, +}; + +static const struct cmd_set truly_offcmds[] = { + { truly_offcmd0, ARRAY_SIZE(truly_offcmd0), 20, }, + { truly_offcmd1, ARRAY_SIZE(truly_offcmd1), }, + { truly_offcmd2, ARRAY_SIZE(truly_offcmd2), 27, }, + { truly_offcmd3, ARRAY_SIZE(truly_offcmd3), 120, }, + { truly_offcmd4, ARRAY_SIZE(truly_offcmd4), }, + { truly_offcmd5, ARRAY_SIZE(truly_offcmd5), }, +}; + +static const struct truly_data truly_fhd_data = { + .panel_oncmds = truly_oncmds, + .num_oncmds = ARRAY_SIZE(truly_oncmds), + .panel_offcmds = truly_offcmds, + .num_offcmds = ARRAY_SIZE(truly_offcmds), +}; + +static const u8 auo_oncmd0[] = { + 0xb0, 0x04, +}; + +static const u8 auo_oncmd1[] = { + 0xd6, 0x01, +}; + +static const u8 auo_oncmd2[] = { + 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 auo_oncmd3[] = { + 0xb4, 0x0c, 0x00, +}; + +static const u8 auo_oncmd4[] = { + 0xb6, 0x4b, 0xdb, 0x00, +}; + +static const u8 auo_oncmd5[] = { + 0xc0, 0x66, +}; + +static const u8 auo_oncmd6[] = { + 0xc1, 0x04, 0x60, 0x00, 0x20, 0x29, 0x41, 0x22, + 0xfb, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5, + 0xff, 0xff, 0x87, 0x8c, 0xc5, 0x11, 0x54, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x11, 0x02, + 0x21, 0x00, 0xff, 0x11, +}; + +static const u8 auo_oncmd7[] = { + 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00, + 0x08, +}; + +static const u8 auo_oncmd8[] = { + 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x00, 0x02, +}; + +static const u8 auo_oncmd9[] = { + 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8, +}; + +static const u8 auo_oncmd10[] = { + 0xc7, 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d, + 0x5b, 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c, + 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d, 0x5b, + 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c, +}; + +static const u8 auo_oncmd11[] = { + 0xcb, 0x7f, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, +}; + +static const u8 auo_oncmd12[] = { + 0xcc, 0x32, +}; + +static const u8 auo_oncmd13[] = { + 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd7, 0x40, 0x19, + 0x19, 0x09, 0x00, +}; + +static const u8 auo_oncmd14[] = { + 0xd1, 0x00, 0x48, 0x16, 0x0f, +}; + +static const u8 auo_oncmd15[] = { + 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x37, 0x37, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 auo_oncmd16[] = { + 0xd5, 0x06, 0x00, 0x00, 0x01, 0x35, 0x01, 0x35, +}; + +static const u8 auo_oncmd17[] = { + 0x29, +}; + +static const u8 auo_oncmd18[] = { + 0x11, +}; + +static const struct cmd_set auo_oncmds[] = { + { auo_oncmd0, ARRAY_SIZE(auo_oncmd0), }, + { auo_oncmd1, ARRAY_SIZE(auo_oncmd1), }, + { auo_oncmd2, ARRAY_SIZE(auo_oncmd2), }, + { auo_oncmd3, ARRAY_SIZE(auo_oncmd3), }, + { auo_oncmd4, ARRAY_SIZE(auo_oncmd4), }, + { auo_oncmd5, ARRAY_SIZE(auo_oncmd5), }, + { auo_oncmd6, ARRAY_SIZE(auo_oncmd6), }, + { auo_oncmd7, ARRAY_SIZE(auo_oncmd7), }, + { auo_oncmd8, ARRAY_SIZE(auo_oncmd8), }, + { auo_oncmd9, ARRAY_SIZE(auo_oncmd9), }, + { auo_oncmd10, ARRAY_SIZE(auo_oncmd10), }, + { auo_oncmd11, ARRAY_SIZE(auo_oncmd11), }, + { auo_oncmd12, ARRAY_SIZE(auo_oncmd12), }, + { auo_oncmd13, ARRAY_SIZE(auo_oncmd13), }, + { auo_oncmd14, ARRAY_SIZE(auo_oncmd14), }, + { auo_oncmd15, ARRAY_SIZE(auo_oncmd15), }, + { auo_oncmd16, ARRAY_SIZE(auo_oncmd16), }, + { auo_oncmd17, ARRAY_SIZE(auo_oncmd17), 100, }, + { auo_oncmd18, ARRAY_SIZE(auo_oncmd18), 120, }, +}; + +static const u8 auo_offcmd0[] = { + 0x28, +}; + +static const u8 auo_offcmd1[] = { + 0xb0, 0x04, +}; + +static const struct cmd_set auo_offcmds[] = { + { auo_offcmd0, ARRAY_SIZE(auo_offcmd0), 10, }, + { auo_offcmd1, ARRAY_SIZE(auo_offcmd1), 120, }, +}; + +static const struct truly_data auo_fhd_data = { + .panel_oncmds = auo_oncmds, + .num_oncmds = ARRAY_SIZE(auo_oncmds), + .panel_offcmds = auo_offcmds, + .num_offcmds = ARRAY_SIZE(auo_offcmds), +}; + +static int truly_r63350_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct truly_panel *truly; + int ret; + + truly = devm_kzalloc(dev, sizeof(*truly), GFP_KERNEL); + if (!truly) + return -ENOMEM; + + truly->data = of_device_get_match_data(dev); + if (!truly->data) + return -ENODEV; + + truly->dev = dev; + + ret = truly_r63350_panel_add(truly); + if (ret) + return ret; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + truly->dsi = dsi; + + ret = mipi_dsi_attach(dsi); + if (ret) { + DRM_DEV_ERROR(dev, "failed to attach DSI device: %d\n", ret); + goto rm_panel; + } + + mipi_dsi_set_drvdata(dsi, truly); + + return 0; + +rm_panel: + drm_panel_remove(&truly->panel); + return ret; +} + +static void truly_r63350_remove(struct mipi_dsi_device *dsi) +{ + struct truly_panel *truly = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(truly->dsi); + drm_panel_remove(&truly->panel); + + return; +} + +static const struct of_device_id truly_r63350_of_match[] = { + { .compatible = "truly,r63350-fhd", .data = &truly_fhd_data, }, + { .compatible = "auo,r63350-fhd", .data = &auo_fhd_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, truly_r63350_of_match); + +static struct mipi_dsi_driver truly_r63350_driver = { + .driver = { + .name = "panel-truly-r63350", + .of_match_table = truly_r63350_of_match, + }, + .probe = truly_r63350_probe, + .remove = truly_r63350_remove, +}; +module_mipi_dsi_driver(truly_r63350_driver); + +MODULE_DESCRIPTION("Truly R63350 DSI Panel Driver"); +MODULE_LICENSE("GPL v2"); |