cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inv_mpu_acpi.c (4620B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * inv_mpu_acpi: ACPI processing for creating client devices
      4 * Copyright (c) 2015, Intel Corporation.
      5 */
      6
      7#ifdef CONFIG_ACPI
      8
      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				strlcpy(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		else
     93			*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				strlcpy(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			} else
    169				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#else
    187
    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#endif