diff options
| -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 7658d19bb111..c7e6d208fa8d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -412,6 +412,7 @@ config ARCH_PRIMA2 | |||
| 412 | bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" | 412 | bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" |
| 413 | select CPU_V7 | 413 | select CPU_V7 |
| 414 | select NO_IOPORT | 414 | select NO_IOPORT |
| 415 | select ARCH_REQUIRE_GPIOLIB | ||
| 415 | select GENERIC_CLOCKEVENTS | 416 | select GENERIC_CLOCKEVENTS |
| 416 | select CLKDEV_LOOKUP | 417 | select CLKDEV_LOOKUP |
| 417 | select GENERIC_IRQ_CHIP | 418 | 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"); |
