Skip to content

Commit 1489038

Browse files
rbudai98kartben
authored andcommitted
drivers: gpio: add max14917
MAX14917 is an eight high-side switch, specified to deliver up to 700mA (min) continuous current per channel. The high-side switches have on-resistance of 120mΩ (typ) at 25°C ambient temperature Signed-off-by: Robert Budai <[email protected]>
1 parent 224b5b7 commit 1489038

File tree

7 files changed

+502
-0
lines changed

7 files changed

+502
-0
lines changed

drivers/gpio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c)
4545
zephyr_library_sources_ifdef(CONFIG_GPIO_LPC11U6X gpio_lpc11u6x.c)
4646
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX14906 gpio_max14906.c)
4747
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX14916 gpio_max14916.c)
48+
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX14917 gpio_max14917.c)
4849
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX22017 gpio_max22017.c)
4950
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX22190 gpio_max22190.c)
5051
zephyr_library_sources_ifdef(CONFIG_GPIO_MAX32 gpio_max32.c)

drivers/gpio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ source "drivers/gpio/Kconfig.lmp90xxx"
135135
source "drivers/gpio/Kconfig.lpc11u6x"
136136
source "drivers/gpio/Kconfig.max14906"
137137
source "drivers/gpio/Kconfig.max14916"
138+
source "drivers/gpio/Kconfig.max14917"
138139
source "drivers/gpio/Kconfig.max22017"
139140
source "drivers/gpio/Kconfig.max22190"
140141
source "drivers/gpio/Kconfig.max32"

drivers/gpio/Kconfig.max14917

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2025 Analog Devices Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# MAX14917 GPIO configuration options
5+
6+
menuconfig GPIO_MAX14917
7+
bool "MAX14917 GPIO driver"
8+
default y
9+
select CRC
10+
depends on DT_HAS_ADI_MAX14917_GPIO_ENABLED && SPI
11+
help
12+
Enable MAX14917 octal industrial digital
13+
output with diagnostics
14+
15+
config GPIO_MAX14917_INIT_PRIORITY
16+
int "Driver init priority"
17+
default 99
18+
depends on GPIO_MAX14917
19+
help
20+
Device driver initialization priority.

