162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for GE FPGA based GPIO 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Martyn Welch <martyn.welch@ge.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * TODO: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Configuration of output modes (totem-pole/open-drain). 1462306a36Sopenharmony_ci * Interrupt configuration - interrupts are always generated, the FPGA relies 1562306a36Sopenharmony_ci * on the I/O interrupt controllers mask to stop them from being propagated. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/platform_device.h> 2462306a36Sopenharmony_ci#include <linux/property.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define GEF_GPIO_DIRECT 0x00 2862306a36Sopenharmony_ci#define GEF_GPIO_IN 0x04 2962306a36Sopenharmony_ci#define GEF_GPIO_OUT 0x08 3062306a36Sopenharmony_ci#define GEF_GPIO_TRIG 0x0C 3162306a36Sopenharmony_ci#define GEF_GPIO_POLAR_A 0x10 3262306a36Sopenharmony_ci#define GEF_GPIO_POLAR_B 0x14 3362306a36Sopenharmony_ci#define GEF_GPIO_INT_STAT 0x18 3462306a36Sopenharmony_ci#define GEF_GPIO_OVERRUN 0x1C 3562306a36Sopenharmony_ci#define GEF_GPIO_MODE 0x20 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const struct of_device_id gef_gpio_ids[] = { 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci .compatible = "gef,sbc610-gpio", 4062306a36Sopenharmony_ci .data = (void *)19, 4162306a36Sopenharmony_ci }, { 4262306a36Sopenharmony_ci .compatible = "gef,sbc310-gpio", 4362306a36Sopenharmony_ci .data = (void *)6, 4462306a36Sopenharmony_ci }, { 4562306a36Sopenharmony_ci .compatible = "ge,imp3a-gpio", 4662306a36Sopenharmony_ci .data = (void *)16, 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci { } 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, gef_gpio_ids); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int __init gef_gpio_probe(struct platform_device *pdev) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 5562306a36Sopenharmony_ci struct gpio_chip *gc; 5662306a36Sopenharmony_ci void __iomem *regs; 5762306a36Sopenharmony_ci int ret; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); 6062306a36Sopenharmony_ci if (!gc) 6162306a36Sopenharmony_ci return -ENOMEM; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 6462306a36Sopenharmony_ci if (IS_ERR(regs)) 6562306a36Sopenharmony_ci return PTR_ERR(regs); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = bgpio_init(gc, dev, 4, regs + GEF_GPIO_IN, regs + GEF_GPIO_OUT, 6862306a36Sopenharmony_ci NULL, NULL, regs + GEF_GPIO_DIRECT, 6962306a36Sopenharmony_ci BGPIOF_BIG_ENDIAN_BYTE_ORDER); 7062306a36Sopenharmony_ci if (ret) 7162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "bgpio_init failed\n"); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Setup pointers to chip functions */ 7462306a36Sopenharmony_ci gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev)); 7562306a36Sopenharmony_ci if (!gc->label) 7662306a36Sopenharmony_ci return -ENOMEM; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci gc->base = -1; 7962306a36Sopenharmony_ci gc->ngpio = (uintptr_t)device_get_match_data(dev); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* This function adds a memory mapped GPIO chip */ 8262306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, gc, NULL); 8362306a36Sopenharmony_ci if (ret) 8462306a36Sopenharmony_ci return dev_err_probe(dev, ret, "GPIO chip registration failed\n"); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic struct platform_driver gef_gpio_driver = { 9062306a36Sopenharmony_ci .driver = { 9162306a36Sopenharmony_ci .name = "gef-gpio", 9262306a36Sopenharmony_ci .of_match_table = gef_gpio_ids, 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_cimodule_platform_driver_probe(gef_gpio_driver, gef_gpio_probe); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciMODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); 9862306a36Sopenharmony_ciMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>"); 9962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 100