307 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2021 Linaro Ltd.3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:4 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.5 */6 7#include <linux/delay.h>8#include <linux/gpio/consumer.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/regulator/consumer.h>12 13#include <video/mipi_display.h>14 15#include <drm/drm_mipi_dsi.h>16#include <drm/drm_modes.h>17#include <drm/drm_panel.h>18 19struct sharp_ls060 {20 struct drm_panel panel;21 struct mipi_dsi_device *dsi;22 struct regulator *vddi_supply;23 struct regulator *vddh_supply;24 struct regulator *avdd_supply;25 struct regulator *avee_supply;26 struct gpio_desc *reset_gpio;27};28 29static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)30{31 return container_of(panel, struct sharp_ls060, panel);32}33 34static void sharp_ls060_reset(struct sharp_ls060 *ctx)35{36 gpiod_set_value_cansleep(ctx->reset_gpio, 0);37 usleep_range(10000, 11000);38 gpiod_set_value_cansleep(ctx->reset_gpio, 1);39 usleep_range(10000, 11000);40 gpiod_set_value_cansleep(ctx->reset_gpio, 0);41 usleep_range(10000, 11000);42}43 44static int sharp_ls060_on(struct sharp_ls060 *ctx)45{46 struct mipi_dsi_device *dsi = ctx->dsi;47 struct device *dev = &dsi->dev;48 int ret;49 50 dsi->mode_flags |= MIPI_DSI_MODE_LPM;51 52 mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13);53 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);54 55 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);56 if (ret < 0) {57 dev_err(dev, "Failed to exit sleep mode: %d\n", ret);58 return ret;59 }60 msleep(120);61 62 ret = mipi_dsi_dcs_set_display_on(dsi);63 if (ret < 0) {64 dev_err(dev, "Failed to set display on: %d\n", ret);65 return ret;66 }67 msleep(50);68 69 return 0;70}71 72static int sharp_ls060_off(struct sharp_ls060 *ctx)73{74 struct mipi_dsi_device *dsi = ctx->dsi;75 struct device *dev = &dsi->dev;76 int ret;77 78 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;79 80 ret = mipi_dsi_dcs_set_display_off(dsi);81 if (ret < 0) {82 dev_err(dev, "Failed to set display off: %d\n", ret);83 return ret;84 }85 usleep_range(2000, 3000);86 87 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);88 if (ret < 0) {89 dev_err(dev, "Failed to enter sleep mode: %d\n", ret);90 return ret;91 }92 msleep(121);93 94 return 0;95}96 97static int sharp_ls060_prepare(struct drm_panel *panel)98{99 struct sharp_ls060 *ctx = to_sharp_ls060(panel);100 struct device *dev = &ctx->dsi->dev;101 int ret;102 103 ret = regulator_enable(ctx->vddi_supply);104 if (ret < 0)105 return ret;106 107 ret = regulator_enable(ctx->avdd_supply);108 if (ret < 0)109 goto err_avdd;110 111 usleep_range(1000, 2000);112 113 ret = regulator_enable(ctx->avee_supply);114 if (ret < 0)115 goto err_avee;116 117 usleep_range(10000, 11000);118 119 ret = regulator_enable(ctx->vddh_supply);120 if (ret < 0)121 goto err_vddh;122 123 usleep_range(10000, 11000);124 125 sharp_ls060_reset(ctx);126 127 ret = sharp_ls060_on(ctx);128 if (ret < 0) {129 dev_err(dev, "Failed to initialize panel: %d\n", ret);130 goto err_on;131 }132 133 return 0;134 135err_on:136 regulator_disable(ctx->vddh_supply);137 138 usleep_range(10000, 11000);139 140err_vddh:141 regulator_disable(ctx->avee_supply);142 143err_avee:144 regulator_disable(ctx->avdd_supply);145 146 gpiod_set_value_cansleep(ctx->reset_gpio, 1);147 148err_avdd:149 regulator_disable(ctx->vddi_supply);150 151 return ret;152}153 154static int sharp_ls060_unprepare(struct drm_panel *panel)155{156 struct sharp_ls060 *ctx = to_sharp_ls060(panel);157 struct device *dev = &ctx->dsi->dev;158 int ret;159 160 ret = sharp_ls060_off(ctx);161 if (ret < 0)162 dev_err(dev, "Failed to un-initialize panel: %d\n", ret);163 164 regulator_disable(ctx->vddh_supply);165 166 usleep_range(10000, 11000);167 168 regulator_disable(ctx->avee_supply);169 regulator_disable(ctx->avdd_supply);170 171 gpiod_set_value_cansleep(ctx->reset_gpio, 1);172 173 regulator_disable(ctx->vddi_supply);174 175 return 0;176}177 178static const struct drm_display_mode sharp_ls060_mode = {179 .clock = (1080 + 96 + 16 + 64) * (1920 + 4 + 1 + 16) * 60 / 1000,180 .hdisplay = 1080,181 .hsync_start = 1080 + 96,182 .hsync_end = 1080 + 96 + 16,183 .htotal = 1080 + 96 + 16 + 64,184 .vdisplay = 1920,185 .vsync_start = 1920 + 4,186 .vsync_end = 1920 + 4 + 1,187 .vtotal = 1920 + 4 + 1 + 16,188 .width_mm = 75,189 .height_mm = 132,190};191 192static int sharp_ls060_get_modes(struct drm_panel *panel,193 struct drm_connector *connector)194{195 struct drm_display_mode *mode;196 197 mode = drm_mode_duplicate(connector->dev, &sharp_ls060_mode);198 if (!mode)199 return -ENOMEM;200 201 drm_mode_set_name(mode);202 203 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;204 connector->display_info.width_mm = mode->width_mm;205 connector->display_info.height_mm = mode->height_mm;206 drm_mode_probed_add(connector, mode);207 208 return 1;209}210 211static const struct drm_panel_funcs sharp_ls060_panel_funcs = {212 .prepare = sharp_ls060_prepare,213 .unprepare = sharp_ls060_unprepare,214 .get_modes = sharp_ls060_get_modes,215};216 217static int sharp_ls060_probe(struct mipi_dsi_device *dsi)218{219 struct device *dev = &dsi->dev;220 struct sharp_ls060 *ctx;221 int ret;222 223 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);224 if (!ctx)225 return -ENOMEM;226 227 ctx->vddi_supply = devm_regulator_get(dev, "vddi");228 if (IS_ERR(ctx->vddi_supply))229 return PTR_ERR(ctx->vddi_supply);230 231 ctx->vddh_supply = devm_regulator_get(dev, "vddh");232 if (IS_ERR(ctx->vddh_supply))233 return PTR_ERR(ctx->vddh_supply);234 235 ctx->avdd_supply = devm_regulator_get(dev, "avdd");236 if (IS_ERR(ctx->avdd_supply))237 return PTR_ERR(ctx->avdd_supply);238 239 ctx->avee_supply = devm_regulator_get(dev, "avee");240 if (IS_ERR(ctx->avee_supply))241 return PTR_ERR(ctx->avee_supply);242 243 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);244 if (IS_ERR(ctx->reset_gpio))245 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),246 "Failed to get reset-gpios\n");247 248 ctx->dsi = dsi;249 mipi_dsi_set_drvdata(dsi, ctx);250 251 dsi->lanes = 4;252 dsi->format = MIPI_DSI_FMT_RGB888;253 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |254 MIPI_DSI_MODE_NO_EOT_PACKET |255 MIPI_DSI_CLOCK_NON_CONTINUOUS;256 257 drm_panel_init(&ctx->panel, dev, &sharp_ls060_panel_funcs,258 DRM_MODE_CONNECTOR_DSI);259 260 ret = drm_panel_of_backlight(&ctx->panel);261 if (ret)262 return dev_err_probe(dev, ret, "Failed to get backlight\n");263 264 drm_panel_add(&ctx->panel);265 266 ret = mipi_dsi_attach(dsi);267 if (ret < 0) {268 dev_err(dev, "Failed to attach to DSI host: %d\n", ret);269 drm_panel_remove(&ctx->panel);270 return ret;271 }272 273 return 0;274}275 276static void sharp_ls060_remove(struct mipi_dsi_device *dsi)277{278 struct sharp_ls060 *ctx = mipi_dsi_get_drvdata(dsi);279 int ret;280 281 ret = mipi_dsi_detach(dsi);282 if (ret < 0)283 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);284 285 drm_panel_remove(&ctx->panel);286}287 288static const struct of_device_id sharp_ls060t1sx01_of_match[] = {289 { .compatible = "sharp,ls060t1sx01" },290 { /* sentinel */ }291};292MODULE_DEVICE_TABLE(of, sharp_ls060t1sx01_of_match);293 294static struct mipi_dsi_driver sharp_ls060_driver = {295 .probe = sharp_ls060_probe,296 .remove = sharp_ls060_remove,297 .driver = {298 .name = "panel-sharp-ls060t1sx01",299 .of_match_table = sharp_ls060t1sx01_of_match,300 },301};302module_mipi_dsi_driver(sharp_ls060_driver);303 304MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");305MODULE_DESCRIPTION("DRM driver for Sharp LS060T1SX01 1080p video mode dsi panel");306MODULE_LICENSE("GPL v2");307