// SPDX-License-Identifier: GPL-2.0-or-later/* * DRM driver for Pervasive Displays RePaper branded e-ink panels * * Copyright 2013-2017 Pervasive Displays, Inc. * Copyright 2017 Noralf Trønnes * * The driver supports: * Material Film: Aurora Mb (V231) * Driver IC: G2 (eTC) * * The controller code was taken from the userspace driver: * https://github.com/repaper/gratis */ #include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/module.h>#include <linux/property.h>#include <linux/sched/clock.h>#include <linux/spi/spi.h>#include <linux/thermal.h> #include <drm/drm_atomic_helper.h>#include <drm/drm_connector.h>#include <drm/drm_damage_helper.h>#include <drm/drm_drv.h>#include <drm/drm_fb_dma_helper.h>#include <drm/drm_fbdev_generic.h>#include <drm/drm_format_helper.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_gem_dma_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_managed.h>#include <drm/drm_modes.h>#include <drm/drm_rect.h>#include <drm/drm_probe_helper.h>#include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID 0x12 enum repaper_model { /* 0 is reserved to avoid clashing with NULL */ E1144CS021 = 1, E1190CS021, E2200CS021, E2271CS021,}; enum repaper_stage { /* Image pixel -> Display pixel */ REPAPER_COMPENSATE, /* B -> W, W -> B (Current Image) */ REPAPER_WHITE, /* B -> N, W -> W (Current Image) */ REPAPER_INVERSE, /* B -> N, W -> B (New Image) */ REPAPER_NORMAL /* B -> B, W -> W (New Image) */}; enum repaper_epd_border_byte { REPAPER_BORDER_BYTE_NONE, REPAPER_BORDER_BYTE_ZERO, REPAPER_BORDER_BYTE_SET,}; struct repaper_epd { struct drm_device drm; struct drm_simple_display_pipe pipe; const struct drm_display_mode *mode; struct drm_connector connector; struct spi_device *spi; struct gpio_desc *panel_on; struct gpio_desc *border; struct gpio_desc *discharge; struct gpio_desc *reset; struct gpio_desc *busy; struct thermal_zone_device *thermal; unsigned int height; unsigned int width; unsigned int bytes_per_scan; const u8 *channel_select; unsigned int stage_time; unsigned int factored_stage_time; bool middle_scan; bool pre_border_byte; enum repaper_epd_border_byte border_byte; u8 *line_buffer; void *current_frame; bool cleared; bool partial;}; static inline struct repaper_epd *drm_to_epd(struct drm_device *drm){ return container_of(drm, struct repaper_epd, drm);} static int repaper_spi_transfer(struct spi_device *spi, u8 header, const void *tx, void *rx, size_t len){ void *txbuf = NULL, *rxbuf = NULL; struct spi_transfer tr[2] = {}; u8 *headerbuf; int ret; headerbuf = kmalloc(1, GFP_KERNEL); if (!headerbuf) return -ENOMEM; headerbuf[0] = header; tr[0].tx_buf = headerbuf; tr[0].len = 1; /* Stack allocated tx? */ if (tx && len <= 32) { txbuf = kmemdup(tx, len, GFP_KERNEL); if (!txbuf) { ret = -ENOMEM; goto out_free; } } if (rx) { rxbuf = kmalloc(len, GFP_KERNEL); if (!rxbuf) { ret = -ENOMEM; goto out_free; } } tr[1].tx_buf = txbuf ? txbuf : tx; tr[1].rx_buf = rxbuf; tr[1].len = len; ndelay(80); ret = spi_sync_transfer(spi, tr, 2); if (rx && !ret) memcpy(rx, rxbuf, len); out_free: kfree(headerbuf); kfree(txbuf); kfree(rxbuf); return ret;} static int repaper_write_buf(struct spi_device *spi, u8 reg, const u8 *buf, size_t len){ int ret; ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1); if (ret) return ret; return repaper_spi_transfer(spi, 0x72, buf, NULL, len);} static int repaper_write_val(struct spi_device *spi, u8 reg, u8 val){ return repaper_write_buf(spi, reg, &val, 1);} static int repaper_read_val(struct spi_device *spi, u8 reg){ int ret; u8 val; ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1); if (ret) return ret; ret = repaper_spi_transfer(spi, 0x73, NULL, &val, 1); return ret ? ret : val;} static int repaper_read_id(struct spi_device *spi){ int ret; u8 id; ret = repaper_spi_transfer(spi, 0x71, NULL, &id, 1); return ret ? ret : id;} static void repaper_spi_mosi_low(struct spi_device *spi){ const u8 buf[1] = { 0 }; spi_write(spi, buf, 1);} /* pixels on display are numbered from 1 so even is actually bits 1,3,5,... */static void repaper_even_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage){ unsigned int b; for (b = 0; b < (epd->width / 8); b++) { if (data) { u8 pixels = data[b] & 0xaa; u8 pixel_mask = 0xff; u8 p1, p2, p3, p4; if (mask) { pixel_mask = (mask[b] ^ pixels) & 0xaa; pixel_mask |= pixel_mask >> 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaa | ((pixels ^ 0xaa) >> 1); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x55 + ((pixels ^ 0xaa) >> 1); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x55 | (pixels ^ 0xaa); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaa | (pixels >> 1); break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55); p1 = (pixels >> 6) & 0x03; p2 = (pixels >> 4) & 0x03; p3 = (pixels >> 2) & 0x03; p4 = (pixels >> 0) & 0x03; pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6); *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; } }} /* pixels on display are numbered from 1 so odd is actually bits 0,2,4,... */static void repaper_odd_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage){ unsigned int b; for (b = epd->width / 8; b > 0; b--) { if (data) { u8 pixels = data[b - 1] & 0x55; u8 pixel_mask = 0xff; if (mask) { pixel_mask = (mask[b - 1] ^ pixels) & 0x55; pixel_mask |= pixel_mask << 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaa | (pixels ^ 0x55); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x55 + (pixels ^ 0x55); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x55 | ((pixels ^ 0x55) << 1); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaa | pixels; break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55); *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; } }} /* interleave bits: (byte)76543210 -> (16 bit).7.6.5.4.3.2.1 */static inline u16 repaper_interleave_bits(u16 value){ value = (value | (value << 4)) & 0x0f0f; value = (value | (value << 2)) & 0x3333; value = (value | (value << 1)) & 0x5555; return value;} /* pixels on display are numbered from 1 */static void repaper_all_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage){ unsigned int b; for (b = epd->width / 8; b > 0; b--) { if (data) { u16 pixels = repaper_interleave_bits(data[b - 1]); u16 pixel_mask = 0xffff; if (mask) { pixel_mask = repaper_interleave_bits(mask[b - 1]); pixel_mask = (pixel_mask ^ pixels) & 0x5555; pixel_mask |= pixel_mask << 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaaaa | (pixels ^ 0x5555); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x5555 + (pixels ^ 0x5555); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x5555 | ((pixels ^ 0x5555) << 1); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaaaa | pixels; break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x5555); *(*pp)++ = pixels >> 8; *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; *(*pp)++ = fixed_value; } }} /* output one line of scan and data bytes to the display */static void repaper_one_line(struct repaper_epd *epd, unsigned int line, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage){ u8 *p = epd->line_buffer; unsigned int b; repaper_spi_mosi_low(epd->spi); if (epd->pre_border_byte) *p++ = 0x00; if (epd->middle_scan) { /* data bytes */ repaper_odd_pixels(epd, &p, data, fixed_value, mask, stage); /* scan line */ for (b = epd->bytes_per_scan; b > 0; b--) { if (line / 4 == b - 1) *p++ = 0x03 << (2 * (line & 0x03)); else *p++ = 0x00; } /* data bytes */ repaper_even_pixels(epd, &p, data, fixed_value, mask, stage); } else { /* * even scan line, but as lines on display are numbered from 1, * line: 1,3,5,... */ for (b = 0; b < epd->bytes_per_scan; b++) { if (0 != (line & 0x01) && line / 8 == b) *p++ = 0xc0 >> (line & 0x06); else *p++ = 0x00; } /* data bytes */ repaper_all_pixels(epd, &p, data, fixed_value, mask, stage); /* * odd scan line, but as lines on display are numbered from 1, * line: 0,2,4,6,... */ for (b = epd->bytes_per_scan; b > 0; b--) { if (0 == (line & 0x01) && line / 8 == b - 1) *p++ = 0x03 << (line & 0x06); else *p++ = 0x00; } } switch (epd->border_byte) { case REPAPER_BORDER_BYTE_NONE: break; case REPAPER_BORDER_BYTE_ZERO: *p++ = 0x00; break; case REPAPER_BORDER_BYTE_SET: switch (stage) { case REPAPER_COMPENSATE: case REPAPER_WHITE: case REPAPER_INVERSE: *p++ = 0x00; break; case REPAPER_NORMAL: *p++ = 0xaa; break; } break; } repaper_write_buf(epd->spi, 0x0a, epd->line_buffer, p - epd->line_buffer); /* Output data to panel */ repaper_write_val(epd->spi, 0x02, 0x07); repaper_spi_mosi_low(epd->spi);} static void repaper_frame_fixed(struct repaper_epd *epd, u8 fixed_value, enum repaper_stage stage){ unsigned int line; for (line = 0; line < epd->height; line++) repaper_one_line(epd, line, NULL, fixed_value, NULL, stage);} static void repaper_frame_data(struct repaper_epd *epd, const u8 *image, const u8 *mask, enum repaper_stage stage){ unsigned int line; if (!mask) { for (line = 0; line < epd->height; line++) { repaper_one_line(epd, line, &image[line * (epd->width / 8)], 0, NULL, stage); } } else { for (line = 0; line < epd->height; line++) { size_t n = line * epd->width / 8; repaper_one_line(epd, line, &image[n], 0, &mask[n], stage); } }} static void repaper_frame_fixed_repeat(struct repaper_epd *epd, u8 fixed_value, enum repaper_stage stage){ u64 start = local_clock(); u64 end = start + (epd->factored_stage_time * 1000 * 1000); do { repaper_frame_fixed(epd, fixed_value, stage); } while (local_clock() < end);} static void repaper_frame_data_repeat(struct repaper_epd *epd, const u8 *image, const u8 *mask, enum repaper_stage stage){ u64 start = local_clock(); u64 end = start + (epd->factored_stage_time * 1000 * 1000); do { repaper_frame_data(epd, image, mask, stage); } while (local_clock() < end);} static void repaper_get_temperature(struct repaper_epd *epd){ int ret, temperature = 0; unsigned int factor10x; if (!epd->thermal) return; ret = thermal_zone_get_temp(epd->thermal, &temperature); if (ret) { DRM_DEV_ERROR(&epd->spi->dev, "Failed to get temperature (%d)\n", ret); return; } temperature /= 1000; if (temperature <= -10) factor10x = 170; else if (temperature <= -5) factor10x = 120; else if (temperature <= 5) factor10x = 80; else if (temperature <= 10) factor10x = 40; else if (temperature <= 15)Lines 1–500 of 1149. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * DRM driver for Pervasive Displays RePaper branded e-ink panels * * Copyright 2013-2017 Pervasive Displays, Inc. * Copyright 2017 Noralf Trønnes * * The driver supports: * Material Film: Aurora Mb (V231) * Driver IC: G2 (eTC) * * The controller code was taken from the userspace driver: * https://github.com/repaper/gratis */ #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/property.h> #include <linux/sched/clock.h> #include <linux/spi/spi.h> #include <linux/thermal.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fbdev_generic.h> #include <drm/drm_format_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_modes.h> #include <drm/drm_rect.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID 0x12 enum repaper_model { /* 0 is reserved to avoid clashing with NULL */ E1144CS021 = 1, E1190CS021, E2200CS021, E2271CS021, }; enum repaper_stage { /* Image pixel -> Display pixel */ REPAPER_COMPENSATE, /* B -> W, W -> B (Current Image) */ REPAPER_WHITE, /* B -> N, W -> W (Current Image) */ REPAPER_INVERSE, /* B -> N, W -> B (New Image) */ REPAPER_NORMAL /* B -> B, W -> W (New Image) */ }; enum repaper_epd_border_byte { REPAPER_BORDER_BYTE_NONE, REPAPER_BORDER_BYTE_ZERO, REPAPER_BORDER_BYTE_SET, }; struct repaper_epd { struct drm_device drm; struct drm_simple_display_pipe pipe; const struct drm_display_mode *mode; struct drm_connector connector; struct spi_device *spi; struct gpio_desc *panel_on; struct gpio_desc *border; struct gpio_desc *discharge; struct gpio_desc *reset; struct gpio_desc *busy; struct thermal_zone_device *thermal; unsigned int height; unsigned int width; unsigned int bytes_per_scan; const u8 *channel_select; unsigned int stage_time; unsigned int factored_stage_time; bool middle_scan; bool pre_border_byte; enum repaper_epd_border_byte border_byte; u8 *line_buffer; void *current_frame; bool cleared; bool partial; }; static inline struct repaper_epd *drm_to_epd(struct drm_device *drm) { return container_of(drm, struct repaper_epd, drm); } static int repaper_spi_transfer(struct spi_device *spi, u8 header, const void *tx, void *rx, size_t len) { void *txbuf = NULL, *rxbuf = NULL; struct spi_transfer tr[2] = {}; u8 *headerbuf; int ret; headerbuf = kmalloc(1, GFP_KERNEL); if (!headerbuf) return -ENOMEM; headerbuf[0] = header; tr[0].tx_buf = headerbuf; tr[0].len = 1; /* Stack allocated tx? */ if (tx && len <= 32) { txbuf = kmemdup(tx, len, GFP_KERNEL); if (!txbuf) { ret = -ENOMEM; goto out_free; } } if (rx) { rxbuf = kmalloc(len, GFP_KERNEL); if (!rxbuf) { ret = -ENOMEM; goto out_free; } } tr[1].tx_buf = txbuf ? txbuf : tx; tr[1].rx_buf = rxbuf; tr[1].len = len; ndelay(80); ret = spi_sync_transfer(spi, tr, 2); if (rx && !ret) memcpy(rx, rxbuf, len); out_free: kfree(headerbuf); kfree(txbuf); kfree(rxbuf); return ret; } static int repaper_write_buf(struct spi_device *spi, u8 reg, const u8 *buf, size_t len) { int ret; ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1); if (ret) return ret; return repaper_spi_transfer(spi, 0x72, buf, NULL, len); } static int repaper_write_val(struct spi_device *spi, u8 reg, u8 val) { return repaper_write_buf(spi, reg, &val, 1); } static int repaper_read_val(struct spi_device *spi, u8 reg) { int ret; u8 val; ret = repaper_spi_transfer(spi, 0x70, ®, NULL, 1); if (ret) return ret; ret = repaper_spi_transfer(spi, 0x73, NULL, &val, 1); return ret ? ret : val; } static int repaper_read_id(struct spi_device *spi) { int ret; u8 id; ret = repaper_spi_transfer(spi, 0x71, NULL, &id, 1); return ret ? ret : id; } static void repaper_spi_mosi_low(struct spi_device *spi) { const u8 buf[1] = { 0 }; spi_write(spi, buf, 1); } /* pixels on display are numbered from 1 so even is actually bits 1,3,5,... */ static void repaper_even_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage) { unsigned int b; for (b = 0; b < (epd->width / 8); b++) { if (data) { u8 pixels = data[b] & 0xaa; u8 pixel_mask = 0xff; u8 p1, p2, p3, p4; if (mask) { pixel_mask = (mask[b] ^ pixels) & 0xaa; pixel_mask |= pixel_mask >> 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaa | ((pixels ^ 0xaa) >> 1); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x55 + ((pixels ^ 0xaa) >> 1); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x55 | (pixels ^ 0xaa); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaa | (pixels >> 1); break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55); p1 = (pixels >> 6) & 0x03; p2 = (pixels >> 4) & 0x03; p3 = (pixels >> 2) & 0x03; p4 = (pixels >> 0) & 0x03; pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6); *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; } } } /* pixels on display are numbered from 1 so odd is actually bits 0,2,4,... */ static void repaper_odd_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage) { unsigned int b; for (b = epd->width / 8; b > 0; b--) { if (data) { u8 pixels = data[b - 1] & 0x55; u8 pixel_mask = 0xff; if (mask) { pixel_mask = (mask[b - 1] ^ pixels) & 0x55; pixel_mask |= pixel_mask << 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaa | (pixels ^ 0x55); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x55 + (pixels ^ 0x55); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x55 | ((pixels ^ 0x55) << 1); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaa | pixels; break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55); *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; } } } /* interleave bits: (byte)76543210 -> (16 bit).7.6.5.4.3.2.1 */ static inline u16 repaper_interleave_bits(u16 value) { value = (value | (value << 4)) & 0x0f0f; value = (value | (value << 2)) & 0x3333; value = (value | (value << 1)) & 0x5555; return value; } /* pixels on display are numbered from 1 */ static void repaper_all_pixels(struct repaper_epd *epd, u8 **pp, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage) { unsigned int b; for (b = epd->width / 8; b > 0; b--) { if (data) { u16 pixels = repaper_interleave_bits(data[b - 1]); u16 pixel_mask = 0xffff; if (mask) { pixel_mask = repaper_interleave_bits(mask[b - 1]); pixel_mask = (pixel_mask ^ pixels) & 0x5555; pixel_mask |= pixel_mask << 1; } switch (stage) { case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */ pixels = 0xaaaa | (pixels ^ 0x5555); break; case REPAPER_WHITE: /* B -> N, W -> W (Current) */ pixels = 0x5555 + (pixels ^ 0x5555); break; case REPAPER_INVERSE: /* B -> N, W -> B (New) */ pixels = 0x5555 | ((pixels ^ 0x5555) << 1); break; case REPAPER_NORMAL: /* B -> B, W -> W (New) */ pixels = 0xaaaa | pixels; break; } pixels = (pixels & pixel_mask) | (~pixel_mask & 0x5555); *(*pp)++ = pixels >> 8; *(*pp)++ = pixels; } else { *(*pp)++ = fixed_value; *(*pp)++ = fixed_value; } } } /* output one line of scan and data bytes to the display */ static void repaper_one_line(struct repaper_epd *epd, unsigned int line, const u8 *data, u8 fixed_value, const u8 *mask, enum repaper_stage stage) { u8 *p = epd->line_buffer; unsigned int b; repaper_spi_mosi_low(epd->spi); if (epd->pre_border_byte) *p++ = 0x00; if (epd->middle_scan) { /* data bytes */ repaper_odd_pixels(epd, &p, data, fixed_value, mask, stage); /* scan line */ for (b = epd->bytes_per_scan; b > 0; b--) { if (line / 4 == b - 1) *p++ = 0x03 << (2 * (line & 0x03)); else *p++ = 0x00; } /* data bytes */ repaper_even_pixels(epd, &p, data, fixed_value, mask, stage); } else { /* * even scan line, but as lines on display are numbered from 1, * line: 1,3,5,... */ for (b = 0; b < epd->bytes_per_scan; b++) { if (0 != (line & 0x01) && line / 8 == b) *p++ = 0xc0 >> (line & 0x06); else *p++ = 0x00; } /* data bytes */ repaper_all_pixels(epd, &p, data, fixed_value, mask, stage); /* * odd scan line, but as lines on display are numbered from 1, * line: 0,2,4,6,... */ for (b = epd->bytes_per_scan; b > 0; b--) { if (0 == (line & 0x01) && line / 8 == b - 1) *p++ = 0x03 << (line & 0x06); else *p++ = 0x00; } } switch (epd->border_byte) { case REPAPER_BORDER_BYTE_NONE: break; case REPAPER_BORDER_BYTE_ZERO: *p++ = 0x00; break; case REPAPER_BORDER_BYTE_SET: switch (stage) { case REPAPER_COMPENSATE: case REPAPER_WHITE: case REPAPER_INVERSE: *p++ = 0x00; break; case REPAPER_NORMAL: *p++ = 0xaa; break; } break; } repaper_write_buf(epd->spi, 0x0a, epd->line_buffer, p - epd->line_buffer); /* Output data to panel */ repaper_write_val(epd->spi, 0x02, 0x07); repaper_spi_mosi_low(epd->spi); } static void repaper_frame_fixed(struct repaper_epd *epd, u8 fixed_value, enum repaper_stage stage) { unsigned int line; for (line = 0; line < epd->height; line++) repaper_one_line(epd, line, NULL, fixed_value, NULL, stage); } static void repaper_frame_data(struct repaper_epd *epd, const u8 *image, const u8 *mask, enum repaper_stage stage) { unsigned int line; if (!mask) { for (line = 0; line < epd->height; line++) { repaper_one_line(epd, line, &image[line * (epd->width / 8)], 0, NULL, stage); } } else { for (line = 0; line < epd->height; line++) { size_t n = line * epd->width / 8; repaper_one_line(epd, line, &image[n], 0, &mask[n], stage); } } } static void repaper_frame_fixed_repeat(struct repaper_epd *epd, u8 fixed_value, enum repaper_stage stage) { u64 start = local_clock(); u64 end = start + (epd->factored_stage_time * 1000 * 1000); do { repaper_frame_fixed(epd, fixed_value, stage); } while (local_clock() < end); } static void repaper_frame_data_repeat(struct repaper_epd *epd, const u8 *image, const u8 *mask, enum repaper_stage stage) { u64 start = local_clock(); u64 end = start + (epd->factored_stage_time * 1000 * 1000); do { repaper_frame_data(epd, image, mask, stage); } while (local_clock() < end); } static void repaper_get_temperature(struct repaper_epd *epd) { int ret, temperature = 0; unsigned int factor10x; if (!epd->thermal) return; ret = thermal_zone_get_temp(epd->thermal, &temperature); if (ret) { DRM_DEV_ERROR(&epd->spi->dev, "Failed to get temperature (%d)\n", ret); return; } temperature /= 1000; if (temperature <= -10) factor10x = 170; else if (temperature <= -5) factor10x = 120; else if (temperature <= 5) factor10x = 80; else if (temperature <= 10) factor10x = 40; else if (temperature <= 15)