1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2019 Google LLC
10 #include <acpi/acpi_device.h>
11 #include <acpi/acpigen.h>
12 #include <acpi/acpi_dp.h>
14 #include <asm/intel_pinctrl_defs.h>
16 #include <asm-generic/gpio.h>
19 static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv
*priv
)
23 * 1. Request to explicitly disable export of GPIOs in CRS, or
24 * 2. Both reset and enable GPIOs are not provided.
26 if (priv
->disable_gpio_export_in_crs
||
27 (!dm_gpio_is_valid(&priv
->reset_gpio
) &&
28 !dm_gpio_is_valid(&priv
->enable_gpio
)))
34 static int acpi_i2c_write_gpio(struct acpi_ctx
*ctx
, struct gpio_desc
*gpio
,
39 if (!dm_gpio_is_valid(gpio
))
42 acpi_device_write_gpio_desc(ctx
, gpio
);
49 int acpi_i2c_fill_ssdt(const struct udevice
*dev
, struct acpi_ctx
*ctx
)
51 int reset_gpio_index
= -1, enable_gpio_index
= -1, irq_gpio_index
= -1;
52 enum i2c_device_t type
= dev_get_driver_data(dev
);
53 struct acpi_i2c_priv
*priv
= dev_get_priv(dev
);
54 struct acpi_dp
*dsd
= NULL
;
55 char scope
[ACPI_PATH_MAX
];
56 char name
[ACPI_NAME_MAX
];
62 tx_state_val
= PAD_CFG0_TX_STATE
;
63 #elif defined(CONFIG_SANDBOX)
64 tx_state_val
= BIT(7); /* test value */
66 #error "Not supported on this architecture"
68 ret
= acpi_get_name(dev
, name
);
70 return log_msg_ret("name", ret
);
71 ret
= acpi_device_scope(dev
, scope
, sizeof(scope
));
73 return log_msg_ret("scope", ret
);
76 acpigen_write_scope(ctx
, scope
);
77 acpigen_write_device(ctx
, name
);
78 acpigen_write_name_string(ctx
, "_HID", priv
->hid
);
79 if (type
== I2C_DEVICE_HID_OVER_I2C
)
80 acpigen_write_name_string(ctx
, "_CID", "PNP0C50");
81 acpigen_write_name_integer(ctx
, "_UID", priv
->uid
);
82 acpigen_write_name_string(ctx
, "_DDN", priv
->desc
);
83 acpigen_write_sta(ctx
, acpi_device_status(dev
));
86 acpigen_write_name(ctx
, "_CRS");
87 acpigen_write_resourcetemplate_header(ctx
);
88 acpi_device_write_i2c_dev(ctx
, dev
);
90 /* Use either Interrupt() or GpioInt() */
91 if (dm_gpio_is_valid(&priv
->irq_gpio
)) {
92 irq_gpio_index
= acpi_i2c_write_gpio(ctx
, &priv
->irq_gpio
,
95 ret
= acpi_device_write_interrupt_irq(ctx
, &priv
->irq
);
97 return log_msg_ret("irq", ret
);
100 if (acpi_i2c_add_gpios_to_crs(priv
)) {
101 reset_gpio_index
= acpi_i2c_write_gpio(ctx
, &priv
->reset_gpio
,
103 enable_gpio_index
= acpi_i2c_write_gpio(ctx
, &priv
->enable_gpio
,
106 acpigen_write_resourcetemplate_footer(ctx
);
108 /* Wake capabilities */
110 acpigen_write_name_integer(ctx
, "_S0W", 4);
111 acpigen_write_prw(ctx
, priv
->wake
, 3);
115 if (priv
->probed
|| priv
->property_count
|| priv
->compat_string
||
116 reset_gpio_index
>= 0 || enable_gpio_index
>= 0 ||
117 irq_gpio_index
>= 0) {
118 char path
[ACPI_PATH_MAX
];
120 ret
= acpi_device_path(dev
, path
, sizeof(path
));
122 return log_msg_ret("path", ret
);
124 dsd
= acpi_dp_new_table("_DSD");
125 if (priv
->compat_string
)
126 acpi_dp_add_string(dsd
, "compatible",
127 priv
->compat_string
);
129 acpi_dp_add_integer(dsd
, "linux,probed", 1);
130 if (irq_gpio_index
>= 0)
131 acpi_dp_add_gpio(dsd
, "irq-gpios", path
,
133 priv
->irq_gpio
.flags
&
135 ACPI_GPIO_ACTIVE_LOW
: 0);
136 if (reset_gpio_index
>= 0)
137 acpi_dp_add_gpio(dsd
, "reset-gpios", path
,
139 priv
->reset_gpio
.flags
&
141 ACPI_GPIO_ACTIVE_LOW
: 0);
142 if (enable_gpio_index
>= 0)
143 acpi_dp_add_gpio(dsd
, "enable-gpios", path
,
144 enable_gpio_index
, 0,
145 priv
->enable_gpio
.flags
&
147 ACPI_GPIO_ACTIVE_LOW
: 0);
148 /* Generic property list is not supported */
149 acpi_dp_write(ctx
, dsd
);
153 if (priv
->has_power_resource
) {
154 ret
= acpi_device_add_power_res(ctx
, tx_state_val
,
155 "\\_SB.GPC0", "\\_SB.SPC0",
156 &priv
->reset_gpio
, priv
->reset_delay_ms
,
157 priv
->reset_off_delay_ms
, &priv
->enable_gpio
,
158 priv
->enable_delay_ms
, priv
->enable_off_delay_ms
,
159 &priv
->stop_gpio
, priv
->stop_delay_ms
,
160 priv
->stop_off_delay_ms
);
162 return log_msg_ret("power", ret
);
164 if (priv
->hid_desc_reg_offset
) {
165 ret
= acpi_device_write_dsm_i2c_hid(ctx
,
166 priv
->hid_desc_reg_offset
);
168 return log_msg_ret("dsm", ret
);
171 acpigen_pop_len(ctx
); /* Device */
172 acpigen_pop_len(ctx
); /* Scope */
177 int acpi_i2c_of_to_plat(struct udevice
*dev
)
179 struct acpi_i2c_priv
*priv
= dev_get_priv(dev
);
181 gpio_request_by_name(dev
, "reset-gpios", 0, &priv
->reset_gpio
,
183 gpio_request_by_name(dev
, "enable-gpios", 0, &priv
->enable_gpio
,
185 gpio_request_by_name(dev
, "irq-gpios", 0, &priv
->irq_gpio
, GPIOD_IS_IN
);
186 gpio_request_by_name(dev
, "stop-gpios", 0, &priv
->stop_gpio
,
188 irq_get_by_index(dev
, 0, &priv
->irq
);
189 priv
->hid
= dev_read_string(dev
, "acpi,hid");
191 return log_msg_ret("hid", -EINVAL
);
192 dev_read_u32(dev
, "acpi,uid", &priv
->uid
);
193 priv
->desc
= dev_read_string(dev
, "acpi,ddn");
194 dev_read_u32(dev
, "acpi,wake", &priv
->wake
);
195 priv
->probed
= dev_read_bool(dev
, "linux,probed");
196 priv
->compat_string
= dev_read_string(dev
, "acpi,compatible");
197 priv
->has_power_resource
= dev_read_bool(dev
,
198 "acpi,has-power-resource");
199 dev_read_u32(dev
, "hid-descr-addr", &priv
->hid_desc_reg_offset
);
200 dev_read_u32(dev
, "reset-delay-ms", &priv
->reset_delay_ms
);
201 dev_read_u32(dev
, "reset-off-delay-ms", &priv
->reset_off_delay_ms
);
202 dev_read_u32(dev
, "enable-delay-ms", &priv
->enable_delay_ms
);
203 dev_read_u32(dev
, "enable-off-delay-ms", &priv
->enable_off_delay_ms
);
204 dev_read_u32(dev
, "stop-delay-ms", &priv
->stop_delay_ms
);
205 dev_read_u32(dev
, "stop-off-delay-ms", &priv
->stop_off_delay_ms
);
210 /* Use name specified in priv or build one from I2C address */
211 static int acpi_i2c_get_name(const struct udevice
*dev
, char *out_name
)
213 struct dm_i2c_chip
*chip
= dev_get_parent_plat(dev
);
214 struct acpi_i2c_priv
*priv
= dev_get_priv(dev
);
216 snprintf(out_name
, ACPI_NAME_MAX
,
217 priv
->hid_desc_reg_offset
? "H%03X" : "D%03X",
223 struct acpi_ops acpi_i2c_ops
= {
224 .fill_ssdt
= acpi_i2c_fill_ssdt
,
225 .get_name
= acpi_i2c_get_name
,