/* * 79234640-9e10-4fea-a5c1-b5aa8b19756f * This _DSM GUID returns information about the GPIO lines mapped to a * discrete INT3472 device. Function number 1 returns a count of the GPIO * lines that are mapped. Subsequent functions return 32 bit ints encoding * information about the GPIO line, including its purpose.
*/ staticconst guid_t int3472_gpio_guid =
GUID_INIT(0x79234640, 0x9e10, 0x4fea,
0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
dev_warn(int3472->dev, "Too many GPIOs mapped\n"); return -EINVAL;
}
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
agpio, con_id, gpio_flags); if (ret) return ret;
int3472->n_sensor_gpios++;
return 0;
}
/* This should *really* only be used when there's no other way... */ staticstruct gpio_desc *
skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, struct acpi_resource_gpio *agpio, constchar *con_id, unsignedlong gpio_flags)
{ struct gpio_desc *desc; int ret;
/** * struct int3472_gpio_map - Map GPIOs to whatever is expected by the * sensor driver (as in DT bindings) * @hid: The ACPI HID of the device without the instance number e.g. INT347E * @type_from: The GPIO type from ACPI ?SDT * @type_to: The assigned GPIO type, typically same as @type_from * @con_id: The name of the GPIO for the device * @polarity_low: GPIO_ACTIVE_LOW true if the @polarity_low is true, * GPIO_ACTIVE_HIGH otherwise
*/ struct int3472_gpio_map { constchar *hid;
u8 type_from;
u8 type_to; bool polarity_low; constchar *con_id;
};
staticconststruct int3472_gpio_map int3472_gpio_map[] = { /* mt9m114 designs declare a powerdown pin which controls the regulators */
{ "INT33F0", INT3472_GPIO_TYPE_POWERDOWN, INT3472_GPIO_TYPE_POWER_ENABLE, false, "vdd" }, /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */
{ "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" },
};
for (i = 0; i < ARRAY_SIZE(int3472_gpio_map); i++) { /* * Map the firmware-provided GPIO to whatever a driver expects * (as in DT bindings). First check if the type matches with the * GPIO map, then further check that the device _HID matches.
*/ if (*type != int3472_gpio_map[i].type_from) continue;
if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL)) continue;
dev_dbg(int3472->dev, "mapping type 0x%02x pin to 0x%02x %s\n",
*type, int3472_gpio_map[i].type_to, int3472_gpio_map[i].con_id);
/** * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor * @ares: A pointer to a &struct acpi_resource * @data: A pointer to a &struct int3472_discrete_device * * This function handles GPIO resources that are against an INT3472 * ACPI device, by checking the value of the corresponding _DSM entry. * This will return a 32bit int, where the lowest byte represents the * function of the GPIO pin: * * 0x00 Reset * 0x01 Power down * 0x0b Power enable * 0x0c Clock enable * 0x0d Privacy LED * 0x13 Hotplug detect * * There are some known platform specific quirks where that does not quite * hold up; for example where a pin with type 0x01 (Power down) is mapped to * a sensor pin that performs a reset function or entries in _CRS and _DSM that * do not actually correspond to a physical connection. These will be handled * by the mapping sub-functions. * * GPIOs will either be mapped directly to the sensor device or else used * to create clocks and regulators via the usual frameworks. * * Return: * * 1 - Continue the loop without adding a copy of the resource to * * the list passed to acpi_dev_get_resources() * * 0 - Continue the loop after adding a copy of the resource to * * the list passed to acpi_dev_get_resources() * * -errno - Error, break loop
*/ staticint skl_int3472_handle_gpio_resources(struct acpi_resource *ares, void *data)
{ struct int3472_discrete_device *int3472 = data; struct acpi_resource_gpio *agpio;
u8 active_value, pin, type; union acpi_object *obj; struct gpio_desc *gpio; constchar *err_msg; constchar *con_id; unsignedlong gpio_flags; int ret;
if (!acpi_gpio_get_io_resource(ares, &agpio)) return 1;
/* * ngpios + 2 because the index of this _DSM function is 1-based and * the first function is just a count.
*/
obj = acpi_evaluate_dsm_typed(int3472->adev->handle,
&int3472_gpio_guid, 0x00,
int3472->ngpios + 2,
NULL, ACPI_TYPE_INTEGER);
if (!obj) {
dev_warn(int3472->dev, "No _DSM entry for GPIO pin %u\n",
agpio->pin_table[0]); return 1;
}
type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value);
pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value); /* Pin field is not really used under Windows and wraps around at 8 bits */ if (pin != (agpio->pin_table[0] & 0xff))
dev_dbg(int3472->dev, FW_BUG "%s %s pin number mismatch _DSM %d resource %d\n",
con_id, agpio->resource_source.string_ptr, pin, agpio->pin_table[0]);
active_value = FIELD_GET(INT3472_GPIO_DSM_SENSOR_ON_VAL, obj->integer.value); if (!active_value)
gpio_flags ^= GPIO_ACTIVE_LOW;
switch (type) { case INT3472_GPIO_TYPE_RESET: case INT3472_GPIO_TYPE_POWERDOWN: case INT3472_GPIO_TYPE_HOTPLUG_DETECT:
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, con_id, gpio_flags); if (ret)
err_msg = "Failed to map GPIO pin to sensor\n";
break; case INT3472_GPIO_TYPE_CLK_ENABLE: case INT3472_GPIO_TYPE_PRIVACY_LED: case INT3472_GPIO_TYPE_POWER_ENABLE: case INT3472_GPIO_TYPE_HANDSHAKE:
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); if (IS_ERR(gpio)) {
ret = PTR_ERR(gpio);
err_msg = "Failed to get GPIO\n"; break;
}
switch (type) { case INT3472_GPIO_TYPE_CLK_ENABLE:
ret = skl_int3472_register_gpio_clock(int3472, gpio); if (ret)
err_msg = "Failed to register clock\n";
break; case INT3472_GPIO_TYPE_PRIVACY_LED:
ret = skl_int3472_register_pled(int3472, gpio); if (ret)
err_msg = "Failed to register LED\n";
break; case INT3472_GPIO_TYPE_POWER_ENABLE:
ret = skl_int3472_register_regulator(int3472, gpio,
GPIO_REGULATOR_ENABLE_TIME,
con_id,
int3472->quirks.avdd_second_sensor); if (ret)
err_msg = "Failed to map power-enable to sensor\n";
break; case INT3472_GPIO_TYPE_HANDSHAKE: /* Setups using a handshake pin need 25 ms enable delay */
ret = skl_int3472_register_regulator(int3472, gpio,
25 * USEC_PER_MSEC,
con_id, NULL); if (ret)
err_msg = "Failed to map handshake to sensor\n";
break; default: /* Never reached */
ret = -EINVAL; break;
}
if (ret)
gpiod_put(gpio);
break; default:
dev_warn(int3472->dev, "GPIO type 0x%02x unknown; the sensor may not work\n",
type);
ret = 1; break;
}
int3472->ngpios++;
ACPI_FREE(obj);
if (ret < 0) return dev_err_probe(int3472->dev, ret, err_msg);
/* Tell acpi_dev_get_resources() to not make a copy of the resource */ return 1;
}
int int3472_discrete_parse_crs(struct int3472_discrete_device *int3472)
{
LIST_HEAD(resource_list); int ret;
skl_int3472_log_sensor_module_name(int3472);
ret = acpi_dev_get_resources(int3472->adev, &resource_list,
skl_int3472_handle_gpio_resources,
int3472); if (ret < 0) return ret;
acpi_dev_free_resource_list(&resource_list);
/* Register _DSM based clock (no-op if a GPIO clock was already registered) */
ret = skl_int3472_register_dsm_clock(int3472); if (ret < 0) return ret;
id = dmi_first_match(skl_int3472_discrete_quirks); if (id)
quirks = id->driver_data;
ret = skl_int3472_fill_cldb(adev, &cldb); if (ret) {
dev_err(&pdev->dev, "Couldn't fill CLDB structure\n"); return ret;
}
if (cldb.control_logic_type != 1) {
dev_err(&pdev->dev, "Unsupported control logic type %u\n",
cldb.control_logic_type); return -EINVAL;
}
/* Max num GPIOs we've seen plus a terminator */
int3472 = devm_kzalloc(&pdev->dev, struct_size(int3472, gpios.table,
INT3472_MAX_SENSOR_GPIOS + 1), GFP_KERNEL); if (!int3472) return -ENOMEM;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.