1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Red Hat 4 * Copyright (C) 2015 Sony Mobile Communications Inc. 5 * Author: Werner Johansson <werner.johansson@sonymobile.com> 6 * 7 * Based on AUO panel driver by Rob Clark <robdclark@gmail.com> 8 */ 9 10 #include <linux/backlight.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/regulator/consumer.h> 15 16 #include <drm/drmP.h> 17 #include <drm/drm_crtc.h> 18 #include <drm/drm_mipi_dsi.h> 19 #include <drm/drm_panel.h> 20 21 #include <video/mipi_display.h> 22 23 struct sharp_nt_panel { 24 struct drm_panel base; 25 struct mipi_dsi_device *dsi; 26 27 struct backlight_device *backlight; 28 struct regulator *supply; 29 struct gpio_desc *reset_gpio; 30 31 bool prepared; 32 bool enabled; 33 34 const struct drm_display_mode *mode; 35 }; 36 37 static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel) 38 { 39 return container_of(panel, struct sharp_nt_panel, base); 40 } 41 42 static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt) 43 { 44 struct mipi_dsi_device *dsi = sharp_nt->dsi; 45 int ret; 46 47 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 48 49 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 50 if (ret < 0) 51 return ret; 52 53 msleep(120); 54 55 /* Novatek two-lane operation */ 56 ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1); 57 if (ret < 0) 58 return ret; 59 60 /* Set both MCU and RGB I/F to 24bpp */ 61 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT | 62 (MIPI_DCS_PIXEL_FMT_24BIT << 4)); 63 if (ret < 0) 64 return ret; 65 66 return 0; 67 } 68 69 static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt) 70 { 71 struct mipi_dsi_device *dsi = sharp_nt->dsi; 72 int ret; 73 74 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 75 76 ret = mipi_dsi_dcs_set_display_on(dsi); 77 if (ret < 0) 78 return ret; 79 80 return 0; 81 } 82 83 static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt) 84 { 85 struct mipi_dsi_device *dsi = sharp_nt->dsi; 86 int ret; 87 88 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 89 90 ret = mipi_dsi_dcs_set_display_off(dsi); 91 if (ret < 0) 92 return ret; 93 94 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 95 if (ret < 0) 96 return ret; 97 98 return 0; 99 } 100 101 102 static int sharp_nt_panel_disable(struct drm_panel *panel) 103 { 104 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 105 106 if (!sharp_nt->enabled) 107 return 0; 108 109 backlight_disable(sharp_nt->backlight); 110 111 sharp_nt->enabled = false; 112 113 return 0; 114 } 115 116 static int sharp_nt_panel_unprepare(struct drm_panel *panel) 117 { 118 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 119 int ret; 120 121 if (!sharp_nt->prepared) 122 return 0; 123 124 ret = sharp_nt_panel_off(sharp_nt); 125 if (ret < 0) { 126 dev_err(panel->dev, "failed to set panel off: %d\n", ret); 127 return ret; 128 } 129 130 regulator_disable(sharp_nt->supply); 131 if (sharp_nt->reset_gpio) 132 gpiod_set_value(sharp_nt->reset_gpio, 0); 133 134 sharp_nt->prepared = false; 135 136 return 0; 137 } 138 139 static int sharp_nt_panel_prepare(struct drm_panel *panel) 140 { 141 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 142 int ret; 143 144 if (sharp_nt->prepared) 145 return 0; 146 147 ret = regulator_enable(sharp_nt->supply); 148 if (ret < 0) 149 return ret; 150 151 msleep(20); 152 153 if (sharp_nt->reset_gpio) { 154 gpiod_set_value(sharp_nt->reset_gpio, 1); 155 msleep(1); 156 gpiod_set_value(sharp_nt->reset_gpio, 0); 157 msleep(1); 158 gpiod_set_value(sharp_nt->reset_gpio, 1); 159 msleep(10); 160 } 161 162 ret = sharp_nt_panel_init(sharp_nt); 163 if (ret < 0) { 164 dev_err(panel->dev, "failed to init panel: %d\n", ret); 165 goto poweroff; 166 } 167 168 ret = sharp_nt_panel_on(sharp_nt); 169 if (ret < 0) { 170 dev_err(panel->dev, "failed to set panel on: %d\n", ret); 171 goto poweroff; 172 } 173 174 sharp_nt->prepared = true; 175 176 return 0; 177 178 poweroff: 179 regulator_disable(sharp_nt->supply); 180 if (sharp_nt->reset_gpio) 181 gpiod_set_value(sharp_nt->reset_gpio, 0); 182 return ret; 183 } 184 185 static int sharp_nt_panel_enable(struct drm_panel *panel) 186 { 187 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 188 189 if (sharp_nt->enabled) 190 return 0; 191 192 backlight_enable(sharp_nt->backlight); 193 194 sharp_nt->enabled = true; 195 196 return 0; 197 } 198 199 static const struct drm_display_mode default_mode = { 200 .clock = 41118, 201 .hdisplay = 540, 202 .hsync_start = 540 + 48, 203 .hsync_end = 540 + 48 + 80, 204 .htotal = 540 + 48 + 80 + 32, 205 .vdisplay = 960, 206 .vsync_start = 960 + 3, 207 .vsync_end = 960 + 3 + 15, 208 .vtotal = 960 + 3 + 15 + 1, 209 .vrefresh = 60, 210 }; 211 212 static int sharp_nt_panel_get_modes(struct drm_panel *panel) 213 { 214 struct drm_display_mode *mode; 215 216 mode = drm_mode_duplicate(panel->drm, &default_mode); 217 if (!mode) { 218 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", 219 default_mode.hdisplay, default_mode.vdisplay, 220 default_mode.vrefresh); 221 return -ENOMEM; 222 } 223 224 drm_mode_set_name(mode); 225 226 drm_mode_probed_add(panel->connector, mode); 227 228 panel->connector->display_info.width_mm = 54; 229 panel->connector->display_info.height_mm = 95; 230 231 return 1; 232 } 233 234 static const struct drm_panel_funcs sharp_nt_panel_funcs = { 235 .disable = sharp_nt_panel_disable, 236 .unprepare = sharp_nt_panel_unprepare, 237 .prepare = sharp_nt_panel_prepare, 238 .enable = sharp_nt_panel_enable, 239 .get_modes = sharp_nt_panel_get_modes, 240 }; 241 242 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) 243 { 244 struct device *dev = &sharp_nt->dsi->dev; 245 246 sharp_nt->mode = &default_mode; 247 248 sharp_nt->supply = devm_regulator_get(dev, "avdd"); 249 if (IS_ERR(sharp_nt->supply)) 250 return PTR_ERR(sharp_nt->supply); 251 252 sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 253 if (IS_ERR(sharp_nt->reset_gpio)) { 254 dev_err(dev, "cannot get reset-gpios %ld\n", 255 PTR_ERR(sharp_nt->reset_gpio)); 256 sharp_nt->reset_gpio = NULL; 257 } else { 258 gpiod_set_value(sharp_nt->reset_gpio, 0); 259 } 260 261 sharp_nt->backlight = devm_of_find_backlight(dev); 262 263 if (IS_ERR(sharp_nt->backlight)) 264 return PTR_ERR(sharp_nt->backlight); 265 266 drm_panel_init(&sharp_nt->base); 267 sharp_nt->base.funcs = &sharp_nt_panel_funcs; 268 sharp_nt->base.dev = &sharp_nt->dsi->dev; 269 270 return drm_panel_add(&sharp_nt->base); 271 } 272 273 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) 274 { 275 if (sharp_nt->base.dev) 276 drm_panel_remove(&sharp_nt->base); 277 } 278 279 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) 280 { 281 struct sharp_nt_panel *sharp_nt; 282 int ret; 283 284 dsi->lanes = 2; 285 dsi->format = MIPI_DSI_FMT_RGB888; 286 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | 287 MIPI_DSI_MODE_VIDEO_HSE | 288 MIPI_DSI_CLOCK_NON_CONTINUOUS | 289 MIPI_DSI_MODE_EOT_PACKET; 290 291 sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL); 292 if (!sharp_nt) 293 return -ENOMEM; 294 295 mipi_dsi_set_drvdata(dsi, sharp_nt); 296 297 sharp_nt->dsi = dsi; 298 299 ret = sharp_nt_panel_add(sharp_nt); 300 if (ret < 0) 301 return ret; 302 303 return mipi_dsi_attach(dsi); 304 } 305 306 static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi) 307 { 308 struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); 309 int ret; 310 311 ret = sharp_nt_panel_disable(&sharp_nt->base); 312 if (ret < 0) 313 dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); 314 315 ret = mipi_dsi_detach(dsi); 316 if (ret < 0) 317 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); 318 319 sharp_nt_panel_del(sharp_nt); 320 321 return 0; 322 } 323 324 static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi) 325 { 326 struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); 327 328 sharp_nt_panel_disable(&sharp_nt->base); 329 } 330 331 static const struct of_device_id sharp_nt_of_match[] = { 332 { .compatible = "sharp,ls043t1le01-qhd", }, 333 { } 334 }; 335 MODULE_DEVICE_TABLE(of, sharp_nt_of_match); 336 337 static struct mipi_dsi_driver sharp_nt_panel_driver = { 338 .driver = { 339 .name = "panel-sharp-ls043t1le01-qhd", 340 .of_match_table = sharp_nt_of_match, 341 }, 342 .probe = sharp_nt_panel_probe, 343 .remove = sharp_nt_panel_remove, 344 .shutdown = sharp_nt_panel_shutdown, 345 }; 346 module_mipi_dsi_driver(sharp_nt_panel_driver); 347 348 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>"); 349 MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver"); 350 MODULE_LICENSE("GPL v2"); 351