153 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * 74xx MMIO GPIO driver4 *5 * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>6 */7 8#include <linux/bits.h>9#include <linux/err.h>10#include <linux/gpio/driver.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/property.h>15 16#define MMIO_74XX_DIR_IN BIT(8)17#define MMIO_74XX_DIR_OUT BIT(9)18#define MMIO_74XX_BIT_CNT(x) ((x) & GENMASK(7, 0))19 20struct mmio_74xx_gpio_priv {21 struct gpio_chip gc;22 unsigned flags;23};24 25static const struct of_device_id mmio_74xx_gpio_ids[] = {26 {27 .compatible = "ti,741g125",28 .data = (const void *)(MMIO_74XX_DIR_IN | 1),29 },30 {31 .compatible = "ti,742g125",32 .data = (const void *)(MMIO_74XX_DIR_IN | 2),33 },34 {35 .compatible = "ti,74125",36 .data = (const void *)(MMIO_74XX_DIR_IN | 4),37 },38 {39 .compatible = "ti,74365",40 .data = (const void *)(MMIO_74XX_DIR_IN | 6),41 },42 {43 .compatible = "ti,74244",44 .data = (const void *)(MMIO_74XX_DIR_IN | 8),45 },46 {47 .compatible = "ti,741624",48 .data = (const void *)(MMIO_74XX_DIR_IN | 16),49 },50 {51 .compatible = "ti,741g74",52 .data = (const void *)(MMIO_74XX_DIR_OUT | 1),53 },54 {55 .compatible = "ti,7474",56 .data = (const void *)(MMIO_74XX_DIR_OUT | 2),57 },58 {59 .compatible = "ti,74175",60 .data = (const void *)(MMIO_74XX_DIR_OUT | 4),61 },62 {63 .compatible = "ti,74174",64 .data = (const void *)(MMIO_74XX_DIR_OUT | 6),65 },66 {67 .compatible = "ti,74273",68 .data = (const void *)(MMIO_74XX_DIR_OUT | 8),69 },70 {71 .compatible = "ti,7416374",72 .data = (const void *)(MMIO_74XX_DIR_OUT | 16),73 },74 { }75};76MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids);77 78static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset)79{80 struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);81 82 if (priv->flags & MMIO_74XX_DIR_OUT)83 return GPIO_LINE_DIRECTION_OUT;84 85 return GPIO_LINE_DIRECTION_IN;86}87 88static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)89{90 struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);91 92 if (priv->flags & MMIO_74XX_DIR_IN)93 return 0;94 95 return -ENOTSUPP;96}97 98static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)99{100 struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);101 102 if (priv->flags & MMIO_74XX_DIR_OUT) {103 gc->set(gc, gpio, val);104 return 0;105 }106 107 return -ENOTSUPP;108}109 110static int mmio_74xx_gpio_probe(struct platform_device *pdev)111{112 struct mmio_74xx_gpio_priv *priv;113 void __iomem *dat;114 int err;115 116 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);117 if (!priv)118 return -ENOMEM;119 120 priv->flags = (uintptr_t)device_get_match_data(&pdev->dev);121 122 dat = devm_platform_ioremap_resource(pdev, 0);123 if (IS_ERR(dat))124 return PTR_ERR(dat);125 126 err = bgpio_init(&priv->gc, &pdev->dev,127 DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),128 dat, NULL, NULL, NULL, NULL, 0);129 if (err)130 return err;131 132 priv->gc.direction_input = mmio_74xx_dir_in;133 priv->gc.direction_output = mmio_74xx_dir_out;134 priv->gc.get_direction = mmio_74xx_get_direction;135 priv->gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);136 priv->gc.owner = THIS_MODULE;137 138 return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);139}140 141static struct platform_driver mmio_74xx_gpio_driver = {142 .driver = {143 .name = "74xx-mmio-gpio",144 .of_match_table = mmio_74xx_gpio_ids,145 },146 .probe = mmio_74xx_gpio_probe,147};148module_platform_driver(mmio_74xx_gpio_driver);149 150MODULE_LICENSE("GPL");151MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");152MODULE_DESCRIPTION("74xx MMIO GPIO driver");153