Skip to content

Commit

Permalink
Merge tag 'intel-gpio-v5.11-1' of gitolite.kernel.org:pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/andy/linux-gpio-intel into devel

intel-gpio for v5.11-1

* Refactor GPIO library to support bias and debounce ACPI settings

The following is an automated git shortlog grouped by driver:

gpiolib:
 -  acpi: Make Intel GPIO tree official for GPIO ACPI work
 -  acpi: Use BIT() macro to increase readability
 -  acpi: Convert pin_index to be u16
 -  acpi: Extract acpi_request_own_gpiod() helper
 -  acpi: Make acpi_gpio_to_gpiod_flags() usable for GpioInt()
 -  acpi: Set initial value for output pin based on bias and polarity
 -  acpi: Move acpi_gpio_to_gpiod_flags() upper in the code
 -  acpi: Move non-critical code outside of critical section
 -  acpi: Take into account debounce settings
 -  acpi: Use named item for enum gpiod_flags variable
 -  acpi: Respect bias settings for GpioInt() resource
 -  Introduce gpio_set_debounce_timeout() for internal use
 -  Extract gpio_set_config_with_argument_optional() helper
 -  move bias related code from gpio_set_config() to gpio_set_bias()
 -  Extract gpio_set_config_with_argument() for future use
 -  use proper API to pack pin configuration parameters
 -  add missed break statement
 -  Replace unsigned by unsigned int

Merge tag 'intel-pinctrl-v5.10-2' into HEAD:
 - Merge tag 'intel-pinctrl-v5.10-2' into HEAD

pinctrl:
 -  intel: Set default bias in case no particular value given
 -  intel: Fix 2 kOhm bias which is 833 Ohm
  • Loading branch information
Linus Walleij committed Nov 17, 2020
2 parents ad9a72f + e709a7b commit dc80a27
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 97 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -7480,6 +7480,7 @@ M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
L: linux-gpio@vger.kernel.org
L: linux-acpi@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
F: Documentation/firmware-guide/acpi/gpio-properties.rst
F: drivers/gpio/gpiolib-acpi.c
F: drivers/gpio/gpiolib-acpi.h
Expand Down
138 changes: 84 additions & 54 deletions drivers/gpio/gpiolib-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,67 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
acpi_gpiochip_request_irq(acpi_gpio, event);
}

static enum gpiod_flags
acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
{
/* GpioInt() implies input configuration */
if (agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
return GPIOD_IN;

switch (agpio->io_restriction) {
case ACPI_IO_RESTRICT_INPUT:
return GPIOD_IN;
case ACPI_IO_RESTRICT_OUTPUT:
/*
* ACPI GPIO resources don't contain an initial value for the
* GPIO. Therefore we deduce that value from the pull field
* and the polarity instead. If the pin is pulled up we assume
* default to be high, if it is pulled down we assume default
* to be low, otherwise we leave pin untouched. For active low
* polarity values will be switched. See also
* Documentation/firmware-guide/acpi/gpio-properties.rst.
*/
switch (agpio->pin_config) {
case ACPI_PIN_CONFIG_PULLUP:
return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH;
case ACPI_PIN_CONFIG_PULLDOWN:
return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
default:
break;
}
default:
break;
}

/*
* Assume that the BIOS has configured the direction and pull
* accordingly.
*/
return GPIOD_ASIS;
}

static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
struct acpi_resource_gpio *agpio,
unsigned int index,
const char *label)
{
int polarity = GPIO_ACTIVE_HIGH;
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
unsigned int pin = agpio->pin_table[index];
struct gpio_desc *desc;
int ret;

desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
if (IS_ERR(desc))
return desc;

ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout);
if (ret)
gpiochip_free_own_desc(desc);

return ret ? ERR_PTR(ret) : desc;
}

static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
{
const char *controller, *pin_str;
Expand Down Expand Up @@ -290,8 +351,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!handler)
return AE_OK;

desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
GPIO_ACTIVE_HIGH, GPIOD_IN);
desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
if (IS_ERR(desc)) {
dev_err(chip->parent,
"Failed to request GPIO for pin 0x%04X, err %ld\n",
Expand Down Expand Up @@ -526,39 +586,6 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
return false;
}

static enum gpiod_flags
acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
{
switch (agpio->io_restriction) {
case ACPI_IO_RESTRICT_INPUT:
return GPIOD_IN;
case ACPI_IO_RESTRICT_OUTPUT:
/*
* ACPI GPIO resources don't contain an initial value for the
* GPIO. Therefore we deduce that value from the pull field
* instead. If the pin is pulled up we assume default to be
* high, if it is pulled down we assume default to be low,
* otherwise we leave pin untouched.
*/
switch (agpio->pin_config) {
case ACPI_PIN_CONFIG_PULLUP:
return GPIOD_OUT_HIGH;
case ACPI_PIN_CONFIG_PULLDOWN:
return GPIOD_OUT_LOW;
default:
break;
}
default:
break;
}

/*
* Assume that the BIOS has configured the direction and pull
* accordingly.
*/
return GPIOD_ASIS;
}

static int
__acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
{
Expand Down Expand Up @@ -633,7 +660,7 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
int pin_index;
u16 pin_index;
bool active_low;
struct gpio_desc *desc;
int n;
Expand All @@ -649,7 +676,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
if (!lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
int pin_index;
u16 pin_index;

if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
lookup->index++;
Expand All @@ -664,6 +691,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
agpio->pin_table[pin_index]);
lookup->info.pin_config = agpio->pin_config;
lookup->info.debounce = agpio->debounce_timeout;
lookup->info.gpioint = gpioint;

/*
Expand All @@ -674,13 +702,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
* - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
*/
if (lookup->info.gpioint) {
lookup->info.flags = GPIOD_IN;
lookup->info.polarity = agpio->polarity;
lookup->info.triggering = agpio->triggering;
} else {
lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
lookup->info.polarity = lookup->active_low;
}

lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio, lookup->info.polarity);
}

return 1;
Expand Down Expand Up @@ -794,7 +822,7 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
if (ret)
return ERR_PTR(ret);

dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n",
dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %u %u\n",
dev_name(&lookup.info.adev->dev), lookup.index,
lookup.pin_index, lookup.active_low);
} else {
Expand Down Expand Up @@ -942,6 +970,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)

if (info.gpioint && idx++ == index) {
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
enum gpiod_flags dflags = GPIOD_ASIS;
char label[32];
int irq;

Expand All @@ -952,11 +981,18 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
if (irq < 0)
return irq;

acpi_gpio_update_gpiod_flags(&dflags, &info);
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);

snprintf(label, sizeof(label), "GpioInt() %d", index);
ret = gpiod_configure_flags(desc, label, lflags, info.flags);
ret = gpiod_configure_flags(desc, label, lflags, dflags);
if (ret < 0)
return ret;

ret = gpio_set_debounce_timeout(desc, info.debounce);
if (ret)
return ret;

irq_flags = acpi_dev_get_irq_type(info.triggering,
info.polarity);

Expand All @@ -982,7 +1018,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
struct gpio_chip *chip = achip->chip;
struct acpi_resource_gpio *agpio;
struct acpi_resource *ares;
int pin_index = (int)address;
u16 pin_index = address;
acpi_status status;
int length;
int i;
Expand All @@ -1005,7 +1041,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
return AE_BAD_PARAMETER;
}

length = min(agpio->pin_table_length, (u16)(pin_index + bits));
length = min_t(u16, agpio->pin_table_length, pin_index + bits);
for (i = pin_index; i < length; ++i) {
int pin = agpio->pin_table[i];
struct acpi_gpio_connection *conn;
Expand Down Expand Up @@ -1042,23 +1078,18 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
}

if (!found) {
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio);
const char *label = "ACPI:OpRegion";

desc = gpiochip_request_own_desc(chip, pin, label,
GPIO_ACTIVE_HIGH,
flags);
desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
if (IS_ERR(desc)) {
status = AE_ERROR;
mutex_unlock(&achip->conn_lock);
status = AE_ERROR;
goto out;
}

conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn) {
status = AE_NO_MEMORY;
gpiochip_free_own_desc(desc);
mutex_unlock(&achip->conn_lock);
status = AE_NO_MEMORY;
goto out;
}

Expand All @@ -1070,8 +1101,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
mutex_unlock(&achip->conn_lock);

if (function == ACPI_WRITE)
gpiod_set_raw_value_cansleep(desc,
!!((1 << i) & *value));
gpiod_set_raw_value_cansleep(desc, !!(*value & BIT(i)));
else
*value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
}
Expand Down Expand Up @@ -1132,7 +1162,7 @@ acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip,
int ret;

*lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
*dflags = 0;
*dflags = GPIOD_ASIS;
*name = NULL;

ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios,
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpio/gpiolib-acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct acpi_device;
* @pin_config: pin bias as provided by ACPI
* @polarity: interrupt polarity as provided by ACPI
* @triggering: triggering type as provided by ACPI
* @debounce: debounce timeout as provided by ACPI
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
*/
struct acpi_gpio_info {
Expand All @@ -27,6 +28,7 @@ struct acpi_gpio_info {
int pin_config;
int polarity;
int triggering;
unsigned int debounce;
unsigned int quirks;
};

Expand Down
Loading

0 comments on commit dc80a27

Please sign in to comment.