1 // SPDX-License-Identifier: GPL-2.0
3 * Panel driver for the Samsung S6D27A1 480x800 DPI RGB panel.
4 * Found in the Samsung Galaxy Ace 2 GT-I8160 mobile phone.
7 #include <drm/drm_mipi_dbi.h>
8 #include <drm/drm_modes.h>
9 #include <drm/drm_panel.h>
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/media-bus-format.h>
16 #include <linux/module.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/spi/spi.h>
21 #include <video/mipi_display.h>
23 #define S6D27A1_PASSWD_L2 0xF0 /* Password Command for Level 2 Control */
24 #define S6D27A1_RESCTL 0xB3 /* Resolution Select Control */
25 #define S6D27A1_PANELCTL2 0xB4 /* ASG Signal Control */
26 #define S6D27A1_READID1 0xDA /* Read panel ID 1 */
27 #define S6D27A1_READID2 0xDB /* Read panel ID 2 */
28 #define S6D27A1_READID3 0xDC /* Read panel ID 3 */
29 #define S6D27A1_DISPCTL 0xF2 /* Display Control */
30 #define S6D27A1_MANPWR 0xF3 /* Manual Control */
31 #define S6D27A1_PWRCTL1 0xF4 /* Power Control */
32 #define S6D27A1_SRCCTL 0xF6 /* Source Control */
33 #define S6D27A1_PANELCTL 0xF7 /* Panel Control*/
35 static const u8 s6d27a1_dbi_read_commands[] = {
45 struct drm_panel panel;
46 struct gpio_desc *reset;
47 struct regulator_bulk_data regulators[2];
50 static const struct drm_display_mode s6d27a1_480_800_mode = {
52 * The vendor driver states that the S6D27A1 panel
53 * has a pixel clock frequency of 49920000 Hz / 2 = 24960000 Hz.
57 .hsync_start = 480 + 63,
58 .hsync_end = 480 + 63 + 2,
59 .htotal = 480 + 63 + 2 + 63,
61 .vsync_start = 800 + 11,
62 .vsync_end = 800 + 11 + 2,
63 .vtotal = 800 + 11 + 2 + 10,
66 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
69 static inline struct s6d27a1 *to_s6d27a1(struct drm_panel *panel)
71 return container_of(panel, struct s6d27a1, panel);
74 static void s6d27a1_read_mtp_id(struct s6d27a1 *ctx)
76 struct mipi_dbi *dbi = &ctx->dbi;
80 ret = mipi_dbi_command_read(dbi, S6D27A1_READID1, &id1);
82 dev_err(ctx->dev, "unable to read MTP ID 1\n");
85 ret = mipi_dbi_command_read(dbi, S6D27A1_READID2, &id2);
87 dev_err(ctx->dev, "unable to read MTP ID 2\n");
90 ret = mipi_dbi_command_read(dbi, S6D27A1_READID3, &id3);
92 dev_err(ctx->dev, "unable to read MTP ID 3\n");
95 dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
98 static int s6d27a1_power_on(struct s6d27a1 *ctx)
100 struct mipi_dbi *dbi = &ctx->dbi;
104 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->regulators),
107 dev_err(ctx->dev, "failed to enable regulators: %d\n", ret);
113 /* Assert reset >=1 ms */
114 gpiod_set_value_cansleep(ctx->reset, 1);
115 usleep_range(1000, 5000);
116 /* De-assert reset */
117 gpiod_set_value_cansleep(ctx->reset, 0);
122 * Exit sleep mode and initialize display - some hammering is
125 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
126 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
129 /* Magic to unlock level 2 control of the display */
130 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0x5A, 0x5A);
132 /* Configure resolution to 480RGBx800 */
133 mipi_dbi_command(dbi, S6D27A1_RESCTL, 0x22);
135 mipi_dbi_command(dbi, S6D27A1_PANELCTL2, 0x00, 0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x0c);
137 mipi_dbi_command(dbi, S6D27A1_MANPWR, 0x01, 0x00, 0x00, 0x08, 0x08, 0x02, 0x00);
139 mipi_dbi_command(dbi, S6D27A1_DISPCTL, 0x19, 0x00, 0x08, 0x0D, 0x03, 0x41, 0x3F);
141 mipi_dbi_command(dbi, S6D27A1_PWRCTL1, 0x00, 0x00, 0x00, 0x00, 0x55,
142 0x44, 0x05, 0x88, 0x4B, 0x50);
144 mipi_dbi_command(dbi, S6D27A1_SRCCTL, 0x03, 0x09, 0x8A, 0x00, 0x01, 0x16);
146 mipi_dbi_command(dbi, S6D27A1_PANELCTL, 0x00, 0x05, 0x06, 0x07, 0x08,
147 0x01, 0x09, 0x0D, 0x0A, 0x0E,
148 0x0B, 0x0F, 0x0C, 0x10, 0x01,
149 0x11, 0x12, 0x13, 0x14, 0x05,
150 0x06, 0x07, 0x08, 0x01, 0x09,
151 0x0D, 0x0A, 0x0E, 0x0B, 0x0F,
152 0x0C, 0x10, 0x01, 0x11, 0x12,
155 /* lock the level 2 control */
156 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0xA5, 0xA5);
158 s6d27a1_read_mtp_id(ctx);
163 static int s6d27a1_power_off(struct s6d27a1 *ctx)
165 /* Go into RESET and disable regulators */
166 gpiod_set_value_cansleep(ctx->reset, 1);
167 return regulator_bulk_disable(ARRAY_SIZE(ctx->regulators),
171 static int s6d27a1_unprepare(struct drm_panel *panel)
173 struct s6d27a1 *ctx = to_s6d27a1(panel);
174 struct mipi_dbi *dbi = &ctx->dbi;
176 mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
178 return s6d27a1_power_off(to_s6d27a1(panel));
181 static int s6d27a1_disable(struct drm_panel *panel)
183 struct s6d27a1 *ctx = to_s6d27a1(panel);
184 struct mipi_dbi *dbi = &ctx->dbi;
186 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
192 static int s6d27a1_prepare(struct drm_panel *panel)
194 return s6d27a1_power_on(to_s6d27a1(panel));
197 static int s6d27a1_enable(struct drm_panel *panel)
199 struct s6d27a1 *ctx = to_s6d27a1(panel);
200 struct mipi_dbi *dbi = &ctx->dbi;
202 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
207 static int s6d27a1_get_modes(struct drm_panel *panel,
208 struct drm_connector *connector)
210 struct s6d27a1 *ctx = to_s6d27a1(panel);
211 struct drm_display_mode *mode;
212 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
214 mode = drm_mode_duplicate(connector->dev, &s6d27a1_480_800_mode);
216 dev_err(ctx->dev, "failed to add mode\n");
220 connector->display_info.bpc = 8;
221 connector->display_info.width_mm = mode->width_mm;
222 connector->display_info.height_mm = mode->height_mm;
223 connector->display_info.bus_flags =
224 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
225 drm_display_info_set_bus_formats(&connector->display_info,
228 drm_mode_set_name(mode);
229 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
231 drm_mode_probed_add(connector, mode);
236 static const struct drm_panel_funcs s6d27a1_drm_funcs = {
237 .disable = s6d27a1_disable,
238 .unprepare = s6d27a1_unprepare,
239 .prepare = s6d27a1_prepare,
240 .enable = s6d27a1_enable,
241 .get_modes = s6d27a1_get_modes,
244 static int s6d27a1_probe(struct spi_device *spi)
246 struct device *dev = &spi->dev;
250 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
257 * VCI is the analog voltage supply
258 * VCCIO is the digital I/O voltage supply
260 ctx->regulators[0].supply = "vci";
261 ctx->regulators[1].supply = "vccio";
262 ret = devm_regulator_bulk_get(dev,
263 ARRAY_SIZE(ctx->regulators),
266 return dev_err_probe(dev, ret, "failed to get regulators\n");
268 ctx->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
269 if (IS_ERR(ctx->reset)) {
270 ret = PTR_ERR(ctx->reset);
271 return dev_err_probe(dev, ret, "no RESET GPIO\n");
274 ret = mipi_dbi_spi_init(spi, &ctx->dbi, NULL);
276 return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
278 ctx->dbi.read_commands = s6d27a1_dbi_read_commands;
280 drm_panel_init(&ctx->panel, dev, &s6d27a1_drm_funcs,
281 DRM_MODE_CONNECTOR_DPI);
283 ret = drm_panel_of_backlight(&ctx->panel);
285 return dev_err_probe(dev, ret, "failed to add backlight\n");
287 spi_set_drvdata(spi, ctx);
289 drm_panel_add(&ctx->panel);
294 static void s6d27a1_remove(struct spi_device *spi)
296 struct s6d27a1 *ctx = spi_get_drvdata(spi);
298 drm_panel_remove(&ctx->panel);
301 static const struct of_device_id s6d27a1_match[] = {
302 { .compatible = "samsung,s6d27a1", },
305 MODULE_DEVICE_TABLE(of, s6d27a1_match);
307 static struct spi_driver s6d27a1_driver = {
308 .probe = s6d27a1_probe,
309 .remove = s6d27a1_remove,
311 .name = "s6d27a1-panel",
312 .of_match_table = s6d27a1_match,
315 module_spi_driver(s6d27a1_driver);
318 MODULE_DESCRIPTION("Samsung S6D27A1 panel driver");
319 MODULE_LICENSE("GPL v2");