root/drivers/usb/typec/ucsi/ucsi_acpi.c

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

DEFINITIONS

This source file includes following definitions.
  1. ucsi_acpi_dsm
  2. ucsi_acpi_cmd
  3. ucsi_acpi_sync
  4. ucsi_acpi_notify
  5. ucsi_acpi_probe
  6. ucsi_acpi_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * UCSI ACPI driver
   4  *
   5  * Copyright (C) 2017, Intel Corporation
   6  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7  */
   8 
   9 #include <linux/platform_device.h>
  10 #include <linux/module.h>
  11 #include <linux/acpi.h>
  12 
  13 #include "ucsi.h"
  14 
  15 #define UCSI_DSM_UUID           "6f8398c2-7ca4-11e4-ad36-631042b5008f"
  16 #define UCSI_DSM_FUNC_WRITE     1
  17 #define UCSI_DSM_FUNC_READ      2
  18 
  19 struct ucsi_acpi {
  20         struct device *dev;
  21         struct ucsi *ucsi;
  22         struct ucsi_ppm ppm;
  23         guid_t guid;
  24 };
  25 
  26 static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func)
  27 {
  28         union acpi_object *obj;
  29 
  30         obj = acpi_evaluate_dsm(ACPI_HANDLE(ua->dev), &ua->guid, 1, func,
  31                                 NULL);
  32         if (!obj) {
  33                 dev_err(ua->dev, "%s: failed to evaluate _DSM %d\n",
  34                         __func__, func);
  35                 return -EIO;
  36         }
  37 
  38         ACPI_FREE(obj);
  39         return 0;
  40 }
  41 
  42 static int ucsi_acpi_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl)
  43 {
  44         struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm);
  45 
  46         ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
  47 
  48         return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
  49 }
  50 
  51 static int ucsi_acpi_sync(struct ucsi_ppm *ppm)
  52 {
  53         struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm);
  54 
  55         return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
  56 }
  57 
  58 static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
  59 {
  60         struct ucsi_acpi *ua = data;
  61 
  62         ucsi_notify(ua->ucsi);
  63 }
  64 
  65 static int ucsi_acpi_probe(struct platform_device *pdev)
  66 {
  67         struct ucsi_acpi *ua;
  68         struct resource *res;
  69         acpi_status status;
  70         int ret;
  71 
  72         ua = devm_kzalloc(&pdev->dev, sizeof(*ua), GFP_KERNEL);
  73         if (!ua)
  74                 return -ENOMEM;
  75 
  76         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  77         if (!res) {
  78                 dev_err(&pdev->dev, "missing memory resource\n");
  79                 return -ENODEV;
  80         }
  81 
  82         /* This will make sure we can use ioremap_nocache() */
  83         status = acpi_release_memory(ACPI_HANDLE(&pdev->dev), res, 1);
  84         if (ACPI_FAILURE(status))
  85                 return -ENOMEM;
  86 
  87         /*
  88          * NOTE: The memory region for the data structures is used also in an
  89          * operation region, which means ACPI has already reserved it. Therefore
  90          * it can not be requested here, and we can not use
  91          * devm_ioremap_resource().
  92          */
  93         ua->ppm.data = devm_ioremap(&pdev->dev, res->start, resource_size(res));
  94         if (!ua->ppm.data)
  95                 return -ENOMEM;
  96 
  97         if (!ua->ppm.data->version)
  98                 return -ENODEV;
  99 
 100         ret = guid_parse(UCSI_DSM_UUID, &ua->guid);
 101         if (ret)
 102                 return ret;
 103 
 104         ua->ppm.cmd = ucsi_acpi_cmd;
 105         ua->ppm.sync = ucsi_acpi_sync;
 106         ua->dev = &pdev->dev;
 107 
 108         status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
 109                                              ACPI_DEVICE_NOTIFY,
 110                                              ucsi_acpi_notify, ua);
 111         if (ACPI_FAILURE(status)) {
 112                 dev_err(&pdev->dev, "failed to install notify handler\n");
 113                 return -ENODEV;
 114         }
 115 
 116         ua->ucsi = ucsi_register_ppm(&pdev->dev, &ua->ppm);
 117         if (IS_ERR(ua->ucsi)) {
 118                 acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
 119                                            ACPI_DEVICE_NOTIFY,
 120                                            ucsi_acpi_notify);
 121                 return PTR_ERR(ua->ucsi);
 122         }
 123 
 124         platform_set_drvdata(pdev, ua);
 125 
 126         return 0;
 127 }
 128 
 129 static int ucsi_acpi_remove(struct platform_device *pdev)
 130 {
 131         struct ucsi_acpi *ua = platform_get_drvdata(pdev);
 132 
 133         ucsi_unregister_ppm(ua->ucsi);
 134 
 135         acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY,
 136                                    ucsi_acpi_notify);
 137 
 138         return 0;
 139 }
 140 
 141 static const struct acpi_device_id ucsi_acpi_match[] = {
 142         { "PNP0CA0", 0 },
 143         { },
 144 };
 145 MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match);
 146 
 147 static struct platform_driver ucsi_acpi_platform_driver = {
 148         .driver = {
 149                 .name = "ucsi_acpi",
 150                 .acpi_match_table = ACPI_PTR(ucsi_acpi_match),
 151         },
 152         .probe = ucsi_acpi_probe,
 153         .remove = ucsi_acpi_remove,
 154 };
 155 
 156 module_platform_driver(ucsi_acpi_platform_driver);
 157 
 158 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
 159 MODULE_LICENSE("GPL v2");
 160 MODULE_DESCRIPTION("UCSI ACPI driver");

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