Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2015 Red Hat
0004  * Copyright (C) 2015 Sony Mobile Communications Inc.
0005  * Author: Werner Johansson <werner.johansson@sonymobile.com>
0006  *
0007  * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/regulator/consumer.h>
0015 
0016 #include <video/mipi_display.h>
0017 
0018 #include <drm/drm_crtc.h>
0019 #include <drm/drm_device.h>
0020 #include <drm/drm_mipi_dsi.h>
0021 #include <drm/drm_panel.h>
0022 
0023 struct sharp_nt_panel {
0024     struct drm_panel base;
0025     struct mipi_dsi_device *dsi;
0026 
0027     struct regulator *supply;
0028     struct gpio_desc *reset_gpio;
0029 
0030     bool prepared;
0031     bool enabled;
0032 
0033     const struct drm_display_mode *mode;
0034 };
0035 
0036 static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
0037 {
0038     return container_of(panel, struct sharp_nt_panel, base);
0039 }
0040 
0041 static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
0042 {
0043     struct mipi_dsi_device *dsi = sharp_nt->dsi;
0044     int ret;
0045 
0046     dsi->mode_flags |= MIPI_DSI_MODE_LPM;
0047 
0048     ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
0049     if (ret < 0)
0050         return ret;
0051 
0052     msleep(120);
0053 
0054     /* Novatek two-lane operation */
0055     ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
0056     if (ret < 0)
0057         return ret;
0058 
0059     /* Set both MCU and RGB I/F to 24bpp */
0060     ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
0061                     (MIPI_DCS_PIXEL_FMT_24BIT << 4));
0062     if (ret < 0)
0063         return ret;
0064 
0065     return 0;
0066 }
0067 
0068 static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
0069 {
0070     struct mipi_dsi_device *dsi = sharp_nt->dsi;
0071     int ret;
0072 
0073     dsi->mode_flags |= MIPI_DSI_MODE_LPM;
0074 
0075     ret = mipi_dsi_dcs_set_display_on(dsi);
0076     if (ret < 0)
0077         return ret;
0078 
0079     return 0;
0080 }
0081 
0082 static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
0083 {
0084     struct mipi_dsi_device *dsi = sharp_nt->dsi;
0085     int ret;
0086 
0087     dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
0088 
0089     ret = mipi_dsi_dcs_set_display_off(dsi);
0090     if (ret < 0)
0091         return ret;
0092 
0093     ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
0094     if (ret < 0)
0095         return ret;
0096 
0097     return 0;
0098 }
0099 
0100 
0101 static int sharp_nt_panel_disable(struct drm_panel *panel)
0102 {
0103     struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
0104 
0105     if (!sharp_nt->enabled)
0106         return 0;
0107 
0108     sharp_nt->enabled = false;
0109 
0110     return 0;
0111 }
0112 
0113 static int sharp_nt_panel_unprepare(struct drm_panel *panel)
0114 {
0115     struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
0116     int ret;
0117 
0118     if (!sharp_nt->prepared)
0119         return 0;
0120 
0121     ret = sharp_nt_panel_off(sharp_nt);
0122     if (ret < 0) {
0123         dev_err(panel->dev, "failed to set panel off: %d\n", ret);
0124         return ret;
0125     }
0126 
0127     regulator_disable(sharp_nt->supply);
0128     if (sharp_nt->reset_gpio)
0129         gpiod_set_value(sharp_nt->reset_gpio, 0);
0130 
0131     sharp_nt->prepared = false;
0132 
0133     return 0;
0134 }
0135 
0136 static int sharp_nt_panel_prepare(struct drm_panel *panel)
0137 {
0138     struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
0139     int ret;
0140 
0141     if (sharp_nt->prepared)
0142         return 0;
0143 
0144     ret = regulator_enable(sharp_nt->supply);
0145     if (ret < 0)
0146         return ret;
0147 
0148     msleep(20);
0149 
0150     if (sharp_nt->reset_gpio) {
0151         gpiod_set_value(sharp_nt->reset_gpio, 1);
0152         msleep(1);
0153         gpiod_set_value(sharp_nt->reset_gpio, 0);
0154         msleep(1);
0155         gpiod_set_value(sharp_nt->reset_gpio, 1);
0156         msleep(10);
0157     }
0158 
0159     ret = sharp_nt_panel_init(sharp_nt);
0160     if (ret < 0) {
0161         dev_err(panel->dev, "failed to init panel: %d\n", ret);
0162         goto poweroff;
0163     }
0164 
0165     ret = sharp_nt_panel_on(sharp_nt);
0166     if (ret < 0) {
0167         dev_err(panel->dev, "failed to set panel on: %d\n", ret);
0168         goto poweroff;
0169     }
0170 
0171     sharp_nt->prepared = true;
0172 
0173     return 0;
0174 
0175 poweroff:
0176     regulator_disable(sharp_nt->supply);
0177     if (sharp_nt->reset_gpio)
0178         gpiod_set_value(sharp_nt->reset_gpio, 0);
0179     return ret;
0180 }
0181 
0182 static int sharp_nt_panel_enable(struct drm_panel *panel)
0183 {
0184     struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
0185 
0186     if (sharp_nt->enabled)
0187         return 0;
0188 
0189     sharp_nt->enabled = true;
0190 
0191     return 0;
0192 }
0193 
0194 static const struct drm_display_mode default_mode = {
0195     .clock = 41118,
0196     .hdisplay = 540,
0197     .hsync_start = 540 + 48,
0198     .hsync_end = 540 + 48 + 80,
0199     .htotal = 540 + 48 + 80 + 32,
0200     .vdisplay = 960,
0201     .vsync_start = 960 + 3,
0202     .vsync_end = 960 + 3 + 15,
0203     .vtotal = 960 + 3 + 15 + 1,
0204 };
0205 
0206 static int sharp_nt_panel_get_modes(struct drm_panel *panel,
0207                     struct drm_connector *connector)
0208 {
0209     struct drm_display_mode *mode;
0210 
0211     mode = drm_mode_duplicate(connector->dev, &default_mode);
0212     if (!mode) {
0213         dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0214             default_mode.hdisplay, default_mode.vdisplay,
0215             drm_mode_vrefresh(&default_mode));
0216         return -ENOMEM;
0217     }
0218 
0219     drm_mode_set_name(mode);
0220 
0221     drm_mode_probed_add(connector, mode);
0222 
0223     connector->display_info.width_mm = 54;
0224     connector->display_info.height_mm = 95;
0225 
0226     return 1;
0227 }
0228 
0229 static const struct drm_panel_funcs sharp_nt_panel_funcs = {
0230     .disable = sharp_nt_panel_disable,
0231     .unprepare = sharp_nt_panel_unprepare,
0232     .prepare = sharp_nt_panel_prepare,
0233     .enable = sharp_nt_panel_enable,
0234     .get_modes = sharp_nt_panel_get_modes,
0235 };
0236 
0237 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
0238 {
0239     struct device *dev = &sharp_nt->dsi->dev;
0240     int ret;
0241 
0242     sharp_nt->mode = &default_mode;
0243 
0244     sharp_nt->supply = devm_regulator_get(dev, "avdd");
0245     if (IS_ERR(sharp_nt->supply))
0246         return PTR_ERR(sharp_nt->supply);
0247 
0248     sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
0249     if (IS_ERR(sharp_nt->reset_gpio)) {
0250         dev_err(dev, "cannot get reset-gpios %ld\n",
0251             PTR_ERR(sharp_nt->reset_gpio));
0252         sharp_nt->reset_gpio = NULL;
0253     } else {
0254         gpiod_set_value(sharp_nt->reset_gpio, 0);
0255     }
0256 
0257     drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
0258                &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
0259 
0260     ret = drm_panel_of_backlight(&sharp_nt->base);
0261     if (ret)
0262         return ret;
0263 
0264     drm_panel_add(&sharp_nt->base);
0265 
0266     return 0;
0267 }
0268 
0269 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
0270 {
0271     if (sharp_nt->base.dev)
0272         drm_panel_remove(&sharp_nt->base);
0273 }
0274 
0275 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
0276 {
0277     struct sharp_nt_panel *sharp_nt;
0278     int ret;
0279 
0280     dsi->lanes = 2;
0281     dsi->format = MIPI_DSI_FMT_RGB888;
0282     dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
0283             MIPI_DSI_MODE_VIDEO_HSE |
0284             MIPI_DSI_CLOCK_NON_CONTINUOUS |
0285             MIPI_DSI_MODE_NO_EOT_PACKET;
0286 
0287     sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
0288     if (!sharp_nt)
0289         return -ENOMEM;
0290 
0291     mipi_dsi_set_drvdata(dsi, sharp_nt);
0292 
0293     sharp_nt->dsi = dsi;
0294 
0295     ret = sharp_nt_panel_add(sharp_nt);
0296     if (ret < 0)
0297         return ret;
0298 
0299     ret = mipi_dsi_attach(dsi);
0300     if (ret < 0) {
0301         sharp_nt_panel_del(sharp_nt);
0302         return ret;
0303     }
0304 
0305     return 0;
0306 }
0307 
0308 static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
0309 {
0310     struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
0311     int ret;
0312 
0313     ret = drm_panel_disable(&sharp_nt->base);
0314     if (ret < 0)
0315         dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
0316 
0317     ret = mipi_dsi_detach(dsi);
0318     if (ret < 0)
0319         dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
0320 
0321     sharp_nt_panel_del(sharp_nt);
0322 
0323     return 0;
0324 }
0325 
0326 static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
0327 {
0328     struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
0329 
0330     drm_panel_disable(&sharp_nt->base);
0331 }
0332 
0333 static const struct of_device_id sharp_nt_of_match[] = {
0334     { .compatible = "sharp,ls043t1le01-qhd", },
0335     { }
0336 };
0337 MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
0338 
0339 static struct mipi_dsi_driver sharp_nt_panel_driver = {
0340     .driver = {
0341         .name = "panel-sharp-ls043t1le01-qhd",
0342         .of_match_table = sharp_nt_of_match,
0343     },
0344     .probe = sharp_nt_panel_probe,
0345     .remove = sharp_nt_panel_remove,
0346     .shutdown = sharp_nt_panel_shutdown,
0347 };
0348 module_mipi_dsi_driver(sharp_nt_panel_driver);
0349 
0350 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
0351 MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
0352 MODULE_LICENSE("GPL v2");