root/drivers/mfd/cros_ec_dev.c

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

DEFINITIONS

This source file includes following definitions.
  1. cros_ec_check_features
  2. cros_ec_class_release
  3. cros_ec_sensors_register
  4. cros_ec_accel_legacy_register
  5. ec_device_probe
  6. ec_device_remove
  7. cros_ec_dev_init
  8. cros_ec_dev_exit

   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");

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