diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-06 17:33:32 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-06 17:33:32 -0500 |
commit | 404a02cbd2ae8bf256a2fa1169bdfe86bb5ebb34 (patch) | |
tree | 99119edc53fdca73ed7586829b8ee736e09440b3 /drivers | |
parent | 28cdac6690cb113856293bf79b40de33dbd8f974 (diff) | |
parent | 1051b9f0f9eab8091fe3bf98320741adf36b4cfa (diff) |
Merge branch 'devel-stable' into devel
Conflicts:
arch/arm/mach-pxa/clock.c
arch/arm/mach-pxa/clock.h
Diffstat (limited to 'drivers')
32 files changed, 2893 insertions, 875 deletions
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/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 a565300a19c8..29935ea921df 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -71,6 +71,8 @@ pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o | |||
71 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o | 71 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o |
72 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o | 72 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o |
73 | 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 | ||
74 | 76 | ||
75 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) | 77 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) |
76 | 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/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/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 27c1fb4b1e0d..ab77297fbed2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1850,6 +1850,16 @@ config FB_PXA_PARAMETERS | |||
1850 | 1850 | ||
1851 | <file:Documentation/fb/pxafb.txt> describes the available parameters. | 1851 | <file:Documentation/fb/pxafb.txt> describes the available parameters. |
1852 | 1852 | ||
1853 | config PXA3XX_GCU | ||
1854 | tristate "PXA3xx 2D graphics accelerator driver" | ||
1855 | depends on FB_PXA | ||
1856 | help | ||
1857 | Kernelspace driver for the 2D graphics controller unit (GCU) | ||
1858 | found on PXA3xx processors. There is a counterpart driver in the | ||
1859 | DirectFB suite, see http://www.directfb.org/ | ||
1860 | |||
1861 | If you compile this as a module, it will be called pxa3xx_gcu. | ||
1862 | |||
1853 | config FB_MBX | 1863 | config FB_MBX |
1854 | tristate "2700G LCD framebuffer support" | 1864 | tristate "2700G LCD framebuffer support" |
1855 | depends on FB && ARCH_PXA | 1865 | depends on FB && ARCH_PXA |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 485e8ed1318c..9260a898f343 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -100,6 +100,7 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o | |||
100 | obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o | 100 | obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o |
101 | obj-$(CONFIG_FB_PXA) += pxafb.o | 101 | obj-$(CONFIG_FB_PXA) += pxafb.o |
102 | obj-$(CONFIG_FB_PXA168) += pxa168fb.o | 102 | obj-$(CONFIG_FB_PXA168) += pxa168fb.o |
103 | obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o | ||
103 | obj-$(CONFIG_FB_W100) += w100fb.o | 104 | obj-$(CONFIG_FB_W100) += w100fb.o |
104 | obj-$(CONFIG_FB_TMIO) += tmiofb.o | 105 | obj-$(CONFIG_FB_TMIO) += tmiofb.o |
105 | obj-$(CONFIG_FB_AU1100) += au1100fb.o | 106 | 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); |