1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Intel LPSS ACPI support. |
4 | * |
5 | * Copyright (C) 2015, Intel Corporation |
6 | * |
7 | * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
8 | * Mika Westerberg <mika.westerberg@linux.intel.com> |
9 | */ |
10 | |
11 | #include <linux/device.h> |
12 | #include <linux/gfp_types.h> |
13 | #include <linux/ioport.h> |
14 | #include <linux/mod_devicetable.h> |
15 | #include <linux/module.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/pm_runtime.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/property.h> |
20 | |
21 | #include <linux/pxa2xx_ssp.h> |
22 | |
23 | #include <asm/errno.h> |
24 | |
25 | #include "intel-lpss.h" |
26 | |
27 | static const struct property_entry spt_spi_properties[] = { |
28 | PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type" , LPSS_SPT_SSP), |
29 | { } |
30 | }; |
31 | |
32 | static const struct software_node spt_spi_node = { |
33 | .properties = spt_spi_properties, |
34 | }; |
35 | |
36 | static const struct intel_lpss_platform_info spt_info = { |
37 | .clk_rate = 120000000, |
38 | .swnode = &spt_spi_node, |
39 | }; |
40 | |
41 | static const struct property_entry spt_i2c_properties[] = { |
42 | PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns" , 230), |
43 | { }, |
44 | }; |
45 | |
46 | static const struct software_node spt_i2c_node = { |
47 | .properties = spt_i2c_properties, |
48 | }; |
49 | |
50 | static const struct intel_lpss_platform_info spt_i2c_info = { |
51 | .clk_rate = 120000000, |
52 | .swnode = &spt_i2c_node, |
53 | }; |
54 | |
55 | static const struct property_entry uart_properties[] = { |
56 | PROPERTY_ENTRY_U32("reg-io-width" , 4), |
57 | PROPERTY_ENTRY_U32("reg-shift" , 2), |
58 | PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible" ), |
59 | { }, |
60 | }; |
61 | |
62 | static const struct software_node uart_node = { |
63 | .properties = uart_properties, |
64 | }; |
65 | |
66 | static const struct intel_lpss_platform_info spt_uart_info = { |
67 | .clk_rate = 120000000, |
68 | .clk_con_id = "baudclk" , |
69 | .swnode = &uart_node, |
70 | }; |
71 | |
72 | static const struct property_entry bxt_spi_properties[] = { |
73 | PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type" , LPSS_BXT_SSP), |
74 | { } |
75 | }; |
76 | |
77 | static const struct software_node bxt_spi_node = { |
78 | .properties = bxt_spi_properties, |
79 | }; |
80 | |
81 | static const struct intel_lpss_platform_info bxt_info = { |
82 | .clk_rate = 100000000, |
83 | .swnode = &bxt_spi_node, |
84 | }; |
85 | |
86 | static const struct property_entry bxt_i2c_properties[] = { |
87 | PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns" , 42), |
88 | PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns" , 171), |
89 | PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns" , 208), |
90 | { }, |
91 | }; |
92 | |
93 | static const struct software_node bxt_i2c_node = { |
94 | .properties = bxt_i2c_properties, |
95 | }; |
96 | |
97 | static const struct intel_lpss_platform_info bxt_i2c_info = { |
98 | .clk_rate = 133000000, |
99 | .swnode = &bxt_i2c_node, |
100 | }; |
101 | |
102 | static const struct property_entry apl_i2c_properties[] = { |
103 | PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns" , 207), |
104 | PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns" , 171), |
105 | PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns" , 208), |
106 | { }, |
107 | }; |
108 | |
109 | static const struct software_node apl_i2c_node = { |
110 | .properties = apl_i2c_properties, |
111 | }; |
112 | |
113 | static const struct intel_lpss_platform_info apl_i2c_info = { |
114 | .clk_rate = 133000000, |
115 | .swnode = &apl_i2c_node, |
116 | }; |
117 | |
118 | static const struct property_entry cnl_spi_properties[] = { |
119 | PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type" , LPSS_CNL_SSP), |
120 | { } |
121 | }; |
122 | |
123 | static const struct software_node cnl_spi_node = { |
124 | .properties = cnl_spi_properties, |
125 | }; |
126 | |
127 | static const struct intel_lpss_platform_info cnl_info = { |
128 | .clk_rate = 120000000, |
129 | .swnode = &cnl_spi_node, |
130 | }; |
131 | |
132 | static const struct intel_lpss_platform_info cnl_i2c_info = { |
133 | .clk_rate = 216000000, |
134 | .swnode = &spt_i2c_node, |
135 | }; |
136 | |
137 | static const struct acpi_device_id intel_lpss_acpi_ids[] = { |
138 | /* SPT */ |
139 | { "INT3440" , (kernel_ulong_t)&spt_info }, |
140 | { "INT3441" , (kernel_ulong_t)&spt_info }, |
141 | { "INT3442" , (kernel_ulong_t)&spt_i2c_info }, |
142 | { "INT3443" , (kernel_ulong_t)&spt_i2c_info }, |
143 | { "INT3444" , (kernel_ulong_t)&spt_i2c_info }, |
144 | { "INT3445" , (kernel_ulong_t)&spt_i2c_info }, |
145 | { "INT3446" , (kernel_ulong_t)&spt_i2c_info }, |
146 | { "INT3447" , (kernel_ulong_t)&spt_i2c_info }, |
147 | { "INT3448" , (kernel_ulong_t)&spt_uart_info }, |
148 | { "INT3449" , (kernel_ulong_t)&spt_uart_info }, |
149 | { "INT344A" , (kernel_ulong_t)&spt_uart_info }, |
150 | /* CNL */ |
151 | { "INT34B0" , (kernel_ulong_t)&cnl_info }, |
152 | { "INT34B1" , (kernel_ulong_t)&cnl_info }, |
153 | { "INT34B2" , (kernel_ulong_t)&cnl_i2c_info }, |
154 | { "INT34B3" , (kernel_ulong_t)&cnl_i2c_info }, |
155 | { "INT34B4" , (kernel_ulong_t)&cnl_i2c_info }, |
156 | { "INT34B5" , (kernel_ulong_t)&cnl_i2c_info }, |
157 | { "INT34B6" , (kernel_ulong_t)&cnl_i2c_info }, |
158 | { "INT34B7" , (kernel_ulong_t)&cnl_i2c_info }, |
159 | { "INT34B8" , (kernel_ulong_t)&spt_uart_info }, |
160 | { "INT34B9" , (kernel_ulong_t)&spt_uart_info }, |
161 | { "INT34BA" , (kernel_ulong_t)&spt_uart_info }, |
162 | { "INT34BC" , (kernel_ulong_t)&cnl_info }, |
163 | /* BXT */ |
164 | { "80860AAC" , (kernel_ulong_t)&bxt_i2c_info }, |
165 | { "80860ABC" , (kernel_ulong_t)&bxt_info }, |
166 | { "80860AC2" , (kernel_ulong_t)&bxt_info }, |
167 | /* APL */ |
168 | { "80865AAC" , (kernel_ulong_t)&apl_i2c_info }, |
169 | { "80865ABC" , (kernel_ulong_t)&bxt_info }, |
170 | { "80865AC2" , (kernel_ulong_t)&bxt_info }, |
171 | { } |
172 | }; |
173 | MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids); |
174 | |
175 | static int intel_lpss_acpi_probe(struct platform_device *pdev) |
176 | { |
177 | const struct intel_lpss_platform_info *data; |
178 | struct intel_lpss_platform_info *info; |
179 | int ret; |
180 | |
181 | data = device_get_match_data(dev: &pdev->dev); |
182 | if (!data) |
183 | return -ENODEV; |
184 | |
185 | info = devm_kmemdup(dev: &pdev->dev, src: data, len: sizeof(*info), GFP_KERNEL); |
186 | if (!info) |
187 | return -ENOMEM; |
188 | |
189 | /* No need to check mem and irq here as intel_lpss_probe() does it for us */ |
190 | info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
191 | info->irq = platform_get_irq(pdev, 0); |
192 | |
193 | ret = intel_lpss_probe(dev: &pdev->dev, info); |
194 | if (ret) |
195 | return ret; |
196 | |
197 | pm_runtime_set_active(dev: &pdev->dev); |
198 | pm_runtime_enable(dev: &pdev->dev); |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | static void intel_lpss_acpi_remove(struct platform_device *pdev) |
204 | { |
205 | intel_lpss_remove(dev: &pdev->dev); |
206 | pm_runtime_disable(dev: &pdev->dev); |
207 | } |
208 | |
209 | static struct platform_driver intel_lpss_acpi_driver = { |
210 | .probe = intel_lpss_acpi_probe, |
211 | .remove_new = intel_lpss_acpi_remove, |
212 | .driver = { |
213 | .name = "intel-lpss" , |
214 | .acpi_match_table = intel_lpss_acpi_ids, |
215 | .pm = pm_ptr(&intel_lpss_pm_ops), |
216 | }, |
217 | }; |
218 | |
219 | module_platform_driver(intel_lpss_acpi_driver); |
220 | |
221 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>" ); |
222 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>" ); |
223 | MODULE_DESCRIPTION("Intel LPSS ACPI driver" ); |
224 | MODULE_LICENSE("GPL v2" ); |
225 | MODULE_IMPORT_NS(INTEL_LPSS); |
226 | |