usb: dwc3: add a SPL_USB_DWC3_GENERIC option for the dwc3 driver
[platform/kernel/u-boot.git] / drivers / i2c / acpi_i2c.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2019 Google LLC
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <i2c.h>
9 #include <log.h>
10 #include <acpi/acpi_device.h>
11 #include <acpi/acpigen.h>
12 #include <acpi/acpi_dp.h>
13 #ifdef CONFIG_X86
14 #include <asm/intel_pinctrl_defs.h>
15 #endif
16 #include <asm-generic/gpio.h>
17 #include <dm/acpi.h>
18
19 static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv *priv)
20 {
21         /*
22          * Return false if:
23          * 1. Request to explicitly disable export of GPIOs in CRS, or
24          * 2. Both reset and enable GPIOs are not provided.
25          */
26         if (priv->disable_gpio_export_in_crs ||
27             (!dm_gpio_is_valid(&priv->reset_gpio) &&
28              !dm_gpio_is_valid(&priv->enable_gpio)))
29                 return false;
30
31         return true;
32 }
33
34 static int acpi_i2c_write_gpio(struct acpi_ctx *ctx, struct gpio_desc *gpio,
35                                int *curindex)
36 {
37         int ret;
38
39         if (!dm_gpio_is_valid(gpio))
40                 return -ENOENT;
41
42         acpi_device_write_gpio_desc(ctx, gpio);
43         ret = *curindex;
44         (*curindex)++;
45
46         return ret;
47 }
48
49 int acpi_i2c_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
50 {
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];
57         int tx_state_val;
58         int curindex = 0;
59         int ret;
60
61 #ifdef CONFIG_X86
62         tx_state_val = PAD_CFG0_TX_STATE;
63 #elif defined(CONFIG_SANDBOX)
64         tx_state_val = BIT(7);  /* test value */
65 #else
66 #error "Not supported on this architecture"
67 #endif
68         ret = acpi_get_name(dev, name);
69         if (ret)
70                 return log_msg_ret("name", ret);
71         ret = acpi_device_scope(dev, scope, sizeof(scope));
72         if (ret)
73                 return log_msg_ret("scope", ret);
74
75         /* Device */
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));
84
85         /* Resources */
86         acpigen_write_name(ctx, "_CRS");
87         acpigen_write_resourcetemplate_header(ctx);
88         acpi_device_write_i2c_dev(ctx, dev);
89
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,
93                                                      &curindex);
94         } else {
95                 ret = acpi_device_write_interrupt_irq(ctx, &priv->irq);
96                 if (ret < 0)
97                         return log_msg_ret("irq", ret);
98         }
99
100         if (acpi_i2c_add_gpios_to_crs(priv)) {
101                 reset_gpio_index = acpi_i2c_write_gpio(ctx, &priv->reset_gpio,
102                                                        &curindex);
103                 enable_gpio_index = acpi_i2c_write_gpio(ctx, &priv->enable_gpio,
104                                                         &curindex);
105         }
106         acpigen_write_resourcetemplate_footer(ctx);
107
108         /* Wake capabilities */
109         if (priv->wake) {
110                 acpigen_write_name_integer(ctx, "_S0W", 4);
111                 acpigen_write_prw(ctx, priv->wake, 3);
112         }
113
114         /* DSD */
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];
119
120                 ret = acpi_device_path(dev, path, sizeof(path));
121                 if (ret)
122                         return log_msg_ret("path", ret);
123
124                 dsd = acpi_dp_new_table("_DSD");
125                 if (priv->compat_string)
126                         acpi_dp_add_string(dsd, "compatible",
127                                            priv->compat_string);
128                 if (priv->probed)
129                         acpi_dp_add_integer(dsd, "linux,probed", 1);
130                 if (irq_gpio_index >= 0)
131                         acpi_dp_add_gpio(dsd, "irq-gpios", path,
132                                          irq_gpio_index, 0,
133                                          priv->irq_gpio.flags &
134                                          GPIOD_ACTIVE_LOW ?
135                                          ACPI_GPIO_ACTIVE_LOW : 0);
136                 if (reset_gpio_index >= 0)
137                         acpi_dp_add_gpio(dsd, "reset-gpios", path,
138                                          reset_gpio_index, 0,
139                                          priv->reset_gpio.flags &
140                                          GPIOD_ACTIVE_LOW ?
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 &
146                                          GPIOD_ACTIVE_LOW ?
147                                          ACPI_GPIO_ACTIVE_LOW : 0);
148                 /* Generic property list is not supported */
149                 acpi_dp_write(ctx, dsd);
150         }
151
152         /* Power Resource */
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);
161                 if (ret)
162                         return log_msg_ret("power", ret);
163         }
164         if (priv->hid_desc_reg_offset) {
165                 ret = acpi_device_write_dsm_i2c_hid(ctx,
166                                                     priv->hid_desc_reg_offset);
167                 if (ret)
168                         return log_msg_ret("dsm", ret);
169         }
170
171         acpigen_pop_len(ctx); /* Device */
172         acpigen_pop_len(ctx); /* Scope */
173
174         return 0;
175 }
176
177 int acpi_i2c_of_to_plat(struct udevice *dev)
178 {
179         struct acpi_i2c_priv *priv = dev_get_priv(dev);
180
181         gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
182                              GPIOD_IS_OUT);
183         gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio,
184                              GPIOD_IS_OUT);
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,
187                              GPIOD_IS_OUT);
188         irq_get_by_index(dev, 0, &priv->irq);
189         priv->hid = dev_read_string(dev, "acpi,hid");
190         if (!priv->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);
206
207         return 0;
208 }
209
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)
212 {
213         struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
214         struct acpi_i2c_priv *priv = dev_get_priv(dev);
215
216         snprintf(out_name, ACPI_NAME_MAX,
217                  priv->hid_desc_reg_offset ? "H%03X" : "D%03X",
218                  chip->chip_addr);
219
220         return 0;
221 }
222
223 struct acpi_ops acpi_i2c_ops = {
224         .fill_ssdt      = acpi_i2c_fill_ssdt,
225         .get_name       = acpi_i2c_get_name,
226 };