mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-30 00:00:16 +01:00
lws_display: SPD1656 driver
Add SPD1656 SPI driver as used in 5.65 inch 7-colour waveshare panel.
This commit is contained in:
parent
d6c4e606e7
commit
9b47b768f4
4 changed files with 523 additions and 3 deletions
|
@ -790,6 +790,7 @@ lws_fx_string(const lws_fx_t *a, char *buf, size_t size);
|
||||||
#include <libwebsockets/lws-dlo.h>
|
#include <libwebsockets/lws-dlo.h>
|
||||||
#include <libwebsockets/lws-ssd1306-i2c.h>
|
#include <libwebsockets/lws-ssd1306-i2c.h>
|
||||||
#include <libwebsockets/lws-ili9341-spi.h>
|
#include <libwebsockets/lws-ili9341-spi.h>
|
||||||
|
#include <libwebsockets/lws-spd1656-spi.h>
|
||||||
#include <libwebsockets/lws-settings.h>
|
#include <libwebsockets/lws-settings.h>
|
||||||
#if defined(LWS_WITH_NETWORK)
|
#if defined(LWS_WITH_NETWORK)
|
||||||
#include <libwebsockets/lws-netdev.h>
|
#include <libwebsockets/lws-netdev.h>
|
||||||
|
|
55
include/libwebsockets/lws-spd1656-spi.h
Normal file
55
include/libwebsockets/lws-spd1656-spi.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* lws abstract display implementation for epd-acep on spi
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__LWS_DISPLAY_SPD1656_SPI_H__)
|
||||||
|
#define __LWS_DISPLAY_SPD1656_SPI_H__
|
||||||
|
|
||||||
|
typedef struct lws_display_spd1656_spi {
|
||||||
|
|
||||||
|
lws_display_t disp; /* use lws_display_spd1656_ops to set */
|
||||||
|
const lws_spi_ops_t *spi; /* spi ops */
|
||||||
|
|
||||||
|
lws_display_completion_t cb;
|
||||||
|
|
||||||
|
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
|
||||||
|
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
|
||||||
|
_lws_plat_gpio_t busy_gpio; /* if gpio ops, busy gpio # */
|
||||||
|
|
||||||
|
uint8_t spi_index; /* cs index starting from 0 */
|
||||||
|
|
||||||
|
} lws_display_spd1656_spi_t;
|
||||||
|
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_init(lws_display_state_t *lds);
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_blit(lws_display_state_t *lds, const uint8_t *src,
|
||||||
|
lws_box_t *box, lws_dll2_owner_t *ids);
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_power(lws_display_state_t *lds, int state);
|
||||||
|
|
||||||
|
#define lws_display_spd1656_ops \
|
||||||
|
.init = lws_display_spd1656_spi_init, \
|
||||||
|
.blit = lws_display_spd1656_spi_blit, \
|
||||||
|
.power = lws_display_spd1656_spi_power
|
||||||
|
#endif
|
|
@ -1,7 +1,8 @@
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
drivers/display/lws-display.c
|
drivers/display/lws-display.c
|
||||||
drivers/display/ssd1306-i2c.c
|
drivers/display/ssd1306-i2c.c
|
||||||
drivers/display/ili9341-spi.c
|
drivers/display/ili9341-spi.c
|
||||||
|
drivers/display/spd1656-spi.c
|
||||||
drivers/i2c/lws-i2c.c
|
drivers/i2c/lws-i2c.c
|
||||||
drivers/i2c/bitbang/lws-bb-i2c.c
|
drivers/i2c/bitbang/lws-bb-i2c.c
|
||||||
drivers/spi/lws-spi.c
|
drivers/spi/lws-spi.c
|
||||||
|
|
463
lib/drivers/display/spd1656-spi.c
Normal file
463
lib/drivers/display/spd1656-spi.c
Normal file
|
@ -0,0 +1,463 @@
|
||||||
|
/*
|
||||||
|
* lws abstract display implementation for Epd 7-colour ACEP SPD1656 on spi
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Based on datasheet
|
||||||
|
*
|
||||||
|
* https://www.waveshare.com/w/upload/b/bf/SPD1656_1.1.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <private-lib-core.h>
|
||||||
|
#include <dlo/private-lib-drivers-display-dlo.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SPD1656_CMD_PSR = 0x00,
|
||||||
|
SPD1656_CMD_PWR = 0x01,
|
||||||
|
SPD1656_CMD_POF = 0x02,
|
||||||
|
SPD1656_CMD_PFS = 0x03,
|
||||||
|
SPD1656_CMD_PON = 0x04,
|
||||||
|
SPD1656_CMD_BTST = 0x06,
|
||||||
|
SPD1656_CMD_DSLP = 0x07,
|
||||||
|
SPD1656_CMD_DTM1 = 0x10,
|
||||||
|
SPD1656_CMD_DSP = 0x11,
|
||||||
|
SPD1656_CMD_DRF = 0x12,
|
||||||
|
SPD1656_CMD_PLL = 0x30,
|
||||||
|
SPD1656_CMD_TSE = 0x41,
|
||||||
|
SPD1656_CMD_CDI = 0x50,
|
||||||
|
SPD1656_CMD_TCON = 0x60,
|
||||||
|
SPD1656_CMD_TRES = 0x61,
|
||||||
|
SPD1656_CMD_PWS = 0xe3,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LWSDISPST_IDLE,
|
||||||
|
LWSDISPST_INIT1,
|
||||||
|
LWSDISPST_INIT2,
|
||||||
|
LWSDISPST_INIT3,
|
||||||
|
LWSDISPST_INIT4,
|
||||||
|
LWSDISPST_WRITE1,
|
||||||
|
LWSDISPST_WRITE2,
|
||||||
|
LWSDISPST_WRITE3,
|
||||||
|
LWSDISPST_WRITE4,
|
||||||
|
LWSDISPST_WRITE5,
|
||||||
|
|
||||||
|
LWSDISPRET_ASYNC = 1
|
||||||
|
} lws_display_update_state_t;
|
||||||
|
|
||||||
|
static const uint8_t spd1656_init1[] = {
|
||||||
|
2, SPD1656_CMD_PSR, 0xef, 0x08,
|
||||||
|
4, SPD1656_CMD_PWR, 0x37, 0x00, 0x23, 0x23,
|
||||||
|
1, SPD1656_CMD_PFS, 0x00,
|
||||||
|
3, SPD1656_CMD_BTST, 0xc7, 0xc7, 0x1d,
|
||||||
|
1, SPD1656_CMD_PLL, 0x39,
|
||||||
|
1, SPD1656_CMD_TSE, 0x00,
|
||||||
|
1, SPD1656_CMD_CDI, 0x37,
|
||||||
|
1, SPD1656_CMD_TCON, 0x22,
|
||||||
|
}, spd1656_init2[] = {
|
||||||
|
4, SPD1656_CMD_TRES, 0, 0, 0, 0, /* filled in */
|
||||||
|
1, SPD1656_CMD_PWS, 0xaa,
|
||||||
|
}, spd1656_init3[] = {
|
||||||
|
1, SPD1656_CMD_CDI, 0x37,
|
||||||
|
}, spd1656_off[] = {
|
||||||
|
1, SPD1656_CMD_DSLP, 0xa5,
|
||||||
|
}, spd1656_write1[] = {
|
||||||
|
4, SPD1656_CMD_TRES, 0, 0, 0, 0, /* filled in */
|
||||||
|
}, spd1656_write1a[] = {
|
||||||
|
0, SPD1656_CMD_DTM1
|
||||||
|
/* ... frame data ... */
|
||||||
|
}, spd1656_write2[] = {
|
||||||
|
0, SPD1656_CMD_PON,
|
||||||
|
}, spd1656_write3[] = {
|
||||||
|
0, SPD1656_CMD_DRF,
|
||||||
|
}, spd1656_write4[] = {
|
||||||
|
0, SPD1656_CMD_POF,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct lws_display_spd1656_spi_state {
|
||||||
|
struct lws_display_state *lds;
|
||||||
|
uint32_t *line[2];
|
||||||
|
lws_surface_error_t *u[2];
|
||||||
|
lws_sorted_usec_list_t sul;
|
||||||
|
int state;
|
||||||
|
int budget;
|
||||||
|
} lws_display_spd1656_spi_state_t;
|
||||||
|
|
||||||
|
#define lds_to_disp(_lds) (const lws_display_spd1656_spi_t *)_lds->disp;
|
||||||
|
#define lds_to_priv(_lds) (lws_display_spd1656_spi_state_t *)_lds->priv;
|
||||||
|
|
||||||
|
#define pack_native_pixel(_line, _x, _c) \
|
||||||
|
{ *_line = (*_line & ~(0xf << (((_x ^ 1) & 7) * 4))) | \
|
||||||
|
(_c << (((_x ^ 1) & 7) * 4)); \
|
||||||
|
if ((_x & 7) == 7) \
|
||||||
|
_line++; }
|
||||||
|
|
||||||
|
static void
|
||||||
|
async_cb(lws_sorted_usec_list_t *sul);
|
||||||
|
|
||||||
|
#define BUSY_TIMEOUT_BUDGET 60
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_busy(lws_display_spd1656_spi_state_t *priv, int level)
|
||||||
|
{
|
||||||
|
const lws_display_spd1656_spi_t *ea = lds_to_disp(priv->lds);
|
||||||
|
|
||||||
|
if (ea->gpio->read(ea->busy_gpio) == level)
|
||||||
|
return 0; /* good */
|
||||||
|
|
||||||
|
if (!--priv->budget) {
|
||||||
|
lwsl_err("%s: timeout waiting idle %d\n", __func__, level);
|
||||||
|
return -1; /* timeout */
|
||||||
|
}
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul, async_cb,
|
||||||
|
LWS_US_PER_MS * 50);
|
||||||
|
|
||||||
|
return 1; /* keeping on trying */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
async_cb(lws_sorted_usec_list_t *sul)
|
||||||
|
{
|
||||||
|
lws_display_spd1656_spi_state_t *priv = lws_container_of(sul,
|
||||||
|
lws_display_spd1656_spi_state_t, sul);
|
||||||
|
const lws_display_spd1656_spi_t *ea = lds_to_disp(priv->lds);
|
||||||
|
uint8_t buf[32];
|
||||||
|
//int budget = 5;
|
||||||
|
|
||||||
|
switch (priv->state) {
|
||||||
|
|
||||||
|
case LWSDISPST_INIT1:
|
||||||
|
/* take reset low for a short time */
|
||||||
|
ea->gpio->set(ea->reset_gpio, 0);
|
||||||
|
priv->state++;
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul,
|
||||||
|
async_cb, LWS_US_PER_MS * 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LWSDISPST_INIT2:
|
||||||
|
/* park reset high again and then wait a bit */
|
||||||
|
ea->gpio->set(ea->reset_gpio, 1);
|
||||||
|
priv->state++;
|
||||||
|
priv->budget = BUSY_TIMEOUT_BUDGET;
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul,
|
||||||
|
async_cb, LWS_US_PER_MS * 10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LWSDISPST_INIT3:
|
||||||
|
if (check_busy(priv, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_init1,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_init1));
|
||||||
|
|
||||||
|
if (ea->spi->in_flight)
|
||||||
|
while (ea->spi->in_flight(ea->spi))
|
||||||
|
;
|
||||||
|
|
||||||
|
memcpy(buf, spd1656_init2, LWS_ARRAY_SIZE(spd1656_init2));
|
||||||
|
|
||||||
|
/* width and height filled in from display struct */
|
||||||
|
|
||||||
|
buf[2] = (ea->disp.ic.wh_px[0].whole >> 8) & 0xff;
|
||||||
|
buf[3] = ea->disp.ic.wh_px[0].whole & 0xff;
|
||||||
|
buf[4] = (ea->disp.ic.wh_px[1].whole >> 8) & 0xff;
|
||||||
|
buf[5] = ea->disp.ic.wh_px[1].whole & 0xff;
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, 0, buf,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_init2));
|
||||||
|
|
||||||
|
if (ea->spi->in_flight)
|
||||||
|
while (ea->spi->in_flight(ea->spi))
|
||||||
|
;
|
||||||
|
|
||||||
|
priv->state++;
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul,
|
||||||
|
async_cb, LWS_US_PER_MS * 10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LWSDISPST_INIT4:
|
||||||
|
priv->state = LWSDISPST_IDLE;
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_init3,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_init3));
|
||||||
|
|
||||||
|
if (ea->spi->in_flight)
|
||||||
|
while (ea->spi->in_flight(ea->spi))
|
||||||
|
;
|
||||||
|
|
||||||
|
if (ea->cb)
|
||||||
|
ea->cb(priv->lds, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case LWSDISPST_WRITE1:
|
||||||
|
|
||||||
|
/* rendered and sent the whole frame of pixel data */
|
||||||
|
|
||||||
|
priv->state++;
|
||||||
|
priv->budget = BUSY_TIMEOUT_BUDGET;
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_write2,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_write2));
|
||||||
|
|
||||||
|
/* fallthru */
|
||||||
|
|
||||||
|
case LWSDISPST_WRITE2:
|
||||||
|
if (check_busy(priv, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->state++;
|
||||||
|
priv->budget = 20000 / 50;
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_write3,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_write3));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is going to start the refresh, it may wait in check_busy
|
||||||
|
* for serveral seconds while it does the sequence on the panel
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* fallthru */
|
||||||
|
|
||||||
|
case LWSDISPST_WRITE3:
|
||||||
|
if (check_busy(priv, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->state++;
|
||||||
|
priv->budget = BUSY_TIMEOUT_BUDGET;
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_write4,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_write4));
|
||||||
|
|
||||||
|
/* fallthru */
|
||||||
|
|
||||||
|
case LWSDISPST_WRITE4:
|
||||||
|
if (check_busy(priv, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->state++;
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul, async_cb,
|
||||||
|
LWS_US_PER_MS * 200);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LWSDISPST_WRITE5:
|
||||||
|
|
||||||
|
/* fully completed the blit */
|
||||||
|
|
||||||
|
priv->state = LWSDISPST_IDLE;
|
||||||
|
if (ea->cb)
|
||||||
|
ea->cb(priv->lds, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_init(struct lws_display_state *lds)
|
||||||
|
{
|
||||||
|
const lws_display_spd1656_spi_t *ea = lds_to_disp(lds);
|
||||||
|
lws_display_spd1656_spi_state_t *priv;
|
||||||
|
|
||||||
|
priv = lws_zalloc(sizeof(*priv), __func__);
|
||||||
|
if (!priv)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
priv->lds = lds;
|
||||||
|
lds->priv = priv;
|
||||||
|
|
||||||
|
ea->gpio->mode(ea->busy_gpio, LWSGGPIO_FL_READ | LWSGGPIO_FL_PULLUP);
|
||||||
|
ea->gpio->mode(ea->reset_gpio, LWSGGPIO_FL_WRITE | LWSGGPIO_FL_PULLUP);
|
||||||
|
|
||||||
|
ea->gpio->set(ea->reset_gpio, 1);
|
||||||
|
priv->state = LWSDISPST_INIT1;
|
||||||
|
lws_sul_schedule(lds->ctx, 0, &priv->sul, async_cb,
|
||||||
|
LWS_US_PER_MS * 200);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no backlight */
|
||||||
|
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_brightness(const struct lws_display *disp, uint8_t b)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_blit(struct lws_display_state *lds, const uint8_t *src,
|
||||||
|
lws_box_t *box, lws_dll2_owner_t *ids)
|
||||||
|
{
|
||||||
|
lws_display_spd1656_spi_state_t *priv = lds_to_priv(lds);
|
||||||
|
const lws_display_spd1656_spi_t *ea = lds_to_disp(lds);
|
||||||
|
lws_greyscale_error_t *gedl_this, *gedl_next;
|
||||||
|
const lws_surface_info_t *ic = &ea->disp.ic;
|
||||||
|
lws_colour_error_t *edl_this, *edl_next;
|
||||||
|
size_t bytes_pl = ic->wh_px[0].whole / 2;
|
||||||
|
const uint8_t *pc = src;
|
||||||
|
lws_display_colour_t c;
|
||||||
|
lws_spi_desc_t desc;
|
||||||
|
uint8_t temp[10];
|
||||||
|
uint32_t *lo;
|
||||||
|
int n, m;
|
||||||
|
|
||||||
|
if (priv->state) {
|
||||||
|
lwsl_warn("%s: ignoring as busy\n", __func__);
|
||||||
|
return 1; /* busy */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priv->line[0]) {
|
||||||
|
/*
|
||||||
|
* We have to allocate the packed line and error diffusion
|
||||||
|
* buffers
|
||||||
|
*/
|
||||||
|
if (ea->spi->alloc_dma)
|
||||||
|
priv->line[0] = ea->spi->alloc_dma(ea->spi, bytes_pl * 2);
|
||||||
|
else
|
||||||
|
priv->line[0] = lws_zalloc(bytes_pl * 2, __func__);
|
||||||
|
|
||||||
|
if (!priv->line[0]) {
|
||||||
|
lwsl_err("%s: OOM\n", __func__);
|
||||||
|
priv->state = LWSDISPST_IDLE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->line[1] = (uint32_t *)(((uint8_t *)priv->line[0]) + bytes_pl);
|
||||||
|
|
||||||
|
if (lws_display_alloc_diffusion(ic, priv->u)) {
|
||||||
|
if (ea->spi->free_dma)
|
||||||
|
ea->spi->free_dma(ea->spi,
|
||||||
|
(void **)&priv->line[0]);
|
||||||
|
else
|
||||||
|
lws_free_set_NULL(priv->line[0]);
|
||||||
|
lwsl_err("%s: OOM\n", __func__);
|
||||||
|
priv->state = LWSDISPST_IDLE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lo = priv->line[box->y.whole & 1];
|
||||||
|
|
||||||
|
// lwsl_notice("%s: switch %d\n", __func__, box->h.whole);
|
||||||
|
|
||||||
|
switch (box->h.whole) {
|
||||||
|
case 0: /* update is finished */
|
||||||
|
priv->state = LWSDISPST_WRITE1;
|
||||||
|
lws_sul_schedule(priv->lds->ctx, 0, &priv->sul, async_cb, 1);
|
||||||
|
if (ea->spi->free_dma)
|
||||||
|
ea->spi->free_dma(ea->spi,
|
||||||
|
(void **)&priv->line[0]);
|
||||||
|
else
|
||||||
|
lws_free_set_NULL(priv->line[0]);
|
||||||
|
lws_free_set_NULL(priv->u[0]);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 1: /* single line = issue line */
|
||||||
|
edl_this = (lws_colour_error_t *)priv->u[(box->y.whole & 1) ^ 1];
|
||||||
|
edl_next = (lws_colour_error_t *)priv->u[box->y.whole & 1];
|
||||||
|
gedl_this = (lws_greyscale_error_t *)edl_this;
|
||||||
|
gedl_next = (lws_greyscale_error_t *)edl_next;
|
||||||
|
|
||||||
|
memset(&desc, 0, sizeof(desc));
|
||||||
|
|
||||||
|
if (!pc) {
|
||||||
|
for (n = 0; n < ic->wh_px[0].whole; n++)
|
||||||
|
pack_native_pixel(lo, n, 1 /* white */);
|
||||||
|
goto go;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ic->greyscale)
|
||||||
|
for (n = 0; n < ic->wh_px[0].whole; n++) {
|
||||||
|
c = (pc[0] << 16) | (pc[0] << 8) | pc[0];
|
||||||
|
|
||||||
|
m = lws_display_palettize_grey(ic, ic->palette,
|
||||||
|
ic->palette_depth, c, &gedl_this[n]);
|
||||||
|
pack_native_pixel(lo, n, (uint8_t)m);
|
||||||
|
|
||||||
|
dist_err_floyd_steinberg_grey(n, ic->wh_px[0].whole,
|
||||||
|
gedl_this, gedl_next);
|
||||||
|
pc++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (n = 0; n < ic->wh_px[0].whole; n++) {
|
||||||
|
c = (pc[2] << 16) | (pc[1] << 8) | pc[0];
|
||||||
|
|
||||||
|
m = lws_display_palettize_col(ic, ic->palette,
|
||||||
|
ic->palette_depth, c, &edl_this[n]);
|
||||||
|
pack_native_pixel(lo, n, (uint8_t)m);
|
||||||
|
|
||||||
|
dist_err_floyd_steinberg_col(n, ic->wh_px[0].whole,
|
||||||
|
edl_this, edl_next);
|
||||||
|
|
||||||
|
pc += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
go:
|
||||||
|
/* priv->line is already allocated for DMA */
|
||||||
|
desc.flags = LWS_SPI_FLAG_DMA_BOUNCE_NOT_NEEDED;
|
||||||
|
desc.flags |= box->y.whole + 1 != ic->wh_px[1].whole ?
|
||||||
|
LWS_SPI_FLAG_DATA_CONTINUE : 0;
|
||||||
|
desc.data = (uint8_t *)priv->line[box->y.whole & 1];
|
||||||
|
desc.count_write = ic->wh_px[0].whole / 2;
|
||||||
|
ea->spi->queue(ea->spi, &desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Start whole page update... no partial updates on this controller,
|
||||||
|
* box must be whole display */
|
||||||
|
|
||||||
|
lwsl_notice("%s: start update\n", __func__);
|
||||||
|
memcpy(temp, spd1656_write1, LWS_ARRAY_SIZE(spd1656_write1));
|
||||||
|
|
||||||
|
/* width and height filled in from display struct */
|
||||||
|
|
||||||
|
temp[2] = (lds->disp->ic.wh_px[0].whole >> 8) & 0xff;
|
||||||
|
temp[3] = lds->disp->ic.wh_px[0].whole & 0xff;
|
||||||
|
temp[4] = (lds->disp->ic.wh_px[1].whole >> 8) & 0xff;
|
||||||
|
temp[5] = lds->disp->ic.wh_px[1].whole & 0xff;
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, 0, temp,
|
||||||
|
LWS_ARRAY_SIZE(spd1656_write1));
|
||||||
|
|
||||||
|
lws_spi_table_issue(ea->spi, LWS_SPI_FLAG_DATA_CONTINUE,
|
||||||
|
spd1656_write1a, LWS_ARRAY_SIZE(spd1656_write1a));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lws_display_spd1656_spi_power(lws_display_state_t *lds, int state)
|
||||||
|
{
|
||||||
|
const lws_display_spd1656_spi_t *ea = lds_to_disp(lds);
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
lws_spi_table_issue(ea->spi, 0, spd1656_off, LWS_ARRAY_SIZE(spd1656_off));
|
||||||
|
|
||||||
|
if (ea->gpio)
|
||||||
|
ea->gpio->set(ea->reset_gpio, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue