2 * This file is part of the coreboot project.
4 * Copyright 2016 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <arch/acpi_device.h>
17 #include <arch/acpigen.h>
18 #include <console/console.h>
19 #include <device/i2c_simple.h>
20 #include <device/device.h>
21 #include <device/path.h>
27 #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
29 static bool i2c_generic_add_gpios_to_crs(struct drivers_i2c_generic_config
*cfg
)
33 * 1. Request to explicitly disable export of GPIOs in CRS, or
34 * 2. Both reset and enable GPIOs are not provided.
36 if (cfg
->disable_gpio_export_in_crs
||
37 ((cfg
->reset_gpio
.pin_count
== 0) &&
38 (cfg
->enable_gpio
.pin_count
== 0)))
44 static int i2c_generic_write_gpio(struct acpi_gpio
*gpio
, int *curr_index
)
48 if (gpio
->pin_count
== 0)
51 acpi_device_write_gpio(gpio
);
58 void i2c_generic_fill_ssdt(struct device
*dev
,
59 void (*callback
)(struct device
*dev
),
60 struct drivers_i2c_generic_config
*config
)
62 const char *scope
= acpi_device_scope(dev
);
63 struct acpi_i2c i2c
= {
64 .address
= dev
->path
.i2c
.device
,
65 .mode_10bit
= dev
->path
.i2c
.mode_10bit
,
66 .speed
= config
->speed
? : I2C_SPEED_FAST
,
69 struct acpi_dp
*dsd
= NULL
;
71 int reset_gpio_index
= -1, enable_gpio_index
= -1, irq_gpio_index
= -1;
72 const char *path
= acpi_device_path(dev
);
74 if (!dev
->enabled
|| !scope
)
78 printk(BIOS_ERR
, "%s: ERROR: HID required\n", dev_path(dev
));
83 acpigen_write_scope(scope
);
84 acpigen_write_device(acpi_device_name(dev
));
85 acpigen_write_name_string("_HID", config
->hid
);
87 acpigen_write_name_string("_CID", config
->cid
);
88 acpigen_write_name_integer("_UID", config
->uid
);
89 acpigen_write_name_string("_DDN", config
->desc
);
90 acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON
);
93 acpigen_write_name("_CRS");
94 acpigen_write_resourcetemplate_header();
95 acpi_device_write_i2c(&i2c
);
97 /* Use either Interrupt() or GpioInt() */
98 if (config
->irq_gpio
.pin_count
)
99 irq_gpio_index
= i2c_generic_write_gpio(&config
->irq_gpio
,
102 acpi_device_write_interrupt(&config
->irq
);
104 if (i2c_generic_add_gpios_to_crs(config
) == true) {
105 reset_gpio_index
= i2c_generic_write_gpio(&config
->reset_gpio
,
107 enable_gpio_index
= i2c_generic_write_gpio(&config
->enable_gpio
,
110 acpigen_write_resourcetemplate_footer();
112 /* Wake capabilities */
114 acpigen_write_name_integer("_S0W", 4);
115 acpigen_write_PRW(config
->wake
, 3);
119 if (config
->probed
|| config
->property_count
||
120 (reset_gpio_index
!= -1) ||
121 (enable_gpio_index
!= -1) || (irq_gpio_index
!= -1)) {
122 dsd
= acpi_dp_new_table("_DSD");
124 acpi_dp_add_integer(dsd
, "linux,probed", 1);
125 if (irq_gpio_index
!= -1)
126 acpi_dp_add_gpio(dsd
, "irq-gpios", path
,
128 config
->irq_gpio
.polarity
==
129 ACPI_GPIO_ACTIVE_LOW
);
130 if (reset_gpio_index
!= -1)
131 acpi_dp_add_gpio(dsd
, "reset-gpios", path
,
133 config
->reset_gpio
.polarity
);
134 if (enable_gpio_index
!= -1)
135 acpi_dp_add_gpio(dsd
, "enable-gpios", path
,
136 enable_gpio_index
, 0,
137 config
->enable_gpio
.polarity
);
138 /* Add generic property list */
139 acpi_dp_add_property_list(dsd
, config
->property_list
,
140 config
->property_count
);
145 if (config
->has_power_resource
) {
146 const struct acpi_power_res_params power_res_params
= {
148 config
->reset_delay_ms
,
149 config
->reset_off_delay_ms
,
150 &config
->enable_gpio
,
151 config
->enable_delay_ms
,
152 config
->enable_off_delay_ms
,
154 config
->stop_delay_ms
,
155 config
->stop_off_delay_ms
157 acpi_device_add_power_res(&power_res_params
);
160 /* Callback if any. */
164 acpigen_pop_len(); /* Device */
165 acpigen_pop_len(); /* Scope */
167 printk(BIOS_INFO
, "%s: %s at %s\n", path
,
168 config
->desc
? : dev
->chip_ops
->name
, dev_path(dev
));
171 static void i2c_generic_fill_ssdt_generator(struct device
*dev
)
173 i2c_generic_fill_ssdt(dev
, NULL
, dev
->chip_info
);
176 /* Use name specified in config or build one from I2C address */
177 static const char *i2c_generic_acpi_name(const struct device
*dev
)
179 struct drivers_i2c_generic_config
*config
= dev
->chip_info
;
185 snprintf(name
, sizeof(name
), "D%03.3X", dev
->path
.i2c
.device
);
191 static struct device_operations i2c_generic_ops
= {
192 .read_resources
= DEVICE_NOOP
,
193 .set_resources
= DEVICE_NOOP
,
194 .enable_resources
= DEVICE_NOOP
,
195 #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
196 .acpi_name
= &i2c_generic_acpi_name
,
197 .acpi_fill_ssdt_generator
= &i2c_generic_fill_ssdt_generator
,
201 static void i2c_generic_enable(struct device
*dev
)
203 struct drivers_i2c_generic_config
*config
= dev
->chip_info
;
208 /* Check if device is present by reading GPIO */
209 if (config
->device_present_gpio
) {
210 int present
= gpio_get(config
->device_present_gpio
);
211 present
^= config
->device_present_gpio_invert
;
213 printk(BIOS_INFO
, "%s is %spresent\n",
214 dev
->chip_ops
->name
, present
? "" : "not ");
222 dev
->ops
= &i2c_generic_ops
;
224 /* Name the device as per description provided in devicetree */
226 dev
->name
= config
->desc
;
229 struct chip_operations drivers_i2c_generic_ops
= {
230 CHIP_NAME("I2C Device")
231 .enable_dev
= &i2c_generic_enable