1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021, Intel Corporation. 4 */ 5 6 #include <linux/acpi.h> 7 #include <linux/kobject.h> 8 #include <linux/platform_device.h> 9 #include <linux/sysfs.h> 10 #include "intel_sar.h" 11 12 /** 13 * get_int_value: Retrieve integer values from ACPI Object 14 * @obj: acpi_object pointer which has the integer value 15 * @out: output pointer will get integer value 16 * 17 * Function is used to retrieve integer value from acpi object. 18 * 19 * Return: 20 * * 0 on success 21 * * -EIO if there is an issue in acpi_object passed. 22 */ 23 static int get_int_value(union acpi_object *obj, int *out) 24 { 25 if (!obj || obj->type != ACPI_TYPE_INTEGER) 26 return -EIO; 27 *out = (int)obj->integer.value; 28 return 0; 29 } 30 31 /** 32 * update_sar_data: sar data is updated based on regulatory mode 33 * @context: pointer to driver context structure 34 * 35 * sar_data is updated based on regulatory value 36 * context->reg_value will never exceed MAX_REGULATORY 37 */ 38 static void update_sar_data(struct wwan_sar_context *context) 39 { 40 struct wwan_device_mode_configuration *config = 41 &context->config_data[context->reg_value]; 42 43 if (config->device_mode_info && 44 context->sar_data.device_mode < config->total_dev_mode) { 45 struct wwan_device_mode_info *dev_mode = 46 &config->device_mode_info[context->sar_data.device_mode]; 47 48 context->sar_data.antennatable_index = dev_mode->antennatable_index; 49 context->sar_data.bandtable_index = dev_mode->bandtable_index; 50 context->sar_data.sartable_index = dev_mode->sartable_index; 51 } 52 } 53 54 /** 55 * parse_package: parse acpi package for retrieving SAR information 56 * @context: pointer to driver context structure 57 * @item : acpi_object pointer 58 * 59 * Given acpi_object is iterated to retrieve information for each device mode. 60 * If a given package corresponding to a specific device mode is faulty, it is 61 * skipped and the specific entry in context structure will have the default value 62 * of zero. Decoding of subsequent device modes is realized by having "continue" 63 * statements in the for loop on encountering error in parsing given device mode. 64 * 65 * Return: 66 * AE_OK if success 67 * AE_ERROR on error 68 */ 69 static acpi_status parse_package(struct wwan_sar_context *context, union acpi_object *item) 70 { 71 struct wwan_device_mode_configuration *data; 72 int value, itr, reg; 73 union acpi_object *num; 74 75 num = &item->package.elements[0]; 76 if (get_int_value(num, &value) || value < 0 || value >= MAX_REGULATORY) 77 return AE_ERROR; 78 79 reg = value; 80 81 data = &context->config_data[reg]; 82 if (data->total_dev_mode > MAX_DEV_MODES || data->total_dev_mode == 0 || 83 item->package.count <= data->total_dev_mode) 84 return AE_ERROR; 85 86 data->device_mode_info = kmalloc_array(data->total_dev_mode, 87 sizeof(struct wwan_device_mode_info), GFP_KERNEL); 88 if (!data->device_mode_info) 89 return AE_ERROR; 90 91 for (itr = 0; itr < data->total_dev_mode; itr++) { 92 struct wwan_device_mode_info temp = { 0 }; 93 94 num = &item->package.elements[itr + 1]; 95 if (num->type != ACPI_TYPE_PACKAGE || num->package.count < TOTAL_DATA) 96 continue; 97 if (get_int_value(&num->package.elements[0], &temp.device_mode)) 98 continue; 99 if (get_int_value(&num->package.elements[1], &temp.bandtable_index)) 100 continue; 101 if (get_int_value(&num->package.elements[2], &temp.antennatable_index)) 102 continue; 103 if (get_int_value(&num->package.elements[3], &temp.sartable_index)) 104 continue; 105 data->device_mode_info[itr] = temp; 106 } 107 return AE_OK; 108 } 109 110 /** 111 * sar_get_device_mode: Extraction of information from BIOS via DSM calls 112 * @device: ACPI device for which to retrieve the data 113 * 114 * Retrieve the current device mode information from the BIOS. 115 * 116 * Return: 117 * AE_OK on success 118 * AE_ERROR on error 119 */ 120 static acpi_status sar_get_device_mode(struct platform_device *device) 121 { 122 struct wwan_sar_context *context = dev_get_drvdata(&device->dev); 123 acpi_status status = AE_OK; 124 union acpi_object *out; 125 u32 rev = 0; 126 int value; 127 128 out = acpi_evaluate_dsm(context->handle, &context->guid, rev, 129 COMMAND_ID_DEV_MODE, NULL); 130 if (get_int_value(out, &value)) { 131 dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE); 132 status = AE_ERROR; 133 goto dev_mode_error; 134 } 135 context->sar_data.device_mode = value; 136 update_sar_data(context); 137 sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME); 138 139 dev_mode_error: 140 ACPI_FREE(out); 141 return status; 142 } 143 144 static const struct acpi_device_id sar_device_ids[] = { 145 { "INTC1092", 0}, 146 {} 147 }; 148 MODULE_DEVICE_TABLE(acpi, sar_device_ids); 149 150 static ssize_t intc_data_show(struct device *dev, struct device_attribute *attr, char *buf) 151 { 152 struct wwan_sar_context *context = dev_get_drvdata(dev); 153 154 return sysfs_emit(buf, "%d %d %d %d\n", context->sar_data.device_mode, 155 context->sar_data.bandtable_index, 156 context->sar_data.antennatable_index, 157 context->sar_data.sartable_index); 158 } 159 static DEVICE_ATTR_RO(intc_data); 160 161 static ssize_t intc_reg_show(struct device *dev, struct device_attribute *attr, char *buf) 162 { 163 struct wwan_sar_context *context = dev_get_drvdata(dev); 164 165 return sysfs_emit(buf, "%d\n", context->reg_value); 166 } 167 168 static ssize_t intc_reg_store(struct device *dev, struct device_attribute *attr, 169 const char *buf, size_t count) 170 { 171 struct wwan_sar_context *context = dev_get_drvdata(dev); 172 unsigned int value; 173 int read; 174 175 if (!count) 176 return -EINVAL; 177 read = kstrtouint(buf, 10, &value); 178 if (read < 0) 179 return read; 180 if (value >= MAX_REGULATORY) 181 return -EOVERFLOW; 182 context->reg_value = value; 183 update_sar_data(context); 184 sysfs_notify(&dev->kobj, NULL, SYSFS_DATANAME); 185 return count; 186 } 187 static DEVICE_ATTR_RW(intc_reg); 188 189 static struct attribute *intcsar_attrs[] = { 190 &dev_attr_intc_data.attr, 191 &dev_attr_intc_reg.attr, 192 NULL 193 }; 194 195 static struct attribute_group intcsar_group = { 196 .attrs = intcsar_attrs, 197 }; 198 199 static void sar_notify(acpi_handle handle, u32 event, void *data) 200 { 201 struct platform_device *device = data; 202 203 if (event == SAR_EVENT) { 204 if (sar_get_device_mode(device) != AE_OK) 205 dev_err(&device->dev, "sar_get_device_mode error"); 206 } 207 } 208 209 static void sar_get_data(int reg, struct wwan_sar_context *context) 210 { 211 union acpi_object *out, req; 212 u32 rev = 0; 213 214 req.type = ACPI_TYPE_INTEGER; 215 req.integer.value = reg; 216 out = acpi_evaluate_dsm(context->handle, &context->guid, rev, 217 COMMAND_ID_CONFIG_TABLE, &req); 218 if (!out) 219 return; 220 if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 && 221 out->package.elements[0].type == ACPI_TYPE_INTEGER && 222 out->package.elements[1].type == ACPI_TYPE_INTEGER && 223 out->package.elements[2].type == ACPI_TYPE_PACKAGE && 224 out->package.elements[2].package.count > 0) { 225 context->config_data[reg].version = out->package.elements[0].integer.value; 226 context->config_data[reg].total_dev_mode = 227 out->package.elements[1].integer.value; 228 if (context->config_data[reg].total_dev_mode <= 0 || 229 context->config_data[reg].total_dev_mode > MAX_DEV_MODES) { 230 ACPI_FREE(out); 231 return; 232 } 233 parse_package(context, &out->package.elements[2]); 234 } 235 ACPI_FREE(out); 236 } 237 238 static int sar_probe(struct platform_device *device) 239 { 240 struct wwan_sar_context *context; 241 int reg; 242 int result; 243 244 context = kzalloc(sizeof(*context), GFP_KERNEL); 245 if (!context) 246 return -ENOMEM; 247 248 context->sar_device = device; 249 context->handle = ACPI_HANDLE(&device->dev); 250 dev_set_drvdata(&device->dev, context); 251 252 result = guid_parse(SAR_DSM_UUID, &context->guid); 253 if (result) { 254 dev_err(&device->dev, "SAR UUID parse error: %d\n", result); 255 goto r_free; 256 } 257 258 for (reg = 0; reg < MAX_REGULATORY; reg++) 259 sar_get_data(reg, context); 260 261 if (sar_get_device_mode(device) != AE_OK) { 262 dev_err(&device->dev, "Failed to get device mode\n"); 263 result = -EIO; 264 goto r_free; 265 } 266 267 result = sysfs_create_group(&device->dev.kobj, &intcsar_group); 268 if (result) { 269 dev_err(&device->dev, "sysfs creation failed\n"); 270 goto r_free; 271 } 272 273 if (acpi_install_notify_handler(ACPI_HANDLE(&device->dev), ACPI_DEVICE_NOTIFY, 274 sar_notify, (void *)device) != AE_OK) { 275 dev_err(&device->dev, "Failed acpi_install_notify_handler\n"); 276 result = -EIO; 277 goto r_sys; 278 } 279 return 0; 280 281 r_sys: 282 sysfs_remove_group(&device->dev.kobj, &intcsar_group); 283 r_free: 284 kfree(context); 285 return result; 286 } 287 288 static int sar_remove(struct platform_device *device) 289 { 290 struct wwan_sar_context *context = dev_get_drvdata(&device->dev); 291 int reg; 292 293 acpi_remove_notify_handler(ACPI_HANDLE(&device->dev), 294 ACPI_DEVICE_NOTIFY, sar_notify); 295 sysfs_remove_group(&device->dev.kobj, &intcsar_group); 296 for (reg = 0; reg < MAX_REGULATORY; reg++) 297 kfree(context->config_data[reg].device_mode_info); 298 299 kfree(context); 300 return 0; 301 } 302 303 static struct platform_driver sar_driver = { 304 .probe = sar_probe, 305 .remove = sar_remove, 306 .driver = { 307 .name = DRVNAME, 308 .owner = THIS_MODULE, 309 .acpi_match_table = ACPI_PTR(sar_device_ids) 310 } 311 }; 312 module_platform_driver(sar_driver); 313 314 MODULE_LICENSE("GPL v2"); 315 MODULE_DESCRIPTION("Platform device driver for INTEL MODEM BIOS SAR"); 316 MODULE_AUTHOR("Shravan S <s.shravan@intel.com>"); 317