]>
Commit | Line | Data |
---|---|---|
eaffc3a7 WY |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2020-2021 Intel Corporation. | |
3 | ||
85301793 | 4 | #include <linux/acpi.h> |
eaffc3a7 | 5 | #include <linux/module.h> |
85301793 WY |
6 | #include <linux/device.h> |
7 | #include <linux/mutex.h> | |
8 | #include <linux/gpio/consumer.h> | |
9 | ||
10 | #define PCL_DRV_NAME "power_ctrl_logic" | |
11 | ||
12 | struct power_ctrl_logic { | |
13 | /* gpio resource*/ | |
14 | struct gpio_desc *reset_gpio; | |
15 | struct gpio_desc *powerdn_gpio; | |
16 | struct gpio_desc *clocken_gpio; | |
17 | struct gpio_desc *indled_gpio; | |
18 | /* status */ | |
19 | struct mutex status_lock; | |
20 | bool power_on; | |
21 | bool gpio_ready; | |
22 | }; | |
23 | ||
24 | struct power_ctrl_gpio { | |
25 | const char *name; | |
26 | struct gpio_desc **pin; | |
27 | }; | |
eaffc3a7 WY |
28 | |
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 }, | |
39 | { } | |
40 | }; | |
41 | ||
eaffc3a7 WY |
42 | static struct power_ctrl_logic pcl = { |
43 | .reset_gpio = NULL, | |
44 | .powerdn_gpio = NULL, | |
45 | .clocken_gpio = NULL, | |
46 | .indled_gpio = NULL, | |
47 | .power_on = false, | |
48 | .gpio_ready = false, | |
49 | }; | |
50 | ||
85301793 WY |
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}, | |
56 | }; | |
eaffc3a7 | 57 | |
85301793 | 58 | static int power_ctrl_logic_add(struct acpi_device *adev) |
eaffc3a7 | 59 | { |
85301793 | 60 | int i, ret; |
eaffc3a7 | 61 | |
85301793 WY |
62 | dev_dbg(&adev->dev, "@%s, enter\n", __func__); |
63 | set_primary_fwnode(&adev->dev, &adev->fwnode); | |
eaffc3a7 | 64 | |
85301793 | 65 | ret = acpi_dev_add_driver_gpios(adev, dsc1_acpi_gpios); |
eaffc3a7 | 66 | if (ret) { |
85301793 | 67 | dev_err(&adev->dev, "@%s: --111---fail to add gpio. ret %d\n", __func__, ret); |
eaffc3a7 WY |
68 | return -EBUSY; |
69 | } | |
85301793 WY |
70 | |
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); | |
75 | return -EPROBE_DEFER; | |
76 | } | |
77 | } | |
eaffc3a7 WY |
78 | |
79 | mutex_lock(&pcl.status_lock); | |
80 | pcl.gpio_ready = true; | |
81 | mutex_unlock(&pcl.status_lock); | |
82 | ||
85301793 | 83 | dev_dbg(&adev->dev, "@%s, exit\n", __func__); |
eaffc3a7 WY |
84 | return ret; |
85 | } | |
86 | ||
85301793 | 87 | static int power_ctrl_logic_remove(struct acpi_device *adev) |
eaffc3a7 | 88 | { |
85301793 | 89 | dev_dbg(&adev->dev, "@%s, enter\n", __func__); |
eaffc3a7 WY |
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); | |
85301793 WY |
101 | dev_dbg(&adev->dev, "@%s, exit\n", __func__); |
102 | return 0; | |
eaffc3a7 WY |
103 | } |
104 | ||
85301793 WY |
105 | static struct acpi_device_id acpi_ids[] = { |
106 | { "INT3472", 0 }, | |
107 | { }, | |
eaffc3a7 | 108 | }; |
85301793 WY |
109 | MODULE_DEVICE_TABLE(acpi, acpi_ids); |
110 | ||
111 | static struct acpi_driver _driver = { | |
112 | .name = PCL_DRV_NAME, | |
113 | .class = PCL_DRV_NAME, | |
114 | .ids = acpi_ids, | |
115 | .ops = { | |
116 | .add = power_ctrl_logic_add, | |
117 | .remove = power_ctrl_logic_remove, | |
118 | }, | |
eaffc3a7 | 119 | }; |
85301793 | 120 | module_acpi_driver(_driver); |
eaffc3a7 WY |
121 | |
122 | int power_ctrl_logic_set_power(int on) | |
123 | { | |
124 | mutex_lock(&pcl.status_lock); | |
85301793 | 125 | if (!pcl.gpio_ready) { |
eaffc3a7 WY |
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); | |
af730376 | 129 | return -EPROBE_DEFER; |
eaffc3a7 WY |
130 | } |
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); | |
136 | pcl.power_on = on; | |
137 | } | |
138 | mutex_unlock(&pcl.status_lock); | |
139 | return 0; | |
140 | } | |
141 | EXPORT_SYMBOL_GPL(power_ctrl_logic_set_power); | |
142 | ||
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"); |