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 (!device_is_ready(irq_gpio.port)) {
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