Furquan Shaikh (furquan@google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17797
-gerrit
commit adc40b32f4df2e27f92b3fa905f769c3962d031b Author: Furquan Shaikh furquan@chromium.org Date: Mon Dec 12 09:23:01 2016 -0800
drivers/i2c/generic: Allow mainboards to export reset and enable GPIOs
Add power management type config option that allows mainboards to either: 1. Define a power resource that uses the reset and enable gpios to power on and off the device using _ON and _OFF methods, or 2. Export reset and enable GPIOs in _CRS and _DSD so that the OS can directly toggle the GPIOs as required.
GPIO type needs to be updated in drivers_i2c_generic_config to use acpi_gpio type so that it can be used for both the above cases.
BUG=chrome-os-partner:60194 BRANCH=None TEST=Verified that elan touchscreen works fine on reef using exported GPIOs.
Change-Id: I4d76f193f615cfc4520869dedc55505c109042f6 Signed-off-by: Furquan Shaikh furquan@chromium.org --- src/drivers/i2c/generic/chip.h | 12 +++- src/drivers/i2c/generic/generic.c | 75 ++++++++++++++++++---- .../google/reef/variants/baseboard/devicetree.cb | 5 +- 3 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/src/drivers/i2c/generic/chip.h b/src/drivers/i2c/generic/chip.h index 736de51..ecd18ab 100644 --- a/src/drivers/i2c/generic/chip.h +++ b/src/drivers/i2c/generic/chip.h @@ -19,6 +19,11 @@ #include <arch/acpi_device.h> #include <device/i2c.h>
+enum power_mgmt_type { + POWER_RESOURCE = 1, + GPIO_EXPORT = 2, +}; + struct drivers_i2c_generic_config { const char *hid; /* ACPI _HID (required) */ const char *cid; /* ACPI _CID */ @@ -42,12 +47,15 @@ struct drivers_i2c_generic_config { unsigned device_present_gpio; unsigned device_present_gpio_invert;
+ /* Power management type. */ + enum power_mgmt_type pwr_mgmt_type; + /* GPIO used to take device out of reset or to put it into reset. */ - unsigned reset_gpio; + struct acpi_gpio reset_gpio; /* Delay to be inserted after device is taken out of reset. */ unsigned reset_delay_ms; /* GPIO used to enable device. */ - unsigned enable_gpio; + struct acpi_gpio enable_gpio; /* Delay to be inserted after device is enabled. */ unsigned enable_delay_ms; }; diff --git a/src/drivers/i2c/generic/generic.c b/src/drivers/i2c/generic/generic.c index b8e5d86..6ca1599 100644 --- a/src/drivers/i2c/generic/generic.c +++ b/src/drivers/i2c/generic/generic.c @@ -29,8 +29,13 @@ static void i2c_generic_add_power_res(struct drivers_i2c_generic_config *config) { const char *power_res_dev_states[] = { "_PR0", "_PR3" }; + unsigned reset_gpio = config->reset_gpio.pins[0]; + unsigned enable_gpio = config->enable_gpio.pins[0];
- if (!config->reset_gpio && !config->enable_gpio) + if (config->pwr_mgmt_type != POWER_RESOURCE) + return; + + if (!reset_gpio && !enable_gpio) return;
/* PowerResource (PRIC, 0, 0) */ @@ -42,29 +47,51 @@ static void i2c_generic_add_power_res(struct drivers_i2c_generic_config *config)
/* Method (_ON, 0, Serialized) */ acpigen_write_method_serialized("_ON", 0); - if (config->reset_gpio) - acpigen_soc_set_tx_gpio(config->reset_gpio); - if (config->enable_gpio) { - acpigen_soc_set_tx_gpio(config->enable_gpio); + if (reset_gpio) + acpigen_soc_set_tx_gpio(reset_gpio); + if (enable_gpio) { + acpigen_soc_set_tx_gpio(enable_gpio); acpigen_write_sleep(config->enable_delay_ms); } - if (config->reset_gpio) { - acpigen_soc_clear_tx_gpio(config->reset_gpio); + if (reset_gpio) { + acpigen_soc_clear_tx_gpio(reset_gpio); acpigen_write_sleep(config->reset_delay_ms); } acpigen_pop_len(); /* _ON method */
/* Method (_OFF, 0, Serialized) */ acpigen_write_method_serialized("_OFF", 0); - if (config->reset_gpio) - acpigen_soc_set_tx_gpio(config->reset_gpio); - if (config->enable_gpio) - acpigen_soc_clear_tx_gpio(config->enable_gpio); + if (reset_gpio) + acpigen_soc_set_tx_gpio(reset_gpio); + if (enable_gpio) + acpigen_soc_clear_tx_gpio(enable_gpio); acpigen_pop_len(); /* _OFF method */
acpigen_pop_len(); /* PowerResource PRIC */ }
+static bool i2c_generic_add_gpios_to_crs(struct drivers_i2c_generic_config *cfg) +{ + if (cfg->pwr_mgmt_type == GPIO_EXPORT) + return true; + + return false; +} + +static int i2c_generic_write_gpio(struct acpi_gpio *gpio, int *curr_index) +{ + int ret = -1; + + if (gpio->pin_count == 0) + return ret; + + acpi_device_write_gpio(gpio); + ret = *curr_index; + (*curr_index)++; + + return ret; +} + void i2c_generic_fill_ssdt(struct device *dev, void (*callback)(struct device *dev)) { @@ -77,6 +104,9 @@ void i2c_generic_fill_ssdt(struct device *dev, .resource = scope, }; struct acpi_dp *dsd = NULL; + int curr_index = 0; + int reset_gpio_index = -1, enable_gpio_index = -1; + const char *path = acpi_device_path(dev);
if (!dev->enabled || !scope) return; @@ -101,6 +131,12 @@ void i2c_generic_fill_ssdt(struct device *dev, acpigen_write_resourcetemplate_header(); acpi_device_write_i2c(&i2c); acpi_device_write_interrupt(&config->irq); + if (i2c_generic_add_gpios_to_crs(config) == true) { + reset_gpio_index = i2c_generic_write_gpio(&config->reset_gpio, + &curr_index); + enable_gpio_index = i2c_generic_write_gpio(&config->enable_gpio, + &curr_index); + } acpigen_write_resourcetemplate_footer();
/* Wake capabilities */ @@ -109,9 +145,20 @@ void i2c_generic_fill_ssdt(struct device *dev, acpigen_write_PRW(config->wake, 3); }
- if (config->probed) { + /* DSD */ + if (config->probed || (reset_gpio_index != -1) || + (enable_gpio_index != -1)) { dsd = acpi_dp_new_table("_DSD"); - acpi_dp_add_integer(dsd, "linux,probed", 1); + if (config->probed) + acpi_dp_add_integer(dsd, "linux,probed", 1); + if (reset_gpio_index != -1) + acpi_dp_add_gpio(dsd, "reset-gpios", path, + reset_gpio_index, 0, + config->reset_gpio.polarity); + if (enable_gpio_index != -1) + acpi_dp_add_gpio(dsd, "enable-gpios", path, + enable_gpio_index, 0, + config->enable_gpio.polarity); acpi_dp_write(dsd); }
@@ -125,7 +172,7 @@ void i2c_generic_fill_ssdt(struct device *dev, acpigen_pop_len(); /* Device */ acpigen_pop_len(); /* Scope */
- printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), + printk(BIOS_INFO, "%s: %s at %s\n", path, config->desc ? : dev->chip_ops->name, dev_path(dev)); }
diff --git a/src/mainboard/google/reef/variants/baseboard/devicetree.cb b/src/mainboard/google/reef/variants/baseboard/devicetree.cb index 49c1ba6..a0b53d6 100644 --- a/src/mainboard/google/reef/variants/baseboard/devicetree.cb +++ b/src/mainboard/google/reef/variants/baseboard/devicetree.cb @@ -177,9 +177,10 @@ chip soc/intel/apollolake register "desc" = ""ELAN Touchscreen"" register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)" register "probed" = "1" - register "reset_gpio" = "GPIO_36" + register "pwr_mgmt_type" = "GPIO_EXPORT" + register "reset_gpio" = "ACPI_GPIO_OUTPUT_ACTIVE_HIGH(GPIO_36)" register "reset_delay_ms" = "20" - register "enable_gpio" = "GPIO_152" + register "enable_gpio" = "ACPI_GPIO_OUTPUT_ACTIVE_HIGH(GPIO_152)" register "enable_delay_ms" = "1" device i2c 10 on end end