Skip to content

Commit 9dbbe96

Browse files
committed
Make reset GPIO_ACTIVE_LOW
Many panels have active low reset GPIOs. This can be seen if we keep reset high after turning the panel on. From a logical perspective this does not make sense: We should assert reset to actually do the reset, not to disable it. Therefore we try check the last element from the reset sequence here. If it sets the GPIO to 1 (high), we assume that reset is active low. Also generate this properly in the device tree fragment to avoid confusion.
1 parent bd30e25 commit 9dbbe96

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

driver.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
from __future__ import annotations
33

44
import datetime
5+
56
import mipi
67
import simple
78
import wrap
8-
from generator import Options
9+
from generator import Options, GpioFlag
910
from panel import Panel, BacklightControl, CommandSequence
1011

1112

@@ -59,7 +60,7 @@ def generate_struct(p: Panel, options: Options) -> str:
5960
variables.append(f'struct regulator_bulk_data supplies[{len(options.regulator)}]')
6061
else:
6162
variables.append('struct regulator *supply')
62-
variables += [f'struct gpio_desc *{name}_gpio' for name in options.gpios]
63+
variables += [f'struct gpio_desc *{name}_gpio' for name in options.gpios.keys()]
6364
variables.append('bool prepared')
6465

6566
s = f'struct {p.short_id} {{'
@@ -109,12 +110,15 @@ def msleep(m: int) -> str:
109110
return f"usleep_range({u}, {u + 1000})"
110111

111112

112-
def generate_reset(p: Panel) -> str:
113+
def generate_reset(p: Panel, options: Options) -> str:
113114
if not p.reset_seq:
114115
return ''
115116

116117
s = f'\nstatic void {p.short_id}_reset(struct {p.short_id} *ctx)\n{{\n'
117118
for state, sleep in p.reset_seq:
119+
# Invert reset sequence if GPIO is active low
120+
if options.gpios["reset"] & GpioFlag.ACTIVE_LOW:
121+
state = int(not bool(state))
118122
s += f'\tgpiod_set_value_cansleep(ctx->reset_gpio, {state});\n'
119123
if sleep:
120124
s += f'\t{msleep(sleep)};\n'
@@ -165,7 +169,7 @@ def generate_commands(p: Panel, options: Options, cmd_name: str) -> str:
165169
def generate_cleanup(p: Panel, options: Options, indent: int = 1) -> str:
166170
cleanup = []
167171
if p.reset_seq:
168-
cleanup.append('gpiod_set_value_cansleep(ctx->reset_gpio, 0);')
172+
cleanup.append('gpiod_set_value_cansleep(ctx->reset_gpio, 1);')
169173
if options.regulator:
170174
if len(options.regulator) > 1:
171175
cleanup.append('regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);')
@@ -370,9 +374,14 @@ def generate_probe(p: Panel, options: Options) -> str:
370374
}}
371375
'''
372376

373-
for name in options.gpios:
377+
for name, flags in options.gpios.items():
378+
# TODO: In the future, we might want to change this to keep panel alive
379+
init = "GPIOD_OUT_LOW"
380+
if name == "reset":
381+
init = "GPIOD_OUT_HIGH"
382+
374383
s += f'''
375-
ctx->{name}_gpio = devm_gpiod_get(dev, "{name}", GPIOD_OUT_LOW);
384+
ctx->{name}_gpio = devm_gpiod_get(dev, "{name}", {init});
376385
if (IS_ERR(ctx->{name}_gpio)) {{
377386
ret = PTR_ERR(ctx->{name}_gpio);
378387
dev_err(dev, "Failed to get {name}-gpios: %d\\n", ret);
@@ -436,11 +445,24 @@ def generate_driver(p: Panel, options: Options) -> None:
436445
c.generated = c.type.generate(c.payload, options)
437446
cmd.generated += c.generated
438447

439-
options.gpios = []
448+
options.gpios = {}
440449
if p.reset_seq:
441-
options.gpios.append('reset')
450+
# Many panels have active low reset GPIOs. This can be seen if we keep
451+
# reset high after turning the panel on. From a logical perspective this
452+
# does not make sense: We should assert reset to actually do the reset,
453+
# not to disable it.
454+
#
455+
# Therefore we try check the last element from the reset sequence here.
456+
# If it sets the GPIO to 1 (high), we assume that reset is active low.
457+
458+
flag = GpioFlag.ACTIVE_HIGH
459+
last_val, _ = p.reset_seq[-1]
460+
if last_val == 1:
461+
flag = GpioFlag.ACTIVE_LOW
462+
463+
options.gpios["reset"] = flag
442464
if options.backlight_gpio:
443-
options.gpios.append('backlight')
465+
options.gpios["backlight"] = GpioFlag.ACTIVE_HIGH
444466

445467
dash_id = p.short_id.replace('_', '-')
446468
compatible = dash_id.split('-', 1)
@@ -469,7 +491,7 @@ def generate_driver(p: Panel, options: Options) -> None:
469491
{{
470492
return container_of(panel, struct {p.short_id}, panel);
471493
}}{generate_macros(p)}
472-
{generate_reset(p)}
494+
{generate_reset(p, options)}
473495
{generate_commands(p, options, 'on')}
474496
{generate_commands(p, options, 'off')}
475497
{generate_prepare(p, options)}

dtsi.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from generator import Options
1+
from generator import Options, GpioFlag
22
from panel import Panel, BacklightControl
33

44

@@ -18,8 +18,9 @@ def generate_supplies(options: Options):
1818

1919
def generate_gpios(options: Options):
2020
s = ""
21-
for r in options.gpios:
22-
s += f"\t\t{r}-gpios = <&msmgpio XY GPIO_ACTIVE_HIGH>;\n"
21+
for name, flags in options.gpios.items():
22+
flags = "GPIO_ACTIVE_LOW" if flags & GpioFlag.ACTIVE_LOW else "GPIO_ACTIVE_HIGH"
23+
s += f"\t\t{name}-gpios = <&msmgpio XY {flags}>;\n"
2324
return s
2425

2526

generator.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
from __future__ import annotations
33

44
from dataclasses import dataclass
5-
from typing import List, Optional, TextIO
5+
from enum import Flag, auto
6+
from typing import List, Optional, TextIO, Dict
7+
8+
9+
class GpioFlag(Flag):
10+
ACTIVE_HIGH = 0
11+
ACTIVE_LOW = auto()
612

713

814
@dataclass(init=False)
@@ -16,4 +22,4 @@ class Options:
1622

1723
# Added by panel driver generator
1824
compatible: str
19-
gpios: List[str]
25+
gpios: Dict[str, GpioFlag]

0 commit comments

Comments
 (0)