1043386a0SNoralf Trønnes // SPDX-License-Identifier: GPL-2.0-or-later 2043386a0SNoralf Trønnes /* 3043386a0SNoralf Trønnes * DRM driver for Sitronix ST7586 panels 4043386a0SNoralf Trønnes * 5043386a0SNoralf Trønnes * Copyright 2017 David Lechner <david@lechnology.com> 6043386a0SNoralf Trønnes */ 7043386a0SNoralf Trønnes 8043386a0SNoralf Trønnes #include <linux/delay.h> 9043386a0SNoralf Trønnes #include <linux/dma-buf.h> 10043386a0SNoralf Trønnes #include <linux/gpio/consumer.h> 11043386a0SNoralf Trønnes #include <linux/module.h> 12043386a0SNoralf Trønnes #include <linux/property.h> 13043386a0SNoralf Trønnes #include <linux/spi/spi.h> 14043386a0SNoralf Trønnes #include <video/mipi_display.h> 15043386a0SNoralf Trønnes 16043386a0SNoralf Trønnes #include <drm/drm_atomic_helper.h> 17043386a0SNoralf Trønnes #include <drm/drm_damage_helper.h> 18043386a0SNoralf Trønnes #include <drm/drm_drv.h> 19043386a0SNoralf Trønnes #include <drm/drm_fb_cma_helper.h> 20043386a0SNoralf Trønnes #include <drm/drm_fb_helper.h> 21043386a0SNoralf Trønnes #include <drm/drm_format_helper.h> 22043386a0SNoralf Trønnes #include <drm/drm_gem_cma_helper.h> 23043386a0SNoralf Trønnes #include <drm/drm_gem_framebuffer_helper.h> 24043386a0SNoralf Trønnes #include <drm/drm_mipi_dbi.h> 25043386a0SNoralf Trønnes #include <drm/drm_rect.h> 26043386a0SNoralf Trønnes #include <drm/drm_vblank.h> 27043386a0SNoralf Trønnes 28043386a0SNoralf Trønnes /* controller-specific commands */ 29043386a0SNoralf Trønnes #define ST7586_DISP_MODE_GRAY 0x38 30043386a0SNoralf Trønnes #define ST7586_DISP_MODE_MONO 0x39 31043386a0SNoralf Trønnes #define ST7586_ENABLE_DDRAM 0x3a 32043386a0SNoralf Trønnes #define ST7586_SET_DISP_DUTY 0xb0 33043386a0SNoralf Trønnes #define ST7586_SET_PART_DISP 0xb4 34043386a0SNoralf Trønnes #define ST7586_SET_NLINE_INV 0xb5 35043386a0SNoralf Trønnes #define ST7586_SET_VOP 0xc0 36043386a0SNoralf Trønnes #define ST7586_SET_BIAS_SYSTEM 0xc3 37043386a0SNoralf Trønnes #define ST7586_SET_BOOST_LEVEL 0xc4 38043386a0SNoralf Trønnes #define ST7586_SET_VOP_OFFSET 0xc7 39043386a0SNoralf Trønnes #define ST7586_ENABLE_ANALOG 0xd0 40043386a0SNoralf Trønnes #define ST7586_AUTO_READ_CTRL 0xd7 41043386a0SNoralf Trønnes #define ST7586_OTP_RW_CTRL 0xe0 42043386a0SNoralf Trønnes #define ST7586_OTP_CTRL_OUT 0xe1 43043386a0SNoralf Trønnes #define ST7586_OTP_READ 0xe3 44043386a0SNoralf Trønnes 45043386a0SNoralf Trønnes #define ST7586_DISP_CTRL_MX BIT(6) 46043386a0SNoralf Trønnes #define ST7586_DISP_CTRL_MY BIT(7) 47043386a0SNoralf Trønnes 48043386a0SNoralf Trønnes /* 49043386a0SNoralf Trønnes * The ST7586 controller has an unusual pixel format where 2bpp grayscale is 50043386a0SNoralf Trønnes * packed 3 pixels per byte with the first two pixels using 3 bits and the 3rd 51043386a0SNoralf Trønnes * pixel using only 2 bits. 52043386a0SNoralf Trønnes * 53043386a0SNoralf Trønnes * | D7 | D6 | D5 || | || 2bpp | 54043386a0SNoralf Trønnes * | (D4) | (D3) | (D2) || D1 | D0 || GRAY | 55043386a0SNoralf Trønnes * +------+------+------++------+------++------+ 56043386a0SNoralf Trønnes * | 1 | 1 | 1 || 1 | 1 || 0 0 | black 57043386a0SNoralf Trønnes * | 1 | 0 | 0 || 1 | 0 || 0 1 | dark gray 58043386a0SNoralf Trønnes * | 0 | 1 | 0 || 0 | 1 || 1 0 | light gray 59043386a0SNoralf Trønnes * | 0 | 0 | 0 || 0 | 0 || 1 1 | white 60043386a0SNoralf Trønnes */ 61043386a0SNoralf Trønnes 62043386a0SNoralf Trønnes static const u8 st7586_lookup[] = { 0x7, 0x4, 0x2, 0x0 }; 63043386a0SNoralf Trønnes 64043386a0SNoralf Trønnes static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, 65043386a0SNoralf Trønnes struct drm_framebuffer *fb, 66043386a0SNoralf Trønnes struct drm_rect *clip) 67043386a0SNoralf Trønnes { 68043386a0SNoralf Trønnes size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1); 69043386a0SNoralf Trønnes unsigned int x, y; 70043386a0SNoralf Trønnes u8 *src, *buf, val; 71043386a0SNoralf Trønnes 72043386a0SNoralf Trønnes buf = kmalloc(len, GFP_KERNEL); 73043386a0SNoralf Trønnes if (!buf) 74043386a0SNoralf Trønnes return; 75043386a0SNoralf Trønnes 76043386a0SNoralf Trønnes drm_fb_xrgb8888_to_gray8(buf, vaddr, fb, clip); 77043386a0SNoralf Trønnes src = buf; 78043386a0SNoralf Trønnes 79043386a0SNoralf Trønnes for (y = clip->y1; y < clip->y2; y++) { 80043386a0SNoralf Trønnes for (x = clip->x1; x < clip->x2; x += 3) { 81043386a0SNoralf Trønnes val = st7586_lookup[*src++ >> 6] << 5; 82043386a0SNoralf Trønnes val |= st7586_lookup[*src++ >> 6] << 2; 83043386a0SNoralf Trønnes val |= st7586_lookup[*src++ >> 6] >> 1; 84043386a0SNoralf Trønnes *dst++ = val; 85043386a0SNoralf Trønnes } 86043386a0SNoralf Trønnes } 87043386a0SNoralf Trønnes 88043386a0SNoralf Trønnes kfree(buf); 89043386a0SNoralf Trønnes } 90043386a0SNoralf Trønnes 91043386a0SNoralf Trønnes static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb, 92043386a0SNoralf Trønnes struct drm_rect *clip) 93043386a0SNoralf Trønnes { 94043386a0SNoralf Trønnes struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 95043386a0SNoralf Trønnes struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; 96043386a0SNoralf Trønnes void *src = cma_obj->vaddr; 97043386a0SNoralf Trønnes int ret = 0; 98043386a0SNoralf Trønnes 99043386a0SNoralf Trønnes if (import_attach) { 100043386a0SNoralf Trønnes ret = dma_buf_begin_cpu_access(import_attach->dmabuf, 101043386a0SNoralf Trønnes DMA_FROM_DEVICE); 102043386a0SNoralf Trønnes if (ret) 103043386a0SNoralf Trønnes return ret; 104043386a0SNoralf Trønnes } 105043386a0SNoralf Trønnes 106043386a0SNoralf Trønnes st7586_xrgb8888_to_gray332(dst, src, fb, clip); 107043386a0SNoralf Trønnes 108043386a0SNoralf Trønnes if (import_attach) 109043386a0SNoralf Trønnes ret = dma_buf_end_cpu_access(import_attach->dmabuf, 110043386a0SNoralf Trønnes DMA_FROM_DEVICE); 111043386a0SNoralf Trønnes 112043386a0SNoralf Trønnes return ret; 113043386a0SNoralf Trønnes } 114043386a0SNoralf Trønnes 115043386a0SNoralf Trønnes static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) 116043386a0SNoralf Trønnes { 117043386a0SNoralf Trønnes struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); 118043386a0SNoralf Trønnes struct mipi_dbi *dbi = &dbidev->dbi; 119043386a0SNoralf Trønnes int start, end, idx, ret = 0; 120043386a0SNoralf Trønnes 121043386a0SNoralf Trønnes if (!dbidev->enabled) 122043386a0SNoralf Trønnes return; 123043386a0SNoralf Trønnes 124043386a0SNoralf Trønnes if (!drm_dev_enter(fb->dev, &idx)) 125043386a0SNoralf Trønnes return; 126043386a0SNoralf Trønnes 127043386a0SNoralf Trønnes /* 3 pixels per byte, so grow clip to nearest multiple of 3 */ 128043386a0SNoralf Trønnes rect->x1 = rounddown(rect->x1, 3); 129043386a0SNoralf Trønnes rect->x2 = roundup(rect->x2, 3); 130043386a0SNoralf Trønnes 131043386a0SNoralf Trønnes DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); 132043386a0SNoralf Trønnes 133043386a0SNoralf Trønnes ret = st7586_buf_copy(dbidev->tx_buf, fb, rect); 134043386a0SNoralf Trønnes if (ret) 135043386a0SNoralf Trønnes goto err_msg; 136043386a0SNoralf Trønnes 137043386a0SNoralf Trønnes /* Pixels are packed 3 per byte */ 138043386a0SNoralf Trønnes start = rect->x1 / 3; 139043386a0SNoralf Trønnes end = rect->x2 / 3; 140043386a0SNoralf Trønnes 141043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 142043386a0SNoralf Trønnes (start >> 8) & 0xFF, start & 0xFF, 143043386a0SNoralf Trønnes (end >> 8) & 0xFF, (end - 1) & 0xFF); 144043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 145043386a0SNoralf Trønnes (rect->y1 >> 8) & 0xFF, rect->y1 & 0xFF, 146043386a0SNoralf Trønnes (rect->y2 >> 8) & 0xFF, (rect->y2 - 1) & 0xFF); 147043386a0SNoralf Trønnes 148043386a0SNoralf Trønnes ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, 149043386a0SNoralf Trønnes (u8 *)dbidev->tx_buf, 150043386a0SNoralf Trønnes (end - start) * (rect->y2 - rect->y1)); 151043386a0SNoralf Trønnes err_msg: 152043386a0SNoralf Trønnes if (ret) 153043386a0SNoralf Trønnes dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); 154043386a0SNoralf Trønnes 155043386a0SNoralf Trønnes drm_dev_exit(idx); 156043386a0SNoralf Trønnes } 157043386a0SNoralf Trønnes 158043386a0SNoralf Trønnes static void st7586_pipe_update(struct drm_simple_display_pipe *pipe, 159043386a0SNoralf Trønnes struct drm_plane_state *old_state) 160043386a0SNoralf Trønnes { 161043386a0SNoralf Trønnes struct drm_plane_state *state = pipe->plane.state; 162043386a0SNoralf Trønnes struct drm_crtc *crtc = &pipe->crtc; 163043386a0SNoralf Trønnes struct drm_rect rect; 164043386a0SNoralf Trønnes 165043386a0SNoralf Trønnes if (drm_atomic_helper_damage_merged(old_state, state, &rect)) 166043386a0SNoralf Trønnes st7586_fb_dirty(state->fb, &rect); 167043386a0SNoralf Trønnes 168043386a0SNoralf Trønnes if (crtc->state->event) { 169043386a0SNoralf Trønnes spin_lock_irq(&crtc->dev->event_lock); 170043386a0SNoralf Trønnes drm_crtc_send_vblank_event(crtc, crtc->state->event); 171043386a0SNoralf Trønnes spin_unlock_irq(&crtc->dev->event_lock); 172043386a0SNoralf Trønnes crtc->state->event = NULL; 173043386a0SNoralf Trønnes } 174043386a0SNoralf Trønnes } 175043386a0SNoralf Trønnes 176043386a0SNoralf Trønnes static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, 177043386a0SNoralf Trønnes struct drm_crtc_state *crtc_state, 178043386a0SNoralf Trønnes struct drm_plane_state *plane_state) 179043386a0SNoralf Trønnes { 180043386a0SNoralf Trønnes struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); 181043386a0SNoralf Trønnes struct drm_framebuffer *fb = plane_state->fb; 182043386a0SNoralf Trønnes struct mipi_dbi *dbi = &dbidev->dbi; 183043386a0SNoralf Trønnes struct drm_rect rect = { 184043386a0SNoralf Trønnes .x1 = 0, 185043386a0SNoralf Trønnes .x2 = fb->width, 186043386a0SNoralf Trønnes .y1 = 0, 187043386a0SNoralf Trønnes .y2 = fb->height, 188043386a0SNoralf Trønnes }; 189043386a0SNoralf Trønnes int idx, ret; 190043386a0SNoralf Trønnes u8 addr_mode; 191043386a0SNoralf Trønnes 192043386a0SNoralf Trønnes if (!drm_dev_enter(pipe->crtc.dev, &idx)) 193043386a0SNoralf Trønnes return; 194043386a0SNoralf Trønnes 195043386a0SNoralf Trønnes DRM_DEBUG_KMS("\n"); 196043386a0SNoralf Trønnes 197043386a0SNoralf Trønnes ret = mipi_dbi_poweron_reset(dbidev); 198043386a0SNoralf Trønnes if (ret) 199043386a0SNoralf Trønnes goto out_exit; 200043386a0SNoralf Trønnes 201043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_AUTO_READ_CTRL, 0x9f); 202043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_OTP_RW_CTRL, 0x00); 203043386a0SNoralf Trønnes 204043386a0SNoralf Trønnes msleep(10); 205043386a0SNoralf Trønnes 206043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_OTP_READ); 207043386a0SNoralf Trønnes 208043386a0SNoralf Trønnes msleep(20); 209043386a0SNoralf Trønnes 210043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_OTP_CTRL_OUT); 211043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 212043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF); 213043386a0SNoralf Trønnes 214043386a0SNoralf Trønnes msleep(50); 215043386a0SNoralf Trønnes 216043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_VOP_OFFSET, 0x00); 217043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_VOP, 0xe3, 0x00); 218043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_BIAS_SYSTEM, 0x02); 219043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_BOOST_LEVEL, 0x04); 220043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_ENABLE_ANALOG, 0x1d); 221043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_NLINE_INV, 0x00); 222043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_DISP_MODE_GRAY); 223043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_ENABLE_DDRAM, 0x02); 224043386a0SNoralf Trønnes 225043386a0SNoralf Trønnes switch (dbidev->rotation) { 226043386a0SNoralf Trønnes default: 227043386a0SNoralf Trønnes addr_mode = 0x00; 228043386a0SNoralf Trønnes break; 229043386a0SNoralf Trønnes case 90: 230043386a0SNoralf Trønnes addr_mode = ST7586_DISP_CTRL_MY; 231043386a0SNoralf Trønnes break; 232043386a0SNoralf Trønnes case 180: 233043386a0SNoralf Trønnes addr_mode = ST7586_DISP_CTRL_MX | ST7586_DISP_CTRL_MY; 234043386a0SNoralf Trønnes break; 235043386a0SNoralf Trønnes case 270: 236043386a0SNoralf Trønnes addr_mode = ST7586_DISP_CTRL_MX; 237043386a0SNoralf Trønnes break; 238043386a0SNoralf Trønnes } 239043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); 240043386a0SNoralf Trønnes 241043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_DISP_DUTY, 0x7f); 242043386a0SNoralf Trønnes mipi_dbi_command(dbi, ST7586_SET_PART_DISP, 0xa0); 243*97ecec8bSJani Nikula mipi_dbi_command(dbi, MIPI_DCS_SET_PARTIAL_ROWS, 0x00, 0x00, 0x00, 0x77); 244043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_EXIT_INVERT_MODE); 245043386a0SNoralf Trønnes 246043386a0SNoralf Trønnes msleep(100); 247043386a0SNoralf Trønnes 248043386a0SNoralf Trønnes dbidev->enabled = true; 249043386a0SNoralf Trønnes st7586_fb_dirty(fb, &rect); 250043386a0SNoralf Trønnes 251043386a0SNoralf Trønnes mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); 252043386a0SNoralf Trønnes out_exit: 253043386a0SNoralf Trønnes drm_dev_exit(idx); 254043386a0SNoralf Trønnes } 255043386a0SNoralf Trønnes 256043386a0SNoralf Trønnes static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe) 257043386a0SNoralf Trønnes { 258043386a0SNoralf Trønnes struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); 259043386a0SNoralf Trønnes 260043386a0SNoralf Trønnes /* 261043386a0SNoralf Trønnes * This callback is not protected by drm_dev_enter/exit since we want to 262043386a0SNoralf Trønnes * turn off the display on regular driver unload. It's highly unlikely 263043386a0SNoralf Trønnes * that the underlying SPI controller is gone should this be called after 264043386a0SNoralf Trønnes * unplug. 265043386a0SNoralf Trønnes */ 266043386a0SNoralf Trønnes 267043386a0SNoralf Trønnes DRM_DEBUG_KMS("\n"); 268043386a0SNoralf Trønnes 269043386a0SNoralf Trønnes if (!dbidev->enabled) 270043386a0SNoralf Trønnes return; 271043386a0SNoralf Trønnes 272043386a0SNoralf Trønnes mipi_dbi_command(&dbidev->dbi, MIPI_DCS_SET_DISPLAY_OFF); 273043386a0SNoralf Trønnes dbidev->enabled = false; 274043386a0SNoralf Trønnes } 275043386a0SNoralf Trønnes 276043386a0SNoralf Trønnes static const u32 st7586_formats[] = { 277043386a0SNoralf Trønnes DRM_FORMAT_XRGB8888, 278043386a0SNoralf Trønnes }; 279043386a0SNoralf Trønnes 280043386a0SNoralf Trønnes static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = { 281043386a0SNoralf Trønnes .enable = st7586_pipe_enable, 282043386a0SNoralf Trønnes .disable = st7586_pipe_disable, 283043386a0SNoralf Trønnes .update = st7586_pipe_update, 284043386a0SNoralf Trønnes .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, 285043386a0SNoralf Trønnes }; 286043386a0SNoralf Trønnes 287043386a0SNoralf Trønnes static const struct drm_display_mode st7586_mode = { 288043386a0SNoralf Trønnes DRM_SIMPLE_MODE(178, 128, 37, 27), 289043386a0SNoralf Trønnes }; 290043386a0SNoralf Trønnes 291043386a0SNoralf Trønnes DEFINE_DRM_GEM_CMA_FOPS(st7586_fops); 292043386a0SNoralf Trønnes 293043386a0SNoralf Trønnes static struct drm_driver st7586_driver = { 294043386a0SNoralf Trønnes .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 295043386a0SNoralf Trønnes .fops = &st7586_fops, 296043386a0SNoralf Trønnes .release = mipi_dbi_release, 297043386a0SNoralf Trønnes DRM_GEM_CMA_VMAP_DRIVER_OPS, 298043386a0SNoralf Trønnes .debugfs_init = mipi_dbi_debugfs_init, 299043386a0SNoralf Trønnes .name = "st7586", 300043386a0SNoralf Trønnes .desc = "Sitronix ST7586", 301043386a0SNoralf Trønnes .date = "20170801", 302043386a0SNoralf Trønnes .major = 1, 303043386a0SNoralf Trønnes .minor = 0, 304043386a0SNoralf Trønnes }; 305043386a0SNoralf Trønnes 306043386a0SNoralf Trønnes static const struct of_device_id st7586_of_match[] = { 307043386a0SNoralf Trønnes { .compatible = "lego,ev3-lcd" }, 308043386a0SNoralf Trønnes {}, 309043386a0SNoralf Trønnes }; 310043386a0SNoralf Trønnes MODULE_DEVICE_TABLE(of, st7586_of_match); 311043386a0SNoralf Trønnes 312043386a0SNoralf Trønnes static const struct spi_device_id st7586_id[] = { 313043386a0SNoralf Trønnes { "ev3-lcd", 0 }, 314043386a0SNoralf Trønnes { }, 315043386a0SNoralf Trønnes }; 316043386a0SNoralf Trønnes MODULE_DEVICE_TABLE(spi, st7586_id); 317043386a0SNoralf Trønnes 318043386a0SNoralf Trønnes static int st7586_probe(struct spi_device *spi) 319043386a0SNoralf Trønnes { 320043386a0SNoralf Trønnes struct device *dev = &spi->dev; 321043386a0SNoralf Trønnes struct mipi_dbi_dev *dbidev; 322043386a0SNoralf Trønnes struct drm_device *drm; 323043386a0SNoralf Trønnes struct mipi_dbi *dbi; 324043386a0SNoralf Trønnes struct gpio_desc *a0; 325043386a0SNoralf Trønnes u32 rotation = 0; 326043386a0SNoralf Trønnes size_t bufsize; 327043386a0SNoralf Trønnes int ret; 328043386a0SNoralf Trønnes 329043386a0SNoralf Trønnes dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL); 330043386a0SNoralf Trønnes if (!dbidev) 331043386a0SNoralf Trønnes return -ENOMEM; 332043386a0SNoralf Trønnes 333043386a0SNoralf Trønnes dbi = &dbidev->dbi; 334043386a0SNoralf Trønnes drm = &dbidev->drm; 335043386a0SNoralf Trønnes ret = devm_drm_dev_init(dev, drm, &st7586_driver); 336043386a0SNoralf Trønnes if (ret) { 337043386a0SNoralf Trønnes kfree(dbidev); 338043386a0SNoralf Trønnes return ret; 339043386a0SNoralf Trønnes } 340043386a0SNoralf Trønnes 341043386a0SNoralf Trønnes drm_mode_config_init(drm); 342043386a0SNoralf Trønnes 343043386a0SNoralf Trønnes bufsize = (st7586_mode.vdisplay + 2) / 3 * st7586_mode.hdisplay; 344043386a0SNoralf Trønnes 345043386a0SNoralf Trønnes dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 346043386a0SNoralf Trønnes if (IS_ERR(dbi->reset)) { 347043386a0SNoralf Trønnes DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); 348043386a0SNoralf Trønnes return PTR_ERR(dbi->reset); 349043386a0SNoralf Trønnes } 350043386a0SNoralf Trønnes 351043386a0SNoralf Trønnes a0 = devm_gpiod_get(dev, "a0", GPIOD_OUT_LOW); 352043386a0SNoralf Trønnes if (IS_ERR(a0)) { 353043386a0SNoralf Trønnes DRM_DEV_ERROR(dev, "Failed to get gpio 'a0'\n"); 354043386a0SNoralf Trønnes return PTR_ERR(a0); 355043386a0SNoralf Trønnes } 356043386a0SNoralf Trønnes 357043386a0SNoralf Trønnes device_property_read_u32(dev, "rotation", &rotation); 358043386a0SNoralf Trønnes 359043386a0SNoralf Trønnes ret = mipi_dbi_spi_init(spi, dbi, a0); 360043386a0SNoralf Trønnes if (ret) 361043386a0SNoralf Trønnes return ret; 362043386a0SNoralf Trønnes 363043386a0SNoralf Trønnes /* Cannot read from this controller via SPI */ 364043386a0SNoralf Trønnes dbi->read_commands = NULL; 365043386a0SNoralf Trønnes 366043386a0SNoralf Trønnes ret = mipi_dbi_dev_init_with_formats(dbidev, &st7586_pipe_funcs, 367043386a0SNoralf Trønnes st7586_formats, ARRAY_SIZE(st7586_formats), 368043386a0SNoralf Trønnes &st7586_mode, rotation, bufsize); 369043386a0SNoralf Trønnes if (ret) 370043386a0SNoralf Trønnes return ret; 371043386a0SNoralf Trønnes 372043386a0SNoralf Trønnes /* 373043386a0SNoralf Trønnes * we are using 8-bit data, so we are not actually swapping anything, 374043386a0SNoralf Trønnes * but setting mipi->swap_bytes makes mipi_dbi_typec3_command() do the 375043386a0SNoralf Trønnes * right thing and not use 16-bit transfers (which results in swapped 376043386a0SNoralf Trønnes * bytes on little-endian systems and causes out of order data to be 377043386a0SNoralf Trønnes * sent to the display). 378043386a0SNoralf Trønnes */ 379043386a0SNoralf Trønnes dbi->swap_bytes = true; 380043386a0SNoralf Trønnes 381043386a0SNoralf Trønnes drm_mode_config_reset(drm); 382043386a0SNoralf Trønnes 383043386a0SNoralf Trønnes ret = drm_dev_register(drm, 0); 384043386a0SNoralf Trønnes if (ret) 385043386a0SNoralf Trønnes return ret; 386043386a0SNoralf Trønnes 387043386a0SNoralf Trønnes spi_set_drvdata(spi, drm); 388043386a0SNoralf Trønnes 389043386a0SNoralf Trønnes drm_fbdev_generic_setup(drm, 0); 390043386a0SNoralf Trønnes 391043386a0SNoralf Trønnes return 0; 392043386a0SNoralf Trønnes } 393043386a0SNoralf Trønnes 394043386a0SNoralf Trønnes static int st7586_remove(struct spi_device *spi) 395043386a0SNoralf Trønnes { 396043386a0SNoralf Trønnes struct drm_device *drm = spi_get_drvdata(spi); 397043386a0SNoralf Trønnes 398043386a0SNoralf Trønnes drm_dev_unplug(drm); 399043386a0SNoralf Trønnes drm_atomic_helper_shutdown(drm); 400043386a0SNoralf Trønnes 401043386a0SNoralf Trønnes return 0; 402043386a0SNoralf Trønnes } 403043386a0SNoralf Trønnes 404043386a0SNoralf Trønnes static void st7586_shutdown(struct spi_device *spi) 405043386a0SNoralf Trønnes { 406043386a0SNoralf Trønnes drm_atomic_helper_shutdown(spi_get_drvdata(spi)); 407043386a0SNoralf Trønnes } 408043386a0SNoralf Trønnes 409043386a0SNoralf Trønnes static struct spi_driver st7586_spi_driver = { 410043386a0SNoralf Trønnes .driver = { 411043386a0SNoralf Trønnes .name = "st7586", 412043386a0SNoralf Trønnes .owner = THIS_MODULE, 413043386a0SNoralf Trønnes .of_match_table = st7586_of_match, 414043386a0SNoralf Trønnes }, 415043386a0SNoralf Trønnes .id_table = st7586_id, 416043386a0SNoralf Trønnes .probe = st7586_probe, 417043386a0SNoralf Trønnes .remove = st7586_remove, 418043386a0SNoralf Trønnes .shutdown = st7586_shutdown, 419043386a0SNoralf Trønnes }; 420043386a0SNoralf Trønnes module_spi_driver(st7586_spi_driver); 421043386a0SNoralf Trønnes 422043386a0SNoralf Trønnes MODULE_DESCRIPTION("Sitronix ST7586 DRM driver"); 423043386a0SNoralf Trønnes MODULE_AUTHOR("David Lechner <david@lechnology.com>"); 424043386a0SNoralf Trønnes MODULE_LICENSE("GPL"); 425