7
7
#include <stdbool.h>
8
8
9
9
#include <zephyr/drivers/i2c.h>
10
+ #include <zephyr/drivers/gpio.h>
10
11
#include <zephyr/sys/util.h>
11
12
#include <zephyr/logging/log.h>
13
+ #include <zephyr/input/input.h>
12
14
13
15
LOG_MODULE_REGISTER (mfd_axp2101 , CONFIG_MFD_LOG_LEVEL );
14
16
17
+ /* Helper macro to enable IRQ management from the device-tree. */
18
+ #if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (x_powers_axp2101 , int_gpios )
19
+ #define MFD_AXP2101_INTERRUPT 1
20
+ #endif
21
+
15
22
struct mfd_axp2101_config {
16
23
struct i2c_dt_spec i2c ;
24
+ struct gpio_dt_spec int_gpio ;
25
+ };
26
+
27
+ #if MFD_AXP2101_INTERRUPT
28
+ struct mfd_axp2101_data {
29
+ struct gpio_callback gpio_cb ;
30
+ const struct device * dev ;
31
+ struct k_work work ;
17
32
};
33
+ #endif /* MFD_AXP2101_INTERRUPT */
18
34
19
- /* Registers */
35
+ /* Registers and (some) corresponding values */
20
36
#define AXP2101_REG_CHIP_ID 0x03U
21
37
#define AXP2101_CHIP_ID 0x4AU
38
+ #define AXP2101_REG_IRQ_ENABLE_0 0x40U
39
+ #define AXP2101_REG_IRQ_ENABLE_1 0x41U
40
+ #define AXP2101_IRQ_ENABLE_1_PWR_ON_NEG_EDGE_IRQ BIT(1)
41
+ #define AXP2101_IRQ_ENABLE_1_PWR_ON_POS_EDGE_IRQ BIT(0)
42
+ #define AXP2101_REG_IRQ_ENABLE_2 0x42U
43
+ #define AXP2101_REG_IRQ_STATUS_0 0x48U
44
+ #define AXP2101_REG_IRQ_STATUS_1 0x49U
45
+ #define AXP2101_IRQ_STATUS_1_PWR_ON_NEG_EDGE_IRQ BIT(1)
46
+ #define AXP2101_IRQ_STATUS_1_PWR_ON_POS_EDGE_IRQ BIT(0)
47
+ #define AXP2101_REG_IRQ_STATUS_2 0x4AU
48
+
49
+ #if MFD_AXP2101_INTERRUPT
50
+
51
+ enum irq_status_reg_idx {
52
+ AXP2101_IRQ_STATUS_0_IDX = 0 ,
53
+ AXP2101_IRQ_STATUS_1_IDX ,
54
+ AXP2101_IRQ_STATUS_2_IDX ,
55
+ AXP2101_IRQ_STATUS_REG_COUNT
56
+ };
57
+
58
+ static const uint8_t axp2101_dflt_irq_enable [] = {
59
+ /* AXP2101_REG_IRQ_ENABLE_0 */
60
+ 0x00 ,
61
+
62
+ /* AXP2101_REG_IRQ_ENABLE_1 */
63
+ #if CONFIG_MFD_AXP2101_POWER_BUTTON
64
+ AXP2101_IRQ_ENABLE_1_PWR_ON_NEG_EDGE_IRQ |
65
+ AXP2101_IRQ_ENABLE_1_PWR_ON_POS_EDGE_IRQ ,
66
+ #else
67
+ 0x00 ,
68
+ #endif
69
+
70
+ /* AXP2101_REG_IRQ_ENABLE_2 */
71
+ 0x00 ,
72
+ };
73
+
74
+ static inline int axp2101_irq_read_and_clear (const struct i2c_dt_spec * i2c ,
75
+ uint8_t irq_status [AXP2101_IRQ_STATUS_REG_COUNT ])
76
+ {
77
+ int ret ;
78
+
79
+ ret = i2c_burst_read_dt (i2c , AXP2101_REG_IRQ_STATUS_0 , irq_status ,
80
+ AXP2101_IRQ_STATUS_REG_COUNT );
81
+ if (ret < 0 ) {
82
+ LOG_ERR ("Failed to read IRQ status registers" );
83
+ return ret ;
84
+ }
85
+
86
+ /* Writing a '1' on a status bit which is already set clears it. Therefore
87
+ * to clear all (and only) the bits that have just been dumped we write
88
+ * the read values back.
89
+ */
90
+ ret = i2c_burst_write_dt (i2c , AXP2101_REG_IRQ_STATUS_0 , irq_status ,
91
+ AXP2101_IRQ_STATUS_REG_COUNT );
92
+ if (ret < 0 ) {
93
+ LOG_ERR ("Failed to clear IRQ status registers" );
94
+ return ret ;
95
+ }
96
+
97
+ return 0 ;
98
+ }
99
+
100
+ static void axp2101_k_work_handler (struct k_work * work )
101
+ {
102
+ struct mfd_axp2101_data * data = CONTAINER_OF (work , struct mfd_axp2101_data , work );
103
+ const struct device * dev = data -> dev ;
104
+ const struct mfd_axp2101_config * config = dev -> config ;
105
+ uint8_t irq_status_regs [AXP2101_IRQ_STATUS_REG_COUNT ];
106
+ int ret ;
107
+
108
+ ret = axp2101_irq_read_and_clear (& config -> i2c , irq_status_regs );
109
+ if (ret < 0 ) {
110
+ goto exit ;
111
+ }
112
+
113
+ #if CONFIG_MFD_AXP2101_POWER_BUTTON
114
+ if (irq_status_regs [AXP2101_IRQ_STATUS_1_IDX ] & AXP2101_IRQ_STATUS_1_PWR_ON_NEG_EDGE_IRQ ) {
115
+ ret = input_report_key (dev , INPUT_KEY_POWER , true, true, K_FOREVER );
116
+ }
117
+ if (irq_status_regs [AXP2101_IRQ_STATUS_1_IDX ] & AXP2101_IRQ_STATUS_1_PWR_ON_POS_EDGE_IRQ ) {
118
+ ret = input_report_key (dev , INPUT_KEY_POWER , false, true, K_FOREVER );
119
+ }
120
+ if (ret < 0 ) {
121
+ LOG_ERR ("Failed to send input event" );
122
+ }
123
+ #endif /* CONFIG_MFD_AXP2101_POWER_BUTTON */
124
+
125
+ exit :
126
+ /* Resubmit work if interrupt is still active */
127
+ if (gpio_pin_get_dt (& config -> int_gpio ) != 0 ) {
128
+ k_work_submit (& data -> work );
129
+ }
130
+ }
131
+
132
+ static void axp2101_interrupt_callback (const struct device * gpio_dev , struct gpio_callback * cb ,
133
+ uint32_t pins )
134
+ {
135
+ struct mfd_axp2101_data * data = CONTAINER_OF (cb , struct mfd_axp2101_data , gpio_cb );
136
+
137
+ ARG_UNUSED (gpio_dev );
138
+ ARG_UNUSED (pins );
139
+
140
+ k_work_submit (& data -> work );
141
+ }
142
+
143
+ static int mfd_axp2101_configure_irq (const struct device * dev )
144
+ {
145
+ const struct mfd_axp2101_config * config = dev -> config ;
146
+ struct mfd_axp2101_data * data = dev -> data ;
147
+ uint8_t dummy_buffer [] = {0xFF , 0xFF , 0xFF };
148
+ int ret ;
149
+
150
+ if (!gpio_is_ready_dt (& config -> int_gpio )) {
151
+ LOG_WRN ("Interrupt GPIO not ready" );
152
+ return - EIO ;
153
+ };
154
+
155
+ k_work_init (& data -> work , axp2101_k_work_handler );
156
+ data -> dev = dev ;
157
+
158
+ /* Enable only selected interrupts (most are enabled by default) */
159
+ ret = i2c_burst_write_dt (& config -> i2c , AXP2101_REG_IRQ_ENABLE_0 ,
160
+ axp2101_dflt_irq_enable ,
161
+ ARRAY_SIZE (axp2101_dflt_irq_enable ));
162
+ if (ret < 0 ) {
163
+ LOG_ERR ("Failed to configure enabled IRQs" );
164
+ return ret ;
165
+ }
166
+
167
+ /* Clear any pending interrupt (if any) */
168
+ ret = i2c_burst_write_dt (& config -> i2c , AXP2101_REG_IRQ_STATUS_0 ,
169
+ dummy_buffer , ARRAY_SIZE (dummy_buffer ));
170
+ if (ret < 0 ) {
171
+ LOG_ERR ("Failed to clear IRQ status registers" );
172
+ return ret ;
173
+ }
174
+
175
+ ret = gpio_pin_configure_dt (& config -> int_gpio , GPIO_INPUT );
176
+ if (ret < 0 ) {
177
+ LOG_ERR ("Failed to configure interrupt GPIO: %d" , ret );
178
+ return ret ;
179
+ }
180
+
181
+ gpio_init_callback (& data -> gpio_cb , axp2101_interrupt_callback , BIT (config -> int_gpio .pin ));
182
+
183
+ ret = gpio_add_callback (config -> int_gpio .port , & data -> gpio_cb );
184
+ if (ret < 0 ) {
185
+ LOG_ERR ("Failed to add GPIO callback: %d" , ret );
186
+ return ret ;
187
+ }
188
+
189
+ ret = gpio_pin_interrupt_configure_dt (& config -> int_gpio , GPIO_INT_EDGE_TO_ACTIVE );
190
+ if (ret < 0 ) {
191
+ LOG_ERR ("Failed to configure GPIO interrupt: %d" , ret );
192
+ return ret ;
193
+ }
194
+
195
+ /* Manually kick the work the 1st time if IRQ line is already asserted. */
196
+ if (gpio_pin_get_dt (& config -> int_gpio ) != 0 ) {
197
+ k_work_submit (& data -> work );
198
+ }
199
+
200
+ return 0 ;
201
+ }
202
+
203
+ #endif /* MFD_AXP2101_INTERRUPT */
22
204
23
205
static int mfd_axp2101_init (const struct device * dev )
24
206
{
@@ -41,15 +223,26 @@ static int mfd_axp2101_init(const struct device *dev)
41
223
return - EINVAL ;
42
224
}
43
225
226
+ #if MFD_AXP2101_INTERRUPT
227
+ ret = mfd_axp2101_configure_irq (dev );
228
+ if (ret != 0 ) {
229
+ return ret ;
230
+ }
231
+ #endif /* MFD_AXP2101_INTERRUPT */
232
+
44
233
return 0 ;
45
234
}
46
235
47
236
#define MFD_AXP2101_DEFINE (node ) \
48
237
static const struct mfd_axp2101_config config##node = { \
49
238
.i2c = I2C_DT_SPEC_GET(node), \
239
+ .int_gpio = GPIO_DT_SPEC_GET_OR(node, int_gpios, {0}) \
50
240
}; \
51
241
\
52
- DEVICE_DT_DEFINE(node, mfd_axp2101_init, NULL, NULL, \
242
+ IF_ENABLED(MFD_AXP2101_INTERRUPT, (static struct mfd_axp2101_data data##node;)) \
243
+ \
244
+ DEVICE_DT_DEFINE(node, mfd_axp2101_init, NULL, \
245
+ COND_CODE_1(MFD_AXP2101_INTERRUPT, (&data##node), (NULL)), \
53
246
&config##node, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL);
54
247
55
248
DT_FOREACH_STATUS_OKAY (x_powers_axp2101 , MFD_AXP2101_DEFINE );
0 commit comments