162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux I2C core ACPI support code
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 Intel Corp, Author: Lan Tianyu <tianyu.lan@intel.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/acpi.h>
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/list.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "i2c-core.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct i2c_acpi_handler_data {
1962306a36Sopenharmony_ci	struct acpi_connection_info info;
2062306a36Sopenharmony_ci	struct i2c_adapter *adapter;
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct gsb_buffer {
2462306a36Sopenharmony_ci	u8	status;
2562306a36Sopenharmony_ci	u8	len;
2662306a36Sopenharmony_ci	union {
2762306a36Sopenharmony_ci		u16	wdata;
2862306a36Sopenharmony_ci		u8	bdata;
2962306a36Sopenharmony_ci		DECLARE_FLEX_ARRAY(u8, data);
3062306a36Sopenharmony_ci	};
3162306a36Sopenharmony_ci} __packed;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct i2c_acpi_lookup {
3462306a36Sopenharmony_ci	struct i2c_board_info *info;
3562306a36Sopenharmony_ci	acpi_handle adapter_handle;
3662306a36Sopenharmony_ci	acpi_handle device_handle;
3762306a36Sopenharmony_ci	acpi_handle search_handle;
3862306a36Sopenharmony_ci	int n;
3962306a36Sopenharmony_ci	int index;
4062306a36Sopenharmony_ci	u32 speed;
4162306a36Sopenharmony_ci	u32 min_speed;
4262306a36Sopenharmony_ci	u32 force_speed;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches
4762306a36Sopenharmony_ci * @ares:	ACPI resource
4862306a36Sopenharmony_ci * @i2c:	Pointer to I2cSerialBus resource will be returned here
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * Checks if the given ACPI resource is of type I2cSerialBus.
5162306a36Sopenharmony_ci * In this case, returns a pointer to it to the caller.
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * Returns true if resource type is of I2cSerialBus, otherwise false.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_cibool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
5662306a36Sopenharmony_ci			       struct acpi_resource_i2c_serialbus **i2c)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct acpi_resource_i2c_serialbus *sb;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
6162306a36Sopenharmony_ci		return false;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	sb = &ares->data.i2c_serial_bus;
6462306a36Sopenharmony_ci	if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
6562306a36Sopenharmony_ci		return false;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	*i2c = sb;
6862306a36Sopenharmony_ci	return true;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int i2c_acpi_resource_count(struct acpi_resource *ares, void *data)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct acpi_resource_i2c_serialbus *sb;
7562306a36Sopenharmony_ci	int *count = data;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (i2c_acpi_get_i2c_resource(ares, &sb))
7862306a36Sopenharmony_ci		*count = *count + 1;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return 1;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/**
8462306a36Sopenharmony_ci * i2c_acpi_client_count - Count the number of I2cSerialBus resources
8562306a36Sopenharmony_ci * @adev:	ACPI device
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * Returns the number of I2cSerialBus resources in the ACPI-device's
8862306a36Sopenharmony_ci * resource-list; or a negative error code.
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ciint i2c_acpi_client_count(struct acpi_device *adev)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int ret, count = 0;
9362306a36Sopenharmony_ci	LIST_HEAD(r);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &r, i2c_acpi_resource_count, &count);
9662306a36Sopenharmony_ci	if (ret < 0)
9762306a36Sopenharmony_ci		return ret;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	acpi_dev_free_resource_list(&r);
10062306a36Sopenharmony_ci	return count;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_client_count);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct i2c_acpi_lookup *lookup = data;
10762306a36Sopenharmony_ci	struct i2c_board_info *info = lookup->info;
10862306a36Sopenharmony_ci	struct acpi_resource_i2c_serialbus *sb;
10962306a36Sopenharmony_ci	acpi_status status;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb))
11262306a36Sopenharmony_ci		return 1;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (lookup->index != -1 && lookup->n++ != lookup->index)
11562306a36Sopenharmony_ci		return 1;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	status = acpi_get_handle(lookup->device_handle,
11862306a36Sopenharmony_ci				 sb->resource_source.string_ptr,
11962306a36Sopenharmony_ci				 &lookup->adapter_handle);
12062306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
12162306a36Sopenharmony_ci		return 1;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	info->addr = sb->slave_address;
12462306a36Sopenharmony_ci	lookup->speed = sb->connection_speed;
12562306a36Sopenharmony_ci	if (sb->access_mode == ACPI_I2C_10BIT_MODE)
12662306a36Sopenharmony_ci		info->flags |= I2C_CLIENT_TEN;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return 1;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct acpi_device_id i2c_acpi_ignored_device_ids[] = {
13262306a36Sopenharmony_ci	/*
13362306a36Sopenharmony_ci	 * ACPI video acpi_devices, which are handled by the acpi-video driver
13462306a36Sopenharmony_ci	 * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	{ ACPI_VIDEO_HID, 0 },
13762306a36Sopenharmony_ci	{}
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct i2c_acpi_irq_context {
14162306a36Sopenharmony_ci	int irq;
14262306a36Sopenharmony_ci	bool wake_capable;
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int i2c_acpi_do_lookup(struct acpi_device *adev,
14662306a36Sopenharmony_ci			      struct i2c_acpi_lookup *lookup)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct i2c_board_info *info = lookup->info;
14962306a36Sopenharmony_ci	struct list_head resource_list;
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (acpi_bus_get_status(adev))
15362306a36Sopenharmony_ci		return -EINVAL;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (!acpi_dev_ready_for_enumeration(adev))
15662306a36Sopenharmony_ci		return -ENODEV;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
15962306a36Sopenharmony_ci		return -ENODEV;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
16262306a36Sopenharmony_ci	lookup->device_handle = acpi_device_handle(adev);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* Look up for I2cSerialBus resource */
16562306a36Sopenharmony_ci	INIT_LIST_HEAD(&resource_list);
16662306a36Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &resource_list,
16762306a36Sopenharmony_ci				     i2c_acpi_fill_info, lookup);
16862306a36Sopenharmony_ci	acpi_dev_free_resource_list(&resource_list);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (ret < 0 || !info->addr)
17162306a36Sopenharmony_ci		return -EINVAL;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int i2c_acpi_add_irq_resource(struct acpi_resource *ares, void *data)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct i2c_acpi_irq_context *irq_ctx = data;
17962306a36Sopenharmony_ci	struct resource r;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (irq_ctx->irq > 0)
18262306a36Sopenharmony_ci		return 1;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (!acpi_dev_resource_interrupt(ares, 0, &r))
18562306a36Sopenharmony_ci		return 1;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	irq_ctx->irq = i2c_dev_irq_from_resources(&r, 1);
18862306a36Sopenharmony_ci	irq_ctx->wake_capable = r.flags & IORESOURCE_IRQ_WAKECAPABLE;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 1; /* No need to add resource to the list */
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/**
19462306a36Sopenharmony_ci * i2c_acpi_get_irq - get device IRQ number from ACPI
19562306a36Sopenharmony_ci * @client: Pointer to the I2C client device
19662306a36Sopenharmony_ci * @wake_capable: Set to true if the IRQ is wake capable
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * Find the IRQ number used by a specific client device.
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Return: The IRQ number or an error code.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_ciint i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&client->dev);
20562306a36Sopenharmony_ci	struct list_head resource_list;
20662306a36Sopenharmony_ci	struct i2c_acpi_irq_context irq_ctx = {
20762306a36Sopenharmony_ci		.irq = -ENOENT,
20862306a36Sopenharmony_ci	};
20962306a36Sopenharmony_ci	int ret;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	INIT_LIST_HEAD(&resource_list);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &resource_list,
21462306a36Sopenharmony_ci				     i2c_acpi_add_irq_resource, &irq_ctx);
21562306a36Sopenharmony_ci	if (ret < 0)
21662306a36Sopenharmony_ci		return ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	acpi_dev_free_resource_list(&resource_list);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (irq_ctx.irq == -ENOENT)
22162306a36Sopenharmony_ci		irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (irq_ctx.irq < 0)
22462306a36Sopenharmony_ci		return irq_ctx.irq;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (wake_capable)
22762306a36Sopenharmony_ci		*wake_capable = irq_ctx.wake_capable;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return irq_ctx.irq;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int i2c_acpi_get_info(struct acpi_device *adev,
23362306a36Sopenharmony_ci			     struct i2c_board_info *info,
23462306a36Sopenharmony_ci			     struct i2c_adapter *adapter,
23562306a36Sopenharmony_ci			     acpi_handle *adapter_handle)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct i2c_acpi_lookup lookup;
23862306a36Sopenharmony_ci	int ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	memset(&lookup, 0, sizeof(lookup));
24162306a36Sopenharmony_ci	lookup.info = info;
24262306a36Sopenharmony_ci	lookup.index = -1;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (acpi_device_enumerated(adev))
24562306a36Sopenharmony_ci		return -EINVAL;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	ret = i2c_acpi_do_lookup(adev, &lookup);
24862306a36Sopenharmony_ci	if (ret)
24962306a36Sopenharmony_ci		return ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (adapter) {
25262306a36Sopenharmony_ci		/* The adapter must match the one in I2cSerialBus() connector */
25362306a36Sopenharmony_ci		if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle)
25462306a36Sopenharmony_ci			return -ENODEV;
25562306a36Sopenharmony_ci	} else {
25662306a36Sopenharmony_ci		struct acpi_device *adapter_adev;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/* The adapter must be present */
25962306a36Sopenharmony_ci		adapter_adev = acpi_fetch_acpi_dev(lookup.adapter_handle);
26062306a36Sopenharmony_ci		if (!adapter_adev)
26162306a36Sopenharmony_ci			return -ENODEV;
26262306a36Sopenharmony_ci		if (acpi_bus_get_status(adapter_adev) ||
26362306a36Sopenharmony_ci		    !adapter_adev->status.present)
26462306a36Sopenharmony_ci			return -ENODEV;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	info->fwnode = acpi_fwnode_handle(adev);
26862306a36Sopenharmony_ci	if (adapter_handle)
26962306a36Sopenharmony_ci		*adapter_handle = lookup.adapter_handle;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	acpi_set_modalias(adev, dev_name(&adev->dev), info->type,
27262306a36Sopenharmony_ci			  sizeof(info->type));
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void i2c_acpi_register_device(struct i2c_adapter *adapter,
27862306a36Sopenharmony_ci				     struct acpi_device *adev,
27962306a36Sopenharmony_ci				     struct i2c_board_info *info)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	/*
28262306a36Sopenharmony_ci	 * Skip registration on boards where the ACPI tables are
28362306a36Sopenharmony_ci	 * known to contain bogus I2C devices.
28462306a36Sopenharmony_ci	 */
28562306a36Sopenharmony_ci	if (acpi_quirk_skip_i2c_client_enumeration(adev))
28662306a36Sopenharmony_ci		return;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	adev->power.flags.ignore_parent = true;
28962306a36Sopenharmony_ci	acpi_device_set_enumerated(adev);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (IS_ERR(i2c_new_client_device(adapter, info)))
29262306a36Sopenharmony_ci		adev->power.flags.ignore_parent = false;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level,
29662306a36Sopenharmony_ci				       void *data, void **return_value)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct i2c_adapter *adapter = data;
29962306a36Sopenharmony_ci	struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
30062306a36Sopenharmony_ci	struct i2c_board_info info;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!adev || i2c_acpi_get_info(adev, &info, adapter, NULL))
30362306a36Sopenharmony_ci		return AE_OK;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	i2c_acpi_register_device(adapter, adev, &info);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return AE_OK;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci#define I2C_ACPI_MAX_SCAN_DEPTH 32
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/**
31362306a36Sopenharmony_ci * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter
31462306a36Sopenharmony_ci * @adap: pointer to adapter
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Enumerate all I2C slave devices behind this adapter by walking the ACPI
31762306a36Sopenharmony_ci * namespace. When a device is found it will be added to the Linux device
31862306a36Sopenharmony_ci * model and bound to the corresponding ACPI handle.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_civoid i2c_acpi_register_devices(struct i2c_adapter *adap)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct acpi_device *adev;
32362306a36Sopenharmony_ci	acpi_status status;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (!has_acpi_companion(&adap->dev))
32662306a36Sopenharmony_ci		return;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
32962306a36Sopenharmony_ci				     I2C_ACPI_MAX_SCAN_DEPTH,
33062306a36Sopenharmony_ci				     i2c_acpi_add_device, NULL,
33162306a36Sopenharmony_ci				     adap, NULL);
33262306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
33362306a36Sopenharmony_ci		dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!adap->dev.parent)
33662306a36Sopenharmony_ci		return;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	adev = ACPI_COMPANION(adap->dev.parent);
33962306a36Sopenharmony_ci	if (!adev)
34062306a36Sopenharmony_ci		return;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	acpi_dev_clear_dependencies(adev);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
34662306a36Sopenharmony_ci	/*
34762306a36Sopenharmony_ci	 * These Silead touchscreen controllers only work at 400KHz, for
34862306a36Sopenharmony_ci	 * some reason they do not work at 100KHz. On some devices the ACPI
34962306a36Sopenharmony_ci	 * tables list another device at their bus as only being capable
35062306a36Sopenharmony_ci	 * of 100KHz, testing has shown that these other devices work fine
35162306a36Sopenharmony_ci	 * at 400KHz (as can be expected of any recent i2c hw) so we force
35262306a36Sopenharmony_ci	 * the speed of the bus to 400 KHz if a Silead device is present.
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	{ "MSSL1680", 0 },
35562306a36Sopenharmony_ci	{}
35662306a36Sopenharmony_ci};
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
35962306a36Sopenharmony_ci					   void *data, void **return_value)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct i2c_acpi_lookup *lookup = data;
36262306a36Sopenharmony_ci	struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (!adev || i2c_acpi_do_lookup(adev, lookup))
36562306a36Sopenharmony_ci		return AE_OK;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (lookup->search_handle != lookup->adapter_handle)
36862306a36Sopenharmony_ci		return AE_OK;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (lookup->speed <= lookup->min_speed)
37162306a36Sopenharmony_ci		lookup->min_speed = lookup->speed;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0)
37462306a36Sopenharmony_ci		lookup->force_speed = I2C_MAX_FAST_MODE_FREQ;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return AE_OK;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci/**
38062306a36Sopenharmony_ci * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI
38162306a36Sopenharmony_ci * @dev: The device owning the bus
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves
38462306a36Sopenharmony_ci * devices connected to this bus and use the speed of slowest device.
38562306a36Sopenharmony_ci *
38662306a36Sopenharmony_ci * Returns the speed in Hz or zero
38762306a36Sopenharmony_ci */
38862306a36Sopenharmony_ciu32 i2c_acpi_find_bus_speed(struct device *dev)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct i2c_acpi_lookup lookup;
39162306a36Sopenharmony_ci	struct i2c_board_info dummy;
39262306a36Sopenharmony_ci	acpi_status status;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (!has_acpi_companion(dev))
39562306a36Sopenharmony_ci		return 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	memset(&lookup, 0, sizeof(lookup));
39862306a36Sopenharmony_ci	lookup.search_handle = ACPI_HANDLE(dev);
39962306a36Sopenharmony_ci	lookup.min_speed = UINT_MAX;
40062306a36Sopenharmony_ci	lookup.info = &dummy;
40162306a36Sopenharmony_ci	lookup.index = -1;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
40462306a36Sopenharmony_ci				     I2C_ACPI_MAX_SCAN_DEPTH,
40562306a36Sopenharmony_ci				     i2c_acpi_lookup_speed, NULL,
40662306a36Sopenharmony_ci				     &lookup, NULL);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
40962306a36Sopenharmony_ci		dev_warn(dev, "unable to find I2C bus speed from ACPI\n");
41062306a36Sopenharmony_ci		return 0;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (lookup.force_speed) {
41462306a36Sopenharmony_ci		if (lookup.force_speed != lookup.min_speed)
41562306a36Sopenharmony_ci			dev_warn(dev, FW_BUG "DSDT uses known not-working I2C bus speed %d, forcing it to %d\n",
41662306a36Sopenharmony_ci				 lookup.min_speed, lookup.force_speed);
41762306a36Sopenharmony_ci		return lookup.force_speed;
41862306a36Sopenharmony_ci	} else if (lookup.min_speed != UINT_MAX) {
41962306a36Sopenharmony_ci		return lookup.min_speed;
42062306a36Sopenharmony_ci	} else {
42162306a36Sopenharmony_ci		return 0;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistruct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct i2c_adapter *adapter;
42962306a36Sopenharmony_ci	struct device *dev;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dev = bus_find_device(&i2c_bus_type, NULL, handle, device_match_acpi_handle);
43262306a36Sopenharmony_ci	if (!dev)
43362306a36Sopenharmony_ci		return NULL;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	adapter = i2c_verify_adapter(dev);
43662306a36Sopenharmony_ci	if (!adapter)
43762306a36Sopenharmony_ci		put_device(dev);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return adapter;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev));
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
44962306a36Sopenharmony_ci			   void *arg)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct acpi_device *adev = arg;
45262306a36Sopenharmony_ci	struct i2c_board_info info;
45362306a36Sopenharmony_ci	acpi_handle adapter_handle;
45462306a36Sopenharmony_ci	struct i2c_adapter *adapter;
45562306a36Sopenharmony_ci	struct i2c_client *client;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (value) {
45862306a36Sopenharmony_ci	case ACPI_RECONFIG_DEVICE_ADD:
45962306a36Sopenharmony_ci		if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle))
46062306a36Sopenharmony_ci			break;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		adapter = i2c_acpi_find_adapter_by_handle(adapter_handle);
46362306a36Sopenharmony_ci		if (!adapter)
46462306a36Sopenharmony_ci			break;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		i2c_acpi_register_device(adapter, adev, &info);
46762306a36Sopenharmony_ci		put_device(&adapter->dev);
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci	case ACPI_RECONFIG_DEVICE_REMOVE:
47062306a36Sopenharmony_ci		if (!acpi_device_enumerated(adev))
47162306a36Sopenharmony_ci			break;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		client = i2c_acpi_find_client_by_adev(adev);
47462306a36Sopenharmony_ci		if (!client)
47562306a36Sopenharmony_ci			break;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		i2c_unregister_device(client);
47862306a36Sopenharmony_ci		put_device(&client->dev);
47962306a36Sopenharmony_ci		break;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return NOTIFY_OK;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistruct notifier_block i2c_acpi_notifier = {
48662306a36Sopenharmony_ci	.notifier_call = i2c_acpi_notify,
48762306a36Sopenharmony_ci};
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource
49162306a36Sopenharmony_ci * @fwnode:  fwnode with the ACPI resources to get the client from
49262306a36Sopenharmony_ci * @index:   Index of ACPI resource to get
49362306a36Sopenharmony_ci * @info:    describes the I2C device; note this is modified (addr gets set)
49462306a36Sopenharmony_ci * Context: can sleep
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * By default the i2c subsys creates an i2c-client for the first I2cSerialBus
49762306a36Sopenharmony_ci * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus
49862306a36Sopenharmony_ci * resources, in that case this function can be used to create an i2c-client
49962306a36Sopenharmony_ci * for other I2cSerialBus resources in the Current Resource Settings table.
50062306a36Sopenharmony_ci *
50162306a36Sopenharmony_ci * Also see i2c_new_client_device, which this function calls to create the
50262306a36Sopenharmony_ci * i2c-client.
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * Returns a pointer to the new i2c-client, or error pointer in case of failure.
50562306a36Sopenharmony_ci * Specifically, -EPROBE_DEFER is returned if the adapter is not found.
50662306a36Sopenharmony_ci */
50762306a36Sopenharmony_cistruct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode,
50862306a36Sopenharmony_ci						 int index,
50962306a36Sopenharmony_ci						 struct i2c_board_info *info)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct i2c_acpi_lookup lookup;
51262306a36Sopenharmony_ci	struct i2c_adapter *adapter;
51362306a36Sopenharmony_ci	struct acpi_device *adev;
51462306a36Sopenharmony_ci	LIST_HEAD(resource_list);
51562306a36Sopenharmony_ci	int ret;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	adev = to_acpi_device_node(fwnode);
51862306a36Sopenharmony_ci	if (!adev)
51962306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	memset(&lookup, 0, sizeof(lookup));
52262306a36Sopenharmony_ci	lookup.info = info;
52362306a36Sopenharmony_ci	lookup.device_handle = acpi_device_handle(adev);
52462306a36Sopenharmony_ci	lookup.index = index;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &resource_list,
52762306a36Sopenharmony_ci				     i2c_acpi_fill_info, &lookup);
52862306a36Sopenharmony_ci	if (ret < 0)
52962306a36Sopenharmony_ci		return ERR_PTR(ret);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	acpi_dev_free_resource_list(&resource_list);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (!info->addr)
53462306a36Sopenharmony_ci		return ERR_PTR(-EADDRNOTAVAIL);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
53762306a36Sopenharmony_ci	if (!adapter)
53862306a36Sopenharmony_ci		return ERR_PTR(-EPROBE_DEFER);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return i2c_new_client_device(adapter, info);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cibool i2c_acpi_waive_d0_probe(struct device *dev)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct i2c_driver *driver = to_i2c_driver(dev->driver);
54762306a36Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE &&
55062306a36Sopenharmony_ci		adev && adev->power.state_for_enumeration >= adev->power.state;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci#ifdef CONFIG_ACPI_I2C_OPREGION
55562306a36Sopenharmony_cistatic int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
55662306a36Sopenharmony_ci		u8 cmd, u8 *data, u8 data_len)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	struct i2c_msg msgs[2];
56062306a36Sopenharmony_ci	int ret;
56162306a36Sopenharmony_ci	u8 *buffer;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	buffer = kzalloc(data_len, GFP_KERNEL);
56462306a36Sopenharmony_ci	if (!buffer)
56562306a36Sopenharmony_ci		return AE_NO_MEMORY;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	msgs[0].addr = client->addr;
56862306a36Sopenharmony_ci	msgs[0].flags = client->flags;
56962306a36Sopenharmony_ci	msgs[0].len = 1;
57062306a36Sopenharmony_ci	msgs[0].buf = &cmd;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	msgs[1].addr = client->addr;
57362306a36Sopenharmony_ci	msgs[1].flags = client->flags | I2C_M_RD;
57462306a36Sopenharmony_ci	msgs[1].len = data_len;
57562306a36Sopenharmony_ci	msgs[1].buf = buffer;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
57862306a36Sopenharmony_ci	if (ret < 0) {
57962306a36Sopenharmony_ci		/* Getting a NACK is unfortunately normal with some DSTDs */
58062306a36Sopenharmony_ci		if (ret == -EREMOTEIO)
58162306a36Sopenharmony_ci			dev_dbg(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",
58262306a36Sopenharmony_ci				data_len, client->addr, cmd, ret);
58362306a36Sopenharmony_ci		else
58462306a36Sopenharmony_ci			dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",
58562306a36Sopenharmony_ci				data_len, client->addr, cmd, ret);
58662306a36Sopenharmony_ci	/* 2 transfers must have completed successfully */
58762306a36Sopenharmony_ci	} else if (ret == 2) {
58862306a36Sopenharmony_ci		memcpy(data, buffer, data_len);
58962306a36Sopenharmony_ci		ret = 0;
59062306a36Sopenharmony_ci	} else {
59162306a36Sopenharmony_ci		ret = -EIO;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	kfree(buffer);
59562306a36Sopenharmony_ci	return ret;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
59962306a36Sopenharmony_ci		u8 cmd, u8 *data, u8 data_len)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	struct i2c_msg msgs[1];
60362306a36Sopenharmony_ci	u8 *buffer;
60462306a36Sopenharmony_ci	int ret = AE_OK;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	buffer = kzalloc(data_len + 1, GFP_KERNEL);
60762306a36Sopenharmony_ci	if (!buffer)
60862306a36Sopenharmony_ci		return AE_NO_MEMORY;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	buffer[0] = cmd;
61162306a36Sopenharmony_ci	memcpy(buffer + 1, data, data_len);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	msgs[0].addr = client->addr;
61462306a36Sopenharmony_ci	msgs[0].flags = client->flags;
61562306a36Sopenharmony_ci	msgs[0].len = data_len + 1;
61662306a36Sopenharmony_ci	msgs[0].buf = buffer;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	kfree(buffer);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (ret < 0) {
62362306a36Sopenharmony_ci		dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret);
62462306a36Sopenharmony_ci		return ret;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* 1 transfer must have completed successfully */
62862306a36Sopenharmony_ci	return (ret == 1) ? 0 : -EIO;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic acpi_status
63262306a36Sopenharmony_cii2c_acpi_space_handler(u32 function, acpi_physical_address command,
63362306a36Sopenharmony_ci			u32 bits, u64 *value64,
63462306a36Sopenharmony_ci			void *handler_context, void *region_context)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
63762306a36Sopenharmony_ci	struct i2c_acpi_handler_data *data = handler_context;
63862306a36Sopenharmony_ci	struct acpi_connection_info *info = &data->info;
63962306a36Sopenharmony_ci	struct acpi_resource_i2c_serialbus *sb;
64062306a36Sopenharmony_ci	struct i2c_adapter *adapter = data->adapter;
64162306a36Sopenharmony_ci	struct i2c_client *client;
64262306a36Sopenharmony_ci	struct acpi_resource *ares;
64362306a36Sopenharmony_ci	u32 accessor_type = function >> 16;
64462306a36Sopenharmony_ci	u8 action = function & ACPI_IO_MASK;
64562306a36Sopenharmony_ci	acpi_status ret;
64662306a36Sopenharmony_ci	int status;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
64962306a36Sopenharmony_ci	if (ACPI_FAILURE(ret))
65062306a36Sopenharmony_ci		return ret;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	client = kzalloc(sizeof(*client), GFP_KERNEL);
65362306a36Sopenharmony_ci	if (!client) {
65462306a36Sopenharmony_ci		ret = AE_NO_MEMORY;
65562306a36Sopenharmony_ci		goto err;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {
65962306a36Sopenharmony_ci		ret = AE_BAD_PARAMETER;
66062306a36Sopenharmony_ci		goto err;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	client->adapter = adapter;
66462306a36Sopenharmony_ci	client->addr = sb->slave_address;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (sb->access_mode == ACPI_I2C_10BIT_MODE)
66762306a36Sopenharmony_ci		client->flags |= I2C_CLIENT_TEN;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	switch (accessor_type) {
67062306a36Sopenharmony_ci	case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
67162306a36Sopenharmony_ci		if (action == ACPI_READ) {
67262306a36Sopenharmony_ci			status = i2c_smbus_read_byte(client);
67362306a36Sopenharmony_ci			if (status >= 0) {
67462306a36Sopenharmony_ci				gsb->bdata = status;
67562306a36Sopenharmony_ci				status = 0;
67662306a36Sopenharmony_ci			}
67762306a36Sopenharmony_ci		} else {
67862306a36Sopenharmony_ci			status = i2c_smbus_write_byte(client, gsb->bdata);
67962306a36Sopenharmony_ci		}
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	case ACPI_GSB_ACCESS_ATTRIB_BYTE:
68362306a36Sopenharmony_ci		if (action == ACPI_READ) {
68462306a36Sopenharmony_ci			status = i2c_smbus_read_byte_data(client, command);
68562306a36Sopenharmony_ci			if (status >= 0) {
68662306a36Sopenharmony_ci				gsb->bdata = status;
68762306a36Sopenharmony_ci				status = 0;
68862306a36Sopenharmony_ci			}
68962306a36Sopenharmony_ci		} else {
69062306a36Sopenharmony_ci			status = i2c_smbus_write_byte_data(client, command,
69162306a36Sopenharmony_ci					gsb->bdata);
69262306a36Sopenharmony_ci		}
69362306a36Sopenharmony_ci		break;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	case ACPI_GSB_ACCESS_ATTRIB_WORD:
69662306a36Sopenharmony_ci		if (action == ACPI_READ) {
69762306a36Sopenharmony_ci			status = i2c_smbus_read_word_data(client, command);
69862306a36Sopenharmony_ci			if (status >= 0) {
69962306a36Sopenharmony_ci				gsb->wdata = status;
70062306a36Sopenharmony_ci				status = 0;
70162306a36Sopenharmony_ci			}
70262306a36Sopenharmony_ci		} else {
70362306a36Sopenharmony_ci			status = i2c_smbus_write_word_data(client, command,
70462306a36Sopenharmony_ci					gsb->wdata);
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
70962306a36Sopenharmony_ci		if (action == ACPI_READ) {
71062306a36Sopenharmony_ci			status = i2c_smbus_read_block_data(client, command,
71162306a36Sopenharmony_ci					gsb->data);
71262306a36Sopenharmony_ci			if (status >= 0) {
71362306a36Sopenharmony_ci				gsb->len = status;
71462306a36Sopenharmony_ci				status = 0;
71562306a36Sopenharmony_ci			}
71662306a36Sopenharmony_ci		} else {
71762306a36Sopenharmony_ci			status = i2c_smbus_write_block_data(client, command,
71862306a36Sopenharmony_ci					gsb->len, gsb->data);
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci		break;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
72362306a36Sopenharmony_ci		if (action == ACPI_READ) {
72462306a36Sopenharmony_ci			status = acpi_gsb_i2c_read_bytes(client, command,
72562306a36Sopenharmony_ci					gsb->data, info->access_length);
72662306a36Sopenharmony_ci		} else {
72762306a36Sopenharmony_ci			status = acpi_gsb_i2c_write_bytes(client, command,
72862306a36Sopenharmony_ci					gsb->data, info->access_length);
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci		break;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	default:
73362306a36Sopenharmony_ci		dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
73462306a36Sopenharmony_ci			 accessor_type, client->addr);
73562306a36Sopenharmony_ci		ret = AE_BAD_PARAMETER;
73662306a36Sopenharmony_ci		goto err;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	gsb->status = status;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci err:
74262306a36Sopenharmony_ci	kfree(client);
74362306a36Sopenharmony_ci	ACPI_FREE(ares);
74462306a36Sopenharmony_ci	return ret;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ciint i2c_acpi_install_space_handler(struct i2c_adapter *adapter)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	acpi_handle handle;
75162306a36Sopenharmony_ci	struct i2c_acpi_handler_data *data;
75262306a36Sopenharmony_ci	acpi_status status;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (!adapter->dev.parent)
75562306a36Sopenharmony_ci		return -ENODEV;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	handle = ACPI_HANDLE(adapter->dev.parent);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (!handle)
76062306a36Sopenharmony_ci		return -ENODEV;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	data = kzalloc(sizeof(struct i2c_acpi_handler_data),
76362306a36Sopenharmony_ci			    GFP_KERNEL);
76462306a36Sopenharmony_ci	if (!data)
76562306a36Sopenharmony_ci		return -ENOMEM;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	data->adapter = adapter;
76862306a36Sopenharmony_ci	status = acpi_bus_attach_private_data(handle, (void *)data);
76962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
77062306a36Sopenharmony_ci		kfree(data);
77162306a36Sopenharmony_ci		return -ENOMEM;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	status = acpi_install_address_space_handler(handle,
77562306a36Sopenharmony_ci				ACPI_ADR_SPACE_GSBUS,
77662306a36Sopenharmony_ci				&i2c_acpi_space_handler,
77762306a36Sopenharmony_ci				NULL,
77862306a36Sopenharmony_ci				data);
77962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
78062306a36Sopenharmony_ci		dev_err(&adapter->dev, "Error installing i2c space handler\n");
78162306a36Sopenharmony_ci		acpi_bus_detach_private_data(handle);
78262306a36Sopenharmony_ci		kfree(data);
78362306a36Sopenharmony_ci		return -ENOMEM;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return 0;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_civoid i2c_acpi_remove_space_handler(struct i2c_adapter *adapter)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	acpi_handle handle;
79262306a36Sopenharmony_ci	struct i2c_acpi_handler_data *data;
79362306a36Sopenharmony_ci	acpi_status status;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (!adapter->dev.parent)
79662306a36Sopenharmony_ci		return;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	handle = ACPI_HANDLE(adapter->dev.parent);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (!handle)
80162306a36Sopenharmony_ci		return;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	acpi_remove_address_space_handler(handle,
80462306a36Sopenharmony_ci				ACPI_ADR_SPACE_GSBUS,
80562306a36Sopenharmony_ci				&i2c_acpi_space_handler);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	status = acpi_bus_get_private_data(handle, (void **)&data);
80862306a36Sopenharmony_ci	if (ACPI_SUCCESS(status))
80962306a36Sopenharmony_ci		kfree(data);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	acpi_bus_detach_private_data(handle);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci#endif /* CONFIG_ACPI_I2C_OPREGION */
814