root/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. asus_t100_matched
  2. asus_acpi_get_sensor_info
  3. acpi_i2c_check_resource
  4. inv_mpu_process_acpi_config
  5. inv_mpu_acpi_create_mux_client
  6. inv_mpu_acpi_delete_mux_client
  7. inv_mpu_acpi_create_mux_client
  8. inv_mpu_acpi_delete_mux_client

   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 
  15 enum inv_mpu_product_name {
  16         INV_MPU_NOT_MATCHED,
  17         INV_MPU_ASUS_T100TA,
  18 };
  19 
  20 static enum inv_mpu_product_name matched_product_name;
  21 
  22 static 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 
  29 static 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 
  43 static 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 
  84 static 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 
 100 static int inv_mpu_process_acpi_config(struct i2c_client *client,
 101                                        unsigned short *primary_addr,
 102                                        unsigned short *secondary_addr)
 103 {
 104         const struct acpi_device_id *id;
 105         struct acpi_device *adev;
 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         adev = ACPI_COMPANION(&client->dev);
 116         if (!adev)
 117                 return -ENODEV;
 118 
 119         ret = acpi_dev_get_resources(adev, &resources,
 120                                      acpi_i2c_check_resource, &i2c_addr);
 121         if (ret < 0)
 122                 return ret;
 123 
 124         acpi_dev_free_resource_list(&resources);
 125         *primary_addr = i2c_addr & 0x0000ffff;
 126         *secondary_addr = (i2c_addr & 0xffff0000) >> 16;
 127 
 128         return 0;
 129 }
 130 
 131 int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
 132 {
 133         struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
 134 
 135         st->mux_client = NULL;
 136         if (ACPI_HANDLE(&client->dev)) {
 137                 struct i2c_board_info info;
 138                 struct acpi_device *adev;
 139                 int ret = -1;
 140 
 141                 adev = ACPI_COMPANION(&client->dev);
 142                 memset(&info, 0, sizeof(info));
 143 
 144                 dmi_check_system(inv_mpu_dev_list);
 145                 switch (matched_product_name) {
 146                 case INV_MPU_ASUS_T100TA:
 147                         ret = asus_acpi_get_sensor_info(adev, client,
 148                                                         &info);
 149                         break;
 150                 /* Add more matched product processing here */
 151                 default:
 152                         break;
 153                 }
 154 
 155                 if (ret < 0) {
 156                         /* No matching DMI, so create device on INV6XX type */
 157                         unsigned short primary, secondary;
 158 
 159                         ret = inv_mpu_process_acpi_config(client, &primary,
 160                                                           &secondary);
 161                         if (!ret && secondary) {
 162                                 char *name;
 163 
 164                                 info.addr = secondary;
 165                                 strlcpy(info.type, dev_name(&adev->dev),
 166                                         sizeof(info.type));
 167                                 name = strchr(info.type, ':');
 168                                 if (name)
 169                                         *name = '\0';
 170                                 strlcat(info.type, "-client",
 171                                         sizeof(info.type));
 172                         } else
 173                                 return 0; /* no secondary addr, which is OK */
 174                 }
 175                 st->mux_client = i2c_new_device(st->muxc->adapter[0], &info);
 176                 if (!st->mux_client)
 177                         return -ENODEV;
 178         }
 179 
 180         return 0;
 181 }
 182 
 183 void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
 184 {
 185         struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
 186 
 187         i2c_unregister_device(st->mux_client);
 188 }
 189 #else
 190 
 191 #include "inv_mpu_iio.h"
 192 
 193 int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
 194 {
 195         return 0;
 196 }
 197 
 198 void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
 199 {
 200 }
 201 #endif

/* [<][>][^][v][top][bottom][index][help] */