Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 403 lines 9.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * DRM driver for the HX8357D LCD controller 4 * 5 * Copyright 2018 Broadcom 6 * Copyright 2018 David Lechner <david@lechnology.com> 7 * Copyright 2016 Noralf Trønnes 8 * Copyright (C) 2015 Adafruit Industries 9 * Copyright (C) 2013 Christian Vogelgsang 10 */ 11 12#include <linux/backlight.h> 13#include <linux/delay.h> 14#include <linux/gpio/consumer.h> 15#include <linux/module.h> 16#include <linux/property.h> 17#include <linux/spi/spi.h> 18 19#include <drm/clients/drm_client_setup.h> 20#include <drm/drm_atomic_helper.h> 21#include <drm/drm_drv.h> 22#include <drm/drm_fbdev_dma.h> 23#include <drm/drm_gem_atomic_helper.h> 24#include <drm/drm_gem_dma_helper.h> 25#include <drm/drm_managed.h> 26#include <drm/drm_mipi_dbi.h> 27#include <drm/drm_modeset_helper.h> 28#include <drm/drm_print.h> 29#include <video/mipi_display.h> 30 31#define HX8357D_SETOSC 0xb0 32#define HX8357D_SETPOWER 0xb1 33#define HX8357D_SETRGB 0xb3 34#define HX8357D_SETCYC 0xb3 35#define HX8357D_SETCOM 0xb6 36#define HX8357D_SETEXTC 0xb9 37#define HX8357D_SETSTBA 0xc0 38#define HX8357D_SETPANEL 0xcc 39#define HX8357D_SETGAMMA 0xe0 40 41#define HX8357D_MADCTL_MY 0x80 42#define HX8357D_MADCTL_MX 0x40 43#define HX8357D_MADCTL_MV 0x20 44#define HX8357D_MADCTL_ML 0x10 45#define HX8357D_MADCTL_RGB 0x00 46#define HX8357D_MADCTL_BGR 0x08 47#define HX8357D_MADCTL_MH 0x04 48 49struct hx8357d_device { 50 struct mipi_dbi_dev dbidev; 51 52 struct drm_plane plane; 53 struct drm_crtc crtc; 54 struct drm_encoder encoder; 55 struct drm_connector connector; 56}; 57 58static struct hx8357d_device *to_hx8357d_device(struct drm_device *dev) 59{ 60 return container_of(drm_to_mipi_dbi_dev(dev), struct hx8357d_device, dbidev); 61} 62 63static const u32 hx8357d_plane_formats[] = { 64 DRM_MIPI_DBI_PLANE_FORMATS, 65}; 66 67static const u64 hx8357d_plane_format_modifiers[] = { 68 DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, 69}; 70 71static const struct drm_plane_helper_funcs hx8357d_plane_helper_funcs = { 72 DRM_MIPI_DBI_PLANE_HELPER_FUNCS, 73}; 74 75static const struct drm_plane_funcs hx8357d_plane_funcs = { 76 DRM_MIPI_DBI_PLANE_FUNCS, 77 .destroy = drm_plane_cleanup, 78}; 79 80static void hx8357d_crtc_helper_atomic_enable(struct drm_crtc *crtc, 81 struct drm_atomic_state *state) 82{ 83 struct drm_device *drm = crtc->dev; 84 struct hx8357d_device *hx8357d = to_hx8357d_device(drm); 85 struct mipi_dbi_dev *dbidev = &hx8357d->dbidev; 86 struct mipi_dbi *dbi = &dbidev->dbi; 87 u8 addr_mode; 88 int ret, idx; 89 90 if (!drm_dev_enter(drm, &idx)) 91 return; 92 93 DRM_DEBUG_KMS("\n"); 94 95 ret = mipi_dbi_poweron_conditional_reset(dbidev); 96 if (ret < 0) 97 goto out_exit; 98 if (ret == 1) 99 goto out_enable; 100 101 /* setextc */ 102 mipi_dbi_command(dbi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57); 103 msleep(150); 104 105 /* setRGB which also enables SDO */ 106 mipi_dbi_command(dbi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06); 107 108 /* -1.52V */ 109 mipi_dbi_command(dbi, HX8357D_SETCOM, 0x25); 110 111 /* Normal mode 70Hz, Idle mode 55 Hz */ 112 mipi_dbi_command(dbi, HX8357D_SETOSC, 0x68); 113 114 /* Set Panel - BGR, Gate direction swapped */ 115 mipi_dbi_command(dbi, HX8357D_SETPANEL, 0x05); 116 117 mipi_dbi_command(dbi, HX8357D_SETPOWER, 118 0x00, /* Not deep standby */ 119 0x15, /* BT */ 120 0x1C, /* VSPR */ 121 0x1C, /* VSNR */ 122 0x83, /* AP */ 123 0xAA); /* FS */ 124 125 mipi_dbi_command(dbi, HX8357D_SETSTBA, 126 0x50, /* OPON normal */ 127 0x50, /* OPON idle */ 128 0x01, /* STBA */ 129 0x3C, /* STBA */ 130 0x1E, /* STBA */ 131 0x08); /* GEN */ 132 133 mipi_dbi_command(dbi, HX8357D_SETCYC, 134 0x02, /* NW 0x02 */ 135 0x40, /* RTN */ 136 0x00, /* DIV */ 137 0x2A, /* DUM */ 138 0x2A, /* DUM */ 139 0x0D, /* GDON */ 140 0x78); /* GDOFF */ 141 142 mipi_dbi_command(dbi, HX8357D_SETGAMMA, 143 0x02, 144 0x0A, 145 0x11, 146 0x1d, 147 0x23, 148 0x35, 149 0x41, 150 0x4b, 151 0x4b, 152 0x42, 153 0x3A, 154 0x27, 155 0x1B, 156 0x08, 157 0x09, 158 0x03, 159 0x02, 160 0x0A, 161 0x11, 162 0x1d, 163 0x23, 164 0x35, 165 0x41, 166 0x4b, 167 0x4b, 168 0x42, 169 0x3A, 170 0x27, 171 0x1B, 172 0x08, 173 0x09, 174 0x03, 175 0x00, 176 0x01); 177 178 /* 16 bit */ 179 mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 180 MIPI_DCS_PIXEL_FMT_16BIT); 181 182 /* TE off */ 183 mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_ON, 0x00); 184 185 /* tear line */ 186 mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02); 187 188 /* Exit Sleep */ 189 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 190 msleep(150); 191 192 /* display on */ 193 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); 194 usleep_range(5000, 7000); 195 196out_enable: 197 switch (dbidev->rotation) { 198 default: 199 addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY; 200 break; 201 case 90: 202 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY; 203 break; 204 case 180: 205 addr_mode = 0; 206 break; 207 case 270: 208 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX; 209 break; 210 } 211 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); 212 213 backlight_enable(dbidev->backlight); 214out_exit: 215 drm_dev_exit(idx); 216} 217 218static const struct drm_crtc_helper_funcs hx8357d_crtc_helper_funcs = { 219 DRM_MIPI_DBI_CRTC_HELPER_FUNCS, 220 .atomic_enable = hx8357d_crtc_helper_atomic_enable, 221}; 222 223static const struct drm_crtc_funcs hx8357d_crtc_funcs = { 224 DRM_MIPI_DBI_CRTC_FUNCS, 225 .destroy = drm_crtc_cleanup, 226}; 227 228static const struct drm_encoder_funcs hx8357d_encoder_funcs = { 229 .destroy = drm_encoder_cleanup, 230}; 231 232static const struct drm_connector_helper_funcs hx8357d_connector_helper_funcs = { 233 DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, 234}; 235 236static const struct drm_connector_funcs hx8357d_connector_funcs = { 237 DRM_MIPI_DBI_CONNECTOR_FUNCS, 238 .destroy = drm_connector_cleanup, 239}; 240 241static const struct drm_mode_config_helper_funcs hx8357d_mode_config_helper_funcs = { 242 DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, 243}; 244 245static const struct drm_mode_config_funcs hx8357d_mode_config_funcs = { 246 DRM_MIPI_DBI_MODE_CONFIG_FUNCS, 247}; 248 249static const struct drm_display_mode yx350hv15_mode = { 250 DRM_SIMPLE_MODE(320, 480, 60, 75), 251}; 252 253DEFINE_DRM_GEM_DMA_FOPS(hx8357d_fops); 254 255static const struct drm_driver hx8357d_driver = { 256 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 257 .fops = &hx8357d_fops, 258 DRM_GEM_DMA_DRIVER_OPS_VMAP, 259 DRM_FBDEV_DMA_DRIVER_OPS, 260 .debugfs_init = mipi_dbi_debugfs_init, 261 .name = "hx8357d", 262 .desc = "HX8357D", 263 .major = 1, 264 .minor = 0, 265}; 266 267static const struct of_device_id hx8357d_of_match[] = { 268 { .compatible = "adafruit,yx350hv15" }, 269 { } 270}; 271MODULE_DEVICE_TABLE(of, hx8357d_of_match); 272 273static const struct spi_device_id hx8357d_id[] = { 274 { "yx350hv15", 0 }, 275 { } 276}; 277MODULE_DEVICE_TABLE(spi, hx8357d_id); 278 279static int hx8357d_probe(struct spi_device *spi) 280{ 281 struct device *dev = &spi->dev; 282 struct hx8357d_device *hx8357d; 283 struct mipi_dbi_dev *dbidev; 284 struct drm_device *drm; 285 struct gpio_desc *dc; 286 struct drm_plane *plane; 287 struct drm_crtc *crtc; 288 struct drm_encoder *encoder; 289 struct drm_connector *connector; 290 u32 rotation = 0; 291 int ret; 292 293 hx8357d = devm_drm_dev_alloc(dev, &hx8357d_driver, struct hx8357d_device, dbidev.drm); 294 if (IS_ERR(hx8357d)) 295 return PTR_ERR(hx8357d); 296 dbidev = &hx8357d->dbidev; 297 drm = &dbidev->drm; 298 299 dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); 300 if (IS_ERR(dc)) 301 return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n"); 302 303 dbidev->backlight = devm_of_find_backlight(dev); 304 if (IS_ERR(dbidev->backlight)) 305 return PTR_ERR(dbidev->backlight); 306 307 device_property_read_u32(dev, "rotation", &rotation); 308 309 ret = mipi_dbi_spi_init(spi, &dbidev->dbi, dc); 310 if (ret) 311 return ret; 312 313 ret = drm_mipi_dbi_dev_init(dbidev, &yx350hv15_mode, hx8357d_plane_formats[0], 314 rotation, 0); 315 if (ret) 316 return ret; 317 318 ret = drmm_mode_config_init(drm); 319 if (ret) 320 return ret; 321 322 drm->mode_config.min_width = dbidev->mode.hdisplay; 323 drm->mode_config.max_width = dbidev->mode.hdisplay; 324 drm->mode_config.min_height = dbidev->mode.vdisplay; 325 drm->mode_config.max_height = dbidev->mode.vdisplay; 326 drm->mode_config.funcs = &hx8357d_mode_config_funcs; 327 drm->mode_config.preferred_depth = 16; 328 drm->mode_config.helper_private = &hx8357d_mode_config_helper_funcs; 329 330 plane = &hx8357d->plane; 331 ret = drm_universal_plane_init(drm, plane, 0, &hx8357d_plane_funcs, 332 hx8357d_plane_formats, ARRAY_SIZE(hx8357d_plane_formats), 333 hx8357d_plane_format_modifiers, 334 DRM_PLANE_TYPE_PRIMARY, NULL); 335 if (ret) 336 return ret; 337 drm_plane_helper_add(plane, &hx8357d_plane_helper_funcs); 338 drm_plane_enable_fb_damage_clips(plane); 339 340 crtc = &hx8357d->crtc; 341 ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &hx8357d_crtc_funcs, NULL); 342 if (ret) 343 return ret; 344 drm_crtc_helper_add(crtc, &hx8357d_crtc_helper_funcs); 345 346 encoder = &hx8357d->encoder; 347 ret = drm_encoder_init(drm, encoder, &hx8357d_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); 348 if (ret) 349 return ret; 350 encoder->possible_crtcs = drm_crtc_mask(crtc); 351 352 connector = &hx8357d->connector; 353 ret = drm_connector_init(drm, connector, &hx8357d_connector_funcs, 354 DRM_MODE_CONNECTOR_SPI); 355 if (ret) 356 return ret; 357 drm_connector_helper_add(connector, &hx8357d_connector_helper_funcs); 358 359 ret = drm_connector_attach_encoder(connector, encoder); 360 if (ret) 361 return ret; 362 363 drm_mode_config_reset(drm); 364 365 ret = drm_dev_register(drm, 0); 366 if (ret) 367 return ret; 368 369 spi_set_drvdata(spi, drm); 370 371 drm_client_setup(drm, NULL); 372 373 return 0; 374} 375 376static void hx8357d_remove(struct spi_device *spi) 377{ 378 struct drm_device *drm = spi_get_drvdata(spi); 379 380 drm_dev_unplug(drm); 381 drm_atomic_helper_shutdown(drm); 382} 383 384static void hx8357d_shutdown(struct spi_device *spi) 385{ 386 drm_atomic_helper_shutdown(spi_get_drvdata(spi)); 387} 388 389static struct spi_driver hx8357d_spi_driver = { 390 .driver = { 391 .name = "hx8357d", 392 .of_match_table = hx8357d_of_match, 393 }, 394 .id_table = hx8357d_id, 395 .probe = hx8357d_probe, 396 .remove = hx8357d_remove, 397 .shutdown = hx8357d_shutdown, 398}; 399module_spi_driver(hx8357d_spi_driver); 400 401MODULE_DESCRIPTION("HX8357D DRM driver"); 402MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); 403MODULE_LICENSE("GPL");