Skip to content

Commit 7e99cd4

Browse files
committed
drivers: gpio: silabs-siwx91x: Device runtime PM
This commit enables the pm device runtime support for the siwx91x gpio driver. Signed-off-by: Sai Santhosh Malae <[email protected]>
1 parent 867a149 commit 7e99cd4

File tree

1 file changed

+92
-49
lines changed

1 file changed

+92
-49
lines changed

drivers/gpio/gpio_silabs_siwx91x.c

Lines changed: 92 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
#define INVALID_PORT 0xFF
3232
#define INTERRUPT_COUNT 8
3333

34+
struct gpio_siwx91x_pin_config_info {
35+
const struct device *port_dev;
36+
gpio_pin_t pin;
37+
gpio_flags_t flags;
38+
};
39+
3440
/* Types */
3541
struct gpio_siwx91x_common_config {
3642
EGPIO_Type *reg;
@@ -58,48 +64,20 @@ struct gpio_siwx91x_port_data {
5864
struct gpio_driver_data common;
5965
/* port ISR callback routine address */
6066
sys_slist_t callbacks;
61-
#if defined(CONFIG_PM)
62-
/* stores the direction of each pin */
63-
uint16_t pin_direction[MAX_PIN_COUNT];
64-
#endif
67+
struct gpio_siwx91x_pin_config_info *pin_config_info;
68+
uint8_t next_pin;
6569
};
6670

6771
/* Functions */
68-
static int gpio_siwx91x_port_pm_action(const struct device *port, enum pm_device_action action)
69-
{
70-
__maybe_unused const struct gpio_siwx91x_port_config *config = port->config;
71-
__maybe_unused struct gpio_siwx91x_port_data *data = port->data;
72-
#if defined(CONFIG_PM)
73-
switch (action) {
74-
case PM_DEVICE_ACTION_RESUME:
75-
for (int pin = 0; pin < MAX_PIN_COUNT; ++pin) {
76-
if (config->common.port_pin_mask & BIT(pin)) {
77-
sl_si91x_gpio_set_pin_direction(config->hal_port, pin,
78-
data->pin_direction[pin]);
79-
}
80-
}
81-
break;
82-
case PM_DEVICE_ACTION_SUSPEND:
83-
for (int pin = 0; pin < MAX_PIN_COUNT; ++pin) {
84-
if (config->common.port_pin_mask & BIT(pin)) {
85-
data->pin_direction[pin] =
86-
sl_si91x_gpio_get_pin_direction(config->hal_port, pin);
87-
}
88-
}
89-
break;
90-
default:
91-
return -ENOTSUP;
92-
}
93-
#endif
94-
return 0;
95-
}
96-
9772
static int gpio_siwx91x_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
9873
{
9974
const struct gpio_siwx91x_port_config *cfg = dev->config;
75+
struct gpio_siwx91x_port_data *port_data = dev->data;
10076
const struct device *parent = cfg->parent;
10177
const struct gpio_siwx91x_common_config *pcfg = parent->config;
78+
uint8_t cur_cfg_pin = 0;
10279
sl_status_t status;
80+
int i;
10381
sl_si91x_gpio_driver_disable_state_t disable_state = GPIO_HZ;
10482

10583
if (flags & GPIO_SINGLE_ENDED) {
@@ -158,6 +136,67 @@ static int gpio_siwx91x_pin_configure(const struct device *dev, gpio_pin_t pin,
158136

159137
sl_si91x_gpio_set_pin_direction(cfg->hal_port, pin, (flags & GPIO_OUTPUT) ? 0 : 1);
160138

139+
for (i = 0; i < port_data->next_pin; i++) {
140+
if (port_data->pin_config_info[i].pin == pin) {
141+
cur_cfg_pin = i;
142+
break;
143+
}
144+
}
145+
146+
if (i == port_data->next_pin) {
147+
cur_cfg_pin = port_data->next_pin;
148+
port_data->next_pin++;
149+
}
150+
151+
if (cur_cfg_pin < __builtin_popcount(cfg->common.port_pin_mask)) {
152+
port_data->pin_config_info[cur_cfg_pin].port_dev = dev;
153+
port_data->pin_config_info[cur_cfg_pin].pin = pin;
154+
port_data->pin_config_info[cur_cfg_pin].flags = flags;
155+
} else {
156+
return -EIO;
157+
}
158+
159+
return 0;
160+
}
161+
162+
static int gpio_siwx91x_pm_action(const struct device *dev, enum pm_device_action action)
163+
{
164+
const struct gpio_siwx91x_common_config *cfg = dev->config;
165+
struct gpio_siwx91x_common_data *data = dev->data;
166+
const struct device **port_dev = data->ports;
167+
const struct gpio_siwx91x_port_config *port_cfg = NULL;
168+
struct gpio_siwx91x_port_data *port_data = NULL;
169+
int pin_cnt;
170+
int ret;
171+
172+
switch (action) {
173+
case PM_DEVICE_ACTION_TURN_ON:
174+
for (int i = 0; i < cfg->port_count; i++) {
175+
port_cfg = port_dev[i]->config;
176+
port_data = port_dev[i]->data;
177+
pin_cnt = 0;
178+
while (port_data->pin_config_info[pin_cnt].port_dev != NULL &&
179+
pin_cnt < __builtin_popcount(port_cfg->common.port_pin_mask)) {
180+
ret = gpio_siwx91x_pin_configure(
181+
port_data->pin_config_info[pin_cnt].port_dev,
182+
port_data->pin_config_info[pin_cnt].pin,
183+
port_data->pin_config_info[pin_cnt].flags);
184+
if (ret) {
185+
return ret;
186+
}
187+
pin_cnt++;
188+
}
189+
}
190+
break;
191+
case PM_DEVICE_ACTION_TURN_OFF:
192+
break;
193+
case PM_DEVICE_ACTION_RESUME:
194+
break;
195+
case PM_DEVICE_ACTION_SUSPEND:
196+
break;
197+
default:
198+
return -ENOTSUP;
199+
}
161200
return 0;
162201
}
163202

@@ -322,16 +361,16 @@ static int gpio_siwx91x_interrupt_configure(const struct device *port, gpio_pin_
322361

323362
static inline int gpio_siwx91x_init_port(const struct device *port)
324363
{
325-
const struct gpio_siwx91x_port_config *cfg = port->config;
326-
const struct device *parent = cfg->parent;
327-
__maybe_unused const struct gpio_siwx91x_common_config *pcfg = parent->config;
328-
struct gpio_siwx91x_common_data *pdata = parent->data;
364+
const struct gpio_siwx91x_port_config *port_cfg = port->config;
365+
const struct device *parent = port_cfg->parent;
366+
__maybe_unused const struct gpio_siwx91x_common_config *cfg = parent->config;
367+
struct gpio_siwx91x_common_data *data = parent->data;
329368

330369
/* Register port as active */
331-
__ASSERT(cfg->port < pcfg->port_count, "Too many ports");
332-
pdata->ports[cfg->port] = port;
370+
__ASSERT(port_cfg->port < cfg->port_count, "Too many ports");
371+
data->ports[port_cfg->port] = port;
333372

334-
return pm_device_driver_init(port, gpio_siwx91x_port_pm_action);
373+
return 0;
335374
}
336375

337376
static void gpio_siwx91x_isr(const struct device *parent)
@@ -386,6 +425,8 @@ static DEVICE_API(gpio, gpio_siwx91x_api) = {
386425
};
387426

388427
#define GPIO_PORT_INIT(n) \
428+
struct gpio_siwx91x_pin_config_info \
429+
pin_config_info_##n[__builtin_popcount(GPIO_PORT_PIN_MASK_FROM_DT_NODE(n))]; \
389430
static const struct gpio_siwx91x_port_config gpio_siwx91x_port_config##n = { \
390431
.common.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(n), \
391432
.parent = DEVICE_DT_GET(DT_PARENT(n)), \
@@ -395,12 +436,13 @@ static DEVICE_API(gpio, gpio_siwx91x_api) = {
395436
DT_REG_ADDR(n), \
396437
.ulp = DT_PROP(DT_PARENT(n), silabs_ulp), \
397438
}; \
398-
static struct gpio_siwx91x_port_data gpio_siwx91x_port_data##n; \
439+
static struct gpio_siwx91x_port_data gpio_siwx91x_port_data##n = { \
440+
.pin_config_info = pin_config_info_##n, \
441+
}; \
399442
\
400-
PM_DEVICE_DT_INST_DEFINE(n, gpio_siwx91x_port_pm_action); \
401-
DEVICE_DT_DEFINE(n, gpio_siwx91x_init_port, PM_DEVICE_DT_INST_GET(n), \
402-
&gpio_siwx91x_port_data##n, &gpio_siwx91x_port_config##n, PRE_KERNEL_1, \
403-
CONFIG_GPIO_INIT_PRIORITY, &gpio_siwx91x_api);
443+
DEVICE_DT_DEFINE(n, gpio_siwx91x_init_port, NULL, &gpio_siwx91x_port_data##n, \
444+
&gpio_siwx91x_port_config##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
445+
&gpio_siwx91x_api);
404446

405447
#define CONFIGURE_SHARED_INTERRUPT(node_id, prop, idx) \
406448
IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), DT_IRQ_BY_IDX(node_id, idx, priority), \
@@ -433,11 +475,12 @@ static DEVICE_API(gpio, gpio_siwx91x_common_api) = { };
433475
data->interrupts[i].port = INVALID_PORT; \
434476
} \
435477
DT_INST_FOREACH_PROP_ELEM(idx, interrupt_names, CONFIGURE_SHARED_INTERRUPT); \
436-
return 0; \
478+
return pm_device_driver_init(dev, gpio_siwx91x_pm_action); \
437479
} \
438-
DEVICE_DT_INST_DEFINE(idx, gpio_siwx91x_init_controller_##idx, NULL, \
439-
&gpio_siwx91x_data##idx, &gpio_siwx91x_config##idx, \
440-
PRE_KERNEL_1, CONFIG_GPIO_SILABS_SIWX91X_COMMON_INIT_PRIORITY, \
480+
PM_DEVICE_DT_INST_DEFINE(idx, gpio_siwx91x_pm_action); \
481+
DEVICE_DT_INST_DEFINE(idx, gpio_siwx91x_init_controller_##idx, PM_DEVICE_DT_INST_GET(idx), \
482+
&gpio_siwx91x_data##idx, &gpio_siwx91x_config##idx, PRE_KERNEL_1, \
483+
CONFIG_GPIO_SILABS_SIWX91X_COMMON_INIT_PRIORITY, \
441484
&gpio_siwx91x_common_api); \
442485
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, GPIO_PORT_INIT);
443486

0 commit comments

Comments
 (0)