blob: 0d7d2aa4293c55ac4323824ddb973cb6412db1a0 [file] [log] [blame]
Furquan Shaikh20a91c92017-02-11 11:16:18 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2017 Google Inc.
5 *
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.
9 *
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.
14 */
15
16#include <arch/acpi_device.h>
17#include <arch/acpigen.h>
18#include <console/console.h>
19#include <device/device.h>
20#include <device/path.h>
21#include <device/spi.h>
22#include <spi-generic.h>
23#include <stdint.h>
24#include <string.h>
25#include "chip.h"
26
27static int spi_acpi_get_bus(struct device *dev)
28{
29 struct device *spi_dev;
30 struct device_operations *ops;
31
32 if (!dev->bus || !dev->bus->dev)
33 return -1;
34
35 spi_dev = dev->bus->dev;
36 ops = spi_dev->ops;
37
38 if (ops && ops->ops_spi_bus &&
39 ops->ops_spi_bus->dev_to_bus)
40 return ops->ops_spi_bus->dev_to_bus(spi_dev);
41
42 return -1;
43}
44
45static void spi_acpi_fill_ssdt_generator(struct device *dev)
46{
47 struct drivers_spi_acpi_config *config = dev->chip_info;
48 const char *scope = acpi_device_scope(dev);
49 struct spi_cfg spi_cfg;
50 struct spi_slave slave;
51 int bus = -1, cs = dev->path.spi.cs;
52 struct acpi_spi spi = {
53 .device_select = cs,
54 .speed = config->speed ? : 1 * MHz,
55 .resource = scope,
56 };
57
58 if (!dev->enabled || !scope)
59 return;
60
61 bus = spi_acpi_get_bus(dev);
62 if (bus == -1) {
63 printk(BIOS_ERR, "%s: ERROR: Cannot get bus for device.\n",
64 dev_path(dev));
65 return;
66 }
67
68 if (!config->hid) {
69 printk(BIOS_ERR, "%s: ERROR: HID required.\n", dev_path(dev));
70 return;
71 }
72
73 if (spi_setup_slave(bus, cs, &slave)) {
74 printk(BIOS_ERR, "%s: ERROR: SPI setup failed.\n",
75 dev_path(dev));
76 return;
77 }
78
79 if (spi_get_config(&slave, &spi_cfg)) {
80 printk(BIOS_ERR, "%s: ERROR: SPI get config failed.\n",
81 dev_path(dev));
82 return;
83 }
84
85 spi.device_select_polarity = spi_cfg.cs_polarity;
86 spi.wire_mode = spi_cfg.wire_mode;
87 spi.data_bit_length = spi_cfg.data_bit_length;
88 spi.clock_phase = spi_cfg.clk_phase;
89
90 /* Device */
91 acpigen_write_scope(scope);
92 acpigen_write_device(acpi_device_name(dev));
93 acpigen_write_name_string("_HID", config->hid);
94 if (config->cid)
95 acpigen_write_name_string("_CID", config->cid);
96 acpigen_write_name_integer("_UID", config->uid);
97 if (config->desc)
98 acpigen_write_name_string("_DDN", config->desc);
99
100 /* Resources */
101 acpigen_write_name("_CRS");
102 acpigen_write_resourcetemplate_header();
103 acpi_device_write_spi(&spi);
104 acpi_device_write_interrupt(&config->irq);
105 acpigen_write_resourcetemplate_footer();
106
107 if (config->compat_string) {
108 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
109 acpi_dp_add_string(dsd, "compatible", config->compat_string);
110 acpi_dp_write(dsd);
111 }
112
113 acpigen_pop_len(); /* Device */
114 acpigen_pop_len(); /* Scope */
115}
116
117static const char *spi_acpi_name(struct device *dev)
118{
119 struct drivers_spi_acpi_config *config = dev->chip_info;
120 static char name[5];
121
122 if (config->name)
123 return config->name;
124
125 snprintf(name, sizeof(name), "S%03.3X", spi_acpi_get_bus(dev));
126 name[4] = '\0';
127 return name;
128}
129
130static struct device_operations spi_acpi_ops = {
131 .read_resources = DEVICE_NOOP,
132 .set_resources = DEVICE_NOOP,
133 .enable_resources = DEVICE_NOOP,
134 .acpi_name = &spi_acpi_name,
135 .acpi_fill_ssdt_generator = &spi_acpi_fill_ssdt_generator,
136};
137
138static void spi_acpi_enable(struct device *dev)
139{
140 dev->ops = &spi_acpi_ops;
141}
142
143struct chip_operations drivers_spi_acpi_ops = {
144 CHIP_NAME("SPI Device")
145 .enable_dev = &spi_acpi_enable
146};