| 1 | |
| 2 | |
| 3 | * DRM driver for Pervasive Displays RePaper branded e-ink panels
|
| 4 | *
|
| 5 | * Copyright 2013-2017 Pervasive Displays, Inc.
|
| 6 | * Copyright 2017 Noralf Trønnes
|
| 7 | *
|
| 8 | * The driver supports:
|
| 9 | * Material Film: Aurora Mb (V231)
|
| 10 | * Driver IC: G2 (eTC)
|
| 11 | *
|
| 12 | * The controller code was taken from the userspace driver:
|
| 13 | * https://github.com/repaper/gratis
|
| 14 |
|
| 15 |
|
| 16 | #include <linux/delay.h>
|
| 17 | #include <linux/gpio/consumer.h>
|
| 18 | #include <linux/module.h>
|
| 19 | #include <linux/property.h>
|
| 20 | #include <linux/sched/clock.h>
|
| 21 | #include <linux/spi/spi.h>
|
| 22 | #include <linux/thermal.h>
|
| 23 |
|
| 24 | #include <drm/clients/drm_client_setup.h>
|
| 25 | #include <drm/drm_atomic_helper.h>
|
| 26 | #include <drm/drm_connector.h>
|
| 27 | #include <drm/drm_damage_helper.h>
|
| 28 | #include <drm/drm_drv.h>
|
| 29 | #include <drm/drm_fb_dma_helper.h>
|
| 30 | #include <drm/drm_fbdev_dma.h>
|
| 31 | #include <drm/drm_format_helper.h>
|
| 32 | #include <drm/drm_framebuffer.h>
|
| 33 | #include <drm/drm_gem_atomic_helper.h>
|
| 34 | #include <drm/drm_gem_dma_helper.h>
|
| 35 | #include <drm/drm_gem_framebuffer_helper.h>
|
| 36 | #include <drm/drm_managed.h>
|
| 37 | #include <drm/drm_modes.h>
|
| 38 | #include <drm/drm_rect.h>
|
| 39 | #include <drm/drm_print.h>
|
| 40 | #include <drm/drm_probe_helper.h>
|
| 41 | #include <drm/drm_simple_kms_helper.h>
|
| 42 |
|
| 43 | #define REPAPER_RID_G2_COG_ID 0x12
|
| 44 |
|
| 45 | enum repaper_model {
|
| 46 |
|
| 47 | E1144CS021 = 1,
|
| 48 | E1190CS021,
|
| 49 | E2200CS021,
|
| 50 | E2271CS021,
|
| 51 | };
|
| 52 |
|
| 53 | enum repaper_stage {
|
| 54 | REPAPER_COMPENSATE,
|
| 55 | REPAPER_WHITE,
|
| 56 | REPAPER_INVERSE,
|
| 57 | REPAPER_NORMAL
|
| 58 | };
|
| 59 |
|
| 60 | enum repaper_epd_border_byte {
|
| 61 | REPAPER_BORDER_BYTE_NONE,
|
| 62 | REPAPER_BORDER_BYTE_ZERO,
|
| 63 | REPAPER_BORDER_BYTE_SET,
|
| 64 | };
|
| 65 |
|
| 66 | struct repaper_epd {
|
| 67 | struct drm_device drm;
|
| 68 | struct drm_simple_display_pipe pipe;
|
| 69 | const struct drm_display_mode *mode;
|
| 70 | struct drm_connector connector;
|
| 71 | struct spi_device *spi;
|
| 72 |
|
| 73 | struct gpio_desc *panel_on;
|
| 74 | struct gpio_desc *border;
|
| 75 | struct gpio_desc *discharge;
|
| 76 | struct gpio_desc *reset;
|
| 77 | struct gpio_desc *busy;
|
| 78 |
|
| 79 | struct thermal_zone_device *thermal;
|
| 80 |
|
| 81 | unsigned int height;
|
| 82 | unsigned int width;
|
| 83 | unsigned int bytes_per_scan;
|
| 84 | const u8 *channel_select;
|
| 85 | unsigned int stage_time;
|
| 86 | unsigned int factored_stage_time;
|
| 87 | bool middle_scan;
|
| 88 | bool pre_border_byte;
|
| 89 | enum repaper_epd_border_byte border_byte;
|
| 90 |
|
| 91 | u8 *line_buffer;
|
| 92 | void *current_frame;
|
| 93 |
|
| 94 | bool cleared;
|
| 95 | bool partial;
|
| 96 | };
|
| 97 |
|
| 98 | static inline struct repaper_epd *drm_to_epd(struct drm_device *drm)
|
| 99 | {
|
| 100 | return container_of(drm, struct repaper_epd, drm);
|
| 101 | }
|
| 102 |
|
| 103 | static int repaper_spi_transfer(struct spi_device *spi, u8 header,
|
| 104 | const void *tx, void *rx, size_t len)
|
| 105 | {
|
| 106 | void *txbuf = NULL, *rxbuf = NULL;
|
| 107 | struct spi_transfer tr[2] = {};
|
| 108 | u8 *headerbuf;
|
| 109 | int ret;
|
| 110 |
|
| 111 | headerbuf = kmalloc(1, GFP_KERNEL);
|
| 112 | if (!headerbuf)
|
| 113 | return -ENOMEM;
|
| 114 |
|
| 115 | headerbuf[0] = header;
|
| 116 | tr[0].tx_buf = headerbuf;
|
| 117 | tr[0].len = 1;
|
| 118 |
|
| 119 |
|
| 120 | if (tx && len <= 32) {
|
| 121 | txbuf = kmemdup(tx, len, GFP_KERNEL);
|
| 122 | if (!txbuf) {
|
| 123 | ret = -ENOMEM;
|
| 124 | goto out_free;
|
| 125 | }
|
| 126 | }
|
| 127 |
|
| 128 | if (rx) {
|
| 129 | rxbuf = kmalloc(len, GFP_KERNEL);
|
| 130 | if (!rxbuf) {
|
| 131 | ret = -ENOMEM;
|
| 132 | goto out_free;
|
| 133 | }
|
| 134 | }
|
| 135 |
|
| 136 | tr[1].tx_buf = txbuf ? txbuf : tx;
|
| 137 | tr[1].rx_buf = rxbuf;
|
| 138 | tr[1].len = len;
|
| 139 |
|
| 140 | ndelay(80);
|
| 141 | ret = spi_sync_transfer(spi, tr, 2);
|
| 142 | if (rx && !ret)
|
| 143 | memcpy(rx, rxbuf, len);
|
| 144 |
|
| 145 | out_free:
|
| 146 | kfree(headerbuf);
|
| 147 | kfree(txbuf);
|
| 148 | kfree(rxbuf);
|
| 149 |
|
| 150 | return ret;
|
| 151 | }
|
| 152 |
|
| 153 | static int repaper_write_buf(struct spi_device *spi, u8 reg,
|
| 154 | const u8 *buf, size_t len)
|
| 155 | {
|
| 156 | int ret;
|
| 157 |
|
| 158 | ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1);
|
| 159 | if (ret)
|
| 160 | return ret;
|
| 161 |
|
| 162 | return repaper_spi_transfer(spi, 0x72, buf, NULL, len);
|
| 163 | }
|
| 164 |
|
| 165 | static int repaper_write_val(struct spi_device *spi, u8 reg, u8 val)
|
| 166 | {
|
| 167 | return repaper_write_buf(spi, reg, &val, 1);
|
| 168 | }
|
| 169 |
|
| 170 | static int repaper_read_val(struct spi_device *spi, u8 reg)
|
| 171 | {
|
| 172 | int ret;
|
| 173 | u8 val;
|
| 174 |
|
| 175 | ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1);
|
| 176 | if (ret)
|
| 177 | return ret;
|
| 178 |
|
| 179 | ret = repaper_spi_transfer(spi, 0x73, NULL, &val, 1);
|
| 180 |
|
| 181 | return ret ? ret : val;
|
| 182 | }
|
| 183 |
|
| 184 | static int repaper_read_id(struct spi_device *spi)
|
| 185 | {
|
| 186 | int ret;
|
| 187 | u8 id;
|
| 188 |
|
| 189 | ret = repaper_spi_transfer(spi, 0x71, NULL, &id, 1);
|
| 190 |
|
| 191 | return ret ? ret : id;
|
| 192 | }
|
| 193 |
|
| 194 | static void repaper_spi_mosi_low(struct spi_device *spi)
|
| 195 | {
|
| 196 | const u8 buf[1] = { 0 };
|
| 197 |
|
| 198 | spi_write(spi, buf, 1);
|
| 199 | }
|
| 200 |
|
| 201 |
|
| 202 | static void repaper_even_pixels(struct repaper_epd *epd, u8 **pp,
|
| 203 | const u8 *data, u8 fixed_value, const u8 *mask,
|
| 204 | enum repaper_stage stage)
|
| 205 | {
|
| 206 | unsigned int b;
|
| 207 |
|
| 208 | for (b = 0; b < (epd->width / 8); b++) {
|
| 209 | if (data) {
|
| 210 | u8 pixels = data[b] & 0xaa;
|
| 211 | u8 pixel_mask = 0xff;
|
| 212 | u8 p1, p2, p3, p4;
|
| 213 |
|
| 214 | if (mask) {
|
| 215 | pixel_mask = (mask[b] ^ pixels) & 0xaa;
|
| 216 | pixel_mask |= pixel_mask >> 1;
|
| 217 | }
|
| 218 |
|
| 219 | switch (stage) {
|
| 220 | case REPAPER_COMPENSATE:
|
| 221 | pixels = 0xaa | ((pixels ^ 0xaa) >> 1);
|
| 222 | break;
|
| 223 | case REPAPER_WHITE:
|
| 224 | pixels = 0x55 + ((pixels ^ 0xaa) >> 1);
|
| 225 | break;
|
| 226 | case REPAPER_INVERSE:
|
| 227 | pixels = 0x55 | (pixels ^ 0xaa);
|
| 228 | break;
|
| 229 | case REPAPER_NORMAL:
|
| 230 | pixels = 0xaa | (pixels >> 1);
|
| 231 | break;
|
| 232 | }
|
| 233 |
|
| 234 | pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55);
|
| 235 | p1 = (pixels >> 6) & 0x03;
|
| 236 | p2 = (pixels >> 4) & 0x03;
|
| 237 | p3 = (pixels >> 2) & 0x03;
|
| 238 | p4 = (pixels >> 0) & 0x03;
|
| 239 | pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6);
|
| 240 | *(*pp)++ = pixels;
|
| 241 | } else {
|
| 242 | *(*pp)++ = fixed_value;
|
| 243 | }
|
| 244 | }
|
| 245 | }
|
| 246 |
|
| 247 |
|
| 248 | static void repaper_odd_pixels(struct repaper_epd *epd, u8 **pp,
|
| 249 | const u8 *data, u8 fixed_value, const u8 *mask,
|
| 250 | enum repaper_stage stage)
|
| 251 | {
|
| 252 | unsigned int b;
|
| 253 |
|
| 254 | for (b = epd->width / 8; b > 0; b--) {
|
| 255 | if (data) {
|
| 256 | u8 pixels = data[b - 1] & 0x55;
|
| 257 | u8 pixel_mask = 0xff;
|
| 258 |
|
| 259 | if (mask) {
|
| 260 | pixel_mask = (mask[b - 1] ^ pixels) & 0x55;
|
| 261 | pixel_mask |= pixel_mask << 1;
|
| 262 | }
|
| 263 |
|
| 264 | switch (stage) {
|
| 265 | case REPAPER_COMPENSATE:
|
| 266 | pixels = 0xaa | (pixels ^ 0x55);
|
| 267 | break;
|
| 268 | case REPAPER_WHITE:
|
| 269 | pixels = 0x55 + (pixels ^ 0x55);
|
| 270 | break;
|
| 271 | case REPAPER_INVERSE:
|
| 272 | pixels = 0x55 | ((pixels ^ 0x55) << 1);
|
| 273 | break;
|
| 274 | case REPAPER_NORMAL:
|
| 275 | pixels = 0xaa | pixels;
|
| 276 | break;
|
| 277 | }
|
| 278 |
|
| 279 | pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55);
|
| 280 | *(*pp)++ = pixels;
|
| 281 | } else {
|
| 282 | *(*pp)++ = fixed_value;
|
| 283 | }
|
| 284 | }
|
| 285 | }
|
| 286 |
|
| 287 |
|
| 288 | static inline u16 repaper_interleave_bits(u16 value)
|
| 289 | {
|
| 290 | value = (value | (value << 4)) & 0x0f0f;
|
| 291 | value = (value | (value << 2)) & 0x3333;
|
| 292 | value = (value | (value << 1)) & 0x5555;
|
| 293 |
|
| 294 | return value;
|
| 295 | }
|
| 296 |
|
| 297 |
|
| 298 | static void repaper_all_pixels(struct repaper_epd *epd, u8 **pp,
|
| 299 | const u8 *data, u8 fixed_value, const u8 *mask,
|
| 300 | enum repaper_stage stage)
|
| 301 | {
|
| 302 | unsigned int b;
|
| 303 |
|
| 304 | for (b = epd->width / 8; b > 0; b--) {
|
| 305 | if (data) {
|
| 306 | u16 pixels = repaper_interleave_bits(data[b - 1]);
|
| 307 | u16 pixel_mask = 0xffff;
|
| 308 |
|
| 309 | if (mask) {
|
| 310 | pixel_mask = repaper_interleave_bits(mask[b - 1]);
|
| 311 |
|
| 312 | pixel_mask = (pixel_mask ^ pixels) & 0x5555;
|
| 313 | pixel_mask |= pixel_mask << 1;
|
| 314 | }
|
| 315 |
|
| 316 | switch (stage) {
|
| 317 | case REPAPER_COMPENSATE:
|
| 318 | pixels = 0xaaaa | (pixels ^ 0x5555);
|
| 319 | break;
|
| 320 | case REPAPER_WHITE:
|
| 321 | pixels = 0x5555 + (pixels ^ 0x5555);
|
| 322 | break;
|
| 323 | case REPAPER_INVERSE:
|
| 324 | pixels = 0x5555 | ((pixels ^ 0x5555) << 1);
|
| 325 | break;
|
| 326 | case REPAPER_NORMAL:
|
| 327 | pixels = 0xaaaa | pixels;
|
| 328 | break;
|
| 329 | }
|
| 330 |
|
| 331 | pixels = (pixels & pixel_mask) | (~pixel_mask & 0x5555);
|
| 332 | *(*pp)++ = pixels >> 8;
|
| 333 | *(*pp)++ = pixels;
|
| 334 | } else {
|
| 335 | *(*pp)++ = fixed_value;
|
| 336 | *(*pp)++ = fixed_value;
|
| 337 | }
|
| 338 | }
|
| 339 | }
|
| 340 |
|
| 341 |
|
| 342 | static void repaper_one_line(struct repaper_epd *epd, unsigned int line,
|
| 343 | const u8 *data, u8 fixed_value, const u8 *mask,
|
| 344 | enum repaper_stage stage)
|
| 345 | {
|
| 346 | u8 *p = epd->line_buffer;
|
| 347 | unsigned int b;
|
| 348 |
|
| 349 | repaper_spi_mosi_low(epd->spi);
|
| 350 |
|
| 351 | if (epd->pre_border_byte)
|
| 352 | *p++ = 0x00;
|
| 353 |
|
| 354 | if (epd->middle_scan) {
|
| 355 |
|
| 356 | repaper_odd_pixels(epd, &p, data, fixed_value, mask, stage);
|
| 357 |
|
| 358 |
|
| 359 | for (b = epd->bytes_per_scan; b > 0; b--) {
|
| 360 | if (line / 4 == b - 1)
|
| 361 | *p++ = 0x03 << (2 * (line & 0x03));
|
| 362 | else
|
| 363 | *p++ = 0x00;
|
| 364 | }
|
| 365 |
|
| 366 |
|
| 367 | repaper_even_pixels(epd, &p, data, fixed_value, mask, stage);
|
| 368 | } else {
|
| 369 | |
| 370 | * even scan line, but as lines on display are numbered from 1,
|
| 371 | * line: 1,3,5,...
|
| 372 |
|
| 373 | for (b = 0; b < epd->bytes_per_scan; b++) {
|
| 374 | if (0 != (line & 0x01) && line / 8 == b)
|
| 375 | *p++ = 0xc0 >> (line & 0x06);
|
| 376 | else
|
| 377 | *p++ = 0x00;
|
| 378 | }
|
| 379 |
|
| 380 |
|
| 381 | repaper_all_pixels(epd, &p, data, fixed_value, mask, stage);
|
| 382 |
|
| 383 | |
| 384 | * odd scan line, but as lines on display are numbered from 1,
|
| 385 | * line: 0,2,4,6,...
|
| 386 |
|
| 387 | for (b = epd->bytes_per_scan; b > 0; b--) {
|
| 388 | if (0 == (line & 0x01) && line / 8 == b - 1)
|
| 389 | *p++ = 0x03 << (line & 0x06);
|
| 390 | else
|
| 391 | *p++ = 0x00;
|
| 392 | }
|
| 393 | }
|
| 394 |
|
| 395 | switch (epd->border_byte) {
|
| 396 | case REPAPER_BORDER_BYTE_NONE:
|
| 397 | break;
|
| 398 |
|
| 399 | case REPAPER_BORDER_BYTE_ZERO:
|
| 400 | *p++ = 0x00;
|
| 401 | break;
|
| 402 |
|
| 403 | case REPAPER_BORDER_BYTE_SET:
|
| 404 | switch (stage) {
|
| 405 | case REPAPER_COMPENSATE:
|
| 406 | case REPAPER_WHITE:
|
| 407 | case REPAPER_INVERSE:
|
| 408 | *p++ = 0x00;
|
| 409 | break;
|
| 410 | case REPAPER_NORMAL:
|
| 411 | *p++ = 0xaa;
|
| 412 | break;
|
| 413 | }
|
| 414 | break;
|
| 415 | }
|
| 416 |
|
| 417 | repaper_write_buf(epd->spi, 0x0a, epd->line_buffer,
|
| 418 | p - epd->line_buffer);
|
| 419 |
|
| 420 |
|
| 421 | repaper_write_val(epd->spi, 0x02, 0x07);
|
| 422 |
|
| 423 | repaper_spi_mosi_low(epd->spi);
|
| 424 | }
|
| 425 |
|
| 426 | static void repaper_frame_fixed(struct repaper_epd *epd, u8 fixed_value,
|
| 427 | enum repaper_stage stage)
|
| 428 | {
|
| 429 | unsigned int line;
|
| 430 |
|
| 431 | for (line = 0; line < epd->height; line++)
|
| 432 | repaper_one_line(epd, line, NULL, fixed_value, NULL, stage);
|
| 433 | }
|
| 434 |
|
| 435 | static void repaper_frame_data(struct repaper_epd *epd, const u8 *image,
|
| 436 | const u8 *mask, enum repaper_stage stage)
|
| 437 | {
|
| 438 | unsigned int line;
|
| 439 |
|
| 440 | if (!mask) {
|
| 441 | for (line = 0; line < epd->height; line++) {
|
| 442 | repaper_one_line(epd, line,
|
| 443 | &image[line * (epd->width / 8)],
|
| 444 | 0, NULL, stage);
|
| 445 | }
|
| 446 | } else {
|
| 447 | for (line = 0; line < epd->height; line++) {
|
| 448 | size_t n = line * epd->width / 8;
|
| 449 |
|
| 450 | repaper_one_line(epd, line, &image[n], 0, &mask[n],
|
| 451 | stage);
|
| 452 | }
|
| 453 | }
|
| 454 | }
|
| 455 |
|
| 456 | static void repaper_frame_fixed_repeat(struct repaper_epd *epd, u8 fixed_value,
|
| 457 | enum repaper_stage stage)
|
| 458 | {
|
| 459 | u64 start = local_clock();
|
| 460 | u64 end = start + ((u64)epd->factored_stage_time * 1000 * 1000);
|
| 461 |
|
| 462 | do {
|
| 463 | repaper_frame_fixed(epd, fixed_value, stage);
|
| 464 | } while (local_clock() < end);
|
| 465 | }
|
| 466 |
|
| 467 | static void repaper_frame_data_repeat(struct repaper_epd *epd, const u8 *image,
|
| 468 | const u8 *mask, enum repaper_stage stage)
|
| 469 | {
|
| 470 | u64 start = local_clock();
|
| 471 | u64 end = start + ((u64)epd->factored_stage_time * 1000 * 1000);
|
| 472 |
|
| 473 | do {
|
| 474 | repaper_frame_data(epd, image, mask, stage);
|
| 475 | } while (local_clock() < end);
|
| 476 | }
|
| 477 |
|
| 478 | static void repaper_get_temperature(struct repaper_epd *epd)
|
| 479 | {
|
| 480 | int ret, temperature = 0;
|
| 481 | unsigned int factor10x;
|
| 482 |
|
| 483 | if (!epd->thermal)
|
| 484 | return;
|
| 485 |
|
| 486 | ret = thermal_zone_get_temp(epd->thermal, &temperature);
|
| 487 | if (ret) {
|
| 488 | DRM_DEV_ERROR(&epd->spi->dev, "Failed to get temperature (%d)\n", ret);
|
| 489 | return;
|
| 490 | }
|
| 491 |
|
| 492 | temperature /= 1000;
|
| 493 |
|
| 494 | if (temperature <= -10)
|
| 495 | factor10x = 170;
|
| 496 | else if (temperature <= -5)
|
| 497 | factor10x = 120;
|
| 498 | else if (temperature <= 5)
|
| 499 | factor10x = 80;
|
| 500 | else if (temperature <= 10)
|
| 501 | factor10x = 40;
|
| 502 | else if (temperature <= 15)
|
| 503 | factor10x = 30;
|
| 504 | else if (temperature <= 20)
|
| 505 | factor10x = 20;
|
| 506 | else if (temperature <= 40)
|
| 507 | factor10x = 10;
|
| 508 | else
|
| 509 | factor10x = 7;
|
| 510 |
|
| 511 | epd->factored_stage_time = epd->stage_time * factor10x / 10;
|
| 512 | }
|
| 513 |
|
| 514 | static int repaper_fb_dirty(struct drm_framebuffer *fb, const struct iosys_map *vmap,
|
| 515 | struct drm_format_conv_state *fmtcnv_state)
|
| 516 | {
|
| 517 | struct repaper_epd *epd = drm_to_epd(fb->dev);
|
| 518 | unsigned int dst_pitch = 0;
|
| 519 | struct iosys_map dst;
|
| 520 | struct drm_rect clip;
|
| 521 | int idx, ret = 0;
|
| 522 | u8 *buf = NULL;
|
| 523 |
|
| 524 | if (!drm_dev_enter(fb->dev, &idx))
|
| 525 | return -ENODEV;
|
| 526 |
|
| 527 |
|
| 528 | clip.x1 = 0;
|
| 529 | clip.x2 = fb->width;
|
| 530 | clip.y1 = 0;
|
| 531 | clip.y2 = fb->height;
|
| 532 |
|
| 533 | repaper_get_temperature(epd);
|
| 534 |
|
| 535 | DRM_DEBUG("Flushing [FB:%d] st=%ums\n", fb->base.id,
|
| 536 | epd->factored_stage_time);
|
| 537 |
|
| 538 | buf = kmalloc(fb->width * fb->height / 8, GFP_KERNEL);
|
| 539 | if (!buf) {
|
| 540 | ret = -ENOMEM;
|
| 541 | goto out_exit;
|
| 542 | }
|
| 543 |
|
| 544 | ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
|
| 545 | if (ret)
|
| 546 | goto out_free;
|
| 547 |
|
| 548 | iosys_map_set_vaddr(&dst, buf);
|
| 549 | drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, &clip, fmtcnv_state);
|
| 550 |
|
| 551 | drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
|
| 552 |
|
| 553 | if (epd->partial) {
|
| 554 | repaper_frame_data_repeat(epd, buf, epd->current_frame,
|
| 555 | REPAPER_NORMAL);
|
| 556 | } else if (epd->cleared) {
|
| 557 | repaper_frame_data_repeat(epd, epd->current_frame, NULL,
|
| 558 | REPAPER_COMPENSATE);
|
| 559 | repaper_frame_data_repeat(epd, epd->current_frame, NULL,
|
| 560 | REPAPER_WHITE);
|
| 561 | repaper_frame_data_repeat(epd, buf, NULL, REPAPER_INVERSE);
|
| 562 | repaper_frame_data_repeat(epd, buf, NULL, REPAPER_NORMAL);
|
| 563 |
|
| 564 | epd->partial = true;
|
| 565 | } else {
|
| 566 |
|
| 567 | repaper_frame_fixed_repeat(epd, 0xff, REPAPER_COMPENSATE);
|
| 568 | repaper_frame_fixed_repeat(epd, 0xff, REPAPER_WHITE);
|
| 569 | repaper_frame_fixed_repeat(epd, 0xaa, REPAPER_INVERSE);
|
| 570 | repaper_frame_fixed_repeat(epd, 0xaa, REPAPER_NORMAL);
|
| 571 |
|
| 572 |
|
| 573 | repaper_frame_fixed_repeat(epd, 0xaa, REPAPER_COMPENSATE);
|
| 574 | repaper_frame_fixed_repeat(epd, 0xaa, REPAPER_WHITE);
|
| 575 | repaper_frame_data_repeat(epd, buf, NULL, REPAPER_INVERSE);
|
| 576 | repaper_frame_data_repeat(epd, buf, NULL, REPAPER_NORMAL);
|
| 577 |
|
| 578 | epd->cleared = true;
|
| 579 | epd->partial = true;
|
| 580 | }
|
| 581 |
|
| 582 | memcpy(epd->current_frame, buf, fb->width * fb->height / 8);
|
| 583 |
|
| 584 | |
| 585 | * An extra frame write is needed if pixels are set in the bottom line,
|
| 586 | * or else grey lines rises up from the pixels
|
| 587 |
|
| 588 | if (epd->pre_border_byte) {
|
| 589 | unsigned int x;
|
| 590 |
|
| 591 | for (x = 0; x < (fb->width / 8); x++)
|
| 592 | if (buf[x + (fb->width * (fb->height - 1) / 8)]) {
|
| 593 | repaper_frame_data_repeat(epd, buf,
|
| 594 | epd->current_frame,
|
| 595 | REPAPER_NORMAL);
|
| 596 | break;
|
| 597 | }
|
| 598 | }
|
| 599 |
|
| 600 | out_free:
|
| 601 | kfree(buf);
|
| 602 | out_exit:
|
| 603 | drm_dev_exit(idx);
|
| 604 |
|
| 605 | return ret;
|
| 606 | }
|
| 607 |
|
| 608 | static void power_off(struct repaper_epd *epd)
|
| 609 | {
|
| 610 |
|
| 611 | gpiod_set_value_cansleep(epd->reset, 0);
|
| 612 | gpiod_set_value_cansleep(epd->panel_on, 0);
|
| 613 | if (epd->border)
|
| 614 | gpiod_set_value_cansleep(epd->border, 0);
|
| 615 |
|
| 616 |
|
| 617 | repaper_spi_mosi_low(epd->spi);
|
| 618 |
|
| 619 |
|
| 620 | gpiod_set_value_cansleep(epd->discharge, 1);
|
| 621 | msleep(150);
|
| 622 | gpiod_set_value_cansleep(epd->discharge, 0);
|
| 623 | }
|
| 624 |
|
| 625 | static enum drm_mode_status repaper_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
|
| 626 | const struct drm_display_mode *mode)
|
| 627 | {
|
| 628 | struct drm_crtc *crtc = &pipe->crtc;
|
| 629 | struct repaper_epd *epd = drm_to_epd(crtc->dev);
|
| 630 |
|
| 631 | return drm_crtc_helper_mode_valid_fixed(crtc, mode, epd->mode);
|
| 632 | }
|
| 633 |
|
| 634 | static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe,
|
| 635 | struct drm_crtc_state *crtc_state,
|
| 636 | struct drm_plane_state *plane_state)
|
| 637 | {
|
| 638 | struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev);
|
| 639 | struct spi_device *spi = epd->spi;
|
| 640 | struct device *dev = &spi->dev;
|
| 641 | bool dc_ok = false;
|
| 642 | int i, ret, idx;
|
| 643 |
|
| 644 | if (!drm_dev_enter(pipe->crtc.dev, &idx))
|
| 645 | return;
|
| 646 |
|
| 647 | DRM_DEBUG_DRIVER("\n");
|
| 648 |
|
| 649 |
|
| 650 | gpiod_set_value_cansleep(epd->reset, 0);
|
| 651 | gpiod_set_value_cansleep(epd->panel_on, 0);
|
| 652 | gpiod_set_value_cansleep(epd->discharge, 0);
|
| 653 | if (epd->border)
|
| 654 | gpiod_set_value_cansleep(epd->border, 0);
|
| 655 | repaper_spi_mosi_low(spi);
|
| 656 | usleep_range(5000, 10000);
|
| 657 |
|
| 658 | gpiod_set_value_cansleep(epd->panel_on, 1);
|
| 659 | |
| 660 | * This delay comes from the repaper.org userspace driver, it's not
|
| 661 | * mentioned in the datasheet.
|
| 662 |
|
| 663 | usleep_range(10000, 15000);
|
| 664 | gpiod_set_value_cansleep(epd->reset, 1);
|
| 665 | if (epd->border)
|
| 666 | gpiod_set_value_cansleep(epd->border, 1);
|
| 667 | usleep_range(5000, 10000);
|
| 668 | gpiod_set_value_cansleep(epd->reset, 0);
|
| 669 | usleep_range(5000, 10000);
|
| 670 | gpiod_set_value_cansleep(epd->reset, 1);
|
| 671 | usleep_range(5000, 10000);
|
| 672 |
|
| 673 |
|
| 674 | for (i = 100; i > 0; i--) {
|
| 675 | if (!gpiod_get_value_cansleep(epd->busy))
|
| 676 | break;
|
| 677 |
|
| 678 | usleep_range(10, 100);
|
| 679 | }
|
| 680 |
|
| 681 | if (!i) {
|
| 682 | DRM_DEV_ERROR(dev, "timeout waiting for panel to become ready.\n");
|
| 683 | power_off(epd);
|
| 684 | goto out_exit;
|
| 685 | }
|
| 686 |
|
| 687 | repaper_read_id(spi);
|
| 688 | ret = repaper_read_id(spi);
|
| 689 | if (ret != REPAPER_RID_G2_COG_ID) {
|
| 690 | if (ret < 0)
|
| 691 | dev_err(dev, "failed to read chip (%d)\n", ret);
|
| 692 | else
|
| 693 | dev_err(dev, "wrong COG ID 0x%02x\n", ret);
|
| 694 | power_off(epd);
|
| 695 | goto out_exit;
|
| 696 | }
|
| 697 |
|
| 698 |
|
| 699 | repaper_write_val(spi, 0x02, 0x40);
|
| 700 |
|
| 701 | ret = repaper_read_val(spi, 0x0f);
|
| 702 | if (ret < 0 || !(ret & 0x80)) {
|
| 703 | if (ret < 0)
|
| 704 | DRM_DEV_ERROR(dev, "failed to read chip (%d)\n", ret);
|
| 705 | else
|
| 706 | DRM_DEV_ERROR(dev, "panel is reported broken\n");
|
| 707 | power_off(epd);
|
| 708 | goto out_exit;
|
| 709 | }
|
| 710 |
|
| 711 |
|
| 712 | repaper_write_val(spi, 0x0b, 0x02);
|
| 713 |
|
| 714 | repaper_write_buf(spi, 0x01, epd->channel_select, 8);
|
| 715 |
|
| 716 | repaper_write_val(spi, 0x07, 0xd1);
|
| 717 |
|
| 718 | repaper_write_val(spi, 0x08, 0x02);
|
| 719 |
|
| 720 | repaper_write_val(spi, 0x09, 0xc2);
|
| 721 |
|
| 722 | repaper_write_val(spi, 0x04, 0x03);
|
| 723 |
|
| 724 | repaper_write_val(spi, 0x03, 0x01);
|
| 725 |
|
| 726 | repaper_write_val(spi, 0x03, 0x00);
|
| 727 | usleep_range(5000, 10000);
|
| 728 |
|
| 729 |
|
| 730 | for (i = 0; i < 4; ++i) {
|
| 731 |
|
| 732 | repaper_write_val(spi, 0x05, 0x01);
|
| 733 | msleep(240);
|
| 734 |
|
| 735 |
|
| 736 | repaper_write_val(spi, 0x05, 0x03);
|
| 737 | msleep(40);
|
| 738 |
|
| 739 |
|
| 740 | repaper_write_val(spi, 0x05, 0x0f);
|
| 741 | msleep(40);
|
| 742 |
|
| 743 |
|
| 744 | ret = repaper_read_val(spi, 0x0f);
|
| 745 | if (ret < 0) {
|
| 746 | DRM_DEV_ERROR(dev, "failed to read chip (%d)\n", ret);
|
| 747 | power_off(epd);
|
| 748 | goto out_exit;
|
| 749 | }
|
| 750 |
|
| 751 | if (ret & 0x40) {
|
| 752 | dc_ok = true;
|
| 753 | break;
|
| 754 | }
|
| 755 | }
|
| 756 |
|
| 757 | if (!dc_ok) {
|
| 758 | DRM_DEV_ERROR(dev, "dc/dc failed\n");
|
| 759 | power_off(epd);
|
| 760 | goto out_exit;
|
| 761 | }
|
| 762 |
|
| 763 | |
| 764 | * Output enable to disable
|
| 765 | * The userspace driver sets this to 0x04, but the datasheet says 0x06
|
| 766 |
|
| 767 | repaper_write_val(spi, 0x02, 0x04);
|
| 768 |
|
| 769 | epd->partial = false;
|
| 770 | out_exit:
|
| 771 | drm_dev_exit(idx);
|
| 772 | }
|
| 773 |
|
| 774 | static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe)
|
| 775 | {
|
| 776 | struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev);
|
| 777 | struct spi_device *spi = epd->spi;
|
| 778 | unsigned int line;
|
| 779 |
|
| 780 | |
| 781 | * This callback is not protected by drm_dev_enter/exit since we want to
|
| 782 | * turn off the display on regular driver unload. It's highly unlikely
|
| 783 | * that the underlying SPI controller is gone should this be called after
|
| 784 | * unplug.
|
| 785 |
|
| 786 |
|
| 787 | DRM_DEBUG_DRIVER("\n");
|
| 788 |
|
| 789 |
|
| 790 | for (line = 0; line < epd->height; line++)
|
| 791 | repaper_one_line(epd, 0x7fffu, NULL, 0x00, NULL,
|
| 792 | REPAPER_COMPENSATE);
|
| 793 |
|
| 794 |
|
| 795 | if (epd->border) {
|
| 796 |
|
| 797 | repaper_one_line(epd, 0x7fffu, NULL, 0x00, NULL,
|
| 798 | REPAPER_COMPENSATE);
|
| 799 | msleep(25);
|
| 800 | gpiod_set_value_cansleep(epd->border, 0);
|
| 801 | msleep(200);
|
| 802 | gpiod_set_value_cansleep(epd->border, 1);
|
| 803 | } else {
|
| 804 |
|
| 805 | repaper_one_line(epd, 0x7fffu, NULL, 0x00, NULL,
|
| 806 | REPAPER_NORMAL);
|
| 807 | msleep(200);
|
| 808 | }
|
| 809 |
|
| 810 |
|
| 811 | repaper_write_val(spi, 0x0b, 0x00);
|
| 812 |
|
| 813 | repaper_write_val(spi, 0x03, 0x01);
|
| 814 |
|
| 815 | repaper_write_val(spi, 0x05, 0x03);
|
| 816 |
|
| 817 | repaper_write_val(spi, 0x05, 0x01);
|
| 818 | msleep(120);
|
| 819 |
|
| 820 | repaper_write_val(spi, 0x04, 0x80);
|
| 821 |
|
| 822 | repaper_write_val(spi, 0x05, 0x00);
|
| 823 |
|
| 824 | repaper_write_val(spi, 0x07, 0x01);
|
| 825 | msleep(50);
|
| 826 |
|
| 827 | power_off(epd);
|
| 828 | }
|
| 829 |
|
| 830 | static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
|
| 831 | struct drm_plane_state *old_state)
|
| 832 | {
|
| 833 | struct drm_plane_state *state = pipe->plane.state;
|
| 834 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
|
| 835 | struct drm_rect rect;
|
| 836 |
|
| 837 | if (!pipe->crtc.state->active)
|
| 838 | return;
|
| 839 |
|
| 840 | if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
| 841 | repaper_fb_dirty(state->fb, shadow_plane_state->data,
|
| 842 | &shadow_plane_state->fmtcnv_state);
|
| 843 | }
|
| 844 |
|
| 845 | static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
|
| 846 | .mode_valid = repaper_pipe_mode_valid,
|
| 847 | .enable = repaper_pipe_enable,
|
| 848 | .disable = repaper_pipe_disable,
|
| 849 | .update = repaper_pipe_update,
|
| 850 | DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
|
| 851 | };
|
| 852 |
|
| 853 | static int repaper_connector_get_modes(struct drm_connector *connector)
|
| 854 | {
|
| 855 | struct repaper_epd *epd = drm_to_epd(connector->dev);
|
| 856 |
|
| 857 | return drm_connector_helper_get_modes_fixed(connector, epd->mode);
|
| 858 | }
|
| 859 |
|
| 860 | static const struct drm_connector_helper_funcs repaper_connector_hfuncs = {
|
| 861 | .get_modes = repaper_connector_get_modes,
|
| 862 | };
|
| 863 |
|
| 864 | static const struct drm_connector_funcs repaper_connector_funcs = {
|
| 865 | .reset = drm_atomic_helper_connector_reset,
|
| 866 | .fill_modes = drm_helper_probe_single_connector_modes,
|
| 867 | .destroy = drm_connector_cleanup,
|
| 868 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
| 869 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
| 870 | };
|
| 871 |
|
| 872 | static const struct drm_mode_config_funcs repaper_mode_config_funcs = {
|
| 873 | .fb_create = drm_gem_fb_create_with_dirty,
|
| 874 | .atomic_check = drm_atomic_helper_check,
|
| 875 | .atomic_commit = drm_atomic_helper_commit,
|
| 876 | };
|
| 877 |
|
| 878 | static const uint32_t repaper_formats[] = {
|
| 879 | DRM_FORMAT_XRGB8888,
|
| 880 | };
|
| 881 |
|
| 882 | static const struct drm_display_mode repaper_e1144cs021_mode = {
|
| 883 | DRM_SIMPLE_MODE(128, 96, 29, 22),
|
| 884 | };
|
| 885 |
|
| 886 | static const u8 repaper_e1144cs021_cs[] = { 0x00, 0x00, 0x00, 0x00,
|
| 887 | 0x00, 0x0f, 0xff, 0x00 };
|
| 888 |
|
| 889 | static const struct drm_display_mode repaper_e1190cs021_mode = {
|
| 890 | DRM_SIMPLE_MODE(144, 128, 36, 32),
|
| 891 | };
|
| 892 |
|
| 893 | static const u8 repaper_e1190cs021_cs[] = { 0x00, 0x00, 0x00, 0x03,
|
| 894 | 0xfc, 0x00, 0x00, 0xff };
|
| 895 |
|
| 896 | static const struct drm_display_mode repaper_e2200cs021_mode = {
|
| 897 | DRM_SIMPLE_MODE(200, 96, 46, 22),
|
| 898 | };
|
| 899 |
|
| 900 | static const u8 repaper_e2200cs021_cs[] = { 0x00, 0x00, 0x00, 0x00,
|
| 901 | 0x01, 0xff, 0xe0, 0x00 };
|
| 902 |
|
| 903 | static const struct drm_display_mode repaper_e2271cs021_mode = {
|
| 904 | DRM_SIMPLE_MODE(264, 176, 57, 38),
|
| 905 | };
|
| 906 |
|
| 907 | static const u8 repaper_e2271cs021_cs[] = { 0x00, 0x00, 0x00, 0x7f,
|
| 908 | 0xff, 0xfe, 0x00, 0x00 };
|
| 909 |
|
| 910 | DEFINE_DRM_GEM_DMA_FOPS(repaper_fops);
|
| 911 |
|
| 912 | static const struct drm_driver repaper_driver = {
|
| 913 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
|
| 914 | .fops = &repaper_fops,
|
| 915 | DRM_GEM_DMA_DRIVER_OPS_VMAP,
|
| 916 | DRM_FBDEV_DMA_DRIVER_OPS,
|
| 917 | .name = "repaper",
|
| 918 | .desc = "Pervasive Displays RePaper e-ink panels",
|
| 919 | .major = 1,
|
| 920 | .minor = 0,
|
| 921 | };
|
| 922 |
|
| 923 | static const struct of_device_id repaper_of_match[] = {
|
| 924 | { .compatible = "pervasive,e1144cs021", .data = (void *)E1144CS021 },
|
| 925 | { .compatible = "pervasive,e1190cs021", .data = (void *)E1190CS021 },
|
| 926 | { .compatible = "pervasive,e2200cs021", .data = (void *)E2200CS021 },
|
| 927 | { .compatible = "pervasive,e2271cs021", .data = (void *)E2271CS021 },
|
| 928 | {},
|
| 929 | };
|
| 930 | MODULE_DEVICE_TABLE(of, repaper_of_match);
|
| 931 |
|
| 932 | static const struct spi_device_id repaper_id[] = {
|
| 933 | { "e1144cs021", E1144CS021 },
|
| 934 | { "e1190cs021", E1190CS021 },
|
| 935 | { "e2200cs021", E2200CS021 },
|
| 936 | { "e2271cs021", E2271CS021 },
|
| 937 | { },
|
| 938 | };
|
| 939 | MODULE_DEVICE_TABLE(spi, repaper_id);
|
| 940 |
|
| 941 | static int repaper_probe(struct spi_device *spi)
|
| 942 | {
|
| 943 | const struct drm_display_mode *mode;
|
| 944 | const struct spi_device_id *spi_id;
|
| 945 | struct device *dev = &spi->dev;
|
| 946 | enum repaper_model model;
|
| 947 | const char *thermal_zone;
|
| 948 | struct repaper_epd *epd;
|
| 949 | size_t line_buffer_size;
|
| 950 | struct drm_device *drm;
|
| 951 | const void *match;
|
| 952 | int ret;
|
| 953 |
|
| 954 | match = device_get_match_data(dev);
|
| 955 | if (match) {
|
| 956 | model = (enum repaper_model)(uintptr_t)match;
|
| 957 | } else {
|
| 958 | spi_id = spi_get_device_id(spi);
|
| 959 | model = (enum repaper_model)spi_id->driver_data;
|
| 960 | }
|
| 961 |
|
| 962 |
|
| 963 | if (!dev->coherent_dma_mask) {
|
| 964 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
| 965 | if (ret) {
|
| 966 | dev_warn(dev, "Failed to set dma mask %d\n", ret);
|
| 967 | return ret;
|
| 968 | }
|
| 969 | }
|
| 970 |
|
| 971 | epd = devm_drm_dev_alloc(dev, &repaper_driver,
|
| 972 | struct repaper_epd, drm);
|
| 973 | if (IS_ERR(epd))
|
| 974 | return PTR_ERR(epd);
|
| 975 |
|
| 976 | drm = &epd->drm;
|
| 977 |
|
| 978 | ret = drmm_mode_config_init(drm);
|
| 979 | if (ret)
|
| 980 | return ret;
|
| 981 | drm->mode_config.funcs = &repaper_mode_config_funcs;
|
| 982 |
|
| 983 | epd->spi = spi;
|
| 984 |
|
| 985 | epd->panel_on = devm_gpiod_get(dev, "panel-on", GPIOD_OUT_LOW);
|
| 986 | if (IS_ERR(epd->panel_on)) {
|
| 987 | ret = PTR_ERR(epd->panel_on);
|
| 988 | if (ret != -EPROBE_DEFER)
|
| 989 | DRM_DEV_ERROR(dev, "Failed to get gpio 'panel-on'\n");
|
| 990 | return ret;
|
| 991 | }
|
| 992 |
|
| 993 | epd->discharge = devm_gpiod_get(dev, "discharge", GPIOD_OUT_LOW);
|
| 994 | if (IS_ERR(epd->discharge)) {
|
| 995 | ret = PTR_ERR(epd->discharge);
|
| 996 | if (ret != -EPROBE_DEFER)
|
| 997 | DRM_DEV_ERROR(dev, "Failed to get gpio 'discharge'\n");
|
| 998 | return ret;
|
| 999 | }
|
| 1000 |
|
| 1001 | epd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
| 1002 | if (IS_ERR(epd->reset)) {
|
| 1003 | ret = PTR_ERR(epd->reset);
|
| 1004 | if (ret != -EPROBE_DEFER)
|
| 1005 | DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
|
| 1006 | return ret;
|
| 1007 | }
|
| 1008 |
|
| 1009 | epd->busy = devm_gpiod_get(dev, "busy", GPIOD_IN);
|
| 1010 | if (IS_ERR(epd->busy)) {
|
| 1011 | ret = PTR_ERR(epd->busy);
|
| 1012 | if (ret != -EPROBE_DEFER)
|
| 1013 | DRM_DEV_ERROR(dev, "Failed to get gpio 'busy'\n");
|
| 1014 | return ret;
|
| 1015 | }
|
| 1016 |
|
| 1017 | if (!device_property_read_string(dev, "pervasive,thermal-zone",
|
| 1018 | &thermal_zone)) {
|
| 1019 | epd->thermal = thermal_zone_get_zone_by_name(thermal_zone);
|
| 1020 | if (IS_ERR(epd->thermal)) {
|
| 1021 | DRM_DEV_ERROR(dev, "Failed to get thermal zone: %s\n", thermal_zone);
|
| 1022 | return PTR_ERR(epd->thermal);
|
| 1023 | }
|
| 1024 | }
|
| 1025 |
|
| 1026 | switch (model) {
|
| 1027 | case E1144CS021:
|
| 1028 | mode = &repaper_e1144cs021_mode;
|
| 1029 | epd->channel_select = repaper_e1144cs021_cs;
|
| 1030 | epd->stage_time = 480;
|
| 1031 | epd->bytes_per_scan = 96 / 4;
|
| 1032 | epd->middle_scan = true;
|
| 1033 | epd->pre_border_byte = false;
|
| 1034 | epd->border_byte = REPAPER_BORDER_BYTE_ZERO;
|
| 1035 | break;
|
| 1036 |
|
| 1037 | case E1190CS021:
|
| 1038 | mode = &repaper_e1190cs021_mode;
|
| 1039 | epd->channel_select = repaper_e1190cs021_cs;
|
| 1040 | epd->stage_time = 480;
|
| 1041 | epd->bytes_per_scan = 128 / 4 / 2;
|
| 1042 | epd->middle_scan = false;
|
| 1043 | epd->pre_border_byte = false;
|
| 1044 | epd->border_byte = REPAPER_BORDER_BYTE_SET;
|
| 1045 | break;
|
| 1046 |
|
| 1047 | case E2200CS021:
|
| 1048 | mode = &repaper_e2200cs021_mode;
|
| 1049 | epd->channel_select = repaper_e2200cs021_cs;
|
| 1050 | epd->stage_time = 480;
|
| 1051 | epd->bytes_per_scan = 96 / 4;
|
| 1052 | epd->middle_scan = true;
|
| 1053 | epd->pre_border_byte = true;
|
| 1054 | epd->border_byte = REPAPER_BORDER_BYTE_NONE;
|
| 1055 | break;
|
| 1056 |
|
| 1057 | case E2271CS021:
|
| 1058 | epd->border = devm_gpiod_get(dev, "border", GPIOD_OUT_LOW);
|
| 1059 | if (IS_ERR(epd->border)) {
|
| 1060 | ret = PTR_ERR(epd->border);
|
| 1061 | if (ret != -EPROBE_DEFER)
|
| 1062 | DRM_DEV_ERROR(dev, "Failed to get gpio 'border'\n");
|
| 1063 | return ret;
|
| 1064 | }
|
| 1065 |
|
| 1066 | mode = &repaper_e2271cs021_mode;
|
| 1067 | epd->channel_select = repaper_e2271cs021_cs;
|
| 1068 | epd->stage_time = 630;
|
| 1069 | epd->bytes_per_scan = 176 / 4;
|
| 1070 | epd->middle_scan = true;
|
| 1071 | epd->pre_border_byte = true;
|
| 1072 | epd->border_byte = REPAPER_BORDER_BYTE_NONE;
|
| 1073 | break;
|
| 1074 |
|
| 1075 | default:
|
| 1076 | return -ENODEV;
|
| 1077 | }
|
| 1078 |
|
| 1079 | epd->mode = mode;
|
| 1080 | epd->width = mode->hdisplay;
|
| 1081 | epd->height = mode->vdisplay;
|
| 1082 | epd->factored_stage_time = epd->stage_time;
|
| 1083 |
|
| 1084 | line_buffer_size = 2 * epd->width / 8 + epd->bytes_per_scan + 2;
|
| 1085 | epd->line_buffer = devm_kzalloc(dev, line_buffer_size, GFP_KERNEL);
|
| 1086 | if (!epd->line_buffer)
|
| 1087 | return -ENOMEM;
|
| 1088 |
|
| 1089 | epd->current_frame = devm_kzalloc(dev, epd->width * epd->height / 8,
|
| 1090 | GFP_KERNEL);
|
| 1091 | if (!epd->current_frame)
|
| 1092 | return -ENOMEM;
|
| 1093 |
|
| 1094 | drm->mode_config.min_width = mode->hdisplay;
|
| 1095 | drm->mode_config.max_width = mode->hdisplay;
|
| 1096 | drm->mode_config.min_height = mode->vdisplay;
|
| 1097 | drm->mode_config.max_height = mode->vdisplay;
|
| 1098 |
|
| 1099 | drm_connector_helper_add(&epd->connector, &repaper_connector_hfuncs);
|
| 1100 | ret = drm_connector_init(drm, &epd->connector, &repaper_connector_funcs,
|
| 1101 | DRM_MODE_CONNECTOR_SPI);
|
| 1102 | if (ret)
|
| 1103 | return ret;
|
| 1104 |
|
| 1105 | ret = drm_simple_display_pipe_init(drm, &epd->pipe, &repaper_pipe_funcs,
|
| 1106 | repaper_formats, ARRAY_SIZE(repaper_formats),
|
| 1107 | NULL, &epd->connector);
|
| 1108 | if (ret)
|
| 1109 | return ret;
|
| 1110 |
|
| 1111 | drm_mode_config_reset(drm);
|
| 1112 |
|
| 1113 | ret = drm_dev_register(drm, 0);
|
| 1114 | if (ret)
|
| 1115 | return ret;
|
| 1116 |
|
| 1117 | spi_set_drvdata(spi, drm);
|
| 1118 |
|
| 1119 | DRM_DEBUG_DRIVER("SPI speed: %uMHz\n", spi->max_speed_hz / 1000000);
|
| 1120 |
|
| 1121 | drm_client_setup(drm, NULL);
|
| 1122 |
|
| 1123 | return 0;
|
| 1124 | }
|
| 1125 |
|
| 1126 | static void repaper_remove(struct spi_device *spi)
|
| 1127 | {
|
| 1128 | struct drm_device *drm = spi_get_drvdata(spi);
|
| 1129 |
|
| 1130 | drm_dev_unplug(drm);
|
| 1131 | drm_atomic_helper_shutdown(drm);
|
| 1132 | }
|
| 1133 |
|
| 1134 | static void repaper_shutdown(struct spi_device *spi)
|
| 1135 | {
|
| 1136 | drm_atomic_helper_shutdown(spi_get_drvdata(spi));
|
| 1137 | }
|
| 1138 |
|
| 1139 | static struct spi_driver repaper_spi_driver = {
|
| 1140 | .driver = {
|
| 1141 | .name = "repaper",
|
| 1142 | .of_match_table = repaper_of_match,
|
| 1143 | },
|
| 1144 | .id_table = repaper_id,
|
| 1145 | .probe = repaper_probe,
|
| 1146 | .remove = repaper_remove,
|
| 1147 | .shutdown = repaper_shutdown,
|
| 1148 | };
|
| 1149 | module_spi_driver(repaper_spi_driver);
|
| 1150 |
|
| 1151 | MODULE_DESCRIPTION("Pervasive Displays RePaper DRM driver");
|
| 1152 | MODULE_AUTHOR("Noralf Trønnes");
|
| 1153 | MODULE_LICENSE("GPL");
|