diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 21:46:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 21:46:13 -0400 |
commit | 8f446a7a069e0af0639385f67c78ee2279bca04c (patch) | |
tree | 580cf495616b36ca0af0826afa87c430cdc1e7cb /drivers | |
parent | 84be4ae2c038e2b03d650cbf2a7cfd9e8d6e9e51 (diff) | |
parent | 04ef037c926ddb31088c976538e29eada4fd1490 (diff) |
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM soc driver specific changes from Olof Johansson:
- A long-coming conversion of various platforms to a common LED
infrastructure
- AT91 is moved over to use the newer MCI driver for MMC
- Pincontrol conversions for samsung platforms
- DT bindings for gscaler on samsung
- i2c driver fixes for tegra, acked by i2c maintainer
Fix up conflicts as per Olof.
* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (48 commits)
drivers: bus: omap_l3: use resources instead of hardcoded irqs
pinctrl: exynos: Fix wakeup IRQ domain registration check
pinctrl: samsung: Uninline samsung_pinctrl_get_soc_data
pinctrl: exynos: Correct the detection of wakeup-eint node
pinctrl: exynos: Mark exynos_irq_demux_eint as inline
pinctrl: exynos: Handle only unmasked wakeup interrupts
pinctrl: exynos: Fix typos in gpio/wkup _irq_mask
pinctrl: exynos: Set pin function to EINT in irq_set_type of GPIO EINTa
drivers: bus: Move the OMAP interconnect driver to drivers/bus/
i2c: tegra: dynamically control fast clk
i2c: tegra: I2_M_NOSTART functionality not supported in Tegra20
ARM: tegra: clock: remove unused clock entry for i2c
ARM: tegra: clock: add connection name in i2c clock entry
i2c: tegra: pass proper name for getting clock
ARM: tegra: clock: add i2c fast clock entry in clock table
ARM: EXYNOS: Adds G-Scaler device from Device Tree
ARM: EXYNOS: Add clock support for G-Scaler
ARM: EXYNOS: Enable pinctrl driver support for EXYNOS4 device tree enabled platform
ARM: dts: Add pinctrl node entries for SAMSUNG EXYNOS4210 SoC
ARM: EXYNOS: skip wakeup interrupt setup if pinctrl driver is used
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/bus/Kconfig | 21 | ||||
-rw-r--r-- | drivers/bus/Makefile | 8 | ||||
-rw-r--r-- | drivers/bus/omap-ocp2scp.c | 88 | ||||
-rw-r--r-- | drivers/bus/omap_l3_noc.c | 267 | ||||
-rw-r--r-- | drivers/bus/omap_l3_noc.h | 176 | ||||
-rw-r--r-- | drivers/bus/omap_l3_smx.c | 297 | ||||
-rw-r--r-- | drivers/bus/omap_l3_smx.h | 338 | ||||
-rw-r--r-- | drivers/char/nwflash.c | 34 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 21 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 130 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 10 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/ledtrig-cpu.c | 163 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 40 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 2 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.c | 579 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.h | 218 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 888 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 239 |
22 files changed, 3420 insertions, 112 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 36d3daa19a74..dbdefa3fe775 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -2,6 +2,8 @@ menu "Device Drivers" | |||
2 | 2 | ||
3 | source "drivers/base/Kconfig" | 3 | source "drivers/base/Kconfig" |
4 | 4 | ||
5 | source "drivers/bus/Kconfig" | ||
6 | |||
5 | source "drivers/connector/Kconfig" | 7 | source "drivers/connector/Kconfig" |
6 | 8 | ||
7 | source "drivers/mtd/Kconfig" | 9 | source "drivers/mtd/Kconfig" |
diff --git a/drivers/Makefile b/drivers/Makefile index 8c30e73cd94c..acb48fa4531c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -6,6 +6,7 @@ | |||
6 | # | 6 | # |
7 | 7 | ||
8 | obj-y += irqchip/ | 8 | obj-y += irqchip/ |
9 | obj-y += bus/ | ||
9 | 10 | ||
10 | # GPIO must come after pinctrl as gpios may need to mux pins etc | 11 | # GPIO must come after pinctrl as gpios may need to mux pins etc |
11 | obj-y += pinctrl/ | 12 | obj-y += pinctrl/ |
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig new file mode 100644 index 000000000000..bbec35d21fe5 --- /dev/null +++ b/drivers/bus/Kconfig | |||
@@ -0,0 +1,21 @@ | |||
1 | # | ||
2 | # Bus Devices | ||
3 | # | ||
4 | |||
5 | menu "Bus devices" | ||
6 | |||
7 | config OMAP_OCP2SCP | ||
8 | tristate "OMAP OCP2SCP DRIVER" | ||
9 | help | ||
10 | Driver to enable ocp2scp module which transforms ocp interface | ||
11 | protocol to scp protocol. In OMAP4, USB PHY is connected via | ||
12 | OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via | ||
13 | OCP2SCP. | ||
14 | |||
15 | config OMAP_INTERCONNECT | ||
16 | tristate "OMAP INTERCONNECT DRIVER" | ||
17 | depends on ARCH_OMAP2PLUS | ||
18 | |||
19 | help | ||
20 | Driver to enable OMAP interconnect error handling driver. | ||
21 | endmenu | ||
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile new file mode 100644 index 000000000000..45d997c85453 --- /dev/null +++ b/drivers/bus/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the bus drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o | ||
6 | |||
7 | # Interconnect bus driver for OMAP SoCs. | ||
8 | obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o | ||
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c new file mode 100644 index 000000000000..ff63560b8467 --- /dev/null +++ b/drivers/bus/omap-ocp2scp.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * omap-ocp2scp.c - transform ocp interface protocol to scp protocol | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | |||
26 | static int ocp2scp_remove_devices(struct device *dev, void *c) | ||
27 | { | ||
28 | struct platform_device *pdev = to_platform_device(dev); | ||
29 | |||
30 | platform_device_unregister(pdev); | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int __devinit omap_ocp2scp_probe(struct platform_device *pdev) | ||
36 | { | ||
37 | int ret; | ||
38 | struct device_node *np = pdev->dev.of_node; | ||
39 | |||
40 | if (np) { | ||
41 | ret = of_platform_populate(np, NULL, NULL, &pdev->dev); | ||
42 | if (ret) { | ||
43 | dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n"); | ||
44 | goto err0; | ||
45 | } | ||
46 | } | ||
47 | pm_runtime_enable(&pdev->dev); | ||
48 | |||
49 | return 0; | ||
50 | |||
51 | err0: | ||
52 | device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); | ||
53 | |||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | static int __devexit omap_ocp2scp_remove(struct platform_device *pdev) | ||
58 | { | ||
59 | pm_runtime_disable(&pdev->dev); | ||
60 | device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | #ifdef CONFIG_OF | ||
66 | static const struct of_device_id omap_ocp2scp_id_table[] = { | ||
67 | { .compatible = "ti,omap-ocp2scp" }, | ||
68 | {} | ||
69 | }; | ||
70 | MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); | ||
71 | #endif | ||
72 | |||
73 | static struct platform_driver omap_ocp2scp_driver = { | ||
74 | .probe = omap_ocp2scp_probe, | ||
75 | .remove = __devexit_p(omap_ocp2scp_remove), | ||
76 | .driver = { | ||
77 | .name = "omap-ocp2scp", | ||
78 | .owner = THIS_MODULE, | ||
79 | .of_match_table = of_match_ptr(omap_ocp2scp_id_table), | ||
80 | }, | ||
81 | }; | ||
82 | |||
83 | module_platform_driver(omap_ocp2scp_driver); | ||
84 | |||
85 | MODULE_ALIAS("platform: omap-ocp2scp"); | ||
86 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
87 | MODULE_DESCRIPTION("OMAP OCP2SCP driver"); | ||
88 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c new file mode 100644 index 000000000000..44b2b3e57882 --- /dev/null +++ b/drivers/bus/omap_l3_noc.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * OMAP4XXX L3 Interconnect error handling driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Corporation | ||
5 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | ||
6 | * Sricharan <r.sricharan@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
21 | * USA | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "soc.h" | ||
32 | #include "omap_l3_noc.h" | ||
33 | |||
34 | /* | ||
35 | * Interrupt Handler for L3 error detection. | ||
36 | * 1) Identify the L3 clockdomain partition to which the error belongs to. | ||
37 | * 2) Identify the slave where the error information is logged | ||
38 | * 3) Print the logged information. | ||
39 | * 4) Add dump stack to provide kernel trace. | ||
40 | * | ||
41 | * Two Types of errors : | ||
42 | * 1) Custom errors in L3 : | ||
43 | * Target like DMM/FW/EMIF generates SRESP=ERR error | ||
44 | * 2) Standard L3 error: | ||
45 | * - Unsupported CMD. | ||
46 | * L3 tries to access target while it is idle | ||
47 | * - OCP disconnect. | ||
48 | * - Address hole error: | ||
49 | * If DSS/ISS/FDIF/USBHOSTFS access a target where they | ||
50 | * do not have connectivity, the error is logged in | ||
51 | * their default target which is DMM2. | ||
52 | * | ||
53 | * On High Secure devices, firewall errors are possible and those | ||
54 | * can be trapped as well. But the trapping is implemented as part | ||
55 | * secure software and hence need not be implemented here. | ||
56 | */ | ||
57 | static irqreturn_t l3_interrupt_handler(int irq, void *_l3) | ||
58 | { | ||
59 | |||
60 | struct omap4_l3 *l3 = _l3; | ||
61 | int inttype, i, k; | ||
62 | int err_src = 0; | ||
63 | u32 std_err_main, err_reg, clear, masterid; | ||
64 | void __iomem *base, *l3_targ_base; | ||
65 | char *target_name, *master_name = "UN IDENTIFIED"; | ||
66 | |||
67 | /* Get the Type of interrupt */ | ||
68 | inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; | ||
69 | |||
70 | for (i = 0; i < L3_MODULES; i++) { | ||
71 | /* | ||
72 | * Read the regerr register of the clock domain | ||
73 | * to determine the source | ||
74 | */ | ||
75 | base = l3->l3_base[i]; | ||
76 | err_reg = __raw_readl(base + l3_flagmux[i] + | ||
77 | + L3_FLAGMUX_REGERR0 + (inttype << 3)); | ||
78 | |||
79 | /* Get the corresponding error and analyse */ | ||
80 | if (err_reg) { | ||
81 | /* Identify the source from control status register */ | ||
82 | err_src = __ffs(err_reg); | ||
83 | |||
84 | /* Read the stderrlog_main_source from clk domain */ | ||
85 | l3_targ_base = base + *(l3_targ[i] + err_src); | ||
86 | std_err_main = __raw_readl(l3_targ_base + | ||
87 | L3_TARG_STDERRLOG_MAIN); | ||
88 | masterid = __raw_readl(l3_targ_base + | ||
89 | L3_TARG_STDERRLOG_MSTADDR); | ||
90 | |||
91 | switch (std_err_main & CUSTOM_ERROR) { | ||
92 | case STANDARD_ERROR: | ||
93 | target_name = | ||
94 | l3_targ_inst_name[i][err_src]; | ||
95 | WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n", | ||
96 | target_name, | ||
97 | __raw_readl(l3_targ_base + | ||
98 | L3_TARG_STDERRLOG_SLVOFSLSB)); | ||
99 | /* clear the std error log*/ | ||
100 | clear = std_err_main | CLEAR_STDERR_LOG; | ||
101 | writel(clear, l3_targ_base + | ||
102 | L3_TARG_STDERRLOG_MAIN); | ||
103 | break; | ||
104 | |||
105 | case CUSTOM_ERROR: | ||
106 | target_name = | ||
107 | l3_targ_inst_name[i][err_src]; | ||
108 | for (k = 0; k < NUM_OF_L3_MASTERS; k++) { | ||
109 | if (masterid == l3_masters[k].id) | ||
110 | master_name = | ||
111 | l3_masters[k].name; | ||
112 | } | ||
113 | WARN(true, "L3 custom error: MASTER:%s TARGET:%s\n", | ||
114 | master_name, target_name); | ||
115 | /* clear the std error log*/ | ||
116 | clear = std_err_main | CLEAR_STDERR_LOG; | ||
117 | writel(clear, l3_targ_base + | ||
118 | L3_TARG_STDERRLOG_MAIN); | ||
119 | break; | ||
120 | |||
121 | default: | ||
122 | /* Nothing to be handled here as of now */ | ||
123 | break; | ||
124 | } | ||
125 | /* Error found so break the for loop */ | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | static int __devinit omap4_l3_probe(struct platform_device *pdev) | ||
133 | { | ||
134 | static struct omap4_l3 *l3; | ||
135 | struct resource *res; | ||
136 | int ret; | ||
137 | |||
138 | l3 = kzalloc(sizeof(*l3), GFP_KERNEL); | ||
139 | if (!l3) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | platform_set_drvdata(pdev, l3); | ||
143 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
144 | if (!res) { | ||
145 | dev_err(&pdev->dev, "couldn't find resource 0\n"); | ||
146 | ret = -ENODEV; | ||
147 | goto err0; | ||
148 | } | ||
149 | |||
150 | l3->l3_base[0] = ioremap(res->start, resource_size(res)); | ||
151 | if (!l3->l3_base[0]) { | ||
152 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
153 | ret = -ENOMEM; | ||
154 | goto err0; | ||
155 | } | ||
156 | |||
157 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
158 | if (!res) { | ||
159 | dev_err(&pdev->dev, "couldn't find resource 1\n"); | ||
160 | ret = -ENODEV; | ||
161 | goto err1; | ||
162 | } | ||
163 | |||
164 | l3->l3_base[1] = ioremap(res->start, resource_size(res)); | ||
165 | if (!l3->l3_base[1]) { | ||
166 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
167 | ret = -ENOMEM; | ||
168 | goto err1; | ||
169 | } | ||
170 | |||
171 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | ||
172 | if (!res) { | ||
173 | dev_err(&pdev->dev, "couldn't find resource 2\n"); | ||
174 | ret = -ENODEV; | ||
175 | goto err2; | ||
176 | } | ||
177 | |||
178 | l3->l3_base[2] = ioremap(res->start, resource_size(res)); | ||
179 | if (!l3->l3_base[2]) { | ||
180 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
181 | ret = -ENOMEM; | ||
182 | goto err2; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * Setup interrupt Handlers | ||
187 | */ | ||
188 | l3->debug_irq = platform_get_irq(pdev, 0); | ||
189 | ret = request_irq(l3->debug_irq, | ||
190 | l3_interrupt_handler, | ||
191 | IRQF_DISABLED, "l3-dbg-irq", l3); | ||
192 | if (ret) { | ||
193 | pr_crit("L3: request_irq failed to register for 0x%x\n", | ||
194 | l3->debug_irq); | ||
195 | goto err3; | ||
196 | } | ||
197 | |||
198 | l3->app_irq = platform_get_irq(pdev, 1); | ||
199 | ret = request_irq(l3->app_irq, | ||
200 | l3_interrupt_handler, | ||
201 | IRQF_DISABLED, "l3-app-irq", l3); | ||
202 | if (ret) { | ||
203 | pr_crit("L3: request_irq failed to register for 0x%x\n", | ||
204 | l3->app_irq); | ||
205 | goto err4; | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | |||
210 | err4: | ||
211 | free_irq(l3->debug_irq, l3); | ||
212 | err3: | ||
213 | iounmap(l3->l3_base[2]); | ||
214 | err2: | ||
215 | iounmap(l3->l3_base[1]); | ||
216 | err1: | ||
217 | iounmap(l3->l3_base[0]); | ||
218 | err0: | ||
219 | kfree(l3); | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static int __devexit omap4_l3_remove(struct platform_device *pdev) | ||
224 | { | ||
225 | struct omap4_l3 *l3 = platform_get_drvdata(pdev); | ||
226 | |||
227 | free_irq(l3->app_irq, l3); | ||
228 | free_irq(l3->debug_irq, l3); | ||
229 | iounmap(l3->l3_base[0]); | ||
230 | iounmap(l3->l3_base[1]); | ||
231 | iounmap(l3->l3_base[2]); | ||
232 | kfree(l3); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | #if defined(CONFIG_OF) | ||
238 | static const struct of_device_id l3_noc_match[] = { | ||
239 | {.compatible = "ti,omap4-l3-noc", }, | ||
240 | {}, | ||
241 | }; | ||
242 | MODULE_DEVICE_TABLE(of, l3_noc_match); | ||
243 | #else | ||
244 | #define l3_noc_match NULL | ||
245 | #endif | ||
246 | |||
247 | static struct platform_driver omap4_l3_driver = { | ||
248 | .probe = omap4_l3_probe, | ||
249 | .remove = __devexit_p(omap4_l3_remove), | ||
250 | .driver = { | ||
251 | .name = "omap_l3_noc", | ||
252 | .owner = THIS_MODULE, | ||
253 | .of_match_table = l3_noc_match, | ||
254 | }, | ||
255 | }; | ||
256 | |||
257 | static int __init omap4_l3_init(void) | ||
258 | { | ||
259 | return platform_driver_register(&omap4_l3_driver); | ||
260 | } | ||
261 | postcore_initcall_sync(omap4_l3_init); | ||
262 | |||
263 | static void __exit omap4_l3_exit(void) | ||
264 | { | ||
265 | platform_driver_unregister(&omap4_l3_driver); | ||
266 | } | ||
267 | module_exit(omap4_l3_exit); | ||
diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h new file mode 100644 index 000000000000..a6ce34dc4814 --- /dev/null +++ b/drivers/bus/omap_l3_noc.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * OMAP4XXX L3 Interconnect error handling driver header | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Corporation | ||
5 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | ||
6 | * sricharan <r.sricharan@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
21 | * USA | ||
22 | */ | ||
23 | #ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H | ||
24 | #define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H | ||
25 | |||
26 | #define L3_MODULES 3 | ||
27 | #define CLEAR_STDERR_LOG (1 << 31) | ||
28 | #define CUSTOM_ERROR 0x2 | ||
29 | #define STANDARD_ERROR 0x0 | ||
30 | #define INBAND_ERROR 0x0 | ||
31 | #define L3_APPLICATION_ERROR 0x0 | ||
32 | #define L3_DEBUG_ERROR 0x1 | ||
33 | |||
34 | /* L3 TARG register offsets */ | ||
35 | #define L3_TARG_STDERRLOG_MAIN 0x48 | ||
36 | #define L3_TARG_STDERRLOG_SLVOFSLSB 0x5c | ||
37 | #define L3_TARG_STDERRLOG_MSTADDR 0x68 | ||
38 | #define L3_FLAGMUX_REGERR0 0xc | ||
39 | |||
40 | #define NUM_OF_L3_MASTERS (sizeof(l3_masters)/sizeof(l3_masters[0])) | ||
41 | |||
42 | static u32 l3_flagmux[L3_MODULES] = { | ||
43 | 0x500, | ||
44 | 0x1000, | ||
45 | 0X0200 | ||
46 | }; | ||
47 | |||
48 | /* L3 Target standard Error register offsets */ | ||
49 | static u32 l3_targ_inst_clk1[] = { | ||
50 | 0x100, /* DMM1 */ | ||
51 | 0x200, /* DMM2 */ | ||
52 | 0x300, /* ABE */ | ||
53 | 0x400, /* L4CFG */ | ||
54 | 0x600, /* CLK2 PWR DISC */ | ||
55 | 0x0, /* Host CLK1 */ | ||
56 | 0x900 /* L4 Wakeup */ | ||
57 | }; | ||
58 | |||
59 | static u32 l3_targ_inst_clk2[] = { | ||
60 | 0x500, /* CORTEX M3 */ | ||
61 | 0x300, /* DSS */ | ||
62 | 0x100, /* GPMC */ | ||
63 | 0x400, /* ISS */ | ||
64 | 0x700, /* IVAHD */ | ||
65 | 0xD00, /* missing in TRM corresponds to AES1*/ | ||
66 | 0x900, /* L4 PER0*/ | ||
67 | 0x200, /* OCMRAM */ | ||
68 | 0x100, /* missing in TRM corresponds to GPMC sERROR*/ | ||
69 | 0x600, /* SGX */ | ||
70 | 0x800, /* SL2 */ | ||
71 | 0x1600, /* C2C */ | ||
72 | 0x1100, /* missing in TRM corresponds PWR DISC CLK1*/ | ||
73 | 0xF00, /* missing in TRM corrsponds to SHA1*/ | ||
74 | 0xE00, /* missing in TRM corresponds to AES2*/ | ||
75 | 0xC00, /* L4 PER3 */ | ||
76 | 0xA00, /* L4 PER1*/ | ||
77 | 0xB00, /* L4 PER2*/ | ||
78 | 0x0, /* HOST CLK2 */ | ||
79 | 0x1800, /* CAL */ | ||
80 | 0x1700 /* LLI */ | ||
81 | }; | ||
82 | |||
83 | static u32 l3_targ_inst_clk3[] = { | ||
84 | 0x0100 /* EMUSS */, | ||
85 | 0x0300, /* DEBUGSS_CT_TBR */ | ||
86 | 0x0 /* HOST CLK3 */ | ||
87 | }; | ||
88 | |||
89 | static struct l3_masters_data { | ||
90 | u32 id; | ||
91 | char name[10]; | ||
92 | } l3_masters[] = { | ||
93 | { 0x0 , "MPU"}, | ||
94 | { 0x10, "CS_ADP"}, | ||
95 | { 0x14, "xxx"}, | ||
96 | { 0x20, "DSP"}, | ||
97 | { 0x30, "IVAHD"}, | ||
98 | { 0x40, "ISS"}, | ||
99 | { 0x44, "DucatiM3"}, | ||
100 | { 0x48, "FaceDetect"}, | ||
101 | { 0x50, "SDMA_Rd"}, | ||
102 | { 0x54, "SDMA_Wr"}, | ||
103 | { 0x58, "xxx"}, | ||
104 | { 0x5C, "xxx"}, | ||
105 | { 0x60, "SGX"}, | ||
106 | { 0x70, "DSS"}, | ||
107 | { 0x80, "C2C"}, | ||
108 | { 0x88, "xxx"}, | ||
109 | { 0x8C, "xxx"}, | ||
110 | { 0x90, "HSI"}, | ||
111 | { 0xA0, "MMC1"}, | ||
112 | { 0xA4, "MMC2"}, | ||
113 | { 0xA8, "MMC6"}, | ||
114 | { 0xB0, "UNIPRO1"}, | ||
115 | { 0xC0, "USBHOSTHS"}, | ||
116 | { 0xC4, "USBOTGHS"}, | ||
117 | { 0xC8, "USBHOSTFS"} | ||
118 | }; | ||
119 | |||
120 | static char *l3_targ_inst_name[L3_MODULES][21] = { | ||
121 | { | ||
122 | "DMM1", | ||
123 | "DMM2", | ||
124 | "ABE", | ||
125 | "L4CFG", | ||
126 | "CLK2 PWR DISC", | ||
127 | "HOST CLK1", | ||
128 | "L4 WAKEUP" | ||
129 | }, | ||
130 | { | ||
131 | "CORTEX M3" , | ||
132 | "DSS ", | ||
133 | "GPMC ", | ||
134 | "ISS ", | ||
135 | "IVAHD ", | ||
136 | "AES1", | ||
137 | "L4 PER0", | ||
138 | "OCMRAM ", | ||
139 | "GPMC sERROR", | ||
140 | "SGX ", | ||
141 | "SL2 ", | ||
142 | "C2C ", | ||
143 | "PWR DISC CLK1", | ||
144 | "SHA1", | ||
145 | "AES2", | ||
146 | "L4 PER3", | ||
147 | "L4 PER1", | ||
148 | "L4 PER2", | ||
149 | "HOST CLK2", | ||
150 | "CAL", | ||
151 | "LLI" | ||
152 | }, | ||
153 | { | ||
154 | "EMUSS", | ||
155 | "DEBUG SOURCE", | ||
156 | "HOST CLK3" | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static u32 *l3_targ[L3_MODULES] = { | ||
161 | l3_targ_inst_clk1, | ||
162 | l3_targ_inst_clk2, | ||
163 | l3_targ_inst_clk3, | ||
164 | }; | ||
165 | |||
166 | struct omap4_l3 { | ||
167 | struct device *dev; | ||
168 | struct clk *ick; | ||
169 | |||
170 | /* memory base */ | ||
171 | void __iomem *l3_base[L3_MODULES]; | ||
172 | |||
173 | int debug_irq; | ||
174 | int app_irq; | ||
175 | }; | ||
176 | #endif | ||
diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c new file mode 100644 index 000000000000..acc216491b8a --- /dev/null +++ b/drivers/bus/omap_l3_smx.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * OMAP3XXX L3 Interconnect Driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Corporation | ||
5 | * Felipe Balbi <balbi@ti.com> | ||
6 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | ||
7 | * Sricharan <r.sricharan@ti.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 as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | * USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/io.h> | ||
30 | #include "omap_l3_smx.h" | ||
31 | |||
32 | static inline u64 omap3_l3_readll(void __iomem *base, u16 reg) | ||
33 | { | ||
34 | return __raw_readll(base + reg); | ||
35 | } | ||
36 | |||
37 | static inline void omap3_l3_writell(void __iomem *base, u16 reg, u64 value) | ||
38 | { | ||
39 | __raw_writell(value, base + reg); | ||
40 | } | ||
41 | |||
42 | static inline enum omap3_l3_code omap3_l3_decode_error_code(u64 error) | ||
43 | { | ||
44 | return (error & 0x0f000000) >> L3_ERROR_LOG_CODE; | ||
45 | } | ||
46 | |||
47 | static inline u32 omap3_l3_decode_addr(u64 error_addr) | ||
48 | { | ||
49 | return error_addr & 0xffffffff; | ||
50 | } | ||
51 | |||
52 | static inline unsigned omap3_l3_decode_cmd(u64 error) | ||
53 | { | ||
54 | return (error & 0x07) >> L3_ERROR_LOG_CMD; | ||
55 | } | ||
56 | |||
57 | static inline enum omap3_l3_initiator_id omap3_l3_decode_initid(u64 error) | ||
58 | { | ||
59 | return (error & 0xff00) >> L3_ERROR_LOG_INITID; | ||
60 | } | ||
61 | |||
62 | static inline unsigned omap3_l3_decode_req_info(u64 error) | ||
63 | { | ||
64 | return (error >> 32) & 0xffff; | ||
65 | } | ||
66 | |||
67 | static char *omap3_l3_code_string(u8 code) | ||
68 | { | ||
69 | switch (code) { | ||
70 | case OMAP_L3_CODE_NOERROR: | ||
71 | return "No Error"; | ||
72 | case OMAP_L3_CODE_UNSUP_CMD: | ||
73 | return "Unsupported Command"; | ||
74 | case OMAP_L3_CODE_ADDR_HOLE: | ||
75 | return "Address Hole"; | ||
76 | case OMAP_L3_CODE_PROTECT_VIOLATION: | ||
77 | return "Protection Violation"; | ||
78 | case OMAP_L3_CODE_IN_BAND_ERR: | ||
79 | return "In-band Error"; | ||
80 | case OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT: | ||
81 | return "Request Timeout Not Accepted"; | ||
82 | case OMAP_L3_CODE_REQ_TOUT_NO_RESP: | ||
83 | return "Request Timeout, no response"; | ||
84 | default: | ||
85 | return "UNKNOWN error"; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static char *omap3_l3_initiator_string(u8 initid) | ||
90 | { | ||
91 | switch (initid) { | ||
92 | case OMAP_L3_LCD: | ||
93 | return "LCD"; | ||
94 | case OMAP_L3_SAD2D: | ||
95 | return "SAD2D"; | ||
96 | case OMAP_L3_IA_MPU_SS_1: | ||
97 | case OMAP_L3_IA_MPU_SS_2: | ||
98 | case OMAP_L3_IA_MPU_SS_3: | ||
99 | case OMAP_L3_IA_MPU_SS_4: | ||
100 | case OMAP_L3_IA_MPU_SS_5: | ||
101 | return "MPU"; | ||
102 | case OMAP_L3_IA_IVA_SS_1: | ||
103 | case OMAP_L3_IA_IVA_SS_2: | ||
104 | case OMAP_L3_IA_IVA_SS_3: | ||
105 | return "IVA_SS"; | ||
106 | case OMAP_L3_IA_IVA_SS_DMA_1: | ||
107 | case OMAP_L3_IA_IVA_SS_DMA_2: | ||
108 | case OMAP_L3_IA_IVA_SS_DMA_3: | ||
109 | case OMAP_L3_IA_IVA_SS_DMA_4: | ||
110 | case OMAP_L3_IA_IVA_SS_DMA_5: | ||
111 | case OMAP_L3_IA_IVA_SS_DMA_6: | ||
112 | return "IVA_SS_DMA"; | ||
113 | case OMAP_L3_IA_SGX: | ||
114 | return "SGX"; | ||
115 | case OMAP_L3_IA_CAM_1: | ||
116 | case OMAP_L3_IA_CAM_2: | ||
117 | case OMAP_L3_IA_CAM_3: | ||
118 | return "CAM"; | ||
119 | case OMAP_L3_IA_DAP: | ||
120 | return "DAP"; | ||
121 | case OMAP_L3_SDMA_WR_1: | ||
122 | case OMAP_L3_SDMA_WR_2: | ||
123 | return "SDMA_WR"; | ||
124 | case OMAP_L3_SDMA_RD_1: | ||
125 | case OMAP_L3_SDMA_RD_2: | ||
126 | case OMAP_L3_SDMA_RD_3: | ||
127 | case OMAP_L3_SDMA_RD_4: | ||
128 | return "SDMA_RD"; | ||
129 | case OMAP_L3_USBOTG: | ||
130 | return "USB_OTG"; | ||
131 | case OMAP_L3_USBHOST: | ||
132 | return "USB_HOST"; | ||
133 | default: | ||
134 | return "UNKNOWN Initiator"; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * omap3_l3_block_irq - handles a register block's irq | ||
140 | * @l3: struct omap3_l3 * | ||
141 | * @base: register block base address | ||
142 | * @error: L3_ERROR_LOG register of our block | ||
143 | * | ||
144 | * Called in hard-irq context. Caller should take care of locking | ||
145 | * | ||
146 | * OMAP36xx TRM gives, on page 2001, Figure 9-10, the Typical Error | ||
147 | * Analysis Sequence, we are following that sequence here, please | ||
148 | * refer to that Figure for more information on the subject. | ||
149 | */ | ||
150 | static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3, | ||
151 | u64 error, int error_addr) | ||
152 | { | ||
153 | u8 code = omap3_l3_decode_error_code(error); | ||
154 | u8 initid = omap3_l3_decode_initid(error); | ||
155 | u8 multi = error & L3_ERROR_LOG_MULTI; | ||
156 | u32 address = omap3_l3_decode_addr(error_addr); | ||
157 | |||
158 | pr_err("%s seen by %s %s at address %x\n", | ||
159 | omap3_l3_code_string(code), | ||
160 | omap3_l3_initiator_string(initid), | ||
161 | multi ? "Multiple Errors" : "", address); | ||
162 | WARN_ON(1); | ||
163 | |||
164 | return IRQ_HANDLED; | ||
165 | } | ||
166 | |||
167 | static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) | ||
168 | { | ||
169 | struct omap3_l3 *l3 = _l3; | ||
170 | u64 status, clear; | ||
171 | u64 error; | ||
172 | u64 error_addr; | ||
173 | u64 err_source = 0; | ||
174 | void __iomem *base; | ||
175 | int int_type; | ||
176 | irqreturn_t ret = IRQ_NONE; | ||
177 | |||
178 | int_type = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; | ||
179 | if (!int_type) { | ||
180 | status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0); | ||
181 | /* | ||
182 | * if we have a timeout error, there's nothing we can | ||
183 | * do besides rebooting the board. So let's BUG on any | ||
184 | * of such errors and handle the others. timeout error | ||
185 | * is severe and not expected to occur. | ||
186 | */ | ||
187 | BUG_ON(status & L3_STATUS_0_TIMEOUT_MASK); | ||
188 | } else { | ||
189 | status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_1); | ||
190 | /* No timeout error for debug sources */ | ||
191 | } | ||
192 | |||
193 | /* identify the error source */ | ||
194 | err_source = __ffs(status); | ||
195 | |||
196 | base = l3->rt + omap3_l3_bases[int_type][err_source]; | ||
197 | error = omap3_l3_readll(base, L3_ERROR_LOG); | ||
198 | if (error) { | ||
199 | error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR); | ||
200 | ret |= omap3_l3_block_irq(l3, error, error_addr); | ||
201 | } | ||
202 | |||
203 | /* Clear the status register */ | ||
204 | clear = (L3_AGENT_STATUS_CLEAR_IA << int_type) | | ||
205 | L3_AGENT_STATUS_CLEAR_TA; | ||
206 | omap3_l3_writell(base, L3_AGENT_STATUS, clear); | ||
207 | |||
208 | /* clear the error log register */ | ||
209 | omap3_l3_writell(base, L3_ERROR_LOG, error); | ||
210 | |||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | static int __init omap3_l3_probe(struct platform_device *pdev) | ||
215 | { | ||
216 | struct omap3_l3 *l3; | ||
217 | struct resource *res; | ||
218 | int ret; | ||
219 | |||
220 | l3 = kzalloc(sizeof(*l3), GFP_KERNEL); | ||
221 | if (!l3) | ||
222 | return -ENOMEM; | ||
223 | |||
224 | platform_set_drvdata(pdev, l3); | ||
225 | |||
226 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
227 | if (!res) { | ||
228 | dev_err(&pdev->dev, "couldn't find resource\n"); | ||
229 | ret = -ENODEV; | ||
230 | goto err0; | ||
231 | } | ||
232 | l3->rt = ioremap(res->start, resource_size(res)); | ||
233 | if (!l3->rt) { | ||
234 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
235 | ret = -ENOMEM; | ||
236 | goto err0; | ||
237 | } | ||
238 | |||
239 | l3->debug_irq = platform_get_irq(pdev, 0); | ||
240 | ret = request_irq(l3->debug_irq, omap3_l3_app_irq, | ||
241 | IRQF_DISABLED | IRQF_TRIGGER_RISING, | ||
242 | "l3-debug-irq", l3); | ||
243 | if (ret) { | ||
244 | dev_err(&pdev->dev, "couldn't request debug irq\n"); | ||
245 | goto err1; | ||
246 | } | ||
247 | |||
248 | l3->app_irq = platform_get_irq(pdev, 1); | ||
249 | ret = request_irq(l3->app_irq, omap3_l3_app_irq, | ||
250 | IRQF_DISABLED | IRQF_TRIGGER_RISING, | ||
251 | "l3-app-irq", l3); | ||
252 | if (ret) { | ||
253 | dev_err(&pdev->dev, "couldn't request app irq\n"); | ||
254 | goto err2; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | |||
259 | err2: | ||
260 | free_irq(l3->debug_irq, l3); | ||
261 | err1: | ||
262 | iounmap(l3->rt); | ||
263 | err0: | ||
264 | kfree(l3); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | static int __exit omap3_l3_remove(struct platform_device *pdev) | ||
269 | { | ||
270 | struct omap3_l3 *l3 = platform_get_drvdata(pdev); | ||
271 | |||
272 | free_irq(l3->app_irq, l3); | ||
273 | free_irq(l3->debug_irq, l3); | ||
274 | iounmap(l3->rt); | ||
275 | kfree(l3); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static struct platform_driver omap3_l3_driver = { | ||
281 | .remove = __exit_p(omap3_l3_remove), | ||
282 | .driver = { | ||
283 | .name = "omap_l3_smx", | ||
284 | }, | ||
285 | }; | ||
286 | |||
287 | static int __init omap3_l3_init(void) | ||
288 | { | ||
289 | return platform_driver_probe(&omap3_l3_driver, omap3_l3_probe); | ||
290 | } | ||
291 | postcore_initcall_sync(omap3_l3_init); | ||
292 | |||
293 | static void __exit omap3_l3_exit(void) | ||
294 | { | ||
295 | platform_driver_unregister(&omap3_l3_driver); | ||
296 | } | ||
297 | module_exit(omap3_l3_exit); | ||
diff --git a/drivers/bus/omap_l3_smx.h b/drivers/bus/omap_l3_smx.h new file mode 100644 index 000000000000..4f3cebca4179 --- /dev/null +++ b/drivers/bus/omap_l3_smx.h | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * OMAP3XXX L3 Interconnect Driver header | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Corporation | ||
5 | * Felipe Balbi <balbi@ti.com> | ||
6 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | ||
7 | * sricharan <r.sricharan@ti.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 as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | * USA | ||
23 | */ | ||
24 | #ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H | ||
25 | #define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H | ||
26 | |||
27 | /* Register definitions. All 64-bit wide */ | ||
28 | #define L3_COMPONENT 0x000 | ||
29 | #define L3_CORE 0x018 | ||
30 | #define L3_AGENT_CONTROL 0x020 | ||
31 | #define L3_AGENT_STATUS 0x028 | ||
32 | #define L3_ERROR_LOG 0x058 | ||
33 | |||
34 | #define L3_ERROR_LOG_MULTI (1 << 31) | ||
35 | #define L3_ERROR_LOG_SECONDARY (1 << 30) | ||
36 | |||
37 | #define L3_ERROR_LOG_ADDR 0x060 | ||
38 | |||
39 | /* Register definitions for Sideband Interconnect */ | ||
40 | #define L3_SI_CONTROL 0x020 | ||
41 | #define L3_SI_FLAG_STATUS_0 0x510 | ||
42 | |||
43 | static const u64 shift = 1; | ||
44 | |||
45 | #define L3_STATUS_0_MPUIA_BRST (shift << 0) | ||
46 | #define L3_STATUS_0_MPUIA_RSP (shift << 1) | ||
47 | #define L3_STATUS_0_MPUIA_INBAND (shift << 2) | ||
48 | #define L3_STATUS_0_IVAIA_BRST (shift << 6) | ||
49 | #define L3_STATUS_0_IVAIA_RSP (shift << 7) | ||
50 | #define L3_STATUS_0_IVAIA_INBAND (shift << 8) | ||
51 | #define L3_STATUS_0_SGXIA_BRST (shift << 9) | ||
52 | #define L3_STATUS_0_SGXIA_RSP (shift << 10) | ||
53 | #define L3_STATUS_0_SGXIA_MERROR (shift << 11) | ||
54 | #define L3_STATUS_0_CAMIA_BRST (shift << 12) | ||
55 | #define L3_STATUS_0_CAMIA_RSP (shift << 13) | ||
56 | #define L3_STATUS_0_CAMIA_INBAND (shift << 14) | ||
57 | #define L3_STATUS_0_DISPIA_BRST (shift << 15) | ||
58 | #define L3_STATUS_0_DISPIA_RSP (shift << 16) | ||
59 | #define L3_STATUS_0_DMARDIA_BRST (shift << 18) | ||
60 | #define L3_STATUS_0_DMARDIA_RSP (shift << 19) | ||
61 | #define L3_STATUS_0_DMAWRIA_BRST (shift << 21) | ||
62 | #define L3_STATUS_0_DMAWRIA_RSP (shift << 22) | ||
63 | #define L3_STATUS_0_USBOTGIA_BRST (shift << 24) | ||
64 | #define L3_STATUS_0_USBOTGIA_RSP (shift << 25) | ||
65 | #define L3_STATUS_0_USBOTGIA_INBAND (shift << 26) | ||
66 | #define L3_STATUS_0_USBHOSTIA_BRST (shift << 27) | ||
67 | #define L3_STATUS_0_USBHOSTIA_INBAND (shift << 28) | ||
68 | #define L3_STATUS_0_SMSTA_REQ (shift << 48) | ||
69 | #define L3_STATUS_0_GPMCTA_REQ (shift << 49) | ||
70 | #define L3_STATUS_0_OCMRAMTA_REQ (shift << 50) | ||
71 | #define L3_STATUS_0_OCMROMTA_REQ (shift << 51) | ||
72 | #define L3_STATUS_0_IVATA_REQ (shift << 54) | ||
73 | #define L3_STATUS_0_SGXTA_REQ (shift << 55) | ||
74 | #define L3_STATUS_0_SGXTA_SERROR (shift << 56) | ||
75 | #define L3_STATUS_0_GPMCTA_SERROR (shift << 57) | ||
76 | #define L3_STATUS_0_L4CORETA_REQ (shift << 58) | ||
77 | #define L3_STATUS_0_L4PERTA_REQ (shift << 59) | ||
78 | #define L3_STATUS_0_L4EMUTA_REQ (shift << 60) | ||
79 | #define L3_STATUS_0_MAD2DTA_REQ (shift << 61) | ||
80 | |||
81 | #define L3_STATUS_0_TIMEOUT_MASK (L3_STATUS_0_MPUIA_BRST \ | ||
82 | | L3_STATUS_0_MPUIA_RSP \ | ||
83 | | L3_STATUS_0_IVAIA_BRST \ | ||
84 | | L3_STATUS_0_IVAIA_RSP \ | ||
85 | | L3_STATUS_0_SGXIA_BRST \ | ||
86 | | L3_STATUS_0_SGXIA_RSP \ | ||
87 | | L3_STATUS_0_CAMIA_BRST \ | ||
88 | | L3_STATUS_0_CAMIA_RSP \ | ||
89 | | L3_STATUS_0_DISPIA_BRST \ | ||
90 | | L3_STATUS_0_DISPIA_RSP \ | ||
91 | | L3_STATUS_0_DMARDIA_BRST \ | ||
92 | | L3_STATUS_0_DMARDIA_RSP \ | ||
93 | | L3_STATUS_0_DMAWRIA_BRST \ | ||
94 | | L3_STATUS_0_DMAWRIA_RSP \ | ||
95 | | L3_STATUS_0_USBOTGIA_BRST \ | ||
96 | | L3_STATUS_0_USBOTGIA_RSP \ | ||
97 | | L3_STATUS_0_USBHOSTIA_BRST \ | ||
98 | | L3_STATUS_0_SMSTA_REQ \ | ||
99 | | L3_STATUS_0_GPMCTA_REQ \ | ||
100 | | L3_STATUS_0_OCMRAMTA_REQ \ | ||
101 | | L3_STATUS_0_OCMROMTA_REQ \ | ||
102 | | L3_STATUS_0_IVATA_REQ \ | ||
103 | | L3_STATUS_0_SGXTA_REQ \ | ||
104 | | L3_STATUS_0_L4CORETA_REQ \ | ||
105 | | L3_STATUS_0_L4PERTA_REQ \ | ||
106 | | L3_STATUS_0_L4EMUTA_REQ \ | ||
107 | | L3_STATUS_0_MAD2DTA_REQ) | ||
108 | |||
109 | #define L3_SI_FLAG_STATUS_1 0x530 | ||
110 | |||
111 | #define L3_STATUS_1_MPU_DATAIA (1 << 0) | ||
112 | #define L3_STATUS_1_DAPIA0 (1 << 3) | ||
113 | #define L3_STATUS_1_DAPIA1 (1 << 4) | ||
114 | #define L3_STATUS_1_IVAIA (1 << 6) | ||
115 | |||
116 | #define L3_PM_ERROR_LOG 0x020 | ||
117 | #define L3_PM_CONTROL 0x028 | ||
118 | #define L3_PM_ERROR_CLEAR_SINGLE 0x030 | ||
119 | #define L3_PM_ERROR_CLEAR_MULTI 0x038 | ||
120 | #define L3_PM_REQ_INFO_PERMISSION(n) (0x048 + (0x020 * n)) | ||
121 | #define L3_PM_READ_PERMISSION(n) (0x050 + (0x020 * n)) | ||
122 | #define L3_PM_WRITE_PERMISSION(n) (0x058 + (0x020 * n)) | ||
123 | #define L3_PM_ADDR_MATCH(n) (0x060 + (0x020 * n)) | ||
124 | |||
125 | /* L3 error log bit fields. Common for IA and TA */ | ||
126 | #define L3_ERROR_LOG_CODE 24 | ||
127 | #define L3_ERROR_LOG_INITID 8 | ||
128 | #define L3_ERROR_LOG_CMD 0 | ||
129 | |||
130 | /* L3 agent status bit fields. */ | ||
131 | #define L3_AGENT_STATUS_CLEAR_IA 0x10000000 | ||
132 | #define L3_AGENT_STATUS_CLEAR_TA 0x01000000 | ||
133 | |||
134 | #define OMAP34xx_IRQ_L3_APP 10 | ||
135 | #define L3_APPLICATION_ERROR 0x0 | ||
136 | #define L3_DEBUG_ERROR 0x1 | ||
137 | |||
138 | enum omap3_l3_initiator_id { | ||
139 | /* LCD has 1 ID */ | ||
140 | OMAP_L3_LCD = 29, | ||
141 | /* SAD2D has 1 ID */ | ||
142 | OMAP_L3_SAD2D = 28, | ||
143 | /* MPU has 5 IDs */ | ||
144 | OMAP_L3_IA_MPU_SS_1 = 27, | ||
145 | OMAP_L3_IA_MPU_SS_2 = 26, | ||
146 | OMAP_L3_IA_MPU_SS_3 = 25, | ||
147 | OMAP_L3_IA_MPU_SS_4 = 24, | ||
148 | OMAP_L3_IA_MPU_SS_5 = 23, | ||
149 | /* IVA2.2 SS has 3 IDs*/ | ||
150 | OMAP_L3_IA_IVA_SS_1 = 22, | ||
151 | OMAP_L3_IA_IVA_SS_2 = 21, | ||
152 | OMAP_L3_IA_IVA_SS_3 = 20, | ||
153 | /* IVA 2.2 SS DMA has 6 IDS */ | ||
154 | OMAP_L3_IA_IVA_SS_DMA_1 = 19, | ||
155 | OMAP_L3_IA_IVA_SS_DMA_2 = 18, | ||
156 | OMAP_L3_IA_IVA_SS_DMA_3 = 17, | ||
157 | OMAP_L3_IA_IVA_SS_DMA_4 = 16, | ||
158 | OMAP_L3_IA_IVA_SS_DMA_5 = 15, | ||
159 | OMAP_L3_IA_IVA_SS_DMA_6 = 14, | ||
160 | /* SGX has 1 ID */ | ||
161 | OMAP_L3_IA_SGX = 13, | ||
162 | /* CAM has 3 ID */ | ||
163 | OMAP_L3_IA_CAM_1 = 12, | ||
164 | OMAP_L3_IA_CAM_2 = 11, | ||
165 | OMAP_L3_IA_CAM_3 = 10, | ||
166 | /* DAP has 1 ID */ | ||
167 | OMAP_L3_IA_DAP = 9, | ||
168 | /* SDMA WR has 2 IDs */ | ||
169 | OMAP_L3_SDMA_WR_1 = 8, | ||
170 | OMAP_L3_SDMA_WR_2 = 7, | ||
171 | /* SDMA RD has 4 IDs */ | ||
172 | OMAP_L3_SDMA_RD_1 = 6, | ||
173 | OMAP_L3_SDMA_RD_2 = 5, | ||
174 | OMAP_L3_SDMA_RD_3 = 4, | ||
175 | OMAP_L3_SDMA_RD_4 = 3, | ||
176 | /* HSUSB OTG has 1 ID */ | ||
177 | OMAP_L3_USBOTG = 2, | ||
178 | /* HSUSB HOST has 1 ID */ | ||
179 | OMAP_L3_USBHOST = 1, | ||
180 | }; | ||
181 | |||
182 | enum omap3_l3_code { | ||
183 | OMAP_L3_CODE_NOERROR = 0, | ||
184 | OMAP_L3_CODE_UNSUP_CMD = 1, | ||
185 | OMAP_L3_CODE_ADDR_HOLE = 2, | ||
186 | OMAP_L3_CODE_PROTECT_VIOLATION = 3, | ||
187 | OMAP_L3_CODE_IN_BAND_ERR = 4, | ||
188 | /* codes 5 and 6 are reserved */ | ||
189 | OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT = 7, | ||
190 | OMAP_L3_CODE_REQ_TOUT_NO_RESP = 8, | ||
191 | /* codes 9 - 15 are also reserved */ | ||
192 | }; | ||
193 | |||
194 | struct omap3_l3 { | ||
195 | struct device *dev; | ||
196 | struct clk *ick; | ||
197 | |||
198 | /* memory base*/ | ||
199 | void __iomem *rt; | ||
200 | |||
201 | int debug_irq; | ||
202 | int app_irq; | ||
203 | |||
204 | /* true when and inband functional error occurs */ | ||
205 | unsigned inband:1; | ||
206 | }; | ||
207 | |||
208 | /* offsets for l3 agents in order with the Flag status register */ | ||
209 | static unsigned int omap3_l3_app_bases[] = { | ||
210 | /* MPU IA */ | ||
211 | 0x1400, | ||
212 | 0x1400, | ||
213 | 0x1400, | ||
214 | /* RESERVED */ | ||
215 | 0, | ||
216 | 0, | ||
217 | 0, | ||
218 | /* IVA 2.2 IA */ | ||
219 | 0x1800, | ||
220 | 0x1800, | ||
221 | 0x1800, | ||
222 | /* SGX IA */ | ||
223 | 0x1c00, | ||
224 | 0x1c00, | ||
225 | /* RESERVED */ | ||
226 | 0, | ||
227 | /* CAMERA IA */ | ||
228 | 0x5800, | ||
229 | 0x5800, | ||
230 | 0x5800, | ||
231 | /* DISPLAY IA */ | ||
232 | 0x5400, | ||
233 | 0x5400, | ||
234 | /* RESERVED */ | ||
235 | 0, | ||
236 | /*SDMA RD IA */ | ||
237 | 0x4c00, | ||
238 | 0x4c00, | ||
239 | /* RESERVED */ | ||
240 | 0, | ||
241 | /* SDMA WR IA */ | ||
242 | 0x5000, | ||
243 | 0x5000, | ||
244 | /* RESERVED */ | ||
245 | 0, | ||
246 | /* USB OTG IA */ | ||
247 | 0x4400, | ||
248 | 0x4400, | ||
249 | 0x4400, | ||
250 | /* USB HOST IA */ | ||
251 | 0x4000, | ||
252 | 0x4000, | ||
253 | /* RESERVED */ | ||
254 | 0, | ||
255 | 0, | ||
256 | 0, | ||
257 | 0, | ||
258 | /* SAD2D IA */ | ||
259 | 0x3000, | ||
260 | 0x3000, | ||
261 | 0x3000, | ||
262 | /* RESERVED */ | ||
263 | 0, | ||
264 | 0, | ||
265 | 0, | ||
266 | 0, | ||
267 | 0, | ||
268 | 0, | ||
269 | 0, | ||
270 | 0, | ||
271 | 0, | ||
272 | 0, | ||
273 | 0, | ||
274 | 0, | ||
275 | /* SMA TA */ | ||
276 | 0x2000, | ||
277 | /* GPMC TA */ | ||
278 | 0x2400, | ||
279 | /* OCM RAM TA */ | ||
280 | 0x2800, | ||
281 | /* OCM ROM TA */ | ||
282 | 0x2C00, | ||
283 | /* L4 CORE TA */ | ||
284 | 0x6800, | ||
285 | /* L4 PER TA */ | ||
286 | 0x6c00, | ||
287 | /* IVA 2.2 TA */ | ||
288 | 0x6000, | ||
289 | /* SGX TA */ | ||
290 | 0x6400, | ||
291 | /* L4 EMU TA */ | ||
292 | 0x7000, | ||
293 | /* GPMC TA */ | ||
294 | 0x2400, | ||
295 | /* L4 CORE TA */ | ||
296 | 0x6800, | ||
297 | /* L4 PER TA */ | ||
298 | 0x6c00, | ||
299 | /* L4 EMU TA */ | ||
300 | 0x7000, | ||
301 | /* MAD2D TA */ | ||
302 | 0x3400, | ||
303 | /* RESERVED */ | ||
304 | 0, | ||
305 | 0, | ||
306 | }; | ||
307 | |||
308 | static unsigned int omap3_l3_debug_bases[] = { | ||
309 | /* MPU DATA IA */ | ||
310 | 0x1400, | ||
311 | /* RESERVED */ | ||
312 | 0, | ||
313 | 0, | ||
314 | /* DAP IA */ | ||
315 | 0x5c00, | ||
316 | 0x5c00, | ||
317 | /* RESERVED */ | ||
318 | 0, | ||
319 | /* IVA 2.2 IA */ | ||
320 | 0x1800, | ||
321 | /* REST RESERVED */ | ||
322 | }; | ||
323 | |||
324 | static u32 *omap3_l3_bases[] = { | ||
325 | omap3_l3_app_bases, | ||
326 | omap3_l3_debug_bases, | ||
327 | }; | ||
328 | |||
329 | /* | ||
330 | * REVISIT define __raw_readll/__raw_writell here, but move them to | ||
331 | * <asm/io.h> at some point | ||
332 | */ | ||
333 | #define __raw_writell(v, a) (__chk_io_ptr(a), \ | ||
334 | *(volatile u64 __force *)(a) = (v)) | ||
335 | #define __raw_readll(a) (__chk_io_ptr(a), \ | ||
336 | *(volatile u64 __force *)(a)) | ||
337 | |||
338 | #endif | ||
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index d45c3345b4af..a0e2f7d70355 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c | |||
@@ -30,7 +30,6 @@ | |||
30 | 30 | ||
31 | #include <asm/hardware/dec21285.h> | 31 | #include <asm/hardware/dec21285.h> |
32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
33 | #include <asm/leds.h> | ||
34 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
35 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
36 | 35 | ||
@@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, | |||
179 | 178 | ||
180 | written = 0; | 179 | written = 0; |
181 | 180 | ||
182 | leds_event(led_claim); | ||
183 | leds_event(led_green_on); | ||
184 | |||
185 | nBlock = (int) p >> 16; //block # of 64K bytes | 181 | nBlock = (int) p >> 16; //block # of 64K bytes |
186 | 182 | ||
187 | /* | 183 | /* |
@@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, | |||
258 | printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); | 254 | printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); |
259 | } | 255 | } |
260 | 256 | ||
261 | /* | ||
262 | * restore reg on exit | ||
263 | */ | ||
264 | leds_event(led_release); | ||
265 | |||
266 | mutex_unlock(&nwflash_mutex); | 257 | mutex_unlock(&nwflash_mutex); |
267 | 258 | ||
268 | return written; | 259 | return written; |
@@ -334,11 +325,6 @@ static int erase_block(int nBlock) | |||
334 | int temp, temp1; | 325 | int temp, temp1; |
335 | 326 | ||
336 | /* | 327 | /* |
337 | * orange LED == erase | ||
338 | */ | ||
339 | leds_event(led_amber_on); | ||
340 | |||
341 | /* | ||
342 | * reset footbridge to the correct offset 0 (...0..3) | 328 | * reset footbridge to the correct offset 0 (...0..3) |
343 | */ | 329 | */ |
344 | *CSR_ROMWRITEREG = 0; | 330 | *CSR_ROMWRITEREG = 0; |
@@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
446 | unsigned long timeout; | 432 | unsigned long timeout; |
447 | unsigned long timeout1; | 433 | unsigned long timeout1; |
448 | 434 | ||
449 | /* | ||
450 | * red LED == write | ||
451 | */ | ||
452 | leds_event(led_amber_off); | ||
453 | leds_event(led_red_on); | ||
454 | |||
455 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); | 435 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); |
456 | 436 | ||
457 | /* | 437 | /* |
@@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
558 | pWritePtr - FLASH_BASE); | 538 | pWritePtr - FLASH_BASE); |
559 | 539 | ||
560 | /* | 540 | /* |
561 | * no LED == waiting | ||
562 | */ | ||
563 | leds_event(led_amber_off); | ||
564 | /* | ||
565 | * wait couple ms | 541 | * wait couple ms |
566 | */ | 542 | */ |
567 | msleep(10); | 543 | msleep(10); |
568 | /* | ||
569 | * red LED == write | ||
570 | */ | ||
571 | leds_event(led_red_on); | ||
572 | 544 | ||
573 | goto WriteRetry; | 545 | goto WriteRetry; |
574 | } else { | 546 | } else { |
@@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) | |||
583 | } | 555 | } |
584 | } | 556 | } |
585 | 557 | ||
586 | /* | ||
587 | * green LED == read/verify | ||
588 | */ | ||
589 | leds_event(led_amber_off); | ||
590 | leds_event(led_green_on); | ||
591 | |||
592 | msleep(10); | 558 | msleep(10); |
593 | 559 | ||
594 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); | 560 | pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); |
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 8af4b06e80f7..a006f0db15af 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -2797,6 +2797,27 @@ static __init void exynos4_gpiolib_init(void) | |||
2797 | int group = 0; | 2797 | int group = 0; |
2798 | void __iomem *gpx_base; | 2798 | void __iomem *gpx_base; |
2799 | 2799 | ||
2800 | #ifdef CONFIG_PINCTRL_SAMSUNG | ||
2801 | /* | ||
2802 | * This gpio driver includes support for device tree support and | ||
2803 | * there are platforms using it. In order to maintain | ||
2804 | * compatibility with those platforms, and to allow non-dt | ||
2805 | * Exynos4210 platforms to use this gpiolib support, a check | ||
2806 | * is added to find out if there is a active pin-controller | ||
2807 | * driver support available. If it is available, this gpiolib | ||
2808 | * support is ignored and the gpiolib support available in | ||
2809 | * pin-controller driver is used. This is a temporary check and | ||
2810 | * will go away when all of the Exynos4210 platforms have | ||
2811 | * switched to using device tree and the pin-ctrl driver. | ||
2812 | */ | ||
2813 | struct device_node *pctrl_np; | ||
2814 | const char *pctrl_compat = "samsung,pinctrl-exynos4210"; | ||
2815 | pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat); | ||
2816 | if (pctrl_np) | ||
2817 | if (of_device_is_available(pctrl_np)) | ||
2818 | return; | ||
2819 | #endif | ||
2820 | |||
2800 | /* gpio part1 */ | 2821 | /* gpio part1 */ |
2801 | gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); | 2822 | gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); |
2802 | if (gpio_base1 == NULL) { | 2823 | if (gpio_base1 == NULL) { |
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 9a08c57bc936..f981ac4e6783 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/i2c-tegra.h> | 28 | #include <linux/i2c-tegra.h> |
29 | #include <linux/of_i2c.h> | 29 | #include <linux/of_i2c.h> |
30 | #include <linux/of_device.h> | ||
30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
31 | 32 | ||
32 | #include <asm/unaligned.h> | 33 | #include <asm/unaligned.h> |
@@ -114,11 +115,21 @@ enum msg_end_type { | |||
114 | }; | 115 | }; |
115 | 116 | ||
116 | /** | 117 | /** |
118 | * struct tegra_i2c_hw_feature : Different HW support on Tegra | ||
119 | * @has_continue_xfer_support: Continue transfer supports. | ||
120 | */ | ||
121 | |||
122 | struct tegra_i2c_hw_feature { | ||
123 | bool has_continue_xfer_support; | ||
124 | }; | ||
125 | |||
126 | /** | ||
117 | * struct tegra_i2c_dev - per device i2c context | 127 | * struct tegra_i2c_dev - per device i2c context |
118 | * @dev: device reference for power management | 128 | * @dev: device reference for power management |
129 | * @hw: Tegra i2c hw feature. | ||
119 | * @adapter: core i2c layer adapter information | 130 | * @adapter: core i2c layer adapter information |
120 | * @clk: clock reference for i2c controller | 131 | * @div_clk: clock reference for div clock of i2c controller. |
121 | * @i2c_clk: clock reference for i2c bus | 132 | * @fast_clk: clock reference for fast clock of i2c controller. |
122 | * @base: ioremapped registers cookie | 133 | * @base: ioremapped registers cookie |
123 | * @cont_id: i2c controller id, used for for packet header | 134 | * @cont_id: i2c controller id, used for for packet header |
124 | * @irq: irq number of transfer complete interrupt | 135 | * @irq: irq number of transfer complete interrupt |
@@ -133,9 +144,10 @@ enum msg_end_type { | |||
133 | */ | 144 | */ |
134 | struct tegra_i2c_dev { | 145 | struct tegra_i2c_dev { |
135 | struct device *dev; | 146 | struct device *dev; |
147 | const struct tegra_i2c_hw_feature *hw; | ||
136 | struct i2c_adapter adapter; | 148 | struct i2c_adapter adapter; |
137 | struct clk *clk; | 149 | struct clk *div_clk; |
138 | struct clk *i2c_clk; | 150 | struct clk *fast_clk; |
139 | void __iomem *base; | 151 | void __iomem *base; |
140 | int cont_id; | 152 | int cont_id; |
141 | int irq; | 153 | int irq; |
@@ -351,16 +363,40 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) | |||
351 | dvc_writel(i2c_dev, val, DVC_CTRL_REG1); | 363 | dvc_writel(i2c_dev, val, DVC_CTRL_REG1); |
352 | } | 364 | } |
353 | 365 | ||
366 | static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) | ||
367 | { | ||
368 | int ret; | ||
369 | ret = clk_prepare_enable(i2c_dev->fast_clk); | ||
370 | if (ret < 0) { | ||
371 | dev_err(i2c_dev->dev, | ||
372 | "Enabling fast clk failed, err %d\n", ret); | ||
373 | return ret; | ||
374 | } | ||
375 | ret = clk_prepare_enable(i2c_dev->div_clk); | ||
376 | if (ret < 0) { | ||
377 | dev_err(i2c_dev->dev, | ||
378 | "Enabling div clk failed, err %d\n", ret); | ||
379 | clk_disable_unprepare(i2c_dev->fast_clk); | ||
380 | } | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) | ||
385 | { | ||
386 | clk_disable_unprepare(i2c_dev->div_clk); | ||
387 | clk_disable_unprepare(i2c_dev->fast_clk); | ||
388 | } | ||
389 | |||
354 | static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | 390 | static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) |
355 | { | 391 | { |
356 | u32 val; | 392 | u32 val; |
357 | int err = 0; | 393 | int err = 0; |
358 | 394 | ||
359 | clk_prepare_enable(i2c_dev->clk); | 395 | tegra_i2c_clock_enable(i2c_dev); |
360 | 396 | ||
361 | tegra_periph_reset_assert(i2c_dev->clk); | 397 | tegra_periph_reset_assert(i2c_dev->div_clk); |
362 | udelay(2); | 398 | udelay(2); |
363 | tegra_periph_reset_deassert(i2c_dev->clk); | 399 | tegra_periph_reset_deassert(i2c_dev->div_clk); |
364 | 400 | ||
365 | if (i2c_dev->is_dvc) | 401 | if (i2c_dev->is_dvc) |
366 | tegra_dvc_init(i2c_dev); | 402 | tegra_dvc_init(i2c_dev); |
@@ -369,7 +405,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | |||
369 | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); | 405 | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); |
370 | i2c_writel(i2c_dev, val, I2C_CNFG); | 406 | i2c_writel(i2c_dev, val, I2C_CNFG); |
371 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); | 407 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); |
372 | clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); | 408 | clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); |
373 | 409 | ||
374 | if (!i2c_dev->is_dvc) { | 410 | if (!i2c_dev->is_dvc) { |
375 | u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); | 411 | u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); |
@@ -387,7 +423,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | |||
387 | if (tegra_i2c_flush_fifos(i2c_dev)) | 423 | if (tegra_i2c_flush_fifos(i2c_dev)) |
388 | err = -ETIMEDOUT; | 424 | err = -ETIMEDOUT; |
389 | 425 | ||
390 | clk_disable_unprepare(i2c_dev->clk); | 426 | tegra_i2c_clock_disable(i2c_dev); |
391 | 427 | ||
392 | if (i2c_dev->irq_disabled) { | 428 | if (i2c_dev->irq_disabled) { |
393 | i2c_dev->irq_disabled = 0; | 429 | i2c_dev->irq_disabled = 0; |
@@ -563,7 +599,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
563 | if (i2c_dev->is_suspended) | 599 | if (i2c_dev->is_suspended) |
564 | return -EBUSY; | 600 | return -EBUSY; |
565 | 601 | ||
566 | clk_prepare_enable(i2c_dev->clk); | 602 | tegra_i2c_clock_enable(i2c_dev); |
567 | for (i = 0; i < num; i++) { | 603 | for (i = 0; i < num; i++) { |
568 | enum msg_end_type end_type = MSG_END_STOP; | 604 | enum msg_end_type end_type = MSG_END_STOP; |
569 | if (i < (num - 1)) { | 605 | if (i < (num - 1)) { |
@@ -576,14 +612,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | |||
576 | if (ret) | 612 | if (ret) |
577 | break; | 613 | break; |
578 | } | 614 | } |
579 | clk_disable_unprepare(i2c_dev->clk); | 615 | tegra_i2c_clock_disable(i2c_dev); |
580 | return ret ?: i; | 616 | return ret ?: i; |
581 | } | 617 | } |
582 | 618 | ||
583 | static u32 tegra_i2c_func(struct i2c_adapter *adap) | 619 | static u32 tegra_i2c_func(struct i2c_adapter *adap) |
584 | { | 620 | { |
585 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | | 621 | struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); |
586 | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; | 622 | u32 ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | |
623 | I2C_FUNC_PROTOCOL_MANGLING; | ||
624 | |||
625 | if (i2c_dev->hw->has_continue_xfer_support) | ||
626 | ret |= I2C_FUNC_NOSTART; | ||
627 | return ret; | ||
587 | } | 628 | } |
588 | 629 | ||
589 | static const struct i2c_algorithm tegra_i2c_algo = { | 630 | static const struct i2c_algorithm tegra_i2c_algo = { |
@@ -591,13 +632,32 @@ static const struct i2c_algorithm tegra_i2c_algo = { | |||
591 | .functionality = tegra_i2c_func, | 632 | .functionality = tegra_i2c_func, |
592 | }; | 633 | }; |
593 | 634 | ||
635 | static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { | ||
636 | .has_continue_xfer_support = false, | ||
637 | }; | ||
638 | |||
639 | static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { | ||
640 | .has_continue_xfer_support = true, | ||
641 | }; | ||
642 | |||
643 | #if defined(CONFIG_OF) | ||
644 | /* Match table for of_platform binding */ | ||
645 | static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { | ||
646 | { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, | ||
647 | { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, | ||
648 | { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, | ||
649 | {}, | ||
650 | }; | ||
651 | MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); | ||
652 | #endif | ||
653 | |||
594 | static int __devinit tegra_i2c_probe(struct platform_device *pdev) | 654 | static int __devinit tegra_i2c_probe(struct platform_device *pdev) |
595 | { | 655 | { |
596 | struct tegra_i2c_dev *i2c_dev; | 656 | struct tegra_i2c_dev *i2c_dev; |
597 | struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; | 657 | struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; |
598 | struct resource *res; | 658 | struct resource *res; |
599 | struct clk *clk; | 659 | struct clk *div_clk; |
600 | struct clk *i2c_clk; | 660 | struct clk *fast_clk; |
601 | const unsigned int *prop; | 661 | const unsigned int *prop; |
602 | void __iomem *base; | 662 | void __iomem *base; |
603 | int irq; | 663 | int irq; |
@@ -622,16 +682,16 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
622 | } | 682 | } |
623 | irq = res->start; | 683 | irq = res->start; |
624 | 684 | ||
625 | clk = devm_clk_get(&pdev->dev, NULL); | 685 | div_clk = devm_clk_get(&pdev->dev, "div-clk"); |
626 | if (IS_ERR(clk)) { | 686 | if (IS_ERR(div_clk)) { |
627 | dev_err(&pdev->dev, "missing controller clock"); | 687 | dev_err(&pdev->dev, "missing controller clock"); |
628 | return PTR_ERR(clk); | 688 | return PTR_ERR(div_clk); |
629 | } | 689 | } |
630 | 690 | ||
631 | i2c_clk = devm_clk_get(&pdev->dev, "i2c"); | 691 | fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); |
632 | if (IS_ERR(i2c_clk)) { | 692 | if (IS_ERR(fast_clk)) { |
633 | dev_err(&pdev->dev, "missing bus clock"); | 693 | dev_err(&pdev->dev, "missing bus clock"); |
634 | return PTR_ERR(i2c_clk); | 694 | return PTR_ERR(fast_clk); |
635 | } | 695 | } |
636 | 696 | ||
637 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); | 697 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); |
@@ -641,8 +701,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
641 | } | 701 | } |
642 | 702 | ||
643 | i2c_dev->base = base; | 703 | i2c_dev->base = base; |
644 | i2c_dev->clk = clk; | 704 | i2c_dev->div_clk = div_clk; |
645 | i2c_dev->i2c_clk = i2c_clk; | 705 | i2c_dev->fast_clk = fast_clk; |
646 | i2c_dev->adapter.algo = &tegra_i2c_algo; | 706 | i2c_dev->adapter.algo = &tegra_i2c_algo; |
647 | i2c_dev->irq = irq; | 707 | i2c_dev->irq = irq; |
648 | i2c_dev->cont_id = pdev->id; | 708 | i2c_dev->cont_id = pdev->id; |
@@ -659,11 +719,18 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
659 | i2c_dev->bus_clk_rate = be32_to_cpup(prop); | 719 | i2c_dev->bus_clk_rate = be32_to_cpup(prop); |
660 | } | 720 | } |
661 | 721 | ||
662 | if (pdev->dev.of_node) | 722 | i2c_dev->hw = &tegra20_i2c_hw; |
723 | |||
724 | if (pdev->dev.of_node) { | ||
725 | const struct of_device_id *match; | ||
726 | match = of_match_device(of_match_ptr(tegra_i2c_of_match), | ||
727 | &pdev->dev); | ||
728 | i2c_dev->hw = match->data; | ||
663 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, | 729 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, |
664 | "nvidia,tegra20-i2c-dvc"); | 730 | "nvidia,tegra20-i2c-dvc"); |
665 | else if (pdev->id == 3) | 731 | } else if (pdev->id == 3) { |
666 | i2c_dev->is_dvc = 1; | 732 | i2c_dev->is_dvc = 1; |
733 | } | ||
667 | init_completion(&i2c_dev->msg_complete); | 734 | init_completion(&i2c_dev->msg_complete); |
668 | 735 | ||
669 | platform_set_drvdata(pdev, i2c_dev); | 736 | platform_set_drvdata(pdev, i2c_dev); |
@@ -681,8 +748,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
681 | return ret; | 748 | return ret; |
682 | } | 749 | } |
683 | 750 | ||
684 | clk_prepare_enable(i2c_dev->i2c_clk); | ||
685 | |||
686 | i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); | 751 | i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); |
687 | i2c_dev->adapter.owner = THIS_MODULE; | 752 | i2c_dev->adapter.owner = THIS_MODULE; |
688 | i2c_dev->adapter.class = I2C_CLASS_HWMON; | 753 | i2c_dev->adapter.class = I2C_CLASS_HWMON; |
@@ -696,7 +761,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) | |||
696 | ret = i2c_add_numbered_adapter(&i2c_dev->adapter); | 761 | ret = i2c_add_numbered_adapter(&i2c_dev->adapter); |
697 | if (ret) { | 762 | if (ret) { |
698 | dev_err(&pdev->dev, "Failed to add I2C adapter\n"); | 763 | dev_err(&pdev->dev, "Failed to add I2C adapter\n"); |
699 | clk_disable_unprepare(i2c_dev->i2c_clk); | ||
700 | return ret; | 764 | return ret; |
701 | } | 765 | } |
702 | 766 | ||
@@ -751,16 +815,6 @@ static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); | |||
751 | #define TEGRA_I2C_PM NULL | 815 | #define TEGRA_I2C_PM NULL |
752 | #endif | 816 | #endif |
753 | 817 | ||
754 | #if defined(CONFIG_OF) | ||
755 | /* Match table for of_platform binding */ | ||
756 | static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { | ||
757 | { .compatible = "nvidia,tegra20-i2c", }, | ||
758 | { .compatible = "nvidia,tegra20-i2c-dvc", }, | ||
759 | {}, | ||
760 | }; | ||
761 | MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); | ||
762 | #endif | ||
763 | |||
764 | static struct platform_driver tegra_i2c_driver = { | 818 | static struct platform_driver tegra_i2c_driver = { |
765 | .probe = tegra_i2c_probe, | 819 | .probe = tegra_i2c_probe, |
766 | .remove = __devexit_p(tegra_i2c_remove), | 820 | .remove = __devexit_p(tegra_i2c_remove), |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c96bbaadeebd..16578d3b52bb 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -506,6 +506,16 @@ config LEDS_TRIGGER_BACKLIGHT | |||
506 | 506 | ||
507 | If unsure, say N. | 507 | If unsure, say N. |
508 | 508 | ||
509 | config LEDS_TRIGGER_CPU | ||
510 | bool "LED CPU Trigger" | ||
511 | depends on LEDS_TRIGGERS | ||
512 | help | ||
513 | This allows LEDs to be controlled by active CPUs. This shows | ||
514 | the active CPUs across an array of LEDs so you can see which | ||
515 | CPUs are active on the system at any given moment. | ||
516 | |||
517 | If unsure, say N. | ||
518 | |||
509 | config LEDS_TRIGGER_GPIO | 519 | config LEDS_TRIGGER_GPIO |
510 | tristate "LED GPIO Trigger" | 520 | tristate "LED GPIO Trigger" |
511 | depends on LEDS_TRIGGERS | 521 | depends on LEDS_TRIGGERS |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a4429a9217bc..a9b627c4f8ba 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -61,5 +61,6 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o | |||
61 | obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o | 61 | obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o |
62 | obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o | 62 | obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o |
63 | obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o | 63 | obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o |
64 | obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o | ||
64 | obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o | 65 | obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o |
65 | obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o | 66 | obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o |
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c new file mode 100644 index 000000000000..b312056da14d --- /dev/null +++ b/drivers/leds/ledtrig-cpu.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * ledtrig-cpu.c - LED trigger based on CPU activity | ||
3 | * | ||
4 | * This LED trigger will be registered for each possible CPU and named as | ||
5 | * cpu0, cpu1, cpu2, cpu3, etc. | ||
6 | * | ||
7 | * It can be bound to any LED just like other triggers using either a | ||
8 | * board file or via sysfs interface. | ||
9 | * | ||
10 | * An API named ledtrig_cpu is exported for any user, who want to add CPU | ||
11 | * activity indication in their code | ||
12 | * | ||
13 | * Copyright 2011 Linus Walleij <linus.walleij@linaro.org> | ||
14 | * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License version 2 as | ||
18 | * published by the Free Software Foundation. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/percpu.h> | ||
27 | #include <linux/syscore_ops.h> | ||
28 | #include <linux/rwsem.h> | ||
29 | #include "leds.h" | ||
30 | |||
31 | #define MAX_NAME_LEN 8 | ||
32 | |||
33 | struct led_trigger_cpu { | ||
34 | char name[MAX_NAME_LEN]; | ||
35 | struct led_trigger *_trig; | ||
36 | struct mutex lock; | ||
37 | int lock_is_inited; | ||
38 | }; | ||
39 | |||
40 | static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); | ||
41 | |||
42 | /** | ||
43 | * ledtrig_cpu - emit a CPU event as a trigger | ||
44 | * @evt: CPU event to be emitted | ||
45 | * | ||
46 | * Emit a CPU event on a CPU core, which will trigger a | ||
47 | * binded LED to turn on or turn off. | ||
48 | */ | ||
49 | void ledtrig_cpu(enum cpu_led_event ledevt) | ||
50 | { | ||
51 | struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); | ||
52 | |||
53 | /* mutex lock should be initialized before calling mutex_call() */ | ||
54 | if (!trig->lock_is_inited) | ||
55 | return; | ||
56 | |||
57 | mutex_lock(&trig->lock); | ||
58 | |||
59 | /* Locate the correct CPU LED */ | ||
60 | switch (ledevt) { | ||
61 | case CPU_LED_IDLE_END: | ||
62 | case CPU_LED_START: | ||
63 | /* Will turn the LED on, max brightness */ | ||
64 | led_trigger_event(trig->_trig, LED_FULL); | ||
65 | break; | ||
66 | |||
67 | case CPU_LED_IDLE_START: | ||
68 | case CPU_LED_STOP: | ||
69 | case CPU_LED_HALTED: | ||
70 | /* Will turn the LED off */ | ||
71 | led_trigger_event(trig->_trig, LED_OFF); | ||
72 | break; | ||
73 | |||
74 | default: | ||
75 | /* Will leave the LED as it is */ | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | mutex_unlock(&trig->lock); | ||
80 | } | ||
81 | EXPORT_SYMBOL(ledtrig_cpu); | ||
82 | |||
83 | static int ledtrig_cpu_syscore_suspend(void) | ||
84 | { | ||
85 | ledtrig_cpu(CPU_LED_STOP); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void ledtrig_cpu_syscore_resume(void) | ||
90 | { | ||
91 | ledtrig_cpu(CPU_LED_START); | ||
92 | } | ||
93 | |||
94 | static void ledtrig_cpu_syscore_shutdown(void) | ||
95 | { | ||
96 | ledtrig_cpu(CPU_LED_HALTED); | ||
97 | } | ||
98 | |||
99 | static struct syscore_ops ledtrig_cpu_syscore_ops = { | ||
100 | .shutdown = ledtrig_cpu_syscore_shutdown, | ||
101 | .suspend = ledtrig_cpu_syscore_suspend, | ||
102 | .resume = ledtrig_cpu_syscore_resume, | ||
103 | }; | ||
104 | |||
105 | static int __init ledtrig_cpu_init(void) | ||
106 | { | ||
107 | int cpu; | ||
108 | |||
109 | /* Supports up to 9999 cpu cores */ | ||
110 | BUILD_BUG_ON(CONFIG_NR_CPUS > 9999); | ||
111 | |||
112 | /* | ||
113 | * Registering CPU led trigger for each CPU core here | ||
114 | * ignores CPU hotplug, but after this CPU hotplug works | ||
115 | * fine with this trigger. | ||
116 | */ | ||
117 | for_each_possible_cpu(cpu) { | ||
118 | struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); | ||
119 | |||
120 | mutex_init(&trig->lock); | ||
121 | |||
122 | snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); | ||
123 | |||
124 | mutex_lock(&trig->lock); | ||
125 | led_trigger_register_simple(trig->name, &trig->_trig); | ||
126 | trig->lock_is_inited = 1; | ||
127 | mutex_unlock(&trig->lock); | ||
128 | } | ||
129 | |||
130 | register_syscore_ops(&ledtrig_cpu_syscore_ops); | ||
131 | |||
132 | pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | module_init(ledtrig_cpu_init); | ||
137 | |||
138 | static void __exit ledtrig_cpu_exit(void) | ||
139 | { | ||
140 | int cpu; | ||
141 | |||
142 | for_each_possible_cpu(cpu) { | ||
143 | struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); | ||
144 | |||
145 | mutex_lock(&trig->lock); | ||
146 | |||
147 | led_trigger_unregister_simple(trig->_trig); | ||
148 | trig->_trig = NULL; | ||
149 | memset(trig->name, 0, MAX_NAME_LEN); | ||
150 | trig->lock_is_inited = 0; | ||
151 | |||
152 | mutex_unlock(&trig->lock); | ||
153 | mutex_destroy(&trig->lock); | ||
154 | } | ||
155 | |||
156 | unregister_syscore_ops(&ledtrig_cpu_syscore_ops); | ||
157 | } | ||
158 | module_exit(ledtrig_cpu_exit); | ||
159 | |||
160 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
161 | MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>"); | ||
162 | MODULE_DESCRIPTION("CPU LED trigger"); | ||
163 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8ca417614c57..598cd0a3adee 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -406,46 +406,6 @@ config MTD_NAND_ATMEL | |||
406 | help | 406 | help |
407 | Enables support for NAND Flash / Smart Media Card interface | 407 | Enables support for NAND Flash / Smart Media Card interface |
408 | on Atmel AT91 and AVR32 processors. | 408 | on Atmel AT91 and AVR32 processors. |
409 | choice | ||
410 | prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" | ||
411 | depends on MTD_NAND_ATMEL | ||
412 | |||
413 | config MTD_NAND_ATMEL_ECC_HW | ||
414 | bool "Hardware ECC" | ||
415 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 | ||
416 | help | ||
417 | Use hardware ECC instead of software ECC when the chip | ||
418 | supports it. | ||
419 | |||
420 | The hardware ECC controller is capable of single bit error | ||
421 | correction and 2-bit random detection per page. | ||
422 | |||
423 | NB : hardware and software ECC schemes are incompatible. | ||
424 | If you switch from one to another, you'll have to erase your | ||
425 | mtd partition. | ||
426 | |||
427 | If unsure, say Y | ||
428 | |||
429 | config MTD_NAND_ATMEL_ECC_SOFT | ||
430 | bool "Software ECC" | ||
431 | help | ||
432 | Use software ECC. | ||
433 | |||
434 | NB : hardware and software ECC schemes are incompatible. | ||
435 | If you switch from one to another, you'll have to erase your | ||
436 | mtd partition. | ||
437 | |||
438 | config MTD_NAND_ATMEL_ECC_NONE | ||
439 | bool "No ECC (testing only, DANGEROUS)" | ||
440 | depends on DEBUG_KERNEL | ||
441 | help | ||
442 | No ECC will be used. | ||
443 | It's not a good idea and it should be reserved for testing | ||
444 | purpose only. | ||
445 | |||
446 | If unsure, say N | ||
447 | |||
448 | endchoice | ||
449 | 409 | ||
450 | config MTD_NAND_PXA3xx | 410 | config MTD_NAND_PXA3xx |
451 | tristate "Support for NAND flash devices on PXA3xx" | 411 | tristate "Support for NAND flash devices on PXA3xx" |
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588bef62..34e94c7f68ca 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -145,6 +145,15 @@ config PINCTRL_COH901 | |||
145 | COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 | 145 | COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 |
146 | ports of 8 GPIO pins each. | 146 | ports of 8 GPIO pins each. |
147 | 147 | ||
148 | config PINCTRL_SAMSUNG | ||
149 | bool "Samsung pinctrl driver" | ||
150 | select PINMUX | ||
151 | select PINCONF | ||
152 | |||
153 | config PINCTRL_EXYNOS4 | ||
154 | bool "Pinctrl driver data for Exynos4 SoC" | ||
155 | select PINCTRL_SAMSUNG | ||
156 | |||
148 | source "drivers/pinctrl/spear/Kconfig" | 157 | source "drivers/pinctrl/spear/Kconfig" |
149 | 158 | ||
150 | endmenu | 159 | endmenu |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f40b1f81ff2c..6a88113e11d9 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -29,5 +29,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o | |||
29 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o | 29 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o |
30 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o | 30 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o |
31 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o | 31 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o |
32 | obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o | ||
33 | obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o | ||
32 | 34 | ||
33 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 35 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c new file mode 100644 index 000000000000..21362f48d370 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.c | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.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 as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This file contains the Samsung Exynos specific information required by the | ||
17 | * the Samsung pinctrl/gpiolib driver. It also includes the implementation of | ||
18 | * external gpio and wakeup interrupt support. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irqdomain.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/of_irq.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/err.h> | ||
30 | |||
31 | #include <asm/mach/irq.h> | ||
32 | |||
33 | #include "pinctrl-samsung.h" | ||
34 | #include "pinctrl-exynos.h" | ||
35 | |||
36 | /* list of external wakeup controllers supported */ | ||
37 | static const struct of_device_id exynos_wkup_irq_ids[] = { | ||
38 | { .compatible = "samsung,exynos4210-wakeup-eint", }, | ||
39 | }; | ||
40 | |||
41 | static void exynos_gpio_irq_unmask(struct irq_data *irqd) | ||
42 | { | ||
43 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
44 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
45 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | ||
46 | unsigned long mask; | ||
47 | |||
48 | mask = readl(d->virt_base + reg_mask); | ||
49 | mask &= ~(1 << edata->pin); | ||
50 | writel(mask, d->virt_base + reg_mask); | ||
51 | } | ||
52 | |||
53 | static void exynos_gpio_irq_mask(struct irq_data *irqd) | ||
54 | { | ||
55 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
56 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
57 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | ||
58 | unsigned long mask; | ||
59 | |||
60 | mask = readl(d->virt_base + reg_mask); | ||
61 | mask |= 1 << edata->pin; | ||
62 | writel(mask, d->virt_base + reg_mask); | ||
63 | } | ||
64 | |||
65 | static void exynos_gpio_irq_ack(struct irq_data *irqd) | ||
66 | { | ||
67 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
68 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
69 | unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; | ||
70 | |||
71 | writel(1 << edata->pin, d->virt_base + reg_pend); | ||
72 | } | ||
73 | |||
74 | static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | ||
75 | { | ||
76 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
77 | struct samsung_pin_ctrl *ctrl = d->ctrl; | ||
78 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
79 | struct samsung_pin_bank *bank = edata->bank; | ||
80 | unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; | ||
81 | unsigned int con, trig_type; | ||
82 | unsigned long reg_con = ctrl->geint_con + edata->eint_offset; | ||
83 | unsigned int mask; | ||
84 | |||
85 | switch (type) { | ||
86 | case IRQ_TYPE_EDGE_RISING: | ||
87 | trig_type = EXYNOS_EINT_EDGE_RISING; | ||
88 | break; | ||
89 | case IRQ_TYPE_EDGE_FALLING: | ||
90 | trig_type = EXYNOS_EINT_EDGE_FALLING; | ||
91 | break; | ||
92 | case IRQ_TYPE_EDGE_BOTH: | ||
93 | trig_type = EXYNOS_EINT_EDGE_BOTH; | ||
94 | break; | ||
95 | case IRQ_TYPE_LEVEL_HIGH: | ||
96 | trig_type = EXYNOS_EINT_LEVEL_HIGH; | ||
97 | break; | ||
98 | case IRQ_TYPE_LEVEL_LOW: | ||
99 | trig_type = EXYNOS_EINT_LEVEL_LOW; | ||
100 | break; | ||
101 | default: | ||
102 | pr_err("unsupported external interrupt type\n"); | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | if (type & IRQ_TYPE_EDGE_BOTH) | ||
107 | __irq_set_handler_locked(irqd->irq, handle_edge_irq); | ||
108 | else | ||
109 | __irq_set_handler_locked(irqd->irq, handle_level_irq); | ||
110 | |||
111 | con = readl(d->virt_base + reg_con); | ||
112 | con &= ~(EXYNOS_EINT_CON_MASK << shift); | ||
113 | con |= trig_type << shift; | ||
114 | writel(con, d->virt_base + reg_con); | ||
115 | |||
116 | reg_con = bank->pctl_offset; | ||
117 | shift = edata->pin * bank->func_width; | ||
118 | mask = (1 << bank->func_width) - 1; | ||
119 | |||
120 | con = readl(d->virt_base + reg_con); | ||
121 | con &= ~(mask << shift); | ||
122 | con |= EXYNOS_EINT_FUNC << shift; | ||
123 | writel(con, d->virt_base + reg_con); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * irq_chip for gpio interrupts. | ||
130 | */ | ||
131 | static struct irq_chip exynos_gpio_irq_chip = { | ||
132 | .name = "exynos_gpio_irq_chip", | ||
133 | .irq_unmask = exynos_gpio_irq_unmask, | ||
134 | .irq_mask = exynos_gpio_irq_mask, | ||
135 | .irq_ack = exynos_gpio_irq_ack, | ||
136 | .irq_set_type = exynos_gpio_irq_set_type, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * given a controller-local external gpio interrupt number, prepare the handler | ||
141 | * data for it. | ||
142 | */ | ||
143 | static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, | ||
144 | struct samsung_pinctrl_drv_data *d) | ||
145 | { | ||
146 | struct samsung_pin_bank *bank = d->ctrl->pin_banks; | ||
147 | struct exynos_geint_data *eint_data; | ||
148 | unsigned int nr_banks = d->ctrl->nr_banks, idx; | ||
149 | unsigned int irq_base = 0, eint_offset = 0; | ||
150 | |||
151 | if (hw >= d->ctrl->nr_gint) { | ||
152 | dev_err(d->dev, "unsupported ext-gpio interrupt\n"); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | for (idx = 0; idx < nr_banks; idx++, bank++) { | ||
157 | if (bank->eint_type != EINT_TYPE_GPIO) | ||
158 | continue; | ||
159 | if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) | ||
160 | break; | ||
161 | irq_base += bank->nr_pins; | ||
162 | eint_offset += 4; | ||
163 | } | ||
164 | |||
165 | if (idx == nr_banks) { | ||
166 | dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); | ||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); | ||
171 | if (!eint_data) { | ||
172 | dev_err(d->dev, "no memory for eint-gpio data\n"); | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | eint_data->bank = bank; | ||
177 | eint_data->pin = hw - irq_base; | ||
178 | eint_data->eint_offset = eint_offset; | ||
179 | return eint_data; | ||
180 | } | ||
181 | |||
182 | static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, | ||
183 | irq_hw_number_t hw) | ||
184 | { | ||
185 | struct samsung_pinctrl_drv_data *d = h->host_data; | ||
186 | struct exynos_geint_data *eint_data; | ||
187 | |||
188 | eint_data = exynos_get_eint_data(hw, d); | ||
189 | if (!eint_data) | ||
190 | return -EINVAL; | ||
191 | |||
192 | irq_set_handler_data(virq, eint_data); | ||
193 | irq_set_chip_data(virq, h->host_data); | ||
194 | irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, | ||
195 | handle_level_irq); | ||
196 | set_irq_flags(virq, IRQF_VALID); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) | ||
201 | { | ||
202 | struct samsung_pinctrl_drv_data *d = h->host_data; | ||
203 | struct exynos_geint_data *eint_data; | ||
204 | |||
205 | eint_data = irq_get_handler_data(virq); | ||
206 | devm_kfree(d->dev, eint_data); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * irq domain callbacks for external gpio interrupt controller. | ||
211 | */ | ||
212 | static const struct irq_domain_ops exynos_gpio_irqd_ops = { | ||
213 | .map = exynos_gpio_irq_map, | ||
214 | .unmap = exynos_gpio_irq_unmap, | ||
215 | .xlate = irq_domain_xlate_twocell, | ||
216 | }; | ||
217 | |||
218 | static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) | ||
219 | { | ||
220 | struct samsung_pinctrl_drv_data *d = data; | ||
221 | struct samsung_pin_ctrl *ctrl = d->ctrl; | ||
222 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
223 | unsigned int svc, group, pin, virq; | ||
224 | |||
225 | svc = readl(d->virt_base + ctrl->svc); | ||
226 | group = EXYNOS_SVC_GROUP(svc); | ||
227 | pin = svc & EXYNOS_SVC_NUM_MASK; | ||
228 | |||
229 | if (!group) | ||
230 | return IRQ_HANDLED; | ||
231 | bank += (group - 1); | ||
232 | |||
233 | virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); | ||
234 | if (!virq) | ||
235 | return IRQ_NONE; | ||
236 | generic_handle_irq(virq); | ||
237 | return IRQ_HANDLED; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * exynos_eint_gpio_init() - setup handling of external gpio interrupts. | ||
242 | * @d: driver data of samsung pinctrl driver. | ||
243 | */ | ||
244 | static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) | ||
245 | { | ||
246 | struct device *dev = d->dev; | ||
247 | unsigned int ret; | ||
248 | |||
249 | if (!d->irq) { | ||
250 | dev_err(dev, "irq number not available\n"); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq, | ||
255 | 0, dev_name(dev), d); | ||
256 | if (ret) { | ||
257 | dev_err(dev, "irq request failed\n"); | ||
258 | return -ENXIO; | ||
259 | } | ||
260 | |||
261 | d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, | ||
262 | &exynos_gpio_irqd_ops, d); | ||
263 | if (!d->gpio_irqd) { | ||
264 | dev_err(dev, "gpio irq domain allocation failed\n"); | ||
265 | return -ENXIO; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static void exynos_wkup_irq_unmask(struct irq_data *irqd) | ||
272 | { | ||
273 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
274 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
275 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
276 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
277 | unsigned long mask; | ||
278 | |||
279 | mask = readl(d->virt_base + reg_mask); | ||
280 | mask &= ~(1 << pin); | ||
281 | writel(mask, d->virt_base + reg_mask); | ||
282 | } | ||
283 | |||
284 | static void exynos_wkup_irq_mask(struct irq_data *irqd) | ||
285 | { | ||
286 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
287 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
288 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
289 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
290 | unsigned long mask; | ||
291 | |||
292 | mask = readl(d->virt_base + reg_mask); | ||
293 | mask |= 1 << pin; | ||
294 | writel(mask, d->virt_base + reg_mask); | ||
295 | } | ||
296 | |||
297 | static void exynos_wkup_irq_ack(struct irq_data *irqd) | ||
298 | { | ||
299 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
300 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
301 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
302 | unsigned long pend = d->ctrl->weint_pend + (bank << 2); | ||
303 | |||
304 | writel(1 << pin, d->virt_base + pend); | ||
305 | } | ||
306 | |||
307 | static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | ||
308 | { | ||
309 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
310 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
311 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
312 | unsigned long reg_con = d->ctrl->weint_con + (bank << 2); | ||
313 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; | ||
314 | unsigned long con, trig_type; | ||
315 | |||
316 | switch (type) { | ||
317 | case IRQ_TYPE_EDGE_RISING: | ||
318 | trig_type = EXYNOS_EINT_EDGE_RISING; | ||
319 | break; | ||
320 | case IRQ_TYPE_EDGE_FALLING: | ||
321 | trig_type = EXYNOS_EINT_EDGE_FALLING; | ||
322 | break; | ||
323 | case IRQ_TYPE_EDGE_BOTH: | ||
324 | trig_type = EXYNOS_EINT_EDGE_BOTH; | ||
325 | break; | ||
326 | case IRQ_TYPE_LEVEL_HIGH: | ||
327 | trig_type = EXYNOS_EINT_LEVEL_HIGH; | ||
328 | break; | ||
329 | case IRQ_TYPE_LEVEL_LOW: | ||
330 | trig_type = EXYNOS_EINT_LEVEL_LOW; | ||
331 | break; | ||
332 | default: | ||
333 | pr_err("unsupported external interrupt type\n"); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | if (type & IRQ_TYPE_EDGE_BOTH) | ||
338 | __irq_set_handler_locked(irqd->irq, handle_edge_irq); | ||
339 | else | ||
340 | __irq_set_handler_locked(irqd->irq, handle_level_irq); | ||
341 | |||
342 | con = readl(d->virt_base + reg_con); | ||
343 | con &= ~(EXYNOS_EINT_CON_MASK << shift); | ||
344 | con |= trig_type << shift; | ||
345 | writel(con, d->virt_base + reg_con); | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * irq_chip for wakeup interrupts | ||
351 | */ | ||
352 | static struct irq_chip exynos_wkup_irq_chip = { | ||
353 | .name = "exynos_wkup_irq_chip", | ||
354 | .irq_unmask = exynos_wkup_irq_unmask, | ||
355 | .irq_mask = exynos_wkup_irq_mask, | ||
356 | .irq_ack = exynos_wkup_irq_ack, | ||
357 | .irq_set_type = exynos_wkup_irq_set_type, | ||
358 | }; | ||
359 | |||
360 | /* interrupt handler for wakeup interrupts 0..15 */ | ||
361 | static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | ||
362 | { | ||
363 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | ||
364 | struct irq_chip *chip = irq_get_chip(irq); | ||
365 | int eint_irq; | ||
366 | |||
367 | chained_irq_enter(chip, desc); | ||
368 | chip->irq_mask(&desc->irq_data); | ||
369 | |||
370 | if (chip->irq_ack) | ||
371 | chip->irq_ack(&desc->irq_data); | ||
372 | |||
373 | eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); | ||
374 | generic_handle_irq(eint_irq); | ||
375 | chip->irq_unmask(&desc->irq_data); | ||
376 | chained_irq_exit(chip, desc); | ||
377 | } | ||
378 | |||
379 | static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, | ||
380 | struct irq_domain *domain) | ||
381 | { | ||
382 | unsigned int irq; | ||
383 | |||
384 | while (pend) { | ||
385 | irq = fls(pend) - 1; | ||
386 | generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); | ||
387 | pend &= ~(1 << irq); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | /* interrupt handler for wakeup interrupt 16 */ | ||
392 | static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) | ||
393 | { | ||
394 | struct irq_chip *chip = irq_get_chip(irq); | ||
395 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | ||
396 | struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; | ||
397 | unsigned long pend; | ||
398 | unsigned long mask; | ||
399 | |||
400 | chained_irq_enter(chip, desc); | ||
401 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); | ||
402 | mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8); | ||
403 | exynos_irq_demux_eint(16, pend & ~mask, eintd->domain); | ||
404 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); | ||
405 | mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC); | ||
406 | exynos_irq_demux_eint(24, pend & ~mask, eintd->domain); | ||
407 | chained_irq_exit(chip, desc); | ||
408 | } | ||
409 | |||
410 | static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq, | ||
411 | irq_hw_number_t hw) | ||
412 | { | ||
413 | irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip, handle_level_irq); | ||
414 | irq_set_chip_data(virq, h->host_data); | ||
415 | set_irq_flags(virq, IRQF_VALID); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * irq domain callbacks for external wakeup interrupt controller. | ||
421 | */ | ||
422 | static const struct irq_domain_ops exynos_wkup_irqd_ops = { | ||
423 | .map = exynos_wkup_irq_map, | ||
424 | .xlate = irq_domain_xlate_twocell, | ||
425 | }; | ||
426 | |||
427 | /* | ||
428 | * exynos_eint_wkup_init() - setup handling of external wakeup interrupts. | ||
429 | * @d: driver data of samsung pinctrl driver. | ||
430 | */ | ||
431 | static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) | ||
432 | { | ||
433 | struct device *dev = d->dev; | ||
434 | struct device_node *wkup_np = NULL; | ||
435 | struct device_node *np; | ||
436 | struct exynos_weint_data *weint_data; | ||
437 | int idx, irq; | ||
438 | |||
439 | for_each_child_of_node(dev->of_node, np) { | ||
440 | if (of_match_node(exynos_wkup_irq_ids, np)) { | ||
441 | wkup_np = np; | ||
442 | break; | ||
443 | } | ||
444 | } | ||
445 | if (!wkup_np) | ||
446 | return -ENODEV; | ||
447 | |||
448 | d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, | ||
449 | &exynos_wkup_irqd_ops, d); | ||
450 | if (!d->wkup_irqd) { | ||
451 | dev_err(dev, "wakeup irq domain allocation failed\n"); | ||
452 | return -ENXIO; | ||
453 | } | ||
454 | |||
455 | weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); | ||
456 | if (!weint_data) { | ||
457 | dev_err(dev, "could not allocate memory for weint_data\n"); | ||
458 | return -ENOMEM; | ||
459 | } | ||
460 | |||
461 | irq = irq_of_parse_and_map(wkup_np, 16); | ||
462 | if (irq) { | ||
463 | weint_data[16].domain = d->wkup_irqd; | ||
464 | irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); | ||
465 | irq_set_handler_data(irq, &weint_data[16]); | ||
466 | } else { | ||
467 | dev_err(dev, "irq number for EINT16-32 not found\n"); | ||
468 | } | ||
469 | |||
470 | for (idx = 0; idx < 16; idx++) { | ||
471 | weint_data[idx].domain = d->wkup_irqd; | ||
472 | weint_data[idx].irq = idx; | ||
473 | |||
474 | irq = irq_of_parse_and_map(wkup_np, idx); | ||
475 | if (irq) { | ||
476 | irq_set_handler_data(irq, &weint_data[idx]); | ||
477 | irq_set_chained_handler(irq, exynos_irq_eint0_15); | ||
478 | } else { | ||
479 | dev_err(dev, "irq number for eint-%x not found\n", idx); | ||
480 | } | ||
481 | } | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | /* pin banks of exynos4210 pin-controller 0 */ | ||
486 | static struct samsung_pin_bank exynos4210_pin_banks0[] = { | ||
487 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), | ||
488 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), | ||
489 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), | ||
490 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), | ||
491 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), | ||
492 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), | ||
493 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), | ||
494 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), | ||
495 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), | ||
496 | EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), | ||
497 | EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), | ||
498 | EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), | ||
499 | EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), | ||
500 | EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), | ||
501 | EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), | ||
502 | EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), | ||
503 | }; | ||
504 | |||
505 | /* pin banks of exynos4210 pin-controller 1 */ | ||
506 | static struct samsung_pin_bank exynos4210_pin_banks1[] = { | ||
507 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), | ||
508 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), | ||
509 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), | ||
510 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), | ||
511 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), | ||
512 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), | ||
513 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), | ||
514 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), | ||
515 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), | ||
516 | EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), | ||
517 | EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), | ||
518 | EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), | ||
519 | EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), | ||
520 | EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), | ||
521 | EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), | ||
522 | EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), | ||
523 | EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), | ||
524 | EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), | ||
525 | EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), | ||
526 | EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), | ||
527 | }; | ||
528 | |||
529 | /* pin banks of exynos4210 pin-controller 2 */ | ||
530 | static struct samsung_pin_bank exynos4210_pin_banks2[] = { | ||
531 | EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), | ||
532 | }; | ||
533 | |||
534 | /* | ||
535 | * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes | ||
536 | * three gpio/pin-mux/pinconfig controllers. | ||
537 | */ | ||
538 | struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { | ||
539 | { | ||
540 | /* pin-controller instance 0 data */ | ||
541 | .pin_banks = exynos4210_pin_banks0, | ||
542 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), | ||
543 | .base = EXYNOS4210_GPIO_A0_START, | ||
544 | .nr_pins = EXYNOS4210_GPIOA_NR_PINS, | ||
545 | .nr_gint = EXYNOS4210_GPIOA_NR_GINT, | ||
546 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
547 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
548 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
549 | .svc = EXYNOS_SVC_OFFSET, | ||
550 | .eint_gpio_init = exynos_eint_gpio_init, | ||
551 | .label = "exynos4210-gpio-ctrl0", | ||
552 | }, { | ||
553 | /* pin-controller instance 1 data */ | ||
554 | .pin_banks = exynos4210_pin_banks1, | ||
555 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), | ||
556 | .base = EXYNOS4210_GPIOA_NR_PINS, | ||
557 | .nr_pins = EXYNOS4210_GPIOB_NR_PINS, | ||
558 | .nr_gint = EXYNOS4210_GPIOB_NR_GINT, | ||
559 | .nr_wint = 32, | ||
560 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
561 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
562 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
563 | .weint_con = EXYNOS_WKUP_ECON_OFFSET, | ||
564 | .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, | ||
565 | .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, | ||
566 | .svc = EXYNOS_SVC_OFFSET, | ||
567 | .eint_gpio_init = exynos_eint_gpio_init, | ||
568 | .eint_wkup_init = exynos_eint_wkup_init, | ||
569 | .label = "exynos4210-gpio-ctrl1", | ||
570 | }, { | ||
571 | /* pin-controller instance 2 data */ | ||
572 | .pin_banks = exynos4210_pin_banks2, | ||
573 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), | ||
574 | .base = EXYNOS4210_GPIOA_NR_PINS + | ||
575 | EXYNOS4210_GPIOB_NR_PINS, | ||
576 | .nr_pins = EXYNOS4210_GPIOC_NR_PINS, | ||
577 | .label = "exynos4210-gpio-ctrl2", | ||
578 | }, | ||
579 | }; | ||
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h new file mode 100644 index 000000000000..31d0a06174e4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.h | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * Exynos specific definitions for Samsung pinctrl and gpiolib driver. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * This file contains the Exynos specific definitions for the Samsung | ||
10 | * pinctrl/gpiolib interface drivers. | ||
11 | * | ||
12 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | */ | ||
19 | |||
20 | #define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) | ||
21 | |||
22 | #define EXYNOS4210_GPIO_A0_NR (8) | ||
23 | #define EXYNOS4210_GPIO_A1_NR (6) | ||
24 | #define EXYNOS4210_GPIO_B_NR (8) | ||
25 | #define EXYNOS4210_GPIO_C0_NR (5) | ||
26 | #define EXYNOS4210_GPIO_C1_NR (5) | ||
27 | #define EXYNOS4210_GPIO_D0_NR (4) | ||
28 | #define EXYNOS4210_GPIO_D1_NR (4) | ||
29 | #define EXYNOS4210_GPIO_E0_NR (5) | ||
30 | #define EXYNOS4210_GPIO_E1_NR (8) | ||
31 | #define EXYNOS4210_GPIO_E2_NR (6) | ||
32 | #define EXYNOS4210_GPIO_E3_NR (8) | ||
33 | #define EXYNOS4210_GPIO_E4_NR (8) | ||
34 | #define EXYNOS4210_GPIO_F0_NR (8) | ||
35 | #define EXYNOS4210_GPIO_F1_NR (8) | ||
36 | #define EXYNOS4210_GPIO_F2_NR (8) | ||
37 | #define EXYNOS4210_GPIO_F3_NR (6) | ||
38 | #define EXYNOS4210_GPIO_J0_NR (8) | ||
39 | #define EXYNOS4210_GPIO_J1_NR (5) | ||
40 | #define EXYNOS4210_GPIO_K0_NR (7) | ||
41 | #define EXYNOS4210_GPIO_K1_NR (7) | ||
42 | #define EXYNOS4210_GPIO_K2_NR (7) | ||
43 | #define EXYNOS4210_GPIO_K3_NR (7) | ||
44 | #define EXYNOS4210_GPIO_L0_NR (8) | ||
45 | #define EXYNOS4210_GPIO_L1_NR (3) | ||
46 | #define EXYNOS4210_GPIO_L2_NR (8) | ||
47 | #define EXYNOS4210_GPIO_Y0_NR (6) | ||
48 | #define EXYNOS4210_GPIO_Y1_NR (4) | ||
49 | #define EXYNOS4210_GPIO_Y2_NR (6) | ||
50 | #define EXYNOS4210_GPIO_Y3_NR (8) | ||
51 | #define EXYNOS4210_GPIO_Y4_NR (8) | ||
52 | #define EXYNOS4210_GPIO_Y5_NR (8) | ||
53 | #define EXYNOS4210_GPIO_Y6_NR (8) | ||
54 | #define EXYNOS4210_GPIO_X0_NR (8) | ||
55 | #define EXYNOS4210_GPIO_X1_NR (8) | ||
56 | #define EXYNOS4210_GPIO_X2_NR (8) | ||
57 | #define EXYNOS4210_GPIO_X3_NR (8) | ||
58 | #define EXYNOS4210_GPIO_Z_NR (7) | ||
59 | |||
60 | enum exynos4210_gpio_xa_start { | ||
61 | EXYNOS4210_GPIO_A0_START = 0, | ||
62 | EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), | ||
63 | EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), | ||
64 | EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), | ||
65 | EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), | ||
66 | EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), | ||
67 | EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), | ||
68 | EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), | ||
69 | EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), | ||
70 | EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), | ||
71 | EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), | ||
72 | EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), | ||
73 | EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), | ||
74 | EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), | ||
75 | EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), | ||
76 | EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), | ||
77 | }; | ||
78 | |||
79 | enum exynos4210_gpio_xb_start { | ||
80 | EXYNOS4210_GPIO_J0_START = 0, | ||
81 | EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), | ||
82 | EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), | ||
83 | EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), | ||
84 | EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), | ||
85 | EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), | ||
86 | EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), | ||
87 | EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), | ||
88 | EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), | ||
89 | EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), | ||
90 | EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), | ||
91 | EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), | ||
92 | EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), | ||
93 | EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), | ||
94 | EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), | ||
95 | EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), | ||
96 | EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), | ||
97 | EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), | ||
98 | EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), | ||
99 | EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), | ||
100 | }; | ||
101 | |||
102 | enum exynos4210_gpio_xc_start { | ||
103 | EXYNOS4210_GPIO_Z_START = 0, | ||
104 | }; | ||
105 | |||
106 | #define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START | ||
107 | #define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START | ||
108 | #define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START | ||
109 | #define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START | ||
110 | #define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START | ||
111 | #define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START | ||
112 | #define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START | ||
113 | #define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START | ||
114 | #define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START | ||
115 | #define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START | ||
116 | #define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START | ||
117 | #define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START | ||
118 | #define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START | ||
119 | #define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START | ||
120 | #define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START | ||
121 | #define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START | ||
122 | #define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START | ||
123 | #define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START | ||
124 | #define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START | ||
125 | #define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START | ||
126 | #define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START | ||
127 | #define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START | ||
128 | #define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START | ||
129 | #define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START | ||
130 | #define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START | ||
131 | #define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START | ||
132 | |||
133 | #define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
134 | #define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
135 | #define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) | ||
136 | #define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) | ||
137 | #define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) | ||
138 | |||
139 | /* External GPIO and wakeup interrupt related definitions */ | ||
140 | #define EXYNOS_GPIO_ECON_OFFSET 0x700 | ||
141 | #define EXYNOS_GPIO_EMASK_OFFSET 0x900 | ||
142 | #define EXYNOS_GPIO_EPEND_OFFSET 0xA00 | ||
143 | #define EXYNOS_WKUP_ECON_OFFSET 0xE00 | ||
144 | #define EXYNOS_WKUP_EMASK_OFFSET 0xF00 | ||
145 | #define EXYNOS_WKUP_EPEND_OFFSET 0xF40 | ||
146 | #define EXYNOS_SVC_OFFSET 0xB08 | ||
147 | #define EXYNOS_EINT_FUNC 0xF | ||
148 | |||
149 | /* helpers to access interrupt service register */ | ||
150 | #define EXYNOS_SVC_GROUP_SHIFT 3 | ||
151 | #define EXYNOS_SVC_GROUP_MASK 0x1f | ||
152 | #define EXYNOS_SVC_NUM_MASK 7 | ||
153 | #define EXYNOS_SVC_GROUP(x) ((x >> EXYNOS_SVC_GROUP_SHIFT) & \ | ||
154 | EXYNOS_SVC_GROUP_MASK) | ||
155 | |||
156 | /* Exynos specific external interrupt trigger types */ | ||
157 | #define EXYNOS_EINT_LEVEL_LOW 0 | ||
158 | #define EXYNOS_EINT_LEVEL_HIGH 1 | ||
159 | #define EXYNOS_EINT_EDGE_FALLING 2 | ||
160 | #define EXYNOS_EINT_EDGE_RISING 3 | ||
161 | #define EXYNOS_EINT_EDGE_BOTH 4 | ||
162 | #define EXYNOS_EINT_CON_MASK 0xF | ||
163 | #define EXYNOS_EINT_CON_LEN 4 | ||
164 | |||
165 | #define EXYNOS_EINT_MAX_PER_BANK 8 | ||
166 | #define EXYNOS_EINT_NR_WKUP_EINT | ||
167 | |||
168 | #define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ | ||
169 | { \ | ||
170 | .pctl_offset = reg, \ | ||
171 | .pin_base = (__gpio##_START), \ | ||
172 | .nr_pins = (__gpio##_NR), \ | ||
173 | .func_width = 4, \ | ||
174 | .pud_width = 2, \ | ||
175 | .drv_width = 2, \ | ||
176 | .conpdn_width = 2, \ | ||
177 | .pudpdn_width = 2, \ | ||
178 | .eint_type = EINT_TYPE_NONE, \ | ||
179 | .name = id \ | ||
180 | } | ||
181 | |||
182 | #define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ | ||
183 | { \ | ||
184 | .pctl_offset = reg, \ | ||
185 | .pin_base = (__gpio##_START), \ | ||
186 | .nr_pins = (__gpio##_NR), \ | ||
187 | .func_width = 4, \ | ||
188 | .pud_width = 2, \ | ||
189 | .drv_width = 2, \ | ||
190 | .conpdn_width = 2, \ | ||
191 | .pudpdn_width = 2, \ | ||
192 | .eint_type = EINT_TYPE_GPIO, \ | ||
193 | .irq_base = (__gpio##_IRQ), \ | ||
194 | .name = id \ | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. | ||
199 | * @bank: pin bank from which this gpio interrupt originates. | ||
200 | * @pin: pin number within the bank. | ||
201 | * @eint_offset: offset to be added to the con/pend/mask register bank base. | ||
202 | */ | ||
203 | struct exynos_geint_data { | ||
204 | struct samsung_pin_bank *bank; | ||
205 | u32 pin; | ||
206 | u32 eint_offset; | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * struct exynos_weint_data: irq specific data for all the wakeup interrupts | ||
211 | * generated by the external wakeup interrupt controller. | ||
212 | * @domain: irq domain representing the external wakeup interrupts | ||
213 | * @irq: interrupt number within the domain. | ||
214 | */ | ||
215 | struct exynos_weint_data { | ||
216 | struct irq_domain *domain; | ||
217 | u32 irq; | ||
218 | }; | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c new file mode 100644 index 000000000000..dd108a94acf9 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -0,0 +1,888 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.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 as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This driver implements the Samsung pinctrl driver. It supports setting up of | ||
17 | * pinmux and pinconf configurations. The gpiolib interface is also included. | ||
18 | * External interrupt (gpio and wakeup) support are not included in this driver | ||
19 | * but provides extensions to which platform specific implementation of the gpio | ||
20 | * and wakeup interrupts can be hooked to. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/gpio.h> | ||
29 | |||
30 | #include "core.h" | ||
31 | #include "pinctrl-samsung.h" | ||
32 | |||
33 | #define GROUP_SUFFIX "-grp" | ||
34 | #define GSUFFIX_LEN sizeof(GROUP_SUFFIX) | ||
35 | #define FUNCTION_SUFFIX "-mux" | ||
36 | #define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) | ||
37 | |||
38 | /* list of all possible config options supported */ | ||
39 | struct pin_config { | ||
40 | char *prop_cfg; | ||
41 | unsigned int cfg_type; | ||
42 | } pcfgs[] = { | ||
43 | { "samsung,pin-pud", PINCFG_TYPE_PUD }, | ||
44 | { "samsung,pin-drv", PINCFG_TYPE_DRV }, | ||
45 | { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, | ||
46 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, | ||
47 | }; | ||
48 | |||
49 | /* check if the selector is a valid pin group selector */ | ||
50 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | ||
51 | { | ||
52 | struct samsung_pinctrl_drv_data *drvdata; | ||
53 | |||
54 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
55 | return drvdata->nr_groups; | ||
56 | } | ||
57 | |||
58 | /* return the name of the group selected by the group selector */ | ||
59 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, | ||
60 | unsigned selector) | ||
61 | { | ||
62 | struct samsung_pinctrl_drv_data *drvdata; | ||
63 | |||
64 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
65 | return drvdata->pin_groups[selector].name; | ||
66 | } | ||
67 | |||
68 | /* return the pin numbers associated with the specified group */ | ||
69 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, | ||
70 | unsigned selector, const unsigned **pins, unsigned *num_pins) | ||
71 | { | ||
72 | struct samsung_pinctrl_drv_data *drvdata; | ||
73 | |||
74 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
75 | *pins = drvdata->pin_groups[selector].pins; | ||
76 | *num_pins = drvdata->pin_groups[selector].num_pins; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* create pinctrl_map entries by parsing device tree nodes */ | ||
81 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
82 | struct device_node *np, struct pinctrl_map **maps, | ||
83 | unsigned *nmaps) | ||
84 | { | ||
85 | struct device *dev = pctldev->dev; | ||
86 | struct pinctrl_map *map; | ||
87 | unsigned long *cfg = NULL; | ||
88 | char *gname, *fname; | ||
89 | int cfg_cnt = 0, map_cnt = 0, idx = 0; | ||
90 | |||
91 | /* count the number of config options specfied in the node */ | ||
92 | for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
93 | if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) | ||
94 | cfg_cnt++; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Find out the number of map entries to create. All the config options | ||
99 | * can be accomadated into a single config map entry. | ||
100 | */ | ||
101 | if (cfg_cnt) | ||
102 | map_cnt = 1; | ||
103 | if (of_find_property(np, "samsung,pin-function", NULL)) | ||
104 | map_cnt++; | ||
105 | if (!map_cnt) { | ||
106 | dev_err(dev, "node %s does not have either config or function " | ||
107 | "configurations\n", np->name); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | /* Allocate memory for pin-map entries */ | ||
112 | map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); | ||
113 | if (!map) { | ||
114 | dev_err(dev, "could not alloc memory for pin-maps\n"); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | *nmaps = 0; | ||
118 | |||
119 | /* | ||
120 | * Allocate memory for pin group name. The pin group name is derived | ||
121 | * from the node name from which these map entries are be created. | ||
122 | */ | ||
123 | gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); | ||
124 | if (!gname) { | ||
125 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
126 | goto free_map; | ||
127 | } | ||
128 | sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); | ||
129 | |||
130 | /* | ||
131 | * don't have config options? then skip over to creating function | ||
132 | * map entries. | ||
133 | */ | ||
134 | if (!cfg_cnt) | ||
135 | goto skip_cfgs; | ||
136 | |||
137 | /* Allocate memory for config entries */ | ||
138 | cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); | ||
139 | if (!cfg) { | ||
140 | dev_err(dev, "failed to alloc memory for configs\n"); | ||
141 | goto free_gname; | ||
142 | } | ||
143 | |||
144 | /* Prepare a list of config settings */ | ||
145 | for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
146 | u32 value; | ||
147 | if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) | ||
148 | cfg[cfg_cnt++] = | ||
149 | PINCFG_PACK(pcfgs[idx].cfg_type, value); | ||
150 | } | ||
151 | |||
152 | /* create the config map entry */ | ||
153 | map[*nmaps].data.configs.group_or_pin = gname; | ||
154 | map[*nmaps].data.configs.configs = cfg; | ||
155 | map[*nmaps].data.configs.num_configs = cfg_cnt; | ||
156 | map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | ||
157 | *nmaps += 1; | ||
158 | |||
159 | skip_cfgs: | ||
160 | /* create the function map entry */ | ||
161 | if (of_find_property(np, "samsung,pin-function", NULL)) { | ||
162 | fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); | ||
163 | if (!fname) { | ||
164 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
165 | goto free_cfg; | ||
166 | } | ||
167 | sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); | ||
168 | |||
169 | map[*nmaps].data.mux.group = gname; | ||
170 | map[*nmaps].data.mux.function = fname; | ||
171 | map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
172 | *nmaps += 1; | ||
173 | } | ||
174 | |||
175 | *maps = map; | ||
176 | return 0; | ||
177 | |||
178 | free_cfg: | ||
179 | kfree(cfg); | ||
180 | free_gname: | ||
181 | kfree(gname); | ||
182 | free_map: | ||
183 | kfree(map); | ||
184 | return -ENOMEM; | ||
185 | } | ||
186 | |||
187 | /* free the memory allocated to hold the pin-map table */ | ||
188 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, | ||
189 | struct pinctrl_map *map, unsigned num_maps) | ||
190 | { | ||
191 | int idx; | ||
192 | |||
193 | for (idx = 0; idx < num_maps; idx++) { | ||
194 | if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { | ||
195 | kfree(map[idx].data.mux.function); | ||
196 | if (!idx) | ||
197 | kfree(map[idx].data.mux.group); | ||
198 | } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { | ||
199 | kfree(map[idx].data.configs.configs); | ||
200 | if (!idx) | ||
201 | kfree(map[idx].data.configs.group_or_pin); | ||
202 | } | ||
203 | }; | ||
204 | |||
205 | kfree(map); | ||
206 | } | ||
207 | |||
208 | /* list of pinctrl callbacks for the pinctrl core */ | ||
209 | static struct pinctrl_ops samsung_pctrl_ops = { | ||
210 | .get_groups_count = samsung_get_group_count, | ||
211 | .get_group_name = samsung_get_group_name, | ||
212 | .get_group_pins = samsung_get_group_pins, | ||
213 | .dt_node_to_map = samsung_dt_node_to_map, | ||
214 | .dt_free_map = samsung_dt_free_map, | ||
215 | }; | ||
216 | |||
217 | /* check if the selector is a valid pin function selector */ | ||
218 | static int samsung_get_functions_count(struct pinctrl_dev *pctldev) | ||
219 | { | ||
220 | struct samsung_pinctrl_drv_data *drvdata; | ||
221 | |||
222 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
223 | return drvdata->nr_functions; | ||
224 | } | ||
225 | |||
226 | /* return the name of the pin function specified */ | ||
227 | static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, | ||
228 | unsigned selector) | ||
229 | { | ||
230 | struct samsung_pinctrl_drv_data *drvdata; | ||
231 | |||
232 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
233 | return drvdata->pmx_functions[selector].name; | ||
234 | } | ||
235 | |||
236 | /* return the groups associated for the specified function selector */ | ||
237 | static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, | ||
238 | unsigned selector, const char * const **groups, | ||
239 | unsigned * const num_groups) | ||
240 | { | ||
241 | struct samsung_pinctrl_drv_data *drvdata; | ||
242 | |||
243 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
244 | *groups = drvdata->pmx_functions[selector].groups; | ||
245 | *num_groups = drvdata->pmx_functions[selector].num_groups; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * given a pin number that is local to a pin controller, find out the pin bank | ||
251 | * and the register base of the pin bank. | ||
252 | */ | ||
253 | static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, | ||
254 | void __iomem **reg, u32 *offset, | ||
255 | struct samsung_pin_bank **bank) | ||
256 | { | ||
257 | struct samsung_pinctrl_drv_data *drvdata; | ||
258 | struct samsung_pin_bank *b; | ||
259 | |||
260 | drvdata = dev_get_drvdata(gc->dev); | ||
261 | b = drvdata->ctrl->pin_banks; | ||
262 | |||
263 | while ((pin >= b->pin_base) && | ||
264 | ((b->pin_base + b->nr_pins - 1) < pin)) | ||
265 | b++; | ||
266 | |||
267 | *reg = drvdata->virt_base + b->pctl_offset; | ||
268 | *offset = pin - b->pin_base; | ||
269 | if (bank) | ||
270 | *bank = b; | ||
271 | |||
272 | /* some banks have two config registers in a single bank */ | ||
273 | if (*offset * b->func_width > BITS_PER_LONG) | ||
274 | *reg += 4; | ||
275 | } | ||
276 | |||
277 | /* enable or disable a pinmux function */ | ||
278 | static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | ||
279 | unsigned group, bool enable) | ||
280 | { | ||
281 | struct samsung_pinctrl_drv_data *drvdata; | ||
282 | const unsigned int *pins; | ||
283 | struct samsung_pin_bank *bank; | ||
284 | void __iomem *reg; | ||
285 | u32 mask, shift, data, pin_offset, cnt; | ||
286 | |||
287 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
288 | pins = drvdata->pin_groups[group].pins; | ||
289 | |||
290 | /* | ||
291 | * for each pin in the pin group selected, program the correspoding pin | ||
292 | * pin function number in the config register. | ||
293 | */ | ||
294 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | ||
295 | pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, | ||
296 | ®, &pin_offset, &bank); | ||
297 | mask = (1 << bank->func_width) - 1; | ||
298 | shift = pin_offset * bank->func_width; | ||
299 | |||
300 | data = readl(reg); | ||
301 | data &= ~(mask << shift); | ||
302 | if (enable) | ||
303 | data |= drvdata->pin_groups[group].func << shift; | ||
304 | writel(data, reg); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | /* enable a specified pinmux by writing to registers */ | ||
309 | static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, | ||
310 | unsigned group) | ||
311 | { | ||
312 | samsung_pinmux_setup(pctldev, selector, group, true); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* disable a specified pinmux by writing to registers */ | ||
317 | static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, | ||
318 | unsigned selector, unsigned group) | ||
319 | { | ||
320 | samsung_pinmux_setup(pctldev, selector, group, false); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * The calls to gpio_direction_output() and gpio_direction_input() | ||
325 | * leads to this function call (via the pinctrl_gpio_direction_{input|output}() | ||
326 | * function called from the gpiolib interface). | ||
327 | */ | ||
328 | static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
329 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
330 | { | ||
331 | struct samsung_pin_bank *bank; | ||
332 | void __iomem *reg; | ||
333 | u32 data, pin_offset, mask, shift; | ||
334 | |||
335 | pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); | ||
336 | mask = (1 << bank->func_width) - 1; | ||
337 | shift = pin_offset * bank->func_width; | ||
338 | |||
339 | data = readl(reg); | ||
340 | data &= ~(mask << shift); | ||
341 | if (!input) | ||
342 | data |= FUNC_OUTPUT << shift; | ||
343 | writel(data, reg); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ | ||
348 | static struct pinmux_ops samsung_pinmux_ops = { | ||
349 | .get_functions_count = samsung_get_functions_count, | ||
350 | .get_function_name = samsung_pinmux_get_fname, | ||
351 | .get_function_groups = samsung_pinmux_get_groups, | ||
352 | .enable = samsung_pinmux_enable, | ||
353 | .disable = samsung_pinmux_disable, | ||
354 | .gpio_set_direction = samsung_pinmux_gpio_set_direction, | ||
355 | }; | ||
356 | |||
357 | /* set or get the pin config settings for a specified pin */ | ||
358 | static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | ||
359 | unsigned long *config, bool set) | ||
360 | { | ||
361 | struct samsung_pinctrl_drv_data *drvdata; | ||
362 | struct samsung_pin_bank *bank; | ||
363 | void __iomem *reg_base; | ||
364 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); | ||
365 | u32 data, width, pin_offset, mask, shift; | ||
366 | u32 cfg_value, cfg_reg; | ||
367 | |||
368 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
369 | pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, | ||
370 | &pin_offset, &bank); | ||
371 | |||
372 | switch (cfg_type) { | ||
373 | case PINCFG_TYPE_PUD: | ||
374 | width = bank->pud_width; | ||
375 | cfg_reg = PUD_REG; | ||
376 | break; | ||
377 | case PINCFG_TYPE_DRV: | ||
378 | width = bank->drv_width; | ||
379 | cfg_reg = DRV_REG; | ||
380 | break; | ||
381 | case PINCFG_TYPE_CON_PDN: | ||
382 | width = bank->conpdn_width; | ||
383 | cfg_reg = CONPDN_REG; | ||
384 | break; | ||
385 | case PINCFG_TYPE_PUD_PDN: | ||
386 | width = bank->pudpdn_width; | ||
387 | cfg_reg = PUDPDN_REG; | ||
388 | break; | ||
389 | default: | ||
390 | WARN_ON(1); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | mask = (1 << width) - 1; | ||
395 | shift = pin_offset * width; | ||
396 | data = readl(reg_base + cfg_reg); | ||
397 | |||
398 | if (set) { | ||
399 | cfg_value = PINCFG_UNPACK_VALUE(*config); | ||
400 | data &= ~(mask << shift); | ||
401 | data |= (cfg_value << shift); | ||
402 | writel(data, reg_base + cfg_reg); | ||
403 | } else { | ||
404 | data >>= shift; | ||
405 | data &= mask; | ||
406 | *config = PINCFG_PACK(cfg_type, data); | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* set the pin config settings for a specified pin */ | ||
412 | static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
413 | unsigned long config) | ||
414 | { | ||
415 | return samsung_pinconf_rw(pctldev, pin, &config, true); | ||
416 | } | ||
417 | |||
418 | /* get the pin config settings for a specified pin */ | ||
419 | static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, | ||
420 | unsigned long *config) | ||
421 | { | ||
422 | return samsung_pinconf_rw(pctldev, pin, config, false); | ||
423 | } | ||
424 | |||
425 | /* set the pin config settings for a specified pin group */ | ||
426 | static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, | ||
427 | unsigned group, unsigned long config) | ||
428 | { | ||
429 | struct samsung_pinctrl_drv_data *drvdata; | ||
430 | const unsigned int *pins; | ||
431 | unsigned int cnt; | ||
432 | |||
433 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
434 | pins = drvdata->pin_groups[group].pins; | ||
435 | |||
436 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) | ||
437 | samsung_pinconf_set(pctldev, pins[cnt], config); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* get the pin config settings for a specified pin group */ | ||
443 | static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, | ||
444 | unsigned int group, unsigned long *config) | ||
445 | { | ||
446 | struct samsung_pinctrl_drv_data *drvdata; | ||
447 | const unsigned int *pins; | ||
448 | |||
449 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
450 | pins = drvdata->pin_groups[group].pins; | ||
451 | samsung_pinconf_get(pctldev, pins[0], config); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ | ||
456 | static struct pinconf_ops samsung_pinconf_ops = { | ||
457 | .pin_config_get = samsung_pinconf_get, | ||
458 | .pin_config_set = samsung_pinconf_set, | ||
459 | .pin_config_group_get = samsung_pinconf_group_get, | ||
460 | .pin_config_group_set = samsung_pinconf_group_set, | ||
461 | }; | ||
462 | |||
463 | /* gpiolib gpio_set callback function */ | ||
464 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | ||
465 | { | ||
466 | void __iomem *reg; | ||
467 | u32 pin_offset, data; | ||
468 | |||
469 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
470 | data = readl(reg + DAT_REG); | ||
471 | data &= ~(1 << pin_offset); | ||
472 | if (value) | ||
473 | data |= 1 << pin_offset; | ||
474 | writel(data, reg + DAT_REG); | ||
475 | } | ||
476 | |||
477 | /* gpiolib gpio_get callback function */ | ||
478 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
479 | { | ||
480 | void __iomem *reg; | ||
481 | u32 pin_offset, data; | ||
482 | |||
483 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
484 | data = readl(reg + DAT_REG); | ||
485 | data >>= pin_offset; | ||
486 | data &= 1; | ||
487 | return data; | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * gpiolib gpio_direction_input callback function. The setting of the pin | ||
492 | * mux function as 'gpio input' will be handled by the pinctrl susbsystem | ||
493 | * interface. | ||
494 | */ | ||
495 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | ||
496 | { | ||
497 | return pinctrl_gpio_direction_input(gc->base + offset); | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * gpiolib gpio_direction_output callback function. The setting of the pin | ||
502 | * mux function as 'gpio output' will be handled by the pinctrl susbsystem | ||
503 | * interface. | ||
504 | */ | ||
505 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | ||
506 | int value) | ||
507 | { | ||
508 | samsung_gpio_set(gc, offset, value); | ||
509 | return pinctrl_gpio_direction_output(gc->base + offset); | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Parse the pin names listed in the 'samsung,pins' property and convert it | ||
514 | * into a list of gpio numbers are create a pin group from it. | ||
515 | */ | ||
516 | static int __init samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, | ||
517 | struct device_node *cfg_np, struct pinctrl_desc *pctl, | ||
518 | unsigned int **pin_list, unsigned int *npins) | ||
519 | { | ||
520 | struct device *dev = &pdev->dev; | ||
521 | struct property *prop; | ||
522 | struct pinctrl_pin_desc const *pdesc = pctl->pins; | ||
523 | unsigned int idx = 0, cnt; | ||
524 | const char *pin_name; | ||
525 | |||
526 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); | ||
527 | if (*npins < 0) { | ||
528 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | ||
529 | return -EINVAL; | ||
530 | } | ||
531 | |||
532 | *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); | ||
533 | if (!*pin_list) { | ||
534 | dev_err(dev, "failed to allocate memory for pin list\n"); | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | |||
538 | of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { | ||
539 | for (cnt = 0; cnt < pctl->npins; cnt++) { | ||
540 | if (pdesc[cnt].name) { | ||
541 | if (!strcmp(pin_name, pdesc[cnt].name)) { | ||
542 | (*pin_list)[idx++] = pdesc[cnt].number; | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | if (cnt == pctl->npins) { | ||
548 | dev_err(dev, "pin %s not valid in %s node\n", | ||
549 | pin_name, cfg_np->name); | ||
550 | devm_kfree(dev, *pin_list); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Parse the information about all the available pin groups and pin functions | ||
560 | * from device node of the pin-controller. A pin group is formed with all | ||
561 | * the pins listed in the "samsung,pins" property. | ||
562 | */ | ||
563 | static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, | ||
564 | struct samsung_pinctrl_drv_data *drvdata) | ||
565 | { | ||
566 | struct device *dev = &pdev->dev; | ||
567 | struct device_node *dev_np = dev->of_node; | ||
568 | struct device_node *cfg_np; | ||
569 | struct samsung_pin_group *groups, *grp; | ||
570 | struct samsung_pmx_func *functions, *func; | ||
571 | unsigned *pin_list; | ||
572 | unsigned int npins, grp_cnt, func_idx = 0; | ||
573 | char *gname, *fname; | ||
574 | int ret; | ||
575 | |||
576 | grp_cnt = of_get_child_count(dev_np); | ||
577 | if (!grp_cnt) | ||
578 | return -EINVAL; | ||
579 | |||
580 | groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); | ||
581 | if (!groups) { | ||
582 | dev_err(dev, "failed allocate memory for ping group list\n"); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | grp = groups; | ||
586 | |||
587 | functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); | ||
588 | if (!functions) { | ||
589 | dev_err(dev, "failed to allocate memory for function list\n"); | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | func = functions; | ||
593 | |||
594 | /* | ||
595 | * Iterate over all the child nodes of the pin controller node | ||
596 | * and create pin groups and pin function lists. | ||
597 | */ | ||
598 | for_each_child_of_node(dev_np, cfg_np) { | ||
599 | u32 function; | ||
600 | if (of_find_property(cfg_np, "interrupt-controller", NULL)) | ||
601 | continue; | ||
602 | |||
603 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | ||
604 | &drvdata->pctl, &pin_list, &npins); | ||
605 | if (ret) | ||
606 | return ret; | ||
607 | |||
608 | /* derive pin group name from the node name */ | ||
609 | gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, | ||
610 | GFP_KERNEL); | ||
611 | if (!gname) { | ||
612 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
613 | return -ENOMEM; | ||
614 | } | ||
615 | sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); | ||
616 | |||
617 | grp->name = gname; | ||
618 | grp->pins = pin_list; | ||
619 | grp->num_pins = npins; | ||
620 | of_property_read_u32(cfg_np, "samsung,pin-function", &function); | ||
621 | grp->func = function; | ||
622 | grp++; | ||
623 | |||
624 | if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) | ||
625 | continue; | ||
626 | |||
627 | /* derive function name from the node name */ | ||
628 | fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, | ||
629 | GFP_KERNEL); | ||
630 | if (!fname) { | ||
631 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
632 | return -ENOMEM; | ||
633 | } | ||
634 | sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); | ||
635 | |||
636 | func->name = fname; | ||
637 | func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); | ||
638 | if (!func->groups) { | ||
639 | dev_err(dev, "failed to alloc memory for group list " | ||
640 | "in pin function"); | ||
641 | return -ENOMEM; | ||
642 | } | ||
643 | func->groups[0] = gname; | ||
644 | func->num_groups = 1; | ||
645 | func++; | ||
646 | func_idx++; | ||
647 | } | ||
648 | |||
649 | drvdata->pin_groups = groups; | ||
650 | drvdata->nr_groups = grp_cnt; | ||
651 | drvdata->pmx_functions = functions; | ||
652 | drvdata->nr_functions = func_idx; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | /* register the pinctrl interface with the pinctrl subsystem */ | ||
658 | static int __init samsung_pinctrl_register(struct platform_device *pdev, | ||
659 | struct samsung_pinctrl_drv_data *drvdata) | ||
660 | { | ||
661 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; | ||
662 | struct pinctrl_pin_desc *pindesc, *pdesc; | ||
663 | struct samsung_pin_bank *pin_bank; | ||
664 | char *pin_names; | ||
665 | int pin, bank, ret; | ||
666 | |||
667 | ctrldesc->name = "samsung-pinctrl"; | ||
668 | ctrldesc->owner = THIS_MODULE; | ||
669 | ctrldesc->pctlops = &samsung_pctrl_ops; | ||
670 | ctrldesc->pmxops = &samsung_pinmux_ops; | ||
671 | ctrldesc->confops = &samsung_pinconf_ops; | ||
672 | |||
673 | pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * | ||
674 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
675 | if (!pindesc) { | ||
676 | dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); | ||
677 | return -ENOMEM; | ||
678 | } | ||
679 | ctrldesc->pins = pindesc; | ||
680 | ctrldesc->npins = drvdata->ctrl->nr_pins; | ||
681 | ctrldesc->npins = drvdata->ctrl->nr_pins; | ||
682 | |||
683 | /* dynamically populate the pin number and pin name for pindesc */ | ||
684 | for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) | ||
685 | pdesc->number = pin + drvdata->ctrl->base; | ||
686 | |||
687 | /* | ||
688 | * allocate space for storing the dynamically generated names for all | ||
689 | * the pins which belong to this pin-controller. | ||
690 | */ | ||
691 | pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * | ||
692 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
693 | if (!pin_names) { | ||
694 | dev_err(&pdev->dev, "mem alloc for pin names failed\n"); | ||
695 | return -ENOMEM; | ||
696 | } | ||
697 | |||
698 | /* for each pin, the name of the pin is pin-bank name + pin number */ | ||
699 | for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { | ||
700 | pin_bank = &drvdata->ctrl->pin_banks[bank]; | ||
701 | for (pin = 0; pin < pin_bank->nr_pins; pin++) { | ||
702 | sprintf(pin_names, "%s-%d", pin_bank->name, pin); | ||
703 | pdesc = pindesc + pin_bank->pin_base + pin; | ||
704 | pdesc->name = pin_names; | ||
705 | pin_names += PIN_NAME_LENGTH; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); | ||
710 | if (!drvdata->pctl_dev) { | ||
711 | dev_err(&pdev->dev, "could not register pinctrl driver\n"); | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | |||
715 | drvdata->grange.name = "samsung-pctrl-gpio-range"; | ||
716 | drvdata->grange.id = 0; | ||
717 | drvdata->grange.base = drvdata->ctrl->base; | ||
718 | drvdata->grange.npins = drvdata->ctrl->nr_pins; | ||
719 | drvdata->grange.gc = drvdata->gc; | ||
720 | pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); | ||
721 | |||
722 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | ||
723 | if (ret) { | ||
724 | pinctrl_unregister(drvdata->pctl_dev); | ||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | /* register the gpiolib interface with the gpiolib subsystem */ | ||
732 | static int __init samsung_gpiolib_register(struct platform_device *pdev, | ||
733 | struct samsung_pinctrl_drv_data *drvdata) | ||
734 | { | ||
735 | struct gpio_chip *gc; | ||
736 | int ret; | ||
737 | |||
738 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | ||
739 | if (!gc) { | ||
740 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | ||
741 | return -ENOMEM; | ||
742 | } | ||
743 | |||
744 | drvdata->gc = gc; | ||
745 | gc->base = drvdata->ctrl->base; | ||
746 | gc->ngpio = drvdata->ctrl->nr_pins; | ||
747 | gc->dev = &pdev->dev; | ||
748 | gc->set = samsung_gpio_set; | ||
749 | gc->get = samsung_gpio_get; | ||
750 | gc->direction_input = samsung_gpio_direction_input; | ||
751 | gc->direction_output = samsung_gpio_direction_output; | ||
752 | gc->label = drvdata->ctrl->label; | ||
753 | gc->owner = THIS_MODULE; | ||
754 | ret = gpiochip_add(gc); | ||
755 | if (ret) { | ||
756 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
757 | "code: %d\n", gc->label, ret); | ||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* unregister the gpiolib interface with the gpiolib subsystem */ | ||
765 | static int __init samsung_gpiolib_unregister(struct platform_device *pdev, | ||
766 | struct samsung_pinctrl_drv_data *drvdata) | ||
767 | { | ||
768 | int ret = gpiochip_remove(drvdata->gc); | ||
769 | if (ret) { | ||
770 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | ||
771 | return ret; | ||
772 | } | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static const struct of_device_id samsung_pinctrl_dt_match[]; | ||
777 | |||
778 | /* retrieve the soc specific data */ | ||
779 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | ||
780 | struct platform_device *pdev) | ||
781 | { | ||
782 | int id; | ||
783 | const struct of_device_id *match; | ||
784 | const struct device_node *node = pdev->dev.of_node; | ||
785 | |||
786 | id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); | ||
787 | if (id < 0) { | ||
788 | dev_err(&pdev->dev, "failed to get alias id\n"); | ||
789 | return NULL; | ||
790 | } | ||
791 | match = of_match_node(samsung_pinctrl_dt_match, node); | ||
792 | return (struct samsung_pin_ctrl *)match->data + id; | ||
793 | } | ||
794 | |||
795 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | ||
796 | { | ||
797 | struct samsung_pinctrl_drv_data *drvdata; | ||
798 | struct device *dev = &pdev->dev; | ||
799 | struct samsung_pin_ctrl *ctrl; | ||
800 | struct resource *res; | ||
801 | int ret; | ||
802 | |||
803 | if (!dev->of_node) { | ||
804 | dev_err(dev, "device tree node not found\n"); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | |||
808 | ctrl = samsung_pinctrl_get_soc_data(pdev); | ||
809 | if (!ctrl) { | ||
810 | dev_err(&pdev->dev, "driver data not available\n"); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
815 | if (!drvdata) { | ||
816 | dev_err(dev, "failed to allocate memory for driver's " | ||
817 | "private data\n"); | ||
818 | return -ENOMEM; | ||
819 | } | ||
820 | drvdata->ctrl = ctrl; | ||
821 | drvdata->dev = dev; | ||
822 | |||
823 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
824 | if (!res) { | ||
825 | dev_err(dev, "cannot find IO resource\n"); | ||
826 | return -ENOENT; | ||
827 | } | ||
828 | |||
829 | drvdata->virt_base = devm_request_and_ioremap(&pdev->dev, res); | ||
830 | if (!drvdata->virt_base) { | ||
831 | dev_err(dev, "ioremap failed\n"); | ||
832 | return -ENODEV; | ||
833 | } | ||
834 | |||
835 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
836 | if (res) | ||
837 | drvdata->irq = res->start; | ||
838 | |||
839 | ret = samsung_gpiolib_register(pdev, drvdata); | ||
840 | if (ret) | ||
841 | return ret; | ||
842 | |||
843 | ret = samsung_pinctrl_register(pdev, drvdata); | ||
844 | if (ret) { | ||
845 | samsung_gpiolib_unregister(pdev, drvdata); | ||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | if (ctrl->eint_gpio_init) | ||
850 | ctrl->eint_gpio_init(drvdata); | ||
851 | if (ctrl->eint_wkup_init) | ||
852 | ctrl->eint_wkup_init(drvdata); | ||
853 | |||
854 | platform_set_drvdata(pdev, drvdata); | ||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static const struct of_device_id samsung_pinctrl_dt_match[] = { | ||
859 | { .compatible = "samsung,pinctrl-exynos4210", | ||
860 | .data = (void *)exynos4210_pin_ctrl }, | ||
861 | {}, | ||
862 | }; | ||
863 | MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); | ||
864 | |||
865 | static struct platform_driver samsung_pinctrl_driver = { | ||
866 | .probe = samsung_pinctrl_probe, | ||
867 | .driver = { | ||
868 | .name = "samsung-pinctrl", | ||
869 | .owner = THIS_MODULE, | ||
870 | .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), | ||
871 | }, | ||
872 | }; | ||
873 | |||
874 | static int __init samsung_pinctrl_drv_register(void) | ||
875 | { | ||
876 | return platform_driver_register(&samsung_pinctrl_driver); | ||
877 | } | ||
878 | postcore_initcall(samsung_pinctrl_drv_register); | ||
879 | |||
880 | static void __exit samsung_pinctrl_drv_unregister(void) | ||
881 | { | ||
882 | platform_driver_unregister(&samsung_pinctrl_driver); | ||
883 | } | ||
884 | module_exit(samsung_pinctrl_drv_unregister); | ||
885 | |||
886 | MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); | ||
887 | MODULE_DESCRIPTION("Samsung pinctrl driver"); | ||
888 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h new file mode 100644 index 000000000000..b8956934cda6 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.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 as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #ifndef __PINCTRL_SAMSUNG_H | ||
18 | #define __PINCTRL_SAMSUNG_H | ||
19 | |||
20 | #include <linux/pinctrl/pinctrl.h> | ||
21 | #include <linux/pinctrl/pinmux.h> | ||
22 | #include <linux/pinctrl/pinconf.h> | ||
23 | #include <linux/pinctrl/consumer.h> | ||
24 | #include <linux/pinctrl/machine.h> | ||
25 | |||
26 | /* register offsets within a pin bank */ | ||
27 | #define DAT_REG 0x4 | ||
28 | #define PUD_REG 0x8 | ||
29 | #define DRV_REG 0xC | ||
30 | #define CONPDN_REG 0x10 | ||
31 | #define PUDPDN_REG 0x14 | ||
32 | |||
33 | /* pinmux function number for pin as gpio output line */ | ||
34 | #define FUNC_OUTPUT 0x1 | ||
35 | |||
36 | /** | ||
37 | * enum pincfg_type - possible pin configuration types supported. | ||
38 | * @PINCFG_TYPE_PUD: Pull up/down configuration. | ||
39 | * @PINCFG_TYPE_DRV: Drive strength configuration. | ||
40 | * @PINCFG_TYPE_CON_PDN: Pin function in power down mode. | ||
41 | * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode. | ||
42 | */ | ||
43 | enum pincfg_type { | ||
44 | PINCFG_TYPE_PUD, | ||
45 | PINCFG_TYPE_DRV, | ||
46 | PINCFG_TYPE_CON_PDN, | ||
47 | PINCFG_TYPE_PUD_PDN, | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * pin configuration (pull up/down and drive strength) type and its value are | ||
52 | * packed together into a 16-bits. The upper 8-bits represent the configuration | ||
53 | * type and the lower 8-bits hold the value of the configuration type. | ||
54 | */ | ||
55 | #define PINCFG_TYPE_MASK 0xFF | ||
56 | #define PINCFG_VALUE_SHIFT 8 | ||
57 | #define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) | ||
58 | #define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) | ||
59 | #define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) | ||
60 | #define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ | ||
61 | PINCFG_VALUE_SHIFT) | ||
62 | /** | ||
63 | * enum eint_type - possible external interrupt types. | ||
64 | * @EINT_TYPE_NONE: bank does not support external interrupts | ||
65 | * @EINT_TYPE_GPIO: bank supportes external gpio interrupts | ||
66 | * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts | ||
67 | * | ||
68 | * Samsung GPIO controller groups all the available pins into banks. The pins | ||
69 | * in a pin bank can support external gpio interrupts or external wakeup | ||
70 | * interrupts or no interrupts at all. From a software perspective, the only | ||
71 | * difference between external gpio and external wakeup interrupts is that | ||
72 | * the wakeup interrupts can additionally wakeup the system if it is in | ||
73 | * suspended state. | ||
74 | */ | ||
75 | enum eint_type { | ||
76 | EINT_TYPE_NONE, | ||
77 | EINT_TYPE_GPIO, | ||
78 | EINT_TYPE_WKUP, | ||
79 | }; | ||
80 | |||
81 | /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ | ||
82 | #define PIN_NAME_LENGTH 10 | ||
83 | |||
84 | #define PIN_GROUP(n, p, f) \ | ||
85 | { \ | ||
86 | .name = n, \ | ||
87 | .pins = p, \ | ||
88 | .num_pins = ARRAY_SIZE(p), \ | ||
89 | .func = f \ | ||
90 | } | ||
91 | |||
92 | #define PMX_FUNC(n, g) \ | ||
93 | { \ | ||
94 | .name = n, \ | ||
95 | .groups = g, \ | ||
96 | .num_groups = ARRAY_SIZE(g), \ | ||
97 | } | ||
98 | |||
99 | struct samsung_pinctrl_drv_data; | ||
100 | |||
101 | /** | ||
102 | * struct samsung_pin_bank: represent a controller pin-bank. | ||
103 | * @reg_offset: starting offset of the pin-bank registers. | ||
104 | * @pin_base: starting pin number of the bank. | ||
105 | * @nr_pins: number of pins included in this bank. | ||
106 | * @func_width: width of the function selector bit field. | ||
107 | * @pud_width: width of the pin pull up/down selector bit field. | ||
108 | * @drv_width: width of the pin driver strength selector bit field. | ||
109 | * @conpdn_width: width of the sleep mode function selector bin field. | ||
110 | * @pudpdn_width: width of the sleep mode pull up/down selector bit field. | ||
111 | * @eint_type: type of the external interrupt supported by the bank. | ||
112 | * @irq_base: starting controller local irq number of the bank. | ||
113 | * @name: name to be prefixed for each pin in this pin bank. | ||
114 | */ | ||
115 | struct samsung_pin_bank { | ||
116 | u32 pctl_offset; | ||
117 | u32 pin_base; | ||
118 | u8 nr_pins; | ||
119 | u8 func_width; | ||
120 | u8 pud_width; | ||
121 | u8 drv_width; | ||
122 | u8 conpdn_width; | ||
123 | u8 pudpdn_width; | ||
124 | enum eint_type eint_type; | ||
125 | u32 irq_base; | ||
126 | char *name; | ||
127 | }; | ||
128 | |||
129 | /** | ||
130 | * struct samsung_pin_ctrl: represent a pin controller. | ||
131 | * @pin_banks: list of pin banks included in this controller. | ||
132 | * @nr_banks: number of pin banks. | ||
133 | * @base: starting system wide pin number. | ||
134 | * @nr_pins: number of pins supported by the controller. | ||
135 | * @nr_gint: number of external gpio interrupts supported. | ||
136 | * @nr_wint: number of external wakeup interrupts supported. | ||
137 | * @geint_con: offset of the ext-gpio controller registers. | ||
138 | * @geint_mask: offset of the ext-gpio interrupt mask registers. | ||
139 | * @geint_pend: offset of the ext-gpio interrupt pending registers. | ||
140 | * @weint_con: offset of the ext-wakeup controller registers. | ||
141 | * @weint_mask: offset of the ext-wakeup interrupt mask registers. | ||
142 | * @weint_pend: offset of the ext-wakeup interrupt pending registers. | ||
143 | * @svc: offset of the interrupt service register. | ||
144 | * @eint_gpio_init: platform specific callback to setup the external gpio | ||
145 | * interrupts for the controller. | ||
146 | * @eint_wkup_init: platform specific callback to setup the external wakeup | ||
147 | * interrupts for the controller. | ||
148 | * @label: for debug information. | ||
149 | */ | ||
150 | struct samsung_pin_ctrl { | ||
151 | struct samsung_pin_bank *pin_banks; | ||
152 | u32 nr_banks; | ||
153 | |||
154 | u32 base; | ||
155 | u32 nr_pins; | ||
156 | u32 nr_gint; | ||
157 | u32 nr_wint; | ||
158 | |||
159 | u32 geint_con; | ||
160 | u32 geint_mask; | ||
161 | u32 geint_pend; | ||
162 | |||
163 | u32 weint_con; | ||
164 | u32 weint_mask; | ||
165 | u32 weint_pend; | ||
166 | |||
167 | u32 svc; | ||
168 | |||
169 | int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); | ||
170 | int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); | ||
171 | char *label; | ||
172 | }; | ||
173 | |||
174 | /** | ||
175 | * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. | ||
176 | * @virt_base: register base address of the controller. | ||
177 | * @dev: device instance representing the controller. | ||
178 | * @irq: interrpt number used by the controller to notify gpio interrupts. | ||
179 | * @ctrl: pin controller instance managed by the driver. | ||
180 | * @pctl: pin controller descriptor registered with the pinctrl subsystem. | ||
181 | * @pctl_dev: cookie representing pinctrl device instance. | ||
182 | * @pin_groups: list of pin groups available to the driver. | ||
183 | * @nr_groups: number of such pin groups. | ||
184 | * @pmx_functions: list of pin functions available to the driver. | ||
185 | * @nr_function: number of such pin functions. | ||
186 | * @gc: gpio_chip instance registered with gpiolib. | ||
187 | * @grange: linux gpio pin range supported by this controller. | ||
188 | */ | ||
189 | struct samsung_pinctrl_drv_data { | ||
190 | void __iomem *virt_base; | ||
191 | struct device *dev; | ||
192 | int irq; | ||
193 | |||
194 | struct samsung_pin_ctrl *ctrl; | ||
195 | struct pinctrl_desc pctl; | ||
196 | struct pinctrl_dev *pctl_dev; | ||
197 | |||
198 | const struct samsung_pin_group *pin_groups; | ||
199 | unsigned int nr_groups; | ||
200 | const struct samsung_pmx_func *pmx_functions; | ||
201 | unsigned int nr_functions; | ||
202 | |||
203 | struct irq_domain *gpio_irqd; | ||
204 | struct irq_domain *wkup_irqd; | ||
205 | |||
206 | struct gpio_chip *gc; | ||
207 | struct pinctrl_gpio_range grange; | ||
208 | }; | ||
209 | |||
210 | /** | ||
211 | * struct samsung_pin_group: represent group of pins of a pinmux function. | ||
212 | * @name: name of the pin group, used to lookup the group. | ||
213 | * @pins: the pins included in this group. | ||
214 | * @num_pins: number of pins included in this group. | ||
215 | * @func: the function number to be programmed when selected. | ||
216 | */ | ||
217 | struct samsung_pin_group { | ||
218 | const char *name; | ||
219 | const unsigned int *pins; | ||
220 | u8 num_pins; | ||
221 | u8 func; | ||
222 | }; | ||
223 | |||
224 | /** | ||
225 | * struct samsung_pmx_func: represent a pin function. | ||
226 | * @name: name of the pin function, used to lookup the function. | ||
227 | * @groups: one or more names of pin groups that provide this function. | ||
228 | * @num_groups: number of groups included in @groups. | ||
229 | */ | ||
230 | struct samsung_pmx_func { | ||
231 | const char *name; | ||
232 | const char **groups; | ||
233 | u8 num_groups; | ||
234 | }; | ||
235 | |||
236 | /* list of all exported SoC specific data */ | ||
237 | extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; | ||
238 | |||
239 | #endif /* __PINCTRL_SAMSUNG_H */ | ||