19af4d80bSFabian Vogt /* 29af4d80bSFabian Vogt * GPIO controller in LSI ZEVIO SoCs. 39af4d80bSFabian Vogt * 49af4d80bSFabian Vogt * Author: Fabian Vogt <fabian@ritter-vogt.de> 59af4d80bSFabian Vogt * 69af4d80bSFabian Vogt * This program is free software; you can redistribute it and/or modify 79af4d80bSFabian Vogt * it under the terms of the GNU General Public License version 2 as 89af4d80bSFabian Vogt * published by the Free Software Foundation. 99af4d80bSFabian Vogt */ 109af4d80bSFabian Vogt 119af4d80bSFabian Vogt #include <linux/spinlock.h> 129af4d80bSFabian Vogt #include <linux/errno.h> 139af4d80bSFabian Vogt #include <linux/module.h> 149af4d80bSFabian Vogt #include <linux/bitops.h> 159af4d80bSFabian Vogt #include <linux/io.h> 169af4d80bSFabian Vogt #include <linux/of_device.h> 179af4d80bSFabian Vogt #include <linux/of_gpio.h> 189af4d80bSFabian Vogt #include <linux/slab.h> 199af4d80bSFabian Vogt #include <linux/gpio.h> 209af4d80bSFabian Vogt 219af4d80bSFabian Vogt /* 229af4d80bSFabian Vogt * Memory layout: 239af4d80bSFabian Vogt * This chip has four gpio sections, each controls 8 GPIOs. 249af4d80bSFabian Vogt * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10. 259af4d80bSFabian Vogt * Disclaimer: Reverse engineered! 269af4d80bSFabian Vogt * For more information refer to: 279af4d80bSFabian Vogt * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29 289af4d80bSFabian Vogt * 299af4d80bSFabian Vogt * 0x00-0x3F: Section 0 309af4d80bSFabian Vogt * +0x00: Masked interrupt status (read-only) 319af4d80bSFabian Vogt * +0x04: R: Interrupt status W: Reset interrupt status 329af4d80bSFabian Vogt * +0x08: R: Interrupt mask W: Mask interrupt 339af4d80bSFabian Vogt * +0x0C: W: Unmask interrupt (write-only) 349af4d80bSFabian Vogt * +0x10: Direction: I/O=1/0 359af4d80bSFabian Vogt * +0x14: Output 369af4d80bSFabian Vogt * +0x18: Input (read-only) 379af4d80bSFabian Vogt * +0x20: R: Level interrupt W: Set as level interrupt 389af4d80bSFabian Vogt * 0x40-0x7F: Section 1 399af4d80bSFabian Vogt * 0x80-0xBF: Section 2 409af4d80bSFabian Vogt * 0xC0-0xFF: Section 3 419af4d80bSFabian Vogt */ 429af4d80bSFabian Vogt 439af4d80bSFabian Vogt #define ZEVIO_GPIO_SECTION_SIZE 0x40 449af4d80bSFabian Vogt 459af4d80bSFabian Vogt /* Offsets to various registers */ 469af4d80bSFabian Vogt #define ZEVIO_GPIO_INT_MASKED_STATUS 0x00 479af4d80bSFabian Vogt #define ZEVIO_GPIO_INT_STATUS 0x04 489af4d80bSFabian Vogt #define ZEVIO_GPIO_INT_UNMASK 0x08 499af4d80bSFabian Vogt #define ZEVIO_GPIO_INT_MASK 0x0C 509af4d80bSFabian Vogt #define ZEVIO_GPIO_DIRECTION 0x10 519af4d80bSFabian Vogt #define ZEVIO_GPIO_OUTPUT 0x14 529af4d80bSFabian Vogt #define ZEVIO_GPIO_INPUT 0x18 539af4d80bSFabian Vogt #define ZEVIO_GPIO_INT_STICKY 0x20 549af4d80bSFabian Vogt 559af4d80bSFabian Vogt #define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \ 569af4d80bSFabian Vogt struct zevio_gpio, chip) 579af4d80bSFabian Vogt 589af4d80bSFabian Vogt /* Bit number of GPIO in its section */ 599af4d80bSFabian Vogt #define ZEVIO_GPIO_BIT(gpio) (gpio&7) 609af4d80bSFabian Vogt 619af4d80bSFabian Vogt struct zevio_gpio { 629af4d80bSFabian Vogt spinlock_t lock; 639af4d80bSFabian Vogt struct of_mm_gpio_chip chip; 649af4d80bSFabian Vogt }; 659af4d80bSFabian Vogt 669af4d80bSFabian Vogt static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, 679af4d80bSFabian Vogt unsigned port_offset) 689af4d80bSFabian Vogt { 699af4d80bSFabian Vogt unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; 709af4d80bSFabian Vogt return readl(IOMEM(c->chip.regs + section_offset + port_offset)); 719af4d80bSFabian Vogt } 729af4d80bSFabian Vogt 739af4d80bSFabian Vogt static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, 749af4d80bSFabian Vogt unsigned port_offset, u32 val) 759af4d80bSFabian Vogt { 769af4d80bSFabian Vogt unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; 779af4d80bSFabian Vogt writel(val, IOMEM(c->chip.regs + section_offset + port_offset)); 789af4d80bSFabian Vogt } 799af4d80bSFabian Vogt 809af4d80bSFabian Vogt /* Functions for struct gpio_chip */ 819af4d80bSFabian Vogt static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) 829af4d80bSFabian Vogt { 839af4d80bSFabian Vogt struct zevio_gpio *controller = to_zevio_gpio(chip); 849af4d80bSFabian Vogt 859af4d80bSFabian Vogt /* Only reading allowed, so no spinlock needed */ 869af4d80bSFabian Vogt u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); 879af4d80bSFabian Vogt 889af4d80bSFabian Vogt return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; 899af4d80bSFabian Vogt } 909af4d80bSFabian Vogt 919af4d80bSFabian Vogt static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) 929af4d80bSFabian Vogt { 939af4d80bSFabian Vogt struct zevio_gpio *controller = to_zevio_gpio(chip); 949af4d80bSFabian Vogt u32 val; 959af4d80bSFabian Vogt 969af4d80bSFabian Vogt spin_lock(&controller->lock); 979af4d80bSFabian Vogt val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); 989af4d80bSFabian Vogt if (value) 999af4d80bSFabian Vogt val |= BIT(ZEVIO_GPIO_BIT(pin)); 1009af4d80bSFabian Vogt else 1019af4d80bSFabian Vogt val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 1029af4d80bSFabian Vogt 1039af4d80bSFabian Vogt zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); 1049af4d80bSFabian Vogt spin_unlock(&controller->lock); 1059af4d80bSFabian Vogt } 1069af4d80bSFabian Vogt 1079af4d80bSFabian Vogt static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) 1089af4d80bSFabian Vogt { 1099af4d80bSFabian Vogt struct zevio_gpio *controller = to_zevio_gpio(chip); 1109af4d80bSFabian Vogt u32 val; 1119af4d80bSFabian Vogt 1129af4d80bSFabian Vogt spin_lock(&controller->lock); 1139af4d80bSFabian Vogt 1149af4d80bSFabian Vogt val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); 1159af4d80bSFabian Vogt val |= BIT(ZEVIO_GPIO_BIT(pin)); 1169af4d80bSFabian Vogt zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); 1179af4d80bSFabian Vogt 1189af4d80bSFabian Vogt spin_unlock(&controller->lock); 1199af4d80bSFabian Vogt 1209af4d80bSFabian Vogt return 0; 1219af4d80bSFabian Vogt } 1229af4d80bSFabian Vogt 1239af4d80bSFabian Vogt static int zevio_gpio_direction_output(struct gpio_chip *chip, 1249af4d80bSFabian Vogt unsigned pin, int value) 1259af4d80bSFabian Vogt { 1269af4d80bSFabian Vogt struct zevio_gpio *controller = to_zevio_gpio(chip); 1279af4d80bSFabian Vogt u32 val; 1289af4d80bSFabian Vogt 1299af4d80bSFabian Vogt spin_lock(&controller->lock); 1309af4d80bSFabian Vogt val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); 1319af4d80bSFabian Vogt if (value) 1329af4d80bSFabian Vogt val |= BIT(ZEVIO_GPIO_BIT(pin)); 1339af4d80bSFabian Vogt else 1349af4d80bSFabian Vogt val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 1359af4d80bSFabian Vogt 1369af4d80bSFabian Vogt zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); 1379af4d80bSFabian Vogt val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); 1389af4d80bSFabian Vogt val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 1399af4d80bSFabian Vogt zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); 1409af4d80bSFabian Vogt 1419af4d80bSFabian Vogt spin_unlock(&controller->lock); 1429af4d80bSFabian Vogt 1439af4d80bSFabian Vogt return 0; 1449af4d80bSFabian Vogt } 1459af4d80bSFabian Vogt 1469af4d80bSFabian Vogt static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) 1479af4d80bSFabian Vogt { 1489af4d80bSFabian Vogt /* 1499af4d80bSFabian Vogt * TODO: Implement IRQs. 1509af4d80bSFabian Vogt * Not implemented yet due to weird lockups 1519af4d80bSFabian Vogt */ 1529af4d80bSFabian Vogt 1539af4d80bSFabian Vogt return -ENXIO; 1549af4d80bSFabian Vogt } 1559af4d80bSFabian Vogt 1569af4d80bSFabian Vogt static struct gpio_chip zevio_gpio_chip = { 1579af4d80bSFabian Vogt .direction_input = zevio_gpio_direction_input, 1589af4d80bSFabian Vogt .direction_output = zevio_gpio_direction_output, 1599af4d80bSFabian Vogt .set = zevio_gpio_set, 1609af4d80bSFabian Vogt .get = zevio_gpio_get, 1619af4d80bSFabian Vogt .to_irq = zevio_gpio_to_irq, 1629af4d80bSFabian Vogt .base = 0, 1639af4d80bSFabian Vogt .owner = THIS_MODULE, 1649af4d80bSFabian Vogt .ngpio = 32, 1659af4d80bSFabian Vogt .of_gpio_n_cells = 2, 1669af4d80bSFabian Vogt }; 1679af4d80bSFabian Vogt 1689af4d80bSFabian Vogt /* Initialization */ 1699af4d80bSFabian Vogt static int zevio_gpio_probe(struct platform_device *pdev) 1709af4d80bSFabian Vogt { 1719af4d80bSFabian Vogt struct zevio_gpio *controller; 1729af4d80bSFabian Vogt int status, i; 1739af4d80bSFabian Vogt 1749af4d80bSFabian Vogt controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); 1759af4d80bSFabian Vogt if (!controller) { 1769af4d80bSFabian Vogt dev_err(&pdev->dev, "not enough free memory\n"); 1779af4d80bSFabian Vogt return -ENOMEM; 1789af4d80bSFabian Vogt } 1799af4d80bSFabian Vogt 1809af4d80bSFabian Vogt /* Copy our reference */ 1819af4d80bSFabian Vogt controller->chip.gc = zevio_gpio_chip; 1829af4d80bSFabian Vogt controller->chip.gc.dev = &pdev->dev; 1839af4d80bSFabian Vogt 1849af4d80bSFabian Vogt status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip)); 1859af4d80bSFabian Vogt if (status) { 1869af4d80bSFabian Vogt dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); 1879af4d80bSFabian Vogt return status; 1889af4d80bSFabian Vogt } 1899af4d80bSFabian Vogt 1909af4d80bSFabian Vogt spin_lock_init(&controller->lock); 1919af4d80bSFabian Vogt 1929af4d80bSFabian Vogt /* Disable interrupts, they only cause errors */ 1939af4d80bSFabian Vogt for (i = 0; i < controller->chip.gc.ngpio; i += 8) 1949af4d80bSFabian Vogt zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); 1959af4d80bSFabian Vogt 1969af4d80bSFabian Vogt dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n"); 1979af4d80bSFabian Vogt 1989af4d80bSFabian Vogt return 0; 1999af4d80bSFabian Vogt } 2009af4d80bSFabian Vogt 2019af4d80bSFabian Vogt static struct of_device_id zevio_gpio_of_match[] = { 2029af4d80bSFabian Vogt { .compatible = "lsi,zevio-gpio", }, 2039af4d80bSFabian Vogt { }, 2049af4d80bSFabian Vogt }; 2059af4d80bSFabian Vogt 2069af4d80bSFabian Vogt MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); 2079af4d80bSFabian Vogt 2089af4d80bSFabian Vogt static struct platform_driver zevio_gpio_driver = { 2099af4d80bSFabian Vogt .driver = { 2109af4d80bSFabian Vogt .name = "gpio-zevio", 2119af4d80bSFabian Vogt .owner = THIS_MODULE, 2129af4d80bSFabian Vogt .of_match_table = of_match_ptr(zevio_gpio_of_match), 2139af4d80bSFabian Vogt }, 2149af4d80bSFabian Vogt .probe = zevio_gpio_probe, 2159af4d80bSFabian Vogt }; 2169af4d80bSFabian Vogt module_platform_driver(zevio_gpio_driver); 2179af4d80bSFabian Vogt 2189af4d80bSFabian Vogt MODULE_LICENSE("GPL"); 2199af4d80bSFabian Vogt MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>"); 2209af4d80bSFabian Vogt MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); 221