blob: 82cb5db5cc8bc0f34f82aa16947b724784dda8bb [file] [log] [blame]
Simon Glass31cc5b42020-09-22 12:45:01 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Google LLC
4 */
5
Simon Glass31cc5b42020-09-22 12:45:01 -06006#include <dm.h>
7#include <i2c.h>
8#include <log.h>
9#include <acpi/acpi_device.h>
10#include <acpi/acpigen.h>
11#include <acpi/acpi_dp.h>
12#ifdef CONFIG_X86
13#include <asm/intel_pinctrl_defs.h>
14#endif
15#include <asm-generic/gpio.h>
16#include <dm/acpi.h>
17
18static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv *priv)
19{
20 /*
21 * Return false if:
22 * 1. Request to explicitly disable export of GPIOs in CRS, or
23 * 2. Both reset and enable GPIOs are not provided.
24 */
25 if (priv->disable_gpio_export_in_crs ||
26 (!dm_gpio_is_valid(&priv->reset_gpio) &&
27 !dm_gpio_is_valid(&priv->enable_gpio)))
28 return false;
29
30 return true;
31}
32
33static int acpi_i2c_write_gpio(struct acpi_ctx *ctx, struct gpio_desc *gpio,
34 int *curindex)
35{
36 int ret;
37
38 if (!dm_gpio_is_valid(gpio))
39 return -ENOENT;
40
41 acpi_device_write_gpio_desc(ctx, gpio);
42 ret = *curindex;
43 (*curindex)++;
44
45 return ret;
46}
47
48int acpi_i2c_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
49{
50 int reset_gpio_index = -1, enable_gpio_index = -1, irq_gpio_index = -1;
51 enum i2c_device_t type = dev_get_driver_data(dev);
52 struct acpi_i2c_priv *priv = dev_get_priv(dev);
53 struct acpi_dp *dsd = NULL;
54 char scope[ACPI_PATH_MAX];
55 char name[ACPI_NAME_MAX];
56 int tx_state_val;
57 int curindex = 0;
58 int ret;
59
60#ifdef CONFIG_X86
61 tx_state_val = PAD_CFG0_TX_STATE;
62#elif defined(CONFIG_SANDBOX)
63 tx_state_val = BIT(7); /* test value */
64#else
65#error "Not supported on this architecture"
66#endif
67 ret = acpi_get_name(dev, name);
68 if (ret)
69 return log_msg_ret("name", ret);
70 ret = acpi_device_scope(dev, scope, sizeof(scope));
71 if (ret)
72 return log_msg_ret("scope", ret);
73
74 /* Device */
75 acpigen_write_scope(ctx, scope);
76 acpigen_write_device(ctx, name);
77 acpigen_write_name_string(ctx, "_HID", priv->hid);
78 if (type == I2C_DEVICE_HID_OVER_I2C)
79 acpigen_write_name_string(ctx, "_CID", "PNP0C50");
80 acpigen_write_name_integer(ctx, "_UID", priv->uid);
81 acpigen_write_name_string(ctx, "_DDN", priv->desc);
82 acpigen_write_sta(ctx, acpi_device_status(dev));
83
84 /* Resources */
85 acpigen_write_name(ctx, "_CRS");
86 acpigen_write_resourcetemplate_header(ctx);
87 acpi_device_write_i2c_dev(ctx, dev);
88
89 /* Use either Interrupt() or GpioInt() */
90 if (dm_gpio_is_valid(&priv->irq_gpio)) {
91 irq_gpio_index = acpi_i2c_write_gpio(ctx, &priv->irq_gpio,
92 &curindex);
93 } else {
94 ret = acpi_device_write_interrupt_irq(ctx, &priv->irq);
95 if (ret < 0)
96 return log_msg_ret("irq", ret);
97 }
98
99 if (acpi_i2c_add_gpios_to_crs(priv)) {
100 reset_gpio_index = acpi_i2c_write_gpio(ctx, &priv->reset_gpio,
101 &curindex);
102 enable_gpio_index = acpi_i2c_write_gpio(ctx, &priv->enable_gpio,
103 &curindex);
104 }
105 acpigen_write_resourcetemplate_footer(ctx);
106
107 /* Wake capabilities */
108 if (priv->wake) {
109 acpigen_write_name_integer(ctx, "_S0W", 4);
110 acpigen_write_prw(ctx, priv->wake, 3);
111 }
112
113 /* DSD */
114 if (priv->probed || priv->property_count || priv->compat_string ||
115 reset_gpio_index >= 0 || enable_gpio_index >= 0 ||
116 irq_gpio_index >= 0) {
117 char path[ACPI_PATH_MAX];
118
119 ret = acpi_device_path(dev, path, sizeof(path));
120 if (ret)
121 return log_msg_ret("path", ret);
122
123 dsd = acpi_dp_new_table("_DSD");
124 if (priv->compat_string)
125 acpi_dp_add_string(dsd, "compatible",
126 priv->compat_string);
127 if (priv->probed)
128 acpi_dp_add_integer(dsd, "linux,probed", 1);
129 if (irq_gpio_index >= 0)
130 acpi_dp_add_gpio(dsd, "irq-gpios", path,
131 irq_gpio_index, 0,
132 priv->irq_gpio.flags &
133 GPIOD_ACTIVE_LOW ?
134 ACPI_GPIO_ACTIVE_LOW : 0);
135 if (reset_gpio_index >= 0)
136 acpi_dp_add_gpio(dsd, "reset-gpios", path,
137 reset_gpio_index, 0,
138 priv->reset_gpio.flags &
139 GPIOD_ACTIVE_LOW ?
140 ACPI_GPIO_ACTIVE_LOW : 0);
141 if (enable_gpio_index >= 0)
142 acpi_dp_add_gpio(dsd, "enable-gpios", path,
143 enable_gpio_index, 0,
144 priv->enable_gpio.flags &
145 GPIOD_ACTIVE_LOW ?
146 ACPI_GPIO_ACTIVE_LOW : 0);
147 /* Generic property list is not supported */
148 acpi_dp_write(ctx, dsd);
149 }
150
151 /* Power Resource */
152 if (priv->has_power_resource) {
153 ret = acpi_device_add_power_res(ctx, tx_state_val,
154 "\\_SB.GPC0", "\\_SB.SPC0",
155 &priv->reset_gpio, priv->reset_delay_ms,
156 priv->reset_off_delay_ms, &priv->enable_gpio,
157 priv->enable_delay_ms, priv->enable_off_delay_ms,
158 &priv->stop_gpio, priv->stop_delay_ms,
159 priv->stop_off_delay_ms);
160 if (ret)
161 return log_msg_ret("power", ret);
162 }
163 if (priv->hid_desc_reg_offset) {
164 ret = acpi_device_write_dsm_i2c_hid(ctx,
165 priv->hid_desc_reg_offset);
166 if (ret)
167 return log_msg_ret("dsm", ret);
168 }
169
170 acpigen_pop_len(ctx); /* Device */
171 acpigen_pop_len(ctx); /* Scope */
172
173 return 0;
174}
175
Simon Glassaad29ae2020-12-03 16:55:21 -0700176int acpi_i2c_of_to_plat(struct udevice *dev)
Simon Glass31cc5b42020-09-22 12:45:01 -0600177{
178 struct acpi_i2c_priv *priv = dev_get_priv(dev);
179
180 gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
181 GPIOD_IS_OUT);
182 gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio,
183 GPIOD_IS_OUT);
184 gpio_request_by_name(dev, "irq-gpios", 0, &priv->irq_gpio, GPIOD_IS_IN);
185 gpio_request_by_name(dev, "stop-gpios", 0, &priv->stop_gpio,
186 GPIOD_IS_OUT);
187 irq_get_by_index(dev, 0, &priv->irq);
188 priv->hid = dev_read_string(dev, "acpi,hid");
189 if (!priv->hid)
190 return log_msg_ret("hid", -EINVAL);
191 dev_read_u32(dev, "acpi,uid", &priv->uid);
192 priv->desc = dev_read_string(dev, "acpi,ddn");
193 dev_read_u32(dev, "acpi,wake", &priv->wake);
194 priv->probed = dev_read_bool(dev, "linux,probed");
195 priv->compat_string = dev_read_string(dev, "acpi,compatible");
196 priv->has_power_resource = dev_read_bool(dev,
197 "acpi,has-power-resource");
198 dev_read_u32(dev, "hid-descr-addr", &priv->hid_desc_reg_offset);
199 dev_read_u32(dev, "reset-delay-ms", &priv->reset_delay_ms);
200 dev_read_u32(dev, "reset-off-delay-ms", &priv->reset_off_delay_ms);
201 dev_read_u32(dev, "enable-delay-ms", &priv->enable_delay_ms);
202 dev_read_u32(dev, "enable-off-delay-ms", &priv->enable_off_delay_ms);
203 dev_read_u32(dev, "stop-delay-ms", &priv->stop_delay_ms);
204 dev_read_u32(dev, "stop-off-delay-ms", &priv->stop_off_delay_ms);
205
206 return 0;
207}
208
209/* Use name specified in priv or build one from I2C address */
210static int acpi_i2c_get_name(const struct udevice *dev, char *out_name)
211{
Simon Glass71fa5b42020-12-03 16:55:18 -0700212 struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
Simon Glass31cc5b42020-09-22 12:45:01 -0600213 struct acpi_i2c_priv *priv = dev_get_priv(dev);
214
215 snprintf(out_name, ACPI_NAME_MAX,
216 priv->hid_desc_reg_offset ? "H%03X" : "D%03X",
217 chip->chip_addr);
218
219 return 0;
220}
221
222struct acpi_ops acpi_i2c_ops = {
223 .fill_ssdt = acpi_i2c_fill_ssdt,
224 .get_name = acpi_i2c_get_name,
225};