diff --git a/drivers/gpio/gpio_emul.c b/drivers/gpio/gpio_emul.c index a78c87bbccb61..8731f56206dad 100644 --- a/drivers/gpio/gpio_emul.c +++ b/drivers/gpio/gpio_emul.c @@ -77,7 +77,7 @@ struct gpio_emul_config { * @ref gpio_add_callback. * * Changes are to @ref gpio_emul_data and @ref gpio_emul_config are - * synchronized using @a mu. + * synchronized using @a k_spinlock. */ struct gpio_emul_data { /** Common @ref gpio_driver_data */ @@ -90,8 +90,8 @@ struct gpio_emul_data { gpio_port_value_t output_vals; /** Interrupt status for each pin */ gpio_port_pins_t interrupts; - /** Mutex to synchronize accesses to driver data and config */ - struct k_mutex mu; + /** Spinlock to synchronize accesses to driver data and config */ + struct k_spinlock lock; /** Singly-linked list of callbacks associated with the controller */ sys_slist_t callbacks; }; @@ -101,7 +101,7 @@ struct gpio_emul_data { * * Use this function to see which pins match the current GPIO configuration. * - * The caller must ensure that @ref gpio_emul_data.mu is locked. + * The caller must ensure that @ref gpio_emul_data.lock is locked. * * @param port The emulated GPIO device pointer * @param mask A mask of flags to match @@ -132,7 +132,7 @@ get_pins_with_flags(const struct device *port, gpio_port_pins_t mask, /** * @brief Obtain a mask of pins that are configured as @ref GPIO_INPUT * - * The caller must ensure that @ref gpio_emul_data.mu is locked. + * The caller must ensure that @ref gpio_emul_data.lock is locked. * * @param port The emulated GPIO device pointer * @@ -146,7 +146,7 @@ static inline gpio_port_pins_t get_input_pins(const struct device *port) /** * @brief Obtain a mask of pins that are configured as @ref GPIO_OUTPUT * - * The caller must ensure that @ref gpio_emul_data.mu is locked. + * The caller must ensure that @ref gpio_emul_data.lock is locked. * * @param port The emulated GPIO device pointer * @@ -254,7 +254,7 @@ static void gpio_emul_gen_interrupt_bits(const struct device *port, * * For more information, see @ref gpio_interface. * - * The caller must ensure that @ref gpio_emul_data.mu is locked. + * The caller must ensure that @ref gpio_emul_data.lock is locked. * * @param port The emulated GPIO port * @param mask The mask of pins that have changed @@ -268,20 +268,26 @@ static void gpio_emul_pend_interrupt(const struct device *port, gpio_port_pins_t gpio_port_pins_t interrupts; struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; + key = k_spin_lock(&drv_data->lock); gpio_emul_gen_interrupt_bits(port, mask, prev_values, values, &interrupts, true); while (interrupts != 0) { + k_spin_unlock(&drv_data->lock, key); gpio_fire_callbacks(&drv_data->callbacks, port, interrupts); + key = k_spin_lock(&drv_data->lock); gpio_emul_gen_interrupt_bits(port, mask, prev_values, values, &interrupts, false); } + + k_spin_unlock(&drv_data->lock, key); } -int gpio_emul_input_set_masked_pend(const struct device *port, gpio_port_pins_t mask, - gpio_port_value_t values, bool pend) +int gpio_emul_input_set_masked_int(const struct device *port, + gpio_port_pins_t mask, + gpio_port_value_t values) { - int ret; gpio_port_pins_t input_mask; gpio_port_pins_t prev_values; struct gpio_emul_data *drv_data = @@ -299,37 +305,41 @@ int gpio_emul_input_set_masked_pend(const struct device *port, gpio_port_pins_t return -EINVAL; } - k_mutex_lock(&drv_data->mu, K_FOREVER); - input_mask = get_input_pins(port); if (~input_mask & mask) { LOG_ERR("Not input pin input_mask=%x mask=%x", input_mask, mask); - ret = -EINVAL; - goto unlock; + return -EINVAL; } prev_values = drv_data->input_vals; drv_data->input_vals &= ~mask; drv_data->input_vals |= values & mask; - values = drv_data->input_vals; - if (pend) { - gpio_emul_pend_interrupt(port, mask, prev_values, values); - } - ret = 0; - -unlock: - k_mutex_unlock(&drv_data->mu); - - return ret; + return 0; } /* documented in drivers/gpio/gpio_emul.h */ int gpio_emul_input_set_masked(const struct device *port, gpio_port_pins_t mask, gpio_port_value_t values) { - return gpio_emul_input_set_masked_pend(port, mask, values, true); + struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + gpio_port_pins_t prev_input_values; + gpio_port_pins_t input_values; + k_spinlock_key_t key; + int rv; + + key = k_spin_lock(&drv_data->lock); + prev_input_values = drv_data->input_vals; + rv = gpio_emul_input_set_masked_int(port, mask, values); + input_values = drv_data->input_vals; + k_spin_unlock(&drv_data->lock, key); + if (rv) { + return rv; + } + + gpio_emul_pend_interrupt(port, mask, prev_input_values, input_values); + return 0; } /* documented in drivers/gpio/gpio_emul.h */ @@ -340,6 +350,7 @@ int gpio_emul_output_get_masked(const struct device *port, gpio_port_pins_t mask (struct gpio_emul_data *)port->data; const struct gpio_emul_config *config = (const struct gpio_emul_config *)port->config; + k_spinlock_key_t key; if (mask == 0) { return 0; @@ -349,9 +360,9 @@ int gpio_emul_output_get_masked(const struct device *port, gpio_port_pins_t mask return -EINVAL; } - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); *values = drv_data->output_vals & get_output_pins(port); - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); return 0; } @@ -363,6 +374,7 @@ int gpio_emul_flags_get(const struct device *port, gpio_pin_t pin, gpio_flags_t (struct gpio_emul_data *)port->data; const struct gpio_emul_config *config = (const struct gpio_emul_config *)port->config; + k_spinlock_key_t key; if (flags == NULL) { return -EINVAL; @@ -372,9 +384,9 @@ int gpio_emul_flags_get(const struct device *port, gpio_pin_t pin, gpio_flags_t return -EINVAL; } - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); *flags = drv_data->flags[pin]; - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); return 0; } @@ -392,6 +404,7 @@ static int gpio_emul_pin_configure(const struct device *port, gpio_pin_t pin, (struct gpio_emul_data *)port->data; const struct gpio_emul_config *config = (const struct gpio_emul_config *)port->config; + k_spinlock_key_t key; int rv; if (flags & GPIO_OPEN_DRAIN) { @@ -406,41 +419,38 @@ static int gpio_emul_pin_configure(const struct device *port, gpio_pin_t pin, return -EINVAL; } - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); drv_data->flags[pin] = flags; if (flags & GPIO_OUTPUT) { if (flags & GPIO_OUTPUT_INIT_LOW) { drv_data->output_vals &= ~BIT(pin); if (flags & GPIO_INPUT) { /* for push-pull mode to generate interrupts */ - rv = gpio_emul_input_set_masked_pend( - port, BIT(pin), drv_data->output_vals, - false); + rv = gpio_emul_input_set_masked_int( + port, BIT(pin), drv_data->output_vals); __ASSERT_NO_MSG(rv == 0); } } else if (flags & GPIO_OUTPUT_INIT_HIGH) { drv_data->output_vals |= BIT(pin); if (flags & GPIO_INPUT) { /* for push-pull mode to generate interrupts */ - rv = gpio_emul_input_set_masked_pend( - port, BIT(pin), drv_data->output_vals, - false); + rv = gpio_emul_input_set_masked_int( + port, BIT(pin), drv_data->output_vals); __ASSERT_NO_MSG(rv == 0); } } } else if (flags & GPIO_INPUT) { if (flags & GPIO_PULL_UP) { - rv = gpio_emul_input_set_masked_pend(port, BIT(pin), BIT(pin), - false); + rv = gpio_emul_input_set_masked_int(port, BIT(pin), BIT(pin)); __ASSERT_NO_MSG(rv == 0); } else if (flags & GPIO_PULL_DOWN) { - rv = gpio_emul_input_set_masked_pend( - port, BIT(pin), 0, false); + rv = gpio_emul_input_set_masked_int( + port, BIT(pin), 0); __ASSERT_NO_MSG(rv == 0); } } - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); gpio_fire_callbacks(&drv_data->callbacks, port, BIT(pin)); return 0; @@ -452,8 +462,9 @@ static int gpio_emul_pin_get_config(const struct device *port, gpio_pin_t pin, { struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); *out_flags = drv_data->flags[pin] & ~(GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH @@ -466,7 +477,7 @@ static int gpio_emul_pin_get_config(const struct device *port, gpio_pin_t pin, } } - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); return 0; } @@ -476,14 +487,15 @@ static int gpio_emul_port_get_raw(const struct device *port, gpio_port_value_t * { struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; if (values == NULL) { return -EINVAL; } - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); *values = drv_data->input_vals & get_input_pins(port); - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); return 0; } @@ -494,11 +506,15 @@ static int gpio_emul_port_set_masked_raw(const struct device *port, { gpio_port_pins_t output_mask; gpio_port_pins_t prev_values; + gpio_port_pins_t prev_input_values; + gpio_port_pins_t input_values; + gpio_port_pins_t input_mask; struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; int rv; - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); output_mask = get_output_pins(port); mask &= output_mask; prev_values = drv_data->output_vals; @@ -507,10 +523,14 @@ static int gpio_emul_port_set_masked_raw(const struct device *port, drv_data->output_vals &= ~mask; drv_data->output_vals |= values; /* in push-pull, set input values & fire interrupts */ - rv = gpio_emul_input_set_masked(port, mask & get_input_pins(port), + prev_input_values = drv_data->input_vals; + input_mask = mask & get_input_pins(port); + rv = gpio_emul_input_set_masked_int(port, input_mask, drv_data->output_vals); - k_mutex_unlock(&drv_data->mu); + input_values = drv_data->input_vals; + k_spin_unlock(&drv_data->lock, key); __ASSERT_NO_MSG(rv == 0); + gpio_emul_pend_interrupt(port, input_mask, prev_input_values, input_values); /* for output-wiring, so the user can take action based on output */ if (prev_values ^ values) { @@ -525,17 +545,23 @@ static int gpio_emul_port_set_bits_raw(const struct device *port, { struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; + gpio_port_pins_t prev_input_values; + gpio_port_pins_t input_values; + gpio_port_pins_t input_mask; int rv; - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); pins &= get_output_pins(port); drv_data->output_vals |= pins; - /* in push-pull, set input values & fire interrupts */ - rv = gpio_emul_input_set_masked(port, pins & get_input_pins(port), + prev_input_values = drv_data->input_vals; + input_mask = pins & get_input_pins(port); + rv = gpio_emul_input_set_masked_int(port, input_mask, drv_data->output_vals); + input_values = drv_data->input_vals; + k_spin_unlock(&drv_data->lock, key); __ASSERT_NO_MSG(rv == 0); - - k_mutex_unlock(&drv_data->mu); + gpio_emul_pend_interrupt(port, input_mask, prev_input_values, input_values); /* for output-wiring, so the user can take action based on output */ gpio_fire_callbacks(&drv_data->callbacks, port, pins & ~get_input_pins(port)); @@ -547,15 +573,22 @@ static int gpio_emul_port_clear_bits_raw(const struct device *port, { struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; + gpio_port_pins_t prev_input_values; + gpio_port_pins_t input_values; + gpio_port_pins_t input_mask; int rv; - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); pins &= get_output_pins(port); drv_data->output_vals &= ~pins; - /* in push-pull, set input values & fire interrupts */ - rv = gpio_emul_input_set_masked(port, pins & get_input_pins(port), drv_data->output_vals); - k_mutex_unlock(&drv_data->mu); + prev_input_values = drv_data->input_vals; + input_mask = pins & get_input_pins(port); + rv = gpio_emul_input_set_masked_int(port, input_mask, drv_data->output_vals); + input_values = drv_data->input_vals; + k_spin_unlock(&drv_data->lock, key); __ASSERT_NO_MSG(rv == 0); + gpio_emul_pend_interrupt(port, input_mask, prev_input_values, input_values); /* for output-wiring, so the user can take action based on output */ gpio_fire_callbacks(&drv_data->callbacks, port, pins & ~get_input_pins(port)); @@ -566,14 +599,15 @@ static int gpio_emul_port_toggle_bits(const struct device *port, gpio_port_pins_ { struct gpio_emul_data *drv_data = (struct gpio_emul_data *)port->data; + k_spinlock_key_t key; int rv; - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); drv_data->output_vals ^= (pins & get_output_pins(port)); /* in push-pull, set input values but do not fire interrupts (yet) */ - rv = gpio_emul_input_set_masked_pend(port, pins & get_input_pins(port), - drv_data->output_vals, false); - k_mutex_unlock(&drv_data->mu); + rv = gpio_emul_input_set_masked_int(port, pins & get_input_pins(port), + drv_data->output_vals); + k_spin_unlock(&drv_data->lock, key); __ASSERT_NO_MSG(rv == 0); /* for output-wiring, so the user can take action based on output */ gpio_fire_callbacks(&drv_data->callbacks, port, pins); @@ -622,6 +656,7 @@ static int gpio_emul_pin_interrupt_configure(const struct device *port, gpio_pin (struct gpio_emul_data *)port->data; const struct gpio_emul_config *config = (const struct gpio_emul_config *)port->config; + k_spinlock_key_t key; if ((BIT(pin) & config->common.port_pin_mask) == 0) { return -EINVAL; @@ -650,7 +685,7 @@ static int gpio_emul_pin_interrupt_configure(const struct device *port, gpio_pin } } - k_mutex_lock(&drv_data->mu, K_FOREVER); + key = k_spin_lock(&drv_data->lock); switch (mode) { case GPIO_INT_MODE_DISABLED: @@ -670,7 +705,7 @@ static int gpio_emul_pin_interrupt_configure(const struct device *port, gpio_pin ret = 0; unlock: - k_mutex_unlock(&drv_data->mu); + k_spin_unlock(&drv_data->lock, key); return ret; } @@ -750,7 +785,7 @@ static int gpio_emul_init(const struct device *dev) (struct gpio_emul_data *)dev->data; sys_slist_init(&drv_data->callbacks); - return k_mutex_init(&drv_data->mu); + return 0; } #ifdef CONFIG_PM_DEVICE