Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Panel driver for the Samsung S6D27A1 480x800 DPI RGB panel.
0004  * Found in the Samsung Galaxy Ace 2 GT-I8160 mobile phone.
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    /* Password Command for Level 2 Control */
0024 #define S6D27A1_RESCTL      0xB3    /* Resolution Select Control */
0025 #define S6D27A1_PANELCTL2   0xB4    /* ASG Signal Control */
0026 #define S6D27A1_READID1     0xDA    /* Read panel ID 1 */
0027 #define S6D27A1_READID2     0xDB    /* Read panel ID 2 */
0028 #define S6D27A1_READID3     0xDC    /* Read panel ID 3 */
0029 #define S6D27A1_DISPCTL     0xF2    /* Display Control */
0030 #define S6D27A1_MANPWR      0xF3    /* Manual Control */
0031 #define S6D27A1_PWRCTL1     0xF4    /* Power Control */
0032 #define S6D27A1_SRCCTL      0xF6    /* Source Control */
0033 #define S6D27A1_PANELCTL    0xF7    /* Panel Control*/
0034 
0035 static const u8 s6d27a1_dbi_read_commands[] = {
0036     S6D27A1_READID1,
0037     S6D27A1_READID2,
0038     S6D27A1_READID3,
0039     0, /* sentinel */
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      * The vendor driver states that the S6D27A1 panel
0053      * has a pixel clock frequency of 49920000 Hz / 2 = 24960000 Hz.
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     /* Power up */
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     /* Assert reset >=1 ms */
0114     gpiod_set_value_cansleep(ctx->reset, 1);
0115     usleep_range(1000, 5000);
0116     /* De-assert reset */
0117     gpiod_set_value_cansleep(ctx->reset, 0);
0118     /* Wait >= 10 ms */
0119     msleep(20);
0120 
0121     /*
0122      * Exit sleep mode and initialize display - some hammering is
0123      * necessary.
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     /* Magic to unlock level 2 control of the display */
0130     mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0x5A, 0x5A);
0131 
0132     /* Configure resolution to 480RGBx800 */
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     /* lock the level 2 control */
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     /* Go into RESET and disable regulators */
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      * VCI   is the analog voltage supply
0258      * VCCIO is the digital I/O voltage supply
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     { /* sentinel */ },
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");