Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Device access for Basin Cove PMIC
0004  *
0005  * Copyright (c) 2019, Intel Corporation.
0006  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
0007  */
0008 
0009 #include <linux/acpi.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/mfd/core.h>
0012 #include <linux/mfd/intel_soc_pmic.h>
0013 #include <linux/mfd/intel_soc_pmic_mrfld.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regmap.h>
0017 
0018 #include <asm/intel_scu_ipc.h>
0019 
0020 /*
0021  * Level 2 IRQs
0022  *
0023  * Firmware on the systems with Basin Cove PMIC services Level 1 IRQs
0024  * without an assistance. Thus, each of the Level 1 IRQ is represented
0025  * as a separate RTE in IOAPIC.
0026  */
0027 static struct resource irq_level2_resources[] = {
0028     DEFINE_RES_IRQ(0), /* power button */
0029     DEFINE_RES_IRQ(0), /* TMU */
0030     DEFINE_RES_IRQ(0), /* thermal */
0031     DEFINE_RES_IRQ(0), /* BCU */
0032     DEFINE_RES_IRQ(0), /* ADC */
0033     DEFINE_RES_IRQ(0), /* charger */
0034     DEFINE_RES_IRQ(0), /* GPIO */
0035 };
0036 
0037 static const struct mfd_cell bcove_dev[] = {
0038     {
0039         .name = "mrfld_bcove_pwrbtn",
0040         .num_resources = 1,
0041         .resources = &irq_level2_resources[0],
0042     }, {
0043         .name = "mrfld_bcove_tmu",
0044         .num_resources = 1,
0045         .resources = &irq_level2_resources[1],
0046     }, {
0047         .name = "mrfld_bcove_thermal",
0048         .num_resources = 1,
0049         .resources = &irq_level2_resources[2],
0050     }, {
0051         .name = "mrfld_bcove_bcu",
0052         .num_resources = 1,
0053         .resources = &irq_level2_resources[3],
0054     }, {
0055         .name = "mrfld_bcove_adc",
0056         .num_resources = 1,
0057         .resources = &irq_level2_resources[4],
0058     }, {
0059         .name = "mrfld_bcove_charger",
0060         .num_resources = 1,
0061         .resources = &irq_level2_resources[5],
0062     }, {
0063         .name = "mrfld_bcove_pwrsrc",
0064         .num_resources = 1,
0065         .resources = &irq_level2_resources[5],
0066     }, {
0067         .name = "mrfld_bcove_gpio",
0068         .num_resources = 1,
0069         .resources = &irq_level2_resources[6],
0070     },
0071     {   .name = "mrfld_bcove_region", },
0072 };
0073 
0074 static int bcove_ipc_byte_reg_read(void *context, unsigned int reg,
0075                     unsigned int *val)
0076 {
0077     struct intel_soc_pmic *pmic = context;
0078     u8 ipc_out;
0079     int ret;
0080 
0081     ret = intel_scu_ipc_dev_ioread8(pmic->scu, reg, &ipc_out);
0082     if (ret)
0083         return ret;
0084 
0085     *val = ipc_out;
0086     return 0;
0087 }
0088 
0089 static int bcove_ipc_byte_reg_write(void *context, unsigned int reg,
0090                      unsigned int val)
0091 {
0092     struct intel_soc_pmic *pmic = context;
0093     u8 ipc_in = val;
0094 
0095     return intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in);
0096 }
0097 
0098 static const struct regmap_config bcove_regmap_config = {
0099     .reg_bits = 16,
0100     .val_bits = 8,
0101     .max_register = 0xff,
0102     .reg_write = bcove_ipc_byte_reg_write,
0103     .reg_read = bcove_ipc_byte_reg_read,
0104 };
0105 
0106 static int bcove_probe(struct platform_device *pdev)
0107 {
0108     struct device *dev = &pdev->dev;
0109     struct intel_soc_pmic *pmic;
0110     unsigned int i;
0111     int ret;
0112 
0113     pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
0114     if (!pmic)
0115         return -ENOMEM;
0116 
0117     pmic->scu = devm_intel_scu_ipc_dev_get(dev);
0118     if (!pmic->scu)
0119         return -ENOMEM;
0120 
0121     platform_set_drvdata(pdev, pmic);
0122     pmic->dev = &pdev->dev;
0123 
0124     pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bcove_regmap_config);
0125     if (IS_ERR(pmic->regmap))
0126         return PTR_ERR(pmic->regmap);
0127 
0128     for (i = 0; i < ARRAY_SIZE(irq_level2_resources); i++) {
0129         ret = platform_get_irq(pdev, i);
0130         if (ret < 0)
0131             return ret;
0132 
0133         irq_level2_resources[i].start = ret;
0134         irq_level2_resources[i].end = ret;
0135     }
0136 
0137     return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0138                     bcove_dev, ARRAY_SIZE(bcove_dev),
0139                     NULL, 0, NULL);
0140 }
0141 
0142 static const struct acpi_device_id bcove_acpi_ids[] = {
0143     { "INTC100E" },
0144     {}
0145 };
0146 MODULE_DEVICE_TABLE(acpi, bcove_acpi_ids);
0147 
0148 static struct platform_driver bcove_driver = {
0149     .driver = {
0150         .name = "intel_soc_pmic_mrfld",
0151         .acpi_match_table = bcove_acpi_ids,
0152     },
0153     .probe = bcove_probe,
0154 };
0155 module_platform_driver(bcove_driver);
0156 
0157 MODULE_DESCRIPTION("IPC driver for Intel SoC Basin Cove PMIC");
0158 MODULE_LICENSE("GPL v2");