]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/media/i2c/power_ctrl_logic.c
1ccd94f9e97e3594ea61312a5cbc3619e5ac36d8
[mirror_ubuntu-jammy-kernel.git] / drivers / media / i2c / power_ctrl_logic.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020-2021 Intel Corporation.
3
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>
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 };
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
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
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 };
57
58 static int power_ctrl_logic_add(struct acpi_device *adev)
59 {
60 int i, ret;
61
62 dev_dbg(&adev->dev, "@%s, enter\n", __func__);
63 set_primary_fwnode(&adev->dev, &adev->fwnode);
64
65 ret = acpi_dev_add_driver_gpios(adev, dsc1_acpi_gpios);
66 if (ret) {
67 dev_err(&adev->dev, "@%s: --111---fail to add gpio. ret %d\n", __func__, ret);
68 return -EBUSY;
69 }
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 }
78
79 mutex_lock(&pcl.status_lock);
80 pcl.gpio_ready = true;
81 mutex_unlock(&pcl.status_lock);
82
83 dev_dbg(&adev->dev, "@%s, exit\n", __func__);
84 return ret;
85 }
86
87 static int power_ctrl_logic_remove(struct acpi_device *adev)
88 {
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__);
102 return 0;
103 }
104
105 static struct acpi_device_id acpi_ids[] = {
106 { "INT3472", 0 },
107 { },
108 };
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 },
119 };
120 module_acpi_driver(_driver);
121
122 int power_ctrl_logic_set_power(int on)
123 {
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;
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");