mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
Add max77851 pmic power driver provided by MAXIM. Bug 200749982 Change-Id: I44cbf11526eb83aa5722f780db4e9a7b6352151c Signed-off-by: Shubhi Garg <shgarg@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.10/+/2693149 Signed-off-by: Bitan Biswas <bbiswas@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2960842 GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
165 lines
4.6 KiB
C
165 lines
4.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
/*
|
|
* Maxim MAX77851 Power Driver
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/mfd/max77851.h>
|
|
#include <linux/module.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/slab.h>
|
|
|
|
struct max77851_poweroff {
|
|
struct regmap *rmap;
|
|
struct device *dev;
|
|
};
|
|
|
|
static struct max77851_poweroff *system_power_off;
|
|
|
|
static void max77851_pm_power_off(void)
|
|
{
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
// TOP_INT0 : read only
|
|
// TOP_INT1 : read clear
|
|
// In Any state, use SW_OFF with SRC_SW_OFF = 0b1 to PD.
|
|
// Use SW_COLD_RST with SRC_SW_COLD_RST = 0b1 to reset O-Type registers after a PD and PU
|
|
|
|
// TOP_INT1_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, TOP_INT1_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// EN_INT_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, EN_INT_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// GPIO_INT0_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, GPIO_INT0_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// GPIO_INT1_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, GPIO_INT1_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// FPS_INT0_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, FPS_INT0_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// FPS_INT1_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, FPS_INT1_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// LDO_INT0_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, LDO_INT0_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// LDO_INT1_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, LDO_INT1_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// BUCK_INT0_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, BUCK_INT0_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// BUCK_INT1_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, BUCK_INT1_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// BUCK_INT2_REG : Read Clear
|
|
ret = regmap_read(system_power_off->rmap, BUCK_INT2_REG, &val);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to read %d\n", ret);
|
|
|
|
// Source Software Off Enabled
|
|
ret = regmap_update_bits(system_power_off->rmap, FPS_SRC_CFG1_REG,
|
|
FPS_SRC_CFG1_SRC_SW_OFF, FPS_SRC_CFG1_SRC_SW_OFF);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to set Source SW Off %d\n", ret);
|
|
|
|
// Software Off Event
|
|
ret = regmap_write(system_power_off->rmap, FPS_SW_REG, FPS_SW_OFF);
|
|
if (ret < 0)
|
|
dev_err(system_power_off->dev, "Failed to set SW Off Event %d\n", ret);
|
|
}
|
|
|
|
static int max77851_poweroff_probe(struct platform_device *pdev)
|
|
{
|
|
struct max77851_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
|
struct device_node *np = pdev->dev.parent->of_node;
|
|
struct max77851_poweroff *poweroff;
|
|
u8 data[3];
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
if (!of_device_is_system_power_controller(np))
|
|
return 0;
|
|
|
|
poweroff = devm_kzalloc(&pdev->dev, sizeof(*poweroff), GFP_KERNEL);
|
|
if (!poweroff)
|
|
return -ENOMEM;
|
|
|
|
poweroff->rmap = chip->rmap;
|
|
poweroff->dev = &pdev->dev;
|
|
|
|
ret = regmap_read(poweroff->rmap, RLOGIC_INT0_REG, &val);
|
|
if (ret < 0) {
|
|
dev_err(poweroff->dev, "failed to read power event : %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = regmap_bulk_read(poweroff->rmap, RLOGIC_INT0_REG, data, ARRAY_SIZE(data));
|
|
if (ret < 0) {
|
|
dev_err(poweroff->dev, "failed to read power event : %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
dev_dbg(poweroff->dev, "power event: 0x%#x, 0x%#x, 0x%#x\n",
|
|
data[0], data[1], data[2]);
|
|
|
|
system_power_off = poweroff;
|
|
|
|
if (!pm_power_off)
|
|
pm_power_off = max77851_pm_power_off;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static struct platform_device_id max77851_poweroff_devtype[] = {
|
|
{ .name = "max77851-power", },
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver max77851_poweroff_driver = {
|
|
.driver = {
|
|
.name = "max77851-power",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.probe = max77851_poweroff_probe,
|
|
.id_table = max77851_poweroff_devtype,
|
|
};
|
|
|
|
module_platform_driver(max77851_poweroff_driver);
|
|
|
|
MODULE_DESCRIPTION("MAX77851 power driver");
|
|
MODULE_AUTHOR("Shubhi Garg<shgarg@nvidia.com>");
|
|
MODULE_AUTHOR("Joan Na<Joan.na@maximintegrated.com>");
|
|
MODULE_ALIAS("platform:max77851-power");
|
|
MODULE_LICENSE("GPL v2");
|