1 /*
2  * Copyright (c) 2023 SILA Embedded Solutions GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT infineon_tle9104
8 
9 #include <errno.h>
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/drivers/gpio/gpio_utils.h>
16 #include <zephyr/drivers/spi.h>
17 #include <zephyr/logging/log.h>
18 #include <zephyr/sys/byteorder.h>
19 
20 LOG_MODULE_REGISTER(gpio_tle9104, CONFIG_GPIO_LOG_LEVEL);
21 
22 /*
23  * The values for the defines below as well as the register definitions were
24  * taken from the datasheet, which can be found at:
25  * https://www.infineon.com/dgdl/Infineon-TLE9104SH-DataSheet-v01_31-EN.pdf?fileId=5546d462766cbe86017676144d76581b
26  */
27 #define TLE9104_RESET_DURATION_TIME_US                    10
28 #define TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US 200
29 #define TLE9104_RESET_DURATION_WAIT_TIME_US               10
30 #define TLE9104_GPIO_COUNT                                4
31 #define TLE9104_INITIALIZATION_TIMEOUT_MS                 1
32 #define TLE9104_ICVERSIONID                               0xB1
33 
34 #define TLE9104_FRAME_RW_POS                 15
35 #define TLE9104_FRAME_PARITY_POS             14
36 #define TLE9104_FRAME_FAULTCOMMUNICATION_POS 13
37 #define TLE9104_FRAME_FAULTGLOBAL_POS        12
38 #define TLE9104_FRAME_ADDRESS_POS            8
39 #define TLE9104_FRAME_DATA_POS               0
40 
41 #define TLE9104_CFG_CWDTIME_LENGTH 2
42 #define TLE9104_CFG_CWDTIME_POS    6
43 
44 #define TLE9104_CTRL_OUT1ONS_BIT                BIT(1)
45 #define TLE9104_CTRL_OUT1ONC_BIT                BIT(0)
46 #define TLE9104_CFG_OUT1DD_BIT                  BIT(0)
47 #define TLE9104_GLOBALSTATUS_OUTEN_BIT          BIT(7)
48 #define TLE9104_GLOBALSTATUS_POR_LATCH_BIT      BIT(0)
49 #define TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT BIT(13)
50 
51 enum tle9104_register {
52 	TLE9104REGISTER_CTRL = 0x00,
53 	TLE9104REGISTER_CFG = 0x01,
54 	TLE9104REGISTER_GLOBALSTATUS = 0x07,
55 	TLE9104REGISTER_ICVID = 0x08,
56 };
57 
58 struct tle9104_config {
59 	/* gpio_driver_config needs to be first */
60 	struct gpio_driver_config common;
61 
62 	struct spi_dt_spec bus;
63 	const struct gpio_dt_spec gpio_reset;
64 	const struct gpio_dt_spec gpio_enable;
65 	const struct gpio_dt_spec gpio_control[TLE9104_GPIO_COUNT];
66 };
67 
68 struct tle9104_data {
69 	/* gpio_driver_data needs to be first */
70 	struct gpio_driver_data common;
71 	/* each bit is one output channel, bit 0 = OUT1, ... */
72 	uint8_t state;
73 	/* same as state, just kept for checking what has to be updated */
74 	uint8_t previous_state;
75 	/* each bit defines if the output channel is configured, see state */
76 	uint8_t configured;
77 	struct k_mutex lock;
78 	/* communication watchdog is getting ignored */
79 	bool cwd_ignore;
80 };
81 
tle9104_set_cfg_cwdtime(uint8_t * destination,uint8_t value)82 static void tle9104_set_cfg_cwdtime(uint8_t *destination, uint8_t value)
83 {
84 	uint8_t length = TLE9104_CFG_CWDTIME_LENGTH;
85 	uint8_t pos = TLE9104_CFG_CWDTIME_POS;
86 
87 	*destination &= ~GENMASK(pos + length - 1, pos);
88 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
89 }
90 
tle9104_calculate_parity(uint16_t value)91 static int tle9104_calculate_parity(uint16_t value)
92 {
93 	int parity = 1 + POPCOUNT(value);
94 
95 	if ((value & BIT(TLE9104_FRAME_PARITY_POS)) != 0) {
96 		parity--;
97 	}
98 
99 	return parity % 2;
100 }
101 
tle9104_apply_parity(uint16_t * value)102 static void tle9104_apply_parity(uint16_t *value)
103 {
104 	int parity = tle9104_calculate_parity(*value);
105 
106 	WRITE_BIT(*value, TLE9104_FRAME_PARITY_POS, parity);
107 }
108 
tle9104_check_parity(uint16_t value)109 static bool tle9104_check_parity(uint16_t value)
110 {
111 	int parity = tle9104_calculate_parity(value);
112 
113 	return ((value & BIT(TLE9104_FRAME_PARITY_POS)) >> TLE9104_FRAME_PARITY_POS) == parity;
114 }
115 
tle9104_transceive_frame(const struct device * dev,bool write,enum tle9104_register write_reg,uint8_t write_data,enum tle9104_register * read_reg,uint8_t * read_data)116 static int tle9104_transceive_frame(const struct device *dev, bool write,
117 				    enum tle9104_register write_reg, uint8_t write_data,
118 				    enum tle9104_register *read_reg, uint8_t *read_data)
119 {
120 	const struct tle9104_config *config = dev->config;
121 	struct tle9104_data *data = dev->data;
122 	uint16_t write_frame;
123 	uint16_t read_frame;
124 	int result;
125 	uint8_t buffer_tx[2];
126 	uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)];
127 	const struct spi_buf tx_buf[] = {{
128 		.buf = buffer_tx,
129 		.len = ARRAY_SIZE(buffer_tx),
130 	}};
131 	const struct spi_buf rx_buf[] = {{
132 		.buf = buffer_rx,
133 		.len = ARRAY_SIZE(buffer_rx),
134 	}};
135 	const struct spi_buf_set tx = {
136 		.buffers = tx_buf,
137 		.count = ARRAY_SIZE(tx_buf),
138 	};
139 	const struct spi_buf_set rx = {
140 		.buffers = rx_buf,
141 		.count = ARRAY_SIZE(rx_buf),
142 	};
143 
144 	write_frame = write_data << TLE9104_FRAME_DATA_POS;
145 	write_frame |= write_reg << TLE9104_FRAME_ADDRESS_POS;
146 	WRITE_BIT(write_frame, TLE9104_FRAME_RW_POS, write);
147 	tle9104_apply_parity(&write_frame);
148 	sys_put_be16(write_frame, buffer_tx);
149 	LOG_DBG("writing in register 0x%02X of TLE9104 value 0x%02X, complete frame 0x%04X",
150 		write_reg, write_data, write_frame);
151 
152 	result = spi_transceive_dt(&config->bus, &tx, &rx);
153 	if (result != 0) {
154 		LOG_ERR("spi_write failed with error %i", result);
155 		return result;
156 	}
157 
158 	read_frame = sys_get_be16(buffer_rx);
159 	LOG_DBG("received complete frame 0x%04X", read_frame);
160 
161 	if (!tle9104_check_parity(read_frame)) {
162 		LOG_ERR("parity check for received frame of TLE9104 failed");
163 		return -EIO;
164 	}
165 
166 	if (!data->cwd_ignore) {
167 		if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) {
168 			LOG_WRN("%s: communication fault reported by TLE9104", dev->name);
169 		}
170 	}
171 
172 	*read_reg = FIELD_GET(GENMASK(TLE9104_FRAME_FAULTGLOBAL_POS - 1, TLE9104_FRAME_ADDRESS_POS),
173 			      read_frame);
174 	*read_data = FIELD_GET(GENMASK(TLE9104_FRAME_ADDRESS_POS - 1, TLE9104_FRAME_DATA_POS),
175 			       read_frame);
176 
177 	return 0;
178 }
179 
tle9104_write_register(const struct device * dev,enum tle9104_register reg,uint8_t value)180 static int tle9104_write_register(const struct device *dev, enum tle9104_register reg,
181 				  uint8_t value)
182 {
183 	enum tle9104_register read_reg;
184 	uint8_t read_data;
185 
186 	return tle9104_transceive_frame(dev, true, reg, value, &read_reg, &read_data);
187 }
188 
tle9104_write_state(const struct device * dev)189 static int tle9104_write_state(const struct device *dev)
190 {
191 	const struct tle9104_config *config = dev->config;
192 	struct tle9104_data *data = dev->data;
193 	bool spi_update_required = false;
194 	uint8_t register_ctrl = 0x00;
195 	int result;
196 
197 	LOG_DBG("writing state 0x%02X to TLE9104", data->state);
198 
199 	for (size_t i = 0; i < TLE9104_GPIO_COUNT; ++i) {
200 		uint8_t mask = GENMASK(i, i);
201 		bool current_value = (data->state & mask) != 0;
202 		bool previous_value = (data->previous_state & mask) != 0;
203 
204 		/*
205 		 * Setting the OUTx_ON bits results in a high impedance output,
206 		 * clearing them pulls the output to ground. Therefore the
207 		 * meaning here is intentionally inverted, as this will then turn
208 		 * out for a low active open drain output to be pulled to ground
209 		 * if set to off.
210 		 */
211 		if (current_value == 0) {
212 			register_ctrl |= TLE9104_CTRL_OUT1ONS_BIT << (2 * i);
213 		} else {
214 			register_ctrl |= TLE9104_CTRL_OUT1ONC_BIT << (2 * i);
215 		}
216 
217 		if (current_value == previous_value) {
218 			continue;
219 		}
220 
221 		if (config->gpio_control[i].port == NULL) {
222 			spi_update_required = true;
223 			continue;
224 		}
225 
226 		result = gpio_pin_set_dt(&config->gpio_control[i], current_value);
227 		if (result != 0) {
228 			LOG_ERR("unable to set control GPIO");
229 			return result;
230 		}
231 	}
232 
233 	if (spi_update_required) {
234 		result = tle9104_write_register(dev, TLE9104REGISTER_CTRL, register_ctrl);
235 		if (result != 0) {
236 			LOG_ERR("unable to set control register");
237 			return result;
238 		}
239 	}
240 
241 	data->previous_state = data->state;
242 
243 	return 0;
244 }
245 
tle9104_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)246 static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
247 {
248 	struct tle9104_data *data = dev->data;
249 	int result;
250 
251 	/* cannot execute a bus operation in an ISR context */
252 	if (k_is_in_isr()) {
253 		return -EWOULDBLOCK;
254 	}
255 
256 	if (pin >= TLE9104_GPIO_COUNT) {
257 		LOG_ERR("invalid pin number %i", pin);
258 		return -EINVAL;
259 	}
260 
261 	if ((flags & GPIO_INPUT) != 0) {
262 		LOG_ERR("cannot configure pin as input");
263 		return -ENOTSUP;
264 	}
265 
266 	if ((flags & GPIO_OUTPUT) == 0) {
267 		LOG_ERR("pin must be configured as an output");
268 		return -ENOTSUP;
269 	}
270 
271 	if ((flags & GPIO_SINGLE_ENDED) == 0) {
272 		LOG_ERR("pin must be configured as single ended");
273 		return -ENOTSUP;
274 	}
275 
276 	if ((flags & GPIO_LINE_OPEN_DRAIN) == 0) {
277 		LOG_ERR("pin must be configured as open drain");
278 		return -ENOTSUP;
279 	}
280 
281 	if ((flags & GPIO_PULL_UP) != 0) {
282 		LOG_ERR("pin cannot have a pull up configured");
283 		return -ENOTSUP;
284 	}
285 
286 	if ((flags & GPIO_PULL_DOWN) != 0) {
287 		LOG_ERR("pin cannot have a pull down configured");
288 		return -ENOTSUP;
289 	}
290 
291 	k_mutex_lock(&data->lock, K_FOREVER);
292 
293 	if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
294 		WRITE_BIT(data->state, pin, 0);
295 	} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
296 		WRITE_BIT(data->state, pin, 1);
297 	}
298 
299 	WRITE_BIT(data->configured, pin, 1);
300 	result = tle9104_write_state(dev);
301 	k_mutex_unlock(&data->lock);
302 
303 	return result;
304 }
305 
tle9104_port_get_raw(const struct device * dev,uint32_t * value)306 static int tle9104_port_get_raw(const struct device *dev, uint32_t *value)
307 {
308 	ARG_UNUSED(dev);
309 	ARG_UNUSED(value);
310 
311 	LOG_ERR("input pins are not available");
312 	return -ENOTSUP;
313 }
314 
tle9104_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)315 static int tle9104_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
316 {
317 	struct tle9104_data *data = dev->data;
318 	int result;
319 
320 	/* cannot execute a bus operation in an ISR context */
321 	if (k_is_in_isr()) {
322 		return -EWOULDBLOCK;
323 	}
324 
325 	k_mutex_lock(&data->lock, K_FOREVER);
326 	data->state = (data->state & ~mask) | (mask & value);
327 	result = tle9104_write_state(dev);
328 	k_mutex_unlock(&data->lock);
329 
330 	return result;
331 }
332 
tle9104_port_set_bits_raw(const struct device * dev,uint32_t mask)333 static int tle9104_port_set_bits_raw(const struct device *dev, uint32_t mask)
334 {
335 	return tle9104_port_set_masked_raw(dev, mask, mask);
336 }
337 
tle9104_port_clear_bits_raw(const struct device * dev,uint32_t mask)338 static int tle9104_port_clear_bits_raw(const struct device *dev, uint32_t mask)
339 {
340 	return tle9104_port_set_masked_raw(dev, mask, 0);
341 }
342 
tle9104_port_toggle_bits(const struct device * dev,uint32_t mask)343 static int tle9104_port_toggle_bits(const struct device *dev, uint32_t mask)
344 {
345 	struct tle9104_data *data = dev->data;
346 	int result;
347 
348 	/* cannot execute a bus operation in an ISR context */
349 	if (k_is_in_isr()) {
350 		return -EWOULDBLOCK;
351 	}
352 
353 	k_mutex_lock(&data->lock, K_FOREVER);
354 	data->state ^= mask;
355 	result = tle9104_write_state(dev);
356 	k_mutex_unlock(&data->lock);
357 
358 	return result;
359 }
360 
tle9104_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)361 static int tle9104_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
362 					   enum gpio_int_mode mode, enum gpio_int_trig trig)
363 {
364 	ARG_UNUSED(dev);
365 	ARG_UNUSED(pin);
366 	ARG_UNUSED(mode);
367 	ARG_UNUSED(trig);
368 	return -ENOTSUP;
369 }
370 
371 static const struct gpio_driver_api api_table = {
372 	.pin_configure = tle9104_pin_configure,
373 	.port_get_raw = tle9104_port_get_raw,
374 	.port_set_masked_raw = tle9104_port_set_masked_raw,
375 	.port_set_bits_raw = tle9104_port_set_bits_raw,
376 	.port_clear_bits_raw = tle9104_port_clear_bits_raw,
377 	.port_toggle_bits = tle9104_port_toggle_bits,
378 	.pin_interrupt_configure = tle9104_pin_interrupt_configure,
379 };
380 
tle9104_init(const struct device * dev)381 static int tle9104_init(const struct device *dev)
382 {
383 	const struct tle9104_config *config = dev->config;
384 	struct tle9104_data *data = dev->data;
385 	uint8_t register_cfg;
386 	uint8_t register_globalstatus;
387 	uint8_t register_icvid;
388 	enum tle9104_register read_reg;
389 	int result;
390 
391 	LOG_DBG("initialize TLE9104 instance %s", dev->name);
392 
393 	data->cwd_ignore = true;
394 
395 	result = k_mutex_init(&data->lock);
396 	if (result != 0) {
397 		LOG_ERR("unable to initialize mutex");
398 		return result;
399 	}
400 
401 	if (!spi_is_ready_dt(&config->bus)) {
402 		LOG_ERR("SPI bus %s is not ready", config->bus.bus->name);
403 		return -ENODEV;
404 	}
405 
406 	register_cfg = 0x00;
407 
408 	for (int i = 0; i < TLE9104_GPIO_COUNT; ++i) {
409 		const struct gpio_dt_spec *current = config->gpio_control + i;
410 
411 		if (current->port == NULL) {
412 			LOG_DBG("got no control port for output %i, will control it via SPI", i);
413 			continue;
414 		}
415 
416 		register_cfg |= TLE9104_CFG_OUT1DD_BIT << i;
417 
418 		if (!gpio_is_ready_dt(current)) {
419 			LOG_ERR("%s: control GPIO is not ready", dev->name);
420 			return -ENODEV;
421 		}
422 
423 		result = gpio_pin_configure_dt(current, GPIO_OUTPUT_INACTIVE);
424 		if (result != 0) {
425 			LOG_ERR("failed to initialize control GPIO %i", i);
426 			return result;
427 		}
428 	}
429 
430 	if (config->gpio_enable.port != NULL) {
431 		if (!gpio_is_ready_dt(&config->gpio_enable)) {
432 			LOG_ERR("%s: enable GPIO is not ready", dev->name);
433 			return -ENODEV;
434 		}
435 
436 		result = gpio_pin_configure_dt(&config->gpio_enable, GPIO_OUTPUT_ACTIVE);
437 		if (result != 0) {
438 			LOG_ERR("failed to enable TLE9104");
439 			return result;
440 		}
441 	}
442 
443 	if (config->gpio_reset.port != NULL) {
444 		if (!gpio_is_ready_dt(&config->gpio_reset)) {
445 			LOG_ERR("%s: reset GPIO is not yet ready", dev->name);
446 			return -ENODEV;
447 		}
448 
449 		result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE);
450 		if (result != 0) {
451 			LOG_ERR("failed to initialize GPIO for reset");
452 			return result;
453 		}
454 
455 		k_busy_wait(TLE9104_RESET_DURATION_TIME_US);
456 		gpio_pin_set_dt(&config->gpio_reset, 0);
457 		k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US +
458 			    TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US);
459 	}
460 
461 	/*
462 	 * The first read value should be the ICVID, this acts also as the setup of the
463 	 * global status register address.
464 	 */
465 	result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg,
466 					  &register_icvid);
467 	if (result != 0) {
468 		return result;
469 	}
470 
471 	if (read_reg != TLE9104REGISTER_ICVID) {
472 		LOG_ERR("expected to read register ICVID, got instead 0x%02X", read_reg);
473 		return -EIO;
474 	}
475 
476 	if (register_icvid != TLE9104_ICVERSIONID) {
477 		LOG_ERR("got unexpected IC version id 0x%02X", register_icvid);
478 		return -EIO;
479 	}
480 
481 	result = tle9104_transceive_frame(dev, false, TLE9104REGISTER_GLOBALSTATUS, 0x00, &read_reg,
482 					  &register_globalstatus);
483 	if (result != 0) {
484 		return result;
485 	}
486 
487 	if (read_reg != TLE9104REGISTER_GLOBALSTATUS) {
488 		LOG_ERR("expected to read register GLOBALSTATUS, got instead 0x%02X", read_reg);
489 		return -EIO;
490 	}
491 
492 	if ((register_globalstatus & TLE9104_GLOBALSTATUS_POR_LATCH_BIT) == 0) {
493 		LOG_ERR("no power on reset detected");
494 		return -EIO;
495 	}
496 
497 	result = tle9104_write_register(dev, TLE9104REGISTER_CFG, register_cfg);
498 	if (result != 0) {
499 		LOG_ERR("unable to write configuration");
500 		return result;
501 	}
502 
503 	register_globalstatus = 0x00;
504 	/* disable communication watchdog */
505 	tle9104_set_cfg_cwdtime(&register_cfg, 0);
506 	/* enable outputs */
507 	register_globalstatus |= TLE9104_GLOBALSTATUS_OUTEN_BIT;
508 
509 	result = tle9104_write_register(dev, TLE9104REGISTER_GLOBALSTATUS, register_globalstatus);
510 	if (result != 0) {
511 		LOG_ERR("unable to write global status");
512 		return result;
513 	}
514 
515 	data->cwd_ignore = false;
516 
517 	return 0;
518 }
519 
520 BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY,
521 	     "TLE9104 must be initialized after SPI");
522 
523 #define TLE9104_INIT_GPIO_FIELDS(inst, gpio)                                                       \
524 	COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, gpio),                                             \
525 		    (GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), gpio, 0)), ({0}))
526 
527 #define TLE9104_INIT(inst)                                                                         \
528 	static const struct tle9104_config tle9104_##inst##_config = {                             \
529 		.common = {                                                                        \
530 				.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst),            \
531 		},                                                                                 \
532 		.bus = SPI_DT_SPEC_INST_GET(                                                       \
533 			inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0),            \
534 		.gpio_enable = TLE9104_INIT_GPIO_FIELDS(inst, en_gpios),                           \
535 		.gpio_reset = TLE9104_INIT_GPIO_FIELDS(inst, resn_gpios),                          \
536 		.gpio_control = {                                                                  \
537 				TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios),                         \
538 				TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios),                         \
539 				TLE9104_INIT_GPIO_FIELDS(inst, in3_gpios),                         \
540 				TLE9104_INIT_GPIO_FIELDS(inst, in4_gpios),                         \
541 		},                                                                                 \
542 	};                                                                                         \
543                                                                                                    \
544 	static struct tle9104_data tle9104_##inst##_drvdata;                                       \
545                                                                                                    \
546 	/* This has to be initialized after the SPI peripheral. */                                 \
547 	DEVICE_DT_INST_DEFINE(inst, tle9104_init, NULL, &tle9104_##inst##_drvdata,                 \
548 			      &tle9104_##inst##_config, POST_KERNEL,                               \
549 			      CONFIG_GPIO_TLE9104_INIT_PRIORITY, &api_table);
550 
551 DT_INST_FOREACH_STATUS_OKAY(TLE9104_INIT)
552