blob: e87946f31b5c4c37924834ba2bbcab4202d56328 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Furquan Shaikh20a91c92017-02-11 11:16:18 -08002
Furquan Shaikh76cedd22020-05-02 10:24:23 -07003#include <acpi/acpi_device.h>
4#include <acpi/acpigen.h>
Furquan Shaikh20a91c92017-02-11 11:16:18 -08005#include <console/console.h>
6#include <device/device.h>
Furquan Shaikh20a91c92017-02-11 11:16:18 -08007#include <device/spi.h>
8#include <spi-generic.h>
Furquan Shaikh20a91c92017-02-11 11:16:18 -08009#include <string.h>
10#include "chip.h"
11
Aaron Durbinaa090cb2017-09-13 16:01:52 -060012static int spi_acpi_get_bus(const struct device *dev)
Furquan Shaikh20a91c92017-02-11 11:16:18 -080013{
14 struct device *spi_dev;
15 struct device_operations *ops;
16
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020017 if (!dev->upstream || !dev->upstream->dev)
Furquan Shaikh20a91c92017-02-11 11:16:18 -080018 return -1;
19
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020020 spi_dev = dev->upstream->dev;
Furquan Shaikh20a91c92017-02-11 11:16:18 -080021 ops = spi_dev->ops;
22
23 if (ops && ops->ops_spi_bus &&
24 ops->ops_spi_bus->dev_to_bus)
25 return ops->ops_spi_bus->dev_to_bus(spi_dev);
26
27 return -1;
28}
29
Duncan Lauriec9db3842017-02-17 17:14:35 -080030static bool spi_acpi_add_gpios_to_crs(struct drivers_spi_acpi_config *config)
31{
32 /*
33 * Return false if:
Matt DeVillierce7b2522023-01-11 17:59:08 -060034 * 1. GPIOs are exported via a power resource, or
Duncan Lauriec9db3842017-02-17 17:14:35 -080035 * 2. Both reset and enable GPIOs are not provided.
36 */
Matt DeVillierce7b2522023-01-11 17:59:08 -060037 if (config->has_power_resource ||
Duncan Lauriec9db3842017-02-17 17:14:35 -080038 ((config->reset_gpio.pin_count == 0) &&
39 (config->enable_gpio.pin_count == 0)))
40 return false;
41
42 return true;
43}
44
45static int spi_acpi_write_gpio(struct acpi_gpio *gpio, int *curr_index)
46{
47 int ret = -1;
48
49 if (gpio->pin_count == 0)
50 return ret;
51
52 acpi_device_write_gpio(gpio);
53 ret = *curr_index;
54 (*curr_index)++;
55
56 return ret;
57}
58
Furquan Shaikh7536a392020-04-24 21:59:21 -070059static void spi_acpi_fill_ssdt_generator(const struct device *dev)
Furquan Shaikh20a91c92017-02-11 11:16:18 -080060{
61 struct drivers_spi_acpi_config *config = dev->chip_info;
62 const char *scope = acpi_device_scope(dev);
Duncan Lauriec9db3842017-02-17 17:14:35 -080063 const char *path = acpi_device_path(dev);
Furquan Shaikh20a91c92017-02-11 11:16:18 -080064 struct acpi_spi spi = {
Furquan Shaikh5bda6422017-04-07 07:13:24 -070065 .device_select = dev->path.spi.cs,
Furquan Shaikh20a91c92017-02-11 11:16:18 -080066 .speed = config->speed ? : 1 * MHz,
67 .resource = scope,
Furquan Shaikh5bda6422017-04-07 07:13:24 -070068 .device_select_polarity = SPI_POLARITY_LOW,
69 .wire_mode = SPI_4_WIRE_MODE,
70 .data_bit_length = 8,
71 .clock_phase = SPI_CLOCK_PHASE_FIRST,
72 .clock_polarity = SPI_POLARITY_LOW,
Furquan Shaikh20a91c92017-02-11 11:16:18 -080073 };
Duncan Lauriec9db3842017-02-17 17:14:35 -080074 int curr_index = 0;
75 int irq_gpio_index = -1;
76 int reset_gpio_index = -1;
77 int enable_gpio_index = -1;
Furquan Shaikh20a91c92017-02-11 11:16:18 -080078
Karthikeyan Ramasubramaniand1c0f952020-11-02 16:26:52 -070079 if (!scope)
Furquan Shaikh20a91c92017-02-11 11:16:18 -080080 return;
81
Furquan Shaikh5bda6422017-04-07 07:13:24 -070082 if (spi_acpi_get_bus(dev) == -1) {
Furquan Shaikh20a91c92017-02-11 11:16:18 -080083 printk(BIOS_ERR, "%s: ERROR: Cannot get bus for device.\n",
Furquan Shaikh5bda6422017-04-07 07:13:24 -070084 dev_path(dev));
Furquan Shaikh20a91c92017-02-11 11:16:18 -080085 return;
86 }
87
88 if (!config->hid) {
89 printk(BIOS_ERR, "%s: ERROR: HID required.\n", dev_path(dev));
90 return;
91 }
92
Furquan Shaikh20a91c92017-02-11 11:16:18 -080093 /* Device */
94 acpigen_write_scope(scope);
95 acpigen_write_device(acpi_device_name(dev));
96 acpigen_write_name_string("_HID", config->hid);
97 if (config->cid)
98 acpigen_write_name_string("_CID", config->cid);
99 acpigen_write_name_integer("_UID", config->uid);
100 if (config->desc)
101 acpigen_write_name_string("_DDN", config->desc);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800102 acpigen_write_STA(acpi_device_status(dev));
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800103
104 /* Resources */
105 acpigen_write_name("_CRS");
106 acpigen_write_resourcetemplate_header();
107 acpi_device_write_spi(&spi);
Duncan Lauriec9db3842017-02-17 17:14:35 -0800108
109 /* Use either Interrupt() or GpioInt() */
110 if (config->irq_gpio.pin_count)
111 irq_gpio_index = spi_acpi_write_gpio(&config->irq_gpio,
112 &curr_index);
113 else
114 acpi_device_write_interrupt(&config->irq);
115
116 /* Add enable/reset GPIOs if needed */
117 if (spi_acpi_add_gpios_to_crs(config)) {
118 reset_gpio_index = spi_acpi_write_gpio(&config->reset_gpio,
119 &curr_index);
120 enable_gpio_index = spi_acpi_write_gpio(&config->enable_gpio,
121 &curr_index);
122 }
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800123 acpigen_write_resourcetemplate_footer();
124
Duncan Lauriec9db3842017-02-17 17:14:35 -0800125 /* Wake capabilities */
126 if (config->wake) {
Tim Wawrzynczak04c71de2021-08-05 09:32:37 -0600127 acpigen_write_name_integer("_S0W", ACPI_DEVICE_SLEEP_D3_HOT);
Duncan Lauriec9db3842017-02-17 17:14:35 -0800128 acpigen_write_PRW(config->wake, 3);
129 };
130
131 /* Write device properties if needed */
132 if (config->compat_string || irq_gpio_index >= 0 ||
133 reset_gpio_index >= 0 || enable_gpio_index >= 0) {
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800134 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
Duncan Lauriec9db3842017-02-17 17:14:35 -0800135 if (config->compat_string)
136 acpi_dp_add_string(dsd, "compatible",
137 config->compat_string);
138 if (irq_gpio_index >= 0)
139 acpi_dp_add_gpio(dsd, "irq-gpios", path,
140 irq_gpio_index, 0,
Furquan Shaikhd2d5e442020-07-01 01:37:13 -0700141 config->irq_gpio.active_low);
Duncan Lauriec9db3842017-02-17 17:14:35 -0800142 if (reset_gpio_index >= 0)
143 acpi_dp_add_gpio(dsd, "reset-gpios", path,
144 reset_gpio_index, 0,
Furquan Shaikhd2d5e442020-07-01 01:37:13 -0700145 config->reset_gpio.active_low);
Duncan Lauriec9db3842017-02-17 17:14:35 -0800146 if (enable_gpio_index >= 0)
147 acpi_dp_add_gpio(dsd, "enable-gpios", path,
148 enable_gpio_index, 0,
Furquan Shaikhd2d5e442020-07-01 01:37:13 -0700149 config->enable_gpio.active_low);
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800150 acpi_dp_write(dsd);
151 }
152
Duncan Lauriec9db3842017-02-17 17:14:35 -0800153 /* Power Resource */
Shelley Chena0603392018-04-26 13:52:30 -0700154 if (config->has_power_resource) {
155 const struct acpi_power_res_params power_res_params = {
156 &config->reset_gpio,
157 config->reset_delay_ms,
158 config->reset_off_delay_ms,
159 &config->enable_gpio,
160 config->enable_delay_ms,
161 config->enable_off_delay_ms,
162 &config->stop_gpio,
163 config->stop_delay_ms,
164 config->stop_off_delay_ms
165 };
166 acpi_device_add_power_res(&power_res_params);
167 }
Duncan Lauriec9db3842017-02-17 17:14:35 -0800168
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800169 acpigen_pop_len(); /* Device */
170 acpigen_pop_len(); /* Scope */
Duncan Lauriec9db3842017-02-17 17:14:35 -0800171
172 printk(BIOS_INFO, "%s: %s at %s\n", path,
173 config->desc ? : dev->chip_ops->name, dev_path(dev));
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800174}
175
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600176static const char *spi_acpi_name(const struct device *dev)
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800177{
178 struct drivers_spi_acpi_config *config = dev->chip_info;
179 static char name[5];
180
181 if (config->name)
182 return config->name;
183
184 snprintf(name, sizeof(name), "S%03.3X", spi_acpi_get_bus(dev));
185 name[4] = '\0';
186 return name;
187}
188
189static struct device_operations spi_acpi_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +0200190 .read_resources = noop_read_resources,
191 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +0200192 .acpi_name = spi_acpi_name,
193 .acpi_fill_ssdt = spi_acpi_fill_ssdt_generator,
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800194};
195
196static void spi_acpi_enable(struct device *dev)
197{
198 dev->ops = &spi_acpi_ops;
199}
200
201struct chip_operations drivers_spi_acpi_ops = {
Nicholas Sudsgaardbfb11be2024-01-30 09:53:46 +0900202 .name = "SPI Device",
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +0100203 .enable_dev = spi_acpi_enable
Furquan Shaikh20a91c92017-02-11 11:16:18 -0800204};