0001
0002
0003
0004
0005
0006
0007 #include <drm/drm_mipi_dbi.h>
0008 #include <drm/drm_modes.h>
0009 #include <drm/drm_panel.h>
0010
0011 #include <linux/delay.h>
0012 #include <linux/gpio/consumer.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/media-bus-format.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/spi/spi.h>
0020
0021 #include <video/mipi_display.h>
0022
0023 #define S6D27A1_PASSWD_L2 0xF0
0024 #define S6D27A1_RESCTL 0xB3
0025 #define S6D27A1_PANELCTL2 0xB4
0026 #define S6D27A1_READID1 0xDA
0027 #define S6D27A1_READID2 0xDB
0028 #define S6D27A1_READID3 0xDC
0029 #define S6D27A1_DISPCTL 0xF2
0030 #define S6D27A1_MANPWR 0xF3
0031 #define S6D27A1_PWRCTL1 0xF4
0032 #define S6D27A1_SRCCTL 0xF6
0033 #define S6D27A1_PANELCTL 0xF7
0034
0035 static const u8 s6d27a1_dbi_read_commands[] = {
0036 S6D27A1_READID1,
0037 S6D27A1_READID2,
0038 S6D27A1_READID3,
0039 0,
0040 };
0041
0042 struct s6d27a1 {
0043 struct device *dev;
0044 struct mipi_dbi dbi;
0045 struct drm_panel panel;
0046 struct gpio_desc *reset;
0047 struct regulator_bulk_data regulators[2];
0048 };
0049
0050 static const struct drm_display_mode s6d27a1_480_800_mode = {
0051
0052
0053
0054
0055 .clock = 24960,
0056 .hdisplay = 480,
0057 .hsync_start = 480 + 63,
0058 .hsync_end = 480 + 63 + 2,
0059 .htotal = 480 + 63 + 2 + 63,
0060 .vdisplay = 800,
0061 .vsync_start = 800 + 11,
0062 .vsync_end = 800 + 11 + 2,
0063 .vtotal = 800 + 11 + 2 + 10,
0064 .width_mm = 50,
0065 .height_mm = 84,
0066 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
0067 };
0068
0069 static inline struct s6d27a1 *to_s6d27a1(struct drm_panel *panel)
0070 {
0071 return container_of(panel, struct s6d27a1, panel);
0072 }
0073
0074 static void s6d27a1_read_mtp_id(struct s6d27a1 *ctx)
0075 {
0076 struct mipi_dbi *dbi = &ctx->dbi;
0077 u8 id1, id2, id3;
0078 int ret;
0079
0080 ret = mipi_dbi_command_read(dbi, S6D27A1_READID1, &id1);
0081 if (ret) {
0082 dev_err(ctx->dev, "unable to read MTP ID 1\n");
0083 return;
0084 }
0085 ret = mipi_dbi_command_read(dbi, S6D27A1_READID2, &id2);
0086 if (ret) {
0087 dev_err(ctx->dev, "unable to read MTP ID 2\n");
0088 return;
0089 }
0090 ret = mipi_dbi_command_read(dbi, S6D27A1_READID3, &id3);
0091 if (ret) {
0092 dev_err(ctx->dev, "unable to read MTP ID 3\n");
0093 return;
0094 }
0095 dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
0096 }
0097
0098 static int s6d27a1_power_on(struct s6d27a1 *ctx)
0099 {
0100 struct mipi_dbi *dbi = &ctx->dbi;
0101 int ret;
0102
0103
0104 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->regulators),
0105 ctx->regulators);
0106 if (ret) {
0107 dev_err(ctx->dev, "failed to enable regulators: %d\n", ret);
0108 return ret;
0109 }
0110
0111 msleep(20);
0112
0113
0114 gpiod_set_value_cansleep(ctx->reset, 1);
0115 usleep_range(1000, 5000);
0116
0117 gpiod_set_value_cansleep(ctx->reset, 0);
0118
0119 msleep(20);
0120
0121
0122
0123
0124
0125 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0126 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0127 msleep(120);
0128
0129
0130 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0x5A, 0x5A);
0131
0132
0133 mipi_dbi_command(dbi, S6D27A1_RESCTL, 0x22);
0134
0135 mipi_dbi_command(dbi, S6D27A1_PANELCTL2, 0x00, 0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x0c);
0136
0137 mipi_dbi_command(dbi, S6D27A1_MANPWR, 0x01, 0x00, 0x00, 0x08, 0x08, 0x02, 0x00);
0138
0139 mipi_dbi_command(dbi, S6D27A1_DISPCTL, 0x19, 0x00, 0x08, 0x0D, 0x03, 0x41, 0x3F);
0140
0141 mipi_dbi_command(dbi, S6D27A1_PWRCTL1, 0x00, 0x00, 0x00, 0x00, 0x55,
0142 0x44, 0x05, 0x88, 0x4B, 0x50);
0143
0144 mipi_dbi_command(dbi, S6D27A1_SRCCTL, 0x03, 0x09, 0x8A, 0x00, 0x01, 0x16);
0145
0146 mipi_dbi_command(dbi, S6D27A1_PANELCTL, 0x00, 0x05, 0x06, 0x07, 0x08,
0147 0x01, 0x09, 0x0D, 0x0A, 0x0E,
0148 0x0B, 0x0F, 0x0C, 0x10, 0x01,
0149 0x11, 0x12, 0x13, 0x14, 0x05,
0150 0x06, 0x07, 0x08, 0x01, 0x09,
0151 0x0D, 0x0A, 0x0E, 0x0B, 0x0F,
0152 0x0C, 0x10, 0x01, 0x11, 0x12,
0153 0x13, 0x14);
0154
0155
0156 mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0xA5, 0xA5);
0157
0158 s6d27a1_read_mtp_id(ctx);
0159
0160 return 0;
0161 }
0162
0163 static int s6d27a1_power_off(struct s6d27a1 *ctx)
0164 {
0165
0166 gpiod_set_value_cansleep(ctx->reset, 1);
0167 return regulator_bulk_disable(ARRAY_SIZE(ctx->regulators),
0168 ctx->regulators);
0169 }
0170
0171 static int s6d27a1_unprepare(struct drm_panel *panel)
0172 {
0173 struct s6d27a1 *ctx = to_s6d27a1(panel);
0174 struct mipi_dbi *dbi = &ctx->dbi;
0175
0176 mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
0177 msleep(120);
0178 return s6d27a1_power_off(to_s6d27a1(panel));
0179 }
0180
0181 static int s6d27a1_disable(struct drm_panel *panel)
0182 {
0183 struct s6d27a1 *ctx = to_s6d27a1(panel);
0184 struct mipi_dbi *dbi = &ctx->dbi;
0185
0186 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
0187 msleep(25);
0188
0189 return 0;
0190 }
0191
0192 static int s6d27a1_prepare(struct drm_panel *panel)
0193 {
0194 return s6d27a1_power_on(to_s6d27a1(panel));
0195 }
0196
0197 static int s6d27a1_enable(struct drm_panel *panel)
0198 {
0199 struct s6d27a1 *ctx = to_s6d27a1(panel);
0200 struct mipi_dbi *dbi = &ctx->dbi;
0201
0202 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0203
0204 return 0;
0205 }
0206
0207 static int s6d27a1_get_modes(struct drm_panel *panel,
0208 struct drm_connector *connector)
0209 {
0210 struct s6d27a1 *ctx = to_s6d27a1(panel);
0211 struct drm_display_mode *mode;
0212 static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0213
0214 mode = drm_mode_duplicate(connector->dev, &s6d27a1_480_800_mode);
0215 if (!mode) {
0216 dev_err(ctx->dev, "failed to add mode\n");
0217 return -ENOMEM;
0218 }
0219
0220 connector->display_info.bpc = 8;
0221 connector->display_info.width_mm = mode->width_mm;
0222 connector->display_info.height_mm = mode->height_mm;
0223 connector->display_info.bus_flags =
0224 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0225 drm_display_info_set_bus_formats(&connector->display_info,
0226 &bus_format, 1);
0227
0228 drm_mode_set_name(mode);
0229 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0230
0231 drm_mode_probed_add(connector, mode);
0232
0233 return 1;
0234 }
0235
0236 static const struct drm_panel_funcs s6d27a1_drm_funcs = {
0237 .disable = s6d27a1_disable,
0238 .unprepare = s6d27a1_unprepare,
0239 .prepare = s6d27a1_prepare,
0240 .enable = s6d27a1_enable,
0241 .get_modes = s6d27a1_get_modes,
0242 };
0243
0244 static int s6d27a1_probe(struct spi_device *spi)
0245 {
0246 struct device *dev = &spi->dev;
0247 struct s6d27a1 *ctx;
0248 int ret;
0249
0250 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0251 if (!ctx)
0252 return -ENOMEM;
0253
0254 ctx->dev = dev;
0255
0256
0257
0258
0259
0260 ctx->regulators[0].supply = "vci";
0261 ctx->regulators[1].supply = "vccio";
0262 ret = devm_regulator_bulk_get(dev,
0263 ARRAY_SIZE(ctx->regulators),
0264 ctx->regulators);
0265 if (ret)
0266 return dev_err_probe(dev, ret, "failed to get regulators\n");
0267
0268 ctx->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
0269 if (IS_ERR(ctx->reset)) {
0270 ret = PTR_ERR(ctx->reset);
0271 return dev_err_probe(dev, ret, "no RESET GPIO\n");
0272 }
0273
0274 ret = mipi_dbi_spi_init(spi, &ctx->dbi, NULL);
0275 if (ret)
0276 return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
0277
0278 ctx->dbi.read_commands = s6d27a1_dbi_read_commands;
0279
0280 drm_panel_init(&ctx->panel, dev, &s6d27a1_drm_funcs,
0281 DRM_MODE_CONNECTOR_DPI);
0282
0283 ret = drm_panel_of_backlight(&ctx->panel);
0284 if (ret)
0285 return dev_err_probe(dev, ret, "failed to add backlight\n");
0286
0287 spi_set_drvdata(spi, ctx);
0288
0289 drm_panel_add(&ctx->panel);
0290
0291 return 0;
0292 }
0293
0294 static void s6d27a1_remove(struct spi_device *spi)
0295 {
0296 struct s6d27a1 *ctx = spi_get_drvdata(spi);
0297
0298 drm_panel_remove(&ctx->panel);
0299 }
0300
0301 static const struct of_device_id s6d27a1_match[] = {
0302 { .compatible = "samsung,s6d27a1", },
0303 { },
0304 };
0305 MODULE_DEVICE_TABLE(of, s6d27a1_match);
0306
0307 static struct spi_driver s6d27a1_driver = {
0308 .probe = s6d27a1_probe,
0309 .remove = s6d27a1_remove,
0310 .driver = {
0311 .name = "s6d27a1-panel",
0312 .of_match_table = s6d27a1_match,
0313 },
0314 };
0315 module_spi_driver(s6d27a1_driver);
0316
0317 MODULE_AUTHOR("Markuss Broks <markuss.broks@gmail.com>");
0318 MODULE_DESCRIPTION("Samsung S6D27A1 panel driver");
0319 MODULE_LICENSE("GPL v2");