linux/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Common code for Intel Cherry Trail ACPI INT33FE pseudo device drivers
   4 * (USB Micro-B and Type-C connector variants).
   5 *
   6 * Copyright (c) 2019 Yauhen Kharuzhy <jekhor@gmail.com>
   7 */
   8
   9#include <linux/acpi.h>
  10#include <linux/i2c.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/slab.h>
  14
  15#include "intel_cht_int33fe_common.h"
  16
  17#define EXPECTED_PTYPE          4
  18
  19static int cht_int33fe_check_hw_type(struct device *dev)
  20{
  21        unsigned long long ptyp;
  22        acpi_status status;
  23        int ret;
  24
  25        status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
  26        if (ACPI_FAILURE(status)) {
  27                dev_err(dev, "Error getting PTYPE\n");
  28                return -ENODEV;
  29        }
  30
  31        /*
  32         * The same ACPI HID is used for different configurations check PTYP
  33         * to ensure that we are dealing with the expected config.
  34         */
  35        if (ptyp != EXPECTED_PTYPE)
  36                return -ENODEV;
  37
  38        /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */
  39        if (!acpi_dev_present("INT34D3", "1", 3)) {
  40                dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n",
  41                        EXPECTED_PTYPE);
  42                return -ENODEV;
  43        }
  44
  45        ret = i2c_acpi_client_count(ACPI_COMPANION(dev));
  46        if (ret < 0)
  47                return ret;
  48
  49        switch (ret) {
  50        case 2:
  51                return INT33FE_HW_MICROB;
  52        case 4:
  53                return INT33FE_HW_TYPEC;
  54        default:
  55                return -ENODEV;
  56        }
  57}
  58
  59static int cht_int33fe_probe(struct platform_device *pdev)
  60{
  61        struct cht_int33fe_data *data;
  62        struct device *dev = &pdev->dev;
  63        int ret;
  64
  65        ret = cht_int33fe_check_hw_type(dev);
  66        if (ret < 0)
  67                return ret;
  68
  69        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  70        if (!data)
  71                return -ENOMEM;
  72
  73        data->dev = dev;
  74
  75        switch (ret) {
  76        case INT33FE_HW_MICROB:
  77                data->probe = cht_int33fe_microb_probe;
  78                data->remove = cht_int33fe_microb_remove;
  79                break;
  80
  81        case INT33FE_HW_TYPEC:
  82                data->probe = cht_int33fe_typec_probe;
  83                data->remove = cht_int33fe_typec_remove;
  84                break;
  85        }
  86
  87        platform_set_drvdata(pdev, data);
  88
  89        return data->probe(data);
  90}
  91
  92static int cht_int33fe_remove(struct platform_device *pdev)
  93{
  94        struct cht_int33fe_data *data = platform_get_drvdata(pdev);
  95
  96        return data->remove(data);
  97}
  98
  99static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
 100        { "INT33FE", },
 101        { }
 102};
 103MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids);
 104
 105static struct platform_driver cht_int33fe_driver = {
 106        .driver = {
 107                .name = "Intel Cherry Trail ACPI INT33FE driver",
 108                .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
 109        },
 110        .probe = cht_int33fe_probe,
 111        .remove = cht_int33fe_remove,
 112};
 113
 114module_platform_driver(cht_int33fe_driver);
 115
 116MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver");
 117MODULE_AUTHOR("Yauhen Kharuzhy <jekhor@gmail.com>");
 118MODULE_LICENSE("GPL v2");
 119