1 /* 2 * 74xx MMIO GPIO driver 3 * 4 * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12 #include <linux/err.h> 13 #include <linux/gpio.h> 14 #include <linux/module.h> 15 #include <linux/of_device.h> 16 #include <linux/basic_mmio_gpio.h> 17 #include <linux/platform_device.h> 18 19 #define MMIO_74XX_DIR_IN (0 << 8) 20 #define MMIO_74XX_DIR_OUT (1 << 8) 21 #define MMIO_74XX_BIT_CNT(x) ((x) & 0xff) 22 23 struct mmio_74xx_gpio_priv { 24 struct bgpio_chip bgc; 25 unsigned flags; 26 }; 27 28 static const struct of_device_id mmio_74xx_gpio_ids[] = { 29 { 30 .compatible = "ti,741g125", 31 .data = (const void *)(MMIO_74XX_DIR_IN | 1), 32 }, 33 { 34 .compatible = "ti,742g125", 35 .data = (const void *)(MMIO_74XX_DIR_IN | 2), 36 }, 37 { 38 .compatible = "ti,74125", 39 .data = (const void *)(MMIO_74XX_DIR_IN | 4), 40 }, 41 { 42 .compatible = "ti,74365", 43 .data = (const void *)(MMIO_74XX_DIR_IN | 6), 44 }, 45 { 46 .compatible = "ti,74244", 47 .data = (const void *)(MMIO_74XX_DIR_IN | 8), 48 }, 49 { 50 .compatible = "ti,741624", 51 .data = (const void *)(MMIO_74XX_DIR_IN | 16), 52 }, 53 { 54 .compatible = "ti,741g74", 55 .data = (const void *)(MMIO_74XX_DIR_OUT | 1), 56 }, 57 { 58 .compatible = "ti,7474", 59 .data = (const void *)(MMIO_74XX_DIR_OUT | 2), 60 }, 61 { 62 .compatible = "ti,74175", 63 .data = (const void *)(MMIO_74XX_DIR_OUT | 4), 64 }, 65 { 66 .compatible = "ti,74174", 67 .data = (const void *)(MMIO_74XX_DIR_OUT | 6), 68 }, 69 { 70 .compatible = "ti,74273", 71 .data = (const void *)(MMIO_74XX_DIR_OUT | 8), 72 }, 73 { 74 .compatible = "ti,7416374", 75 .data = (const void *)(MMIO_74XX_DIR_OUT | 16), 76 }, 77 { } 78 }; 79 MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids); 80 81 static inline struct mmio_74xx_gpio_priv *to_74xx_gpio(struct gpio_chip *gc) 82 { 83 struct bgpio_chip *bgc = to_bgpio_chip(gc); 84 85 return container_of(bgc, struct mmio_74xx_gpio_priv, bgc); 86 } 87 88 static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset) 89 { 90 struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc); 91 92 return (priv->flags & MMIO_74XX_DIR_OUT) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; 93 } 94 95 static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio) 96 { 97 struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc); 98 99 return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0; 100 } 101 102 static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 103 { 104 struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc); 105 106 if (priv->flags & MMIO_74XX_DIR_OUT) { 107 gc->set(gc, gpio, val); 108 return 0; 109 } 110 111 return -ENOTSUPP; 112 } 113 114 static int mmio_74xx_gpio_probe(struct platform_device *pdev) 115 { 116 const struct of_device_id *of_id = 117 of_match_device(mmio_74xx_gpio_ids, &pdev->dev); 118 struct mmio_74xx_gpio_priv *priv; 119 struct resource *res; 120 void __iomem *dat; 121 int err; 122 123 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 124 if (!priv) 125 return -ENOMEM; 126 127 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 128 dat = devm_ioremap_resource(&pdev->dev, res); 129 if (IS_ERR(dat)) 130 return PTR_ERR(dat); 131 132 priv->flags = (uintptr_t) of_id->data; 133 134 err = bgpio_init(&priv->bgc, &pdev->dev, 135 DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8), 136 dat, NULL, NULL, NULL, NULL, 0); 137 if (err) 138 return err; 139 140 priv->bgc.gc.direction_input = mmio_74xx_dir_in; 141 priv->bgc.gc.direction_output = mmio_74xx_dir_out; 142 priv->bgc.gc.get_direction = mmio_74xx_get_direction; 143 priv->bgc.gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags); 144 priv->bgc.gc.owner = THIS_MODULE; 145 146 platform_set_drvdata(pdev, priv); 147 148 return gpiochip_add(&priv->bgc.gc); 149 } 150 151 static int mmio_74xx_gpio_remove(struct platform_device *pdev) 152 { 153 struct mmio_74xx_gpio_priv *priv = platform_get_drvdata(pdev); 154 155 return bgpio_remove(&priv->bgc); 156 } 157 158 static struct platform_driver mmio_74xx_gpio_driver = { 159 .driver = { 160 .name = "74xx-mmio-gpio", 161 .of_match_table = mmio_74xx_gpio_ids, 162 }, 163 .probe = mmio_74xx_gpio_probe, 164 .remove = mmio_74xx_gpio_remove, 165 }; 166 module_platform_driver(mmio_74xx_gpio_driver); 167 168 MODULE_LICENSE("GPL"); 169 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 170 MODULE_DESCRIPTION("74xx MMIO GPIO driver"); 171