File Index
Files and directories
Sign in
FILE

pixpaper.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/tiny/pixpaper.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * DRM driver for PIXPAPER e-ink panel
   4 *
   5 * Author: LiangCheng Wang <zaq14760@gmail.com>,
   6 */
   7#include <linux/delay.h>
   8#include <linux/module.h>
   9#include <linux/spi/spi.h>
  10
  11#include <drm/clients/drm_client_setup.h>
  12#include <drm/drm_atomic.h>
  13#include <drm/drm_atomic_helper.h>
  14#include <drm/drm_drv.h>
  15#include <drm/drm_fbdev_shmem.h>
  16#include <drm/drm_framebuffer.h>
  17#include <drm/drm_gem_atomic_helper.h>
  18#include <drm/drm_gem_shmem_helper.h>
  19#include <drm/drm_gem_framebuffer_helper.h>
  20#include <drm/drm_print.h>
  21#include <drm/drm_probe_helper.h>
  22
  23/*
  24 * Note on Undocumented Commands/Registers:
  25 *
  26 * Several commands and register parameters defined in this header are not
  27 * documented in the datasheet. Their values and usage have been derived
  28 * through analysis of existing userspace example programs.
  29 *
  30 * These 'unknown' definitions are crucial for the proper initialization
  31 * and stable operation of the panel. Modifying these values without
  32 * thorough understanding may lead to display anomalies, panel damage,
  33 * or unexpected behavior.
  34 */
  35
  36/* Command definitions */
  37#define PIXPAPER_CMD_PANEL_SETTING 0x00	/* R00H: Panel settings */
  38#define PIXPAPER_CMD_POWER_SETTING 0x01	/* R01H: Power settings */
  39#define PIXPAPER_CMD_POWER_OFF 0x02		/* R02H: Power off */
  40#define PIXPAPER_CMD_POWER_OFF_SEQUENCE 0x03	/* R03H: Power off sequence */
  41#define PIXPAPER_CMD_POWER_ON 0x04		/* R04H: Power on */
  42#define PIXPAPER_CMD_BOOSTER_SOFT_START 0x06	/* R06H: Booster soft start */
  43#define PIXPAPER_CMD_DEEP_SLEEP 0x07		/* R07H: Deep sleep */
  44#define PIXPAPER_CMD_DATA_START_TRANSMISSION 0x10
  45/* R10H: Data transmission start */
  46#define PIXPAPER_CMD_DISPLAY_REFRESH 0x12	/* R12H: Display refresh */
  47#define PIXPAPER_CMD_PLL_CONTROL 0x30		/* R30H: PLL control */
  48#define PIXPAPER_CMD_TEMP_SENSOR_CALIB 0x41
  49/* R41H: Temperature sensor calibration */
  50#define PIXPAPER_CMD_UNKNOWN_4D 0x4D		/* R4DH: Unknown command */
  51#define PIXPAPER_CMD_VCOM_INTERVAL 0x50	/* R50H: VCOM interval */
  52#define PIXPAPER_CMD_UNKNOWN_60 0x60		/* R60H: Unknown command */
  53#define PIXPAPER_CMD_RESOLUTION_SETTING 0x61	/* R61H: Resolution settings */
  54#define PIXPAPER_CMD_GATE_SOURCE_START 0x65	/* R65H: Gate/source start */
  55#define PIXPAPER_CMD_UNKNOWN_B4 0xB4		/* RB4H: Unknown command */
  56#define PIXPAPER_CMD_UNKNOWN_B5 0xB5		/* RB5H: Unknown command */
  57#define PIXPAPER_CMD_UNKNOWN_E0 0xE0		/* RE0H: Unknown command */
  58#define PIXPAPER_CMD_POWER_SAVING 0xE3		/* RE3H: Power saving */
  59#define PIXPAPER_CMD_UNKNOWN_E7 0xE7		/* RE7H: Unknown command */
  60#define PIXPAPER_CMD_UNKNOWN_E9 0xE9		/* RE9H: Unknown command */
  61
  62/* R00H PSR - First Parameter */
  63#define PIXPAPER_PSR_RST_N BIT(0)
  64/* Bit 0: RST_N, 1=no effect (default), 0=reset with booster OFF */
  65#define PIXPAPER_PSR_SHD_N BIT(1)
  66/* Bit 1: SHD_N, 1=booster ON (default), 0=booster OFF */
  67#define PIXPAPER_PSR_SHL BIT(2)
  68/* Bit 2: SHL, 1=shift right (default), 0=shift left */
  69#define PIXPAPER_PSR_UD BIT(3)
  70/* Bit 3: UD, 1=scan up (default), 0=scan down */
  71#define PIXPAPER_PSR_PST_MODE BIT(5)
  72/* Bit 5: PST_MODE, 0=frame scanning (default), 1=external */
  73#define PIXPAPER_PSR_RES_MASK (3 << 6)
  74/* Bits 7-6: RES[1:0], resolution setting */
  75#define PIXPAPER_PSR_RES_176x296 (0x0 << 6)	/* 00: 176x296 */
  76#define PIXPAPER_PSR_RES_128x296 (0x1 << 6)	/* 01: 128x296 */
  77#define PIXPAPER_PSR_RES_128x250 (0x2 << 6)	/* 10: 128x250 */
  78#define PIXPAPER_PSR_RES_112x204 (0x3 << 6)	/* 11: 112x204 */
  79#define PIXPAPER_PSR_CONFIG                                           \
  80	(PIXPAPER_PSR_RST_N | PIXPAPER_PSR_SHD_N | PIXPAPER_PSR_SHL | \
  81	 PIXPAPER_PSR_UD)
  82/* 0x0F: Default settings, resolution set by R61H */
  83
  84/* R00H PSR - Second Parameter */
  85#define PIXPAPER_PSR2_VC_LUTZ \
  86	(1 << 0) /* Bit 0: VC_LUTZ, 1=VCOM float after refresh (default), 0=no effect */
  87#define PIXPAPER_PSR2_NORG \
  88	(1 << 1) /* Bit 1: NORG, 1=VCOM to GND before power off, 0=no effect (default) */
  89#define PIXPAPER_PSR2_TIEG \
  90	(1 << 2) /* Bit 2: TIEG, 1=VGN to GND on power off, 0=no effect (default) */
  91#define PIXPAPER_PSR2_TS_AUTO \
  92	(1 << 3) /* Bit 3: TS_AUTO, 1=sensor on RST_N low to high (default), 0=on booster */
  93#define PIXPAPER_PSR2_VCMZ \
  94	(1 << 4) /* Bit 4: VCMZ, 1=VCOM always floating, 0=no effect (default) */
  95#define PIXPAPER_PSR2_FOPT \
  96	(1 << 5) /* Bit 5: FOPT, 0=scan 1 frame (default), 1=no scan, HiZ */
  97#define PIXPAPER_PSR_CONFIG2     \
  98	(PIXPAPER_PSR2_VC_LUTZ | \
  99	 PIXPAPER_PSR2_TS_AUTO) /* 0x09: Default VCOM and temp sensor settings */
 100
 101/* R01H PWR - Power Setting Register */
 102/* First Parameter */
 103#define PIXPAPER_PWR_VDG_EN \
 104	(1 << 0) /* Bit 0: VDG_EN, 1=internal DCDC for VGP/VGN (default), 0=external */
 105#define PIXPAPER_PWR_VDS_EN \
 106	(1 << 1) /* Bit 1: VDS_EN, 1=internal regulator for VSP/VSN (default), 0=external */
 107#define PIXPAPER_PWR_VSC_EN \
 108	(1 << 2) /* Bit 2: VSC_EN, 1=internal regulator for VSPL (default), 0=external */
 109#define PIXPAPER_PWR_V_MODE \
 110	(1 << 3) /* Bit 3: V_MODE, 0=Mode0 (default), 1=Mode1 */
 111#define PIXPAPER_PWR_CONFIG1                         \
 112	(PIXPAPER_PWR_VDG_EN | PIXPAPER_PWR_VDS_EN | \
 113	 PIXPAPER_PWR_VSC_EN) /* 0x07: Internal power for VGP/VGN, VSP/VSN, VSPL */
 114
 115/* Second Parameter */
 116#define PIXPAPER_PWR_VGPN_MASK \
 117	(3 << 0) /* Bits 1-0: VGPN, VGP/VGN voltage levels */
 118#define PIXPAPER_PWR_VGPN_20V (0x0 << 0) /* 00: VGP=20V, VGN=-20V (default) */
 119#define PIXPAPER_PWR_VGPN_17V (0x1 << 0) /* 01: VGP=17V, VGN=-17V */
 120#define PIXPAPER_PWR_VGPN_15V (0x2 << 0) /* 10: VGP=15V, VGN=-15V */
 121#define PIXPAPER_PWR_VGPN_10V (0x3 << 0) /* 11: VGP=10V, VGN=-10V */
 122#define PIXPAPER_PWR_CONFIG2 PIXPAPER_PWR_VGPN_20V /* 0x00: VGP=20V, VGN=-20V */
 123
 124/* Third, Fourth, Sixth Parameters (VSP_1, VSPL_0, VSPL_1) */
 125#define PIXPAPER_PWR_VSP_8_2V 0x22 /* VSP_1/VSPL_1: 8.2V (34 decimal) */
 126#define PIXPAPER_PWR_VSPL_15V 0x78 /* VSPL_0: 15V (120 decimal) */
 127
 128/* Fifth Parameter (VSN_1) */
 129#define PIXPAPER_PWR_VSN_4V 0x0A /* VSN_1: -4V (10 decimal) */
 130
 131/* R03H PFS - Power Off Sequence Setting Register */
 132/* First Parameter */
 133#define PIXPAPER_PFS_T_VDS_OFF_MASK \
 134	(3 << 0) /* Bits 1-0: T_VDS_OFF, VSP/VSN power-off sequence */
 135#define PIXPAPER_PFS_T_VDS_OFF_20MS (0x0 << 0) /* 00: 20 ms (default) */
 136#define PIXPAPER_PFS_T_VDS_OFF_40MS (0x1 << 0) /* 01: 40 ms */
 137#define PIXPAPER_PFS_T_VDS_OFF_60MS (0x2 << 0) /* 10: 60 ms */
 138#define PIXPAPER_PFS_T_VDS_OFF_80MS (0x3 << 0) /* 11: 80 ms */
 139#define PIXPAPER_PFS_T_VDPG_OFF_MASK \
 140	(3 << 4) /* Bits 5-4: T_VDPG_OFF, VGP/VGN power-off sequence */
 141#define PIXPAPER_PFS_T_VDPG_OFF_20MS (0x0 << 4) /* 00: 20 ms (default) */
 142#define PIXPAPER_PFS_T_VDPG_OFF_40MS (0x1 << 4) /* 01: 40 ms */
 143#define PIXPAPER_PFS_T_VDPG_OFF_60MS (0x2 << 4) /* 10: 60 ms */
 144#define PIXPAPER_PFS_T_VDPG_OFF_80MS (0x3 << 4) /* 11: 80 ms */
 145#define PIXPAPER_PFS_CONFIG1           \
 146	(PIXPAPER_PFS_T_VDS_OFF_20MS | \
 147	 PIXPAPER_PFS_T_VDPG_OFF_20MS) /* 0x10: Default 20 ms for VSP/VSN and VGP/VGN */
 148
 149/* Second Parameter */
 150#define PIXPAPER_PFS_VGP_EXT_MASK \
 151	(0xF << 0) /* Bits 3-0: VGP_EXT, VGP extension time */
 152#define PIXPAPER_PFS_VGP_EXT_0MS (0x0 << 0) /* 0000: 0 ms */
 153#define PIXPAPER_PFS_VGP_EXT_500MS (0x1 << 0) /* 0001: 500 ms */
 154#define PIXPAPER_PFS_VGP_EXT_1000MS (0x2 << 0) /* 0010: 1000 ms */
 155#define PIXPAPER_PFS_VGP_EXT_1500MS (0x3 << 0) /* 0011: 1500 ms */
 156#define PIXPAPER_PFS_VGP_EXT_2000MS (0x4 << 0) /* 0100: 2000 ms (default) */
 157#define PIXPAPER_PFS_VGP_EXT_2500MS (0x5 << 0) /* 0101: 2500 ms */
 158#define PIXPAPER_PFS_VGP_EXT_3000MS (0x6 << 0) /* 0110: 3000 ms */
 159#define PIXPAPER_PFS_VGP_EXT_3500MS (0x7 << 0) /* 0111: 3500 ms */
 160#define PIXPAPER_PFS_VGP_EXT_4000MS (0x8 << 0) /* 1000: 4000 ms */
 161#define PIXPAPER_PFS_VGP_EXT_4500MS (0x9 << 0) /* 1001: 4500 ms */
 162#define PIXPAPER_PFS_VGP_EXT_5000MS (0xA << 0) /* 1010: 5000 ms */
 163#define PIXPAPER_PFS_VGP_EXT_5500MS (0xB << 0) /* 1011: 5500 ms */
 164#define PIXPAPER_PFS_VGP_EXT_6000MS (0xC << 0) /* 1100: 6000 ms */
 165#define PIXPAPER_PFS_VGP_EXT_6500MS (0xD << 0) /* 1101: 6500 ms */
 166#define PIXPAPER_PFS_VGP_LEN_MASK \
 167	(0xF << 4) /* Bits 7-4: VGP_LEN, VGP at 10V during power-off */
 168#define PIXPAPER_PFS_VGP_LEN_0MS (0x0 << 4) /* 0000: 0 ms */
 169#define PIXPAPER_PFS_VGP_LEN_500MS (0x1 << 4) /* 0001: 500 ms */
 170#define PIXPAPER_PFS_VGP_LEN_1000MS (0x2 << 4) /* 0010: 1000 ms */
 171#define PIXPAPER_PFS_VGP_LEN_1500MS (0x3 << 4) /* 0011: 1500 ms */
 172#define PIXPAPER_PFS_VGP_LEN_2000MS (0x4 << 4) /* 0100: 2000 ms */
 173#define PIXPAPER_PFS_VGP_LEN_2500MS (0x5 << 4) /* 0101: 2500 ms (default) */
 174#define PIXPAPER_PFS_VGP_LEN_3000MS (0x6 << 4) /* 0110: 3000 ms */
 175#define PIXPAPER_PFS_VGP_LEN_3500MS (0x7 << 4) /* 0111: 3500 ms */
 176#define PIXPAPER_PFS_VGP_LEN_4000MS (0x8 << 4) /* 1000: 4000 ms */
 177#define PIXPAPER_PFS_VGP_LEN_4500MS (0x9 << 4) /* 1001: 4500 ms */
 178#define PIXPAPER_PFS_VGP_LEN_5000MS (0xA << 4) /* 1010: 5000 ms */
 179#define PIXPAPER_PFS_VGP_LEN_5500MS (0xB << 4) /* 1011: 5500 ms */
 180#define PIXPAPER_PFS_VGP_LEN_6000MS (0xC << 4) /* 1100: 6000 ms */
 181#define PIXPAPER_PFS_VGP_LEN_6500MS (0xD << 4) /* 1101: 6500 ms */
 182#define PIXPAPER_PFS_CONFIG2           \
 183	(PIXPAPER_PFS_VGP_EXT_1000MS | \
 184	 PIXPAPER_PFS_VGP_LEN_2500MS) /* 0x54: VGP extension 1000 ms, VGP at 10V for 2500 ms */
 185
 186/* Third Parameter */
 187#define PIXPAPER_PFS_XON_LEN_MASK \
 188	(0xF << 0) /* Bits 3-0: XON_LEN, XON enable time */
 189#define PIXPAPER_PFS_XON_LEN_0MS (0x0 << 0) /* 0000: 0 ms */
 190#define PIXPAPER_PFS_XON_LEN_500MS (0x1 << 0) /* 0001: 500 ms */
 191#define PIXPAPER_PFS_XON_LEN_1000MS (0x2 << 0) /* 0010: 1000 ms */
 192#define PIXPAPER_PFS_XON_LEN_1500MS (0x3 << 0) /* 0011: 1500 ms */
 193#define PIXPAPER_PFS_XON_LEN_2000MS (0x4 << 0) /* 0100: 2000 ms (default) */
 194#define PIXPAPER_PFS_XON_LEN_2500MS (0x5 << 0) /* 0101: 2500 ms */
 195#define PIXPAPER_PFS_XON_LEN_3000MS (0x6 << 0) /* 0110: 3000 ms */
 196#define PIXPAPER_PFS_XON_LEN_3500MS (0x7 << 0) /* 0111: 3500 ms */
 197#define PIXPAPER_PFS_XON_LEN_4000MS (0x8 << 0) /* 1000: 4000 ms */
 198#define PIXPAPER_PFS_XON_LEN_4500MS (0x9 << 0) /* 1001: 4500 ms */
 199#define PIXPAPER_PFS_XON_LEN_5000MS (0xA << 0) /* 1010: 5000 ms */
 200#define PIXPAPER_PFS_XON_LEN_5500MS (0xB << 0) /* 1011: 5500 ms */
 201#define PIXPAPER_PFS_XON_LEN_6000MS (0xC << 0) /* 1100: 6000 ms */
 202#define PIXPAPER_PFS_XON_DLY_MASK \
 203	(0xF << 4) /* Bits 7-4: XON_DLY, XON delay time */
 204#define PIXPAPER_PFS_XON_DLY_0MS (0x0 << 4) /* 0000: 0 ms */
 205#define PIXPAPER_PFS_XON_DLY_500MS (0x1 << 4) /* 0001: 500 ms */
 206#define PIXPAPER_PFS_XON_DLY_1000MS (0x2 << 4) /* 0010: 1000 ms */
 207#define PIXPAPER_PFS_XON_DLY_1500MS (0x3 << 4) /* 0011: 1500 ms */
 208#define PIXPAPER_PFS_XON_DLY_2000MS (0x4 << 4) /* 0100: 2000 ms (default) */
 209#define PIXPAPER_PFS_XON_DLY_2500MS (0x5 << 4) /* 0101: 2500 ms */
 210#define PIXPAPER_PFS_XON_DLY_3000MS (0x6 << 4) /* 0110: 3000 ms */
 211#define PIXPAPER_PFS_XON_DLY_3500MS (0x7 << 4) /* 0111: 3500 ms */
 212#define PIXPAPER_PFS_XON_DLY_4000MS (0x8 << 4) /* 1000: 4000 ms */
 213#define PIXPAPER_PFS_XON_DLY_4500MS (0x9 << 4) /* 1001: 4500 ms */
 214#define PIXPAPER_PFS_XON_DLY_5000MS (0xA << 4) /* 1010: 5000 ms */
 215#define PIXPAPER_PFS_XON_DLY_5500MS (0xB << 4) /* 1011: 5500 ms */
 216#define PIXPAPER_PFS_XON_DLY_6000MS (0xC << 4) /* 1100: 6000 ms */
 217#define PIXPAPER_PFS_CONFIG3           \
 218	(PIXPAPER_PFS_XON_LEN_2000MS | \
 219	 PIXPAPER_PFS_XON_DLY_2000MS) /* 0x44: XON enable and delay at 2000 ms */
 220
 221/* R06H BTST - Booster Soft Start Command */
 222/* First Parameter */
 223#define PIXPAPER_BTST_PHA_SFT_MASK \
 224	(3 << 0) /* Bits 1-0: PHA_SFT, soft start period for phase A */
 225#define PIXPAPER_BTST_PHA_SFT_10MS (0x0 << 0) /* 00: 10 ms (default) */
 226#define PIXPAPER_BTST_PHA_SFT_20MS (0x1 << 0) /* 01: 20 ms */
 227#define PIXPAPER_BTST_PHA_SFT_30MS (0x2 << 0) /* 10: 30 ms */
 228#define PIXPAPER_BTST_PHA_SFT_40MS (0x3 << 0) /* 11: 40 ms */
 229#define PIXPAPER_BTST_PHB_SFT_MASK \
 230	(3 << 2) /* Bits 3-2: PHB_SFT, soft start period for phase B */
 231#define PIXPAPER_BTST_PHB_SFT_10MS (0x0 << 2) /* 00: 10 ms (default) */
 232#define PIXPAPER_BTST_PHB_SFT_20MS (0x1 << 2) /* 01: 20 ms */
 233#define PIXPAPER_BTST_PHB_SFT_30MS (0x2 << 2) /* 10: 30 ms */
 234#define PIXPAPER_BTST_PHB_SFT_40MS (0x3 << 2) /* 11: 40 ms */
 235#define PIXPAPER_BTST_CONFIG1         \
 236	(PIXPAPER_BTST_PHA_SFT_40MS | \
 237	 PIXPAPER_BTST_PHB_SFT_40MS) /* 0x0F: 40 ms for phase A and B */
 238
 239/* Second to Seventh Parameters (Driving Strength or Minimum OFF Time) */
 240#define PIXPAPER_BTST_CONFIG2 0x0A /* Strength11 */
 241#define PIXPAPER_BTST_CONFIG3 0x2F /* Period48 */
 242#define PIXPAPER_BTST_CONFIG4 0x25 /* Strength38 */
 243#define PIXPAPER_BTST_CONFIG5 0x22 /* Period35 */
 244#define PIXPAPER_BTST_CONFIG6 0x2E /* Strength47 */
 245#define PIXPAPER_BTST_CONFIG7 0x21 /* Period34 */
 246
 247/* R12H: DRF (Display Refresh) */
 248#define PIXPAPER_DRF_VCOM_AC 0x00 /* AC VCOM: VCOM follows LUTC (default) */
 249#define PIXPAPER_DRF_VCOM_DC 0x01 /* DC VCOM: VCOM fixed to VCOMDC */
 250
 251/* R30H PLL - PLL Control Register */
 252/* First Parameter */
 253#define PIXPAPER_PLL_FR_MASK (0x7 << 0) /* Bits 2-0: FR, frame rate */
 254#define PIXPAPER_PLL_FR_12_5HZ (0x0 << 0) /* 000: 12.5 Hz */
 255#define PIXPAPER_PLL_FR_25HZ (0x1 << 0)	/* 001: 25 Hz */
 256#define PIXPAPER_PLL_FR_50HZ (0x2 << 0) /* 010: 50 Hz (default) */
 257#define PIXPAPER_PLL_FR_65HZ (0x3 << 0) /* 011: 65 Hz */
 258#define PIXPAPER_PLL_FR_75HZ (0x4 << 0) /* 100: 75 Hz */
 259#define PIXPAPER_PLL_FR_85HZ (0x5 << 0) /* 101: 85 Hz */
 260#define PIXPAPER_PLL_FR_100HZ (0x6 << 0) /* 110: 100 Hz */
 261#define PIXPAPER_PLL_FR_120HZ (0x7 << 0) /* 111: 120 Hz */
 262#define PIXPAPER_PLL_DFR \
 263	(1 << 3) /* Bit 3: Dynamic frame rate, 0=disabled (default), 1=enabled */
 264#define PIXPAPER_PLL_CONFIG \
 265	(PIXPAPER_PLL_FR_50HZ) /* 0x02: 50 Hz, dynamic frame rate disabled */
 266
 267/* R41H TSE - Temperature Sensor Calibration Register */
 268/* First Parameter */
 269#define PIXPAPER_TSE_TO_MASK \
 270	(0xF << 0) /* Bits 3-0: TO[3:0], temperature offset */
 271#define PIXPAPER_TSE_TO_POS_0C (0x0 << 0) /* 0000: +0°C (default) */
 272#define PIXPAPER_TSE_TO_POS_0_5C (0x1 << 0) /* 0001: +0.5°C */
 273#define PIXPAPER_TSE_TO_POS_1C (0x2 << 0) /* 0010: +1°C */
 274#define PIXPAPER_TSE_TO_POS_1_5C (0x3 << 0) /* 0011: +1.5°C */
 275#define PIXPAPER_TSE_TO_POS_2C (0x4 << 0) /* 0100: +2°C */
 276#define PIXPAPER_TSE_TO_POS_2_5C (0x5 << 0) /* 0101: +2.5°C */
 277#define PIXPAPER_TSE_TO_POS_3C (0x6 << 0) /* 0110: +3°C */
 278#define PIXPAPER_TSE_TO_POS_3_5C (0x7 << 0) /* 0111: +3.5°C */
 279#define PIXPAPER_TSE_TO_NEG_4C (0x8 << 0) /* 1000: -4°C */
 280#define PIXPAPER_TSE_TO_NEG_3_5C (0x9 << 0) /* 1001: -3.5°C */
 281#define PIXPAPER_TSE_TO_NEG_3C (0xA << 0) /* 1010: -3°C */
 282#define PIXPAPER_TSE_TO_NEG_2_5C (0xB << 0) /* 1011: -2.5°C */
 283#define PIXPAPER_TSE_TO_NEG_2C (0xC << 0) /* 1100: -2°C */
 284#define PIXPAPER_TSE_TO_NEG_1_5C (0xD << 0) /* 1101: -1.5°C */
 285#define PIXPAPER_TSE_TO_NEG_1C (0xE << 0) /* 1110: -1°C */
 286#define PIXPAPER_TSE_TO_NEG_0_5C (0xF << 0) /* 1111: -0.5°C */
 287#define PIXPAPER_TSE_TO_FINE_MASK \
 288	(0x3 << 4) /* Bits 5-4: TO[5:4], fine adjustment for positive offsets */
 289#define PIXPAPER_TSE_TO_FINE_0C (0x0 << 4) /* 00: +0.0°C (default) */
 290#define PIXPAPER_TSE_TO_FINE_0_25C (0x1 << 4) /* 01: +0.25°C */
 291#define PIXPAPER_TSE_ENABLE \
 292	(0 << 7) /* Bit 7: TSE, 0=internal sensor enabled (default), 1=disabled (external) */
 293#define PIXPAPER_TSE_DISABLE \
 294	(1 << 7) /* Bit 7: TSE, 1=internal sensor disabled, use external */
 295#define PIXPAPER_TSE_CONFIG                                 \
 296	(PIXPAPER_TSE_TO_POS_0C | PIXPAPER_TSE_TO_FINE_0C | \
 297	 PIXPAPER_TSE_ENABLE) /* 0x00: Internal sensor enabled, +0°C offset */
 298
 299/* R4DH */
 300#define PIXPAPER_UNKNOWN_4D_CONFIG \
 301	0x78 /* This value is essential for initialization, derived from userspace examples. */
 302
 303/* R50H CDI - VCOM and DATA Interval Setting Register */
 304/* First Parameter */
 305#define PIXPAPER_CDI_INTERVAL_MASK \
 306	(0xF << 0) /* Bits 3-0: CDI[3:0], VCOM and data interval (hsync) */
 307#define PIXPAPER_CDI_17_HSYNC (0x0 << 0) /* 0000: 17 hsync */
 308#define PIXPAPER_CDI_16_HSYNC (0x1 << 0) /* 0001: 16 hsync */
 309#define PIXPAPER_CDI_15_HSYNC (0x2 << 0) /* 0010: 15 hsync */
 310#define PIXPAPER_CDI_14_HSYNC (0x3 << 0) /* 0011: 14 hsync */
 311#define PIXPAPER_CDI_13_HSYNC (0x4 << 0) /* 0100: 13 hsync */
 312#define PIXPAPER_CDI_12_HSYNC (0x5 << 0) /* 0101: 12 hsync */
 313#define PIXPAPER_CDI_11_HSYNC (0x6 << 0) /* 0110: 11 hsync */
 314#define PIXPAPER_CDI_10_HSYNC (0x7 << 0) /* 0111: 10 hsync (default) */
 315#define PIXPAPER_CDI_9_HSYNC (0x8 << 0) /* 1000: 9 hsync */
 316#define PIXPAPER_CDI_8_HSYNC (0x9 << 0) /* 1001: 8 hsync */
 317#define PIXPAPER_CDI_7_HSYNC (0xA << 0) /* 1010: 7 hsync */
 318#define PIXPAPER_CDI_6_HSYNC (0xB << 0) /* 1011: 6 hsync */
 319#define PIXPAPER_CDI_5_HSYNC (0xC << 0) /* 1100: 5 hsync */
 320#define PIXPAPER_CDI_4_HSYNC (0xD << 0) /* 1101: 4 hsync */
 321#define PIXPAPER_CDI_3_HSYNC (0xE << 0) /* 1110: 3 hsync */
 322#define PIXPAPER_CDI_2_HSYNC (0xF << 0) /* 1111: 2 hsync */
 323#define PIXPAPER_CDI_DDX \
 324	(1 << 4) /* Bit 4: DDX, 0=grayscale mapping 0, 1=grayscale mapping 1 (default) */
 325#define PIXPAPER_CDI_VBD_MASK \
 326	(0x7 << 5) /* Bits 7-5: VBD[2:0], border data selection */
 327#define PIXPAPER_CDI_VBD_FLOAT (0x0 << 5) /* 000: Floating (DDX=0 or 1) */
 328#define PIXPAPER_CDI_VBD_GRAY3_DDX0 \
 329	(0x1 << 5) /* 001: Gray3 (border_buf=011) when DDX=0 */
 330#define PIXPAPER_CDI_VBD_GRAY2_DDX0 \
 331	(0x2 << 5) /* 010: Gray2 (border_buf=010) when DDX=0 */
 332#define PIXPAPER_CDI_VBD_GRAY1_DDX0 \
 333	(0x3 << 5) /* 011: Gray1 (border_buf=001) when DDX=0 */
 334#define PIXPAPER_CDI_VBD_GRAY0_DDX0 \
 335	(0x4 << 5) /* 100: Gray0 (border_buf=000) when DDX=0 */
 336#define PIXPAPER_CDI_VBD_GRAY0_DDX1 \
 337	(0x0 << 5) /* 000: Gray0 (border_buf=000) when DDX=1 */
 338#define PIXPAPER_CDI_VBD_GRAY1_DDX1 \
 339	(0x1 << 5) /* 001: Gray1 (border_buf=001) when DDX=1 */
 340#define PIXPAPER_CDI_VBD_GRAY2_DDX1 \
 341	(0x2 << 5) /* 010: Gray2 (border_buf=010) when DDX=1 */
 342#define PIXPAPER_CDI_VBD_GRAY3_DDX1 \
 343	(0x3 << 5) /* 011: Gray3 (border_buf=011) when DDX=1 */
 344#define PIXPAPER_CDI_VBD_FLOAT_DDX1 (0x4 << 5) /* 100: Floating when DDX=1 */
 345#define PIXPAPER_CDI_CONFIG                         \
 346	(PIXPAPER_CDI_10_HSYNC | PIXPAPER_CDI_DDX | \
 347	 PIXPAPER_CDI_VBD_GRAY1_DDX1) /* 0x37: 10 hsync, DDX=1, border Gray1 */
 348
 349/* R60H */
 350#define PIXPAPER_UNKNOWN_60_CONFIG1 \
 351	0x02 /* This value is essential for initialization, derived from userspace examples. */
 352#define PIXPAPER_UNKNOWN_60_CONFIG2 \
 353	0x02 /* This value is essential for initialization, derived from userspace examples. */
 354
 355/* R61H TRES - Resolution Setting Register */
 356#define PIXPAPER_TRES_HRES_H                  \
 357	((PIXPAPER_PANEL_BUFFER_WIDTH >> 8) & \
 358	 0xFF) /* HRES[9:8]: High byte of horizontal resolution (128) */
 359#define PIXPAPER_TRES_HRES_L           \
 360	(PIXPAPER_PANEL_BUFFER_WIDTH & \
 361	 0xFF) /* HRES[7:0]: Low byte of horizontal resolution (128 = 0x80) */
 362#define PIXPAPER_TRES_VRES_H      \
 363	((PIXPAPER_HEIGHT >> 8) & \
 364	 0xFF) /* VRES[9:8]: High byte of vertical resolution (250) */
 365#define PIXPAPER_TRES_VRES_L \
 366	(PIXPAPER_HEIGHT &   \
 367	 0xFF) /* VRES[7:0]: Low byte of vertical resolution (250 = 0xFA) */
 368
 369/* R65H GSST - Gate/Source Start Setting Register */
 370#define PIXPAPER_GSST_S_START 0x00 /* S_Start[7:0]: First source line (S0) */
 371#define PIXPAPER_GSST_RESERVED 0x00 /* Reserved byte */
 372#define PIXPAPER_GSST_G_START_H \
 373	0x00 /* G_Start[8]: High bit of first gate line (G0) */
 374#define PIXPAPER_GSST_G_START_L \
 375	0x00 /* G_Start[7:0]: Low byte of first gate line (G0) */
 376
 377/* RB4H */
 378#define PIXPAPER_UNKNOWN_B4_CONFIG \
 379	0xD0 /* This value is essential for initialization, derived from userspace examples. */
 380
 381/* RB5H */
 382#define PIXPAPER_UNKNOWN_B5_CONFIG \
 383	0x03 /* This value is essential for initialization, derived from userspace examples. */
 384
 385/* RE0H */
 386#define PIXPAPER_UNKNOWN_E0_CONFIG \
 387	0x00 /* This value is essential for initialization, derived from userspace examples. */
 388
 389/* RE3H PWS - Power Saving Register */
 390/* First Parameter */
 391#define PIXPAPER_PWS_VCOM_W_MASK \
 392	(0xF                     \
 393	 << 4) /* Bits 7-4: VCOM_W[3:0], VCOM power-saving width (line periods) */
 394#define PIXPAPER_PWS_VCOM_W_0 (0x0 << 4) /* 0000: 0 line periods */
 395#define PIXPAPER_PWS_VCOM_W_1 (0x1 << 4) /* 0001: 1 line period */
 396#define PIXPAPER_PWS_VCOM_W_2 (0x2 << 4) /* 0010: 2 line periods */
 397#define PIXPAPER_PWS_VCOM_W_3 (0x3 << 4) /* 0011: 3 line periods */
 398#define PIXPAPER_PWS_VCOM_W_4 (0x4 << 4) /* 0100: 4 line periods */
 399#define PIXPAPER_PWS_VCOM_W_5 (0x5 << 4) /* 0101: 5 line periods */
 400#define PIXPAPER_PWS_VCOM_W_6 (0x6 << 4) /* 0110: 6 line periods */
 401#define PIXPAPER_PWS_VCOM_W_7 (0x7 << 4) /* 0111: 7 line periods */
 402#define PIXPAPER_PWS_VCOM_W_8 (0x8 << 4) /* 1000: 8 line periods */
 403#define PIXPAPER_PWS_VCOM_W_9 (0x9 << 4) /* 1001: 9 line periods */
 404#define PIXPAPER_PWS_VCOM_W_10 (0xA << 4) /* 1010: 10 line periods */
 405#define PIXPAPER_PWS_VCOM_W_11 (0xB << 4) /* 1011: 11 line periods */
 406#define PIXPAPER_PWS_VCOM_W_12 (0xC << 4) /* 1100: 12 line periods */
 407#define PIXPAPER_PWS_VCOM_W_13 (0xD << 4) /* 1101: 13 line periods */
 408#define PIXPAPER_PWS_VCOM_W_14 (0xE << 4) /* 1110: 14 line periods */
 409#define PIXPAPER_PWS_VCOM_W_15 (0xF << 4) /* 1111: 15 line periods */
 410#define PIXPAPER_PWS_SD_W_MASK \
 411	(0xF << 0) /* Bits 3-0: SD_W[3:0], source power-saving width (660 ns units) */
 412#define PIXPAPER_PWS_SD_W_0 (0x0 << 0) /* 0000: 0 ns */
 413#define PIXPAPER_PWS_SD_W_1 (0x1 << 0) /* 0001: 660 ns */
 414#define PIXPAPER_PWS_SD_W_2 (0x2 << 0) /* 0010: 1320 ns */
 415#define PIXPAPER_PWS_SD_W_3 (0x3 << 0) /* 0011: 1980 ns */
 416#define PIXPAPER_PWS_SD_W_4 (0x4 << 0) /* 0100: 2640 ns */
 417#define PIXPAPER_PWS_SD_W_5 (0x5 << 0) /* 0101: 3300 ns */
 418#define PIXPAPER_PWS_SD_W_6 (0x6 << 0) /* 0110: 3960 ns */
 419#define PIXPAPER_PWS_SD_W_7 (0x7 << 0) /* 0111: 4620 ns */
 420#define PIXPAPER_PWS_SD_W_8 (0x8 << 0) /* 1000: 5280 ns */
 421#define PIXPAPER_PWS_SD_W_9 (0x9 << 0) /* 1001: 5940 ns */
 422#define PIXPAPER_PWS_SD_W_10 (0xA << 0) /* 1010: 6600 ns */
 423#define PIXPAPER_PWS_SD_W_11 (0xB << 0) /* 1011: 7260 ns */
 424#define PIXPAPER_PWS_SD_W_12 (0xC << 0) /* 1100: 7920 ns */
 425#define PIXPAPER_PWS_SD_W_13 (0xD << 0) /* 1101: 8580 ns */
 426#define PIXPAPER_PWS_SD_W_14 (0xE << 0) /* 1110: 9240 ns */
 427#define PIXPAPER_PWS_SD_W_15 (0xF << 0) /* 1111: 9900 ns */
 428#define PIXPAPER_PWS_CONFIG      \
 429	(PIXPAPER_PWS_VCOM_W_2 | \
 430	 PIXPAPER_PWS_SD_W_2) /* 0x22: VCOM 2 line periods (160 µs), source 1320 ns */
 431
 432/* RE7H */
 433#define PIXPAPER_UNKNOWN_E7_CONFIG \
 434	0x1C /* This value is essential for initialization, derived from userspace examples. */
 435
 436/* RE9H */
 437#define PIXPAPER_UNKNOWN_E9_CONFIG \
 438	0x01 /* This value is essential for initialization, derived from userspace examples. */
 439
 440MODULE_IMPORT_NS("DMA_BUF");
 441
 442/*
 443 * The panel has a visible resolution of 122x250.
 444 * However, the controller requires the horizontal resolution to be aligned to 128 pixels.
 445 * No porch or sync timing values are provided in the datasheet, so we define minimal
 446 * placeholder values to satisfy the DRM framework.
 447 */
 448
 449/* Panel visible resolution */
 450#define PIXPAPER_WIDTH           122
 451#define PIXPAPER_HEIGHT          250
 452
 453/* Controller requires 128 horizontal pixels total (for memory alignment) */
 454#define PIXPAPER_HTOTAL          128
 455#define PIXPAPER_HFP             2
 456#define PIXPAPER_HSYNC           2
 457#define PIXPAPER_HBP             (PIXPAPER_HTOTAL - PIXPAPER_WIDTH - PIXPAPER_HFP - PIXPAPER_HSYNC)
 458
 459/*
 460 * According to the datasheet, the total vertical blanking must be 55 lines,
 461 * regardless of how the vertical back porch is set.
 462 * Here we allocate VFP=2, VSYNC=2, and VBP=51 to sum up to 55 lines.
 463 * Total vertical lines = 250 (visible) + 55 (blanking) = 305.
 464 */
 465#define PIXPAPER_VTOTAL  (250 + 55)
 466#define PIXPAPER_VFP     2
 467#define PIXPAPER_VSYNC   2
 468#define PIXPAPER_VBP     (55 - PIXPAPER_VFP - PIXPAPER_VSYNC)
 469
 470/*
 471 * Pixel clock calculation:
 472 * pixel_clock = htotal * vtotal * refresh_rate
 473 *             = 128 * 305 * 50
 474 *             = 1,952,000 Hz = 1952 kHz
 475 */
 476#define PIXPAPER_PIXEL_CLOCK     1952
 477
 478#define PIXPAPER_WIDTH_MM        24    /* approximate from 23.7046mm */
 479#define PIXPAPER_HEIGHT_MM       49    /* approximate from 48.55mm */
 480
 481#define PIXPAPER_SPI_BITS_PER_WORD	8
 482#define PIXPAPER_SPI_SPEED_DEFAULT      1000000
 483
 484#define PIXPAPER_PANEL_BUFFER_WIDTH	128
 485#define PIXPAPER_PANEL_BUFFER_TWO_BYTES_PER_ROW (PIXPAPER_PANEL_BUFFER_WIDTH / 4)
 486
 487#define PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL		60
 488#define PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL		200
 489#define PIXPAPER_COLOR_THRESHOLD_YELLOW_MIN_GREEN	180
 490
 491struct pixpaper_error_ctx {
 492	int errno_code;
 493};
 494
 495struct pixpaper_panel {
 496	struct drm_device drm;
 497	struct drm_plane plane;
 498	struct drm_crtc crtc;
 499	struct drm_encoder encoder;
 500	struct drm_connector connector;
 501
 502	struct spi_device *spi;
 503	struct gpio_desc *reset;
 504	struct gpio_desc *busy;
 505	struct gpio_desc *dc;
 506};
 507
 508static inline struct pixpaper_panel *to_pixpaper_panel(struct drm_device *drm)
 509{
 510	return container_of(drm, struct pixpaper_panel, drm);
 511}
 512
 513static void pixpaper_wait_for_panel(struct pixpaper_panel *panel)
 514{
 515	unsigned int timeout_ms = 10000;
 516	unsigned long timeout_jiffies = jiffies + msecs_to_jiffies(timeout_ms);
 517
 518	usleep_range(1000, 1500);
 519	while (gpiod_get_value_cansleep(panel->busy) != 1) {
 520		if (time_after(jiffies, timeout_jiffies)) {
 521			drm_warn(&panel->drm, "Busy wait timed out\n");
 522			return;
 523		}
 524		usleep_range(100, 200);
 525	}
 526}
 527
 528static void pixpaper_spi_sync(struct spi_device *spi, struct spi_message *msg,
 529			      struct pixpaper_error_ctx *err)
 530{
 531	if (err->errno_code)
 532		return;
 533
 534	int ret = spi_sync(spi, msg);
 535
 536	if (ret < 0)
 537		err->errno_code = ret;
 538}
 539
 540static void pixpaper_send_cmd(struct pixpaper_panel *panel, u8 cmd,
 541			      struct pixpaper_error_ctx *err)
 542{
 543	if (err->errno_code)
 544		return;
 545
 546	struct spi_transfer xfer = {
 547		.tx_buf = &cmd,
 548		.len = 1,
 549	};
 550	struct spi_message msg;
 551
 552	spi_message_init(&msg);
 553	spi_message_add_tail(&xfer, &msg);
 554
 555	gpiod_set_value_cansleep(panel->dc, 0);
 556	usleep_range(1, 5);
 557	pixpaper_spi_sync(panel->spi, &msg, err);
 558}
 559
 560static void pixpaper_send_data(struct pixpaper_panel *panel, u8 data,
 561			       struct pixpaper_error_ctx *err)
 562{
 563	if (err->errno_code)
 564		return;
 565
 566	struct spi_transfer xfer = {
 567		.tx_buf = &data,
 568		.len = 1,
 569	};
 570	struct spi_message msg;
 571
 572	spi_message_init(&msg);
 573	spi_message_add_tail(&xfer, &msg);
 574
 575	gpiod_set_value_cansleep(panel->dc, 1);
 576	usleep_range(1, 5);
 577	pixpaper_spi_sync(panel->spi, &msg, err);
 578}
 579
 580static int pixpaper_panel_hw_init(struct pixpaper_panel *panel)
 581{
 582	struct pixpaper_error_ctx err = { .errno_code = 0 };
 583
 584	gpiod_set_value_cansleep(panel->reset, 0);
 585	msleep(50);
 586	gpiod_set_value_cansleep(panel->reset, 1);
 587	msleep(50);
 588
 589	pixpaper_wait_for_panel(panel);
 590
 591	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_4D, &err);
 592	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_4D_CONFIG, &err);
 593	if (err.errno_code)
 594		goto init_fail;
 595	pixpaper_wait_for_panel(panel);
 596
 597	pixpaper_send_cmd(panel, PIXPAPER_CMD_PANEL_SETTING, &err);
 598	pixpaper_send_data(panel, PIXPAPER_PSR_CONFIG, &err);
 599	pixpaper_send_data(panel, PIXPAPER_PSR_CONFIG2, &err);
 600	if (err.errno_code)
 601		goto init_fail;
 602	pixpaper_wait_for_panel(panel);
 603
 604	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_SETTING, &err);
 605	pixpaper_send_data(panel, PIXPAPER_PWR_CONFIG1, &err);
 606	pixpaper_send_data(panel, PIXPAPER_PWR_CONFIG2, &err);
 607	pixpaper_send_data(panel, PIXPAPER_PWR_VSP_8_2V, &err);
 608	pixpaper_send_data(panel, PIXPAPER_PWR_VSPL_15V, &err);
 609	pixpaper_send_data(panel, PIXPAPER_PWR_VSN_4V, &err);
 610	pixpaper_send_data(panel, PIXPAPER_PWR_VSP_8_2V, &err);
 611	if (err.errno_code)
 612		goto init_fail;
 613	pixpaper_wait_for_panel(panel);
 614
 615	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_OFF_SEQUENCE, &err);
 616	pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG1, &err);
 617	pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG2, &err);
 618	pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG3, &err);
 619	if (err.errno_code)
 620		goto init_fail;
 621	pixpaper_wait_for_panel(panel);
 622
 623	pixpaper_send_cmd(panel, PIXPAPER_CMD_BOOSTER_SOFT_START, &err);
 624	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG1, &err);
 625	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG2, &err);
 626	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG3, &err);
 627	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG4, &err);
 628	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG5, &err);
 629	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG6, &err);
 630	pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG7, &err);
 631	if (err.errno_code)
 632		goto init_fail;
 633	pixpaper_wait_for_panel(panel);
 634
 635	pixpaper_send_cmd(panel, PIXPAPER_CMD_PLL_CONTROL, &err);
 636	pixpaper_send_data(panel, PIXPAPER_PLL_CONFIG, &err);
 637	if (err.errno_code)
 638		goto init_fail;
 639	pixpaper_wait_for_panel(panel);
 640
 641	pixpaper_send_cmd(panel, PIXPAPER_CMD_TEMP_SENSOR_CALIB, &err);
 642	pixpaper_send_data(panel, PIXPAPER_TSE_CONFIG, &err);
 643	if (err.errno_code)
 644		goto init_fail;
 645	pixpaper_wait_for_panel(panel);
 646
 647	pixpaper_send_cmd(panel, PIXPAPER_CMD_VCOM_INTERVAL, &err);
 648	pixpaper_send_data(panel, PIXPAPER_CDI_CONFIG, &err);
 649	if (err.errno_code)
 650		goto init_fail;
 651	pixpaper_wait_for_panel(panel);
 652
 653	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_60, &err);
 654	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_60_CONFIG1, &err);
 655	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_60_CONFIG2, &err);
 656	if (err.errno_code)
 657		goto init_fail;
 658	pixpaper_wait_for_panel(panel);
 659
 660	pixpaper_send_cmd(panel, PIXPAPER_CMD_RESOLUTION_SETTING, &err);
 661	pixpaper_send_data(panel, PIXPAPER_TRES_HRES_H, &err);
 662	pixpaper_send_data(panel, PIXPAPER_TRES_HRES_L, &err);
 663	pixpaper_send_data(panel, PIXPAPER_TRES_VRES_H, &err);
 664	pixpaper_send_data(panel, PIXPAPER_TRES_VRES_L, &err);
 665	if (err.errno_code)
 666		goto init_fail;
 667	pixpaper_wait_for_panel(panel);
 668
 669	pixpaper_send_cmd(panel, PIXPAPER_CMD_GATE_SOURCE_START, &err);
 670	pixpaper_send_data(panel, PIXPAPER_GSST_S_START, &err);
 671	pixpaper_send_data(panel, PIXPAPER_GSST_RESERVED, &err);
 672	pixpaper_send_data(panel, PIXPAPER_GSST_G_START_H, &err);
 673	pixpaper_send_data(panel, PIXPAPER_GSST_G_START_L, &err);
 674	if (err.errno_code)
 675		goto init_fail;
 676	pixpaper_wait_for_panel(panel);
 677
 678	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E7, &err);
 679	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E7_CONFIG, &err);
 680	if (err.errno_code)
 681		goto init_fail;
 682	pixpaper_wait_for_panel(panel);
 683
 684	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_SAVING, &err);
 685	pixpaper_send_data(panel, PIXPAPER_PWS_CONFIG, &err);
 686	if (err.errno_code)
 687		goto init_fail;
 688	pixpaper_wait_for_panel(panel);
 689
 690	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E0, &err);
 691	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E0_CONFIG, &err);
 692	if (err.errno_code)
 693		goto init_fail;
 694	pixpaper_wait_for_panel(panel);
 695
 696	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_B4, &err);
 697	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_B4_CONFIG, &err);
 698	if (err.errno_code)
 699		goto init_fail;
 700	pixpaper_wait_for_panel(panel);
 701
 702	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_B5, &err);
 703	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_B5_CONFIG, &err);
 704	if (err.errno_code)
 705		goto init_fail;
 706	pixpaper_wait_for_panel(panel);
 707
 708	pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E9, &err);
 709	pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E9_CONFIG, &err);
 710	if (err.errno_code)
 711		goto init_fail;
 712	pixpaper_wait_for_panel(panel);
 713
 714	return 0;
 715
 716init_fail:
 717	drm_err(&panel->drm, "Hardware initialization failed (err=%d)\n",
 718		err.errno_code);
 719	return err.errno_code;
 720}
 721
 722/*
 723 * Convert framebuffer pixels to 2-bit e-paper format:
 724 *   00 - White
 725 *   01 - Black
 726 *   10 - Yellow
 727 *   11 - Red
 728 */
 729static u8 pack_pixels_to_byte(__le32 *src_pixels, int i, int j,
 730			      struct drm_framebuffer *fb)
 731{
 732	u8 packed_byte = 0;
 733	int k;
 734
 735	for (k = 0; k < 4; k++) {
 736		int current_pixel_x = j * 4 + k;
 737		u8 two_bit_val;
 738
 739		if (current_pixel_x < PIXPAPER_WIDTH) {
 740			u32 pixel_offset =
 741				(i * (fb->pitches[0] / 4)) + current_pixel_x;
 742			u32 pixel = le32_to_cpu(src_pixels[pixel_offset]);
 743			u32 r = (pixel >> 16) & 0xFF;
 744			u32 g = (pixel >> 8) & 0xFF;
 745			u32 b = pixel & 0xFF;
 746
 747			if (r < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
 748			    g < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
 749			    b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
 750				two_bit_val = 0b00;
 751			} else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
 752				   g > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
 753				   b > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL) {
 754				two_bit_val = 0b01;
 755			} else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
 756				   g < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
 757				   b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
 758				two_bit_val = 0b11;
 759			} else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
 760				   g > PIXPAPER_COLOR_THRESHOLD_YELLOW_MIN_GREEN &&
 761				   b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
 762				two_bit_val = 0b10;
 763			} else {
 764				two_bit_val = 0b01;
 765			}
 766		} else {
 767			two_bit_val = 0b01;
 768		}
 769
 770		packed_byte |= two_bit_val << ((3 - k) * 2);
 771	}
 772
 773	return packed_byte;
 774}
 775
 776static int pixpaper_plane_helper_atomic_check(struct drm_plane *plane,
 777					      struct drm_atomic_state *state)
 778{
 779	struct drm_plane_state *new_plane_state =
 780		drm_atomic_get_new_plane_state(state, plane);
 781	struct drm_crtc *new_crtc = new_plane_state->crtc;
 782	struct drm_crtc_state *new_crtc_state = NULL;
 783	int ret;
 784
 785	if (new_crtc)
 786		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
 787
 788	ret = drm_atomic_helper_check_plane_state(new_plane_state,
 789						  new_crtc_state, DRM_PLANE_NO_SCALING,
 790						  DRM_PLANE_NO_SCALING, false, false);
 791	if (ret)
 792		return ret;
 793	else if (!new_plane_state->visible)
 794		return 0;
 795
 796	return 0;
 797}
 798
 799static int pixpaper_crtc_helper_atomic_check(struct drm_crtc *crtc,
 800					     struct drm_atomic_state *state)
 801{
 802	struct drm_crtc_state *crtc_state =
 803		drm_atomic_get_new_crtc_state(state, crtc);
 804
 805	if (!crtc_state->enable)
 806		return 0;
 807
 808	return drm_atomic_helper_check_crtc_primary_plane(crtc_state);
 809}
 810
 811static void pixpaper_crtc_atomic_enable(struct drm_crtc *crtc,
 812					struct drm_atomic_state *state)
 813{
 814	struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
 815	struct drm_device *drm = &panel->drm;
 816	int idx;
 817	struct pixpaper_error_ctx err = { .errno_code = 0 };
 818
 819	if (!drm_dev_enter(drm, &idx))
 820		return;
 821
 822	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_ON, &err);
 823	if (err.errno_code) {
 824		drm_err_once(drm, "Failed to send PON command: %d\n", err.errno_code);
 825		goto exit_drm_dev;
 826	}
 827
 828	pixpaper_wait_for_panel(panel);
 829
 830	drm_dbg(drm, "Panel enabled and powered on\n");
 831
 832exit_drm_dev:
 833	drm_dev_exit(idx);
 834}
 835
 836static void pixpaper_crtc_atomic_disable(struct drm_crtc *crtc,
 837					 struct drm_atomic_state *state)
 838{
 839	struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
 840	struct drm_device *drm = &panel->drm;
 841	struct pixpaper_error_ctx err = { .errno_code = 0 };
 842	int idx;
 843
 844	if (!drm_dev_enter(drm, &idx))
 845		return;
 846
 847	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_OFF, &err);
 848	if (err.errno_code) {
 849		drm_err_once(drm, "Failed to send POF command: %d\n", err.errno_code);
 850		goto exit_drm_dev;
 851	}
 852	pixpaper_wait_for_panel(panel);
 853
 854	drm_dbg(drm, "Panel disabled\n");
 855
 856exit_drm_dev:
 857	drm_dev_exit(idx);
 858}
 859
 860static void pixpaper_plane_atomic_update(struct drm_plane *plane,
 861					 struct drm_atomic_state *state)
 862{
 863	struct drm_plane_state *plane_state =
 864		drm_atomic_get_new_plane_state(state, plane);
 865	struct drm_shadow_plane_state *shadow_plane_state =
 866		to_drm_shadow_plane_state(plane_state);
 867	struct drm_crtc *crtc = plane_state->crtc;
 868	struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
 869
 870	struct drm_device *drm = &panel->drm;
 871	struct drm_framebuffer *fb = plane_state->fb;
 872	struct iosys_map map = shadow_plane_state->data[0];
 873	void *vaddr = map.vaddr;
 874	int i, j, idx;
 875	__le32 *src_pixels = NULL;
 876	struct pixpaper_error_ctx err = { .errno_code = 0 };
 877
 878	if (!drm_dev_enter(drm, &idx))
 879		return;
 880
 881	drm_dbg(drm, "Starting frame update (phys=%dx%d, buf_w=%d)\n",
 882		PIXPAPER_WIDTH, PIXPAPER_HEIGHT, PIXPAPER_PANEL_BUFFER_WIDTH);
 883
 884	if (!fb || !plane_state->visible) {
 885		drm_err_once(drm, "No framebuffer or plane not visible, skipping update\n");
 886		goto update_cleanup;
 887	}
 888
 889	src_pixels = (__le32 *)vaddr;
 890
 891	pixpaper_send_cmd(panel, PIXPAPER_CMD_DATA_START_TRANSMISSION, &err);
 892	if (err.errno_code)
 893		goto update_cleanup;
 894
 895	pixpaper_wait_for_panel(panel);
 896
 897	for (i = 0; i < PIXPAPER_HEIGHT; i++) {
 898		for (j = 0; j < PIXPAPER_PANEL_BUFFER_TWO_BYTES_PER_ROW; j++) {
 899			u8 packed_byte =
 900				pack_pixels_to_byte(src_pixels, i, j, fb);
 901
 902			pixpaper_wait_for_panel(panel);
 903			pixpaper_send_data(panel, packed_byte, &err);
 904		}
 905	}
 906	pixpaper_wait_for_panel(panel);
 907
 908	pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_ON, &err);
 909	if (err.errno_code) {
 910		drm_err_once(drm, "Failed to send PON command: %d\n", err.errno_code);
 911		goto update_cleanup;
 912	}
 913	pixpaper_wait_for_panel(panel);
 914
 915	pixpaper_send_cmd(panel, PIXPAPER_CMD_DISPLAY_REFRESH, &err);
 916	pixpaper_send_data(panel, PIXPAPER_DRF_VCOM_AC, &err);
 917	if (err.errno_code) {
 918		drm_err_once(drm, "Failed sending data after DRF: %d\n", err.errno_code);
 919		goto update_cleanup;
 920	}
 921	pixpaper_wait_for_panel(panel);
 922
 923update_cleanup:
 924	if (err.errno_code && err.errno_code != -ETIMEDOUT)
 925		drm_err_once(drm, "Frame update function failed with error %d\n", err.errno_code);
 926
 927	drm_dev_exit(idx);
 928}
 929
 930static const struct drm_display_mode pixpaper_mode = {
 931	.clock = PIXPAPER_PIXEL_CLOCK,
 932	.hdisplay = PIXPAPER_WIDTH,
 933	.hsync_start = PIXPAPER_WIDTH + PIXPAPER_HFP,
 934	.hsync_end = PIXPAPER_WIDTH + PIXPAPER_HFP + PIXPAPER_HSYNC,
 935	.htotal = PIXPAPER_HTOTAL,
 936	.vdisplay = PIXPAPER_HEIGHT,
 937	.vsync_start = PIXPAPER_HEIGHT + PIXPAPER_VFP,
 938	.vsync_end = PIXPAPER_HEIGHT + PIXPAPER_VFP + PIXPAPER_VSYNC,
 939	.vtotal = PIXPAPER_VTOTAL,
 940	.width_mm = PIXPAPER_WIDTH_MM,
 941	.height_mm = PIXPAPER_HEIGHT_MM,
 942	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
 943};
 944
 945static int pixpaper_connector_get_modes(struct drm_connector *connector)
 946{
 947	return drm_connector_helper_get_modes_fixed(connector, &pixpaper_mode);
 948}
 949
 950static const struct drm_plane_funcs pixpaper_plane_funcs = {
 951	.update_plane = drm_atomic_helper_update_plane,
 952	.disable_plane = drm_atomic_helper_disable_plane,
 953	.destroy = drm_plane_cleanup,
 954	DRM_GEM_SHADOW_PLANE_FUNCS,
 955};
 956
 957static const struct drm_plane_helper_funcs pixpaper_plane_helper_funcs = {
 958	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
 959	.atomic_check = pixpaper_plane_helper_atomic_check,
 960	.atomic_update = pixpaper_plane_atomic_update,
 961};
 962
 963static const struct drm_crtc_funcs pixpaper_crtc_funcs = {
 964	.set_config = drm_atomic_helper_set_config,
 965	.page_flip = drm_atomic_helper_page_flip,
 966	.reset = drm_atomic_helper_crtc_reset,
 967	.destroy = drm_crtc_cleanup,
 968	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 969	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 970};
 971
 972static enum drm_mode_status
 973pixpaper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
 974{
 975	if (mode->hdisplay == PIXPAPER_WIDTH &&
 976	    mode->vdisplay == PIXPAPER_HEIGHT) {
 977		return MODE_OK;
 978	}
 979	return MODE_BAD;
 980}
 981
 982static const struct drm_crtc_helper_funcs pixpaper_crtc_helper_funcs = {
 983	.mode_valid = pixpaper_mode_valid,
 984	.atomic_check = pixpaper_crtc_helper_atomic_check,
 985	.atomic_enable = pixpaper_crtc_atomic_enable,
 986	.atomic_disable = pixpaper_crtc_atomic_disable,
 987};
 988
 989static const struct drm_encoder_funcs pixpaper_encoder_funcs = {
 990	.destroy = drm_encoder_cleanup,
 991};
 992
 993static const struct drm_connector_funcs pixpaper_connector_funcs = {
 994	.reset = drm_atomic_helper_connector_reset,
 995	.fill_modes = drm_helper_probe_single_connector_modes,
 996	.destroy = drm_connector_cleanup,
 997	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 998	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 999};
