linux/drivers/platform/x86/intel_cht_int33fe.c
<<
>>
Prefs
   1/*
   2 * Intel Cherry Trail ACPI INT33FE pseudo device driver
   3 *
   4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * Some Intel Cherry Trail based device which ship with Windows 10, have
  11 * this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2
  12 * resources, for 4 different chips attached to various i2c busses:
  13 * 1. The Whiskey Cove pmic, which is also described by the INT34D3 ACPI device
  14 * 2. Maxim MAX17047 Fuel Gauge Controller
  15 * 3. FUSB302 USB Type-C Controller
  16 * 4. PI3USB30532 USB switch
  17 *
  18 * So this driver is a stub / pseudo driver whose only purpose is to
  19 * instantiate i2c-clients for chips 2 - 4, so that standard i2c drivers
  20 * for these chips can bind to the them.
  21 */
  22
  23#include <linux/acpi.h>
  24#include <linux/i2c.h>
  25#include <linux/interrupt.h>
  26#include <linux/module.h>
  27#include <linux/regulator/consumer.h>
  28#include <linux/slab.h>
  29
  30#define EXPECTED_PTYPE          4
  31
  32struct cht_int33fe_data {
  33        struct i2c_client *max17047;
  34        struct i2c_client *fusb302;
  35        struct i2c_client *pi3usb30532;
  36        /* Contain a list-head must be per device */
  37        struct device_connection connections[3];
  38};
  39
  40/*
  41 * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
  42 * the max17047 both through the INT33FE ACPI device (it is right there
  43 * in the resources table) as well as through a separate MAX17047 device.
  44 *
  45 * These helpers are used to work around this by checking if an i2c-client
  46 * for the max17047 has already been registered.
  47 */
  48static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
  49{
  50        struct i2c_client **max17047 = data;
  51        struct acpi_device *adev;
  52        const char *hid;
  53
  54        adev = ACPI_COMPANION(dev);
  55        if (!adev)
  56                return 0;
  57
  58        hid = acpi_device_hid(adev);
  59
  60        /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */
  61        if (strcmp(hid, "MAX17047"))
  62                return 0;
  63
  64        *max17047 = to_i2c_client(dev);
  65        return 1;
  66}
  67
  68static struct i2c_client *cht_int33fe_find_max17047(void)
  69{
  70        struct i2c_client *max17047 = NULL;
  71
  72        i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
  73        return max17047;
  74}
  75
  76static const char * const max17047_suppliers[] = { "bq24190-charger" };
  77
  78static const struct property_entry max17047_props[] = {
  79        PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers),
  80        { }
  81};
  82
  83static const struct property_entry fusb302_props[] = {
  84        PROPERTY_ENTRY_STRING("fcs,extcon-name", "cht_wcove_pwrsrc"),
  85        PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000),
  86        PROPERTY_ENTRY_U32("fcs,max-sink-microamp",   3000000),
  87        PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000),
  88        { }
  89};
  90
  91static int cht_int33fe_probe(struct i2c_client *client)
  92{
  93        struct device *dev = &client->dev;
  94        struct i2c_board_info board_info;
  95        struct cht_int33fe_data *data;
  96        struct i2c_client *max17047;
  97        struct regulator *regulator;
  98        unsigned long long ptyp;
  99        acpi_status status;
 100        int fusb302_irq;
 101        int ret;
 102
 103        status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
 104        if (ACPI_FAILURE(status)) {
 105                dev_err(dev, "Error getting PTYPE\n");
 106                return -ENODEV;
 107        }
 108
 109        /*
 110         * The same ACPI HID is used for different configurations check PTYP
 111         * to ensure that we are dealing with the expected config.
 112         */
 113        if (ptyp != EXPECTED_PTYPE)
 114                return -ENODEV;
 115
 116        /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */
 117        if (!acpi_dev_present("INT34D3", "1", 3)) {
 118                dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n",
 119                        EXPECTED_PTYPE);
 120                return -ENODEV;
 121        }
 122
 123        /*
 124         * We expect the WC PMIC to be paired with a TI bq24292i charger-IC.
 125         * We check for the bq24292i vbus regulator here, this has 2 purposes:
 126         * 1) The bq24292i allows charging with up to 12V, setting the fusb302's
 127         *    max-snk voltage to 12V with another charger-IC is not good.
 128         * 2) For the fusb302 driver to get the bq24292i vbus regulator, the
 129         *    regulator-map, which is part of the bq24292i regulator_init_data,
 130         *    must be registered before the fusb302 is instantiated, otherwise
 131         *    it will end up with a dummy-regulator.
 132         * Note "cht_wc_usb_typec_vbus" comes from the regulator_init_data
 133         * which is defined in i2c-cht-wc.c from where the bq24292i i2c-client
 134         * gets instantiated. We use regulator_get_optional here so that we
 135         * don't end up getting a dummy-regulator ourselves.
 136         */
 137        regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus");
 138        if (IS_ERR(regulator)) {
 139                ret = PTR_ERR(regulator);
 140                return (ret == -ENODEV) ? -EPROBE_DEFER : ret;
 141        }
 142        regulator_put(regulator);
 143
 144        /* The FUSB302 uses the irq at index 1 and is the only irq user */
 145        fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
 146        if (fusb302_irq < 0) {
 147                if (fusb302_irq != -EPROBE_DEFER)
 148                        dev_err(dev, "Error getting FUSB302 irq\n");
 149                return fusb302_irq;
 150        }
 151
 152        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 153        if (!data)
 154                return -ENOMEM;
 155
 156        /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */
 157        max17047 = cht_int33fe_find_max17047();
 158        if (max17047) {
 159                /* Pre-existing i2c-client for the max17047, add device-props */
 160                ret = device_add_properties(&max17047->dev, max17047_props);
 161                if (ret)
 162                        return ret;
 163                /* And re-probe to get the new device-props applied. */
 164                ret = device_reprobe(&max17047->dev);
 165                if (ret)
 166                        dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
 167        } else {
 168                memset(&board_info, 0, sizeof(board_info));
 169                strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
 170                board_info.dev_name = "max17047";
 171                board_info.properties = max17047_props;
 172                data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
 173                if (!data->max17047)
 174                        return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
 175        }
 176
 177        data->connections[0].endpoint[0] = "i2c-fusb302";
 178        data->connections[0].endpoint[1] = "i2c-pi3usb30532";
 179        data->connections[0].id = "typec-switch";
 180        data->connections[1].endpoint[0] = "i2c-fusb302";
 181        data->connections[1].endpoint[1] = "i2c-pi3usb30532";
 182        data->connections[1].id = "typec-mux";
 183        data->connections[2].endpoint[0] = "i2c-fusb302";
 184        data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
 185        data->connections[2].id = "usb-role-switch";
 186
 187        device_connection_add(&data->connections[0]);
 188        device_connection_add(&data->connections[1]);
 189        device_connection_add(&data->connections[2]);
 190
 191        memset(&board_info, 0, sizeof(board_info));
 192        strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
 193        board_info.dev_name = "fusb302";
 194        board_info.properties = fusb302_props;
 195        board_info.irq = fusb302_irq;
 196
 197        data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
 198        if (!data->fusb302)
 199                goto out_unregister_max17047;
 200
 201        memset(&board_info, 0, sizeof(board_info));
 202        board_info.dev_name = "pi3usb30532";
 203        strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
 204
 205        data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
 206        if (!data->pi3usb30532)
 207                goto out_unregister_fusb302;
 208
 209        i2c_set_clientdata(client, data);
 210
 211        return 0;
 212
 213out_unregister_fusb302:
 214        i2c_unregister_device(data->fusb302);
 215
 216out_unregister_max17047:
 217        if (data->max17047)
 218                i2c_unregister_device(data->max17047);
 219
 220        device_connection_remove(&data->connections[2]);
 221        device_connection_remove(&data->connections[1]);
 222        device_connection_remove(&data->connections[0]);
 223
 224        return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
 225}
 226
 227static int cht_int33fe_remove(struct i2c_client *i2c)
 228{
 229        struct cht_int33fe_data *data = i2c_get_clientdata(i2c);
 230
 231        i2c_unregister_device(data->pi3usb30532);
 232        i2c_unregister_device(data->fusb302);
 233        if (data->max17047)
 234                i2c_unregister_device(data->max17047);
 235
 236        device_connection_remove(&data->connections[2]);
 237        device_connection_remove(&data->connections[1]);
 238        device_connection_remove(&data->connections[0]);
 239
 240        return 0;
 241}
 242
 243static const struct i2c_device_id cht_int33fe_i2c_id[] = {
 244        { }
 245};
 246MODULE_DEVICE_TABLE(i2c, cht_int33fe_i2c_id);
 247
 248static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
 249        { "INT33FE", },
 250        { }
 251};
 252MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids);
 253
 254static struct i2c_driver cht_int33fe_driver = {
 255        .driver = {
 256                .name = "Intel Cherry Trail ACPI INT33FE driver",
 257                .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
 258        },
 259        .probe_new = cht_int33fe_probe,
 260        .remove = cht_int33fe_remove,
 261        .id_table = cht_int33fe_i2c_id,
 262        .disable_i2c_core_irq_mapping = true,
 263};
 264
 265module_i2c_driver(cht_int33fe_driver);
 266
 267MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver");
 268MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 269MODULE_LICENSE("GPL");
 270