diff options
-rw-r--r-- | drivers/mfd/Kconfig | 23 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 3 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-acpi.c | 84 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-pci.c | 113 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss.c | 524 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss.h | 62 |
6 files changed, 809 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 653815950aa2..268b6dd79acc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -328,6 +328,29 @@ config INTEL_SOC_PMIC | |||
328 | thermal, charger and related power management functions | 328 | thermal, charger and related power management functions |
329 | on these systems. | 329 | on these systems. |
330 | 330 | ||
331 | config MFD_INTEL_LPSS | ||
332 | tristate | ||
333 | select COMMON_CLK | ||
334 | select MFD_CORE | ||
335 | |||
336 | config MFD_INTEL_LPSS_ACPI | ||
337 | tristate "Intel Low Power Subsystem support in ACPI mode" | ||
338 | select MFD_INTEL_LPSS | ||
339 | depends on X86 && ACPI | ||
340 | help | ||
341 | This driver supports Intel Low Power Subsystem (LPSS) devices such as | ||
342 | I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake | ||
343 | PCH) in ACPI mode. | ||
344 | |||
345 | config MFD_INTEL_LPSS_PCI | ||
346 | tristate "Intel Low Power Subsystem support in PCI mode" | ||
347 | select MFD_INTEL_LPSS | ||
348 | depends on X86 && PCI | ||
349 | help | ||
350 | This driver supports Intel Low Power Subsystem (LPSS) devices such as | ||
351 | I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake | ||
352 | PCH) in PCI mode. | ||
353 | |||
331 | config MFD_INTEL_MSIC | 354 | config MFD_INTEL_MSIC |
332 | bool "Intel MSIC" | 355 | bool "Intel MSIC" |
333 | depends on INTEL_SCU_IPC | 356 | depends on INTEL_SCU_IPC |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ea40e076cb61..9d730a2d1878 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -161,6 +161,9 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o | |||
161 | obj-$(CONFIG_MFD_TPS65090) += tps65090.o | 161 | obj-$(CONFIG_MFD_TPS65090) += tps65090.o |
162 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o | 162 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o |
163 | obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o | 163 | obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o |
164 | obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o | ||
165 | obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o | ||
166 | obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o | ||
164 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o | 167 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o |
165 | obj-$(CONFIG_MFD_PALMAS) += palmas.o | 168 | obj-$(CONFIG_MFD_PALMAS) += palmas.o |
166 | obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o | 169 | obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o |
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c new file mode 100644 index 000000000000..0d92d73bfa0e --- /dev/null +++ b/drivers/mfd/intel-lpss-acpi.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Intel LPSS ACPI support. | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * | ||
6 | * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||
7 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/acpi.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include "intel-lpss.h" | ||
23 | |||
24 | static const struct intel_lpss_platform_info spt_info = { | ||
25 | .clk_rate = 120000000, | ||
26 | }; | ||
27 | |||
28 | static const struct acpi_device_id intel_lpss_acpi_ids[] = { | ||
29 | /* SPT */ | ||
30 | { "INT3446", (kernel_ulong_t)&spt_info }, | ||
31 | { "INT3447", (kernel_ulong_t)&spt_info }, | ||
32 | { } | ||
33 | }; | ||
34 | MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids); | ||
35 | |||
36 | static int intel_lpss_acpi_probe(struct platform_device *pdev) | ||
37 | { | ||
38 | struct intel_lpss_platform_info *info; | ||
39 | const struct acpi_device_id *id; | ||
40 | |||
41 | id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev); | ||
42 | if (!id) | ||
43 | return -ENODEV; | ||
44 | |||
45 | info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), | ||
46 | GFP_KERNEL); | ||
47 | if (!info) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
51 | info->irq = platform_get_irq(pdev, 0); | ||
52 | |||
53 | pm_runtime_set_active(&pdev->dev); | ||
54 | pm_runtime_enable(&pdev->dev); | ||
55 | |||
56 | return intel_lpss_probe(&pdev->dev, info); | ||
57 | } | ||
58 | |||
59 | static int intel_lpss_acpi_remove(struct platform_device *pdev) | ||
60 | { | ||
61 | intel_lpss_remove(&pdev->dev); | ||
62 | pm_runtime_disable(&pdev->dev); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static INTEL_LPSS_PM_OPS(intel_lpss_acpi_pm_ops); | ||
68 | |||
69 | static struct platform_driver intel_lpss_acpi_driver = { | ||
70 | .probe = intel_lpss_acpi_probe, | ||
71 | .remove = intel_lpss_acpi_remove, | ||
72 | .driver = { | ||
73 | .name = "intel-lpss", | ||
74 | .acpi_match_table = intel_lpss_acpi_ids, | ||
75 | .pm = &intel_lpss_acpi_pm_ops, | ||
76 | }, | ||
77 | }; | ||
78 | |||
79 | module_platform_driver(intel_lpss_acpi_driver); | ||
80 | |||
81 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); | ||
82 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); | ||
83 | MODULE_DESCRIPTION("Intel LPSS ACPI driver"); | ||
84 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c new file mode 100644 index 000000000000..9236dffeb4d6 --- /dev/null +++ b/drivers/mfd/intel-lpss-pci.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * Intel LPSS PCI support. | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * | ||
6 | * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||
7 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/ioport.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | |||
21 | #include "intel-lpss.h" | ||
22 | |||
23 | static int intel_lpss_pci_probe(struct pci_dev *pdev, | ||
24 | const struct pci_device_id *id) | ||
25 | { | ||
26 | struct intel_lpss_platform_info *info; | ||
27 | int ret; | ||
28 | |||
29 | ret = pcim_enable_device(pdev); | ||
30 | if (ret) | ||
31 | return ret; | ||
32 | |||
33 | info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), | ||
34 | GFP_KERNEL); | ||
35 | if (!info) | ||
36 | return -ENOMEM; | ||
37 | |||
38 | info->mem = &pdev->resource[0]; | ||
39 | info->irq = pdev->irq; | ||
40 | |||
41 | /* Probably it is enough to set this for iDMA capable devices only */ | ||
42 | pci_set_master(pdev); | ||
43 | |||
44 | ret = intel_lpss_probe(&pdev->dev, info); | ||
45 | if (ret) | ||
46 | return ret; | ||
47 | |||
48 | pm_runtime_put(&pdev->dev); | ||
49 | pm_runtime_allow(&pdev->dev); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static void intel_lpss_pci_remove(struct pci_dev *pdev) | ||
55 | { | ||
56 | pm_runtime_forbid(&pdev->dev); | ||
57 | pm_runtime_get_sync(&pdev->dev); | ||
58 | |||
59 | intel_lpss_remove(&pdev->dev); | ||
60 | } | ||
61 | |||
62 | static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops); | ||
63 | |||
64 | static const struct intel_lpss_platform_info spt_info = { | ||
65 | .clk_rate = 120000000, | ||
66 | }; | ||
67 | |||
68 | static const struct intel_lpss_platform_info spt_uart_info = { | ||
69 | .clk_rate = 120000000, | ||
70 | .clk_con_id = "baudclk", | ||
71 | }; | ||
72 | |||
73 | static const struct pci_device_id intel_lpss_pci_ids[] = { | ||
74 | /* SPT-LP */ | ||
75 | { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, | ||
76 | { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, | ||
77 | { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, | ||
78 | { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, | ||
79 | { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info }, | ||
80 | { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info }, | ||
81 | { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info }, | ||
82 | { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info }, | ||
83 | { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info }, | ||
84 | { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info }, | ||
85 | { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, | ||
86 | /* SPT-H */ | ||
87 | { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, | ||
88 | { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, | ||
89 | { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, | ||
90 | { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, | ||
91 | { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info }, | ||
92 | { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info }, | ||
93 | { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, | ||
94 | { } | ||
95 | }; | ||
96 | MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); | ||
97 | |||
98 | static struct pci_driver intel_lpss_pci_driver = { | ||
99 | .name = "intel-lpss", | ||
100 | .id_table = intel_lpss_pci_ids, | ||
101 | .probe = intel_lpss_pci_probe, | ||
102 | .remove = intel_lpss_pci_remove, | ||
103 | .driver = { | ||
104 | .pm = &intel_lpss_pci_pm_ops, | ||
105 | }, | ||
106 | }; | ||
107 | |||
108 | module_pci_driver(intel_lpss_pci_driver); | ||
109 | |||
110 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); | ||
111 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); | ||
112 | MODULE_DESCRIPTION("Intel LPSS PCI driver"); | ||
113 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c new file mode 100644 index 000000000000..fdf4d5c1add2 --- /dev/null +++ b/drivers/mfd/intel-lpss.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * Intel Sunrisepoint LPSS core support. | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * | ||
6 | * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||
7 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
8 | * Heikki Krogerus <heikki.krogerus@linux.intel.com> | ||
9 | * Jarkko Nikula <jarkko.nikula@linux.intel.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clkdev.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/debugfs.h> | ||
20 | #include <linux/idr.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mfd/core.h> | ||
25 | #include <linux/pm_qos.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | |||
29 | #include "intel-lpss.h" | ||
30 | |||
31 | #define LPSS_DEV_OFFSET 0x000 | ||
32 | #define LPSS_DEV_SIZE 0x200 | ||
33 | #define LPSS_PRIV_OFFSET 0x200 | ||
34 | #define LPSS_PRIV_SIZE 0x100 | ||
35 | #define LPSS_IDMA64_OFFSET 0x800 | ||
36 | #define LPSS_IDMA64_SIZE 0x800 | ||
37 | |||
38 | /* Offsets from lpss->priv */ | ||
39 | #define LPSS_PRIV_RESETS 0x04 | ||
40 | #define LPSS_PRIV_RESETS_FUNC BIT(2) | ||
41 | #define LPSS_PRIV_RESETS_IDMA 0x3 | ||
42 | |||
43 | #define LPSS_PRIV_ACTIVELTR 0x10 | ||
44 | #define LPSS_PRIV_IDLELTR 0x14 | ||
45 | |||
46 | #define LPSS_PRIV_LTR_REQ BIT(15) | ||
47 | #define LPSS_PRIV_LTR_SCALE_MASK 0xc00 | ||
48 | #define LPSS_PRIV_LTR_SCALE_1US 0x800 | ||
49 | #define LPSS_PRIV_LTR_SCALE_32US 0xc00 | ||
50 | #define LPSS_PRIV_LTR_VALUE_MASK 0x3ff | ||
51 | |||
52 | #define LPSS_PRIV_SSP_REG 0x20 | ||
53 | #define LPSS_PRIV_SSP_REG_DIS_DMA_FIN BIT(0) | ||
54 | |||
55 | #define LPSS_PRIV_REMAP_ADDR_LO 0x40 | ||
56 | #define LPSS_PRIV_REMAP_ADDR_HI 0x44 | ||
57 | |||
58 | #define LPSS_PRIV_CAPS 0xfc | ||
59 | #define LPSS_PRIV_CAPS_NO_IDMA BIT(8) | ||
60 | #define LPSS_PRIV_CAPS_TYPE_SHIFT 4 | ||
61 | #define LPSS_PRIV_CAPS_TYPE_MASK (0xf << LPSS_PRIV_CAPS_TYPE_SHIFT) | ||
62 | |||
63 | /* This matches the type field in CAPS register */ | ||
64 | enum intel_lpss_dev_type { | ||
65 | LPSS_DEV_I2C = 0, | ||
66 | LPSS_DEV_UART, | ||
67 | LPSS_DEV_SPI, | ||
68 | }; | ||
69 | |||
70 | struct intel_lpss { | ||
71 | const struct intel_lpss_platform_info *info; | ||
72 | enum intel_lpss_dev_type type; | ||
73 | struct clk *clk; | ||
74 | struct clk_lookup *clock; | ||
75 | const struct mfd_cell *cell; | ||
76 | struct device *dev; | ||
77 | void __iomem *priv; | ||
78 | int devid; | ||
79 | u32 caps; | ||
80 | u32 active_ltr; | ||
81 | u32 idle_ltr; | ||
82 | struct dentry *debugfs; | ||
83 | }; | ||
84 | |||
85 | static const struct resource intel_lpss_dev_resources[] = { | ||
86 | DEFINE_RES_MEM_NAMED(LPSS_DEV_OFFSET, LPSS_DEV_SIZE, "lpss_dev"), | ||
87 | DEFINE_RES_MEM_NAMED(LPSS_PRIV_OFFSET, LPSS_PRIV_SIZE, "lpss_priv"), | ||
88 | DEFINE_RES_IRQ(0), | ||
89 | }; | ||
90 | |||
91 | static const struct resource intel_lpss_idma64_resources[] = { | ||
92 | DEFINE_RES_MEM(LPSS_IDMA64_OFFSET, LPSS_IDMA64_SIZE), | ||
93 | DEFINE_RES_IRQ(0), | ||
94 | }; | ||
95 | |||
96 | #define LPSS_IDMA64_DRIVER_NAME "idma64" | ||
97 | |||
98 | /* | ||
99 | * Cells needs to be ordered so that the iDMA is created first. This is | ||
100 | * because we need to be sure the DMA is available when the host controller | ||
101 | * driver is probed. | ||
102 | */ | ||
103 | static const struct mfd_cell intel_lpss_idma64_cell = { | ||
104 | .name = LPSS_IDMA64_DRIVER_NAME, | ||
105 | .num_resources = ARRAY_SIZE(intel_lpss_idma64_resources), | ||
106 | .resources = intel_lpss_idma64_resources, | ||
107 | }; | ||
108 | |||
109 | static const struct mfd_cell intel_lpss_i2c_cell = { | ||
110 | .name = "i2c_designware", | ||
111 | .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), | ||
112 | .resources = intel_lpss_dev_resources, | ||
113 | }; | ||
114 | |||
115 | static const struct mfd_cell intel_lpss_uart_cell = { | ||
116 | .name = "dw-apb-uart", | ||
117 | .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), | ||
118 | .resources = intel_lpss_dev_resources, | ||
119 | }; | ||
120 | |||
121 | static const struct mfd_cell intel_lpss_spi_cell = { | ||
122 | .name = "pxa2xx-spi", | ||
123 | .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), | ||
124 | .resources = intel_lpss_dev_resources, | ||
125 | }; | ||
126 | |||
127 | static DEFINE_IDA(intel_lpss_devid_ida); | ||
128 | static struct dentry *intel_lpss_debugfs; | ||
129 | |||
130 | static int intel_lpss_request_dma_module(const char *name) | ||
131 | { | ||
132 | static bool intel_lpss_dma_requested; | ||
133 | |||
134 | if (intel_lpss_dma_requested) | ||
135 | return 0; | ||
136 | |||
137 | intel_lpss_dma_requested = true; | ||
138 | return request_module("%s", name); | ||
139 | } | ||
140 | |||
141 | static void intel_lpss_cache_ltr(struct intel_lpss *lpss) | ||
142 | { | ||
143 | lpss->active_ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); | ||
144 | lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR); | ||
145 | } | ||
146 | |||
147 | static int intel_lpss_debugfs_add(struct intel_lpss *lpss) | ||
148 | { | ||
149 | struct dentry *dir; | ||
150 | |||
151 | dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs); | ||
152 | if (IS_ERR(dir)) | ||
153 | return PTR_ERR(dir); | ||
154 | |||
155 | /* Cache the values into lpss structure */ | ||
156 | intel_lpss_cache_ltr(lpss); | ||
157 | |||
158 | debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps); | ||
159 | debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr); | ||
160 | debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr); | ||
161 | |||
162 | lpss->debugfs = dir; | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static void intel_lpss_debugfs_remove(struct intel_lpss *lpss) | ||
167 | { | ||
168 | debugfs_remove_recursive(lpss->debugfs); | ||
169 | } | ||
170 | |||
171 | static void intel_lpss_ltr_set(struct device *dev, s32 val) | ||
172 | { | ||
173 | struct intel_lpss *lpss = dev_get_drvdata(dev); | ||
174 | u32 ltr; | ||
175 | |||
176 | /* | ||
177 | * Program latency tolerance (LTR) accordingly what has been asked | ||
178 | * by the PM QoS layer or disable it in case we were passed | ||
179 | * negative value or PM_QOS_LATENCY_ANY. | ||
180 | */ | ||
181 | ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); | ||
182 | |||
183 | if (val == PM_QOS_LATENCY_ANY || val < 0) { | ||
184 | ltr &= ~LPSS_PRIV_LTR_REQ; | ||
185 | } else { | ||
186 | ltr |= LPSS_PRIV_LTR_REQ; | ||
187 | ltr &= ~LPSS_PRIV_LTR_SCALE_MASK; | ||
188 | ltr &= ~LPSS_PRIV_LTR_VALUE_MASK; | ||
189 | |||
190 | if (val > LPSS_PRIV_LTR_VALUE_MASK) | ||
191 | ltr |= LPSS_PRIV_LTR_SCALE_32US | val >> 5; | ||
192 | else | ||
193 | ltr |= LPSS_PRIV_LTR_SCALE_1US | val; | ||
194 | } | ||
195 | |||
196 | if (ltr == lpss->active_ltr) | ||
197 | return; | ||
198 | |||
199 | writel(ltr, lpss->priv + LPSS_PRIV_ACTIVELTR); | ||
200 | writel(ltr, lpss->priv + LPSS_PRIV_IDLELTR); | ||
201 | |||
202 | /* Cache the values into lpss structure */ | ||
203 | intel_lpss_cache_ltr(lpss); | ||
204 | } | ||
205 | |||
206 | static void intel_lpss_ltr_expose(struct intel_lpss *lpss) | ||
207 | { | ||
208 | lpss->dev->power.set_latency_tolerance = intel_lpss_ltr_set; | ||
209 | dev_pm_qos_expose_latency_tolerance(lpss->dev); | ||
210 | } | ||
211 | |||
212 | static void intel_lpss_ltr_hide(struct intel_lpss *lpss) | ||
213 | { | ||
214 | dev_pm_qos_hide_latency_tolerance(lpss->dev); | ||
215 | lpss->dev->power.set_latency_tolerance = NULL; | ||
216 | } | ||
217 | |||
218 | static int intel_lpss_assign_devs(struct intel_lpss *lpss) | ||
219 | { | ||
220 | unsigned int type; | ||
221 | |||
222 | type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; | ||
223 | type >>= LPSS_PRIV_CAPS_TYPE_SHIFT; | ||
224 | |||
225 | switch (type) { | ||
226 | case LPSS_DEV_I2C: | ||
227 | lpss->cell = &intel_lpss_i2c_cell; | ||
228 | break; | ||
229 | case LPSS_DEV_UART: | ||
230 | lpss->cell = &intel_lpss_uart_cell; | ||
231 | break; | ||
232 | case LPSS_DEV_SPI: | ||
233 | lpss->cell = &intel_lpss_spi_cell; | ||
234 | break; | ||
235 | default: | ||
236 | return -ENODEV; | ||
237 | } | ||
238 | |||
239 | lpss->type = type; | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static bool intel_lpss_has_idma(const struct intel_lpss *lpss) | ||
245 | { | ||
246 | return (lpss->caps & LPSS_PRIV_CAPS_NO_IDMA) == 0; | ||
247 | } | ||
248 | |||
249 | static void intel_lpss_set_remap_addr(const struct intel_lpss *lpss) | ||
250 | { | ||
251 | resource_size_t addr = lpss->info->mem->start; | ||
252 | |||
253 | writel(addr, lpss->priv + LPSS_PRIV_REMAP_ADDR_LO); | ||
254 | #if BITS_PER_LONG > 32 | ||
255 | writel(addr >> 32, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); | ||
256 | #else | ||
257 | writel(0, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); | ||
258 | #endif | ||
259 | } | ||
260 | |||
261 | static void intel_lpss_deassert_reset(const struct intel_lpss *lpss) | ||
262 | { | ||
263 | u32 value = LPSS_PRIV_RESETS_FUNC | LPSS_PRIV_RESETS_IDMA; | ||
264 | |||
265 | /* Bring out the device from reset */ | ||
266 | writel(value, lpss->priv + LPSS_PRIV_RESETS); | ||
267 | } | ||
268 | |||
269 | static void intel_lpss_init_dev(const struct intel_lpss *lpss) | ||
270 | { | ||
271 | u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; | ||
272 | |||
273 | intel_lpss_deassert_reset(lpss); | ||
274 | |||
275 | if (!intel_lpss_has_idma(lpss)) | ||
276 | return; | ||
277 | |||
278 | intel_lpss_set_remap_addr(lpss); | ||
279 | |||
280 | /* Make sure that SPI multiblock DMA transfers are re-enabled */ | ||
281 | if (lpss->type == LPSS_DEV_SPI) | ||
282 | writel(value, lpss->priv + LPSS_PRIV_SSP_REG); | ||
283 | } | ||
284 | |||
285 | static void intel_lpss_unregister_clock_tree(struct clk *clk) | ||
286 | { | ||
287 | struct clk *parent; | ||
288 | |||
289 | while (clk) { | ||
290 | parent = clk_get_parent(clk); | ||
291 | clk_unregister(clk); | ||
292 | clk = parent; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, | ||
297 | const char *devname, | ||
298 | struct clk **clk) | ||
299 | { | ||
300 | char name[32]; | ||
301 | struct clk *tmp = *clk; | ||
302 | |||
303 | snprintf(name, sizeof(name), "%s-enable", devname); | ||
304 | tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, | ||
305 | lpss->priv, 0, 0, NULL); | ||
306 | if (IS_ERR(tmp)) | ||
307 | return PTR_ERR(tmp); | ||
308 | |||
309 | snprintf(name, sizeof(name), "%s-div", devname); | ||
310 | tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), | ||
311 | 0, lpss->priv, 1, 15, 16, 15, 0, | ||
312 | NULL); | ||
313 | if (IS_ERR(tmp)) | ||
314 | return PTR_ERR(tmp); | ||
315 | *clk = tmp; | ||
316 | |||
317 | snprintf(name, sizeof(name), "%s-update", devname); | ||
318 | tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), | ||
319 | CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); | ||
320 | if (IS_ERR(tmp)) | ||
321 | return PTR_ERR(tmp); | ||
322 | *clk = tmp; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int intel_lpss_register_clock(struct intel_lpss *lpss) | ||
328 | { | ||
329 | const struct mfd_cell *cell = lpss->cell; | ||
330 | struct clk *clk; | ||
331 | char devname[24]; | ||
332 | int ret; | ||
333 | |||
334 | if (!lpss->info->clk_rate) | ||
335 | return 0; | ||
336 | |||
337 | /* Root clock */ | ||
338 | clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, | ||
339 | CLK_IS_ROOT, lpss->info->clk_rate); | ||
340 | if (IS_ERR(clk)) | ||
341 | return PTR_ERR(clk); | ||
342 | |||
343 | snprintf(devname, sizeof(devname), "%s.%d", cell->name, lpss->devid); | ||
344 | |||
345 | /* | ||
346 | * Support for clock divider only if it has some preset value. | ||
347 | * Otherwise we assume that the divider is not used. | ||
348 | */ | ||
349 | if (lpss->type != LPSS_DEV_I2C) { | ||
350 | ret = intel_lpss_register_clock_divider(lpss, devname, &clk); | ||
351 | if (ret) | ||
352 | goto err_clk_register; | ||
353 | } | ||
354 | |||
355 | ret = -ENOMEM; | ||
356 | |||
357 | /* Clock for the host controller */ | ||
358 | lpss->clock = clkdev_create(clk, lpss->info->clk_con_id, "%s", devname); | ||
359 | if (!lpss->clock) | ||
360 | goto err_clk_register; | ||
361 | |||
362 | lpss->clk = clk; | ||
363 | |||
364 | return 0; | ||
365 | |||
366 | err_clk_register: | ||
367 | intel_lpss_unregister_clock_tree(clk); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static void intel_lpss_unregister_clock(struct intel_lpss *lpss) | ||
373 | { | ||
374 | if (IS_ERR_OR_NULL(lpss->clk)) | ||
375 | return; | ||
376 | |||
377 | clkdev_drop(lpss->clock); | ||
378 | intel_lpss_unregister_clock_tree(lpss->clk); | ||
379 | } | ||
380 | |||
381 | int intel_lpss_probe(struct device *dev, | ||
382 | const struct intel_lpss_platform_info *info) | ||
383 | { | ||
384 | struct intel_lpss *lpss; | ||
385 | int ret; | ||
386 | |||
387 | if (!info || !info->mem || info->irq <= 0) | ||
388 | return -EINVAL; | ||
389 | |||
390 | lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL); | ||
391 | if (!lpss) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | lpss->priv = devm_ioremap(dev, info->mem->start + LPSS_PRIV_OFFSET, | ||
395 | LPSS_PRIV_SIZE); | ||
396 | if (!lpss->priv) | ||
397 | return -ENOMEM; | ||
398 | |||
399 | lpss->info = info; | ||
400 | lpss->dev = dev; | ||
401 | lpss->caps = readl(lpss->priv + LPSS_PRIV_CAPS); | ||
402 | |||
403 | dev_set_drvdata(dev, lpss); | ||
404 | |||
405 | ret = intel_lpss_assign_devs(lpss); | ||
406 | if (ret) | ||
407 | return ret; | ||
408 | |||
409 | intel_lpss_init_dev(lpss); | ||
410 | |||
411 | lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); | ||
412 | if (lpss->devid < 0) | ||
413 | return lpss->devid; | ||
414 | |||
415 | ret = intel_lpss_register_clock(lpss); | ||
416 | if (ret) | ||
417 | goto err_clk_register; | ||
418 | |||
419 | intel_lpss_ltr_expose(lpss); | ||
420 | |||
421 | ret = intel_lpss_debugfs_add(lpss); | ||
422 | if (ret) | ||
423 | dev_warn(dev, "Failed to create debugfs entries\n"); | ||
424 | |||
425 | if (intel_lpss_has_idma(lpss)) { | ||
426 | /* | ||
427 | * Ensure the DMA driver is loaded before the host | ||
428 | * controller device appears, so that the host controller | ||
429 | * driver can request its DMA channels as early as | ||
430 | * possible. | ||
431 | * | ||
432 | * If the DMA module is not there that's OK as well. | ||
433 | */ | ||
434 | intel_lpss_request_dma_module(LPSS_IDMA64_DRIVER_NAME); | ||
435 | |||
436 | ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell, | ||
437 | 1, info->mem, info->irq, NULL); | ||
438 | if (ret) | ||
439 | dev_warn(dev, "Failed to add %s, fallback to PIO\n", | ||
440 | LPSS_IDMA64_DRIVER_NAME); | ||
441 | } | ||
442 | |||
443 | ret = mfd_add_devices(dev, lpss->devid, lpss->cell, | ||
444 | 1, info->mem, info->irq, NULL); | ||
445 | if (ret) | ||
446 | goto err_remove_ltr; | ||
447 | |||
448 | return 0; | ||
449 | |||
450 | err_remove_ltr: | ||
451 | intel_lpss_debugfs_remove(lpss); | ||
452 | intel_lpss_ltr_hide(lpss); | ||
453 | |||
454 | err_clk_register: | ||
455 | ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); | ||
456 | |||
457 | return ret; | ||
458 | } | ||
459 | EXPORT_SYMBOL_GPL(intel_lpss_probe); | ||
460 | |||
461 | void intel_lpss_remove(struct device *dev) | ||
462 | { | ||
463 | struct intel_lpss *lpss = dev_get_drvdata(dev); | ||
464 | |||
465 | mfd_remove_devices(dev); | ||
466 | intel_lpss_debugfs_remove(lpss); | ||
467 | intel_lpss_ltr_hide(lpss); | ||
468 | intel_lpss_unregister_clock(lpss); | ||
469 | ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); | ||
470 | } | ||
471 | EXPORT_SYMBOL_GPL(intel_lpss_remove); | ||
472 | |||
473 | static int resume_lpss_device(struct device *dev, void *data) | ||
474 | { | ||
475 | pm_runtime_resume(dev); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | int intel_lpss_prepare(struct device *dev) | ||
480 | { | ||
481 | /* | ||
482 | * Resume both child devices before entering system sleep. This | ||
483 | * ensures that they are in proper state before they get suspended. | ||
484 | */ | ||
485 | device_for_each_child_reverse(dev, NULL, resume_lpss_device); | ||
486 | return 0; | ||
487 | } | ||
488 | EXPORT_SYMBOL_GPL(intel_lpss_prepare); | ||
489 | |||
490 | int intel_lpss_suspend(struct device *dev) | ||
491 | { | ||
492 | return 0; | ||
493 | } | ||
494 | EXPORT_SYMBOL_GPL(intel_lpss_suspend); | ||
495 | |||
496 | int intel_lpss_resume(struct device *dev) | ||
497 | { | ||
498 | struct intel_lpss *lpss = dev_get_drvdata(dev); | ||
499 | |||
500 | intel_lpss_init_dev(lpss); | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | EXPORT_SYMBOL_GPL(intel_lpss_resume); | ||
505 | |||
506 | static int __init intel_lpss_init(void) | ||
507 | { | ||
508 | intel_lpss_debugfs = debugfs_create_dir("intel_lpss", NULL); | ||
509 | return 0; | ||
510 | } | ||
511 | module_init(intel_lpss_init); | ||
512 | |||
513 | static void __exit intel_lpss_exit(void) | ||
514 | { | ||
515 | debugfs_remove(intel_lpss_debugfs); | ||
516 | } | ||
517 | module_exit(intel_lpss_exit); | ||
518 | |||
519 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); | ||
520 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); | ||
521 | MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); | ||
522 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); | ||
523 | MODULE_DESCRIPTION("Intel LPSS core driver"); | ||
524 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h new file mode 100644 index 000000000000..f28cb28a62f8 --- /dev/null +++ b/drivers/mfd/intel-lpss.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Intel LPSS core support. | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * | ||
6 | * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||
7 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #ifndef __MFD_INTEL_LPSS_H | ||
15 | #define __MFD_INTEL_LPSS_H | ||
16 | |||
17 | struct device; | ||
18 | struct resource; | ||
19 | |||
20 | struct intel_lpss_platform_info { | ||
21 | struct resource *mem; | ||
22 | int irq; | ||
23 | unsigned long clk_rate; | ||
24 | const char *clk_con_id; | ||
25 | }; | ||
26 | |||
27 | int intel_lpss_probe(struct device *dev, | ||
28 | const struct intel_lpss_platform_info *info); | ||
29 | void intel_lpss_remove(struct device *dev); | ||
30 | |||
31 | #ifdef CONFIG_PM | ||
32 | int intel_lpss_prepare(struct device *dev); | ||
33 | int intel_lpss_suspend(struct device *dev); | ||
34 | int intel_lpss_resume(struct device *dev); | ||
35 | |||
36 | #ifdef CONFIG_PM_SLEEP | ||
37 | #define INTEL_LPSS_SLEEP_PM_OPS \ | ||
38 | .prepare = intel_lpss_prepare, \ | ||
39 | .suspend = intel_lpss_suspend, \ | ||
40 | .resume = intel_lpss_resume, \ | ||
41 | .freeze = intel_lpss_suspend, \ | ||
42 | .thaw = intel_lpss_resume, \ | ||
43 | .poweroff = intel_lpss_suspend, \ | ||
44 | .restore = intel_lpss_resume, | ||
45 | #endif | ||
46 | |||
47 | #define INTEL_LPSS_RUNTIME_PM_OPS \ | ||
48 | .runtime_suspend = intel_lpss_suspend, \ | ||
49 | .runtime_resume = intel_lpss_resume, | ||
50 | |||
51 | #else /* !CONFIG_PM */ | ||
52 | #define INTEL_LPSS_SLEEP_PM_OPS | ||
53 | #define INTEL_LPSS_RUNTIME_PM_OPS | ||
54 | #endif /* CONFIG_PM */ | ||
55 | |||
56 | #define INTEL_LPSS_PM_OPS(name) \ | ||
57 | const struct dev_pm_ops name = { \ | ||
58 | INTEL_LPSS_SLEEP_PM_OPS \ | ||
59 | INTEL_LPSS_RUNTIME_PM_OPS \ | ||
60 | } | ||
61 | |||
62 | #endif /* __MFD_INTEL_LPSS_H */ | ||