diff options
Diffstat (limited to 'drivers/acpi/acpi_lpss.c')
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 167 |
1 files changed, 58 insertions, 109 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index b0ea767c8696..93d160661f4c 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
@@ -54,55 +54,58 @@ ACPI_MODULE_NAME("acpi_lpss"); | |||
54 | 54 | ||
55 | #define LPSS_PRV_REG_COUNT 9 | 55 | #define LPSS_PRV_REG_COUNT 9 |
56 | 56 | ||
57 | struct lpss_shared_clock { | 57 | /* LPSS Flags */ |
58 | const char *name; | 58 | #define LPSS_CLK BIT(0) |
59 | unsigned long rate; | 59 | #define LPSS_CLK_GATE BIT(1) |
60 | struct clk *clk; | 60 | #define LPSS_CLK_DIVIDER BIT(2) |
61 | }; | 61 | #define LPSS_LTR BIT(3) |
62 | #define LPSS_SAVE_CTX BIT(4) | ||
62 | 63 | ||
63 | struct lpss_private_data; | 64 | struct lpss_private_data; |
64 | 65 | ||
65 | struct lpss_device_desc { | 66 | struct lpss_device_desc { |
66 | bool clk_required; | 67 | unsigned int flags; |
67 | const char *clkdev_name; | ||
68 | bool ltr_required; | ||
69 | unsigned int prv_offset; | 68 | unsigned int prv_offset; |
70 | size_t prv_size_override; | 69 | size_t prv_size_override; |
71 | bool clk_divider; | ||
72 | bool clk_gate; | ||
73 | bool save_ctx; | ||
74 | struct lpss_shared_clock *shared_clock; | ||
75 | void (*setup)(struct lpss_private_data *pdata); | 70 | void (*setup)(struct lpss_private_data *pdata); |
76 | }; | 71 | }; |
77 | 72 | ||
78 | static struct lpss_device_desc lpss_dma_desc = { | 73 | static struct lpss_device_desc lpss_dma_desc = { |
79 | .clk_required = true, | 74 | .flags = LPSS_CLK, |
80 | .clkdev_name = "hclk", | ||
81 | }; | 75 | }; |
82 | 76 | ||
83 | struct lpss_private_data { | 77 | struct lpss_private_data { |
84 | void __iomem *mmio_base; | 78 | void __iomem *mmio_base; |
85 | resource_size_t mmio_size; | 79 | resource_size_t mmio_size; |
80 | unsigned int fixed_clk_rate; | ||
86 | struct clk *clk; | 81 | struct clk *clk; |
87 | const struct lpss_device_desc *dev_desc; | 82 | const struct lpss_device_desc *dev_desc; |
88 | u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; | 83 | u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; |
89 | }; | 84 | }; |
90 | 85 | ||
86 | /* UART Component Parameter Register */ | ||
87 | #define LPSS_UART_CPR 0xF4 | ||
88 | #define LPSS_UART_CPR_AFCE BIT(4) | ||
89 | |||
91 | static void lpss_uart_setup(struct lpss_private_data *pdata) | 90 | static void lpss_uart_setup(struct lpss_private_data *pdata) |
92 | { | 91 | { |
93 | unsigned int offset; | 92 | unsigned int offset; |
94 | u32 reg; | 93 | u32 val; |
95 | 94 | ||
96 | offset = pdata->dev_desc->prv_offset + LPSS_TX_INT; | 95 | offset = pdata->dev_desc->prv_offset + LPSS_TX_INT; |
97 | reg = readl(pdata->mmio_base + offset); | 96 | val = readl(pdata->mmio_base + offset); |
98 | writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + offset); | 97 | writel(val | LPSS_TX_INT_MASK, pdata->mmio_base + offset); |
99 | 98 | ||
100 | offset = pdata->dev_desc->prv_offset + LPSS_GENERAL; | 99 | val = readl(pdata->mmio_base + LPSS_UART_CPR); |
101 | reg = readl(pdata->mmio_base + offset); | 100 | if (!(val & LPSS_UART_CPR_AFCE)) { |
102 | writel(reg | LPSS_GENERAL_UART_RTS_OVRD, pdata->mmio_base + offset); | 101 | offset = pdata->dev_desc->prv_offset + LPSS_GENERAL; |
102 | val = readl(pdata->mmio_base + offset); | ||
103 | val |= LPSS_GENERAL_UART_RTS_OVRD; | ||
104 | writel(val, pdata->mmio_base + offset); | ||
105 | } | ||
103 | } | 106 | } |
104 | 107 | ||
105 | static void lpss_i2c_setup(struct lpss_private_data *pdata) | 108 | static void byt_i2c_setup(struct lpss_private_data *pdata) |
106 | { | 109 | { |
107 | unsigned int offset; | 110 | unsigned int offset; |
108 | u32 val; | 111 | u32 val; |
@@ -111,100 +114,56 @@ static void lpss_i2c_setup(struct lpss_private_data *pdata) | |||
111 | val = readl(pdata->mmio_base + offset); | 114 | val = readl(pdata->mmio_base + offset); |
112 | val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; | 115 | val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; |
113 | writel(val, pdata->mmio_base + offset); | 116 | writel(val, pdata->mmio_base + offset); |
114 | } | ||
115 | 117 | ||
116 | static struct lpss_device_desc wpt_dev_desc = { | 118 | if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset)) |
117 | .clk_required = true, | 119 | pdata->fixed_clk_rate = 133000000; |
118 | .prv_offset = 0x800, | 120 | } |
119 | .ltr_required = true, | ||
120 | .clk_divider = true, | ||
121 | .clk_gate = true, | ||
122 | }; | ||
123 | 121 | ||
124 | static struct lpss_device_desc lpt_dev_desc = { | 122 | static struct lpss_device_desc lpt_dev_desc = { |
125 | .clk_required = true, | 123 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR, |
126 | .prv_offset = 0x800, | 124 | .prv_offset = 0x800, |
127 | .ltr_required = true, | ||
128 | .clk_divider = true, | ||
129 | .clk_gate = true, | ||
130 | }; | 125 | }; |
131 | 126 | ||
132 | static struct lpss_device_desc lpt_i2c_dev_desc = { | 127 | static struct lpss_device_desc lpt_i2c_dev_desc = { |
133 | .clk_required = true, | 128 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR, |
134 | .prv_offset = 0x800, | 129 | .prv_offset = 0x800, |
135 | .ltr_required = true, | ||
136 | .clk_gate = true, | ||
137 | }; | 130 | }; |
138 | 131 | ||
139 | static struct lpss_device_desc lpt_uart_dev_desc = { | 132 | static struct lpss_device_desc lpt_uart_dev_desc = { |
140 | .clk_required = true, | 133 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR, |
141 | .prv_offset = 0x800, | 134 | .prv_offset = 0x800, |
142 | .ltr_required = true, | ||
143 | .clk_divider = true, | ||
144 | .clk_gate = true, | ||
145 | .setup = lpss_uart_setup, | 135 | .setup = lpss_uart_setup, |
146 | }; | 136 | }; |
147 | 137 | ||
148 | static struct lpss_device_desc lpt_sdio_dev_desc = { | 138 | static struct lpss_device_desc lpt_sdio_dev_desc = { |
139 | .flags = LPSS_LTR, | ||
149 | .prv_offset = 0x1000, | 140 | .prv_offset = 0x1000, |
150 | .prv_size_override = 0x1018, | 141 | .prv_size_override = 0x1018, |
151 | .ltr_required = true, | ||
152 | }; | ||
153 | |||
154 | static struct lpss_shared_clock pwm_clock = { | ||
155 | .name = "pwm_clk", | ||
156 | .rate = 25000000, | ||
157 | }; | 142 | }; |
158 | 143 | ||
159 | static struct lpss_device_desc byt_pwm_dev_desc = { | 144 | static struct lpss_device_desc byt_pwm_dev_desc = { |
160 | .clk_required = true, | 145 | .flags = LPSS_SAVE_CTX, |
161 | .save_ctx = true, | ||
162 | .shared_clock = &pwm_clock, | ||
163 | }; | 146 | }; |
164 | 147 | ||
165 | static struct lpss_device_desc byt_uart_dev_desc = { | 148 | static struct lpss_device_desc byt_uart_dev_desc = { |
166 | .clk_required = true, | 149 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, |
167 | .prv_offset = 0x800, | 150 | .prv_offset = 0x800, |
168 | .clk_divider = true, | ||
169 | .clk_gate = true, | ||
170 | .save_ctx = true, | ||
171 | .setup = lpss_uart_setup, | 151 | .setup = lpss_uart_setup, |
172 | }; | 152 | }; |
173 | 153 | ||
174 | static struct lpss_device_desc byt_spi_dev_desc = { | 154 | static struct lpss_device_desc byt_spi_dev_desc = { |
175 | .clk_required = true, | 155 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, |
176 | .prv_offset = 0x400, | 156 | .prv_offset = 0x400, |
177 | .clk_divider = true, | ||
178 | .clk_gate = true, | ||
179 | .save_ctx = true, | ||
180 | }; | 157 | }; |
181 | 158 | ||
182 | static struct lpss_device_desc byt_sdio_dev_desc = { | 159 | static struct lpss_device_desc byt_sdio_dev_desc = { |
183 | .clk_required = true, | 160 | .flags = LPSS_CLK, |
184 | }; | ||
185 | |||
186 | static struct lpss_shared_clock i2c_clock = { | ||
187 | .name = "i2c_clk", | ||
188 | .rate = 100000000, | ||
189 | }; | 161 | }; |
190 | 162 | ||
191 | static struct lpss_device_desc byt_i2c_dev_desc = { | 163 | static struct lpss_device_desc byt_i2c_dev_desc = { |
192 | .clk_required = true, | 164 | .flags = LPSS_CLK | LPSS_SAVE_CTX, |
193 | .prv_offset = 0x800, | 165 | .prv_offset = 0x800, |
194 | .save_ctx = true, | 166 | .setup = byt_i2c_setup, |
195 | .shared_clock = &i2c_clock, | ||
196 | .setup = lpss_i2c_setup, | ||
197 | }; | ||
198 | |||
199 | static struct lpss_shared_clock bsw_pwm_clock = { | ||
200 | .name = "pwm_clk", | ||
201 | .rate = 19200000, | ||
202 | }; | ||
203 | |||
204 | static struct lpss_device_desc bsw_pwm_dev_desc = { | ||
205 | .clk_required = true, | ||
206 | .save_ctx = true, | ||
207 | .shared_clock = &bsw_pwm_clock, | ||
208 | }; | 167 | }; |
209 | 168 | ||
210 | #else | 169 | #else |
@@ -237,7 +196,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { | |||
237 | { "INT33FC", }, | 196 | { "INT33FC", }, |
238 | 197 | ||
239 | /* Braswell LPSS devices */ | 198 | /* Braswell LPSS devices */ |
240 | { "80862288", LPSS_ADDR(bsw_pwm_dev_desc) }, | 199 | { "80862288", LPSS_ADDR(byt_pwm_dev_desc) }, |
241 | { "8086228A", LPSS_ADDR(byt_uart_dev_desc) }, | 200 | { "8086228A", LPSS_ADDR(byt_uart_dev_desc) }, |
242 | { "8086228E", LPSS_ADDR(byt_spi_dev_desc) }, | 201 | { "8086228E", LPSS_ADDR(byt_spi_dev_desc) }, |
243 | { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) }, | 202 | { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) }, |
@@ -251,7 +210,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { | |||
251 | { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, | 210 | { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, |
252 | { "INT3437", }, | 211 | { "INT3437", }, |
253 | 212 | ||
254 | { "INT3438", LPSS_ADDR(wpt_dev_desc) }, | 213 | /* Wildcat Point LPSS devices */ |
214 | { "INT3438", LPSS_ADDR(lpt_dev_desc) }, | ||
255 | 215 | ||
256 | { } | 216 | { } |
257 | }; | 217 | }; |
@@ -276,7 +236,6 @@ static int register_device_clock(struct acpi_device *adev, | |||
276 | struct lpss_private_data *pdata) | 236 | struct lpss_private_data *pdata) |
277 | { | 237 | { |
278 | const struct lpss_device_desc *dev_desc = pdata->dev_desc; | 238 | const struct lpss_device_desc *dev_desc = pdata->dev_desc; |
279 | struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; | ||
280 | const char *devname = dev_name(&adev->dev); | 239 | const char *devname = dev_name(&adev->dev); |
281 | struct clk *clk = ERR_PTR(-ENODEV); | 240 | struct clk *clk = ERR_PTR(-ENODEV); |
282 | struct lpss_clk_data *clk_data; | 241 | struct lpss_clk_data *clk_data; |
@@ -289,12 +248,7 @@ static int register_device_clock(struct acpi_device *adev, | |||
289 | clk_data = platform_get_drvdata(lpss_clk_dev); | 248 | clk_data = platform_get_drvdata(lpss_clk_dev); |
290 | if (!clk_data) | 249 | if (!clk_data) |
291 | return -ENODEV; | 250 | return -ENODEV; |
292 | 251 | clk = clk_data->clk; | |
293 | if (dev_desc->clkdev_name) { | ||
294 | clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, | ||
295 | devname); | ||
296 | return 0; | ||
297 | } | ||
298 | 252 | ||
299 | if (!pdata->mmio_base | 253 | if (!pdata->mmio_base |
300 | || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE) | 254 | || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE) |
@@ -303,24 +257,19 @@ static int register_device_clock(struct acpi_device *adev, | |||
303 | parent = clk_data->name; | 257 | parent = clk_data->name; |
304 | prv_base = pdata->mmio_base + dev_desc->prv_offset; | 258 | prv_base = pdata->mmio_base + dev_desc->prv_offset; |
305 | 259 | ||
306 | if (shared_clock) { | 260 | if (pdata->fixed_clk_rate) { |
307 | clk = shared_clock->clk; | 261 | clk = clk_register_fixed_rate(NULL, devname, parent, 0, |
308 | if (!clk) { | 262 | pdata->fixed_clk_rate); |
309 | clk = clk_register_fixed_rate(NULL, shared_clock->name, | 263 | goto out; |
310 | "lpss_clk", 0, | ||
311 | shared_clock->rate); | ||
312 | shared_clock->clk = clk; | ||
313 | } | ||
314 | parent = shared_clock->name; | ||
315 | } | 264 | } |
316 | 265 | ||
317 | if (dev_desc->clk_gate) { | 266 | if (dev_desc->flags & LPSS_CLK_GATE) { |
318 | clk = clk_register_gate(NULL, devname, parent, 0, | 267 | clk = clk_register_gate(NULL, devname, parent, 0, |
319 | prv_base, 0, 0, NULL); | 268 | prv_base, 0, 0, NULL); |
320 | parent = devname; | 269 | parent = devname; |
321 | } | 270 | } |
322 | 271 | ||
323 | if (dev_desc->clk_divider) { | 272 | if (dev_desc->flags & LPSS_CLK_DIVIDER) { |
324 | /* Prevent division by zero */ | 273 | /* Prevent division by zero */ |
325 | if (!readl(prv_base)) | 274 | if (!readl(prv_base)) |
326 | writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); | 275 | writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); |
@@ -344,7 +293,7 @@ static int register_device_clock(struct acpi_device *adev, | |||
344 | kfree(parent); | 293 | kfree(parent); |
345 | kfree(clk_name); | 294 | kfree(clk_name); |
346 | } | 295 | } |
347 | 296 | out: | |
348 | if (IS_ERR(clk)) | 297 | if (IS_ERR(clk)) |
349 | return PTR_ERR(clk); | 298 | return PTR_ERR(clk); |
350 | 299 | ||
@@ -392,7 +341,10 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
392 | 341 | ||
393 | pdata->dev_desc = dev_desc; | 342 | pdata->dev_desc = dev_desc; |
394 | 343 | ||
395 | if (dev_desc->clk_required) { | 344 | if (dev_desc->setup) |
345 | dev_desc->setup(pdata); | ||
346 | |||
347 | if (dev_desc->flags & LPSS_CLK) { | ||
396 | ret = register_device_clock(adev, pdata); | 348 | ret = register_device_clock(adev, pdata); |
397 | if (ret) { | 349 | if (ret) { |
398 | /* Skip the device, but continue the namespace scan. */ | 350 | /* Skip the device, but continue the namespace scan. */ |
@@ -413,9 +365,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
413 | goto err_out; | 365 | goto err_out; |
414 | } | 366 | } |
415 | 367 | ||
416 | if (dev_desc->setup) | ||
417 | dev_desc->setup(pdata); | ||
418 | |||
419 | adev->driver_data = pdata; | 368 | adev->driver_data = pdata; |
420 | pdev = acpi_create_platform_device(adev); | 369 | pdev = acpi_create_platform_device(adev); |
421 | if (!IS_ERR_OR_NULL(pdev)) { | 370 | if (!IS_ERR_OR_NULL(pdev)) { |
@@ -692,19 +641,19 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, | |||
692 | 641 | ||
693 | switch (action) { | 642 | switch (action) { |
694 | case BUS_NOTIFY_BOUND_DRIVER: | 643 | case BUS_NOTIFY_BOUND_DRIVER: |
695 | if (pdata->dev_desc->save_ctx) | 644 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
696 | pdev->dev.pm_domain = &acpi_lpss_pm_domain; | 645 | pdev->dev.pm_domain = &acpi_lpss_pm_domain; |
697 | break; | 646 | break; |
698 | case BUS_NOTIFY_UNBOUND_DRIVER: | 647 | case BUS_NOTIFY_UNBOUND_DRIVER: |
699 | if (pdata->dev_desc->save_ctx) | 648 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
700 | pdev->dev.pm_domain = NULL; | 649 | pdev->dev.pm_domain = NULL; |
701 | break; | 650 | break; |
702 | case BUS_NOTIFY_ADD_DEVICE: | 651 | case BUS_NOTIFY_ADD_DEVICE: |
703 | if (pdata->dev_desc->ltr_required) | 652 | if (pdata->dev_desc->flags & LPSS_LTR) |
704 | return sysfs_create_group(&pdev->dev.kobj, | 653 | return sysfs_create_group(&pdev->dev.kobj, |
705 | &lpss_attr_group); | 654 | &lpss_attr_group); |
706 | case BUS_NOTIFY_DEL_DEVICE: | 655 | case BUS_NOTIFY_DEL_DEVICE: |
707 | if (pdata->dev_desc->ltr_required) | 656 | if (pdata->dev_desc->flags & LPSS_LTR) |
708 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); | 657 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); |
709 | default: | 658 | default: |
710 | break; | 659 | break; |
@@ -721,7 +670,7 @@ static void acpi_lpss_bind(struct device *dev) | |||
721 | { | 670 | { |
722 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); | 671 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
723 | 672 | ||
724 | if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) | 673 | if (!pdata || !pdata->mmio_base || !(pdata->dev_desc->flags & LPSS_LTR)) |
725 | return; | 674 | return; |
726 | 675 | ||
727 | if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) | 676 | if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) |