1000
1001static const struct drm_connector_helper_funcs pixpaper_connector_helper_funcs = {
1002	.get_modes = pixpaper_connector_get_modes,
1003};
1004
1005DEFINE_DRM_GEM_FOPS(pixpaper_fops);
1006
1007static struct drm_driver pixpaper_drm_driver = {
1008	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
1009	.fops = &pixpaper_fops,
1010	.name = "pixpaper",
1011	.desc = "DRM driver for PIXPAPER e-ink",
1012	.major = 1,
1013	.minor = 0,
1014	DRM_GEM_SHMEM_DRIVER_OPS,
1015	DRM_FBDEV_SHMEM_DRIVER_OPS,
1016};
1017
1018static const struct drm_mode_config_funcs pixpaper_mode_config_funcs = {
1019	.fb_create = drm_gem_fb_create_with_dirty,
1020	.atomic_check = drm_atomic_helper_check,
1021	.atomic_commit = drm_atomic_helper_commit,
1022};
1023
1024static int pixpaper_probe(struct spi_device *spi)
1025{
1026	struct device *dev = &spi->dev;
1027	struct pixpaper_panel *panel;
1028	struct drm_device *drm;
1029	int ret;
1030
1031	panel = devm_drm_dev_alloc(dev, &pixpaper_drm_driver,
1032				   struct pixpaper_panel, drm);
1033	if (IS_ERR(panel))
1034		return PTR_ERR(panel);
1035
1036	drm = &panel->drm;
1037	panel->spi = spi;
1038	spi_set_drvdata(spi, panel);
1039
1040	spi->mode = SPI_MODE_0;
1041	spi->bits_per_word = PIXPAPER_SPI_BITS_PER_WORD;
1042
1043	if (!spi->max_speed_hz) {
1044		drm_warn(drm,
1045			 "spi-max-frequency not specified in DT, using default %u Hz\n",
1046			 PIXPAPER_SPI_SPEED_DEFAULT);
1047		spi->max_speed_hz = PIXPAPER_SPI_SPEED_DEFAULT;
1048	}
1049
1050	ret = spi_setup(spi);
1051	if (ret < 0) {
1052		drm_err(drm, "SPI setup failed: %d\n", ret);
1053		return ret;
1054	}
1055
1056	if (!dev->dma_mask)
1057		dev->dma_mask = &dev->coherent_dma_mask;
1058	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
1059	if (ret) {
1060		drm_err(drm, "Failed to set DMA mask: %d\n", ret);
1061		return ret;
1062	}
1063
1064	panel->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
1065	if (IS_ERR(panel->reset))
1066		return PTR_ERR(panel->reset);
1067
1068	panel->busy = devm_gpiod_get(dev, "busy", GPIOD_IN);
1069	if (IS_ERR(panel->busy))
1070		return PTR_ERR(panel->busy);
1071
1072	panel->dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_HIGH);
1073	if (IS_ERR(panel->dc))
1074		return PTR_ERR(panel->dc);
1075
1076	ret = pixpaper_panel_hw_init(panel);
1077	if (ret) {
1078		drm_err(drm, "Panel hardware initialization failed: %d\n", ret);
1079		return ret;
1080	}
1081
1082	ret = drmm_mode_config_init(drm);
1083	if (ret)
1084		return ret;
1085	drm->mode_config.funcs = &pixpaper_mode_config_funcs;
1086	drm->mode_config.min_width = PIXPAPER_WIDTH;
1087	drm->mode_config.max_width = PIXPAPER_WIDTH;
1088	drm->mode_config.min_height = PIXPAPER_HEIGHT;
1089	drm->mode_config.max_height = PIXPAPER_HEIGHT;
1090
1091	ret = drm_universal_plane_init(drm, &panel->plane, 1,
1092				       &pixpaper_plane_funcs,
1093				       (const uint32_t[]){ DRM_FORMAT_XRGB8888 },
1094				       1, NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
1095	if (ret)
1096		return ret;
1097	drm_plane_helper_add(&panel->plane, &pixpaper_plane_helper_funcs);
1098
1099	ret = drm_crtc_init_with_planes(drm, &panel->crtc, &panel->plane, NULL,
1100					&pixpaper_crtc_funcs, NULL);
1101	if (ret)
1102		return ret;
1103	drm_crtc_helper_add(&panel->crtc, &pixpaper_crtc_helper_funcs);
1104
1105	ret = drm_encoder_init(drm, &panel->encoder, &pixpaper_encoder_funcs,
1106			       DRM_MODE_ENCODER_NONE, NULL);
1107	if (ret)
1108		return ret;
1109	panel->encoder.possible_crtcs = drm_crtc_mask(&panel->crtc);
1110
1111	ret = drm_connector_init(drm, &panel->connector,
1112				 &pixpaper_connector_funcs,
1113				 DRM_MODE_CONNECTOR_SPI);
1114	if (ret)
1115		return ret;
1116
1117	drm_connector_helper_add(&panel->connector,
1118				 &pixpaper_connector_helper_funcs);
1119	drm_connector_attach_encoder(&panel->connector, &panel->encoder);
1120
1121	drm_mode_config_reset(drm);
1122
1123	ret = drm_dev_register(drm, 0);
1124	if (ret)
1125		return ret;
1126
1127	drm_client_setup(drm, NULL);
1128
1129	return 0;
1130}
1131
1132static void pixpaper_remove(struct spi_device *spi)
1133{
1134	struct pixpaper_panel *panel = spi_get_drvdata(spi);
1135
1136	if (!panel)
1137		return;
1138
1139	drm_dev_unplug(&panel->drm);
1140	drm_atomic_helper_shutdown(&panel->drm);
1141}
1142
1143static const struct spi_device_id pixpaper_ids[] = { { "pixpaper", 0 }, {} };
1144MODULE_DEVICE_TABLE(spi, pixpaper_ids);
1145
1146static const struct of_device_id pixpaper_dt_ids[] = {
1147	{ .compatible = "mayqueen,pixpaper" },
1148	{}
1149};
1150MODULE_DEVICE_TABLE(of, pixpaper_dt_ids);
1151
1152static struct spi_driver pixpaper_spi_driver = {
1153	.driver = {
1154		.name = "pixpaper",
1155		.of_match_table = pixpaper_dt_ids,
1156	},
1157	.id_table = pixpaper_ids,
1158	.probe = pixpaper_probe,
1159	.remove = pixpaper_remove,
1160};
1161
1162module_spi_driver(pixpaper_spi_driver);
1163
1164MODULE_AUTHOR("LiangCheng Wang");
1165MODULE_DESCRIPTION("DRM SPI driver for PIXPAPER e-ink panel");
1166MODULE_LICENSE("GPL");
~/ Read-only file preview.