1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020-2021 Intel Corporation.
4 #include <linux/acpi.h>
5 #include <linux/module.h>
6 #include <linux/device.h>
7 #include <linux/mutex.h>
8 #include <linux/gpio/consumer.h>
10 #define PCL_DRV_NAME "power_ctrl_logic"
12 struct power_ctrl_logic
{
14 struct gpio_desc
*reset_gpio
;
15 struct gpio_desc
*powerdn_gpio
;
16 struct gpio_desc
*clocken_gpio
;
17 struct gpio_desc
*indled_gpio
;
19 struct mutex status_lock
;
24 struct power_ctrl_gpio
{
26 struct gpio_desc
**pin
;
29 /* mcu gpio resources*/
30 static const struct acpi_gpio_params camreset_gpio
= { 0, 0, false };
31 static const struct acpi_gpio_params campwdn_gpio
= { 1, 0, false };
32 static const struct acpi_gpio_params midmclken_gpio
= { 2, 0, false };
33 static const struct acpi_gpio_params led_gpio
= { 3, 0, false };
34 static const struct acpi_gpio_mapping dsc1_acpi_gpios
[] = {
35 { "camreset-gpios", &camreset_gpio
, 1 },
36 { "campwdn-gpios", &campwdn_gpio
, 1 },
37 { "midmclken-gpios", &midmclken_gpio
, 1 },
38 { "indled-gpios", &led_gpio
, 1 },
42 static struct power_ctrl_logic pcl
= {
51 static struct power_ctrl_gpio pcl_gpios
[] = {
52 { "camreset", &pcl
.reset_gpio
},
53 { "campwdn", &pcl
.powerdn_gpio
},
54 { "midmclken", &pcl
.clocken_gpio
},
55 { "indled", &pcl
.indled_gpio
},
58 static int power_ctrl_logic_add(struct acpi_device
*adev
)
62 dev_dbg(&adev
->dev
, "@%s, enter\n", __func__
);
63 set_primary_fwnode(&adev
->dev
, &adev
->fwnode
);
65 ret
= acpi_dev_add_driver_gpios(adev
, dsc1_acpi_gpios
);
67 dev_err(&adev
->dev
, "@%s: --111---fail to add gpio. ret %d\n", __func__
, ret
);
71 for (i
= 0; i
< ARRAY_SIZE(pcl_gpios
); i
++) {
72 *pcl_gpios
[i
].pin
= gpiod_get(&adev
->dev
, pcl_gpios
[i
].name
, GPIOD_OUT_LOW
);
73 if (IS_ERR(*pcl_gpios
[i
].pin
)) {
74 dev_dbg(&adev
->dev
, "failed to get gpio %s\n", pcl_gpios
[i
].name
);
79 mutex_lock(&pcl
.status_lock
);
80 pcl
.gpio_ready
= true;
81 mutex_unlock(&pcl
.status_lock
);
83 dev_dbg(&adev
->dev
, "@%s, exit\n", __func__
);
87 static int power_ctrl_logic_remove(struct acpi_device
*adev
)
89 dev_dbg(&adev
->dev
, "@%s, enter\n", __func__
);
90 mutex_lock(&pcl
.status_lock
);
91 pcl
.gpio_ready
= false;
92 gpiod_set_value_cansleep(pcl
.reset_gpio
, 0);
93 gpiod_put(pcl
.reset_gpio
);
94 gpiod_set_value_cansleep(pcl
.powerdn_gpio
, 0);
95 gpiod_put(pcl
.powerdn_gpio
);
96 gpiod_set_value_cansleep(pcl
.clocken_gpio
, 0);
97 gpiod_put(pcl
.clocken_gpio
);
98 gpiod_set_value_cansleep(pcl
.indled_gpio
, 0);
99 gpiod_put(pcl
.indled_gpio
);
100 mutex_unlock(&pcl
.status_lock
);
101 dev_dbg(&adev
->dev
, "@%s, exit\n", __func__
);
105 static struct acpi_device_id acpi_ids
[] = {
109 MODULE_DEVICE_TABLE(acpi
, acpi_ids
);
111 static struct acpi_driver _driver
= {
112 .name
= PCL_DRV_NAME
,
113 .class = PCL_DRV_NAME
,
116 .add
= power_ctrl_logic_add
,
117 .remove
= power_ctrl_logic_remove
,
120 module_acpi_driver(_driver
);
122 int power_ctrl_logic_set_power(int on
)
124 mutex_lock(&pcl
.status_lock
);
125 if (!pcl
.gpio_ready
) {
126 pr_debug("@%s,failed to set power, gpio_ready=%d, on=%d\n",
127 __func__
, pcl
.gpio_ready
, on
);
128 mutex_unlock(&pcl
.status_lock
);
129 return -EPROBE_DEFER
;
131 if (pcl
.power_on
!= on
) {
132 gpiod_set_value_cansleep(pcl
.reset_gpio
, on
);
133 gpiod_set_value_cansleep(pcl
.powerdn_gpio
, on
);
134 gpiod_set_value_cansleep(pcl
.clocken_gpio
, on
);
135 gpiod_set_value_cansleep(pcl
.indled_gpio
, on
);
138 mutex_unlock(&pcl
.status_lock
);
141 EXPORT_SYMBOL_GPL(power_ctrl_logic_set_power
);
143 MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
144 MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
145 MODULE_AUTHOR("Xu, Chongyang <chongyang.xu@intel.com>");
146 MODULE_DESCRIPTION("Power Control Logic Driver");
147 MODULE_LICENSE("GPL v2");