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