linux/drivers/mfd/intel_soc_pmic_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Intel SoC PMIC MFD Driver
   4 *
   5 * Copyright (C) 2013, 2014 Intel Corporation. All rights reserved.
   6 *
   7 * Author: Yang, Bin <bin.yang@intel.com>
   8 * Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
   9 */
  10
  11#include <linux/acpi.h>
  12#include <linux/i2c.h>
  13#include <linux/interrupt.h>
  14#include <linux/module.h>
  15#include <linux/mfd/core.h>
  16#include <linux/mfd/intel_soc_pmic.h>
  17#include <linux/pwm.h>
  18#include <linux/regmap.h>
  19
  20#include "intel_soc_pmic_core.h"
  21
  22/* Crystal Cove PMIC shares same ACPI ID between different platforms */
  23#define BYT_CRC_HRV             2
  24#define CHT_CRC_HRV             3
  25
  26/* PWM consumed by the Intel GFX */
  27static struct pwm_lookup crc_pwm_lookup[] = {
  28        PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL),
  29};
  30
  31static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
  32                                    const struct i2c_device_id *i2c_id)
  33{
  34        struct device *dev = &i2c->dev;
  35        struct intel_soc_pmic_config *config;
  36        struct intel_soc_pmic *pmic;
  37        unsigned long long hrv;
  38        acpi_status status;
  39        int ret;
  40
  41        /*
  42         * There are 2 different Crystal Cove PMICs a Bay Trail and Cherry
  43         * Trail version, use _HRV to differentiate between the 2.
  44         */
  45        status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv);
  46        if (ACPI_FAILURE(status)) {
  47                dev_err(dev, "Failed to get PMIC hardware revision\n");
  48                return -ENODEV;
  49        }
  50
  51        switch (hrv) {
  52        case BYT_CRC_HRV:
  53                config = &intel_soc_pmic_config_byt_crc;
  54                break;
  55        case CHT_CRC_HRV:
  56                config = &intel_soc_pmic_config_cht_crc;
  57                break;
  58        default:
  59                dev_warn(dev, "Unknown hardware rev %llu, assuming BYT\n", hrv);
  60                config = &intel_soc_pmic_config_byt_crc;
  61        }
  62
  63        pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
  64        if (!pmic)
  65                return -ENOMEM;
  66
  67        dev_set_drvdata(dev, pmic);
  68
  69        pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
  70        if (IS_ERR(pmic->regmap))
  71                return PTR_ERR(pmic->regmap);
  72
  73        pmic->irq = i2c->irq;
  74
  75        ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
  76                                  config->irq_flags | IRQF_ONESHOT,
  77                                  0, config->irq_chip,
  78                                  &pmic->irq_chip_data);
  79        if (ret)
  80                return ret;
  81
  82        ret = enable_irq_wake(pmic->irq);
  83        if (ret)
  84                dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);
  85
  86        /* Add lookup table for crc-pwm */
  87        pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
  88
  89        ret = mfd_add_devices(dev, -1, config->cell_dev,
  90                              config->n_cell_devs, NULL, 0,
  91                              regmap_irq_get_domain(pmic->irq_chip_data));
  92        if (ret)
  93                goto err_del_irq_chip;
  94
  95        return 0;
  96
  97err_del_irq_chip:
  98        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
  99        return ret;
 100}
 101
 102static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c)
 103{
 104        struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev);
 105
 106        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
 107
 108        /* remove crc-pwm lookup table */
 109        pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
 110
 111        mfd_remove_devices(&i2c->dev);
 112
 113        return 0;
 114}
 115
 116static void intel_soc_pmic_shutdown(struct i2c_client *i2c)
 117{
 118        struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev);
 119
 120        disable_irq(pmic->irq);
 121
 122        return;
 123}
 124
 125#if defined(CONFIG_PM_SLEEP)
 126static int intel_soc_pmic_suspend(struct device *dev)
 127{
 128        struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
 129
 130        disable_irq(pmic->irq);
 131
 132        return 0;
 133}
 134
 135static int intel_soc_pmic_resume(struct device *dev)
 136{
 137        struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
 138
 139        enable_irq(pmic->irq);
 140
 141        return 0;
 142}
 143#endif
 144
 145static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend,
 146                         intel_soc_pmic_resume);
 147
 148static const struct i2c_device_id intel_soc_pmic_i2c_id[] = {
 149        { }
 150};
 151MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id);
 152
 153#if defined(CONFIG_ACPI)
 154static const struct acpi_device_id intel_soc_pmic_acpi_match[] = {
 155        { "INT33FD" },
 156        { },
 157};
 158MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match);
 159#endif
 160
 161static struct i2c_driver intel_soc_pmic_i2c_driver = {
 162        .driver = {
 163                .name = "intel_soc_pmic_i2c",
 164                .pm = &intel_soc_pmic_pm_ops,
 165                .acpi_match_table = ACPI_PTR(intel_soc_pmic_acpi_match),
 166        },
 167        .probe = intel_soc_pmic_i2c_probe,
 168        .remove = intel_soc_pmic_i2c_remove,
 169        .id_table = intel_soc_pmic_i2c_id,
 170        .shutdown = intel_soc_pmic_shutdown,
 171};
 172
 173module_i2c_driver(intel_soc_pmic_i2c_driver);
 174
 175MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC");
 176MODULE_LICENSE("GPL v2");
 177MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
 178MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>");
 179