1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Power off driver for ams AS3722 device.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Laxman Dewangan <ldewangan@nvidia.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/mfd/as3722.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/of_device.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun struct as3722_poweroff {
18*4882a593Smuzhiyun struct device *dev;
19*4882a593Smuzhiyun struct as3722 *as3722;
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static struct as3722_poweroff *as3722_pm_poweroff;
23*4882a593Smuzhiyun
as3722_pm_power_off(void)24*4882a593Smuzhiyun static void as3722_pm_power_off(void)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun int ret;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (!as3722_pm_poweroff) {
29*4882a593Smuzhiyun pr_err("AS3722 poweroff is not initialised\n");
30*4882a593Smuzhiyun return;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun ret = as3722_update_bits(as3722_pm_poweroff->as3722,
34*4882a593Smuzhiyun AS3722_RESET_CONTROL_REG, AS3722_POWER_OFF, AS3722_POWER_OFF);
35*4882a593Smuzhiyun if (ret < 0)
36*4882a593Smuzhiyun dev_err(as3722_pm_poweroff->dev,
37*4882a593Smuzhiyun "RESET_CONTROL_REG update failed, %d\n", ret);
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
as3722_poweroff_probe(struct platform_device * pdev)40*4882a593Smuzhiyun static int as3722_poweroff_probe(struct platform_device *pdev)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun struct as3722_poweroff *as3722_poweroff;
43*4882a593Smuzhiyun struct device_node *np = pdev->dev.parent->of_node;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (!np)
46*4882a593Smuzhiyun return -EINVAL;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (!of_property_read_bool(np, "ams,system-power-controller"))
49*4882a593Smuzhiyun return 0;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun as3722_poweroff = devm_kzalloc(&pdev->dev, sizeof(*as3722_poweroff),
52*4882a593Smuzhiyun GFP_KERNEL);
53*4882a593Smuzhiyun if (!as3722_poweroff)
54*4882a593Smuzhiyun return -ENOMEM;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun as3722_poweroff->as3722 = dev_get_drvdata(pdev->dev.parent);
57*4882a593Smuzhiyun as3722_poweroff->dev = &pdev->dev;
58*4882a593Smuzhiyun as3722_pm_poweroff = as3722_poweroff;
59*4882a593Smuzhiyun if (!pm_power_off)
60*4882a593Smuzhiyun pm_power_off = as3722_pm_power_off;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
as3722_poweroff_remove(struct platform_device * pdev)65*4882a593Smuzhiyun static int as3722_poweroff_remove(struct platform_device *pdev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun if (pm_power_off == as3722_pm_power_off)
68*4882a593Smuzhiyun pm_power_off = NULL;
69*4882a593Smuzhiyun as3722_pm_poweroff = NULL;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun return 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun static struct platform_driver as3722_poweroff_driver = {
75*4882a593Smuzhiyun .driver = {
76*4882a593Smuzhiyun .name = "as3722-power-off",
77*4882a593Smuzhiyun },
78*4882a593Smuzhiyun .probe = as3722_poweroff_probe,
79*4882a593Smuzhiyun .remove = as3722_poweroff_remove,
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun module_platform_driver(as3722_poweroff_driver);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun MODULE_DESCRIPTION("Power off driver for ams AS3722 PMIC Device");
85*4882a593Smuzhiyun MODULE_ALIAS("platform:as3722-power-off");
86*4882a593Smuzhiyun MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
87*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
88