cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hi655x-pmic.c (4663B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Device driver for MFD hi655x PMIC
      4 *
      5 * Copyright (c) 2016 HiSilicon Ltd.
      6 *
      7 * Authors:
      8 * Chen Feng <puck.chen@hisilicon.com>
      9 * Fei  Wang <w.f@huawei.com>
     10 */
     11
     12#include <linux/io.h>
     13#include <linux/interrupt.h>
     14#include <linux/init.h>
     15#include <linux/mfd/core.h>
     16#include <linux/mfd/hi655x-pmic.h>
     17#include <linux/module.h>
     18#include <linux/gpio/consumer.h>
     19#include <linux/of_platform.h>
     20#include <linux/platform_device.h>
     21#include <linux/regmap.h>
     22
     23static const struct regmap_irq hi655x_irqs[] = {
     24	{ .reg_offset = 0, .mask = OTMP_D1R_INT_MASK },
     25	{ .reg_offset = 0, .mask = VSYS_2P5_R_INT_MASK },
     26	{ .reg_offset = 0, .mask = VSYS_UV_D3R_INT_MASK },
     27	{ .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT_MASK },
     28	{ .reg_offset = 0, .mask = PWRON_D4SR_INT_MASK },
     29	{ .reg_offset = 0, .mask = PWRON_D20F_INT_MASK },
     30	{ .reg_offset = 0, .mask = PWRON_D20R_INT_MASK },
     31	{ .reg_offset = 0, .mask = RESERVE_INT_MASK },
     32};
     33
     34static const struct regmap_irq_chip hi655x_irq_chip = {
     35	.name = "hi655x-pmic",
     36	.irqs = hi655x_irqs,
     37	.num_regs = 1,
     38	.num_irqs = ARRAY_SIZE(hi655x_irqs),
     39	.status_base = HI655X_IRQ_STAT_BASE,
     40	.ack_base = HI655X_IRQ_STAT_BASE,
     41	.mask_base = HI655X_IRQ_MASK_BASE,
     42};
     43
     44static struct regmap_config hi655x_regmap_config = {
     45	.reg_bits = 32,
     46	.reg_stride = HI655X_STRIDE,
     47	.val_bits = 8,
     48	.max_register = HI655X_BUS_ADDR(0x400) - HI655X_STRIDE,
     49};
     50
     51static const struct resource pwrkey_resources[] = {
     52	{
     53		.name	= "down",
     54		.start	= PWRON_D20R_INT,
     55		.end	= PWRON_D20R_INT,
     56		.flags	= IORESOURCE_IRQ,
     57	}, {
     58		.name	= "up",
     59		.start	= PWRON_D20F_INT,
     60		.end	= PWRON_D20F_INT,
     61		.flags	= IORESOURCE_IRQ,
     62	}, {
     63		.name	= "hold 4s",
     64		.start	= PWRON_D4SR_INT,
     65		.end	= PWRON_D4SR_INT,
     66		.flags	= IORESOURCE_IRQ,
     67	},
     68};
     69
     70static const struct mfd_cell hi655x_pmic_devs[] = {
     71	{
     72		.name		= "hi65xx-powerkey",
     73		.num_resources	= ARRAY_SIZE(pwrkey_resources),
     74		.resources	= &pwrkey_resources[0],
     75	},
     76	{	.name		= "hi655x-regulator",	},
     77	{	.name		= "hi655x-clk",		},
     78};
     79
     80static void hi655x_local_irq_clear(struct regmap *map)
     81{
     82	int i;
     83
     84	regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR);
     85	for (i = 0; i < HI655X_IRQ_ARRAY; i++) {
     86		regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE,
     87			     HI655X_IRQ_CLR);
     88	}
     89}
     90
     91static int hi655x_pmic_probe(struct platform_device *pdev)
     92{
     93	int ret;
     94	struct hi655x_pmic *pmic;
     95	struct device *dev = &pdev->dev;
     96	void __iomem *base;
     97
     98	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
     99	if (!pmic)
    100		return -ENOMEM;
    101	pmic->dev = dev;
    102
    103	pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    104	base = devm_ioremap_resource(dev, pmic->res);
    105	if (IS_ERR(base))
    106		return PTR_ERR(base);
    107
    108	pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
    109						 &hi655x_regmap_config);
    110	if (IS_ERR(pmic->regmap))
    111		return PTR_ERR(pmic->regmap);
    112
    113	regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
    114	if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
    115		dev_warn(dev, "PMU version %d unsupported\n", pmic->ver);
    116		return -EINVAL;
    117	}
    118
    119	hi655x_local_irq_clear(pmic->regmap);
    120
    121	pmic->gpio = devm_gpiod_get_optional(dev, "pmic", GPIOD_IN);
    122	if (IS_ERR(pmic->gpio))
    123		return dev_err_probe(dev, PTR_ERR(pmic->gpio),
    124				"Failed to request hi655x pmic-gpio");
    125
    126	ret = regmap_add_irq_chip(pmic->regmap, gpiod_to_irq(pmic->gpio),
    127				  IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0,
    128				  &hi655x_irq_chip, &pmic->irq_data);
    129	if (ret) {
    130		dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret);
    131		return ret;
    132	}
    133
    134	platform_set_drvdata(pdev, pmic);
    135
    136	ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs,
    137			      ARRAY_SIZE(hi655x_pmic_devs), NULL, 0,
    138			      regmap_irq_get_domain(pmic->irq_data));
    139	if (ret) {
    140		dev_err(dev, "Failed to register device %d\n", ret);
    141		regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
    142		return ret;
    143	}
    144
    145	return 0;
    146}
    147
    148static int hi655x_pmic_remove(struct platform_device *pdev)
    149{
    150	struct hi655x_pmic *pmic = platform_get_drvdata(pdev);
    151
    152	regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
    153	mfd_remove_devices(&pdev->dev);
    154	return 0;
    155}
    156
    157static const struct of_device_id hi655x_pmic_match[] = {
    158	{ .compatible = "hisilicon,hi655x-pmic", },
    159	{},
    160};
    161MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
    162
    163static struct platform_driver hi655x_pmic_driver = {
    164	.driver	= {
    165		.name =	"hi655x-pmic",
    166		.of_match_table = of_match_ptr(hi655x_pmic_match),
    167	},
    168	.probe  = hi655x_pmic_probe,
    169	.remove = hi655x_pmic_remove,
    170};
    171module_platform_driver(hi655x_pmic_driver);
    172
    173MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
    174MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver");
    175MODULE_LICENSE("GPL v2");