Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic DSI Command Mode panel driver
0004  *
0005  * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/
0006  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
0007  */
0008 
0009 #include <linux/backlight.h>
0010 #include <linux/delay.h>
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/module.h>
0014 #include <linux/of_device.h>
0015 #include <linux/regulator/consumer.h>
0016 
0017 #include <drm/drm_connector.h>
0018 #include <drm/drm_mipi_dsi.h>
0019 #include <drm/drm_modes.h>
0020 #include <drm/drm_panel.h>
0021 
0022 #include <video/mipi_display.h>
0023 
0024 #define DCS_GET_ID1     0xda
0025 #define DCS_GET_ID2     0xdb
0026 #define DCS_GET_ID3     0xdc
0027 
0028 #define DCS_REGULATOR_SUPPLY_NUM 2
0029 
0030 static const struct of_device_id dsicm_of_match[];
0031 
0032 struct dsic_panel_data {
0033     u32 xres;
0034     u32 yres;
0035     u32 refresh;
0036     u32 width_mm;
0037     u32 height_mm;
0038     u32 max_hs_rate;
0039     u32 max_lp_rate;
0040     bool te_support;
0041 };
0042 
0043 struct panel_drv_data {
0044     struct mipi_dsi_device *dsi;
0045     struct drm_panel panel;
0046     struct drm_display_mode mode;
0047 
0048     struct mutex lock;
0049 
0050     struct backlight_device *bldev;
0051     struct backlight_device *extbldev;
0052 
0053     unsigned long   hw_guard_end;   /* next value of jiffies when we can
0054                      * issue the next sleep in/out command
0055                      */
0056     unsigned long   hw_guard_wait;  /* max guard time in jiffies */
0057 
0058     const struct dsic_panel_data *panel_data;
0059 
0060     struct gpio_desc *reset_gpio;
0061 
0062     struct regulator_bulk_data supplies[DCS_REGULATOR_SUPPLY_NUM];
0063 
0064     bool use_dsi_backlight;
0065 
0066     /* runtime variables */
0067     bool enabled;
0068 
0069     bool intro_printed;
0070 };
0071 
0072 static inline struct panel_drv_data *panel_to_ddata(struct drm_panel *panel)
0073 {
0074     return container_of(panel, struct panel_drv_data, panel);
0075 }
0076 
0077 static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable)
0078 {
0079     struct backlight_device *backlight;
0080 
0081     if (ddata->bldev)
0082         backlight = ddata->bldev;
0083     else if (ddata->extbldev)
0084         backlight = ddata->extbldev;
0085     else
0086         return;
0087 
0088     if (enable)
0089         backlight_enable(backlight);
0090     else
0091         backlight_disable(backlight);
0092 }
0093 
0094 static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
0095 {
0096     ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
0097     ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
0098 }
0099 
0100 static void hw_guard_wait(struct panel_drv_data *ddata)
0101 {
0102     unsigned long wait = ddata->hw_guard_end - jiffies;
0103 
0104     if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
0105         set_current_state(TASK_UNINTERRUPTIBLE);
0106         schedule_timeout(wait);
0107     }
0108 }
0109 
0110 static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
0111 {
0112     return mipi_dsi_dcs_read(ddata->dsi, dcs_cmd, data, 1);
0113 }
0114 
0115 static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
0116 {
0117     return mipi_dsi_dcs_write(ddata->dsi, dcs_cmd, &param, 1);
0118 }
0119 
0120 static int dsicm_sleep_in(struct panel_drv_data *ddata)
0121 
0122 {
0123     int r;
0124 
0125     hw_guard_wait(ddata);
0126 
0127     r = mipi_dsi_dcs_enter_sleep_mode(ddata->dsi);
0128     if (r)
0129         return r;
0130 
0131     hw_guard_start(ddata, 120);
0132 
0133     usleep_range(5000, 10000);
0134 
0135     return 0;
0136 }
0137 
0138 static int dsicm_sleep_out(struct panel_drv_data *ddata)
0139 {
0140     int r;
0141 
0142     hw_guard_wait(ddata);
0143 
0144     r = mipi_dsi_dcs_exit_sleep_mode(ddata->dsi);
0145     if (r)
0146         return r;
0147 
0148     hw_guard_start(ddata, 120);
0149 
0150     usleep_range(5000, 10000);
0151 
0152     return 0;
0153 }
0154 
0155 static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
0156 {
0157     int r;
0158 
0159     r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
0160     if (r)
0161         return r;
0162     r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
0163     if (r)
0164         return r;
0165     r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
0166     if (r)
0167         return r;
0168 
0169     return 0;
0170 }
0171 
0172 static int dsicm_set_update_window(struct panel_drv_data *ddata)
0173 {
0174     struct mipi_dsi_device *dsi = ddata->dsi;
0175     int r;
0176 
0177     r = mipi_dsi_dcs_set_column_address(dsi, 0, ddata->mode.hdisplay - 1);
0178     if (r < 0)
0179         return r;
0180 
0181     r = mipi_dsi_dcs_set_page_address(dsi, 0, ddata->mode.vdisplay - 1);
0182     if (r < 0)
0183         return r;
0184 
0185     return 0;
0186 }
0187 
0188 static int dsicm_bl_update_status(struct backlight_device *dev)
0189 {
0190     struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
0191     int r = 0;
0192     int level = backlight_get_brightness(dev);
0193 
0194     dev_dbg(&ddata->dsi->dev, "update brightness to %d\n", level);
0195 
0196     mutex_lock(&ddata->lock);
0197 
0198     if (ddata->enabled)
0199         r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
0200                       level);
0201 
0202     mutex_unlock(&ddata->lock);
0203 
0204     return r;
0205 }
0206 
0207 static int dsicm_bl_get_intensity(struct backlight_device *dev)
0208 {
0209     return backlight_get_brightness(dev);
0210 }
0211 
0212 static const struct backlight_ops dsicm_bl_ops = {
0213     .get_brightness = dsicm_bl_get_intensity,
0214     .update_status  = dsicm_bl_update_status,
0215 };
0216 
0217 static ssize_t num_dsi_errors_show(struct device *dev,
0218         struct device_attribute *attr, char *buf)
0219 {
0220     struct panel_drv_data *ddata = dev_get_drvdata(dev);
0221     u8 errors = 0;
0222     int r = -ENODEV;
0223 
0224     mutex_lock(&ddata->lock);
0225 
0226     if (ddata->enabled)
0227         r = dsicm_dcs_read_1(ddata, MIPI_DCS_GET_ERROR_COUNT_ON_DSI, &errors);
0228 
0229     mutex_unlock(&ddata->lock);
0230 
0231     if (r)
0232         return r;
0233 
0234     return sysfs_emit(buf, "%d\n", errors);
0235 }
0236 
0237 static ssize_t hw_revision_show(struct device *dev,
0238         struct device_attribute *attr, char *buf)
0239 {
0240     struct panel_drv_data *ddata = dev_get_drvdata(dev);
0241     u8 id1, id2, id3;
0242     int r = -ENODEV;
0243 
0244     mutex_lock(&ddata->lock);
0245 
0246     if (ddata->enabled)
0247         r = dsicm_get_id(ddata, &id1, &id2, &id3);
0248 
0249     mutex_unlock(&ddata->lock);
0250 
0251     if (r)
0252         return r;
0253 
0254     return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3);
0255 }
0256 
0257 static DEVICE_ATTR_RO(num_dsi_errors);
0258 static DEVICE_ATTR_RO(hw_revision);
0259 
0260 static struct attribute *dsicm_attrs[] = {
0261     &dev_attr_num_dsi_errors.attr,
0262     &dev_attr_hw_revision.attr,
0263     NULL,
0264 };
0265 
0266 static const struct attribute_group dsicm_attr_group = {
0267     .attrs = dsicm_attrs,
0268 };
0269 
0270 static void dsicm_hw_reset(struct panel_drv_data *ddata)
0271 {
0272     gpiod_set_value(ddata->reset_gpio, 1);
0273     udelay(10);
0274     /* reset the panel */
0275     gpiod_set_value(ddata->reset_gpio, 0);
0276     /* assert reset */
0277     udelay(10);
0278     gpiod_set_value(ddata->reset_gpio, 1);
0279     /* wait after releasing reset */
0280     usleep_range(5000, 10000);
0281 }
0282 
0283 static int dsicm_power_on(struct panel_drv_data *ddata)
0284 {
0285     u8 id1, id2, id3;
0286     int r;
0287 
0288     dsicm_hw_reset(ddata);
0289 
0290     ddata->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
0291 
0292     r = dsicm_sleep_out(ddata);
0293     if (r)
0294         goto err;
0295 
0296     r = dsicm_get_id(ddata, &id1, &id2, &id3);
0297     if (r)
0298         goto err;
0299 
0300     r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
0301     if (r)
0302         goto err;
0303 
0304     r = dsicm_dcs_write_1(ddata, MIPI_DCS_WRITE_CONTROL_DISPLAY,
0305             (1<<2) | (1<<5));   /* BL | BCTRL */
0306     if (r)
0307         goto err;
0308 
0309     r = mipi_dsi_dcs_set_pixel_format(ddata->dsi, MIPI_DCS_PIXEL_FMT_24BIT);
0310     if (r)
0311         goto err;
0312 
0313     r = dsicm_set_update_window(ddata);
0314     if (r)
0315         goto err;
0316 
0317     r = mipi_dsi_dcs_set_display_on(ddata->dsi);
0318     if (r)
0319         goto err;
0320 
0321     if (ddata->panel_data->te_support) {
0322         r = mipi_dsi_dcs_set_tear_on(ddata->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
0323         if (r)
0324             goto err;
0325     }
0326 
0327     /* possible panel bug */
0328     msleep(100);
0329 
0330     ddata->enabled = true;
0331 
0332     if (!ddata->intro_printed) {
0333         dev_info(&ddata->dsi->dev, "panel revision %02x.%02x.%02x\n",
0334             id1, id2, id3);
0335         ddata->intro_printed = true;
0336     }
0337 
0338     ddata->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
0339 
0340     return 0;
0341 err:
0342     dev_err(&ddata->dsi->dev, "error while enabling panel, issuing HW reset\n");
0343 
0344     dsicm_hw_reset(ddata);
0345 
0346     return r;
0347 }
0348 
0349 static int dsicm_power_off(struct panel_drv_data *ddata)
0350 {
0351     int r;
0352 
0353     ddata->enabled = false;
0354 
0355     r = mipi_dsi_dcs_set_display_off(ddata->dsi);
0356     if (!r)
0357         r = dsicm_sleep_in(ddata);
0358 
0359     if (r) {
0360         dev_err(&ddata->dsi->dev,
0361                 "error disabling panel, issuing HW reset\n");
0362         dsicm_hw_reset(ddata);
0363     }
0364 
0365     return r;
0366 }
0367 
0368 static int dsicm_prepare(struct drm_panel *panel)
0369 {
0370     struct panel_drv_data *ddata = panel_to_ddata(panel);
0371     int r;
0372 
0373     r = regulator_bulk_enable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
0374     if (r)
0375         dev_err(&ddata->dsi->dev, "failed to enable supplies: %d\n", r);
0376 
0377     return r;
0378 }
0379 
0380 static int dsicm_enable(struct drm_panel *panel)
0381 {
0382     struct panel_drv_data *ddata = panel_to_ddata(panel);
0383     int r;
0384 
0385     mutex_lock(&ddata->lock);
0386 
0387     r = dsicm_power_on(ddata);
0388     if (r)
0389         goto err;
0390 
0391     mutex_unlock(&ddata->lock);
0392 
0393     dsicm_bl_power(ddata, true);
0394 
0395     return 0;
0396 err:
0397     dev_err(&ddata->dsi->dev, "enable failed (%d)\n", r);
0398     mutex_unlock(&ddata->lock);
0399     return r;
0400 }
0401 
0402 static int dsicm_unprepare(struct drm_panel *panel)
0403 {
0404     struct panel_drv_data *ddata = panel_to_ddata(panel);
0405     int r;
0406 
0407     r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
0408     if (r)
0409         dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);
0410 
0411     return r;
0412 }
0413 
0414 static int dsicm_disable(struct drm_panel *panel)
0415 {
0416     struct panel_drv_data *ddata = panel_to_ddata(panel);
0417     int r;
0418 
0419     dsicm_bl_power(ddata, false);
0420 
0421     mutex_lock(&ddata->lock);
0422 
0423     r = dsicm_power_off(ddata);
0424 
0425     mutex_unlock(&ddata->lock);
0426 
0427     return r;
0428 }
0429 
0430 static int dsicm_get_modes(struct drm_panel *panel,
0431                struct drm_connector *connector)
0432 {
0433     struct panel_drv_data *ddata = panel_to_ddata(panel);
0434     struct drm_display_mode *mode;
0435 
0436     mode = drm_mode_duplicate(connector->dev, &ddata->mode);
0437     if (!mode) {
0438         dev_err(&ddata->dsi->dev, "failed to add mode %ux%ux@%u kHz\n",
0439             ddata->mode.hdisplay, ddata->mode.vdisplay,
0440             ddata->mode.clock);
0441         return -ENOMEM;
0442     }
0443 
0444     connector->display_info.width_mm = ddata->panel_data->width_mm;
0445     connector->display_info.height_mm = ddata->panel_data->height_mm;
0446 
0447     drm_mode_probed_add(connector, mode);
0448 
0449     return 1;
0450 }
0451 
0452 static const struct drm_panel_funcs dsicm_panel_funcs = {
0453     .unprepare = dsicm_unprepare,
0454     .disable = dsicm_disable,
0455     .prepare = dsicm_prepare,
0456     .enable = dsicm_enable,
0457     .get_modes = dsicm_get_modes,
0458 };
0459 
0460 static int dsicm_probe_of(struct mipi_dsi_device *dsi)
0461 {
0462     struct backlight_device *backlight;
0463     struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
0464     int err;
0465     struct drm_display_mode *mode = &ddata->mode;
0466 
0467     ddata->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
0468     if (IS_ERR(ddata->reset_gpio)) {
0469         err = PTR_ERR(ddata->reset_gpio);
0470         dev_err(&dsi->dev, "reset gpio request failed: %d", err);
0471         return err;
0472     }
0473 
0474     mode->hdisplay = mode->hsync_start = mode->hsync_end = mode->htotal =
0475         ddata->panel_data->xres;
0476     mode->vdisplay = mode->vsync_start = mode->vsync_end = mode->vtotal =
0477         ddata->panel_data->yres;
0478     mode->clock = ddata->panel_data->xres * ddata->panel_data->yres *
0479         ddata->panel_data->refresh / 1000;
0480     mode->width_mm = ddata->panel_data->width_mm;
0481     mode->height_mm = ddata->panel_data->height_mm;
0482     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0483     drm_mode_set_name(mode);
0484 
0485     ddata->supplies[0].supply = "vpnl";
0486     ddata->supplies[1].supply = "vddi";
0487     err = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ddata->supplies),
0488                       ddata->supplies);
0489     if (err)
0490         return err;
0491 
0492     backlight = devm_of_find_backlight(&dsi->dev);
0493     if (IS_ERR(backlight))
0494         return PTR_ERR(backlight);
0495 
0496     /* If no backlight device is found assume native backlight support */
0497     if (backlight)
0498         ddata->extbldev = backlight;
0499     else
0500         ddata->use_dsi_backlight = true;
0501 
0502     return 0;
0503 }
0504 
0505 static int dsicm_probe(struct mipi_dsi_device *dsi)
0506 {
0507     struct panel_drv_data *ddata;
0508     struct backlight_device *bldev = NULL;
0509     struct device *dev = &dsi->dev;
0510     int r;
0511 
0512     dev_dbg(dev, "probe\n");
0513 
0514     ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
0515     if (!ddata)
0516         return -ENOMEM;
0517 
0518     mipi_dsi_set_drvdata(dsi, ddata);
0519     ddata->dsi = dsi;
0520 
0521     ddata->panel_data = of_device_get_match_data(dev);
0522     if (!ddata->panel_data)
0523         return -ENODEV;
0524 
0525     r = dsicm_probe_of(dsi);
0526     if (r)
0527         return r;
0528 
0529     mutex_init(&ddata->lock);
0530 
0531     dsicm_hw_reset(ddata);
0532 
0533     drm_panel_init(&ddata->panel, dev, &dsicm_panel_funcs,
0534                DRM_MODE_CONNECTOR_DSI);
0535 
0536     if (ddata->use_dsi_backlight) {
0537         struct backlight_properties props = { 0 };
0538         props.max_brightness = 255;
0539         props.type = BACKLIGHT_RAW;
0540 
0541         bldev = devm_backlight_device_register(dev, dev_name(dev),
0542             dev, ddata, &dsicm_bl_ops, &props);
0543         if (IS_ERR(bldev)) {
0544             r = PTR_ERR(bldev);
0545             goto err_bl;
0546         }
0547 
0548         ddata->bldev = bldev;
0549     }
0550 
0551     r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
0552     if (r) {
0553         dev_err(dev, "failed to create sysfs files\n");
0554         goto err_bl;
0555     }
0556 
0557     dsi->lanes = 2;
0558     dsi->format = MIPI_DSI_FMT_RGB888;
0559     dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
0560               MIPI_DSI_MODE_NO_EOT_PACKET;
0561     dsi->hs_rate = ddata->panel_data->max_hs_rate;
0562     dsi->lp_rate = ddata->panel_data->max_lp_rate;
0563 
0564     drm_panel_add(&ddata->panel);
0565 
0566     r = mipi_dsi_attach(dsi);
0567     if (r < 0)
0568         goto err_dsi_attach;
0569 
0570     return 0;
0571 
0572 err_dsi_attach:
0573     drm_panel_remove(&ddata->panel);
0574     sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
0575 err_bl:
0576     if (ddata->extbldev)
0577         put_device(&ddata->extbldev->dev);
0578 
0579     return r;
0580 }
0581 
0582 static int dsicm_remove(struct mipi_dsi_device *dsi)
0583 {
0584     struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
0585 
0586     dev_dbg(&dsi->dev, "remove\n");
0587 
0588     mipi_dsi_detach(dsi);
0589 
0590     drm_panel_remove(&ddata->panel);
0591 
0592     sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
0593 
0594     if (ddata->extbldev)
0595         put_device(&ddata->extbldev->dev);
0596 
0597     return 0;
0598 }
0599 
0600 static const struct dsic_panel_data taal_data = {
0601     .xres = 864,
0602     .yres = 480,
0603     .refresh = 60,
0604     .width_mm = 0,
0605     .height_mm = 0,
0606     .max_hs_rate = 300000000,
0607     .max_lp_rate = 10000000,
0608     .te_support = true,
0609 };
0610 
0611 static const struct dsic_panel_data himalaya_data = {
0612     .xres = 480,
0613     .yres = 864,
0614     .refresh = 60,
0615     .width_mm = 49,
0616     .height_mm = 88,
0617     .max_hs_rate = 300000000,
0618     .max_lp_rate = 10000000,
0619     .te_support = false,
0620 };
0621 
0622 static const struct dsic_panel_data droid4_data = {
0623     .xres = 540,
0624     .yres = 960,
0625     .refresh = 60,
0626     .width_mm = 50,
0627     .height_mm = 89,
0628     .max_hs_rate = 300000000,
0629     .max_lp_rate = 10000000,
0630     .te_support = false,
0631 };
0632 
0633 static const struct of_device_id dsicm_of_match[] = {
0634     { .compatible = "tpo,taal", .data = &taal_data },
0635     { .compatible = "nokia,himalaya", &himalaya_data },
0636     { .compatible = "motorola,droid4-panel", &droid4_data },
0637     {},
0638 };
0639 
0640 MODULE_DEVICE_TABLE(of, dsicm_of_match);
0641 
0642 static struct mipi_dsi_driver dsicm_driver = {
0643     .probe = dsicm_probe,
0644     .remove = dsicm_remove,
0645     .driver = {
0646         .name = "panel-dsi-cm",
0647         .of_match_table = dsicm_of_match,
0648     },
0649 };
0650 module_mipi_dsi_driver(dsicm_driver);
0651 
0652 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
0653 MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
0654 MODULE_LICENSE("GPL");