diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-07-02 17:03:51 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-07-02 17:05:04 -0400 |
commit | c911a3169ed81bbda023740b76457aa795a4f910 (patch) | |
tree | 8e05e98068f0380376735a8575af9bb42ab27502 | |
parent | ca24a145573124732152daff105ba68cc9a2b545 (diff) | |
parent | 5130216265f6f924a4ba8214787241be96d93467 (diff) |
Merge branch 'prima2/drivers' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel into next/pinctrl
* 'prima2/drivers' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel:
PINCTRL: SiRF: add GPIO and GPIO irq support in CSR SiRFprimaII
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Linus Walleij <inus.walleij@linaro.org>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/gpio.h | 13 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/irqs.h | 2 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sirf.c | 489 |
4 files changed, 503 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a91009c61870..571b3d25c9bc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -389,6 +389,7 @@ config ARCH_PRIMA2 | |||
389 | bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" | 389 | bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" |
390 | select CPU_V7 | 390 | select CPU_V7 |
391 | select NO_IOPORT | 391 | select NO_IOPORT |
392 | select ARCH_WANT_OPTIONAL_GPIOLIB | ||
392 | select GENERIC_CLOCKEVENTS | 393 | select GENERIC_CLOCKEVENTS |
393 | select CLKDEV_LOOKUP | 394 | select CLKDEV_LOOKUP |
394 | select GENERIC_IRQ_CHIP | 395 | select GENERIC_IRQ_CHIP |
diff --git a/arch/arm/mach-prima2/include/mach/gpio.h b/arch/arm/mach-prima2/include/mach/gpio.h new file mode 100644 index 000000000000..1904bb03876e --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/gpio.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __MACH_GPIO_H | ||
2 | #define __MACH_GPIO_H | ||
3 | |||
4 | /* Pull up/down values */ | ||
5 | enum sirfsoc_gpio_pull { | ||
6 | SIRFSOC_GPIO_PULL_NONE, | ||
7 | SIRFSOC_GPIO_PULL_UP, | ||
8 | SIRFSOC_GPIO_PULL_DOWN, | ||
9 | }; | ||
10 | |||
11 | void sirfsoc_gpio_set_pull(unsigned gpio, unsigned mode); | ||
12 | |||
13 | #endif | ||
diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h index bb354f952fd6..f6014a07541f 100644 --- a/arch/arm/mach-prima2/include/mach/irqs.h +++ b/arch/arm/mach-prima2/include/mach/irqs.h | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | #define SIRFSOC_INTENAL_IRQ_START 0 | 12 | #define SIRFSOC_INTENAL_IRQ_START 0 |
13 | #define SIRFSOC_INTENAL_IRQ_END 59 | 13 | #define SIRFSOC_INTENAL_IRQ_END 59 |
14 | 14 | #define SIRFSOC_GPIO_IRQ_START (SIRFSOC_INTENAL_IRQ_END + 1) | |
15 | #define NR_IRQS 220 | 15 | #define NR_IRQS 220 |
16 | 16 | ||
17 | #endif | 17 | #endif |
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index e9f8e7d11001..2aae8a8978e9 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c | |||
@@ -8,24 +8,61 @@ | |||
8 | 8 | ||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/irq.h> | ||
11 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
14 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/irqdomain.h> | ||
15 | #include <linux/pinctrl/pinctrl.h> | 17 | #include <linux/pinctrl/pinctrl.h> |
16 | #include <linux/pinctrl/pinmux.h> | 18 | #include <linux/pinctrl/pinmux.h> |
19 | #include <linux/pinctrl/consumer.h> | ||
17 | #include <linux/of.h> | 20 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 21 | #include <linux/of_address.h> |
19 | #include <linux/of_device.h> | 22 | #include <linux/of_device.h> |
20 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
21 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/gpio.h> | ||
26 | #include <linux/of_gpio.h> | ||
22 | 27 | ||
23 | #define DRIVER_NAME "pinmux-sirf" | 28 | #define DRIVER_NAME "pinmux-sirf" |
24 | 29 | ||
25 | #define SIRFSOC_NUM_PADS 622 | 30 | #define SIRFSOC_NUM_PADS 622 |
26 | #define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) | ||
27 | #define SIRFSOC_RSC_PIN_MUX 0x4 | 31 | #define SIRFSOC_RSC_PIN_MUX 0x4 |
28 | 32 | ||
33 | #define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) | ||
34 | #define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) | ||
35 | #define SIRFSOC_GPIO_DSP_EN0 (0x80) | ||
36 | #define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) | ||
37 | #define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) | ||
38 | |||
39 | #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 | ||
40 | #define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK 0x2 | ||
41 | #define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK 0x4 | ||
42 | #define SIRFSOC_GPIO_CTL_INTR_EN_MASK 0x8 | ||
43 | #define SIRFSOC_GPIO_CTL_INTR_STS_MASK 0x10 | ||
44 | #define SIRFSOC_GPIO_CTL_OUT_EN_MASK 0x20 | ||
45 | #define SIRFSOC_GPIO_CTL_DATAOUT_MASK 0x40 | ||
46 | #define SIRFSOC_GPIO_CTL_DATAIN_MASK 0x80 | ||
47 | #define SIRFSOC_GPIO_CTL_PULL_MASK 0x100 | ||
48 | #define SIRFSOC_GPIO_CTL_PULL_HIGH 0x200 | ||
49 | #define SIRFSOC_GPIO_CTL_DSP_INT 0x400 | ||
50 | |||
51 | #define SIRFSOC_GPIO_NO_OF_BANKS 5 | ||
52 | #define SIRFSOC_GPIO_BANK_SIZE 32 | ||
53 | #define SIRFSOC_GPIO_NUM(bank, index) (((bank)*(32)) + (index)) | ||
54 | |||
55 | struct sirfsoc_gpio_bank { | ||
56 | struct of_mm_gpio_chip chip; | ||
57 | struct irq_domain *domain; | ||
58 | int id; | ||
59 | int parent_irq; | ||
60 | spinlock_t lock; | ||
61 | }; | ||
62 | |||
63 | static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; | ||
64 | static DEFINE_SPINLOCK(sgpio_lock); | ||
65 | |||
29 | /* | 66 | /* |
30 | * pad list for the pinmux subsystem | 67 | * pad list for the pinmux subsystem |
31 | * refer to CS-131858-DC-6A.xls | 68 | * refer to CS-131858-DC-6A.xls |
@@ -1204,7 +1241,457 @@ static int __init sirfsoc_pinmux_init(void) | |||
1204 | } | 1241 | } |
1205 | arch_initcall(sirfsoc_pinmux_init); | 1242 | arch_initcall(sirfsoc_pinmux_init); |
1206 | 1243 | ||
1244 | static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
1245 | { | ||
1246 | struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip), | ||
1247 | struct sirfsoc_gpio_bank, chip); | ||
1248 | |||
1249 | return irq_find_mapping(bank->domain, offset); | ||
1250 | } | ||
1251 | |||
1252 | static inline int sirfsoc_gpio_to_offset(unsigned int gpio) | ||
1253 | { | ||
1254 | return gpio % SIRFSOC_GPIO_BANK_SIZE; | ||
1255 | } | ||
1256 | |||
1257 | static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio) | ||
1258 | { | ||
1259 | return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE]; | ||
1260 | } | ||
1261 | |||
1262 | void sirfsoc_gpio_set_pull(unsigned gpio, unsigned mode) | ||
1263 | { | ||
1264 | struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(gpio); | ||
1265 | int idx = sirfsoc_gpio_to_offset(gpio); | ||
1266 | u32 val, offset; | ||
1267 | unsigned long flags; | ||
1268 | |||
1269 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1270 | |||
1271 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1272 | |||
1273 | val = readl(bank->chip.regs + offset); | ||
1274 | |||
1275 | switch (mode) { | ||
1276 | case SIRFSOC_GPIO_PULL_NONE: | ||
1277 | val &= ~SIRFSOC_GPIO_CTL_PULL_MASK; | ||
1278 | break; | ||
1279 | case SIRFSOC_GPIO_PULL_UP: | ||
1280 | val |= SIRFSOC_GPIO_CTL_PULL_MASK; | ||
1281 | val |= SIRFSOC_GPIO_CTL_PULL_HIGH; | ||
1282 | break; | ||
1283 | case SIRFSOC_GPIO_PULL_DOWN: | ||
1284 | val |= SIRFSOC_GPIO_CTL_PULL_MASK; | ||
1285 | val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH; | ||
1286 | break; | ||
1287 | default: | ||
1288 | break; | ||
1289 | } | ||
1290 | |||
1291 | writel(val, bank->chip.regs + offset); | ||
1292 | |||
1293 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1294 | } | ||
1295 | EXPORT_SYMBOL(sirfsoc_gpio_set_pull); | ||
1296 | |||
1297 | static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip) | ||
1298 | { | ||
1299 | return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip); | ||
1300 | } | ||
1301 | |||
1302 | static void sirfsoc_gpio_irq_ack(struct irq_data *d) | ||
1303 | { | ||
1304 | struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); | ||
1305 | int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; | ||
1306 | u32 val, offset; | ||
1307 | unsigned long flags; | ||
1308 | |||
1309 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1310 | |||
1311 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1312 | |||
1313 | val = readl(bank->chip.regs + offset); | ||
1314 | |||
1315 | writel(val, bank->chip.regs + offset); | ||
1316 | |||
1317 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1318 | } | ||
1319 | |||
1320 | static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx) | ||
1321 | { | ||
1322 | u32 val, offset; | ||
1323 | unsigned long flags; | ||
1324 | |||
1325 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1326 | |||
1327 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1328 | |||
1329 | val = readl(bank->chip.regs + offset); | ||
1330 | val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; | ||
1331 | val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; | ||
1332 | writel(val, bank->chip.regs + offset); | ||
1333 | |||
1334 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1335 | } | ||
1336 | |||
1337 | static void sirfsoc_gpio_irq_mask(struct irq_data *d) | ||
1338 | { | ||
1339 | struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); | ||
1340 | |||
1341 | __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); | ||
1342 | } | ||
1343 | |||
1344 | static void sirfsoc_gpio_irq_unmask(struct irq_data *d) | ||
1345 | { | ||
1346 | struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); | ||
1347 | int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; | ||
1348 | u32 val, offset; | ||
1349 | unsigned long flags; | ||
1350 | |||
1351 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1352 | |||
1353 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1354 | |||
1355 | val = readl(bank->chip.regs + offset); | ||
1356 | val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; | ||
1357 | val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK; | ||
1358 | writel(val, bank->chip.regs + offset); | ||
1359 | |||
1360 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1361 | } | ||
1362 | |||
1363 | static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) | ||
1364 | { | ||
1365 | struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); | ||
1366 | int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE; | ||
1367 | u32 val, offset; | ||
1368 | unsigned long flags; | ||
1369 | |||
1370 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1371 | |||
1372 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1373 | |||
1374 | val = readl(bank->chip.regs + offset); | ||
1375 | val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; | ||
1376 | |||
1377 | switch (type) { | ||
1378 | case IRQ_TYPE_NONE: | ||
1379 | break; | ||
1380 | case IRQ_TYPE_EDGE_RISING: | ||
1381 | val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; | ||
1382 | val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK; | ||
1383 | break; | ||
1384 | case IRQ_TYPE_EDGE_FALLING: | ||
1385 | val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; | ||
1386 | val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; | ||
1387 | break; | ||
1388 | case IRQ_TYPE_EDGE_BOTH: | ||
1389 | val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK | | ||
1390 | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK; | ||
1391 | break; | ||
1392 | case IRQ_TYPE_LEVEL_LOW: | ||
1393 | val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); | ||
1394 | val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK; | ||
1395 | break; | ||
1396 | case IRQ_TYPE_LEVEL_HIGH: | ||
1397 | val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK; | ||
1398 | val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK); | ||
1399 | break; | ||
1400 | } | ||
1401 | |||
1402 | writel(val, bank->chip.regs + offset); | ||
1403 | |||
1404 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | static struct irq_chip sirfsoc_irq_chip = { | ||
1410 | .name = "sirf-gpio-irq", | ||
1411 | .irq_ack = sirfsoc_gpio_irq_ack, | ||
1412 | .irq_mask = sirfsoc_gpio_irq_mask, | ||
1413 | .irq_unmask = sirfsoc_gpio_irq_unmask, | ||
1414 | .irq_set_type = sirfsoc_gpio_irq_type, | ||
1415 | }; | ||
1416 | |||
1417 | static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) | ||
1418 | { | ||
1419 | struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq); | ||
1420 | u32 status, ctrl; | ||
1421 | int idx = 0; | ||
1422 | unsigned int first_irq; | ||
1423 | |||
1424 | status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id)); | ||
1425 | if (!status) { | ||
1426 | printk(KERN_WARNING | ||
1427 | "%s: gpio id %d status %#x no interrupt is flaged\n", | ||
1428 | __func__, bank->id, status); | ||
1429 | handle_bad_irq(irq, desc); | ||
1430 | return; | ||
1431 | } | ||
1432 | |||
1433 | first_irq = bank->domain->revmap_data.legacy.first_irq; | ||
1434 | |||
1435 | while (status) { | ||
1436 | ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx)); | ||
1437 | |||
1438 | /* | ||
1439 | * Here we must check whether the corresponding GPIO's interrupt | ||
1440 | * has been enabled, otherwise just skip it | ||
1441 | */ | ||
1442 | if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) { | ||
1443 | pr_debug("%s: gpio id %d idx %d happens\n", | ||
1444 | __func__, bank->id, idx); | ||
1445 | generic_handle_irq(first_irq + idx); | ||
1446 | } | ||
1447 | |||
1448 | idx++; | ||
1449 | status = status >> 1; | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset) | ||
1454 | { | ||
1455 | u32 val; | ||
1456 | unsigned long flags; | ||
1457 | |||
1458 | spin_lock_irqsave(&bank->lock, flags); | ||
1459 | |||
1460 | val = readl(bank->chip.regs + ctrl_offset); | ||
1461 | val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK; | ||
1462 | writel(val, bank->chip.regs + ctrl_offset); | ||
1463 | |||
1464 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1465 | } | ||
1466 | |||
1467 | static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
1468 | { | ||
1469 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1470 | unsigned long flags; | ||
1471 | |||
1472 | if (pinctrl_request_gpio(chip->base + offset)) | ||
1473 | return -ENODEV; | ||
1474 | |||
1475 | spin_lock_irqsave(&bank->lock, flags); | ||
1476 | |||
1477 | /* | ||
1478 | * default status: | ||
1479 | * set direction as input and mask irq | ||
1480 | */ | ||
1481 | sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); | ||
1482 | __sirfsoc_gpio_irq_mask(bank, offset); | ||
1483 | |||
1484 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1485 | |||
1486 | return 0; | ||
1487 | } | ||
1488 | |||
1489 | static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
1490 | { | ||
1491 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1492 | unsigned long flags; | ||
1493 | |||
1494 | spin_lock_irqsave(&bank->lock, flags); | ||
1495 | |||
1496 | __sirfsoc_gpio_irq_mask(bank, offset); | ||
1497 | sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset)); | ||
1498 | |||
1499 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1500 | |||
1501 | pinctrl_free_gpio(chip->base + offset); | ||
1502 | } | ||
1503 | |||
1504 | static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) | ||
1505 | { | ||
1506 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1507 | int idx = sirfsoc_gpio_to_offset(gpio); | ||
1508 | unsigned long flags; | ||
1509 | unsigned offset; | ||
1510 | |||
1511 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1512 | |||
1513 | spin_lock_irqsave(&bank->lock, flags); | ||
1514 | |||
1515 | sirfsoc_gpio_set_input(bank, offset); | ||
1516 | |||
1517 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1518 | |||
1519 | return 0; | ||
1520 | } | ||
1521 | |||
1522 | static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset, | ||
1523 | int value) | ||
1524 | { | ||
1525 | u32 out_ctrl; | ||
1526 | unsigned long flags; | ||
1527 | |||
1528 | spin_lock_irqsave(&bank->lock, flags); | ||
1529 | |||
1530 | out_ctrl = readl(bank->chip.regs + offset); | ||
1531 | if (value) | ||
1532 | out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; | ||
1533 | else | ||
1534 | out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; | ||
1535 | |||
1536 | out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK; | ||
1537 | out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK; | ||
1538 | writel(out_ctrl, bank->chip.regs + offset); | ||
1539 | |||
1540 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1541 | } | ||
1542 | |||
1543 | static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) | ||
1544 | { | ||
1545 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1546 | int idx = sirfsoc_gpio_to_offset(gpio); | ||
1547 | u32 offset; | ||
1548 | unsigned long flags; | ||
1549 | |||
1550 | offset = SIRFSOC_GPIO_CTRL(bank->id, idx); | ||
1551 | |||
1552 | spin_lock_irqsave(&sgpio_lock, flags); | ||
1553 | |||
1554 | sirfsoc_gpio_set_output(bank, offset, value); | ||
1555 | |||
1556 | spin_unlock_irqrestore(&sgpio_lock, flags); | ||
1557 | |||
1558 | return 0; | ||
1559 | } | ||
1560 | |||
1561 | static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset) | ||
1562 | { | ||
1563 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1564 | u32 val; | ||
1565 | unsigned long flags; | ||
1566 | |||
1567 | spin_lock_irqsave(&bank->lock, flags); | ||
1568 | |||
1569 | val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); | ||
1570 | |||
1571 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1572 | |||
1573 | return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK); | ||
1574 | } | ||
1575 | |||
1576 | static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, | ||
1577 | int value) | ||
1578 | { | ||
1579 | struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip); | ||
1580 | u32 ctrl; | ||
1581 | unsigned long flags; | ||
1582 | |||
1583 | spin_lock_irqsave(&bank->lock, flags); | ||
1584 | |||
1585 | ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); | ||
1586 | if (value) | ||
1587 | ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK; | ||
1588 | else | ||
1589 | ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK; | ||
1590 | writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset)); | ||
1591 | |||
1592 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1593 | } | ||
1594 | |||
1595 | int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, | ||
1596 | irq_hw_number_t hwirq) | ||
1597 | { | ||
1598 | struct sirfsoc_gpio_bank *bank = d->host_data; | ||
1599 | |||
1600 | if (!bank) | ||
1601 | return -EINVAL; | ||
1602 | |||
1603 | irq_set_chip(irq, &sirfsoc_irq_chip); | ||
1604 | irq_set_handler(irq, handle_level_irq); | ||
1605 | irq_set_chip_data(irq, bank); | ||
1606 | set_irq_flags(irq, IRQF_VALID); | ||
1607 | |||
1608 | return 0; | ||
1609 | } | ||
1610 | |||
1611 | const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = { | ||
1612 | .map = sirfsoc_gpio_irq_map, | ||
1613 | .xlate = irq_domain_xlate_twocell, | ||
1614 | }; | ||
1615 | |||
1616 | static int __devinit sirfsoc_gpio_probe(struct device_node *np) | ||
1617 | { | ||
1618 | int i, err = 0; | ||
1619 | struct sirfsoc_gpio_bank *bank; | ||
1620 | void *regs; | ||
1621 | struct platform_device *pdev; | ||
1622 | |||
1623 | pdev = of_find_device_by_node(np); | ||
1624 | if (!pdev) | ||
1625 | return -ENODEV; | ||
1626 | |||
1627 | regs = of_iomap(np, 0); | ||
1628 | if (!regs) | ||
1629 | return -ENOMEM; | ||
1630 | |||
1631 | for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { | ||
1632 | bank = &sgpio_bank[i]; | ||
1633 | spin_lock_init(&bank->lock); | ||
1634 | bank->chip.gc.request = sirfsoc_gpio_request; | ||
1635 | bank->chip.gc.free = sirfsoc_gpio_free; | ||
1636 | bank->chip.gc.direction_input = sirfsoc_gpio_direction_input; | ||
1637 | bank->chip.gc.get = sirfsoc_gpio_get_value; | ||
1638 | bank->chip.gc.direction_output = sirfsoc_gpio_direction_output; | ||
1639 | bank->chip.gc.set = sirfsoc_gpio_set_value; | ||
1640 | bank->chip.gc.to_irq = sirfsoc_gpio_to_irq; | ||
1641 | bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE; | ||
1642 | bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE; | ||
1643 | bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); | ||
1644 | bank->chip.gc.of_node = np; | ||
1645 | bank->chip.regs = regs; | ||
1646 | bank->id = i; | ||
1647 | bank->parent_irq = platform_get_irq(pdev, i); | ||
1648 | if (bank->parent_irq < 0) { | ||
1649 | err = bank->parent_irq; | ||
1650 | goto out; | ||
1651 | } | ||
1652 | |||
1653 | err = gpiochip_add(&bank->chip.gc); | ||
1654 | if (err) { | ||
1655 | pr_err("%s: error in probe function with status %d\n", | ||
1656 | np->full_name, err); | ||
1657 | goto out; | ||
1658 | } | ||
1659 | |||
1660 | bank->domain = irq_domain_add_legacy(np, SIRFSOC_GPIO_BANK_SIZE, | ||
1661 | SIRFSOC_GPIO_IRQ_START + i * SIRFSOC_GPIO_BANK_SIZE, 0, | ||
1662 | &sirfsoc_gpio_irq_simple_ops, bank); | ||
1663 | |||
1664 | if (!bank->domain) { | ||
1665 | pr_err("%s: Failed to create irqdomain\n", np->full_name); | ||
1666 | err = -ENOSYS; | ||
1667 | goto out; | ||
1668 | } | ||
1669 | |||
1670 | irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq); | ||
1671 | irq_set_handler_data(bank->parent_irq, bank); | ||
1672 | } | ||
1673 | |||
1674 | out: | ||
1675 | iounmap(regs); | ||
1676 | return err; | ||
1677 | } | ||
1678 | |||
1679 | static int __init sirfsoc_gpio_init(void) | ||
1680 | { | ||
1681 | |||
1682 | struct device_node *np; | ||
1683 | |||
1684 | np = of_find_matching_node(NULL, pinmux_ids); | ||
1685 | |||
1686 | if (!np) | ||
1687 | return -ENODEV; | ||
1688 | |||
1689 | return sirfsoc_gpio_probe(np); | ||
1690 | } | ||
1691 | subsys_initcall(sirfsoc_gpio_init); | ||
1692 | |||
1207 | MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " | 1693 | MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " |
1694 | "Yuping Luo <yuping.luo@csr.com>, " | ||
1208 | "Barry Song <baohua.song@csr.com>"); | 1695 | "Barry Song <baohua.song@csr.com>"); |
1209 | MODULE_DESCRIPTION("SIRFSOC pin control driver"); | 1696 | MODULE_DESCRIPTION("SIRFSOC pin control driver"); |
1210 | MODULE_LICENSE("GPL"); | 1697 | MODULE_LICENSE("GPL"); |