162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * GPIO controller in LSI ZEVIO SoCs. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Fabian Vogt <fabian@ritter-vogt.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Memory layout: 2162306a36Sopenharmony_ci * This chip has four gpio sections, each controls 8 GPIOs. 2262306a36Sopenharmony_ci * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10. 2362306a36Sopenharmony_ci * Disclaimer: Reverse engineered! 2462306a36Sopenharmony_ci * For more information refer to: 2562306a36Sopenharmony_ci * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * 0x00-0x3F: Section 0 2862306a36Sopenharmony_ci * +0x00: Masked interrupt status (read-only) 2962306a36Sopenharmony_ci * +0x04: R: Interrupt status W: Reset interrupt status 3062306a36Sopenharmony_ci * +0x08: R: Interrupt mask W: Mask interrupt 3162306a36Sopenharmony_ci * +0x0C: W: Unmask interrupt (write-only) 3262306a36Sopenharmony_ci * +0x10: Direction: I/O=1/0 3362306a36Sopenharmony_ci * +0x14: Output 3462306a36Sopenharmony_ci * +0x18: Input (read-only) 3562306a36Sopenharmony_ci * +0x20: R: Level interrupt W: Set as level interrupt 3662306a36Sopenharmony_ci * 0x40-0x7F: Section 1 3762306a36Sopenharmony_ci * 0x80-0xBF: Section 2 3862306a36Sopenharmony_ci * 0xC0-0xFF: Section 3 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define ZEVIO_GPIO_SECTION_SIZE 0x40 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Offsets to various registers */ 4462306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00 4562306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_STATUS 0x04 4662306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_UNMASK 0x08 4762306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_MASK 0x0C 4862306a36Sopenharmony_ci#define ZEVIO_GPIO_DIRECTION 0x10 4962306a36Sopenharmony_ci#define ZEVIO_GPIO_OUTPUT 0x14 5062306a36Sopenharmony_ci#define ZEVIO_GPIO_INPUT 0x18 5162306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_STICKY 0x20 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Bit number of GPIO in its section */ 5462306a36Sopenharmony_ci#define ZEVIO_GPIO_BIT(gpio) (gpio&7) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct zevio_gpio { 5762306a36Sopenharmony_ci struct gpio_chip chip; 5862306a36Sopenharmony_ci spinlock_t lock; 5962306a36Sopenharmony_ci void __iomem *regs; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, 6362306a36Sopenharmony_ci unsigned port_offset) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; 6662306a36Sopenharmony_ci return readl(IOMEM(c->regs + section_offset + port_offset)); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, 7062306a36Sopenharmony_ci unsigned port_offset, u32 val) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; 7362306a36Sopenharmony_ci writel(val, IOMEM(c->regs + section_offset + port_offset)); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Functions for struct gpio_chip */ 7762306a36Sopenharmony_cistatic int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct zevio_gpio *controller = gpiochip_get_data(chip); 8062306a36Sopenharmony_ci u32 val, dir; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci spin_lock(&controller->lock); 8362306a36Sopenharmony_ci dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); 8462306a36Sopenharmony_ci if (dir & BIT(ZEVIO_GPIO_BIT(pin))) 8562306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); 8862306a36Sopenharmony_ci spin_unlock(&controller->lock); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct zevio_gpio *controller = gpiochip_get_data(chip); 9662306a36Sopenharmony_ci u32 val; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock(&controller->lock); 9962306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); 10062306a36Sopenharmony_ci if (value) 10162306a36Sopenharmony_ci val |= BIT(ZEVIO_GPIO_BIT(pin)); 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); 10662306a36Sopenharmony_ci spin_unlock(&controller->lock); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct zevio_gpio *controller = gpiochip_get_data(chip); 11262306a36Sopenharmony_ci u32 val; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci spin_lock(&controller->lock); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); 11762306a36Sopenharmony_ci val |= BIT(ZEVIO_GPIO_BIT(pin)); 11862306a36Sopenharmony_ci zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci spin_unlock(&controller->lock); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int zevio_gpio_direction_output(struct gpio_chip *chip, 12662306a36Sopenharmony_ci unsigned pin, int value) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct zevio_gpio *controller = gpiochip_get_data(chip); 12962306a36Sopenharmony_ci u32 val; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci spin_lock(&controller->lock); 13262306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); 13362306a36Sopenharmony_ci if (value) 13462306a36Sopenharmony_ci val |= BIT(ZEVIO_GPIO_BIT(pin)); 13562306a36Sopenharmony_ci else 13662306a36Sopenharmony_ci val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); 13962306a36Sopenharmony_ci val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); 14062306a36Sopenharmony_ci val &= ~BIT(ZEVIO_GPIO_BIT(pin)); 14162306a36Sopenharmony_ci zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci spin_unlock(&controller->lock); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * TODO: Implement IRQs. 15262306a36Sopenharmony_ci * Not implemented yet due to weird lockups 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return -ENXIO; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic const struct gpio_chip zevio_gpio_chip = { 15962306a36Sopenharmony_ci .direction_input = zevio_gpio_direction_input, 16062306a36Sopenharmony_ci .direction_output = zevio_gpio_direction_output, 16162306a36Sopenharmony_ci .set = zevio_gpio_set, 16262306a36Sopenharmony_ci .get = zevio_gpio_get, 16362306a36Sopenharmony_ci .to_irq = zevio_gpio_to_irq, 16462306a36Sopenharmony_ci .base = 0, 16562306a36Sopenharmony_ci .owner = THIS_MODULE, 16662306a36Sopenharmony_ci .ngpio = 32, 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* Initialization */ 17062306a36Sopenharmony_cistatic int zevio_gpio_probe(struct platform_device *pdev) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct zevio_gpio *controller; 17362306a36Sopenharmony_ci int status, i; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); 17662306a36Sopenharmony_ci if (!controller) 17762306a36Sopenharmony_ci return -ENOMEM; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Copy our reference */ 18062306a36Sopenharmony_ci controller->chip = zevio_gpio_chip; 18162306a36Sopenharmony_ci controller->chip.parent = &pdev->dev; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci controller->regs = devm_platform_ioremap_resource(pdev, 0); 18462306a36Sopenharmony_ci if (IS_ERR(controller->regs)) 18562306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(controller->regs), 18662306a36Sopenharmony_ci "failed to ioremap memory resource\n"); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci status = devm_gpiochip_add_data(&pdev->dev, &controller->chip, controller); 18962306a36Sopenharmony_ci if (status) { 19062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); 19162306a36Sopenharmony_ci return status; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci spin_lock_init(&controller->lock); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Disable interrupts, they only cause errors */ 19762306a36Sopenharmony_ci for (i = 0; i < controller->chip.ngpio; i += 8) 19862306a36Sopenharmony_ci zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci dev_dbg(controller->chip.parent, "ZEVIO GPIO controller set up!\n"); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic const struct of_device_id zevio_gpio_of_match[] = { 20662306a36Sopenharmony_ci { .compatible = "lsi,zevio-gpio", }, 20762306a36Sopenharmony_ci { }, 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic struct platform_driver zevio_gpio_driver = { 21162306a36Sopenharmony_ci .driver = { 21262306a36Sopenharmony_ci .name = "gpio-zevio", 21362306a36Sopenharmony_ci .of_match_table = zevio_gpio_of_match, 21462306a36Sopenharmony_ci .suppress_bind_attrs = true, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci .probe = zevio_gpio_probe, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_cibuiltin_platform_driver(zevio_gpio_driver); 219