1 /*
2  * Copyright (c) 2023 Grinn
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT adi_ad5592
7 
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/spi.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/byteorder.h>
12 
13 #include <zephyr/drivers/mfd/ad5592.h>
14 
15 #define AD5592_GPIO_READBACK_EN BIT(10)
16 #define AD5592_LDAC_READBACK_EN BIT(6)
17 #define AD5592_REG_SOFTWARE_RESET 0x0FU
18 #define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC
19 #define AD5592_REG_VAL_MASK 0x3FF
20 #define AD5592_REG_RESET_VAL_MASK 0x7FF
21 #define AD5592_REG_SHIFT_VAL 11
22 #define AD5592_REG_READBACK_SHIFT_VAL 2
23 
24 #define AD5592_SPI_SPEC_CONF (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \
25 			      SPI_OP_MODE_MASTER | SPI_MODE_CPOL)
26 
27 struct mfd_ad5592_config {
28 	struct gpio_dt_spec reset_gpio;
29 	struct spi_dt_spec bus;
30 };
31 
mfd_ad5592_read_raw(const struct device * dev,uint16_t * val)32 int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val)
33 {
34 	const struct mfd_ad5592_config *config = dev->config;
35 	uint16_t nop_msg = 0;
36 
37 	struct spi_buf tx_buf[] = {
38 		{
39 			.buf = &nop_msg,
40 			.len = sizeof(nop_msg)
41 		}
42 	};
43 
44 	const struct spi_buf_set tx = {
45 		.buffers = tx_buf,
46 		.count = 1
47 	};
48 
49 	struct spi_buf rx_buf[] = {
50 		{
51 			.buf = val,
52 			.len = sizeof(uint16_t)
53 		}
54 	};
55 
56 	const struct spi_buf_set rx = {
57 		.buffers = rx_buf,
58 		.count = 1
59 	};
60 
61 	return spi_transceive_dt(&config->bus, &tx, &rx);
62 }
63 
mfd_ad5592_write_raw(const struct device * dev,uint16_t val)64 int mfd_ad5592_write_raw(const struct device *dev, uint16_t val)
65 {
66 	const struct mfd_ad5592_config *config = dev->config;
67 
68 	struct spi_buf tx_buf[] = {
69 		{
70 			.buf = &val,
71 			.len = sizeof(val)
72 		}
73 	};
74 
75 	const struct spi_buf_set tx = {
76 		.buffers = tx_buf,
77 		.count = 1
78 	};
79 
80 	return spi_write_dt(&config->bus, &tx);
81 }
82 
mfd_ad5592_read_reg(const struct device * dev,uint8_t reg,uint8_t reg_data,uint16_t * val)83 int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val)
84 {
85 	uint16_t data;
86 	uint16_t msg;
87 	int ret;
88 
89 	switch (reg) {
90 	case AD5592_REG_GPIO_INPUT_EN:
91 		msg = sys_cpu_to_be16(AD5592_GPIO_READBACK_EN |
92 				      (AD5592_REG_GPIO_INPUT_EN << AD5592_REG_SHIFT_VAL) |
93 				      reg_data);
94 		break;
95 	default:
96 		msg = sys_cpu_to_be16(AD5592_LDAC_READBACK_EN |
97 				      (AD5592_REG_READ_AND_LDAC << AD5592_REG_SHIFT_VAL) |
98 				      reg << AD5592_REG_READBACK_SHIFT_VAL);
99 		break;
100 	}
101 
102 	ret = mfd_ad5592_write_raw(dev, msg);
103 	if (ret < 0) {
104 		return ret;
105 	}
106 
107 	ret = mfd_ad5592_read_raw(dev, &data);
108 	if (ret < 0) {
109 		return ret;
110 	}
111 
112 	*val = sys_be16_to_cpu(data);
113 
114 	return 0;
115 }
116 
mfd_ad5592_write_reg(const struct device * dev,uint8_t reg,uint16_t val)117 int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val)
118 {
119 	uint16_t write_mask;
120 	uint16_t msg;
121 
122 	switch (reg) {
123 	case AD5592_REG_SOFTWARE_RESET:
124 		write_mask = AD5592_REG_RESET_VAL_MASK;
125 		break;
126 	default:
127 		write_mask = AD5592_REG_VAL_MASK;
128 		break;
129 	}
130 
131 	msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & write_mask));
132 
133 	return mfd_ad5592_write_raw(dev, msg);
134 }
135 
mfd_add592_software_reset(const struct device * dev)136 static int mfd_add592_software_reset(const struct device *dev)
137 {
138 	return mfd_ad5592_write_reg(dev,
139 				    AD5592_REG_SOFTWARE_RESET,
140 				    AD5592_SOFTWARE_RESET_MAGIC_VAL);
141 }
142 
mfd_ad5592_init(const struct device * dev)143 static int mfd_ad5592_init(const struct device *dev)
144 {
145 	const struct mfd_ad5592_config *config = dev->config;
146 	int ret;
147 
148 	if (!spi_is_ready_dt(&config->bus)) {
149 		return -ENODEV;
150 	}
151 
152 	if (!gpio_is_ready_dt(&config->reset_gpio)) {
153 		return -ENODEV;
154 	}
155 
156 	ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
157 	if (ret < 0) {
158 		return ret;
159 	}
160 
161 	ret = mfd_add592_software_reset(dev);
162 	if (ret < 0) {
163 		return ret;
164 	}
165 
166 	return 0;
167 }
168 
169 #define MFD_AD5592_DEFINE(inst)							\
170 	static const struct mfd_ad5592_config mfd_ad5592_config_##inst = {	\
171 		.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios),		\
172 		.bus = SPI_DT_SPEC_INST_GET(inst, AD5592_SPI_SPEC_CONF, 0),	\
173 	};									\
174 										\
175 	DEVICE_DT_INST_DEFINE(inst, mfd_ad5592_init, NULL,			\
176 			      NULL,						\
177 			      &mfd_ad5592_config_##inst,			\
178 			      POST_KERNEL,					\
179 			      CONFIG_MFD_INIT_PRIORITY,				\
180 			      NULL);
181 
182 DT_INST_FOREACH_STATUS_OKAY(MFD_AD5592_DEFINE);
183