brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · f7bce42 Raw
199 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * inv_mpu_acpi: ACPI processing for creating client devices4 * Copyright (c) 2015, Intel Corporation.5 */6 7#ifdef CONFIG_ACPI8 9#include <linux/kernel.h>10#include <linux/i2c.h>11#include <linux/dmi.h>12#include <linux/acpi.h>13#include "inv_mpu_iio.h"14 15enum inv_mpu_product_name {16	INV_MPU_NOT_MATCHED,17	INV_MPU_ASUS_T100TA,18};19 20static enum inv_mpu_product_name matched_product_name;21 22static int __init asus_t100_matched(const struct dmi_system_id *d)23{24	matched_product_name = INV_MPU_ASUS_T100TA;25 26	return 0;27}28 29static const struct dmi_system_id inv_mpu_dev_list[] = {30	{31	.callback = asus_t100_matched,32	.ident = "Asus Transformer Book T100",33		.matches = {34			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC"),35			DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),36			DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),37		},38	},39	/* Add more matching tables here..*/40	{}41};42 43static int asus_acpi_get_sensor_info(struct acpi_device *adev,44				     struct i2c_client *client,45				     struct i2c_board_info *info)46{47	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};48	int i;49	acpi_status status;50	union acpi_object *cpm;51	int ret;52 53	status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);54	if (ACPI_FAILURE(status))55		return -ENODEV;56 57	cpm = buffer.pointer;58	for (i = 0; i < cpm->package.count; ++i) {59		union acpi_object *elem;60		int j;61 62		elem = &cpm->package.elements[i];63		for (j = 0; j < elem->package.count; ++j) {64			union acpi_object *sub_elem;65 66			sub_elem = &elem->package.elements[j];67			if (sub_elem->type == ACPI_TYPE_STRING)68				strscpy(info->type, sub_elem->string.pointer,69					sizeof(info->type));70			else if (sub_elem->type == ACPI_TYPE_INTEGER) {71				if (sub_elem->integer.value != client->addr) {72					info->addr = sub_elem->integer.value;73					break; /* Not a MPU6500 primary */74				}75			}76		}77	}78	ret = cpm->package.count;79	kfree(buffer.pointer);80 81	return ret;82}83 84static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)85{86	struct acpi_resource_i2c_serialbus *sb;87	u32 *addr = data;88 89	if (i2c_acpi_get_i2c_resource(ares, &sb)) {90		if (*addr)91			*addr |= (sb->slave_address << 16);92		else93			*addr = sb->slave_address;94	}95 96	/* Tell the ACPI core that we already copied this address */97	return 1;98}99 100static int inv_mpu_process_acpi_config(struct i2c_client *client,101				       unsigned short *primary_addr,102				       unsigned short *secondary_addr)103{104	struct acpi_device *adev = ACPI_COMPANION(&client->dev);105	const struct acpi_device_id *id;106	u32 i2c_addr = 0;107	LIST_HEAD(resources);108	int ret;109 110	id = acpi_match_device(client->dev.driver->acpi_match_table,111			       &client->dev);112	if (!id)113		return -ENODEV;114 115	ret = acpi_dev_get_resources(adev, &resources,116				     acpi_i2c_check_resource, &i2c_addr);117	if (ret < 0)118		return ret;119 120	acpi_dev_free_resource_list(&resources);121	*primary_addr = i2c_addr & 0x0000ffff;122	*secondary_addr = (i2c_addr & 0xffff0000) >> 16;123 124	return 0;125}126 127int inv_mpu_acpi_create_mux_client(struct i2c_client *client)128{129	struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));130	struct acpi_device *adev = ACPI_COMPANION(&client->dev);131 132	st->mux_client = NULL;133	if (adev) {134		struct i2c_board_info info;135		struct i2c_client *mux_client;136		int ret = -1;137 138		memset(&info, 0, sizeof(info));139 140		dmi_check_system(inv_mpu_dev_list);141		switch (matched_product_name) {142		case INV_MPU_ASUS_T100TA:143			ret = asus_acpi_get_sensor_info(adev, client,144							&info);145			break;146		/* Add more matched product processing here */147		default:148			break;149		}150 151		if (ret < 0) {152			/* No matching DMI, so create device on INV6XX type */153			unsigned short primary, secondary;154 155			ret = inv_mpu_process_acpi_config(client, &primary,156							  &secondary);157			if (!ret && secondary) {158				char *name;159 160				info.addr = secondary;161				strscpy(info.type, dev_name(&adev->dev),162					sizeof(info.type));163				name = strchr(info.type, ':');164				if (name)165					*name = '\0';166				strlcat(info.type, "-client",167					sizeof(info.type));168			} else169				return 0; /* no secondary addr, which is OK */170		}171		mux_client = i2c_new_client_device(st->muxc->adapter[0], &info);172		if (IS_ERR(mux_client))173			return PTR_ERR(mux_client);174		st->mux_client = mux_client;175	}176 177	return 0;178}179 180void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)181{182	struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));183 184	i2c_unregister_device(st->mux_client);185}186#else187 188#include "inv_mpu_iio.h"189 190int inv_mpu_acpi_create_mux_client(struct i2c_client *client)191{192	return 0;193}194 195void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)196{197}198#endif199