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