panel-samsung-s6d27a1.c (8259B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Panel driver for the Samsung S6D27A1 480x800 DPI RGB panel. 4 * Found in the Samsung Galaxy Ace 2 GT-I8160 mobile phone. 5 */ 6 7#include <drm/drm_mipi_dbi.h> 8#include <drm/drm_modes.h> 9#include <drm/drm_panel.h> 10 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> 17#include <linux/of.h> 18#include <linux/regulator/consumer.h> 19#include <linux/spi/spi.h> 20 21#include <video/mipi_display.h> 22 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*/ 34 35static const u8 s6d27a1_dbi_read_commands[] = { 36 S6D27A1_READID1, 37 S6D27A1_READID2, 38 S6D27A1_READID3, 39 0, /* sentinel */ 40}; 41 42struct s6d27a1 { 43 struct device *dev; 44 struct mipi_dbi dbi; 45 struct drm_panel panel; 46 struct gpio_desc *reset; 47 struct regulator_bulk_data regulators[2]; 48}; 49 50static const struct drm_display_mode s6d27a1_480_800_mode = { 51 /* 52 * The vendor driver states that the S6D27A1 panel 53 * has a pixel clock frequency of 49920000 Hz / 2 = 24960000 Hz. 54 */ 55 .clock = 24960, 56 .hdisplay = 480, 57 .hsync_start = 480 + 63, 58 .hsync_end = 480 + 63 + 2, 59 .htotal = 480 + 63 + 2 + 63, 60 .vdisplay = 800, 61 .vsync_start = 800 + 11, 62 .vsync_end = 800 + 11 + 2, 63 .vtotal = 800 + 11 + 2 + 10, 64 .width_mm = 50, 65 .height_mm = 84, 66 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 67}; 68 69static inline struct s6d27a1 *to_s6d27a1(struct drm_panel *panel) 70{ 71 return container_of(panel, struct s6d27a1, panel); 72} 73 74static void s6d27a1_read_mtp_id(struct s6d27a1 *ctx) 75{ 76 struct mipi_dbi *dbi = &ctx->dbi; 77 u8 id1, id2, id3; 78 int ret; 79 80 ret = mipi_dbi_command_read(dbi, S6D27A1_READID1, &id1); 81 if (ret) { 82 dev_err(ctx->dev, "unable to read MTP ID 1\n"); 83 return; 84 } 85 ret = mipi_dbi_command_read(dbi, S6D27A1_READID2, &id2); 86 if (ret) { 87 dev_err(ctx->dev, "unable to read MTP ID 2\n"); 88 return; 89 } 90 ret = mipi_dbi_command_read(dbi, S6D27A1_READID3, &id3); 91 if (ret) { 92 dev_err(ctx->dev, "unable to read MTP ID 3\n"); 93 return; 94 } 95 dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3); 96} 97 98static int s6d27a1_power_on(struct s6d27a1 *ctx) 99{ 100 struct mipi_dbi *dbi = &ctx->dbi; 101 int ret; 102 103 /* Power up */ 104 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->regulators), 105 ctx->regulators); 106 if (ret) { 107 dev_err(ctx->dev, "failed to enable regulators: %d\n", ret); 108 return ret; 109 } 110 111 msleep(20); 112 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); 118 /* Wait >= 10 ms */ 119 msleep(20); 120 121 /* 122 * Exit sleep mode and initialize display - some hammering is 123 * necessary. 124 */ 125 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 126 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 127 msleep(120); 128 129 /* Magic to unlock level 2 control of the display */ 130 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0x5A, 0x5A); 131 132 /* Configure resolution to 480RGBx800 */ 133 mipi_dbi_command(dbi, S6D27A1_RESCTL, 0x22); 134 135 mipi_dbi_command(dbi, S6D27A1_PANELCTL2, 0x00, 0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x0c); 136 137 mipi_dbi_command(dbi, S6D27A1_MANPWR, 0x01, 0x00, 0x00, 0x08, 0x08, 0x02, 0x00); 138 139 mipi_dbi_command(dbi, S6D27A1_DISPCTL, 0x19, 0x00, 0x08, 0x0D, 0x03, 0x41, 0x3F); 140 141 mipi_dbi_command(dbi, S6D27A1_PWRCTL1, 0x00, 0x00, 0x00, 0x00, 0x55, 142 0x44, 0x05, 0x88, 0x4B, 0x50); 143 144 mipi_dbi_command(dbi, S6D27A1_SRCCTL, 0x03, 0x09, 0x8A, 0x00, 0x01, 0x16); 145 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, 153 0x13, 0x14); 154 155 /* lock the level 2 control */ 156 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0xA5, 0xA5); 157 158 s6d27a1_read_mtp_id(ctx); 159 160 return 0; 161} 162 163static int s6d27a1_power_off(struct s6d27a1 *ctx) 164{ 165 /* Go into RESET and disable regulators */ 166 gpiod_set_value_cansleep(ctx->reset, 1); 167 return regulator_bulk_disable(ARRAY_SIZE(ctx->regulators), 168 ctx->regulators); 169} 170 171static int s6d27a1_unprepare(struct drm_panel *panel) 172{ 173 struct s6d27a1 *ctx = to_s6d27a1(panel); 174 struct mipi_dbi *dbi = &ctx->dbi; 175 176 mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE); 177 msleep(120); 178 return s6d27a1_power_off(to_s6d27a1(panel)); 179} 180 181static int s6d27a1_disable(struct drm_panel *panel) 182{ 183 struct s6d27a1 *ctx = to_s6d27a1(panel); 184 struct mipi_dbi *dbi = &ctx->dbi; 185 186 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF); 187 msleep(25); 188 189 return 0; 190} 191 192static int s6d27a1_prepare(struct drm_panel *panel) 193{ 194 return s6d27a1_power_on(to_s6d27a1(panel)); 195} 196 197static int s6d27a1_enable(struct drm_panel *panel) 198{ 199 struct s6d27a1 *ctx = to_s6d27a1(panel); 200 struct mipi_dbi *dbi = &ctx->dbi; 201 202 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); 203 204 return 0; 205} 206 207static int s6d27a1_get_modes(struct drm_panel *panel, 208 struct drm_connector *connector) 209{ 210 struct s6d27a1 *ctx = to_s6d27a1(panel); 211 struct drm_display_mode *mode; 212 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; 213 214 mode = drm_mode_duplicate(connector->dev, &s6d27a1_480_800_mode); 215 if (!mode) { 216 dev_err(ctx->dev, "failed to add mode\n"); 217 return -ENOMEM; 218 } 219 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, 226 &bus_format, 1); 227 228 drm_mode_set_name(mode); 229 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 230 231 drm_mode_probed_add(connector, mode); 232 233 return 1; 234} 235 236static 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, 242}; 243 244static int s6d27a1_probe(struct spi_device *spi) 245{ 246 struct device *dev = &spi->dev; 247 struct s6d27a1 *ctx; 248 int ret; 249 250 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 251 if (!ctx) 252 return -ENOMEM; 253 254 ctx->dev = dev; 255 256 /* 257 * VCI is the analog voltage supply 258 * VCCIO is the digital I/O voltage supply 259 */ 260 ctx->regulators[0].supply = "vci"; 261 ctx->regulators[1].supply = "vccio"; 262 ret = devm_regulator_bulk_get(dev, 263 ARRAY_SIZE(ctx->regulators), 264 ctx->regulators); 265 if (ret) 266 return dev_err_probe(dev, ret, "failed to get regulators\n"); 267 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"); 272 } 273 274 ret = mipi_dbi_spi_init(spi, &ctx->dbi, NULL); 275 if (ret) 276 return dev_err_probe(dev, ret, "MIPI DBI init failed\n"); 277 278 ctx->dbi.read_commands = s6d27a1_dbi_read_commands; 279 280 drm_panel_init(&ctx->panel, dev, &s6d27a1_drm_funcs, 281 DRM_MODE_CONNECTOR_DPI); 282 283 ret = drm_panel_of_backlight(&ctx->panel); 284 if (ret) 285 return dev_err_probe(dev, ret, "failed to add backlight\n"); 286 287 spi_set_drvdata(spi, ctx); 288 289 drm_panel_add(&ctx->panel); 290 291 return 0; 292} 293 294static void s6d27a1_remove(struct spi_device *spi) 295{ 296 struct s6d27a1 *ctx = spi_get_drvdata(spi); 297 298 drm_panel_remove(&ctx->panel); 299} 300 301static const struct of_device_id s6d27a1_match[] = { 302 { .compatible = "samsung,s6d27a1", }, 303 { /* sentinel */ }, 304}; 305MODULE_DEVICE_TABLE(of, s6d27a1_match); 306 307static struct spi_driver s6d27a1_driver = { 308 .probe = s6d27a1_probe, 309 .remove = s6d27a1_remove, 310 .driver = { 311 .name = "s6d27a1-panel", 312 .of_match_table = s6d27a1_match, 313 }, 314}; 315module_spi_driver(s6d27a1_driver); 316 317MODULE_AUTHOR("Markuss Broks <markuss.broks@gmail.com>"); 318MODULE_DESCRIPTION("Samsung S6D27A1 panel driver"); 319MODULE_LICENSE("GPL v2");