1 /*
2 * Copyright (c) 2020 Hubert Miś
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ftdi_ft800
8
9 #include <zephyr/drivers/misc/ft8xx/ft8xx.h>
10
11 #include <stddef.h>
12 #include <stdint.h>
13
14 #include <zephyr/device.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/logging/log.h>
17
18 #include <zephyr/drivers/misc/ft8xx/ft8xx_copro.h>
19 #include <zephyr/drivers/misc/ft8xx/ft8xx_common.h>
20 #include <zephyr/drivers/misc/ft8xx/ft8xx_dl.h>
21 #include <zephyr/drivers/misc/ft8xx/ft8xx_memory.h>
22
23 #include "ft8xx_drv.h"
24 #include "ft8xx_host_commands.h"
25
26 LOG_MODULE_REGISTER(ft8xx, CONFIG_DISPLAY_LOG_LEVEL);
27
28 #define FT8XX_DLSWAP_FRAME 0x02
29
30 #define FT8XX_EXPECTED_ID 0x7C
31
32 struct ft8xx_config {
33 uint16_t vsize;
34 uint16_t voffset;
35 uint16_t vcycle;
36 uint16_t vsync0;
37 uint16_t vsync1;
38 uint16_t hsize;
39 uint16_t hoffset;
40 uint16_t hcycle;
41 uint16_t hsync0;
42 uint16_t hsync1;
43 uint8_t pclk;
44 uint8_t pclk_pol :1;
45 uint8_t cspread :1;
46 uint8_t swizzle :4;
47 };
48
49 struct ft8xx_data {
50 const struct ft8xx_config *config;
51 ft8xx_int_callback irq_callback;
52 };
53
54 const static struct ft8xx_config ft8xx_config = {
55 .pclk = DT_INST_PROP(0, pclk),
56 .pclk_pol = DT_INST_PROP(0, pclk_pol),
57 .cspread = DT_INST_PROP(0, cspread),
58 .swizzle = DT_INST_PROP(0, swizzle),
59 .vsize = DT_INST_PROP(0, vsize),
60 .voffset = DT_INST_PROP(0, voffset),
61 .vcycle = DT_INST_PROP(0, vcycle),
62 .vsync0 = DT_INST_PROP(0, vsync0),
63 .vsync1 = DT_INST_PROP(0, vsync1),
64 .hsize = DT_INST_PROP(0, hsize),
65 .hoffset = DT_INST_PROP(0, hoffset),
66 .hcycle = DT_INST_PROP(0, hcycle),
67 .hsync0 = DT_INST_PROP(0, hsync0),
68 .hsync1 = DT_INST_PROP(0, hsync1),
69 };
70
71 static struct ft8xx_data ft8xx_data = {
72 .config = &ft8xx_config,
73 .irq_callback = NULL,
74 };
75
host_command(uint8_t cmd)76 static void host_command(uint8_t cmd)
77 {
78 int err;
79
80 err = ft8xx_drv_command(cmd);
81 __ASSERT(err == 0, "Writing FT8xx command failed");
82 }
83
wait(void)84 static void wait(void)
85 {
86 k_sleep(K_MSEC(20));
87 }
88
verify_chip(void)89 static bool verify_chip(void)
90 {
91 uint32_t id = ft8xx_rd32(FT800_REG_ID);
92
93 return (id & 0xff) == FT8XX_EXPECTED_ID;
94 }
95
ft8xx_init(const struct device * dev)96 static int ft8xx_init(const struct device *dev)
97 {
98 int ret;
99 const struct ft8xx_config *config = dev->config;
100
101 ret = ft8xx_drv_init();
102 if (ret < 0) {
103 LOG_ERR("FT8xx driver initialization failed with %d", ret);
104 return ret;
105 }
106
107 /* Reset display controller */
108 host_command(CORERST);
109 host_command(ACTIVE);
110 wait();
111 host_command(CLKEXT);
112 host_command(CLK48M);
113 wait();
114
115 host_command(CORERST);
116 host_command(ACTIVE);
117 wait();
118 host_command(CLKEXT);
119 host_command(CLK48M);
120 wait();
121
122 if (!verify_chip()) {
123 LOG_ERR("FT8xx chip not recognized");
124 return -ENODEV;
125 }
126
127 /* Disable LCD */
128 ft8xx_wr8(FT800_REG_GPIO, 0);
129 ft8xx_wr8(FT800_REG_PCLK, 0);
130
131 /* Configure LCD */
132 ft8xx_wr16(FT800_REG_HSIZE, config->hsize);
133 ft8xx_wr16(FT800_REG_HCYCLE, config->hcycle);
134 ft8xx_wr16(FT800_REG_HOFFSET, config->hoffset);
135 ft8xx_wr16(FT800_REG_HSYNC0, config->hsync0);
136 ft8xx_wr16(FT800_REG_HSYNC1, config->hsync1);
137 ft8xx_wr16(FT800_REG_VSIZE, config->vsize);
138 ft8xx_wr16(FT800_REG_VCYCLE, config->vcycle);
139 ft8xx_wr16(FT800_REG_VOFFSET, config->voffset);
140 ft8xx_wr16(FT800_REG_VSYNC0, config->vsync0);
141 ft8xx_wr16(FT800_REG_VSYNC1, config->vsync1);
142 ft8xx_wr8(FT800_REG_SWIZZLE, config->swizzle);
143 ft8xx_wr8(FT800_REG_PCLK_POL, config->pclk_pol);
144 ft8xx_wr8(FT800_REG_CSPREAD, config->cspread);
145
146 /* Display initial screen */
147
148 /* Set the initial color */
149 ft8xx_wr32(FT800_RAM_DL + 0, FT8XX_CLEAR_COLOR_RGB(0, 0x80, 0));
150 /* Clear to the initial color */
151 ft8xx_wr32(FT800_RAM_DL + 4, FT8XX_CLEAR(1, 1, 1));
152 /* End the display list */
153 ft8xx_wr32(FT800_RAM_DL + 8, FT8XX_DISPLAY());
154 ft8xx_wr8(FT800_REG_DLSWAP, FT8XX_DLSWAP_FRAME);
155
156 /* Enable LCD */
157
158 /* Enable display bit */
159 ft8xx_wr8(FT800_REG_GPIO_DIR, 0x80);
160 ft8xx_wr8(FT800_REG_GPIO, 0x80);
161 /* Enable backlight */
162 ft8xx_wr16(FT800_REG_PWM_HZ, 0x00FA);
163 ft8xx_wr8(FT800_REG_PWM_DUTY, 0x10);
164 /* Enable LCD signals */
165 ft8xx_wr8(FT800_REG_PCLK, config->pclk);
166
167 return 0;
168 }
169
170 DEVICE_DT_INST_DEFINE(0, ft8xx_init, NULL, &ft8xx_data, &ft8xx_config,
171 POST_KERNEL, CONFIG_FT800_INIT_PRIORITY, NULL);
172
ft8xx_get_touch_tag(void)173 int ft8xx_get_touch_tag(void)
174 {
175 /* Read FT800_REG_INT_FLAGS to clear IRQ */
176 (void)ft8xx_rd8(FT800_REG_INT_FLAGS);
177
178 return (int)ft8xx_rd8(FT800_REG_TOUCH_TAG);
179 }
180
ft8xx_drv_irq_triggered(const struct device * dev,struct gpio_callback * cb,uint32_t pins)181 void ft8xx_drv_irq_triggered(const struct device *dev, struct gpio_callback *cb,
182 uint32_t pins)
183 {
184 if (ft8xx_data.irq_callback != NULL) {
185 ft8xx_data.irq_callback();
186 }
187 }
188
ft8xx_register_int(ft8xx_int_callback callback)189 void ft8xx_register_int(ft8xx_int_callback callback)
190 {
191 if (ft8xx_data.irq_callback != NULL) {
192 return;
193 }
194
195 ft8xx_data.irq_callback = callback;
196 ft8xx_wr8(FT800_REG_INT_MASK, 0x04);
197 ft8xx_wr8(FT800_REG_INT_EN, 0x01);
198 }
199
ft8xx_calibrate(struct ft8xx_touch_transform * data)200 void ft8xx_calibrate(struct ft8xx_touch_transform *data)
201 {
202 uint32_t result = 0;
203
204 do {
205 ft8xx_copro_cmd_dlstart();
206 ft8xx_copro_cmd(FT8XX_CLEAR_COLOR_RGB(0x00, 0x00, 0x00));
207 ft8xx_copro_cmd(FT8XX_CLEAR(1, 1, 1));
208 ft8xx_copro_cmd_calibrate(&result);
209 } while (result == 0);
210
211 data->a = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_A);
212 data->b = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_B);
213 data->c = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_C);
214 data->d = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_D);
215 data->e = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_E);
216 data->f = ft8xx_rd32(FT800_REG_TOUCH_TRANSFORM_F);
217 }
218
ft8xx_touch_transform_set(const struct ft8xx_touch_transform * data)219 void ft8xx_touch_transform_set(const struct ft8xx_touch_transform *data)
220 {
221 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_A, data->a);
222 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_B, data->b);
223 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_C, data->c);
224 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_D, data->d);
225 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_E, data->e);
226 ft8xx_wr32(FT800_REG_TOUCH_TRANSFORM_F, data->f);
227 }
228