1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space 4 * 5 * Copyright (C) 2014 Google, Inc. 6 */ 7 8 #include <linux/mfd/core.h> 9 #include <linux/mfd/cros_ec.h> 10 #include <linux/module.h> 11 #include <linux/mod_devicetable.h> 12 #include <linux/of_platform.h> 13 #include <linux/platform_device.h> 14 #include <linux/platform_data/cros_ec_chardev.h> 15 #include <linux/platform_data/cros_ec_commands.h> 16 #include <linux/platform_data/cros_ec_proto.h> 17 #include <linux/slab.h> 18 19 #define DRV_NAME "cros-ec-dev" 20 21 static struct class cros_class = { 22 .owner = THIS_MODULE, 23 .name = "chromeos", 24 }; 25 26 /** 27 * cros_feature_to_name - CrOS feature id to name/short description. 28 * @id: The feature identifier. 29 * @name: Device name associated with the feature id. 30 * @desc: Short name that will be displayed. 31 */ 32 struct cros_feature_to_name { 33 unsigned int id; 34 const char *name; 35 const char *desc; 36 }; 37 38 /** 39 * cros_feature_to_cells - CrOS feature id to mfd cells association. 40 * @id: The feature identifier. 41 * @mfd_cells: Pointer to the array of mfd cells that needs to be added. 42 * @num_cells: Number of mfd cells into the array. 43 */ 44 struct cros_feature_to_cells { 45 unsigned int id; 46 const struct mfd_cell *mfd_cells; 47 unsigned int num_cells; 48 }; 49 50 static const struct cros_feature_to_name cros_mcu_devices[] = { 51 { 52 .id = EC_FEATURE_FINGERPRINT, 53 .name = CROS_EC_DEV_FP_NAME, 54 .desc = "Fingerprint", 55 }, 56 { 57 .id = EC_FEATURE_ISH, 58 .name = CROS_EC_DEV_ISH_NAME, 59 .desc = "Integrated Sensor Hub", 60 }, 61 { 62 .id = EC_FEATURE_SCP, 63 .name = CROS_EC_DEV_SCP_NAME, 64 .desc = "System Control Processor", 65 }, 66 { 67 .id = EC_FEATURE_TOUCHPAD, 68 .name = CROS_EC_DEV_TP_NAME, 69 .desc = "Touchpad", 70 }, 71 }; 72 73 static const struct mfd_cell cros_ec_cec_cells[] = { 74 { .name = "cros-ec-cec", }, 75 }; 76 77 static const struct mfd_cell cros_ec_rtc_cells[] = { 78 { .name = "cros-ec-rtc", }, 79 }; 80 81 static const struct mfd_cell cros_usbpd_charger_cells[] = { 82 { .name = "cros-usbpd-charger", }, 83 { .name = "cros-usbpd-logger", }, 84 }; 85 86 static const struct cros_feature_to_cells cros_subdevices[] = { 87 { 88 .id = EC_FEATURE_CEC, 89 .mfd_cells = cros_ec_cec_cells, 90 .num_cells = ARRAY_SIZE(cros_ec_cec_cells), 91 }, 92 { 93 .id = EC_FEATURE_RTC, 94 .mfd_cells = cros_ec_rtc_cells, 95 .num_cells = ARRAY_SIZE(cros_ec_rtc_cells), 96 }, 97 { 98 .id = EC_FEATURE_USB_PD, 99 .mfd_cells = cros_usbpd_charger_cells, 100 .num_cells = ARRAY_SIZE(cros_usbpd_charger_cells), 101 }, 102 }; 103 104 static const struct mfd_cell cros_ec_platform_cells[] = { 105 { .name = "cros-ec-chardev", }, 106 { .name = "cros-ec-debugfs", }, 107 { .name = "cros-ec-lightbar", }, 108 { .name = "cros-ec-sysfs", }, 109 }; 110 111 static const struct mfd_cell cros_ec_vbc_cells[] = { 112 { .name = "cros-ec-vbc", } 113 }; 114 115 static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) 116 { 117 struct cros_ec_command *msg; 118 int ret; 119 120 if (ec->features[0] == -1U && ec->features[1] == -1U) { 121 /* features bitmap not read yet */ 122 msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); 123 if (!msg) 124 return -ENOMEM; 125 126 msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset; 127 msg->insize = sizeof(ec->features); 128 129 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); 130 if (ret < 0) { 131 dev_warn(ec->dev, "cannot get EC features: %d/%d\n", 132 ret, msg->result); 133 memset(ec->features, 0, sizeof(ec->features)); 134 } else { 135 memcpy(ec->features, msg->data, sizeof(ec->features)); 136 } 137 138 dev_dbg(ec->dev, "EC features %08x %08x\n", 139 ec->features[0], ec->features[1]); 140 141 kfree(msg); 142 } 143 144 return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); 145 } 146 147 static void cros_ec_class_release(struct device *dev) 148 { 149 kfree(to_cros_ec_dev(dev)); 150 } 151 152 static void cros_ec_sensors_register(struct cros_ec_dev *ec) 153 { 154 /* 155 * Issue a command to get the number of sensor reported. 156 * Build an array of sensors driver and register them all. 157 */ 158 int ret, i, id, sensor_num; 159 struct mfd_cell *sensor_cells; 160 struct cros_ec_sensor_platform *sensor_platforms; 161 int sensor_type[MOTIONSENSE_TYPE_MAX]; 162 struct ec_params_motion_sense *params; 163 struct ec_response_motion_sense *resp; 164 struct cros_ec_command *msg; 165 166 msg = kzalloc(sizeof(struct cros_ec_command) + 167 max(sizeof(*params), sizeof(*resp)), GFP_KERNEL); 168 if (msg == NULL) 169 return; 170 171 msg->version = 2; 172 msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; 173 msg->outsize = sizeof(*params); 174 msg->insize = sizeof(*resp); 175 176 params = (struct ec_params_motion_sense *)msg->data; 177 params->cmd = MOTIONSENSE_CMD_DUMP; 178 179 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); 180 if (ret < 0) { 181 dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n", 182 ret, msg->result); 183 goto error; 184 } 185 186 resp = (struct ec_response_motion_sense *)msg->data; 187 sensor_num = resp->dump.sensor_count; 188 /* 189 * Allocate 2 extra sensors if lid angle sensor and/or FIFO are needed. 190 */ 191 sensor_cells = kcalloc(sensor_num + 2, sizeof(struct mfd_cell), 192 GFP_KERNEL); 193 if (sensor_cells == NULL) 194 goto error; 195 196 sensor_platforms = kcalloc(sensor_num, 197 sizeof(struct cros_ec_sensor_platform), 198 GFP_KERNEL); 199 if (sensor_platforms == NULL) 200 goto error_platforms; 201 202 memset(sensor_type, 0, sizeof(sensor_type)); 203 id = 0; 204 for (i = 0; i < sensor_num; i++) { 205 params->cmd = MOTIONSENSE_CMD_INFO; 206 params->info.sensor_num = i; 207 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); 208 if (ret < 0) { 209 dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n", 210 i, ret, msg->result); 211 continue; 212 } 213 switch (resp->info.type) { 214 case MOTIONSENSE_TYPE_ACCEL: 215 sensor_cells[id].name = "cros-ec-accel"; 216 break; 217 case MOTIONSENSE_TYPE_BARO: 218 sensor_cells[id].name = "cros-ec-baro"; 219 break; 220 case MOTIONSENSE_TYPE_GYRO: 221 sensor_cells[id].name = "cros-ec-gyro"; 222 break; 223 case MOTIONSENSE_TYPE_MAG: 224 sensor_cells[id].name = "cros-ec-mag"; 225 break; 226 case MOTIONSENSE_TYPE_PROX: 227 sensor_cells[id].name = "cros-ec-prox"; 228 break; 229 case MOTIONSENSE_TYPE_LIGHT: 230 sensor_cells[id].name = "cros-ec-light"; 231 break; 232 case MOTIONSENSE_TYPE_ACTIVITY: 233 sensor_cells[id].name = "cros-ec-activity"; 234 break; 235 default: 236 dev_warn(ec->dev, "unknown type %d\n", resp->info.type); 237 continue; 238 } 239 sensor_platforms[id].sensor_num = i; 240 sensor_cells[id].id = sensor_type[resp->info.type]; 241 sensor_cells[id].platform_data = &sensor_platforms[id]; 242 sensor_cells[id].pdata_size = 243 sizeof(struct cros_ec_sensor_platform); 244 245 sensor_type[resp->info.type]++; 246 id++; 247 } 248 249 if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) 250 ec->has_kb_wake_angle = true; 251 252 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { 253 sensor_cells[id].name = "cros-ec-ring"; 254 id++; 255 } 256 if (cros_ec_check_features(ec, 257 EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) { 258 sensor_cells[id].name = "cros-ec-lid-angle"; 259 id++; 260 } 261 262 ret = mfd_add_devices(ec->dev, 0, sensor_cells, id, 263 NULL, 0, NULL); 264 if (ret) 265 dev_err(ec->dev, "failed to add EC sensors\n"); 266 267 kfree(sensor_platforms); 268 error_platforms: 269 kfree(sensor_cells); 270 error: 271 kfree(msg); 272 } 273 274 static struct cros_ec_sensor_platform sensor_platforms[] = { 275 { .sensor_num = 0 }, 276 { .sensor_num = 1 } 277 }; 278 279 static const struct mfd_cell cros_ec_accel_legacy_cells[] = { 280 { 281 .name = "cros-ec-accel-legacy", 282 .platform_data = &sensor_platforms[0], 283 .pdata_size = sizeof(struct cros_ec_sensor_platform), 284 }, 285 { 286 .name = "cros-ec-accel-legacy", 287 .platform_data = &sensor_platforms[1], 288 .pdata_size = sizeof(struct cros_ec_sensor_platform), 289 } 290 }; 291 292 static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec) 293 { 294 struct cros_ec_device *ec_dev = ec->ec_dev; 295 u8 status; 296 int ret; 297 298 /* 299 * ECs that need legacy support are the main EC, directly connected to 300 * the AP. 301 */ 302 if (ec->cmd_offset != 0) 303 return; 304 305 /* 306 * Check if EC supports direct memory reads and if EC has 307 * accelerometers. 308 */ 309 if (ec_dev->cmd_readmem) { 310 ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, 1, 311 &status); 312 if (ret < 0) { 313 dev_warn(ec->dev, "EC direct read error.\n"); 314 return; 315 } 316 317 /* Check if EC has accelerometers. */ 318 if (!(status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) { 319 dev_info(ec->dev, "EC does not have accelerometers.\n"); 320 return; 321 } 322 } 323 324 /* 325 * The device may still support accelerometers: 326 * it would be an older ARM based device that do not suppor the 327 * EC_CMD_GET_FEATURES command. 328 * 329 * Register 2 accelerometers, we will fail in the IIO driver if there 330 * are no sensors. 331 */ 332 ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells, 333 ARRAY_SIZE(cros_ec_accel_legacy_cells)); 334 if (ret) 335 dev_err(ec_dev->dev, "failed to add EC sensors\n"); 336 } 337 338 static int ec_device_probe(struct platform_device *pdev) 339 { 340 int retval = -ENOMEM; 341 struct device_node *node; 342 struct device *dev = &pdev->dev; 343 struct cros_ec_platform *ec_platform = dev_get_platdata(dev); 344 struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); 345 int i; 346 347 if (!ec) 348 return retval; 349 350 dev_set_drvdata(dev, ec); 351 ec->ec_dev = dev_get_drvdata(dev->parent); 352 ec->dev = dev; 353 ec->cmd_offset = ec_platform->cmd_offset; 354 ec->features[0] = -1U; /* Not cached yet */ 355 ec->features[1] = -1U; /* Not cached yet */ 356 device_initialize(&ec->class_dev); 357 358 for (i = 0; i < ARRAY_SIZE(cros_mcu_devices); i++) { 359 /* 360 * Check whether this is actually a dedicated MCU rather 361 * than an standard EC. 362 */ 363 if (cros_ec_check_features(ec, cros_mcu_devices[i].id)) { 364 dev_info(dev, "CrOS %s MCU detected\n", 365 cros_mcu_devices[i].desc); 366 /* 367 * Help userspace differentiating ECs from other MCU, 368 * regardless of the probing order. 369 */ 370 ec_platform->ec_name = cros_mcu_devices[i].name; 371 break; 372 } 373 } 374 375 /* 376 * Add the class device 377 */ 378 ec->class_dev.class = &cros_class; 379 ec->class_dev.parent = dev; 380 ec->class_dev.release = cros_ec_class_release; 381 382 retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); 383 if (retval) { 384 dev_err(dev, "dev_set_name failed => %d\n", retval); 385 goto failed; 386 } 387 388 retval = device_add(&ec->class_dev); 389 if (retval) 390 goto failed; 391 392 /* check whether this EC is a sensor hub. */ 393 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) 394 cros_ec_sensors_register(ec); 395 else 396 /* Workaroud for older EC firmware */ 397 cros_ec_accel_legacy_register(ec); 398 399 /* 400 * The following subdevices can be detected by sending the 401 * EC_FEATURE_GET_CMD Embedded Controller device. 402 */ 403 for (i = 0; i < ARRAY_SIZE(cros_subdevices); i++) { 404 if (cros_ec_check_features(ec, cros_subdevices[i].id)) { 405 retval = mfd_add_hotplug_devices(ec->dev, 406 cros_subdevices[i].mfd_cells, 407 cros_subdevices[i].num_cells); 408 if (retval) 409 dev_err(ec->dev, 410 "failed to add %s subdevice: %d\n", 411 cros_subdevices[i].mfd_cells->name, 412 retval); 413 } 414 } 415 416 /* 417 * The following subdevices cannot be detected by sending the 418 * EC_FEATURE_GET_CMD to the Embedded Controller device. 419 */ 420 retval = mfd_add_hotplug_devices(ec->dev, cros_ec_platform_cells, 421 ARRAY_SIZE(cros_ec_platform_cells)); 422 if (retval) 423 dev_warn(ec->dev, 424 "failed to add cros-ec platform devices: %d\n", 425 retval); 426 427 /* Check whether this EC instance has a VBC NVRAM */ 428 node = ec->ec_dev->dev->of_node; 429 if (of_property_read_bool(node, "google,has-vbc-nvram")) { 430 retval = mfd_add_hotplug_devices(ec->dev, cros_ec_vbc_cells, 431 ARRAY_SIZE(cros_ec_vbc_cells)); 432 if (retval) 433 dev_warn(ec->dev, "failed to add VBC devices: %d\n", 434 retval); 435 } 436 437 return 0; 438 439 failed: 440 put_device(&ec->class_dev); 441 return retval; 442 } 443 444 static int ec_device_remove(struct platform_device *pdev) 445 { 446 struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); 447 448 mfd_remove_devices(ec->dev); 449 device_unregister(&ec->class_dev); 450 return 0; 451 } 452 453 static const struct platform_device_id cros_ec_id[] = { 454 { DRV_NAME, 0 }, 455 { /* sentinel */ } 456 }; 457 MODULE_DEVICE_TABLE(platform, cros_ec_id); 458 459 static struct platform_driver cros_ec_dev_driver = { 460 .driver = { 461 .name = DRV_NAME, 462 }, 463 .id_table = cros_ec_id, 464 .probe = ec_device_probe, 465 .remove = ec_device_remove, 466 }; 467 468 static int __init cros_ec_dev_init(void) 469 { 470 int ret; 471 472 ret = class_register(&cros_class); 473 if (ret) { 474 pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); 475 return ret; 476 } 477 478 /* Register the driver */ 479 ret = platform_driver_register(&cros_ec_dev_driver); 480 if (ret < 0) { 481 pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret); 482 goto failed_devreg; 483 } 484 return 0; 485 486 failed_devreg: 487 class_unregister(&cros_class); 488 return ret; 489 } 490 491 static void __exit cros_ec_dev_exit(void) 492 { 493 platform_driver_unregister(&cros_ec_dev_driver); 494 class_unregister(&cros_class); 495 } 496 497 module_init(cros_ec_dev_init); 498 module_exit(cros_ec_dev_exit); 499 500 MODULE_ALIAS("platform:" DRV_NAME); 501 MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>"); 502 MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); 503 MODULE_VERSION("1.0"); 504 MODULE_LICENSE("GPL"); 505