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 23struct mmio_74xx_gpio_priv { 24 struct bgpio_chip bgc; 25 unsigned flags; 26}; 27 28static 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}; 79MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids); 80 81static 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 88static 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 95static 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 102static 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 114static 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 = (unsigned)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 151static 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 158static 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}; 166module_platform_driver(mmio_74xx_gpio_driver); 167 168MODULE_LICENSE("GPL"); 169MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 170MODULE_DESCRIPTION("74xx MMIO GPIO driver"); 171