drivers/gpio/gpio_max14917.c

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
/*
2+
* Copyright (c) 2025 Analog Devices Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/drivers/gpio.h>
8+
#include <zephyr/drivers/spi.h>
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/sys/byteorder.h>
11+
#include <zephyr/sys/crc.h>
12+
13+
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
14+
#include <zephyr/logging/log.h>
15+
16+
LOG_MODULE_REGISTER(gpio_max14917);
17+
18+
#include <zephyr/drivers/gpio/gpio_utils.h>
19+
20+
#include "gpio_max14917.h"
21+
22+
#define DT_DRV_COMPAT adi_max14917_gpio
23+
24+
static int max14917_reg_trans_spi_diag(const struct device *dev)
25+
{
26+
int ret = 0;
27+
uint8_t crc;
28+
29+
uint8_t local_tx_buff[MAX14917_MAX_PKT_SIZE] = {0};
30+
uint8_t local_rx_buff[MAX14917_MAX_PKT_SIZE] = {0};
31+
32+
struct max14917_data *data = dev->data;
33+
const struct max14917_config *config = dev->config;
34+
35+
struct spi_buf tx_buf = {
36+
.buf = &local_tx_buff,
37+
.len = config->pkt_size,
38+
};
39+
const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1};
40+
41+
struct spi_buf rx_buf = {
42+
.buf = &local_rx_buff,
43+
.len = config->pkt_size,
44+
};
45+
const struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1};
46+
47+
local_tx_buff[0] = data->gpios_ON;
48+
49+
/* If CRC enabled calculate it */
50+
if (config->crc_en) {
51+
crc = crc8(&local_tx_buff[0], 1, MAX14917_CRC_POLY, MAX14917_CRC_INI_VAL, false);
52+
local_tx_buff[1] = (crc & MAX14917_CRC_MASK);
53+
}
54+
55+
/* Perform SPI transaction */
56+
ret = spi_transceive_dt(&config->spi, &tx, &rx);
57+
if (ret) {
58+
LOG_ERR("SPI transfer failed");
59+
return ret;
60+
}
61+
62+
/* If CRC enabled check it */
63+
if (config->crc_en) {
64+
crc = crc8(&local_tx_buff[0], 1, MAX14917_CRC_POLY, MAX14917_CRC_INI_VAL, false);
65+
crc = (crc & MAX14917_CRC_MASK);
66+
if (crc != (local_rx_buff[1] & 0x1F)) {
67+
LOG_ERR("READ CRC ERR (%d)-(%d)\n", crc, (local_rx_buff[1] & 0x1F));
68+
return -EINVAL;
69+
}
70+
/* Set error flags in device data */
71+
data->comm_err = (local_rx_buff[1] & MAX14917_COMM_ERR);
72+
data->verr = (local_rx_buff[1] & MAX14917_VERR);
73+
data->therm_err = (local_rx_buff[1] & MAX14917_THERM_ERR);
74+
}
75+
76+
data->gpios_fault = local_rx_buff[0];
77+
78+
return 0;
79+
}
80+
81+
static int max14917_fault_check(const struct device *dev)
82+
{
83+
int ret;
84+
const struct max14917_data *data = dev->data;
85+
const struct max14917_config *config = dev->config;
86+
87+
if (gpio_pin_get_dt(&config->fault_gpio)) {
88+
LOG_DBG("FAULT GPIO is high");
89+
}
90+
91+
/* Update error flags */
92+
ret = max14917_reg_trans_spi_diag(dev);
93+
if (ret) {
94+
return ret;
95+
}
96+
97+
if (data->comm_err) {
98+
LOG_DBG("COMMERR flag is active");
99+
}
100+
if (data->verr) {
101+
LOG_DBG("VERR flag is active");
102+
}
103+
if (data->therm_err) {
104+
LOG_DBG("THERMERR flag is active");
105+
}
106+
107+
for (int i = 0; i < MAX14917_CHANNELS; i++) {
108+
if (data->gpios_fault & BIT(i)) {
109+
LOG_DBG("Channel %d has a fault", i);
110+
}
111+
}
112+
113+
return 0;
114+
}
115+
116+
static int gpio_max14917_init(const struct device *dev)
117+
{
118+
struct max14917_data *data = dev->data;
119+
const struct max14917_config *config = dev->config;
120+
int err = 0;
121+
122+
LOG_DBG(" --- GPIO max14917 init IN ---");
123+
124+
if (!spi_is_ready_dt(&config->spi)) {
125+
LOG_ERR("SPI bus is not ready\n");
126+
return -ENODEV;
127+
}
128+
129+
/* Output GPIOS */
130+
/* setup EN gpio - normal low */
131+
if (!gpio_is_ready_dt(&config->en_gpio)) {
132+
LOG_ERR("EN GPIO device not ready");
133+
return -ENODEV;
134+
}
135+
136+
err = gpio_pin_configure_dt(&config->en_gpio, GPIO_OUTPUT);
137+
if (err < 0) {
138+
LOG_ERR("Failed to configure EN GPIO");
139+
return err;
140+
}
141+
142+
/* setup SYNC gpio - normal low */
143+
if (!gpio_is_ready_dt(&config->sync_gpio)) {
144+
LOG_ERR("SYNC GPIO device not ready");
145+
return -ENODEV;
146+
}
147+
148+
err = gpio_pin_configure_dt(&config->sync_gpio, GPIO_OUTPUT);
149+
if (err < 0) {
150+
LOG_ERR("Failed to configure SYNC GPIO");
151+
return err;
152+
}
153+
/* setup CRCEN gpio - normal low */
154+
if (!gpio_is_ready_dt(&config->crcen_gpio)) {
155+
LOG_ERR("CRCEN GPIO device not ready");
156+
return -ENODEV;
157+
}
158+
159+
err = gpio_pin_configure_dt(&config->crcen_gpio, GPIO_OUTPUT);
160+
if (err < 0) {
161+
LOG_ERR("Failed to configure CRCEN GPIO");
162+
return err;
163+
}
164+
/* Input GPIOS */
165+
/* setup VDDOK gpio - normal low */
166+
if (!gpio_is_ready_dt(&config->vddok_gpio)) {
167+
LOG_ERR("VDDOK GPIO device not ready");
168+
return -ENODEV;
169+
}
170+
171+
err = gpio_pin_configure_dt(&config->vddok_gpio, GPIO_INPUT);
172+
if (err < 0) {
173+
LOG_ERR("Failed to configure VDDOK GPIO");
174+
return err;
175+
}
176+
/* setup READY gpio - normal low */
177+
if (!gpio_is_ready_dt(&config->ready_gpio)) {
178+
LOG_ERR("VDDOK READY device not ready");
179+
return -ENODEV;
180+
}
181+
182+
err = gpio_pin_configure_dt(&config->ready_gpio, GPIO_INPUT);
183+
if (err < 0) {
184+
LOG_ERR("Failed to configure READY GPIO");
185+
return err;
186+
}
187+
/* setup COMERR gpio - normal low */
188+
if (!gpio_is_ready_dt(&config->comerr_gpio)) {
189+
LOG_ERR("COMERR GPIO device not ready");
190+
return -ENODEV;
191+
}
192+
193+
err = gpio_pin_configure_dt(&config->comerr_gpio, GPIO_INPUT);
194+
if (err < 0) {
195+
LOG_ERR("Failed to configure COMERR GPIO");
196+
return err;
197+
}
198+
/* setup FAULT gpio - normal low */
199+
if (!gpio_is_ready_dt(&config->fault_gpio)) {
200+
LOG_ERR("FAULT GPIO device not ready");
201+
return -ENODEV;
202+
}
203+
204+
err = gpio_pin_configure_dt(&config->fault_gpio, GPIO_INPUT);
205+
if (err < 0) {
206+
LOG_ERR("Failed to configure FAULT GPIO");
207+
return err;
208+
}
209+
210+
err = gpio_pin_set_dt(&config->en_gpio, 1);
211+
if (err) {
212+
return err;
213+
}
214+
err = gpio_pin_set_dt(&config->sync_gpio, 1);
215+
if (err) {
216+
return err;
217+
}
218+
219+
if (config->crc_en) {
220+
err = gpio_pin_set_dt(&config->crcen_gpio, 1);
221+
} else {
222+
err = gpio_pin_set_dt(&config->crcen_gpio, 0);
223+
}
224+
225+
if (err) {
226+
return err;
227+
}
228+
229+
/* Initialize satus and fault flags to 0 */
230+
data->gpios_ON = 0;
231+
data->gpios_fault = 0;
232+
233+
err = max14917_fault_check(dev);
234+
235+
return err;
236+
}
237+
238+
static int gpio_max14917_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
239+
{
240+
int err = 0;
241+
242+
if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) {
243+
return -ENOTSUP;
244+
}
245+
246+
if ((flags & GPIO_SINGLE_ENDED) != 0) {
247+
return -ENOTSUP;
248+
}
249+
250+
if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
251+
return -ENOTSUP;
252+
}
253+
254+
if (flags & GPIO_INT_ENABLE) {
255+
return -ENOTSUP;
256+
}
257+
258+
switch (flags & GPIO_DIR_MASK) {
259+
case GPIO_OUTPUT:
260+
break;
261+
case GPIO_INPUT:
262+
default:
263+
LOG_ERR("NOT SUPPORTED OPTION!");
264+
return -ENOTSUP;
265+
}
266+
267+
return err;
268+
}
269+
270+
static int gpio_max14917_port_get_raw(const struct device *dev, gpio_port_value_t *value)
271+
{
272+
int ret;
273+
const struct max14917_data *data = dev->data;
274+
275+
ret = max14917_fault_check(dev);
276+
if (ret) {
277+
return ret;
278+
}
279+
280+
*value = data->gpios_ON;
281+
282+
return 0;
283+
}
284+
285+
static int gpio_max14917_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
286+
{
287+
int ret;
288+
struct max14917_data *data = dev->data;
289+
290+
ret = max14917_fault_check(dev);
291+
if (ret) {
292+
return ret;
293+
}
294+
295+
data->gpios_ON = data->gpios_ON | pins;
296+
297+
return max14917_reg_trans_spi_diag(dev);
298+
}
299+
300+
static int gpio_max14917_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
301+
{
302+
int ret;
303+
struct max14917_data *data = dev->data;
304+
305+
ret = max14917_fault_check(dev);
306+
if (ret) {
307+
return ret;
308+
}
309+
310+
data->gpios_ON = data->gpios_ON & ~pins;
311+
312+
return max14917_reg_trans_spi_diag(dev);
313+
}
314+
315+
static int gpio_max14917_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
316+
{
317+
int ret;
318+
struct max14917_data *data = dev->data;
319+
320+
ret = max14917_fault_check(dev);
321+
if (ret) {
322+
return ret;
323+
}
324+
325+
data->gpios_ON ^= pins;
326+
327+
return max14917_reg_trans_spi_diag(dev);
328+
}
329+
330+
static DEVICE_API(gpio, gpio_max14917_api) = {
331+
.pin_configure = gpio_max14917_config,
332+
.port_get_raw = gpio_max14917_port_get_raw,
333+
.port_set_bits_raw = gpio_max14917_port_set_bits_raw,
334+
.port_clear_bits_raw = gpio_max14917_port_clear_bits_raw,
335+
.port_toggle_bits = gpio_max14917_port_toggle_bits,
336+
};
337+
338+
#define GPIO_MAX14917_DEVICE(id) \
339+
static const struct max14917_config max14917_##id##_cfg = { \
340+
.spi = SPI_DT_SPEC_INST_GET(id, SPI_OP_MODE_MASTER | SPI_WORD_SET(8U), 0U), \
341+
.vddok_gpio = GPIO_DT_SPEC_INST_GET(id, vddok_gpios), \
342+
.ready_gpio = GPIO_DT_SPEC_INST_GET(id, ready_gpios), \
343+
.comerr_gpio = GPIO_DT_SPEC_INST_GET(id, comerr_gpios), \
344+
.fault_gpio = GPIO_DT_SPEC_INST_GET(id, fault_gpios), \
345+
.en_gpio = GPIO_DT_SPEC_INST_GET(id, en_gpios), \
346+
.sync_gpio = GPIO_DT_SPEC_INST_GET(id, sync_gpios), \
347+
.crcen_gpio = GPIO_DT_SPEC_INST_GET(id, crcen_gpios), \
348+
.crc_en = DT_INST_PROP(id, crc_en), \
349+
.pkt_size = (DT_INST_PROP(id, crc_en) & 0x1) ? 2 : 1, \
350+
}; \
351+
\
352+
static struct max14917_data max14917_##id##_data; \
353+
\
354+
DEVICE_DT_INST_DEFINE(id, &gpio_max14917_init, NULL, &max14917_##id##_data, \
355+
&max14917_##id##_cfg, POST_KERNEL, \
356+
CONFIG_GPIO_MAX14917_INIT_PRIORITY, &gpio_max14917_api);
357+
358+
DT_INST_FOREACH_STATUS_OKAY(GPIO_MAX14917_DEVICE)

0 commit comments

Comments
 (0)