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