linux/drivers/mfd/intel_soc_pmic_mrfld.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Device access for Basin Cove PMIC
   4 *
   5 * Copyright (c) 2019, Intel Corporation.
   6 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
   7 */
   8
   9#include <linux/acpi.h>
  10#include <linux/interrupt.h>
  11#include <linux/mfd/core.h>
  12#include <linux/mfd/intel_soc_pmic.h>
  13#include <linux/mfd/intel_soc_pmic_mrfld.h>
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/regmap.h>
  17
  18#include <asm/intel_scu_ipc.h>
  19
  20/*
  21 * Level 2 IRQs
  22 *
  23 * Firmware on the systems with Basin Cove PMIC services Level 1 IRQs
  24 * without an assistance. Thus, each of the Level 1 IRQ is represented
  25 * as a separate RTE in IOAPIC.
  26 */
  27static struct resource irq_level2_resources[] = {
  28        DEFINE_RES_IRQ(0), /* power button */
  29        DEFINE_RES_IRQ(0), /* TMU */
  30        DEFINE_RES_IRQ(0), /* thermal */
  31        DEFINE_RES_IRQ(0), /* BCU */
  32        DEFINE_RES_IRQ(0), /* ADC */
  33        DEFINE_RES_IRQ(0), /* charger */
  34        DEFINE_RES_IRQ(0), /* GPIO */
  35};
  36
  37static const struct mfd_cell bcove_dev[] = {
  38        {
  39                .name = "mrfld_bcove_pwrbtn",
  40                .num_resources = 1,
  41                .resources = &irq_level2_resources[0],
  42        }, {
  43                .name = "mrfld_bcove_tmu",
  44                .num_resources = 1,
  45                .resources = &irq_level2_resources[1],
  46        }, {
  47                .name = "mrfld_bcove_thermal",
  48                .num_resources = 1,
  49                .resources = &irq_level2_resources[2],
  50        }, {
  51                .name = "mrfld_bcove_bcu",
  52                .num_resources = 1,
  53                .resources = &irq_level2_resources[3],
  54        }, {
  55                .name = "mrfld_bcove_adc",
  56                .num_resources = 1,
  57                .resources = &irq_level2_resources[4],
  58        }, {
  59                .name = "mrfld_bcove_charger",
  60                .num_resources = 1,
  61                .resources = &irq_level2_resources[5],
  62        }, {
  63                .name = "mrfld_bcove_pwrsrc",
  64                .num_resources = 1,
  65                .resources = &irq_level2_resources[5],
  66        }, {
  67                .name = "mrfld_bcove_gpio",
  68                .num_resources = 1,
  69                .resources = &irq_level2_resources[6],
  70        },
  71        {       .name = "mrfld_bcove_region", },
  72};
  73
  74static int bcove_ipc_byte_reg_read(void *context, unsigned int reg,
  75                                    unsigned int *val)
  76{
  77        struct intel_soc_pmic *pmic = context;
  78        u8 ipc_out;
  79        int ret;
  80
  81        ret = intel_scu_ipc_dev_ioread8(pmic->scu, reg, &ipc_out);
  82        if (ret)
  83                return ret;
  84
  85        *val = ipc_out;
  86        return 0;
  87}
  88
  89static int bcove_ipc_byte_reg_write(void *context, unsigned int reg,
  90                                     unsigned int val)
  91{
  92        struct intel_soc_pmic *pmic = context;
  93        u8 ipc_in = val;
  94
  95        return intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in);
  96}
  97
  98static const struct regmap_config bcove_regmap_config = {
  99        .reg_bits = 16,
 100        .val_bits = 8,
 101        .max_register = 0xff,
 102        .reg_write = bcove_ipc_byte_reg_write,
 103        .reg_read = bcove_ipc_byte_reg_read,
 104};
 105
 106static int bcove_probe(struct platform_device *pdev)
 107{
 108        struct device *dev = &pdev->dev;
 109        struct intel_soc_pmic *pmic;
 110        unsigned int i;
 111        int ret;
 112
 113        pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
 114        if (!pmic)
 115                return -ENOMEM;
 116
 117        pmic->scu = devm_intel_scu_ipc_dev_get(dev);
 118        if (!pmic->scu)
 119                return -ENOMEM;
 120
 121        platform_set_drvdata(pdev, pmic);
 122        pmic->dev = &pdev->dev;
 123
 124        pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bcove_regmap_config);
 125        if (IS_ERR(pmic->regmap))
 126                return PTR_ERR(pmic->regmap);
 127
 128        for (i = 0; i < ARRAY_SIZE(irq_level2_resources); i++) {
 129                ret = platform_get_irq(pdev, i);
 130                if (ret < 0)
 131                        return ret;
 132
 133                irq_level2_resources[i].start = ret;
 134                irq_level2_resources[i].end = ret;
 135        }
 136
 137        return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
 138                                    bcove_dev, ARRAY_SIZE(bcove_dev),
 139                                    NULL, 0, NULL);
 140}
 141
 142static const struct acpi_device_id bcove_acpi_ids[] = {
 143        { "INTC100E" },
 144        {}
 145};
 146MODULE_DEVICE_TABLE(acpi, bcove_acpi_ids);
 147
 148static struct platform_driver bcove_driver = {
 149        .driver = {
 150                .name = "intel_soc_pmic_mrfld",
 151                .acpi_match_table = bcove_acpi_ids,
 152        },
 153        .probe = bcove_probe,
 154};
 155module_platform_driver(bcove_driver);
 156
 157MODULE_DESCRIPTION("IPC driver for Intel SoC Basin Cove PMIC");
 158MODULE_LICENSE("GPL v2");
 159