Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * AMD ACPI support for ACPI2platform device.
4 : : *
5 : : * Copyright (c) 2014,2015 AMD Corporation.
6 : : * Authors: Ken Xue <Ken.Xue@amd.com>
7 : : * Wu, Jeff <Jeff.Wu@amd.com>
8 : : */
9 : :
10 : : #include <linux/clk-provider.h>
11 : : #include <linux/platform_data/clk-st.h>
12 : : #include <linux/platform_device.h>
13 : : #include <linux/pm_domain.h>
14 : : #include <linux/clkdev.h>
15 : : #include <linux/acpi.h>
16 : : #include <linux/err.h>
17 : : #include <linux/io.h>
18 : : #include <linux/pm.h>
19 : :
20 : : #include "internal.h"
21 : :
22 : : ACPI_MODULE_NAME("acpi_apd");
23 : : struct apd_private_data;
24 : :
25 : : /**
26 : : * ACPI_APD_SYSFS : add device attributes in sysfs
27 : : * ACPI_APD_PM : attach power domain to device
28 : : */
29 : : #define ACPI_APD_SYSFS BIT(0)
30 : : #define ACPI_APD_PM BIT(1)
31 : :
32 : : /**
33 : : * struct apd_device_desc - a descriptor for apd device
34 : : * @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM
35 : : * @fixed_clk_rate: fixed rate input clock source for acpi device;
36 : : * 0 means no fixed rate input clock source
37 : : * @setup: a hook routine to set device resource during create platform device
38 : : *
39 : : * Device description defined as acpi_device_id.driver_data
40 : : */
41 : : struct apd_device_desc {
42 : : unsigned int flags;
43 : : unsigned int fixed_clk_rate;
44 : : struct property_entry *properties;
45 : : int (*setup)(struct apd_private_data *pdata);
46 : : };
47 : :
48 : : struct apd_private_data {
49 : : struct clk *clk;
50 : : struct acpi_device *adev;
51 : : const struct apd_device_desc *dev_desc;
52 : : };
53 : :
54 : : #if defined(CONFIG_X86_AMD_PLATFORM_DEVICE) || defined(CONFIG_ARM64)
55 : : #define APD_ADDR(desc) ((unsigned long)&desc)
56 : :
57 : : static int acpi_apd_setup(struct apd_private_data *pdata)
58 : : {
59 : : const struct apd_device_desc *dev_desc = pdata->dev_desc;
60 : : struct clk *clk;
61 : :
62 : : if (dev_desc->fixed_clk_rate) {
63 : : clk = clk_register_fixed_rate(&pdata->adev->dev,
64 : : dev_name(&pdata->adev->dev),
65 : : NULL, 0, dev_desc->fixed_clk_rate);
66 : : clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev));
67 : : pdata->clk = clk;
68 : : }
69 : :
70 : : return 0;
71 : : }
72 : :
73 : : #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
74 : :
75 : : static int misc_check_res(struct acpi_resource *ares, void *data)
76 : : {
77 : : struct resource res;
78 : :
79 : : return !acpi_dev_resource_memory(ares, &res);
80 : : }
81 : :
82 : : static int st_misc_setup(struct apd_private_data *pdata)
83 : : {
84 : : struct acpi_device *adev = pdata->adev;
85 : : struct platform_device *clkdev;
86 : : struct st_clk_data *clk_data;
87 : : struct resource_entry *rentry;
88 : : struct list_head resource_list;
89 : : int ret;
90 : :
91 : : clk_data = devm_kzalloc(&adev->dev, sizeof(*clk_data), GFP_KERNEL);
92 : : if (!clk_data)
93 : : return -ENOMEM;
94 : :
95 : : INIT_LIST_HEAD(&resource_list);
96 : : ret = acpi_dev_get_resources(adev, &resource_list, misc_check_res,
97 : : NULL);
98 : : if (ret < 0)
99 : : return -ENOENT;
100 : :
101 : : list_for_each_entry(rentry, &resource_list, node) {
102 : : clk_data->base = devm_ioremap(&adev->dev, rentry->res->start,
103 : : resource_size(rentry->res));
104 : : break;
105 : : }
106 : :
107 : : acpi_dev_free_resource_list(&resource_list);
108 : :
109 : : clkdev = platform_device_register_data(&adev->dev, "clk-st",
110 : : PLATFORM_DEVID_NONE, clk_data,
111 : : sizeof(*clk_data));
112 : : return PTR_ERR_OR_ZERO(clkdev);
113 : : }
114 : :
115 : : static const struct apd_device_desc cz_i2c_desc = {
116 : : .setup = acpi_apd_setup,
117 : : .fixed_clk_rate = 133000000,
118 : : };
119 : :
120 : : static const struct apd_device_desc wt_i2c_desc = {
121 : : .setup = acpi_apd_setup,
122 : : .fixed_clk_rate = 150000000,
123 : : };
124 : :
125 : : static struct property_entry uart_properties[] = {
126 : : PROPERTY_ENTRY_U32("reg-io-width", 4),
127 : : PROPERTY_ENTRY_U32("reg-shift", 2),
128 : : PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
129 : : { },
130 : : };
131 : :
132 : : static const struct apd_device_desc cz_uart_desc = {
133 : : .setup = acpi_apd_setup,
134 : : .fixed_clk_rate = 48000000,
135 : : .properties = uart_properties,
136 : : };
137 : :
138 : : static const struct apd_device_desc st_misc_desc = {
139 : : .setup = st_misc_setup,
140 : : };
141 : : #endif
142 : :
143 : : #ifdef CONFIG_ARM64
144 : : static const struct apd_device_desc xgene_i2c_desc = {
145 : : .setup = acpi_apd_setup,
146 : : .fixed_clk_rate = 100000000,
147 : : };
148 : :
149 : : static const struct apd_device_desc vulcan_spi_desc = {
150 : : .setup = acpi_apd_setup,
151 : : .fixed_clk_rate = 133000000,
152 : : };
153 : :
154 : : static const struct apd_device_desc hip07_i2c_desc = {
155 : : .setup = acpi_apd_setup,
156 : : .fixed_clk_rate = 200000000,
157 : : };
158 : :
159 : : static const struct apd_device_desc hip08_i2c_desc = {
160 : : .setup = acpi_apd_setup,
161 : : .fixed_clk_rate = 250000000,
162 : : };
163 : :
164 : : static const struct apd_device_desc hip08_lite_i2c_desc = {
165 : : .setup = acpi_apd_setup,
166 : : .fixed_clk_rate = 125000000,
167 : : };
168 : :
169 : : static const struct apd_device_desc thunderx2_i2c_desc = {
170 : : .setup = acpi_apd_setup,
171 : : .fixed_clk_rate = 125000000,
172 : : };
173 : :
174 : : static const struct apd_device_desc nxp_i2c_desc = {
175 : : .setup = acpi_apd_setup,
176 : : .fixed_clk_rate = 350000000,
177 : : };
178 : :
179 : : static const struct apd_device_desc hip08_spi_desc = {
180 : : .setup = acpi_apd_setup,
181 : : .fixed_clk_rate = 250000000,
182 : : };
183 : : #endif
184 : :
185 : : #else
186 : :
187 : : #define APD_ADDR(desc) (0UL)
188 : :
189 : : #endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
190 : :
191 : : /**
192 : : * Create platform device during acpi scan attach handle.
193 : : * Return value > 0 on success of creating device.
194 : : */
195 : 0 : static int acpi_apd_create_device(struct acpi_device *adev,
196 : : const struct acpi_device_id *id)
197 : : {
198 : 0 : const struct apd_device_desc *dev_desc = (void *)id->driver_data;
199 : 0 : struct apd_private_data *pdata;
200 : 0 : struct platform_device *pdev;
201 : 0 : int ret;
202 : :
203 [ # # ]: 0 : if (!dev_desc) {
204 : 0 : pdev = acpi_create_platform_device(adev, NULL);
205 [ # # # # ]: 0 : return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
206 : : }
207 : :
208 : 0 : pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
209 [ # # ]: 0 : if (!pdata)
210 : : return -ENOMEM;
211 : :
212 : 0 : pdata->adev = adev;
213 : 0 : pdata->dev_desc = dev_desc;
214 : :
215 [ # # ]: 0 : if (dev_desc->setup) {
216 : 0 : ret = dev_desc->setup(pdata);
217 [ # # ]: 0 : if (ret)
218 : 0 : goto err_out;
219 : : }
220 : :
221 : 0 : adev->driver_data = pdata;
222 : 0 : pdev = acpi_create_platform_device(adev, dev_desc->properties);
223 [ # # # # ]: 0 : if (!IS_ERR_OR_NULL(pdev))
224 : : return 1;
225 : :
226 : 0 : ret = PTR_ERR(pdev);
227 : 0 : adev->driver_data = NULL;
228 : :
229 : 0 : err_out:
230 : 0 : kfree(pdata);
231 : 0 : return ret;
232 : : }
233 : :
234 : : static const struct acpi_device_id acpi_apd_device_ids[] = {
235 : : /* Generic apd devices */
236 : : #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
237 : : { "AMD0010", APD_ADDR(cz_i2c_desc) },
238 : : { "AMDI0010", APD_ADDR(wt_i2c_desc) },
239 : : { "AMD0020", APD_ADDR(cz_uart_desc) },
240 : : { "AMDI0020", APD_ADDR(cz_uart_desc) },
241 : : { "AMD0030", },
242 : : { "AMD0040", APD_ADDR(st_misc_desc)},
243 : : #endif
244 : : #ifdef CONFIG_ARM64
245 : : { "APMC0D0F", APD_ADDR(xgene_i2c_desc) },
246 : : { "BRCM900D", APD_ADDR(vulcan_spi_desc) },
247 : : { "CAV900D", APD_ADDR(vulcan_spi_desc) },
248 : : { "CAV9007", APD_ADDR(thunderx2_i2c_desc) },
249 : : { "HISI02A1", APD_ADDR(hip07_i2c_desc) },
250 : : { "HISI02A2", APD_ADDR(hip08_i2c_desc) },
251 : : { "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) },
252 : : { "HISI0173", APD_ADDR(hip08_spi_desc) },
253 : : { "NXP0001", APD_ADDR(nxp_i2c_desc) },
254 : : #endif
255 : : { }
256 : : };
257 : :
258 : : static struct acpi_scan_handler apd_handler = {
259 : : .ids = acpi_apd_device_ids,
260 : : .attach = acpi_apd_create_device,
261 : : };
262 : :
263 : 28 : void __init acpi_apd_init(void)
264 : : {
265 : 28 : acpi_scan_add_handler(&apd_handler);
266 : 28 : }
|