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