• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpi_device.h>
4 #include <acpi/acpigen.h>
5 #include <console/console.h>
6 #include <device/device.h>
7 #include <device/spi.h>
8 #include <spi-generic.h>
9 #include <stdio.h>
10 
11 #include "chip.h"
12 
spi_acpi_get_bus(const struct device * dev)13 static int spi_acpi_get_bus(const struct device *dev)
14 {
15 	struct device *spi_dev;
16 	struct device_operations *ops;
17 
18 	if (!dev->upstream || !dev->upstream->dev)
19 		return -1;
20 
21 	spi_dev = dev->upstream->dev;
22 	ops = spi_dev->ops;
23 
24 	if (ops && ops->ops_spi_bus &&
25 	    ops->ops_spi_bus->dev_to_bus)
26 		return ops->ops_spi_bus->dev_to_bus(spi_dev);
27 
28 	return -1;
29 }
30 
spi_acpi_add_gpios_to_crs(struct drivers_spi_acpi_config * config)31 static bool spi_acpi_add_gpios_to_crs(struct drivers_spi_acpi_config *config)
32 {
33 	/*
34 	 * Return false if:
35 	 * 1. GPIOs are exported via a power resource, or
36 	 * 2. Both reset and enable GPIOs are not provided.
37 	 */
38 	if (config->has_power_resource ||
39 	    ((config->reset_gpio.pin_count == 0) &&
40 	     (config->enable_gpio.pin_count == 0)))
41 		return false;
42 
43 	return true;
44 }
45 
spi_acpi_write_gpio(struct acpi_gpio * gpio,int * curr_index)46 static int spi_acpi_write_gpio(struct acpi_gpio *gpio, int *curr_index)
47 {
48 	int ret = -1;
49 
50 	if (gpio->pin_count == 0)
51 		return ret;
52 
53 	acpi_device_write_gpio(gpio);
54 	ret = *curr_index;
55 	(*curr_index)++;
56 
57 	return ret;
58 }
59 
spi_acpi_fill_ssdt_generator(const struct device * dev)60 static void spi_acpi_fill_ssdt_generator(const struct device *dev)
61 {
62 	struct drivers_spi_acpi_config *config = dev->chip_info;
63 	const char *scope = acpi_device_scope(dev);
64 	const char *path = acpi_device_path(dev);
65 	struct acpi_spi spi = {
66 		.device_select = dev->path.spi.cs,
67 		.speed = config->speed ? : 1 * MHz,
68 		.resource = scope,
69 		.device_select_polarity = SPI_POLARITY_LOW,
70 		.wire_mode = SPI_4_WIRE_MODE,
71 		.data_bit_length = 8,
72 		.clock_phase = SPI_CLOCK_PHASE_FIRST,
73 		.clock_polarity = SPI_POLARITY_LOW,
74 	};
75 	int curr_index = 0;
76 	int irq_gpio_index = -1;
77 	int reset_gpio_index = -1;
78 	int enable_gpio_index = -1;
79 
80 	if (!scope)
81 		return;
82 
83 	if (spi_acpi_get_bus(dev) == -1) {
84 		printk(BIOS_ERR, "%s: ERROR: Cannot get bus for device.\n",
85 			dev_path(dev));
86 		return;
87 	}
88 
89 	if (!config->hid) {
90 		printk(BIOS_ERR, "%s: ERROR: HID required.\n", dev_path(dev));
91 		return;
92 	}
93 
94 	/* Device */
95 	acpigen_write_scope(scope);
96 	acpigen_write_device(acpi_device_name(dev));
97 	acpigen_write_name_string("_HID", config->hid);
98 	if (config->cid)
99 		acpigen_write_name_string("_CID", config->cid);
100 	acpigen_write_name_integer("_UID", config->uid);
101 	if (config->desc)
102 		acpigen_write_name_string("_DDN", config->desc);
103 	acpigen_write_STA(acpi_device_status(dev));
104 
105 	/* Resources */
106 	acpigen_write_name("_CRS");
107 	acpigen_write_resourcetemplate_header();
108 	acpi_device_write_spi(&spi);
109 
110 	/* Use either Interrupt() or GpioInt() */
111 	if (config->irq_gpio.pin_count)
112 		irq_gpio_index = spi_acpi_write_gpio(&config->irq_gpio,
113 						     &curr_index);
114 	else
115 		acpi_device_write_interrupt(&config->irq);
116 
117 	/* Add enable/reset GPIOs if needed */
118 	if (spi_acpi_add_gpios_to_crs(config)) {
119 		reset_gpio_index = spi_acpi_write_gpio(&config->reset_gpio,
120 						       &curr_index);
121 		enable_gpio_index = spi_acpi_write_gpio(&config->enable_gpio,
122 							&curr_index);
123 	}
124 	acpigen_write_resourcetemplate_footer();
125 
126 	/* Wake capabilities */
127 	if (config->wake) {
128 		acpigen_write_name_integer("_S0W", ACPI_DEVICE_SLEEP_D3_HOT);
129 		acpigen_write_PRW(config->wake, 3);
130 	};
131 
132 	/* Write device properties if needed */
133 	if (config->compat_string || irq_gpio_index >= 0 ||
134 	    reset_gpio_index >= 0 || enable_gpio_index >= 0 || config->property_count) {
135 		struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
136 		if (config->compat_string)
137 			acpi_dp_add_string(dsd, "compatible",
138 					   config->compat_string);
139 		if (irq_gpio_index >= 0)
140 			acpi_dp_add_gpio(dsd, "irq-gpios", path,
141 					 irq_gpio_index, 0,
142 					 config->irq_gpio.active_low);
143 		if (reset_gpio_index >= 0)
144 			acpi_dp_add_gpio(dsd, "reset-gpios", path,
145 					 reset_gpio_index, 0,
146 					 config->reset_gpio.active_low);
147 		if (enable_gpio_index >= 0)
148 			acpi_dp_add_gpio(dsd, "enable-gpios", path,
149 					 enable_gpio_index, 0,
150 					 config->enable_gpio.active_low);
151 		/* Add generic property list */
152 		if (config->property_count > 0)
153 			acpi_dp_add_property_list(dsd, config->property_list,
154 					 config->property_count);
155 		acpi_dp_write(dsd);
156 	}
157 
158 	/* Power Resource */
159 	if (config->has_power_resource) {
160 		const struct acpi_power_res_params power_res_params = {
161 			&config->reset_gpio,
162 			config->reset_delay_ms,
163 			config->reset_off_delay_ms,
164 			&config->enable_gpio,
165 			config->enable_delay_ms,
166 			config->enable_off_delay_ms,
167 			&config->stop_gpio,
168 			config->stop_delay_ms,
169 			config->stop_off_delay_ms
170 		};
171 		acpi_device_add_power_res(&power_res_params);
172 	}
173 
174 	acpigen_pop_len(); /* Device */
175 	acpigen_pop_len(); /* Scope */
176 
177 	printk(BIOS_INFO, "%s: %s at %s\n", path,
178 	       config->desc ? : dev->chip_ops->name, dev_path(dev));
179 }
180 
spi_acpi_name(const struct device * dev)181 static const char *spi_acpi_name(const struct device *dev)
182 {
183 	struct drivers_spi_acpi_config *config = dev->chip_info;
184 	static char name[5];
185 
186 	if (config->name)
187 		return config->name;
188 
189 	snprintf(name, sizeof(name), "S%03.3X", spi_acpi_get_bus(dev));
190 	name[4] = '\0';
191 	return name;
192 }
193 
194 static struct device_operations spi_acpi_ops = {
195 	.read_resources		= noop_read_resources,
196 	.set_resources		= noop_set_resources,
197 	.acpi_name		= spi_acpi_name,
198 	.acpi_fill_ssdt		= spi_acpi_fill_ssdt_generator,
199 };
200 
spi_acpi_enable(struct device * dev)201 static void spi_acpi_enable(struct device *dev)
202 {
203 	dev->ops = &spi_acpi_ops;
204 }
205 
206 struct chip_operations drivers_spi_acpi_ops = {
207 	.name = "SPI Device",
208 	.enable_dev = spi_acpi_enable
209 };
210