1 /* 2 * AppliedMicro X-Gene SoC GPIO-Standby Driver 3 * 4 * Copyright (c) 2014, Applied Micro Circuits Corporation 5 * Author: Tin Huynh <tnhuynh@apm.com>. 6 * Y Vo <yvo@apm.com>. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <linux/module.h> 23 #include <linux/io.h> 24 #include <linux/platform_device.h> 25 #include <linux/of_gpio.h> 26 #include <linux/gpio/driver.h> 27 #include <linux/acpi.h> 28 29 #include "gpiolib.h" 30 31 #define XGENE_MAX_GPIO_DS 22 32 #define XGENE_MAX_GPIO_DS_IRQ 6 33 34 #define GPIO_MASK(x) (1U << ((x) % 32)) 35 36 #define MPA_GPIO_INT_LVL 0x0290 37 #define MPA_GPIO_OE_ADDR 0x029c 38 #define MPA_GPIO_OUT_ADDR 0x02a0 39 #define MPA_GPIO_IN_ADDR 0x02a4 40 #define MPA_GPIO_SEL_LO 0x0294 41 42 /** 43 * struct xgene_gpio_sb - GPIO-Standby private data structure. 44 * @gc: memory-mapped GPIO controllers. 45 * @irq: Mapping GPIO pins and interrupt number 46 * nirq: Number of GPIO pins that supports interrupt 47 */ 48 struct xgene_gpio_sb { 49 struct gpio_chip gc; 50 u32 *irq; 51 u32 nirq; 52 }; 53 54 static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio, int val) 55 { 56 u32 data; 57 58 data = gc->read_reg(reg); 59 if (val) 60 data |= GPIO_MASK(gpio); 61 else 62 data &= ~GPIO_MASK(gpio); 63 gc->write_reg(reg, data); 64 } 65 66 static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) 67 { 68 struct xgene_gpio_sb *priv = gpiochip_get_data(gc); 69 70 if (priv->irq[gpio]) 71 return priv->irq[gpio]; 72 73 return -ENXIO; 74 } 75 76 static int xgene_gpio_sb_probe(struct platform_device *pdev) 77 { 78 struct xgene_gpio_sb *priv; 79 u32 ret, i; 80 u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D}; 81 struct resource *res; 82 void __iomem *regs; 83 84 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 85 if (!priv) 86 return -ENOMEM; 87 88 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 89 regs = devm_ioremap_resource(&pdev->dev, res); 90 if (IS_ERR(regs)) 91 return PTR_ERR(regs); 92 93 ret = bgpio_init(&priv->gc, &pdev->dev, 4, 94 regs + MPA_GPIO_IN_ADDR, 95 regs + MPA_GPIO_OUT_ADDR, NULL, 96 regs + MPA_GPIO_OE_ADDR, NULL, 0); 97 if (ret) 98 return ret; 99 100 priv->gc.to_irq = apm_gpio_sb_to_irq; 101 priv->gc.ngpio = XGENE_MAX_GPIO_DS; 102 103 priv->nirq = XGENE_MAX_GPIO_DS_IRQ; 104 105 priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS, 106 GFP_KERNEL); 107 if (!priv->irq) 108 return -ENOMEM; 109 110 for (i = 0; i < priv->nirq; i++) { 111 priv->irq[default_lines[i]] = platform_get_irq(pdev, i); 112 xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_SEL_LO, 113 default_lines[i] * 2, 1); 114 xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_INT_LVL, i, 1); 115 } 116 117 platform_set_drvdata(pdev, priv); 118 119 ret = gpiochip_add_data(&priv->gc, priv); 120 if (ret) 121 dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n"); 122 else 123 dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); 124 125 if (priv->nirq > 0) { 126 /* Register interrupt handlers for gpio signaled acpi events */ 127 acpi_gpiochip_request_interrupts(&priv->gc); 128 } 129 130 return ret; 131 } 132 133 static int xgene_gpio_sb_remove(struct platform_device *pdev) 134 { 135 struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); 136 137 if (priv->nirq > 0) { 138 acpi_gpiochip_free_interrupts(&priv->gc); 139 } 140 141 gpiochip_remove(&priv->gc); 142 return 0; 143 } 144 145 static const struct of_device_id xgene_gpio_sb_of_match[] = { 146 {.compatible = "apm,xgene-gpio-sb", }, 147 {}, 148 }; 149 MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); 150 151 #ifdef CONFIG_ACPI 152 static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = { 153 {"APMC0D15", 0}, 154 {}, 155 }; 156 MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match); 157 #endif 158 159 static struct platform_driver xgene_gpio_sb_driver = { 160 .driver = { 161 .name = "xgene-gpio-sb", 162 .of_match_table = xgene_gpio_sb_of_match, 163 .acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match), 164 }, 165 .probe = xgene_gpio_sb_probe, 166 .remove = xgene_gpio_sb_remove, 167 }; 168 module_platform_driver(xgene_gpio_sb_driver); 169 170 MODULE_AUTHOR("AppliedMicro"); 171 MODULE_DESCRIPTION("APM X-Gene GPIO Standby driver"); 172 MODULE_LICENSE("GPL"); 173