linux/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Author: Dan Scally <djrscally@gmail.com> */
   3
   4#include <linux/i2c.h>
   5#include <linux/mfd/core.h>
   6#include <linux/mfd/tps68470.h>
   7#include <linux/platform_device.h>
   8#include <linux/regmap.h>
   9
  10#include "intel_skl_int3472_common.h"
  11
  12#define DESIGNED_FOR_CHROMEOS           1
  13#define DESIGNED_FOR_WINDOWS            2
  14
  15static const struct mfd_cell tps68470_cros[] = {
  16        { .name = "tps68470-gpio" },
  17        { .name = "tps68470_pmic_opregion" },
  18};
  19
  20static const struct mfd_cell tps68470_win[] = {
  21        { .name = "tps68470-gpio" },
  22        { .name = "tps68470-clk" },
  23        { .name = "tps68470-regulator" },
  24};
  25
  26static const struct regmap_config tps68470_regmap_config = {
  27        .reg_bits = 8,
  28        .val_bits = 8,
  29        .max_register = TPS68470_REG_MAX,
  30};
  31
  32static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
  33{
  34        unsigned int version;
  35        int ret;
  36
  37        /* Force software reset */
  38        ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
  39        if (ret)
  40                return ret;
  41
  42        ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
  43        if (ret) {
  44                dev_err(dev, "Failed to read revision register: %d\n", ret);
  45                return ret;
  46        }
  47
  48        dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
  49
  50        return 0;
  51}
  52
  53/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for
  54 * @adev: A pointer to a &struct acpi_device
  55 *
  56 * Check CLDB buffer against the PMIC's adev. If present, then we check
  57 * the value of control_logic_type field and follow one of the
  58 * following scenarios:
  59 *
  60 *      1. No CLDB - likely ACPI tables designed for ChromeOS. We
  61 *      create platform devices for the GPIOs and OpRegion drivers.
  62 *
  63 *      2. CLDB, with control_logic_type = 2 - probably ACPI tables
  64 *      made for Windows 2-in-1 platforms. Register pdevs for GPIO,
  65 *      Clock and Regulator drivers to bind to.
  66 *
  67 *      3. Any other value in control_logic_type, we should never have
  68 *      gotten to this point; fail probe and return.
  69 *
  70 * Return:
  71 * * 1          Device intended for ChromeOS
  72 * * 2          Device intended for Windows
  73 * * -EINVAL    Where @adev has an object named CLDB but it does not conform to
  74 *              our expectations
  75 */
  76static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
  77{
  78        struct int3472_cldb cldb = { 0 };
  79        int ret;
  80
  81        /*
  82         * A CLDB buffer that exists, but which does not match our expectations
  83         * should trigger an error so we don't blindly continue.
  84         */
  85        ret = skl_int3472_fill_cldb(adev, &cldb);
  86        if (ret && ret != -ENODEV)
  87                return ret;
  88
  89        if (ret)
  90                return DESIGNED_FOR_CHROMEOS;
  91
  92        if (cldb.control_logic_type != 2)
  93                return -EINVAL;
  94
  95        return DESIGNED_FOR_WINDOWS;
  96}
  97
  98int skl_int3472_tps68470_probe(struct i2c_client *client)
  99{
 100        struct acpi_device *adev = ACPI_COMPANION(&client->dev);
 101        struct regmap *regmap;
 102        int device_type;
 103        int ret;
 104
 105        regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
 106        if (IS_ERR(regmap)) {
 107                dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
 108                return PTR_ERR(regmap);
 109        }
 110
 111        i2c_set_clientdata(client, regmap);
 112
 113        ret = tps68470_chip_init(&client->dev, regmap);
 114        if (ret < 0) {
 115                dev_err(&client->dev, "TPS68470 init error %d\n", ret);
 116                return ret;
 117        }
 118
 119        device_type = skl_int3472_tps68470_calc_type(adev);
 120        switch (device_type) {
 121        case DESIGNED_FOR_WINDOWS:
 122                ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
 123                                           tps68470_win, ARRAY_SIZE(tps68470_win),
 124                                           NULL, 0, NULL);
 125                break;
 126        case DESIGNED_FOR_CHROMEOS:
 127                ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
 128                                           tps68470_cros, ARRAY_SIZE(tps68470_cros),
 129                                           NULL, 0, NULL);
 130                break;
 131        default:
 132                dev_err(&client->dev, "Failed to add MFD devices\n");
 133                return device_type;
 134        }
 135
 136        return ret;
 137}
 138