diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 19:50:35 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 19:50:35 -0500 |
commit | 3c0cb7c31c206aaedb967e44b98442bbeb17a6c4 (patch) | |
tree | 3ecba45d7ffae4fba4a5aafaef4af5b0b1105bde /drivers | |
parent | f70f5b9dc74ca7d0a64c4ead3fb28da09dc1b234 (diff) | |
parent | 404a02cbd2ae8bf256a2fa1169bdfe86bb5ebb34 (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (416 commits)
ARM: DMA: add support for DMA debugging
ARM: PL011: add DMA burst threshold support for ST variants
ARM: PL011: Add support for transmit DMA
ARM: PL011: Ensure IRQs are disabled in UART interrupt handler
ARM: PL011: Separate hardware FIFO size from TTY FIFO size
ARM: PL011: Allow better handling of vendor data
ARM: PL011: Ensure error flags are clear at startup
ARM: PL011: include revision number in boot-time port printk
ARM: vexpress: add sched_clock() for Versatile Express
ARM i.MX53: Make MX53 EVK bootable
ARM i.MX53: Some bug fix about MX53 MSL code
ARM: 6607/1: sa1100: Update platform device registration
ARM: 6606/1: sa1100: Fix platform device registration
ARM i.MX51: rename IPU irqs
ARM i.MX51: Add ipu clock support
ARM: imx/mx27_3ds: Add PMIC support
ARM: DMA: Replace page_to_dma()/dma_to_page() with pfn_to_dma()/dma_to_pfn()
mx51: fix usb clock support
MX51: Add support for usb host 2
arch/arm/plat-mxc/ehci.c: fix errors/typos
...
Diffstat (limited to 'drivers')
46 files changed, 4285 insertions, 1031 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index a2b902f4d437..3d93b3a3d630 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -111,4 +111,6 @@ source "drivers/xen/Kconfig" | |||
111 | source "drivers/staging/Kconfig" | 111 | source "drivers/staging/Kconfig" |
112 | 112 | ||
113 | source "drivers/platform/Kconfig" | 113 | source "drivers/platform/Kconfig" |
114 | |||
115 | source "drivers/clk/Kconfig" | ||
114 | endmenu | 116 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index f3ebb30f1b7f..bf15ce7493d2 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -115,3 +115,5 @@ obj-$(CONFIG_VLYNQ) += vlynq/ | |||
115 | obj-$(CONFIG_STAGING) += staging/ | 115 | obj-$(CONFIG_STAGING) += staging/ |
116 | obj-y += platform/ | 116 | obj-y += platform/ |
117 | obj-y += ieee802154/ | 117 | obj-y += ieee802154/ |
118 | #common clk code | ||
119 | obj-y += clk/ | ||
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 2737b9752205..e7df019d29d4 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c | |||
@@ -147,6 +147,39 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) | |||
147 | clk_put(pclk); | 147 | clk_put(pclk); |
148 | } | 148 | } |
149 | 149 | ||
150 | static int amba_get_enable_vcore(struct amba_device *pcdev) | ||
151 | { | ||
152 | struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); | ||
153 | int ret; | ||
154 | |||
155 | pcdev->vcore = vcore; | ||
156 | |||
157 | if (IS_ERR(vcore)) { | ||
158 | /* It is OK not to supply a vcore regulator */ | ||
159 | if (PTR_ERR(vcore) == -ENODEV) | ||
160 | return 0; | ||
161 | return PTR_ERR(vcore); | ||
162 | } | ||
163 | |||
164 | ret = regulator_enable(vcore); | ||
165 | if (ret) { | ||
166 | regulator_put(vcore); | ||
167 | pcdev->vcore = ERR_PTR(-ENODEV); | ||
168 | } | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static void amba_put_disable_vcore(struct amba_device *pcdev) | ||
174 | { | ||
175 | struct regulator *vcore = pcdev->vcore; | ||
176 | |||
177 | if (!IS_ERR(vcore)) { | ||
178 | regulator_disable(vcore); | ||
179 | regulator_put(vcore); | ||
180 | } | ||
181 | } | ||
182 | |||
150 | /* | 183 | /* |
151 | * These are the device model conversion veneers; they convert the | 184 | * These are the device model conversion veneers; they convert the |
152 | * device model structures to our more specific structures. | 185 | * device model structures to our more specific structures. |
@@ -159,6 +192,10 @@ static int amba_probe(struct device *dev) | |||
159 | int ret; | 192 | int ret; |
160 | 193 | ||
161 | do { | 194 | do { |
195 | ret = amba_get_enable_vcore(pcdev); | ||
196 | if (ret) | ||
197 | break; | ||
198 | |||
162 | ret = amba_get_enable_pclk(pcdev); | 199 | ret = amba_get_enable_pclk(pcdev); |
163 | if (ret) | 200 | if (ret) |
164 | break; | 201 | break; |
@@ -168,6 +205,7 @@ static int amba_probe(struct device *dev) | |||
168 | break; | 205 | break; |
169 | 206 | ||
170 | amba_put_disable_pclk(pcdev); | 207 | amba_put_disable_pclk(pcdev); |
208 | amba_put_disable_vcore(pcdev); | ||
171 | } while (0); | 209 | } while (0); |
172 | 210 | ||
173 | return ret; | 211 | return ret; |
@@ -180,6 +218,7 @@ static int amba_remove(struct device *dev) | |||
180 | int ret = drv->remove(pcdev); | 218 | int ret = drv->remove(pcdev); |
181 | 219 | ||
182 | amba_put_disable_pclk(pcdev); | 220 | amba_put_disable_pclk(pcdev); |
221 | amba_put_disable_vcore(pcdev); | ||
183 | 222 | ||
184 | return ret; | 223 | return ret; |
185 | } | 224 | } |
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig new file mode 100644 index 000000000000..4168c8896e16 --- /dev/null +++ b/drivers/clk/Kconfig | |||
@@ -0,0 +1,4 @@ | |||
1 | |||
2 | config CLKDEV_LOOKUP | ||
3 | bool | ||
4 | select HAVE_CLK | ||
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile new file mode 100644 index 000000000000..07613fa172c9 --- /dev/null +++ b/drivers/clk/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | |||
2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o | ||
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c new file mode 100644 index 000000000000..0fc0a79852de --- /dev/null +++ b/drivers/clk/clkdev.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * drivers/clk/clkdev.c | ||
3 | * | ||
4 | * Copyright (C) 2008 Russell King. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Helper for the clk API to assist looking up a struct clk. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/clkdev.h> | ||
22 | |||
23 | static LIST_HEAD(clocks); | ||
24 | static DEFINE_MUTEX(clocks_mutex); | ||
25 | |||
26 | /* | ||
27 | * Find the correct struct clk for the device and connection ID. | ||
28 | * We do slightly fuzzy matching here: | ||
29 | * An entry with a NULL ID is assumed to be a wildcard. | ||
30 | * If an entry has a device ID, it must match | ||
31 | * If an entry has a connection ID, it must match | ||
32 | * Then we take the most specific entry - with the following | ||
33 | * order of precedence: dev+con > dev only > con only. | ||
34 | */ | ||
35 | static struct clk *clk_find(const char *dev_id, const char *con_id) | ||
36 | { | ||
37 | struct clk_lookup *p; | ||
38 | struct clk *clk = NULL; | ||
39 | int match, best = 0; | ||
40 | |||
41 | list_for_each_entry(p, &clocks, node) { | ||
42 | match = 0; | ||
43 | if (p->dev_id) { | ||
44 | if (!dev_id || strcmp(p->dev_id, dev_id)) | ||
45 | continue; | ||
46 | match += 2; | ||
47 | } | ||
48 | if (p->con_id) { | ||
49 | if (!con_id || strcmp(p->con_id, con_id)) | ||
50 | continue; | ||
51 | match += 1; | ||
52 | } | ||
53 | |||
54 | if (match > best) { | ||
55 | clk = p->clk; | ||
56 | if (match != 3) | ||
57 | best = match; | ||
58 | else | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | return clk; | ||
63 | } | ||
64 | |||
65 | struct clk *clk_get_sys(const char *dev_id, const char *con_id) | ||
66 | { | ||
67 | struct clk *clk; | ||
68 | |||
69 | mutex_lock(&clocks_mutex); | ||
70 | clk = clk_find(dev_id, con_id); | ||
71 | if (clk && !__clk_get(clk)) | ||
72 | clk = NULL; | ||
73 | mutex_unlock(&clocks_mutex); | ||
74 | |||
75 | return clk ? clk : ERR_PTR(-ENOENT); | ||
76 | } | ||
77 | EXPORT_SYMBOL(clk_get_sys); | ||
78 | |||
79 | struct clk *clk_get(struct device *dev, const char *con_id) | ||
80 | { | ||
81 | const char *dev_id = dev ? dev_name(dev) : NULL; | ||
82 | |||
83 | return clk_get_sys(dev_id, con_id); | ||
84 | } | ||
85 | EXPORT_SYMBOL(clk_get); | ||
86 | |||
87 | void clk_put(struct clk *clk) | ||
88 | { | ||
89 | __clk_put(clk); | ||
90 | } | ||
91 | EXPORT_SYMBOL(clk_put); | ||
92 | |||
93 | void clkdev_add(struct clk_lookup *cl) | ||
94 | { | ||
95 | mutex_lock(&clocks_mutex); | ||
96 | list_add_tail(&cl->node, &clocks); | ||
97 | mutex_unlock(&clocks_mutex); | ||
98 | } | ||
99 | EXPORT_SYMBOL(clkdev_add); | ||
100 | |||
101 | void __init clkdev_add_table(struct clk_lookup *cl, size_t num) | ||
102 | { | ||
103 | mutex_lock(&clocks_mutex); | ||
104 | while (num--) { | ||
105 | list_add_tail(&cl->node, &clocks); | ||
106 | cl++; | ||
107 | } | ||
108 | mutex_unlock(&clocks_mutex); | ||
109 | } | ||
110 | |||
111 | #define MAX_DEV_ID 20 | ||
112 | #define MAX_CON_ID 16 | ||
113 | |||
114 | struct clk_lookup_alloc { | ||
115 | struct clk_lookup cl; | ||
116 | char dev_id[MAX_DEV_ID]; | ||
117 | char con_id[MAX_CON_ID]; | ||
118 | }; | ||
119 | |||
120 | struct clk_lookup * __init_refok | ||
121 | clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) | ||
122 | { | ||
123 | struct clk_lookup_alloc *cla; | ||
124 | |||
125 | cla = __clkdev_alloc(sizeof(*cla)); | ||
126 | if (!cla) | ||
127 | return NULL; | ||
128 | |||
129 | cla->cl.clk = clk; | ||
130 | if (con_id) { | ||
131 | strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); | ||
132 | cla->cl.con_id = cla->con_id; | ||
133 | } | ||
134 | |||
135 | if (dev_fmt) { | ||
136 | va_list ap; | ||
137 | |||
138 | va_start(ap, dev_fmt); | ||
139 | vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); | ||
140 | cla->cl.dev_id = cla->dev_id; | ||
141 | va_end(ap); | ||
142 | } | ||
143 | |||
144 | return &cla->cl; | ||
145 | } | ||
146 | EXPORT_SYMBOL(clkdev_alloc); | ||
147 | |||
148 | int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, | ||
149 | struct device *dev) | ||
150 | { | ||
151 | struct clk *r = clk_get(dev, id); | ||
152 | struct clk_lookup *l; | ||
153 | |||
154 | if (IS_ERR(r)) | ||
155 | return PTR_ERR(r); | ||
156 | |||
157 | l = clkdev_alloc(r, alias, alias_dev_name); | ||
158 | clk_put(r); | ||
159 | if (!l) | ||
160 | return -ENODEV; | ||
161 | clkdev_add(l); | ||
162 | return 0; | ||
163 | } | ||
164 | EXPORT_SYMBOL(clk_add_alias); | ||
165 | |||
166 | /* | ||
167 | * clkdev_drop - remove a clock dynamically allocated | ||
168 | */ | ||
169 | void clkdev_drop(struct clk_lookup *cl) | ||
170 | { | ||
171 | mutex_lock(&clocks_mutex); | ||
172 | list_del(&cl->node); | ||
173 | mutex_unlock(&clocks_mutex); | ||
174 | kfree(cl); | ||
175 | } | ||
176 | EXPORT_SYMBOL(clkdev_drop); | ||
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index d0602dd5d1b2..d5a5d4d9c19b 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c | |||
@@ -273,50 +273,6 @@ struct sdma_channel { | |||
273 | #define MXC_SDMA_MIN_PRIORITY 1 | 273 | #define MXC_SDMA_MIN_PRIORITY 1 |
274 | #define MXC_SDMA_MAX_PRIORITY 7 | 274 | #define MXC_SDMA_MAX_PRIORITY 7 |
275 | 275 | ||
276 | /** | ||
277 | * struct sdma_script_start_addrs - SDMA script start pointers | ||
278 | * | ||
279 | * start addresses of the different functions in the physical | ||
280 | * address space of the SDMA engine. | ||
281 | */ | ||
282 | struct sdma_script_start_addrs { | ||
283 | u32 ap_2_ap_addr; | ||
284 | u32 ap_2_bp_addr; | ||
285 | u32 ap_2_ap_fixed_addr; | ||
286 | u32 bp_2_ap_addr; | ||
287 | u32 loopback_on_dsp_side_addr; | ||
288 | u32 mcu_interrupt_only_addr; | ||
289 | u32 firi_2_per_addr; | ||
290 | u32 firi_2_mcu_addr; | ||
291 | u32 per_2_firi_addr; | ||
292 | u32 mcu_2_firi_addr; | ||
293 | u32 uart_2_per_addr; | ||
294 | u32 uart_2_mcu_addr; | ||
295 | u32 per_2_app_addr; | ||
296 | u32 mcu_2_app_addr; | ||
297 | u32 per_2_per_addr; | ||
298 | u32 uartsh_2_per_addr; | ||
299 | u32 uartsh_2_mcu_addr; | ||
300 | u32 per_2_shp_addr; | ||
301 | u32 mcu_2_shp_addr; | ||
302 | u32 ata_2_mcu_addr; | ||
303 | u32 mcu_2_ata_addr; | ||
304 | u32 app_2_per_addr; | ||
305 | u32 app_2_mcu_addr; | ||
306 | u32 shp_2_per_addr; | ||
307 | u32 shp_2_mcu_addr; | ||
308 | u32 mshc_2_mcu_addr; | ||
309 | u32 mcu_2_mshc_addr; | ||
310 | u32 spdif_2_mcu_addr; | ||
311 | u32 mcu_2_spdif_addr; | ||
312 | u32 asrc_2_mcu_addr; | ||
313 | u32 ext_mem_2_ipu_addr; | ||
314 | u32 descrambler_addr; | ||
315 | u32 dptc_dvfs_addr; | ||
316 | u32 utra_addr; | ||
317 | u32 ram_code_start_addr; | ||
318 | }; | ||
319 | |||
320 | #define SDMA_FIRMWARE_MAGIC 0x414d4453 | 276 | #define SDMA_FIRMWARE_MAGIC 0x414d4453 |
321 | 277 | ||
322 | /** | 278 | /** |
@@ -1127,8 +1083,74 @@ static void sdma_issue_pending(struct dma_chan *chan) | |||
1127 | */ | 1083 | */ |
1128 | } | 1084 | } |
1129 | 1085 | ||
1130 | static int __init sdma_init(struct sdma_engine *sdma, | 1086 | #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 |
1131 | void *ram_code, int ram_code_size) | 1087 | |
1088 | static void sdma_add_scripts(struct sdma_engine *sdma, | ||
1089 | const struct sdma_script_start_addrs *addr) | ||
1090 | { | ||
1091 | s32 *addr_arr = (u32 *)addr; | ||
1092 | s32 *saddr_arr = (u32 *)sdma->script_addrs; | ||
1093 | int i; | ||
1094 | |||
1095 | for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) | ||
1096 | if (addr_arr[i] > 0) | ||
1097 | saddr_arr[i] = addr_arr[i]; | ||
1098 | } | ||
1099 | |||
1100 | static int __init sdma_get_firmware(struct sdma_engine *sdma, | ||
1101 | const char *cpu_name, int to_version) | ||
1102 | { | ||
1103 | const struct firmware *fw; | ||
1104 | char *fwname; | ||
1105 | const struct sdma_firmware_header *header; | ||
1106 | int ret; | ||
1107 | const struct sdma_script_start_addrs *addr; | ||
1108 | unsigned short *ram_code; | ||
1109 | |||
1110 | fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version); | ||
1111 | if (!fwname) | ||
1112 | return -ENOMEM; | ||
1113 | |||
1114 | ret = request_firmware(&fw, fwname, sdma->dev); | ||
1115 | if (ret) { | ||
1116 | kfree(fwname); | ||
1117 | return ret; | ||
1118 | } | ||
1119 | kfree(fwname); | ||
1120 | |||
1121 | if (fw->size < sizeof(*header)) | ||
1122 | goto err_firmware; | ||
1123 | |||
1124 | header = (struct sdma_firmware_header *)fw->data; | ||
1125 | |||
1126 | if (header->magic != SDMA_FIRMWARE_MAGIC) | ||
1127 | goto err_firmware; | ||
1128 | if (header->ram_code_start + header->ram_code_size > fw->size) | ||
1129 | goto err_firmware; | ||
1130 | |||
1131 | addr = (void *)header + header->script_addrs_start; | ||
1132 | ram_code = (void *)header + header->ram_code_start; | ||
1133 | |||
1134 | clk_enable(sdma->clk); | ||
1135 | /* download the RAM image for SDMA */ | ||
1136 | sdma_load_script(sdma, ram_code, | ||
1137 | header->ram_code_size, | ||
1138 | sdma->script_addrs->ram_code_start_addr); | ||
1139 | clk_disable(sdma->clk); | ||
1140 | |||
1141 | sdma_add_scripts(sdma, addr); | ||
1142 | |||
1143 | dev_info(sdma->dev, "loaded firmware %d.%d\n", | ||
1144 | header->version_major, | ||
1145 | header->version_minor); | ||
1146 | |||
1147 | err_firmware: | ||
1148 | release_firmware(fw); | ||
1149 | |||
1150 | return ret; | ||
1151 | } | ||
1152 | |||
1153 | static int __init sdma_init(struct sdma_engine *sdma) | ||
1132 | { | 1154 | { |
1133 | int i, ret; | 1155 | int i, ret; |
1134 | dma_addr_t ccb_phys; | 1156 | dma_addr_t ccb_phys; |
@@ -1192,11 +1214,6 @@ static int __init sdma_init(struct sdma_engine *sdma, | |||
1192 | 1214 | ||
1193 | __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR); | 1215 | __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR); |
1194 | 1216 | ||
1195 | /* download the RAM image for SDMA */ | ||
1196 | sdma_load_script(sdma, ram_code, | ||
1197 | ram_code_size, | ||
1198 | sdma->script_addrs->ram_code_start_addr); | ||
1199 | |||
1200 | /* Set bits of CONFIG register with given context switching mode */ | 1217 | /* Set bits of CONFIG register with given context switching mode */ |
1201 | __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); | 1218 | __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); |
1202 | 1219 | ||
@@ -1216,14 +1233,9 @@ err_dma_alloc: | |||
1216 | static int __init sdma_probe(struct platform_device *pdev) | 1233 | static int __init sdma_probe(struct platform_device *pdev) |
1217 | { | 1234 | { |
1218 | int ret; | 1235 | int ret; |
1219 | const struct firmware *fw; | ||
1220 | const struct sdma_firmware_header *header; | ||
1221 | const struct sdma_script_start_addrs *addr; | ||
1222 | int irq; | 1236 | int irq; |
1223 | unsigned short *ram_code; | ||
1224 | struct resource *iores; | 1237 | struct resource *iores; |
1225 | struct sdma_platform_data *pdata = pdev->dev.platform_data; | 1238 | struct sdma_platform_data *pdata = pdev->dev.platform_data; |
1226 | char *fwname; | ||
1227 | int i; | 1239 | int i; |
1228 | dma_cap_mask_t mask; | 1240 | dma_cap_mask_t mask; |
1229 | struct sdma_engine *sdma; | 1241 | struct sdma_engine *sdma; |
@@ -1262,38 +1274,9 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1262 | if (ret) | 1274 | if (ret) |
1263 | goto err_request_irq; | 1275 | goto err_request_irq; |
1264 | 1276 | ||
1265 | fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", | 1277 | sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); |
1266 | pdata->cpu_name, pdata->to_version); | ||
1267 | if (!fwname) { | ||
1268 | ret = -ENOMEM; | ||
1269 | goto err_cputype; | ||
1270 | } | ||
1271 | |||
1272 | ret = request_firmware(&fw, fwname, &pdev->dev); | ||
1273 | if (ret) { | ||
1274 | dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n", | ||
1275 | fwname, ret); | ||
1276 | kfree(fwname); | ||
1277 | goto err_cputype; | ||
1278 | } | ||
1279 | kfree(fwname); | ||
1280 | |||
1281 | if (fw->size < sizeof(*header)) | ||
1282 | goto err_firmware; | ||
1283 | |||
1284 | header = (struct sdma_firmware_header *)fw->data; | ||
1285 | |||
1286 | if (header->magic != SDMA_FIRMWARE_MAGIC) | ||
1287 | goto err_firmware; | ||
1288 | if (header->ram_code_start + header->ram_code_size > fw->size) | ||
1289 | goto err_firmware; | ||
1290 | |||
1291 | addr = (void *)header + header->script_addrs_start; | ||
1292 | ram_code = (void *)header + header->ram_code_start; | ||
1293 | sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL); | ||
1294 | if (!sdma->script_addrs) | 1278 | if (!sdma->script_addrs) |
1295 | goto err_firmware; | 1279 | goto err_alloc; |
1296 | memcpy(sdma->script_addrs, addr, sizeof(*addr)); | ||
1297 | 1280 | ||
1298 | sdma->version = pdata->sdma_version; | 1281 | sdma->version = pdata->sdma_version; |
1299 | 1282 | ||
@@ -1316,10 +1299,15 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1316 | list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels); | 1299 | list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels); |
1317 | } | 1300 | } |
1318 | 1301 | ||
1319 | ret = sdma_init(sdma, ram_code, header->ram_code_size); | 1302 | ret = sdma_init(sdma); |
1320 | if (ret) | 1303 | if (ret) |
1321 | goto err_init; | 1304 | goto err_init; |
1322 | 1305 | ||
1306 | if (pdata->script_addrs) | ||
1307 | sdma_add_scripts(sdma, pdata->script_addrs); | ||
1308 | |||
1309 | sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version); | ||
1310 | |||
1323 | sdma->dma_device.dev = &pdev->dev; | 1311 | sdma->dma_device.dev = &pdev->dev; |
1324 | 1312 | ||
1325 | sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; | 1313 | sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; |
@@ -1336,10 +1324,6 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1336 | goto err_init; | 1324 | goto err_init; |
1337 | } | 1325 | } |
1338 | 1326 | ||
1339 | dev_info(&pdev->dev, "initialized (firmware %d.%d)\n", | ||
1340 | header->version_major, | ||
1341 | header->version_minor); | ||
1342 | |||
1343 | /* request channel 0. This is an internal control channel | 1327 | /* request channel 0. This is an internal control channel |
1344 | * to the SDMA engine and not available to clients. | 1328 | * to the SDMA engine and not available to clients. |
1345 | */ | 1329 | */ |
@@ -1347,15 +1331,13 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1347 | dma_cap_set(DMA_SLAVE, mask); | 1331 | dma_cap_set(DMA_SLAVE, mask); |
1348 | dma_request_channel(mask, NULL, NULL); | 1332 | dma_request_channel(mask, NULL, NULL); |
1349 | 1333 | ||
1350 | release_firmware(fw); | 1334 | dev_info(sdma->dev, "initialized\n"); |
1351 | 1335 | ||
1352 | return 0; | 1336 | return 0; |
1353 | 1337 | ||
1354 | err_init: | 1338 | err_init: |
1355 | kfree(sdma->script_addrs); | 1339 | kfree(sdma->script_addrs); |
1356 | err_firmware: | 1340 | err_alloc: |
1357 | release_firmware(fw); | ||
1358 | err_cputype: | ||
1359 | free_irq(irq, sdma); | 1341 | free_irq(irq, sdma); |
1360 | err_request_irq: | 1342 | err_request_irq: |
1361 | iounmap(sdma->regs); | 1343 | iounmap(sdma->regs); |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3143ac795eb0..082495bb08a7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -230,11 +230,11 @@ config GPIO_STMPE | |||
230 | This enables support for the GPIOs found on the STMPE I/O | 230 | This enables support for the GPIOs found on the STMPE I/O |
231 | Expanders. | 231 | Expanders. |
232 | 232 | ||
233 | config GPIO_TC35892 | 233 | config GPIO_TC3589X |
234 | bool "TC35892 GPIOs" | 234 | bool "TC3589X GPIOs" |
235 | depends on MFD_TC35892 | 235 | depends on MFD_TC3589X |
236 | help | 236 | help |
237 | This enables support for the GPIOs found on the TC35892 | 237 | This enables support for the GPIOs found on the TC3589X |
238 | I/O Expander. | 238 | I/O Expander. |
239 | 239 | ||
240 | config GPIO_TWL4030 | 240 | config GPIO_TWL4030 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bdf3ddec0652..39bfd7a37650 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o | |||
24 | obj-$(CONFIG_GPIO_PCH) += pch_gpio.o | 24 | obj-$(CONFIG_GPIO_PCH) += pch_gpio.o |
25 | obj-$(CONFIG_GPIO_PL061) += pl061.o | 25 | obj-$(CONFIG_GPIO_PL061) += pl061.o |
26 | obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o | 26 | obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o |
27 | obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o | 27 | obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o |
28 | obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o | 28 | obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o |
29 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o | 29 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o |
30 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o | 30 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o |
diff --git a/drivers/gpio/tc35892-gpio.c b/drivers/gpio/tc35892-gpio.c deleted file mode 100644 index 7e10c935a047..000000000000 --- a/drivers/gpio/tc35892-gpio.c +++ /dev/null | |||
@@ -1,389 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/mfd/tc35892.h> | ||
17 | |||
18 | /* | ||
19 | * These registers are modified under the irq bus lock and cached to avoid | ||
20 | * unnecessary writes in bus_sync_unlock. | ||
21 | */ | ||
22 | enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; | ||
23 | |||
24 | #define CACHE_NR_REGS 4 | ||
25 | #define CACHE_NR_BANKS 3 | ||
26 | |||
27 | struct tc35892_gpio { | ||
28 | struct gpio_chip chip; | ||
29 | struct tc35892 *tc35892; | ||
30 | struct device *dev; | ||
31 | struct mutex irq_lock; | ||
32 | |||
33 | int irq_base; | ||
34 | |||
35 | /* Caches of interrupt control registers for bus_lock */ | ||
36 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
37 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
38 | }; | ||
39 | |||
40 | static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip) | ||
41 | { | ||
42 | return container_of(chip, struct tc35892_gpio, chip); | ||
43 | } | ||
44 | |||
45 | static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
46 | { | ||
47 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
48 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
49 | u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; | ||
50 | u8 mask = 1 << (offset % 8); | ||
51 | int ret; | ||
52 | |||
53 | ret = tc35892_reg_read(tc35892, reg); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | |||
57 | return ret & mask; | ||
58 | } | ||
59 | |||
60 | static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
61 | { | ||
62 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
63 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
64 | u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; | ||
65 | unsigned pos = offset % 8; | ||
66 | u8 data[] = {!!val << pos, 1 << pos}; | ||
67 | |||
68 | tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data); | ||
69 | } | ||
70 | |||
71 | static int tc35892_gpio_direction_output(struct gpio_chip *chip, | ||
72 | unsigned offset, int val) | ||
73 | { | ||
74 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
75 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
76 | u8 reg = TC35892_GPIODIR0 + offset / 8; | ||
77 | unsigned pos = offset % 8; | ||
78 | |||
79 | tc35892_gpio_set(chip, offset, val); | ||
80 | |||
81 | return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos); | ||
82 | } | ||
83 | |||
84 | static int tc35892_gpio_direction_input(struct gpio_chip *chip, | ||
85 | unsigned offset) | ||
86 | { | ||
87 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
88 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
89 | u8 reg = TC35892_GPIODIR0 + offset / 8; | ||
90 | unsigned pos = offset % 8; | ||
91 | |||
92 | return tc35892_set_bits(tc35892, reg, 1 << pos, 0); | ||
93 | } | ||
94 | |||
95 | static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
96 | { | ||
97 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
98 | |||
99 | return tc35892_gpio->irq_base + offset; | ||
100 | } | ||
101 | |||
102 | static struct gpio_chip template_chip = { | ||
103 | .label = "tc35892", | ||
104 | .owner = THIS_MODULE, | ||
105 | .direction_input = tc35892_gpio_direction_input, | ||
106 | .get = tc35892_gpio_get, | ||
107 | .direction_output = tc35892_gpio_direction_output, | ||
108 | .set = tc35892_gpio_set, | ||
109 | .to_irq = tc35892_gpio_to_irq, | ||
110 | .can_sleep = 1, | ||
111 | }; | ||
112 | |||
113 | static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
114 | { | ||
115 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
116 | int offset = irq - tc35892_gpio->irq_base; | ||
117 | int regoffset = offset / 8; | ||
118 | int mask = 1 << (offset % 8); | ||
119 | |||
120 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
121 | tc35892_gpio->regs[REG_IBE][regoffset] |= mask; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask; | ||
126 | |||
127 | if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) | ||
128 | tc35892_gpio->regs[REG_IS][regoffset] |= mask; | ||
129 | else | ||
130 | tc35892_gpio->regs[REG_IS][regoffset] &= ~mask; | ||
131 | |||
132 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) | ||
133 | tc35892_gpio->regs[REG_IEV][regoffset] |= mask; | ||
134 | else | ||
135 | tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static void tc35892_gpio_irq_lock(unsigned int irq) | ||
141 | { | ||
142 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
143 | |||
144 | mutex_lock(&tc35892_gpio->irq_lock); | ||
145 | } | ||
146 | |||
147 | static void tc35892_gpio_irq_sync_unlock(unsigned int irq) | ||
148 | { | ||
149 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
150 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
151 | static const u8 regmap[] = { | ||
152 | [REG_IBE] = TC35892_GPIOIBE0, | ||
153 | [REG_IEV] = TC35892_GPIOIEV0, | ||
154 | [REG_IS] = TC35892_GPIOIS0, | ||
155 | [REG_IE] = TC35892_GPIOIE0, | ||
156 | }; | ||
157 | int i, j; | ||
158 | |||
159 | for (i = 0; i < CACHE_NR_REGS; i++) { | ||
160 | for (j = 0; j < CACHE_NR_BANKS; j++) { | ||
161 | u8 old = tc35892_gpio->oldregs[i][j]; | ||
162 | u8 new = tc35892_gpio->regs[i][j]; | ||
163 | |||
164 | if (new == old) | ||
165 | continue; | ||
166 | |||
167 | tc35892_gpio->oldregs[i][j] = new; | ||
168 | tc35892_reg_write(tc35892, regmap[i] + j * 8, new); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | mutex_unlock(&tc35892_gpio->irq_lock); | ||
173 | } | ||
174 | |||
175 | static void tc35892_gpio_irq_mask(unsigned int irq) | ||
176 | { | ||
177 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
178 | int offset = irq - tc35892_gpio->irq_base; | ||
179 | int regoffset = offset / 8; | ||
180 | int mask = 1 << (offset % 8); | ||
181 | |||
182 | tc35892_gpio->regs[REG_IE][regoffset] &= ~mask; | ||
183 | } | ||
184 | |||
185 | static void tc35892_gpio_irq_unmask(unsigned int irq) | ||
186 | { | ||
187 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
188 | int offset = irq - tc35892_gpio->irq_base; | ||
189 | int regoffset = offset / 8; | ||
190 | int mask = 1 << (offset % 8); | ||
191 | |||
192 | tc35892_gpio->regs[REG_IE][regoffset] |= mask; | ||
193 | } | ||
194 | |||
195 | static struct irq_chip tc35892_gpio_irq_chip = { | ||
196 | .name = "tc35892-gpio", | ||
197 | .bus_lock = tc35892_gpio_irq_lock, | ||
198 | .bus_sync_unlock = tc35892_gpio_irq_sync_unlock, | ||
199 | .mask = tc35892_gpio_irq_mask, | ||
200 | .unmask = tc35892_gpio_irq_unmask, | ||
201 | .set_type = tc35892_gpio_irq_set_type, | ||
202 | }; | ||
203 | |||
204 | static irqreturn_t tc35892_gpio_irq(int irq, void *dev) | ||
205 | { | ||
206 | struct tc35892_gpio *tc35892_gpio = dev; | ||
207 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
208 | u8 status[CACHE_NR_BANKS]; | ||
209 | int ret; | ||
210 | int i; | ||
211 | |||
212 | ret = tc35892_block_read(tc35892, TC35892_GPIOMIS0, | ||
213 | ARRAY_SIZE(status), status); | ||
214 | if (ret < 0) | ||
215 | return IRQ_NONE; | ||
216 | |||
217 | for (i = 0; i < ARRAY_SIZE(status); i++) { | ||
218 | unsigned int stat = status[i]; | ||
219 | if (!stat) | ||
220 | continue; | ||
221 | |||
222 | while (stat) { | ||
223 | int bit = __ffs(stat); | ||
224 | int line = i * 8 + bit; | ||
225 | |||
226 | handle_nested_irq(tc35892_gpio->irq_base + line); | ||
227 | stat &= ~(1 << bit); | ||
228 | } | ||
229 | |||
230 | tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]); | ||
231 | } | ||
232 | |||
233 | return IRQ_HANDLED; | ||
234 | } | ||
235 | |||
236 | static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio) | ||
237 | { | ||
238 | int base = tc35892_gpio->irq_base; | ||
239 | int irq; | ||
240 | |||
241 | for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { | ||
242 | set_irq_chip_data(irq, tc35892_gpio); | ||
243 | set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip, | ||
244 | handle_simple_irq); | ||
245 | set_irq_nested_thread(irq, 1); | ||
246 | #ifdef CONFIG_ARM | ||
247 | set_irq_flags(irq, IRQF_VALID); | ||
248 | #else | ||
249 | set_irq_noprobe(irq); | ||
250 | #endif | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static void tc35892_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio) | ||
257 | { | ||
258 | int base = tc35892_gpio->irq_base; | ||
259 | int irq; | ||
260 | |||
261 | for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { | ||
262 | #ifdef CONFIG_ARM | ||
263 | set_irq_flags(irq, 0); | ||
264 | #endif | ||
265 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
266 | set_irq_chip_data(irq, NULL); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | static int __devinit tc35892_gpio_probe(struct platform_device *pdev) | ||
271 | { | ||
272 | struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent); | ||
273 | struct tc35892_gpio_platform_data *pdata; | ||
274 | struct tc35892_gpio *tc35892_gpio; | ||
275 | int ret; | ||
276 | int irq; | ||
277 | |||
278 | pdata = tc35892->pdata->gpio; | ||
279 | if (!pdata) | ||
280 | return -ENODEV; | ||
281 | |||
282 | irq = platform_get_irq(pdev, 0); | ||
283 | if (irq < 0) | ||
284 | return irq; | ||
285 | |||
286 | tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL); | ||
287 | if (!tc35892_gpio) | ||
288 | return -ENOMEM; | ||
289 | |||
290 | mutex_init(&tc35892_gpio->irq_lock); | ||
291 | |||
292 | tc35892_gpio->dev = &pdev->dev; | ||
293 | tc35892_gpio->tc35892 = tc35892; | ||
294 | |||
295 | tc35892_gpio->chip = template_chip; | ||
296 | tc35892_gpio->chip.ngpio = tc35892->num_gpio; | ||
297 | tc35892_gpio->chip.dev = &pdev->dev; | ||
298 | tc35892_gpio->chip.base = pdata->gpio_base; | ||
299 | |||
300 | tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0); | ||
301 | |||
302 | /* Bring the GPIO module out of reset */ | ||
303 | ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL, | ||
304 | TC35892_RSTCTRL_GPIRST, 0); | ||
305 | if (ret < 0) | ||
306 | goto out_free; | ||
307 | |||
308 | ret = tc35892_gpio_irq_init(tc35892_gpio); | ||
309 | if (ret) | ||
310 | goto out_free; | ||
311 | |||
312 | ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT, | ||
313 | "tc35892-gpio", tc35892_gpio); | ||
314 | if (ret) { | ||
315 | dev_err(&pdev->dev, "unable to get irq: %d\n", ret); | ||
316 | goto out_removeirq; | ||
317 | } | ||
318 | |||
319 | ret = gpiochip_add(&tc35892_gpio->chip); | ||
320 | if (ret) { | ||
321 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); | ||
322 | goto out_freeirq; | ||
323 | } | ||
324 | |||
325 | if (pdata->setup) | ||
326 | pdata->setup(tc35892, tc35892_gpio->chip.base); | ||
327 | |||
328 | platform_set_drvdata(pdev, tc35892_gpio); | ||
329 | |||
330 | return 0; | ||
331 | |||
332 | out_freeirq: | ||
333 | free_irq(irq, tc35892_gpio); | ||
334 | out_removeirq: | ||
335 | tc35892_gpio_irq_remove(tc35892_gpio); | ||
336 | out_free: | ||
337 | kfree(tc35892_gpio); | ||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static int __devexit tc35892_gpio_remove(struct platform_device *pdev) | ||
342 | { | ||
343 | struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev); | ||
344 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
345 | struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio; | ||
346 | int irq = platform_get_irq(pdev, 0); | ||
347 | int ret; | ||
348 | |||
349 | if (pdata->remove) | ||
350 | pdata->remove(tc35892, tc35892_gpio->chip.base); | ||
351 | |||
352 | ret = gpiochip_remove(&tc35892_gpio->chip); | ||
353 | if (ret < 0) { | ||
354 | dev_err(tc35892_gpio->dev, | ||
355 | "unable to remove gpiochip: %d\n", ret); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | free_irq(irq, tc35892_gpio); | ||
360 | tc35892_gpio_irq_remove(tc35892_gpio); | ||
361 | |||
362 | platform_set_drvdata(pdev, NULL); | ||
363 | kfree(tc35892_gpio); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static struct platform_driver tc35892_gpio_driver = { | ||
369 | .driver.name = "tc35892-gpio", | ||
370 | .driver.owner = THIS_MODULE, | ||
371 | .probe = tc35892_gpio_probe, | ||
372 | .remove = __devexit_p(tc35892_gpio_remove), | ||
373 | }; | ||
374 | |||
375 | static int __init tc35892_gpio_init(void) | ||
376 | { | ||
377 | return platform_driver_register(&tc35892_gpio_driver); | ||
378 | } | ||
379 | subsys_initcall(tc35892_gpio_init); | ||
380 | |||
381 | static void __exit tc35892_gpio_exit(void) | ||
382 | { | ||
383 | platform_driver_unregister(&tc35892_gpio_driver); | ||
384 | } | ||
385 | module_exit(tc35892_gpio_exit); | ||
386 | |||
387 | MODULE_LICENSE("GPL v2"); | ||
388 | MODULE_DESCRIPTION("TC35892 GPIO driver"); | ||
389 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c new file mode 100644 index 000000000000..180d584454fb --- /dev/null +++ b/drivers/gpio/tc3589x-gpio.c | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/mfd/tc3589x.h> | ||
17 | |||
18 | /* | ||
19 | * These registers are modified under the irq bus lock and cached to avoid | ||
20 | * unnecessary writes in bus_sync_unlock. | ||
21 | */ | ||
22 | enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; | ||
23 | |||
24 | #define CACHE_NR_REGS 4 | ||
25 | #define CACHE_NR_BANKS 3 | ||
26 | |||
27 | struct tc3589x_gpio { | ||
28 | struct gpio_chip chip; | ||
29 | struct tc3589x *tc3589x; | ||
30 | struct device *dev; | ||
31 | struct mutex irq_lock; | ||
32 | |||
33 | int irq_base; | ||
34 | |||
35 | /* Caches of interrupt control registers for bus_lock */ | ||
36 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
37 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
38 | }; | ||
39 | |||
40 | static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip) | ||
41 | { | ||
42 | return container_of(chip, struct tc3589x_gpio, chip); | ||
43 | } | ||
44 | |||
45 | static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
46 | { | ||
47 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
48 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
49 | u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; | ||
50 | u8 mask = 1 << (offset % 8); | ||
51 | int ret; | ||
52 | |||
53 | ret = tc3589x_reg_read(tc3589x, reg); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | |||
57 | return ret & mask; | ||
58 | } | ||
59 | |||
60 | static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
61 | { | ||
62 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
63 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
64 | u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; | ||
65 | unsigned pos = offset % 8; | ||
66 | u8 data[] = {!!val << pos, 1 << pos}; | ||
67 | |||
68 | tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data); | ||
69 | } | ||
70 | |||
71 | static int tc3589x_gpio_direction_output(struct gpio_chip *chip, | ||
72 | unsigned offset, int val) | ||
73 | { | ||
74 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
75 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
76 | u8 reg = TC3589x_GPIODIR0 + offset / 8; | ||
77 | unsigned pos = offset % 8; | ||
78 | |||
79 | tc3589x_gpio_set(chip, offset, val); | ||
80 | |||
81 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos); | ||
82 | } | ||
83 | |||
84 | static int tc3589x_gpio_direction_input(struct gpio_chip *chip, | ||
85 | unsigned offset) | ||
86 | { | ||
87 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
88 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
89 | u8 reg = TC3589x_GPIODIR0 + offset / 8; | ||
90 | unsigned pos = offset % 8; | ||
91 | |||
92 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); | ||
93 | } | ||
94 | |||
95 | static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
96 | { | ||
97 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
98 | |||
99 | return tc3589x_gpio->irq_base + offset; | ||
100 | } | ||
101 | |||
102 | static struct gpio_chip template_chip = { | ||
103 | .label = "tc3589x", | ||
104 | .owner = THIS_MODULE, | ||
105 | .direction_input = tc3589x_gpio_direction_input, | ||
106 | .get = tc3589x_gpio_get, | ||
107 | .direction_output = tc3589x_gpio_direction_output, | ||
108 | .set = tc3589x_gpio_set, | ||
109 | .to_irq = tc3589x_gpio_to_irq, | ||
110 | .can_sleep = 1, | ||
111 | }; | ||
112 | |||
113 | static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
114 | { | ||
115 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
116 | int offset = irq - tc3589x_gpio->irq_base; | ||
117 | int regoffset = offset / 8; | ||
118 | int mask = 1 << (offset % 8); | ||
119 | |||
120 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
121 | tc3589x_gpio->regs[REG_IBE][regoffset] |= mask; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask; | ||
126 | |||
127 | if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) | ||
128 | tc3589x_gpio->regs[REG_IS][regoffset] |= mask; | ||
129 | else | ||
130 | tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask; | ||
131 | |||
132 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) | ||
133 | tc3589x_gpio->regs[REG_IEV][regoffset] |= mask; | ||
134 | else | ||
135 | tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static void tc3589x_gpio_irq_lock(unsigned int irq) | ||
141 | { | ||
142 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
143 | |||
144 | mutex_lock(&tc3589x_gpio->irq_lock); | ||
145 | } | ||
146 | |||
147 | static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) | ||
148 | { | ||
149 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
150 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
151 | static const u8 regmap[] = { | ||
152 | [REG_IBE] = TC3589x_GPIOIBE0, | ||
153 | [REG_IEV] = TC3589x_GPIOIEV0, | ||
154 | [REG_IS] = TC3589x_GPIOIS0, | ||
155 | [REG_IE] = TC3589x_GPIOIE0, | ||
156 | }; | ||
157 | int i, j; | ||
158 | |||
159 | for (i = 0; i < CACHE_NR_REGS; i++) { | ||
160 | for (j = 0; j < CACHE_NR_BANKS; j++) { | ||
161 | u8 old = tc3589x_gpio->oldregs[i][j]; | ||
162 | u8 new = tc3589x_gpio->regs[i][j]; | ||
163 | |||
164 | if (new == old) | ||
165 | continue; | ||
166 | |||
167 | tc3589x_gpio->oldregs[i][j] = new; | ||
168 | tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | mutex_unlock(&tc3589x_gpio->irq_lock); | ||
173 | } | ||
174 | |||
175 | static void tc3589x_gpio_irq_mask(unsigned int irq) | ||
176 | { | ||
177 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
178 | int offset = irq - tc3589x_gpio->irq_base; | ||
179 | int regoffset = offset / 8; | ||
180 | int mask = 1 << (offset % 8); | ||
181 | |||
182 | tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; | ||
183 | } | ||
184 | |||
185 | static void tc3589x_gpio_irq_unmask(unsigned int irq) | ||
186 | { | ||
187 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
188 | int offset = irq - tc3589x_gpio->irq_base; | ||
189 | int regoffset = offset / 8; | ||
190 | int mask = 1 << (offset % 8); | ||
191 | |||
192 | tc3589x_gpio->regs[REG_IE][regoffset] |= mask; | ||
193 | } | ||
194 | |||
195 | static struct irq_chip tc3589x_gpio_irq_chip = { | ||
196 | .name = "tc3589x-gpio", | ||
197 | .bus_lock = tc3589x_gpio_irq_lock, | ||
198 | .bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, | ||
199 | .mask = tc3589x_gpio_irq_mask, | ||
200 | .unmask = tc3589x_gpio_irq_unmask, | ||
201 | .set_type = tc3589x_gpio_irq_set_type, | ||
202 | }; | ||
203 | |||
204 | static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) | ||
205 | { | ||
206 | struct tc3589x_gpio *tc3589x_gpio = dev; | ||
207 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
208 | u8 status[CACHE_NR_BANKS]; | ||
209 | int ret; | ||
210 | int i; | ||
211 | |||
212 | ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0, | ||
213 | ARRAY_SIZE(status), status); | ||
214 | if (ret < 0) | ||
215 | return IRQ_NONE; | ||
216 | |||
217 | for (i = 0; i < ARRAY_SIZE(status); i++) { | ||
218 | unsigned int stat = status[i]; | ||
219 | if (!stat) | ||
220 | continue; | ||
221 | |||
222 | while (stat) { | ||
223 | int bit = __ffs(stat); | ||
224 | int line = i * 8 + bit; | ||
225 | |||
226 | handle_nested_irq(tc3589x_gpio->irq_base + line); | ||
227 | stat &= ~(1 << bit); | ||
228 | } | ||
229 | |||
230 | tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]); | ||
231 | } | ||
232 | |||
233 | return IRQ_HANDLED; | ||
234 | } | ||
235 | |||
236 | static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) | ||
237 | { | ||
238 | int base = tc3589x_gpio->irq_base; | ||
239 | int irq; | ||
240 | |||
241 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { | ||
242 | set_irq_chip_data(irq, tc3589x_gpio); | ||
243 | set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip, | ||
244 | handle_simple_irq); | ||
245 | set_irq_nested_thread(irq, 1); | ||
246 | #ifdef CONFIG_ARM | ||
247 | set_irq_flags(irq, IRQF_VALID); | ||
248 | #else | ||
249 | set_irq_noprobe(irq); | ||
250 | #endif | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) | ||
257 | { | ||
258 | int base = tc3589x_gpio->irq_base; | ||
259 | int irq; | ||
260 | |||
261 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { | ||
262 | #ifdef CONFIG_ARM | ||
263 | set_irq_flags(irq, 0); | ||
264 | #endif | ||
265 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
266 | set_irq_chip_data(irq, NULL); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) | ||
271 | { | ||
272 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | ||
273 | struct tc3589x_gpio_platform_data *pdata; | ||
274 | struct tc3589x_gpio *tc3589x_gpio; | ||
275 | int ret; | ||
276 | int irq; | ||
277 | |||
278 | pdata = tc3589x->pdata->gpio; | ||
279 | if (!pdata) | ||
280 | return -ENODEV; | ||
281 | |||
282 | irq = platform_get_irq(pdev, 0); | ||
283 | if (irq < 0) | ||
284 | return irq; | ||
285 | |||
286 | tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); | ||
287 | if (!tc3589x_gpio) | ||
288 | return -ENOMEM; | ||
289 | |||
290 | mutex_init(&tc3589x_gpio->irq_lock); | ||
291 | |||
292 | tc3589x_gpio->dev = &pdev->dev; | ||
293 | tc3589x_gpio->tc3589x = tc3589x; | ||
294 | |||
295 | tc3589x_gpio->chip = template_chip; | ||
296 | tc3589x_gpio->chip.ngpio = tc3589x->num_gpio; | ||
297 | tc3589x_gpio->chip.dev = &pdev->dev; | ||
298 | tc3589x_gpio->chip.base = pdata->gpio_base; | ||
299 | |||
300 | tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); | ||
301 | |||
302 | /* Bring the GPIO module out of reset */ | ||
303 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, | ||
304 | TC3589x_RSTCTRL_GPIRST, 0); | ||
305 | if (ret < 0) | ||
306 | goto out_free; | ||
307 | |||
308 | ret = tc3589x_gpio_irq_init(tc3589x_gpio); | ||
309 | if (ret) | ||
310 | goto out_free; | ||
311 | |||
312 | ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, | ||
313 | "tc3589x-gpio", tc3589x_gpio); | ||
314 | if (ret) { | ||
315 | dev_err(&pdev->dev, "unable to get irq: %d\n", ret); | ||
316 | goto out_removeirq; | ||
317 | } | ||
318 | |||
319 | ret = gpiochip_add(&tc3589x_gpio->chip); | ||
320 | if (ret) { | ||
321 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); | ||
322 | goto out_freeirq; | ||
323 | } | ||
324 | |||
325 | if (pdata->setup) | ||
326 | pdata->setup(tc3589x, tc3589x_gpio->chip.base); | ||
327 | |||
328 | platform_set_drvdata(pdev, tc3589x_gpio); | ||
329 | |||
330 | return 0; | ||
331 | |||
332 | out_freeirq: | ||
333 | free_irq(irq, tc3589x_gpio); | ||
334 | out_removeirq: | ||
335 | tc3589x_gpio_irq_remove(tc3589x_gpio); | ||
336 | out_free: | ||
337 | kfree(tc3589x_gpio); | ||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) | ||
342 | { | ||
343 | struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); | ||
344 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
345 | struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; | ||
346 | int irq = platform_get_irq(pdev, 0); | ||
347 | int ret; | ||
348 | |||
349 | if (pdata->remove) | ||
350 | pdata->remove(tc3589x, tc3589x_gpio->chip.base); | ||
351 | |||
352 | ret = gpiochip_remove(&tc3589x_gpio->chip); | ||
353 | if (ret < 0) { | ||
354 | dev_err(tc3589x_gpio->dev, | ||
355 | "unable to remove gpiochip: %d\n", ret); | ||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | free_irq(irq, tc3589x_gpio); | ||
360 | tc3589x_gpio_irq_remove(tc3589x_gpio); | ||
361 | |||
362 | platform_set_drvdata(pdev, NULL); | ||
363 | kfree(tc3589x_gpio); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static struct platform_driver tc3589x_gpio_driver = { | ||
369 | .driver.name = "tc3589x-gpio", | ||
370 | .driver.owner = THIS_MODULE, | ||
371 | .probe = tc3589x_gpio_probe, | ||
372 | .remove = __devexit_p(tc3589x_gpio_remove), | ||
373 | }; | ||
374 | |||
375 | static int __init tc3589x_gpio_init(void) | ||
376 | { | ||
377 | return platform_driver_register(&tc3589x_gpio_driver); | ||
378 | } | ||
379 | subsys_initcall(tc3589x_gpio_init); | ||
380 | |||
381 | static void __exit tc3589x_gpio_exit(void) | ||
382 | { | ||
383 | platform_driver_unregister(&tc3589x_gpio_driver); | ||
384 | } | ||
385 | module_exit(tc3589x_gpio_exit); | ||
386 | |||
387 | MODULE_LICENSE("GPL v2"); | ||
388 | MODULE_DESCRIPTION("TC3589x GPIO driver"); | ||
389 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 3a87f3ba5f75..c76bd3183beb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -459,6 +459,16 @@ config KEYBOARD_OMAP4 | |||
459 | To compile this driver as a module, choose M here: the | 459 | To compile this driver as a module, choose M here: the |
460 | module will be called omap4-keypad. | 460 | module will be called omap4-keypad. |
461 | 461 | ||
462 | config KEYBOARD_TC3589X | ||
463 | tristate "TC3589X Keypad support" | ||
464 | depends on MFD_TC3589X | ||
465 | help | ||
466 | Say Y here if you want to use the keypad controller on | ||
467 | TC35892/3 I/O expander. | ||
468 | |||
469 | To compile this driver as a module, choose M here: the | ||
470 | module will be called tc3589x-keypad. | ||
471 | |||
462 | config KEYBOARD_TNETV107X | 472 | config KEYBOARD_TNETV107X |
463 | tristate "TI TNETV107X keypad support" | 473 | tristate "TI TNETV107X keypad support" |
464 | depends on ARCH_DAVINCI_TNETV107X | 474 | depends on ARCH_DAVINCI_TNETV107X |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 622de73a445d..2aa6ce248b71 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -41,6 +41,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | |||
41 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 41 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
42 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 42 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
43 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | 43 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o |
44 | obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o | ||
44 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o | 45 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o |
45 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o | 46 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o |
46 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | 47 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o |
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c new file mode 100644 index 000000000000..69dc0cb20a00 --- /dev/null +++ b/drivers/input/keyboard/tc3589x-keypad.c | |||
@@ -0,0 +1,472 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> | ||
5 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
6 | * | ||
7 | * License Terms: GNU General Public License, version 2 | ||
8 | * | ||
9 | * TC35893 MFD Keypad Controller driver | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/input/matrix_keypad.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/mfd/tc3589x.h> | ||
21 | |||
22 | /* Maximum supported keypad matrix row/columns size */ | ||
23 | #define TC3589x_MAX_KPROW 8 | ||
24 | #define TC3589x_MAX_KPCOL 12 | ||
25 | |||
26 | /* keypad related Constants */ | ||
27 | #define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF | ||
28 | #define DEDICATED_KEY_VAL 0xFF | ||
29 | |||
30 | /* Pull up/down masks */ | ||
31 | #define TC3589x_NO_PULL_MASK 0x0 | ||
32 | #define TC3589x_PULL_DOWN_MASK 0x1 | ||
33 | #define TC3589x_PULL_UP_MASK 0x2 | ||
34 | #define TC3589x_PULLUP_ALL_MASK 0xAA | ||
35 | #define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)) | ||
36 | |||
37 | /* Bit masks for IOCFG register */ | ||
38 | #define IOCFG_BALLCFG 0x01 | ||
39 | #define IOCFG_IG 0x08 | ||
40 | |||
41 | #define KP_EVCODE_COL_MASK 0x0F | ||
42 | #define KP_EVCODE_ROW_MASK 0x70 | ||
43 | #define KP_RELEASE_EVT_MASK 0x80 | ||
44 | |||
45 | #define KP_ROW_SHIFT 4 | ||
46 | |||
47 | #define KP_NO_VALID_KEY_MASK 0x7F | ||
48 | |||
49 | /* bit masks for RESTCTRL register */ | ||
50 | #define TC3589x_KBDRST 0x2 | ||
51 | #define TC3589x_IRQRST 0x10 | ||
52 | #define TC3589x_RESET_ALL 0x1B | ||
53 | |||
54 | /* KBDMFS register bit mask */ | ||
55 | #define TC3589x_KBDMFS_EN 0x1 | ||
56 | |||
57 | /* CLKEN register bitmask */ | ||
58 | #define KPD_CLK_EN 0x1 | ||
59 | |||
60 | /* RSTINTCLR register bit mask */ | ||
61 | #define IRQ_CLEAR 0x1 | ||
62 | |||
63 | /* bit masks for keyboard interrupts*/ | ||
64 | #define TC3589x_EVT_LOSS_INT 0x8 | ||
65 | #define TC3589x_EVT_INT 0x4 | ||
66 | #define TC3589x_KBD_LOSS_INT 0x2 | ||
67 | #define TC3589x_KBD_INT 0x1 | ||
68 | |||
69 | /* bit masks for keyboard interrupt clear*/ | ||
70 | #define TC3589x_EVT_INT_CLR 0x2 | ||
71 | #define TC3589x_KBD_INT_CLR 0x1 | ||
72 | |||
73 | #define TC3589x_KBD_KEYMAP_SIZE 64 | ||
74 | |||
75 | /** | ||
76 | * struct tc_keypad - data structure used by keypad driver | ||
77 | * @input: pointer to input device object | ||
78 | * @board: keypad platform device | ||
79 | * @krow: number of rows | ||
80 | * @kcol: number of coloumns | ||
81 | * @keymap: matrix scan code table for keycodes | ||
82 | */ | ||
83 | struct tc_keypad { | ||
84 | struct tc3589x *tc3589x; | ||
85 | struct input_dev *input; | ||
86 | const struct tc3589x_keypad_platform_data *board; | ||
87 | unsigned int krow; | ||
88 | unsigned int kcol; | ||
89 | unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE]; | ||
90 | bool keypad_stopped; | ||
91 | }; | ||
92 | |||
93 | static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) | ||
94 | { | ||
95 | int ret; | ||
96 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
97 | u8 settle_time = keypad->board->settle_time; | ||
98 | u8 dbounce_period = keypad->board->debounce_period; | ||
99 | u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */ | ||
100 | u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */ | ||
101 | |||
102 | /* validate platform configurations */ | ||
103 | if (keypad->board->kcol > TC3589x_MAX_KPCOL || | ||
104 | keypad->board->krow > TC3589x_MAX_KPROW || | ||
105 | keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE || | ||
106 | keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE) | ||
107 | return -EINVAL; | ||
108 | |||
109 | /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */ | ||
110 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE, | ||
111 | (rows << KP_ROW_SHIFT) | column); | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | /* configure dedicated key config, no dedicated key selected */ | ||
116 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | /* Configure settle time */ | ||
125 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time); | ||
126 | if (ret < 0) | ||
127 | return ret; | ||
128 | |||
129 | /* Configure debounce time */ | ||
130 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | |||
134 | /* Start of initialise keypad GPIOs */ | ||
135 | ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | |||
139 | /* Configure pull-up resistors for all row GPIOs */ | ||
140 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB, | ||
141 | TC3589x_PULLUP_ALL_MASK); | ||
142 | if (ret < 0) | ||
143 | return ret; | ||
144 | |||
145 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB, | ||
146 | TC3589x_PULLUP_ALL_MASK); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | /* Configure pull-up resistors for all column GPIOs */ | ||
151 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB, | ||
152 | TC3589x_PULLUP_ALL_MASK); | ||
153 | if (ret < 0) | ||
154 | return ret; | ||
155 | |||
156 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB, | ||
157 | TC3589x_PULLUP_ALL_MASK); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | |||
161 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB, | ||
162 | TC3589x_PULLUP_ALL_MASK); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | #define TC35893_DATA_REGS 4 | ||
168 | #define TC35893_KEYCODE_FIFO_EMPTY 0x7f | ||
169 | #define TC35893_KEYCODE_FIFO_CLEAR 0xff | ||
170 | #define TC35893_KEYPAD_ROW_SHIFT 0x3 | ||
171 | |||
172 | static irqreturn_t tc3589x_keypad_irq(int irq, void *dev) | ||
173 | { | ||
174 | struct tc_keypad *keypad = dev; | ||
175 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
176 | u8 i, row_index, col_index, kbd_code, up; | ||
177 | u8 code; | ||
178 | |||
179 | for (i = 0; i < TC35893_DATA_REGS * 2; i++) { | ||
180 | kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO); | ||
181 | |||
182 | /* loop till fifo is empty and no more keys are pressed */ | ||
183 | if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY || | ||
184 | kbd_code == TC35893_KEYCODE_FIFO_CLEAR) | ||
185 | continue; | ||
186 | |||
187 | /* valid key is found */ | ||
188 | col_index = kbd_code & KP_EVCODE_COL_MASK; | ||
189 | row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT; | ||
190 | code = MATRIX_SCAN_CODE(row_index, col_index, | ||
191 | TC35893_KEYPAD_ROW_SHIFT); | ||
192 | up = kbd_code & KP_RELEASE_EVT_MASK; | ||
193 | |||
194 | input_event(keypad->input, EV_MSC, MSC_SCAN, code); | ||
195 | input_report_key(keypad->input, keypad->keymap[code], !up); | ||
196 | input_sync(keypad->input); | ||
197 | } | ||
198 | |||
199 | /* clear IRQ */ | ||
200 | tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
201 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
202 | /* enable IRQ */ | ||
203 | tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
204 | 0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
205 | |||
206 | return IRQ_HANDLED; | ||
207 | } | ||
208 | |||
209 | static int tc3589x_keypad_enable(struct tc_keypad *keypad) | ||
210 | { | ||
211 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
212 | int ret; | ||
213 | |||
214 | /* pull the keypad module out of reset */ | ||
215 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | |||
219 | /* configure KBDMFS */ | ||
220 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN); | ||
221 | if (ret < 0) | ||
222 | return ret; | ||
223 | |||
224 | /* enable the keypad clock */ | ||
225 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN); | ||
226 | if (ret < 0) | ||
227 | return ret; | ||
228 | |||
229 | /* clear pending IRQs */ | ||
230 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | |||
234 | /* enable the IRQs */ | ||
235 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0, | ||
236 | TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
237 | if (ret < 0) | ||
238 | return ret; | ||
239 | |||
240 | keypad->keypad_stopped = false; | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int tc3589x_keypad_disable(struct tc_keypad *keypad) | ||
246 | { | ||
247 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
248 | int ret; | ||
249 | |||
250 | /* clear IRQ */ | ||
251 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
252 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
253 | if (ret < 0) | ||
254 | return ret; | ||
255 | |||
256 | /* disable all interrupts */ | ||
257 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
258 | ~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0); | ||
259 | if (ret < 0) | ||
260 | return ret; | ||
261 | |||
262 | /* disable the keypad module */ | ||
263 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | /* put the keypad module into reset */ | ||
268 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1); | ||
269 | |||
270 | keypad->keypad_stopped = true; | ||
271 | |||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static int tc3589x_keypad_open(struct input_dev *input) | ||
276 | { | ||
277 | int error; | ||
278 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
279 | |||
280 | /* enable the keypad module */ | ||
281 | error = tc3589x_keypad_enable(keypad); | ||
282 | if (error < 0) { | ||
283 | dev_err(&input->dev, "failed to enable keypad module\n"); | ||
284 | return error; | ||
285 | } | ||
286 | |||
287 | error = tc3589x_keypad_init_key_hardware(keypad); | ||
288 | if (error < 0) { | ||
289 | dev_err(&input->dev, "failed to configure keypad module\n"); | ||
290 | return error; | ||
291 | } | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static void tc3589x_keypad_close(struct input_dev *input) | ||
297 | { | ||
298 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
299 | |||
300 | /* disable the keypad module */ | ||
301 | tc3589x_keypad_disable(keypad); | ||
302 | } | ||
303 | |||
304 | static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) | ||
305 | { | ||
306 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | ||
307 | struct tc_keypad *keypad; | ||
308 | struct input_dev *input; | ||
309 | const struct tc3589x_keypad_platform_data *plat; | ||
310 | int error, irq; | ||
311 | |||
312 | plat = tc3589x->pdata->keypad; | ||
313 | if (!plat) { | ||
314 | dev_err(&pdev->dev, "invalid keypad platform data\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | irq = platform_get_irq(pdev, 0); | ||
319 | if (irq < 0) | ||
320 | return irq; | ||
321 | |||
322 | keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); | ||
323 | input = input_allocate_device(); | ||
324 | if (!keypad || !input) { | ||
325 | dev_err(&pdev->dev, "failed to allocate keypad memory\n"); | ||
326 | error = -ENOMEM; | ||
327 | goto err_free_mem; | ||
328 | } | ||
329 | |||
330 | keypad->board = plat; | ||
331 | keypad->input = input; | ||
332 | keypad->tc3589x = tc3589x; | ||
333 | |||
334 | input->id.bustype = BUS_I2C; | ||
335 | input->name = pdev->name; | ||
336 | input->dev.parent = &pdev->dev; | ||
337 | |||
338 | input->keycode = keypad->keymap; | ||
339 | input->keycodesize = sizeof(keypad->keymap[0]); | ||
340 | input->keycodemax = ARRAY_SIZE(keypad->keymap); | ||
341 | |||
342 | input->open = tc3589x_keypad_open; | ||
343 | input->close = tc3589x_keypad_close; | ||
344 | |||
345 | input_set_drvdata(input, keypad); | ||
346 | |||
347 | input_set_capability(input, EV_MSC, MSC_SCAN); | ||
348 | |||
349 | __set_bit(EV_KEY, input->evbit); | ||
350 | if (!plat->no_autorepeat) | ||
351 | __set_bit(EV_REP, input->evbit); | ||
352 | |||
353 | matrix_keypad_build_keymap(plat->keymap_data, 0x3, | ||
354 | input->keycode, input->keybit); | ||
355 | |||
356 | error = request_threaded_irq(irq, NULL, | ||
357 | tc3589x_keypad_irq, plat->irqtype, | ||
358 | "tc3589x-keypad", keypad); | ||
359 | if (error < 0) { | ||
360 | dev_err(&pdev->dev, | ||
361 | "Could not allocate irq %d,error %d\n", | ||
362 | irq, error); | ||
363 | goto err_free_mem; | ||
364 | } | ||
365 | |||
366 | error = input_register_device(input); | ||
367 | if (error) { | ||
368 | dev_err(&pdev->dev, "Could not register input device\n"); | ||
369 | goto err_free_irq; | ||
370 | } | ||
371 | |||
372 | /* let platform decide if keypad is a wakeup source or not */ | ||
373 | device_init_wakeup(&pdev->dev, plat->enable_wakeup); | ||
374 | device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup); | ||
375 | |||
376 | platform_set_drvdata(pdev, keypad); | ||
377 | |||
378 | return 0; | ||
379 | |||
380 | err_free_irq: | ||
381 | free_irq(irq, keypad); | ||
382 | err_free_mem: | ||
383 | input_free_device(input); | ||
384 | kfree(keypad); | ||
385 | return error; | ||
386 | } | ||
387 | |||
388 | static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) | ||
389 | { | ||
390 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
391 | int irq = platform_get_irq(pdev, 0); | ||
392 | |||
393 | if (!keypad->keypad_stopped) | ||
394 | tc3589x_keypad_disable(keypad); | ||
395 | |||
396 | free_irq(irq, keypad); | ||
397 | |||
398 | input_unregister_device(keypad->input); | ||
399 | |||
400 | kfree(keypad); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | #ifdef CONFIG_PM | ||
406 | static int tc3589x_keypad_suspend(struct device *dev) | ||
407 | { | ||
408 | struct platform_device *pdev = to_platform_device(dev); | ||
409 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
410 | int irq = platform_get_irq(pdev, 0); | ||
411 | |||
412 | /* keypad is already off; we do nothing */ | ||
413 | if (keypad->keypad_stopped) | ||
414 | return 0; | ||
415 | |||
416 | /* if device is not a wakeup source, disable it for powersave */ | ||
417 | if (!device_may_wakeup(&pdev->dev)) | ||
418 | tc3589x_keypad_disable(keypad); | ||
419 | else | ||
420 | enable_irq_wake(irq); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int tc3589x_keypad_resume(struct device *dev) | ||
426 | { | ||
427 | struct platform_device *pdev = to_platform_device(dev); | ||
428 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
429 | int irq = platform_get_irq(pdev, 0); | ||
430 | |||
431 | if (!keypad->keypad_stopped) | ||
432 | return 0; | ||
433 | |||
434 | /* enable the device to resume normal operations */ | ||
435 | if (!device_may_wakeup(&pdev->dev)) | ||
436 | tc3589x_keypad_enable(keypad); | ||
437 | else | ||
438 | disable_irq_wake(irq); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, | ||
444 | tc3589x_keypad_suspend, tc3589x_keypad_resume); | ||
445 | #endif | ||
446 | |||
447 | static struct platform_driver tc3589x_keypad_driver = { | ||
448 | .driver.name = "tc3589x-keypad", | ||
449 | .driver.owner = THIS_MODULE, | ||
450 | #ifdef CONFIG_PM | ||
451 | .driver.pm = &tc3589x_keypad_dev_pm_ops, | ||
452 | #endif | ||
453 | .probe = tc3589x_keypad_probe, | ||
454 | .remove = __devexit_p(tc3589x_keypad_remove), | ||
455 | }; | ||
456 | |||
457 | static int __init tc3589x_keypad_init(void) | ||
458 | { | ||
459 | return platform_driver_register(&tc3589x_keypad_driver); | ||
460 | } | ||
461 | module_init(tc3589x_keypad_init); | ||
462 | |||
463 | static void __exit tc3589x_keypad_exit(void) | ||
464 | { | ||
465 | return platform_driver_unregister(&tc3589x_keypad_driver); | ||
466 | } | ||
467 | module_exit(tc3589x_keypad_exit); | ||
468 | |||
469 | MODULE_LICENSE("GPL v2"); | ||
470 | MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer"); | ||
471 | MODULE_DESCRIPTION("TC35893 Keypad Driver"); | ||
472 | MODULE_ALIAS("platform:tc3589x-keypad") | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3a1493b8b5e5..e8e704f52746 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -218,12 +218,12 @@ config MFD_STMPE | |||
218 | Keypad: stmpe-keypad | 218 | Keypad: stmpe-keypad |
219 | Touchscreen: stmpe-ts | 219 | Touchscreen: stmpe-ts |
220 | 220 | ||
221 | config MFD_TC35892 | 221 | config MFD_TC3589X |
222 | bool "Support Toshiba TC35892" | 222 | bool "Support Toshiba TC35892 and variants" |
223 | depends on I2C=y && GENERIC_HARDIRQS | 223 | depends on I2C=y && GENERIC_HARDIRQS |
224 | select MFD_CORE | 224 | select MFD_CORE |
225 | help | 225 | help |
226 | Support for the Toshiba TC35892 I/O Expander. | 226 | Support for the Toshiba TC35892 and variants I/O Expander. |
227 | 227 | ||
228 | This driver provides common support for accessing the device, | 228 | This driver provides common support for accessing the device, |
229 | additional drivers must be enabled in order to use the | 229 | additional drivers must be enabled in order to use the |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f54b3659abbb..e590d1e44cf0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o | |||
16 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o | 16 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
17 | 17 | ||
18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
19 | obj-$(CONFIG_MFD_TC35892) += tc35892.o | 19 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o |
20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | 20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o |
21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | 21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o |
22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | 22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o |
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c deleted file mode 100644 index e619e2a55997..000000000000 --- a/drivers/mfd/tc35892.c +++ /dev/null | |||
@@ -1,345 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/mfd/core.h> | ||
15 | #include <linux/mfd/tc35892.h> | ||
16 | |||
17 | /** | ||
18 | * tc35892_reg_read() - read a single TC35892 register | ||
19 | * @tc35892: Device to read from | ||
20 | * @reg: Register to read | ||
21 | */ | ||
22 | int tc35892_reg_read(struct tc35892 *tc35892, u8 reg) | ||
23 | { | ||
24 | int ret; | ||
25 | |||
26 | ret = i2c_smbus_read_byte_data(tc35892->i2c, reg); | ||
27 | if (ret < 0) | ||
28 | dev_err(tc35892->dev, "failed to read reg %#x: %d\n", | ||
29 | reg, ret); | ||
30 | |||
31 | return ret; | ||
32 | } | ||
33 | EXPORT_SYMBOL_GPL(tc35892_reg_read); | ||
34 | |||
35 | /** | ||
36 | * tc35892_reg_read() - write a single TC35892 register | ||
37 | * @tc35892: Device to write to | ||
38 | * @reg: Register to read | ||
39 | * @data: Value to write | ||
40 | */ | ||
41 | int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data) | ||
42 | { | ||
43 | int ret; | ||
44 | |||
45 | ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data); | ||
46 | if (ret < 0) | ||
47 | dev_err(tc35892->dev, "failed to write reg %#x: %d\n", | ||
48 | reg, ret); | ||
49 | |||
50 | return ret; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(tc35892_reg_write); | ||
53 | |||
54 | /** | ||
55 | * tc35892_block_read() - read multiple TC35892 registers | ||
56 | * @tc35892: Device to read from | ||
57 | * @reg: First register | ||
58 | * @length: Number of registers | ||
59 | * @values: Buffer to write to | ||
60 | */ | ||
61 | int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values) | ||
62 | { | ||
63 | int ret; | ||
64 | |||
65 | ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values); | ||
66 | if (ret < 0) | ||
67 | dev_err(tc35892->dev, "failed to read regs %#x: %d\n", | ||
68 | reg, ret); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | EXPORT_SYMBOL_GPL(tc35892_block_read); | ||
73 | |||
74 | /** | ||
75 | * tc35892_block_write() - write multiple TC35892 registers | ||
76 | * @tc35892: Device to write to | ||
77 | * @reg: First register | ||
78 | * @length: Number of registers | ||
79 | * @values: Values to write | ||
80 | */ | ||
81 | int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length, | ||
82 | const u8 *values) | ||
83 | { | ||
84 | int ret; | ||
85 | |||
86 | ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length, | ||
87 | values); | ||
88 | if (ret < 0) | ||
89 | dev_err(tc35892->dev, "failed to write regs %#x: %d\n", | ||
90 | reg, ret); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | EXPORT_SYMBOL_GPL(tc35892_block_write); | ||
95 | |||
96 | /** | ||
97 | * tc35892_set_bits() - set the value of a bitfield in a TC35892 register | ||
98 | * @tc35892: Device to write to | ||
99 | * @reg: Register to write | ||
100 | * @mask: Mask of bits to set | ||
101 | * @values: Value to set | ||
102 | */ | ||
103 | int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val) | ||
104 | { | ||
105 | int ret; | ||
106 | |||
107 | mutex_lock(&tc35892->lock); | ||
108 | |||
109 | ret = tc35892_reg_read(tc35892, reg); | ||
110 | if (ret < 0) | ||
111 | goto out; | ||
112 | |||
113 | ret &= ~mask; | ||
114 | ret |= val; | ||
115 | |||
116 | ret = tc35892_reg_write(tc35892, reg, ret); | ||
117 | |||
118 | out: | ||
119 | mutex_unlock(&tc35892->lock); | ||
120 | return ret; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(tc35892_set_bits); | ||
123 | |||
124 | static struct resource gpio_resources[] = { | ||
125 | { | ||
126 | .start = TC35892_INT_GPIIRQ, | ||
127 | .end = TC35892_INT_GPIIRQ, | ||
128 | .flags = IORESOURCE_IRQ, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static struct mfd_cell tc35892_devs[] = { | ||
133 | { | ||
134 | .name = "tc35892-gpio", | ||
135 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
136 | .resources = &gpio_resources[0], | ||
137 | }, | ||
138 | }; | ||
139 | |||
140 | static irqreturn_t tc35892_irq(int irq, void *data) | ||
141 | { | ||
142 | struct tc35892 *tc35892 = data; | ||
143 | int status; | ||
144 | |||
145 | status = tc35892_reg_read(tc35892, TC35892_IRQST); | ||
146 | if (status < 0) | ||
147 | return IRQ_NONE; | ||
148 | |||
149 | while (status) { | ||
150 | int bit = __ffs(status); | ||
151 | |||
152 | handle_nested_irq(tc35892->irq_base + bit); | ||
153 | status &= ~(1 << bit); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * A dummy read or write (to any register) appears to be necessary to | ||
158 | * have the last interrupt clear (for example, GPIO IC write) take | ||
159 | * effect. | ||
160 | */ | ||
161 | tc35892_reg_read(tc35892, TC35892_IRQST); | ||
162 | |||
163 | return IRQ_HANDLED; | ||
164 | } | ||
165 | |||
166 | static void tc35892_irq_dummy(unsigned int irq) | ||
167 | { | ||
168 | /* No mask/unmask at this level */ | ||
169 | } | ||
170 | |||
171 | static struct irq_chip tc35892_irq_chip = { | ||
172 | .name = "tc35892", | ||
173 | .mask = tc35892_irq_dummy, | ||
174 | .unmask = tc35892_irq_dummy, | ||
175 | }; | ||
176 | |||
177 | static int tc35892_irq_init(struct tc35892 *tc35892) | ||
178 | { | ||
179 | int base = tc35892->irq_base; | ||
180 | int irq; | ||
181 | |||
182 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
183 | set_irq_chip_data(irq, tc35892); | ||
184 | set_irq_chip_and_handler(irq, &tc35892_irq_chip, | ||
185 | handle_edge_irq); | ||
186 | set_irq_nested_thread(irq, 1); | ||
187 | #ifdef CONFIG_ARM | ||
188 | set_irq_flags(irq, IRQF_VALID); | ||
189 | #else | ||
190 | set_irq_noprobe(irq); | ||
191 | #endif | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static void tc35892_irq_remove(struct tc35892 *tc35892) | ||
198 | { | ||
199 | int base = tc35892->irq_base; | ||
200 | int irq; | ||
201 | |||
202 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
203 | #ifdef CONFIG_ARM | ||
204 | set_irq_flags(irq, 0); | ||
205 | #endif | ||
206 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
207 | set_irq_chip_data(irq, NULL); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int tc35892_chip_init(struct tc35892 *tc35892) | ||
212 | { | ||
213 | int manf, ver, ret; | ||
214 | |||
215 | manf = tc35892_reg_read(tc35892, TC35892_MANFCODE); | ||
216 | if (manf < 0) | ||
217 | return manf; | ||
218 | |||
219 | ver = tc35892_reg_read(tc35892, TC35892_VERSION); | ||
220 | if (ver < 0) | ||
221 | return ver; | ||
222 | |||
223 | if (manf != TC35892_MANFCODE_MAGIC) { | ||
224 | dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
229 | |||
230 | /* Put everything except the IRQ module into reset */ | ||
231 | ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL, | ||
232 | TC35892_RSTCTRL_TIMRST | ||
233 | | TC35892_RSTCTRL_ROTRST | ||
234 | | TC35892_RSTCTRL_KBDRST | ||
235 | | TC35892_RSTCTRL_GPIRST); | ||
236 | if (ret < 0) | ||
237 | return ret; | ||
238 | |||
239 | /* Clear the reset interrupt. */ | ||
240 | return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1); | ||
241 | } | ||
242 | |||
243 | static int __devinit tc35892_probe(struct i2c_client *i2c, | ||
244 | const struct i2c_device_id *id) | ||
245 | { | ||
246 | struct tc35892_platform_data *pdata = i2c->dev.platform_data; | ||
247 | struct tc35892 *tc35892; | ||
248 | int ret; | ||
249 | |||
250 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
251 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
252 | return -EIO; | ||
253 | |||
254 | tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL); | ||
255 | if (!tc35892) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | mutex_init(&tc35892->lock); | ||
259 | |||
260 | tc35892->dev = &i2c->dev; | ||
261 | tc35892->i2c = i2c; | ||
262 | tc35892->pdata = pdata; | ||
263 | tc35892->irq_base = pdata->irq_base; | ||
264 | tc35892->num_gpio = id->driver_data; | ||
265 | |||
266 | i2c_set_clientdata(i2c, tc35892); | ||
267 | |||
268 | ret = tc35892_chip_init(tc35892); | ||
269 | if (ret) | ||
270 | goto out_free; | ||
271 | |||
272 | ret = tc35892_irq_init(tc35892); | ||
273 | if (ret) | ||
274 | goto out_free; | ||
275 | |||
276 | ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq, | ||
277 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
278 | "tc35892", tc35892); | ||
279 | if (ret) { | ||
280 | dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret); | ||
281 | goto out_removeirq; | ||
282 | } | ||
283 | |||
284 | ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs, | ||
285 | ARRAY_SIZE(tc35892_devs), NULL, | ||
286 | tc35892->irq_base); | ||
287 | if (ret) { | ||
288 | dev_err(tc35892->dev, "failed to add children\n"); | ||
289 | goto out_freeirq; | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | |||
294 | out_freeirq: | ||
295 | free_irq(tc35892->i2c->irq, tc35892); | ||
296 | out_removeirq: | ||
297 | tc35892_irq_remove(tc35892); | ||
298 | out_free: | ||
299 | kfree(tc35892); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static int __devexit tc35892_remove(struct i2c_client *client) | ||
304 | { | ||
305 | struct tc35892 *tc35892 = i2c_get_clientdata(client); | ||
306 | |||
307 | mfd_remove_devices(tc35892->dev); | ||
308 | |||
309 | free_irq(tc35892->i2c->irq, tc35892); | ||
310 | tc35892_irq_remove(tc35892); | ||
311 | |||
312 | kfree(tc35892); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static const struct i2c_device_id tc35892_id[] = { | ||
318 | { "tc35892", 24 }, | ||
319 | { } | ||
320 | }; | ||
321 | MODULE_DEVICE_TABLE(i2c, tc35892_id); | ||
322 | |||
323 | static struct i2c_driver tc35892_driver = { | ||
324 | .driver.name = "tc35892", | ||
325 | .driver.owner = THIS_MODULE, | ||
326 | .probe = tc35892_probe, | ||
327 | .remove = __devexit_p(tc35892_remove), | ||
328 | .id_table = tc35892_id, | ||
329 | }; | ||
330 | |||
331 | static int __init tc35892_init(void) | ||
332 | { | ||
333 | return i2c_add_driver(&tc35892_driver); | ||
334 | } | ||
335 | subsys_initcall(tc35892_init); | ||
336 | |||
337 | static void __exit tc35892_exit(void) | ||
338 | { | ||
339 | i2c_del_driver(&tc35892_driver); | ||
340 | } | ||
341 | module_exit(tc35892_exit); | ||
342 | |||
343 | MODULE_LICENSE("GPL v2"); | ||
344 | MODULE_DESCRIPTION("TC35892 MFD core driver"); | ||
345 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c new file mode 100644 index 000000000000..729dbeed2ce0 --- /dev/null +++ b/drivers/mfd/tc3589x.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License, version 2 | ||
5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/mfd/core.h> | ||
15 | #include <linux/mfd/tc3589x.h> | ||
16 | |||
17 | #define TC3589x_CLKMODE_MODCTL_SLEEP 0x0 | ||
18 | #define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0) | ||
19 | |||
20 | /** | ||
21 | * tc3589x_reg_read() - read a single TC3589x register | ||
22 | * @tc3589x: Device to read from | ||
23 | * @reg: Register to read | ||
24 | */ | ||
25 | int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) | ||
26 | { | ||
27 | int ret; | ||
28 | |||
29 | ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg); | ||
30 | if (ret < 0) | ||
31 | dev_err(tc3589x->dev, "failed to read reg %#x: %d\n", | ||
32 | reg, ret); | ||
33 | |||
34 | return ret; | ||
35 | } | ||
36 | EXPORT_SYMBOL_GPL(tc3589x_reg_read); | ||
37 | |||
38 | /** | ||
39 | * tc3589x_reg_read() - write a single TC3589x register | ||
40 | * @tc3589x: Device to write to | ||
41 | * @reg: Register to read | ||
42 | * @data: Value to write | ||
43 | */ | ||
44 | int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data) | ||
45 | { | ||
46 | int ret; | ||
47 | |||
48 | ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data); | ||
49 | if (ret < 0) | ||
50 | dev_err(tc3589x->dev, "failed to write reg %#x: %d\n", | ||
51 | reg, ret); | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(tc3589x_reg_write); | ||
56 | |||
57 | /** | ||
58 | * tc3589x_block_read() - read multiple TC3589x registers | ||
59 | * @tc3589x: Device to read from | ||
60 | * @reg: First register | ||
61 | * @length: Number of registers | ||
62 | * @values: Buffer to write to | ||
63 | */ | ||
64 | int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values) | ||
65 | { | ||
66 | int ret; | ||
67 | |||
68 | ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values); | ||
69 | if (ret < 0) | ||
70 | dev_err(tc3589x->dev, "failed to read regs %#x: %d\n", | ||
71 | reg, ret); | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(tc3589x_block_read); | ||
76 | |||
77 | /** | ||
78 | * tc3589x_block_write() - write multiple TC3589x registers | ||
79 | * @tc3589x: Device to write to | ||
80 | * @reg: First register | ||
81 | * @length: Number of registers | ||
82 | * @values: Values to write | ||
83 | */ | ||
84 | int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, | ||
85 | const u8 *values) | ||
86 | { | ||
87 | int ret; | ||
88 | |||
89 | ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length, | ||
90 | values); | ||
91 | if (ret < 0) | ||
92 | dev_err(tc3589x->dev, "failed to write regs %#x: %d\n", | ||
93 | reg, ret); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(tc3589x_block_write); | ||
98 | |||
99 | /** | ||
100 | * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register | ||
101 | * @tc3589x: Device to write to | ||
102 | * @reg: Register to write | ||
103 | * @mask: Mask of bits to set | ||
104 | * @values: Value to set | ||
105 | */ | ||
106 | int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | mutex_lock(&tc3589x->lock); | ||
111 | |||
112 | ret = tc3589x_reg_read(tc3589x, reg); | ||
113 | if (ret < 0) | ||
114 | goto out; | ||
115 | |||
116 | ret &= ~mask; | ||
117 | ret |= val; | ||
118 | |||
119 | ret = tc3589x_reg_write(tc3589x, reg, ret); | ||
120 | |||
121 | out: | ||
122 | mutex_unlock(&tc3589x->lock); | ||
123 | return ret; | ||
124 | } | ||
125 | EXPORT_SYMBOL_GPL(tc3589x_set_bits); | ||
126 | |||
127 | static struct resource gpio_resources[] = { | ||
128 | { | ||
129 | .start = TC3589x_INT_GPIIRQ, | ||
130 | .end = TC3589x_INT_GPIIRQ, | ||
131 | .flags = IORESOURCE_IRQ, | ||
132 | }, | ||
133 | }; | ||
134 | |||
135 | static struct resource keypad_resources[] = { | ||
136 | { | ||
137 | .start = TC3589x_INT_KBDIRQ, | ||
138 | .end = TC3589x_INT_KBDIRQ, | ||
139 | .flags = IORESOURCE_IRQ, | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | static struct mfd_cell tc3589x_dev_gpio[] = { | ||
144 | { | ||
145 | .name = "tc3589x-gpio", | ||
146 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
147 | .resources = &gpio_resources[0], | ||
148 | }, | ||
149 | }; | ||
150 | |||
151 | static struct mfd_cell tc3589x_dev_keypad[] = { | ||
152 | { | ||
153 | .name = "tc3589x-keypad", | ||
154 | .num_resources = ARRAY_SIZE(keypad_resources), | ||
155 | .resources = &keypad_resources[0], | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | static irqreturn_t tc3589x_irq(int irq, void *data) | ||
160 | { | ||
161 | struct tc3589x *tc3589x = data; | ||
162 | int status; | ||
163 | |||
164 | again: | ||
165 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
166 | if (status < 0) | ||
167 | return IRQ_NONE; | ||
168 | |||
169 | while (status) { | ||
170 | int bit = __ffs(status); | ||
171 | |||
172 | handle_nested_irq(tc3589x->irq_base + bit); | ||
173 | status &= ~(1 << bit); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * A dummy read or write (to any register) appears to be necessary to | ||
178 | * have the last interrupt clear (for example, GPIO IC write) take | ||
179 | * effect. In such a case, recheck for any interrupt which is still | ||
180 | * pending. | ||
181 | */ | ||
182 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
183 | if (status) | ||
184 | goto again; | ||
185 | |||
186 | return IRQ_HANDLED; | ||
187 | } | ||
188 | |||
189 | static int tc3589x_irq_init(struct tc3589x *tc3589x) | ||
190 | { | ||
191 | int base = tc3589x->irq_base; | ||
192 | int irq; | ||
193 | |||
194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
195 | set_irq_chip_data(irq, tc3589x); | ||
196 | set_irq_chip_and_handler(irq, &dummy_irq_chip, | ||
197 | handle_edge_irq); | ||
198 | set_irq_nested_thread(irq, 1); | ||
199 | #ifdef CONFIG_ARM | ||
200 | set_irq_flags(irq, IRQF_VALID); | ||
201 | #else | ||
202 | set_irq_noprobe(irq); | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void tc3589x_irq_remove(struct tc3589x *tc3589x) | ||
210 | { | ||
211 | int base = tc3589x->irq_base; | ||
212 | int irq; | ||
213 | |||
214 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
215 | #ifdef CONFIG_ARM | ||
216 | set_irq_flags(irq, 0); | ||
217 | #endif | ||
218 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
219 | set_irq_chip_data(irq, NULL); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static int tc3589x_chip_init(struct tc3589x *tc3589x) | ||
224 | { | ||
225 | int manf, ver, ret; | ||
226 | |||
227 | manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE); | ||
228 | if (manf < 0) | ||
229 | return manf; | ||
230 | |||
231 | ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION); | ||
232 | if (ver < 0) | ||
233 | return ver; | ||
234 | |||
235 | if (manf != TC3589x_MANFCODE_MAGIC) { | ||
236 | dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
241 | |||
242 | /* | ||
243 | * Put everything except the IRQ module into reset; | ||
244 | * also spare the GPIO module for any pin initialization | ||
245 | * done during pre-kernel boot | ||
246 | */ | ||
247 | ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL, | ||
248 | TC3589x_RSTCTRL_TIMRST | ||
249 | | TC3589x_RSTCTRL_ROTRST | ||
250 | | TC3589x_RSTCTRL_KBDRST); | ||
251 | if (ret < 0) | ||
252 | return ret; | ||
253 | |||
254 | /* Clear the reset interrupt. */ | ||
255 | return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); | ||
256 | } | ||
257 | |||
258 | static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | ||
259 | { | ||
260 | int ret = 0; | ||
261 | unsigned int blocks = tc3589x->pdata->block; | ||
262 | |||
263 | if (blocks & TC3589x_BLOCK_GPIO) { | ||
264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, | ||
265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, | ||
266 | tc3589x->irq_base); | ||
267 | if (ret) { | ||
268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); | ||
269 | return ret; | ||
270 | } | ||
271 | dev_info(tc3589x->dev, "added gpio block\n"); | ||
272 | } | ||
273 | |||
274 | if (blocks & TC3589x_BLOCK_KEYPAD) { | ||
275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | ||
276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | ||
277 | tc3589x->irq_base); | ||
278 | if (ret) { | ||
279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | ||
280 | return ret; | ||
281 | } | ||
282 | dev_info(tc3589x->dev, "added keypad block\n"); | ||
283 | } | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static int __devinit tc3589x_probe(struct i2c_client *i2c, | ||
289 | const struct i2c_device_id *id) | ||
290 | { | ||
291 | struct tc3589x_platform_data *pdata = i2c->dev.platform_data; | ||
292 | struct tc3589x *tc3589x; | ||
293 | int ret; | ||
294 | |||
295 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
296 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
297 | return -EIO; | ||
298 | |||
299 | tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); | ||
300 | if (!tc3589x) | ||
301 | return -ENOMEM; | ||
302 | |||
303 | mutex_init(&tc3589x->lock); | ||
304 | |||
305 | tc3589x->dev = &i2c->dev; | ||
306 | tc3589x->i2c = i2c; | ||
307 | tc3589x->pdata = pdata; | ||
308 | tc3589x->irq_base = pdata->irq_base; | ||
309 | tc3589x->num_gpio = id->driver_data; | ||
310 | |||
311 | i2c_set_clientdata(i2c, tc3589x); | ||
312 | |||
313 | ret = tc3589x_chip_init(tc3589x); | ||
314 | if (ret) | ||
315 | goto out_free; | ||
316 | |||
317 | ret = tc3589x_irq_init(tc3589x); | ||
318 | if (ret) | ||
319 | goto out_free; | ||
320 | |||
321 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, | ||
322 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
323 | "tc3589x", tc3589x); | ||
324 | if (ret) { | ||
325 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | ||
326 | goto out_removeirq; | ||
327 | } | ||
328 | |||
329 | ret = tc3589x_device_init(tc3589x); | ||
330 | if (ret) { | ||
331 | dev_err(tc3589x->dev, "failed to add child devices\n"); | ||
332 | goto out_freeirq; | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | |||
337 | out_freeirq: | ||
338 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
339 | out_removeirq: | ||
340 | tc3589x_irq_remove(tc3589x); | ||
341 | out_free: | ||
342 | kfree(tc3589x); | ||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | static int __devexit tc3589x_remove(struct i2c_client *client) | ||
347 | { | ||
348 | struct tc3589x *tc3589x = i2c_get_clientdata(client); | ||
349 | |||
350 | mfd_remove_devices(tc3589x->dev); | ||
351 | |||
352 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
353 | tc3589x_irq_remove(tc3589x); | ||
354 | |||
355 | kfree(tc3589x); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int tc3589x_suspend(struct device *dev) | ||
361 | { | ||
362 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
363 | struct i2c_client *client = tc3589x->i2c; | ||
364 | int ret = 0; | ||
365 | |||
366 | /* put the system to sleep mode */ | ||
367 | if (!device_may_wakeup(&client->dev)) | ||
368 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
369 | TC3589x_CLKMODE_MODCTL_SLEEP); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int tc3589x_resume(struct device *dev) | ||
375 | { | ||
376 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
377 | struct i2c_client *client = tc3589x->i2c; | ||
378 | int ret = 0; | ||
379 | |||
380 | /* enable the system into operation */ | ||
381 | if (!device_may_wakeup(&client->dev)) | ||
382 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
383 | TC3589x_CLKMODE_MODCTL_OPERATION); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, | ||
389 | tc3589x_resume); | ||
390 | |||
391 | static const struct i2c_device_id tc3589x_id[] = { | ||
392 | { "tc3589x", 24 }, | ||
393 | { } | ||
394 | }; | ||
395 | MODULE_DEVICE_TABLE(i2c, tc3589x_id); | ||
396 | |||
397 | static struct i2c_driver tc3589x_driver = { | ||
398 | .driver.name = "tc3589x", | ||
399 | .driver.owner = THIS_MODULE, | ||
400 | #ifdef CONFIG_PM | ||
401 | .driver.pm = &tc3589x_dev_pm_ops, | ||
402 | #endif | ||
403 | .probe = tc3589x_probe, | ||
404 | .remove = __devexit_p(tc3589x_remove), | ||
405 | .id_table = tc3589x_id, | ||
406 | }; | ||
407 | |||
408 | static int __init tc3589x_init(void) | ||
409 | { | ||
410 | return i2c_add_driver(&tc3589x_driver); | ||
411 | } | ||
412 | subsys_initcall(tc3589x_init); | ||
413 | |||
414 | static void __exit tc3589x_exit(void) | ||
415 | { | ||
416 | i2c_del_driver(&tc3589x_driver); | ||
417 | } | ||
418 | module_exit(tc3589x_exit); | ||
419 | |||
420 | MODULE_LICENSE("GPL v2"); | ||
421 | MODULE_DESCRIPTION("TC3589x MFD core driver"); | ||
422 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87b4fc6c98c2..563022825667 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/highmem.h> | 19 | #include <linux/highmem.h> |
20 | #include <linux/log2.h> | 20 | #include <linux/log2.h> |
21 | #include <linux/mmc/host.h> | 21 | #include <linux/mmc/host.h> |
22 | #include <linux/mmc/card.h> | ||
22 | #include <linux/amba/bus.h> | 23 | #include <linux/amba/bus.h> |
23 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
24 | #include <linux/scatterlist.h> | 25 | #include <linux/scatterlist.h> |
@@ -45,6 +46,12 @@ static unsigned int fmax = 515633; | |||
45 | * is asserted (likewise for RX) | 46 | * is asserted (likewise for RX) |
46 | * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY | 47 | * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY |
47 | * is asserted (likewise for RX) | 48 | * is asserted (likewise for RX) |
49 | * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware | ||
50 | * and will not work at all. | ||
51 | * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when | ||
52 | * using DMA. | ||
53 | * @sdio: variant supports SDIO | ||
54 | * @st_clkdiv: true if using a ST-specific clock divider algorithm | ||
48 | */ | 55 | */ |
49 | struct variant_data { | 56 | struct variant_data { |
50 | unsigned int clkreg; | 57 | unsigned int clkreg; |
@@ -52,6 +59,10 @@ struct variant_data { | |||
52 | unsigned int datalength_bits; | 59 | unsigned int datalength_bits; |
53 | unsigned int fifosize; | 60 | unsigned int fifosize; |
54 | unsigned int fifohalfsize; | 61 | unsigned int fifohalfsize; |
62 | bool broken_blockend; | ||
63 | bool broken_blockend_dma; | ||
64 | bool sdio; | ||
65 | bool st_clkdiv; | ||
55 | }; | 66 | }; |
56 | 67 | ||
57 | static struct variant_data variant_arm = { | 68 | static struct variant_data variant_arm = { |
@@ -65,6 +76,8 @@ static struct variant_data variant_u300 = { | |||
65 | .fifohalfsize = 8 * 4, | 76 | .fifohalfsize = 8 * 4, |
66 | .clkreg_enable = 1 << 13, /* HWFCEN */ | 77 | .clkreg_enable = 1 << 13, /* HWFCEN */ |
67 | .datalength_bits = 16, | 78 | .datalength_bits = 16, |
79 | .broken_blockend_dma = true, | ||
80 | .sdio = true, | ||
68 | }; | 81 | }; |
69 | 82 | ||
70 | static struct variant_data variant_ux500 = { | 83 | static struct variant_data variant_ux500 = { |
@@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = { | |||
73 | .clkreg = MCI_CLK_ENABLE, | 86 | .clkreg = MCI_CLK_ENABLE, |
74 | .clkreg_enable = 1 << 14, /* HWFCEN */ | 87 | .clkreg_enable = 1 << 14, /* HWFCEN */ |
75 | .datalength_bits = 24, | 88 | .datalength_bits = 24, |
89 | .broken_blockend = true, | ||
90 | .sdio = true, | ||
91 | .st_clkdiv = true, | ||
76 | }; | 92 | }; |
93 | |||
77 | /* | 94 | /* |
78 | * This must be called with host->lock held | 95 | * This must be called with host->lock held |
79 | */ | 96 | */ |
@@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) | |||
86 | if (desired >= host->mclk) { | 103 | if (desired >= host->mclk) { |
87 | clk = MCI_CLK_BYPASS; | 104 | clk = MCI_CLK_BYPASS; |
88 | host->cclk = host->mclk; | 105 | host->cclk = host->mclk; |
106 | } else if (variant->st_clkdiv) { | ||
107 | /* | ||
108 | * DB8500 TRM says f = mclk / (clkdiv + 2) | ||
109 | * => clkdiv = (mclk / f) - 2 | ||
110 | * Round the divider up so we don't exceed the max | ||
111 | * frequency | ||
112 | */ | ||
113 | clk = DIV_ROUND_UP(host->mclk, desired) - 2; | ||
114 | if (clk >= 256) | ||
115 | clk = 255; | ||
116 | host->cclk = host->mclk / (clk + 2); | ||
89 | } else { | 117 | } else { |
118 | /* | ||
119 | * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) | ||
120 | * => clkdiv = mclk / (2 * f) - 1 | ||
121 | */ | ||
90 | clk = host->mclk / (2 * desired) - 1; | 122 | clk = host->mclk / (2 * desired) - 1; |
91 | if (clk >= 256) | 123 | if (clk >= 256) |
92 | clk = 255; | 124 | clk = 255; |
@@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) | |||
129 | spin_lock(&host->lock); | 161 | spin_lock(&host->lock); |
130 | } | 162 | } |
131 | 163 | ||
164 | static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) | ||
165 | { | ||
166 | void __iomem *base = host->base; | ||
167 | |||
168 | if (host->singleirq) { | ||
169 | unsigned int mask0 = readl(base + MMCIMASK0); | ||
170 | |||
171 | mask0 &= ~MCI_IRQ1MASK; | ||
172 | mask0 |= mask; | ||
173 | |||
174 | writel(mask0, base + MMCIMASK0); | ||
175 | } | ||
176 | |||
177 | writel(mask, base + MMCIMASK1); | ||
178 | } | ||
179 | |||
132 | static void mmci_stop_data(struct mmci_host *host) | 180 | static void mmci_stop_data(struct mmci_host *host) |
133 | { | 181 | { |
134 | writel(0, host->base + MMCIDATACTRL); | 182 | writel(0, host->base + MMCIDATACTRL); |
135 | writel(0, host->base + MMCIMASK1); | 183 | mmci_set_mask1(host, 0); |
136 | host->data = NULL; | 184 | host->data = NULL; |
137 | } | 185 | } |
138 | 186 | ||
@@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | |||
162 | host->data = data; | 210 | host->data = data; |
163 | host->size = data->blksz * data->blocks; | 211 | host->size = data->blksz * data->blocks; |
164 | host->data_xfered = 0; | 212 | host->data_xfered = 0; |
213 | host->blockend = false; | ||
214 | host->dataend = false; | ||
165 | 215 | ||
166 | mmci_init_sg(host, data); | 216 | mmci_init_sg(host, data); |
167 | 217 | ||
@@ -196,9 +246,14 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | |||
196 | irqmask = MCI_TXFIFOHALFEMPTYMASK; | 246 | irqmask = MCI_TXFIFOHALFEMPTYMASK; |
197 | } | 247 | } |
198 | 248 | ||
249 | /* The ST Micro variants has a special bit to enable SDIO */ | ||
250 | if (variant->sdio && host->mmc->card) | ||
251 | if (mmc_card_sdio(host->mmc->card)) | ||
252 | datactrl |= MCI_ST_DPSM_SDIOEN; | ||
253 | |||
199 | writel(datactrl, base + MMCIDATACTRL); | 254 | writel(datactrl, base + MMCIDATACTRL); |
200 | writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); | 255 | writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); |
201 | writel(irqmask, base + MMCIMASK1); | 256 | mmci_set_mask1(host, irqmask); |
202 | } | 257 | } |
203 | 258 | ||
204 | static void | 259 | static void |
@@ -233,20 +288,9 @@ static void | |||
233 | mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | 288 | mmci_data_irq(struct mmci_host *host, struct mmc_data *data, |
234 | unsigned int status) | 289 | unsigned int status) |
235 | { | 290 | { |
236 | if (status & MCI_DATABLOCKEND) { | 291 | struct variant_data *variant = host->variant; |
237 | host->data_xfered += data->blksz; | 292 | |
238 | #ifdef CONFIG_ARCH_U300 | 293 | /* First check for errors */ |
239 | /* | ||
240 | * On the U300 some signal or other is | ||
241 | * badly routed so that a data write does | ||
242 | * not properly terminate with a MCI_DATAEND | ||
243 | * status flag. This quirk will make writes | ||
244 | * work again. | ||
245 | */ | ||
246 | if (data->flags & MMC_DATA_WRITE) | ||
247 | status |= MCI_DATAEND; | ||
248 | #endif | ||
249 | } | ||
250 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { | 294 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { |
251 | dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); | 295 | dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); |
252 | if (status & MCI_DATACRCFAIL) | 296 | if (status & MCI_DATACRCFAIL) |
@@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
255 | data->error = -ETIMEDOUT; | 299 | data->error = -ETIMEDOUT; |
256 | else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) | 300 | else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) |
257 | data->error = -EIO; | 301 | data->error = -EIO; |
258 | status |= MCI_DATAEND; | 302 | |
303 | /* Force-complete the transaction */ | ||
304 | host->blockend = true; | ||
305 | host->dataend = true; | ||
259 | 306 | ||
260 | /* | 307 | /* |
261 | * We hit an error condition. Ensure that any data | 308 | * We hit an error condition. Ensure that any data |
@@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
273 | local_irq_restore(flags); | 320 | local_irq_restore(flags); |
274 | } | 321 | } |
275 | } | 322 | } |
276 | if (status & MCI_DATAEND) { | 323 | |
324 | /* | ||
325 | * On ARM variants in PIO mode, MCI_DATABLOCKEND | ||
326 | * is always sent first, and we increase the | ||
327 | * transfered number of bytes for that IRQ. Then | ||
328 | * MCI_DATAEND follows and we conclude the transaction. | ||
329 | * | ||
330 | * On the Ux500 single-IRQ variant MCI_DATABLOCKEND | ||
331 | * doesn't seem to immediately clear from the status, | ||
332 | * so we can't use it keep count when only one irq is | ||
333 | * used because the irq will hit for other reasons, and | ||
334 | * then the flag is still up. So we use the MCI_DATAEND | ||
335 | * IRQ at the end of the entire transfer because | ||
336 | * MCI_DATABLOCKEND is broken. | ||
337 | * | ||
338 | * In the U300, the IRQs can arrive out-of-order, | ||
339 | * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, | ||
340 | * so for this case we use the flags "blockend" and | ||
341 | * "dataend" to make sure both IRQs have arrived before | ||
342 | * concluding the transaction. (This does not apply | ||
343 | * to the Ux500 which doesn't fire MCI_DATABLOCKEND | ||
344 | * at all.) In DMA mode it suffers from the same problem | ||
345 | * as the Ux500. | ||
346 | */ | ||
347 | if (status & MCI_DATABLOCKEND) { | ||
348 | /* | ||
349 | * Just being a little over-cautious, we do not | ||
350 | * use this progressive update if the hardware blockend | ||
351 | * flag is unreliable: since it can stay high between | ||
352 | * IRQs it will corrupt the transfer counter. | ||
353 | */ | ||
354 | if (!variant->broken_blockend) | ||
355 | host->data_xfered += data->blksz; | ||
356 | host->blockend = true; | ||
357 | } | ||
358 | |||
359 | if (status & MCI_DATAEND) | ||
360 | host->dataend = true; | ||
361 | |||
362 | /* | ||
363 | * On variants with broken blockend we shall only wait for dataend, | ||
364 | * on others we must sync with the blockend signal since they can | ||
365 | * appear out-of-order. | ||
366 | */ | ||
367 | if (host->dataend && (host->blockend || variant->broken_blockend)) { | ||
277 | mmci_stop_data(host); | 368 | mmci_stop_data(host); |
278 | 369 | ||
370 | /* Reset these flags */ | ||
371 | host->blockend = false; | ||
372 | host->dataend = false; | ||
373 | |||
374 | /* | ||
375 | * Variants with broken blockend flags need to handle the | ||
376 | * end of the entire transfer here. | ||
377 | */ | ||
378 | if (variant->broken_blockend && !data->error) | ||
379 | host->data_xfered += data->blksz * data->blocks; | ||
380 | |||
279 | if (!data->stop) { | 381 | if (!data->stop) { |
280 | mmci_request_end(host, data->mrq); | 382 | mmci_request_end(host, data->mrq); |
281 | } else { | 383 | } else { |
@@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem | |||
356 | variant->fifosize : variant->fifohalfsize; | 458 | variant->fifosize : variant->fifohalfsize; |
357 | count = min(remain, maxcnt); | 459 | count = min(remain, maxcnt); |
358 | 460 | ||
359 | writesl(base + MMCIFIFO, ptr, count >> 2); | 461 | /* |
462 | * The ST Micro variant for SDIO transfer sizes | ||
463 | * less then 8 bytes should have clock H/W flow | ||
464 | * control disabled. | ||
465 | */ | ||
466 | if (variant->sdio && | ||
467 | mmc_card_sdio(host->mmc->card)) { | ||
468 | if (count < 8) | ||
469 | writel(readl(host->base + MMCICLOCK) & | ||
470 | ~variant->clkreg_enable, | ||
471 | host->base + MMCICLOCK); | ||
472 | else | ||
473 | writel(readl(host->base + MMCICLOCK) | | ||
474 | variant->clkreg_enable, | ||
475 | host->base + MMCICLOCK); | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * SDIO especially may want to send something that is | ||
480 | * not divisible by 4 (as opposed to card sectors | ||
481 | * etc), and the FIFO only accept full 32-bit writes. | ||
482 | * So compensate by adding +3 on the count, a single | ||
483 | * byte become a 32bit write, 7 bytes will be two | ||
484 | * 32bit writes etc. | ||
485 | */ | ||
486 | writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); | ||
360 | 487 | ||
361 | ptr += count; | 488 | ptr += count; |
362 | remain -= count; | 489 | remain -= count; |
@@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | |||
437 | * "any data available" mode. | 564 | * "any data available" mode. |
438 | */ | 565 | */ |
439 | if (status & MCI_RXACTIVE && host->size < variant->fifosize) | 566 | if (status & MCI_RXACTIVE && host->size < variant->fifosize) |
440 | writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); | 567 | mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); |
441 | 568 | ||
442 | /* | 569 | /* |
443 | * If we run out of data, disable the data IRQs; this | 570 | * If we run out of data, disable the data IRQs; this |
@@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | |||
446 | * stops us racing with our data end IRQ. | 573 | * stops us racing with our data end IRQ. |
447 | */ | 574 | */ |
448 | if (host->size == 0) { | 575 | if (host->size == 0) { |
449 | writel(0, base + MMCIMASK1); | 576 | mmci_set_mask1(host, 0); |
450 | writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); | 577 | writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); |
451 | } | 578 | } |
452 | 579 | ||
@@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) | |||
469 | struct mmc_data *data; | 596 | struct mmc_data *data; |
470 | 597 | ||
471 | status = readl(host->base + MMCISTATUS); | 598 | status = readl(host->base + MMCISTATUS); |
599 | |||
600 | if (host->singleirq) { | ||
601 | if (status & readl(host->base + MMCIMASK1)) | ||
602 | mmci_pio_irq(irq, dev_id); | ||
603 | |||
604 | status &= ~MCI_IRQ1MASK; | ||
605 | } | ||
606 | |||
472 | status &= readl(host->base + MMCIMASK0); | 607 | status &= readl(host->base + MMCIMASK0); |
473 | writel(status, host->base + MMCICLEAR); | 608 | writel(status, host->base + MMCICLEAR); |
474 | 609 | ||
@@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
635 | struct variant_data *variant = id->data; | 770 | struct variant_data *variant = id->data; |
636 | struct mmci_host *host; | 771 | struct mmci_host *host; |
637 | struct mmc_host *mmc; | 772 | struct mmc_host *mmc; |
773 | unsigned int mask; | ||
638 | int ret; | 774 | int ret; |
639 | 775 | ||
640 | /* must have platform data */ | 776 | /* must have platform data */ |
@@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) | |||
806 | if (ret) | 942 | if (ret) |
807 | goto unmap; | 943 | goto unmap; |
808 | 944 | ||
809 | ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); | 945 | if (dev->irq[1] == NO_IRQ) |
810 | if (ret) | 946 | host->singleirq = true; |
811 | goto irq0_free; | 947 | else { |
948 | ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, | ||
949 | DRIVER_NAME " (pio)", host); | ||
950 | if (ret) | ||
951 | goto irq0_free; | ||
952 | } | ||
812 | 953 | ||
813 | writel(MCI_IRQENABLE, host->base + MMCIMASK0); | 954 | mask = MCI_IRQENABLE; |
955 | /* Don't use the datablockend flag if it's broken */ | ||
956 | if (variant->broken_blockend) | ||
957 | mask &= ~MCI_DATABLOCKEND; | ||
814 | 958 | ||
815 | amba_set_drvdata(dev, mmc); | 959 | writel(mask, host->base + MMCIMASK0); |
816 | 960 | ||
817 | mmc_add_host(mmc); | 961 | amba_set_drvdata(dev, mmc); |
818 | 962 | ||
819 | dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", | 963 | dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", |
820 | mmc_hostname(mmc), amba_rev(dev), amba_config(dev), | 964 | mmc_hostname(mmc), amba_part(dev), amba_rev(dev), |
821 | (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); | 965 | (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); |
822 | 966 | ||
967 | mmc_add_host(mmc); | ||
968 | |||
823 | return 0; | 969 | return 0; |
824 | 970 | ||
825 | irq0_free: | 971 | irq0_free: |
@@ -864,7 +1010,8 @@ static int __devexit mmci_remove(struct amba_device *dev) | |||
864 | writel(0, host->base + MMCIDATACTRL); | 1010 | writel(0, host->base + MMCIDATACTRL); |
865 | 1011 | ||
866 | free_irq(dev->irq[0], host); | 1012 | free_irq(dev->irq[0], host); |
867 | free_irq(dev->irq[1], host); | 1013 | if (!host->singleirq) |
1014 | free_irq(dev->irq[1], host); | ||
868 | 1015 | ||
869 | if (host->gpio_wp != -ENOSYS) | 1016 | if (host->gpio_wp != -ENOSYS) |
870 | gpio_free(host->gpio_wp); | 1017 | gpio_free(host->gpio_wp); |
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4ae887fc0189..df06f01aac89 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h | |||
@@ -139,6 +139,11 @@ | |||
139 | MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ | 139 | MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ |
140 | MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) | 140 | MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) |
141 | 141 | ||
142 | /* These interrupts are directed to IRQ1 when two IRQ lines are available */ | ||
143 | #define MCI_IRQ1MASK \ | ||
144 | (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ | ||
145 | MCI_TXFIFOHALFEMPTYMASK) | ||
146 | |||
142 | #define NR_SG 16 | 147 | #define NR_SG 16 |
143 | 148 | ||
144 | struct clk; | 149 | struct clk; |
@@ -154,6 +159,7 @@ struct mmci_host { | |||
154 | int gpio_cd; | 159 | int gpio_cd; |
155 | int gpio_wp; | 160 | int gpio_wp; |
156 | int gpio_cd_irq; | 161 | int gpio_cd_irq; |
162 | bool singleirq; | ||
157 | 163 | ||
158 | unsigned int data_xfered; | 164 | unsigned int data_xfered; |
159 | 165 | ||
@@ -171,6 +177,9 @@ struct mmci_host { | |||
171 | struct timer_list timer; | 177 | struct timer_list timer; |
172 | unsigned int oldstat; | 178 | unsigned int oldstat; |
173 | 179 | ||
180 | bool blockend; | ||
181 | bool dataend; | ||
182 | |||
174 | /* pio stuff */ | 183 | /* pio stuff */ |
175 | struct sg_mapping_iter sg_miter; | 184 | struct sg_mapping_iter sg_miter; |
176 | unsigned int size; | 185 | unsigned int size; |
diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c index 32b1c6fb2de1..5f771ab712c4 100644 --- a/drivers/net/caif/caif_shm_u5500.c +++ b/drivers/net/caif/caif_shm_u5500.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
14 | #include <mach/mbox.h> | 14 | #include <mach/mbox-db5500.h> |
15 | #include <net/caif/caif_shm.h> | 15 | #include <net/caif/caif_shm.h> |
16 | 16 | ||
17 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index c80a7a6e7698..de886f3dfd39 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -215,7 +215,8 @@ config PCMCIA_PXA2XX | |||
215 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ | 215 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ |
216 | || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ | 216 | || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ |
217 | || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \ | 217 | || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \ |
218 | || MACH_VPAC270 || MACH_BALLOON3) | 218 | || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \ |
219 | || MACH_COLIBRI320) | ||
219 | select PCMCIA_SOC_COMMON | 220 | select PCMCIA_SOC_COMMON |
220 | help | 221 | help |
221 | Say Y here to include support for the PXA2xx PCMCIA controller | 222 | Say Y here to include support for the PXA2xx PCMCIA controller |
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 8d9386a22eb3..29935ea921df 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -50,8 +50,9 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o | |||
50 | sa1100_cs-y += sa1100_generic.o | 50 | sa1100_cs-y += sa1100_generic.o |
51 | sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o | 51 | sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o |
52 | sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o | 52 | sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o |
53 | sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o | 53 | sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o |
54 | sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o | 54 | sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o |
55 | sa1100_cs-$(CONFIG_SA1100_NANOENGINE) += sa1100_nanoengine.o | ||
55 | sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o | 56 | sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o |
56 | sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o | 57 | sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o |
57 | 58 | ||
@@ -70,6 +71,8 @@ pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o | |||
70 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o | 71 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o |
71 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o | 72 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o |
72 | pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o | 73 | pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o |
74 | pxa2xx-obj-$(CONFIG_MACH_COLIBRI) += pxa2xx_colibri.o | ||
75 | pxa2xx-obj-$(CONFIG_MACH_COLIBRI320) += pxa2xx_colibri.o | ||
73 | 76 | ||
74 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) | 77 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) |
75 | 78 | ||
diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c index dbbdd0063202..453c54c97612 100644 --- a/drivers/pcmcia/pxa2xx_balloon3.c +++ b/drivers/pcmcia/pxa2xx_balloon3.c | |||
@@ -39,12 +39,10 @@ static struct pcmcia_irqs irqs[] = { | |||
39 | static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 39 | static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
40 | { | 40 | { |
41 | uint16_t ver; | 41 | uint16_t ver; |
42 | int ret; | ||
43 | static void __iomem *fpga_ver; | ||
44 | 42 | ||
45 | ver = __raw_readw(BALLOON3_FPGA_VER); | 43 | ver = __raw_readw(BALLOON3_FPGA_VER); |
46 | if (ver > 0x0201) | 44 | if (ver < 0x4f08) |
47 | pr_warn("The FPGA code, version 0x%04x, is newer than rel-0.3. " | 45 | pr_warn("The FPGA code, version 0x%04x, is too old. " |
48 | "PCMCIA/CF support might be broken in this version!", | 46 | "PCMCIA/CF support might be broken in this version!", |
49 | ver); | 47 | ver); |
50 | 48 | ||
@@ -97,8 +95,9 @@ static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | |||
97 | static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | 95 | static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
98 | const socket_state_t *state) | 96 | const socket_state_t *state) |
99 | { | 97 | { |
100 | __raw_writew((state->flags & SS_RESET) ? BALLOON3_CF_RESET : 0, | 98 | __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG | |
101 | BALLOON3_CF_CONTROL_REG); | 99 | ((state->flags & SS_RESET) ? |
100 | BALLOON3_FPGA_SETnCLR : 0)); | ||
102 | return 0; | 101 | return 0; |
103 | } | 102 | } |
104 | 103 | ||
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index ae07b4db8a6e..3755e7c8c715 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | 27 | ||
28 | #include <mach/hardware.h> | 28 | #include <mach/hardware.h> |
29 | #include <mach/smemc.h> | ||
29 | #include <asm/io.h> | 30 | #include <asm/io.h> |
30 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
@@ -116,37 +117,49 @@ static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz, | |||
116 | 117 | ||
117 | static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock ) | 118 | static int pxa2xx_pcmcia_set_mcmem( int sock, int speed, int clock ) |
118 | { | 119 | { |
119 | MCMEM(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 120 | uint32_t val; |
121 | |||
122 | val = ((pxa2xx_mcxx_setup(speed, clock) | ||
120 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 123 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
121 | | ((pxa2xx_mcxx_asst(speed, clock) | 124 | | ((pxa2xx_mcxx_asst(speed, clock) |
122 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 125 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
123 | | ((pxa2xx_mcxx_hold(speed, clock) | 126 | | ((pxa2xx_mcxx_hold(speed, clock) |
124 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 127 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
125 | 128 | ||
129 | __raw_writel(val, MCMEM(sock)); | ||
130 | |||
126 | return 0; | 131 | return 0; |
127 | } | 132 | } |
128 | 133 | ||
129 | static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock ) | 134 | static int pxa2xx_pcmcia_set_mcio( int sock, int speed, int clock ) |
130 | { | 135 | { |
131 | MCIO(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 136 | uint32_t val; |
137 | |||
138 | val = ((pxa2xx_mcxx_setup(speed, clock) | ||
132 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 139 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
133 | | ((pxa2xx_mcxx_asst(speed, clock) | 140 | | ((pxa2xx_mcxx_asst(speed, clock) |
134 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 141 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
135 | | ((pxa2xx_mcxx_hold(speed, clock) | 142 | | ((pxa2xx_mcxx_hold(speed, clock) |
136 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 143 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
137 | 144 | ||
145 | __raw_writel(val, MCIO(sock)); | ||
146 | |||
138 | return 0; | 147 | return 0; |
139 | } | 148 | } |
140 | 149 | ||
141 | static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) | 150 | static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock ) |
142 | { | 151 | { |
143 | MCATT(sock) = ((pxa2xx_mcxx_setup(speed, clock) | 152 | uint32_t val; |
153 | |||
154 | val = ((pxa2xx_mcxx_setup(speed, clock) | ||
144 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) | 155 | & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) |
145 | | ((pxa2xx_mcxx_asst(speed, clock) | 156 | | ((pxa2xx_mcxx_asst(speed, clock) |
146 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) | 157 | & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) |
147 | | ((pxa2xx_mcxx_hold(speed, clock) | 158 | | ((pxa2xx_mcxx_hold(speed, clock) |
148 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); | 159 | & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); |
149 | 160 | ||
161 | __raw_writel(val, MCATT(sock)); | ||
162 | |||
150 | return 0; | 163 | return 0; |
151 | } | 164 | } |
152 | 165 | ||
@@ -166,8 +179,8 @@ static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int cl | |||
166 | 179 | ||
167 | static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) | 180 | static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt) |
168 | { | 181 | { |
169 | unsigned int clk = get_memclk_frequency_10khz(); | 182 | unsigned long clk = clk_get_rate(skt->clk); |
170 | return pxa2xx_pcmcia_set_mcxx(skt, clk); | 183 | return pxa2xx_pcmcia_set_mcxx(skt, clk / 10000); |
171 | } | 184 | } |
172 | 185 | ||
173 | #ifdef CONFIG_CPU_FREQ | 186 | #ifdef CONFIG_CPU_FREQ |
@@ -205,19 +218,18 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | |||
205 | static void pxa2xx_configure_sockets(struct device *dev) | 218 | static void pxa2xx_configure_sockets(struct device *dev) |
206 | { | 219 | { |
207 | struct pcmcia_low_level *ops = dev->platform_data; | 220 | struct pcmcia_low_level *ops = dev->platform_data; |
208 | |||
209 | /* | 221 | /* |
210 | * We have at least one socket, so set MECR:CIT | 222 | * We have at least one socket, so set MECR:CIT |
211 | * (Card Is There) | 223 | * (Card Is There) |
212 | */ | 224 | */ |
213 | MECR |= MECR_CIT; | 225 | uint32_t mecr = MECR_CIT; |
214 | 226 | ||
215 | /* Set MECR:NOS (Number Of Sockets) */ | 227 | /* Set MECR:NOS (Number Of Sockets) */ |
216 | if ((ops->first + ops->nr) > 1 || | 228 | if ((ops->first + ops->nr) > 1 || |
217 | machine_is_viper() || machine_is_arcom_zeus()) | 229 | machine_is_viper() || machine_is_arcom_zeus()) |
218 | MECR |= MECR_NOS; | 230 | mecr |= MECR_NOS; |
219 | else | 231 | |
220 | MECR &= ~MECR_NOS; | 232 | __raw_writel(mecr, MECR); |
221 | } | 233 | } |
222 | 234 | ||
223 | static const char *skt_names[] = { | 235 | static const char *skt_names[] = { |
@@ -270,24 +282,41 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) | |||
270 | struct pcmcia_low_level *ops; | 282 | struct pcmcia_low_level *ops; |
271 | struct skt_dev_info *sinfo; | 283 | struct skt_dev_info *sinfo; |
272 | struct soc_pcmcia_socket *skt; | 284 | struct soc_pcmcia_socket *skt; |
285 | struct clk *clk; | ||
273 | 286 | ||
274 | ops = (struct pcmcia_low_level *)dev->dev.platform_data; | 287 | ops = (struct pcmcia_low_level *)dev->dev.platform_data; |
275 | if (!ops) | 288 | if (!ops) { |
289 | ret = -ENODEV; | ||
290 | goto err0; | ||
291 | } | ||
292 | |||
293 | if (cpu_is_pxa320() && ops->nr > 1) { | ||
294 | dev_err(&dev->dev, "pxa320 supports only one pcmcia slot"); | ||
295 | ret = -EINVAL; | ||
296 | goto err0; | ||
297 | } | ||
298 | |||
299 | clk = clk_get(&dev->dev, NULL); | ||
300 | if (!clk) | ||
276 | return -ENODEV; | 301 | return -ENODEV; |
277 | 302 | ||
278 | pxa2xx_drv_pcmcia_ops(ops); | 303 | pxa2xx_drv_pcmcia_ops(ops); |
279 | 304 | ||
280 | sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); | 305 | sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); |
281 | if (!sinfo) | 306 | if (!sinfo) { |
307 | clk_put(clk); | ||
282 | return -ENOMEM; | 308 | return -ENOMEM; |
309 | } | ||
283 | 310 | ||
284 | sinfo->nskt = ops->nr; | 311 | sinfo->nskt = ops->nr; |
312 | sinfo->clk = clk; | ||
285 | 313 | ||
286 | /* Initialize processor specific parameters */ | 314 | /* Initialize processor specific parameters */ |
287 | for (i = 0; i < ops->nr; i++) { | 315 | for (i = 0; i < ops->nr; i++) { |
288 | skt = &sinfo->skt[i]; | 316 | skt = &sinfo->skt[i]; |
289 | 317 | ||
290 | skt->nr = ops->first + i; | 318 | skt->nr = ops->first + i; |
319 | skt->clk = clk; | ||
291 | skt->ops = ops; | 320 | skt->ops = ops; |
292 | skt->socket.owner = ops->owner; | 321 | skt->socket.owner = ops->owner; |
293 | skt->socket.dev.parent = &dev->dev; | 322 | skt->socket.dev.parent = &dev->dev; |
@@ -295,18 +324,26 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) | |||
295 | 324 | ||
296 | ret = pxa2xx_drv_pcmcia_add_one(skt); | 325 | ret = pxa2xx_drv_pcmcia_add_one(skt); |
297 | if (ret) | 326 | if (ret) |
298 | break; | 327 | goto err1; |
299 | } | 328 | } |
300 | 329 | ||
301 | if (ret) { | 330 | if (ret) { |
302 | while (--i >= 0) | 331 | while (--i >= 0) |
303 | soc_pcmcia_remove_one(&sinfo->skt[i]); | 332 | soc_pcmcia_remove_one(&sinfo->skt[i]); |
304 | kfree(sinfo); | 333 | kfree(sinfo); |
334 | clk_put(clk); | ||
305 | } else { | 335 | } else { |
306 | pxa2xx_configure_sockets(&dev->dev); | 336 | pxa2xx_configure_sockets(&dev->dev); |
307 | dev_set_drvdata(&dev->dev, sinfo); | 337 | dev_set_drvdata(&dev->dev, sinfo); |
308 | } | 338 | } |
309 | 339 | ||
340 | return 0; | ||
341 | |||
342 | err1: | ||
343 | while (--i >= 0) | ||
344 | soc_pcmcia_remove_one(&sinfo->skt[i]); | ||
345 | kfree(sinfo); | ||
346 | err0: | ||
310 | return ret; | 347 | return ret; |
311 | } | 348 | } |
312 | 349 | ||
@@ -320,6 +357,7 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) | |||
320 | for (i = 0; i < sinfo->nskt; i++) | 357 | for (i = 0; i < sinfo->nskt; i++) |
321 | soc_pcmcia_remove_one(&sinfo->skt[i]); | 358 | soc_pcmcia_remove_one(&sinfo->skt[i]); |
322 | 359 | ||
360 | clk_put(sinfo->clk); | ||
323 | kfree(sinfo); | 361 | kfree(sinfo); |
324 | return 0; | 362 | return 0; |
325 | } | 363 | } |
diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c new file mode 100644 index 000000000000..c3f72192af66 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_colibri.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_colibri.c | ||
3 | * | ||
4 | * Driver for Toradex Colibri PXA270 CF socket | ||
5 | * | ||
6 | * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/gpio.h> | ||
18 | |||
19 | #include <asm/mach-types.h> | ||
20 | |||
21 | #include "soc_common.h" | ||
22 | |||
23 | #define COLIBRI270_RESET_GPIO 53 | ||
24 | #define COLIBRI270_PPEN_GPIO 107 | ||
25 | #define COLIBRI270_BVD1_GPIO 83 | ||
26 | #define COLIBRI270_BVD2_GPIO 82 | ||
27 | #define COLIBRI270_DETECT_GPIO 84 | ||
28 | #define COLIBRI270_READY_GPIO 1 | ||
29 | |||
30 | #define COLIBRI320_RESET_GPIO 77 | ||
31 | #define COLIBRI320_PPEN_GPIO 57 | ||
32 | #define COLIBRI320_BVD1_GPIO 53 | ||
33 | #define COLIBRI320_BVD2_GPIO 79 | ||
34 | #define COLIBRI320_DETECT_GPIO 81 | ||
35 | #define COLIBRI320_READY_GPIO 29 | ||
36 | |||
37 | static struct { | ||
38 | int reset_gpio; | ||
39 | int ppen_gpio; | ||
40 | int bvd1_gpio; | ||
41 | int bvd2_gpio; | ||
42 | int detect_gpio; | ||
43 | int ready_gpio; | ||
44 | } colibri_pcmcia_gpio; | ||
45 | |||
46 | static struct pcmcia_irqs colibri_irqs[] = { | ||
47 | { | ||
48 | .sock = 0, | ||
49 | .str = "PCMCIA CD" | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
54 | { | ||
55 | int ret; | ||
56 | |||
57 | ret = gpio_request(colibri_pcmcia_gpio.detect_gpio, "DETECT"); | ||
58 | if (ret) | ||
59 | goto err1; | ||
60 | ret = gpio_direction_input(colibri_pcmcia_gpio.detect_gpio); | ||
61 | if (ret) | ||
62 | goto err2; | ||
63 | |||
64 | ret = gpio_request(colibri_pcmcia_gpio.ready_gpio, "READY"); | ||
65 | if (ret) | ||
66 | goto err2; | ||
67 | ret = gpio_direction_input(colibri_pcmcia_gpio.ready_gpio); | ||
68 | if (ret) | ||
69 | goto err3; | ||
70 | |||
71 | ret = gpio_request(colibri_pcmcia_gpio.bvd1_gpio, "BVD1"); | ||
72 | if (ret) | ||
73 | goto err3; | ||
74 | ret = gpio_direction_input(colibri_pcmcia_gpio.bvd1_gpio); | ||
75 | if (ret) | ||
76 | goto err4; | ||
77 | |||
78 | ret = gpio_request(colibri_pcmcia_gpio.bvd2_gpio, "BVD2"); | ||
79 | if (ret) | ||
80 | goto err4; | ||
81 | ret = gpio_direction_input(colibri_pcmcia_gpio.bvd2_gpio); | ||
82 | if (ret) | ||
83 | goto err5; | ||
84 | |||
85 | ret = gpio_request(colibri_pcmcia_gpio.ppen_gpio, "PPEN"); | ||
86 | if (ret) | ||
87 | goto err5; | ||
88 | ret = gpio_direction_output(colibri_pcmcia_gpio.ppen_gpio, 0); | ||
89 | if (ret) | ||
90 | goto err6; | ||
91 | |||
92 | ret = gpio_request(colibri_pcmcia_gpio.reset_gpio, "RESET"); | ||
93 | if (ret) | ||
94 | goto err6; | ||
95 | ret = gpio_direction_output(colibri_pcmcia_gpio.reset_gpio, 1); | ||
96 | if (ret) | ||
97 | goto err7; | ||
98 | |||
99 | colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpio.detect_gpio); | ||
100 | skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpio.ready_gpio); | ||
101 | |||
102 | return soc_pcmcia_request_irqs(skt, colibri_irqs, | ||
103 | ARRAY_SIZE(colibri_irqs)); | ||
104 | |||
105 | err7: | ||
106 | gpio_free(colibri_pcmcia_gpio.detect_gpio); | ||
107 | err6: | ||
108 | gpio_free(colibri_pcmcia_gpio.ready_gpio); | ||
109 | err5: | ||
110 | gpio_free(colibri_pcmcia_gpio.bvd1_gpio); | ||
111 | err4: | ||
112 | gpio_free(colibri_pcmcia_gpio.bvd2_gpio); | ||
113 | err3: | ||
114 | gpio_free(colibri_pcmcia_gpio.reset_gpio); | ||
115 | err2: | ||
116 | gpio_free(colibri_pcmcia_gpio.ppen_gpio); | ||
117 | err1: | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
122 | { | ||
123 | gpio_free(colibri_pcmcia_gpio.detect_gpio); | ||
124 | gpio_free(colibri_pcmcia_gpio.ready_gpio); | ||
125 | gpio_free(colibri_pcmcia_gpio.bvd1_gpio); | ||
126 | gpio_free(colibri_pcmcia_gpio.bvd2_gpio); | ||
127 | gpio_free(colibri_pcmcia_gpio.reset_gpio); | ||
128 | gpio_free(colibri_pcmcia_gpio.ppen_gpio); | ||
129 | } | ||
130 | |||
131 | static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
132 | struct pcmcia_state *state) | ||
133 | { | ||
134 | |||
135 | state->detect = !!gpio_get_value(colibri_pcmcia_gpio.detect_gpio); | ||
136 | state->ready = !!gpio_get_value(colibri_pcmcia_gpio.ready_gpio); | ||
137 | state->bvd1 = !!gpio_get_value(colibri_pcmcia_gpio.bvd1_gpio); | ||
138 | state->bvd2 = !!gpio_get_value(colibri_pcmcia_gpio.bvd2_gpio); | ||
139 | state->wrprot = 0; | ||
140 | state->vs_3v = 1; | ||
141 | state->vs_Xv = 0; | ||
142 | } | ||
143 | |||
144 | static int | ||
145 | colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
146 | const socket_state_t *state) | ||
147 | { | ||
148 | gpio_set_value(colibri_pcmcia_gpio.ppen_gpio, | ||
149 | !(state->Vcc == 33 && state->Vpp < 50)); | ||
150 | gpio_set_value(colibri_pcmcia_gpio.reset_gpio, state->flags & SS_RESET); | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static void colibri_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
155 | { | ||
156 | } | ||
157 | |||
158 | static void colibri_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | static struct pcmcia_low_level colibri_pcmcia_ops = { | ||
163 | .owner = THIS_MODULE, | ||
164 | |||
165 | .first = 0, | ||
166 | .nr = 1, | ||
167 | |||
168 | .hw_init = colibri_pcmcia_hw_init, | ||
169 | .hw_shutdown = colibri_pcmcia_hw_shutdown, | ||
170 | |||
171 | .socket_state = colibri_pcmcia_socket_state, | ||
172 | .configure_socket = colibri_pcmcia_configure_socket, | ||
173 | |||
174 | .socket_init = colibri_pcmcia_socket_init, | ||
175 | .socket_suspend = colibri_pcmcia_socket_suspend, | ||
176 | }; | ||
177 | |||
178 | static struct platform_device *colibri_pcmcia_device; | ||
179 | |||
180 | static int __init colibri_pcmcia_init(void) | ||
181 | { | ||
182 | int ret; | ||
183 | |||
184 | colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
185 | if (!colibri_pcmcia_device) | ||
186 | return -ENOMEM; | ||
187 | |||
188 | /* Colibri PXA270 */ | ||
189 | if (machine_is_colibri()) { | ||
190 | colibri_pcmcia_gpio.reset_gpio = COLIBRI270_RESET_GPIO; | ||
191 | colibri_pcmcia_gpio.ppen_gpio = COLIBRI270_PPEN_GPIO; | ||
192 | colibri_pcmcia_gpio.bvd1_gpio = COLIBRI270_BVD1_GPIO; | ||
193 | colibri_pcmcia_gpio.bvd2_gpio = COLIBRI270_BVD2_GPIO; | ||
194 | colibri_pcmcia_gpio.detect_gpio = COLIBRI270_DETECT_GPIO; | ||
195 | colibri_pcmcia_gpio.ready_gpio = COLIBRI270_READY_GPIO; | ||
196 | /* Colibri PXA320 */ | ||
197 | } else if (machine_is_colibri320()) { | ||
198 | colibri_pcmcia_gpio.reset_gpio = COLIBRI320_RESET_GPIO; | ||
199 | colibri_pcmcia_gpio.ppen_gpio = COLIBRI320_PPEN_GPIO; | ||
200 | colibri_pcmcia_gpio.bvd1_gpio = COLIBRI320_BVD1_GPIO; | ||
201 | colibri_pcmcia_gpio.bvd2_gpio = COLIBRI320_BVD2_GPIO; | ||
202 | colibri_pcmcia_gpio.detect_gpio = COLIBRI320_DETECT_GPIO; | ||
203 | colibri_pcmcia_gpio.ready_gpio = COLIBRI320_READY_GPIO; | ||
204 | } | ||
205 | |||
206 | ret = platform_device_add_data(colibri_pcmcia_device, | ||
207 | &colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops)); | ||
208 | |||
209 | if (!ret) | ||
210 | ret = platform_device_add(colibri_pcmcia_device); | ||
211 | |||
212 | if (ret) | ||
213 | platform_device_put(colibri_pcmcia_device); | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static void __exit colibri_pcmcia_exit(void) | ||
219 | { | ||
220 | platform_device_unregister(colibri_pcmcia_device); | ||
221 | } | ||
222 | |||
223 | module_init(colibri_pcmcia_init); | ||
224 | module_exit(colibri_pcmcia_exit); | ||
225 | |||
226 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
227 | MODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320"); | ||
228 | MODULE_ALIAS("platform:pxa2xx-pcmcia"); | ||
229 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 6b228590b3fd..fb9740d3e9a7 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c | |||
@@ -53,6 +53,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { | |||
53 | #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600) | 53 | #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600) |
54 | pcmcia_h3600_init, | 54 | pcmcia_h3600_init, |
55 | #endif | 55 | #endif |
56 | #ifdef CONFIG_SA1100_NANOENGINE | ||
57 | pcmcia_nanoengine_init, | ||
58 | #endif | ||
56 | #ifdef CONFIG_SA1100_SHANNON | 59 | #ifdef CONFIG_SA1100_SHANNON |
57 | pcmcia_shannon_init, | 60 | pcmcia_shannon_init, |
58 | #endif | 61 | #endif |
diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h index 794f96a35bba..adb08dbc723f 100644 --- a/drivers/pcmcia/sa1100_generic.h +++ b/drivers/pcmcia/sa1100_generic.h | |||
@@ -13,6 +13,7 @@ extern int pcmcia_freebird_init(struct device *); | |||
13 | extern int pcmcia_gcplus_init(struct device *); | 13 | extern int pcmcia_gcplus_init(struct device *); |
14 | extern int pcmcia_graphicsmaster_init(struct device *); | 14 | extern int pcmcia_graphicsmaster_init(struct device *); |
15 | extern int pcmcia_h3600_init(struct device *); | 15 | extern int pcmcia_h3600_init(struct device *); |
16 | extern int pcmcia_nanoengine_init(struct device *); | ||
16 | extern int pcmcia_pangolin_init(struct device *); | 17 | extern int pcmcia_pangolin_init(struct device *); |
17 | extern int pcmcia_pfs168_init(struct device *); | 18 | extern int pcmcia_pfs168_init(struct device *); |
18 | extern int pcmcia_shannon_init(struct device *); | 19 | extern int pcmcia_shannon_init(struct device *); |
diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c new file mode 100644 index 000000000000..3d2652e2f5ae --- /dev/null +++ b/drivers/pcmcia/sa1100_nanoengine.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_nanoengine.c | ||
3 | * | ||
4 | * PCMCIA implementation routines for BSI nanoEngine. | ||
5 | * | ||
6 | * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine | ||
7 | * board you should carefully read this: | ||
8 | * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/ | ||
9 | * | ||
10 | * Copyright (C) 2010 Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br> | ||
11 | * | ||
12 | * Based on original work for kernel 2.4 by | ||
13 | * Miguel Freitas <miguel@cpti.cetuc.puc-rio.br> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License version 2 as | ||
17 | * published by the Free Software Foundation. | ||
18 | * | ||
19 | */ | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/signal.h> | ||
28 | |||
29 | #include <asm/mach-types.h> | ||
30 | #include <asm/irq.h> | ||
31 | |||
32 | #include <mach/hardware.h> | ||
33 | #include <mach/nanoengine.h> | ||
34 | |||
35 | #include "sa1100_generic.h" | ||
36 | |||
37 | static struct pcmcia_irqs irqs_skt0[] = { | ||
38 | /* socket, IRQ, name */ | ||
39 | { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" }, | ||
40 | }; | ||
41 | |||
42 | static struct pcmcia_irqs irqs_skt1[] = { | ||
43 | /* socket, IRQ, name */ | ||
44 | { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" }, | ||
45 | }; | ||
46 | |||
47 | struct nanoengine_pins { | ||
48 | unsigned input_pins; | ||
49 | unsigned output_pins; | ||
50 | unsigned clear_outputs; | ||
51 | unsigned transition_pins; | ||
52 | unsigned pci_irq; | ||
53 | struct pcmcia_irqs *pcmcia_irqs; | ||
54 | unsigned pcmcia_irqs_size; | ||
55 | }; | ||
56 | |||
57 | static struct nanoengine_pins nano_skts[] = { | ||
58 | { | ||
59 | .input_pins = GPIO_PC_READY0 | GPIO_PC_CD0, | ||
60 | .output_pins = GPIO_PC_RESET0, | ||
61 | .clear_outputs = GPIO_PC_RESET0, | ||
62 | .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD0, | ||
63 | .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY0, | ||
64 | .pcmcia_irqs = irqs_skt0, | ||
65 | .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt0) | ||
66 | }, { | ||
67 | .input_pins = GPIO_PC_READY1 | GPIO_PC_CD1, | ||
68 | .output_pins = GPIO_PC_RESET1, | ||
69 | .clear_outputs = GPIO_PC_RESET1, | ||
70 | .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD1, | ||
71 | .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY1, | ||
72 | .pcmcia_irqs = irqs_skt1, | ||
73 | .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt1) | ||
74 | } | ||
75 | }; | ||
76 | |||
77 | unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts); | ||
78 | |||
79 | static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
80 | { | ||
81 | unsigned i = skt->nr; | ||
82 | |||
83 | if (i >= num_nano_pcmcia_sockets) | ||
84 | return -ENXIO; | ||
85 | |||
86 | GPDR &= ~nano_skts[i].input_pins; | ||
87 | GPDR |= nano_skts[i].output_pins; | ||
88 | GPCR = nano_skts[i].clear_outputs; | ||
89 | set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH); | ||
90 | skt->socket.pci_irq = nano_skts[i].pci_irq; | ||
91 | |||
92 | return soc_pcmcia_request_irqs(skt, | ||
93 | nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Release all resources. | ||
98 | */ | ||
99 | static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
100 | { | ||
101 | unsigned i = skt->nr; | ||
102 | |||
103 | if (i >= num_nano_pcmcia_sockets) | ||
104 | return; | ||
105 | |||
106 | soc_pcmcia_free_irqs(skt, | ||
107 | nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); | ||
108 | } | ||
109 | |||
110 | static int nanoengine_pcmcia_configure_socket( | ||
111 | struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
112 | { | ||
113 | unsigned reset; | ||
114 | unsigned i = skt->nr; | ||
115 | |||
116 | if (i >= num_nano_pcmcia_sockets) | ||
117 | return -ENXIO; | ||
118 | |||
119 | switch (i) { | ||
120 | case 0: | ||
121 | reset = GPIO_PC_RESET0; | ||
122 | break; | ||
123 | case 1: | ||
124 | reset = GPIO_PC_RESET1; | ||
125 | break; | ||
126 | default: | ||
127 | return -ENXIO; | ||
128 | } | ||
129 | |||
130 | if (state->flags & SS_RESET) | ||
131 | GPSR = reset; | ||
132 | else | ||
133 | GPCR = reset; | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void nanoengine_pcmcia_socket_state( | ||
139 | struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | ||
140 | { | ||
141 | unsigned long levels = GPLR; | ||
142 | unsigned i = skt->nr; | ||
143 | |||
144 | if (i >= num_nano_pcmcia_sockets) | ||
145 | return; | ||
146 | |||
147 | memset(state, 0, sizeof(struct pcmcia_state)); | ||
148 | switch (i) { | ||
149 | case 0: | ||
150 | state->ready = (levels & GPIO_PC_READY0) ? 1 : 0; | ||
151 | state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0; | ||
152 | break; | ||
153 | case 1: | ||
154 | state->ready = (levels & GPIO_PC_READY1) ? 1 : 0; | ||
155 | state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0; | ||
156 | break; | ||
157 | default: | ||
158 | return; | ||
159 | } | ||
160 | state->bvd1 = 1; | ||
161 | state->bvd2 = 1; | ||
162 | state->wrprot = 0; /* Not available */ | ||
163 | state->vs_3v = 1; /* Can only apply 3.3V */ | ||
164 | state->vs_Xv = 0; | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * Enable card status IRQs on (re-)initialisation. This can | ||
169 | * be called at initialisation, power management event, or | ||
170 | * pcmcia event. | ||
171 | */ | ||
172 | static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
173 | { | ||
174 | unsigned i = skt->nr; | ||
175 | |||
176 | if (i >= num_nano_pcmcia_sockets) | ||
177 | return; | ||
178 | |||
179 | soc_pcmcia_enable_irqs(skt, | ||
180 | nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Disable card status IRQs on suspend. | ||
185 | */ | ||
186 | static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
187 | { | ||
188 | unsigned i = skt->nr; | ||
189 | |||
190 | if (i >= num_nano_pcmcia_sockets) | ||
191 | return; | ||
192 | |||
193 | soc_pcmcia_disable_irqs(skt, | ||
194 | nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); | ||
195 | } | ||
196 | |||
197 | static struct pcmcia_low_level nanoengine_pcmcia_ops = { | ||
198 | .owner = THIS_MODULE, | ||
199 | |||
200 | .hw_init = nanoengine_pcmcia_hw_init, | ||
201 | .hw_shutdown = nanoengine_pcmcia_hw_shutdown, | ||
202 | |||
203 | .configure_socket = nanoengine_pcmcia_configure_socket, | ||
204 | .socket_state = nanoengine_pcmcia_socket_state, | ||
205 | .socket_init = nanoengine_pcmcia_socket_init, | ||
206 | .socket_suspend = nanoengine_pcmcia_socket_suspend, | ||
207 | }; | ||
208 | |||
209 | int pcmcia_nanoengine_init(struct device *dev) | ||
210 | { | ||
211 | int ret = -ENODEV; | ||
212 | |||
213 | if (machine_is_nanoengine()) | ||
214 | ret = sa11xx_drv_pcmcia_probe( | ||
215 | dev, &nanoengine_pcmcia_ops, 0, 2); | ||
216 | |||
217 | return ret; | ||
218 | } | ||
219 | |||
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 2fe8cb8e95cd..5a9a392eacdf 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
@@ -31,20 +31,20 @@ | |||
31 | ======================================================================*/ | 31 | ======================================================================*/ |
32 | 32 | ||
33 | 33 | ||
34 | #include <linux/module.h> | 34 | #include <linux/cpufreq.h> |
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/io.h> | ||
38 | #include <linux/irq.h> | ||
37 | #include <linux/kernel.h> | 39 | #include <linux/kernel.h> |
38 | #include <linux/timer.h> | ||
39 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/module.h> | ||
42 | #include <linux/moduleparam.h> | ||
40 | #include <linux/mutex.h> | 43 | #include <linux/mutex.h> |
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/irq.h> | ||
43 | #include <linux/spinlock.h> | 44 | #include <linux/spinlock.h> |
44 | #include <linux/cpufreq.h> | 45 | #include <linux/timer.h> |
45 | 46 | ||
46 | #include <mach/hardware.h> | 47 | #include <mach/hardware.h> |
47 | #include <asm/io.h> | ||
48 | #include <asm/system.h> | 48 | #include <asm/system.h> |
49 | 49 | ||
50 | #include "soc_common.h" | 50 | #include "soc_common.h" |
@@ -74,7 +74,8 @@ EXPORT_SYMBOL(soc_pcmcia_debug); | |||
74 | 74 | ||
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | #define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket) | 77 | #define to_soc_pcmcia_socket(x) \ |
78 | container_of(x, struct soc_pcmcia_socket, socket) | ||
78 | 79 | ||
79 | static unsigned short | 80 | static unsigned short |
80 | calc_speed(unsigned short *spds, int num, unsigned short dflt) | 81 | calc_speed(unsigned short *spds, int num, unsigned short dflt) |
@@ -91,11 +92,15 @@ calc_speed(unsigned short *spds, int num, unsigned short dflt) | |||
91 | return speed; | 92 | return speed; |
92 | } | 93 | } |
93 | 94 | ||
94 | void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing) | 95 | void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, |
96 | struct soc_pcmcia_timing *timing) | ||
95 | { | 97 | { |
96 | timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); | 98 | timing->io = |
97 | timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | 99 | calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); |
98 | timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | 100 | timing->mem = |
101 | calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | ||
102 | timing->attr = | ||
103 | calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); | ||
99 | } | 104 | } |
100 | EXPORT_SYMBOL(soc_common_pcmcia_get_timing); | 105 | EXPORT_SYMBOL(soc_common_pcmcia_get_timing); |
101 | 106 | ||
@@ -137,8 +142,8 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) | |||
137 | * | 142 | * |
138 | * Convert PCMCIA socket state to our socket configure structure. | 143 | * Convert PCMCIA socket state to our socket configure structure. |
139 | */ | 144 | */ |
140 | static int | 145 | static int soc_common_pcmcia_config_skt( |
141 | soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state) | 146 | struct soc_pcmcia_socket *skt, socket_state_t *state) |
142 | { | 147 | { |
143 | int ret; | 148 | int ret; |
144 | 149 | ||
@@ -150,7 +155,8 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat | |||
150 | */ | 155 | */ |
151 | if (skt->irq_state != 1 && state->io_irq) { | 156 | if (skt->irq_state != 1 && state->io_irq) { |
152 | skt->irq_state = 1; | 157 | skt->irq_state = 1; |
153 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING); | 158 | set_irq_type(skt->socket.pci_irq, |
159 | IRQ_TYPE_EDGE_FALLING); | ||
154 | } else if (skt->irq_state == 1 && state->io_irq == 0) { | 160 | } else if (skt->irq_state == 1 && state->io_irq == 0) { |
155 | skt->irq_state = 0; | 161 | skt->irq_state = 0; |
156 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); | 162 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); |
@@ -304,24 +310,24 @@ soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | |||
304 | * of power configuration, reset, &c. We also record the value of | 310 | * of power configuration, reset, &c. We also record the value of |
305 | * `state' in order to regurgitate it to the PCMCIA core later. | 311 | * `state' in order to regurgitate it to the PCMCIA core later. |
306 | */ | 312 | */ |
307 | static int | 313 | static int soc_common_pcmcia_set_socket( |
308 | soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | 314 | struct pcmcia_socket *sock, socket_state_t *state) |
309 | { | 315 | { |
310 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | 316 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); |
311 | 317 | ||
312 | debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", | 318 | debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n", |
313 | (state->csc_mask==0)?"<NONE> ":"", | 319 | (state->csc_mask == 0) ? "<NONE> " : "", |
314 | (state->csc_mask&SS_DETECT)?"DETECT ":"", | 320 | (state->csc_mask & SS_DETECT) ? "DETECT " : "", |
315 | (state->csc_mask&SS_READY)?"READY ":"", | 321 | (state->csc_mask & SS_READY) ? "READY " : "", |
316 | (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", | 322 | (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "", |
317 | (state->csc_mask&SS_BATWARN)?"BATWARN ":"", | 323 | (state->csc_mask & SS_BATWARN) ? "BATWARN " : "", |
318 | (state->csc_mask&SS_STSCHG)?"STSCHG ":"", | 324 | (state->csc_mask & SS_STSCHG) ? "STSCHG " : "", |
319 | (state->flags==0)?"<NONE> ":"", | 325 | (state->flags == 0) ? "<NONE> " : "", |
320 | (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", | 326 | (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "", |
321 | (state->flags&SS_IOCARD)?"IOCARD ":"", | 327 | (state->flags & SS_IOCARD) ? "IOCARD " : "", |
322 | (state->flags&SS_RESET)?"RESET ":"", | 328 | (state->flags & SS_RESET) ? "RESET " : "", |
323 | (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", | 329 | (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "", |
324 | (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", | 330 | (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "", |
325 | state->Vcc, state->Vpp, state->io_irq); | 331 | state->Vcc, state->Vpp, state->io_irq); |
326 | 332 | ||
327 | return soc_common_pcmcia_config_skt(skt, state); | 333 | return soc_common_pcmcia_config_skt(skt, state); |
@@ -336,8 +342,8 @@ soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
336 | * | 342 | * |
337 | * Returns: 0 on success, -1 on error | 343 | * Returns: 0 on success, -1 on error |
338 | */ | 344 | */ |
339 | static int | 345 | static int soc_common_pcmcia_set_io_map( |
340 | soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) | 346 | struct pcmcia_socket *sock, struct pccard_io_map *map) |
341 | { | 347 | { |
342 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | 348 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); |
343 | unsigned short speed = map->speed; | 349 | unsigned short speed = map->speed; |
@@ -346,14 +352,14 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m | |||
346 | map->map, map->speed, (unsigned long long)map->start, | 352 | map->map, map->speed, (unsigned long long)map->start, |
347 | (unsigned long long)map->stop); | 353 | (unsigned long long)map->stop); |
348 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", | 354 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", |
349 | (map->flags==0)?"<NONE>":"", | 355 | (map->flags == 0) ? "<NONE>" : "", |
350 | (map->flags&MAP_ACTIVE)?"ACTIVE ":"", | 356 | (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", |
351 | (map->flags&MAP_16BIT)?"16BIT ":"", | 357 | (map->flags & MAP_16BIT) ? "16BIT " : "", |
352 | (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", | 358 | (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", |
353 | (map->flags&MAP_0WS)?"0WS ":"", | 359 | (map->flags & MAP_0WS) ? "0WS " : "", |
354 | (map->flags&MAP_WRPROT)?"WRPROT ":"", | 360 | (map->flags & MAP_WRPROT) ? "WRPROT " : "", |
355 | (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", | 361 | (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "", |
356 | (map->flags&MAP_PREFETCH)?"PREFETCH ":""); | 362 | (map->flags & MAP_PREFETCH) ? "PREFETCH " : ""); |
357 | 363 | ||
358 | if (map->map >= MAX_IO_WIN) { | 364 | if (map->map >= MAX_IO_WIN) { |
359 | printk(KERN_ERR "%s(): map (%d) out of range\n", __func__, | 365 | printk(KERN_ERR "%s(): map (%d) out of range\n", __func__, |
@@ -390,8 +396,8 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m | |||
390 | * | 396 | * |
391 | * Returns: 0 on success, -ERRNO on error | 397 | * Returns: 0 on success, -ERRNO on error |
392 | */ | 398 | */ |
393 | static int | 399 | static int soc_common_pcmcia_set_mem_map( |
394 | soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) | 400 | struct pcmcia_socket *sock, struct pccard_mem_map *map) |
395 | { | 401 | { |
396 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | 402 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); |
397 | struct resource *res; | 403 | struct resource *res; |
@@ -400,14 +406,14 @@ soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map | |||
400 | debug(skt, 2, "map %u speed %u card_start %08x\n", | 406 | debug(skt, 2, "map %u speed %u card_start %08x\n", |
401 | map->map, map->speed, map->card_start); | 407 | map->map, map->speed, map->card_start); |
402 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", | 408 | debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", |
403 | (map->flags==0)?"<NONE>":"", | 409 | (map->flags == 0) ? "<NONE>" : "", |
404 | (map->flags&MAP_ACTIVE)?"ACTIVE ":"", | 410 | (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", |
405 | (map->flags&MAP_16BIT)?"16BIT ":"", | 411 | (map->flags & MAP_16BIT) ? "16BIT " : "", |
406 | (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", | 412 | (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", |
407 | (map->flags&MAP_0WS)?"0WS ":"", | 413 | (map->flags & MAP_0WS) ? "0WS " : "", |
408 | (map->flags&MAP_WRPROT)?"WRPROT ":"", | 414 | (map->flags & MAP_WRPROT) ? "WRPROT " : "", |
409 | (map->flags&MAP_ATTRIB)?"ATTRIB ":"", | 415 | (map->flags & MAP_ATTRIB) ? "ATTRIB " : "", |
410 | (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); | 416 | (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : ""); |
411 | 417 | ||
412 | if (map->map >= MAX_WIN) | 418 | if (map->map >= MAX_WIN) |
413 | return -EINVAL; | 419 | return -EINVAL; |
@@ -462,8 +468,8 @@ static struct bittbl conf_bits[] = { | |||
462 | { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, | 468 | { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, |
463 | }; | 469 | }; |
464 | 470 | ||
465 | static void | 471 | static void dump_bits(char **p, const char *prefix, |
466 | dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) | 472 | unsigned int val, struct bittbl *bits, int sz) |
467 | { | 473 | { |
468 | char *b = *p; | 474 | char *b = *p; |
469 | int i; | 475 | int i; |
@@ -481,13 +487,14 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i | |||
481 | * | 487 | * |
482 | * Returns: the number of characters added to the buffer | 488 | * Returns: the number of characters added to the buffer |
483 | */ | 489 | */ |
484 | static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) | 490 | static ssize_t show_status( |
491 | struct device *dev, struct device_attribute *attr, char *buf) | ||
485 | { | 492 | { |
486 | struct soc_pcmcia_socket *skt = | 493 | struct soc_pcmcia_socket *skt = |
487 | container_of(dev, struct soc_pcmcia_socket, socket.dev); | 494 | container_of(dev, struct soc_pcmcia_socket, socket.dev); |
488 | char *p = buf; | 495 | char *p = buf; |
489 | 496 | ||
490 | p+=sprintf(p, "slot : %d\n", skt->nr); | 497 | p += sprintf(p, "slot : %d\n", skt->nr); |
491 | 498 | ||
492 | dump_bits(&p, "status", skt->status, | 499 | dump_bits(&p, "status", skt->status, |
493 | status_bits, ARRAY_SIZE(status_bits)); | 500 | status_bits, ARRAY_SIZE(status_bits)); |
@@ -496,12 +503,12 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch | |||
496 | dump_bits(&p, "cs_flags", skt->cs_state.flags, | 503 | dump_bits(&p, "cs_flags", skt->cs_state.flags, |
497 | conf_bits, ARRAY_SIZE(conf_bits)); | 504 | conf_bits, ARRAY_SIZE(conf_bits)); |
498 | 505 | ||
499 | p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); | 506 | p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); |
500 | p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); | 507 | p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); |
501 | p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, | 508 | p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, |
502 | skt->socket.pci_irq); | 509 | skt->socket.pci_irq); |
503 | if (skt->ops->show_timing) | 510 | if (skt->ops->show_timing) |
504 | p+=skt->ops->show_timing(skt, p); | 511 | p += skt->ops->show_timing(skt, p); |
505 | 512 | ||
506 | return p-buf; | 513 | return p-buf; |
507 | } | 514 | } |
@@ -594,7 +601,7 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) | |||
594 | 601 | ||
595 | mutex_lock(&soc_pcmcia_sockets_lock); | 602 | mutex_lock(&soc_pcmcia_sockets_lock); |
596 | list_for_each_entry(skt, &soc_pcmcia_sockets, node) | 603 | list_for_each_entry(skt, &soc_pcmcia_sockets, node) |
597 | if ( skt->ops->frequency_change ) | 604 | if (skt->ops->frequency_change) |
598 | ret += skt->ops->frequency_change(skt, val, freqs); | 605 | ret += skt->ops->frequency_change(skt, val, freqs); |
599 | mutex_unlock(&soc_pcmcia_sockets_lock); | 606 | mutex_unlock(&soc_pcmcia_sockets_lock); |
600 | 607 | ||
@@ -620,7 +627,8 @@ fs_initcall(soc_pcmcia_cpufreq_register); | |||
620 | 627 | ||
621 | static void soc_pcmcia_cpufreq_unregister(void) | 628 | static void soc_pcmcia_cpufreq_unregister(void) |
622 | { | 629 | { |
623 | cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); | 630 | cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, |
631 | CPUFREQ_TRANSITION_NOTIFIER); | ||
624 | } | 632 | } |
625 | module_exit(soc_pcmcia_cpufreq_unregister); | 633 | module_exit(soc_pcmcia_cpufreq_unregister); |
626 | 634 | ||
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index bbcd5385a221..9daa73615c8b 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define _ASM_ARCH_PCMCIA | 10 | #define _ASM_ARCH_PCMCIA |
11 | 11 | ||
12 | /* include the world */ | 12 | /* include the world */ |
13 | #include <linux/clk.h> | ||
13 | #include <linux/cpufreq.h> | 14 | #include <linux/cpufreq.h> |
14 | #include <pcmcia/ss.h> | 15 | #include <pcmcia/ss.h> |
15 | #include <pcmcia/cistpl.h> | 16 | #include <pcmcia/cistpl.h> |
@@ -29,6 +30,7 @@ struct soc_pcmcia_socket { | |||
29 | * Info from low level handler | 30 | * Info from low level handler |
30 | */ | 31 | */ |
31 | unsigned int nr; | 32 | unsigned int nr; |
33 | struct clk *clk; | ||
32 | 34 | ||
33 | /* | 35 | /* |
34 | * Core PCMCIA state | 36 | * Core PCMCIA state |
@@ -56,6 +58,7 @@ struct soc_pcmcia_socket { | |||
56 | 58 | ||
57 | struct skt_dev_info { | 59 | struct skt_dev_info { |
58 | int nskt; | 60 | int nskt; |
61 | struct clk *clk; | ||
59 | struct soc_pcmcia_socket skt[0]; | 62 | struct soc_pcmcia_socket skt[0]; |
60 | }; | 63 | }; |
61 | 64 | ||
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e4a44b641702..88ea52b8647a 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
@@ -39,10 +39,10 @@ | |||
39 | #include <mach/regs-ost.h> | 39 | #include <mach/regs-ost.h> |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | #define RTC_DEF_DIVIDER 32768 - 1 | 42 | #define RTC_DEF_DIVIDER (32768 - 1) |
43 | #define RTC_DEF_TRIM 0 | 43 | #define RTC_DEF_TRIM 0 |
44 | 44 | ||
45 | static unsigned long rtc_freq = 1024; | 45 | static const unsigned long RTC_FREQ = 1024; |
46 | static unsigned long timer_freq; | 46 | static unsigned long timer_freq; |
47 | static struct rtc_time rtc_alarm; | 47 | static struct rtc_time rtc_alarm; |
48 | static DEFINE_SPINLOCK(sa1100_rtc_lock); | 48 | static DEFINE_SPINLOCK(sa1100_rtc_lock); |
@@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm) | |||
61 | * Calculate the next alarm time given the requested alarm time mask | 61 | * Calculate the next alarm time given the requested alarm time mask |
62 | * and the current time. | 62 | * and the current time. |
63 | */ | 63 | */ |
64 | static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) | 64 | static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, |
65 | struct rtc_time *alrm) | ||
65 | { | 66 | { |
66 | unsigned long next_time; | 67 | unsigned long next_time; |
67 | unsigned long now_time; | 68 | unsigned long now_time; |
@@ -116,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
116 | rtsr = RTSR; | 117 | rtsr = RTSR; |
117 | /* clear interrupt sources */ | 118 | /* clear interrupt sources */ |
118 | RTSR = 0; | 119 | RTSR = 0; |
119 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | 120 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
121 | * See also the comments in sa1100_rtc_probe(). */ | ||
122 | if (rtsr & (RTSR_ALE | RTSR_HZE)) { | ||
123 | /* This is the original code, before there was the if test | ||
124 | * above. This code does not clear interrupts that were not | ||
125 | * enabled. */ | ||
126 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | ||
127 | } else { | ||
128 | /* For some reason, it is possible to enter this routine | ||
129 | * without interruptions enabled, it has been tested with | ||
130 | * several units (Bug in SA11xx chip?). | ||
131 | * | ||
132 | * This situation leads to an infinite "loop" of interrupt | ||
133 | * routine calling and as a result the processor seems to | ||
134 | * lock on its first call to open(). */ | ||
135 | RTSR = RTSR_AL | RTSR_HZ; | ||
136 | } | ||
120 | 137 | ||
121 | /* clear alarm interrupt if it has occurred */ | 138 | /* clear alarm interrupt if it has occurred */ |
122 | if (rtsr & RTSR_AL) | 139 | if (rtsr & RTSR_AL) |
@@ -139,8 +156,58 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
139 | return IRQ_HANDLED; | 156 | return IRQ_HANDLED; |
140 | } | 157 | } |
141 | 158 | ||
159 | static int sa1100_irq_set_freq(struct device *dev, int freq) | ||
160 | { | ||
161 | if (freq < 1 || freq > timer_freq) { | ||
162 | return -EINVAL; | ||
163 | } else { | ||
164 | struct rtc_device *rtc = (struct rtc_device *)dev; | ||
165 | |||
166 | rtc->irq_freq = freq; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | } | ||
171 | |||
142 | static int rtc_timer1_count; | 172 | static int rtc_timer1_count; |
143 | 173 | ||
174 | static int sa1100_irq_set_state(struct device *dev, int enabled) | ||
175 | { | ||
176 | spin_lock_irq(&sa1100_rtc_lock); | ||
177 | if (enabled) { | ||
178 | struct rtc_device *rtc = (struct rtc_device *)dev; | ||
179 | |||
180 | OSMR1 = timer_freq / rtc->irq_freq + OSCR; | ||
181 | OIER |= OIER_E1; | ||
182 | rtc_timer1_count = 1; | ||
183 | } else { | ||
184 | OIER &= ~OIER_E1; | ||
185 | } | ||
186 | spin_unlock_irq(&sa1100_rtc_lock); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static inline int sa1100_timer1_retrigger(struct rtc_device *rtc) | ||
192 | { | ||
193 | unsigned long diff; | ||
194 | unsigned long period = timer_freq / rtc->irq_freq; | ||
195 | |||
196 | spin_lock_irq(&sa1100_rtc_lock); | ||
197 | |||
198 | do { | ||
199 | OSMR1 += period; | ||
200 | diff = OSMR1 - OSCR; | ||
201 | /* If OSCR > OSMR1, diff is a very large number (unsigned | ||
202 | * math). This means we have a lost interrupt. */ | ||
203 | } while (diff > period); | ||
204 | OIER |= OIER_E1; | ||
205 | |||
206 | spin_unlock_irq(&sa1100_rtc_lock); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
144 | static irqreturn_t timer1_interrupt(int irq, void *dev_id) | 211 | static irqreturn_t timer1_interrupt(int irq, void *dev_id) |
145 | { | 212 | { |
146 | struct platform_device *pdev = to_platform_device(dev_id); | 213 | struct platform_device *pdev = to_platform_device(dev_id); |
@@ -158,7 +225,11 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) | |||
158 | rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); | 225 | rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); |
159 | 226 | ||
160 | if (rtc_timer1_count == 1) | 227 | if (rtc_timer1_count == 1) |
161 | rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2))); | 228 | rtc_timer1_count = |
229 | (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2))); | ||
230 | |||
231 | /* retrigger. */ | ||
232 | sa1100_timer1_retrigger(rtc); | ||
162 | 233 | ||
163 | return IRQ_HANDLED; | 234 | return IRQ_HANDLED; |
164 | } | 235 | } |
@@ -166,8 +237,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) | |||
166 | static int sa1100_rtc_read_callback(struct device *dev, int data) | 237 | static int sa1100_rtc_read_callback(struct device *dev, int data) |
167 | { | 238 | { |
168 | if (data & RTC_PF) { | 239 | if (data & RTC_PF) { |
240 | struct rtc_device *rtc = (struct rtc_device *)dev; | ||
241 | |||
169 | /* interpolate missed periods and set match for the next */ | 242 | /* interpolate missed periods and set match for the next */ |
170 | unsigned long period = timer_freq / rtc_freq; | 243 | unsigned long period = timer_freq / rtc->irq_freq; |
171 | unsigned long oscr = OSCR; | 244 | unsigned long oscr = OSCR; |
172 | unsigned long osmr1 = OSMR1; | 245 | unsigned long osmr1 = OSMR1; |
173 | unsigned long missed = (oscr - osmr1)/period; | 246 | unsigned long missed = (oscr - osmr1)/period; |
@@ -178,7 +251,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) | |||
178 | * Here we compare (match - OSCR) 8 instead of 0 -- | 251 | * Here we compare (match - OSCR) 8 instead of 0 -- |
179 | * see comment in pxa_timer_interrupt() for explanation. | 252 | * see comment in pxa_timer_interrupt() for explanation. |
180 | */ | 253 | */ |
181 | while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { | 254 | while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) { |
182 | data += 0x100; | 255 | data += 0x100; |
183 | OSSR = OSSR_M1; /* clear match on timer 1 */ | 256 | OSSR = OSSR_M1; /* clear match on timer 1 */ |
184 | OSMR1 = osmr1 + period; | 257 | OSMR1 = osmr1 + period; |
@@ -190,25 +263,29 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) | |||
190 | static int sa1100_rtc_open(struct device *dev) | 263 | static int sa1100_rtc_open(struct device *dev) |
191 | { | 264 | { |
192 | int ret; | 265 | int ret; |
266 | struct rtc_device *rtc = (struct rtc_device *)dev; | ||
193 | 267 | ||
194 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, | 268 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, |
195 | "rtc 1Hz", dev); | 269 | "rtc 1Hz", dev); |
196 | if (ret) { | 270 | if (ret) { |
197 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); | 271 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); |
198 | goto fail_ui; | 272 | goto fail_ui; |
199 | } | 273 | } |
200 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, | 274 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, |
201 | "rtc Alrm", dev); | 275 | "rtc Alrm", dev); |
202 | if (ret) { | 276 | if (ret) { |
203 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); | 277 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); |
204 | goto fail_ai; | 278 | goto fail_ai; |
205 | } | 279 | } |
206 | ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, | 280 | ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, |
207 | "rtc timer", dev); | 281 | "rtc timer", dev); |
208 | if (ret) { | 282 | if (ret) { |
209 | dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); | 283 | dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); |
210 | goto fail_pi; | 284 | goto fail_pi; |
211 | } | 285 | } |
286 | rtc->max_user_freq = RTC_FREQ; | ||
287 | sa1100_irq_set_freq(dev, RTC_FREQ); | ||
288 | |||
212 | return 0; | 289 | return 0; |
213 | 290 | ||
214 | fail_pi: | 291 | fail_pi: |
@@ -236,7 +313,7 @@ static void sa1100_rtc_release(struct device *dev) | |||
236 | static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, | 313 | static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, |
237 | unsigned long arg) | 314 | unsigned long arg) |
238 | { | 315 | { |
239 | switch(cmd) { | 316 | switch (cmd) { |
240 | case RTC_AIE_OFF: | 317 | case RTC_AIE_OFF: |
241 | spin_lock_irq(&sa1100_rtc_lock); | 318 | spin_lock_irq(&sa1100_rtc_lock); |
242 | RTSR &= ~RTSR_ALE; | 319 | RTSR &= ~RTSR_ALE; |
@@ -257,25 +334,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
257 | RTSR |= RTSR_HZE; | 334 | RTSR |= RTSR_HZE; |
258 | spin_unlock_irq(&sa1100_rtc_lock); | 335 | spin_unlock_irq(&sa1100_rtc_lock); |
259 | return 0; | 336 | return 0; |
260 | case RTC_PIE_OFF: | ||
261 | spin_lock_irq(&sa1100_rtc_lock); | ||
262 | OIER &= ~OIER_E1; | ||
263 | spin_unlock_irq(&sa1100_rtc_lock); | ||
264 | return 0; | ||
265 | case RTC_PIE_ON: | ||
266 | spin_lock_irq(&sa1100_rtc_lock); | ||
267 | OSMR1 = timer_freq / rtc_freq + OSCR; | ||
268 | OIER |= OIER_E1; | ||
269 | rtc_timer1_count = 1; | ||
270 | spin_unlock_irq(&sa1100_rtc_lock); | ||
271 | return 0; | ||
272 | case RTC_IRQP_READ: | ||
273 | return put_user(rtc_freq, (unsigned long *)arg); | ||
274 | case RTC_IRQP_SET: | ||
275 | if (arg < 1 || arg > timer_freq) | ||
276 | return -EINVAL; | ||
277 | rtc_freq = arg; | ||
278 | return 0; | ||
279 | } | 337 | } |
280 | return -ENOIOCTLCMD; | 338 | return -ENOIOCTLCMD; |
281 | } | 339 | } |
@@ -327,12 +385,15 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
327 | 385 | ||
328 | static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) | 386 | static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) |
329 | { | 387 | { |
388 | struct rtc_device *rtc = (struct rtc_device *)dev; | ||
389 | |||
330 | seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); | 390 | seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); |
331 | seq_printf(seq, "update_IRQ\t: %s\n", | 391 | seq_printf(seq, "update_IRQ\t: %s\n", |
332 | (RTSR & RTSR_HZE) ? "yes" : "no"); | 392 | (RTSR & RTSR_HZE) ? "yes" : "no"); |
333 | seq_printf(seq, "periodic_IRQ\t: %s\n", | 393 | seq_printf(seq, "periodic_IRQ\t: %s\n", |
334 | (OIER & OIER_E1) ? "yes" : "no"); | 394 | (OIER & OIER_E1) ? "yes" : "no"); |
335 | seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); | 395 | seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq); |
396 | seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); | ||
336 | 397 | ||
337 | return 0; | 398 | return 0; |
338 | } | 399 | } |
@@ -347,6 +408,8 @@ static const struct rtc_class_ops sa1100_rtc_ops = { | |||
347 | .read_alarm = sa1100_rtc_read_alarm, | 408 | .read_alarm = sa1100_rtc_read_alarm, |
348 | .set_alarm = sa1100_rtc_set_alarm, | 409 | .set_alarm = sa1100_rtc_set_alarm, |
349 | .proc = sa1100_rtc_proc, | 410 | .proc = sa1100_rtc_proc, |
411 | .irq_set_freq = sa1100_irq_set_freq, | ||
412 | .irq_set_state = sa1100_irq_set_state, | ||
350 | }; | 413 | }; |
351 | 414 | ||
352 | static int sa1100_rtc_probe(struct platform_device *pdev) | 415 | static int sa1100_rtc_probe(struct platform_device *pdev) |
@@ -364,7 +427,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
364 | */ | 427 | */ |
365 | if (RTTR == 0) { | 428 | if (RTTR == 0) { |
366 | RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); | 429 | RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); |
367 | dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); | 430 | dev_warn(&pdev->dev, "warning: " |
431 | "initializing default clock divider/trim value\n"); | ||
368 | /* The current RTC value probably doesn't make sense either */ | 432 | /* The current RTC value probably doesn't make sense either */ |
369 | RCNR = 0; | 433 | RCNR = 0; |
370 | } | 434 | } |
@@ -372,13 +436,42 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
372 | device_init_wakeup(&pdev->dev, 1); | 436 | device_init_wakeup(&pdev->dev, 1); |
373 | 437 | ||
374 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, | 438 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, |
375 | THIS_MODULE); | 439 | THIS_MODULE); |
376 | 440 | ||
377 | if (IS_ERR(rtc)) | 441 | if (IS_ERR(rtc)) |
378 | return PTR_ERR(rtc); | 442 | return PTR_ERR(rtc); |
379 | 443 | ||
380 | platform_set_drvdata(pdev, rtc); | 444 | platform_set_drvdata(pdev, rtc); |
381 | 445 | ||
446 | /* Set the irq_freq */ | ||
447 | /*TODO: Find out who is messing with this value after we initialize | ||
448 | * it here.*/ | ||
449 | rtc->irq_freq = RTC_FREQ; | ||
450 | |||
451 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | ||
452 | * See also the comments in sa1100_rtc_interrupt(). | ||
453 | * | ||
454 | * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an | ||
455 | * interrupt pending, even though interrupts were never enabled. | ||
456 | * In this case, this bit it must be reset before enabling | ||
457 | * interruptions to avoid a nonexistent interrupt to occur. | ||
458 | * | ||
459 | * In principle, the same problem would apply to bit 0, although it has | ||
460 | * never been observed to happen. | ||
461 | * | ||
462 | * This issue is addressed both here and in sa1100_rtc_interrupt(). | ||
463 | * If the issue is not addressed here, in the times when the processor | ||
464 | * wakes up with the bit set there will be one spurious interrupt. | ||
465 | * | ||
466 | * The issue is also dealt with in sa1100_rtc_interrupt() to be on the | ||
467 | * safe side, once the condition that lead to this strange | ||
468 | * initialization is unknown and could in principle happen during | ||
469 | * normal processing. | ||
470 | * | ||
471 | * Notice that clearing bit 1 and 0 is accomplished by writting ONES to | ||
472 | * the corresponding bits in RTSR. */ | ||
473 | RTSR = RTSR_AL | RTSR_HZ; | ||
474 | |||
382 | return 0; | 475 | return 0; |
383 | } | 476 | } |
384 | 477 | ||
@@ -386,7 +479,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) | |||
386 | { | 479 | { |
387 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 480 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
388 | 481 | ||
389 | if (rtc) | 482 | if (rtc) |
390 | rtc_device_unregister(rtc); | 483 | rtc_device_unregister(rtc); |
391 | 484 | ||
392 | return 0; | 485 | return 0; |
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 6ca7a44f29c2..e76d7d000128 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * | 7 | * |
8 | * Copyright 1999 ARM Limited | 8 | * Copyright 1999 ARM Limited |
9 | * Copyright (C) 2000 Deep Blue Solutions Ltd. | 9 | * Copyright (C) 2000 Deep Blue Solutions Ltd. |
10 | * Copyright (C) 2010 ST-Ericsson SA | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * 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 | * it under the terms of the GNU General Public License as published by |
@@ -48,6 +49,9 @@ | |||
48 | #include <linux/amba/serial.h> | 49 | #include <linux/amba/serial.h> |
49 | #include <linux/clk.h> | 50 | #include <linux/clk.h> |
50 | #include <linux/slab.h> | 51 | #include <linux/slab.h> |
52 | #include <linux/dmaengine.h> | ||
53 | #include <linux/dma-mapping.h> | ||
54 | #include <linux/scatterlist.h> | ||
51 | 55 | ||
52 | #include <asm/io.h> | 56 | #include <asm/io.h> |
53 | #include <asm/sizes.h> | 57 | #include <asm/sizes.h> |
@@ -63,21 +67,6 @@ | |||
63 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) | 67 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) |
64 | #define UART_DUMMY_DR_RX (1 << 16) | 68 | #define UART_DUMMY_DR_RX (1 << 16) |
65 | 69 | ||
66 | /* | ||
67 | * We wrap our port structure around the generic uart_port. | ||
68 | */ | ||
69 | struct uart_amba_port { | ||
70 | struct uart_port port; | ||
71 | struct clk *clk; | ||
72 | unsigned int im; /* interrupt mask */ | ||
73 | unsigned int old_status; | ||
74 | unsigned int ifls; /* vendor-specific */ | ||
75 | unsigned int lcrh_tx; /* vendor-specific */ | ||
76 | unsigned int lcrh_rx; /* vendor-specific */ | ||
77 | bool oversampling; /* vendor-specific */ | ||
78 | bool autorts; | ||
79 | }; | ||
80 | |||
81 | /* There is by now at least one vendor with differing details, so handle it */ | 70 | /* There is by now at least one vendor with differing details, so handle it */ |
82 | struct vendor_data { | 71 | struct vendor_data { |
83 | unsigned int ifls; | 72 | unsigned int ifls; |
@@ -85,6 +74,7 @@ struct vendor_data { | |||
85 | unsigned int lcrh_tx; | 74 | unsigned int lcrh_tx; |
86 | unsigned int lcrh_rx; | 75 | unsigned int lcrh_rx; |
87 | bool oversampling; | 76 | bool oversampling; |
77 | bool dma_threshold; | ||
88 | }; | 78 | }; |
89 | 79 | ||
90 | static struct vendor_data vendor_arm = { | 80 | static struct vendor_data vendor_arm = { |
@@ -93,6 +83,7 @@ static struct vendor_data vendor_arm = { | |||
93 | .lcrh_tx = UART011_LCRH, | 83 | .lcrh_tx = UART011_LCRH, |
94 | .lcrh_rx = UART011_LCRH, | 84 | .lcrh_rx = UART011_LCRH, |
95 | .oversampling = false, | 85 | .oversampling = false, |
86 | .dma_threshold = false, | ||
96 | }; | 87 | }; |
97 | 88 | ||
98 | static struct vendor_data vendor_st = { | 89 | static struct vendor_data vendor_st = { |
@@ -101,22 +92,535 @@ static struct vendor_data vendor_st = { | |||
101 | .lcrh_tx = ST_UART011_LCRH_TX, | 92 | .lcrh_tx = ST_UART011_LCRH_TX, |
102 | .lcrh_rx = ST_UART011_LCRH_RX, | 93 | .lcrh_rx = ST_UART011_LCRH_RX, |
103 | .oversampling = true, | 94 | .oversampling = true, |
95 | .dma_threshold = true, | ||
96 | }; | ||
97 | |||
98 | /* Deals with DMA transactions */ | ||
99 | struct pl011_dmatx_data { | ||
100 | struct dma_chan *chan; | ||
101 | struct scatterlist sg; | ||
102 | char *buf; | ||
103 | bool queued; | ||
104 | }; | 104 | }; |
105 | 105 | ||
106 | /* | ||
107 | * We wrap our port structure around the generic uart_port. | ||
108 | */ | ||
109 | struct uart_amba_port { | ||
110 | struct uart_port port; | ||
111 | struct clk *clk; | ||
112 | const struct vendor_data *vendor; | ||
113 | unsigned int dmacr; /* dma control reg */ | ||
114 | unsigned int im; /* interrupt mask */ | ||
115 | unsigned int old_status; | ||
116 | unsigned int fifosize; /* vendor-specific */ | ||
117 | unsigned int lcrh_tx; /* vendor-specific */ | ||
118 | unsigned int lcrh_rx; /* vendor-specific */ | ||
119 | bool autorts; | ||
120 | char type[12]; | ||
121 | #ifdef CONFIG_DMA_ENGINE | ||
122 | /* DMA stuff */ | ||
123 | bool using_dma; | ||
124 | struct pl011_dmatx_data dmatx; | ||
125 | #endif | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * All the DMA operation mode stuff goes inside this ifdef. | ||
130 | * This assumes that you have a generic DMA device interface, | ||
131 | * no custom DMA interfaces are supported. | ||
132 | */ | ||
133 | #ifdef CONFIG_DMA_ENGINE | ||
134 | |||
135 | #define PL011_DMA_BUFFER_SIZE PAGE_SIZE | ||
136 | |||
137 | static void pl011_dma_probe_initcall(struct uart_amba_port *uap) | ||
138 | { | ||
139 | /* DMA is the sole user of the platform data right now */ | ||
140 | struct amba_pl011_data *plat = uap->port.dev->platform_data; | ||
141 | struct dma_slave_config tx_conf = { | ||
142 | .dst_addr = uap->port.mapbase + UART01x_DR, | ||
143 | .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, | ||
144 | .direction = DMA_TO_DEVICE, | ||
145 | .dst_maxburst = uap->fifosize >> 1, | ||
146 | }; | ||
147 | struct dma_chan *chan; | ||
148 | dma_cap_mask_t mask; | ||
149 | |||
150 | /* We need platform data */ | ||
151 | if (!plat || !plat->dma_filter) { | ||
152 | dev_info(uap->port.dev, "no DMA platform data\n"); | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | /* Try to acquire a generic DMA engine slave channel */ | ||
157 | dma_cap_zero(mask); | ||
158 | dma_cap_set(DMA_SLAVE, mask); | ||
159 | |||
160 | chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); | ||
161 | if (!chan) { | ||
162 | dev_err(uap->port.dev, "no TX DMA channel!\n"); | ||
163 | return; | ||
164 | } | ||
165 | |||
166 | dmaengine_slave_config(chan, &tx_conf); | ||
167 | uap->dmatx.chan = chan; | ||
168 | |||
169 | dev_info(uap->port.dev, "DMA channel TX %s\n", | ||
170 | dma_chan_name(uap->dmatx.chan)); | ||
171 | } | ||
172 | |||
173 | #ifndef MODULE | ||
174 | /* | ||
175 | * Stack up the UARTs and let the above initcall be done at device | ||
176 | * initcall time, because the serial driver is called as an arch | ||
177 | * initcall, and at this time the DMA subsystem is not yet registered. | ||
178 | * At this point the driver will switch over to using DMA where desired. | ||
179 | */ | ||
180 | struct dma_uap { | ||
181 | struct list_head node; | ||
182 | struct uart_amba_port *uap; | ||
183 | }; | ||
184 | |||
185 | static LIST_HEAD(pl011_dma_uarts); | ||
186 | |||
187 | static int __init pl011_dma_initcall(void) | ||
188 | { | ||
189 | struct list_head *node, *tmp; | ||
190 | |||
191 | list_for_each_safe(node, tmp, &pl011_dma_uarts) { | ||
192 | struct dma_uap *dmau = list_entry(node, struct dma_uap, node); | ||
193 | pl011_dma_probe_initcall(dmau->uap); | ||
194 | list_del(node); | ||
195 | kfree(dmau); | ||
196 | } | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | device_initcall(pl011_dma_initcall); | ||
201 | |||
202 | static void pl011_dma_probe(struct uart_amba_port *uap) | ||
203 | { | ||
204 | struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); | ||
205 | if (dmau) { | ||
206 | dmau->uap = uap; | ||
207 | list_add_tail(&dmau->node, &pl011_dma_uarts); | ||
208 | } | ||
209 | } | ||
210 | #else | ||
211 | static void pl011_dma_probe(struct uart_amba_port *uap) | ||
212 | { | ||
213 | pl011_dma_probe_initcall(uap); | ||
214 | } | ||
215 | #endif | ||
216 | |||
217 | static void pl011_dma_remove(struct uart_amba_port *uap) | ||
218 | { | ||
219 | /* TODO: remove the initcall if it has not yet executed */ | ||
220 | if (uap->dmatx.chan) | ||
221 | dma_release_channel(uap->dmatx.chan); | ||
222 | } | ||
223 | |||
224 | |||
225 | /* Forward declare this for the refill routine */ | ||
226 | static int pl011_dma_tx_refill(struct uart_amba_port *uap); | ||
227 | |||
228 | /* | ||
229 | * The current DMA TX buffer has been sent. | ||
230 | * Try to queue up another DMA buffer. | ||
231 | */ | ||
232 | static void pl011_dma_tx_callback(void *data) | ||
233 | { | ||
234 | struct uart_amba_port *uap = data; | ||
235 | struct pl011_dmatx_data *dmatx = &uap->dmatx; | ||
236 | unsigned long flags; | ||
237 | u16 dmacr; | ||
238 | |||
239 | spin_lock_irqsave(&uap->port.lock, flags); | ||
240 | if (uap->dmatx.queued) | ||
241 | dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, | ||
242 | DMA_TO_DEVICE); | ||
243 | |||
244 | dmacr = uap->dmacr; | ||
245 | uap->dmacr = dmacr & ~UART011_TXDMAE; | ||
246 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
247 | |||
248 | /* | ||
249 | * If TX DMA was disabled, it means that we've stopped the DMA for | ||
250 | * some reason (eg, XOFF received, or we want to send an X-char.) | ||
251 | * | ||
252 | * Note: we need to be careful here of a potential race between DMA | ||
253 | * and the rest of the driver - if the driver disables TX DMA while | ||
254 | * a TX buffer completing, we must update the tx queued status to | ||
255 | * get further refills (hence we check dmacr). | ||
256 | */ | ||
257 | if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || | ||
258 | uart_circ_empty(&uap->port.state->xmit)) { | ||
259 | uap->dmatx.queued = false; | ||
260 | spin_unlock_irqrestore(&uap->port.lock, flags); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | if (pl011_dma_tx_refill(uap) <= 0) { | ||
265 | /* | ||
266 | * We didn't queue a DMA buffer for some reason, but we | ||
267 | * have data pending to be sent. Re-enable the TX IRQ. | ||
268 | */ | ||
269 | uap->im |= UART011_TXIM; | ||
270 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
271 | } | ||
272 | spin_unlock_irqrestore(&uap->port.lock, flags); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Try to refill the TX DMA buffer. | ||
277 | * Locking: called with port lock held and IRQs disabled. | ||
278 | * Returns: | ||
279 | * 1 if we queued up a TX DMA buffer. | ||
280 | * 0 if we didn't want to handle this by DMA | ||
281 | * <0 on error | ||
282 | */ | ||
283 | static int pl011_dma_tx_refill(struct uart_amba_port *uap) | ||
284 | { | ||
285 | struct pl011_dmatx_data *dmatx = &uap->dmatx; | ||
286 | struct dma_chan *chan = dmatx->chan; | ||
287 | struct dma_device *dma_dev = chan->device; | ||
288 | struct dma_async_tx_descriptor *desc; | ||
289 | struct circ_buf *xmit = &uap->port.state->xmit; | ||
290 | unsigned int count; | ||
291 | |||
292 | /* | ||
293 | * Try to avoid the overhead involved in using DMA if the | ||
294 | * transaction fits in the first half of the FIFO, by using | ||
295 | * the standard interrupt handling. This ensures that we | ||
296 | * issue a uart_write_wakeup() at the appropriate time. | ||
297 | */ | ||
298 | count = uart_circ_chars_pending(xmit); | ||
299 | if (count < (uap->fifosize >> 1)) { | ||
300 | uap->dmatx.queued = false; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Bodge: don't send the last character by DMA, as this | ||
306 | * will prevent XON from notifying us to restart DMA. | ||
307 | */ | ||
308 | count -= 1; | ||
309 | |||
310 | /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ | ||
311 | if (count > PL011_DMA_BUFFER_SIZE) | ||
312 | count = PL011_DMA_BUFFER_SIZE; | ||
313 | |||
314 | if (xmit->tail < xmit->head) | ||
315 | memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); | ||
316 | else { | ||
317 | size_t first = UART_XMIT_SIZE - xmit->tail; | ||
318 | size_t second = xmit->head; | ||
319 | |||
320 | memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); | ||
321 | if (second) | ||
322 | memcpy(&dmatx->buf[first], &xmit->buf[0], second); | ||
323 | } | ||
324 | |||
325 | dmatx->sg.length = count; | ||
326 | |||
327 | if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { | ||
328 | uap->dmatx.queued = false; | ||
329 | dev_dbg(uap->port.dev, "unable to map TX DMA\n"); | ||
330 | return -EBUSY; | ||
331 | } | ||
332 | |||
333 | desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, | ||
334 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
335 | if (!desc) { | ||
336 | dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); | ||
337 | uap->dmatx.queued = false; | ||
338 | /* | ||
339 | * If DMA cannot be used right now, we complete this | ||
340 | * transaction via IRQ and let the TTY layer retry. | ||
341 | */ | ||
342 | dev_dbg(uap->port.dev, "TX DMA busy\n"); | ||
343 | return -EBUSY; | ||
344 | } | ||
345 | |||
346 | /* Some data to go along to the callback */ | ||
347 | desc->callback = pl011_dma_tx_callback; | ||
348 | desc->callback_param = uap; | ||
349 | |||
350 | /* All errors should happen at prepare time */ | ||
351 | dmaengine_submit(desc); | ||
352 | |||
353 | /* Fire the DMA transaction */ | ||
354 | dma_dev->device_issue_pending(chan); | ||
355 | |||
356 | uap->dmacr |= UART011_TXDMAE; | ||
357 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
358 | uap->dmatx.queued = true; | ||
359 | |||
360 | /* | ||
361 | * Now we know that DMA will fire, so advance the ring buffer | ||
362 | * with the stuff we just dispatched. | ||
363 | */ | ||
364 | xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); | ||
365 | uap->port.icount.tx += count; | ||
366 | |||
367 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
368 | uart_write_wakeup(&uap->port); | ||
369 | |||
370 | return 1; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * We received a transmit interrupt without a pending X-char but with | ||
375 | * pending characters. | ||
376 | * Locking: called with port lock held and IRQs disabled. | ||
377 | * Returns: | ||
378 | * false if we want to use PIO to transmit | ||
379 | * true if we queued a DMA buffer | ||
380 | */ | ||
381 | static bool pl011_dma_tx_irq(struct uart_amba_port *uap) | ||
382 | { | ||
383 | if (!uap->using_dma) | ||
384 | return false; | ||
385 | |||
386 | /* | ||
387 | * If we already have a TX buffer queued, but received a | ||
388 | * TX interrupt, it will be because we've just sent an X-char. | ||
389 | * Ensure the TX DMA is enabled and the TX IRQ is disabled. | ||
390 | */ | ||
391 | if (uap->dmatx.queued) { | ||
392 | uap->dmacr |= UART011_TXDMAE; | ||
393 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
394 | uap->im &= ~UART011_TXIM; | ||
395 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
396 | return true; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * We don't have a TX buffer queued, so try to queue one. | ||
401 | * If we succesfully queued a buffer, mask the TX IRQ. | ||
402 | */ | ||
403 | if (pl011_dma_tx_refill(uap) > 0) { | ||
404 | uap->im &= ~UART011_TXIM; | ||
405 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
406 | return true; | ||
407 | } | ||
408 | return false; | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * Stop the DMA transmit (eg, due to received XOFF). | ||
413 | * Locking: called with port lock held and IRQs disabled. | ||
414 | */ | ||
415 | static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) | ||
416 | { | ||
417 | if (uap->dmatx.queued) { | ||
418 | uap->dmacr &= ~UART011_TXDMAE; | ||
419 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * Try to start a DMA transmit, or in the case of an XON/OFF | ||
425 | * character queued for send, try to get that character out ASAP. | ||
426 | * Locking: called with port lock held and IRQs disabled. | ||
427 | * Returns: | ||
428 | * false if we want the TX IRQ to be enabled | ||
429 | * true if we have a buffer queued | ||
430 | */ | ||
431 | static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) | ||
432 | { | ||
433 | u16 dmacr; | ||
434 | |||
435 | if (!uap->using_dma) | ||
436 | return false; | ||
437 | |||
438 | if (!uap->port.x_char) { | ||
439 | /* no X-char, try to push chars out in DMA mode */ | ||
440 | bool ret = true; | ||
441 | |||
442 | if (!uap->dmatx.queued) { | ||
443 | if (pl011_dma_tx_refill(uap) > 0) { | ||
444 | uap->im &= ~UART011_TXIM; | ||
445 | ret = true; | ||
446 | } else { | ||
447 | uap->im |= UART011_TXIM; | ||
448 | ret = false; | ||
449 | } | ||
450 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
451 | } else if (!(uap->dmacr & UART011_TXDMAE)) { | ||
452 | uap->dmacr |= UART011_TXDMAE; | ||
453 | writew(uap->dmacr, | ||
454 | uap->port.membase + UART011_DMACR); | ||
455 | } | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * We have an X-char to send. Disable DMA to prevent it loading | ||
461 | * the TX fifo, and then see if we can stuff it into the FIFO. | ||
462 | */ | ||
463 | dmacr = uap->dmacr; | ||
464 | uap->dmacr &= ~UART011_TXDMAE; | ||
465 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
466 | |||
467 | if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { | ||
468 | /* | ||
469 | * No space in the FIFO, so enable the transmit interrupt | ||
470 | * so we know when there is space. Note that once we've | ||
471 | * loaded the character, we should just re-enable DMA. | ||
472 | */ | ||
473 | return false; | ||
474 | } | ||
475 | |||
476 | writew(uap->port.x_char, uap->port.membase + UART01x_DR); | ||
477 | uap->port.icount.tx++; | ||
478 | uap->port.x_char = 0; | ||
479 | |||
480 | /* Success - restore the DMA state */ | ||
481 | uap->dmacr = dmacr; | ||
482 | writew(dmacr, uap->port.membase + UART011_DMACR); | ||
483 | |||
484 | return true; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * Flush the transmit buffer. | ||
489 | * Locking: called with port lock held and IRQs disabled. | ||
490 | */ | ||
491 | static void pl011_dma_flush_buffer(struct uart_port *port) | ||
492 | { | ||
493 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
494 | |||
495 | if (!uap->using_dma) | ||
496 | return; | ||
497 | |||
498 | /* Avoid deadlock with the DMA engine callback */ | ||
499 | spin_unlock(&uap->port.lock); | ||
500 | dmaengine_terminate_all(uap->dmatx.chan); | ||
501 | spin_lock(&uap->port.lock); | ||
502 | if (uap->dmatx.queued) { | ||
503 | dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, | ||
504 | DMA_TO_DEVICE); | ||
505 | uap->dmatx.queued = false; | ||
506 | uap->dmacr &= ~UART011_TXDMAE; | ||
507 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | |||
512 | static void pl011_dma_startup(struct uart_amba_port *uap) | ||
513 | { | ||
514 | if (!uap->dmatx.chan) | ||
515 | return; | ||
516 | |||
517 | uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); | ||
518 | if (!uap->dmatx.buf) { | ||
519 | dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); | ||
520 | uap->port.fifosize = uap->fifosize; | ||
521 | return; | ||
522 | } | ||
523 | |||
524 | sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); | ||
525 | |||
526 | /* The DMA buffer is now the FIFO the TTY subsystem can use */ | ||
527 | uap->port.fifosize = PL011_DMA_BUFFER_SIZE; | ||
528 | uap->using_dma = true; | ||
529 | |||
530 | /* Turn on DMA error (RX/TX will be enabled on demand) */ | ||
531 | uap->dmacr |= UART011_DMAONERR; | ||
532 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
533 | |||
534 | /* | ||
535 | * ST Micro variants has some specific dma burst threshold | ||
536 | * compensation. Set this to 16 bytes, so burst will only | ||
537 | * be issued above/below 16 bytes. | ||
538 | */ | ||
539 | if (uap->vendor->dma_threshold) | ||
540 | writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, | ||
541 | uap->port.membase + ST_UART011_DMAWM); | ||
542 | } | ||
543 | |||
544 | static void pl011_dma_shutdown(struct uart_amba_port *uap) | ||
545 | { | ||
546 | if (!uap->using_dma) | ||
547 | return; | ||
548 | |||
549 | /* Disable RX and TX DMA */ | ||
550 | while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) | ||
551 | barrier(); | ||
552 | |||
553 | spin_lock_irq(&uap->port.lock); | ||
554 | uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); | ||
555 | writew(uap->dmacr, uap->port.membase + UART011_DMACR); | ||
556 | spin_unlock_irq(&uap->port.lock); | ||
557 | |||
558 | /* In theory, this should already be done by pl011_dma_flush_buffer */ | ||
559 | dmaengine_terminate_all(uap->dmatx.chan); | ||
560 | if (uap->dmatx.queued) { | ||
561 | dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, | ||
562 | DMA_TO_DEVICE); | ||
563 | uap->dmatx.queued = false; | ||
564 | } | ||
565 | |||
566 | kfree(uap->dmatx.buf); | ||
567 | |||
568 | uap->using_dma = false; | ||
569 | } | ||
570 | |||
571 | #else | ||
572 | /* Blank functions if the DMA engine is not available */ | ||
573 | static inline void pl011_dma_probe(struct uart_amba_port *uap) | ||
574 | { | ||
575 | } | ||
576 | |||
577 | static inline void pl011_dma_remove(struct uart_amba_port *uap) | ||
578 | { | ||
579 | } | ||
580 | |||
581 | static inline void pl011_dma_startup(struct uart_amba_port *uap) | ||
582 | { | ||
583 | } | ||
584 | |||
585 | static inline void pl011_dma_shutdown(struct uart_amba_port *uap) | ||
586 | { | ||
587 | } | ||
588 | |||
589 | static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) | ||
590 | { | ||
591 | return false; | ||
592 | } | ||
593 | |||
594 | static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) | ||
595 | { | ||
596 | } | ||
597 | |||
598 | static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) | ||
599 | { | ||
600 | return false; | ||
601 | } | ||
602 | |||
603 | #define pl011_dma_flush_buffer NULL | ||
604 | #endif | ||
605 | |||
606 | |||
106 | static void pl011_stop_tx(struct uart_port *port) | 607 | static void pl011_stop_tx(struct uart_port *port) |
107 | { | 608 | { |
108 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 609 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
109 | 610 | ||
110 | uap->im &= ~UART011_TXIM; | 611 | uap->im &= ~UART011_TXIM; |
111 | writew(uap->im, uap->port.membase + UART011_IMSC); | 612 | writew(uap->im, uap->port.membase + UART011_IMSC); |
613 | pl011_dma_tx_stop(uap); | ||
112 | } | 614 | } |
113 | 615 | ||
114 | static void pl011_start_tx(struct uart_port *port) | 616 | static void pl011_start_tx(struct uart_port *port) |
115 | { | 617 | { |
116 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 618 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
117 | 619 | ||
118 | uap->im |= UART011_TXIM; | 620 | if (!pl011_dma_tx_start(uap)) { |
119 | writew(uap->im, uap->port.membase + UART011_IMSC); | 621 | uap->im |= UART011_TXIM; |
622 | writew(uap->im, uap->port.membase + UART011_IMSC); | ||
623 | } | ||
120 | } | 624 | } |
121 | 625 | ||
122 | static void pl011_stop_rx(struct uart_port *port) | 626 | static void pl011_stop_rx(struct uart_port *port) |
@@ -203,7 +707,11 @@ static void pl011_tx_chars(struct uart_amba_port *uap) | |||
203 | return; | 707 | return; |
204 | } | 708 | } |
205 | 709 | ||
206 | count = uap->port.fifosize >> 1; | 710 | /* If we are using DMA mode, try to send some characters. */ |
711 | if (pl011_dma_tx_irq(uap)) | ||
712 | return; | ||
713 | |||
714 | count = uap->fifosize >> 1; | ||
207 | do { | 715 | do { |
208 | writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); | 716 | writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); |
209 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 717 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
@@ -246,10 +754,11 @@ static void pl011_modem_status(struct uart_amba_port *uap) | |||
246 | static irqreturn_t pl011_int(int irq, void *dev_id) | 754 | static irqreturn_t pl011_int(int irq, void *dev_id) |
247 | { | 755 | { |
248 | struct uart_amba_port *uap = dev_id; | 756 | struct uart_amba_port *uap = dev_id; |
757 | unsigned long flags; | ||
249 | unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; | 758 | unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; |
250 | int handled = 0; | 759 | int handled = 0; |
251 | 760 | ||
252 | spin_lock(&uap->port.lock); | 761 | spin_lock_irqsave(&uap->port.lock, flags); |
253 | 762 | ||
254 | status = readw(uap->port.membase + UART011_MIS); | 763 | status = readw(uap->port.membase + UART011_MIS); |
255 | if (status) { | 764 | if (status) { |
@@ -274,7 +783,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) | |||
274 | handled = 1; | 783 | handled = 1; |
275 | } | 784 | } |
276 | 785 | ||
277 | spin_unlock(&uap->port.lock); | 786 | spin_unlock_irqrestore(&uap->port.lock, flags); |
278 | 787 | ||
279 | return IRQ_RETVAL(handled); | 788 | return IRQ_RETVAL(handled); |
280 | } | 789 | } |
@@ -396,7 +905,7 @@ static int pl011_startup(struct uart_port *port) | |||
396 | if (retval) | 905 | if (retval) |
397 | goto clk_dis; | 906 | goto clk_dis; |
398 | 907 | ||
399 | writew(uap->ifls, uap->port.membase + UART011_IFLS); | 908 | writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); |
400 | 909 | ||
401 | /* | 910 | /* |
402 | * Provoke TX FIFO interrupt into asserting. | 911 | * Provoke TX FIFO interrupt into asserting. |
@@ -423,11 +932,18 @@ static int pl011_startup(struct uart_port *port) | |||
423 | cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; | 932 | cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; |
424 | writew(cr, uap->port.membase + UART011_CR); | 933 | writew(cr, uap->port.membase + UART011_CR); |
425 | 934 | ||
935 | /* Clear pending error interrupts */ | ||
936 | writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, | ||
937 | uap->port.membase + UART011_ICR); | ||
938 | |||
426 | /* | 939 | /* |
427 | * initialise the old status of the modem signals | 940 | * initialise the old status of the modem signals |
428 | */ | 941 | */ |
429 | uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; | 942 | uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; |
430 | 943 | ||
944 | /* Startup DMA */ | ||
945 | pl011_dma_startup(uap); | ||
946 | |||
431 | /* | 947 | /* |
432 | * Finally, enable interrupts | 948 | * Finally, enable interrupts |
433 | */ | 949 | */ |
@@ -467,6 +983,8 @@ static void pl011_shutdown(struct uart_port *port) | |||
467 | writew(0xffff, uap->port.membase + UART011_ICR); | 983 | writew(0xffff, uap->port.membase + UART011_ICR); |
468 | spin_unlock_irq(&uap->port.lock); | 984 | spin_unlock_irq(&uap->port.lock); |
469 | 985 | ||
986 | pl011_dma_shutdown(uap); | ||
987 | |||
470 | /* | 988 | /* |
471 | * Free the interrupt | 989 | * Free the interrupt |
472 | */ | 990 | */ |
@@ -498,13 +1016,18 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
498 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 1016 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
499 | unsigned int lcr_h, old_cr; | 1017 | unsigned int lcr_h, old_cr; |
500 | unsigned long flags; | 1018 | unsigned long flags; |
501 | unsigned int baud, quot; | 1019 | unsigned int baud, quot, clkdiv; |
1020 | |||
1021 | if (uap->vendor->oversampling) | ||
1022 | clkdiv = 8; | ||
1023 | else | ||
1024 | clkdiv = 16; | ||
502 | 1025 | ||
503 | /* | 1026 | /* |
504 | * Ask the core to calculate the divisor for us. | 1027 | * Ask the core to calculate the divisor for us. |
505 | */ | 1028 | */ |
506 | baud = uart_get_baud_rate(port, termios, old, 0, | 1029 | baud = uart_get_baud_rate(port, termios, old, 0, |
507 | port->uartclk/(uap->oversampling ? 8 : 16)); | 1030 | port->uartclk / clkdiv); |
508 | 1031 | ||
509 | if (baud > port->uartclk/16) | 1032 | if (baud > port->uartclk/16) |
510 | quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); | 1033 | quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); |
@@ -532,7 +1055,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
532 | if (!(termios->c_cflag & PARODD)) | 1055 | if (!(termios->c_cflag & PARODD)) |
533 | lcr_h |= UART01x_LCRH_EPS; | 1056 | lcr_h |= UART01x_LCRH_EPS; |
534 | } | 1057 | } |
535 | if (port->fifosize > 1) | 1058 | if (uap->fifosize > 1) |
536 | lcr_h |= UART01x_LCRH_FEN; | 1059 | lcr_h |= UART01x_LCRH_FEN; |
537 | 1060 | ||
538 | spin_lock_irqsave(&port->lock, flags); | 1061 | spin_lock_irqsave(&port->lock, flags); |
@@ -588,8 +1111,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
588 | uap->autorts = false; | 1111 | uap->autorts = false; |
589 | } | 1112 | } |
590 | 1113 | ||
591 | if (uap->oversampling) { | 1114 | if (uap->vendor->oversampling) { |
592 | if (baud > port->uartclk/16) | 1115 | if (baud > port->uartclk / 16) |
593 | old_cr |= ST_UART011_CR_OVSFACT; | 1116 | old_cr |= ST_UART011_CR_OVSFACT; |
594 | else | 1117 | else |
595 | old_cr &= ~ST_UART011_CR_OVSFACT; | 1118 | old_cr &= ~ST_UART011_CR_OVSFACT; |
@@ -622,7 +1145,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
622 | 1145 | ||
623 | static const char *pl011_type(struct uart_port *port) | 1146 | static const char *pl011_type(struct uart_port *port) |
624 | { | 1147 | { |
625 | return port->type == PORT_AMBA ? "AMBA/PL011" : NULL; | 1148 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
1149 | return uap->port.type == PORT_AMBA ? uap->type : NULL; | ||
626 | } | 1150 | } |
627 | 1151 | ||
628 | /* | 1152 | /* |
@@ -679,6 +1203,7 @@ static struct uart_ops amba_pl011_pops = { | |||
679 | .break_ctl = pl011_break_ctl, | 1203 | .break_ctl = pl011_break_ctl, |
680 | .startup = pl011_startup, | 1204 | .startup = pl011_startup, |
681 | .shutdown = pl011_shutdown, | 1205 | .shutdown = pl011_shutdown, |
1206 | .flush_buffer = pl011_dma_flush_buffer, | ||
682 | .set_termios = pl011_set_termios, | 1207 | .set_termios = pl011_set_termios, |
683 | .type = pl011_type, | 1208 | .type = pl011_type, |
684 | .release_port = pl010_release_port, | 1209 | .release_port = pl010_release_port, |
@@ -761,7 +1286,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, | |||
761 | 1286 | ||
762 | *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); | 1287 | *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); |
763 | 1288 | ||
764 | if (uap->oversampling) { | 1289 | if (uap->vendor->oversampling) { |
765 | if (readw(uap->port.membase + UART011_CR) | 1290 | if (readw(uap->port.membase + UART011_CR) |
766 | & ST_UART011_CR_OVSFACT) | 1291 | & ST_UART011_CR_OVSFACT) |
767 | *baud *= 2; | 1292 | *baud *= 2; |
@@ -858,19 +1383,22 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
858 | goto unmap; | 1383 | goto unmap; |
859 | } | 1384 | } |
860 | 1385 | ||
861 | uap->ifls = vendor->ifls; | 1386 | uap->vendor = vendor; |
862 | uap->lcrh_rx = vendor->lcrh_rx; | 1387 | uap->lcrh_rx = vendor->lcrh_rx; |
863 | uap->lcrh_tx = vendor->lcrh_tx; | 1388 | uap->lcrh_tx = vendor->lcrh_tx; |
864 | uap->oversampling = vendor->oversampling; | 1389 | uap->fifosize = vendor->fifosize; |
865 | uap->port.dev = &dev->dev; | 1390 | uap->port.dev = &dev->dev; |
866 | uap->port.mapbase = dev->res.start; | 1391 | uap->port.mapbase = dev->res.start; |
867 | uap->port.membase = base; | 1392 | uap->port.membase = base; |
868 | uap->port.iotype = UPIO_MEM; | 1393 | uap->port.iotype = UPIO_MEM; |
869 | uap->port.irq = dev->irq[0]; | 1394 | uap->port.irq = dev->irq[0]; |
870 | uap->port.fifosize = vendor->fifosize; | 1395 | uap->port.fifosize = uap->fifosize; |
871 | uap->port.ops = &amba_pl011_pops; | 1396 | uap->port.ops = &amba_pl011_pops; |
872 | uap->port.flags = UPF_BOOT_AUTOCONF; | 1397 | uap->port.flags = UPF_BOOT_AUTOCONF; |
873 | uap->port.line = i; | 1398 | uap->port.line = i; |
1399 | pl011_dma_probe(uap); | ||
1400 | |||
1401 | snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); | ||
874 | 1402 | ||
875 | amba_ports[i] = uap; | 1403 | amba_ports[i] = uap; |
876 | 1404 | ||
@@ -879,6 +1407,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
879 | if (ret) { | 1407 | if (ret) { |
880 | amba_set_drvdata(dev, NULL); | 1408 | amba_set_drvdata(dev, NULL); |
881 | amba_ports[i] = NULL; | 1409 | amba_ports[i] = NULL; |
1410 | pl011_dma_remove(uap); | ||
882 | clk_put(uap->clk); | 1411 | clk_put(uap->clk); |
883 | unmap: | 1412 | unmap: |
884 | iounmap(base); | 1413 | iounmap(base); |
@@ -902,6 +1431,7 @@ static int pl011_remove(struct amba_device *dev) | |||
902 | if (amba_ports[i] == uap) | 1431 | if (amba_ports[i] == uap) |
903 | amba_ports[i] = NULL; | 1432 | amba_ports[i] = NULL; |
904 | 1433 | ||
1434 | pl011_dma_remove(uap); | ||
905 | iounmap(uap->port.membase); | 1435 | iounmap(uap->port.membase); |
906 | clk_put(uap->clk); | 1436 | clk_put(uap->clk); |
907 | kfree(uap); | 1437 | kfree(uap); |
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 67eb3770868f..5a7c8f1d76c6 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -41,6 +41,7 @@ config USB_ARCH_HAS_OHCI | |||
41 | default y if MFD_TC6393XB | 41 | default y if MFD_TC6393XB |
42 | default y if ARCH_W90X900 | 42 | default y if ARCH_W90X900 |
43 | default y if ARCH_DAVINCI_DA8XX | 43 | default y if ARCH_DAVINCI_DA8XX |
44 | default y if ARCH_CNS3XXX | ||
44 | # PPC: | 45 | # PPC: |
45 | default y if STB03xxx | 46 | default y if STB03xxx |
46 | default y if PPC_MPC52xx | 47 | default y if PPC_MPC52xx |
@@ -66,6 +67,7 @@ config USB_ARCH_HAS_EHCI | |||
66 | default y if ARCH_AT91SAM9G45 | 67 | default y if ARCH_AT91SAM9G45 |
67 | default y if ARCH_MXC | 68 | default y if ARCH_MXC |
68 | default y if ARCH_OMAP3 | 69 | default y if ARCH_OMAP3 |
70 | default y if ARCH_CNS3XXX | ||
69 | default PCI | 71 | default PCI |
70 | 72 | ||
71 | # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. | 73 | # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. |
diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 5bdbfe619853..77b1eb577029 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c | |||
@@ -93,9 +93,9 @@ void fsl_udc_clk_finalize(struct platform_device *pdev) | |||
93 | 93 | ||
94 | /* workaround ENGcm09152 for i.MX35 */ | 94 | /* workaround ENGcm09152 for i.MX35 */ |
95 | if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { | 95 | if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { |
96 | v = readl(MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR + | 96 | v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + |
97 | USBPHYCTRL_OTGBASE_OFFSET)); | 97 | USBPHYCTRL_OTGBASE_OFFSET)); |
98 | writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR + | 98 | writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + |
99 | USBPHYCTRL_OTGBASE_OFFSET)); | 99 | USBPHYCTRL_OTGBASE_OFFSET)); |
100 | } | 100 | } |
101 | #endif | 101 | #endif |
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6f4f8e6a40c7..f8970d151d2a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -147,6 +147,14 @@ config USB_W90X900_EHCI | |||
147 | ---help--- | 147 | ---help--- |
148 | Enables support for the W90X900 USB controller | 148 | Enables support for the W90X900 USB controller |
149 | 149 | ||
150 | config USB_CNS3XXX_EHCI | ||
151 | bool "Cavium CNS3XXX EHCI Module" | ||
152 | depends on USB_EHCI_HCD && ARCH_CNS3XXX | ||
153 | ---help--- | ||
154 | Enable support for the CNS3XXX SOC's on-chip EHCI controller. | ||
155 | It is needed for high-speed (480Mbit/sec) USB 2.0 device | ||
156 | support. | ||
157 | |||
150 | config USB_OXU210HP_HCD | 158 | config USB_OXU210HP_HCD |
151 | tristate "OXU210HP HCD support" | 159 | tristate "OXU210HP HCD support" |
152 | depends on USB | 160 | depends on USB |
@@ -286,6 +294,13 @@ config USB_OHCI_HCD_SSB | |||
286 | 294 | ||
287 | If unsure, say N. | 295 | If unsure, say N. |
288 | 296 | ||
297 | config USB_CNS3XXX_OHCI | ||
298 | bool "Cavium CNS3XXX OHCI Module" | ||
299 | depends on USB_OHCI_HCD && ARCH_CNS3XXX | ||
300 | ---help--- | ||
301 | Enable support for the CNS3XXX SOC's on-chip OHCI controller. | ||
302 | It is needed for low-speed USB 1.0 device support. | ||
303 | |||
289 | config USB_OHCI_BIG_ENDIAN_DESC | 304 | config USB_OHCI_BIG_ENDIAN_DESC |
290 | bool | 305 | bool |
291 | depends on USB_OHCI_HCD | 306 | depends on USB_OHCI_HCD |
diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c new file mode 100644 index 000000000000..708a05b5d258 --- /dev/null +++ b/drivers/usb/host/ehci-cns3xxx.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cavium Networks | ||
3 | * | ||
4 | * This file is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License, Version 2, as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/atomic.h> | ||
11 | #include <mach/cns3xxx.h> | ||
12 | #include <mach/pm.h> | ||
13 | |||
14 | static int cns3xxx_ehci_init(struct usb_hcd *hcd) | ||
15 | { | ||
16 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
17 | int retval; | ||
18 | |||
19 | /* | ||
20 | * EHCI and OHCI share the same clock and power, | ||
21 | * resetting twice would cause the 1st controller been reset. | ||
22 | * Therefore only do power up at the first up device, and | ||
23 | * power down at the last down device. | ||
24 | * | ||
25 | * Set USB AHB INCR length to 16 | ||
26 | */ | ||
27 | if (atomic_inc_return(&usb_pwr_ref) == 1) { | ||
28 | cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); | ||
29 | cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
30 | cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); | ||
31 | __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), | ||
32 | MISC_CHIP_CONFIG_REG); | ||
33 | } | ||
34 | |||
35 | ehci->caps = hcd->regs; | ||
36 | ehci->regs = hcd->regs | ||
37 | + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); | ||
38 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | ||
39 | |||
40 | hcd->has_tt = 0; | ||
41 | ehci_reset(ehci); | ||
42 | |||
43 | retval = ehci_init(hcd); | ||
44 | if (retval) | ||
45 | return retval; | ||
46 | |||
47 | ehci_port_power(ehci, 0); | ||
48 | |||
49 | return retval; | ||
50 | } | ||
51 | |||
52 | static const struct hc_driver cns3xxx_ehci_hc_driver = { | ||
53 | .description = hcd_name, | ||
54 | .product_desc = "CNS3XXX EHCI Host Controller", | ||
55 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
56 | .irq = ehci_irq, | ||
57 | .flags = HCD_MEMORY | HCD_USB2, | ||
58 | .reset = cns3xxx_ehci_init, | ||
59 | .start = ehci_run, | ||
60 | .stop = ehci_stop, | ||
61 | .shutdown = ehci_shutdown, | ||
62 | .urb_enqueue = ehci_urb_enqueue, | ||
63 | .urb_dequeue = ehci_urb_dequeue, | ||
64 | .endpoint_disable = ehci_endpoint_disable, | ||
65 | .endpoint_reset = ehci_endpoint_reset, | ||
66 | .get_frame_number = ehci_get_frame, | ||
67 | .hub_status_data = ehci_hub_status_data, | ||
68 | .hub_control = ehci_hub_control, | ||
69 | #ifdef CONFIG_PM | ||
70 | .bus_suspend = ehci_bus_suspend, | ||
71 | .bus_resume = ehci_bus_resume, | ||
72 | #endif | ||
73 | .relinquish_port = ehci_relinquish_port, | ||
74 | .port_handed_over = ehci_port_handed_over, | ||
75 | |||
76 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
77 | }; | ||
78 | |||
79 | static int cns3xxx_ehci_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | struct device *dev = &pdev->dev; | ||
82 | struct usb_hcd *hcd; | ||
83 | const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; | ||
84 | struct resource *res; | ||
85 | int irq; | ||
86 | int retval; | ||
87 | |||
88 | if (usb_disabled()) | ||
89 | return -ENODEV; | ||
90 | |||
91 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
92 | if (!res) { | ||
93 | dev_err(dev, "Found HC with no IRQ.\n"); | ||
94 | return -ENODEV; | ||
95 | } | ||
96 | irq = res->start; | ||
97 | |||
98 | hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); | ||
99 | if (!hcd) | ||
100 | return -ENOMEM; | ||
101 | |||
102 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
103 | if (!res) { | ||
104 | dev_err(dev, "Found HC with no register addr.\n"); | ||
105 | retval = -ENODEV; | ||
106 | goto err1; | ||
107 | } | ||
108 | |||
109 | hcd->rsrc_start = res->start; | ||
110 | hcd->rsrc_len = res->end - res->start + 1; | ||
111 | |||
112 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, | ||
113 | driver->description)) { | ||
114 | dev_dbg(dev, "controller already in use\n"); | ||
115 | retval = -EBUSY; | ||
116 | goto err1; | ||
117 | } | ||
118 | |||
119 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
120 | if (hcd->regs == NULL) { | ||
121 | dev_dbg(dev, "error mapping memory\n"); | ||
122 | retval = -EFAULT; | ||
123 | goto err2; | ||
124 | } | ||
125 | |||
126 | retval = usb_add_hcd(hcd, irq, IRQF_SHARED); | ||
127 | if (retval == 0) | ||
128 | return retval; | ||
129 | |||
130 | iounmap(hcd->regs); | ||
131 | err2: | ||
132 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
133 | err1: | ||
134 | usb_put_hcd(hcd); | ||
135 | |||
136 | return retval; | ||
137 | } | ||
138 | |||
139 | static int cns3xxx_ehci_remove(struct platform_device *pdev) | ||
140 | { | ||
141 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
142 | |||
143 | usb_remove_hcd(hcd); | ||
144 | iounmap(hcd->regs); | ||
145 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
146 | |||
147 | /* | ||
148 | * EHCI and OHCI share the same clock and power, | ||
149 | * resetting twice would cause the 1st controller been reset. | ||
150 | * Therefore only do power up at the first up device, and | ||
151 | * power down at the last down device. | ||
152 | */ | ||
153 | if (atomic_dec_return(&usb_pwr_ref) == 0) | ||
154 | cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
155 | |||
156 | usb_put_hcd(hcd); | ||
157 | |||
158 | platform_set_drvdata(pdev, NULL); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | MODULE_ALIAS("platform:cns3xxx-ehci"); | ||
164 | |||
165 | static struct platform_driver cns3xxx_ehci_driver = { | ||
166 | .probe = cns3xxx_ehci_probe, | ||
167 | .remove = cns3xxx_ehci_remove, | ||
168 | .driver = { | ||
169 | .name = "cns3xxx-ehci", | ||
170 | }, | ||
171 | }; | ||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e9062806d4a2..d0c8f7c03e05 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1216,6 +1216,11 @@ MODULE_LICENSE ("GPL"); | |||
1216 | #define PLATFORM_DRIVER ehci_octeon_driver | 1216 | #define PLATFORM_DRIVER ehci_octeon_driver |
1217 | #endif | 1217 | #endif |
1218 | 1218 | ||
1219 | #ifdef CONFIG_USB_CNS3XXX_EHCI | ||
1220 | #include "ehci-cns3xxx.c" | ||
1221 | #define PLATFORM_DRIVER cns3xxx_ehci_driver | ||
1222 | #endif | ||
1223 | |||
1219 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ | 1224 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
1220 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ | 1225 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
1221 | !defined(XILINX_OF_PLATFORM_DRIVER) | 1226 | !defined(XILINX_OF_PLATFORM_DRIVER) |
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index bce85055019a..a22d2df769a9 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #define ULPI_VIEWPORT_OFFSET 0x170 | 28 | #define ULPI_VIEWPORT_OFFSET 0x170 |
29 | 29 | ||
30 | struct ehci_mxc_priv { | 30 | struct ehci_mxc_priv { |
31 | struct clk *usbclk, *ahbclk; | 31 | struct clk *usbclk, *ahbclk, *phy1clk; |
32 | struct usb_hcd *hcd; | 32 | struct usb_hcd *hcd; |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -168,17 +168,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
168 | goto err_ioremap; | 168 | goto err_ioremap; |
169 | } | 169 | } |
170 | 170 | ||
171 | /* call platform specific init function */ | ||
172 | if (pdata->init) { | ||
173 | ret = pdata->init(pdev); | ||
174 | if (ret) { | ||
175 | dev_err(dev, "platform init failed\n"); | ||
176 | goto err_init; | ||
177 | } | ||
178 | /* platforms need some time to settle changed IO settings */ | ||
179 | mdelay(10); | ||
180 | } | ||
181 | |||
182 | /* enable clocks */ | 171 | /* enable clocks */ |
183 | priv->usbclk = clk_get(dev, "usb"); | 172 | priv->usbclk = clk_get(dev, "usb"); |
184 | if (IS_ERR(priv->usbclk)) { | 173 | if (IS_ERR(priv->usbclk)) { |
@@ -196,6 +185,28 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
196 | clk_enable(priv->ahbclk); | 185 | clk_enable(priv->ahbclk); |
197 | } | 186 | } |
198 | 187 | ||
188 | /* "dr" device has its own clock */ | ||
189 | if (pdev->id == 0) { | ||
190 | priv->phy1clk = clk_get(dev, "usb_phy1"); | ||
191 | if (IS_ERR(priv->phy1clk)) { | ||
192 | ret = PTR_ERR(priv->phy1clk); | ||
193 | goto err_clk_phy; | ||
194 | } | ||
195 | clk_enable(priv->phy1clk); | ||
196 | } | ||
197 | |||
198 | |||
199 | /* call platform specific init function */ | ||
200 | if (pdata->init) { | ||
201 | ret = pdata->init(pdev); | ||
202 | if (ret) { | ||
203 | dev_err(dev, "platform init failed\n"); | ||
204 | goto err_init; | ||
205 | } | ||
206 | /* platforms need some time to settle changed IO settings */ | ||
207 | mdelay(10); | ||
208 | } | ||
209 | |||
199 | /* setup specific usb hw */ | 210 | /* setup specific usb hw */ |
200 | ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); | 211 | ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); |
201 | if (ret < 0) | 212 | if (ret < 0) |
@@ -230,6 +241,11 @@ err_add: | |||
230 | if (pdata && pdata->exit) | 241 | if (pdata && pdata->exit) |
231 | pdata->exit(pdev); | 242 | pdata->exit(pdev); |
232 | err_init: | 243 | err_init: |
244 | if (priv->phy1clk) { | ||
245 | clk_disable(priv->phy1clk); | ||
246 | clk_put(priv->phy1clk); | ||
247 | } | ||
248 | err_clk_phy: | ||
233 | if (priv->ahbclk) { | 249 | if (priv->ahbclk) { |
234 | clk_disable(priv->ahbclk); | 250 | clk_disable(priv->ahbclk); |
235 | clk_put(priv->ahbclk); | 251 | clk_put(priv->ahbclk); |
@@ -273,6 +289,10 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) | |||
273 | clk_disable(priv->ahbclk); | 289 | clk_disable(priv->ahbclk); |
274 | clk_put(priv->ahbclk); | 290 | clk_put(priv->ahbclk); |
275 | } | 291 | } |
292 | if (priv->phy1clk) { | ||
293 | clk_disable(priv->phy1clk); | ||
294 | clk_put(priv->phy1clk); | ||
295 | } | ||
276 | 296 | ||
277 | kfree(priv); | 297 | kfree(priv); |
278 | 298 | ||
diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c new file mode 100644 index 000000000000..f05ef87e934c --- /dev/null +++ b/drivers/usb/host/ohci-cns3xxx.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cavium Networks | ||
3 | * | ||
4 | * This file is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License, Version 2, as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/atomic.h> | ||
11 | #include <mach/cns3xxx.h> | ||
12 | #include <mach/pm.h> | ||
13 | |||
14 | static int __devinit | ||
15 | cns3xxx_ohci_start(struct usb_hcd *hcd) | ||
16 | { | ||
17 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
18 | int ret; | ||
19 | |||
20 | /* | ||
21 | * EHCI and OHCI share the same clock and power, | ||
22 | * resetting twice would cause the 1st controller been reset. | ||
23 | * Therefore only do power up at the first up device, and | ||
24 | * power down at the last down device. | ||
25 | * | ||
26 | * Set USB AHB INCR length to 16 | ||
27 | */ | ||
28 | if (atomic_inc_return(&usb_pwr_ref) == 1) { | ||
29 | cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); | ||
30 | cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
31 | cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); | ||
32 | __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), | ||
33 | MISC_CHIP_CONFIG_REG); | ||
34 | } | ||
35 | |||
36 | ret = ohci_init(ohci); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | |||
40 | ohci->num_ports = 1; | ||
41 | |||
42 | ret = ohci_run(ohci); | ||
43 | if (ret < 0) { | ||
44 | err("can't start %s", hcd->self.bus_name); | ||
45 | ohci_stop(hcd); | ||
46 | return ret; | ||
47 | } | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static const struct hc_driver cns3xxx_ohci_hc_driver = { | ||
52 | .description = hcd_name, | ||
53 | .product_desc = "CNS3XXX OHCI Host controller", | ||
54 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
55 | .irq = ohci_irq, | ||
56 | .flags = HCD_USB11 | HCD_MEMORY, | ||
57 | .start = cns3xxx_ohci_start, | ||
58 | .stop = ohci_stop, | ||
59 | .shutdown = ohci_shutdown, | ||
60 | .urb_enqueue = ohci_urb_enqueue, | ||
61 | .urb_dequeue = ohci_urb_dequeue, | ||
62 | .endpoint_disable = ohci_endpoint_disable, | ||
63 | .get_frame_number = ohci_get_frame, | ||
64 | .hub_status_data = ohci_hub_status_data, | ||
65 | .hub_control = ohci_hub_control, | ||
66 | #ifdef CONFIG_PM | ||
67 | .bus_suspend = ohci_bus_suspend, | ||
68 | .bus_resume = ohci_bus_resume, | ||
69 | #endif | ||
70 | .start_port_reset = ohci_start_port_reset, | ||
71 | }; | ||
72 | |||
73 | static int cns3xxx_ohci_probe(struct platform_device *pdev) | ||
74 | { | ||
75 | struct device *dev = &pdev->dev; | ||
76 | struct usb_hcd *hcd; | ||
77 | const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; | ||
78 | struct resource *res; | ||
79 | int irq; | ||
80 | int retval; | ||
81 | |||
82 | if (usb_disabled()) | ||
83 | return -ENODEV; | ||
84 | |||
85 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
86 | if (!res) { | ||
87 | dev_err(dev, "Found HC with no IRQ.\n"); | ||
88 | return -ENODEV; | ||
89 | } | ||
90 | irq = res->start; | ||
91 | |||
92 | hcd = usb_create_hcd(driver, dev, dev_name(dev)); | ||
93 | if (!hcd) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
97 | if (!res) { | ||
98 | dev_err(dev, "Found HC with no register addr.\n"); | ||
99 | retval = -ENODEV; | ||
100 | goto err1; | ||
101 | } | ||
102 | hcd->rsrc_start = res->start; | ||
103 | hcd->rsrc_len = res->end - res->start + 1; | ||
104 | |||
105 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, | ||
106 | driver->description)) { | ||
107 | dev_dbg(dev, "controller already in use\n"); | ||
108 | retval = -EBUSY; | ||
109 | goto err1; | ||
110 | } | ||
111 | |||
112 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
113 | if (!hcd->regs) { | ||
114 | dev_dbg(dev, "error mapping memory\n"); | ||
115 | retval = -EFAULT; | ||
116 | goto err2; | ||
117 | } | ||
118 | |||
119 | ohci_hcd_init(hcd_to_ohci(hcd)); | ||
120 | |||
121 | retval = usb_add_hcd(hcd, irq, IRQF_SHARED); | ||
122 | if (retval == 0) | ||
123 | return retval; | ||
124 | |||
125 | iounmap(hcd->regs); | ||
126 | err2: | ||
127 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
128 | err1: | ||
129 | usb_put_hcd(hcd); | ||
130 | return retval; | ||
131 | } | ||
132 | |||
133 | static int cns3xxx_ohci_remove(struct platform_device *pdev) | ||
134 | { | ||
135 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
136 | |||
137 | usb_remove_hcd(hcd); | ||
138 | iounmap(hcd->regs); | ||
139 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
140 | |||
141 | /* | ||
142 | * EHCI and OHCI share the same clock and power, | ||
143 | * resetting twice would cause the 1st controller been reset. | ||
144 | * Therefore only do power up at the first up device, and | ||
145 | * power down at the last down device. | ||
146 | */ | ||
147 | if (atomic_dec_return(&usb_pwr_ref) == 0) | ||
148 | cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); | ||
149 | |||
150 | usb_put_hcd(hcd); | ||
151 | |||
152 | platform_set_drvdata(pdev, NULL); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | MODULE_ALIAS("platform:cns3xxx-ohci"); | ||
158 | |||
159 | static struct platform_driver ohci_hcd_cns3xxx_driver = { | ||
160 | .probe = cns3xxx_ohci_probe, | ||
161 | .remove = cns3xxx_ohci_remove, | ||
162 | .driver = { | ||
163 | .name = "cns3xxx-ohci", | ||
164 | }, | ||
165 | }; | ||
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5179acb7aa2f..5cb6731ba443 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -1111,6 +1111,11 @@ MODULE_LICENSE ("GPL"); | |||
1111 | #define PLATFORM_DRIVER ohci_octeon_driver | 1111 | #define PLATFORM_DRIVER ohci_octeon_driver |
1112 | #endif | 1112 | #endif |
1113 | 1113 | ||
1114 | #ifdef CONFIG_USB_CNS3XXX_OHCI | ||
1115 | #include "ohci-cns3xxx.c" | ||
1116 | #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver | ||
1117 | #endif | ||
1118 | |||
1114 | #if !defined(PCI_DRIVER) && \ | 1119 | #if !defined(PCI_DRIVER) && \ |
1115 | !defined(PLATFORM_DRIVER) && \ | 1120 | !defined(PLATFORM_DRIVER) && \ |
1116 | !defined(OMAP1_PLATFORM_DRIVER) && \ | 1121 | !defined(OMAP1_PLATFORM_DRIVER) && \ |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9f36a29b10b4..55dc6fb6e909 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1932,6 +1932,16 @@ config FB_PXA_PARAMETERS | |||
1932 | 1932 | ||
1933 | <file:Documentation/fb/pxafb.txt> describes the available parameters. | 1933 | <file:Documentation/fb/pxafb.txt> describes the available parameters. |
1934 | 1934 | ||
1935 | config PXA3XX_GCU | ||
1936 | tristate "PXA3xx 2D graphics accelerator driver" | ||
1937 | depends on FB_PXA | ||
1938 | help | ||
1939 | Kernelspace driver for the 2D graphics controller unit (GCU) | ||
1940 | found on PXA3xx processors. There is a counterpart driver in the | ||
1941 | DirectFB suite, see http://www.directfb.org/ | ||
1942 | |||
1943 | If you compile this as a module, it will be called pxa3xx_gcu. | ||
1944 | |||
1935 | config FB_MBX | 1945 | config FB_MBX |
1936 | tristate "2700G LCD framebuffer support" | 1946 | tristate "2700G LCD framebuffer support" |
1937 | depends on FB && ARCH_PXA | 1947 | depends on FB && ARCH_PXA |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f9de51c39ad7..8c8fabdff9d0 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -101,6 +101,7 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o | |||
101 | obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o | 101 | obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o |
102 | obj-$(CONFIG_FB_PXA) += pxafb.o | 102 | obj-$(CONFIG_FB_PXA) += pxafb.o |
103 | obj-$(CONFIG_FB_PXA168) += pxa168fb.o | 103 | obj-$(CONFIG_FB_PXA168) += pxa168fb.o |
104 | obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o | ||
104 | obj-$(CONFIG_FB_W100) += w100fb.o | 105 | obj-$(CONFIG_FB_W100) += w100fb.o |
105 | obj-$(CONFIG_FB_TMIO) += tmiofb.o | 106 | obj-$(CONFIG_FB_TMIO) += tmiofb.o |
106 | obj-$(CONFIG_FB_AU1100) += au1100fb.o | 107 | obj-$(CONFIG_FB_AU1100) += au1100fb.o |
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c new file mode 100644 index 000000000000..b81168df253d --- /dev/null +++ b/drivers/video/pxa3xx-gcu.c | |||
@@ -0,0 +1,772 @@ | |||
1 | /* | ||
2 | * pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers | ||
3 | * | ||
4 | * This driver needs a DirectFB counterpart in user space, communication | ||
5 | * is handled via mmap()ed memory areas and an ioctl. | ||
6 | * | ||
7 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | ||
8 | * Copyright (c) 2009 Janine Kropp <nin@directfb.org> | ||
9 | * Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.org> | ||
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 program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * WARNING: This controller is attached to System Bus 2 of the PXA which | ||
28 | * needs its arbiter to be enabled explictly (CKENB & 1<<9). | ||
29 | * There is currently no way to do this from Linux, so you need to teach | ||
30 | * your bootloader for now. | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/version.h> | ||
35 | |||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/dma-mapping.h> | ||
38 | #include <linux/miscdevice.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/spinlock.h> | ||
41 | #include <linux/uaccess.h> | ||
42 | #include <linux/ioctl.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/clk.h> | ||
47 | #include <linux/fs.h> | ||
48 | #include <linux/io.h> | ||
49 | |||
50 | #include "pxa3xx-gcu.h" | ||
51 | |||
52 | #define DRV_NAME "pxa3xx-gcu" | ||
53 | #define MISCDEV_MINOR 197 | ||
54 | |||
55 | #define REG_GCCR 0x00 | ||
56 | #define GCCR_SYNC_CLR (1 << 9) | ||
57 | #define GCCR_BP_RST (1 << 8) | ||
58 | #define GCCR_ABORT (1 << 6) | ||
59 | #define GCCR_STOP (1 << 4) | ||
60 | |||
61 | #define REG_GCISCR 0x04 | ||
62 | #define REG_GCIECR 0x08 | ||
63 | #define REG_GCRBBR 0x20 | ||
64 | #define REG_GCRBLR 0x24 | ||
65 | #define REG_GCRBHR 0x28 | ||
66 | #define REG_GCRBTR 0x2C | ||
67 | #define REG_GCRBEXHR 0x30 | ||
68 | |||
69 | #define IE_EOB (1 << 0) | ||
70 | #define IE_EEOB (1 << 5) | ||
71 | #define IE_ALL 0xff | ||
72 | |||
73 | #define SHARED_SIZE PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared)) | ||
74 | |||
75 | /* #define PXA3XX_GCU_DEBUG */ | ||
76 | /* #define PXA3XX_GCU_DEBUG_TIMER */ | ||
77 | |||
78 | #ifdef PXA3XX_GCU_DEBUG | ||
79 | #define QDUMP(msg) \ | ||
80 | do { \ | ||
81 | QPRINT(priv, KERN_DEBUG, msg); \ | ||
82 | } while (0) | ||
83 | #else | ||
84 | #define QDUMP(msg) do {} while (0) | ||
85 | #endif | ||
86 | |||
87 | #define QERROR(msg) \ | ||
88 | do { \ | ||
89 | QPRINT(priv, KERN_ERR, msg); \ | ||
90 | } while (0) | ||
91 | |||
92 | struct pxa3xx_gcu_batch { | ||
93 | struct pxa3xx_gcu_batch *next; | ||
94 | u32 *ptr; | ||
95 | dma_addr_t phys; | ||
96 | unsigned long length; | ||
97 | }; | ||
98 | |||
99 | struct pxa3xx_gcu_priv { | ||
100 | void __iomem *mmio_base; | ||
101 | struct clk *clk; | ||
102 | struct pxa3xx_gcu_shared *shared; | ||
103 | dma_addr_t shared_phys; | ||
104 | struct resource *resource_mem; | ||
105 | struct miscdevice misc_dev; | ||
106 | struct file_operations misc_fops; | ||
107 | wait_queue_head_t wait_idle; | ||
108 | wait_queue_head_t wait_free; | ||
109 | spinlock_t spinlock; | ||
110 | struct timeval base_time; | ||
111 | |||
112 | struct pxa3xx_gcu_batch *free; | ||
113 | |||
114 | struct pxa3xx_gcu_batch *ready; | ||
115 | struct pxa3xx_gcu_batch *ready_last; | ||
116 | struct pxa3xx_gcu_batch *running; | ||
117 | }; | ||
118 | |||
119 | static inline unsigned long | ||
120 | gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off) | ||
121 | { | ||
122 | return __raw_readl(priv->mmio_base + off); | ||
123 | } | ||
124 | |||
125 | static inline void | ||
126 | gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val) | ||
127 | { | ||
128 | __raw_writel(val, priv->mmio_base + off); | ||
129 | } | ||
130 | |||
131 | #define QPRINT(priv, level, msg) \ | ||
132 | do { \ | ||
133 | struct timeval tv; \ | ||
134 | struct pxa3xx_gcu_shared *shared = priv->shared; \ | ||
135 | u32 base = gc_readl(priv, REG_GCRBBR); \ | ||
136 | \ | ||
137 | do_gettimeofday(&tv); \ | ||
138 | \ | ||
139 | printk(level "%ld.%03ld.%03ld - %-17s: %-21s (%s, " \ | ||
140 | "STATUS " \ | ||
141 | "0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, " \ | ||
142 | "T %5ld)\n", \ | ||
143 | tv.tv_sec - priv->base_time.tv_sec, \ | ||
144 | tv.tv_usec / 1000, tv.tv_usec % 1000, \ | ||
145 | __func__, msg, \ | ||
146 | shared->hw_running ? "running" : " idle", \ | ||
147 | gc_readl(priv, REG_GCISCR), \ | ||
148 | gc_readl(priv, REG_GCRBBR), \ | ||
149 | gc_readl(priv, REG_GCRBLR), \ | ||
150 | (gc_readl(priv, REG_GCRBEXHR) - base) / 4, \ | ||
151 | (gc_readl(priv, REG_GCRBHR) - base) / 4, \ | ||
152 | (gc_readl(priv, REG_GCRBTR) - base) / 4); \ | ||
153 | } while (0) | ||
154 | |||
155 | static void | ||
156 | pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv) | ||
157 | { | ||
158 | QDUMP("RESET"); | ||
159 | |||
160 | /* disable interrupts */ | ||
161 | gc_writel(priv, REG_GCIECR, 0); | ||
162 | |||
163 | /* reset hardware */ | ||
164 | gc_writel(priv, REG_GCCR, GCCR_ABORT); | ||
165 | gc_writel(priv, REG_GCCR, 0); | ||
166 | |||
167 | memset(priv->shared, 0, SHARED_SIZE); | ||
168 | priv->shared->buffer_phys = priv->shared_phys; | ||
169 | priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC; | ||
170 | |||
171 | do_gettimeofday(&priv->base_time); | ||
172 | |||
173 | /* set up the ring buffer pointers */ | ||
174 | gc_writel(priv, REG_GCRBLR, 0); | ||
175 | gc_writel(priv, REG_GCRBBR, priv->shared_phys); | ||
176 | gc_writel(priv, REG_GCRBTR, priv->shared_phys); | ||
177 | |||
178 | /* enable all IRQs except EOB */ | ||
179 | gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB); | ||
180 | } | ||
181 | |||
182 | static void | ||
183 | dump_whole_state(struct pxa3xx_gcu_priv *priv) | ||
184 | { | ||
185 | struct pxa3xx_gcu_shared *sh = priv->shared; | ||
186 | u32 base = gc_readl(priv, REG_GCRBBR); | ||
187 | |||
188 | QDUMP("DUMP"); | ||
189 | |||
190 | printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n" | ||
191 | "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n", | ||
192 | sh->hw_running ? "running" : "idle ", | ||
193 | gc_readl(priv, REG_GCISCR), | ||
194 | gc_readl(priv, REG_GCRBBR), | ||
195 | gc_readl(priv, REG_GCRBLR), | ||
196 | (gc_readl(priv, REG_GCRBEXHR) - base) / 4, | ||
197 | (gc_readl(priv, REG_GCRBHR) - base) / 4, | ||
198 | (gc_readl(priv, REG_GCRBTR) - base) / 4); | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | flush_running(struct pxa3xx_gcu_priv *priv) | ||
203 | { | ||
204 | struct pxa3xx_gcu_batch *running = priv->running; | ||
205 | struct pxa3xx_gcu_batch *next; | ||
206 | |||
207 | while (running) { | ||
208 | next = running->next; | ||
209 | running->next = priv->free; | ||
210 | priv->free = running; | ||
211 | running = next; | ||
212 | } | ||
213 | |||
214 | priv->running = NULL; | ||
215 | } | ||
216 | |||
217 | static void | ||
218 | run_ready(struct pxa3xx_gcu_priv *priv) | ||
219 | { | ||
220 | unsigned int num = 0; | ||
221 | struct pxa3xx_gcu_shared *shared = priv->shared; | ||
222 | struct pxa3xx_gcu_batch *ready = priv->ready; | ||
223 | |||
224 | QDUMP("Start"); | ||
225 | |||
226 | BUG_ON(!ready); | ||
227 | |||
228 | shared->buffer[num++] = 0x05000000; | ||
229 | |||
230 | while (ready) { | ||
231 | shared->buffer[num++] = 0x00000001; | ||
232 | shared->buffer[num++] = ready->phys; | ||
233 | ready = ready->next; | ||
234 | } | ||
235 | |||
236 | shared->buffer[num++] = 0x05000000; | ||
237 | priv->running = priv->ready; | ||
238 | priv->ready = priv->ready_last = NULL; | ||
239 | gc_writel(priv, REG_GCRBLR, 0); | ||
240 | shared->hw_running = 1; | ||
241 | |||
242 | /* ring base address */ | ||
243 | gc_writel(priv, REG_GCRBBR, shared->buffer_phys); | ||
244 | |||
245 | /* ring tail address */ | ||
246 | gc_writel(priv, REG_GCRBTR, shared->buffer_phys + num * 4); | ||
247 | |||
248 | /* ring length */ | ||
249 | gc_writel(priv, REG_GCRBLR, ((num + 63) & ~63) * 4); | ||
250 | } | ||
251 | |||
252 | static irqreturn_t | ||
253 | pxa3xx_gcu_handle_irq(int irq, void *ctx) | ||
254 | { | ||
255 | struct pxa3xx_gcu_priv *priv = ctx; | ||
256 | struct pxa3xx_gcu_shared *shared = priv->shared; | ||
257 | u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL; | ||
258 | |||
259 | QDUMP("-Interrupt"); | ||
260 | |||
261 | if (!status) | ||
262 | return IRQ_NONE; | ||
263 | |||
264 | spin_lock(&priv->spinlock); | ||
265 | shared->num_interrupts++; | ||
266 | |||
267 | if (status & IE_EEOB) { | ||
268 | QDUMP(" [EEOB]"); | ||
269 | |||
270 | flush_running(priv); | ||
271 | wake_up_all(&priv->wait_free); | ||
272 | |||
273 | if (priv->ready) { | ||
274 | run_ready(priv); | ||
275 | } else { | ||
276 | /* There is no more data prepared by the userspace. | ||
277 | * Set hw_running = 0 and wait for the next userspace | ||
278 | * kick-off */ | ||
279 | shared->num_idle++; | ||
280 | shared->hw_running = 0; | ||
281 | |||
282 | QDUMP(" '-> Idle."); | ||
283 | |||
284 | /* set ring buffer length to zero */ | ||
285 | gc_writel(priv, REG_GCRBLR, 0); | ||
286 | |||
287 | wake_up_all(&priv->wait_idle); | ||
288 | } | ||
289 | |||
290 | shared->num_done++; | ||
291 | } else { | ||
292 | QERROR(" [???]"); | ||
293 | dump_whole_state(priv); | ||
294 | } | ||
295 | |||
296 | /* Clear the interrupt */ | ||
297 | gc_writel(priv, REG_GCISCR, status); | ||
298 | spin_unlock(&priv->spinlock); | ||
299 | |||
300 | return IRQ_HANDLED; | ||
301 | } | ||
302 | |||
303 | static int | ||
304 | pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv) | ||
305 | { | ||
306 | int ret = 0; | ||
307 | |||
308 | QDUMP("Waiting for idle..."); | ||
309 | |||
310 | /* Does not need to be atomic. There's a lock in user space, | ||
311 | * but anyhow, this is just for statistics. */ | ||
312 | priv->shared->num_wait_idle++; | ||
313 | |||
314 | while (priv->shared->hw_running) { | ||
315 | int num = priv->shared->num_interrupts; | ||
316 | u32 rbexhr = gc_readl(priv, REG_GCRBEXHR); | ||
317 | |||
318 | ret = wait_event_interruptible_timeout(priv->wait_idle, | ||
319 | !priv->shared->hw_running, HZ*4); | ||
320 | |||
321 | if (ret < 0) | ||
322 | break; | ||
323 | |||
324 | if (ret > 0) | ||
325 | continue; | ||
326 | |||
327 | if (gc_readl(priv, REG_GCRBEXHR) == rbexhr && | ||
328 | priv->shared->num_interrupts == num) { | ||
329 | QERROR("TIMEOUT"); | ||
330 | ret = -ETIMEDOUT; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | QDUMP("done"); | ||
336 | |||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | static int | ||
341 | pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv) | ||
342 | { | ||
343 | int ret = 0; | ||
344 | |||
345 | QDUMP("Waiting for free..."); | ||
346 | |||
347 | /* Does not need to be atomic. There's a lock in user space, | ||
348 | * but anyhow, this is just for statistics. */ | ||
349 | priv->shared->num_wait_free++; | ||
350 | |||
351 | while (!priv->free) { | ||
352 | u32 rbexhr = gc_readl(priv, REG_GCRBEXHR); | ||
353 | |||
354 | ret = wait_event_interruptible_timeout(priv->wait_free, | ||
355 | priv->free, HZ*4); | ||
356 | |||
357 | if (ret < 0) | ||
358 | break; | ||
359 | |||
360 | if (ret > 0) | ||
361 | continue; | ||
362 | |||
363 | if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) { | ||
364 | QERROR("TIMEOUT"); | ||
365 | ret = -ETIMEDOUT; | ||
366 | break; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | QDUMP("done"); | ||
371 | |||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | /* Misc device layer */ | ||
376 | |||
377 | static ssize_t | ||
378 | pxa3xx_gcu_misc_write(struct file *filp, const char *buff, | ||
379 | size_t count, loff_t *offp) | ||
380 | { | ||
381 | int ret; | ||
382 | unsigned long flags; | ||
383 | struct pxa3xx_gcu_batch *buffer; | ||
384 | struct pxa3xx_gcu_priv *priv = | ||
385 | container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops); | ||
386 | |||
387 | int words = count / 4; | ||
388 | |||
389 | /* Does not need to be atomic. There's a lock in user space, | ||
390 | * but anyhow, this is just for statistics. */ | ||
391 | priv->shared->num_writes++; | ||
392 | |||
393 | priv->shared->num_words += words; | ||
394 | |||
395 | /* Last word reserved for batch buffer end command */ | ||
396 | if (words >= PXA3XX_GCU_BATCH_WORDS) | ||
397 | return -E2BIG; | ||
398 | |||
399 | /* Wait for a free buffer */ | ||
400 | if (!priv->free) { | ||
401 | ret = pxa3xx_gcu_wait_free(priv); | ||
402 | if (ret < 0) | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * Get buffer from free list | ||
408 | */ | ||
409 | spin_lock_irqsave(&priv->spinlock, flags); | ||
410 | |||
411 | buffer = priv->free; | ||
412 | priv->free = buffer->next; | ||
413 | |||
414 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
415 | |||
416 | |||
417 | /* Copy data from user into buffer */ | ||
418 | ret = copy_from_user(buffer->ptr, buff, words * 4); | ||
419 | if (ret) { | ||
420 | spin_lock_irqsave(&priv->spinlock, flags); | ||
421 | buffer->next = priv->free; | ||
422 | priv->free = buffer; | ||
423 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | buffer->length = words; | ||
428 | |||
429 | /* Append batch buffer end command */ | ||
430 | buffer->ptr[words] = 0x01000000; | ||
431 | |||
432 | /* | ||
433 | * Add buffer to ready list | ||
434 | */ | ||
435 | spin_lock_irqsave(&priv->spinlock, flags); | ||
436 | |||
437 | buffer->next = NULL; | ||
438 | |||
439 | if (priv->ready) { | ||
440 | BUG_ON(priv->ready_last == NULL); | ||
441 | |||
442 | priv->ready_last->next = buffer; | ||
443 | } else | ||
444 | priv->ready = buffer; | ||
445 | |||
446 | priv->ready_last = buffer; | ||
447 | |||
448 | if (!priv->shared->hw_running) | ||
449 | run_ready(priv); | ||
450 | |||
451 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
452 | |||
453 | return words * 4; | ||
454 | } | ||
455 | |||
456 | |||
457 | static long | ||
458 | pxa3xx_gcu_misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||
459 | { | ||
460 | unsigned long flags; | ||
461 | struct pxa3xx_gcu_priv *priv = | ||
462 | container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops); | ||
463 | |||
464 | switch (cmd) { | ||
465 | case PXA3XX_GCU_IOCTL_RESET: | ||
466 | spin_lock_irqsave(&priv->spinlock, flags); | ||
467 | pxa3xx_gcu_reset(priv); | ||
468 | spin_unlock_irqrestore(&priv->spinlock, flags); | ||
469 | return 0; | ||
470 | |||
471 | case PXA3XX_GCU_IOCTL_WAIT_IDLE: | ||
472 | return pxa3xx_gcu_wait_idle(priv); | ||
473 | } | ||
474 | |||
475 | return -ENOSYS; | ||
476 | } | ||
477 | |||
478 | static int | ||
479 | pxa3xx_gcu_misc_mmap(struct file *filp, struct vm_area_struct *vma) | ||
480 | { | ||
481 | unsigned int size = vma->vm_end - vma->vm_start; | ||
482 | struct pxa3xx_gcu_priv *priv = | ||
483 | container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops); | ||
484 | |||
485 | switch (vma->vm_pgoff) { | ||
486 | case 0: | ||
487 | /* hand out the shared data area */ | ||
488 | if (size != SHARED_SIZE) | ||
489 | return -EINVAL; | ||
490 | |||
491 | return dma_mmap_coherent(NULL, vma, | ||
492 | priv->shared, priv->shared_phys, size); | ||
493 | |||
494 | case SHARED_SIZE >> PAGE_SHIFT: | ||
495 | /* hand out the MMIO base for direct register access | ||
496 | * from userspace */ | ||
497 | if (size != resource_size(priv->resource_mem)) | ||
498 | return -EINVAL; | ||
499 | |||
500 | vma->vm_flags |= VM_IO; | ||
501 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
502 | |||
503 | return io_remap_pfn_range(vma, vma->vm_start, | ||
504 | priv->resource_mem->start >> PAGE_SHIFT, | ||
505 | size, vma->vm_page_prot); | ||
506 | } | ||
507 | |||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | |||
512 | #ifdef PXA3XX_GCU_DEBUG_TIMER | ||
513 | static struct timer_list pxa3xx_gcu_debug_timer; | ||
514 | |||
515 | static void pxa3xx_gcu_debug_timedout(unsigned long ptr) | ||
516 | { | ||
517 | struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr; | ||
518 | |||
519 | QERROR("Timer DUMP"); | ||
520 | |||
521 | /* init the timer structure */ | ||
522 | init_timer(&pxa3xx_gcu_debug_timer); | ||
523 | pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout; | ||
524 | pxa3xx_gcu_debug_timer.data = ptr; | ||
525 | pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */ | ||
526 | |||
527 | add_timer(&pxa3xx_gcu_debug_timer); | ||
528 | } | ||
529 | |||
530 | static void pxa3xx_gcu_init_debug_timer(void) | ||
531 | { | ||
532 | pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer); | ||
533 | } | ||
534 | #else | ||
535 | static inline void pxa3xx_gcu_init_debug_timer(void) {} | ||
536 | #endif | ||
537 | |||
538 | static int | ||
539 | add_buffer(struct platform_device *dev, | ||
540 | struct pxa3xx_gcu_priv *priv) | ||
541 | { | ||
542 | struct pxa3xx_gcu_batch *buffer; | ||
543 | |||
544 | buffer = kzalloc(sizeof(struct pxa3xx_gcu_batch), GFP_KERNEL); | ||
545 | if (!buffer) | ||
546 | return -ENOMEM; | ||
547 | |||
548 | buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, | ||
549 | &buffer->phys, GFP_KERNEL); | ||
550 | if (!buffer->ptr) { | ||
551 | kfree(buffer); | ||
552 | return -ENOMEM; | ||
553 | } | ||
554 | |||
555 | buffer->next = priv->free; | ||
556 | |||
557 | priv->free = buffer; | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static void | ||
563 | free_buffers(struct platform_device *dev, | ||
564 | struct pxa3xx_gcu_priv *priv) | ||
565 | { | ||
566 | struct pxa3xx_gcu_batch *next, *buffer = priv->free; | ||
567 | |||
568 | while (buffer) { | ||
569 | next = buffer->next; | ||
570 | |||
571 | dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, | ||
572 | buffer->ptr, buffer->phys); | ||
573 | |||
574 | kfree(buffer); | ||
575 | |||
576 | buffer = next; | ||
577 | } | ||
578 | |||
579 | priv->free = NULL; | ||
580 | } | ||
581 | |||
582 | static int __devinit | ||
583 | pxa3xx_gcu_probe(struct platform_device *dev) | ||
584 | { | ||
585 | int i, ret, irq; | ||
586 | struct resource *r; | ||
587 | struct pxa3xx_gcu_priv *priv; | ||
588 | |||
589 | priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); | ||
590 | if (!priv) | ||
591 | return -ENOMEM; | ||
592 | |||
593 | for (i = 0; i < 8; i++) { | ||
594 | ret = add_buffer(dev, priv); | ||
595 | if (ret) { | ||
596 | dev_err(&dev->dev, "failed to allocate DMA memory\n"); | ||
597 | goto err_free_priv; | ||
598 | } | ||
599 | } | ||
600 | |||
601 | init_waitqueue_head(&priv->wait_idle); | ||
602 | init_waitqueue_head(&priv->wait_free); | ||
603 | spin_lock_init(&priv->spinlock); | ||
604 | |||
605 | /* we allocate the misc device structure as part of our own allocation, | ||
606 | * so we can get a pointer to our priv structure later on with | ||
607 | * container_of(). This isn't really necessary as we have a fixed minor | ||
608 | * number anyway, but this is to avoid statics. */ | ||
609 | |||
610 | priv->misc_fops.owner = THIS_MODULE; | ||
611 | priv->misc_fops.write = pxa3xx_gcu_misc_write; | ||
612 | priv->misc_fops.unlocked_ioctl = pxa3xx_gcu_misc_ioctl; | ||
613 | priv->misc_fops.mmap = pxa3xx_gcu_misc_mmap; | ||
614 | |||
615 | priv->misc_dev.minor = MISCDEV_MINOR, | ||
616 | priv->misc_dev.name = DRV_NAME, | ||
617 | priv->misc_dev.fops = &priv->misc_fops, | ||
618 | |||
619 | /* register misc device */ | ||
620 | ret = misc_register(&priv->misc_dev); | ||
621 | if (ret < 0) { | ||
622 | dev_err(&dev->dev, "misc_register() for minor %d failed\n", | ||
623 | MISCDEV_MINOR); | ||
624 | goto err_free_priv; | ||
625 | } | ||
626 | |||
627 | /* handle IO resources */ | ||
628 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
629 | if (r == NULL) { | ||
630 | dev_err(&dev->dev, "no I/O memory resource defined\n"); | ||
631 | ret = -ENODEV; | ||
632 | goto err_misc_deregister; | ||
633 | } | ||
634 | |||
635 | if (!request_mem_region(r->start, resource_size(r), dev->name)) { | ||
636 | dev_err(&dev->dev, "failed to request I/O memory\n"); | ||
637 | ret = -EBUSY; | ||
638 | goto err_misc_deregister; | ||
639 | } | ||
640 | |||
641 | priv->mmio_base = ioremap_nocache(r->start, resource_size(r)); | ||
642 | if (!priv->mmio_base) { | ||
643 | dev_err(&dev->dev, "failed to map I/O memory\n"); | ||
644 | ret = -EBUSY; | ||
645 | goto err_free_mem_region; | ||
646 | } | ||
647 | |||
648 | /* allocate dma memory */ | ||
649 | priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE, | ||
650 | &priv->shared_phys, GFP_KERNEL); | ||
651 | |||
652 | if (!priv->shared) { | ||
653 | dev_err(&dev->dev, "failed to allocate DMA memory\n"); | ||
654 | ret = -ENOMEM; | ||
655 | goto err_free_io; | ||
656 | } | ||
657 | |||
658 | /* enable the clock */ | ||
659 | priv->clk = clk_get(&dev->dev, NULL); | ||
660 | if (IS_ERR(priv->clk)) { | ||
661 | dev_err(&dev->dev, "failed to get clock\n"); | ||
662 | ret = -ENODEV; | ||
663 | goto err_free_dma; | ||
664 | } | ||
665 | |||
666 | ret = clk_enable(priv->clk); | ||
667 | if (ret < 0) { | ||
668 | dev_err(&dev->dev, "failed to enable clock\n"); | ||
669 | goto err_put_clk; | ||
670 | } | ||
671 | |||
672 | /* request the IRQ */ | ||
673 | irq = platform_get_irq(dev, 0); | ||
674 | if (irq < 0) { | ||
675 | dev_err(&dev->dev, "no IRQ defined\n"); | ||
676 | ret = -ENODEV; | ||
677 | goto err_put_clk; | ||
678 | } | ||
679 | |||
680 | ret = request_irq(irq, pxa3xx_gcu_handle_irq, | ||
681 | IRQF_DISABLED, DRV_NAME, priv); | ||
682 | if (ret) { | ||
683 | dev_err(&dev->dev, "request_irq failed\n"); | ||
684 | ret = -EBUSY; | ||
685 | goto err_put_clk; | ||
686 | } | ||
687 | |||
688 | platform_set_drvdata(dev, priv); | ||
689 | priv->resource_mem = r; | ||
690 | pxa3xx_gcu_reset(priv); | ||
691 | pxa3xx_gcu_init_debug_timer(); | ||
692 | |||
693 | dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", | ||
694 | (void *) r->start, (void *) priv->shared_phys, | ||
695 | SHARED_SIZE, irq); | ||
696 | return 0; | ||
697 | |||
698 | err_put_clk: | ||
699 | clk_disable(priv->clk); | ||
700 | clk_put(priv->clk); | ||
701 | |||
702 | err_free_dma: | ||
703 | dma_free_coherent(&dev->dev, SHARED_SIZE, | ||
704 | priv->shared, priv->shared_phys); | ||
705 | |||
706 | err_free_io: | ||
707 | iounmap(priv->mmio_base); | ||
708 | |||
709 | err_free_mem_region: | ||
710 | release_mem_region(r->start, resource_size(r)); | ||
711 | |||
712 | err_misc_deregister: | ||
713 | misc_deregister(&priv->misc_dev); | ||
714 | |||
715 | err_free_priv: | ||
716 | platform_set_drvdata(dev, NULL); | ||
717 | free_buffers(dev, priv); | ||
718 | kfree(priv); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static int __devexit | ||
723 | pxa3xx_gcu_remove(struct platform_device *dev) | ||
724 | { | ||
725 | struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev); | ||
726 | struct resource *r = priv->resource_mem; | ||
727 | |||
728 | pxa3xx_gcu_wait_idle(priv); | ||
729 | |||
730 | misc_deregister(&priv->misc_dev); | ||
731 | dma_free_coherent(&dev->dev, SHARED_SIZE, | ||
732 | priv->shared, priv->shared_phys); | ||
733 | iounmap(priv->mmio_base); | ||
734 | release_mem_region(r->start, resource_size(r)); | ||
735 | platform_set_drvdata(dev, NULL); | ||
736 | clk_disable(priv->clk); | ||
737 | free_buffers(dev, priv); | ||
738 | kfree(priv); | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static struct platform_driver pxa3xx_gcu_driver = { | ||
744 | .probe = pxa3xx_gcu_probe, | ||
745 | .remove = __devexit_p(pxa3xx_gcu_remove), | ||
746 | .driver = { | ||
747 | .owner = THIS_MODULE, | ||
748 | .name = DRV_NAME, | ||
749 | }, | ||
750 | }; | ||
751 | |||
752 | static int __init | ||
753 | pxa3xx_gcu_init(void) | ||
754 | { | ||
755 | return platform_driver_register(&pxa3xx_gcu_driver); | ||
756 | } | ||
757 | |||
758 | static void __exit | ||
759 | pxa3xx_gcu_exit(void) | ||
760 | { | ||
761 | platform_driver_unregister(&pxa3xx_gcu_driver); | ||
762 | } | ||
763 | |||
764 | module_init(pxa3xx_gcu_init); | ||
765 | module_exit(pxa3xx_gcu_exit); | ||
766 | |||
767 | MODULE_DESCRIPTION("PXA3xx graphics controller unit driver"); | ||
768 | MODULE_LICENSE("GPL"); | ||
769 | MODULE_ALIAS_MISCDEV(MISCDEV_MINOR); | ||
770 | MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, " | ||
771 | "Denis Oliver Kropp <dok@directfb.org>, " | ||
772 | "Daniel Mack <daniel@caiaq.de>"); | ||
diff --git a/drivers/video/pxa3xx-gcu.h b/drivers/video/pxa3xx-gcu.h new file mode 100644 index 000000000000..0428ed03dc49 --- /dev/null +++ b/drivers/video/pxa3xx-gcu.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef __PXA3XX_GCU_H__ | ||
2 | #define __PXA3XX_GCU_H__ | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | /* Number of 32bit words in display list (ring buffer). */ | ||
7 | #define PXA3XX_GCU_BUFFER_WORDS ((256 * 1024 - 256) / 4) | ||
8 | |||
9 | /* To be increased when breaking the ABI */ | ||
10 | #define PXA3XX_GCU_SHARED_MAGIC 0x30000001 | ||
11 | |||
12 | #define PXA3XX_GCU_BATCH_WORDS 8192 | ||
13 | |||
14 | struct pxa3xx_gcu_shared { | ||
15 | u32 buffer[PXA3XX_GCU_BUFFER_WORDS]; | ||
16 | |||
17 | bool hw_running; | ||
18 | |||
19 | unsigned long buffer_phys; | ||
20 | |||
21 | unsigned int num_words; | ||
22 | unsigned int num_writes; | ||
23 | unsigned int num_done; | ||
24 | unsigned int num_interrupts; | ||
25 | unsigned int num_wait_idle; | ||
26 | unsigned int num_wait_free; | ||
27 | unsigned int num_idle; | ||
28 | |||
29 | u32 magic; | ||
30 | }; | ||
31 | |||
32 | /* Initialization and synchronization. | ||
33 | * Hardware is started upon write(). */ | ||
34 | #define PXA3XX_GCU_IOCTL_RESET _IO('G', 0) | ||
35 | #define PXA3XX_GCU_IOCTL_WAIT_IDLE _IO('G', 2) | ||
36 | |||
37 | #endif /* __PXA3XX_GCU_H__ */ | ||
38 | |||
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 2ee7dac55a3c..86f7cac1026c 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c | |||
@@ -270,7 +270,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) | |||
270 | return -ENOMEM; | 270 | return -ENOMEM; |
271 | } | 271 | } |
272 | 272 | ||
273 | imx2_wdt.clk = clk_get_sys("imx-wdt.0", NULL); | 273 | imx2_wdt.clk = clk_get(&pdev->dev, NULL); |
274 | if (IS_ERR(imx2_wdt.clk)) { | 274 | if (IS_ERR(imx2_wdt.clk)) { |
275 | dev_err(&pdev->dev, "can't get Watchdog clock\n"); | 275 | dev_err(&pdev->dev, "can't get Watchdog clock\n"); |
276 | return PTR_ERR(imx2_wdt.clk); | 276 | return PTR_ERR(imx2_wdt.clk); |