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