Skip to content

Commit 3137842

Browse files
rbudai98buha
authored andcommitted
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 67517bf commit 3137842

File tree

2 files changed

+449
-0
lines changed

2 files changed

+449
-0
lines changed

drivers/power/max22216/max22216.c

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
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+
uint8_t tx[3] = {
44+
(uint8_t)(reg_addr | NO_OS_BIT(8)),
45+
(uint8_t)no_os_field_get(0xFF00, data),
46+
(uint8_t)no_os_field_get(0x00FF, data)
47+
};
48+
49+
return no_os_spi_write_and_read(desc->spi_desc, tx, 3);
50+
}
51+
52+
int max22216_read_reg(struct max22216_desc *desc, uint8_t reg_addr,
53+
uint16_t *data)
54+
{
55+
int ret;
56+
uint8_t tx[3] = { reg_addr, 0x00, 0x00};
57+
58+
if (!desc || !desc->spi_desc)
59+
return -EINVAL;
60+
61+
ret = no_os_spi_write_and_read(desc->spi_desc, tx, 3);
62+
if (ret)
63+
return ret;
64+
ret = no_os_spi_write_and_read(desc->spi_desc, tx, 3);
65+
if (ret)
66+
return ret;
67+
68+
desc->status_reg = tx[0];
69+
70+
*data = (tx[1] << 8) | tx[2];
71+
72+
return 0;
73+
}
74+
75+
int max22216_write_reg_list(struct max22216_desc *desc,
76+
max22216_reg_setting_t* list, uint8_t elem_nr)
77+
{
78+
int ret;
79+
uint8_t i;
80+
81+
if (!desc || !desc->spi_desc || !list)
82+
return -1;
83+
84+
for (i = 0; i < elem_nr; i++) {
85+
ret = max22216_write_reg(desc, list[i].reg_addr, list[i].data);
86+
if (ret)
87+
return ret;
88+
}
89+
return 0;
90+
}
91+
92+
int erase_fault_reg(struct max22216_desc *desc)
93+
{
94+
int ret;
95+
uint16_t data = 0;
96+
97+
ret = max22216_write_reg(desc, MAX22216_FAULT1, 0xFFFF);
98+
if (ret)
99+
return ret;
100+
ret = max22216_read_reg(desc, MAX22216_FAULT0, &data);
101+
if (ret)
102+
return ret;
103+
return max22216_read_reg(desc, MAX22216_FAULT1, &data);
104+
}
105+
106+
int max22216_set_enable_pin(struct max22216_desc *desc, bool value)
107+
{
108+
int ret;
109+
110+
if (!desc || !desc->drv_en_gpio)
111+
return -EINVAL;
112+
113+
return no_os_gpio_set_value(desc->drv_en_gpio,
114+
value ? NO_OS_GPIO_HIGH : NO_OS_GPIO_LOW);
115+
}
116+
117+
int max22216_check_fault_pin(struct max22216_desc *desc, bool *fault_status)
118+
{
119+
int ret;
120+
uint8_t value;
121+
122+
if (!desc || !desc->fault_gpio || !fault_status)
123+
return -EINVAL;
124+
125+
ret = no_os_gpio_get_value(desc->fault_gpio, &value);
126+
if (ret)
127+
return ret;
128+
129+
*fault_status = (value == NO_OS_GPIO_LOW); // Assuming LOW indicates a fault
130+
return 0;
131+
}
132+
133+
int max22216_current_reg_control(struct max22216_desc *desc, uint8_t channel_nr,
134+
uint16_t value)
135+
{
136+
int ret;
137+
uint16_t test_value;
138+
max22216_reg_setting_t reg_setting;
139+
// Prepare register settings for current control
140+
uint8_t reg_addr = MAX22216_CFG_DC_H_0 + (channel_nr *
141+
MAX22216_CHANNEL_CONFIG_REG_SHIFT);
142+
143+
if (!desc || !desc->spi_desc)
144+
return -EINVAL;
145+
146+
147+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
148+
return -EINVAL;
149+
150+
// Write the register settings
151+
ret = max22216_write_reg(desc, reg_addr, value);
152+
if (ret)
153+
return ret;
154+
155+
ret = max22216_read_reg(desc, reg_addr, &test_value);
156+
if (ret)
157+
return ret;
158+
159+
if (test_value != value)
160+
return -EINVAL;
161+
162+
return 0;
163+
}
164+
165+
int max22216_turn_on(struct max22216_desc *desc, uint8_t channel_nr)
166+
{
167+
int ret;
168+
uint16_t data;
169+
170+
if (!desc || !desc->spi_desc)
171+
return -EINVAL;
172+
173+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
174+
return -EINVAL;
175+
176+
ret = max22216_read_reg(desc,
177+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
178+
if (ret)
179+
return ret;
180+
ret = max22216_write_reg(desc,
181+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT),
182+
data | NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT));
183+
if (ret)
184+
return ret;
185+
ret = max22216_read_reg(desc,
186+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
187+
if (ret)
188+
return ret;
189+
if (!(data | NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT)))
190+
return -1;
191+
192+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
193+
if (ret)
194+
return ret;
195+
ret = max22216_write_reg(desc, MAX22216_GLOBAL_CTRL,
196+
data | NO_OS_BIT(channel_nr));
197+
if (ret)
198+
return ret;
199+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
200+
if (ret)
201+
return ret;
202+
if (!(data | NO_OS_BIT(channel_nr)))
203+
return -EINVAL;
204+
205+
return 0;
206+
207+
}
208+
209+
int max22216_turn_off(struct max22216_desc *desc, uint8_t channel_nr)
210+
{
211+
int ret;
212+
uint16_t data;
213+
214+
if (!desc || !desc->spi_desc)
215+
return -EINVAL;
216+
if (channel_nr >= MAX22216_NR_OF_CHANNELS)
217+
return -EINVAL;
218+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
219+
if (ret)
220+
return ret;
221+
ret = max22216_write_reg(desc, MAX22216_GLOBAL_CTRL,
222+
data & ~(NO_OS_BIT(channel_nr)));
223+
if (ret)
224+
return ret;
225+
ret = max22216_read_reg(desc, MAX22216_GLOBAL_CTRL, &data);
226+
if (ret)
227+
return ret;
228+
if (data & (NO_OS_BIT(channel_nr)))
229+
// Indicates that the relevant bits for the channel were not cleared as expected
230+
return -EINVAL;
231+
ret = max22216_read_reg(desc,
232+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
233+
if (ret)
234+
return ret;
235+
ret = max22216_write_reg(desc,
236+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT),
237+
data & ~NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT));
238+
if (ret)
239+
return ret;
240+
ret = max22216_read_reg(desc,
241+
MAX22216_CFG_IND_0_0 + (channel_nr * MAX22216_CHANNEL_CONFIG_REG_SHIFT), &data);
242+
if (ret)
243+
return ret;
244+
if (data & NO_OS_BIT(MAX22216_CFG_IND_DITHERING_BIT))
245+
return -EINVAL;
246+
247+
return 0;
248+
}
249+
250+
int max22216_set_current_ma(struct max22216_desc *desc, uint8_t channel_nr,
251+
uint16_t current_ma)
252+
{
253+
int ret;
254+
uint16_t reg_value = (uint16_t)(current_ma / (MAX22216_K_CDR * MAX22216_GAIN *
255+
MAX22216_SNSF));
256+
257+
if (!desc)
258+
return -EINVAL;
259+
260+
ret = max22216_current_reg_control(desc, channel_nr, reg_value);
261+
if (ret)
262+
return ret;
263+
264+
return 0;
265+
}
266+
267+
int max22216_init(struct max22216_desc **desc,
268+
struct max22216_init_param *param)
269+
{
270+
int ret;
271+
272+
if (!desc || !param || !param->spi_ip)
273+
return -EINVAL;
274+
275+
struct max22216_desc *dev = calloc(1, sizeof(*dev));
276+
277+
if (!dev)
278+
return -ENOMEM;
279+
280+
struct no_os_gpio_desc *max22216_drv_en_desc = calloc(1,
281+
sizeof(*max22216_drv_en_desc));
282+
if (!max22216_drv_en_desc)
283+
goto error1;
284+
struct no_os_gpio_desc *max22216_fault_desc = calloc(1,
285+
sizeof(*max22216_fault_desc));
286+
287+
if (!max22216_fault_desc)
288+
goto error2;
289+
290+
ret = no_os_spi_init(&dev->spi_desc, param->spi_ip);
291+
if (ret)
292+
goto error1;
293+
294+
// Setup for enable pin
295+
ret = no_os_gpio_get(&max22216_drv_en_desc, param->drv_en_gpio_ip);
296+
if (ret)
297+
goto error1;
298+
299+
dev->drv_en_gpio = max22216_drv_en_desc;
300+
ret = no_os_gpio_direction_output(max22216_drv_en_desc, NO_OS_GPIO_HIGH);
301+
if (ret)
302+
goto error1;
303+
304+
ret = no_os_gpio_set_value(max22216_drv_en_desc, NO_OS_GPIO_HIGH);
305+
if (ret)
306+
goto error1;
307+
308+
// Setup for fault pin polling
309+
ret = no_os_gpio_get(&max22216_fault_desc, param->fault_gpio_ip);
310+
if (ret)
311+
goto error1;
312+
313+
dev->fault_gpio = max22216_fault_desc;
314+
315+
ret = no_os_gpio_direction_input(max22216_fault_desc);
316+
if (ret)
317+
goto error1;
318+
319+
dev->status_reg = 0;
320+
*desc = dev;
321+
return 0;
322+
323+
error1:
324+
free(max22216_fault_desc);
325+
error2:
326+
free(max22216_drv_en_desc);
327+
error3:
328+
free(dev);
329+
return ret;
330+
}
331+
332+
int max22216_remove(struct max22216_desc *desc)
333+
{
334+
if (!desc)
335+
return -1;
336+
if (desc->spi_desc)
337+
no_os_spi_remove(desc->spi_desc);
338+
if (desc->drv_en_gpio)
339+
no_os_gpio_remove(desc->drv_en_gpio);
340+
if (desc->fault_gpio)
341+
no_os_gpio_remove(desc->fault_gpio);
342+
free(desc);
343+
return 0;
344+
}

0 commit comments

Comments
 (0)