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> Reviewed-on: https://review.coreboot.org/17797 Tested-by: build bot (Jenkins) Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
This commit is contained in:
parent
c804826be9
commit
98915bb7a9
|
@ -19,6 +19,11 @@
|
||||||
#include <arch/acpi_device.h>
|
#include <arch/acpi_device.h>
|
||||||
#include <device/i2c.h>
|
#include <device/i2c.h>
|
||||||
|
|
||||||
|
enum power_mgmt_type {
|
||||||
|
POWER_RESOURCE = 1,
|
||||||
|
GPIO_EXPORT = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct drivers_i2c_generic_config {
|
struct drivers_i2c_generic_config {
|
||||||
const char *hid; /* ACPI _HID (required) */
|
const char *hid; /* ACPI _HID (required) */
|
||||||
const char *cid; /* ACPI _CID */
|
const char *cid; /* ACPI _CID */
|
||||||
|
@ -42,12 +47,15 @@ struct drivers_i2c_generic_config {
|
||||||
unsigned device_present_gpio;
|
unsigned device_present_gpio;
|
||||||
unsigned device_present_gpio_invert;
|
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. */
|
/* 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. */
|
/* Delay to be inserted after device is taken out of reset. */
|
||||||
unsigned reset_delay_ms;
|
unsigned reset_delay_ms;
|
||||||
/* GPIO used to enable device. */
|
/* GPIO used to enable device. */
|
||||||
unsigned enable_gpio;
|
struct acpi_gpio enable_gpio;
|
||||||
/* Delay to be inserted after device is enabled. */
|
/* Delay to be inserted after device is enabled. */
|
||||||
unsigned enable_delay_ms;
|
unsigned enable_delay_ms;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,8 +29,13 @@
|
||||||
static void i2c_generic_add_power_res(struct drivers_i2c_generic_config *config)
|
static void i2c_generic_add_power_res(struct drivers_i2c_generic_config *config)
|
||||||
{
|
{
|
||||||
const char *power_res_dev_states[] = { "_PR0", "_PR3" };
|
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;
|
return;
|
||||||
|
|
||||||
/* PowerResource (PRIC, 0, 0) */
|
/* 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) */
|
/* Method (_ON, 0, Serialized) */
|
||||||
acpigen_write_method_serialized("_ON", 0);
|
acpigen_write_method_serialized("_ON", 0);
|
||||||
if (config->reset_gpio)
|
if (reset_gpio)
|
||||||
acpigen_soc_set_tx_gpio(config->reset_gpio);
|
acpigen_soc_set_tx_gpio(reset_gpio);
|
||||||
if (config->enable_gpio) {
|
if (enable_gpio) {
|
||||||
acpigen_soc_set_tx_gpio(config->enable_gpio);
|
acpigen_soc_set_tx_gpio(enable_gpio);
|
||||||
acpigen_write_sleep(config->enable_delay_ms);
|
acpigen_write_sleep(config->enable_delay_ms);
|
||||||
}
|
}
|
||||||
if (config->reset_gpio) {
|
if (reset_gpio) {
|
||||||
acpigen_soc_clear_tx_gpio(config->reset_gpio);
|
acpigen_soc_clear_tx_gpio(reset_gpio);
|
||||||
acpigen_write_sleep(config->reset_delay_ms);
|
acpigen_write_sleep(config->reset_delay_ms);
|
||||||
}
|
}
|
||||||
acpigen_pop_len(); /* _ON method */
|
acpigen_pop_len(); /* _ON method */
|
||||||
|
|
||||||
/* Method (_OFF, 0, Serialized) */
|
/* Method (_OFF, 0, Serialized) */
|
||||||
acpigen_write_method_serialized("_OFF", 0);
|
acpigen_write_method_serialized("_OFF", 0);
|
||||||
if (config->reset_gpio)
|
if (reset_gpio)
|
||||||
acpigen_soc_set_tx_gpio(config->reset_gpio);
|
acpigen_soc_set_tx_gpio(reset_gpio);
|
||||||
if (config->enable_gpio)
|
if (enable_gpio)
|
||||||
acpigen_soc_clear_tx_gpio(config->enable_gpio);
|
acpigen_soc_clear_tx_gpio(enable_gpio);
|
||||||
acpigen_pop_len(); /* _OFF method */
|
acpigen_pop_len(); /* _OFF method */
|
||||||
|
|
||||||
acpigen_pop_len(); /* PowerResource PRIC */
|
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 i2c_generic_fill_ssdt(struct device *dev,
|
||||||
void (*callback)(struct device *dev),
|
void (*callback)(struct device *dev),
|
||||||
struct drivers_i2c_generic_config *config)
|
struct drivers_i2c_generic_config *config)
|
||||||
|
@ -77,6 +104,9 @@ void i2c_generic_fill_ssdt(struct device *dev,
|
||||||
.resource = scope,
|
.resource = scope,
|
||||||
};
|
};
|
||||||
struct acpi_dp *dsd = NULL;
|
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)
|
if (!dev->enabled || !scope)
|
||||||
return;
|
return;
|
||||||
|
@ -101,6 +131,12 @@ void i2c_generic_fill_ssdt(struct device *dev,
|
||||||
acpigen_write_resourcetemplate_header();
|
acpigen_write_resourcetemplate_header();
|
||||||
acpi_device_write_i2c(&i2c);
|
acpi_device_write_i2c(&i2c);
|
||||||
acpi_device_write_interrupt(&config->irq);
|
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();
|
acpigen_write_resourcetemplate_footer();
|
||||||
|
|
||||||
/* Wake capabilities */
|
/* Wake capabilities */
|
||||||
|
@ -109,9 +145,20 @@ void i2c_generic_fill_ssdt(struct device *dev,
|
||||||
acpigen_write_PRW(config->wake, 3);
|
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");
|
dsd = acpi_dp_new_table("_DSD");
|
||||||
|
if (config->probed)
|
||||||
acpi_dp_add_integer(dsd, "linux,probed", 1);
|
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);
|
acpi_dp_write(dsd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +172,7 @@ void i2c_generic_fill_ssdt(struct device *dev,
|
||||||
acpigen_pop_len(); /* Device */
|
acpigen_pop_len(); /* Device */
|
||||||
acpigen_pop_len(); /* Scope */
|
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));
|
config->desc ? : dev->chip_ops->name, dev_path(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,10 +177,9 @@ chip soc/intel/apollolake
|
||||||
register "desc" = ""ELAN Touchscreen""
|
register "desc" = ""ELAN Touchscreen""
|
||||||
register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)"
|
register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)"
|
||||||
register "probed" = "1"
|
register "probed" = "1"
|
||||||
register "reset_gpio" = "GPIO_36"
|
register "pwr_mgmt_type" = "GPIO_EXPORT"
|
||||||
register "reset_delay_ms" = "20"
|
register "reset_gpio" = "ACPI_GPIO_OUTPUT_ACTIVE_HIGH(GPIO_36)"
|
||||||
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
|
device i2c 10 on end
|
||||||
end
|
end
|
||||||
end # - I2C 3
|
end # - I2C 3
|
||||||
|
|
Loading…
Reference in New Issue