Skip to content

Commit 25634e6

Browse files
committed
drivers: power: add max22216
The MAX22216 integrate four programmable 36V half-bridges. It is primarily intended to drive inductive loads such as on-off solenoid valves, DC motors, proportional valves, bi-stable valves, relays, etc. Signed-off-by: rbudai98 <robert.budai@analog.com>
1 parent ab9d192 commit 25634e6

File tree

2 files changed

+450
-0
lines changed

2 files changed

+450
-0
lines changed

drivers/power/max22216/max22216.c

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
/***************************************************************************//**
2+
* @file max22216.c
3+
* @brief Current control
4+
* @author Robert Budai (robert.budai@analog.com)
5+
********************************************************************************
6+
* Copyright 2025(c) Analog Devices, Inc.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright notice,
12+
* this list of conditions and the following disclaimer.
13+
*
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* 3. Neither the name of Analog Devices, Inc. nor the names of its
19+
* contributors may be used to endorse or promote products derived from this
20+
* software without specific prior written permission.
21+
*
22+
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
23+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
25+
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28+
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
*******************************************************************************/
33+
34+
#include "max22216.h"
35+
36+
int max22216_write_reg(struct max22216_desc *desc, uint8_t reg_addr,
37+
uint16_t data)
38+
{
39+
int ret = 0;
40+
41+
if (!desc || !desc->spi_desc)
42+
return -EINVAL;
43+
no_os_field_get(data, MP_OS_GEN_MASK())
44+
uint8_t tx[3] = {
45+
(uint8_t)(reg_addr | NO_OS_BIT(8)),
46+
(uint8_t)no_os_field_get(0xFF00, data),
47+
(uint8_t)no_os_field_get(0x00FF, data)
48+
};
49+
50+
return no_os_spi_write_and_read(desc->spi_desc, tx, 3);
51+
}
52+
53+
int max22216_read_reg(struct max22216_desc *desc, uint8_t reg_addr,
54+
uint16_t *data)
55+
{
56+
int ret;
57+
uint8_t tx[3] = { reg_addr, 0x00, 0x00};
58+
59+
if (!desc || !desc->spi_desc)
60+
return -EINVAL;
61+
62+
ret = no_os_spi_write_and_read(desc->spi_desc, tx, 3);
63+
if (ret)
64+
return ret;
65+
ret = no_os_spi_write_and_read(desc->spi_desc, tx, 3);
66+
if (ret)
67+
return ret;
68+
69+
desc->status_reg = tx[0];
70+
71+
*data = (tx[1] << 8) | tx[2];
72+
73+
return 0;
74+
}
75+
76+
int max22216_write_reg_list(struct max22216_desc *desc,
77+
max22216_reg_setting_t* list, uint8_t elem_nr)
78+
{
79+
int ret;
80+
uint8_t i;
81+
82+
if (!desc || !desc->spi_desc || !list)
83+
return -1;
84+
85+
for (i = 0; i < elem_nr; i++) {
86+
ret = max22216_write_reg(desc, list[i].reg_addr, list[i].data);
87+
if (ret)
88+
return ret;
89+
}
90+
return 0;
91+
}
92+
93+
int erase_fault_reg(struct max22216_desc *desc)
94+
{
95+
int ret;
96+
uint16_t data = 0;
97+
98+
ret = max22216_write_reg(desc, MAX22216_FAULT1, 0xFFFF);
99+
if (ret)
100+
return ret;
101+
ret = max22216_read_reg(desc, MAX22216_FAULT0, &data);
102+
if (ret)
103+
return ret;
104+
return max22216_read_reg(desc, MAX22216_FAULT1, &data);
105+
}
106+
107+
int max22216_set_enable_pin(struct max22216_desc *desc, bool value)
108+
{
109+
int ret;
110+
111+
if (!desc || !desc->drv_en_gpio)
112+
return -EINVAL;
113+
114+
return no_os_gpio_set_value(desc->drv_en_gpio,
115+
value ? NO_OS_GPIO_HIGH : NO_OS_GPIO_LOW);
116+
}
117+
118+
int max22216_check_fault_pin(struct max22216_desc *desc, bool *fault_status)
119+
{
120+
int ret;
121+
uint8_t value;
122+
123+
if (!desc || !desc->fault_gpio || !fault_status)
124+
return -EINVAL;
125+
126+
ret = no_os_gpio_get_value(desc->fault_gpio, &value);
127+
if (ret)
128+
return ret;
129+
130+
*fault_status = (value == NO_OS_GPIO_LOW); // Assuming LOW indicates a fault
131+
return 0;
132+
}
133+
134+
int max22216_current_reg_control(struct max22216_desc *desc, uint8_t channel_nr,
135+
uint16_t value)
136+
{
137+
int ret;
138+
uint16_t test_value;
139+
max22216_reg_setting_t reg_setting;
140+
// Prepare register settings for current control
141+
uint8_t reg_addr = MAX22216_CFG_DC_H_0 + (channel_nr *
142+
MAX22216_CHANNEL_CONFIG_REG_SHIFT);
143+
144+
if (!desc || !desc->spi_desc)
145+
return -EINVAL;
146+
147+
148+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
149+
return -EINVAL;
150+
151+
// Write the register settings
152+
ret = max22216_write_reg(desc, reg_addr, value);
153+
if (ret)
154+
return ret;
155+
156+
ret = max22216_read_reg(desc, reg_addr, &test_value);
157+
if (ret)
158+
return ret;
159+
160+
if (test_value != value)
161+
return -EINVAL;
162+
163+
return 0;
164+
}
165+
166+
int max22216_turn_on(struct max22216_desc *desc, uint8_t channel_nr)
167+
{
168+
int ret;
169+
uint16_t data;
170+
171+
if (!desc || !desc->spi_desc)
172+
return -EINVAL;
173+
174+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
175+
return -EINVAL;
176+
177+
ret = max22216_read_reg(desc,
178+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
179+
if (ret)
180+
return ret;
181+
ret = max22216_write_reg(desc,
182+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT),
183+
data | NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT));
184+
if (ret)
185+
return ret;
186+
ret = max22216_read_reg(desc,
187+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
188+
if (ret)
189+
return ret;
190+
if (!(data | NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT)))
191+
return -1;
192+
193+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
194+
if (ret)
195+
return ret;
196+
ret = max22216_write_reg(desc, MAX22216_GLOBAL_CTRL,
197+
data | NO_OS_BIT(channel_nr));
198+
if (ret)
199+
return ret;
200+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
201+
if (ret)
202+
return ret;
203+
if (!(data | NO_OS_BIT(channel_nr)))
204+
return -EINVAL;
205+
206+
return 0;
207+
208+
}
209+
210+
int max22216_turn_off(struct max22216_desc *desc, uint8_t channel_nr)
211+
{
212+
int ret;
213+
uint16_t data;
214+
215+
if (!desc || !desc->spi_desc)
216+
return -EINVAL;
217+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
218+
return -EINVAL;
219+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
220+
if (ret)
221+
return ret;
222+
ret = max22216_write_reg(desc, MAX22216_GLOBAL_CTRL,
223+
data & ~(NO_OS_BIT(channel_nr)));
224+
if (ret)
225+
return ret;
226+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
227+
if (ret)
228+
return ret;
229+
if (data & (NO_OS_BIT(channel_nr)))
230+
// Indicates that the relevant bits for the channel were not cleared as expected
231+
return -EINVAL;
232+
ret = max22216_read_reg(desc,
233+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
234+
if (ret)
235+
return ret;
236+
ret = max22216_write_reg(desc,
237+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT),
238+
data & ~NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT));
239+
if (ret)
240+
return ret;
241+
ret = max22216_read_reg(desc,
242+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
243+
if (ret)
244+
return ret;
245+
if (data & NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT))
246+
return -EINVAL;
247+
248+
return 0;
249+
}
250+
251+
int max22216_set_current_ma(struct max22216_desc *desc, uint8_t channel_nr,
252+
uint16_t current_ma)
253+
{
254+
int ret;
255+
uint16_t reg_value = (uint16_t)(current_ma / (MAX22216_K_CDR * MAX22216_GAIN *
256+
MAX22216_SNSF));
257+
258+
if (!desc)
259+
return -EINVAL;
260+
261+
ret = max22216_current_reg_control(desc, channel_nr, reg_value);
262+
if (ret)
263+
return ret;
264+
265+
return 0;
266+
}
267+
268+
int max22216_init(struct max22216_desc **desc,
269+
struct max22216_init_param *param)
270+
{
271+
int ret;
272+
273+
if (!desc || !param || !param->spi_ip)
274+
return -EINVAL;
275+
276+
struct max22216_desc *dev = calloc(1, sizeof(*dev));
277+
278+
if (!dev)
279+
return -ENOMEM;
280+
281+
struct no_os_gpio_desc *max22216_drv_en_desc = calloc(1,
282+
sizeof(*max22216_drv_en_desc));
283+
if (!max22216_drv_en_desc)
284+
goto error1;
285+
struct no_os_gpio_desc *max22216_fault_desc = calloc(1,
286+
sizeof(*max22216_fault_desc));
287+
288+
if (!max22216_fault_desc)
289+
goto error2;
290+
291+
ret = no_os_spi_init(&dev->spi_desc, param->spi_ip);
292+
if (ret)
293+
goto error1;
294+
295+
// Setup for enable pin
296+
ret = no_os_gpio_get(&max22216_drv_en_desc, param->drv_en_gpio_ip);
297+
if (ret)
298+
goto error1;
299+
300+
dev->drv_en_gpio = max22216_drv_en_desc;
301+
ret = no_os_gpio_direction_output(max22216_drv_en_desc, NO_OS_GPIO_HIGH);
302+
if (ret)
303+
goto error1;
304+
305+
ret = no_os_gpio_set_value(max22216_drv_en_desc, NO_OS_GPIO_HIGH);
306+
if (ret)
307+
goto error1;
308+
309+
// Setup for fault pin polling
310+
ret = no_os_gpio_get(&max22216_fault_desc, param->fault_gpio_ip);
311+
if (ret)
312+
goto error1;
313+
314+
dev->fault_gpio = max22216_fault_desc;
315+
316+
ret = no_os_gpio_direction_input(max22216_fault_desc);
317+
if (ret)
318+
goto error1;
319+
320+
dev->status_reg = 0;
321+
*desc = dev;
322+
return 0;
323+
324+
error1:
325+
free(max22216_fault_desc);
326+
error2:
327+
free(max22216_drv_en_desc);
328+
error3:
329+
free(dev);
330+
return ret;
331+
}
332+
333+
int max22216_remove(struct max22216_desc *desc)
334+
{
335+
if (!desc)
336+
return -1;
337+
if (desc->spi_desc)
338+
no_os_spi_remove(desc->spi_desc);
339+
if (desc->drv_en_gpio)
340+
no_os_gpio_remove(desc->drv_en_gpio);
341+
if (desc->fault_gpio)
342+
no_os_gpio_remove(desc->fault_gpio);
343+
free(desc);
344+
return 0;
345+
}

0 commit comments

Comments
 (0)