|
110 | 110 | return val; \
|
111 | 111 | } while (0)
|
112 | 112 |
|
| 113 | +#define ST7789V_IDS { 0x85, 0x85, 0x52 } |
| 114 | +#define ST7789V_IDS_SIZE 3 |
| 115 | + |
113 | 116 | struct st7789_panel_info {
|
114 | 117 | const struct drm_display_mode *mode;
|
115 | 118 | u32 bus_format;
|
@@ -157,6 +160,76 @@ static int st7789v_write_data(struct st7789v *ctx, u8 cmd)
|
157 | 160 | return st7789v_spi_write(ctx, ST7789V_DATA, cmd);
|
158 | 161 | }
|
159 | 162 |
|
| 163 | +static int st7789v_read_data(struct st7789v *ctx, u8 cmd, u8 *buf, |
| 164 | + unsigned int len) |
| 165 | +{ |
| 166 | + struct spi_transfer xfer[2] = { }; |
| 167 | + struct spi_message msg; |
| 168 | + u16 txbuf = ((ST7789V_COMMAND & 1) << 8) | cmd; |
| 169 | + u16 rxbuf[4] = {}; |
| 170 | + u8 bit9 = 0; |
| 171 | + int ret, i; |
| 172 | + |
| 173 | + switch (len) { |
| 174 | + case 1: |
| 175 | + case 3: |
| 176 | + case 4: |
| 177 | + break; |
| 178 | + default: |
| 179 | + return -EOPNOTSUPP; |
| 180 | + } |
| 181 | + |
| 182 | + spi_message_init(&msg); |
| 183 | + |
| 184 | + xfer[0].tx_buf = &txbuf; |
| 185 | + xfer[0].len = sizeof(txbuf); |
| 186 | + spi_message_add_tail(&xfer[0], &msg); |
| 187 | + |
| 188 | + xfer[1].rx_buf = rxbuf; |
| 189 | + xfer[1].len = len * 2; |
| 190 | + spi_message_add_tail(&xfer[1], &msg); |
| 191 | + |
| 192 | + ret = spi_sync(ctx->spi, &msg); |
| 193 | + if (ret) |
| 194 | + return ret; |
| 195 | + |
| 196 | + for (i = 0; i < len; i++) { |
| 197 | + buf[i] = rxbuf[i] >> i | (bit9 << (9 - i)); |
| 198 | + if (i) |
| 199 | + bit9 = rxbuf[i] & GENMASK(i - 1, 0); |
| 200 | + } |
| 201 | + |
| 202 | + return 0; |
| 203 | +} |
| 204 | + |
| 205 | +static int st7789v_check_id(struct drm_panel *panel) |
| 206 | +{ |
| 207 | + const u8 st7789v_ids[ST7789V_IDS_SIZE] = ST7789V_IDS; |
| 208 | + struct st7789v *ctx = panel_to_st7789v(panel); |
| 209 | + bool invalid_ids = false; |
| 210 | + int ret, i; |
| 211 | + u8 ids[3]; |
| 212 | + |
| 213 | + if (ctx->spi->mode & SPI_NO_RX) |
| 214 | + return 0; |
| 215 | + |
| 216 | + ret = st7789v_read_data(ctx, MIPI_DCS_GET_DISPLAY_ID, ids, ST7789V_IDS_SIZE); |
| 217 | + if (ret) |
| 218 | + return ret; |
| 219 | + |
| 220 | + for (i = 0; i < ST7789V_IDS_SIZE; i++) { |
| 221 | + if (ids[i] != st7789v_ids[i]) { |
| 222 | + invalid_ids = true; |
| 223 | + break; |
| 224 | + } |
| 225 | + } |
| 226 | + |
| 227 | + if (invalid_ids) |
| 228 | + return -EIO; |
| 229 | + |
| 230 | + return 0; |
| 231 | +} |
| 232 | + |
160 | 233 | static const struct drm_display_mode default_mode = {
|
161 | 234 | .clock = 7000,
|
162 | 235 | .hdisplay = 240,
|
@@ -295,6 +368,14 @@ static int st7789v_prepare(struct drm_panel *panel)
|
295 | 368 | gpiod_set_value(ctx->reset, 0);
|
296 | 369 | msleep(120);
|
297 | 370 |
|
| 371 | + /* |
| 372 | + * Avoid failing if the IDs are invalid in case the Rx bus width |
| 373 | + * description is missing. |
| 374 | + */ |
| 375 | + ret = st7789v_check_id(panel); |
| 376 | + if (ret) |
| 377 | + dev_warn(panel->dev, "Unrecognized panel IDs"); |
| 378 | + |
298 | 379 | ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_EXIT_SLEEP_MODE));
|
299 | 380 |
|
300 | 381 | /* We need to wait 120ms after a sleep out command */
|
|
0 commit comments