1 /*
2  * Copyright (c) 2020 Hubert Miś
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "ft8xx_drv.h"
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/spi.h>
12 #include <zephyr/logging/log.h>
13 
14 #define LOG_MODULE_NAME ft8xx_drv
15 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
16 
17 #define DT_DRV_COMPAT ftdi_ft800
18 #define NODE_ID DT_INST(0, DT_DRV_COMPAT)
19 
20 /* SPI device */
21 static const struct spi_dt_spec spi = SPI_DT_SPEC_INST_GET(0,
22 					 SPI_WORD_SET(8) | SPI_OP_MODE_MASTER,
23 					 0);
24 
25 /* GPIO int line */
26 static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios);
27 
28 static struct gpio_callback irq_cb_data;
29 
ft8xx_drv_irq_triggered(const struct device * dev,struct gpio_callback * cb,uint32_t pins)30 __weak void ft8xx_drv_irq_triggered(const struct device *dev,
31 				     struct gpio_callback *cb, uint32_t pins)
32 {
33 	/* Intentionally empty */
34 }
35 
36 /* Protocol details */
37 #define ADDR_SIZE 3
38 #define DUMMY_READ_SIZE 1
39 #define COMMAND_SIZE 3
40 #define MAX_READ_LEN (UINT16_MAX - ADDR_SIZE - DUMMY_READ_SIZE)
41 #define MAX_WRITE_LEN (UINT16_MAX - ADDR_SIZE)
42 
43 #define READ_OP 0x00
44 #define WRITE_OP 0x80
45 #define COMMAND_OP 0x40
46 
insert_addr(uint32_t addr,uint8_t * buff)47 static void insert_addr(uint32_t addr, uint8_t *buff)
48 {
49 	buff[0] = (addr >> 16) & 0x3f;
50 	buff[1] = (addr >> 8) & 0xff;
51 	buff[2] = (addr) & 0xff;
52 }
53 
ft8xx_drv_init(void)54 int ft8xx_drv_init(void)
55 {
56 	int ret;
57 
58 	if (!spi_is_ready_dt(&spi)) {
59 		LOG_ERR("SPI bus %s not ready", spi.bus->name);
60 		return -ENODEV;
61 	}
62 
63 	/* TODO: Verify if such entry in DTS is present.
64 	 * If not, use polling mode.
65 	 */
66 	if (!gpio_is_ready_dt(&irq_gpio)) {
67 		LOG_ERR("GPIO device %s is not ready", irq_gpio.port->name);
68 		return -ENODEV;
69 	}
70 
71 	ret = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT);
72 	if (ret != 0) {
73 		return ret;
74 	}
75 
76 	ret = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
77 	if (ret != 0) {
78 		return ret;
79 	}
80 
81 	gpio_init_callback(&irq_cb_data, ft8xx_drv_irq_triggered, BIT(irq_gpio.pin));
82 	gpio_add_callback(irq_gpio.port, &irq_cb_data);
83 
84 	return 0;
85 }
86 
ft8xx_drv_write(uint32_t address,const uint8_t * data,unsigned int length)87 int ft8xx_drv_write(uint32_t address, const uint8_t *data, unsigned int length)
88 {
89 	int ret;
90 	uint8_t addr_buf[ADDR_SIZE];
91 
92 	insert_addr(address, addr_buf);
93 	addr_buf[0] |= WRITE_OP;
94 
95 	struct spi_buf tx[] = {
96 		{
97 			.buf = addr_buf,
98 			.len = sizeof(addr_buf),
99 		},
100 		{
101 			/* Discard const, it is implicit for TX buffer */
102 			.buf = (uint8_t *)data,
103 			.len = length,
104 		},
105 	};
106 
107 	struct spi_buf_set tx_bufs = {
108 		.buffers = tx,
109 		.count = 2,
110 	};
111 
112 	ret = spi_write_dt(&spi, &tx_bufs);
113 	if (ret < 0) {
114 		LOG_ERR("SPI write error: %d", ret);
115 	}
116 
117 	return ret;
118 }
119 
ft8xx_drv_read(uint32_t address,uint8_t * data,unsigned int length)120 int ft8xx_drv_read(uint32_t address, uint8_t *data, unsigned int length)
121 {
122 	int ret;
123 	uint8_t dummy_read_buf[ADDR_SIZE + DUMMY_READ_SIZE];
124 	uint8_t addr_buf[ADDR_SIZE];
125 
126 	insert_addr(address, addr_buf);
127 	addr_buf[0] |= READ_OP;
128 
129 	struct spi_buf tx = {
130 		.buf = addr_buf,
131 		.len = sizeof(addr_buf),
132 	};
133 
134 	struct spi_buf_set tx_bufs = {
135 		.buffers = &tx,
136 		.count = 1,
137 	};
138 
139 	struct spi_buf rx[] = {
140 		{
141 			.buf = dummy_read_buf,
142 			.len = sizeof(dummy_read_buf),
143 		},
144 		{
145 			.buf = data,
146 			.len = length,
147 		},
148 	};
149 
150 	struct spi_buf_set rx_bufs = {
151 		.buffers = rx,
152 		.count = 2,
153 	};
154 
155 	ret = spi_transceive_dt(&spi, &tx_bufs, &rx_bufs);
156 	if (ret < 0) {
157 		LOG_ERR("SPI transceive error: %d", ret);
158 	}
159 
160 	return ret;
161 }
162 
ft8xx_drv_command(uint8_t command)163 int ft8xx_drv_command(uint8_t command)
164 {
165 	int ret;
166 	/* Most commands include COMMAND_OP bit. ACTIVE power mode command is
167 	 * an exception with value 0x00.
168 	 */
169 	uint8_t cmd_buf[COMMAND_SIZE] = {command, 0, 0};
170 
171 	struct spi_buf tx = {
172 		.buf = cmd_buf,
173 		.len = sizeof(cmd_buf),
174 	};
175 
176 	struct spi_buf_set tx_bufs = {
177 		.buffers = &tx,
178 		.count = 1,
179 	};
180 
181 	ret = spi_write_dt(&spi, &tx_bufs);
182 	if (ret < 0) {
183 		LOG_ERR("SPI command error: %d", ret);
184 	}
185 
186 	return ret;
187 }
188