mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 13:41:55 +00:00
dc0c386e09
The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring <robh@kernel.org> Link: https://lore.kernel.org/r/20230714174731.4059811-1-robh@kernel.org Signed-off-by: Lee Jones <lee@kernel.org>
175 lines
4.5 KiB
C
175 lines
4.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Device driver for MFD hi655x PMIC
|
|
*
|
|
* Copyright (c) 2016 HiSilicon Ltd.
|
|
*
|
|
* Authors:
|
|
* Chen Feng <puck.chen@hisilicon.com>
|
|
* Fei Wang <w.f@huawei.com>
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/init.h>
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/mfd/hi655x-pmic.h>
|
|
#include <linux/module.h>
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/mod_devicetable.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regmap.h>
|
|
|
|
static const struct regmap_irq hi655x_irqs[] = {
|
|
{ .reg_offset = 0, .mask = OTMP_D1R_INT_MASK },
|
|
{ .reg_offset = 0, .mask = VSYS_2P5_R_INT_MASK },
|
|
{ .reg_offset = 0, .mask = VSYS_UV_D3R_INT_MASK },
|
|
{ .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT_MASK },
|
|
{ .reg_offset = 0, .mask = PWRON_D4SR_INT_MASK },
|
|
{ .reg_offset = 0, .mask = PWRON_D20F_INT_MASK },
|
|
{ .reg_offset = 0, .mask = PWRON_D20R_INT_MASK },
|
|
{ .reg_offset = 0, .mask = RESERVE_INT_MASK },
|
|
};
|
|
|
|
static const struct regmap_irq_chip hi655x_irq_chip = {
|
|
.name = "hi655x-pmic",
|
|
.irqs = hi655x_irqs,
|
|
.num_regs = 1,
|
|
.num_irqs = ARRAY_SIZE(hi655x_irqs),
|
|
.status_base = HI655X_IRQ_STAT_BASE,
|
|
.ack_base = HI655X_IRQ_STAT_BASE,
|
|
.mask_base = HI655X_IRQ_MASK_BASE,
|
|
};
|
|
|
|
static struct regmap_config hi655x_regmap_config = {
|
|
.reg_bits = 32,
|
|
.reg_stride = HI655X_STRIDE,
|
|
.val_bits = 8,
|
|
.max_register = HI655X_BUS_ADDR(0x400) - HI655X_STRIDE,
|
|
};
|
|
|
|
static const struct resource pwrkey_resources[] = {
|
|
{
|
|
.name = "down",
|
|
.start = PWRON_D20R_INT,
|
|
.end = PWRON_D20R_INT,
|
|
.flags = IORESOURCE_IRQ,
|
|
}, {
|
|
.name = "up",
|
|
.start = PWRON_D20F_INT,
|
|
.end = PWRON_D20F_INT,
|
|
.flags = IORESOURCE_IRQ,
|
|
}, {
|
|
.name = "hold 4s",
|
|
.start = PWRON_D4SR_INT,
|
|
.end = PWRON_D4SR_INT,
|
|
.flags = IORESOURCE_IRQ,
|
|
},
|
|
};
|
|
|
|
static const struct mfd_cell hi655x_pmic_devs[] = {
|
|
{
|
|
.name = "hi65xx-powerkey",
|
|
.num_resources = ARRAY_SIZE(pwrkey_resources),
|
|
.resources = &pwrkey_resources[0],
|
|
},
|
|
{ .name = "hi655x-regulator", },
|
|
{ .name = "hi655x-clk", },
|
|
};
|
|
|
|
static void hi655x_local_irq_clear(struct regmap *map)
|
|
{
|
|
int i;
|
|
|
|
regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR);
|
|
for (i = 0; i < HI655X_IRQ_ARRAY; i++) {
|
|
regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE,
|
|
HI655X_IRQ_CLR);
|
|
}
|
|
}
|
|
|
|
static int hi655x_pmic_probe(struct platform_device *pdev)
|
|
{
|
|
int ret;
|
|
struct hi655x_pmic *pmic;
|
|
struct device *dev = &pdev->dev;
|
|
void __iomem *base;
|
|
|
|
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
|
|
if (!pmic)
|
|
return -ENOMEM;
|
|
pmic->dev = dev;
|
|
|
|
base = devm_platform_ioremap_resource(pdev, 0);
|
|
if (IS_ERR(base))
|
|
return PTR_ERR(base);
|
|
|
|
pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
|
|
&hi655x_regmap_config);
|
|
if (IS_ERR(pmic->regmap))
|
|
return PTR_ERR(pmic->regmap);
|
|
|
|
regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
|
|
if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
|
|
dev_warn(dev, "PMU version %d unsupported\n", pmic->ver);
|
|
return -EINVAL;
|
|
}
|
|
|
|
hi655x_local_irq_clear(pmic->regmap);
|
|
|
|
pmic->gpio = devm_gpiod_get_optional(dev, "pmic", GPIOD_IN);
|
|
if (IS_ERR(pmic->gpio))
|
|
return dev_err_probe(dev, PTR_ERR(pmic->gpio),
|
|
"Failed to request hi655x pmic-gpio");
|
|
|
|
ret = regmap_add_irq_chip(pmic->regmap, gpiod_to_irq(pmic->gpio),
|
|
IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0,
|
|
&hi655x_irq_chip, &pmic->irq_data);
|
|
if (ret) {
|
|
dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, pmic);
|
|
|
|
ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs,
|
|
ARRAY_SIZE(hi655x_pmic_devs), NULL, 0,
|
|
regmap_irq_get_domain(pmic->irq_data));
|
|
if (ret) {
|
|
dev_err(dev, "Failed to register device %d\n", ret);
|
|
regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hi655x_pmic_remove(struct platform_device *pdev)
|
|
{
|
|
struct hi655x_pmic *pmic = platform_get_drvdata(pdev);
|
|
|
|
regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
|
|
mfd_remove_devices(&pdev->dev);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id hi655x_pmic_match[] = {
|
|
{ .compatible = "hisilicon,hi655x-pmic", },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
|
|
|
|
static struct platform_driver hi655x_pmic_driver = {
|
|
.driver = {
|
|
.name = "hi655x-pmic",
|
|
.of_match_table = hi655x_pmic_match,
|
|
},
|
|
.probe = hi655x_pmic_probe,
|
|
.remove = hi655x_pmic_remove,
|
|
};
|
|
module_platform_driver(hi655x_pmic_driver);
|
|
|
|
MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
|
|
MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver");
|
|
MODULE_LICENSE("GPL v2");
|