1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <linux/backlight.h> 4 #include <linux/delay.h> 5 #include <linux/gpio/consumer.h> 6 #include <linux/module.h> 7 #include <linux/property.h> 8 #include <linux/spi/spi.h> 9 10 #include <drm/clients/drm_client_setup.h> 11 #include <drm/drm_atomic_helper.h> 12 #include <drm/drm_drv.h> 13 #include <drm/drm_fbdev_dma.h> 14 #include <drm/drm_gem_atomic_helper.h> 15 #include <drm/drm_gem_dma_helper.h> 16 #include <drm/drm_mipi_dbi.h> 17 #include <drm/drm_modeset_helper.h> 18 #include <drm/drm_print.h> 19 20 #include <video/mipi_display.h> 21 22 #define ILI9163_FRMCTR1 0xb1 23 24 #define ILI9163_PWCTRL1 0xc0 25 #define ILI9163_PWCTRL2 0xc1 26 #define ILI9163_VMCTRL1 0xc5 27 #define ILI9163_VMCTRL2 0xc7 28 #define ILI9163_PWCTRLA 0xcb 29 #define ILI9163_PWCTRLB 0xcf 30 31 #define ILI9163_EN3GAM 0xf2 32 33 #define ILI9163_MADCTL_BGR BIT(3) 34 #define ILI9163_MADCTL_MV BIT(5) 35 #define ILI9163_MADCTL_MX BIT(6) 36 #define ILI9163_MADCTL_MY BIT(7) 37 38 struct ili9163_device { 39 struct mipi_dbi_dev dbidev; 40 41 struct drm_plane plane; 42 struct drm_crtc crtc; 43 struct drm_encoder encoder; 44 struct drm_connector connector; 45 }; 46 47 static struct ili9163_device *to_ili9163_device(struct drm_device *dev) 48 { 49 return container_of(drm_to_mipi_dbi_dev(dev), struct ili9163_device, dbidev); 50 } 51 52 static const u32 ili9163_plane_formats[] = { 53 DRM_MIPI_DBI_PLANE_FORMATS, 54 }; 55 56 static const u64 ili9163_plane_format_modifiers[] = { 57 DRM_MIPI_DBI_PLANE_FORMAT_MODIFIERS, 58 }; 59 60 static const struct drm_plane_helper_funcs ili9163_plane_helper_funcs = { 61 DRM_MIPI_DBI_PLANE_HELPER_FUNCS, 62 }; 63 64 static const struct drm_plane_funcs ili9163_plane_funcs = { 65 DRM_MIPI_DBI_PLANE_FUNCS, 66 .destroy = drm_plane_cleanup, 67 }; 68 69 static void ili9163_crtc_helper_atomic_enable(struct drm_crtc *crtc, 70 struct drm_atomic_state *state) 71 { 72 struct drm_device *drm = crtc->dev; 73 struct ili9163_device *ili9163 = to_ili9163_device(drm); 74 struct mipi_dbi_dev *dbidev = &ili9163->dbidev; 75 struct mipi_dbi *dbi = &dbidev->dbi; 76 u8 addr_mode; 77 int ret, idx; 78 79 if (!drm_dev_enter(drm, &idx)) 80 return; 81 82 DRM_DEBUG_KMS("\n"); 83 84 ret = mipi_dbi_poweron_conditional_reset(dbidev); 85 if (ret < 0) 86 goto out_exit; 87 if (ret == 1) 88 goto out_enable; 89 90 /* Gamma */ 91 mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, 0x04); 92 mipi_dbi_command(dbi, ILI9163_EN3GAM, 0x00); 93 94 /* Frame Rate */ 95 mipi_dbi_command(dbi, ILI9163_FRMCTR1, 0x0a, 0x14); 96 97 /* Power Control */ 98 mipi_dbi_command(dbi, ILI9163_PWCTRL1, 0x0a, 0x00); 99 mipi_dbi_command(dbi, ILI9163_PWCTRL2, 0x02); 100 101 /* VCOM */ 102 mipi_dbi_command(dbi, ILI9163_VMCTRL1, 0x2f, 0x3e); 103 mipi_dbi_command(dbi, ILI9163_VMCTRL2, 0x40); 104 105 /* Memory Access Control */ 106 mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); 107 108 mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 109 msleep(100); 110 111 mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); 112 msleep(100); 113 114 out_enable: 115 switch (dbidev->rotation) { 116 default: 117 addr_mode = ILI9163_MADCTL_MX | ILI9163_MADCTL_MY; 118 break; 119 case 90: 120 addr_mode = ILI9163_MADCTL_MX | ILI9163_MADCTL_MV; 121 break; 122 case 180: 123 addr_mode = 0; 124 break; 125 case 270: 126 addr_mode = ILI9163_MADCTL_MY | ILI9163_MADCTL_MV; 127 break; 128 } 129 addr_mode |= ILI9163_MADCTL_BGR; 130 mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); 131 132 backlight_enable(dbidev->backlight); 133 out_exit: 134 drm_dev_exit(idx); 135 } 136 137 static const struct drm_crtc_helper_funcs ili9163_crtc_helper_funcs = { 138 DRM_MIPI_DBI_CRTC_HELPER_FUNCS, 139 .atomic_enable = ili9163_crtc_helper_atomic_enable, 140 }; 141 142 static const struct drm_crtc_funcs ili9163_crtc_funcs = { 143 DRM_MIPI_DBI_CRTC_FUNCS, 144 .destroy = drm_crtc_cleanup, 145 }; 146 147 static const struct drm_encoder_funcs ili9163_encoder_funcs = { 148 .destroy = drm_encoder_cleanup, 149 }; 150 151 static const struct drm_connector_helper_funcs ili9163_connector_helper_funcs = { 152 DRM_MIPI_DBI_CONNECTOR_HELPER_FUNCS, 153 }; 154 155 static const struct drm_connector_funcs ili9163_connector_funcs = { 156 DRM_MIPI_DBI_CONNECTOR_FUNCS, 157 .destroy = drm_connector_cleanup, 158 }; 159 160 static const struct drm_mode_config_helper_funcs ili9163_mode_config_helper_funcs = { 161 DRM_MIPI_DBI_MODE_CONFIG_HELPER_FUNCS, 162 }; 163 164 static const struct drm_mode_config_funcs ili9163_mode_config_funcs = { 165 DRM_MIPI_DBI_MODE_CONFIG_FUNCS, 166 }; 167 168 static const struct drm_display_mode yx240qv29_mode = { 169 DRM_SIMPLE_MODE(128, 160, 28, 35), 170 }; 171 172 DEFINE_DRM_GEM_DMA_FOPS(ili9163_fops); 173 174 static struct drm_driver ili9163_driver = { 175 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 176 .fops = &ili9163_fops, 177 DRM_GEM_DMA_DRIVER_OPS_VMAP, 178 DRM_FBDEV_DMA_DRIVER_OPS, 179 .debugfs_init = mipi_dbi_debugfs_init, 180 .name = "ili9163", 181 .desc = "Ilitek ILI9163", 182 .major = 1, 183 .minor = 0, 184 }; 185 186 static const struct of_device_id ili9163_of_match[] = { 187 { .compatible = "newhaven,1.8-128160EF" }, 188 { } 189 }; 190 MODULE_DEVICE_TABLE(of, ili9163_of_match); 191 192 static const struct spi_device_id ili9163_id[] = { 193 { "nhd-1.8-128160EF", 0 }, 194 { } 195 }; 196 MODULE_DEVICE_TABLE(spi, ili9163_id); 197 198 static int ili9163_probe(struct spi_device *spi) 199 { 200 struct device *dev = &spi->dev; 201 struct ili9163_device *ili9163; 202 struct mipi_dbi_dev *dbidev; 203 struct drm_device *drm; 204 struct mipi_dbi *dbi; 205 struct gpio_desc *dc; 206 struct drm_plane *plane; 207 struct drm_crtc *crtc; 208 struct drm_encoder *encoder; 209 struct drm_connector *connector; 210 u32 rotation = 0; 211 int ret; 212 213 ili9163 = devm_drm_dev_alloc(dev, &ili9163_driver, struct ili9163_device, dbidev.drm); 214 if (IS_ERR(ili9163)) 215 return PTR_ERR(ili9163); 216 dbidev = &ili9163->dbidev; 217 dbi = &dbidev->dbi; 218 drm = &dbidev->drm; 219 220 spi_set_drvdata(spi, drm); 221 222 dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 223 if (IS_ERR(dbi->reset)) { 224 DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); 225 return PTR_ERR(dbi->reset); 226 } 227 228 dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW); 229 if (IS_ERR(dc)) { 230 DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); 231 return PTR_ERR(dc); 232 } 233 234 dbidev->backlight = devm_of_find_backlight(dev); 235 if (IS_ERR(dbidev->backlight)) 236 return PTR_ERR(dbidev->backlight); 237 238 device_property_read_u32(dev, "rotation", &rotation); 239 240 ret = mipi_dbi_spi_init(spi, dbi, dc); 241 if (ret) 242 return ret; 243 244 ret = drm_mipi_dbi_dev_init(dbidev, &yx240qv29_mode, ili9163_plane_formats[0], 245 rotation, 0); 246 if (ret) 247 return ret; 248 249 ret = drmm_mode_config_init(drm); 250 if (ret) 251 return ret; 252 253 drm->mode_config.min_width = dbidev->mode.hdisplay; 254 drm->mode_config.max_width = dbidev->mode.hdisplay; 255 drm->mode_config.min_height = dbidev->mode.vdisplay; 256 drm->mode_config.max_height = dbidev->mode.vdisplay; 257 drm->mode_config.funcs = &ili9163_mode_config_funcs; 258 drm->mode_config.preferred_depth = 16; 259 drm->mode_config.helper_private = &ili9163_mode_config_helper_funcs; 260 261 plane = &ili9163->plane; 262 ret = drm_universal_plane_init(drm, plane, 0, &ili9163_plane_funcs, 263 ili9163_plane_formats, ARRAY_SIZE(ili9163_plane_formats), 264 ili9163_plane_format_modifiers, 265 DRM_PLANE_TYPE_PRIMARY, NULL); 266 if (ret) 267 return ret; 268 drm_plane_helper_add(plane, &ili9163_plane_helper_funcs); 269 drm_plane_enable_fb_damage_clips(plane); 270 271 crtc = &ili9163->crtc; 272 ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, &ili9163_crtc_funcs, NULL); 273 if (ret) 274 return ret; 275 drm_crtc_helper_add(crtc, &ili9163_crtc_helper_funcs); 276 277 encoder = &ili9163->encoder; 278 ret = drm_encoder_init(drm, encoder, &ili9163_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); 279 if (ret) 280 return ret; 281 encoder->possible_crtcs = drm_crtc_mask(crtc); 282 283 connector = &ili9163->connector; 284 ret = drm_connector_init(drm, connector, &ili9163_connector_funcs, 285 DRM_MODE_CONNECTOR_SPI); 286 if (ret) 287 return ret; 288 drm_connector_helper_add(connector, &ili9163_connector_helper_funcs); 289 290 ret = drm_connector_attach_encoder(connector, encoder); 291 if (ret) 292 return ret; 293 294 drm_mode_config_reset(drm); 295 296 ret = drm_dev_register(drm, 0); 297 if (ret) 298 return ret; 299 300 drm_client_setup(drm, NULL); 301 302 return 0; 303 } 304 305 static void ili9163_remove(struct spi_device *spi) 306 { 307 struct drm_device *drm = spi_get_drvdata(spi); 308 309 drm_dev_unplug(drm); 310 drm_atomic_helper_shutdown(drm); 311 } 312 313 static void ili9163_shutdown(struct spi_device *spi) 314 { 315 drm_atomic_helper_shutdown(spi_get_drvdata(spi)); 316 } 317 318 static struct spi_driver ili9163_spi_driver = { 319 .driver = { 320 .name = "ili9163", 321 .of_match_table = ili9163_of_match, 322 }, 323 .id_table = ili9163_id, 324 .probe = ili9163_probe, 325 .remove = ili9163_remove, 326 .shutdown = ili9163_shutdown, 327 }; 328 module_spi_driver(ili9163_spi_driver); 329 330 MODULE_DESCRIPTION("Ilitek ILI9163 DRM driver"); 331 MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>"); 332 MODULE_LICENSE("GPL"); 333