root/drivers/mfd/intel_soc_pmic_chtwc.c

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

DEFINITIONS

This source file includes following definitions.
  1. cht_wc_byte_reg_read
  2. cht_wc_byte_reg_write
  3. cht_wc_probe
  4. cht_wc_shutdown
  5. cht_wc_suspend
  6. cht_wc_resume

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC
   4  *
   5  * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
   6  *
   7  * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
   8  * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
   9  */
  10 
  11 #include <linux/acpi.h>
  12 #include <linux/delay.h>
  13 #include <linux/err.h>
  14 #include <linux/i2c.h>
  15 #include <linux/interrupt.h>
  16 #include <linux/kernel.h>
  17 #include <linux/mfd/core.h>
  18 #include <linux/mfd/intel_soc_pmic.h>
  19 #include <linux/regmap.h>
  20 
  21 /* PMIC device registers */
  22 #define REG_OFFSET_MASK         GENMASK(7, 0)
  23 #define REG_ADDR_MASK           GENMASK(15, 8)
  24 #define REG_ADDR_SHIFT          8
  25 
  26 #define CHT_WC_IRQLVL1          0x6e02
  27 #define CHT_WC_IRQLVL1_MASK     0x6e0e
  28 
  29 /* Whiskey Cove PMIC share same ACPI ID between different platforms */
  30 #define CHT_WC_HRV              3
  31 
  32 /* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */
  33 enum {
  34         CHT_WC_PWRSRC_IRQ = 0,
  35         CHT_WC_THRM_IRQ,
  36         CHT_WC_BCU_IRQ,
  37         CHT_WC_ADC_IRQ,
  38         CHT_WC_EXT_CHGR_IRQ,
  39         CHT_WC_GPIO_IRQ,
  40         /* There is no irq 6 */
  41         CHT_WC_CRIT_IRQ = 7,
  42 };
  43 
  44 static struct resource cht_wc_pwrsrc_resources[] = {
  45         DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ),
  46 };
  47 
  48 static struct resource cht_wc_ext_charger_resources[] = {
  49         DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ),
  50 };
  51 
  52 static struct mfd_cell cht_wc_dev[] = {
  53         {
  54                 .name = "cht_wcove_pwrsrc",
  55                 .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources),
  56                 .resources = cht_wc_pwrsrc_resources,
  57         }, {
  58                 .name = "cht_wcove_ext_chgr",
  59                 .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources),
  60                 .resources = cht_wc_ext_charger_resources,
  61         },
  62         {       .name = "cht_wcove_region", },
  63         {       .name = "cht_wcove_leds", },
  64 };
  65 
  66 /*
  67  * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte
  68  * register address space per I2C address, so we use 16 bit register
  69  * addresses where the high 8 bits contain the I2C client address.
  70  */
  71 static int cht_wc_byte_reg_read(void *context, unsigned int reg,
  72                                 unsigned int *val)
  73 {
  74         struct i2c_client *client = context;
  75         int ret, orig_addr = client->addr;
  76 
  77         if (!(reg & REG_ADDR_MASK)) {
  78                 dev_err(&client->dev, "Error I2C address not specified\n");
  79                 return -EINVAL;
  80         }
  81 
  82         client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
  83         ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK);
  84         client->addr = orig_addr;
  85 
  86         if (ret < 0)
  87                 return ret;
  88 
  89         *val = ret;
  90         return 0;
  91 }
  92 
  93 static int cht_wc_byte_reg_write(void *context, unsigned int reg,
  94                                  unsigned int val)
  95 {
  96         struct i2c_client *client = context;
  97         int ret, orig_addr = client->addr;
  98 
  99         if (!(reg & REG_ADDR_MASK)) {
 100                 dev_err(&client->dev, "Error I2C address not specified\n");
 101                 return -EINVAL;
 102         }
 103 
 104         client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
 105         ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val);
 106         client->addr = orig_addr;
 107 
 108         return ret;
 109 }
 110 
 111 static const struct regmap_config cht_wc_regmap_cfg = {
 112         .reg_bits = 16,
 113         .val_bits = 8,
 114         .reg_write = cht_wc_byte_reg_write,
 115         .reg_read = cht_wc_byte_reg_read,
 116 };
 117 
 118 static const struct regmap_irq cht_wc_regmap_irqs[] = {
 119         REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)),
 120         REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)),
 121         REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)),
 122         REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)),
 123         REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)),
 124         REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)),
 125         REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)),
 126 };
 127 
 128 static const struct regmap_irq_chip cht_wc_regmap_irq_chip = {
 129         .name = "cht_wc_irq_chip",
 130         .status_base = CHT_WC_IRQLVL1,
 131         .mask_base = CHT_WC_IRQLVL1_MASK,
 132         .irqs = cht_wc_regmap_irqs,
 133         .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs),
 134         .num_regs = 1,
 135 };
 136 
 137 static int cht_wc_probe(struct i2c_client *client)
 138 {
 139         struct device *dev = &client->dev;
 140         struct intel_soc_pmic *pmic;
 141         acpi_status status;
 142         unsigned long long hrv;
 143         int ret;
 144 
 145         status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv);
 146         if (ACPI_FAILURE(status)) {
 147                 dev_err(dev, "Failed to get PMIC hardware revision\n");
 148                 return -ENODEV;
 149         }
 150         if (hrv != CHT_WC_HRV) {
 151                 dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv);
 152                 return -ENODEV;
 153         }
 154         if (client->irq < 0) {
 155                 dev_err(dev, "Invalid IRQ\n");
 156                 return -EINVAL;
 157         }
 158 
 159         pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
 160         if (!pmic)
 161                 return -ENOMEM;
 162 
 163         pmic->irq = client->irq;
 164         pmic->dev = dev;
 165         i2c_set_clientdata(client, pmic);
 166 
 167         pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg);
 168         if (IS_ERR(pmic->regmap))
 169                 return PTR_ERR(pmic->regmap);
 170 
 171         ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
 172                                        IRQF_ONESHOT | IRQF_SHARED, 0,
 173                                        &cht_wc_regmap_irq_chip,
 174                                        &pmic->irq_chip_data);
 175         if (ret)
 176                 return ret;
 177 
 178         return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
 179                                 cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0,
 180                                 regmap_irq_get_domain(pmic->irq_chip_data));
 181 }
 182 
 183 static void cht_wc_shutdown(struct i2c_client *client)
 184 {
 185         struct intel_soc_pmic *pmic = i2c_get_clientdata(client);
 186 
 187         disable_irq(pmic->irq);
 188 }
 189 
 190 static int __maybe_unused cht_wc_suspend(struct device *dev)
 191 {
 192         struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
 193 
 194         disable_irq(pmic->irq);
 195 
 196         return 0;
 197 }
 198 
 199 static int __maybe_unused cht_wc_resume(struct device *dev)
 200 {
 201         struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
 202 
 203         enable_irq(pmic->irq);
 204 
 205         return 0;
 206 }
 207 static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume);
 208 
 209 static const struct i2c_device_id cht_wc_i2c_id[] = {
 210         { }
 211 };
 212 
 213 static const struct acpi_device_id cht_wc_acpi_ids[] = {
 214         { "INT34D3", },
 215         { }
 216 };
 217 
 218 static struct i2c_driver cht_wc_driver = {
 219         .driver = {
 220                 .name   = "CHT Whiskey Cove PMIC",
 221                 .pm     = &cht_wc_pm_ops,
 222                 .acpi_match_table = cht_wc_acpi_ids,
 223         },
 224         .probe_new = cht_wc_probe,
 225         .shutdown = cht_wc_shutdown,
 226         .id_table = cht_wc_i2c_id,
 227 };
 228 builtin_i2c_driver(cht_wc_driver);

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