Skip to content

Commit

Permalink
gpio_fsm: Rework the atomic-vs-non-atomic split
Browse files Browse the repository at this point in the history
Partition the code to separate atomic and non-atomic methods so that
none of them have to handle both cases. The result avoids using deferred
work unless necessary, and should be easier to understand.

Signed-off-by: Phil Elwell <[email protected]>
  • Loading branch information
pelwell committed Sep 8, 2023
1 parent 672307c commit 79b6520
Showing 1 changed file with 41 additions and 43 deletions.
84 changes: 41 additions & 43 deletions drivers/gpio/gpio-fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,6 @@ static void free_symbols(struct symtab_entry **symtab)
}
}

static void gpio_fsm_go_to_state(struct gpio_fsm *gf,
struct fsm_state *new_state);

static void gpio_fsm_set_soft(struct gpio_fsm *gf,
unsigned int off, int val);

Expand All @@ -213,6 +210,7 @@ static void gpio_fsm_enter_state(struct gpio_fsm *gf,
dev_dbg(gf->dev, "enter_state(%s)\n", state->name);

gf->current_state = state;
gf->delay_target_state = NULL;

// 1. Apply any listed signals
for (i = 0; i < state->num_signals; i++) {
Expand Down Expand Up @@ -271,7 +269,7 @@ static void gpio_fsm_enter_state(struct gpio_fsm *gf,
dev_info(gf->dev,
"GF_SOFT %d=%d -> %s\n", event->index,
event->value, event->target->name);
gpio_fsm_go_to_state(gf, event->target);
gpio_fsm_enter_state(gf, event->target);
return;
}
}
Expand All @@ -284,7 +282,7 @@ static void gpio_fsm_enter_state(struct gpio_fsm *gf,
inp_state->value = event->value;
inp_state->enabled = true;

value = gpiod_get_value(gf->input_gpios->desc[event->index]);
value = gpiod_get_value_cansleep(gf->input_gpios->desc[event->index]);

// Clear stale event state
disable_irq(inp_state->irq);
Expand All @@ -299,7 +297,7 @@ static void gpio_fsm_enter_state(struct gpio_fsm *gf,
dev_info(gf->dev,
"GF_IN %d=%d -> %s\n", event->index,
event->value, event->target->name);
gpio_fsm_go_to_state(gf, event->target);
gpio_fsm_enter_state(gf, event->target);
return;
}
}
Expand All @@ -325,6 +323,33 @@ static void gpio_fsm_go_to_state(struct gpio_fsm *gf,
dev_dbg(gf->dev, "go_to_state(%s)\n",
new_state ? new_state->name : "<unset>");

state = gf->current_state;

/* Disable any enabled GPIO IRQs */
for (i = 0; i < state->num_gpio_events; i++) {
gp_ev = &state->gpio_events[i];
inp_state = &gf->input_gpio_states[gp_ev->index];
if (inp_state->enabled) {
inp_state->enabled = false;
irq_set_irq_type(inp_state->irq,
IRQF_TRIGGER_NONE);
}
}

gpio_fsm_enter_state(gf, new_state);
}

static void gpio_fsm_go_to_state_deferred(struct gpio_fsm *gf,
struct fsm_state *new_state)
{
struct input_gpio_state *inp_state;
struct gpio_event *gp_ev;
struct fsm_state *state;
int i;

dev_dbg(gf->dev, "go_to_state_deferred(%s)\n",
new_state ? new_state->name : "<unset>");

spin_lock(&gf->spinlock);

if (gf->next_state) {
Expand All @@ -335,57 +360,31 @@ static void gpio_fsm_go_to_state(struct gpio_fsm *gf,

gf->next_state = new_state;
state = gf->current_state;
gf->delay_target_state = NULL;

if (state) {
/* Disarm any GPIO IRQs */
for (i = 0; i < state->num_gpio_events; i++) {
gp_ev = &state->gpio_events[i];
inp_state = &gf->input_gpio_states[gp_ev->index];
inp_state->target = NULL;
}
/* Disarm any GPIO IRQs */
for (i = 0; i < state->num_gpio_events; i++) {
gp_ev = &state->gpio_events[i];
inp_state = &gf->input_gpio_states[gp_ev->index];
inp_state->target = NULL;
}

spin_unlock(&gf->spinlock);

if (new_state)
schedule_work(&gf->work);
schedule_work(&gf->work);
}

static void gpio_fsm_work(struct work_struct *work)
{
struct input_gpio_state *inp_state;
struct fsm_state *new_state;
struct fsm_state *state;
struct gpio_event *gp_ev;
struct gpio_fsm *gf;
int i;

gf = container_of(work, struct gpio_fsm, work);
spin_lock(&gf->spinlock);
state = gf->current_state;
new_state = gf->next_state;
if (!new_state)
new_state = gf->delay_target_state;
gf->next_state = NULL;
gf->delay_target_state = NULL;
spin_unlock(&gf->spinlock);

if (state) {
/* Disable any enabled GPIO IRQs */
for (i = 0; i < state->num_gpio_events; i++) {
gp_ev = &state->gpio_events[i];
inp_state = &gf->input_gpio_states[gp_ev->index];
if (inp_state->enabled) {
inp_state->enabled = false;
irq_set_irq_type(inp_state->irq,
IRQF_TRIGGER_NONE);
}
}
}

if (new_state)
gpio_fsm_enter_state(gf, new_state);
gpio_fsm_go_to_state(gf, new_state);
}

static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id)
Expand All @@ -404,7 +403,7 @@ static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id)
if (gf->debug)
dev_info(gf->dev, "GF_IN %d->%d -> %s\n",
inp_state->index, inp_state->value, target->name);
gpio_fsm_go_to_state(gf, target);
gpio_fsm_go_to_state_deferred(gf, target);
return IRQ_HANDLED;
}

Expand All @@ -416,12 +415,11 @@ static void gpio_fsm_timer(struct timer_list *timer)
target = gf->delay_target_state;
if (!target)
return;

if (gf->debug)
dev_info(gf->dev, "GF_DELAY %d -> %s\n", gf->delay_ms,
target->name);

gpio_fsm_go_to_state(gf, target);
gpio_fsm_go_to_state_deferred(gf, target);
}

int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state,
Expand Down Expand Up @@ -1119,7 +1117,7 @@ static int gpio_fsm_probe(struct platform_device *pdev)
if (gf->debug)
dev_info(gf->dev, "Start -> %s\n", gf->start_state->name);

gpio_fsm_go_to_state(gf, gf->start_state);
gpio_fsm_enter_state(gf, gf->start_state);

return devm_gpiochip_add_data(dev, &gf->gc, gf);
}
Expand Down

0 comments on commit 79b6520

Please sign in to comment.