Merge tag 'f2fs-for-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[platform/kernel/linux-rpi.git] / drivers / gpio / gpio-74xx-mmio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * 74xx MMIO GPIO driver
4  *
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
20 struct mmio_74xx_gpio_priv {
21         struct gpio_chip        gc;
22         unsigned                flags;
23 };
24
25 static 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 };
76 MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids);
77
78 static 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
88 static 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
98 static 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
110 static 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         platform_set_drvdata(pdev, priv);
139
140         return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
141 }
142
143 static struct platform_driver mmio_74xx_gpio_driver = {
144         .driver = {
145                 .name           = "74xx-mmio-gpio",
146                 .of_match_table = mmio_74xx_gpio_ids,
147         },
148         .probe  = mmio_74xx_gpio_probe,
149 };
150 module_platform_driver(mmio_74xx_gpio_driver);
151
152 MODULE_LICENSE("GPL");
153 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
154 MODULE_DESCRIPTION("74xx MMIO GPIO driver");